mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 09:35:09 +02:00
2534eb4480
May improve performance slightly, and should fix the last instances of #19555
240 lines
6.9 KiB
C++
240 lines
6.9 KiB
C++
#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:
|
|
Vec4F32::LoadU8Norm(data_ + decFmt_.c0off).Store(color);
|
|
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(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);
|