From be8a5604965d4bb91bfc2e2a7472f991a9969b09 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Tue, 30 Jul 2024 19:27:52 +0200 Subject: [PATCH] optimize index buffers --- .../Renderer/Metal/MetalMemoryManager.cpp | 67 ++++++++++++++----- .../Latte/Renderer/Metal/MetalMemoryManager.h | 66 ++++++++++++++++-- .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 4 +- .../HW/Latte/Renderer/Metal/MetalRenderer.h | 7 +- .../Renderer/Metal/ShaderSourcePresent.h | 3 +- 5 files changed, 120 insertions(+), 27 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp index 9ec94c0e..d09ab116 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp @@ -1,5 +1,57 @@ +#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" +const size_t BUFFER_ALLOCATION_SIZE = 8 * 1024 * 1024; + +MetalBufferAllocation MetalBufferAllocator::GetBufferAllocation(size_t size) +{ + // First, try to find a free range + for (uint32 i = 0; i < m_freeBufferRanges.size(); i++) + { + auto& range = m_freeBufferRanges[i]; + if (range.size >= size) + { + MetalBufferAllocation allocation; + allocation.bufferIndex = range.bufferIndex; + allocation.bufferOffset = range.offset; + allocation.data = (uint8*)m_buffers[range.bufferIndex]->contents() + range.offset; + + range.offset += size; + range.size -= size; + + if (range.size == 0) + { + m_freeBufferRanges.erase(m_freeBufferRanges.begin() + i); + } + + return allocation; + } + } + + // If no free range was found, allocate a new buffer + MTL::Buffer* buffer = m_mtlr->GetDevice()->newBuffer(std::max(size, BUFFER_ALLOCATION_SIZE), MTL::ResourceStorageModeShared); + + MetalBufferAllocation allocation; + allocation.bufferIndex = m_buffers.size(); + allocation.bufferOffset = 0; + allocation.data = buffer->contents(); + + m_buffers.push_back(buffer); + + // If the buffer is larger than the requested size, add the remaining space to the free buffer ranges + if (size < BUFFER_ALLOCATION_SIZE) + { + MetalBufferRange range; + range.bufferIndex = allocation.bufferIndex; + range.offset = size; + range.size = BUFFER_ALLOCATION_SIZE - size; + + m_freeBufferRanges.push_back(range); + } + + return allocation; +} + void* MetalMemoryManager::GetTextureUploadBuffer(size_t size) { if (m_textureUploadBuffer.size() < size) @@ -10,21 +62,6 @@ void* MetalMemoryManager::GetTextureUploadBuffer(size_t size) return m_textureUploadBuffer.data(); } -// TODO: optimize this -MetalBufferAllocation MetalMemoryManager::GetBufferAllocation(size_t size) -{ - MTL::Buffer* buffer = m_mtlr->GetDevice()->newBuffer(size, MTL::ResourceStorageModeShared); - - MetalBufferAllocation allocation; - allocation.bufferIndex = m_buffers.size(); - allocation.bufferOffset = 0; - allocation.data = buffer->contents(); - - m_buffers.push_back(buffer); - - return allocation; -} - void MetalMemoryManager::InitBufferCache(size_t size) { if (m_bufferCache) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h index ee773047..c099360f 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h @@ -4,6 +4,8 @@ #include "Cafe/HW/Latte/ISA/LatteReg.h" +//const uint32 bufferAllocatorIndexShift = 24; + struct MetalBufferAllocation { void* data; @@ -11,16 +13,69 @@ struct MetalBufferAllocation size_t bufferOffset; }; -class MetalMemoryManager +struct MetalBufferRange +{ + uint32 bufferIndex; + size_t offset; + size_t size; +}; + +class MetalBufferAllocator { public: - MetalMemoryManager(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {} + MetalBufferAllocator(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {} + + void ResetTemporaryBuffers() + { + m_freeBufferRanges.clear(); + + // Register the free ranges + for (uint32 i = 0; i < m_buffers.size(); i++) + { + m_freeBufferRanges.push_back({i, 0, m_buffers[i]->length()}); + } + } MTL::Buffer* GetBuffer(uint32 bufferIndex) { return m_buffers[bufferIndex]; } + MetalBufferAllocation GetBufferAllocation(size_t size); + +private: + class MetalRenderer* m_mtlr; + + std::vector m_buffers; + std::vector m_freeBufferRanges; +}; + +class MetalMemoryManager +{ +public: + MetalMemoryManager(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer}, m_bufferAllocator(metalRenderer) {} + + void ResetTemporaryBuffers() + { + m_bufferAllocator/*s[m_bufferAllocatorIndex]*/.ResetTemporaryBuffers(); + //m_bufferAllocatorIndex = (m_bufferAllocatorIndex + 1) % 2; + } + + MTL::Buffer* GetBuffer(uint32 bufferIndex) + { + //uint32 bufferAllocatorIndex = (bufferIndex >> bufferAllocatorIndexShift); + + return m_bufferAllocator/*s[bufferAllocatorIndex]*/.GetBuffer(bufferIndex); + } + + MetalBufferAllocation GetBufferAllocation(size_t size) + { + auto allocation = m_bufferAllocator/*s[m_bufferAllocatorIndex]*/.GetBufferAllocation(size); + //allocation.bufferIndex |= (m_bufferAllocatorIndex << bufferAllocatorIndexShift); + + return allocation; + } + MTL::Buffer* GetBufferCache() { return m_bufferCache; @@ -28,8 +83,6 @@ public: void* GetTextureUploadBuffer(size_t size); - MetalBufferAllocation GetBufferAllocation(size_t size); - // Buffer cache void InitBufferCache(size_t size); void UploadToBufferCache(const void* data, size_t offset, size_t size); @@ -39,6 +92,9 @@ private: class MetalRenderer* m_mtlr; std::vector m_textureUploadBuffer; - std::vector m_buffers; + + MetalBufferAllocator m_bufferAllocator;//s[2]; + //uint8 m_bufferAllocatorIndex = 0; + MTL::Buffer* m_bufferCache = nullptr; }; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index af022a0f..23213009 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -456,7 +456,7 @@ void MetalRenderer::draw_beginSequence() LatteSHRC_UpdateActiveShaders(); if (LatteGPUState.activeShaderHasError) { - cemuLog_logDebugOnce(LogType::Force, "Skipping drawcalls due to shader error"); + debug_printf("Skipping drawcalls due to shader error\n"); m_state.skipDrawSequence = true; cemu_assert_debug(false); return; @@ -506,10 +506,8 @@ void MetalRenderer::draw_beginSequence() void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) { - // TODO: uncomment //if (m_state.skipDrawSequence) //{ - // printf("skipping draw\n"); // return; //} diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index 0c09ee24..45e9e703 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -18,7 +18,7 @@ #define MAX_MTL_TEXTURES 31 -struct MetalBufferRange +struct MetalBoundBuffer { bool needsRebind = false; sint32 offset = -1; @@ -28,7 +28,7 @@ struct MetalState { bool skipDrawSequence = false; class CachedFBOMtl* activeFBO = nullptr; - MetalBufferRange vertexBuffers[MAX_MTL_BUFFERS] = {{}}; + MetalBoundBuffer vertexBuffers[MAX_MTL_BUFFERS] = {{}}; class LatteTextureViewMtl* textures[MAX_MTL_TEXTURES] = {nullptr}; MTL::Texture* colorRenderTargets[8] = {nullptr}; MTL::Texture* depthRenderTarget = nullptr; @@ -333,6 +333,9 @@ private: m_commandBuffer->release(); m_commandBuffer = nullptr; + // Reset temporary buffers + m_memoryManager->ResetTemporaryBuffers(); + // Debug m_commandQueue->insertDebugCaptureBoundary(); } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/ShaderSourcePresent.h b/src/Cafe/HW/Latte/Renderer/Metal/ShaderSourcePresent.h index 0ca7cbbe..ad3f6971 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/ShaderSourcePresent.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/ShaderSourcePresent.h @@ -1,5 +1,4 @@ -#include -const char* presentLibrarySource = \ +inline const char* presentLibrarySource = \ "#include \n" \ "using namespace metal;\n" \ "\n" \