diff --git a/src/gpu/vk/GrVkOpsRenderPass.cpp b/src/gpu/vk/GrVkOpsRenderPass.cpp index 6b2b51159a..bc01d53c24 100644 --- a/src/gpu/vk/GrVkOpsRenderPass.cpp +++ b/src/gpu/vk/GrVkOpsRenderPass.cpp @@ -181,6 +181,11 @@ void GrVkOpsRenderPass::submit() { // We don't want to actually submit the secondary command buffer if it is wrapped. if (this->wrapsSecondaryCommandBuffer()) { + // We pass the ownership of the GrVkSecondaryCommandBuffer to the special wrapped + // GrVkRenderTarget since it's lifetime matches the lifetime we need to keep the + // GrVkResources on the GrVkSecondaryCommandBuffer alive. + static_cast(fRenderTarget)->addWrappedGrSecondaryCommandBuffer( + std::move(fCurrentSecondaryCommandBuffer)); return; } diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp index 2bfa452dfa..1494bca50b 100644 --- a/src/gpu/vk/GrVkRenderTarget.cpp +++ b/src/gpu/vk/GrVkRenderTarget.cpp @@ -356,6 +356,11 @@ void GrVkRenderTarget::releaseInternalObjects() { fCachedSimpleRenderPass->unref(gpu); fCachedSimpleRenderPass = nullptr; } + for (int i = 0; i < fGrSecondaryCommandBuffers.count(); ++i) { + SkASSERT(fGrSecondaryCommandBuffers[i]); + fGrSecondaryCommandBuffers[i]->releaseResources(gpu); + } + fGrSecondaryCommandBuffers.reset(); } void GrVkRenderTarget::abandonInternalObjects() { @@ -380,6 +385,11 @@ void GrVkRenderTarget::abandonInternalObjects() { fCachedSimpleRenderPass->unrefAndAbandon(); fCachedSimpleRenderPass = nullptr; } + for (int i = 0; i < fGrSecondaryCommandBuffers.count(); ++i) { + SkASSERT(fGrSecondaryCommandBuffers[i]); + fGrSecondaryCommandBuffers[i]->abandonGPUData(); + } + fGrSecondaryCommandBuffers.reset(); } void GrVkRenderTarget::onRelease() { diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h index 99bac20908..0a4cdc339b 100644 --- a/src/gpu/vk/GrVkRenderTarget.h +++ b/src/gpu/vk/GrVkRenderTarget.h @@ -13,14 +13,13 @@ #include "src/gpu/vk/GrVkImage.h" #include "include/gpu/vk/GrVkTypes.h" +#include "src/gpu/vk/GrVkCommandBuffer.h" #include "src/gpu/vk/GrVkRenderPass.h" #include "src/gpu/vk/GrVkResourceProvider.h" -class GrVkCommandBuffer; class GrVkFramebuffer; class GrVkGpu; class GrVkImageView; -class GrVkSecondaryCommandBuffer; class GrVkStencilAttachment; struct GrVkImageInfo; @@ -91,6 +90,10 @@ public: void addResources(GrVkCommandBuffer& commandBuffer); + void addWrappedGrSecondaryCommandBuffer(std::unique_ptr cmdBuffer) { + fGrSecondaryCommandBuffers.push_back(std::move(cmdBuffer)); + } + protected: GrVkRenderTarget(GrVkGpu* gpu, const GrSurfaceDesc& desc, @@ -183,6 +186,16 @@ private: // VkCommandBuffer and not VK_NULL_HANDLE. In this case the render target will not be backed by // an actual VkImage and will thus be limited in terms of what it can be used for. VkCommandBuffer fSecondaryCommandBuffer = VK_NULL_HANDLE; + // When we wrap a secondary command buffer, we will record GrVkResources onto it which need to + // be kept alive till the command buffer gets submitted and the GPU has finished. However, in + // the wrapped case, we don't know when the command buffer gets submitted and when it is + // finished on the GPU since the client is in charge of that. However, we do require that the + // client keeps the GrVkSecondaryCBDrawContext alive and call releaseResources on it once the + // GPU is finished all the work. Thus we can use this to manage the lifetime of our + // GrVkSecondaryCommandBuffers. By storing them on the GrVkRenderTarget, which is owned by the + // SkGpuDevice on the GrVkSecondaryCBDrawContext, we assure that the GrVkResources held by the + // GrVkSecondaryCommandBuffer don't get deleted before they are allowed to. + SkTArray> fGrSecondaryCommandBuffers; }; #endif