diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp index 51885e51..6f54272c 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp @@ -368,6 +368,57 @@ MTL::VertexFormat GetMtlVertexFormat(uint8 format) } } +uint32 GetMtlVertexFormatSize(uint8 format) +{ + switch (format) + { + case FMT_32_32_32_32_FLOAT: + return 16; + case FMT_32_32_32_FLOAT: + return 12; + case FMT_32_32_FLOAT: + return 8; + case FMT_32_FLOAT: + return 4; + case FMT_8_8_8_8: + return 4; + case FMT_8_8_8: + return 3; + case FMT_8_8: + return 2; + case FMT_8: + return 1; + case FMT_32_32_32_32: + return 16; + case FMT_32_32_32: + return 12; + case FMT_32_32: + return 8; + case FMT_32: + return 4; + case FMT_16_16_16_16: + return 8; + case FMT_16_16_16: + return 6; + case FMT_16_16: + return 4; + case FMT_16: + return 2; + case FMT_16_16_16_16_FLOAT: + return 8; + case FMT_16_16_16_FLOAT: + return 6; + case FMT_16_16_FLOAT: + return 4; + case FMT_16_FLOAT: + return 2; + case FMT_2_10_10_10: + return 4; + default: + return 0; + } +} + MTL::IndexType GetMtlIndexType(Renderer::INDEX_TYPE indexType) { switch (indexType) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h index cc0c5e02..2c805527 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h @@ -42,6 +42,8 @@ MTL::PrimitiveType GetMtlPrimitiveType(LattePrimitiveMode primitiveMode); MTL::VertexFormat GetMtlVertexFormat(uint8 format); +uint32 GetMtlVertexFormatSize(uint8 format); + MTL::IndexType GetMtlIndexType(Renderer::INDEX_TYPE indexType); MTL::BlendOperation GetMtlBlendOp(Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC combineFunc); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp index ade541ba..1d068426 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp @@ -298,6 +298,7 @@ MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const Latte { std::optional fetchType; + uint32 minBufferStride = 0; for (sint32 j = 0; j < bufferGroup.attribCount; ++j) { auto& attr = bufferGroup.attrib[j]; @@ -311,6 +312,8 @@ MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const Latte attribute->setBufferIndex(GET_MTL_VERTEX_BUFFER_INDEX(attr.attributeBufferIndex)); attribute->setFormat(GetMtlVertexFormat(attr.format)); + minBufferStride = std::max(minBufferStride, attr.offset + GetMtlVertexFormatSize(attr.format)); + if (fetchType.has_value()) cemu_assert_debug(fetchType == attr.fetchType); else @@ -327,24 +330,30 @@ MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const Latte uint32 bufferStride = (lcr.GetRawView()[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF; bufferStride = Align(bufferStride, 4); - // HACK + auto layout = vertexDescriptor->layouts()->object(GET_MTL_VERTEX_BUFFER_INDEX(bufferIndex)); if (bufferStride == 0) { - debug_printf("vertex buffer %u has a vertex stride of 0 bytes, using 4 bytes instead\n", bufferIndex); - bufferStride = 4; - } + // Buffer stride cannot be zero, let's use the minimum stride + bufferStride = minBufferStride; + debug_printf("vertex buffer %u has a vertex stride of 0 bytes, using %u bytes instead\n", bufferIndex, bufferStride); - auto layout = vertexDescriptor->layouts()->object(GET_MTL_VERTEX_BUFFER_INDEX(bufferIndex)); - layout->setStride(bufferStride); - if (!fetchType.has_value() || fetchType == LatteConst::VertexFetchType2::VERTEX_DATA) - layout->setStepFunction(MTL::VertexStepFunctionPerVertex); - else if (fetchType == LatteConst::VertexFetchType2::INSTANCE_DATA) - layout->setStepFunction(MTL::VertexStepFunctionPerInstance); + // Additionally, constant vertex function must be used + layout->setStepFunction(MTL::VertexStepFunctionConstant); + layout->setStepRate(0); + } else { - debug_printf("unimplemented vertex fetch type %u\n", (uint32)fetchType.value()); - cemu_assert(false); + if (!fetchType.has_value() || fetchType == LatteConst::VertexFetchType2::VERTEX_DATA) + layout->setStepFunction(MTL::VertexStepFunctionPerVertex); + else if (fetchType == LatteConst::VertexFetchType2::INSTANCE_DATA) + layout->setStepFunction(MTL::VertexStepFunctionPerInstance); + else + { + debug_printf("unimplemented vertex fetch type %u\n", (uint32)fetchType.value()); + cemu_assert(false); + } } + layout->setStride(bufferStride); } auto mtlVertexShader = static_cast(vertexShader->shader);