/* * 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 "include/gpu/vk/GrVkTypes.h" #include "src/gpu/GrManagedResource.h" #include "src/gpu/GrRefCnt.h" #include "src/gpu/vk/GrVkGpu.h" #include "src/gpu/vk/GrVkSemaphore.h" #include "src/gpu/vk/GrVkUtil.h" class GrVkFramebuffer; class GrVkImage; class GrVkPipeline; class GrVkPipelineState; class GrVkRenderPass; class GrVkRenderTarget; class GrVkCommandBuffer { public: virtual ~GrVkCommandBuffer() {} void invalidateState(); //////////////////////////////////////////////////////////////////////////// // CommandBuffer commands //////////////////////////////////////////////////////////////////////////// enum BarrierType { kBufferMemory_BarrierType, kImageMemory_BarrierType }; void pipelineBarrier(const GrVkGpu* gpu, const GrManagedResource* resource, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, bool byRegion, BarrierType barrierType, void* barrier); void bindInputBuffer(GrVkGpu* gpu, uint32_t binding, sk_sp buffer); void bindIndexBuffer(GrVkGpu* gpu, sk_sp buffer); void bindPipeline(const GrVkGpu* gpu, sk_sp pipeline); void bindDescriptorSets(const GrVkGpu* gpu, VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount, const VkDescriptorSet* descriptorSets, uint32_t dynamicOffsetCount, const uint32_t* dynamicOffsets); void pushConstants(const GrVkGpu* gpu, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* values); 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); void drawIndexed(const GrVkGpu* gpu, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); void draw(const GrVkGpu* gpu, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); void drawIndirect(const GrVkGpu* gpu, sk_sp indirectBuffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); void drawIndexedIndirect(const GrVkGpu* gpu, sk_sp indirectBuffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); // Add ref-counted resource that will be tracked and released when this command buffer finishes // execution void addResource(sk_sp resource) { SkASSERT(resource); resource->notifyQueuedForWorkOnGpu(); fTrackedResources.push_back(std::move(resource)); } void addResource(const GrManagedResource* resource) { this->addResource(sk_ref_sp(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(gr_rp resource) { SkASSERT(resource); resource->notifyQueuedForWorkOnGpu(); fTrackedRecycledResources.push_back(std::move(resource)); } void addRecycledResource(const GrRecycledResource* resource) { this->addRecycledResource(gr_ref_rp(resource)); } void addGrBuffer(sk_sp buffer) { fTrackedGpuBuffers.push_back(std::move(buffer)); } void addGrSurface(sk_sp surface) { fTrackedGpuSurfaces.push_back(std::move(surface)); } void releaseResources(); void freeGPUData(const GrGpu* gpu, VkCommandPool pool) const; bool hasWork() const { return fHasWork; } protected: GrVkCommandBuffer(VkCommandBuffer cmdBuffer, bool isWrapped = false) : fIsActive(isWrapped) // All wrapped command buffers start as active , fCmdBuffer(cmdBuffer) , fIsWrapped(isWrapped) { this->invalidateState(); } bool isWrapped() const { return fIsWrapped; } void addingWork(const GrVkGpu* gpu); void submitPipelineBarriers(const GrVkGpu* gpu, bool forSelfDependency = false); private: static constexpr int kInitialTrackedResourcesCount = 32; protected: template using TrackedResourceArray = SkSTArray; TrackedResourceArray> fTrackedResources; TrackedResourceArray> fTrackedRecycledResources; SkSTArray<16, sk_sp> fTrackedGpuBuffers; SkSTArray<16, gr_cb> fTrackedGpuSurfaces; // 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; bool fHasWork = false; // 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 = nullptr; VkCommandBuffer fCmdBuffer; virtual void onReleaseResources() {} virtual void onFreeGPUData(const GrVkGpu* gpu) const = 0; static constexpr uint32_t kMaxInputBuffers = 2; VkBuffer fBoundInputBuffers[kMaxInputBuffers]; VkBuffer fBoundIndexBuffer; // Cached values used for dynamic state updates VkViewport fCachedViewport; VkRect2D fCachedScissor; float fCachedBlendConstant[4]; // Tracking of memory barriers so that we can submit them all in a batch together. SkSTArray<1, VkBufferMemoryBarrier> fBufferBarriers; SkSTArray<2, VkImageMemoryBarrier> fImageBarriers; bool fBarriersByRegion = false; VkPipelineStageFlags fSrcStageMask = 0; VkPipelineStageFlags fDstStageMask = 0; bool fIsWrapped; }; class GrVkSecondaryCommandBuffer; class GrVkPrimaryCommandBuffer : public GrVkCommandBuffer { public: ~GrVkPrimaryCommandBuffer() override; static GrVkPrimaryCommandBuffer* Create(GrVkGpu* gpu, VkCommandPool cmdPool); void begin(GrVkGpu* gpu); void end(GrVkGpu* gpu, bool abandoningBuffer = false); // Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used // in the render pass. bool beginRenderPass(GrVkGpu* gpu, const GrVkRenderPass*, sk_sp, const VkClearValue clearValues[], const GrSurface* target, const SkIRect& bounds, bool forSecondaryCB); void endRenderPass(const GrVkGpu* gpu); void nexSubpass(GrVkGpu* gpu, bool forSecondaryCB); // 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, std::unique_ptr 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 GrManagedResource* srcResource, VkImage srcImage, VkImageLayout srcLayout, const GrManagedResource* 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, sk_sp dstBuffer, uint32_t copyRegionCount, const VkBufferImageCopy* copyRegions); // All uses of copyBufferToImage are done with buffers from our staging manager. The staging // manager will handle making sure the command buffer refs the buffer. Thus we just pass in the // raw VkBuffer here and don't worry about refs. void copyBufferToImage(const GrVkGpu* gpu, VkBuffer srcBuffer, GrVkImage* dstImage, VkImageLayout dstLayout, uint32_t copyRegionCount, const VkBufferImageCopy* copyRegions); void copyBuffer(GrVkGpu* gpu, sk_sp srcBuffer, sk_sp dstBuffer, uint32_t regionCount, const VkBufferCopy* regions); void updateBuffer(GrVkGpu* gpu, sk_sp dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* data); void resolveImage(GrVkGpu* gpu, const GrVkImage& srcImage, const GrVkImage& dstImage, uint32_t regionCount, const VkImageResolve* regions); bool submitToQueue(GrVkGpu* gpu, VkQueue queue, SkTArray& signalSemaphores, SkTArray& waitSemaphores); void forceSync(GrVkGpu* gpu); bool finished(GrVkGpu* gpu); void addFinishedProc(sk_sp finishedProc); void callFinishedProcs() { fFinishedProcs.reset(); } void recycleSecondaryCommandBuffers(GrVkCommandPool* cmdPool); private: explicit GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer) : INHERITED(cmdBuffer) , fSubmitFence(VK_NULL_HANDLE) {} void onFreeGPUData(const GrVkGpu* gpu) const override; void onReleaseResources() override; SkTArray, true> fSecondaryCommandBuffers; VkFence fSubmitFence; SkTArray> fFinishedProcs; using INHERITED = GrVkCommandBuffer; }; class GrVkSecondaryCommandBuffer : public GrVkCommandBuffer { public: static GrVkSecondaryCommandBuffer* Create(GrVkGpu* gpu, GrVkCommandPool* cmdPool); // Used for wrapping an external secondary command buffer. static GrVkSecondaryCommandBuffer* Create(VkCommandBuffer externalSecondaryCB, const GrVkRenderPass* externalRenderPass); void begin(GrVkGpu* gpu, const GrVkFramebuffer* framebuffer, const GrVkRenderPass* compatibleRenderPass); void end(GrVkGpu* gpu); void recycle(GrVkCommandPool* cmdPool); VkCommandBuffer vkCommandBuffer() { return fCmdBuffer; } private: explicit GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer, const GrVkRenderPass* externalRenderPass) : INHERITED(cmdBuffer, SkToBool(externalRenderPass)) { fActiveRenderPass = externalRenderPass; } void onFreeGPUData(const GrVkGpu* gpu) const override {} // Used for accessing fIsActive (on GrVkCommandBuffer) friend class GrVkPrimaryCommandBuffer; using INHERITED = GrVkCommandBuffer; }; #endif