implement vertex stride workaround

This commit is contained in:
Samuliak 2024-08-06 20:42:38 +02:00
parent 82dcbd98a6
commit ac651eba77
3 changed files with 25 additions and 16 deletions

View File

@ -1,6 +1,7 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#include "Metal/MTLResource.hpp"
const size_t BUFFER_ALLOCATION_SIZE = 8 * 1024 * 1024; 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 vertexBufferRange = m_bufferRanges[bufferIndex];
auto& restrideInfo = vertexBufferRange->restrideInfo; auto& restrideInfo = vertexBufferRange->restrideInfo;
@ -87,21 +88,28 @@ MetalRestridedBufferRange MetalVertexBufferCache::RestrideBufferIfNeeded(uint32
if (stride % 4 == 0) if (stride % 4 == 0)
{ {
// No restride needed // No restride needed
return {nullptr, vertexBufferRange->offset}; return {bufferCache, vertexBufferRange->offset};
} }
if (restrideInfo.memoryInvalidated || stride != restrideInfo.lastStride) if (restrideInfo.memoryInvalidated || stride != restrideInfo.lastStride)
{ {
// TODO: restride // TODO: use compute/void vertex function instead
throw std::runtime_error("restride needed"); 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.memoryInvalidated = false;
restrideInfo.lastStride = stride; restrideInfo.lastStride = newStride;
} }
// TODO: remove
throw std::runtime_error("restride unimplemented");
return {restrideInfo.buffer, 0}; return {restrideInfo.buffer, 0};
} }

View File

@ -97,7 +97,7 @@ public:
range = nullptr; range = nullptr;
} }
MetalRestridedBufferRange RestrideBufferIfNeeded(uint32 bufferIndex, size_t stride); MetalRestridedBufferRange RestrideBufferIfNeeded(MTL::Buffer* bufferCache, uint32 bufferIndex, size_t stride);
private: private:
class MetalRenderer* m_mtlr; class MetalRenderer* m_mtlr;
@ -159,13 +159,7 @@ public:
MetalRestridedBufferRange RestrideBufferIfNeeded(uint32 bufferIndex, size_t stride) MetalRestridedBufferRange RestrideBufferIfNeeded(uint32 bufferIndex, size_t stride)
{ {
auto range = m_vertexBufferCache.RestrideBufferIfNeeded(bufferIndex, stride); return m_vertexBufferCache.RestrideBufferIfNeeded(m_bufferCache, bufferIndex, stride);
if (!range.buffer)
{
range.buffer = m_bufferCache;
}
return range;
} }
private: private:

View File

@ -63,6 +63,13 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
uint32 bufferStride = (LatteGPUState.contextNew.GetRawView()[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF; uint32 bufferStride = (LatteGPUState.contextNew.GetRawView()[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;
bufferStride = align(bufferStride, 4); 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)); auto layout = vertexDescriptor->layouts()->object(GET_MTL_VERTEX_BUFFER_INDEX(bufferIndex));
layout->setStride(bufferStride); layout->setStride(bufferStride);
if (!fetchType.has_value() || fetchType == LatteConst::VertexFetchType2::VERTEX_DATA) if (!fetchType.has_value() || fetchType == LatteConst::VertexFetchType2::VERTEX_DATA)