/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrVkCommandBuffer_DEFINED #define GrVkCommandBuffer_DEFINED #include "GrVkGpu.h" #include "GrVkResource.h" #include "GrVkSemaphore.h" #include "GrVkUtil.h" #include "vk/GrVkTypes.h" class GrVkBuffer; class GrVkFramebuffer; class GrVkIndexBuffer; class GrVkImage; class GrVkPipeline; class GrVkPipelineState; class GrVkRenderPass; class GrVkRenderTarget; class GrVkTransferBuffer; class GrVkVertexBuffer; class GrVkCommandBuffer : public GrVkResource { public: void invalidateState(); //////////////////////////////////////////////////////////////////////////// // CommandBuffer commands //////////////////////////////////////////////////////////////////////////// enum BarrierType { kMemory_BarrierType, kBufferMemory_BarrierType, kImageMemory_BarrierType }; void pipelineBarrier(const GrVkGpu* gpu, const GrVkResource* resource, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, bool byRegion, BarrierType barrierType, void* barrier); void bindInputBuffer(GrVkGpu* gpu, uint32_t binding, const GrVkVertexBuffer* vbuffer); void bindIndexBuffer(GrVkGpu* gpu, const GrVkIndexBuffer* ibuffer); void bindPipeline(const GrVkGpu* gpu, const GrVkPipeline* pipeline); void bindDescriptorSets(const GrVkGpu* gpu, GrVkPipelineState*, GrVkPipelineLayout* layout, uint32_t firstSet, uint32_t setCount, const VkDescriptorSet* descriptorSets, uint32_t dynamicOffsetCount, const uint32_t* dynamicOffsets); void bindDescriptorSets(const GrVkGpu* gpu, const SkTArray<const GrVkRecycledResource*>&, const SkTArray<const GrVkResource*>&, GrVkPipelineLayout* layout, uint32_t firstSet, uint32_t setCount, const VkDescriptorSet* descriptorSets, uint32_t dynamicOffsetCount, const uint32_t* dynamicOffsets); GrVkCommandPool* commandPool() { return fCmdPool; } void setViewport(const GrVkGpu* gpu, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* viewports); void setScissor(const GrVkGpu* gpu, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* scissors); void setBlendConstants(const GrVkGpu* gpu, const float blendConstants[4]); // Commands that only work inside of a render pass void clearAttachments(const GrVkGpu* gpu, int numAttachments, const VkClearAttachment* attachments, int numRects, const VkClearRect* clearRects) const; void drawIndexed(const GrVkGpu* gpu, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) const; void draw(const GrVkGpu* gpu, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const; // Add ref-counted resource that will be tracked and released when this command buffer finishes // execution void addResource(const GrVkResource* resource) { resource->ref(); resource->notifyAddedToCommandBuffer(); fTrackedResources.append(1, &resource); } // Add ref-counted resource that will be tracked and released when this command buffer finishes // execution. When it is released, it will signal that the resource can be recycled for reuse. void addRecycledResource(const GrVkRecycledResource* resource) { resource->ref(); resource->notifyAddedToCommandBuffer(); fTrackedRecycledResources.append(1, &resource); } // Add ref-counted resource that will be tracked and released when this command buffer finishes // recording. void addRecordingResource(const GrVkResource* resource) { resource->ref(); resource->notifyAddedToCommandBuffer(); fTrackedRecordingResources.append(1, &resource); } void releaseResources(GrVkGpu* gpu); protected: GrVkCommandBuffer(VkCommandBuffer cmdBuffer, GrVkCommandPool* cmdPool, const GrVkRenderPass* rp = nullptr) : fIsActive(false) , fActiveRenderPass(rp) , fCmdBuffer(cmdBuffer) , fCmdPool(cmdPool) , fNumResets(0) { fTrackedResources.setReserve(kInitialTrackedResourcesCount); fTrackedRecycledResources.setReserve(kInitialTrackedResourcesCount); fTrackedRecordingResources.setReserve(kInitialTrackedResourcesCount); this->invalidateState(); } bool isWrapped() const { return fCmdPool == nullptr; } SkTDArray<const GrVkResource*> fTrackedResources; SkTDArray<const GrVkRecycledResource*> fTrackedRecycledResources; SkTDArray<const GrVkResource*> fTrackedRecordingResources; // Tracks whether we are in the middle of a command buffer begin/end calls and thus can add // new commands to the buffer; bool fIsActive; // Stores a pointer to the current active render pass (i.e. begin has been called but not // end). A nullptr means there is no active render pass. The GrVKCommandBuffer does not own // the render pass. const GrVkRenderPass* fActiveRenderPass; VkCommandBuffer fCmdBuffer; // Raw pointer, not refcounted. The command pool controls the command buffer's lifespan, so // it's guaranteed to outlive us. GrVkCommandPool* fCmdPool; private: static const int kInitialTrackedResourcesCount = 32; void freeGPUData(GrVkGpu* gpu) const final override; virtual void onFreeGPUData(GrVkGpu* gpu) const = 0; void abandonGPUData() const final override; virtual void onAbandonGPUData() const = 0; virtual void onReleaseResources(GrVkGpu* gpu) {} static constexpr uint32_t kMaxInputBuffers = 2; VkBuffer fBoundInputBuffers[kMaxInputBuffers]; VkBuffer fBoundIndexBuffer; // When resetting the command buffer, we remove the tracked resources from their arrays, and // we prefer to not free all the memory every time so usually we just rewind. However, to avoid // all arrays growing to the max size, after so many resets we'll do a full reset of the tracked // resource arrays. static const int kNumRewindResetsBeforeFullReset = 8; int fNumResets; // Cached values used for dynamic state updates VkViewport fCachedViewport; VkRect2D fCachedScissor; float fCachedBlendConstant[4]; #ifdef SK_DEBUG mutable bool fResourcesReleased = false; #endif }; class GrVkSecondaryCommandBuffer; class GrVkPrimaryCommandBuffer : public GrVkCommandBuffer { public: ~GrVkPrimaryCommandBuffer() override; static GrVkPrimaryCommandBuffer* Create(const GrVkGpu* gpu, GrVkCommandPool* cmdPool); void begin(const GrVkGpu* gpu); void end(GrVkGpu* gpu); // Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used // in the render pass. void beginRenderPass(const GrVkGpu* gpu, const GrVkRenderPass* renderPass, const VkClearValue clearValues[], const GrVkRenderTarget& target, const SkIRect& bounds, bool forSecondaryCB); void endRenderPass(const GrVkGpu* gpu); // Submits the SecondaryCommandBuffer into this command buffer. It is required that we are // currently inside a render pass that is compatible with the one used to create the // SecondaryCommandBuffer. void executeCommands(const GrVkGpu* gpu, GrVkSecondaryCommandBuffer* secondaryBuffer); // Commands that only work outside of a render pass void clearColorImage(const GrVkGpu* gpu, GrVkImage* image, const VkClearColorValue* color, uint32_t subRangeCount, const VkImageSubresourceRange* subRanges); void clearDepthStencilImage(const GrVkGpu* gpu, GrVkImage* image, const VkClearDepthStencilValue* color, uint32_t subRangeCount, const VkImageSubresourceRange* subRanges); void copyImage(const GrVkGpu* gpu, GrVkImage* srcImage, VkImageLayout srcLayout, GrVkImage* dstImage, VkImageLayout dstLayout, uint32_t copyRegionCount, const VkImageCopy* copyRegions); void blitImage(const GrVkGpu* gpu, const GrVkResource* srcResource, VkImage srcImage, VkImageLayout srcLayout, const GrVkResource* dstResource, VkImage dstImage, VkImageLayout dstLayout, uint32_t blitRegionCount, const VkImageBlit* blitRegions, VkFilter filter); void blitImage(const GrVkGpu* gpu, const GrVkImage& srcImage, const GrVkImage& dstImage, uint32_t blitRegionCount, const VkImageBlit* blitRegions, VkFilter filter); void copyImageToBuffer(const GrVkGpu* gpu, GrVkImage* srcImage, VkImageLayout srcLayout, GrVkTransferBuffer* dstBuffer, uint32_t copyRegionCount, const VkBufferImageCopy* copyRegions); void copyBufferToImage(const GrVkGpu* gpu, GrVkTransferBuffer* srcBuffer, GrVkImage* dstImage, VkImageLayout dstLayout, uint32_t copyRegionCount, const VkBufferImageCopy* copyRegions); void copyBuffer(GrVkGpu* gpu, GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, uint32_t regionCount, const VkBufferCopy* regions); void updateBuffer(GrVkGpu* gpu, GrVkBuffer* dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* data); void resolveImage(GrVkGpu* gpu, const GrVkImage& srcImage, const GrVkImage& dstImage, uint32_t regionCount, const VkImageResolve* regions); void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync, SkTArray<GrVkSemaphore::Resource*>& signalSemaphores, SkTArray<GrVkSemaphore::Resource*>& waitSemaphores); bool finished(const GrVkGpu* gpu); void addFinishedProc(sk_sp<GrRefCntedCallback> finishedProc); void recycleSecondaryCommandBuffers(); #ifdef SK_TRACE_VK_RESOURCES void dumpInfo() const override { SkDebugf("GrVkPrimaryCommandBuffer: %d (%d refs)\n", fCmdBuffer, this->getRefCnt()); } #endif private: explicit GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer, GrVkCommandPool* cmdPool) : INHERITED(cmdBuffer, cmdPool) , fSubmitFence(VK_NULL_HANDLE) {} void onFreeGPUData(GrVkGpu* gpu) const override; void onAbandonGPUData() const override; void onReleaseResources(GrVkGpu* gpu) override; SkTArray<GrVkSecondaryCommandBuffer*, true> fSecondaryCommandBuffers; VkFence fSubmitFence; SkTArray<sk_sp<GrRefCntedCallback>> fFinishedProcs; typedef GrVkCommandBuffer INHERITED; }; class GrVkSecondaryCommandBuffer : public GrVkCommandBuffer { public: static GrVkSecondaryCommandBuffer* Create(const GrVkGpu* gpu, GrVkCommandPool* cmdPool); // Used for wrapping an external secondary command buffer. static GrVkSecondaryCommandBuffer* Create(VkCommandBuffer externalSecondaryCB); void begin(const GrVkGpu* gpu, const GrVkFramebuffer* framebuffer, const GrVkRenderPass* compatibleRenderPass); void end(GrVkGpu* gpu); VkCommandBuffer vkCommandBuffer() { return fCmdBuffer; } #ifdef SK_TRACE_VK_RESOURCES void dumpInfo() const override { SkDebugf("GrVkSecondaryCommandBuffer: %d (%d refs)\n", fCmdBuffer, this->getRefCnt()); } #endif private: explicit GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer, GrVkCommandPool* cmdPool) : INHERITED(cmdBuffer, cmdPool) {} void onFreeGPUData(GrVkGpu* gpu) const override {} void onAbandonGPUData() const override {} friend class GrVkPrimaryCommandBuffer; typedef GrVkCommandBuffer INHERITED; }; #endif