mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Break out VertexReader, prepare VertexReader for CrossSIMD use in software transform
This commit is contained in:
@@ -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
@@ -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)); }
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user