1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef GrVkCommandBuffer_DEFINED 9 #define GrVkCommandBuffer_DEFINED 10 11 #include "GrVkGpu.h" 12 #include "GrVkResource.h" 13 #include "GrVkSemaphore.h" 14 #include "GrVkUtil.h" 15 #include "vk/GrVkDefines.h" 16 17 class GrVkFramebuffer; 18 class GrVkPipeline; 19 class GrVkRenderPass; 20 class GrVkRenderTarget; 21 class GrVkTransferBuffer; 22 23 class GrVkCommandBuffer : public GrVkResource { 24 public: 25 void invalidateState(); 26 27 //////////////////////////////////////////////////////////////////////////// 28 // CommandBuffer commands 29 //////////////////////////////////////////////////////////////////////////// 30 enum BarrierType { 31 kMemory_BarrierType, 32 kBufferMemory_BarrierType, 33 kImageMemory_BarrierType 34 }; 35 36 void pipelineBarrier(const GrVkGpu* gpu, 37 VkPipelineStageFlags srcStageMask, 38 VkPipelineStageFlags dstStageMask, 39 bool byRegion, 40 BarrierType barrierType, 41 void* barrier) const; 42 bindVertexBuffer(GrVkGpu * gpu,GrVkVertexBuffer * vbuffer)43 void bindVertexBuffer(GrVkGpu* gpu, GrVkVertexBuffer* vbuffer) { 44 VkBuffer vkBuffer = vbuffer->buffer(); 45 // TODO: once vbuffer->offset() no longer always returns 0, we will need to track the offset 46 // to know if we can skip binding or not. 47 if (!fBoundVertexBufferIsValid || vkBuffer != fBoundVertexBuffer) { 48 VkDeviceSize offset = vbuffer->offset(); 49 GR_VK_CALL(gpu->vkInterface(), CmdBindVertexBuffers(fCmdBuffer, 50 0, 51 1, 52 &vkBuffer, 53 &offset)); 54 fBoundVertexBufferIsValid = true; 55 fBoundVertexBuffer = vkBuffer; 56 addResource(vbuffer->resource()); 57 } 58 } 59 bindIndexBuffer(GrVkGpu * gpu,GrVkIndexBuffer * ibuffer)60 void bindIndexBuffer(GrVkGpu* gpu, GrVkIndexBuffer* ibuffer) { 61 VkBuffer vkBuffer = ibuffer->buffer(); 62 // TODO: once ibuffer->offset() no longer always returns 0, we will need to track the offset 63 // to know if we can skip binding or not. 64 if (!fBoundIndexBufferIsValid || vkBuffer != fBoundIndexBuffer) { 65 GR_VK_CALL(gpu->vkInterface(), CmdBindIndexBuffer(fCmdBuffer, 66 vkBuffer, 67 ibuffer->offset(), 68 VK_INDEX_TYPE_UINT16)); 69 fBoundIndexBufferIsValid = true; 70 fBoundIndexBuffer = vkBuffer; 71 addResource(ibuffer->resource()); 72 } 73 } 74 75 void bindPipeline(const GrVkGpu* gpu, const GrVkPipeline* pipeline); 76 77 void bindDescriptorSets(const GrVkGpu* gpu, 78 GrVkPipelineState*, 79 VkPipelineLayout layout, 80 uint32_t firstSet, 81 uint32_t setCount, 82 const VkDescriptorSet* descriptorSets, 83 uint32_t dynamicOffsetCount, 84 const uint32_t* dynamicOffsets); 85 86 void bindDescriptorSets(const GrVkGpu* gpu, 87 const SkTArray<const GrVkRecycledResource*>&, 88 const SkTArray<const GrVkResource*>&, 89 VkPipelineLayout layout, 90 uint32_t firstSet, 91 uint32_t setCount, 92 const VkDescriptorSet* descriptorSets, 93 uint32_t dynamicOffsetCount, 94 const uint32_t* dynamicOffsets); 95 96 void setViewport(const GrVkGpu* gpu, 97 uint32_t firstViewport, 98 uint32_t viewportCount, 99 const VkViewport* viewports); 100 101 void setScissor(const GrVkGpu* gpu, 102 uint32_t firstScissor, 103 uint32_t scissorCount, 104 const VkRect2D* scissors); 105 106 void setBlendConstants(const GrVkGpu* gpu, const float blendConstants[4]); 107 108 // Commands that only work inside of a render pass 109 void clearAttachments(const GrVkGpu* gpu, 110 int numAttachments, 111 const VkClearAttachment* attachments, 112 int numRects, 113 const VkClearRect* clearRects) const; 114 115 void drawIndexed(const GrVkGpu* gpu, 116 uint32_t indexCount, 117 uint32_t instanceCount, 118 uint32_t firstIndex, 119 int32_t vertexOffset, 120 uint32_t firstInstance) const; 121 122 void draw(const GrVkGpu* gpu, 123 uint32_t vertexCount, 124 uint32_t instanceCount, 125 uint32_t firstVertex, 126 uint32_t firstInstance) const; 127 128 // Add ref-counted resource that will be tracked and released when this 129 // command buffer finishes execution addResource(const GrVkResource * resource)130 void addResource(const GrVkResource* resource) { 131 resource->ref(); 132 fTrackedResources.append(1, &resource); 133 } 134 135 // Add ref-counted resource that will be tracked and released when this command buffer finishes 136 // execution. When it is released, it will signal that the resource can be recycled for reuse. addRecycledResource(const GrVkRecycledResource * resource)137 void addRecycledResource(const GrVkRecycledResource* resource) { 138 resource->ref(); 139 fTrackedRecycledResources.append(1, &resource); 140 } 141 142 void reset(GrVkGpu* gpu); 143 144 protected: 145 GrVkCommandBuffer(VkCommandBuffer cmdBuffer, const GrVkRenderPass* rp = VK_NULL_HANDLE) fIsActive(false)146 : fIsActive(false) 147 , fActiveRenderPass(rp) 148 , fCmdBuffer(cmdBuffer) 149 , fBoundVertexBufferIsValid(false) 150 , fBoundIndexBufferIsValid(false) 151 , fNumResets(0) { 152 fTrackedResources.setReserve(kInitialTrackedResourcesCount); 153 fTrackedRecycledResources.setReserve(kInitialTrackedResourcesCount); 154 this->invalidateState(); 155 } 156 157 SkTDArray<const GrVkResource*> fTrackedResources; 158 SkTDArray<const GrVkRecycledResource*> fTrackedRecycledResources; 159 160 // Tracks whether we are in the middle of a command buffer begin/end calls and thus can add 161 // new commands to the buffer; 162 bool fIsActive; 163 164 // Stores a pointer to the current active render pass (i.e. begin has been called but not 165 // end). A nullptr means there is no active render pass. The GrVKCommandBuffer does not own 166 // the render pass. 167 const GrVkRenderPass* fActiveRenderPass; 168 169 VkCommandBuffer fCmdBuffer; 170 171 private: 172 static const int kInitialTrackedResourcesCount = 32; 173 174 void freeGPUData(const GrVkGpu* gpu) const override; 175 virtual void onFreeGPUData(const GrVkGpu* gpu) const = 0; 176 void abandonSubResources() const override; 177 onReset(GrVkGpu * gpu)178 virtual void onReset(GrVkGpu* gpu) {} 179 180 VkBuffer fBoundVertexBuffer; 181 bool fBoundVertexBufferIsValid; 182 183 VkBuffer fBoundIndexBuffer; 184 bool fBoundIndexBufferIsValid; 185 186 // When resetting the command buffer, we remove the tracked resources from their arrays, and 187 // we prefer to not free all the memory every time so usually we just rewind. However, to avoid 188 // all arrays growing to the max size, after so many resets we'll do a full reset of the tracked 189 // resource arrays. 190 static const int kNumRewindResetsBeforeFullReset = 8; 191 int fNumResets; 192 193 // Cached values used for dynamic state updates 194 VkViewport fCachedViewport; 195 VkRect2D fCachedScissor; 196 float fCachedBlendConstant[4]; 197 }; 198 199 class GrVkSecondaryCommandBuffer; 200 201 class GrVkPrimaryCommandBuffer : public GrVkCommandBuffer { 202 public: 203 ~GrVkPrimaryCommandBuffer() override; 204 205 static GrVkPrimaryCommandBuffer* Create(const GrVkGpu* gpu, VkCommandPool cmdPool); 206 207 void begin(const GrVkGpu* gpu); 208 void end(const GrVkGpu* gpu); 209 210 // Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used 211 // in the render pass. 212 void beginRenderPass(const GrVkGpu* gpu, 213 const GrVkRenderPass* renderPass, 214 const VkClearValue* clearValues, 215 const GrVkRenderTarget& target, 216 const SkIRect& bounds, 217 bool forSecondaryCB); 218 void endRenderPass(const GrVkGpu* gpu); 219 220 // Submits the SecondaryCommandBuffer into this command buffer. It is required that we are 221 // currently inside a render pass that is compatible with the one used to create the 222 // SecondaryCommandBuffer. 223 void executeCommands(const GrVkGpu* gpu, 224 GrVkSecondaryCommandBuffer* secondaryBuffer); 225 226 // Commands that only work outside of a render pass 227 void clearColorImage(const GrVkGpu* gpu, 228 GrVkImage* image, 229 const VkClearColorValue* color, 230 uint32_t subRangeCount, 231 const VkImageSubresourceRange* subRanges); 232 233 void clearDepthStencilImage(const GrVkGpu* gpu, 234 GrVkImage* image, 235 const VkClearDepthStencilValue* color, 236 uint32_t subRangeCount, 237 const VkImageSubresourceRange* subRanges); 238 239 void copyImage(const GrVkGpu* gpu, 240 GrVkImage* srcImage, 241 VkImageLayout srcLayout, 242 GrVkImage* dstImage, 243 VkImageLayout dstLayout, 244 uint32_t copyRegionCount, 245 const VkImageCopy* copyRegions); 246 247 void blitImage(const GrVkGpu* gpu, 248 const GrVkResource* srcResource, 249 VkImage srcImage, 250 VkImageLayout srcLayout, 251 const GrVkResource* dstResource, 252 VkImage dstImage, 253 VkImageLayout dstLayout, 254 uint32_t blitRegionCount, 255 const VkImageBlit* blitRegions, 256 VkFilter filter); 257 blitImage(const GrVkGpu * gpu,const GrVkImage & srcImage,const GrVkImage & dstImage,uint32_t blitRegionCount,const VkImageBlit * blitRegions,VkFilter filter)258 void blitImage(const GrVkGpu* gpu, 259 const GrVkImage& srcImage, 260 const GrVkImage& dstImage, 261 uint32_t blitRegionCount, 262 const VkImageBlit* blitRegions, 263 VkFilter filter) { 264 this->blitImage(gpu, 265 srcImage.resource(), 266 srcImage.image(), 267 srcImage.currentLayout(), 268 dstImage.resource(), 269 dstImage.image(), 270 dstImage.currentLayout(), 271 blitRegionCount, 272 blitRegions, 273 filter); 274 } 275 276 void copyImageToBuffer(const GrVkGpu* gpu, 277 GrVkImage* srcImage, 278 VkImageLayout srcLayout, 279 GrVkTransferBuffer* dstBuffer, 280 uint32_t copyRegionCount, 281 const VkBufferImageCopy* copyRegions); 282 283 void copyBufferToImage(const GrVkGpu* gpu, 284 GrVkTransferBuffer* srcBuffer, 285 GrVkImage* dstImage, 286 VkImageLayout dstLayout, 287 uint32_t copyRegionCount, 288 const VkBufferImageCopy* copyRegions); 289 290 void updateBuffer(GrVkGpu* gpu, 291 GrVkBuffer* dstBuffer, 292 VkDeviceSize dstOffset, 293 VkDeviceSize dataSize, 294 const void* data); 295 296 void resolveImage(GrVkGpu* gpu, 297 const GrVkImage& srcImage, 298 const GrVkImage& dstImage, 299 uint32_t regionCount, 300 const VkImageResolve* regions); 301 302 void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync, 303 const GrVkSemaphore::Resource* signalSemaphore, 304 SkTArray<const GrVkSemaphore::Resource*>& waitSemaphores); 305 bool finished(const GrVkGpu* gpu) const; 306 307 #ifdef SK_TRACE_VK_RESOURCES dumpInfo()308 void dumpInfo() const override { 309 SkDebugf("GrVkPrimaryCommandBuffer: %d (%d refs)\n", fCmdBuffer, this->getRefCnt()); 310 } 311 #endif 312 313 private: GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer)314 explicit GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer) 315 : INHERITED(cmdBuffer) 316 , fSubmitFence(VK_NULL_HANDLE) {} 317 318 void onFreeGPUData(const GrVkGpu* gpu) const override; 319 320 void onReset(GrVkGpu* gpu) override; 321 322 SkTArray<GrVkSecondaryCommandBuffer*, true> fSecondaryCommandBuffers; 323 VkFence fSubmitFence; 324 325 typedef GrVkCommandBuffer INHERITED; 326 }; 327 328 class GrVkSecondaryCommandBuffer : public GrVkCommandBuffer { 329 public: 330 static GrVkSecondaryCommandBuffer* Create(const GrVkGpu* gpu, VkCommandPool cmdPool); 331 332 void begin(const GrVkGpu* gpu, const GrVkFramebuffer* framebuffer, 333 const GrVkRenderPass* compatibleRenderPass); 334 void end(const GrVkGpu* gpu); 335 336 #ifdef SK_TRACE_VK_RESOURCES dumpInfo()337 void dumpInfo() const override { 338 SkDebugf("GrVkSecondaryCommandBuffer: %d (%d refs)\n", fCmdBuffer, this->getRefCnt()); 339 } 340 #endif 341 342 private: GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer)343 explicit GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer) 344 : INHERITED(cmdBuffer) { 345 } 346 onFreeGPUData(const GrVkGpu * gpu)347 void onFreeGPUData(const GrVkGpu* gpu) const override {} 348 349 friend class GrVkPrimaryCommandBuffer; 350 351 typedef GrVkCommandBuffer INHERITED; 352 }; 353 354 #endif 355