Convert CPMemory to BitField and enum class

Additionally, VCacheEnhance has been added to UVAT_group1.  According to YAGCD, this field is always 1.

TVtxDesc also now has separate low and high fields whose hex values correspond with the proper registers, instead of having one 33-bit value.  This change was made in a way that should be backwards-compatible.
This commit is contained in:
Pokechu22 2021-02-08 15:22:10 -08:00
parent c27efb3f1f
commit f749fcfa9f
21 changed files with 705 additions and 603 deletions

View File

@ -49,21 +49,17 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
const VAT& vtxAttr = cpMem.vtxAttr[vatIndex]; const VAT& vtxAttr = cpMem.vtxAttr[vatIndex];
// Colors // Colors
const std::array<u64, 2> colDesc{ const std::array<ColorFormat, 2> colComp{
vtxDesc.Color0,
vtxDesc.Color1,
};
const std::array<u32, 2> colComp{
vtxAttr.g0.Color0Comp, vtxAttr.g0.Color0Comp,
vtxAttr.g0.Color1Comp, vtxAttr.g0.Color1Comp,
}; };
const std::array<u32, 8> tcElements{ const std::array<TexComponentCount, 8> tcElements{
vtxAttr.g0.Tex0CoordElements, vtxAttr.g1.Tex1CoordElements, vtxAttr.g1.Tex2CoordElements, vtxAttr.g0.Tex0CoordElements, vtxAttr.g1.Tex1CoordElements, vtxAttr.g1.Tex2CoordElements,
vtxAttr.g1.Tex3CoordElements, vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements, vtxAttr.g1.Tex3CoordElements, vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements,
vtxAttr.g2.Tex6CoordElements, vtxAttr.g2.Tex7CoordElements, vtxAttr.g2.Tex6CoordElements, vtxAttr.g2.Tex7CoordElements,
}; };
const std::array<u32, 8> tcFormat{ const std::array<ComponentFormat, 8> tcFormat{
vtxAttr.g0.Tex0CoordFormat, vtxAttr.g1.Tex1CoordFormat, vtxAttr.g1.Tex2CoordFormat, vtxAttr.g0.Tex0CoordFormat, vtxAttr.g1.Tex1CoordFormat, vtxAttr.g1.Tex2CoordFormat,
vtxAttr.g1.Tex3CoordFormat, vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat, vtxAttr.g1.Tex3CoordFormat, vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat,
vtxAttr.g2.Tex6CoordFormat, vtxAttr.g2.Tex7CoordFormat, vtxAttr.g2.Tex6CoordFormat, vtxAttr.g2.Tex7CoordFormat,
@ -72,21 +68,20 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
std::array<int, 21> sizes{}; std::array<int, 21> sizes{};
// Add position and texture matrix indices // Add position and texture matrix indices
u64 vtxDescHex = cpMem.vtxDesc.Hex; sizes[0] = vtxDesc.low.PosMatIdx;
for (int i = 0; i < 9; ++i) for (size_t i = 0; i < vtxDesc.low.TexMatIdx.Size(); ++i)
{ {
sizes[i] = vtxDescHex & 1; sizes[i + 1] = vtxDesc.low.TexMatIdx[i];
vtxDescHex >>= 1;
} }
// Position // Position
sizes[9] = VertexLoader_Position::GetSize(vtxDesc.Position, vtxAttr.g0.PosFormat, sizes[9] = VertexLoader_Position::GetSize(vtxDesc.low.Position, vtxAttr.g0.PosFormat,
vtxAttr.g0.PosElements); vtxAttr.g0.PosElements);
// Normals // Normals
if (vtxDesc.Normal != NOT_PRESENT) if (vtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{ {
sizes[10] = VertexLoader_Normal::GetSize(vtxDesc.Normal, vtxAttr.g0.NormalFormat, sizes[10] = VertexLoader_Normal::GetSize(vtxDesc.low.Normal, vtxAttr.g0.NormalFormat,
vtxAttr.g0.NormalElements, vtxAttr.g0.NormalIndex3); vtxAttr.g0.NormalElements, vtxAttr.g0.NormalIndex3);
} }
else else
@ -95,33 +90,33 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
} }
// Colors // Colors
for (size_t i = 0; i < colDesc.size(); i++) for (size_t i = 0; i < vtxDesc.low.Color.Size(); i++)
{ {
int size = 0; int size = 0;
switch (colDesc[i]) switch (vtxDesc.low.Color[i])
{ {
case NOT_PRESENT: case VertexComponentFormat::NotPresent:
break; break;
case DIRECT: case VertexComponentFormat::Direct:
switch (colComp[i]) switch (colComp[i])
{ {
case FORMAT_16B_565: case ColorFormat::RGB565:
size = 2; size = 2;
break; break;
case FORMAT_24B_888: case ColorFormat::RGB888:
size = 3; size = 3;
break; break;
case FORMAT_32B_888x: case ColorFormat::RGB888x:
size = 4; size = 4;
break; break;
case FORMAT_16B_4444: case ColorFormat::RGBA4444:
size = 2; size = 2;
break; break;
case FORMAT_24B_6666: case ColorFormat::RGBA6666:
size = 3; size = 3;
break; break;
case FORMAT_32B_8888: case ColorFormat::RGBA8888:
size = 4; size = 4;
break; break;
default: default:
@ -129,10 +124,10 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
break; break;
} }
break; break;
case INDEX8: case VertexComponentFormat::Index8:
size = 1; size = 1;
break; break;
case INDEX16: case VertexComponentFormat::Index16:
size = 2; size = 2;
break; break;
} }
@ -141,11 +136,10 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
} }
// Texture coordinates // Texture coordinates
vtxDescHex = vtxDesc.Hex >> 17;
for (size_t i = 0; i < tcFormat.size(); i++) for (size_t i = 0; i < tcFormat.size(); i++)
{ {
sizes[13 + i] = VertexLoader_TextCoord::GetSize(vtxDescHex & 3, tcFormat[i], tcElements[i]); sizes[13 + i] =
vtxDescHex >>= 2; VertexLoader_TextCoord::GetSize(vtxDesc.high.TexCoord[i], tcFormat[i], tcElements[i]);
} }
return sizes; return sizes;
@ -267,13 +261,11 @@ void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem)
switch (subCmd & 0xF0) switch (subCmd & 0xF0)
{ {
case 0x50: case 0x50:
cpMem.vtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits cpMem.vtxDesc.low.Hex = value;
cpMem.vtxDesc.Hex |= value;
break; break;
case 0x60: case 0x60:
cpMem.vtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits cpMem.vtxDesc.high.Hex = value;
cpMem.vtxDesc.Hex |= (u64)value << 17;
break; break;
case 0x70: case 0x70:

View File

@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include "Common/MsgHandler.h"
#include "Core/FifoPlayer/FifoAnalyzer.h" #include "Core/FifoPlayer/FifoAnalyzer.h"
#include "Core/FifoPlayer/FifoRecorder.h" #include "Core/FifoPlayer/FifoRecorder.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
@ -44,14 +45,28 @@ void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, const u8* vertexData,
int numVertices) int numVertices)
{ {
// Skip if not indexed array // Skip if not indexed array
int arrayType = (s_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3; VertexComponentFormat arrayType;
if (arrayType < 2) if (arrayIndex == ARRAY_POSITION)
arrayType = s_CpMem.vtxDesc.low.Position;
else if (arrayIndex == ARRAY_NORMAL)
arrayType = s_CpMem.vtxDesc.low.Normal;
else if (arrayIndex == ARRAY_COLOR || arrayIndex == ARRAY_COLOR2)
arrayType = s_CpMem.vtxDesc.low.Color[arrayIndex - ARRAY_COLOR];
else if (arrayIndex >= ARRAY_POSITION && arrayIndex < ARRAY_POSITION + 8)
arrayType = s_CpMem.vtxDesc.high.TexCoord[arrayIndex - ARRAY_POSITION];
else
{
PanicAlertFmt("Invalid arrayIndex {}", arrayIndex);
return;
}
if (!IsIndexed(arrayType))
return; return;
int maxIndex = 0; int maxIndex = 0;
// Determine min and max indices // Determine min and max indices
if (arrayType == INDEX8) if (arrayType == VertexComponentFormat::Index8)
{ {
for (int i = 0; i < numVertices; ++i) for (int i = 0; i < numVertices; ++i)
{ {

View File

@ -183,8 +183,8 @@ static void ParseColorAttributes(InputVertexData* dst, DataReader& src,
const auto set_default_color = [](u8* color, int i) { const auto set_default_color = [](u8* color, int i) {
// The default alpha channel seems to depend on the number of components in the vertex format. // The default alpha channel seems to depend on the number of components in the vertex format.
const auto& g0 = g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0; const auto& g0 = g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0;
const u32 color_elements = i == 0 ? g0.Color0Elements : g0.Color1Elements; const auto color_elements = i == 0 ? g0.Color0Elements.Value() : g0.Color1Elements.Value();
color[0] = color_elements == 0 ? 255 : 0; color[0] = color_elements == ColorComponentCount::RGB ? 255 : 0;
color[1] = 255; color[1] = 255;
color[2] = 255; color[2] = 255;
color[3] = 255; color[3] = 255;

View File

@ -17,7 +17,9 @@ void DoCPState(PointerWrap& p)
p.DoArray(g_main_cp_state.array_strides); p.DoArray(g_main_cp_state.array_strides);
p.Do(g_main_cp_state.matrix_index_a); p.Do(g_main_cp_state.matrix_index_a);
p.Do(g_main_cp_state.matrix_index_b); p.Do(g_main_cp_state.matrix_index_b);
p.Do(g_main_cp_state.vtx_desc.Hex); u64 vtx_desc = g_main_cp_state.vtx_desc.GetLegacyHex();
p.Do(vtx_desc);
g_main_cp_state.vtx_desc.SetLegacyHex(vtx_desc);
p.DoArray(g_main_cp_state.vtx_attr); p.DoArray(g_main_cp_state.vtx_attr);
p.DoMarker("CP Memory"); p.DoMarker("CP Memory");
if (p.mode == PointerWrap::MODE_READ) if (p.mode == PointerWrap::MODE_READ)

View File

@ -4,8 +4,11 @@
#pragma once #pragma once
#include "Common/BitField.h"
#include "Common/BitSet.h" #include "Common/BitSet.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/EnumFormatter.h"
#include "Common/MsgHandler.h"
enum enum
{ {
@ -50,176 +53,262 @@ enum
}; };
// Vertex components // Vertex components
enum enum class VertexComponentFormat
{ {
NOT_PRESENT = 0, NotPresent = 0,
DIRECT = 1, Direct = 1,
INDEX8 = 2, Index8 = 2,
INDEX16 = 3, Index16 = 3,
};
MASK_INDEXED = 2, template <>
struct fmt::formatter<VertexComponentFormat> : EnumFormatter<VertexComponentFormat::Index16>
{
formatter() : EnumFormatter({"Not present", "Direct", "8-bit index", "16-bit index"}) {}
}; };
enum constexpr bool IsIndexed(VertexComponentFormat format)
{ {
FORMAT_UBYTE = 0, // 2 Cmp return format == VertexComponentFormat::Index8 || format == VertexComponentFormat::Index16;
FORMAT_BYTE = 1, // 3 Cmp }
FORMAT_USHORT = 2,
FORMAT_SHORT = 3, enum class ComponentFormat
FORMAT_FLOAT = 4, {
UByte = 0, // Invalid for normals
Byte = 1,
UShort = 2, // Invalid for normals
Short = 3,
Float = 4,
};
template <>
struct fmt::formatter<ComponentFormat> : EnumFormatter<ComponentFormat::Float>
{
formatter() : EnumFormatter({"Unsigned Byte", "Byte", "Unsigned Short", "Short", "Float"}) {}
}; };
enum constexpr u32 GetElementSize(ComponentFormat format)
{ {
FORMAT_16B_565 = 0, // NA switch (format)
FORMAT_24B_888 = 1,
FORMAT_32B_888x = 2,
FORMAT_16B_4444 = 3,
FORMAT_24B_6666 = 4,
FORMAT_32B_8888 = 5,
};
#pragma pack(4)
union TVtxDesc
{
u64 Hex;
struct
{ {
// 0: not present case ComponentFormat::UByte:
// 1: present case ComponentFormat::Byte:
u64 PosMatIdx : 1; return 1;
u64 Tex0MatIdx : 1; case ComponentFormat::UShort:
u64 Tex1MatIdx : 1; case ComponentFormat::Short:
u64 Tex2MatIdx : 1; return 2;
u64 Tex3MatIdx : 1; case ComponentFormat::Float:
u64 Tex4MatIdx : 1; return 4;
u64 Tex5MatIdx : 1; default:
u64 Tex6MatIdx : 1; PanicAlertFmt("Unknown format {}", format);
u64 Tex7MatIdx : 1; return 0;
}
}
// 00: not present enum class CoordComponentCount
// 01: direct {
// 10: 8 bit index XY = 0,
// 11: 16 bit index XYZ = 1,
u64 Position : 2; };
u64 Normal : 2; template <>
u64 Color0 : 2; struct fmt::formatter<CoordComponentCount> : EnumFormatter<CoordComponentCount::XYZ>
u64 Color1 : 2; {
u64 Tex0Coord : 2; formatter() : EnumFormatter({"2 (x, y)", "3 (x, y, z)"}) {}
u64 Tex1Coord : 2; };
u64 Tex2Coord : 2;
u64 Tex3Coord : 2; enum class NormalComponentCount
u64 Tex4Coord : 2; {
u64 Tex5Coord : 2; N = 0,
u64 Tex6Coord : 2; NBT = 1,
u64 Tex7Coord : 2; };
u64 : 31; template <>
struct fmt::formatter<NormalComponentCount> : EnumFormatter<NormalComponentCount::NBT>
{
formatter() : EnumFormatter({"1 (n)", "3 (n, b, t)"}) {}
};
enum class ColorComponentCount
{
RGB = 0,
RGBA = 1,
};
template <>
struct fmt::formatter<ColorComponentCount> : EnumFormatter<ColorComponentCount::RGBA>
{
formatter() : EnumFormatter({"3 (r, g, b)", "4 (r, g, b, a)"}) {}
};
enum class ColorFormat
{
RGB565 = 0, // 16b
RGB888 = 1, // 24b
RGB888x = 2, // 32b
RGBA4444 = 3, // 16b
RGBA6666 = 4, // 24b
RGBA8888 = 5, // 32b
};
template <>
struct fmt::formatter<ColorFormat> : EnumFormatter<ColorFormat::RGBA8888>
{
static constexpr array_type names = {
"RGB 16 bits 565", "RGB 24 bits 888", "RGB 32 bits 888x",
"RGBA 16 bits 4444", "RGBA 24 bits 6666", "RGBA 32 bits 8888",
};
formatter() : EnumFormatter(names) {}
};
enum class TexComponentCount
{
S = 0,
ST = 1,
};
template <>
struct fmt::formatter<TexComponentCount> : EnumFormatter<TexComponentCount::ST>
{
formatter() : EnumFormatter({"1 (s)", "2 (s, t)"}) {}
};
struct TVtxDesc
{
union Low
{
// false: not present
// true: present
BitField<0, 1, bool, u32> PosMatIdx;
BitField<1, 1, bool, u32> Tex0MatIdx;
BitField<2, 1, bool, u32> Tex1MatIdx;
BitField<3, 1, bool, u32> Tex2MatIdx;
BitField<4, 1, bool, u32> Tex3MatIdx;
BitField<5, 1, bool, u32> Tex4MatIdx;
BitField<6, 1, bool, u32> Tex5MatIdx;
BitField<7, 1, bool, u32> Tex6MatIdx;
BitField<8, 1, bool, u32> Tex7MatIdx;
BitFieldArray<1, 1, 8, bool, u32> TexMatIdx;
BitField<9, 2, VertexComponentFormat> Position;
BitField<11, 2, VertexComponentFormat> Normal;
BitField<13, 2, VertexComponentFormat> Color0;
BitField<15, 2, VertexComponentFormat> Color1;
BitFieldArray<13, 2, 2, VertexComponentFormat> Color;
u32 Hex;
};
union High
{
BitField<0, 2, VertexComponentFormat> Tex0Coord;
BitField<2, 2, VertexComponentFormat> Tex1Coord;
BitField<4, 2, VertexComponentFormat> Tex2Coord;
BitField<6, 2, VertexComponentFormat> Tex3Coord;
BitField<8, 2, VertexComponentFormat> Tex4Coord;
BitField<10, 2, VertexComponentFormat> Tex5Coord;
BitField<12, 2, VertexComponentFormat> Tex6Coord;
BitField<14, 2, VertexComponentFormat> Tex7Coord;
BitFieldArray<0, 2, 8, VertexComponentFormat> TexCoord;
u32 Hex;
}; };
struct Low low;
{ High high;
u32 Hex0, Hex1;
};
// Easily index into the Position..Tex7Coord fields. // This structure was originally packed into bits 0..32, using 33 total bits.
u32 GetVertexArrayStatus(int idx) { return (Hex >> (9 + idx * 2)) & 0x3; } // The actual format has 17 bits in the low one and 16 bits in the high one,
// but the old format is still supported for compatibility.
u64 GetLegacyHex() const { return (low.Hex & 0x1FFFF) | (u64(high.Hex) << 17); }
u32 GetLegacyHex0() const { return static_cast<u32>(GetLegacyHex()); }
// Only *1* bit is used in this
u32 GetLegacyHex1() const { return static_cast<u32>(GetLegacyHex() >> 32); }
void SetLegacyHex(u64 value)
{
low.Hex = value & 0x1FFFF;
high.Hex = value >> 17;
}
}; };
union UVAT_group0 union UVAT_group0
{ {
u32 Hex; u32 Hex;
struct // 0:8
{ BitField<0, 1, CoordComponentCount> PosElements;
// 0:8 BitField<1, 3, ComponentFormat> PosFormat;
u32 PosElements : 1; BitField<4, 5, u32> PosFrac;
u32 PosFormat : 3; // 9:12
u32 PosFrac : 5; BitField<9, 1, NormalComponentCount> NormalElements;
// 9:12 BitField<10, 3, ComponentFormat> NormalFormat;
u32 NormalElements : 1; // 13:16
u32 NormalFormat : 3; BitField<13, 1, ColorComponentCount> Color0Elements;
// 13:16 BitField<14, 3, ColorFormat> Color0Comp;
u32 Color0Elements : 1; // 17:20
u32 Color0Comp : 3; BitField<17, 1, ColorComponentCount> Color1Elements;
// 17:20 BitField<18, 3, ColorFormat> Color1Comp;
u32 Color1Elements : 1; // 21:29
u32 Color1Comp : 3; BitField<21, 1, TexComponentCount> Tex0CoordElements;
// 21:29 BitField<22, 3, ComponentFormat> Tex0CoordFormat;
u32 Tex0CoordElements : 1; BitField<25, 5, u32> Tex0Frac;
u32 Tex0CoordFormat : 3; // 30:31
u32 Tex0Frac : 5; BitField<30, 1, u32> ByteDequant;
// 30:31 BitField<31, 1, u32> NormalIndex3;
u32 ByteDequant : 1;
u32 NormalIndex3 : 1;
};
}; };
union UVAT_group1 union UVAT_group1
{ {
u32 Hex; u32 Hex;
struct // 0:8
{ BitField<0, 1, TexComponentCount> Tex1CoordElements;
// 0:8 BitField<1, 3, ComponentFormat> Tex1CoordFormat;
u32 Tex1CoordElements : 1; BitField<4, 5, u32> Tex1Frac;
u32 Tex1CoordFormat : 3; // 9:17
u32 Tex1Frac : 5; BitField<9, 1, TexComponentCount> Tex2CoordElements;
// 9:17 BitField<10, 3, ComponentFormat> Tex2CoordFormat;
u32 Tex2CoordElements : 1; BitField<13, 5, u32> Tex2Frac;
u32 Tex2CoordFormat : 3; // 18:26
u32 Tex2Frac : 5; BitField<18, 1, TexComponentCount> Tex3CoordElements;
// 18:26 BitField<19, 3, ComponentFormat> Tex3CoordFormat;
u32 Tex3CoordElements : 1; BitField<22, 5, u32> Tex3Frac;
u32 Tex3CoordFormat : 3; // 27:30
u32 Tex3Frac : 5; BitField<27, 1, TexComponentCount> Tex4CoordElements;
// 27:30 BitField<28, 3, ComponentFormat> Tex4CoordFormat;
u32 Tex4CoordElements : 1; // 31
u32 Tex4CoordFormat : 3; BitField<31, 1, u32> VCacheEnhance;
//
u32 : 1;
};
}; };
union UVAT_group2 union UVAT_group2
{ {
u32 Hex; u32 Hex;
struct // 0:4
{ BitField<0, 5, u32> Tex4Frac;
// 0:4 // 5:13
u32 Tex4Frac : 5; BitField<5, 1, TexComponentCount> Tex5CoordElements;
// 5:13 BitField<6, 3, ComponentFormat> Tex5CoordFormat;
u32 Tex5CoordElements : 1; BitField<9, 5, u32> Tex5Frac;
u32 Tex5CoordFormat : 3; // 14:22
u32 Tex5Frac : 5; BitField<14, 1, TexComponentCount> Tex6CoordElements;
// 14:22 BitField<15, 3, ComponentFormat> Tex6CoordFormat;
u32 Tex6CoordElements : 1; BitField<18, 5, u32> Tex6Frac;
u32 Tex6CoordFormat : 3; // 23:31
u32 Tex6Frac : 5; BitField<23, 1, TexComponentCount> Tex7CoordElements;
// 23:31 BitField<24, 3, ComponentFormat> Tex7CoordFormat;
u32 Tex7CoordElements : 1; BitField<27, 5, u32> Tex7Frac;
u32 Tex7CoordFormat : 3;
u32 Tex7Frac : 5;
};
}; };
struct ColorAttr struct ColorAttr
{ {
u8 Elements; ColorComponentCount Elements;
u8 Comp; ColorFormat Comp;
}; };
struct TexAttr struct TexAttr
{ {
u8 Elements; TexComponentCount Elements;
u8 Format; ComponentFormat Format;
u8 Frac; u8 Frac;
}; };
struct TVtxAttr struct TVtxAttr
{ {
u8 PosElements; CoordComponentCount PosElements;
u8 PosFormat; ComponentFormat PosFormat;
u8 PosFrac; u8 PosFrac;
u8 NormalElements; NormalComponentCount NormalElements;
u8 NormalFormat; ComponentFormat NormalFormat;
ColorAttr color[2]; ColorAttr color[2];
TexAttr texCoord[8]; TexAttr texCoord[8];
bool ByteDequant; bool ByteDequant;
@ -229,39 +318,23 @@ struct TVtxAttr
// Matrix indices // Matrix indices
union TMatrixIndexA union TMatrixIndexA
{ {
struct BitField<0, 6, u32> PosNormalMtxIdx;
{ BitField<6, 6, u32> Tex0MtxIdx;
u32 PosNormalMtxIdx : 6; BitField<12, 6, u32> Tex1MtxIdx;
u32 Tex0MtxIdx : 6; BitField<18, 6, u32> Tex2MtxIdx;
u32 Tex1MtxIdx : 6; BitField<24, 6, u32> Tex3MtxIdx;
u32 Tex2MtxIdx : 6; u32 Hex;
u32 Tex3MtxIdx : 6;
};
struct
{
u32 Hex : 30;
u32 unused : 2;
};
}; };
union TMatrixIndexB union TMatrixIndexB
{ {
struct BitField<0, 6, u32> Tex4MtxIdx;
{ BitField<6, 6, u32> Tex5MtxIdx;
u32 Tex4MtxIdx : 6; BitField<12, 6, u32> Tex6MtxIdx;
u32 Tex5MtxIdx : 6; BitField<18, 6, u32> Tex7MtxIdx;
u32 Tex6MtxIdx : 6; u32 Hex;
u32 Tex7MtxIdx : 6;
};
struct
{
u32 Hex : 24;
u32 unused : 8;
};
}; };
#pragma pack()
struct VAT struct VAT
{ {
UVAT_group0 g0; UVAT_group0 g0;

View File

@ -2,11 +2,12 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "VideoCommon/VertexLoader.h"
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoCommon/DataReader.h" #include "VideoCommon/DataReader.h"
#include "VideoCommon/VertexLoader.h"
#include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexLoaderUtils.h" #include "VideoCommon/VertexLoaderUtils.h"
#include "VideoCommon/VertexLoader_Color.h" #include "VideoCommon/VertexLoader_Color.h"
@ -84,20 +85,13 @@ void VertexLoader::CompileVertexTranslator()
// Reset pipeline // Reset pipeline
m_numPipelineStages = 0; m_numPipelineStages = 0;
// Colors
const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
// TextureCoord
const u64 tc[8] = {m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord,
m_VtxDesc.Tex3Coord, m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord,
m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord};
u32 components = 0; u32 components = 0;
// Position in pc vertex format. // Position in pc vertex format.
int nat_offset = 0; int nat_offset = 0;
// Position Matrix Index // Position Matrix Index
if (m_VtxDesc.PosMatIdx) if (m_VtxDesc.low.PosMatIdx)
{ {
WriteCall(PosMtx_ReadDirect_UByte); WriteCall(PosMtx_ReadDirect_UByte);
components |= VB_HAS_POSMTXIDX; components |= VB_HAS_POSMTXIDX;
@ -110,49 +104,49 @@ void VertexLoader::CompileVertexTranslator()
m_VertexSize += 1; m_VertexSize += 1;
} }
if (m_VtxDesc.Tex0MatIdx) if (m_VtxDesc.low.Tex0MatIdx)
{ {
m_VertexSize += 1; m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX0; components |= VB_HAS_TEXMTXIDX0;
WriteCall(TexMtx_ReadDirect_UByte); WriteCall(TexMtx_ReadDirect_UByte);
} }
if (m_VtxDesc.Tex1MatIdx) if (m_VtxDesc.low.Tex1MatIdx)
{ {
m_VertexSize += 1; m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX1; components |= VB_HAS_TEXMTXIDX1;
WriteCall(TexMtx_ReadDirect_UByte); WriteCall(TexMtx_ReadDirect_UByte);
} }
if (m_VtxDesc.Tex2MatIdx) if (m_VtxDesc.low.Tex2MatIdx)
{ {
m_VertexSize += 1; m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX2; components |= VB_HAS_TEXMTXIDX2;
WriteCall(TexMtx_ReadDirect_UByte); WriteCall(TexMtx_ReadDirect_UByte);
} }
if (m_VtxDesc.Tex3MatIdx) if (m_VtxDesc.low.Tex3MatIdx)
{ {
m_VertexSize += 1; m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX3; components |= VB_HAS_TEXMTXIDX3;
WriteCall(TexMtx_ReadDirect_UByte); WriteCall(TexMtx_ReadDirect_UByte);
} }
if (m_VtxDesc.Tex4MatIdx) if (m_VtxDesc.low.Tex4MatIdx)
{ {
m_VertexSize += 1; m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX4; components |= VB_HAS_TEXMTXIDX4;
WriteCall(TexMtx_ReadDirect_UByte); WriteCall(TexMtx_ReadDirect_UByte);
} }
if (m_VtxDesc.Tex5MatIdx) if (m_VtxDesc.low.Tex5MatIdx)
{ {
m_VertexSize += 1; m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX5; components |= VB_HAS_TEXMTXIDX5;
WriteCall(TexMtx_ReadDirect_UByte); WriteCall(TexMtx_ReadDirect_UByte);
} }
if (m_VtxDesc.Tex6MatIdx) if (m_VtxDesc.low.Tex6MatIdx)
{ {
m_VertexSize += 1; m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX6; components |= VB_HAS_TEXMTXIDX6;
WriteCall(TexMtx_ReadDirect_UByte); WriteCall(TexMtx_ReadDirect_UByte);
} }
if (m_VtxDesc.Tex7MatIdx) if (m_VtxDesc.low.Tex7MatIdx)
{ {
m_VertexSize += 1; m_VertexSize += 1;
components |= VB_HAS_TEXMTXIDX7; components |= VB_HAS_TEXMTXIDX7;
@ -160,12 +154,12 @@ void VertexLoader::CompileVertexTranslator()
} }
// Write vertex position loader // Write vertex position loader
WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat, WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.low.Position, m_VtxAttr.PosFormat,
m_VtxAttr.PosElements)); m_VtxAttr.PosElements));
m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.low.Position, m_VtxAttr.PosFormat,
m_VtxAttr.PosElements); m_VtxAttr.PosElements);
int pos_elements = m_VtxAttr.PosElements + 2; int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3;
m_native_vtx_decl.position.components = pos_elements; m_native_vtx_decl.position.components = pos_elements;
m_native_vtx_decl.position.enable = true; m_native_vtx_decl.position.enable = true;
m_native_vtx_decl.position.offset = nat_offset; m_native_vtx_decl.position.offset = nat_offset;
@ -174,23 +168,24 @@ void VertexLoader::CompileVertexTranslator()
nat_offset += pos_elements * sizeof(float); nat_offset += pos_elements * sizeof(float);
// Normals // Normals
if (m_VtxDesc.Normal != NOT_PRESENT) if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{ {
m_VertexSize += VertexLoader_Normal::GetSize(m_VtxDesc.Normal, m_VtxAttr.NormalFormat, m_VertexSize += VertexLoader_Normal::GetSize(m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat,
m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3); m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3);
TPipelineFunction pFunc = VertexLoader_Normal::GetFunction( TPipelineFunction pFunc =
m_VtxDesc.Normal, m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3); VertexLoader_Normal::GetFunction(m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat,
m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3);
if (pFunc == nullptr) if (pFunc == nullptr)
{ {
PanicAlertFmt("VertexLoader_Normal::GetFunction({} {} {} {}) returned zero!", PanicAlertFmt("VertexLoader_Normal::GetFunction({} {} {} {}) returned zero!",
m_VtxDesc.Normal, m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements, m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements,
m_VtxAttr.NormalIndex3); m_VtxAttr.NormalIndex3);
} }
WriteCall(pFunc); WriteCall(pFunc);
for (int i = 0; i < (vtx_attr.NormalElements ? 3 : 1); i++) for (int i = 0; i < (vtx_attr.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++)
{ {
m_native_vtx_decl.normals[i].components = 3; m_native_vtx_decl.normals[i].components = 3;
m_native_vtx_decl.normals[i].enable = true; m_native_vtx_decl.normals[i].enable = true;
@ -201,43 +196,43 @@ void VertexLoader::CompileVertexTranslator()
} }
components |= VB_HAS_NRM0; components |= VB_HAS_NRM0;
if (m_VtxAttr.NormalElements == 1) if (m_VtxAttr.NormalElements == NormalComponentCount::NBT)
components |= VB_HAS_NRM1 | VB_HAS_NRM2; components |= VB_HAS_NRM1 | VB_HAS_NRM2;
} }
for (int i = 0; i < 2; i++) for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++)
{ {
m_native_vtx_decl.colors[i].components = 4; m_native_vtx_decl.colors[i].components = 4;
m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE;
m_native_vtx_decl.colors[i].integer = false; m_native_vtx_decl.colors[i].integer = false;
switch (col[i]) switch (m_VtxDesc.low.Color[i])
{ {
case NOT_PRESENT: case VertexComponentFormat::NotPresent:
break; break;
case DIRECT: case VertexComponentFormat::Direct:
switch (m_VtxAttr.color[i].Comp) switch (m_VtxAttr.color[i].Comp)
{ {
case FORMAT_16B_565: case ColorFormat::RGB565:
m_VertexSize += 2; m_VertexSize += 2;
WriteCall(Color_ReadDirect_16b_565); WriteCall(Color_ReadDirect_16b_565);
break; break;
case FORMAT_24B_888: case ColorFormat::RGB888:
m_VertexSize += 3; m_VertexSize += 3;
WriteCall(Color_ReadDirect_24b_888); WriteCall(Color_ReadDirect_24b_888);
break; break;
case FORMAT_32B_888x: case ColorFormat::RGB888x:
m_VertexSize += 4; m_VertexSize += 4;
WriteCall(Color_ReadDirect_32b_888x); WriteCall(Color_ReadDirect_32b_888x);
break; break;
case FORMAT_16B_4444: case ColorFormat::RGBA4444:
m_VertexSize += 2; m_VertexSize += 2;
WriteCall(Color_ReadDirect_16b_4444); WriteCall(Color_ReadDirect_16b_4444);
break; break;
case FORMAT_24B_6666: case ColorFormat::RGBA6666:
m_VertexSize += 3; m_VertexSize += 3;
WriteCall(Color_ReadDirect_24b_6666); WriteCall(Color_ReadDirect_24b_6666);
break; break;
case FORMAT_32B_8888: case ColorFormat::RGBA8888:
m_VertexSize += 4; m_VertexSize += 4;
WriteCall(Color_ReadDirect_32b_8888); WriteCall(Color_ReadDirect_32b_8888);
break; break;
@ -246,26 +241,26 @@ void VertexLoader::CompileVertexTranslator()
break; break;
} }
break; break;
case INDEX8: case VertexComponentFormat::Index8:
m_VertexSize += 1; m_VertexSize += 1;
switch (m_VtxAttr.color[i].Comp) switch (m_VtxAttr.color[i].Comp)
{ {
case FORMAT_16B_565: case ColorFormat::RGB565:
WriteCall(Color_ReadIndex8_16b_565); WriteCall(Color_ReadIndex8_16b_565);
break; break;
case FORMAT_24B_888: case ColorFormat::RGB888:
WriteCall(Color_ReadIndex8_24b_888); WriteCall(Color_ReadIndex8_24b_888);
break; break;
case FORMAT_32B_888x: case ColorFormat::RGB888x:
WriteCall(Color_ReadIndex8_32b_888x); WriteCall(Color_ReadIndex8_32b_888x);
break; break;
case FORMAT_16B_4444: case ColorFormat::RGBA4444:
WriteCall(Color_ReadIndex8_16b_4444); WriteCall(Color_ReadIndex8_16b_4444);
break; break;
case FORMAT_24B_6666: case ColorFormat::RGBA6666:
WriteCall(Color_ReadIndex8_24b_6666); WriteCall(Color_ReadIndex8_24b_6666);
break; break;
case FORMAT_32B_8888: case ColorFormat::RGBA8888:
WriteCall(Color_ReadIndex8_32b_8888); WriteCall(Color_ReadIndex8_32b_8888);
break; break;
default: default:
@ -273,26 +268,26 @@ void VertexLoader::CompileVertexTranslator()
break; break;
} }
break; break;
case INDEX16: case VertexComponentFormat::Index16:
m_VertexSize += 2; m_VertexSize += 2;
switch (m_VtxAttr.color[i].Comp) switch (m_VtxAttr.color[i].Comp)
{ {
case FORMAT_16B_565: case ColorFormat::RGB565:
WriteCall(Color_ReadIndex16_16b_565); WriteCall(Color_ReadIndex16_16b_565);
break; break;
case FORMAT_24B_888: case ColorFormat::RGB888:
WriteCall(Color_ReadIndex16_24b_888); WriteCall(Color_ReadIndex16_24b_888);
break; break;
case FORMAT_32B_888x: case ColorFormat::RGB888x:
WriteCall(Color_ReadIndex16_32b_888x); WriteCall(Color_ReadIndex16_32b_888x);
break; break;
case FORMAT_16B_4444: case ColorFormat::RGBA4444:
WriteCall(Color_ReadIndex16_16b_4444); WriteCall(Color_ReadIndex16_16b_4444);
break; break;
case FORMAT_24B_6666: case ColorFormat::RGBA6666:
WriteCall(Color_ReadIndex16_24b_6666); WriteCall(Color_ReadIndex16_24b_6666);
break; break;
case FORMAT_32B_8888: case ColorFormat::RGBA8888:
WriteCall(Color_ReadIndex16_32b_8888); WriteCall(Color_ReadIndex16_32b_8888);
break; break;
default: default:
@ -302,7 +297,7 @@ void VertexLoader::CompileVertexTranslator()
break; break;
} }
// Common for the three bottom cases // Common for the three bottom cases
if (col[i] != NOT_PRESENT) if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent)
{ {
components |= VB_HAS_COL0 << i; components |= VB_HAS_COL0 << i;
m_native_vtx_decl.colors[i].offset = nat_offset; m_native_vtx_decl.colors[i].offset = nat_offset;
@ -312,38 +307,40 @@ void VertexLoader::CompileVertexTranslator()
} }
// Texture matrix indices (remove if corresponding texture coordinate isn't enabled) // Texture matrix indices (remove if corresponding texture coordinate isn't enabled)
for (int i = 0; i < 8; i++) for (size_t i = 0; i < m_VtxDesc.high.TexCoord.Size(); i++)
{ {
m_native_vtx_decl.texcoords[i].offset = nat_offset; m_native_vtx_decl.texcoords[i].offset = nat_offset;
m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; m_native_vtx_decl.texcoords[i].type = VAR_FLOAT;
m_native_vtx_decl.texcoords[i].integer = false; m_native_vtx_decl.texcoords[i].integer = false;
const int format = m_VtxAttr.texCoord[i].Format; const auto tc = m_VtxDesc.high.TexCoord[i].Value();
const int elements = m_VtxAttr.texCoord[i].Elements; const auto format = m_VtxAttr.texCoord[i].Format;
const auto elements = m_VtxAttr.texCoord[i].Elements;
if (tc[i] != NOT_PRESENT) if (tc != VertexComponentFormat::NotPresent)
{ {
ASSERT_MSG(VIDEO, DIRECT <= tc[i] && tc[i] <= INDEX16, ASSERT_MSG(VIDEO, VertexComponentFormat::Direct <= tc && tc <= VertexComponentFormat::Index16,
"Invalid texture coordinates!\n(tc[i] = %d)", (u32)tc[i]); "Invalid texture coordinates!\n(tc = %d)", (u32)tc);
ASSERT_MSG(VIDEO, FORMAT_UBYTE <= format && format <= FORMAT_FLOAT, ASSERT_MSG(VIDEO, ComponentFormat::UByte <= format && format <= ComponentFormat::Float,
"Invalid texture coordinates format!\n(format = %d)", format); "Invalid texture coordinates format!\n(format = %d)", (u32)format);
ASSERT_MSG(VIDEO, 0 <= elements && elements <= 1, ASSERT_MSG(VIDEO, elements == TexComponentCount::S || elements == TexComponentCount::ST,
"Invalid number of texture coordinates elements!\n(elements = %d)", elements); "Invalid number of texture coordinates elements!\n(elements = %d)", (u32)elements);
components |= VB_HAS_UV0 << i; components |= VB_HAS_UV0 << i;
WriteCall(VertexLoader_TextCoord::GetFunction(tc[i], format, elements)); WriteCall(VertexLoader_TextCoord::GetFunction(tc, format, elements));
m_VertexSize += VertexLoader_TextCoord::GetSize(tc[i], format, elements); m_VertexSize += VertexLoader_TextCoord::GetSize(tc, format, elements);
} }
if (components & (VB_HAS_TEXMTXIDX0 << i)) if (components & (VB_HAS_TEXMTXIDX0 << i))
{ {
m_native_vtx_decl.texcoords[i].enable = true; m_native_vtx_decl.texcoords[i].enable = true;
if (tc[i] != NOT_PRESENT) if (tc != VertexComponentFormat::NotPresent)
{ {
// if texmtx is included, texcoord will always be 3 floats, z will be the texmtx index // if texmtx is included, texcoord will always be 3 floats, z will be the texmtx index
m_native_vtx_decl.texcoords[i].components = 3; m_native_vtx_decl.texcoords[i].components = 3;
nat_offset += 12; nat_offset += 12;
WriteCall(m_VtxAttr.texCoord[i].Elements ? TexMtx_Write_Float : TexMtx_Write_Float2); WriteCall(m_VtxAttr.texCoord[i].Elements == TexComponentCount::ST ? TexMtx_Write_Float :
TexMtx_Write_Float2);
} }
else else
{ {
@ -354,21 +351,22 @@ void VertexLoader::CompileVertexTranslator()
} }
else else
{ {
if (tc[i] != NOT_PRESENT) if (tc != VertexComponentFormat::NotPresent)
{ {
m_native_vtx_decl.texcoords[i].enable = true; m_native_vtx_decl.texcoords[i].enable = true;
m_native_vtx_decl.texcoords[i].components = vtx_attr.texCoord[i].Elements ? 2 : 1; m_native_vtx_decl.texcoords[i].components =
nat_offset += 4 * (vtx_attr.texCoord[i].Elements ? 2 : 1); vtx_attr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1;
nat_offset += 4 * (vtx_attr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1);
} }
} }
if (tc[i] == NOT_PRESENT) if (tc == VertexComponentFormat::NotPresent)
{ {
// if there's more tex coords later, have to write a dummy call // if there's more tex coords later, have to write a dummy call
int j = i + 1; size_t j = i + 1;
for (; j < 8; ++j) for (; j < m_VtxDesc.high.TexCoord.Size(); ++j)
{ {
if (tc[j] != NOT_PRESENT) if (m_VtxDesc.high.TexCoord[j] != VertexComponentFormat::NotPresent)
{ {
WriteCall(VertexLoader_TextCoord::GetDummyFunction()); // important to get indices right! WriteCall(VertexLoader_TextCoord::GetDummyFunction()); // important to get indices right!
break; break;
@ -383,8 +381,8 @@ void VertexLoader::CompileVertexTranslator()
} }
} }
// indexed position formats may skip a the vertex // indexed position formats may skip the vertex
if (m_VtxDesc.Position & 2) if (IsIndexed(m_VtxDesc.low.Position))
{ {
WriteCall(SkipVertex); WriteCall(SkipVertex);
} }

View File

@ -3,6 +3,9 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "VideoCommon/VertexLoaderARM64.h" #include "VideoCommon/VertexLoaderARM64.h"
#include <array>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoCommon/DataReader.h" #include "VideoCommon/DataReader.h"
#include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderManager.h"
@ -45,11 +48,11 @@ VertexLoaderARM64::VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_at
WriteProtect(); WriteProtect();
} }
void VertexLoaderARM64::GetVertexAddr(int array, u64 attribute, ARM64Reg reg) void VertexLoaderARM64::GetVertexAddr(int array, VertexComponentFormat attribute, ARM64Reg reg)
{ {
if (attribute & MASK_INDEXED) if (IsIndexed(attribute))
{ {
if (attribute == INDEX8) if (attribute == VertexComponentFormat::Index8)
{ {
if (m_src_ofs < 4096) if (m_src_ofs < 4096)
{ {
@ -83,7 +86,8 @@ void VertexLoaderARM64::GetVertexAddr(int array, u64 attribute, ARM64Reg reg)
if (array == ARRAY_POSITION) if (array == ARRAY_POSITION)
{ {
EOR(scratch2_reg, scratch1_reg, 0, attribute == INDEX8 ? 7 : 15); // 0xFF : 0xFFFF EOR(scratch2_reg, scratch1_reg, 0,
attribute == VertexComponentFormat::Index8 ? 7 : 15); // 0xFF : 0xFFFF
m_skip_vertex = CBZ(scratch2_reg); m_skip_vertex = CBZ(scratch2_reg);
} }
@ -97,23 +101,24 @@ void VertexLoaderARM64::GetVertexAddr(int array, u64 attribute, ARM64Reg reg)
ADD(reg, src_reg, m_src_ofs); ADD(reg, src_reg, m_src_ofs);
} }
s32 VertexLoaderARM64::GetAddressImm(int array, u64 attribute, Arm64Gen::ARM64Reg reg, u32 align) s32 VertexLoaderARM64::GetAddressImm(int array, VertexComponentFormat attribute,
Arm64Gen::ARM64Reg reg, u32 align)
{ {
if (attribute & MASK_INDEXED || (m_src_ofs > 255 && (m_src_ofs & (align - 1)))) if (IsIndexed(attribute) || (m_src_ofs > 255 && (m_src_ofs & (align - 1))))
GetVertexAddr(array, attribute, reg); GetVertexAddr(array, attribute, reg);
else else
return m_src_ofs; return m_src_ofs;
return -1; return -1;
} }
int VertexLoaderARM64::ReadVertex(u64 attribute, int format, int count_in, int count_out, int VertexLoaderARM64::ReadVertex(VertexComponentFormat attribute, ComponentFormat format,
bool dequantize, u8 scaling_exponent, int count_in, int count_out, bool dequantize, u8 scaling_exponent,
AttributeFormat* native_format, s32 offset) AttributeFormat* native_format, s32 offset)
{ {
ARM64Reg coords = count_in == 3 ? Q31 : D31; ARM64Reg coords = count_in == 3 ? Q31 : D31;
ARM64Reg scale = count_in == 3 ? Q30 : D30; ARM64Reg scale = count_in == 3 ? Q30 : D30;
int elem_size = 1 << (format / 2); int elem_size = GetElementSize(format);
int load_bytes = elem_size * count_in; int load_bytes = elem_size * count_in;
int load_size = int load_size =
load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
@ -136,24 +141,24 @@ int VertexLoaderARM64::ReadVertex(u64 attribute, int format, int count_in, int c
m_float_emit.LDR(load_size, IndexType::Unsigned, coords, src_reg, offset); m_float_emit.LDR(load_size, IndexType::Unsigned, coords, src_reg, offset);
} }
if (format != FORMAT_FLOAT) if (format != ComponentFormat::Float)
{ {
// Extend and convert to float // Extend and convert to float
switch (format) switch (format)
{ {
case FORMAT_UBYTE: case ComponentFormat::UByte:
m_float_emit.UXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); m_float_emit.UXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
break; break;
case FORMAT_BYTE: case ComponentFormat::Byte:
m_float_emit.SXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); m_float_emit.SXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
break; break;
case FORMAT_USHORT: case ComponentFormat::UShort:
m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
break; break;
case FORMAT_SHORT: case ComponentFormat::Short:
m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
break; break;
@ -207,20 +212,20 @@ int VertexLoaderARM64::ReadVertex(u64 attribute, int format, int count_in, int c
native_format->integer = false; native_format->integer = false;
m_dst_ofs += sizeof(float) * count_out; m_dst_ofs += sizeof(float) * count_out;
if (attribute == DIRECT) if (attribute == VertexComponentFormat::Direct)
m_src_ofs += load_bytes; m_src_ofs += load_bytes;
return load_bytes; return load_bytes;
} }
void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset) void VertexLoaderARM64::ReadColor(VertexComponentFormat attribute, ColorFormat format, s32 offset)
{ {
int load_bytes = 0; int load_bytes = 0;
switch (format) switch (format)
{ {
case FORMAT_24B_888: case ColorFormat::RGB888:
case FORMAT_32B_888x: case ColorFormat::RGB888x:
case FORMAT_32B_8888: case ColorFormat::RGBA8888:
if (offset == -1) if (offset == -1)
LDR(IndexType::Unsigned, scratch2_reg, EncodeRegTo64(scratch1_reg), 0); LDR(IndexType::Unsigned, scratch2_reg, EncodeRegTo64(scratch1_reg), 0);
else if (offset & 3) // Not aligned - unscaled else if (offset & 3) // Not aligned - unscaled
@ -228,13 +233,13 @@ void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset)
else else
LDR(IndexType::Unsigned, scratch2_reg, src_reg, offset); LDR(IndexType::Unsigned, scratch2_reg, src_reg, offset);
if (format != FORMAT_32B_8888) if (format != ColorFormat::RGBA8888)
ORRI2R(scratch2_reg, scratch2_reg, 0xFF000000); ORRI2R(scratch2_reg, scratch2_reg, 0xFF000000);
STR(IndexType::Unsigned, scratch2_reg, dst_reg, m_dst_ofs); STR(IndexType::Unsigned, scratch2_reg, dst_reg, m_dst_ofs);
load_bytes = 3 + (format != FORMAT_24B_888); load_bytes = format == ColorFormat::RGB888 ? 3 : 4;
break; break;
case FORMAT_16B_565: case ColorFormat::RGB565:
// RRRRRGGG GGGBBBBB // RRRRRGGG GGGBBBBB
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
if (offset == -1) if (offset == -1)
@ -270,7 +275,7 @@ void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset)
load_bytes = 2; load_bytes = 2;
break; break;
case FORMAT_16B_4444: case ColorFormat::RGBA4444:
// BBBBAAAA RRRRGGGG // BBBBAAAA RRRRGGGG
// REV16 - RRRRGGGG BBBBAAAA // REV16 - RRRRGGGG BBBBAAAA
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
@ -303,7 +308,7 @@ void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset)
load_bytes = 2; load_bytes = 2;
break; break;
case FORMAT_24B_6666: case ColorFormat::RGBA6666:
// RRRRRRGG GGGGBBBB BBAAAAAA // RRRRRRGG GGGGBBBB BBAAAAAA
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
if (offset == -1) if (offset == -1)
@ -349,7 +354,7 @@ void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset)
load_bytes = 3; load_bytes = 3;
break; break;
} }
if (attribute == DIRECT) if (attribute == VertexComponentFormat::Direct)
m_src_ofs += load_bytes; m_src_ofs += load_bytes;
} }
@ -370,24 +375,19 @@ void VertexLoaderARM64::GenerateVertexLoader()
// We can touch all except v8-v15 // We can touch all except v8-v15
// If we need to use those, we need to retain the lower 64bits(!) of the register // If we need to use those, we need to retain the lower 64bits(!) of the register
const u64 tc[8] = {
m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord,
m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord,
};
bool has_tc = false; bool has_tc = false;
bool has_tc_scale = false; bool has_tc_scale = false;
for (int i = 0; i < 8; i++) for (size_t i = 0; i < m_VtxDesc.high.TexCoord.Size(); i++)
{ {
has_tc |= tc[i] != 0; has_tc |= m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent;
has_tc_scale |= !!m_VtxAttr.texCoord[i].Frac; has_tc_scale |= !!m_VtxAttr.texCoord[i].Frac;
} }
bool need_scale = bool need_scale = (m_VtxAttr.ByteDequant && m_VtxAttr.PosFrac) || (has_tc && has_tc_scale) ||
(m_VtxAttr.ByteDequant && m_VtxAttr.PosFrac) || (has_tc && has_tc_scale) || m_VtxDesc.Normal; (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent);
AlignCode16(); AlignCode16();
if (m_VtxDesc.Position & MASK_INDEXED) if (IsIndexed(m_VtxDesc.low.Position))
MOV(skipped_reg, WZR); MOV(skipped_reg, WZR);
MOV(saved_count, count_reg); MOV(saved_count, count_reg);
@ -399,7 +399,7 @@ void VertexLoaderARM64::GenerateVertexLoader()
const u8* loop_start = GetCodePtr(); const u8* loop_start = GetCodePtr();
if (m_VtxDesc.PosMatIdx) if (m_VtxDesc.low.PosMatIdx)
{ {
LDRB(IndexType::Unsigned, scratch1_reg, src_reg, m_src_ofs); LDRB(IndexType::Unsigned, scratch1_reg, src_reg, m_src_ofs);
AND(scratch1_reg, scratch1_reg, 0, 5); AND(scratch1_reg, scratch1_reg, 0, 5);
@ -422,50 +422,47 @@ void VertexLoaderARM64::GenerateVertexLoader()
m_dst_ofs += sizeof(u32); m_dst_ofs += sizeof(u32);
} }
u32 texmatidx_ofs[8]; std::array<u32, 8> texmatidx_ofs;
const u64 tm[8] = { for (size_t i = 0; i < m_VtxDesc.low.TexMatIdx.Size(); i++)
m_VtxDesc.Tex0MatIdx, m_VtxDesc.Tex1MatIdx, m_VtxDesc.Tex2MatIdx, m_VtxDesc.Tex3MatIdx,
m_VtxDesc.Tex4MatIdx, m_VtxDesc.Tex5MatIdx, m_VtxDesc.Tex6MatIdx, m_VtxDesc.Tex7MatIdx,
};
for (int i = 0; i < 8; i++)
{ {
if (tm[i]) if (m_VtxDesc.low.TexMatIdx[i])
texmatidx_ofs[i] = m_src_ofs++; texmatidx_ofs[i] = m_src_ofs++;
} }
// Position // Position
{ {
int elem_size = 1 << (m_VtxAttr.PosFormat / 2); int elem_size = GetElementSize(m_VtxAttr.PosFormat);
int load_bytes = elem_size * (m_VtxAttr.PosElements + 2); int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3;
int load_bytes = elem_size * pos_elements;
int load_size = int load_size =
load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
load_size <<= 3; load_size <<= 3;
s32 offset = s32 offset = GetAddressImm(ARRAY_POSITION, m_VtxDesc.low.Position, EncodeRegTo64(scratch1_reg),
GetAddressImm(ARRAY_POSITION, m_VtxDesc.Position, EncodeRegTo64(scratch1_reg), load_size); load_size);
int pos_elements = m_VtxAttr.PosElements + 2; ReadVertex(m_VtxDesc.low.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements,
ReadVertex(m_VtxDesc.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements,
m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position, offset); m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position, offset);
} }
if (m_VtxDesc.Normal) if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{ {
static const u8 map[8] = {7, 6, 15, 14}; static const u8 map[8] = {7, 6, 15, 14};
u8 scaling_exponent = map[m_VtxAttr.NormalFormat]; const u8 scaling_exponent = map[u32(m_VtxAttr.NormalFormat)];
const int limit = m_VtxAttr.NormalElements == NormalComponentCount::NBT ? 3 : 1;
s32 offset = -1; s32 offset = -1;
for (int i = 0; i < (m_VtxAttr.NormalElements ? 3 : 1); i++) for (int i = 0; i < (m_VtxAttr.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++)
{ {
if (!i || m_VtxAttr.NormalIndex3) if (!i || m_VtxAttr.NormalIndex3)
{ {
int elem_size = 1 << (m_VtxAttr.NormalFormat / 2); int elem_size = GetElementSize(m_VtxAttr.NormalFormat);
int load_bytes = elem_size * 3; int load_bytes = elem_size * 3;
int load_size = load_bytes == 1 ? int load_size = load_bytes == 1 ?
1 : 1 :
load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
offset = GetAddressImm(ARRAY_NORMAL, m_VtxDesc.Normal, EncodeRegTo64(scratch1_reg), offset = GetAddressImm(ARRAY_NORMAL, m_VtxDesc.low.Normal, EncodeRegTo64(scratch1_reg),
load_size << 3); load_size << 3);
if (offset == -1) if (offset == -1)
@ -473,7 +470,7 @@ void VertexLoaderARM64::GenerateVertexLoader()
else else
offset += i * elem_size * 3; offset += i * elem_size * 3;
} }
int bytes_read = ReadVertex(m_VtxDesc.Normal, m_VtxAttr.NormalFormat, 3, 3, true, int bytes_read = ReadVertex(m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, 3, 3, true,
scaling_exponent, &m_native_vtx_decl.normals[i], offset); scaling_exponent, &m_native_vtx_decl.normals[i], offset);
if (offset == -1) if (offset == -1)
@ -483,25 +480,26 @@ void VertexLoaderARM64::GenerateVertexLoader()
} }
m_native_components |= VB_HAS_NRM0; m_native_components |= VB_HAS_NRM0;
if (m_VtxAttr.NormalElements) if (m_VtxAttr.NormalElements == NormalComponentCount::NBT)
m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2;
} }
const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++)
for (int i = 0; i < 2; i++)
{ {
m_native_vtx_decl.colors[i].components = 4; m_native_vtx_decl.colors[i].components = 4;
m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE;
m_native_vtx_decl.colors[i].integer = false; m_native_vtx_decl.colors[i].integer = false;
if (col[i]) if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent)
{ {
u32 align = 4; u32 align = 4;
if (m_VtxAttr.color[i].Comp == FORMAT_16B_565 || m_VtxAttr.color[i].Comp == FORMAT_16B_4444) if (m_VtxAttr.color[i].Comp == ColorFormat::RGB565 ||
m_VtxAttr.color[i].Comp == ColorFormat::RGBA4444)
align = 2; align = 2;
s32 offset = GetAddressImm(ARRAY_COLOR + i, col[i], EncodeRegTo64(scratch1_reg), align); s32 offset = GetAddressImm(ARRAY_COLOR + int(i), m_VtxDesc.low.Color[i],
ReadColor(col[i], m_VtxAttr.color[i].Comp, offset); EncodeRegTo64(scratch1_reg), align);
ReadColor(m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp, offset);
m_native_components |= VB_HAS_COL0 << i; m_native_components |= VB_HAS_COL0 << i;
m_native_vtx_decl.colors[i].components = 4; m_native_vtx_decl.colors[i].components = 4;
m_native_vtx_decl.colors[i].enable = true; m_native_vtx_decl.colors[i].enable = true;
@ -512,31 +510,32 @@ void VertexLoaderARM64::GenerateVertexLoader()
} }
} }
for (int i = 0; i < 8; i++) for (size_t i = 0; i < m_VtxDesc.high.TexCoord.Size(); i++)
{ {
m_native_vtx_decl.texcoords[i].offset = m_dst_ofs; m_native_vtx_decl.texcoords[i].offset = m_dst_ofs;
m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; m_native_vtx_decl.texcoords[i].type = VAR_FLOAT;
m_native_vtx_decl.texcoords[i].integer = false; m_native_vtx_decl.texcoords[i].integer = false;
int elements = m_VtxAttr.texCoord[i].Elements + 1; int elements = m_VtxAttr.texCoord[i].Elements == TexComponentCount::S ? 1 : 2;
if (tc[i]) if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent)
{ {
m_native_components |= VB_HAS_UV0 << i; m_native_components |= VB_HAS_UV0 << i;
int elem_size = 1 << (m_VtxAttr.texCoord[i].Format / 2); int elem_size = GetElementSize(m_VtxAttr.texCoord[i].Format);
int load_bytes = elem_size * (elements + 2); int load_bytes = elem_size * (elements + 2);
int load_size = load_bytes == 1 ? int load_size = load_bytes == 1 ?
1 : 1 :
load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
load_size <<= 3; load_size <<= 3;
s32 offset = s32 offset = GetAddressImm(ARRAY_TEXCOORD0 + int(i), m_VtxDesc.high.TexCoord[i],
GetAddressImm(ARRAY_TEXCOORD0 + i, tc[i], EncodeRegTo64(scratch1_reg), load_size); EncodeRegTo64(scratch1_reg), load_size);
u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac; u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac;
ReadVertex(tc[i], m_VtxAttr.texCoord[i].Format, elements, tm[i] ? 2 : elements, ReadVertex(m_VtxDesc.high.TexCoord[i], m_VtxAttr.texCoord[i].Format, elements,
m_VtxAttr.ByteDequant, scaling_exponent, &m_native_vtx_decl.texcoords[i], offset); m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.ByteDequant, scaling_exponent,
&m_native_vtx_decl.texcoords[i], offset);
} }
if (tm[i]) if (m_VtxDesc.low.TexMatIdx[i])
{ {
m_native_components |= VB_HAS_TEXMTXIDX0 << i; m_native_components |= VB_HAS_TEXMTXIDX0 << i;
m_native_vtx_decl.texcoords[i].components = 3; m_native_vtx_decl.texcoords[i].components = 3;
@ -547,7 +546,7 @@ void VertexLoaderARM64::GenerateVertexLoader()
LDRB(IndexType::Unsigned, scratch2_reg, src_reg, texmatidx_ofs[i]); LDRB(IndexType::Unsigned, scratch2_reg, src_reg, texmatidx_ofs[i]);
m_float_emit.UCVTF(S31, scratch2_reg); m_float_emit.UCVTF(S31, scratch2_reg);
if (tc[i]) if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent)
{ {
m_float_emit.STR(32, IndexType::Unsigned, D31, dst_reg, m_dst_ofs); m_float_emit.STR(32, IndexType::Unsigned, D31, dst_reg, m_dst_ofs);
m_dst_ofs += sizeof(float); m_dst_ofs += sizeof(float);
@ -587,7 +586,7 @@ void VertexLoaderARM64::GenerateVertexLoader()
SUB(count_reg, count_reg, 1); SUB(count_reg, count_reg, 1);
CBNZ(count_reg, loop_start); CBNZ(count_reg, loop_start);
if (m_VtxDesc.Position & MASK_INDEXED) if (IsIndexed(m_VtxDesc.low.Position))
{ {
SUB(W0, saved_count, skipped_reg); SUB(W0, saved_count, skipped_reg);
RET(X30); RET(X30);

View File

@ -9,6 +9,9 @@
#include "VideoCommon/VertexLoaderBase.h" #include "VideoCommon/VertexLoaderBase.h"
class DataReader; class DataReader;
enum class VertexComponentFormat;
enum class ComponentFormat;
enum class ColorFormat;
class VertexLoaderARM64 : public VertexLoaderBase, public Arm64Gen::ARM64CodeBlock class VertexLoaderARM64 : public VertexLoaderBase, public Arm64Gen::ARM64CodeBlock
{ {
@ -25,10 +28,11 @@ private:
u32 m_dst_ofs = 0; u32 m_dst_ofs = 0;
Arm64Gen::FixupBranch m_skip_vertex; Arm64Gen::FixupBranch m_skip_vertex;
Arm64Gen::ARM64FloatEmitter m_float_emit; Arm64Gen::ARM64FloatEmitter m_float_emit;
void GetVertexAddr(int array, u64 attribute, Arm64Gen::ARM64Reg reg); void GetVertexAddr(int array, VertexComponentFormat attribute, Arm64Gen::ARM64Reg reg);
s32 GetAddressImm(int array, u64 attribute, Arm64Gen::ARM64Reg reg, u32 align); s32 GetAddressImm(int array, VertexComponentFormat attribute, Arm64Gen::ARM64Reg reg, u32 align);
int ReadVertex(u64 attribute, int format, int count_in, int count_out, bool dequantize, int ReadVertex(VertexComponentFormat attribute, ComponentFormat format, int count_in,
u8 scaling_exponent, AttributeFormat* native_format, s32 offset = -1); int count_out, bool dequantize, u8 scaling_exponent,
void ReadColor(u64 attribute, int format, s32 offset); AttributeFormat* native_format, s32 offset = -1);
void ReadColor(VertexComponentFormat attribute, ColorFormat format, s32 offset);
void GenerateVertexLoader(); void GenerateVertexLoader();
}; };

View File

@ -81,64 +81,33 @@ std::string VertexLoaderBase::ToString() const
dest += GetName(); dest += GetName();
dest += ": "; dest += ": ";
static constexpr std::array<const char*, 4> pos_mode{{ dest += fmt::format("{}b skin: {} P: {} {}-{} ", m_VertexSize, m_VtxDesc.low.PosMatIdx,
"Inv", m_VtxAttr.PosElements, m_VtxDesc.low.Position, m_VtxAttr.PosFormat);
"Dir",
"I8",
"I16",
}};
static constexpr std::array<const char*, 8> pos_formats{{
"u8",
"s8",
"u16",
"s16",
"flt",
"Inv",
"Inv",
"Inv",
}};
static constexpr std::array<const char*, 8> color_format{{
"565",
"888",
"888x",
"4444",
"6666",
"8888",
"Inv",
"Inv",
}};
dest += fmt::format("{}b skin: {} P: {} {}-{} ", m_VertexSize, m_VtxDesc.PosMatIdx, if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
m_VtxAttr.PosElements ? 3 : 2, pos_mode[m_VtxDesc.Position],
pos_formats[m_VtxAttr.PosFormat]);
if (m_VtxDesc.Normal)
{ {
dest += fmt::format("Nrm: {} {}-{} ", m_VtxAttr.NormalElements, pos_mode[m_VtxDesc.Normal], dest += fmt::format("Nrm: {} {}-{} ", m_VtxAttr.NormalElements, m_VtxDesc.low.Normal,
pos_formats[m_VtxAttr.NormalFormat]); m_VtxAttr.NormalFormat);
} }
const std::array<u64, 2> color_mode{{m_VtxDesc.Color0, m_VtxDesc.Color1}}; for (size_t i = 0; i < g_main_cp_state.vtx_desc.low.Color.Size(); i++)
for (size_t i = 0; i < color_mode.size(); i++)
{ {
if (color_mode[i] == 0) if (g_main_cp_state.vtx_desc.low.Color[i] == VertexComponentFormat::NotPresent)
continue; continue;
const auto& color = m_VtxAttr.color[i]; const auto& color = m_VtxAttr.color[i];
dest += fmt::format("C{}: {} {}-{} ", i, color.Elements, pos_mode[color_mode[i]], dest += fmt::format("C{}: {} {}-{} ", i, color.Elements, g_main_cp_state.vtx_desc.low.Color[i],
color_format[color.Comp]); color.Comp);
} }
const std::array<u64, 8> tex_mode{{m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord,
m_VtxDesc.Tex3Coord, m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, for (size_t i = 0; i < g_main_cp_state.vtx_desc.high.TexCoord.Size(); i++)
m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord}};
for (size_t i = 0; i < tex_mode.size(); i++)
{ {
if (tex_mode[i] == 0) if (g_main_cp_state.vtx_desc.high.TexCoord[i] == VertexComponentFormat::NotPresent)
continue; continue;
const auto& tex_coord = m_VtxAttr.texCoord[i]; const auto& tex_coord = m_VtxAttr.texCoord[i];
dest += fmt::format("T{}: {} {}-{} ", i, tex_coord.Elements, pos_mode[tex_mode[i]], dest += fmt::format("T{}: {} {}-{} ", i, tex_coord.Elements,
pos_formats[tex_coord.Format]); g_main_cp_state.vtx_desc.high.TexCoord[i], tex_coord.Format);
} }
dest += fmt::format(" - {} v", m_numLoadedVertices); dest += fmt::format(" - {} v", m_numLoadedVertices);
return dest; return dest;
@ -200,8 +169,9 @@ public:
{ {
ERROR_LOG_FMT(VIDEO, ERROR_LOG_FMT(VIDEO,
"The two vertex loaders have loaded different data " "The two vertex loaders have loaded different data "
"(guru meditation {:#018x}, {:#010x}, {:#010x}, {:#010x}).", "(guru meditation {:#010x}, {:#010x}, {:#010x}, {:#010x}, {:#010x}).",
m_VtxDesc.Hex, m_vat.g0.Hex, m_vat.g1.Hex, m_vat.g2.Hex); m_VtxDesc.low.Hex, m_VtxDesc.high.Hex, m_vat.g0.Hex, m_vat.g1.Hex,
m_vat.g2.Hex);
} }
memcpy(dst.GetPointer(), buffer_a.data(), count_a * m_native_vtx_decl.stride); memcpy(dst.GetPointer(), buffer_a.data(), count_a * m_native_vtx_decl.stride);

View File

@ -23,8 +23,8 @@ public:
VertexLoaderUID() {} VertexLoaderUID() {}
VertexLoaderUID(const TVtxDesc& vtx_desc, const VAT& vat) VertexLoaderUID(const TVtxDesc& vtx_desc, const VAT& vat)
{ {
vid[0] = vtx_desc.Hex & 0xFFFFFFFF; vid[0] = vtx_desc.GetLegacyHex0();
vid[1] = vtx_desc.Hex >> 32; vid[1] = vtx_desc.GetLegacyHex1();
vid[2] = vat.g0.Hex; vid[2] = vat.g0.Hex;
vid[3] = vat.g1.Hex; vid[3] = vat.g1.Hex;
vid[4] = vat.g2.Hex; vid[4] = vat.g2.Hex;

View File

@ -77,11 +77,26 @@ void UpdateVertexArrayPointers()
// But the vertex arrays with invalid addresses aren't actually enabled. // But the vertex arrays with invalid addresses aren't actually enabled.
// Note: Only array bases 0 through 11 are used by the Vertex loaders. // Note: Only array bases 0 through 11 are used by the Vertex loaders.
// 12 through 15 are used for loading data into xfmem. // 12 through 15 are used for loading data into xfmem.
for (int i = 0; i < 12; i++) // We also only update the array base if the vertex description states we are going to use it.
if (IsIndexed(g_main_cp_state.vtx_desc.low.Position))
cached_arraybases[ARRAY_POSITION] =
Memory::GetPointer(g_main_cp_state.array_bases[ARRAY_POSITION]);
if (IsIndexed(g_main_cp_state.vtx_desc.low.Normal))
cached_arraybases[ARRAY_NORMAL] = Memory::GetPointer(g_main_cp_state.array_bases[ARRAY_NORMAL]);
for (size_t i = 0; i < g_main_cp_state.vtx_desc.low.Color.Size(); i++)
{ {
// Only update the array base if the vertex description states we are going to use it. if (IsIndexed(g_main_cp_state.vtx_desc.low.Color[i]))
if (g_main_cp_state.vtx_desc.GetVertexArrayStatus(i) & MASK_INDEXED) cached_arraybases[ARRAY_COLOR + i] =
cached_arraybases[i] = Memory::GetPointer(g_main_cp_state.array_bases[i]); Memory::GetPointer(g_main_cp_state.array_bases[ARRAY_COLOR + i]);
}
for (size_t i = 0; i < g_main_cp_state.vtx_desc.high.TexCoord.Size(); i++)
{
if (IsIndexed(g_main_cp_state.vtx_desc.high.TexCoord[i]))
cached_arraybases[ARRAY_TEXCOORD0 + i] =
Memory::GetPointer(g_main_cp_state.array_bases[ARRAY_TEXCOORD0 + i]);
} }
g_main_cp_state.bases_dirty = false; g_main_cp_state.bases_dirty = false;
@ -317,15 +332,13 @@ void LoadCPReg(u32 sub_cmd, u32 value, bool is_preprocess)
break; break;
case VCD_LO: case VCD_LO:
state->vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits state->vtx_desc.low.Hex = value;
state->vtx_desc.Hex |= value;
state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG); state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG);
state->bases_dirty = true; state->bases_dirty = true;
break; break;
case VCD_HI: case VCD_HI:
state->vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits state->vtx_desc.high.Hex = value;
state->vtx_desc.Hex |= (u64)value << 17;
state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG); state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG);
state->bases_dirty = true; state->bases_dirty = true;
break; break;
@ -371,8 +384,8 @@ void FillCPMemoryArray(u32* memory)
{ {
memory[MATINDEX_A] = g_main_cp_state.matrix_index_a.Hex; memory[MATINDEX_A] = g_main_cp_state.matrix_index_a.Hex;
memory[MATINDEX_B] = g_main_cp_state.matrix_index_b.Hex; memory[MATINDEX_B] = g_main_cp_state.matrix_index_b.Hex;
memory[VCD_LO] = (u32)g_main_cp_state.vtx_desc.Hex; memory[VCD_LO] = g_main_cp_state.vtx_desc.low.Hex;
memory[VCD_HI] = (u32)(g_main_cp_state.vtx_desc.Hex >> 17); memory[VCD_HI] = g_main_cp_state.vtx_desc.high.Hex;
for (int i = 0; i < CP_NUM_VAT_REG; ++i) for (int i = 0; i < CP_NUM_VAT_REG; ++i)
{ {

View File

@ -2,6 +2,9 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "VideoCommon/VertexLoaderX64.h"
#include <array>
#include <cstring> #include <cstring>
#include <string> #include <string>
@ -15,7 +18,6 @@
#include "Common/x64Emitter.h" #include "Common/x64Emitter.h"
#include "VideoCommon/DataReader.h" #include "VideoCommon/DataReader.h"
#include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexLoaderX64.h"
using namespace Gen; using namespace Gen;
@ -55,12 +57,12 @@ VertexLoaderX64::VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att)
JitRegister::Register(region, GetCodePtr(), name.c_str()); JitRegister::Register(region, GetCodePtr(), name.c_str());
} }
OpArg VertexLoaderX64::GetVertexAddr(int array, u64 attribute) OpArg VertexLoaderX64::GetVertexAddr(int array, VertexComponentFormat attribute)
{ {
OpArg data = MDisp(src_reg, m_src_ofs); OpArg data = MDisp(src_reg, m_src_ofs);
if (attribute & MASK_INDEXED) if (IsIndexed(attribute))
{ {
int bits = attribute == INDEX8 ? 8 : 16; int bits = attribute == VertexComponentFormat::Index8 ? 8 : 16;
LoadAndSwap(bits, scratch1, data); LoadAndSwap(bits, scratch1, data);
m_src_ofs += bits / 8; m_src_ofs += bits / 8;
if (array == ARRAY_POSITION) if (array == ARRAY_POSITION)
@ -78,8 +80,8 @@ OpArg VertexLoaderX64::GetVertexAddr(int array, u64 attribute)
} }
} }
int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count_in, int count_out, int VertexLoaderX64::ReadVertex(OpArg data, VertexComponentFormat attribute, ComponentFormat format,
bool dequantize, u8 scaling_exponent, int count_in, int count_out, bool dequantize, u8 scaling_exponent,
AttributeFormat* native_format) AttributeFormat* native_format)
{ {
static const __m128i shuffle_lut[5][3] = { static const __m128i shuffle_lut[5][3] = {
@ -115,7 +117,7 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
X64Reg coords = XMM0; X64Reg coords = XMM0;
int elem_size = 1 << (format / 2); int elem_size = GetElementSize(format);
int load_bytes = elem_size * count_in; int load_bytes = elem_size * count_in;
OpArg dest = MDisp(dst_reg, m_dst_ofs); OpArg dest = MDisp(dst_reg, m_dst_ofs);
@ -127,7 +129,7 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
m_dst_ofs += sizeof(float) * count_out; m_dst_ofs += sizeof(float) * count_out;
if (attribute == DIRECT) if (attribute == VertexComponentFormat::Direct)
m_src_ofs += load_bytes; m_src_ofs += load_bytes;
if (cpu_info.bSSSE3) if (cpu_info.bSSSE3)
@ -139,12 +141,12 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
else else
MOVD_xmm(coords, data); MOVD_xmm(coords, data);
PSHUFB(coords, MPIC(&shuffle_lut[format][count_in - 1])); PSHUFB(coords, MPIC(&shuffle_lut[u32(format)][count_in - 1]));
// Sign-extend. // Sign-extend.
if (format == FORMAT_BYTE) if (format == ComponentFormat::Byte)
PSRAD(coords, 24); PSRAD(coords, 24);
if (format == FORMAT_SHORT) if (format == ComponentFormat::Short)
PSRAD(coords, 16); PSRAD(coords, 16);
} }
else else
@ -153,20 +155,20 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
X64Reg temp = XMM1; X64Reg temp = XMM1;
switch (format) switch (format)
{ {
case FORMAT_UBYTE: case ComponentFormat::UByte:
MOVD_xmm(coords, data); MOVD_xmm(coords, data);
PXOR(temp, R(temp)); PXOR(temp, R(temp));
PUNPCKLBW(coords, R(temp)); PUNPCKLBW(coords, R(temp));
PUNPCKLWD(coords, R(temp)); PUNPCKLWD(coords, R(temp));
break; break;
case FORMAT_BYTE: case ComponentFormat::Byte:
MOVD_xmm(coords, data); MOVD_xmm(coords, data);
PUNPCKLBW(coords, R(coords)); PUNPCKLBW(coords, R(coords));
PUNPCKLWD(coords, R(coords)); PUNPCKLWD(coords, R(coords));
PSRAD(coords, 24); PSRAD(coords, 24);
break; break;
case FORMAT_USHORT: case ComponentFormat::UShort:
case FORMAT_SHORT: case ComponentFormat::Short:
switch (count_in) switch (count_in)
{ {
case 1: case 1:
@ -185,12 +187,12 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
PSHUFLW(coords, R(coords), 0xAC); // ..Z.Y.X. PSHUFLW(coords, R(coords), 0xAC); // ..Z.Y.X.
break; break;
} }
if (format == FORMAT_SHORT) if (format == ComponentFormat::Short)
PSRAD(coords, 16); PSRAD(coords, 16);
else else
PSRLD(coords, 16); PSRLD(coords, 16);
break; break;
case FORMAT_FLOAT: case ComponentFormat::Float:
// Floats don't need to be scaled or converted, // Floats don't need to be scaled or converted,
// so we can just load/swap/store them directly // so we can just load/swap/store them directly
// and return early. // and return early.
@ -231,7 +233,7 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
} }
} }
if (format != FORMAT_FLOAT) if (format != ComponentFormat::Float)
{ {
CVTDQ2PS(coords, R(coords)); CVTDQ2PS(coords, R(coords));
@ -265,22 +267,22 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
return load_bytes; return load_bytes;
} }
void VertexLoaderX64::ReadColor(OpArg data, u64 attribute, int format) void VertexLoaderX64::ReadColor(OpArg data, VertexComponentFormat attribute, ColorFormat format)
{ {
int load_bytes = 0; int load_bytes = 0;
switch (format) switch (format)
{ {
case FORMAT_24B_888: case ColorFormat::RGB888:
case FORMAT_32B_888x: case ColorFormat::RGB888x:
case FORMAT_32B_8888: case ColorFormat::RGBA8888:
MOV(32, R(scratch1), data); MOV(32, R(scratch1), data);
if (format != FORMAT_32B_8888) if (format != ColorFormat::RGBA8888)
OR(32, R(scratch1), Imm32(0xFF000000)); OR(32, R(scratch1), Imm32(0xFF000000));
MOV(32, MDisp(dst_reg, m_dst_ofs), R(scratch1)); MOV(32, MDisp(dst_reg, m_dst_ofs), R(scratch1));
load_bytes = 3 + (format != FORMAT_24B_888); load_bytes = format == ColorFormat::RGB888 ? 3 : 4;
break; break;
case FORMAT_16B_565: case ColorFormat::RGB565:
// RRRRRGGG GGGBBBBB // RRRRRGGG GGGBBBBB
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
LoadAndSwap(16, scratch1, data); LoadAndSwap(16, scratch1, data);
@ -320,7 +322,7 @@ void VertexLoaderX64::ReadColor(OpArg data, u64 attribute, int format)
load_bytes = 2; load_bytes = 2;
break; break;
case FORMAT_16B_4444: case ColorFormat::RGBA4444:
// RRRRGGGG BBBBAAAA // RRRRGGGG BBBBAAAA
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
LoadAndSwap(16, scratch1, data); LoadAndSwap(16, scratch1, data);
@ -348,7 +350,7 @@ void VertexLoaderX64::ReadColor(OpArg data, u64 attribute, int format)
load_bytes = 2; load_bytes = 2;
break; break;
case FORMAT_24B_6666: case ColorFormat::RGBA6666:
// RRRRRRGG GGGGBBBB BBAAAAAA // RRRRRRGG GGGGBBBB BBAAAAAA
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
data.AddMemOffset(-1); // subtract one from address so we can use a 32bit load and bswap data.AddMemOffset(-1); // subtract one from address so we can use a 32bit load and bswap
@ -380,7 +382,7 @@ void VertexLoaderX64::ReadColor(OpArg data, u64 attribute, int format)
load_bytes = 3; load_bytes = 3;
break; break;
} }
if (attribute == DIRECT) if (attribute == VertexComponentFormat::Direct)
m_src_ofs += load_bytes; m_src_ofs += load_bytes;
} }
@ -399,14 +401,14 @@ void VertexLoaderX64::GenerateVertexLoader()
MOV(64, R(base_reg), R(ABI_PARAM4)); MOV(64, R(base_reg), R(ABI_PARAM4));
if (m_VtxDesc.Position & MASK_INDEXED) if (IsIndexed(m_VtxDesc.low.Position))
XOR(32, R(skipped_reg), R(skipped_reg)); XOR(32, R(skipped_reg), R(skipped_reg));
// TODO: load constants into registers outside the main loop // TODO: load constants into registers outside the main loop
const u8* loop_start = GetCodePtr(); const u8* loop_start = GetCodePtr();
if (m_VtxDesc.PosMatIdx) if (m_VtxDesc.low.PosMatIdx)
{ {
MOVZX(32, 8, scratch1, MDisp(src_reg, m_src_ofs)); MOVZX(32, 8, scratch1, MDisp(src_reg, m_src_ofs));
AND(32, R(scratch1), Imm8(0x3F)); AND(32, R(scratch1), Imm8(0x3F));
@ -428,51 +430,47 @@ void VertexLoaderX64::GenerateVertexLoader()
m_dst_ofs += sizeof(u32); m_dst_ofs += sizeof(u32);
} }
u32 texmatidx_ofs[8]; std::array<u32, 8> texmatidx_ofs;
const u64 tm[8] = { for (size_t i = 0; i < m_VtxDesc.low.TexMatIdx.Size(); i++)
m_VtxDesc.Tex0MatIdx, m_VtxDesc.Tex1MatIdx, m_VtxDesc.Tex2MatIdx, m_VtxDesc.Tex3MatIdx,
m_VtxDesc.Tex4MatIdx, m_VtxDesc.Tex5MatIdx, m_VtxDesc.Tex6MatIdx, m_VtxDesc.Tex7MatIdx,
};
for (int i = 0; i < 8; i++)
{ {
if (tm[i]) if (m_VtxDesc.low.TexMatIdx[i])
texmatidx_ofs[i] = m_src_ofs++; texmatidx_ofs[i] = m_src_ofs++;
} }
OpArg data = GetVertexAddr(ARRAY_POSITION, m_VtxDesc.Position); OpArg data = GetVertexAddr(ARRAY_POSITION, m_VtxDesc.low.Position);
int pos_elements = 2 + m_VtxAttr.PosElements; int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3;
ReadVertex(data, m_VtxDesc.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements, ReadVertex(data, m_VtxDesc.low.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements,
m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position); m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position);
if (m_VtxDesc.Normal) if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{ {
static const u8 map[8] = {7, 6, 15, 14}; static const u8 map[8] = {7, 6, 15, 14};
u8 scaling_exponent = map[m_VtxAttr.NormalFormat]; const u8 scaling_exponent = map[u32(m_VtxAttr.NormalFormat)];
const int limit = m_VtxAttr.NormalElements == NormalComponentCount::NBT ? 3 : 1;
for (int i = 0; i < (m_VtxAttr.NormalElements ? 3 : 1); i++) for (int i = 0; i < limit; i++)
{ {
if (!i || m_VtxAttr.NormalIndex3) if (!i || m_VtxAttr.NormalIndex3)
{ {
data = GetVertexAddr(ARRAY_NORMAL, m_VtxDesc.Normal); data = GetVertexAddr(ARRAY_NORMAL, m_VtxDesc.low.Normal);
int elem_size = 1 << (m_VtxAttr.NormalFormat / 2); int elem_size = GetElementSize(m_VtxAttr.NormalFormat);
data.AddMemOffset(i * elem_size * 3); data.AddMemOffset(i * elem_size * 3);
} }
data.AddMemOffset(ReadVertex(data, m_VtxDesc.Normal, m_VtxAttr.NormalFormat, 3, 3, true, data.AddMemOffset(ReadVertex(data, m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, 3, 3, true,
scaling_exponent, &m_native_vtx_decl.normals[i])); scaling_exponent, &m_native_vtx_decl.normals[i]));
} }
m_native_components |= VB_HAS_NRM0; m_native_components |= VB_HAS_NRM0;
if (m_VtxAttr.NormalElements) if (m_VtxAttr.NormalElements == NormalComponentCount::NBT)
m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2;
} }
const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++)
for (int i = 0; i < 2; i++)
{ {
if (col[i]) if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent)
{ {
data = GetVertexAddr(ARRAY_COLOR + i, col[i]); data = GetVertexAddr(ARRAY_COLOR + int(i), m_VtxDesc.low.Color[i]);
ReadColor(data, col[i], m_VtxAttr.color[i].Comp); ReadColor(data, m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp);
m_native_components |= VB_HAS_COL0 << i; m_native_components |= VB_HAS_COL0 << i;
m_native_vtx_decl.colors[i].components = 4; m_native_vtx_decl.colors[i].components = 4;
m_native_vtx_decl.colors[i].enable = true; m_native_vtx_decl.colors[i].enable = true;
@ -483,22 +481,19 @@ void VertexLoaderX64::GenerateVertexLoader()
} }
} }
const u64 tc[8] = { for (size_t i = 0; i < m_VtxDesc.high.TexCoord.Size(); i++)
m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord,
m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord,
};
for (int i = 0; i < 8; i++)
{ {
int elements = m_VtxAttr.texCoord[i].Elements + 1; int elements = m_VtxAttr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1;
if (tc[i]) if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent)
{ {
data = GetVertexAddr(ARRAY_TEXCOORD0 + i, tc[i]); data = GetVertexAddr(ARRAY_TEXCOORD0 + int(i), m_VtxDesc.high.TexCoord[i]);
u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac; u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac;
ReadVertex(data, tc[i], m_VtxAttr.texCoord[i].Format, elements, tm[i] ? 2 : elements, ReadVertex(data, m_VtxDesc.high.TexCoord[i], m_VtxAttr.texCoord[i].Format, elements,
m_VtxAttr.ByteDequant, scaling_exponent, &m_native_vtx_decl.texcoords[i]); 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; m_native_components |= VB_HAS_UV0 << i;
} }
if (tm[i]) if (m_VtxDesc.low.TexMatIdx[i])
{ {
m_native_components |= VB_HAS_TEXMTXIDX0 << i; m_native_components |= VB_HAS_TEXMTXIDX0 << i;
m_native_vtx_decl.texcoords[i].components = 3; m_native_vtx_decl.texcoords[i].components = 3;
@ -506,7 +501,7 @@ void VertexLoaderX64::GenerateVertexLoader()
m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; m_native_vtx_decl.texcoords[i].type = VAR_FLOAT;
m_native_vtx_decl.texcoords[i].integer = false; m_native_vtx_decl.texcoords[i].integer = false;
MOVZX(64, 8, scratch1, MDisp(src_reg, texmatidx_ofs[i])); MOVZX(64, 8, scratch1, MDisp(src_reg, texmatidx_ofs[i]));
if (tc[i]) if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent)
{ {
CVTSI2SS(XMM0, R(scratch1)); CVTSI2SS(XMM0, R(scratch1));
MOVSS(MDisp(dst_reg, m_dst_ofs), XMM0); MOVSS(MDisp(dst_reg, m_dst_ofs), XMM0);
@ -537,7 +532,7 @@ void VertexLoaderX64::GenerateVertexLoader()
ABI_PopRegistersAndAdjustStack(regs, 0); ABI_PopRegistersAndAdjustStack(regs, 0);
if (m_VtxDesc.Position & MASK_INDEXED) if (IsIndexed(m_VtxDesc.low.Position))
{ {
SUB(32, R(ABI_RETURN), R(skipped_reg)); SUB(32, R(ABI_RETURN), R(skipped_reg));
RET(); RET();

View File

@ -8,6 +8,10 @@
#include "Common/x64Emitter.h" #include "Common/x64Emitter.h"
#include "VideoCommon/VertexLoaderBase.h" #include "VideoCommon/VertexLoaderBase.h"
enum class VertexComponentFormat;
enum class ComponentFormat;
enum class ColorFormat;
class VertexLoaderX64 : public VertexLoaderBase, public Gen::X64CodeBlock class VertexLoaderX64 : public VertexLoaderBase, public Gen::X64CodeBlock
{ {
public: public:
@ -22,9 +26,10 @@ private:
u32 m_src_ofs = 0; u32 m_src_ofs = 0;
u32 m_dst_ofs = 0; u32 m_dst_ofs = 0;
Gen::FixupBranch m_skip_vertex; Gen::FixupBranch m_skip_vertex;
Gen::OpArg GetVertexAddr(int array, u64 attribute); Gen::OpArg GetVertexAddr(int array, VertexComponentFormat attribute);
int ReadVertex(Gen::OpArg data, u64 attribute, int format, int count_in, int count_out, int ReadVertex(Gen::OpArg data, VertexComponentFormat attribute, ComponentFormat format,
bool dequantize, u8 scaling_exponent, AttributeFormat* native_format); int count_in, int count_out, bool dequantize, u8 scaling_exponent,
void ReadColor(Gen::OpArg data, u64 attribute, int format); AttributeFormat* native_format);
void ReadColor(Gen::OpArg data, VertexComponentFormat attribute, ColorFormat format);
void GenerateVertexLoader(); void GenerateVertexLoader();
}; };

View File

@ -230,12 +230,15 @@ constexpr Types InitializeTable()
constexpr Types s_table = InitializeTable(); constexpr Types s_table = InitializeTable();
} // Anonymous namespace } // Anonymous namespace
u32 VertexLoader_Normal::GetSize(u64 type, u32 format, u32 elements, u32 index3) u32 VertexLoader_Normal::GetSize(VertexComponentFormat type, ComponentFormat format,
NormalComponentCount elements, u32 index3)
{ {
return s_table[type][index3][elements][format].gc_size; return s_table[u32(type)][index3][u32(elements)][u32(format)].gc_size;
} }
TPipelineFunction VertexLoader_Normal::GetFunction(u64 type, u32 format, u32 elements, u32 index3) TPipelineFunction VertexLoader_Normal::GetFunction(VertexComponentFormat type,
ComponentFormat format,
NormalComponentCount elements, u32 index3)
{ {
return s_table[type][index3][elements][format].function; return s_table[u32(type)][index3][u32(elements)][u32(format)].function;
} }

View File

@ -7,10 +7,16 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoCommon/VertexLoader.h" #include "VideoCommon/VertexLoader.h"
enum class VertexComponentFormat;
enum class ComponentFormat;
enum class NormalComponentCount;
class VertexLoader_Normal class VertexLoader_Normal
{ {
public: public:
static u32 GetSize(u64 type, u32 format, u32 elements, u32 index3); static u32 GetSize(VertexComponentFormat type, ComponentFormat format,
NormalComponentCount elements, u32 index3);
static TPipelineFunction GetFunction(u64 type, u32 format, u32 elements, u32 index3); static TPipelineFunction GetFunction(VertexComponentFormat type, ComponentFormat format,
NormalComponentCount elements, u32 index3);
}; };

View File

@ -200,12 +200,15 @@ constexpr u32 s_table_read_position_vertex_size[4][8][2] = {
}; };
} // Anonymous namespace } // Anonymous namespace
u32 VertexLoader_Position::GetSize(u64 type, u32 format, u32 elements) u32 VertexLoader_Position::GetSize(VertexComponentFormat type, ComponentFormat format,
CoordComponentCount elements)
{ {
return s_table_read_position_vertex_size[type][format][elements]; return s_table_read_position_vertex_size[u32(type)][u32(format)][u32(elements)];
} }
TPipelineFunction VertexLoader_Position::GetFunction(u64 type, u32 format, u32 elements) TPipelineFunction VertexLoader_Position::GetFunction(VertexComponentFormat type,
ComponentFormat format,
CoordComponentCount elements)
{ {
return s_table_read_position[type][format][elements]; return s_table_read_position[u32(type)][u32(format)][u32(elements)];
} }

View File

@ -7,10 +7,16 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoCommon/VertexLoader.h" #include "VideoCommon/VertexLoader.h"
enum class VertexComponentFormat;
enum class ComponentFormat;
enum class CoordComponentCount;
class VertexLoader_Position class VertexLoader_Position
{ {
public: public:
static u32 GetSize(u64 type, u32 format, u32 elements); static u32 GetSize(VertexComponentFormat type, ComponentFormat format,
CoordComponentCount elements);
static TPipelineFunction GetFunction(u64 type, u32 format, u32 elements); static TPipelineFunction GetFunction(VertexComponentFormat type, ComponentFormat format,
CoordComponentCount elements);
}; };

View File

@ -191,14 +191,17 @@ constexpr u32 s_table_read_tex_coord_vertex_size[4][8][2] = {
}; };
} // Anonymous namespace } // Anonymous namespace
u32 VertexLoader_TextCoord::GetSize(u64 type, u32 format, u32 elements) u32 VertexLoader_TextCoord::GetSize(VertexComponentFormat type, ComponentFormat format,
TexComponentCount elements)
{ {
return s_table_read_tex_coord_vertex_size[type][format][elements]; return s_table_read_tex_coord_vertex_size[u32(type)][u32(format)][u32(elements)];
} }
TPipelineFunction VertexLoader_TextCoord::GetFunction(u64 type, u32 format, u32 elements) TPipelineFunction VertexLoader_TextCoord::GetFunction(VertexComponentFormat type,
ComponentFormat format,
TexComponentCount elements)
{ {
return s_table_read_tex_coord[type][format][elements]; return s_table_read_tex_coord[u32(type)][u32(format)][u32(elements)];
} }
TPipelineFunction VertexLoader_TextCoord::GetDummyFunction() TPipelineFunction VertexLoader_TextCoord::GetDummyFunction()

View File

@ -7,12 +7,18 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoCommon/VertexLoader.h" #include "VideoCommon/VertexLoader.h"
enum class VertexComponentFormat;
enum class ComponentFormat;
enum class TexComponentCount;
class VertexLoader_TextCoord class VertexLoader_TextCoord
{ {
public: public:
static u32 GetSize(u64 type, u32 format, u32 elements); static u32 GetSize(VertexComponentFormat type, ComponentFormat format,
TexComponentCount elements);
static TPipelineFunction GetFunction(u64 type, u32 format, u32 elements); static TPipelineFunction GetFunction(VertexComponentFormat type, ComponentFormat format,
TexComponentCount elements);
// It is important to synchronize tcIndex. // It is important to synchronize tcIndex.
static TPipelineFunction GetDummyFunction(); static TPipelineFunction GetDummyFunction();

View File

@ -618,9 +618,9 @@ void VertexShaderManager::SetVertexFormat(u32 components)
// The default alpha channel seems to depend on the number of components in the vertex format. // The default alpha channel seems to depend on the number of components in the vertex format.
// If the vertex attribute has an alpha channel, zero is used, otherwise one. // If the vertex attribute has an alpha channel, zero is used, otherwise one.
const u32 color_chan_alpha = const auto g0 = g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0;
(g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0.Color0Elements ^ 1) | const u32 color_chan_alpha = (g0.Color0Elements == ColorComponentCount::RGB ? 1 : 0) |
((g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0.Color1Elements ^ 1) << 1); (g0.Color1Elements == ColorComponentCount::RGB ? 2 : 0);
if (color_chan_alpha != constants.color_chan_alpha) if (color_chan_alpha != constants.color_chan_alpha)
{ {
constants.color_chan_alpha = color_chan_alpha; constants.color_chan_alpha = color_chan_alpha;

View File

@ -28,7 +28,7 @@ TEST(VertexLoaderUID, UniqueEnough)
memset(&vat, 0, sizeof(vat)); memset(&vat, 0, sizeof(vat));
uids.insert(VertexLoaderUID(vtx_desc, vat)); uids.insert(VertexLoaderUID(vtx_desc, vat));
vtx_desc.Hex = 0xFEDCBA9876543210ull; vtx_desc.SetLegacyHex(0xFEDCBA9876543210ull);
EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat))); EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat)));
uids.insert(VertexLoaderUID(vtx_desc, vat)); uids.insert(VertexLoaderUID(vtx_desc, vat));
@ -106,29 +106,37 @@ protected:
std::unique_ptr<VertexLoaderBase> m_loader; std::unique_ptr<VertexLoaderBase> m_loader;
}; };
class VertexLoaderParamTest : public VertexLoaderTest, class VertexLoaderParamTest
public ::testing::WithParamInterface<std::tuple<int, int, int, int>> : public VertexLoaderTest,
public ::testing::WithParamInterface<
std::tuple<VertexComponentFormat, ComponentFormat, CoordComponentCount, int>>
{ {
}; };
INSTANTIATE_TEST_CASE_P(AllCombinations, VertexLoaderParamTest, INSTANTIATE_TEST_CASE_P(
::testing::Combine(::testing::Values(DIRECT, INDEX8, INDEX16), AllCombinations, VertexLoaderParamTest,
::testing::Values(FORMAT_UBYTE, FORMAT_BYTE, ::testing::Combine(
FORMAT_USHORT, FORMAT_SHORT, ::testing::Values(VertexComponentFormat::Direct, VertexComponentFormat::Index8,
FORMAT_FLOAT), VertexComponentFormat::Index16),
::testing::Values(0, 1), // elements ::testing::Values(ComponentFormat::UByte, ComponentFormat::Byte, ComponentFormat::UShort,
::testing::Values(0, 1, 31) // frac ComponentFormat::Short, ComponentFormat::Float),
)); ::testing::Values(CoordComponentCount::XY, CoordComponentCount::XYZ),
::testing::Values(0, 1, 31) // frac
));
TEST_P(VertexLoaderParamTest, PositionAll) TEST_P(VertexLoaderParamTest, PositionAll)
{ {
int addr, format, elements, frac; VertexComponentFormat addr;
ComponentFormat format;
CoordComponentCount elements;
int frac;
std::tie(addr, format, elements, frac) = GetParam(); std::tie(addr, format, elements, frac) = GetParam();
this->m_vtx_desc.Position = addr; this->m_vtx_desc.low.Position = addr;
this->m_vtx_attr.g0.PosFormat = format; this->m_vtx_attr.g0.PosFormat = format;
this->m_vtx_attr.g0.PosElements = elements; this->m_vtx_attr.g0.PosElements = elements;
this->m_vtx_attr.g0.PosFrac = frac; this->m_vtx_attr.g0.PosFrac = frac;
this->m_vtx_attr.g0.ByteDequant = true; this->m_vtx_attr.g0.ByteDequant = true;
elements += 2; const u32 elem_size = GetElementSize(format);
const u32 elem_count = elements == CoordComponentCount::XY ? 2 : 3;
std::vector<float> values = { std::vector<float> values = {
std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest(),
@ -153,38 +161,37 @@ TEST_P(VertexLoaderParamTest, PositionAll)
ASSERT_EQ(0u, values.size() % 2); ASSERT_EQ(0u, values.size() % 2);
ASSERT_EQ(0u, values.size() % 3); ASSERT_EQ(0u, values.size() % 3);
int count = (int)values.size() / elements; int count = (int)values.size() / elem_count;
u32 elem_size = 1 << (format / 2); size_t input_size = elem_count * elem_size;
size_t input_size = elements * elem_size; if (IsIndexed(addr))
if (addr & MASK_INDEXED)
{ {
input_size = addr - 1; input_size = addr == VertexComponentFormat::Index8 ? 1 : 2;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
if (addr == INDEX8) if (addr == VertexComponentFormat::Index8)
Input<u8>(i); Input<u8>(i);
else else
Input<u16>(i); Input<u16>(i);
VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer(); VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer();
g_main_cp_state.array_strides[ARRAY_POSITION] = elements * elem_size; g_main_cp_state.array_strides[ARRAY_POSITION] = elem_count * elem_size;
} }
CreateAndCheckSizes(input_size, elements * sizeof(float)); CreateAndCheckSizes(input_size, elem_count * sizeof(float));
for (float value : values) for (float value : values)
{ {
switch (format) switch (format)
{ {
case FORMAT_UBYTE: case ComponentFormat::UByte:
Input((u8)value); Input((u8)value);
break; break;
case FORMAT_BYTE: case ComponentFormat::Byte:
Input((s8)value); Input((s8)value);
break; break;
case FORMAT_USHORT: case ComponentFormat::UShort:
Input((u16)value); Input((u16)value);
break; break;
case FORMAT_SHORT: case ComponentFormat::Short:
Input((s16)value); Input((s16)value);
break; break;
case FORMAT_FLOAT: case ComponentFormat::Float:
Input(value); Input(value);
break; break;
} }
@ -192,29 +199,29 @@ TEST_P(VertexLoaderParamTest, PositionAll)
RunVertices(count); RunVertices(count);
float scale = 1.f / (1u << (format == FORMAT_FLOAT ? 0 : frac)); float scale = 1.f / (1u << (format == ComponentFormat::Float ? 0 : frac));
for (auto iter = values.begin(); iter != values.end();) for (auto iter = values.begin(); iter != values.end();)
{ {
float f, g; float f, g;
switch (format) switch (format)
{ {
case FORMAT_UBYTE: case ComponentFormat::UByte:
f = (u8)*iter++; f = (u8)*iter++;
g = (u8)*iter++; g = (u8)*iter++;
break; break;
case FORMAT_BYTE: case ComponentFormat::Byte:
f = (s8)*iter++; f = (s8)*iter++;
g = (s8)*iter++; g = (s8)*iter++;
break; break;
case FORMAT_USHORT: case ComponentFormat::UShort:
f = (u16)*iter++; f = (u16)*iter++;
g = (u16)*iter++; g = (u16)*iter++;
break; break;
case FORMAT_SHORT: case ComponentFormat::Short:
f = (s16)*iter++; f = (s16)*iter++;
g = (s16)*iter++; g = (s16)*iter++;
break; break;
case FORMAT_FLOAT: case ComponentFormat::Float:
f = *iter++; f = *iter++;
g = *iter++; g = *iter++;
break; break;
@ -228,8 +235,8 @@ TEST_P(VertexLoaderParamTest, PositionAll)
TEST_F(VertexLoaderTest, PositionIndex16FloatXY) TEST_F(VertexLoaderTest, PositionIndex16FloatXY)
{ {
m_vtx_desc.Position = INDEX16; m_vtx_desc.low.Position = VertexComponentFormat::Index16;
m_vtx_attr.g0.PosFormat = FORMAT_FLOAT; m_vtx_attr.g0.PosFormat = ComponentFormat::Float;
CreateAndCheckSizes(sizeof(u16), 2 * sizeof(float)); CreateAndCheckSizes(sizeof(u16), 2 * sizeof(float));
Input<u16>(1); Input<u16>(1);
Input<u16>(0); Input<u16>(0);
@ -246,47 +253,49 @@ TEST_F(VertexLoaderTest, PositionIndex16FloatXY)
} }
class VertexLoaderSpeedTest : public VertexLoaderTest, class VertexLoaderSpeedTest : public VertexLoaderTest,
public ::testing::WithParamInterface<std::tuple<int, int>> public ::testing::WithParamInterface<std::tuple<ComponentFormat, int>>
{ {
}; };
INSTANTIATE_TEST_CASE_P(FormatsAndElements, VertexLoaderSpeedTest, INSTANTIATE_TEST_CASE_P(
::testing::Combine(::testing::Values(FORMAT_UBYTE, FORMAT_BYTE, FormatsAndElements, VertexLoaderSpeedTest,
FORMAT_USHORT, FORMAT_SHORT, ::testing::Combine(::testing::Values(ComponentFormat::UByte, ComponentFormat::Byte,
FORMAT_FLOAT), ComponentFormat::UShort, ComponentFormat::Short,
::testing::Values(0, 1) // elements ComponentFormat::Float),
)); ::testing::Values(0, 1)));
TEST_P(VertexLoaderSpeedTest, PositionDirectAll) TEST_P(VertexLoaderSpeedTest, PositionDirectAll)
{ {
int format, elements; ComponentFormat format;
std::tie(format, elements) = GetParam(); int elements_i;
const char* map[] = {"u8", "s8", "u16", "s16", "float"}; std::tie(format, elements_i) = GetParam();
printf("format: %s, elements: %d\n", map[format], elements); CoordComponentCount elements = static_cast<CoordComponentCount>(elements_i);
m_vtx_desc.Position = DIRECT; fmt::print("format: {}, elements: {}\n", format, elements);
const u32 elem_count = elements == CoordComponentCount::XY ? 2 : 3;
m_vtx_desc.low.Position = VertexComponentFormat::Direct;
m_vtx_attr.g0.PosFormat = format; m_vtx_attr.g0.PosFormat = format;
m_vtx_attr.g0.PosElements = elements; m_vtx_attr.g0.PosElements = elements;
elements += 2; const size_t elem_size = GetElementSize(format);
size_t elem_size = static_cast<size_t>(1) << (format / 2); CreateAndCheckSizes(elem_count * elem_size, elem_count * sizeof(float));
CreateAndCheckSizes(elements * elem_size, elements * sizeof(float));
for (int i = 0; i < 1000; ++i) for (int i = 0; i < 1000; ++i)
RunVertices(100000); RunVertices(100000);
} }
TEST_P(VertexLoaderSpeedTest, TexCoordSingleElement) TEST_P(VertexLoaderSpeedTest, TexCoordSingleElement)
{ {
int format, elements; ComponentFormat format;
std::tie(format, elements) = GetParam(); int elements_i;
const char* map[] = {"u8", "s8", "u16", "s16", "float"}; std::tie(format, elements_i) = GetParam();
printf("format: %s, elements: %d\n", map[format], elements); TexComponentCount elements = static_cast<TexComponentCount>(elements_i);
m_vtx_desc.Position = DIRECT; fmt::print("format: {}, elements: {}\n", format, elements);
m_vtx_attr.g0.PosFormat = FORMAT_BYTE; const u32 elem_count = elements == TexComponentCount::S ? 1 : 2;
m_vtx_desc.Tex0Coord = DIRECT; m_vtx_desc.low.Position = VertexComponentFormat::Direct;
m_vtx_attr.g0.PosFormat = ComponentFormat::Byte;
m_vtx_desc.high.Tex0Coord = VertexComponentFormat::Direct;
m_vtx_attr.g0.Tex0CoordFormat = format; m_vtx_attr.g0.Tex0CoordFormat = format;
m_vtx_attr.g0.Tex0CoordElements = elements; m_vtx_attr.g0.Tex0CoordElements = elements;
elements += 1; const size_t elem_size = GetElementSize(format);
size_t elem_size = static_cast<size_t>(1) << (format / 2); CreateAndCheckSizes(2 * sizeof(s8) + elem_count * elem_size,
CreateAndCheckSizes(2 * sizeof(s8) + elements * elem_size, 2 * sizeof(float) + elem_count * sizeof(float));
2 * sizeof(float) + elements * sizeof(float));
for (int i = 0; i < 1000; ++i) for (int i = 0; i < 1000; ++i)
RunVertices(100000); RunVertices(100000);
} }
@ -294,52 +303,52 @@ TEST_P(VertexLoaderSpeedTest, TexCoordSingleElement)
TEST_F(VertexLoaderTest, LargeFloatVertexSpeed) TEST_F(VertexLoaderTest, LargeFloatVertexSpeed)
{ {
// Enables most attributes in floating point indexed mode to test speed. // Enables most attributes in floating point indexed mode to test speed.
m_vtx_desc.PosMatIdx = 1; m_vtx_desc.low.PosMatIdx = 1;
m_vtx_desc.Tex0MatIdx = 1; m_vtx_desc.low.Tex0MatIdx = 1;
m_vtx_desc.Tex1MatIdx = 1; m_vtx_desc.low.Tex1MatIdx = 1;
m_vtx_desc.Tex2MatIdx = 1; m_vtx_desc.low.Tex2MatIdx = 1;
m_vtx_desc.Tex3MatIdx = 1; m_vtx_desc.low.Tex3MatIdx = 1;
m_vtx_desc.Tex4MatIdx = 1; m_vtx_desc.low.Tex4MatIdx = 1;
m_vtx_desc.Tex5MatIdx = 1; m_vtx_desc.low.Tex5MatIdx = 1;
m_vtx_desc.Tex6MatIdx = 1; m_vtx_desc.low.Tex6MatIdx = 1;
m_vtx_desc.Tex7MatIdx = 1; m_vtx_desc.low.Tex7MatIdx = 1;
m_vtx_desc.Position = INDEX16; m_vtx_desc.low.Position = VertexComponentFormat::Index16;
m_vtx_desc.Normal = INDEX16; m_vtx_desc.low.Normal = VertexComponentFormat::Index16;
m_vtx_desc.Color0 = INDEX16; m_vtx_desc.low.Color0 = VertexComponentFormat::Index16;
m_vtx_desc.Color1 = INDEX16; m_vtx_desc.low.Color1 = VertexComponentFormat::Index16;
m_vtx_desc.Tex0Coord = INDEX16; m_vtx_desc.high.Tex0Coord = VertexComponentFormat::Index16;
m_vtx_desc.Tex1Coord = INDEX16; m_vtx_desc.high.Tex1Coord = VertexComponentFormat::Index16;
m_vtx_desc.Tex2Coord = INDEX16; m_vtx_desc.high.Tex2Coord = VertexComponentFormat::Index16;
m_vtx_desc.Tex3Coord = INDEX16; m_vtx_desc.high.Tex3Coord = VertexComponentFormat::Index16;
m_vtx_desc.Tex4Coord = INDEX16; m_vtx_desc.high.Tex4Coord = VertexComponentFormat::Index16;
m_vtx_desc.Tex5Coord = INDEX16; m_vtx_desc.high.Tex5Coord = VertexComponentFormat::Index16;
m_vtx_desc.Tex6Coord = INDEX16; m_vtx_desc.high.Tex6Coord = VertexComponentFormat::Index16;
m_vtx_desc.Tex7Coord = INDEX16; m_vtx_desc.high.Tex7Coord = VertexComponentFormat::Index16;
m_vtx_attr.g0.PosElements = 1; // XYZ m_vtx_attr.g0.PosElements = CoordComponentCount::XYZ;
m_vtx_attr.g0.PosFormat = FORMAT_FLOAT; m_vtx_attr.g0.PosFormat = ComponentFormat::Float;
m_vtx_attr.g0.NormalElements = 1; // NBT m_vtx_attr.g0.NormalElements = NormalComponentCount::NBT;
m_vtx_attr.g0.NormalFormat = FORMAT_FLOAT; m_vtx_attr.g0.NormalFormat = ComponentFormat::Float;
m_vtx_attr.g0.Color0Elements = 1; // Has Alpha m_vtx_attr.g0.Color0Elements = ColorComponentCount::RGBA;
m_vtx_attr.g0.Color0Comp = FORMAT_32B_8888; m_vtx_attr.g0.Color0Comp = ColorFormat::RGBA8888;
m_vtx_attr.g0.Color1Elements = 1; // Has Alpha m_vtx_attr.g0.Color1Elements = ColorComponentCount::RGBA;
m_vtx_attr.g0.Color1Comp = FORMAT_32B_8888; m_vtx_attr.g0.Color1Comp = ColorFormat::RGBA8888;
m_vtx_attr.g0.Tex0CoordElements = 1; // ST m_vtx_attr.g0.Tex0CoordElements = TexComponentCount::ST;
m_vtx_attr.g0.Tex0CoordFormat = FORMAT_FLOAT; m_vtx_attr.g0.Tex0CoordFormat = ComponentFormat::Float;
m_vtx_attr.g1.Tex1CoordElements = 1; // ST m_vtx_attr.g1.Tex1CoordElements = TexComponentCount::ST;
m_vtx_attr.g1.Tex1CoordFormat = FORMAT_FLOAT; m_vtx_attr.g1.Tex1CoordFormat = ComponentFormat::Float;
m_vtx_attr.g1.Tex2CoordElements = 1; // ST m_vtx_attr.g1.Tex2CoordElements = TexComponentCount::ST;
m_vtx_attr.g1.Tex2CoordFormat = FORMAT_FLOAT; m_vtx_attr.g1.Tex2CoordFormat = ComponentFormat::Float;
m_vtx_attr.g1.Tex3CoordElements = 1; // ST m_vtx_attr.g1.Tex3CoordElements = TexComponentCount::ST;
m_vtx_attr.g1.Tex3CoordFormat = FORMAT_FLOAT; m_vtx_attr.g1.Tex3CoordFormat = ComponentFormat::Float;
m_vtx_attr.g1.Tex4CoordElements = 1; // ST m_vtx_attr.g1.Tex4CoordElements = TexComponentCount::ST;
m_vtx_attr.g1.Tex4CoordFormat = FORMAT_FLOAT; m_vtx_attr.g1.Tex4CoordFormat = ComponentFormat::Float;
m_vtx_attr.g2.Tex5CoordElements = 1; // ST m_vtx_attr.g2.Tex5CoordElements = TexComponentCount::ST;
m_vtx_attr.g2.Tex5CoordFormat = FORMAT_FLOAT; m_vtx_attr.g2.Tex5CoordFormat = ComponentFormat::Float;
m_vtx_attr.g2.Tex6CoordElements = 1; // ST m_vtx_attr.g2.Tex6CoordElements = TexComponentCount::ST;
m_vtx_attr.g2.Tex6CoordFormat = FORMAT_FLOAT; m_vtx_attr.g2.Tex6CoordFormat = ComponentFormat::Float;
m_vtx_attr.g2.Tex7CoordElements = 1; // ST m_vtx_attr.g2.Tex7CoordElements = TexComponentCount::ST;
m_vtx_attr.g2.Tex7CoordFormat = FORMAT_FLOAT; m_vtx_attr.g2.Tex7CoordFormat = ComponentFormat::Float;
CreateAndCheckSizes(33, 156); CreateAndCheckSizes(33, 156);