diff --git a/src/dawn/native/CommandBuffer.cpp b/src/dawn/native/CommandBuffer.cpp index fd7d73473b..ea4a620d43 100644 --- a/src/dawn/native/CommandBuffer.cpp +++ b/src/dawn/native/CommandBuffer.cpp @@ -25,6 +25,8 @@ // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include + #include "dawn/native/CommandBuffer.h" #include "dawn/native/Buffer.h" @@ -45,6 +47,7 @@ CommandBufferBase::CommandBufferBase(CommandEncoder* encoder, mCommands(encoder->AcquireCommands()), mResourceUsages(encoder->AcquireResourceUsages()), mIndirectDrawMetadata(encoder->AcquireIndirectDrawMetadata()), + mTemporaryTexturesForEarlyDestroy(encoder->AcquireTemporaryTexturesForEarlyDestroy()), mEncoderLabel(encoder->GetLabel()) { GetObjectTrackingList()->Track(this); } @@ -105,6 +108,20 @@ const ityp::vector& CommandBufferBase::GetIndir return mIndirectDrawMetadata; } +void CommandBufferBase::ExtractTemporaryTexturesForEarlyDestroy( + std::vector>* temporaryTexturesForEarlyDestroy) { + if (mTemporaryTexturesForEarlyDestroy.empty()) { + return; + } + + temporaryTexturesForEarlyDestroy->insert(temporaryTexturesForEarlyDestroy->end(), + std::make_move_iterator( + mTemporaryTexturesForEarlyDestroy.begin()), + std::make_move_iterator( + mTemporaryTexturesForEarlyDestroy.end())); + mTemporaryTexturesForEarlyDestroy.clear(); +} + CommandIterator* CommandBufferBase::GetCommandIteratorForTesting() { return &mCommands; } diff --git a/src/dawn/native/CommandBuffer.h b/src/dawn/native/CommandBuffer.h index 3f7be31940..6a1b81e0d1 100644 --- a/src/dawn/native/CommandBuffer.h +++ b/src/dawn/native/CommandBuffer.h @@ -68,6 +68,8 @@ class CommandBufferBase : public ApiObjectBase { const CommandBufferResourceUsage& GetResourceUsages() const; const ityp::vector& GetIndirectDrawMetadata(); + void ExtractTemporaryTexturesForEarlyDestroy( + std::vector>* temporaryTexturesForEarlyDestroy); CommandIterator* GetCommandIteratorForTesting(); @@ -81,6 +83,7 @@ class CommandBufferBase : public ApiObjectBase { CommandBufferResourceUsage mResourceUsages; ityp::vector mIndirectDrawMetadata; + std::vector> mTemporaryTexturesForEarlyDestroy; std::string mEncoderLabel; }; diff --git a/src/dawn/native/CommandEncoder.cpp b/src/dawn/native/CommandEncoder.cpp index 3f653c1568..525752656b 100644 --- a/src/dawn/native/CommandEncoder.cpp +++ b/src/dawn/native/CommandEncoder.cpp @@ -1278,10 +1278,18 @@ CommandIterator CommandEncoder::AcquireCommands() { return mEncodingContext.AcquireCommands(); } +std::vector> CommandEncoder::AcquireTemporaryTexturesForEarlyDestroy() { + return std::move(mTemporaryTexturesForEarlyDestroy); +} + void CommandEncoder::TrackUsedQuerySet(QuerySetBase* querySet) { mUsedQuerySets.insert(querySet); } +void CommandEncoder::TrackTemporaryTextureForEarlyDestroy(Ref texture) { + mTemporaryTexturesForEarlyDestroy.push_back(std::move(texture)); +} + ityp::vector CommandEncoder::AcquireIndirectDrawMetadata() { return mEncodingContext.AcquireIndirectDrawMetadata(); } diff --git a/src/dawn/native/CommandEncoder.h b/src/dawn/native/CommandEncoder.h index 0712e8a209..0e447a927b 100644 --- a/src/dawn/native/CommandEncoder.h +++ b/src/dawn/native/CommandEncoder.h @@ -62,8 +62,10 @@ class CommandEncoder final : public ApiObjectBase { CommandIterator AcquireCommands(); CommandBufferResourceUsage AcquireResourceUsages(); ityp::vector AcquireIndirectDrawMetadata(); + std::vector> AcquireTemporaryTexturesForEarlyDestroy(); void TrackUsedQuerySet(QuerySetBase* querySet); + void TrackTemporaryTextureForEarlyDestroy(Ref texture); // Dawn API ComputePassEncoder* APIBeginComputePass(const ComputePassDescriptor* descriptor); @@ -144,6 +146,7 @@ class CommandEncoder final : public ApiObjectBase { absl::flat_hash_set mTopLevelBuffers; absl::flat_hash_set mTopLevelTextures; absl::flat_hash_set mUsedQuerySets; + std::vector> mTemporaryTexturesForEarlyDestroy; uint64_t mDebugGroupStackSize = 0; diff --git a/src/dawn/native/RenderPassWorkaroundsHelper.cpp b/src/dawn/native/RenderPassWorkaroundsHelper.cpp index 4b4165b342..c047e04a73 100644 --- a/src/dawn/native/RenderPassWorkaroundsHelper.cpp +++ b/src/dawn/native/RenderPassWorkaroundsHelper.cpp @@ -151,6 +151,7 @@ MaybeError RenderPassWorkaroundsHelper::Initialize( DAWN_ASSERT(device->IsLockedByCurrentThreadIfNeeded()); DAWN_TRY_ASSIGN(temporaryResolveTexture, device->CreateTexture(&descriptor)); + encoder->TrackTemporaryTextureForEarlyDestroy(temporaryResolveTexture); TextureViewDescriptor viewDescriptor = {}; DAWN_TRY_ASSIGN( diff --git a/src/dawn/native/vulkan/QueueVk.cpp b/src/dawn/native/vulkan/QueueVk.cpp index 82d6d608f0..d971a840ad 100644 --- a/src/dawn/native/vulkan/QueueVk.cpp +++ b/src/dawn/native/vulkan/QueueVk.cpp @@ -103,13 +103,23 @@ MaybeError Queue::Initialize() { MaybeError Queue::SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) { TRACE_EVENT_BEGIN0(GetDevice()->GetPlatform(), Recording, "CommandBufferVk::RecordCommands"); + DAWN_ASSERT(mPendingTexturesToDestroyOnSubmit.empty()); CommandRecordingContext* recordingContext = GetPendingRecordingContext(); for (uint32_t i = 0; i < commandCount; ++i) { - DAWN_TRY(ToBackend(commands[i])->RecordCommands(recordingContext)); + MaybeError recordResult = ToBackend(commands[i])->RecordCommands(recordingContext); + if (recordResult.IsError()) { + mPendingTexturesToDestroyOnSubmit.clear(); + return recordResult; + } + commands[i]->ExtractTemporaryTexturesForEarlyDestroy(&mPendingTexturesToDestroyOnSubmit); } TRACE_EVENT_END0(GetDevice()->GetPlatform(), Recording, "CommandBufferVk::RecordCommands"); - DAWN_TRY(SubmitPendingCommandsImpl()); + MaybeError submitResult = SubmitPendingCommandsImpl(); + if (submitResult.IsError()) { + mPendingTexturesToDestroyOnSubmit.clear(); + return submitResult; + } return {}; } @@ -346,6 +356,13 @@ MaybeError Queue::SubmitPendingCommandsImpl() { }); TRACE_EVENT_END0(device->GetPlatform(), Recording, "vkQueueSubmit"); + // Destroy temporary resolve textures while the pending serial still refers to this submit. + // Otherwise command-buffer teardown schedules their Vulkan memory release on the next serial. + for (auto& texture : mPendingTexturesToDestroyOnSubmit) { + texture->Destroy(); + } + mPendingTexturesToDestroyOnSubmit.clear(); + // Enqueue the semaphores before incrementing the serial, so that they can be deleted as // soon as the current submission is finished. for (VkSemaphore semaphore : mRecordingContext.waitSemaphores) { diff --git a/src/dawn/native/vulkan/QueueVk.h b/src/dawn/native/vulkan/QueueVk.h index 96a5b64766..0966374dc3 100644 --- a/src/dawn/native/vulkan/QueueVk.h +++ b/src/dawn/native/vulkan/QueueVk.h @@ -92,6 +92,7 @@ class Queue final : public QueueBase { MutexProtected> mUnusedCommands; // There is always a valid recording context stored in mRecordingContext CommandRecordingContext mRecordingContext; + std::vector> mPendingTexturesToDestroyOnSubmit; uint32_t mQueueFamily = 0; VkQueue mQueue = VK_NULL_HANDLE;