diff --git a/CMakeLists.txt b/CMakeLists.txt index 55c6a75e42..b4d2e86350 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2049,6 +2049,7 @@ set(GPU_SOURCES GPU/Common/VertexDecoderCommon.h GPU/Common/VertexDecoderHandwritten.cpp GPU/Common/VertexDecoderHandwritten.h + GPU/Common/VertexReader.h GPU/Common/TransformCommon.cpp GPU/Common/TransformCommon.h GPU/Common/IndexGenerator.cpp diff --git a/Common/Math/CrossSIMD.h b/Common/Math/CrossSIMD.h index 91f8bd4d2b..af834e9f4a 100644 --- a/Common/Math/CrossSIMD.h +++ b/Common/Math/CrossSIMD.h @@ -201,6 +201,8 @@ struct Vec4F32 { static Vec4F32 Load(const float *src) { return Vec4F32{ _mm_loadu_ps(src) }; } static Vec4F32 LoadAligned(const float *src) { return Vec4F32{ _mm_load_ps(src) }; } + static Vec4F32 Load2(const float *src) { return Vec4F32{ _mm_castpd_ps(_mm_load_sd((const double *)src)) }; } + static Vec4F32 LoadS8Norm(const int8_t *src) { __m128i value = _mm_set1_epi32(*((uint32_t *)src)); __m128i value16 = _mm_unpacklo_epi8(value, value); @@ -209,6 +211,15 @@ struct Vec4F32 { value32 = _mm_srai_epi32(value32, 24); return Vec4F32 { _mm_mul_ps(_mm_cvtepi32_ps(value32), _mm_set1_ps(1.0f / 128.0f)) }; } + + static Vec4F32 LoadU8Norm(const uint8_t *src) { + __m128i value = _mm_set1_epi32(*((uint32_t *)src)); + __m128i value16 = _mm_unpacklo_epi8(value, value); + __m128i value32 = _mm_unpacklo_epi16(value16, value16); + // Sign extension. A bit ugly without SSE4. + value32 = _mm_srli_epi32(value32, 24); + return Vec4F32{_mm_mul_ps(_mm_cvtepi32_ps(value32), _mm_set1_ps(1.0f / 128.0f))}; + } static Vec4F32 LoadS16Norm(const int16_t *src) { // Divides by 32768.0f __m128i bits = _mm_loadl_epi64((const __m128i*)src); // Sign extension. A bit ugly without SSE4. @@ -621,10 +632,19 @@ struct Vec4F32 { const int16x8_t value16 = vmovl_s8(value); return Vec4F32 { vcvtq_n_f32_s32(vmovl_s16(vget_low_s16(value16)), 7) }; } + static Vec4F32 LoadU8Norm(const uint8_t *src) { + const uint8x8_t value = (uint8x8_t)vdup_n_u32(*((uint32_t *)src)); + const uint16x8_t value16 = vmovl_u8(value); + return Vec4F32{ vmulq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(value16))), vdupq_n_f32(1.0f / 255.0f))}; + } static Vec4F32 LoadS16Norm(const int16_t *src) { // Divides by 32768.0f return Vec4F32 { vcvtq_n_f32_s32(vmovl_s16(vld1_s16(src)), 15) }; } static Vec4F32 LoadAligned(const float *src) { return Vec4F32{ vld1q_f32(src) }; } + static Vec4F32 Load2(const float *src) { + float32x2_t two = vld1_f32(src); + return Vec4F32{ vcombine_f32(two, two) }; + } static Vec4F32 LoadConvertS16(const int16_t *src) { int16x4_t value = vld1_s16(src); @@ -1113,10 +1133,20 @@ struct Vec4F32 { static Vec4F32 LoadS8Norm(const int8_t *src) { return LoadConvertS8(src) * (1.0f / 128.0f); } + static Vec4F32 LoadU8Norm(const uint8_t *src) { + return LoadConvertU8(src) * (1.0f / 255.0f); + } static Vec4F32 LoadS16Norm(const int16_t *src) { // Divides by 32768.0f return LoadConvertS16(src) * (1.0f / 32768.0f); } static Vec4F32 LoadAligned(const float *src) { return Vec4F32{ (__m128)__lsx_vld(src, 0) }; } + static Vec4F32 Load2(const float *src) { + // Load 2 floats and set the last two lanes to 0.0f + // NOTE: This is bad, it over-loads. + __m128 low = __lsx_vld(src, 0); + __m128 zero = __lsx_vldi(0); + return Vec4F32{ __lsx_vshuf4i_w(low, zero, 0b11111001) }; + } static Vec4F32 LoadConvertS16(const int16_t *src) { __m128i value = __lsx_vldrepl_d(src, 0); @@ -1319,10 +1349,10 @@ struct Vec4F32 { __m128 masked = (__m128)__lsx_vinsgr2vr_w((__m128i)v, 0, 3); __m128 mul = (__m128)__lsx_vfmul_s(masked, b.v); // Sum all elements: horizontal add - __m128 shuf1 = (__m128)__lsx_vshuf4i_w((__m128i)mul, 0b10110001); // Rotate elements - __m128 sum1 = (__m128)__lsx_vfadd_s(mul, shuf1); - __m128 shuf2 = (__m128)__lsx_vshuf4i_w((__m128i)sum1, 0b01001110); // Swap pairs - __m128 sum2 = (__m128)__lsx_vfadd_s(sum1, shuf2); + __m128i shuf1 = __lsx_vshuf4i_w((__m128i)mul, 0b10110001); // Rotate elements + __m128 sum1 = (__m128)__lsx_vfadd_s(mul, (__m128)shuf1); + __m128i shuf2 = __lsx_vshuf4i_w((__m128i)sum1, 0b01001110); // Swap pairs + __m128 sum2 = (__m128)__lsx_vfadd_s(sum1, (__m128)shuf2); float fval; int ival = __lsx_vpickve2gr_w((__m128i)sum2, 0); memcpy(&fval, &ival, sizeof(float)); @@ -1332,10 +1362,10 @@ struct Vec4F32 { float Dot4(Vec4F32 b) { __m128 mul = (__m128)__lsx_vfmul_s(v, b.v); // Sum all elements: horizontal add - __m128 shuf1 = (__m128)__lsx_vshuf4i_w((__m128i)mul, 0b10110001); // Rotate elements - __m128 sum1 = (__m128)__lsx_vfadd_s(mul, shuf1); - __m128 shuf2 = (__m128)__lsx_vshuf4i_w((__m128i)sum1, 0b01001110); // Swap pairs - __m128 sum2 = (__m128)__lsx_vfadd_s(sum1, shuf2); + __m128i shuf1 = __lsx_vshuf4i_w((__m128i)mul, 0b10110001); // Rotate elements + __m128 sum1 = (__m128)__lsx_vfadd_s(mul, (__m128)shuf1); + __m128i shuf2 = __lsx_vshuf4i_w((__m128i)sum1, 0b01001110); // Swap pairs + __m128 sum2 = (__m128)__lsx_vfadd_s(sum1, (__m128)shuf2); float fval; int ival = __lsx_vpickve2gr_w((__m128i)sum2, 0); memcpy(&fval, &ival, sizeof(float)); @@ -1607,6 +1637,13 @@ struct Vec4F32 { } return temp; } + static Vec4F32 LoadU8Norm(const uint8_t *src) { + Vec4F32 temp; + for (int i = 0; i < 4; i++) { + temp.v[i] = (float)src[i] * (1.0f / 255.0f); + } + return temp; + } static Vec4F32 LoadS16Norm(const int16_t *src) { // Divides by 32768.0f Vec4F32 temp; for (int i = 0; i < 4; i++) { @@ -1614,6 +1651,8 @@ struct Vec4F32 { } return temp; } + static Vec4F32 Load2(const float *src) { return Vec4F32{{ src[0], src[1], 0.0f, 0.0f }}; } + void Store(float *dst) { memcpy(dst, v, sizeof(v)); } void Store2(float *dst) { memcpy(dst, v, sizeof(v[0]) * 2); } void StoreAligned(float *dst) { memcpy(dst, v, sizeof(v)); } diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index ba39d4e0e8..cd56bdfd89 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -32,6 +32,7 @@ #include "GPU/Common/SoftwareTransformCommon.h" #include "GPU/Common/TransformCommon.h" #include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/Common/VertexReader.h" #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Software/Clipper.h" diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 1817621890..f48e653bef 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -32,6 +32,7 @@ #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/Util/AudioFormat.h" // for clamp_u8 #include "GPU/Common/ShaderCommon.h" +#include "GPU/Common/VertexReader.h" #include "GPU/GPUState.h" #include "GPU/ge_constants.h" #include "GPU/Math3D.h" diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index e2278999e2..f7ae78503c 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -44,11 +44,6 @@ #include "Common/FakeEmitter.h" #endif -// DecVtxFormat - vertex formats for PC -// Kind of like a D3D VertexDeclaration. -// Can write code to easily bind these using OpenGL, or read these manually. -// No morph support, that is taken care of by the VertexDecoder. - // Keep this in 4 bits. enum { DEC_NONE, @@ -68,6 +63,9 @@ enum { DEC_U16_4, }; +// DecVtxFormat - vertex formats for PC +// Kind of like a D3D VertexDeclaration. +// No morph support, that is taken care of by the VertexDecoder. struct DecVtxFormat { u8 w0fmt; u8 w0off; // first 4 weights u8 w1fmt; u8 w1off; // second 4 weights @@ -120,204 +118,6 @@ public: } }; -// Reads decoded vertex formats in a convenient way. For software transform and debugging. -class VertexReader { -public: - VertexReader(const u8 *base, const DecVtxFormat &decFmt, int vtype) : base_(base), data_(base), decFmt_(decFmt), vtype_(vtype) {} - - // TODO: Only reason we might want to still keep the separation of ReadPosThrough and ReadPosNonThrough is - // in case we need to do some rounding for through mode. I doubt it's needed though. - void ReadPosAuto(float pos[3]) const { - // Only DEC_FLOAT_3 is supported. - const float *f = (const float *)(data_ + decFmt_.posoff); - pos[0] = f[0]; - pos[1] = f[1]; - if (!isThrough()) { - pos[2] = f[2]; - } else { - // Integer value passed in a float. Clamped to 0, 65535. - pos[2] = f[2]; - } - } - - void ReadPosThrough(float pos[3]) const { - // Only DEC_FLOAT_3 is supported. - const float *f = (const float *)(data_ + decFmt_.posoff); - pos[0] = f[0]; - pos[1] = f[1]; - // Integer value passed in a float. Clamped to 0, 65535 (but where?) - pos[2] = f[2]; - } - - void ReadPosNonThrough(float pos[3]) const { - // Only DEC_FLOAT_3 is supported. - const float *f = (const float *)(data_ + decFmt_.posoff); - memcpy(pos, f, 12); - } - - void ReadNrm(float nrm[3]) const { - switch (decFmt_.nrmfmt) { - case DEC_FLOAT_3: - //memcpy(nrm, data_ + decFmt_.nrmoff, 12); - { - const float *f = (const float *)(data_ + decFmt_.nrmoff); - for (int i = 0; i < 3; i++) - nrm[i] = f[i]; - } - break; - case DEC_S16_3: - { - const s16 *s = (const s16 *)(data_ + decFmt_.nrmoff); - for (int i = 0; i < 3; i++) - nrm[i] = s[i] * (1.f / 32767.f); - } - break; - case DEC_S8_3: - { - const s8 *b = (const s8 *)(data_ + decFmt_.nrmoff); - for (int i = 0; i < 3; i++) - nrm[i] = b[i] * (1.f / 127.f); - } - break; - default: - memset(nrm, 0, sizeof(float) * 3); - break; - } - } - - void ReadUV(float uv[2]) const { - // Only DEC_FLOAT_2 is supported. - const float *f = (const float *)(data_ + decFmt_.uvoff); - uv[0] = f[0]; - uv[1] = f[1]; - } - - void ReadColor0(float color[4]) const { - switch (decFmt_.c0fmt) { - case DEC_U8_4: - Uint8x4ToFloat4(color, *(const u32 *)(data_ + decFmt_.c0off)); - break; - case DEC_FLOAT_4: - memcpy(color, data_ + decFmt_.c0off, 16); - break; - default: - memset(color, 0, sizeof(float) * 4); - break; - } - } - - u32 ReadColor0_8888() const { - switch (decFmt_.c0fmt) { - case DEC_U8_4: - { - const u8 *b = (const u8 *)(data_ + decFmt_.c0off); - u32 value; - memcpy(&value, b, 4); - return value; - } - break; - case DEC_FLOAT_4: - { - const float *f = (const float *)(data_ + decFmt_.c0off); - return Float4ToUint8x4_NoClamp(f); - } - break; - default: - return 0; - } - } - - void ReadColor1(float color[3]) const { - switch (decFmt_.c1fmt) { - case DEC_U8_4: - { - const u8 *b = (const u8 *)(data_ + decFmt_.c1off); - for (int i = 0; i < 3; i++) - color[i] = b[i] * (1.f / 255.f); - } - break; - case DEC_FLOAT_4: - memcpy(color, data_ + decFmt_.c1off, 12); - break; - default: - memset(color, 0, sizeof(float) * 3); - break; - } - } - - void ReadWeights(float weights[8]) const { - const float *f = (const float *)(data_ + decFmt_.w0off); - const u8 *b = (const u8 *)(data_ + decFmt_.w0off); - const u16 *s = (const u16 *)(data_ + decFmt_.w0off); - switch (decFmt_.w0fmt) { - case DEC_FLOAT_1: - case DEC_FLOAT_2: - case DEC_FLOAT_3: - case DEC_FLOAT_4: - for (int i = 0; i <= decFmt_.w0fmt - DEC_FLOAT_1; i++) - weights[i] = f[i]; - break; - case DEC_U8_1: weights[0] = b[0] * (1.f / 128.f); break; - case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i] = b[i] * (1.f / 128.f); break; - case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i] = b[i] * (1.f / 128.f); break; - case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i] = b[i] * (1.f / 128.f); break; - case DEC_U16_1: weights[0] = s[0] * (1.f / 32768.f); break; - case DEC_U16_2: for (int i = 0; i < 2; i++) weights[i] = s[i] * (1.f / 32768.f); break; - case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i] = s[i] * (1.f / 32768.f); break; - case DEC_U16_4: for (int i = 0; i < 4; i++) weights[i] = s[i] * (1.f / 32768.f); break; - default: - ERROR_LOG_REPORT_ONCE(fmtw0, Log::G3D, "Reader: Unsupported W0 Format %d", decFmt_.w0fmt); - memset(weights, 0, sizeof(float) * 8); - break; - } - - f = (const float *)(data_ + decFmt_.w1off); - b = (const u8 *)(data_ + decFmt_.w1off); - s = (const u16 *)(data_ + decFmt_.w1off); - switch (decFmt_.w1fmt) { - case 0: - // It's fine for there to be w0 weights but not w1. - break; - case DEC_FLOAT_1: - case DEC_FLOAT_2: - case DEC_FLOAT_3: - case DEC_FLOAT_4: - for (int i = 0; i <= decFmt_.w1fmt - DEC_FLOAT_1; i++) - weights[i+4] = f[i]; - break; - case DEC_U8_1: weights[4] = b[0] * (1.f / 128.f); break; - case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i+4] = b[i] * (1.f / 128.f); break; - case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i+4] = b[i] * (1.f / 128.f); break; - case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i+4] = b[i] * (1.f / 128.f); break; - case DEC_U16_1: weights[4] = s[0] * (1.f / 32768.f); break; - case DEC_U16_2: for (int i = 0; i < 2; i++) weights[i+4] = s[i] * (1.f / 32768.f); break; - case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i+4] = s[i] * (1.f / 32768.f); break; - case DEC_U16_4: for (int i = 0; i < 4; i++) weights[i+4] = s[i] * (1.f / 32768.f); break; - default: - memset(weights + 4, 0, sizeof(float) * 4); - break; - } - } - - bool hasColor0() const { return decFmt_.c0fmt != 0; } - bool hasColor1() const { return decFmt_.c1fmt != 0; } - bool hasNormal() const { return decFmt_.nrmfmt != 0; } - bool hasUV() const { return decFmt_.uvfmt != 0; } - bool isThrough() const { return (vtype_ & GE_VTYPE_THROUGH) != 0; } - void Goto(int index) { - data_ = base_ + index * decFmt_.stride; - } - -private: - const u8 *base_; - const u8 *data_; - DecVtxFormat decFmt_; - int vtype_; -}; -// Debugging utilities -void PrintDecodedVertex(const VertexReader &vtx); - - class VertexDecoder; class VertexDecoderJitCache; diff --git a/GPU/Common/VertexReader.h b/GPU/Common/VertexReader.h new file mode 100644 index 0000000000..2cc59ba529 --- /dev/null +++ b/GPU/Common/VertexReader.h @@ -0,0 +1,239 @@ +#pragma once + +#include "Common/Math/CrossSIMD.h" +#include "GPU/Common/VertexDecoderCommon.h" + +// Reads decoded vertex formats in a convenient way. For software transform and debugging. +class VertexReader { +public: + VertexReader(const u8 *base, const DecVtxFormat &decFmt, int vtype) : base_(base), data_(base), decFmt_(decFmt), vtype_(vtype) {} + + Vec4F32 ReadPosF32() const { + // Only DEC_FLOAT_3 is supported. + const float *f = (const float *)(data_ + decFmt_.posoff); + return Vec4F32::Load(f); + } + + // TODO: Only reason we might want to still keep the separation of ReadPosThrough and ReadPosNonThrough is + // in case we need to do some rounding for through mode. I doubt it's needed though. + void ReadPosAuto(float pos[3]) const { + // Only DEC_FLOAT_3 is supported. + const float *f = (const float *)(data_ + decFmt_.posoff); + pos[0] = f[0]; + pos[1] = f[1]; + if (!isThrough()) { + pos[2] = f[2]; + } else { + // Integer value passed in a float. Clamped to 0, 65535. + pos[2] = f[2]; + } + } + + void ReadPosThrough(float pos[3]) const { + // Only DEC_FLOAT_3 is supported. + const float *f = (const float *)(data_ + decFmt_.posoff); + pos[0] = f[0]; + pos[1] = f[1]; + // Integer value passed in a float. Clamped to 0, 65535 (but where?) + pos[2] = f[2]; + } + + void ReadPosNonThrough(float pos[3]) const { + // Only DEC_FLOAT_3 is supported. + const float *f = (const float *)(data_ + decFmt_.posoff); + memcpy(pos, f, 12); + } + + // NOTE: The W component of the return value becomes undefined. + Vec4F32 ReadNrmF32() const { + switch (decFmt_.nrmfmt) { + case DEC_FLOAT_3: + return Vec4F32::Load((const float *)(data_ + decFmt_.nrmoff)); + case DEC_S16_3: + return Vec4F32::LoadS16Norm((const s16 *)(data_ + decFmt_.nrmoff)); + case DEC_S8_3: + return Vec4F32::LoadS8Norm((const s8 *)(data_ + decFmt_.nrmoff)); + default: + return Vec4F32::Zero(); + } + } + + void ReadNrm(float nrm[3]) const { + switch (decFmt_.nrmfmt) { + case DEC_FLOAT_3: + //memcpy(nrm, data_ + decFmt_.nrmoff, 12); + { + const float *f = (const float *)(data_ + decFmt_.nrmoff); + for (int i = 0; i < 3; i++) + nrm[i] = f[i]; + } + break; + case DEC_S16_3: + { + const s16 *s = (const s16 *)(data_ + decFmt_.nrmoff); + for (int i = 0; i < 3; i++) + nrm[i] = s[i] * (1.f / 32768.f); + } + break; + case DEC_S8_3: + { + const s8 *b = (const s8 *)(data_ + decFmt_.nrmoff); + for (int i = 0; i < 3; i++) + nrm[i] = b[i] * (1.f / 128.f); + } + break; + default: + memset(nrm, 0, sizeof(float) * 3); + break; + } + } + + void ReadUV(float uv[2]) const { + // Only DEC_FLOAT_2 is supported. + const float *f = (const float *)(data_ + decFmt_.uvoff); + uv[0] = f[0]; + uv[1] = f[1]; + } + + Vec4F32 ReadUVF32() const { + // Only DEC_FLOAT_2 is supported. + // The upper two lanes of the return value become undefined. + const float *f = (const float *)(data_ + decFmt_.uvoff); + return Vec4F32::Load2(f); + } + + void ReadColor0(float color[4]) const { + switch (decFmt_.c0fmt) { + case DEC_U8_4: + Uint8x4ToFloat4(color, *(const u32 *)(data_ + decFmt_.c0off)); + break; + case DEC_FLOAT_4: + memcpy(color, data_ + decFmt_.c0off, 16); + break; + default: + memset(color, 0, sizeof(float) * 4); + break; + } + } + + Vec4F32 ReadColorF32() const { + switch (decFmt_.c0fmt) { + case DEC_U8_4: + return Vec4F32::LoadU8Norm((const u8 *)(data_ + decFmt_.c0off)); + case DEC_FLOAT_4: + return Vec4F32::Load((const float *)(data_ + decFmt_.c0off)); + default: + return Vec4F32::Zero(); + } + } + + u32 ReadColor0_8888() const { + switch (decFmt_.c0fmt) { + case DEC_U8_4: + { + const u8 *b = (const u8 *)(data_ + decFmt_.c0off); + u32 value; + memcpy(&value, b, 4); + return value; + } + break; + case DEC_FLOAT_4: + { + const float *f = (const float *)(data_ + decFmt_.c0off); + return Float4ToUint8x4_NoClamp(f); + } + break; + default: + return 0; + } + } + + void ReadColor1(float color[3]) const { + switch (decFmt_.c1fmt) { + case DEC_U8_4: + { + const u8 *b = (const u8 *)(data_ + decFmt_.c1off); + for (int i = 0; i < 3; i++) + color[i] = b[i] * (1.f / 255.f); + } + break; + case DEC_FLOAT_4: + memcpy(color, data_ + decFmt_.c1off, 12); + break; + default: + memset(color, 0, sizeof(float) * 3); + break; + } + } + + void ReadWeights(float weights[8]) const { + const float *f = (const float *)(data_ + decFmt_.w0off); + const u8 *b = (const u8 *)(data_ + decFmt_.w0off); + const u16 *s = (const u16 *)(data_ + decFmt_.w0off); + switch (decFmt_.w0fmt) { + case DEC_FLOAT_1: + case DEC_FLOAT_2: + case DEC_FLOAT_3: + case DEC_FLOAT_4: + for (int i = 0; i <= decFmt_.w0fmt - DEC_FLOAT_1; i++) + weights[i] = f[i]; + break; + case DEC_U8_1: weights[0] = b[0] * (1.f / 128.f); break; + case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i] = b[i] * (1.f / 128.f); break; + case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i] = b[i] * (1.f / 128.f); break; + case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i] = b[i] * (1.f / 128.f); break; + case DEC_U16_1: weights[0] = s[0] * (1.f / 32768.f); break; + case DEC_U16_2: for (int i = 0; i < 2; i++) weights[i] = s[i] * (1.f / 32768.f); break; + case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i] = s[i] * (1.f / 32768.f); break; + case DEC_U16_4: for (int i = 0; i < 4; i++) weights[i] = s[i] * (1.f / 32768.f); break; + default: + ERROR_LOG_REPORT_ONCE(fmtw0, Log::G3D, "Reader: Unsupported W0 Format %d", decFmt_.w0fmt); + memset(weights, 0, sizeof(float) * 8); + break; + } + + f = (const float *)(data_ + decFmt_.w1off); + b = (const u8 *)(data_ + decFmt_.w1off); + s = (const u16 *)(data_ + decFmt_.w1off); + switch (decFmt_.w1fmt) { + case 0: + // It's fine for there to be w0 weights but not w1. + break; + case DEC_FLOAT_1: + case DEC_FLOAT_2: + case DEC_FLOAT_3: + case DEC_FLOAT_4: + for (int i = 0; i <= decFmt_.w1fmt - DEC_FLOAT_1; i++) + weights[i + 4] = f[i]; + break; + case DEC_U8_1: weights[4] = b[0] * (1.f / 128.f); break; + case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i + 4] = b[i] * (1.f / 128.f); break; + case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i + 4] = b[i] * (1.f / 128.f); break; + case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i + 4] = b[i] * (1.f / 128.f); break; + case DEC_U16_1: weights[4] = s[0] * (1.f / 32768.f); break; + case DEC_U16_2: for (int i = 0; i < 2; i++) weights[i + 4] = s[i] * (1.f / 32768.f); break; + case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i + 4] = s[i] * (1.f / 32768.f); break; + case DEC_U16_4: for (int i = 0; i < 4; i++) weights[i + 4] = s[i] * (1.f / 32768.f); break; + default: + memset(weights + 4, 0, sizeof(float) * 4); + break; + } + } + + bool hasColor0() const { return decFmt_.c0fmt != 0; } + bool hasColor1() const { return decFmt_.c1fmt != 0; } + bool hasNormal() const { return decFmt_.nrmfmt != 0; } + bool hasUV() const { return decFmt_.uvfmt != 0; } + bool isThrough() const { return (vtype_ & GE_VTYPE_THROUGH) != 0; } + void Goto(int index) { + data_ = base_ + index * decFmt_.stride; + } + +private: + const u8 *base_; + const u8 *data_; + DecVtxFormat decFmt_; + int vtype_; +}; +// Debugging utilities +void PrintDecodedVertex(const VertexReader &vtx); diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 4c02d7f78a..5fd034eb66 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -281,6 +281,7 @@ + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index e7e3d17f4a..b3b7a6a2de 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -264,6 +264,9 @@ Common + + Common + diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 92a8a6c1e6..f57c1fcc02 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -28,6 +28,7 @@ #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/SoftwareTransformCommon.h" +#include "GPU/Common/VertexReader.h" #include "Common/Math/SIMDHeaders.h" #include "GPU/Software/BinManager.h" #include "GPU/Software/Clipper.h"