From ac651eba7762053a43ea8224b9d7ece78899b356 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Tue, 6 Aug 2024 20:42:38 +0200 Subject: [PATCH] implement vertex stride workaround --- .../Renderer/Metal/MetalMemoryManager.cpp | 24 ++++++++++++------- .../Latte/Renderer/Metal/MetalMemoryManager.h | 10 ++------ .../Renderer/Metal/MetalPipelineCache.cpp | 7 ++++++ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp index 897e9593..bba887b9 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp @@ -1,6 +1,7 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" +#include "Metal/MTLResource.hpp" const size_t BUFFER_ALLOCATION_SIZE = 8 * 1024 * 1024; @@ -79,7 +80,7 @@ MetalVertexBufferCache::~MetalVertexBufferCache() } } -MetalRestridedBufferRange MetalVertexBufferCache::RestrideBufferIfNeeded(uint32 bufferIndex, size_t stride) +MetalRestridedBufferRange MetalVertexBufferCache::RestrideBufferIfNeeded(MTL::Buffer* bufferCache, uint32 bufferIndex, size_t stride) { auto vertexBufferRange = m_bufferRanges[bufferIndex]; auto& restrideInfo = vertexBufferRange->restrideInfo; @@ -87,21 +88,28 @@ MetalRestridedBufferRange MetalVertexBufferCache::RestrideBufferIfNeeded(uint32 if (stride % 4 == 0) { // No restride needed - return {nullptr, vertexBufferRange->offset}; + return {bufferCache, vertexBufferRange->offset}; } if (restrideInfo.memoryInvalidated || stride != restrideInfo.lastStride) { - // TODO: restride - throw std::runtime_error("restride needed"); + // TODO: use compute/void vertex function instead + size_t newStride = align(stride, 4); + size_t newSize = vertexBufferRange->size / stride * newStride; + restrideInfo.buffer = m_mtlr->GetDevice()->newBuffer(newSize, MTL::StorageModeShared); + + uint8* oldPtr = (uint8*)bufferCache->contents() + vertexBufferRange->offset; + uint8* newPtr = (uint8*)restrideInfo.buffer->contents(); + + for (size_t elem = 0; elem < vertexBufferRange->size / stride; elem++) + { + memcpy(newPtr + elem * newStride, oldPtr + elem * stride, stride); + } restrideInfo.memoryInvalidated = false; - restrideInfo.lastStride = stride; + restrideInfo.lastStride = newStride; } - // TODO: remove - throw std::runtime_error("restride unimplemented"); - return {restrideInfo.buffer, 0}; } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h index 5ee0b37d..93011ae3 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h @@ -97,7 +97,7 @@ public: range = nullptr; } - MetalRestridedBufferRange RestrideBufferIfNeeded(uint32 bufferIndex, size_t stride); + MetalRestridedBufferRange RestrideBufferIfNeeded(MTL::Buffer* bufferCache, uint32 bufferIndex, size_t stride); private: class MetalRenderer* m_mtlr; @@ -159,13 +159,7 @@ public: MetalRestridedBufferRange RestrideBufferIfNeeded(uint32 bufferIndex, size_t stride) { - auto range = m_vertexBufferCache.RestrideBufferIfNeeded(bufferIndex, stride); - if (!range.buffer) - { - range.buffer = m_bufferCache; - } - - return range; + return m_vertexBufferCache.RestrideBufferIfNeeded(m_bufferCache, bufferIndex, stride); } private: diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp index 46918f8f..d4d04312 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp @@ -63,6 +63,13 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS uint32 bufferStride = (LatteGPUState.contextNew.GetRawView()[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF; bufferStride = align(bufferStride, 4); + // HACK + if (bufferStride == 0) + { + debug_printf("vertex buffer %u has a vertex stride of 0 bytes, using 4 bytes instead\n", bufferIndex); + bufferStride = 4; + } + auto layout = vertexDescriptor->layouts()->object(GET_MTL_VERTEX_BUFFER_INDEX(bufferIndex)); layout->setStride(bufferStride); if (!fetchType.has_value() || fetchType == LatteConst::VertexFetchType2::VERTEX_DATA)