Merge pull request #9540 from Pokechu22/better-fifo-analyzer-part-2

Fifo analyzer quality of life improvements
This commit is contained in:
Mat M
2021-05-14 15:51:53 -04:00
committed by GitHub
28 changed files with 918 additions and 816 deletions

View File

@ -63,6 +63,11 @@ enum
ARRAY_TEXCOORD0 = 4,
NUM_TEXCOORD_ARRAYS = 8,
ARRAY_XF_A = 12, // Usually used for position matrices
ARRAY_XF_B = 13, // Usually used for normal matrices
ARRAY_XF_C = 14, // Usually used for tex coord matrices
ARRAY_XF_D = 15, // Usually used for light objects
// Number of arrays related to vertex components (position, normal, color, tex coord)
// Excludes the 4 arrays used for indexed XF loads
NUM_VERTEX_COMPONENT_ARRAYS = 12,
@ -317,10 +322,10 @@ union UVAT_group0
// 21:29
BitField<21, 1, TexComponentCount> Tex0CoordElements;
BitField<22, 3, ComponentFormat> Tex0CoordFormat;
BitField<25, 5, u32> Tex0Frac;
BitField<25, 5, u8, u32> Tex0Frac;
// 30:31
BitField<30, 1, u32> ByteDequant;
BitField<31, 1, u32> NormalIndex3;
BitField<30, 1, bool, u32> ByteDequant;
BitField<31, 1, bool, u32> NormalIndex3;
};
template <>
struct fmt::formatter<UVAT_group0>
@ -363,20 +368,20 @@ union UVAT_group1
// 0:8
BitField<0, 1, TexComponentCount> Tex1CoordElements;
BitField<1, 3, ComponentFormat> Tex1CoordFormat;
BitField<4, 5, u32> Tex1Frac;
BitField<4, 5, u8, u32> Tex1Frac;
// 9:17
BitField<9, 1, TexComponentCount> Tex2CoordElements;
BitField<10, 3, ComponentFormat> Tex2CoordFormat;
BitField<13, 5, u32> Tex2Frac;
BitField<13, 5, u8, u32> Tex2Frac;
// 18:26
BitField<18, 1, TexComponentCount> Tex3CoordElements;
BitField<19, 3, ComponentFormat> Tex3CoordFormat;
BitField<22, 5, u32> Tex3Frac;
BitField<22, 5, u8, u32> Tex3Frac;
// 27:30
BitField<27, 1, TexComponentCount> Tex4CoordElements;
BitField<28, 3, ComponentFormat> Tex4CoordFormat;
// 31
BitField<31, 1, u32> VCacheEnhance;
BitField<31, 1, bool, u32> VCacheEnhance;
};
template <>
struct fmt::formatter<UVAT_group1>
@ -410,19 +415,19 @@ union UVAT_group2
{
u32 Hex;
// 0:4
BitField<0, 5, u32> Tex4Frac;
BitField<0, 5, u8, u32> Tex4Frac;
// 5:13
BitField<5, 1, TexComponentCount> Tex5CoordElements;
BitField<6, 3, ComponentFormat> Tex5CoordFormat;
BitField<9, 5, u32> Tex5Frac;
BitField<9, 5, u8, u32> Tex5Frac;
// 14:22
BitField<14, 1, TexComponentCount> Tex6CoordElements;
BitField<15, 3, ComponentFormat> Tex6CoordFormat;
BitField<18, 5, u32> Tex6Frac;
BitField<18, 5, u8, u32> Tex6Frac;
// 23:31
BitField<23, 1, TexComponentCount> Tex7CoordElements;
BitField<24, 3, ComponentFormat> Tex7CoordFormat;
BitField<27, 5, u32> Tex7Frac;
BitField<27, 5, u8, u32> Tex7Frac;
};
template <>
struct fmt::formatter<UVAT_group2>
@ -450,30 +455,123 @@ struct fmt::formatter<UVAT_group2>
}
};
struct ColorAttr
struct VAT
{
ColorComponentCount Elements;
ColorFormat Comp;
};
UVAT_group0 g0;
UVAT_group1 g1;
UVAT_group2 g2;
struct TexAttr
{
TexComponentCount Elements;
ComponentFormat Format;
u8 Frac;
constexpr ColorComponentCount GetColorElements(size_t idx) const
{
switch (idx)
{
case 0:
return g0.Color0Elements;
case 1:
return g0.Color1Elements;
default:
PanicAlertFmt("Invalid color index {}", idx);
return ColorComponentCount::RGB;
}
}
constexpr ColorFormat GetColorFormat(size_t idx) const
{
switch (idx)
{
case 0:
return g0.Color0Comp;
case 1:
return g0.Color1Comp;
default:
PanicAlertFmt("Invalid color index {}", idx);
return ColorFormat::RGB565;
}
}
constexpr TexComponentCount GetTexElements(size_t idx) const
{
switch (idx)
{
case 0:
return g0.Tex0CoordElements;
case 1:
return g1.Tex1CoordElements;
case 2:
return g1.Tex2CoordElements;
case 3:
return g1.Tex3CoordElements;
case 4:
return g1.Tex4CoordElements;
case 5:
return g2.Tex5CoordElements;
case 6:
return g2.Tex6CoordElements;
case 7:
return g2.Tex7CoordElements;
default:
PanicAlertFmt("Invalid tex coord index {}", idx);
return TexComponentCount::S;
}
}
constexpr ComponentFormat GetTexFormat(size_t idx) const
{
switch (idx)
{
case 0:
return g0.Tex0CoordFormat;
case 1:
return g1.Tex1CoordFormat;
case 2:
return g1.Tex2CoordFormat;
case 3:
return g1.Tex3CoordFormat;
case 4:
return g1.Tex4CoordFormat;
case 5:
return g2.Tex5CoordFormat;
case 6:
return g2.Tex6CoordFormat;
case 7:
return g2.Tex7CoordFormat;
default:
PanicAlertFmt("Invalid tex coord index {}", idx);
return ComponentFormat::UByte;
}
}
constexpr u8 GetTexFrac(size_t idx) const
{
switch (idx)
{
case 0:
return g0.Tex0Frac;
case 1:
return g1.Tex1Frac;
case 2:
return g1.Tex2Frac;
case 3:
return g1.Tex3Frac;
case 4:
return g2.Tex4Frac;
case 5:
return g2.Tex5Frac;
case 6:
return g2.Tex6Frac;
case 7:
return g2.Tex7Frac;
default:
PanicAlertFmt("Invalid tex coord index {}", idx);
return 0;
}
}
};
struct TVtxAttr
template <>
struct fmt::formatter<VAT>
{
CoordComponentCount PosElements;
ComponentFormat PosFormat;
u8 PosFrac;
NormalComponentCount NormalElements;
ComponentFormat NormalFormat;
ColorAttr color[2];
TexAttr texCoord[8];
bool ByteDequant;
u8 NormalIndex3;
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const VAT& vat, FormatContext& ctx)
{
return format_to(ctx.out(), "{}\n{}\n{}", vat.g0, vat.g1, vat.g2);
}
};
// Matrix indices
@ -518,13 +616,6 @@ struct fmt::formatter<TMatrixIndexB>
}
};
struct VAT
{
UVAT_group0 g0;
UVAT_group1 g1;
UVAT_group2 g2;
};
class VertexLoaderBase;
// STATE_TO_SAVE

View File

@ -72,21 +72,16 @@ VertexLoader::VertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr)
CompileVertexTranslator();
// generate frac factors
m_posScale = 1.0f / (1U << m_VtxAttr.PosFrac);
for (int i = 0; i < 8; i++)
m_tcScale[i] = 1.0f / (1U << m_VtxAttr.texCoord[i].Frac);
m_posScale = 1.0f / (1U << m_VtxAttr.g0.PosFrac);
for (u32 i = 0; i < 8; i++)
m_tcScale[i] = 1.0f / (1U << m_VtxAttr.GetTexFrac(i));
}
void VertexLoader::CompileVertexTranslator()
{
m_VertexSize = 0;
const TVtxAttr& vtx_attr = m_VtxAttr;
// Reset pipeline
m_numPipelineStages = 0;
u32 components = 0;
// Position in pc vertex format.
int nat_offset = 0;
@ -94,72 +89,25 @@ void VertexLoader::CompileVertexTranslator()
if (m_VtxDesc.low.PosMatIdx)
{
WriteCall(PosMtx_ReadDirect_UByte);
components |= VB_HAS_POSMTXIDX;
m_native_vtx_decl.posmtx.components = 4;
m_native_vtx_decl.posmtx.enable = true;
m_native_vtx_decl.posmtx.offset = nat_offset;
m_native_vtx_decl.posmtx.type = VAR_UNSIGNED_BYTE;
m_native_vtx_decl.posmtx.integer = true;
nat_offset += 4;
m_VertexSize += 1;
}
if (m_VtxDesc.low.Tex0MatIdx)
for (auto texmtxidx : m_VtxDesc.low.TexMatIdx)
{
m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX0;
WriteCall(TexMtx_ReadDirect_UByte);
}
if (m_VtxDesc.low.Tex1MatIdx)
{
m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX1;
WriteCall(TexMtx_ReadDirect_UByte);
}
if (m_VtxDesc.low.Tex2MatIdx)
{
m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX2;
WriteCall(TexMtx_ReadDirect_UByte);
}
if (m_VtxDesc.low.Tex3MatIdx)
{
m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX3;
WriteCall(TexMtx_ReadDirect_UByte);
}
if (m_VtxDesc.low.Tex4MatIdx)
{
m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX4;
WriteCall(TexMtx_ReadDirect_UByte);
}
if (m_VtxDesc.low.Tex5MatIdx)
{
m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX5;
WriteCall(TexMtx_ReadDirect_UByte);
}
if (m_VtxDesc.low.Tex6MatIdx)
{
m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX6;
WriteCall(TexMtx_ReadDirect_UByte);
}
if (m_VtxDesc.low.Tex7MatIdx)
{
m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX7;
WriteCall(TexMtx_ReadDirect_UByte);
if (texmtxidx)
WriteCall(TexMtx_ReadDirect_UByte);
}
// Write vertex position loader
WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.low.Position, m_VtxAttr.PosFormat,
m_VtxAttr.PosElements));
WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.low.Position, m_VtxAttr.g0.PosFormat,
m_VtxAttr.g0.PosElements));
m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.low.Position, m_VtxAttr.PosFormat,
m_VtxAttr.PosElements);
int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3;
int pos_elements = m_VtxAttr.g0.PosElements == CoordComponentCount::XY ? 2 : 3;
m_native_vtx_decl.position.components = pos_elements;
m_native_vtx_decl.position.enable = true;
m_native_vtx_decl.position.offset = nat_offset;
@ -170,22 +118,19 @@ void VertexLoader::CompileVertexTranslator()
// Normals
if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{
m_VertexSize += VertexLoader_Normal::GetSize(m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat,
m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3);
TPipelineFunction pFunc =
VertexLoader_Normal::GetFunction(m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat,
m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3);
VertexLoader_Normal::GetFunction(m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat,
m_VtxAttr.g0.NormalElements, m_VtxAttr.g0.NormalIndex3);
if (pFunc == nullptr)
{
PanicAlertFmt("VertexLoader_Normal::GetFunction({} {} {} {}) returned zero!",
m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements,
m_VtxAttr.NormalIndex3);
m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, m_VtxAttr.g0.NormalElements,
m_VtxAttr.g0.NormalIndex3);
}
WriteCall(pFunc);
for (int i = 0; i < (vtx_attr.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++)
for (int i = 0; i < (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++)
{
m_native_vtx_decl.normals[i].components = 3;
m_native_vtx_decl.normals[i].enable = true;
@ -194,10 +139,6 @@ void VertexLoader::CompileVertexTranslator()
m_native_vtx_decl.normals[i].integer = false;
nat_offset += 12;
}
components |= VB_HAS_NRM0;
if (m_VtxAttr.NormalElements == NormalComponentCount::NBT)
components |= VB_HAS_NRM1 | VB_HAS_NRM2;
}
for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++)
@ -205,101 +146,17 @@ void VertexLoader::CompileVertexTranslator()
m_native_vtx_decl.colors[i].components = 4;
m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE;
m_native_vtx_decl.colors[i].integer = false;
switch (m_VtxDesc.low.Color[i])
{
case VertexComponentFormat::NotPresent:
break;
case VertexComponentFormat::Direct:
switch (m_VtxAttr.color[i].Comp)
{
case ColorFormat::RGB565:
m_VertexSize += 2;
WriteCall(Color_ReadDirect_16b_565);
break;
case ColorFormat::RGB888:
m_VertexSize += 3;
WriteCall(Color_ReadDirect_24b_888);
break;
case ColorFormat::RGB888x:
m_VertexSize += 4;
WriteCall(Color_ReadDirect_32b_888x);
break;
case ColorFormat::RGBA4444:
m_VertexSize += 2;
WriteCall(Color_ReadDirect_16b_4444);
break;
case ColorFormat::RGBA6666:
m_VertexSize += 3;
WriteCall(Color_ReadDirect_24b_6666);
break;
case ColorFormat::RGBA8888:
m_VertexSize += 4;
WriteCall(Color_ReadDirect_32b_8888);
break;
default:
ASSERT(0);
break;
}
break;
case VertexComponentFormat::Index8:
m_VertexSize += 1;
switch (m_VtxAttr.color[i].Comp)
{
case ColorFormat::RGB565:
WriteCall(Color_ReadIndex8_16b_565);
break;
case ColorFormat::RGB888:
WriteCall(Color_ReadIndex8_24b_888);
break;
case ColorFormat::RGB888x:
WriteCall(Color_ReadIndex8_32b_888x);
break;
case ColorFormat::RGBA4444:
WriteCall(Color_ReadIndex8_16b_4444);
break;
case ColorFormat::RGBA6666:
WriteCall(Color_ReadIndex8_24b_6666);
break;
case ColorFormat::RGBA8888:
WriteCall(Color_ReadIndex8_32b_8888);
break;
default:
ASSERT(0);
break;
}
break;
case VertexComponentFormat::Index16:
m_VertexSize += 2;
switch (m_VtxAttr.color[i].Comp)
{
case ColorFormat::RGB565:
WriteCall(Color_ReadIndex16_16b_565);
break;
case ColorFormat::RGB888:
WriteCall(Color_ReadIndex16_24b_888);
break;
case ColorFormat::RGB888x:
WriteCall(Color_ReadIndex16_32b_888x);
break;
case ColorFormat::RGBA4444:
WriteCall(Color_ReadIndex16_16b_4444);
break;
case ColorFormat::RGBA6666:
WriteCall(Color_ReadIndex16_24b_6666);
break;
case ColorFormat::RGBA8888:
WriteCall(Color_ReadIndex16_32b_8888);
break;
default:
ASSERT(0);
break;
}
break;
}
// Common for the three bottom cases
TPipelineFunction pFunc =
VertexLoader_Color::GetFunction(m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i));
if (pFunc != nullptr)
WriteCall(pFunc);
else
ASSERT(m_VtxDesc.low.Color[i] == VertexComponentFormat::NotPresent);
if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent)
{
components |= VB_HAS_COL0 << i;
m_native_vtx_decl.colors[i].offset = nat_offset;
m_native_vtx_decl.colors[i].enable = true;
nat_offset += 4;
@ -314,8 +171,8 @@ void VertexLoader::CompileVertexTranslator()
m_native_vtx_decl.texcoords[i].integer = false;
const auto tc = m_VtxDesc.high.TexCoord[i].Value();
const auto format = m_VtxAttr.texCoord[i].Format;
const auto elements = m_VtxAttr.texCoord[i].Elements;
const auto format = m_VtxAttr.GetTexFormat(i);
const auto elements = m_VtxAttr.GetTexElements(i);
if (tc != VertexComponentFormat::NotPresent)
{
@ -326,26 +183,21 @@ void VertexLoader::CompileVertexTranslator()
ASSERT_MSG(VIDEO, elements == TexComponentCount::S || elements == TexComponentCount::ST,
"Invalid number of texture coordinates elements!\n(elements = %d)", (u32)elements);
components |= VB_HAS_UV0 << i;
WriteCall(VertexLoader_TextCoord::GetFunction(tc, format, elements));
m_VertexSize += VertexLoader_TextCoord::GetSize(tc, format, elements);
}
if (components & (VB_HAS_TEXMTXIDX0 << i))
if (m_VtxDesc.low.TexMatIdx[i])
{
m_native_vtx_decl.texcoords[i].enable = true;
m_native_vtx_decl.texcoords[i].components = 3;
nat_offset += 12;
if (tc != VertexComponentFormat::NotPresent)
{
// if texmtx is included, texcoord will always be 3 floats, z will be the texmtx index
m_native_vtx_decl.texcoords[i].components = 3;
nat_offset += 12;
WriteCall(m_VtxAttr.texCoord[i].Elements == TexComponentCount::ST ? TexMtx_Write_Float :
TexMtx_Write_Float2);
WriteCall(elements == TexComponentCount::ST ? TexMtx_Write_Float : TexMtx_Write_Float2);
}
else
{
m_native_vtx_decl.texcoords[i].components = 3;
nat_offset += 12;
WriteCall(TexMtx_Write_Float3);
}
}
@ -354,26 +206,29 @@ void VertexLoader::CompileVertexTranslator()
if (tc != VertexComponentFormat::NotPresent)
{
m_native_vtx_decl.texcoords[i].enable = true;
m_native_vtx_decl.texcoords[i].components =
vtx_attr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1;
nat_offset += 4 * (vtx_attr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1);
m_native_vtx_decl.texcoords[i].components = elements == TexComponentCount::ST ? 2 : 1;
nat_offset += 4 * (elements == TexComponentCount::ST ? 2 : 1);
}
}
if (tc == VertexComponentFormat::NotPresent)
{
// if there's more tex coords later, have to write a dummy call
size_t j = i + 1;
for (; j < m_VtxDesc.high.TexCoord.Size(); ++j)
bool has_more = false;
for (size_t j = 0; j < m_VtxDesc.high.TexCoord.Size(); ++j)
{
if (m_VtxDesc.high.TexCoord[j] != VertexComponentFormat::NotPresent)
{
has_more = true;
WriteCall(VertexLoader_TextCoord::GetDummyFunction()); // important to get indices right!
break;
}
else if (m_VtxDesc.low.TexMatIdx[i])
{
has_more = true;
}
}
// tricky!
if (j == 8 && !((components & VB_HAS_TEXMTXIDXALL) & (VB_HAS_TEXMTXIDXALL << (i + 1))))
if (!has_more)
{
// no more tex coords and tex matrices, so exit loop
break;
@ -387,7 +242,6 @@ void VertexLoader::CompileVertexTranslator()
WriteCall(SkipVertex);
}
m_native_components = components;
m_native_vtx_decl.stride = nat_offset;
}

View File

@ -22,8 +22,6 @@ public:
VertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr);
int RunVertices(DataReader src, DataReader dst, int count) override;
std::string GetName() const override { return "OldLoader"; }
bool IsInitialized() override { return true; } // This vertex loader supports all formats
// They are used for the communication with the loader functions
float m_posScale;
float m_tcScale[8];

View File

@ -25,6 +25,20 @@ constexpr ARM64Reg stride_reg = ARM64Reg::X11;
constexpr ARM64Reg arraybase_reg = ARM64Reg::X10;
constexpr ARM64Reg scale_reg = ARM64Reg::X9;
static constexpr int GetLoadSize(int load_bytes)
{
if (load_bytes == 1)
return 1;
else if (load_bytes <= 2)
return 2;
else if (load_bytes <= 4)
return 4;
else if (load_bytes <= 8)
return 8;
else
return 16;
}
alignas(16) static const float scale_factors[] = {
1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3),
1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7),
@ -39,9 +53,6 @@ alignas(16) static const float scale_factors[] = {
VertexLoaderARM64::VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_att)
: VertexLoaderBase(vtx_desc, vtx_att), m_float_emit(this)
{
if (!IsInitialized())
return;
AllocCodeSpace(4096);
ClearCodeSpace();
GenerateVertexLoader();
@ -120,8 +131,7 @@ int VertexLoaderARM64::ReadVertex(VertexComponentFormat attribute, ComponentForm
int elem_size = GetElementSize(format);
int load_bytes = elem_size * count_in;
int load_size =
load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
int load_size = GetLoadSize(load_bytes);
load_size <<= 3;
elem_size <<= 3;
@ -380,10 +390,11 @@ void VertexLoaderARM64::GenerateVertexLoader()
for (size_t i = 0; i < m_VtxDesc.high.TexCoord.Size(); i++)
{
has_tc |= m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent;
has_tc_scale |= !!m_VtxAttr.texCoord[i].Frac;
has_tc_scale |= (m_VtxAttr.GetTexFrac(i) != 0);
}
bool need_scale = (m_VtxAttr.ByteDequant && m_VtxAttr.PosFrac) || (has_tc && has_tc_scale) ||
bool need_scale = (m_VtxAttr.g0.ByteDequant && m_VtxAttr.g0.PosFrac) ||
(has_tc && has_tc_scale) ||
(m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent);
AlignCode16();
@ -412,7 +423,6 @@ void VertexLoaderARM64::GenerateVertexLoader()
STR(IndexType::Unsigned, scratch1_reg, EncodeRegTo64(scratch2_reg), 0);
SetJumpTarget(dont_store);
m_native_components |= VB_HAS_POSMTXIDX;
m_native_vtx_decl.posmtx.components = 4;
m_native_vtx_decl.posmtx.enable = true;
m_native_vtx_decl.posmtx.offset = m_dst_ofs;
@ -431,36 +441,33 @@ void VertexLoaderARM64::GenerateVertexLoader()
// Position
{
int elem_size = GetElementSize(m_VtxAttr.PosFormat);
int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3;
int elem_size = GetElementSize(m_VtxAttr.g0.PosFormat);
int pos_elements = m_VtxAttr.g0.PosElements == CoordComponentCount::XY ? 2 : 3;
int load_bytes = elem_size * pos_elements;
int load_size =
load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
int load_size = GetLoadSize(load_bytes);
load_size <<= 3;
s32 offset = GetAddressImm(ARRAY_POSITION, m_VtxDesc.low.Position, EncodeRegTo64(scratch1_reg),
load_size);
ReadVertex(m_VtxDesc.low.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements,
m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position, offset);
ReadVertex(m_VtxDesc.low.Position, m_VtxAttr.g0.PosFormat, pos_elements, pos_elements,
m_VtxAttr.g0.ByteDequant, m_VtxAttr.g0.PosFrac, &m_native_vtx_decl.position, offset);
}
if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{
static const u8 map[8] = {7, 6, 15, 14};
const u8 scaling_exponent = map[u32(m_VtxAttr.NormalFormat)];
const int limit = m_VtxAttr.NormalElements == NormalComponentCount::NBT ? 3 : 1;
const u8 scaling_exponent = map[u32(m_VtxAttr.g0.NormalFormat.Value())];
const int limit = m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT ? 3 : 1;
s32 offset = -1;
for (int i = 0; i < (m_VtxAttr.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++)
for (int i = 0; i < (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++)
{
if (!i || m_VtxAttr.NormalIndex3)
if (!i || m_VtxAttr.g0.NormalIndex3)
{
int elem_size = GetElementSize(m_VtxAttr.NormalFormat);
int elem_size = GetElementSize(m_VtxAttr.g0.NormalFormat);
int load_bytes = elem_size * 3;
int load_size = load_bytes == 1 ?
1 :
load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
int load_size = GetLoadSize(load_bytes);
offset = GetAddressImm(ARRAY_NORMAL, m_VtxDesc.low.Normal, EncodeRegTo64(scratch1_reg),
load_size << 3);
@ -470,7 +477,7 @@ void VertexLoaderARM64::GenerateVertexLoader()
else
offset += i * elem_size * 3;
}
int bytes_read = ReadVertex(m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, 3, 3, true,
int bytes_read = ReadVertex(m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, 3, 3, true,
scaling_exponent, &m_native_vtx_decl.normals[i], offset);
if (offset == -1)
@ -478,10 +485,6 @@ void VertexLoaderARM64::GenerateVertexLoader()
else
offset += bytes_read;
}
m_native_components |= VB_HAS_NRM0;
if (m_VtxAttr.NormalElements == NormalComponentCount::NBT)
m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2;
}
for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++)
@ -493,14 +496,13 @@ void VertexLoaderARM64::GenerateVertexLoader()
if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent)
{
u32 align = 4;
if (m_VtxAttr.color[i].Comp == ColorFormat::RGB565 ||
m_VtxAttr.color[i].Comp == ColorFormat::RGBA4444)
if (m_VtxAttr.GetColorFormat(i) == ColorFormat::RGB565 ||
m_VtxAttr.GetColorFormat(i) == ColorFormat::RGBA4444)
align = 2;
s32 offset = GetAddressImm(ARRAY_COLOR0 + int(i), m_VtxDesc.low.Color[i],
EncodeRegTo64(scratch1_reg), align);
ReadColor(m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp, offset);
m_native_components |= VB_HAS_COL0 << i;
ReadColor(m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i), offset);
m_native_vtx_decl.colors[i].components = 4;
m_native_vtx_decl.colors[i].enable = true;
m_native_vtx_decl.colors[i].offset = m_dst_ofs;
@ -516,28 +518,23 @@ void VertexLoaderARM64::GenerateVertexLoader()
m_native_vtx_decl.texcoords[i].type = VAR_FLOAT;
m_native_vtx_decl.texcoords[i].integer = false;
int elements = m_VtxAttr.texCoord[i].Elements == TexComponentCount::S ? 1 : 2;
int elements = m_VtxAttr.GetTexElements(i) == TexComponentCount::S ? 1 : 2;
if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent)
{
m_native_components |= VB_HAS_UV0 << i;
int elem_size = GetElementSize(m_VtxAttr.texCoord[i].Format);
int elem_size = GetElementSize(m_VtxAttr.GetTexFormat(i));
int load_bytes = elem_size * (elements + 2);
int load_size = load_bytes == 1 ?
1 :
load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
int load_size = GetLoadSize(load_bytes);
load_size <<= 3;
s32 offset = GetAddressImm(ARRAY_TEXCOORD0 + int(i), m_VtxDesc.high.TexCoord[i],
EncodeRegTo64(scratch1_reg), load_size);
u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac;
ReadVertex(m_VtxDesc.high.TexCoord[i], m_VtxAttr.texCoord[i].Format, elements,
m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.ByteDequant, scaling_exponent,
&m_native_vtx_decl.texcoords[i], offset);
u8 scaling_exponent = m_VtxAttr.GetTexFrac(i);
ReadVertex(m_VtxDesc.high.TexCoord[i], m_VtxAttr.GetTexFormat(i), elements,
m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.g0.ByteDequant,
scaling_exponent, &m_native_vtx_decl.texcoords[i], offset);
}
if (m_VtxDesc.low.TexMatIdx[i])
{
m_native_components |= VB_HAS_TEXMTXIDX0 << i;
m_native_vtx_decl.texcoords[i].components = 3;
m_native_vtx_decl.texcoords[i].enable = true;
m_native_vtx_decl.texcoords[i].type = VAR_FLOAT;
@ -603,7 +600,7 @@ void VertexLoaderARM64::GenerateVertexLoader()
FlushIcache();
m_VertexSize = m_src_ofs;
ASSERT(m_vertex_size == m_src_ofs);
m_native_vtx_decl.stride = m_dst_ofs;
}

View File

@ -19,8 +19,6 @@ public:
VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_att);
protected:
std::string GetName() const override { return "VertexLoaderARM64"; }
bool IsInitialized() override { return true; }
int RunVertices(DataReader src, DataReader dst, int count) override;
private:

View File

@ -19,6 +19,10 @@
#include "VideoCommon/DataReader.h"
#include "VideoCommon/VertexLoader.h"
#include "VideoCommon/VertexLoader_Color.h"
#include "VideoCommon/VertexLoader_Normal.h"
#include "VideoCommon/VertexLoader_Position.h"
#include "VideoCommon/VertexLoader_TextCoord.h"
#ifdef _M_X86_64
#include "VideoCommon/VertexLoaderX64.h"
@ -26,93 +30,6 @@
#include "VideoCommon/VertexLoaderARM64.h"
#endif
VertexLoaderBase::VertexLoaderBase(const TVtxDesc& vtx_desc, const VAT& vtx_attr)
: m_VtxDesc{vtx_desc}, m_vat{vtx_attr}
{
SetVAT(vtx_attr);
}
void VertexLoaderBase::SetVAT(const VAT& vat)
{
m_VtxAttr.PosElements = vat.g0.PosElements;
m_VtxAttr.PosFormat = vat.g0.PosFormat;
m_VtxAttr.PosFrac = vat.g0.PosFrac;
m_VtxAttr.NormalElements = vat.g0.NormalElements;
m_VtxAttr.NormalFormat = vat.g0.NormalFormat;
m_VtxAttr.color[0].Elements = vat.g0.Color0Elements;
m_VtxAttr.color[0].Comp = vat.g0.Color0Comp;
m_VtxAttr.color[1].Elements = vat.g0.Color1Elements;
m_VtxAttr.color[1].Comp = vat.g0.Color1Comp;
m_VtxAttr.texCoord[0].Elements = vat.g0.Tex0CoordElements;
m_VtxAttr.texCoord[0].Format = vat.g0.Tex0CoordFormat;
m_VtxAttr.texCoord[0].Frac = vat.g0.Tex0Frac;
m_VtxAttr.ByteDequant = vat.g0.ByteDequant;
m_VtxAttr.NormalIndex3 = vat.g0.NormalIndex3;
m_VtxAttr.texCoord[1].Elements = vat.g1.Tex1CoordElements;
m_VtxAttr.texCoord[1].Format = vat.g1.Tex1CoordFormat;
m_VtxAttr.texCoord[1].Frac = vat.g1.Tex1Frac;
m_VtxAttr.texCoord[2].Elements = vat.g1.Tex2CoordElements;
m_VtxAttr.texCoord[2].Format = vat.g1.Tex2CoordFormat;
m_VtxAttr.texCoord[2].Frac = vat.g1.Tex2Frac;
m_VtxAttr.texCoord[3].Elements = vat.g1.Tex3CoordElements;
m_VtxAttr.texCoord[3].Format = vat.g1.Tex3CoordFormat;
m_VtxAttr.texCoord[3].Frac = vat.g1.Tex3Frac;
m_VtxAttr.texCoord[4].Elements = vat.g1.Tex4CoordElements;
m_VtxAttr.texCoord[4].Format = vat.g1.Tex4CoordFormat;
m_VtxAttr.texCoord[4].Frac = vat.g2.Tex4Frac;
m_VtxAttr.texCoord[5].Elements = vat.g2.Tex5CoordElements;
m_VtxAttr.texCoord[5].Format = vat.g2.Tex5CoordFormat;
m_VtxAttr.texCoord[5].Frac = vat.g2.Tex5Frac;
m_VtxAttr.texCoord[6].Elements = vat.g2.Tex6CoordElements;
m_VtxAttr.texCoord[6].Format = vat.g2.Tex6CoordFormat;
m_VtxAttr.texCoord[6].Frac = vat.g2.Tex6Frac;
m_VtxAttr.texCoord[7].Elements = vat.g2.Tex7CoordElements;
m_VtxAttr.texCoord[7].Format = vat.g2.Tex7CoordFormat;
m_VtxAttr.texCoord[7].Frac = vat.g2.Tex7Frac;
};
std::string VertexLoaderBase::ToString() const
{
std::string dest;
dest.reserve(250);
dest += GetName();
dest += ": ";
dest += fmt::format("{}b skin: {} P: {} {}-{} ", m_VertexSize, m_VtxDesc.low.PosMatIdx,
m_VtxAttr.PosElements, m_VtxDesc.low.Position, m_VtxAttr.PosFormat);
if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{
dest += fmt::format("Nrm: {} {}-{} ", m_VtxAttr.NormalElements, m_VtxDesc.low.Normal,
m_VtxAttr.NormalFormat);
}
for (size_t i = 0; i < g_main_cp_state.vtx_desc.low.Color.Size(); i++)
{
if (g_main_cp_state.vtx_desc.low.Color[i] == VertexComponentFormat::NotPresent)
continue;
const auto& color = m_VtxAttr.color[i];
dest += fmt::format("C{}: {} {}-{} ", i, color.Elements, g_main_cp_state.vtx_desc.low.Color[i],
color.Comp);
}
for (size_t i = 0; i < g_main_cp_state.vtx_desc.high.TexCoord.Size(); i++)
{
if (g_main_cp_state.vtx_desc.high.TexCoord[i] == VertexComponentFormat::NotPresent)
continue;
const auto& tex_coord = m_VtxAttr.texCoord[i];
dest += fmt::format("T{}: {} {}-{} ", i, tex_coord.Elements,
g_main_cp_state.vtx_desc.high.TexCoord[i], tex_coord.Format);
}
dest += fmt::format(" - {} v", m_numLoadedVertices);
return dest;
}
// a hacky implementation to compare two vertex loaders
class VertexLoaderTester : public VertexLoaderBase
{
@ -121,31 +38,25 @@ public:
const TVtxDesc& vtx_desc, const VAT& vtx_attr)
: VertexLoaderBase(vtx_desc, vtx_attr), a(std::move(a_)), b(std::move(b_))
{
m_initialized = a && b && a->IsInitialized() && b->IsInitialized();
if (m_initialized)
ASSERT(a && b);
if (a->m_vertex_size == b->m_vertex_size && a->m_native_components == b->m_native_components &&
a->m_native_vtx_decl.stride == b->m_native_vtx_decl.stride)
{
m_initialized = a->m_VertexSize == b->m_VertexSize &&
a->m_native_components == b->m_native_components &&
a->m_native_vtx_decl.stride == b->m_native_vtx_decl.stride;
// These are generated from the VAT and vertex desc, so they should match.
// m_native_vtx_decl.stride isn't set yet, though.
ASSERT(m_vertex_size == a->m_vertex_size && m_native_components == a->m_native_components);
if (m_initialized)
{
m_VertexSize = a->m_VertexSize;
m_native_components = a->m_native_components;
memcpy(&m_native_vtx_decl, &a->m_native_vtx_decl, sizeof(PortableVertexDeclaration));
}
else
{
ERROR_LOG_FMT(VIDEO, "Can't compare vertex loaders that expect different vertex formats!");
ERROR_LOG_FMT(VIDEO, "a: m_VertexSize {}, m_native_components {:#010x}, stride {}",
a->m_VertexSize, a->m_native_components, a->m_native_vtx_decl.stride);
ERROR_LOG_FMT(VIDEO, "b: m_VertexSize {}, m_native_components {:#010x}, stride {}",
b->m_VertexSize, b->m_native_components, b->m_native_vtx_decl.stride);
}
memcpy(&m_native_vtx_decl, &a->m_native_vtx_decl, sizeof(PortableVertexDeclaration));
}
else
{
PanicAlertFmt("Can't compare vertex loaders that expect different vertex formats!\n"
"a: m_vertex_size {}, m_native_components {:#010x}, stride {}\n"
"b: m_vertex_size {}, m_native_components {:#010x}, stride {}",
a->m_vertex_size, a->m_native_components, a->m_native_vtx_decl.stride,
b->m_vertex_size, b->m_native_components, b->m_native_vtx_decl.stride);
}
}
~VertexLoaderTester() override {}
int RunVertices(DataReader src, DataReader dst, int count) override
{
buffer_a.resize(count * a->m_native_vtx_decl.stride + 4);
@ -168,22 +79,17 @@ public:
std::min(count_a, count_b) * m_native_vtx_decl.stride))
{
ERROR_LOG_FMT(VIDEO,
"The two vertex loaders have loaded different data "
"(guru meditation {:#010x}, {:#010x}, {:#010x}, {:#010x}, {:#010x}).",
m_VtxDesc.low.Hex, m_VtxDesc.high.Hex, m_vat.g0.Hex, m_vat.g1.Hex,
m_vat.g2.Hex);
"The two vertex loaders have loaded different data. Configuration:"
"\nVertex desc:\n{}\n\nVertex attr:\n{}",
m_VtxDesc, m_VtxAttr);
}
memcpy(dst.GetPointer(), buffer_a.data(), count_a * m_native_vtx_decl.stride);
m_numLoadedVertices += count;
return count_a;
}
std::string GetName() const override { return "CompareLoader"; }
bool IsInitialized() override { return m_initialized; }
private:
bool m_initialized;
std::unique_ptr<VertexLoaderBase> a;
std::unique_ptr<VertexLoaderBase> b;
@ -191,36 +97,112 @@ private:
std::vector<u8> buffer_b;
};
template <class Function>
static void GetComponentSizes(const TVtxDesc& vtx_desc, const VAT& vtx_attr, Function f)
{
if (vtx_desc.low.PosMatIdx)
f(1);
for (auto texmtxidx : vtx_desc.low.TexMatIdx)
{
if (texmtxidx)
f(1);
}
const u32 pos_size = VertexLoader_Position::GetSize(vtx_desc.low.Position, vtx_attr.g0.PosFormat,
vtx_attr.g0.PosElements);
if (pos_size != 0)
f(pos_size);
const u32 norm_size =
VertexLoader_Normal::GetSize(vtx_desc.low.Normal, vtx_attr.g0.NormalFormat,
vtx_attr.g0.NormalElements, vtx_attr.g0.NormalIndex3);
if (norm_size != 0)
f(norm_size);
for (u32 i = 0; i < vtx_desc.low.Color.Size(); i++)
{
const u32 color_size =
VertexLoader_Color::GetSize(vtx_desc.low.Color[i], vtx_attr.GetColorFormat(i));
if (color_size != 0)
f(color_size);
}
for (u32 i = 0; i < vtx_desc.high.TexCoord.Size(); i++)
{
const u32 tc_size = VertexLoader_TextCoord::GetSize(
vtx_desc.high.TexCoord[i], vtx_attr.GetTexFormat(i), vtx_attr.GetTexElements(i));
if (tc_size != 0)
f(tc_size);
}
}
u32 VertexLoaderBase::GetVertexSize(const TVtxDesc& vtx_desc, const VAT& vtx_attr)
{
u32 size = 0;
GetComponentSizes(vtx_desc, vtx_attr, [&size](u32 s) { size += s; });
return size;
}
u32 VertexLoaderBase::GetVertexComponents(const TVtxDesc& vtx_desc, const VAT& vtx_attr)
{
u32 components = 0;
if (vtx_desc.low.PosMatIdx)
components |= VB_HAS_POSMTXIDX;
for (u32 i = 0; i < vtx_desc.low.TexMatIdx.Size(); i++)
{
if (vtx_desc.low.TexMatIdx[i])
components |= VB_HAS_TEXMTXIDX0 << i;
}
// Vertices always have positions; thus there is no VB_HAS_POS as it would always be set
if (vtx_desc.low.Normal != VertexComponentFormat::NotPresent)
{
components |= VB_HAS_NRM0;
if (vtx_attr.g0.NormalElements == NormalComponentCount::NBT)
components |= VB_HAS_NRM1 | VB_HAS_NRM2;
}
for (u32 i = 0; i < vtx_desc.low.Color.Size(); i++)
{
if (vtx_desc.low.Color[i] != VertexComponentFormat::NotPresent)
components |= VB_HAS_COL0 << i;
}
for (u32 i = 0; i < vtx_desc.high.TexCoord.Size(); i++)
{
if (vtx_desc.high.TexCoord[i] != VertexComponentFormat::NotPresent)
components |= VB_HAS_UV0 << i;
}
return components;
}
std::vector<u32> VertexLoaderBase::GetVertexComponentSizes(const TVtxDesc& vtx_desc,
const VAT& vtx_attr)
{
std::vector<u32> sizes;
GetComponentSizes(vtx_desc, vtx_attr, [&sizes](u32 s) { sizes.push_back(s); });
return sizes;
}
std::unique_ptr<VertexLoaderBase> VertexLoaderBase::CreateVertexLoader(const TVtxDesc& vtx_desc,
const VAT& vtx_attr)
{
std::unique_ptr<VertexLoaderBase> loader;
std::unique_ptr<VertexLoaderBase> loader = nullptr;
//#define COMPARE_VERTEXLOADERS
#if defined(COMPARE_VERTEXLOADERS) && defined(_M_X86_64)
// first try: Any new VertexLoader vs the old one
loader = std::make_unique<VertexLoaderTester>(
std::make_unique<VertexLoader>(vtx_desc, vtx_attr), // the software one
std::make_unique<VertexLoaderX64>(vtx_desc, vtx_attr), // the new one to compare
vtx_desc, vtx_attr);
if (loader->IsInitialized())
return loader;
#elif defined(_M_X86_64)
#if defined(_M_X86_64)
loader = std::make_unique<VertexLoaderX64>(vtx_desc, vtx_attr);
if (loader->IsInitialized())
return loader;
#elif defined(_M_ARM_64)
loader = std::make_unique<VertexLoaderARM64>(vtx_desc, vtx_attr);
if (loader->IsInitialized())
return loader;
#endif
// last try: The old VertexLoader
loader = std::make_unique<VertexLoader>(vtx_desc, vtx_attr);
if (loader->IsInitialized())
return loader;
// Use the software loader as a fallback
// (not currently applicable, as both VertexLoaderX64 and VertexLoaderARM64
// are always usable, but if a loader that only works on some CPUs is created
// then this fallback would be used)
if (!loader)
loader = std::make_unique<VertexLoader>(vtx_desc, vtx_attr);
PanicAlertFmt("No Vertex Loader found.");
return nullptr;
#if defined(COMPARE_VERTEXLOADERS)
return std::make_unique<VertexLoaderTester>(
std::make_unique<VertexLoader>(vtx_desc, vtx_attr), // the software one
std::move(loader), // the new one to compare
vtx_desc, vtx_attr);
#else
return loader;
#endif
}

View File

@ -7,6 +7,7 @@
#include <array>
#include <memory>
#include <string>
#include <vector>
#include "Common/CommonTypes.h"
#include "VideoCommon/CPMemory.h"
@ -60,33 +61,31 @@ struct hash<VertexLoaderUID>
class VertexLoaderBase
{
public:
static u32 GetVertexSize(const TVtxDesc& vtx_desc, const VAT& vtx_attr);
static u32 GetVertexComponents(const TVtxDesc& vtx_desc, const VAT& vtx_attr);
static std::vector<u32> GetVertexComponentSizes(const TVtxDesc& vtx_desc, const VAT& vtx_attr);
static std::unique_ptr<VertexLoaderBase> CreateVertexLoader(const TVtxDesc& vtx_desc,
const VAT& vtx_attr);
virtual ~VertexLoaderBase() {}
virtual int RunVertices(DataReader src, DataReader dst, int count) = 0;
virtual bool IsInitialized() = 0;
// For debugging / profiling
std::string ToString() const;
virtual std::string GetName() const = 0;
// per loader public state
int m_VertexSize = 0; // number of bytes of a raw GC vertex
PortableVertexDeclaration m_native_vtx_decl{};
u32 m_native_components = 0;
const u32 m_vertex_size; // number of bytes of a raw GC vertex
const u32 m_native_components;
// used by VertexLoaderManager
NativeVertexFormat* m_native_vertex_format = nullptr;
int m_numLoadedVertices = 0;
protected:
VertexLoaderBase(const TVtxDesc& vtx_desc, const VAT& vtx_attr);
void SetVAT(const VAT& vat);
VertexLoaderBase(const TVtxDesc& vtx_desc, const VAT& vtx_attr)
: m_VtxDesc{vtx_desc}, m_VtxAttr{vtx_attr}, m_vertex_size{GetVertexSize(vtx_desc, vtx_attr)},
m_native_components{GetVertexComponents(vtx_desc, vtx_attr)}
{
}
// GC vertex format
TVtxAttr m_VtxAttr; // VAT decoded into easy format
TVtxDesc m_VtxDesc; // Not really used currently - or well it is, but could be easily avoided.
VAT m_vat;
const VAT m_VtxAttr;
const TVtxDesc m_VtxDesc;
};

View File

@ -114,34 +114,6 @@ struct entry
};
} // namespace
std::string VertexLoadersToString()
{
std::lock_guard<std::mutex> lk(s_vertex_loader_map_lock);
std::vector<entry> entries;
size_t total_size = 0;
for (const auto& map_entry : s_vertex_loader_map)
{
entry e = {map_entry.second->ToString(),
static_cast<u64>(map_entry.second->m_numLoadedVertices)};
total_size += e.text.size() + 1;
entries.push_back(std::move(e));
}
sort(entries.begin(), entries.end());
std::string dest;
dest.reserve(total_size);
for (const entry& entry : entries)
{
dest += entry.text;
dest += '\n';
}
return dest;
}
void MarkAllDirty()
{
g_main_cp_state.attr_dirty = BitSet32::AllTrue(8);
@ -275,7 +247,7 @@ int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bo
VertexLoaderBase* loader = RefreshLoader(vtx_attr_group, is_preprocess);
int size = count * loader->m_VertexSize;
int size = count * loader->m_vertex_size;
if ((int)src.size() < size)
return -1;

View File

@ -38,9 +38,6 @@ NativeVertexFormat* GetUberVertexFormat(const PortableVertexDeclaration& decl);
// Returns -1 if buf_size is insufficient, else the amount of bytes consumed
int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bool is_preprocess);
// For debugging
std::string VertexLoadersToString();
NativeVertexFormat* GetCurrentVertexFormat();
// Resolved pointers to array bases. Used by vertex loaders.

View File

@ -45,15 +45,13 @@ static OpArg MPIC(const void* ptr)
VertexLoaderX64::VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att)
: VertexLoaderBase(vtx_desc, vtx_att)
{
if (!IsInitialized())
return;
AllocCodeSpace(4096);
ClearCodeSpace();
GenerateVertexLoader();
WriteProtect();
const std::string name = ToString();
const std::string name =
fmt::format("VertexLoaderX64\nVtx desc: \n{}\nVAT:\n{}", vtx_desc, vtx_att);
JitRegister::Register(region, GetCodePtr(), name.c_str());
}
@ -420,7 +418,6 @@ void VertexLoaderX64::GenerateVertexLoader()
MOV(32, MPIC(VertexLoaderManager::position_matrix_index, count_reg, SCALE_4), R(scratch1));
SetJumpTarget(dont_store);
m_native_components |= VB_HAS_POSMTXIDX;
m_native_vtx_decl.posmtx.components = 4;
m_native_vtx_decl.posmtx.enable = true;
m_native_vtx_decl.posmtx.offset = m_dst_ofs;
@ -438,31 +435,27 @@ void VertexLoaderX64::GenerateVertexLoader()
}
OpArg data = GetVertexAddr(ARRAY_POSITION, m_VtxDesc.low.Position);
int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3;
ReadVertex(data, m_VtxDesc.low.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements,
m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position);
int pos_elements = m_VtxAttr.g0.PosElements == CoordComponentCount::XY ? 2 : 3;
ReadVertex(data, m_VtxDesc.low.Position, m_VtxAttr.g0.PosFormat, pos_elements, pos_elements,
m_VtxAttr.g0.ByteDequant, m_VtxAttr.g0.PosFrac, &m_native_vtx_decl.position);
if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{
static const u8 map[8] = {7, 6, 15, 14};
const u8 scaling_exponent = map[u32(m_VtxAttr.NormalFormat)];
const int limit = m_VtxAttr.NormalElements == NormalComponentCount::NBT ? 3 : 1;
const u8 scaling_exponent = map[u32(m_VtxAttr.g0.NormalFormat.Value())];
const int limit = m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT ? 3 : 1;
for (int i = 0; i < limit; i++)
{
if (!i || m_VtxAttr.NormalIndex3)
if (!i || m_VtxAttr.g0.NormalIndex3)
{
data = GetVertexAddr(ARRAY_NORMAL, m_VtxDesc.low.Normal);
int elem_size = GetElementSize(m_VtxAttr.NormalFormat);
int elem_size = GetElementSize(m_VtxAttr.g0.NormalFormat);
data.AddMemOffset(i * elem_size * 3);
}
data.AddMemOffset(ReadVertex(data, m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, 3, 3, true,
scaling_exponent, &m_native_vtx_decl.normals[i]));
data.AddMemOffset(ReadVertex(data, m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, 3, 3,
true, scaling_exponent, &m_native_vtx_decl.normals[i]));
}
m_native_components |= VB_HAS_NRM0;
if (m_VtxAttr.NormalElements == NormalComponentCount::NBT)
m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2;
}
for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++)
@ -470,8 +463,7 @@ void VertexLoaderX64::GenerateVertexLoader()
if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent)
{
data = GetVertexAddr(ARRAY_COLOR0 + int(i), m_VtxDesc.low.Color[i]);
ReadColor(data, m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp);
m_native_components |= VB_HAS_COL0 << i;
ReadColor(data, m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i));
m_native_vtx_decl.colors[i].components = 4;
m_native_vtx_decl.colors[i].enable = true;
m_native_vtx_decl.colors[i].offset = m_dst_ofs;
@ -483,19 +475,17 @@ void VertexLoaderX64::GenerateVertexLoader()
for (size_t i = 0; i < m_VtxDesc.high.TexCoord.Size(); i++)
{
int elements = m_VtxAttr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1;
int elements = m_VtxAttr.GetTexElements(i) == TexComponentCount::ST ? 2 : 1;
if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent)
{
data = GetVertexAddr(ARRAY_TEXCOORD0 + int(i), m_VtxDesc.high.TexCoord[i]);
u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac;
ReadVertex(data, m_VtxDesc.high.TexCoord[i], m_VtxAttr.texCoord[i].Format, elements,
m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.ByteDequant, scaling_exponent,
&m_native_vtx_decl.texcoords[i]);
m_native_components |= VB_HAS_UV0 << i;
u8 scaling_exponent = m_VtxAttr.GetTexFrac(i);
ReadVertex(data, m_VtxDesc.high.TexCoord[i], m_VtxAttr.GetTexFormat(i), elements,
m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.g0.ByteDequant,
scaling_exponent, &m_native_vtx_decl.texcoords[i]);
}
if (m_VtxDesc.low.TexMatIdx[i])
{
m_native_components |= VB_HAS_TEXMTXIDX0 << i;
m_native_vtx_decl.texcoords[i].components = 3;
m_native_vtx_decl.texcoords[i].enable = true;
m_native_vtx_decl.texcoords[i].type = VAR_FLOAT;
@ -546,7 +536,7 @@ void VertexLoaderX64::GenerateVertexLoader()
RET();
}
m_VertexSize = m_src_ofs;
ASSERT(m_vertex_size == m_src_ofs);
m_native_vtx_decl.stride = m_dst_ofs;
}

View File

@ -18,8 +18,6 @@ public:
VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att);
protected:
std::string GetName() const override { return "VertexLoaderX64"; }
bool IsInitialized() override { return true; }
int RunVertices(DataReader src, DataReader dst, int count) override;
private:

View File

@ -5,6 +5,7 @@
#include <cstring>
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "Common/Swap.h"
#include "VideoCommon/VertexLoader.h"
@ -136,7 +137,6 @@ void Color_ReadIndex_32b_8888(VertexLoader* loader)
(index * g_main_cp_state.array_strides[ARRAY_COLOR0 + loader->m_colIndex]);
SetCol(loader, Read32(address));
}
} // Anonymous namespace
void Color_ReadDirect_24b_888(VertexLoader* loader)
{
@ -149,10 +149,12 @@ void Color_ReadDirect_32b_888x(VertexLoader* loader)
SetCol(loader, Read24(DataGetPosition()));
DataSkip(4);
}
void Color_ReadDirect_16b_565(VertexLoader* loader)
{
SetCol565(loader, DataRead<u16>());
}
void Color_ReadDirect_16b_4444(VertexLoader* loader)
{
u16 value;
@ -161,62 +163,52 @@ void Color_ReadDirect_16b_4444(VertexLoader* loader)
SetCol4444(loader, value);
DataSkip(2);
}
void Color_ReadDirect_24b_6666(VertexLoader* loader)
{
SetCol6666(loader, Common::swap32(DataGetPosition() - 1));
DataSkip(3);
}
void Color_ReadDirect_32b_8888(VertexLoader* loader)
{
SetCol(loader, DataReadU32Unswapped());
}
void Color_ReadIndex8_16b_565(VertexLoader* loader)
constexpr TPipelineFunction s_table_read_color[4][6] = {
{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{Color_ReadDirect_16b_565, Color_ReadDirect_24b_888, Color_ReadDirect_32b_888x,
Color_ReadDirect_16b_4444, Color_ReadDirect_24b_6666, Color_ReadDirect_32b_8888},
{Color_ReadIndex_16b_565<u8>, Color_ReadIndex_24b_888<u8>, Color_ReadIndex_32b_888x<u8>,
Color_ReadIndex_16b_4444<u8>, Color_ReadIndex_24b_6666<u8>, Color_ReadIndex_32b_8888<u8>},
{Color_ReadIndex_16b_565<u16>, Color_ReadIndex_24b_888<u16>, Color_ReadIndex_32b_888x<u16>,
Color_ReadIndex_16b_4444<u16>, Color_ReadIndex_24b_6666<u16>, Color_ReadIndex_32b_8888<u16>},
};
constexpr u32 s_table_read_color_vertex_size[4][6] = {
{0, 0, 0, 0, 0, 0},
{2, 3, 4, 2, 3, 4},
{1, 1, 1, 1, 1, 1},
{2, 2, 2, 2, 2, 2},
};
} // Anonymous namespace
u32 VertexLoader_Color::GetSize(VertexComponentFormat type, ColorFormat format)
{
Color_ReadIndex_16b_565<u8>(loader);
}
void Color_ReadIndex8_24b_888(VertexLoader* loader)
{
Color_ReadIndex_24b_888<u8>(loader);
}
void Color_ReadIndex8_32b_888x(VertexLoader* loader)
{
Color_ReadIndex_32b_888x<u8>(loader);
}
void Color_ReadIndex8_16b_4444(VertexLoader* loader)
{
Color_ReadIndex_16b_4444<u8>(loader);
}
void Color_ReadIndex8_24b_6666(VertexLoader* loader)
{
Color_ReadIndex_24b_6666<u8>(loader);
}
void Color_ReadIndex8_32b_8888(VertexLoader* loader)
{
Color_ReadIndex_32b_8888<u8>(loader);
if (format > ColorFormat::RGBA8888)
{
PanicAlertFmt("Invalid color format {}", format);
return 0;
}
return s_table_read_color_vertex_size[u32(type)][u32(format)];
}
void Color_ReadIndex16_16b_565(VertexLoader* loader)
TPipelineFunction VertexLoader_Color::GetFunction(VertexComponentFormat type, ColorFormat format)
{
Color_ReadIndex_16b_565<u16>(loader);
}
void Color_ReadIndex16_24b_888(VertexLoader* loader)
{
Color_ReadIndex_24b_888<u16>(loader);
}
void Color_ReadIndex16_32b_888x(VertexLoader* loader)
{
Color_ReadIndex_32b_888x<u16>(loader);
}
void Color_ReadIndex16_16b_4444(VertexLoader* loader)
{
Color_ReadIndex_16b_4444<u16>(loader);
}
void Color_ReadIndex16_24b_6666(VertexLoader* loader)
{
Color_ReadIndex_24b_6666<u16>(loader);
}
void Color_ReadIndex16_32b_8888(VertexLoader* loader)
{
Color_ReadIndex_32b_8888<u16>(loader);
if (format > ColorFormat::RGBA8888)
{
PanicAlertFmt("Invalid color format {}", format);
return nullptr;
}
return s_table_read_color[u32(type)][u32(format)];
}

View File

@ -4,25 +4,15 @@
#pragma once
class VertexLoader;
#include "Common/CommonTypes.h"
#include "VideoCommon/VertexLoader.h"
void Color_ReadDirect_24b_888(VertexLoader* loader);
void Color_ReadDirect_32b_888x(VertexLoader* loader);
void Color_ReadDirect_16b_565(VertexLoader* loader);
void Color_ReadDirect_16b_4444(VertexLoader* loader);
void Color_ReadDirect_24b_6666(VertexLoader* loader);
void Color_ReadDirect_32b_8888(VertexLoader* loader);
enum class VertexComponentFormat;
enum class ColorFormat;
void Color_ReadIndex8_16b_565(VertexLoader* loader);
void Color_ReadIndex8_24b_888(VertexLoader* loader);
void Color_ReadIndex8_32b_888x(VertexLoader* loader);
void Color_ReadIndex8_16b_4444(VertexLoader* loader);
void Color_ReadIndex8_24b_6666(VertexLoader* loader);
void Color_ReadIndex8_32b_8888(VertexLoader* loader);
void Color_ReadIndex16_16b_565(VertexLoader* loader);
void Color_ReadIndex16_24b_888(VertexLoader* loader);
void Color_ReadIndex16_32b_888x(VertexLoader* loader);
void Color_ReadIndex16_16b_4444(VertexLoader* loader);
void Color_ReadIndex16_24b_6666(VertexLoader* loader);
void Color_ReadIndex16_32b_8888(VertexLoader* loader);
class VertexLoader_Color
{
public:
static u32 GetSize(VertexComponentFormat type, ColorFormat format);
static TPipelineFunction GetFunction(VertexComponentFormat type, ColorFormat format);
};

View File

@ -259,12 +259,19 @@ void LoadXFReg(u32 transferSize, u32 baseAddress, DataReader src)
}
}
constexpr std::tuple<u32, u32, u32> ExtractIndexedXF(u32 val)
{
const u32 index = val >> 16;
const u32 address = val & 0xFFF; // check mask
const u32 size = ((val >> 12) & 0xF) + 1;
return {index, address, size};
}
// TODO - verify that it is correct. Seems to work, though.
void LoadIndexedXF(u32 val, int refarray)
{
int index = val >> 16;
int address = val & 0xFFF; // check mask
int size = ((val >> 12) & 0xF) + 1;
const auto [index, address, size] = ExtractIndexedXF(val);
// load stuff from array to address in xf mem
u32* currData = (u32*)(&xfmem) + address;
@ -279,7 +286,7 @@ void LoadIndexedXF(u32 val, int refarray)
g_main_cp_state.array_strides[refarray] * index);
}
bool changed = false;
for (int i = 0; i < size; ++i)
for (u32 i = 0; i < size; ++i)
{
if (currData[i] != Common::swap32(newData[i]))
{
@ -290,15 +297,14 @@ void LoadIndexedXF(u32 val, int refarray)
}
if (changed)
{
for (int i = 0; i < size; ++i)
for (u32 i = 0; i < size; ++i)
currData[i] = Common::swap32(newData[i]);
}
}
void PreprocessIndexedXF(u32 val, int refarray)
{
const u32 index = val >> 16;
const u32 size = ((val >> 12) & 0xF) + 1;
const auto [index, address, size] = ExtractIndexedXF(val);
const u8* new_data = Memory::GetPointer(g_preprocess_cp_state.array_bases[refarray] +
g_preprocess_cp_state.array_strides[refarray] * index);
@ -643,3 +649,18 @@ std::pair<std::string, std::string> GetXFTransferInfo(const u8* data)
return std::make_pair(fmt::to_string(name), fmt::to_string(desc));
}
std::pair<std::string, std::string> GetXFIndexedLoadInfo(u8 array, u32 value)
{
const auto [index, address, size] = ExtractIndexedXF(value);
const auto desc = fmt::format("Load {} bytes to XF address {:03x} from CP array {} row {}", size,
address, array, index);
fmt::memory_buffer written;
for (u32 i = 0; i < size; i++)
{
fmt::format_to(written, "{}\n", GetXFMemName(address + i));
}
return std::make_pair(desc, fmt::to_string(written));
}

View File

@ -13,3 +13,4 @@ std::pair<std::string, std::string> GetXFRegInfo(u32 address, u32 value);
std::string GetXFMemName(u32 address);
std::string GetXFMemDescription(u32 address, u32 value);
std::pair<std::string, std::string> GetXFTransferInfo(const u8* data);
std::pair<std::string, std::string> GetXFIndexedLoadInfo(u8 array, u32 value);