optimize index buffers

This commit is contained in:
Samuliak 2024-07-30 19:27:52 +02:00
parent 0cb83d4668
commit be8a560496
5 changed files with 120 additions and 27 deletions

View File

@ -1,5 +1,57 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.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) void* MetalMemoryManager::GetTextureUploadBuffer(size_t size)
{ {
if (m_textureUploadBuffer.size() < size) if (m_textureUploadBuffer.size() < size)
@ -10,21 +62,6 @@ void* MetalMemoryManager::GetTextureUploadBuffer(size_t size)
return m_textureUploadBuffer.data(); 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) void MetalMemoryManager::InitBufferCache(size_t size)
{ {
if (m_bufferCache) if (m_bufferCache)

View File

@ -4,6 +4,8 @@
#include "Cafe/HW/Latte/ISA/LatteReg.h" #include "Cafe/HW/Latte/ISA/LatteReg.h"
//const uint32 bufferAllocatorIndexShift = 24;
struct MetalBufferAllocation struct MetalBufferAllocation
{ {
void* data; void* data;
@ -11,16 +13,69 @@ struct MetalBufferAllocation
size_t bufferOffset; size_t bufferOffset;
}; };
class MetalMemoryManager struct MetalBufferRange
{
uint32 bufferIndex;
size_t offset;
size_t size;
};
class MetalBufferAllocator
{ {
public: 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) MTL::Buffer* GetBuffer(uint32 bufferIndex)
{ {
return m_buffers[bufferIndex]; return m_buffers[bufferIndex];
} }
MetalBufferAllocation GetBufferAllocation(size_t size);
private:
class MetalRenderer* m_mtlr;
std::vector<MTL::Buffer*> m_buffers;
std::vector<MetalBufferRange> 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() MTL::Buffer* GetBufferCache()
{ {
return m_bufferCache; return m_bufferCache;
@ -28,8 +83,6 @@ public:
void* GetTextureUploadBuffer(size_t size); void* GetTextureUploadBuffer(size_t size);
MetalBufferAllocation GetBufferAllocation(size_t size);
// Buffer cache // Buffer cache
void InitBufferCache(size_t size); void InitBufferCache(size_t size);
void UploadToBufferCache(const void* data, size_t offset, size_t size); void UploadToBufferCache(const void* data, size_t offset, size_t size);
@ -39,6 +92,9 @@ private:
class MetalRenderer* m_mtlr; class MetalRenderer* m_mtlr;
std::vector<uint8> m_textureUploadBuffer; std::vector<uint8> m_textureUploadBuffer;
std::vector<MTL::Buffer*> m_buffers;
MetalBufferAllocator m_bufferAllocator;//s[2];
//uint8 m_bufferAllocatorIndex = 0;
MTL::Buffer* m_bufferCache = nullptr; MTL::Buffer* m_bufferCache = nullptr;
}; };

View File

@ -456,7 +456,7 @@ void MetalRenderer::draw_beginSequence()
LatteSHRC_UpdateActiveShaders(); LatteSHRC_UpdateActiveShaders();
if (LatteGPUState.activeShaderHasError) 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; m_state.skipDrawSequence = true;
cemu_assert_debug(false); cemu_assert_debug(false);
return; 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) 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) //if (m_state.skipDrawSequence)
//{ //{
// printf("skipping draw\n");
// return; // return;
//} //}

View File

@ -18,7 +18,7 @@
#define MAX_MTL_TEXTURES 31 #define MAX_MTL_TEXTURES 31
struct MetalBufferRange struct MetalBoundBuffer
{ {
bool needsRebind = false; bool needsRebind = false;
sint32 offset = -1; sint32 offset = -1;
@ -28,7 +28,7 @@ struct MetalState
{ {
bool skipDrawSequence = false; bool skipDrawSequence = false;
class CachedFBOMtl* activeFBO = nullptr; class CachedFBOMtl* activeFBO = nullptr;
MetalBufferRange vertexBuffers[MAX_MTL_BUFFERS] = {{}}; MetalBoundBuffer vertexBuffers[MAX_MTL_BUFFERS] = {{}};
class LatteTextureViewMtl* textures[MAX_MTL_TEXTURES] = {nullptr}; class LatteTextureViewMtl* textures[MAX_MTL_TEXTURES] = {nullptr};
MTL::Texture* colorRenderTargets[8] = {nullptr}; MTL::Texture* colorRenderTargets[8] = {nullptr};
MTL::Texture* depthRenderTarget = nullptr; MTL::Texture* depthRenderTarget = nullptr;
@ -333,6 +333,9 @@ private:
m_commandBuffer->release(); m_commandBuffer->release();
m_commandBuffer = nullptr; m_commandBuffer = nullptr;
// Reset temporary buffers
m_memoryManager->ResetTemporaryBuffers();
// Debug // Debug
m_commandQueue->insertDebugCaptureBoundary(); m_commandQueue->insertDebugCaptureBoundary();
} }

View File

@ -1,5 +1,4 @@
#include <cmath> inline const char* presentLibrarySource = \
const char* presentLibrarySource = \
"#include <metal_stdlib>\n" \ "#include <metal_stdlib>\n" \
"using namespace metal;\n" \ "using namespace metal;\n" \
"\n" \ "\n" \