Metal: convert triangle fan to triangle list

This commit is contained in:
Fabio Arnold 2026-03-16 22:09:24 +01:00
parent 2913a8ca7a
commit 2ec9c00dc6
2 changed files with 44 additions and 25 deletions

View File

@ -117,16 +117,22 @@ uint32 LatteIndices_calculateIndexOutputSize(LattePrimitiveMode primitiveMode, L
} }
else if (primitiveMode == LattePrimitiveMode::TRIANGLE_FAN && g_renderer->GetType() == RendererAPI::Metal) 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 (indexType == LatteIndexType::AUTO)
{ {
if (count <= 0xFFFF) if (count <= 0xFFFF)
return count * sizeof(uint16); return numTriangles * 3 * sizeof(uint16);
return count * sizeof(uint32); return numTriangles * 3 * sizeof(uint32);
} }
if (indexType == LatteIndexType::U16_BE || indexType == LatteIndexType::U16_LE) 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) if (indexType == LatteIndexType::U32_BE || indexType == LatteIndexType::U32_LE)
return count * sizeof(uint32); return numTriangles * 3 * sizeof(uint32);
cemu_assert_suspicious(); cemu_assert_suspicious();
return 0; return 0;
} }
@ -326,36 +332,46 @@ void LatteIndices_generateAutoLineLoopIndices(void* indexDataOutput, uint32 coun
template<typename T> template<typename T>
void LatteIndices_unpackTriangleFanAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_unpackTriangleFanAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)
{ {
if (count <= 2)
return;
sint32 numTriangles = count - 2;
const betype<T>* src = (betype<T>*)indexDataInput; const betype<T>* src = (betype<T>*)indexDataInput;
T idx0 = src[0];
indexMin = std::min(indexMin, (uint32)idx0);
indexMax = std::max(indexMax, (uint32)idx0);
T* dst = (T*)indexDataOutput; T* dst = (T*)indexDataOutput;
// TODO: check this for (sint32 i = 0; i < numTriangles; i++)
for (sint32 i = 0; i < count; i++)
{ {
uint32 i0; T idx1 = src[1];
if (i % 2 == 0) T idx2 = src[2];
i0 = i / 2; indexMin = std::min(indexMin, (uint32)idx1);
else indexMax = std::max(indexMax, (uint32)idx1);
i0 = count - 1 - i / 2; indexMin = std::min(indexMin, (uint32)idx2);
T idx = src[i0]; indexMax = std::max(indexMax, (uint32)idx2);
indexMin = std::min(indexMin, (uint32)idx); dst[0] = idx0;
indexMax = std::max(indexMax, (uint32)idx); dst[1] = idx1;
dst[i] = idx; dst[2] = idx2;
src += 1;
dst += 3;
} }
} }
template<typename T> template<typename T>
void LatteIndices_generateAutoTriangleFanIndices(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_generateAutoTriangleFanIndices(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)
{ {
const betype<T>* src = (betype<T>*)indexDataInput; if (count <= 2)
return;
sint32 numTriangles = count - 2;
T* dst = (T*)indexDataOutput; T* dst = (T*)indexDataOutput;
for (sint32 i = 0; i < count; i++) for (sint32 i = 0; i < numTriangles; i++)
{ {
T idx = i; T idx0 = 0;
if (idx % 2 == 0) T idx1 = i + 1;
idx = idx / 2; T idx2 = i + 2;
else dst[0] = idx0;
idx = count - 1 - idx / 2; dst[1] = idx1;
dst[i] = idx; dst[2] = idx2;
dst += 3;
} }
indexMin = 0; indexMin = 0;
indexMax = std::max(count, 1u) - 1; indexMax = std::max(count, 1u) - 1;
@ -868,7 +884,10 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
LatteIndices_unpackTriangleFanAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_unpackTriangleFanAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);
else else
cemu_assert_debug(false); cemu_assert_debug(false);
outputCount = count; if (count >= 2)
outputCount = (count - 2) * 3;
else
outputCount = 0;
} }
else else
{ {

View File

@ -244,7 +244,7 @@ MTL::PrimitiveType GetMtlPrimitiveType(LattePrimitiveMode primitiveMode)
case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLES: case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLES:
return MTL::PrimitiveTypeTriangle; return MTL::PrimitiveTypeTriangle;
case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_FAN: 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: case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_STRIP:
return MTL::PrimitiveTypeTriangleStrip; return MTL::PrimitiveTypeTriangleStrip;
case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUADS: case Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUADS: