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 "include/core/SkRefCnt.h" 12 #include "include/private/base/SkAssert.h" 13 #include "include/private/base/SkTArray.h" 14 #include "include/private/base/SkTo.h" 15 #include "include/private/gpu/vk/SkiaVulkan.h" 16 #include "src/gpu/GpuRefCnt.h" 17 #include "src/gpu/RefCntedCallback.h" 18 #include "src/gpu/ganesh/GrBuffer.h" 19 #include "src/gpu/ganesh/GrManagedResource.h" 20 #include "src/gpu/ganesh/GrSurface.h" 21 #include "src/gpu/ganesh/vk/GrVkSemaphore.h" 22 23 #include <cstdint> 24 #include <memory> 25 #include <utility> 26 27 class GrGpu; 28 class GrGpuBuffer; 29 class GrVkBuffer; 30 class GrVkCommandPool; 31 class GrVkFramebuffer; 32 class GrVkGpu; 33 class GrVkImage; 34 class GrVkPipeline; 35 class GrVkRenderPass; 36 struct GrSubmitInfo; 37 struct SkIRect; 38 39 class GrVkCommandBuffer { 40 public: ~GrVkCommandBuffer()41 virtual ~GrVkCommandBuffer() {} 42 43 void invalidateState(); 44 45 //////////////////////////////////////////////////////////////////////////// 46 // CommandBuffer commands 47 //////////////////////////////////////////////////////////////////////////// 48 enum BarrierType { 49 kBufferMemory_BarrierType, 50 kImageMemory_BarrierType 51 }; 52 53 void pipelineBarrier(const GrVkGpu* gpu, 54 const GrManagedResource* resource, 55 VkPipelineStageFlags srcStageMask, 56 VkPipelineStageFlags dstStageMask, 57 bool byRegion, 58 BarrierType barrierType, 59 void* barrier); 60 61 void bindInputBuffer(GrVkGpu* gpu, uint32_t binding, sk_sp<const GrBuffer> buffer); 62 63 void bindIndexBuffer(GrVkGpu* gpu, sk_sp<const GrBuffer> buffer); 64 65 void bindPipeline(const GrVkGpu* gpu, sk_sp<const GrVkPipeline> pipeline); 66 67 void bindDescriptorSets(const GrVkGpu* gpu, 68 VkPipelineLayout layout, 69 uint32_t firstSet, 70 uint32_t setCount, 71 const VkDescriptorSet* descriptorSets, 72 uint32_t dynamicOffsetCount, 73 const uint32_t* dynamicOffsets); 74 75 void pushConstants(const GrVkGpu* gpu, VkPipelineLayout layout, 76 VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, 77 const void* values); 78 79 void setViewport(const GrVkGpu* gpu, 80 uint32_t firstViewport, 81 uint32_t viewportCount, 82 const VkViewport* viewports); 83 84 void setScissor(const GrVkGpu* gpu, 85 uint32_t firstScissor, 86 uint32_t scissorCount, 87 const VkRect2D* scissors); 88 89 void setBlendConstants(const GrVkGpu* gpu, const float blendConstants[4]); 90 91 // Commands that only work inside of a render pass 92 void clearAttachments(const GrVkGpu* gpu, 93 int numAttachments, 94 const VkClearAttachment* attachments, 95 int numRects, 96 const VkClearRect* clearRects); 97 98 void drawIndexed(const GrVkGpu* gpu, 99 uint32_t indexCount, 100 uint32_t instanceCount, 101 uint32_t firstIndex, 102 int32_t vertexOffset, 103 uint32_t firstInstance); 104 105 void draw(const GrVkGpu* gpu, 106 uint32_t vertexCount, 107 uint32_t instanceCount, 108 uint32_t firstVertex, 109 uint32_t firstInstance); 110 111 void drawIndirect(const GrVkGpu* gpu, 112 sk_sp<const GrBuffer> indirectBuffer, 113 VkDeviceSize offset, 114 uint32_t drawCount, 115 uint32_t stride); 116 117 void drawIndexedIndirect(const GrVkGpu* gpu, 118 sk_sp<const GrBuffer> indirectBuffer, 119 VkDeviceSize offset, 120 uint32_t drawCount, 121 uint32_t stride); 122 123 // Add ref-counted resource that will be tracked and released when this command buffer finishes 124 // execution addResource(sk_sp<const GrManagedResource> resource)125 void addResource(sk_sp<const GrManagedResource> resource) { 126 SkASSERT(resource); 127 fTrackedResources.push_back(std::move(resource)); 128 } addResource(const GrManagedResource * resource)129 void addResource(const GrManagedResource* resource) { 130 this->addResource(sk_ref_sp(resource)); 131 } 132 133 // Add ref-counted resource that will be tracked and released when this command buffer finishes 134 // execution. When it is released, it will signal that the resource can be recycled for reuse. addRecycledResource(gr_rp<const GrRecycledResource> resource)135 void addRecycledResource(gr_rp<const GrRecycledResource> resource) { 136 SkASSERT(resource); 137 fTrackedRecycledResources.push_back(std::move(resource)); 138 } 139 addRecycledResource(const GrRecycledResource * resource)140 void addRecycledResource(const GrRecycledResource* resource) { 141 this->addRecycledResource(gr_ref_rp<const GrRecycledResource>(resource)); 142 } 143 addGrBuffer(sk_sp<const GrBuffer> buffer)144 void addGrBuffer(sk_sp<const GrBuffer> buffer) { 145 fTrackedGpuBuffers.push_back(std::move(buffer)); 146 } 147 addGrSurface(sk_sp<const GrSurface> surface)148 void addGrSurface(sk_sp<const GrSurface> surface) { 149 fTrackedGpuSurfaces.push_back(std::move(surface)); 150 } 151 152 void releaseResources(); 153 154 void freeGPUData(const GrGpu* gpu, VkCommandPool pool) const; 155 hasWork()156 bool hasWork() const { return fHasWork; } 157 158 protected: 159 GrVkCommandBuffer(VkCommandBuffer cmdBuffer, bool isWrapped = false) fIsActive(isWrapped)160 : fIsActive(isWrapped) // All wrapped command buffers start as active 161 , fCmdBuffer(cmdBuffer) 162 , fIsWrapped(isWrapped) { 163 this->invalidateState(); 164 } 165 isWrapped()166 bool isWrapped() const { return fIsWrapped; } 167 168 void addingWork(const GrVkGpu* gpu); 169 170 void submitPipelineBarriers(const GrVkGpu* gpu, bool forSelfDependency = false); 171 172 private: 173 static constexpr int kInitialTrackedResourcesCount = 32; 174 175 protected: 176 template <typename T> 177 using TrackedResourceArray = skia_private::STArray<kInitialTrackedResourcesCount, T>; 178 TrackedResourceArray<sk_sp<const GrManagedResource>> fTrackedResources; 179 TrackedResourceArray<gr_rp<const GrRecycledResource>> fTrackedRecycledResources; 180 skia_private::STArray<16, sk_sp<const GrBuffer>> fTrackedGpuBuffers; 181 skia_private::STArray<16, gr_cb<const GrSurface>> fTrackedGpuSurfaces; 182 183 // Tracks whether we are in the middle of a command buffer begin/end calls and thus can add 184 // new commands to the buffer; 185 bool fIsActive; 186 bool fHasWork = false; 187 188 // Stores a pointer to the current active render pass (i.e. begin has been called but not 189 // end). A nullptr means there is no active render pass. The GrVKCommandBuffer does not own 190 // the render pass. 191 const GrVkRenderPass* fActiveRenderPass = nullptr; 192 193 VkCommandBuffer fCmdBuffer; 194 onReleaseResources()195 virtual void onReleaseResources() {} 196 virtual void onFreeGPUData(const GrVkGpu* gpu) const = 0; 197 198 static constexpr uint32_t kMaxInputBuffers = 2; 199 200 VkBuffer fBoundInputBuffers[kMaxInputBuffers]; 201 VkBuffer fBoundIndexBuffer; 202 203 // Cached values used for dynamic state updates 204 VkViewport fCachedViewport; 205 VkRect2D fCachedScissor; 206 float fCachedBlendConstant[4]; 207 208 // Tracking of memory barriers so that we can submit them all in a batch together. 209 skia_private::STArray<1, VkBufferMemoryBarrier> fBufferBarriers; 210 skia_private::STArray<2, VkImageMemoryBarrier> fImageBarriers; 211 bool fBarriersByRegion = false; 212 VkPipelineStageFlags fSrcStageMask = 0; 213 VkPipelineStageFlags fDstStageMask = 0; 214 215 bool fIsWrapped; 216 }; 217 218 class GrVkSecondaryCommandBuffer; 219 220 class GrVkPrimaryCommandBuffer : public GrVkCommandBuffer { 221 public: 222 ~GrVkPrimaryCommandBuffer() override; 223 224 static GrVkPrimaryCommandBuffer* Create(GrVkGpu* gpu, VkCommandPool cmdPool); 225 226 void begin(GrVkGpu* gpu); 227 void end(GrVkGpu* gpu, bool abandoningBuffer = false); 228 229 // Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used 230 // in the render pass. 231 bool beginRenderPass(GrVkGpu* gpu, 232 const GrVkRenderPass*, 233 sk_sp<const GrVkFramebuffer>, 234 const VkClearValue clearValues[], 235 const GrSurface* target, 236 const SkIRect& bounds, 237 bool forSecondaryCB); 238 void endRenderPass(const GrVkGpu* gpu); 239 240 void nexSubpass(GrVkGpu* gpu, bool forSecondaryCB); 241 242 // Submits the SecondaryCommandBuffer into this command buffer. It is required that we are 243 // currently inside a render pass that is compatible with the one used to create the 244 // SecondaryCommandBuffer. 245 void executeCommands(const GrVkGpu* gpu, 246 std::unique_ptr<GrVkSecondaryCommandBuffer> secondaryBuffer); 247 248 // Commands that only work outside of a render pass 249 void clearColorImage(const GrVkGpu* gpu, 250 GrVkImage* image, 251 const VkClearColorValue* color, 252 uint32_t subRangeCount, 253 const VkImageSubresourceRange* subRanges); 254 255 void clearDepthStencilImage(const GrVkGpu* gpu, 256 GrVkImage* image, 257 const VkClearDepthStencilValue* color, 258 uint32_t subRangeCount, 259 const VkImageSubresourceRange* subRanges); 260 261 void copyImage(const GrVkGpu* gpu, 262 GrVkImage* srcImage, 263 VkImageLayout srcLayout, 264 GrVkImage* dstImage, 265 VkImageLayout dstLayout, 266 uint32_t copyRegionCount, 267 const VkImageCopy* copyRegions); 268 269 void blitImage(const GrVkGpu* gpu, 270 const GrManagedResource* srcResource, 271 VkImage srcImage, 272 VkImageLayout srcLayout, 273 const GrManagedResource* dstResource, 274 VkImage dstImage, 275 VkImageLayout dstLayout, 276 uint32_t blitRegionCount, 277 const VkImageBlit* blitRegions, 278 VkFilter filter); 279 280 void blitImage(const GrVkGpu* gpu, 281 const GrVkImage& srcImage, 282 const GrVkImage& dstImage, 283 uint32_t blitRegionCount, 284 const VkImageBlit* blitRegions, 285 VkFilter filter); 286 287 void copyImageToBuffer(const GrVkGpu* gpu, 288 GrVkImage* srcImage, 289 VkImageLayout srcLayout, 290 sk_sp<GrGpuBuffer> dstBuffer, 291 uint32_t copyRegionCount, 292 const VkBufferImageCopy* copyRegions); 293 294 // All uses of copyBufferToImage are done with buffers from our staging manager. The staging 295 // manager will handle making sure the command buffer refs the buffer. Thus we just pass in the 296 // raw VkBuffer here and don't worry about refs. 297 void copyBufferToImage(const GrVkGpu* gpu, 298 VkBuffer srcBuffer, 299 GrVkImage* dstImage, 300 VkImageLayout dstLayout, 301 uint32_t copyRegionCount, 302 const VkBufferImageCopy* copyRegions); 303 304 void fillBuffer(GrVkGpu* gpu, 305 sk_sp<GrGpuBuffer>, 306 VkDeviceSize offset, 307 VkDeviceSize size, 308 uint32_t data); 309 310 void copyBuffer(GrVkGpu* gpu, 311 sk_sp<GrGpuBuffer> srcBuffer, 312 sk_sp<GrGpuBuffer> dstBuffer, 313 uint32_t regionCount, 314 const VkBufferCopy* regions); 315 316 void updateBuffer(GrVkGpu* gpu, 317 sk_sp<GrVkBuffer> dstBuffer, 318 VkDeviceSize dstOffset, 319 VkDeviceSize dataSize, 320 const void* data); 321 322 void resolveImage(GrVkGpu* gpu, 323 const GrVkImage& srcImage, 324 const GrVkImage& dstImage, 325 uint32_t regionCount, 326 const VkImageResolve* regions); 327 328 bool submitToQueue(GrVkGpu* gpu, 329 VkQueue queue, 330 skia_private::TArray<GrVkSemaphore::Resource*>& signalSemaphores, 331 skia_private::TArray<GrVkSemaphore::Resource*>& waitSemaphores, 332 const GrSubmitInfo&); 333 334 void forceSync(GrVkGpu* gpu); 335 336 bool finished(GrVkGpu* gpu); 337 338 void addFinishedProc(sk_sp<skgpu::RefCntedCallback> finishedProc); 339 callFinishedProcs()340 void callFinishedProcs() { 341 fFinishedProcs.clear(); 342 } 343 344 void recycleSecondaryCommandBuffers(GrVkCommandPool* cmdPool); 345 346 private: GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer)347 explicit GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer) 348 : INHERITED(cmdBuffer) 349 , fSubmitFence(VK_NULL_HANDLE) {} 350 351 void onFreeGPUData(const GrVkGpu* gpu) const override; 352 353 void onReleaseResources() override; 354 355 skia_private::TArray<std::unique_ptr<GrVkSecondaryCommandBuffer>, true> fSecondaryCommandBuffers; 356 VkFence fSubmitFence; 357 skia_private::TArray<sk_sp<skgpu::RefCntedCallback>> fFinishedProcs; 358 359 using INHERITED = GrVkCommandBuffer; 360 }; 361 362 class GrVkSecondaryCommandBuffer : public GrVkCommandBuffer { 363 public: 364 static GrVkSecondaryCommandBuffer* Create(GrVkGpu* gpu, GrVkCommandPool* cmdPool); 365 // Used for wrapping an external secondary command buffer. 366 static GrVkSecondaryCommandBuffer* Create(VkCommandBuffer externalSecondaryCB, 367 const GrVkRenderPass* externalRenderPass); 368 369 void begin(GrVkGpu* gpu, const GrVkFramebuffer* framebuffer, 370 const GrVkRenderPass* compatibleRenderPass); 371 void end(GrVkGpu* gpu); 372 373 void recycle(GrVkCommandPool* cmdPool); 374 vkCommandBuffer()375 VkCommandBuffer vkCommandBuffer() { return fCmdBuffer; } 376 377 private: GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer,const GrVkRenderPass * externalRenderPass)378 explicit GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer, 379 const GrVkRenderPass* externalRenderPass) 380 : INHERITED(cmdBuffer, SkToBool(externalRenderPass)) { 381 fActiveRenderPass = externalRenderPass; 382 } 383 onFreeGPUData(const GrVkGpu * gpu)384 void onFreeGPUData(const GrVkGpu* gpu) const override {} 385 386 // Used for accessing fIsActive (on GrVkCommandBuffer) 387 friend class GrVkPrimaryCommandBuffer; 388 389 using INHERITED = GrVkCommandBuffer; 390 }; 391 392 #endif 393