mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-12-01 13:34:18 +01:00
rework the command buffer system
This commit is contained in:
parent
2890819118
commit
8a8037377f
@ -1,7 +1,7 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h"
|
||||
#include "HW/Latte/Renderer/Metal/LatteToMtl.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
|
||||
|
||||
LatteTextureReadbackInfoMtl::~LatteTextureReadbackInfoMtl()
|
||||
{
|
||||
|
@ -201,8 +201,6 @@ public:
|
||||
|
||||
void EndFrame()
|
||||
{
|
||||
CheckForCompletedCommandBuffers();
|
||||
|
||||
// Unlock all buffers
|
||||
for (uint32_t i = 0; i < m_buffers.size(); i++)
|
||||
{
|
||||
@ -255,7 +253,6 @@ public:
|
||||
auto result = m_executingCommandBuffers.emplace(std::make_pair(m_activeCommandBuffer, std::vector<uint32>{}));
|
||||
cemu_assert_debug(result.second);
|
||||
m_activeCommandBufferIt = result.first;
|
||||
commandBuffer->retain();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -263,41 +260,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this function should be more more lightweight and leave the checking for completion to the caller, but this works fine for now, since there is always only one instance of this class
|
||||
void CheckForCompletedCommandBuffers(/*MTL::CommandBuffer* commandBuffer, bool erase = true*/)
|
||||
void CommandBufferFinished(MTL::CommandBuffer* commandBuffer)
|
||||
{
|
||||
bool atLeastOneCompleted = false;
|
||||
for (auto it = m_executingCommandBuffers.begin(); it != m_executingCommandBuffers.end();)
|
||||
auto it = m_executingCommandBuffers.find(commandBuffer);
|
||||
for (auto bufferIndex : it->second)
|
||||
{
|
||||
if (CommandBufferCompleted(it->first))
|
||||
{
|
||||
for (auto bufferIndex : it->second)
|
||||
{
|
||||
auto& buffer = m_buffers[bufferIndex];
|
||||
buffer.m_data.m_commandBufferCount--;
|
||||
auto& buffer = m_buffers[bufferIndex];
|
||||
buffer.m_data.m_commandBufferCount--;
|
||||
|
||||
// TODO: is this neccessary?
|
||||
if (!buffer.m_data.IsLocked() && buffer.m_data.m_commandBufferCount == 0)
|
||||
FreeBuffer(bufferIndex);
|
||||
}
|
||||
|
||||
it->first->release();
|
||||
|
||||
it = m_executingCommandBuffers.erase(it);
|
||||
|
||||
atLeastOneCompleted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
// TODO: is this neccessary?
|
||||
if (!buffer.m_data.IsLocked() && buffer.m_data.m_commandBufferCount == 0)
|
||||
FreeBuffer(bufferIndex);
|
||||
}
|
||||
|
||||
if (atLeastOneCompleted)
|
||||
LatteIndices_invalidateAll();
|
||||
|
||||
//if (erase)
|
||||
// m_commandBuffersFrames.erase(commandBuffer);
|
||||
m_executingCommandBuffers.erase(it);
|
||||
}
|
||||
|
||||
MTL::Buffer* GetBuffer(uint32 bufferIndex)
|
||||
|
@ -3,13 +3,7 @@
|
||||
|
||||
bool LatteQueryObjectMtl::getResult(uint64& numSamplesPassed)
|
||||
{
|
||||
if (!m_commandBuffer)
|
||||
{
|
||||
numSamplesPassed = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!CommandBufferCompleted(m_commandBuffer))
|
||||
if (m_commandBuffer && !CommandBufferCompleted(m_commandBuffer))
|
||||
return false;
|
||||
|
||||
uint64* resultPtr = m_mtlr->GetOcclusionQueryResultsPtr();
|
||||
@ -38,7 +32,7 @@ void LatteQueryObjectMtl::end()
|
||||
m_range.end = m_mtlr->GetOcclusionQueryIndex();
|
||||
m_mtlr->EndOcclusionQuery();
|
||||
|
||||
m_commandBuffer = m_mtlr->GetCurrentCommandBuffer()->retain();
|
||||
if (m_mtlr->IsCommandBufferActive())
|
||||
m_commandBuffer = m_mtlr->GetAndRetainCurrentCommandBufferIfNotCompleted();
|
||||
if (m_commandBuffer)
|
||||
m_mtlr->RequestSoonCommit();
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "Cemu/Logging/CemuLogging.h"
|
||||
#include "Cafe/HW/Latte/Core/FetchShader.h"
|
||||
#include "Cafe/HW/Latte/Core/LatteConst.h"
|
||||
#include "HW/Latte/Renderer/Metal/MetalCommon.h"
|
||||
#include "config/CemuConfig.h"
|
||||
#include "gui/guiWrapper.h"
|
||||
|
||||
@ -398,12 +399,9 @@ void MetalRenderer::Flush(bool waitIdle)
|
||||
{
|
||||
if (m_recordedDrawcalls > 0 || waitIdle)
|
||||
CommitCommandBuffer();
|
||||
if (waitIdle)
|
||||
{
|
||||
cemu_assert_debug(m_currentCommandBuffer.m_commited);
|
||||
|
||||
m_currentCommandBuffer.m_commandBuffer->waitUntilCompleted();
|
||||
}
|
||||
if (waitIdle && m_executingCommandBuffers.size() != 0)
|
||||
m_executingCommandBuffers.back()->waitUntilCompleted();
|
||||
}
|
||||
|
||||
void MetalRenderer::NotifyLatteCommandProcessorIdle()
|
||||
@ -1397,13 +1395,12 @@ void MetalRenderer::occlusionQuery_destroy(LatteQueryObject* queryObj) {
|
||||
}
|
||||
|
||||
void MetalRenderer::occlusionQuery_flush() {
|
||||
// TODO: wait for all command buffers with occlusion queries?
|
||||
if (m_occlusionQuery.m_lastCommandBuffer)
|
||||
m_occlusionQuery.m_lastCommandBuffer->waitUntilCompleted();
|
||||
}
|
||||
|
||||
void MetalRenderer::occlusionQuery_updateState() {
|
||||
// TODO: implement
|
||||
ProcessFinishedCommandBuffers();
|
||||
}
|
||||
|
||||
void MetalRenderer::SetBuffer(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::Buffer* buffer, size_t offset, uint32 index)
|
||||
@ -1686,6 +1683,9 @@ void MetalRenderer::CommitCommandBuffer()
|
||||
|
||||
EndEncoding();
|
||||
|
||||
ProcessFinishedCommandBuffers();
|
||||
|
||||
// Commit the command buffer
|
||||
if (!m_currentCommandBuffer.m_commited)
|
||||
{
|
||||
// Handled differently, since it seems like Metal doesn't always call the completion handler
|
||||
@ -1695,12 +1695,14 @@ void MetalRenderer::CommitCommandBuffer()
|
||||
|
||||
// Signal event
|
||||
m_eventValue = (m_eventValue + 1) % EVENT_VALUE_WRAP;
|
||||
m_currentCommandBuffer.m_commandBuffer->encodeSignalEvent(m_event, m_eventValue);
|
||||
auto mtlCommandBuffer = m_currentCommandBuffer.m_commandBuffer;
|
||||
mtlCommandBuffer->encodeSignalEvent(m_event, m_eventValue);
|
||||
|
||||
m_currentCommandBuffer.m_commandBuffer->commit();
|
||||
m_currentCommandBuffer.m_commandBuffer->release();
|
||||
mtlCommandBuffer->commit();
|
||||
m_currentCommandBuffer.m_commited = true;
|
||||
|
||||
m_executingCommandBuffers.push_back(mtlCommandBuffer);
|
||||
|
||||
m_memoryManager->GetTemporaryBufferAllocator().SetActiveCommandBuffer(nullptr);
|
||||
|
||||
// Debug
|
||||
@ -1708,6 +1710,31 @@ void MetalRenderer::CommitCommandBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
void MetalRenderer::ProcessFinishedCommandBuffers()
|
||||
{
|
||||
// Check for finished command buffers
|
||||
bool atLeastOneCompleted = false;
|
||||
for (auto it = m_executingCommandBuffers.begin(); it != m_executingCommandBuffers.end();)
|
||||
{
|
||||
auto commandBuffer = *it;
|
||||
if (CommandBufferCompleted(commandBuffer))
|
||||
{
|
||||
m_memoryManager->GetTemporaryBufferAllocator().CommandBufferFinished(commandBuffer);
|
||||
commandBuffer->release();
|
||||
it = m_executingCommandBuffers.erase(it);
|
||||
atLeastOneCompleted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Invalidate indices if at least one command buffer has completed
|
||||
if (atLeastOneCompleted)
|
||||
LatteIndices_invalidateAll();
|
||||
}
|
||||
|
||||
bool MetalRenderer::AcquireDrawable(bool mainWindow)
|
||||
{
|
||||
auto& layer = GetLayer(mainWindow);
|
||||
|
@ -289,6 +289,15 @@ public:
|
||||
return m_currentCommandBuffer.m_commandBuffer;
|
||||
}
|
||||
|
||||
MTL::CommandBuffer* GetAndRetainCurrentCommandBufferIfNotCompleted()
|
||||
{
|
||||
// The command buffer has been commited and has finished execution
|
||||
if (m_currentCommandBuffer.m_commited && m_executingCommandBuffers.size() == 0)
|
||||
return nullptr;
|
||||
|
||||
return GetCurrentCommandBuffer()->retain();
|
||||
}
|
||||
|
||||
void RequestSoonCommit()
|
||||
{
|
||||
m_commitTreshold = m_recordedDrawcalls + 8;
|
||||
@ -337,6 +346,7 @@ public:
|
||||
MTL::BlitCommandEncoder* GetBlitCommandEncoder();
|
||||
void EndEncoding();
|
||||
void CommitCommandBuffer();
|
||||
void ProcessFinishedCommandBuffers();
|
||||
|
||||
bool AcquireDrawable(bool mainWindow);
|
||||
|
||||
@ -428,9 +438,13 @@ public:
|
||||
void EndOcclusionQuery()
|
||||
{
|
||||
m_occlusionQuery.m_active = false;
|
||||
|
||||
// Release the old command buffer
|
||||
if (m_occlusionQuery.m_lastCommandBuffer)
|
||||
m_occlusionQuery.m_lastCommandBuffer->release();
|
||||
m_occlusionQuery.m_lastCommandBuffer = GetCurrentCommandBuffer()->retain();
|
||||
|
||||
// Get and retain the current command buffer
|
||||
m_occlusionQuery.m_lastCommandBuffer = GetAndRetainCurrentCommandBufferIfNotCompleted();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -491,6 +505,7 @@ private:
|
||||
|
||||
// Active objects
|
||||
MetalCommandBuffer m_currentCommandBuffer{};
|
||||
std::vector<MTL::CommandBuffer*> m_executingCommandBuffers;
|
||||
MetalEncoderType m_encoderType = MetalEncoderType::None;
|
||||
MTL::CommandEncoder* m_commandEncoder = nullptr;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user