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/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};
}

View File

@ -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:

View File

@ -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)