Break out VertexReader, prepare VertexReader for CrossSIMD use in software transform

This commit is contained in:
Henrik Rydgård
2026-06-04 12:18:18 +02:00
parent 7e265fd1c4
commit 195455a7f4
9 changed files with 297 additions and 211 deletions
+1
View File
@@ -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
+47 -8
View File
@@ -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)); }
+1
View File
@@ -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"
+1
View File
@@ -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"
+3 -203
View File
@@ -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;
+239
View File
@@ -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);
+1
View File
@@ -281,6 +281,7 @@
<ClInclude Include="Common\TransformCommon.h" />
<ClInclude Include="Common\VertexDecoderCommon.h" />
<ClInclude Include="Common\VertexDecoderHandwritten.h" />
<ClInclude Include="Common\VertexReader.h" />
<ClInclude Include="Common\VertexShaderGenerator.h" />
<ClInclude Include="D3D11\D3D11Util.h" />
<ClInclude Include="D3D11\DrawEngineD3D11.h" />
+3
View File
@@ -264,6 +264,9 @@
<ClInclude Include="GPUStateSIMDUtil.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\VertexReader.h">
<Filter>Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
+1
View File
@@ -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"