mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-12-01 21:44:17 +01:00
use multiple command buffers per frame
This commit is contained in:
parent
34d8076ab6
commit
0c73ff8452
@ -23,18 +23,22 @@ void LatteTextureReadbackInfoMtl::StartTransfer()
|
|||||||
auto blitCommandEncoder = m_mtlr->GetBlitCommandEncoder();
|
auto blitCommandEncoder = m_mtlr->GetBlitCommandEncoder();
|
||||||
|
|
||||||
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();
|
||||||
|
// TODO: uncomment
|
||||||
|
//m_mtlr->RequestSoonCommit();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LatteTextureReadbackInfoMtl::IsFinished()
|
bool LatteTextureReadbackInfoMtl::IsFinished()
|
||||||
{
|
{
|
||||||
// TODO: implement
|
// HACK: just return true for now, otherwise the game would freeze
|
||||||
|
//return m_mtlr->CommandBufferCompleted(m_commandBuffer);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LatteTextureReadbackInfoMtl::ForceFinish()
|
void LatteTextureReadbackInfoMtl::ForceFinish()
|
||||||
{
|
{
|
||||||
// TODO: implement
|
m_mtlr->WaitForCommandBufferCompletion(m_commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8* LatteTextureReadbackInfoMtl::GetData()
|
uint8* LatteTextureReadbackInfoMtl::GetData()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
|
||||||
#include "Cafe/HW/Latte/Core/LatteTextureReadbackInfo.h"
|
#include "Cafe/HW/Latte/Core/LatteTextureReadbackInfo.h"
|
||||||
|
|
||||||
class LatteTextureReadbackInfoMtl : public LatteTextureReadbackInfo
|
class LatteTextureReadbackInfoMtl : public LatteTextureReadbackInfo
|
||||||
@ -18,5 +19,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
class MetalRenderer* m_mtlr;
|
class MetalRenderer* m_mtlr;
|
||||||
|
|
||||||
|
MTL::CommandBuffer* m_commandBuffer = nullptr;
|
||||||
|
|
||||||
uint32 m_bufferOffset = 0;
|
uint32 m_bufferOffset = 0;
|
||||||
};
|
};
|
||||||
|
@ -15,9 +15,12 @@
|
|||||||
#include "Cafe/HW/Latte/Core/LatteShader.h"
|
#include "Cafe/HW/Latte/Core/LatteShader.h"
|
||||||
#include "Cafe/HW/Latte/Core/LatteIndices.h"
|
#include "Cafe/HW/Latte/Core/LatteIndices.h"
|
||||||
#include "Cemu/Logging/CemuDebugLogging.h"
|
#include "Cemu/Logging/CemuDebugLogging.h"
|
||||||
|
#include "Common/precompiled.h"
|
||||||
#include "Metal/MTLPixelFormat.hpp"
|
#include "Metal/MTLPixelFormat.hpp"
|
||||||
#include "gui/guiWrapper.h"
|
#include "gui/guiWrapper.h"
|
||||||
|
|
||||||
|
#define COMMIT_TRESHOLD 256
|
||||||
|
|
||||||
extern bool hasValidFramebufferAttached;
|
extern bool hasValidFramebufferAttached;
|
||||||
|
|
||||||
float supportBufferData[512 * 4];
|
float supportBufferData[512 * 4];
|
||||||
@ -113,7 +116,7 @@ MetalRenderer::~MetalRenderer()
|
|||||||
m_device->release();
|
m_device->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: don't ignore "mainWindow" argument
|
// TODO: don't ignore "mainWindow" argument and respect size
|
||||||
void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow)
|
void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow)
|
||||||
{
|
{
|
||||||
const auto& windowInfo = gui_getWindowInfo().window_main;
|
const auto& windowInfo = gui_getWindowInfo().window_main;
|
||||||
@ -168,19 +171,23 @@ void MetalRenderer::DrawEmptyFrame(bool mainWindow)
|
|||||||
|
|
||||||
void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC)
|
void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC)
|
||||||
{
|
{
|
||||||
EndEncoding();
|
|
||||||
|
|
||||||
if (m_drawable)
|
if (m_drawable)
|
||||||
{
|
{
|
||||||
EnsureCommandBuffer();
|
auto commandBuffer = GetCommandBuffer();
|
||||||
m_commandBuffer->presentDrawable(m_drawable);
|
commandBuffer->presentDrawable(m_drawable);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
debug_printf("skipped present!\n");
|
debug_printf("skipped present!\n");
|
||||||
}
|
}
|
||||||
m_drawable = nullptr;
|
m_drawable = nullptr;
|
||||||
|
|
||||||
|
// Release all the command buffers
|
||||||
CommitCommandBuffer();
|
CommitCommandBuffer();
|
||||||
|
for (uint32 i = 0; i < m_commandBuffers.size(); i++)
|
||||||
|
m_commandBuffers[i].m_commandBuffer->release();
|
||||||
|
m_commandBuffers.clear();
|
||||||
|
|
||||||
// Reset temporary buffers
|
// Reset temporary buffers
|
||||||
m_memoryManager->ResetTemporaryBuffers();
|
m_memoryManager->ResetTemporaryBuffers();
|
||||||
@ -223,18 +230,20 @@ bool MetalRenderer::BeginFrame(bool mainWindow)
|
|||||||
|
|
||||||
void MetalRenderer::Flush(bool waitIdle)
|
void MetalRenderer::Flush(bool waitIdle)
|
||||||
{
|
{
|
||||||
// TODO: should we?
|
// TODO: commit if commit on idle is requested
|
||||||
|
if (m_recordedDrawcalls > 0)
|
||||||
CommitCommandBuffer();
|
CommitCommandBuffer();
|
||||||
if (waitIdle)
|
if (waitIdle)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO: shouldn't we wait for all command buffers?
|
||||||
|
WaitForCommandBufferCompletion(GetCurrentCommandBuffer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalRenderer::NotifyLatteCommandProcessorIdle()
|
void MetalRenderer::NotifyLatteCommandProcessorIdle()
|
||||||
{
|
{
|
||||||
// TODO: should we?
|
// TODO: commit if commit on idle is requested
|
||||||
CommitCommandBuffer();
|
//CommitCommandBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalRenderer::AppendOverlayDebugInfo()
|
void MetalRenderer::AppendOverlayDebugInfo()
|
||||||
@ -452,7 +461,7 @@ LatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView
|
|||||||
|
|
||||||
void MetalRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height)
|
void MetalRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height)
|
||||||
{
|
{
|
||||||
EnsureCommandBuffer();
|
GetCommandBuffer();
|
||||||
|
|
||||||
// scale copy size to effective size
|
// scale copy size to effective size
|
||||||
sint32 effectiveCopyWidth = width;
|
sint32 effectiveCopyWidth = width;
|
||||||
@ -809,11 +818,15 @@ void MetalRenderer::draw_endSequence()
|
|||||||
if (pixelShader)
|
if (pixelShader)
|
||||||
LatteRenderTarget_trackUpdates();
|
LatteRenderTarget_trackUpdates();
|
||||||
bool hasReadback = LatteTextureReadback_Update();
|
bool hasReadback = LatteTextureReadback_Update();
|
||||||
//m_recordedDrawcalls++;
|
m_recordedDrawcalls++;
|
||||||
//if (m_recordedDrawcalls >= m_submitThreshold || hasReadback)
|
// The number of draw calls needs to twice as big, since we are interrupting the render pass
|
||||||
//{
|
if (m_recordedDrawcalls >= COMMIT_TRESHOLD * 2 || hasReadback)
|
||||||
// SubmitCommandBuffer();
|
{
|
||||||
//}
|
CommitCommandBuffer();
|
||||||
|
|
||||||
|
// TODO: where should this be called?
|
||||||
|
LatteTextureReadback_UpdateFinishedTransfers(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* MetalRenderer::indexData_reserveIndexMemory(uint32 size, uint32& offset, uint32& bufferIndex)
|
void* MetalRenderer::indexData_reserveIndexMemory(uint32 size, uint32& offset, uint32& bufferIndex)
|
||||||
@ -830,22 +843,38 @@ void MetalRenderer::indexData_uploadIndexMemory(uint32 offset, uint32 size)
|
|||||||
// Do nothing, since the buffer has shared storage mode
|
// Do nothing, since the buffer has shared storage mode
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalRenderer::EnsureCommandBuffer()
|
MTL::CommandBuffer* MetalRenderer::GetCommandBuffer()
|
||||||
{
|
{
|
||||||
if (!m_commandBuffer)
|
bool needsNewCommandBuffer = (m_commandBuffers.empty() || m_commandBuffers.back().m_commited);
|
||||||
|
if (needsNewCommandBuffer)
|
||||||
{
|
{
|
||||||
// Debug
|
// Debug
|
||||||
//m_commandQueue->insertDebugCaptureBoundary();
|
//m_commandQueue->insertDebugCaptureBoundary();
|
||||||
|
|
||||||
m_commandBuffer = m_commandQueue->commandBuffer();
|
MTL::CommandBuffer* mtlCommandBuffer = m_commandQueue->commandBuffer();
|
||||||
|
m_commandBuffers.push_back({mtlCommandBuffer});
|
||||||
|
|
||||||
|
return mtlCommandBuffer;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return m_commandBuffers.back().m_commandBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetalRenderer::CommandBufferCompleted(MTL::CommandBuffer* commandBuffer)
|
||||||
|
{
|
||||||
|
return commandBuffer->status() == MTL::CommandBufferStatusCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalRenderer::WaitForCommandBufferCompletion(MTL::CommandBuffer* commandBuffer)
|
||||||
|
{
|
||||||
|
commandBuffer->waitUntilCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some render passes clear the attachments, forceRecreate is supposed to be used in those cases
|
// Some render passes clear the attachments, forceRecreate is supposed to be used in those cases
|
||||||
MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8], MTL::Texture* depthRenderTarget, bool forceRecreate, bool rebindStateIfNewEncoder)
|
MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8], MTL::Texture* depthRenderTarget, bool forceRecreate, bool rebindStateIfNewEncoder)
|
||||||
{
|
{
|
||||||
EnsureCommandBuffer();
|
|
||||||
|
|
||||||
// Check if we need to begin a new render pass
|
// Check if we need to begin a new render pass
|
||||||
if (m_commandEncoder)
|
if (m_commandEncoder)
|
||||||
{
|
{
|
||||||
@ -881,6 +910,8 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(MTL::RenderPas
|
|||||||
EndEncoding();
|
EndEncoding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto commandBuffer = GetCommandBuffer();
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
m_state.m_lastUsedFBO = m_state.m_activeFBO;
|
m_state.m_lastUsedFBO = m_state.m_activeFBO;
|
||||||
for (uint8 i = 0; i < 8; i++)
|
for (uint8 i = 0; i < 8; i++)
|
||||||
@ -889,7 +920,7 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(MTL::RenderPas
|
|||||||
}
|
}
|
||||||
m_state.m_depthRenderTarget = depthRenderTarget;
|
m_state.m_depthRenderTarget = depthRenderTarget;
|
||||||
|
|
||||||
auto renderCommandEncoder = m_commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
auto renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
||||||
m_commandEncoder = renderCommandEncoder;
|
m_commandEncoder = renderCommandEncoder;
|
||||||
m_encoderType = MetalEncoderType::Render;
|
m_encoderType = MetalEncoderType::Render;
|
||||||
|
|
||||||
@ -914,7 +945,9 @@ MTL::ComputeCommandEncoder* MetalRenderer::GetComputeCommandEncoder()
|
|||||||
EndEncoding();
|
EndEncoding();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto computeCommandEncoder = m_commandBuffer->computeCommandEncoder();
|
auto commandBuffer = GetCommandBuffer();
|
||||||
|
|
||||||
|
auto computeCommandEncoder = commandBuffer->computeCommandEncoder();
|
||||||
m_commandEncoder = computeCommandEncoder;
|
m_commandEncoder = computeCommandEncoder;
|
||||||
m_encoderType = MetalEncoderType::Compute;
|
m_encoderType = MetalEncoderType::Compute;
|
||||||
|
|
||||||
@ -933,7 +966,9 @@ MTL::BlitCommandEncoder* MetalRenderer::GetBlitCommandEncoder()
|
|||||||
EndEncoding();
|
EndEncoding();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto blitCommandEncoder = m_commandBuffer->blitCommandEncoder();
|
auto commandBuffer = GetCommandBuffer();
|
||||||
|
|
||||||
|
auto blitCommandEncoder = commandBuffer->blitCommandEncoder();
|
||||||
m_commandEncoder = blitCommandEncoder;
|
m_commandEncoder = blitCommandEncoder;
|
||||||
m_encoderType = MetalEncoderType::Blit;
|
m_encoderType = MetalEncoderType::Blit;
|
||||||
|
|
||||||
@ -942,32 +977,37 @@ MTL::BlitCommandEncoder* MetalRenderer::GetBlitCommandEncoder()
|
|||||||
|
|
||||||
void MetalRenderer::EndEncoding()
|
void MetalRenderer::EndEncoding()
|
||||||
{
|
{
|
||||||
if (m_commandEncoder)
|
if (m_encoderType != MetalEncoderType::None)
|
||||||
{
|
{
|
||||||
m_commandEncoder->endEncoding();
|
m_commandEncoder->endEncoding();
|
||||||
m_commandEncoder->release();
|
m_commandEncoder->release();
|
||||||
m_commandEncoder = nullptr;
|
|
||||||
m_encoderType = MetalEncoderType::None;
|
m_encoderType = MetalEncoderType::None;
|
||||||
|
|
||||||
|
// Commit the command buffer if enough draw calls have been recorded
|
||||||
|
if (m_recordedDrawcalls >= COMMIT_TRESHOLD)
|
||||||
|
CommitCommandBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalRenderer::CommitCommandBuffer()
|
void MetalRenderer::CommitCommandBuffer()
|
||||||
|
{
|
||||||
|
m_recordedDrawcalls = 0;
|
||||||
|
|
||||||
|
if (m_commandBuffers.size() != 0)
|
||||||
{
|
{
|
||||||
EndEncoding();
|
EndEncoding();
|
||||||
|
|
||||||
if (m_commandBuffer)
|
auto& commandBuffer = m_commandBuffers.back();
|
||||||
|
if (!commandBuffer.m_commited)
|
||||||
{
|
{
|
||||||
m_commandBuffer->commit();
|
commandBuffer.m_commandBuffer->commit();
|
||||||
m_commandBuffer->release();
|
commandBuffer.m_commited = true;
|
||||||
m_commandBuffer = nullptr;
|
|
||||||
|
|
||||||
// TODO: where should this be called?
|
|
||||||
LatteTextureReadback_UpdateFinishedTransfers(false);
|
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
//m_commandQueue->insertDebugCaptureBoundary();
|
//m_commandQueue->insertDebugCaptureBoundary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MetalRenderer::AcquireNextDrawable(bool mainWindow)
|
bool MetalRenderer::AcquireNextDrawable(bool mainWindow)
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||||
|
|
||||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h"
|
#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h"
|
||||||
|
#include "Common/precompiled.h"
|
||||||
|
#include "Metal/MTLCommandBuffer.hpp"
|
||||||
|
|
||||||
#define MAX_MTL_BUFFERS 31
|
#define MAX_MTL_BUFFERS 31
|
||||||
#define GET_MTL_VERTEX_BUFFER_INDEX(index) (MAX_MTL_BUFFERS - index - 2)
|
#define GET_MTL_VERTEX_BUFFER_INDEX(index) (MAX_MTL_BUFFERS - index - 2)
|
||||||
@ -47,6 +49,12 @@ struct MetalState
|
|||||||
MTL::ScissorRect m_scissor = {0, 0, 0, 0};
|
MTL::ScissorRect m_scissor = {0, 0, 0, 0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MetalCommandBuffer
|
||||||
|
{
|
||||||
|
MTL::CommandBuffer* m_commandBuffer;
|
||||||
|
bool m_commited = false;
|
||||||
|
};
|
||||||
|
|
||||||
enum class MetalEncoderType
|
enum class MetalEncoderType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
@ -231,7 +239,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
void EnsureCommandBuffer();
|
MTL::CommandBuffer* GetCurrentCommandBuffer()
|
||||||
|
{
|
||||||
|
cemu_assert_debug(m_commandBuffers.size() != 0);
|
||||||
|
|
||||||
|
return m_commandBuffers[m_commandBuffers.size() - 1].m_commandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTL::CommandBuffer* GetCommandBuffer();
|
||||||
|
bool CommandBufferCompleted(MTL::CommandBuffer* commandBuffer);
|
||||||
|
void WaitForCommandBufferCompletion(MTL::CommandBuffer* commandBuffer);
|
||||||
MTL::RenderCommandEncoder* GetRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8], MTL::Texture* depthRenderTarget, bool forceRecreate = false, bool rebindStateIfNewEncoder = true);
|
MTL::RenderCommandEncoder* GetRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8], MTL::Texture* depthRenderTarget, bool forceRecreate = false, bool rebindStateIfNewEncoder = true);
|
||||||
MTL::ComputeCommandEncoder* GetComputeCommandEncoder();
|
MTL::ComputeCommandEncoder* GetComputeCommandEncoder();
|
||||||
MTL::BlitCommandEncoder* GetBlitCommandEncoder();
|
MTL::BlitCommandEncoder* GetBlitCommandEncoder();
|
||||||
@ -280,7 +297,8 @@ private:
|
|||||||
MTL::Buffer* m_xfbRingBuffer;
|
MTL::Buffer* m_xfbRingBuffer;
|
||||||
|
|
||||||
// Active objects
|
// Active objects
|
||||||
MTL::CommandBuffer* m_commandBuffer = nullptr;
|
std::vector<MetalCommandBuffer> m_commandBuffers;
|
||||||
|
uint32 m_recordedDrawcalls = 0;
|
||||||
MetalEncoderType m_encoderType = MetalEncoderType::None;
|
MetalEncoderType m_encoderType = MetalEncoderType::None;
|
||||||
MTL::CommandEncoder* m_commandEncoder = nullptr;
|
MTL::CommandEncoder* m_commandEncoder = nullptr;
|
||||||
CA::MetalDrawable* m_drawable = nullptr;
|
CA::MetalDrawable* m_drawable = nullptr;
|
||||||
|
Loading…
Reference in New Issue
Block a user