Latte: Remove calculation of unused minIndex

This commit is contained in:
Exzap 2026-06-21 12:38:36 +02:00
parent 57bc919e7c
commit e142fadfcd
8 changed files with 70 additions and 142 deletions

View File

@ -168,7 +168,7 @@ void LatteCP_ProcessRingbuffer();
// buffer cache // buffer cache
void LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, uint32 attribBufferDirtyMask, uint32 vsUniformBufferDirtyMask, uint32 psUniformBufferDirtyMask, uint32 gsUniformBufferDirtyMask, uint8& stageUniformModifiedMask, bool isIncremental = false); void LatteBufferCache_Sync(uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, uint32 attribBufferDirtyMask, uint32 vsUniformBufferDirtyMask, uint32 psUniformBufferDirtyMask, uint32 gsUniformBufferDirtyMask, uint8& stageUniformModifiedMask, bool isIncremental = false);
bool LatteBufferCache_LoadRemappedUniforms(struct LatteDecompilerShader* shader, float* uniformData, bool aluConstDirty, uint32 uniformBufferDirtyMask); bool LatteBufferCache_LoadRemappedUniforms(struct LatteDecompilerShader* shader, float* uniformData, bool aluConstDirty, uint32 uniformBufferDirtyMask);
void LatteRenderTarget_updateViewport(); void LatteRenderTarget_updateViewport();

View File

@ -185,7 +185,7 @@ void LatteBufferCache_ProcessQueues()
} }
// upload vertex and uniform buffers and update bindings // upload vertex and uniform buffers and update bindings
void LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, uint32 attribBufferDirtyMask, uint32 vsUniformBufferDirtyMask, uint32 psUniformBufferDirtyMask, uint32 gsUniformBufferDirtyMask, uint8& stageUniformModifiedMask, bool isIncremental) void LatteBufferCache_Sync(uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, uint32 attribBufferDirtyMask, uint32 vsUniformBufferDirtyMask, uint32 psUniformBufferDirtyMask, uint32 gsUniformBufferDirtyMask, uint8& stageUniformModifiedMask, bool isIncremental)
{ {
LatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader(); LatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader();
cemu_assert_debug(parsedFetchShader); cemu_assert_debug(parsedFetchShader);

View File

@ -21,7 +21,6 @@ struct
LatteIndexType lastIndexType; LatteIndexType lastIndexType;
uint64 lastUsed; uint64 lastUsed;
// output // output
uint32 indexMin;
uint32 indexMax; uint32 indexMax;
Renderer::INDEX_TYPE renderIndexType; Renderer::INDEX_TYPE renderIndexType;
uint32 outputCount; uint32 outputCount;
@ -140,7 +139,7 @@ uint32 LatteIndices_calculateIndexOutputSize(LattePrimitiveMode primitiveMode, L
} }
template<typename T> template<typename T>
void LatteIndices_convertBE(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_convertBE(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
const betype<T>* src = (betype<T>*)indexDataInput; const betype<T>* src = (betype<T>*)indexDataInput;
T* dst = (T*)indexDataOutput; T* dst = (T*)indexDataOutput;
@ -148,7 +147,6 @@ void LatteIndices_convertBE(const void* indexDataInput, void* indexDataOutput, u
{ {
T v = *src; T v = *src;
*dst = v; *dst = v;
indexMin = std::min(indexMin, (uint32)v);
indexMax = std::max(indexMax, (uint32)v); indexMax = std::max(indexMax, (uint32)v);
dst++; dst++;
src++; src++;
@ -156,7 +154,7 @@ void LatteIndices_convertBE(const void* indexDataInput, void* indexDataOutput, u
} }
template<typename T> template<typename T>
void LatteIndices_convertLE(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_convertLE(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
const T* src = (T*)indexDataInput; const T* src = (T*)indexDataInput;
T* dst = (T*)indexDataOutput; T* dst = (T*)indexDataOutput;
@ -164,7 +162,6 @@ void LatteIndices_convertLE(const void* indexDataInput, void* indexDataOutput, u
{ {
T v = *src; T v = *src;
*dst = v; *dst = v;
indexMin = std::min(indexMin, (uint32)v);
indexMax = std::max(indexMax, (uint32)v); indexMax = std::max(indexMax, (uint32)v);
dst++; dst++;
src++; src++;
@ -172,7 +169,7 @@ void LatteIndices_convertLE(const void* indexDataInput, void* indexDataOutput, u
} }
template<typename T> template<typename T>
void LatteIndices_unpackQuadsAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_unpackQuadsAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
sint32 numQuads = count / 4; sint32 numQuads = count / 4;
const betype<T>* src = (betype<T>*)indexDataInput; const betype<T>* src = (betype<T>*)indexDataInput;
@ -183,13 +180,9 @@ void LatteIndices_unpackQuadsAndConvert(const void* indexDataInput, void* indexD
T idx1 = src[1]; T idx1 = src[1];
T idx2 = src[2]; T idx2 = src[2];
T idx3 = src[3]; T idx3 = src[3];
indexMin = std::min(indexMin, (uint32)idx0);
indexMax = std::max(indexMax, (uint32)idx0); indexMax = std::max(indexMax, (uint32)idx0);
indexMin = std::min(indexMin, (uint32)idx1);
indexMax = std::max(indexMax, (uint32)idx1); indexMax = std::max(indexMax, (uint32)idx1);
indexMin = std::min(indexMin, (uint32)idx2);
indexMax = std::max(indexMax, (uint32)idx2); indexMax = std::max(indexMax, (uint32)idx2);
indexMin = std::min(indexMin, (uint32)idx3);
indexMax = std::max(indexMax, (uint32)idx3); indexMax = std::max(indexMax, (uint32)idx3);
dst[0] = idx0; dst[0] = idx0;
dst[1] = idx1; dst[1] = idx1;
@ -203,7 +196,7 @@ void LatteIndices_unpackQuadsAndConvert(const void* indexDataInput, void* indexD
} }
template<typename T> template<typename T>
void LatteIndices_generateAutoQuadIndices(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_generateAutoQuadIndices(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
sint32 numQuads = count / 4; sint32 numQuads = count / 4;
const betype<T>* src = (betype<T>*)indexDataInput; const betype<T>* src = (betype<T>*)indexDataInput;
@ -223,12 +216,11 @@ void LatteIndices_generateAutoQuadIndices(const void* indexDataInput, void* inde
src += 4; src += 4;
dst += 6; dst += 6;
} }
indexMin = 0;
indexMax = std::max(count, 1u) - 1; indexMax = std::max(count, 1u) - 1;
} }
template<typename T> template<typename T>
void LatteIndices_unpackQuadStripAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_unpackQuadStripAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
if (count <= 3) if (count <= 3)
return; return;
@ -241,13 +233,9 @@ void LatteIndices_unpackQuadStripAndConvert(const void* indexDataInput, void* in
T idx1 = src[1]; T idx1 = src[1];
T idx2 = src[2]; T idx2 = src[2];
T idx3 = src[3]; T idx3 = src[3];
indexMin = std::min(indexMin, (uint32)idx0);
indexMax = std::max(indexMax, (uint32)idx0); indexMax = std::max(indexMax, (uint32)idx0);
indexMin = std::min(indexMin, (uint32)idx1);
indexMax = std::max(indexMax, (uint32)idx1); indexMax = std::max(indexMax, (uint32)idx1);
indexMin = std::min(indexMin, (uint32)idx2);
indexMax = std::max(indexMax, (uint32)idx2); indexMax = std::max(indexMax, (uint32)idx2);
indexMin = std::min(indexMin, (uint32)idx3);
indexMax = std::max(indexMax, (uint32)idx3); indexMax = std::max(indexMax, (uint32)idx3);
dst[0] = idx0; dst[0] = idx0;
dst[1] = idx1; dst[1] = idx1;
@ -261,7 +249,7 @@ void LatteIndices_unpackQuadStripAndConvert(const void* indexDataInput, void* in
} }
template<typename T> template<typename T>
void LatteIndices_unpackLineLoopAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_unpackLineLoopAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
if (count <= 0) if (count <= 0)
return; return;
@ -271,7 +259,6 @@ void LatteIndices_unpackLineLoopAndConvert(const void* indexDataInput, void* ind
for (sint32 i = 0; i < (sint32)count; i++) for (sint32 i = 0; i < (sint32)count; i++)
{ {
T idx = *src; T idx = *src;
indexMin = std::min(indexMin, (uint32)idx);
indexMax = std::max(indexMax, (uint32)idx); indexMax = std::max(indexMax, (uint32)idx);
*dst = idx; *dst = idx;
src++; src++;
@ -281,7 +268,7 @@ void LatteIndices_unpackLineLoopAndConvert(const void* indexDataInput, void* ind
} }
template<typename T> template<typename T>
void LatteIndices_generateAutoQuadStripIndices(void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_generateAutoQuadStripIndices(void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
if (count <= 3) if (count <= 3)
return; return;
@ -301,13 +288,12 @@ void LatteIndices_generateAutoQuadStripIndices(void* indexDataOutput, uint32 cou
dst[5] = idx3; dst[5] = idx3;
dst += 6; dst += 6;
} }
indexMin = 0;
indexMax = std::max(count, 1u) - 1; indexMax = std::max(count, 1u) - 1;
} }
template<typename T> template<typename T>
void LatteIndices_generateAutoLineLoopIndices(void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_generateAutoLineLoopIndices(void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
if (count == 0) if (count == 0)
return; return;
@ -319,12 +305,11 @@ void LatteIndices_generateAutoLineLoopIndices(void* indexDataOutput, uint32 coun
} }
*dst = 0; *dst = 0;
dst++; dst++;
indexMin = 0;
indexMax = std::max(count, 1u) - 1; indexMax = std::max(count, 1u) - 1;
} }
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& indexMax)
{ {
const betype<T>* src = (betype<T>*)indexDataInput; const betype<T>* src = (betype<T>*)indexDataInput;
T* dst = (T*)indexDataOutput; T* dst = (T*)indexDataOutput;
@ -337,14 +322,13 @@ void LatteIndices_unpackTriangleFanAndConvert(const void* indexDataInput, void*
else else
i0 = count - 1 - i / 2; i0 = count - 1 - i / 2;
T idx = src[i0]; T idx = src[i0];
indexMin = std::min(indexMin, (uint32)idx);
indexMax = std::max(indexMax, (uint32)idx); indexMax = std::max(indexMax, (uint32)idx);
dst[i] = idx; dst[i] = idx;
} }
} }
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& indexMax)
{ {
const betype<T>* src = (betype<T>*)indexDataInput; const betype<T>* src = (betype<T>*)indexDataInput;
T* dst = (T*)indexDataOutput; T* dst = (T*)indexDataOutput;
@ -357,13 +341,12 @@ void LatteIndices_generateAutoTriangleFanIndices(const void* indexDataInput, voi
idx = count - 1 - idx / 2; idx = count - 1 - idx / 2;
dst[i] = idx; dst[i] = idx;
} }
indexMin = 0;
indexMax = std::max(count, 1u) - 1; indexMax = std::max(count, 1u) - 1;
} }
#if defined(ARCH_X86_64) #if defined(ARCH_X86_64)
ATTRIBUTE_AVX2 ATTRIBUTE_AVX2
void LatteIndices_fastConvertU16_AVX2(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_fastConvertU16_AVX2(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
// using AVX + AVX2 we can process 16 indices at a time // using AVX + AVX2 we can process 16 indices at a time
const uint16* indicesU16BE = (const uint16*)indexDataInput; const uint16* indicesU16BE = (const uint16*)indexDataInput;
@ -385,33 +368,23 @@ void LatteIndices_fastConvertU16_AVX2(const void* indexDataInput, void* indexDat
// endian swap // endian swap
mIndexData = _mm256_shuffle_epi8(mIndexData, mShuffle16Swap); mIndexData = _mm256_shuffle_epi8(mIndexData, mShuffle16Swap);
_mm256_store_si256((__m256i*)indexOutput, mIndexData); _mm256_store_si256((__m256i*)indexOutput, mIndexData);
mMin = _mm256_min_epu16(mIndexData, mMin);
mMax = _mm256_max_epu16(mIndexData, mMax); mMax = _mm256_max_epu16(mIndexData, mMax);
indexOutput += 16; indexOutput += 16;
} while (--count16); } while (--count16);
// fold 32 to 16 byte // fold 32 to 16 byte
mMin = _mm256_min_epu16(mMin, _mm256_permute2x128_si256(mMin, mMin, 1));
mMax = _mm256_max_epu16(mMax, _mm256_permute2x128_si256(mMax, mMax, 1)); mMax = _mm256_max_epu16(mMax, _mm256_permute2x128_si256(mMax, mMax, 1));
// fold 16 to 8 byte // fold 16 to 8 byte
mMin = _mm256_min_epu16(mMin, _mm256_shuffle_epi32(mMin, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6)));
mMax = _mm256_max_epu16(mMax, _mm256_shuffle_epi32(mMax, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6))); mMax = _mm256_max_epu16(mMax, _mm256_shuffle_epi32(mMax, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6)));
uint16* mMinU16 = (uint16*)&mMin;
uint16* mMaxU16 = (uint16*)&mMax; uint16* mMaxU16 = (uint16*)&mMax;
indexMin = std::min(indexMin, (uint32)mMinU16[0]);
indexMin = std::min(indexMin, (uint32)mMinU16[1]);
indexMin = std::min(indexMin, (uint32)mMinU16[2]);
indexMin = std::min(indexMin, (uint32)mMinU16[3]);
indexMax = std::max(indexMax, (uint32)mMaxU16[0]); indexMax = std::max(indexMax, (uint32)mMaxU16[0]);
indexMax = std::max(indexMax, (uint32)mMaxU16[1]); indexMax = std::max(indexMax, (uint32)mMaxU16[1]);
indexMax = std::max(indexMax, (uint32)mMaxU16[2]); indexMax = std::max(indexMax, (uint32)mMaxU16[2]);
indexMax = std::max(indexMax, (uint32)mMaxU16[3]); indexMax = std::max(indexMax, (uint32)mMaxU16[3]);
} }
// process remaining indices // process remaining indices
uint32 _minIndex = 0xFFFFFFFF;
uint32 _maxIndex = 0; uint32 _maxIndex = 0;
for (sint32 i = countRemaining; (--i) >= 0;) for (sint32 i = countRemaining; (--i) >= 0;)
{ {
@ -420,15 +393,13 @@ void LatteIndices_fastConvertU16_AVX2(const void* indexDataInput, void* indexDat
indexOutput++; indexOutput++;
indicesU16BE++; indicesU16BE++;
_maxIndex = std::max(_maxIndex, (uint32)idx); _maxIndex = std::max(_maxIndex, (uint32)idx);
_minIndex = std::min(_minIndex, (uint32)idx);
} }
// update min/max // update max
indexMax = std::max(indexMax, _maxIndex); indexMax = std::max(indexMax, _maxIndex);
indexMin = std::min(indexMin, _minIndex);
} }
ATTRIBUTE_SSE41 ATTRIBUTE_SSE41
void LatteIndices_fastConvertU16_SSE41(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_fastConvertU16_SSE41(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
// SSSE3 & SSE4.1 optimized decoding // SSSE3 & SSE4.1 optimized decoding
const uint16* indicesU16BE = (const uint16*)indexDataInput; const uint16* indicesU16BE = (const uint16*)indexDataInput;
@ -437,7 +408,6 @@ void LatteIndices_fastConvertU16_SSE41(const void* indexDataInput, void* indexDa
sint32 countRemaining = count & 7; sint32 countRemaining = count & 7;
if (count8) if (count8)
{ {
__m128i mMin = _mm_set_epi16((short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF);
__m128i mMax = _mm_set_epi16(0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000); __m128i mMax = _mm_set_epi16(0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000);
__m128i mTemp; __m128i mTemp;
__m128i* mRawIndices = (__m128i*)indicesU16BE; __m128i* mRawIndices = (__m128i*)indicesU16BE;
@ -450,14 +420,12 @@ void LatteIndices_fastConvertU16_SSE41(const void* indexDataInput, void* indexDa
mTemp = _mm_loadu_si128(mRawIndices); mTemp = _mm_loadu_si128(mRawIndices);
mRawIndices++; mRawIndices++;
mTemp = _mm_shuffle_epi8(mTemp, shufmask); mTemp = _mm_shuffle_epi8(mTemp, shufmask);
mMin = _mm_min_epu16(mMin, mTemp);
mMax = _mm_max_epu16(mMax, mTemp); mMax = _mm_max_epu16(mMax, mTemp);
_mm_store_si128(mOutputIndices, mTemp); _mm_store_si128(mOutputIndices, mTemp);
mOutputIndices++; mOutputIndices++;
} }
uint16* mMaxU16 = (uint16*)&mMax; uint16* mMaxU16 = (uint16*)&mMax;
uint16* mMinU16 = (uint16*)&mMin;
indexMax = std::max(indexMax, (uint32)mMaxU16[0]); indexMax = std::max(indexMax, (uint32)mMaxU16[0]);
indexMax = std::max(indexMax, (uint32)mMaxU16[1]); indexMax = std::max(indexMax, (uint32)mMaxU16[1]);
@ -467,16 +435,7 @@ void LatteIndices_fastConvertU16_SSE41(const void* indexDataInput, void* indexDa
indexMax = std::max(indexMax, (uint32)mMaxU16[5]); indexMax = std::max(indexMax, (uint32)mMaxU16[5]);
indexMax = std::max(indexMax, (uint32)mMaxU16[6]); indexMax = std::max(indexMax, (uint32)mMaxU16[6]);
indexMax = std::max(indexMax, (uint32)mMaxU16[7]); indexMax = std::max(indexMax, (uint32)mMaxU16[7]);
indexMin = std::min(indexMin, (uint32)mMinU16[0]);
indexMin = std::min(indexMin, (uint32)mMinU16[1]);
indexMin = std::min(indexMin, (uint32)mMinU16[2]);
indexMin = std::min(indexMin, (uint32)mMinU16[3]);
indexMin = std::min(indexMin, (uint32)mMinU16[4]);
indexMin = std::min(indexMin, (uint32)mMinU16[5]);
indexMin = std::min(indexMin, (uint32)mMinU16[6]);
indexMin = std::min(indexMin, (uint32)mMinU16[7]);
} }
uint32 _minIndex = 0xFFFFFFFF;
uint32 _maxIndex = 0; uint32 _maxIndex = 0;
for (sint32 i = countRemaining; (--i) >= 0;) for (sint32 i = countRemaining; (--i) >= 0;)
{ {
@ -485,14 +444,12 @@ void LatteIndices_fastConvertU16_SSE41(const void* indexDataInput, void* indexDa
indexOutput++; indexOutput++;
indicesU16BE++; indicesU16BE++;
_maxIndex = std::max(_maxIndex, (uint32)idx); _maxIndex = std::max(_maxIndex, (uint32)idx);
_minIndex = std::min(_minIndex, (uint32)idx);
} }
indexMax = std::max(indexMax, _maxIndex); indexMax = std::max(indexMax, _maxIndex);
indexMin = std::min(indexMin, _minIndex);
} }
ATTRIBUTE_AVX2 ATTRIBUTE_AVX2
void LatteIndices_fastConvertU32_AVX2(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_fastConvertU32_AVX2(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
// using AVX + AVX2 we can process 8 indices at a time // using AVX + AVX2 we can process 8 indices at a time
const uint32* indicesU32BE = (const uint32*)indexDataInput; const uint32* indicesU32BE = (const uint32*)indexDataInput;
@ -501,7 +458,6 @@ void LatteIndices_fastConvertU32_AVX2(const void* indexDataInput, void* indexDat
sint32 countRemaining = count & 7; sint32 countRemaining = count & 7;
if (count8) if (count8)
{ {
__m256i mMin = _mm256_set_epi32((sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF);
__m256i mMax = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, 0); __m256i mMax = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, 0);
__m256i mShuffle32Swap = _mm256_set_epi8(28,29,30,31, __m256i mShuffle32Swap = _mm256_set_epi8(28,29,30,31,
24,25,26,27, 24,25,26,27,
@ -520,29 +476,20 @@ void LatteIndices_fastConvertU32_AVX2(const void* indexDataInput, void* indexDat
// endian swap // endian swap
mIndexData = _mm256_shuffle_epi8(mIndexData, mShuffle32Swap); mIndexData = _mm256_shuffle_epi8(mIndexData, mShuffle32Swap);
_mm256_store_si256((__m256i*)indexOutput, mIndexData); _mm256_store_si256((__m256i*)indexOutput, mIndexData);
mMin = _mm256_min_epu32(mIndexData, mMin);
mMax = _mm256_max_epu32(mIndexData, mMax); mMax = _mm256_max_epu32(mIndexData, mMax);
indexOutput += 8; indexOutput += 8;
} while (--count8); } while (--count8);
// fold 32 to 16 byte // fold 32 to 16 byte
mMin = _mm256_min_epu32(mMin, _mm256_permute2x128_si256(mMin, mMin, 1));
mMax = _mm256_max_epu32(mMax, _mm256_permute2x128_si256(mMax, mMax, 1)); mMax = _mm256_max_epu32(mMax, _mm256_permute2x128_si256(mMax, mMax, 1));
// fold 16 to 8 byte // fold 16 to 8 byte
mMin = _mm256_min_epu32(mMin, _mm256_shuffle_epi32(mMin, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6)));
mMax = _mm256_max_epu32(mMax, _mm256_shuffle_epi32(mMax, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6))); mMax = _mm256_max_epu32(mMax, _mm256_shuffle_epi32(mMax, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6)));
uint32* mMinU32 = (uint32*)&mMin;
uint32* mMaxU32 = (uint32*)&mMax; uint32* mMaxU32 = (uint32*)&mMax;
indexMin = std::min(indexMin, (uint32)mMinU32[0]);
indexMin = std::min(indexMin, (uint32)mMinU32[1]);
indexMax = std::max(indexMax, (uint32)mMaxU32[0]); indexMax = std::max(indexMax, (uint32)mMaxU32[0]);
indexMax = std::max(indexMax, (uint32)mMaxU32[1]); indexMax = std::max(indexMax, (uint32)mMaxU32[1]);
} }
// process remaining indices // process remaining indices
uint32 _minIndex = 0xFFFFFFFF;
uint32 _maxIndex = 0; uint32 _maxIndex = 0;
for (sint32 i = countRemaining; (--i) >= 0;) for (sint32 i = countRemaining; (--i) >= 0;)
{ {
@ -551,15 +498,13 @@ void LatteIndices_fastConvertU32_AVX2(const void* indexDataInput, void* indexDat
indexOutput++; indexOutput++;
indicesU32BE++; indicesU32BE++;
_maxIndex = std::max(_maxIndex, (uint32)idx); _maxIndex = std::max(_maxIndex, (uint32)idx);
_minIndex = std::min(_minIndex, (uint32)idx);
} }
// update min/max // update min/max
indexMax = std::max(indexMax, _maxIndex); indexMax = std::max(indexMax, _maxIndex);
indexMin = std::min(indexMin, _minIndex);
} }
#elif defined(__aarch64__) #elif defined(__aarch64__)
void LatteIndices_fastConvertU16_NEON(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_fastConvertU16_NEON(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
const uint16* indicesU16BE = (const uint16*)indexDataInput; const uint16* indicesU16BE = (const uint16*)indexDataInput;
uint16* indexOutput = (uint16*)indexDataOutput; uint16* indexOutput = (uint16*)indexDataOutput;
@ -568,7 +513,6 @@ void LatteIndices_fastConvertU16_NEON(const void* indexDataInput, void* indexDat
if (count8) if (count8)
{ {
uint16x8_t mMin = vdupq_n_u16(0xFFFF);
uint16x8_t mMax = vdupq_n_u16(0x0000); uint16x8_t mMax = vdupq_n_u16(0x0000);
uint16x8_t mTemp; uint16x8_t mTemp;
uint16x8_t* mRawIndices = (uint16x8_t*) indicesU16BE; uint16x8_t* mRawIndices = (uint16x8_t*) indicesU16BE;
@ -581,22 +525,18 @@ void LatteIndices_fastConvertU16_NEON(const void* indexDataInput, void* indexDat
mTemp = vld1q_u16((uint16*)mRawIndices); mTemp = vld1q_u16((uint16*)mRawIndices);
mRawIndices++; mRawIndices++;
mTemp = vrev16q_u8(mTemp); mTemp = vrev16q_u8(mTemp);
mMin = vminq_u16(mMin, mTemp);
mMax = vmaxq_u16(mMax, mTemp); mMax = vmaxq_u16(mMax, mTemp);
vst1q_u16((uint16*)mOutputIndices, mTemp); vst1q_u16((uint16*)mOutputIndices, mTemp);
mOutputIndices++; mOutputIndices++;
} }
uint16* mMaxU16 = (uint16*)&mMax; uint16* mMaxU16 = (uint16*)&mMax;
uint16* mMinU16 = (uint16*)&mMin;
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
indexMax = std::max(indexMax, (uint32)mMaxU16[i]); indexMax = std::max(indexMax, (uint32)mMaxU16[i]);
indexMin = std::min(indexMin, (uint32)mMinU16[i]);
} }
} }
// process remaining indices // process remaining indices
uint32 _minIndex = 0xFFFFFFFF;
uint32 _maxIndex = 0; uint32 _maxIndex = 0;
for (sint32 i = countRemaining; (--i) >= 0;) for (sint32 i = countRemaining; (--i) >= 0;)
{ {
@ -605,14 +545,12 @@ void LatteIndices_fastConvertU16_NEON(const void* indexDataInput, void* indexDat
indexOutput++; indexOutput++;
indicesU16BE++; indicesU16BE++;
_maxIndex = std::max(_maxIndex, (uint32)idx); _maxIndex = std::max(_maxIndex, (uint32)idx);
_minIndex = std::min(_minIndex, (uint32)idx);
} }
// update min/max // update min/max
indexMax = std::max(indexMax, _maxIndex); indexMax = std::max(indexMax, _maxIndex);
indexMin = std::min(indexMin, _minIndex);
} }
void LatteIndices_fastConvertU32_NEON(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_fastConvertU32_NEON(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMax)
{ {
const uint32* indicesU32BE = (const uint32*)indexDataInput; const uint32* indicesU32BE = (const uint32*)indexDataInput;
uint32* indexOutput = (uint32*)indexDataOutput; uint32* indexOutput = (uint32*)indexDataOutput;
@ -621,7 +559,6 @@ void LatteIndices_fastConvertU32_NEON(const void* indexDataInput, void* indexDat
if (count8) if (count8)
{ {
uint32x4_t mMin = vdupq_n_u32(0xFFFFFFFF);
uint32x4_t mMax = vdupq_n_u32(0x00000000); uint32x4_t mMax = vdupq_n_u32(0x00000000);
uint32x4_t mTemp; uint32x4_t mTemp;
uint32x4_t* mRawIndices = (uint32x4_t*) indicesU32BE; uint32x4_t* mRawIndices = (uint32x4_t*) indicesU32BE;
@ -634,22 +571,18 @@ void LatteIndices_fastConvertU32_NEON(const void* indexDataInput, void* indexDat
mTemp = vld1q_u32((uint32*)mRawIndices); mTemp = vld1q_u32((uint32*)mRawIndices);
mRawIndices++; mRawIndices++;
mTemp = vrev32q_u8(mTemp); mTemp = vrev32q_u8(mTemp);
mMin = vminq_u32(mMin, mTemp);
mMax = vmaxq_u32(mMax, mTemp); mMax = vmaxq_u32(mMax, mTemp);
vst1q_u32((uint32*)mOutputIndices, mTemp); vst1q_u32((uint32*)mOutputIndices, mTemp);
mOutputIndices++; mOutputIndices++;
} }
uint32* mMaxU32 = (uint32*)&mMax; uint32* mMaxU32 = (uint32*)&mMax;
uint32* mMinU32 = (uint32*)&mMin;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
indexMax = std::max(indexMax, mMaxU32[i]); indexMax = std::max(indexMax, mMaxU32[i]);
indexMin = std::min(indexMin, mMinU32[i]);
} }
} }
// process remaining indices // process remaining indices
uint32 _minIndex = 0xFFFFFFFF;
uint32 _maxIndex = 0; uint32 _maxIndex = 0;
for (sint32 i = countRemaining; (--i) >= 0;) for (sint32 i = countRemaining; (--i) >= 0;)
{ {
@ -658,21 +591,18 @@ void LatteIndices_fastConvertU32_NEON(const void* indexDataInput, void* indexDat
indexOutput++; indexOutput++;
indicesU32BE++; indicesU32BE++;
_maxIndex = std::max(_maxIndex, idx); _maxIndex = std::max(_maxIndex, idx);
_minIndex = std::min(_minIndex, idx);
} }
// update min/max // update min/max
indexMax = std::max(indexMax, _maxIndex); indexMax = std::max(indexMax, _maxIndex);
indexMin = std::min(indexMin, _minIndex);
} }
#endif #endif
template<typename T> template<typename T>
void _LatteIndices_alternativeCalculateIndexMinMax(const void* indexData, uint32 count, uint32 primitiveRestartIndex, uint32& indexMin, uint32& indexMax) void _LatteIndices_alternativeCalculateIndexMax(const void* indexData, uint32 count, uint32 primitiveRestartIndex, uint32& indexMax)
{ {
cemu_assert_debug(count != 0); cemu_assert_debug(count != 0);
const betype<T>* idxPtrT = (betype<T>*)indexData; const betype<T>* idxPtrT = (betype<T>*)indexData;
T _indexMin = *idxPtrT;
T _indexMax = *idxPtrT; T _indexMax = *idxPtrT;
cemu_assert_debug(primitiveRestartIndex <= std::numeric_limits<T>::max()); cemu_assert_debug(primitiveRestartIndex <= std::numeric_limits<T>::max());
T restartIndexT = (T)primitiveRestartIndex; T restartIndexT = (T)primitiveRestartIndex;
@ -681,23 +611,20 @@ void _LatteIndices_alternativeCalculateIndexMinMax(const void* indexData, uint32
T idx = *idxPtrT; T idx = *idxPtrT;
if (idx != restartIndexT) if (idx != restartIndexT)
{ {
_indexMin = std::min(_indexMin, idx);
_indexMax = std::max(_indexMax, idx); _indexMax = std::max(_indexMax, idx);
} }
idxPtrT++; idxPtrT++;
count--; count--;
} }
indexMin = _indexMin;
indexMax = _indexMax; indexMax = _indexMax;
} }
// calculate min and max index while taking primitive restart into account // calculate min and max index while taking primitive restart into account
// fallback implementation in case the fast path gives us invalid results // fallback implementation in case the fast path gives us invalid results
void LatteIndices_alternativeCalculateIndexMinMax(const void* indexData, LatteIndexType indexType, uint32 count, uint32& indexMin, uint32& indexMax) void LatteIndices_alternativeCalculateIndexMax(const void* indexData, LatteIndexType indexType, uint32 count, uint32& indexMax)
{ {
if (count == 0) if (count == 0)
{ {
indexMin = 0;
indexMax = 0; indexMax = 0;
return; return;
} }
@ -705,11 +632,11 @@ void LatteIndices_alternativeCalculateIndexMinMax(const void* indexData, LatteIn
if (indexType == LatteIndexType::U16_BE) if (indexType == LatteIndexType::U16_BE)
{ {
_LatteIndices_alternativeCalculateIndexMinMax<uint16>(indexData, count, primitiveRestartIndex, indexMin, indexMax); _LatteIndices_alternativeCalculateIndexMax<uint16>(indexData, count, primitiveRestartIndex, indexMax);
} }
else if (indexType == LatteIndexType::U32_BE) else if (indexType == LatteIndexType::U32_BE)
{ {
_LatteIndices_alternativeCalculateIndexMinMax<uint32>(indexData, count, primitiveRestartIndex, indexMin, indexMax); _LatteIndices_alternativeCalculateIndexMax<uint32>(indexData, count, primitiveRestartIndex, indexMax);
} }
else else
{ {
@ -717,7 +644,7 @@ void LatteIndices_alternativeCalculateIndexMinMax(const void* indexData, LatteIn
} }
} }
void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32 count, LattePrimitiveMode primitiveMode, uint32& indexMin, uint32& indexMax, Renderer::INDEX_TYPE& renderIndexType, uint32& outputCount, Renderer::IndexAllocation& indexAllocation) void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32 count, LattePrimitiveMode primitiveMode, uint32& indexMax, Renderer::INDEX_TYPE& renderIndexType, uint32& outputCount, Renderer::IndexAllocation& indexAllocation)
{ {
// what this should do: // what this should do:
// [x] use fast SIMD-based index decoding // [x] use fast SIMD-based index decoding
@ -733,7 +660,6 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
}); });
if (cacheEntry != LatteIndexCache.entry.end()) if (cacheEntry != LatteIndexCache.entry.end())
{ {
indexMin = cacheEntry->indexMin;
indexMax = cacheEntry->indexMax; indexMax = cacheEntry->indexMax;
renderIndexType = cacheEntry->renderIndexType; renderIndexType = cacheEntry->renderIndexType;
outputCount = cacheEntry->outputCount; outputCount = cacheEntry->outputCount;
@ -759,7 +685,6 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
if (indexOutputSize == 0) if (indexOutputSize == 0)
{ {
outputCount = count; outputCount = count;
indexMin = 0;
indexMax = std::max(count, 1u)-1; indexMax = std::max(count, 1u)-1;
renderIndexType = Renderer::INDEX_TYPE::NONE; renderIndexType = Renderer::INDEX_TYPE::NONE;
indexAllocation = {}; indexAllocation = {};
@ -770,7 +695,6 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
void* indexOutputPtr = indexAllocation.mem; void* indexOutputPtr = indexAllocation.mem;
// decode indices // decode indices
indexMin = std::numeric_limits<uint32>::max();
indexMax = std::numeric_limits<uint32>::min(); indexMax = std::numeric_limits<uint32>::min();
if (primitiveMode == LattePrimitiveMode::QUADS) if (primitiveMode == LattePrimitiveMode::QUADS)
{ {
@ -779,19 +703,19 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
{ {
if (count <= 0xFFFF) if (count <= 0xFFFF)
{ {
LatteIndices_generateAutoQuadIndices<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_generateAutoQuadIndices<uint16>(indexData, indexOutputPtr, count, indexMax);
renderIndexType = Renderer::INDEX_TYPE::U16; renderIndexType = Renderer::INDEX_TYPE::U16;
} }
else else
{ {
LatteIndices_generateAutoQuadIndices<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_generateAutoQuadIndices<uint32>(indexData, indexOutputPtr, count, indexMax);
renderIndexType = Renderer::INDEX_TYPE::U32; renderIndexType = Renderer::INDEX_TYPE::U32;
} }
} }
else if (indexType == LatteIndexType::U16_BE) else if (indexType == LatteIndexType::U16_BE)
LatteIndices_unpackQuadsAndConvert<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_unpackQuadsAndConvert<uint16>(indexData, indexOutputPtr, count, indexMax);
else if (indexType == LatteIndexType::U32_BE) else if (indexType == LatteIndexType::U32_BE)
LatteIndices_unpackQuadsAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_unpackQuadsAndConvert<uint32>(indexData, indexOutputPtr, count, indexMax);
else else
cemu_assert_debug(false); cemu_assert_debug(false);
outputCount = count / 4 * 6; outputCount = count / 4 * 6;
@ -803,19 +727,19 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
{ {
if (count <= 0xFFFF) if (count <= 0xFFFF)
{ {
LatteIndices_generateAutoQuadStripIndices<uint16>(indexOutputPtr, count, indexMin, indexMax); LatteIndices_generateAutoQuadStripIndices<uint16>(indexOutputPtr, count, indexMax);
renderIndexType = Renderer::INDEX_TYPE::U16; renderIndexType = Renderer::INDEX_TYPE::U16;
} }
else else
{ {
LatteIndices_generateAutoQuadStripIndices<uint32>(indexOutputPtr, count, indexMin, indexMax); LatteIndices_generateAutoQuadStripIndices<uint32>(indexOutputPtr, count, indexMax);
renderIndexType = Renderer::INDEX_TYPE::U32; renderIndexType = Renderer::INDEX_TYPE::U32;
} }
} }
else if (indexType == LatteIndexType::U16_BE) else if (indexType == LatteIndexType::U16_BE)
LatteIndices_unpackQuadStripAndConvert<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_unpackQuadStripAndConvert<uint16>(indexData, indexOutputPtr, count, indexMax);
else if (indexType == LatteIndexType::U32_BE) else if (indexType == LatteIndexType::U32_BE)
LatteIndices_unpackQuadStripAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_unpackQuadStripAndConvert<uint32>(indexData, indexOutputPtr, count, indexMax);
else else
cemu_assert_debug(false); cemu_assert_debug(false);
if (count >= 2) if (count >= 2)
@ -830,19 +754,19 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
{ {
if (count <= 0xFFFF) if (count <= 0xFFFF)
{ {
LatteIndices_generateAutoLineLoopIndices<uint16>(indexOutputPtr, count, indexMin, indexMax); LatteIndices_generateAutoLineLoopIndices<uint16>(indexOutputPtr, count, indexMax);
renderIndexType = Renderer::INDEX_TYPE::U16; renderIndexType = Renderer::INDEX_TYPE::U16;
} }
else else
{ {
LatteIndices_generateAutoLineLoopIndices<uint32>(indexOutputPtr, count, indexMin, indexMax); LatteIndices_generateAutoLineLoopIndices<uint32>(indexOutputPtr, count, indexMax);
renderIndexType = Renderer::INDEX_TYPE::U32; renderIndexType = Renderer::INDEX_TYPE::U32;
} }
} }
else if (indexType == LatteIndexType::U16_BE) else if (indexType == LatteIndexType::U16_BE)
LatteIndices_unpackLineLoopAndConvert<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_unpackLineLoopAndConvert<uint16>(indexData, indexOutputPtr, count, indexMax);
else if (indexType == LatteIndexType::U32_BE) else if (indexType == LatteIndexType::U32_BE)
LatteIndices_unpackLineLoopAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_unpackLineLoopAndConvert<uint32>(indexData, indexOutputPtr, count, indexMax);
else else
cemu_assert_debug(false); cemu_assert_debug(false);
outputCount = count + 1; outputCount = count + 1;
@ -853,19 +777,19 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
{ {
if (count <= 0xFFFF) if (count <= 0xFFFF)
{ {
LatteIndices_generateAutoTriangleFanIndices<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_generateAutoTriangleFanIndices<uint16>(indexData, indexOutputPtr, count, indexMax);
renderIndexType = Renderer::INDEX_TYPE::U16; renderIndexType = Renderer::INDEX_TYPE::U16;
} }
else else
{ {
LatteIndices_generateAutoTriangleFanIndices<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_generateAutoTriangleFanIndices<uint32>(indexData, indexOutputPtr, count, indexMax);
renderIndexType = Renderer::INDEX_TYPE::U32; renderIndexType = Renderer::INDEX_TYPE::U32;
} }
} }
else if (indexType == LatteIndexType::U16_BE) else if (indexType == LatteIndexType::U16_BE)
LatteIndices_unpackTriangleFanAndConvert<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_unpackTriangleFanAndConvert<uint16>(indexData, indexOutputPtr, count, indexMax);
else if (indexType == LatteIndexType::U32_BE) else if (indexType == LatteIndexType::U32_BE)
LatteIndices_unpackTriangleFanAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_unpackTriangleFanAndConvert<uint32>(indexData, indexOutputPtr, count, indexMax);
else else
cemu_assert_debug(false); cemu_assert_debug(false);
outputCount = count; outputCount = count;
@ -876,48 +800,48 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
{ {
#if defined(ARCH_X86_64) #if defined(ARCH_X86_64)
if (g_CPUFeatures.x86.avx2) if (g_CPUFeatures.x86.avx2)
LatteIndices_fastConvertU16_AVX2(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_fastConvertU16_AVX2(indexData, indexOutputPtr, count, indexMax);
else if (g_CPUFeatures.x86.sse4_1 && g_CPUFeatures.x86.ssse3) else if (g_CPUFeatures.x86.sse4_1 && g_CPUFeatures.x86.ssse3)
LatteIndices_fastConvertU16_SSE41(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_fastConvertU16_SSE41(indexData, indexOutputPtr, count, indexMax);
else else
LatteIndices_convertBE<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_convertBE<uint16>(indexData, indexOutputPtr, count, indexMax);
#elif defined(__aarch64__) #elif defined(__aarch64__)
LatteIndices_fastConvertU16_NEON(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_fastConvertU16_NEON(indexData, indexOutputPtr, count, indexMax);
#else #else
LatteIndices_convertBE<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_convertBE<uint16>(indexData, indexOutputPtr, count, indexMax);
#endif #endif
} }
else if (indexType == LatteIndexType::U32_BE) else if (indexType == LatteIndexType::U32_BE)
{ {
#if defined(ARCH_X86_64) #if defined(ARCH_X86_64)
if (g_CPUFeatures.x86.avx2) if (g_CPUFeatures.x86.avx2)
LatteIndices_fastConvertU32_AVX2(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_fastConvertU32_AVX2(indexData, indexOutputPtr, count, indexMax);
else else
LatteIndices_convertBE<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_convertBE<uint32>(indexData, indexOutputPtr, count, indexMax);
#elif defined(__aarch64__) #elif defined(__aarch64__)
LatteIndices_fastConvertU32_NEON(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_fastConvertU32_NEON(indexData, indexOutputPtr, count, indexMax);
#else #else
LatteIndices_convertBE<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_convertBE<uint32>(indexData, indexOutputPtr, count, indexMax);
#endif #endif
} }
else if (indexType == LatteIndexType::U16_LE) else if (indexType == LatteIndexType::U16_LE)
{ {
LatteIndices_convertLE<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_convertLE<uint16>(indexData, indexOutputPtr, count, indexMax);
} }
else if (indexType == LatteIndexType::U32_LE) else if (indexType == LatteIndexType::U32_LE)
{ {
LatteIndices_convertLE<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax); LatteIndices_convertLE<uint32>(indexData, indexOutputPtr, count, indexMax);
} }
else else
cemu_assert_debug(false); cemu_assert_debug(false);
outputCount = count; outputCount = count;
} }
// the above algorithms use a simplistic approach to get indexMin/indexMax // the above algorithms use a fast approach to get indexMax which does not filter out indices matching primitiveRestartIndex
// here we make sure primitive restart indices dont influence the index range // here we use a fallback in case the determined index equals the primitive restart index
if (primitiveRestartIndex == indexMin || primitiveRestartIndex == indexMax) if (primitiveRestartIndex == indexMax)
{ {
// recalculate index range but filter out primitive restart index // recalculate index range but filter out primitive restart index
LatteIndices_alternativeCalculateIndexMinMax(indexData, indexType, count, indexMin, indexMax); LatteIndices_alternativeCalculateIndexMax(indexData, indexType, count, indexMax);
} }
g_renderer->indexData_uploadIndexMemory(indexAllocation); g_renderer->indexData_uploadIndexMemory(indexAllocation);
performanceMonitor.cycle[performanceMonitor.cycleIndex].indexDataUploaded += indexOutputSize; performanceMonitor.cycle[performanceMonitor.cycleIndex].indexDataUploaded += indexOutputSize;
@ -934,7 +858,6 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
lruEntry->lastCount = count; lruEntry->lastCount = count;
lruEntry->lastPrimitiveMode = primitiveMode; lruEntry->lastPrimitiveMode = primitiveMode;
lruEntry->lastIndexType = indexType; lruEntry->lastIndexType = indexType;
lruEntry->indexMin = indexMin;
lruEntry->indexMax = indexMax; lruEntry->indexMax = indexMax;
lruEntry->renderIndexType = renderIndexType; lruEntry->renderIndexType = renderIndexType;
lruEntry->outputCount = outputCount; lruEntry->outputCount = outputCount;

View File

@ -4,4 +4,4 @@
void LatteIndices_invalidate(const void* memPtr, uint32 size); void LatteIndices_invalidate(const void* memPtr, uint32 size);
void LatteIndices_invalidateAll(); void LatteIndices_invalidateAll();
void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32 count, LattePrimitiveMode primitiveMode, uint32& indexMin, uint32& indexMax, Renderer::INDEX_TYPE& renderIndexType, uint32& outputCount, Renderer::IndexAllocation& indexAllocation); void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32 count, LattePrimitiveMode primitiveMode, uint32& indexMax, Renderer::INDEX_TYPE& renderIndexType, uint32& outputCount, Renderer::IndexAllocation& indexAllocation);

View File

@ -1142,10 +1142,9 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
// Index buffer // Index buffer
Renderer::INDEX_TYPE hostIndexType; Renderer::INDEX_TYPE hostIndexType;
uint32 hostIndexCount; uint32 hostIndexCount;
uint32 indexMin = 0;
uint32 indexMax = 0; uint32 indexMax = 0;
Renderer::IndexAllocation indexAllocation; Renderer::IndexAllocation indexAllocation;
LatteIndices_decode(memory_getPointerFromVirtualOffset(indexDataMPTR), indexType, count, primitiveMode, indexMin, indexMax, hostIndexType, hostIndexCount, indexAllocation); LatteIndices_decode(memory_getPointerFromVirtualOffset(indexDataMPTR), indexType, count, primitiveMode, indexMax, hostIndexType, hostIndexCount, indexAllocation);
auto indexAllocationMtl = static_cast<MetalSynchronizedHeapAllocator::AllocatorReservation*>(indexAllocation.rendererInternal); auto indexAllocationMtl = static_cast<MetalSynchronizedHeapAllocator::AllocatorReservation*>(indexAllocation.rendererInternal);
// Buffer cache // Buffer cache
@ -1165,7 +1164,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
// synchronize vertex and uniform cache and update buffer bindings // synchronize vertex and uniform cache and update buffer bindings
// We need to call this before getting the render command encoder, since it can cause buffer copies // We need to call this before getting the render command encoder, since it can cause buffer copies
uint8 stageUniformModifiedMask = 0; uint8 stageUniformModifiedMask = 0;
LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask); LatteBufferCache_Sync(indexMax + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask);
} }
// Render pass // Render pass

View File

@ -976,7 +976,7 @@ void OpenGLRenderer::draw_genericDrawHandler(uint32 baseVertex, uint32 baseInsta
// synchronize vertex and uniform buffers // synchronize vertex and uniform buffers
uint8 stageUniformModifiedMask = 0; uint8 stageUniformModifiedMask = 0;
LatteBufferCache_Sync(indexState.minIndex + baseVertex, indexState.maxIndex + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask); LatteBufferCache_Sync(indexState.maxIndex + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask);
_setupVertexAttributes(); _setupVertexAttributes();

View File

@ -58,6 +58,14 @@ void VulkanBenchmarkPrintResults()
cemuLog_log(LogType::Force, "--- Vulkan API CPU benchmark ---"); cemuLog_log(LogType::Force, "--- Vulkan API CPU benchmark ---");
cemuLog_log(LogType::Force, "Elapsed cycles this frame: {:} | Current cycle {:} | NumFunc {:}", elapsedCycles, currentCycle, s_vulkanBenchmarkFuncs.size()); cemuLog_log(LogType::Force, "Elapsed cycles this frame: {:} | Current cycle {:} | NumFunc {:}", elapsedCycles, currentCycle, s_vulkanBenchmarkFuncs.size());
// sum up total time of Vulkan calls
uint64 totalVkCycles = 0;
for (auto& it : s_vulkanBenchmarkFuncs)
{
totalVkCycles += it->cycles;
}
cemuLog_log(LogType::Force, "Total Vulkan time: {:.4}%", ((double)totalVkCycles / elapsedCyclesDbl) * 100.0);
std::vector<sint32> sortedIndices(s_vulkanBenchmarkFuncs.size()); std::vector<sint32> sortedIndices(s_vulkanBenchmarkFuncs.size());
std::iota(sortedIndices.begin(), sortedIndices.end(), 0); std::iota(sortedIndices.begin(), sortedIndices.end(), 0);
std::sort(sortedIndices.begin(), sortedIndices.end(), std::sort(sortedIndices.begin(), sortedIndices.end(),

View File

@ -1368,10 +1368,9 @@ void VulkanRenderer::draw_execute_first(uint32 baseVertex, uint32 baseInstance,
Renderer::INDEX_TYPE hostIndexType; Renderer::INDEX_TYPE hostIndexType;
uint32 hostIndexCount; uint32 hostIndexCount;
uint32 indexMin = 0;
uint32 indexMax = 0; uint32 indexMax = 0;
Renderer::IndexAllocation indexAllocation; Renderer::IndexAllocation indexAllocation;
LatteIndices_decode(memory_getPointerFromVirtualOffset(indexDataMPTR), indexType, count, primitiveMode, indexMin, indexMax, hostIndexType, hostIndexCount, indexAllocation); LatteIndices_decode(memory_getPointerFromVirtualOffset(indexDataMPTR), indexType, count, primitiveMode, indexMax, hostIndexType, hostIndexCount, indexAllocation);
VKRSynchronizedHeapAllocator::AllocatorReservation* indexReservation = (VKRSynchronizedHeapAllocator::AllocatorReservation*)indexAllocation.rendererInternal; VKRSynchronizedHeapAllocator::AllocatorReservation* indexReservation = (VKRSynchronizedHeapAllocator::AllocatorReservation*)indexAllocation.rendererInternal;
// update index binding // update index binding
if (hostIndexType != INDEX_TYPE::NONE) if (hostIndexType != INDEX_TYPE::NONE)
@ -1412,7 +1411,7 @@ void VulkanRenderer::draw_execute_first(uint32 baseVertex, uint32 baseInstance,
{ {
// synchronize vertex and uniform cache and update buffer bindings // synchronize vertex and uniform cache and update buffer bindings
uint8 stageUniformModifiedMask = 0; uint8 stageUniformModifiedMask = 0;
LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask); LatteBufferCache_Sync(indexMax + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask);
} }
PipelineInfo* pipeline_info = draw_getOrCreateGraphicsPipeline(count); PipelineInfo* pipeline_info = draw_getOrCreateGraphicsPipeline(count);
@ -1537,10 +1536,9 @@ void VulkanRenderer::draw_execute_continued(uint32 baseVertex, uint32 baseInstan
Renderer::INDEX_TYPE hostIndexType; Renderer::INDEX_TYPE hostIndexType;
uint32 hostIndexCount; uint32 hostIndexCount;
uint32 indexMin = 0;
uint32 indexMax = 0; uint32 indexMax = 0;
Renderer::IndexAllocation indexAllocation; Renderer::IndexAllocation indexAllocation;
LatteIndices_decode(memory_getPointerFromVirtualOffset(indexDataMPTR), indexType, count, primitiveMode, indexMin, indexMax, hostIndexType, hostIndexCount, indexAllocation); LatteIndices_decode(memory_getPointerFromVirtualOffset(indexDataMPTR), indexType, count, primitiveMode, indexMax, hostIndexType, hostIndexCount, indexAllocation);
VKRSynchronizedHeapAllocator::AllocatorReservation* indexReservation = (VKRSynchronizedHeapAllocator::AllocatorReservation*)indexAllocation.rendererInternal; VKRSynchronizedHeapAllocator::AllocatorReservation* indexReservation = (VKRSynchronizedHeapAllocator::AllocatorReservation*)indexAllocation.rendererInternal;
// update index binding // update index binding
if (hostIndexType != INDEX_TYPE::NONE) if (hostIndexType != INDEX_TYPE::NONE)
@ -1580,7 +1578,7 @@ void VulkanRenderer::draw_execute_continued(uint32 baseVertex, uint32 baseInstan
else else
{ {
// synchronize vertex and uniform cache and update buffer bindings // synchronize vertex and uniform cache and update buffer bindings
LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, drawcallContext.vertexBufferDirtyMask, drawcallContext.vsUniformBufferDirtyMask, drawcallContext.psUniformBufferDirtyMask, drawcallContext.gsUniformBufferDirtyMask, stageUniformModifiedMask, true); LatteBufferCache_Sync(indexMax + baseVertex, baseInstance, instanceCount, drawcallContext.vertexBufferDirtyMask, drawcallContext.vsUniformBufferDirtyMask, drawcallContext.psUniformBufferDirtyMask, drawcallContext.gsUniformBufferDirtyMask, stageUniformModifiedMask, true);
} }
m_state.descriptorSetsChanged = false; m_state.descriptorSetsChanged = false;