From 2ec9c00dc6e2e6209a2463d257d8a80fca030e35 Mon Sep 17 00:00:00 2001 From: Fabio Arnold Date: Mon, 16 Mar 2026 22:09:24 +0100 Subject: [PATCH] Metal: convert triangle fan to triangle list --- src/Cafe/HW/Latte/Core/LatteIndices.cpp | 67 ++++++++++++------- .../HW/Latte/Renderer/Metal/LatteToMtl.cpp | 2 +- 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteIndices.cpp b/src/Cafe/HW/Latte/Core/LatteIndices.cpp index 260c6cd6..77f66581 100644 --- a/src/Cafe/HW/Latte/Core/LatteIndices.cpp +++ b/src/Cafe/HW/Latte/Core/LatteIndices.cpp @@ -117,16 +117,22 @@ uint32 LatteIndices_calculateIndexOutputSize(LattePrimitiveMode primitiveMode, L } else if (primitiveMode == LattePrimitiveMode::TRIANGLE_FAN && g_renderer->GetType() == RendererAPI::Metal) { + // Metal doesn't support triangle fan -> convert to triangle list + if (count <= 2) + { + return 0; + } + uint32 numTriangles = count - 2; if (indexType == LatteIndexType::AUTO) { if (count <= 0xFFFF) - return count * sizeof(uint16); - return count * sizeof(uint32); + return numTriangles * 3 * sizeof(uint16); + return numTriangles * 3 * sizeof(uint32); } if (indexType == LatteIndexType::U16_BE || indexType == LatteIndexType::U16_LE) - return count * sizeof(uint16); + return numTriangles * 3 * sizeof(uint16); if (indexType == LatteIndexType::U32_BE || indexType == LatteIndexType::U32_LE) - return count * sizeof(uint32); + return numTriangles * 3 * sizeof(uint32); cemu_assert_suspicious(); return 0; } @@ -326,36 +332,46 @@ void LatteIndices_generateAutoLineLoopIndices(void* indexDataOutput, uint32 coun template void LatteIndices_unpackTriangleFanAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) { + if (count <= 2) + return; + sint32 numTriangles = count - 2; const betype* src = (betype*)indexDataInput; + T idx0 = src[0]; + indexMin = std::min(indexMin, (uint32)idx0); + indexMax = std::max(indexMax, (uint32)idx0); T* dst = (T*)indexDataOutput; - // TODO: check this - for (sint32 i = 0; i < count; i++) + for (sint32 i = 0; i < numTriangles; i++) { - uint32 i0; - if (i % 2 == 0) - i0 = i / 2; - else - i0 = count - 1 - i / 2; - T idx = src[i0]; - indexMin = std::min(indexMin, (uint32)idx); - indexMax = std::max(indexMax, (uint32)idx); - dst[i] = idx; + T idx1 = src[1]; + T idx2 = src[2]; + indexMin = std::min(indexMin, (uint32)idx1); + indexMax = std::max(indexMax, (uint32)idx1); + indexMin = std::min(indexMin, (uint32)idx2); + indexMax = std::max(indexMax, (uint32)idx2); + dst[0] = idx0; + dst[1] = idx1; + dst[2] = idx2; + src += 1; + dst += 3; } } template void LatteIndices_generateAutoTriangleFanIndices(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) { - const betype* src = (betype*)indexDataInput; + if (count <= 2) + return; + sint32 numTriangles = count - 2; T* dst = (T*)indexDataOutput; - for (sint32 i = 0; i < count; i++) + for (sint32 i = 0; i < numTriangles; i++) { - T idx = i; - if (idx % 2 == 0) - idx = idx / 2; - else - idx = count - 1 - idx / 2; - dst[i] = idx; + T idx0 = 0; + T idx1 = i + 1; + T idx2 = i + 2; + dst[0] = idx0; + dst[1] = idx1; + dst[2] = idx2; + dst += 3; } indexMin = 0; indexMax = std::max(count, 1u) - 1; @@ -868,7 +884,10 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32 LatteIndices_unpackTriangleFanAndConvert(indexData, indexOutputPtr, count, indexMin, indexMax); else cemu_assert_debug(false); - outputCount = count; + if (count >= 2) + outputCount = (count - 2) * 3; + else + outputCount = 0; } else { diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp index 7bf295df..28404ba6 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp @@ -244,7 +244,7 @@ MTL::PrimitiveType GetMtlPrimitiveType(LattePrimitiveMode primitiveMode) case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLES: return MTL::PrimitiveTypeTriangle; case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_FAN: - return MTL::PrimitiveTypeTriangleStrip; + return MTL::PrimitiveTypeTriangle; // triangle fans are emulated as a triangle list case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_STRIP: return MTL::PrimitiveTypeTriangleStrip; case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUADS: