release command buffers properly

This commit is contained in:
Samuliak 2024-09-14 08:23:45 +02:00
parent e5dcd93dc3
commit b5954d8f5b
4 changed files with 43 additions and 31 deletions

View file

@ -5,6 +5,8 @@
LatteTextureReadbackInfoMtl::~LatteTextureReadbackInfoMtl() LatteTextureReadbackInfoMtl::~LatteTextureReadbackInfoMtl()
{ {
if (m_commandBuffer)
m_commandBuffer->release();
} }
void LatteTextureReadbackInfoMtl::StartTransfer() void LatteTextureReadbackInfoMtl::StartTransfer()
@ -24,7 +26,7 @@ void LatteTextureReadbackInfoMtl::StartTransfer()
blitCommandEncoder->copyFromTexture(baseTexture->GetTexture(), 0, 0, MTL::Origin{0, 0, 0}, MTL::Size{(uint32)baseTexture->width, (uint32)baseTexture->height, 1}, m_mtlr->GetTextureReadbackBuffer(), m_bufferOffset, bytesPerRow, bytesPerImage); blitCommandEncoder->copyFromTexture(baseTexture->GetTexture(), 0, 0, MTL::Origin{0, 0, 0}, MTL::Size{(uint32)baseTexture->width, (uint32)baseTexture->height, 1}, m_mtlr->GetTextureReadbackBuffer(), m_bufferOffset, bytesPerRow, bytesPerImage);
m_commandBuffer = m_mtlr->GetCurrentCommandBuffer(); m_commandBuffer = m_mtlr->GetCurrentCommandBuffer()->retain();
m_mtlr->RequestSoonCommit(); m_mtlr->RequestSoonCommit();
} }

View file

@ -3,6 +3,7 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#include "Common/precompiled.h" #include "Common/precompiled.h"
#include "Metal/MTLResource.hpp" #include "Metal/MTLResource.hpp"
#include <utility>
struct MetalBufferRange struct MetalBufferRange
{ {
@ -162,7 +163,8 @@ typedef MetalBufferAllocator<Empty> MetalDefaultBufferAllocator;
struct MetalSyncedBuffer struct MetalSyncedBuffer
{ {
std::vector<MTL::CommandBuffer*> m_commandBuffers; uint32 m_commandBufferCount = 0;
MTL::CommandBuffer* m_lastCommandBuffer = nullptr;
uint32 m_lock = 0; uint32 m_lock = 0;
bool IsLocked() const bool IsLocked() const
@ -191,7 +193,7 @@ public:
// TODO: is this really necessary? // TODO: is this really necessary?
// Release the buffer if it wasn't released due to the lock // Release the buffer if it wasn't released due to the lock
if (!buffer.m_data.IsLocked() && buffer.m_data.m_commandBuffers.empty()) if (!buffer.m_data.IsLocked() && buffer.m_data.m_commandBufferCount == 0)
FreeBuffer(bufferIndex); FreeBuffer(bufferIndex);
} }
@ -206,7 +208,7 @@ public:
if (buffer.m_data.m_lock != 0) if (buffer.m_data.m_lock != 0)
{ {
if (buffer.m_data.m_commandBuffers.empty()) if (buffer.m_data.m_commandBufferCount == 0)
FreeBuffer(i); FreeBuffer(i);
buffer.m_data.m_lock = 0; buffer.m_data.m_lock = 0;
@ -218,7 +220,7 @@ public:
if (!m_buffers.empty()) if (!m_buffers.empty())
{ {
auto& backBuffer = m_buffers.back(); auto& backBuffer = m_buffers.back();
if (backBuffer.m_data.m_commandBuffers.empty()) if (backBuffer.m_data.m_commandBufferCount == 0)
{ {
// Release the back buffer if it hasn't been accessed for a while // Release the back buffer if it hasn't been accessed for a while
if (m_framesSinceBackBufferAccess >= BUFFER_RELEASE_FRAME_TRESHOLD) if (m_framesSinceBackBufferAccess >= BUFFER_RELEASE_FRAME_TRESHOLD)
@ -246,34 +248,34 @@ public:
void SetActiveCommandBuffer(MTL::CommandBuffer* commandBuffer) void SetActiveCommandBuffer(MTL::CommandBuffer* commandBuffer)
{ {
m_activeCommandBuffer = commandBuffer; m_activeCommandBuffer = commandBuffer;
auto result = m_executingCommandBuffers.emplace(std::make_pair(m_activeCommandBuffer, std::vector<uint32>{}));
cemu_assert_debug(result.second);
m_activeCommandBufferIt = result.first;
commandBuffer->retain();
} }
void CheckForCompletedCommandBuffers(/*MTL::CommandBuffer* commandBuffer, bool erase = true*/) void CheckForCompletedCommandBuffers(/*MTL::CommandBuffer* commandBuffer, bool erase = true*/)
{ {
for (uint32_t i = 0; i < m_buffers.size(); i++) for (auto it = m_executingCommandBuffers.begin(); it != m_executingCommandBuffers.end();)
{ {
auto& buffer = m_buffers[i]; if (CommandBufferCompleted(it->first))
for (uint32_t j = 0; j < buffer.m_data.m_commandBuffers.size(); j++)
{ {
if (CommandBufferCompleted(buffer.m_data.m_commandBuffers[j])) for (auto bufferIndex : it->second)
{ {
if (buffer.m_data.m_commandBuffers.size() == 1) auto& buffer = m_buffers[bufferIndex];
{ buffer.m_data.m_commandBufferCount--;
if (!buffer.m_data.IsLocked())
{ if (!buffer.m_data.IsLocked() && buffer.m_data.m_commandBufferCount == 0)
// All command buffers using it have finished execution, we can use it again FreeBuffer(bufferIndex);
FreeBuffer(i);
} }
buffer.m_data.m_commandBuffers.clear(); it->first->release();
break;
it = m_executingCommandBuffers.erase(it);
} }
else else
{ {
buffer.m_data.m_commandBuffers.erase(buffer.m_data.m_commandBuffers.begin() + j); ++it;
j--;
}
}
} }
} }
@ -286,8 +288,12 @@ public:
cemu_assert_debug(m_activeCommandBuffer); cemu_assert_debug(m_activeCommandBuffer);
auto& buffer = m_buffers[bufferIndex]; auto& buffer = m_buffers[bufferIndex];
if (buffer.m_data.m_commandBuffers.empty() || buffer.m_data.m_commandBuffers.back() != m_activeCommandBuffer/*std::find(buffer.m_commandBuffers.begin(), buffer.m_commandBuffers.end(), m_activeCommandBuffer) == buffer.m_commandBuffers.end()*/) if (buffer.m_data.m_commandBufferCount == 0 || buffer.m_data.m_lastCommandBuffer != m_activeCommandBuffer)
buffer.m_data.m_commandBuffers.push_back(m_activeCommandBuffer); {
m_activeCommandBufferIt->second.push_back(bufferIndex);
buffer.m_data.m_commandBufferCount++;
buffer.m_data.m_lastCommandBuffer = m_activeCommandBuffer;
}
return buffer.m_buffer; return buffer.m_buffer;
} }
@ -348,5 +354,8 @@ public:
private: private:
MTL::CommandBuffer* m_activeCommandBuffer = nullptr; MTL::CommandBuffer* m_activeCommandBuffer = nullptr;
std::map<MTL::CommandBuffer*, std::vector<uint32>> m_executingCommandBuffers;
std::map<MTL::CommandBuffer*, std::vector<uint32>>::iterator m_activeCommandBufferIt;
uint16 m_framesSinceBackBufferAccess = 0; uint16 m_framesSinceBackBufferAccess = 0;
}; };

View file

@ -22,6 +22,9 @@ LatteQueryObjectMtl::~LatteQueryObjectMtl()
{ {
if (m_queryIndex != INVALID_UINT32) if (m_queryIndex != INVALID_UINT32)
m_mtlr->ReleaseOcclusionQueryIndex(m_queryIndex); m_mtlr->ReleaseOcclusionQueryIndex(m_queryIndex);
if (m_commandBuffer)
m_commandBuffer->release();
} }
void LatteQueryObjectMtl::begin() void LatteQueryObjectMtl::begin()
@ -35,7 +38,7 @@ void LatteQueryObjectMtl::end()
m_mtlr->SetActiveOcclusionQueryIndex(INVALID_UINT32); m_mtlr->SetActiveOcclusionQueryIndex(INVALID_UINT32);
if (m_mtlr->IsCommandBufferActive()) if (m_mtlr->IsCommandBufferActive())
{ {
m_commandBuffer = m_mtlr->GetCurrentCommandBuffer(); m_commandBuffer = m_mtlr->GetCurrentCommandBuffer()->retain();
m_mtlr->RequestSoonCommit(); m_mtlr->RequestSoonCommit();
} }
} }

View file

@ -267,11 +267,8 @@ void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC)
if (swapDRC) if (swapDRC)
SwapBuffer(false); SwapBuffer(false);
// Release all the command buffers // Reset the command buffers (they are released in)
CommitCommandBuffer(); CommitCommandBuffer();
// TODO: release
//for (uint32 i = 0; i < m_commandBuffers.size(); i++)
// m_commandBuffers[i].m_commandBuffer->release();
m_commandBuffers.clear(); m_commandBuffers.clear();
// Release frame persistent buffers // Release frame persistent buffers
@ -1581,6 +1578,7 @@ void MetalRenderer::CommitCommandBuffer()
//}); //});
commandBuffer.m_commandBuffer->commit(); commandBuffer.m_commandBuffer->commit();
commandBuffer.m_commandBuffer->release();
commandBuffer.m_commited = true; commandBuffer.m_commited = true;
m_memoryManager->GetTemporaryBufferAllocator().SetActiveCommandBuffer(nullptr); m_memoryManager->GetTemporaryBufferAllocator().SetActiveCommandBuffer(nullptr);