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];
// Colors
const std::array<u64, 2> colDesc{
vtxDesc.Color0,
vtxDesc.Color1,
};
const std::array<u32, 2> colComp{
const std::array<ColorFormat, 2> colComp{
vtxAttr.g0.Color0Comp,
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.g1.Tex3CoordElements, vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements,
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.g1.Tex3CoordFormat, vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat,
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{};
// Add position and texture matrix indices
u64 vtxDescHex = cpMem.vtxDesc.Hex;
for (int i = 0; i < 9; ++i)
sizes[0] = vtxDesc.low.PosMatIdx;
for (size_t i = 0; i < vtxDesc.low.TexMatIdx.Size(); ++i)
{
sizes[i] = vtxDescHex & 1;
vtxDescHex >>= 1;
sizes[i + 1] = vtxDesc.low.TexMatIdx[i];
}
// 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);
// 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);
}
else
@ -95,33 +90,33 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
}
// Colors
for (size_t i = 0; i < colDesc.size(); i++)
for (size_t i = 0; i < vtxDesc.low.Color.Size(); i++)
{
int size = 0;
switch (colDesc[i])
switch (vtxDesc.low.Color[i])
{
case NOT_PRESENT:
case VertexComponentFormat::NotPresent:
break;
case DIRECT:
case VertexComponentFormat::Direct:
switch (colComp[i])
{
case FORMAT_16B_565:
case ColorFormat::RGB565:
size = 2;
break;
case FORMAT_24B_888:
case ColorFormat::RGB888:
size = 3;
break;
case FORMAT_32B_888x:
case ColorFormat::RGB888x:
size = 4;
break;
case FORMAT_16B_4444:
case ColorFormat::RGBA4444:
size = 2;
break;
case FORMAT_24B_6666:
case ColorFormat::RGBA6666:
size = 3;
break;
case FORMAT_32B_8888:
case ColorFormat::RGBA8888:
size = 4;
break;
default:
@ -129,10 +124,10 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
break;
}
break;
case INDEX8:
case VertexComponentFormat::Index8:
size = 1;
break;
case INDEX16:
case VertexComponentFormat::Index16:
size = 2;
break;
}
@ -141,11 +136,10 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
}
// Texture coordinates
vtxDescHex = vtxDesc.Hex >> 17;
for (size_t i = 0; i < tcFormat.size(); i++)
{
sizes[13 + i] = VertexLoader_TextCoord::GetSize(vtxDescHex & 3, tcFormat[i], tcElements[i]);
vtxDescHex >>= 2;
sizes[13 + i] =
VertexLoader_TextCoord::GetSize(vtxDesc.high.TexCoord[i], tcFormat[i], tcElements[i]);
}
return sizes;
@ -267,13 +261,11 @@ void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem)
switch (subCmd & 0xF0)
{
case 0x50:
cpMem.vtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits
cpMem.vtxDesc.Hex |= value;
cpMem.vtxDesc.low.Hex = value;
break;
case 0x60:
cpMem.vtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits
cpMem.vtxDesc.Hex |= (u64)value << 17;
cpMem.vtxDesc.high.Hex = value;
break;
case 0x70:

View File

@ -6,6 +6,7 @@
#include <algorithm>
#include "Common/MsgHandler.h"
#include "Core/FifoPlayer/FifoAnalyzer.h"
#include "Core/FifoPlayer/FifoRecorder.h"
#include "Core/HW/Memmap.h"
@ -44,14 +45,28 @@ void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, const u8* vertexData,
int numVertices)
{
// Skip if not indexed array
int arrayType = (s_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3;
if (arrayType < 2)
VertexComponentFormat arrayType;
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;
int maxIndex = 0;
// Determine min and max indices
if (arrayType == INDEX8)
if (arrayType == VertexComponentFormat::Index8)
{
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) {
// 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 u32 color_elements = i == 0 ? g0.Color0Elements : g0.Color1Elements;
color[0] = color_elements == 0 ? 255 : 0;
const auto color_elements = i == 0 ? g0.Color0Elements.Value() : g0.Color1Elements.Value();
color[0] = color_elements == ColorComponentCount::RGB ? 255 : 0;
color[1] = 255;
color[2] = 255;
color[3] = 255;

View File

@ -17,7 +17,9 @@ void DoCPState(PointerWrap& p)
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_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.DoMarker("CP Memory");
if (p.mode == PointerWrap::MODE_READ)

View File

@ -4,8 +4,11 @@
#pragma once
#include "Common/BitField.h"
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Common/EnumFormatter.h"
#include "Common/MsgHandler.h"
enum
{
@ -50,176 +53,262 @@ enum
};
// Vertex components
enum
enum class VertexComponentFormat
{
NOT_PRESENT = 0,
DIRECT = 1,
INDEX8 = 2,
INDEX16 = 3,
MASK_INDEXED = 2,
NotPresent = 0,
Direct = 1,
Index8 = 2,
Index16 = 3,
};
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
FORMAT_BYTE = 1, // 3 Cmp
FORMAT_USHORT = 2,
FORMAT_SHORT = 3,
FORMAT_FLOAT = 4,
return format == VertexComponentFormat::Index8 || format == VertexComponentFormat::Index16;
}
enum class ComponentFormat
{
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
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
switch (format)
{
// 0: not present
// 1: present
u64 PosMatIdx : 1;
u64 Tex0MatIdx : 1;
u64 Tex1MatIdx : 1;
u64 Tex2MatIdx : 1;
u64 Tex3MatIdx : 1;
u64 Tex4MatIdx : 1;
u64 Tex5MatIdx : 1;
u64 Tex6MatIdx : 1;
u64 Tex7MatIdx : 1;
case ComponentFormat::UByte:
case ComponentFormat::Byte:
return 1;
case ComponentFormat::UShort:
case ComponentFormat::Short:
return 2;
case ComponentFormat::Float:
return 4;
default:
PanicAlertFmt("Unknown format {}", format);
return 0;
}
}
// 00: not present
// 01: direct
// 10: 8 bit index
// 11: 16 bit index
u64 Position : 2;
u64 Normal : 2;
u64 Color0 : 2;
u64 Color1 : 2;
u64 Tex0Coord : 2;
u64 Tex1Coord : 2;
u64 Tex2Coord : 2;
u64 Tex3Coord : 2;
u64 Tex4Coord : 2;
u64 Tex5Coord : 2;
u64 Tex6Coord : 2;
u64 Tex7Coord : 2;
u64 : 31;
enum class CoordComponentCount
{
XY = 0,
XYZ = 1,
};
template <>
struct fmt::formatter<CoordComponentCount> : EnumFormatter<CoordComponentCount::XYZ>
{
formatter() : EnumFormatter({"2 (x, y)", "3 (x, y, z)"}) {}
};
enum class NormalComponentCount
{
N = 0,
NBT = 1,
};
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
{
u32 Hex0, Hex1;
};
Low low;
High high;
// Easily index into the Position..Tex7Coord fields.
u32 GetVertexArrayStatus(int idx) { return (Hex >> (9 + idx * 2)) & 0x3; }
// This structure was originally packed into bits 0..32, using 33 total bits.
// 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
{
u32 Hex;
struct
{
// 0:8
u32 PosElements : 1;
u32 PosFormat : 3;
u32 PosFrac : 5;
// 9:12
u32 NormalElements : 1;
u32 NormalFormat : 3;
// 13:16
u32 Color0Elements : 1;
u32 Color0Comp : 3;
// 17:20
u32 Color1Elements : 1;
u32 Color1Comp : 3;
// 21:29
u32 Tex0CoordElements : 1;
u32 Tex0CoordFormat : 3;
u32 Tex0Frac : 5;
// 30:31
u32 ByteDequant : 1;
u32 NormalIndex3 : 1;
};
// 0:8
BitField<0, 1, CoordComponentCount> PosElements;
BitField<1, 3, ComponentFormat> PosFormat;
BitField<4, 5, u32> PosFrac;
// 9:12
BitField<9, 1, NormalComponentCount> NormalElements;
BitField<10, 3, ComponentFormat> NormalFormat;
// 13:16
BitField<13, 1, ColorComponentCount> Color0Elements;
BitField<14, 3, ColorFormat> Color0Comp;
// 17:20
BitField<17, 1, ColorComponentCount> Color1Elements;
BitField<18, 3, ColorFormat> Color1Comp;
// 21:29
BitField<21, 1, TexComponentCount> Tex0CoordElements;
BitField<22, 3, ComponentFormat> Tex0CoordFormat;
BitField<25, 5, u32> Tex0Frac;
// 30:31
BitField<30, 1, u32> ByteDequant;
BitField<31, 1, u32> NormalIndex3;
};
union UVAT_group1
{
u32 Hex;
struct
{
// 0:8
u32 Tex1CoordElements : 1;
u32 Tex1CoordFormat : 3;
u32 Tex1Frac : 5;
// 9:17
u32 Tex2CoordElements : 1;
u32 Tex2CoordFormat : 3;
u32 Tex2Frac : 5;
// 18:26
u32 Tex3CoordElements : 1;
u32 Tex3CoordFormat : 3;
u32 Tex3Frac : 5;
// 27:30
u32 Tex4CoordElements : 1;
u32 Tex4CoordFormat : 3;
//
u32 : 1;
};
// 0:8
BitField<0, 1, TexComponentCount> Tex1CoordElements;
BitField<1, 3, ComponentFormat> Tex1CoordFormat;
BitField<4, 5, u32> Tex1Frac;
// 9:17
BitField<9, 1, TexComponentCount> Tex2CoordElements;
BitField<10, 3, ComponentFormat> Tex2CoordFormat;
BitField<13, 5, u32> Tex2Frac;
// 18:26
BitField<18, 1, TexComponentCount> Tex3CoordElements;
BitField<19, 3, ComponentFormat> Tex3CoordFormat;
BitField<22, 5, u32> Tex3Frac;
// 27:30
BitField<27, 1, TexComponentCount> Tex4CoordElements;
BitField<28, 3, ComponentFormat> Tex4CoordFormat;
// 31
BitField<31, 1, u32> VCacheEnhance;
};
union UVAT_group2
{
u32 Hex;
struct
{
// 0:4
u32 Tex4Frac : 5;
// 5:13
u32 Tex5CoordElements : 1;
u32 Tex5CoordFormat : 3;
u32 Tex5Frac : 5;
// 14:22
u32 Tex6CoordElements : 1;
u32 Tex6CoordFormat : 3;
u32 Tex6Frac : 5;
// 23:31
u32 Tex7CoordElements : 1;
u32 Tex7CoordFormat : 3;
u32 Tex7Frac : 5;
};
// 0:4
BitField<0, 5, u32> Tex4Frac;
// 5:13
BitField<5, 1, TexComponentCount> Tex5CoordElements;
BitField<6, 3, ComponentFormat> Tex5CoordFormat;
BitField<9, 5, u32> Tex5Frac;
// 14:22
BitField<14, 1, TexComponentCount> Tex6CoordElements;
BitField<15, 3, ComponentFormat> Tex6CoordFormat;
BitField<18, 5, u32> Tex6Frac;
// 23:31
BitField<23, 1, TexComponentCount> Tex7CoordElements;
BitField<24, 3, ComponentFormat> Tex7CoordFormat;
BitField<27, 5, u32> Tex7Frac;
};
struct ColorAttr
{
u8 Elements;
u8 Comp;
ColorComponentCount Elements;
ColorFormat Comp;
};
struct TexAttr
{
u8 Elements;
u8 Format;
TexComponentCount Elements;
ComponentFormat Format;
u8 Frac;
};
struct TVtxAttr
{
u8 PosElements;
u8 PosFormat;
CoordComponentCount PosElements;
ComponentFormat PosFormat;
u8 PosFrac;
u8 NormalElements;
u8 NormalFormat;
NormalComponentCount NormalElements;
ComponentFormat NormalFormat;
ColorAttr color[2];
TexAttr texCoord[8];
bool ByteDequant;
@ -229,39 +318,23 @@ struct TVtxAttr
// Matrix indices
union TMatrixIndexA
{
struct
{
u32 PosNormalMtxIdx : 6;
u32 Tex0MtxIdx : 6;
u32 Tex1MtxIdx : 6;
u32 Tex2MtxIdx : 6;
u32 Tex3MtxIdx : 6;
};
struct
{
u32 Hex : 30;
u32 unused : 2;
};
BitField<0, 6, u32> PosNormalMtxIdx;
BitField<6, 6, u32> Tex0MtxIdx;
BitField<12, 6, u32> Tex1MtxIdx;
BitField<18, 6, u32> Tex2MtxIdx;
BitField<24, 6, u32> Tex3MtxIdx;
u32 Hex;
};
union TMatrixIndexB
{
struct
{
u32 Tex4MtxIdx : 6;
u32 Tex5MtxIdx : 6;
u32 Tex6MtxIdx : 6;
u32 Tex7MtxIdx : 6;
};
struct
{
u32 Hex : 24;
u32 unused : 8;
};
BitField<0, 6, u32> Tex4MtxIdx;
BitField<6, 6, u32> Tex5MtxIdx;
BitField<12, 6, u32> Tex6MtxIdx;
BitField<18, 6, u32> Tex7MtxIdx;
u32 Hex;
};
#pragma pack()
struct VAT
{
UVAT_group0 g0;

View File

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

View File

@ -3,6 +3,9 @@
// Refer to the license.txt file included.
#include "VideoCommon/VertexLoaderARM64.h"
#include <array>
#include "Common/CommonTypes.h"
#include "VideoCommon/DataReader.h"
#include "VideoCommon/VertexLoaderManager.h"
@ -45,11 +48,11 @@ VertexLoaderARM64::VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_at
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)
{
@ -83,7 +86,8 @@ void VertexLoaderARM64::GetVertexAddr(int array, u64 attribute, ARM64Reg reg)
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);
}
@ -97,23 +101,24 @@ void VertexLoaderARM64::GetVertexAddr(int array, u64 attribute, ARM64Reg reg)
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);
else
return m_src_ofs;
return -1;
}
int VertexLoaderARM64::ReadVertex(u64 attribute, int format, int count_in, int count_out,
bool dequantize, u8 scaling_exponent,
int VertexLoaderARM64::ReadVertex(VertexComponentFormat attribute, ComponentFormat format,
int count_in, int count_out, bool dequantize, u8 scaling_exponent,
AttributeFormat* native_format, s32 offset)
{
ARM64Reg coords = count_in == 3 ? Q31 : D31;
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_size =
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);
}
if (format != FORMAT_FLOAT)
if (format != ComponentFormat::Float)
{
// Extend and convert to float
switch (format)
{
case FORMAT_UBYTE:
case ComponentFormat::UByte:
m_float_emit.UXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
break;
case FORMAT_BYTE:
case ComponentFormat::Byte:
m_float_emit.SXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
break;
case FORMAT_USHORT:
case ComponentFormat::UShort:
m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
break;
case FORMAT_SHORT:
case ComponentFormat::Short:
m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords));
break;
@ -207,20 +212,20 @@ int VertexLoaderARM64::ReadVertex(u64 attribute, int format, int count_in, int c
native_format->integer = false;
m_dst_ofs += sizeof(float) * count_out;
if (attribute == DIRECT)
if (attribute == VertexComponentFormat::Direct)
m_src_ofs += 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;
switch (format)
{
case FORMAT_24B_888:
case FORMAT_32B_888x:
case FORMAT_32B_8888:
case ColorFormat::RGB888:
case ColorFormat::RGB888x:
case ColorFormat::RGBA8888:
if (offset == -1)
LDR(IndexType::Unsigned, scratch2_reg, EncodeRegTo64(scratch1_reg), 0);
else if (offset & 3) // Not aligned - unscaled
@ -228,13 +233,13 @@ void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset)
else
LDR(IndexType::Unsigned, scratch2_reg, src_reg, offset);
if (format != FORMAT_32B_8888)
if (format != ColorFormat::RGBA8888)
ORRI2R(scratch2_reg, scratch2_reg, 0xFF000000);
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;
case FORMAT_16B_565:
case ColorFormat::RGB565:
// RRRRRGGG GGGBBBBB
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
if (offset == -1)
@ -270,7 +275,7 @@ void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset)
load_bytes = 2;
break;
case FORMAT_16B_4444:
case ColorFormat::RGBA4444:
// BBBBAAAA RRRRGGGG
// REV16 - RRRRGGGG BBBBAAAA
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
@ -303,7 +308,7 @@ void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset)
load_bytes = 2;
break;
case FORMAT_24B_6666:
case ColorFormat::RGBA6666:
// RRRRRRGG GGGGBBBB BBAAAAAA
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
if (offset == -1)
@ -349,7 +354,7 @@ void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset)
load_bytes = 3;
break;
}
if (attribute == DIRECT)
if (attribute == VertexComponentFormat::Direct)
m_src_ofs += load_bytes;
}
@ -370,24 +375,19 @@ void VertexLoaderARM64::GenerateVertexLoader()
// We can touch all except v8-v15
// 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_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;
}
bool need_scale =
(m_VtxAttr.ByteDequant && m_VtxAttr.PosFrac) || (has_tc && has_tc_scale) || m_VtxDesc.Normal;
bool need_scale = (m_VtxAttr.ByteDequant && m_VtxAttr.PosFrac) || (has_tc && has_tc_scale) ||
(m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent);
AlignCode16();
if (m_VtxDesc.Position & MASK_INDEXED)
if (IsIndexed(m_VtxDesc.low.Position))
MOV(skipped_reg, WZR);
MOV(saved_count, count_reg);
@ -399,7 +399,7 @@ void VertexLoaderARM64::GenerateVertexLoader()
const u8* loop_start = GetCodePtr();
if (m_VtxDesc.PosMatIdx)
if (m_VtxDesc.low.PosMatIdx)
{
LDRB(IndexType::Unsigned, scratch1_reg, src_reg, m_src_ofs);
AND(scratch1_reg, scratch1_reg, 0, 5);
@ -422,50 +422,47 @@ void VertexLoaderARM64::GenerateVertexLoader()
m_dst_ofs += sizeof(u32);
}
u32 texmatidx_ofs[8];
const u64 tm[8] = {
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++)
std::array<u32, 8> texmatidx_ofs;
for (size_t i = 0; i < m_VtxDesc.low.TexMatIdx.Size(); i++)
{
if (tm[i])
if (m_VtxDesc.low.TexMatIdx[i])
texmatidx_ofs[i] = m_src_ofs++;
}
// Position
{
int elem_size = 1 << (m_VtxAttr.PosFormat / 2);
int load_bytes = elem_size * (m_VtxAttr.PosElements + 2);
int elem_size = GetElementSize(m_VtxAttr.PosFormat);
int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3;
int load_bytes = elem_size * pos_elements;
int load_size =
load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
load_size <<= 3;
s32 offset =
GetAddressImm(ARRAY_POSITION, m_VtxDesc.Position, EncodeRegTo64(scratch1_reg), load_size);
int pos_elements = m_VtxAttr.PosElements + 2;
ReadVertex(m_VtxDesc.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements,
s32 offset = GetAddressImm(ARRAY_POSITION, m_VtxDesc.low.Position, EncodeRegTo64(scratch1_reg),
load_size);
ReadVertex(m_VtxDesc.low.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements,
m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position, offset);
}
if (m_VtxDesc.Normal)
if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{
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;
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)
{
int elem_size = 1 << (m_VtxAttr.NormalFormat / 2);
int elem_size = GetElementSize(m_VtxAttr.NormalFormat);
int load_bytes = elem_size * 3;
int load_size = load_bytes == 1 ?
1 :
load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
offset = GetAddressImm(ARRAY_NORMAL, m_VtxDesc.Normal, EncodeRegTo64(scratch1_reg),
offset = GetAddressImm(ARRAY_NORMAL, m_VtxDesc.low.Normal, EncodeRegTo64(scratch1_reg),
load_size << 3);
if (offset == -1)
@ -473,7 +470,7 @@ void VertexLoaderARM64::GenerateVertexLoader()
else
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);
if (offset == -1)
@ -483,25 +480,26 @@ void VertexLoaderARM64::GenerateVertexLoader()
}
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;
}
const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
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].type = VAR_UNSIGNED_BYTE;
m_native_vtx_decl.colors[i].integer = false;
if (col[i])
if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent)
{
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;
s32 offset = GetAddressImm(ARRAY_COLOR + i, col[i], EncodeRegTo64(scratch1_reg), align);
ReadColor(col[i], m_VtxAttr.color[i].Comp, offset);
s32 offset = GetAddressImm(ARRAY_COLOR + int(i), m_VtxDesc.low.Color[i],
EncodeRegTo64(scratch1_reg), align);
ReadColor(m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp, offset);
m_native_components |= VB_HAS_COL0 << i;
m_native_vtx_decl.colors[i].components = 4;
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].type = VAR_FLOAT;
m_native_vtx_decl.texcoords[i].integer = false;
int elements = m_VtxAttr.texCoord[i].Elements + 1;
if (tc[i])
int elements = m_VtxAttr.texCoord[i].Elements == TexComponentCount::S ? 1 : 2;
if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent)
{
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_size = load_bytes == 1 ?
1 :
load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16;
load_size <<= 3;
s32 offset =
GetAddressImm(ARRAY_TEXCOORD0 + i, tc[i], EncodeRegTo64(scratch1_reg), load_size);
s32 offset = GetAddressImm(ARRAY_TEXCOORD0 + int(i), m_VtxDesc.high.TexCoord[i],
EncodeRegTo64(scratch1_reg), load_size);
u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac;
ReadVertex(tc[i], m_VtxAttr.texCoord[i].Format, elements, tm[i] ? 2 : elements,
m_VtxAttr.ByteDequant, scaling_exponent, &m_native_vtx_decl.texcoords[i], offset);
ReadVertex(m_VtxDesc.high.TexCoord[i], m_VtxAttr.texCoord[i].Format, elements,
m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.ByteDequant, scaling_exponent,
&m_native_vtx_decl.texcoords[i], offset);
}
if (tm[i])
if (m_VtxDesc.low.TexMatIdx[i])
{
m_native_components |= VB_HAS_TEXMTXIDX0 << i;
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]);
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_dst_ofs += sizeof(float);
@ -587,7 +586,7 @@ void VertexLoaderARM64::GenerateVertexLoader()
SUB(count_reg, count_reg, 1);
CBNZ(count_reg, loop_start);
if (m_VtxDesc.Position & MASK_INDEXED)
if (IsIndexed(m_VtxDesc.low.Position))
{
SUB(W0, saved_count, skipped_reg);
RET(X30);

View File

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

View File

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

View File

@ -23,8 +23,8 @@ public:
VertexLoaderUID() {}
VertexLoaderUID(const TVtxDesc& vtx_desc, const VAT& vat)
{
vid[0] = vtx_desc.Hex & 0xFFFFFFFF;
vid[1] = vtx_desc.Hex >> 32;
vid[0] = vtx_desc.GetLegacyHex0();
vid[1] = vtx_desc.GetLegacyHex1();
vid[2] = vat.g0.Hex;
vid[3] = vat.g1.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.
// Note: Only array bases 0 through 11 are used by the Vertex loaders.
// 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 (g_main_cp_state.vtx_desc.GetVertexArrayStatus(i) & MASK_INDEXED)
cached_arraybases[i] = Memory::GetPointer(g_main_cp_state.array_bases[i]);
if (IsIndexed(g_main_cp_state.vtx_desc.low.Color[i]))
cached_arraybases[ARRAY_COLOR + 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;
@ -317,15 +332,13 @@ void LoadCPReg(u32 sub_cmd, u32 value, bool is_preprocess)
break;
case VCD_LO:
state->vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits
state->vtx_desc.Hex |= value;
state->vtx_desc.low.Hex = value;
state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG);
state->bases_dirty = true;
break;
case VCD_HI:
state->vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits
state->vtx_desc.Hex |= (u64)value << 17;
state->vtx_desc.high.Hex = value;
state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG);
state->bases_dirty = true;
break;
@ -371,8 +384,8 @@ void FillCPMemoryArray(u32* memory)
{
memory[MATINDEX_A] = g_main_cp_state.matrix_index_a.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_HI] = (u32)(g_main_cp_state.vtx_desc.Hex >> 17);
memory[VCD_LO] = g_main_cp_state.vtx_desc.low.Hex;
memory[VCD_HI] = g_main_cp_state.vtx_desc.high.Hex;
for (int i = 0; i < CP_NUM_VAT_REG; ++i)
{

View File

@ -2,6 +2,9 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoCommon/VertexLoaderX64.h"
#include <array>
#include <cstring>
#include <string>
@ -15,7 +18,6 @@
#include "Common/x64Emitter.h"
#include "VideoCommon/DataReader.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexLoaderX64.h"
using namespace Gen;
@ -55,12 +57,12 @@ VertexLoaderX64::VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att)
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);
if (attribute & MASK_INDEXED)
if (IsIndexed(attribute))
{
int bits = attribute == INDEX8 ? 8 : 16;
int bits = attribute == VertexComponentFormat::Index8 ? 8 : 16;
LoadAndSwap(bits, scratch1, data);
m_src_ofs += bits / 8;
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,
bool dequantize, u8 scaling_exponent,
int VertexLoaderX64::ReadVertex(OpArg data, VertexComponentFormat attribute, ComponentFormat format,
int count_in, int count_out, bool dequantize, u8 scaling_exponent,
AttributeFormat* native_format)
{
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;
int elem_size = 1 << (format / 2);
int elem_size = GetElementSize(format);
int load_bytes = elem_size * count_in;
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;
if (attribute == DIRECT)
if (attribute == VertexComponentFormat::Direct)
m_src_ofs += load_bytes;
if (cpu_info.bSSSE3)
@ -139,12 +141,12 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
else
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.
if (format == FORMAT_BYTE)
if (format == ComponentFormat::Byte)
PSRAD(coords, 24);
if (format == FORMAT_SHORT)
if (format == ComponentFormat::Short)
PSRAD(coords, 16);
}
else
@ -153,20 +155,20 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
X64Reg temp = XMM1;
switch (format)
{
case FORMAT_UBYTE:
case ComponentFormat::UByte:
MOVD_xmm(coords, data);
PXOR(temp, R(temp));
PUNPCKLBW(coords, R(temp));
PUNPCKLWD(coords, R(temp));
break;
case FORMAT_BYTE:
case ComponentFormat::Byte:
MOVD_xmm(coords, data);
PUNPCKLBW(coords, R(coords));
PUNPCKLWD(coords, R(coords));
PSRAD(coords, 24);
break;
case FORMAT_USHORT:
case FORMAT_SHORT:
case ComponentFormat::UShort:
case ComponentFormat::Short:
switch (count_in)
{
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.
break;
}
if (format == FORMAT_SHORT)
if (format == ComponentFormat::Short)
PSRAD(coords, 16);
else
PSRLD(coords, 16);
break;
case FORMAT_FLOAT:
case ComponentFormat::Float:
// Floats don't need to be scaled or converted,
// so we can just load/swap/store them directly
// 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));
@ -265,22 +267,22 @@ int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count
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;
switch (format)
{
case FORMAT_24B_888:
case FORMAT_32B_888x:
case FORMAT_32B_8888:
case ColorFormat::RGB888:
case ColorFormat::RGB888x:
case ColorFormat::RGBA8888:
MOV(32, R(scratch1), data);
if (format != FORMAT_32B_8888)
if (format != ColorFormat::RGBA8888)
OR(32, R(scratch1), Imm32(0xFF000000));
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;
case FORMAT_16B_565:
case ColorFormat::RGB565:
// RRRRRGGG GGGBBBBB
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
LoadAndSwap(16, scratch1, data);
@ -320,7 +322,7 @@ void VertexLoaderX64::ReadColor(OpArg data, u64 attribute, int format)
load_bytes = 2;
break;
case FORMAT_16B_4444:
case ColorFormat::RGBA4444:
// RRRRGGGG BBBBAAAA
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
LoadAndSwap(16, scratch1, data);
@ -348,7 +350,7 @@ void VertexLoaderX64::ReadColor(OpArg data, u64 attribute, int format)
load_bytes = 2;
break;
case FORMAT_24B_6666:
case ColorFormat::RGBA6666:
// RRRRRRGG GGGGBBBB BBAAAAAA
// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
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;
break;
}
if (attribute == DIRECT)
if (attribute == VertexComponentFormat::Direct)
m_src_ofs += load_bytes;
}
@ -399,14 +401,14 @@ void VertexLoaderX64::GenerateVertexLoader()
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));
// TODO: load constants into registers outside the main loop
const u8* loop_start = GetCodePtr();
if (m_VtxDesc.PosMatIdx)
if (m_VtxDesc.low.PosMatIdx)
{
MOVZX(32, 8, scratch1, MDisp(src_reg, m_src_ofs));
AND(32, R(scratch1), Imm8(0x3F));
@ -428,51 +430,47 @@ void VertexLoaderX64::GenerateVertexLoader()
m_dst_ofs += sizeof(u32);
}
u32 texmatidx_ofs[8];
const u64 tm[8] = {
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++)
std::array<u32, 8> texmatidx_ofs;
for (size_t i = 0; i < m_VtxDesc.low.TexMatIdx.Size(); i++)
{
if (tm[i])
if (m_VtxDesc.low.TexMatIdx[i])
texmatidx_ofs[i] = m_src_ofs++;
}
OpArg data = GetVertexAddr(ARRAY_POSITION, m_VtxDesc.Position);
int pos_elements = 2 + m_VtxAttr.PosElements;
ReadVertex(data, m_VtxDesc.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements,
OpArg data = GetVertexAddr(ARRAY_POSITION, m_VtxDesc.low.Position);
int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3;
ReadVertex(data, m_VtxDesc.low.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements,
m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position);
if (m_VtxDesc.Normal)
if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{
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)
{
data = GetVertexAddr(ARRAY_NORMAL, m_VtxDesc.Normal);
int elem_size = 1 << (m_VtxAttr.NormalFormat / 2);
data = GetVertexAddr(ARRAY_NORMAL, m_VtxDesc.low.Normal);
int elem_size = GetElementSize(m_VtxAttr.NormalFormat);
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]));
}
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;
}
const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
for (int i = 0; i < 2; i++)
for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++)
{
if (col[i])
if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent)
{
data = GetVertexAddr(ARRAY_COLOR + i, col[i]);
ReadColor(data, col[i], m_VtxAttr.color[i].Comp);
data = GetVertexAddr(ARRAY_COLOR + int(i), m_VtxDesc.low.Color[i]);
ReadColor(data, m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp);
m_native_components |= VB_HAS_COL0 << i;
m_native_vtx_decl.colors[i].components = 4;
m_native_vtx_decl.colors[i].enable = true;
@ -483,22 +481,19 @@ void VertexLoaderX64::GenerateVertexLoader()
}
}
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,
};
for (int i = 0; i < 8; i++)
for (size_t i = 0; i < m_VtxDesc.high.TexCoord.Size(); i++)
{
int elements = m_VtxAttr.texCoord[i].Elements + 1;
if (tc[i])
int elements = m_VtxAttr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1;
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;
ReadVertex(data, tc[i], m_VtxAttr.texCoord[i].Format, elements, tm[i] ? 2 : elements,
m_VtxAttr.ByteDequant, scaling_exponent, &m_native_vtx_decl.texcoords[i]);
ReadVertex(data, m_VtxDesc.high.TexCoord[i], m_VtxAttr.texCoord[i].Format, elements,
m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.ByteDequant, scaling_exponent,
&m_native_vtx_decl.texcoords[i]);
m_native_components |= VB_HAS_UV0 << i;
}
if (tm[i])
if (m_VtxDesc.low.TexMatIdx[i])
{
m_native_components |= VB_HAS_TEXMTXIDX0 << i;
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].integer = false;
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));
MOVSS(MDisp(dst_reg, m_dst_ofs), XMM0);
@ -537,7 +532,7 @@ void VertexLoaderX64::GenerateVertexLoader()
ABI_PopRegistersAndAdjustStack(regs, 0);
if (m_VtxDesc.Position & MASK_INDEXED)
if (IsIndexed(m_VtxDesc.low.Position))
{
SUB(32, R(ABI_RETURN), R(skipped_reg));
RET();

View File

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

View File

@ -230,12 +230,15 @@ constexpr Types InitializeTable()
constexpr Types s_table = InitializeTable();
} // 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 "VideoCommon/VertexLoader.h"
enum class VertexComponentFormat;
enum class ComponentFormat;
enum class NormalComponentCount;
class VertexLoader_Normal
{
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
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 "VideoCommon/VertexLoader.h"
enum class VertexComponentFormat;
enum class ComponentFormat;
enum class CoordComponentCount;
class VertexLoader_Position
{
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
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()

View File

@ -7,12 +7,18 @@
#include "Common/CommonTypes.h"
#include "VideoCommon/VertexLoader.h"
enum class VertexComponentFormat;
enum class ComponentFormat;
enum class TexComponentCount;
class VertexLoader_TextCoord
{
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.
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.
// If the vertex attribute has an alpha channel, zero is used, otherwise one.
const u32 color_chan_alpha =
(g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0.Color0Elements ^ 1) |
((g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0.Color1Elements ^ 1) << 1);
const auto g0 = g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0;
const u32 color_chan_alpha = (g0.Color0Elements == ColorComponentCount::RGB ? 1 : 0) |
(g0.Color1Elements == ColorComponentCount::RGB ? 2 : 0);
if (color_chan_alpha != constants.color_chan_alpha)
{
constants.color_chan_alpha = color_chan_alpha;

View File

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