Merge pull request #12684 from Pokechu22/invalid-vertex-component

Fix out of bounds accesses for invalid vertex component formats
This commit is contained in:
Admiral H. Curtiss 2024-04-04 22:10:18 +02:00 committed by GitHub
commit ad331205d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 364 additions and 88 deletions

View File

@ -137,7 +137,7 @@ void DolphinAnalytics::ReportGameStart()
}
// Keep in sync with enum class GameQuirk definition.
constexpr std::array<const char*, 28> GAME_QUIRKS_NAMES{
constexpr std::array<const char*, 32> GAME_QUIRKS_NAMES{
"directly-reads-wiimote-input",
"uses-DVDLowStopLaser",
"uses-DVDLowOffset",
@ -166,6 +166,10 @@ constexpr std::array<const char*, 28> GAME_QUIRKS_NAMES{
"mismatched-gpu-tex-coords-between-cp-and-xf",
"mismatched-gpu-matrix-indices-between-cp-and-xf",
"reads-bounding-box",
"invalid-position-component-format",
"invalid-normal-component-format",
"invalid-texture-coordinate-component-format",
"invalid-color-component-format",
};
static_assert(GAME_QUIRKS_NAMES.size() == static_cast<u32>(GameQuirk::COUNT),
"Game quirks names and enum definition are out of sync.");

View File

@ -94,6 +94,15 @@ enum class GameQuirk
// only a few read them (from PE_BBOX_LEFT etc.)
READS_BOUNDING_BOX,
// A few games use invalid vertex component formats, but the two known cases (Fifa Street and
// Def Jam: Fight for New York, see https://bugs.dolphin-emu.org/issues/12719) only use invalid
// normal formats and lighting is disabled in those cases, so it doesn't end up mattering.
// It's possible other games use invalid formats, possibly on other vertex components.
INVALID_POSITION_COMPONENT_FORMAT,
INVALID_NORMAL_COMPONENT_FORMAT,
INVALID_TEXTURE_COORDINATE_COMPONENT_FORMAT,
INVALID_COLOR_COMPONENT_FORMAT,
COUNT,
};

View File

@ -25,7 +25,7 @@ Gfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
{
using FormatMap = Common::EnumMap<DXGI_FORMAT, ComponentFormat::Float>;
using FormatMap = Common::EnumMap<DXGI_FORMAT, ComponentFormat::InvalidFloat7>;
static constexpr auto f = [](FormatMap a) { return a; }; // Deduction helper
static constexpr std::array<FormatMap, 4> d3d_float_format_lookup = {
@ -35,6 +35,9 @@ DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
DXGI_FORMAT_R16_UNORM,
DXGI_FORMAT_R16_SNORM,
DXGI_FORMAT_R32_FLOAT,
DXGI_FORMAT_R32_FLOAT,
DXGI_FORMAT_R32_FLOAT,
DXGI_FORMAT_R32_FLOAT,
}),
f({
DXGI_FORMAT_R8G8_UNORM,
@ -42,6 +45,9 @@ DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
DXGI_FORMAT_R16G16_UNORM,
DXGI_FORMAT_R16G16_SNORM,
DXGI_FORMAT_R32G32_FLOAT,
DXGI_FORMAT_R32G32_FLOAT,
DXGI_FORMAT_R32G32_FLOAT,
DXGI_FORMAT_R32G32_FLOAT,
}),
f({
DXGI_FORMAT_UNKNOWN,
@ -49,6 +55,9 @@ DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32_FLOAT,
}),
f({
DXGI_FORMAT_R8G8B8A8_UNORM,
@ -56,6 +65,9 @@ DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
DXGI_FORMAT_R16G16B16A16_UNORM,
DXGI_FORMAT_R16G16B16A16_SNORM,
DXGI_FORMAT_R32G32B32A32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT,
}),
};
@ -66,6 +78,9 @@ DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
DXGI_FORMAT_R16_UINT,
DXGI_FORMAT_R16_SINT,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
}),
f({
DXGI_FORMAT_R8G8_UINT,
@ -73,6 +88,9 @@ DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
DXGI_FORMAT_R16G16_UINT,
DXGI_FORMAT_R16G16_SINT,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
}),
f({
DXGI_FORMAT_UNKNOWN,
@ -80,6 +98,9 @@ DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
}),
f({
DXGI_FORMAT_R8G8B8A8_UINT,
@ -87,6 +108,9 @@ DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
DXGI_FORMAT_R16G16B16A16_UINT,
DXGI_FORMAT_R16G16B16A16_SINT,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
}),
};

View File

@ -17,31 +17,45 @@ static DXGI_FORMAT VarToDXGIFormat(ComponentFormat t, u32 components, bool integ
static constexpr auto f = [](ComponentArray a) { return a; }; // Deduction helper
// NOTE: 3-component formats are not valid.
static constexpr Common::EnumMap<ComponentArray, ComponentFormat::Float> float_type_lookup = {
f({DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM}), // UByte
f({DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM,
DXGI_FORMAT_R8G8B8A8_SNORM}), // Byte
f({DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM,
DXGI_FORMAT_R16G16B16A16_UNORM}), // UShort
f({DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16B16A16_SNORM,
DXGI_FORMAT_R16G16B16A16_SNORM}), // Short
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Float
};
static constexpr Common::EnumMap<ComponentArray, ComponentFormat::InvalidFloat7>
float_type_lookup = {
f({DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM}), // UByte
f({DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM,
DXGI_FORMAT_R8G8B8A8_SNORM}), // Byte
f({DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM,
DXGI_FORMAT_R16G16B16A16_UNORM}), // UShort
f({DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16B16A16_SNORM,
DXGI_FORMAT_R16G16B16A16_SNORM}), // Short
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Float
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Invalid
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Invalid
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Invalid
};
static constexpr Common::EnumMap<ComponentArray, ComponentFormat::Float> integer_type_lookup = {
f({DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8B8A8_UINT,
DXGI_FORMAT_R8G8B8A8_UINT}), // UByte
f({DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8B8A8_SINT,
DXGI_FORMAT_R8G8B8A8_SINT}), // Byte
f({DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16B16A16_UINT,
DXGI_FORMAT_R16G16B16A16_UINT}), // UShort
f({DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16B16A16_SINT,
DXGI_FORMAT_R16G16B16A16_SINT}), // Short
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Float
};
static constexpr Common::EnumMap<ComponentArray, ComponentFormat::InvalidFloat7>
integer_type_lookup = {
f({DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8B8A8_UINT,
DXGI_FORMAT_R8G8B8A8_UINT}), // UByte
f({DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8B8A8_SINT,
DXGI_FORMAT_R8G8B8A8_SINT}), // Byte
f({DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16B16A16_UINT,
DXGI_FORMAT_R16G16B16A16_UINT}), // UShort
f({DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16B16A16_SINT,
DXGI_FORMAT_R16G16B16A16_SINT}), // Short
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Float
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Invalid
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Invalid
f({DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT}), // Invalid
};
ASSERT(components > 0 && components <= 4);
return integer ? integer_type_lookup[t][components - 1] : float_type_lookup[t][components - 1];

View File

@ -49,6 +49,9 @@ static MTLVertexFormat ConvertFormat(ComponentFormat format, int count, bool int
default: return MTLVertexFormatInvalid;
}
case ComponentFormat::Float:
case ComponentFormat::InvalidFloat5:
case ComponentFormat::InvalidFloat6:
case ComponentFormat::InvalidFloat7:
switch (count)
{
case 1: return MTLVertexFormatFloat;
@ -100,6 +103,9 @@ static MTLVertexFormat ConvertFormat(ComponentFormat format, int count, bool int
default: return MTLVertexFormatInvalid;
}
case ComponentFormat::Float:
case ComponentFormat::InvalidFloat5:
case ComponentFormat::InvalidFloat6:
case ComponentFormat::InvalidFloat7:
switch (count)
{
case 1: return MTLVertexFormatFloat;

View File

@ -26,8 +26,9 @@ OGLGfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
static inline GLuint VarToGL(ComponentFormat t)
{
static constexpr Common::EnumMap<GLuint, ComponentFormat::Float> lookup = {
GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_FLOAT,
static constexpr Common::EnumMap<GLuint, ComponentFormat::InvalidFloat7> lookup = {
GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT,
GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT,
};
return lookup[t];
}

View File

@ -149,11 +149,14 @@ static void ReadVertexAttribute(T* dst, DataReader src, const AttributeFormat& f
dst[i_dst] = ReadNormalized<T, s16>(src.Read<s16, swap>());
break;
case ComponentFormat::Float:
case ComponentFormat::InvalidFloat5:
case ComponentFormat::InvalidFloat6:
case ComponentFormat::InvalidFloat7:
dst[i_dst] = ReadNormalized<T, float>(src.Read<float, swap>());
break;
}
ASSERT_MSG(VIDEO, !format.integer || format.type != ComponentFormat::Float,
ASSERT_MSG(VIDEO, !format.integer || (format.type < ComponentFormat::Float),
"only non-float values are allowed to be streamed as integer");
}
for (; i < components; i++)

View File

@ -19,31 +19,45 @@ static VkFormat VarToVkFormat(ComponentFormat t, uint32_t components, bool integ
using ComponentArray = std::array<VkFormat, 4>;
static constexpr auto f = [](ComponentArray a) { return a; }; // Deduction helper
static constexpr Common::EnumMap<ComponentArray, ComponentFormat::Float> float_type_lookup = {
f({VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM, VK_FORMAT_R8G8B8_UNORM,
VK_FORMAT_R8G8B8A8_UNORM}), // UByte
f({VK_FORMAT_R8_SNORM, VK_FORMAT_R8G8_SNORM, VK_FORMAT_R8G8B8_SNORM,
VK_FORMAT_R8G8B8A8_SNORM}), // Byte
f({VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM, VK_FORMAT_R16G16B16_UNORM,
VK_FORMAT_R16G16B16A16_UNORM}), // UShort
f({VK_FORMAT_R16_SNORM, VK_FORMAT_R16G16_SNORM, VK_FORMAT_R16G16B16_SNORM,
VK_FORMAT_R16G16B16A16_SNORM}), // Short
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Float
};
static constexpr Common::EnumMap<ComponentArray, ComponentFormat::InvalidFloat7>
float_type_lookup = {
f({VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM, VK_FORMAT_R8G8B8_UNORM,
VK_FORMAT_R8G8B8A8_UNORM}), // UByte
f({VK_FORMAT_R8_SNORM, VK_FORMAT_R8G8_SNORM, VK_FORMAT_R8G8B8_SNORM,
VK_FORMAT_R8G8B8A8_SNORM}), // Byte
f({VK_FORMAT_R16_UNORM, VK_FORMAT_R16G16_UNORM, VK_FORMAT_R16G16B16_UNORM,
VK_FORMAT_R16G16B16A16_UNORM}), // UShort
f({VK_FORMAT_R16_SNORM, VK_FORMAT_R16G16_SNORM, VK_FORMAT_R16G16B16_SNORM,
VK_FORMAT_R16G16B16A16_SNORM}), // Short
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Float
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Invalid
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Invalid
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Invalid
};
static constexpr Common::EnumMap<ComponentArray, ComponentFormat::Float> integer_type_lookup = {
f({VK_FORMAT_R8_UINT, VK_FORMAT_R8G8_UINT, VK_FORMAT_R8G8B8_UINT,
VK_FORMAT_R8G8B8A8_UINT}), // UByte
f({VK_FORMAT_R8_SINT, VK_FORMAT_R8G8_SINT, VK_FORMAT_R8G8B8_SINT,
VK_FORMAT_R8G8B8A8_SINT}), // Byte
f({VK_FORMAT_R16_UINT, VK_FORMAT_R16G16_UINT, VK_FORMAT_R16G16B16_UINT,
VK_FORMAT_R16G16B16A16_UINT}), // UShort
f({VK_FORMAT_R16_SINT, VK_FORMAT_R16G16_SINT, VK_FORMAT_R16G16B16_SINT,
VK_FORMAT_R16G16B16A16_SINT}), // Short
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Float
};
static constexpr Common::EnumMap<ComponentArray, ComponentFormat::InvalidFloat7>
integer_type_lookup = {
f({VK_FORMAT_R8_UINT, VK_FORMAT_R8G8_UINT, VK_FORMAT_R8G8B8_UINT,
VK_FORMAT_R8G8B8A8_UINT}), // UByte
f({VK_FORMAT_R8_SINT, VK_FORMAT_R8G8_SINT, VK_FORMAT_R8G8B8_SINT,
VK_FORMAT_R8G8B8A8_SINT}), // Byte
f({VK_FORMAT_R16_UINT, VK_FORMAT_R16G16_UINT, VK_FORMAT_R16G16B16_UINT,
VK_FORMAT_R16G16B16A16_UINT}), // UShort
f({VK_FORMAT_R16_SINT, VK_FORMAT_R16G16_SINT, VK_FORMAT_R16G16B16_SINT,
VK_FORMAT_R16G16B16A16_SINT}), // Short
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Float
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Invalid
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Invalid
f({VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT}), // Invalid
};
ASSERT(components > 0 && components <= 4);
return integer ? integer_type_lookup[t][components - 1] : float_type_lookup[t][components - 1];

View File

@ -122,7 +122,16 @@ enum class ComponentFormat
UShort = 2, // Invalid for normals
Short = 3,
Float = 4,
// Known to be used by Fifa Street and Def Jam: Fight for New York
// See https://bugs.dolphin-emu.org/issues/12719
// Assumed to behave the same as float, but further testing is needed
InvalidFloat5 = 5,
// Not known to be used
InvalidFloat6 = 6,
InvalidFloat7 = 7,
};
// NOTE: don't include the invalid formats here, so that EnumFormatter marks them as invalid
// (EnumFormatter also handles bounds-checking).
template <>
struct fmt::formatter<ComponentFormat> : EnumFormatter<ComponentFormat::Float>
{
@ -141,6 +150,9 @@ constexpr u32 GetElementSize(ComponentFormat format)
case ComponentFormat::Short:
return 2;
case ComponentFormat::Float:
case ComponentFormat::InvalidFloat5:
case ComponentFormat::InvalidFloat6:
case ComponentFormat::InvalidFloat7:
return 4;
default:
PanicAlertFmt("Unknown format {}", format);

View File

@ -116,7 +116,7 @@ void VertexLoaderARM64::ReadVertex(VertexComponentFormat attribute, ComponentFor
m_float_emit.LDUR(load_size, coords, reg, offset);
if (format != ComponentFormat::Float)
if (format < ComponentFormat::Float)
{
// Extend and convert to float
switch (format)
@ -394,8 +394,8 @@ void VertexLoaderARM64::GenerateVertexLoader()
if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{
static constexpr Common::EnumMap<u8, static_cast<ComponentFormat>(7)> SCALE_MAP = {7, 6, 15, 14,
0, 0, 0, 0};
static constexpr Common::EnumMap<u8, ComponentFormat::InvalidFloat7> SCALE_MAP = {7, 6, 15, 14,
0, 0, 0, 0};
const u8 scaling_exponent = SCALE_MAP[m_VtxAttr.g0.NormalFormat];
// Normal

View File

@ -319,6 +319,51 @@ static void CheckCPConfiguration(int vtx_attr_group)
DolphinAnalytics::Instance().ReportGameQuirk(
GameQuirk::MISMATCHED_GPU_MATRIX_INDICES_BETWEEN_CP_AND_XF);
}
if (g_main_cp_state.vtx_attr[vtx_attr_group].g0.PosFormat >= ComponentFormat::InvalidFloat5)
{
WARN_LOG_FMT(VIDEO, "Invalid position format {} for VAT {} - {:08x} {:08x} {:08x}",
g_main_cp_state.vtx_attr[vtx_attr_group].g0.PosFormat, vtx_attr_group,
g_main_cp_state.vtx_attr[vtx_attr_group].g0.Hex,
g_main_cp_state.vtx_attr[vtx_attr_group].g1.Hex,
g_main_cp_state.vtx_attr[vtx_attr_group].g2.Hex);
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::INVALID_POSITION_COMPONENT_FORMAT);
}
if (g_main_cp_state.vtx_attr[vtx_attr_group].g0.NormalFormat >= ComponentFormat::InvalidFloat5)
{
WARN_LOG_FMT(VIDEO, "Invalid normal format {} for VAT {} - {:08x} {:08x} {:08x}",
g_main_cp_state.vtx_attr[vtx_attr_group].g0.NormalFormat, vtx_attr_group,
g_main_cp_state.vtx_attr[vtx_attr_group].g0.Hex,
g_main_cp_state.vtx_attr[vtx_attr_group].g1.Hex,
g_main_cp_state.vtx_attr[vtx_attr_group].g2.Hex);
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::INVALID_NORMAL_COMPONENT_FORMAT);
}
for (size_t i = 0; i < 8; i++)
{
if (g_main_cp_state.vtx_attr[vtx_attr_group].GetTexFormat(i) >= ComponentFormat::InvalidFloat5)
{
WARN_LOG_FMT(VIDEO,
"Invalid texture coordinate {} format {} for VAT {} - {:08x} {:08x} {:08x}", i,
g_main_cp_state.vtx_attr[vtx_attr_group].GetTexFormat(i), vtx_attr_group,
g_main_cp_state.vtx_attr[vtx_attr_group].g0.Hex,
g_main_cp_state.vtx_attr[vtx_attr_group].g1.Hex,
g_main_cp_state.vtx_attr[vtx_attr_group].g2.Hex);
DolphinAnalytics::Instance().ReportGameQuirk(
GameQuirk::INVALID_TEXTURE_COORDINATE_COMPONENT_FORMAT);
}
}
for (size_t i = 0; i < 2; i++)
{
if (g_main_cp_state.vtx_attr[vtx_attr_group].GetColorFormat(i) > ColorFormat::RGBA8888)
{
WARN_LOG_FMT(VIDEO, "Invalid color {} format {} for VAT {} - {:08x} {:08x} {:08x}", i,
g_main_cp_state.vtx_attr[vtx_attr_group].GetColorFormat(i), vtx_attr_group,
g_main_cp_state.vtx_attr[vtx_attr_group].g0.Hex,
g_main_cp_state.vtx_attr[vtx_attr_group].g1.Hex,
g_main_cp_state.vtx_attr[vtx_attr_group].g2.Hex);
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::INVALID_COLOR_COMPONENT_FORMAT);
}
}
}
template <bool IsPreprocess>

View File

@ -83,22 +83,32 @@ void VertexLoaderX64::ReadVertex(OpArg data, VertexComponentFormat attribute,
bool dequantize, u8 scaling_exponent,
AttributeFormat* native_format)
{
static const __m128i shuffle_lut[5][3] = {
{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFF00L), // 1x u8
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFF01L, 0xFFFFFF00L), // 2x u8
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFF02L, 0xFFFFFF01L, 0xFFFFFF00L)}, // 3x u8
{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00FFFFFFL), // 1x s8
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x01FFFFFFL, 0x00FFFFFFL), // 2x s8
_mm_set_epi32(0xFFFFFFFFL, 0x02FFFFFFL, 0x01FFFFFFL, 0x00FFFFFFL)}, // 3x s8
{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFF0001L), // 1x u16
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFF0203L, 0xFFFF0001L), // 2x u16
_mm_set_epi32(0xFFFFFFFFL, 0xFFFF0405L, 0xFFFF0203L, 0xFFFF0001L)}, // 3x u16
{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x0001FFFFL), // 1x s16
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x0203FFFFL, 0x0001FFFFL), // 2x s16
_mm_set_epi32(0xFFFFFFFFL, 0x0405FFFFL, 0x0203FFFFL, 0x0001FFFFL)}, // 3x s16
{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00010203L), // 1x float
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x04050607L, 0x00010203L), // 2x float
_mm_set_epi32(0xFFFFFFFFL, 0x08090A0BL, 0x04050607L, 0x00010203L)}, // 3x float
using ShuffleRow = std::array<__m128i, 3>;
static const Common::EnumMap<ShuffleRow, ComponentFormat::InvalidFloat7> shuffle_lut = {
ShuffleRow{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFF00L), // 1x u8
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFF01L, 0xFFFFFF00L), // 2x u8
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFF02L, 0xFFFFFF01L, 0xFFFFFF00L)}, // 3x u8
ShuffleRow{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00FFFFFFL), // 1x s8
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x01FFFFFFL, 0x00FFFFFFL), // 2x s8
_mm_set_epi32(0xFFFFFFFFL, 0x02FFFFFFL, 0x01FFFFFFL, 0x00FFFFFFL)}, // 3x s8
ShuffleRow{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFF0001L), // 1x u16
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFF0203L, 0xFFFF0001L), // 2x u16
_mm_set_epi32(0xFFFFFFFFL, 0xFFFF0405L, 0xFFFF0203L, 0xFFFF0001L)}, // 3x u16
ShuffleRow{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x0001FFFFL), // 1x s16
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x0203FFFFL, 0x0001FFFFL), // 2x s16
_mm_set_epi32(0xFFFFFFFFL, 0x0405FFFFL, 0x0203FFFFL, 0x0001FFFFL)}, // 3x s16
ShuffleRow{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00010203L), // 1x float
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x04050607L, 0x00010203L), // 2x float
_mm_set_epi32(0xFFFFFFFFL, 0x08090A0BL, 0x04050607L, 0x00010203L)}, // 3x float
ShuffleRow{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00010203L), // 1x invalid
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x04050607L, 0x00010203L), // 2x invalid
_mm_set_epi32(0xFFFFFFFFL, 0x08090A0BL, 0x04050607L, 0x00010203L)}, // 3x invalid
ShuffleRow{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00010203L), // 1x invalid
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x04050607L, 0x00010203L), // 2x invalid
_mm_set_epi32(0xFFFFFFFFL, 0x08090A0BL, 0x04050607L, 0x00010203L)}, // 3x invalid
ShuffleRow{_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00010203L), // 1x invalid
_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x04050607L, 0x00010203L), // 2x invalid
_mm_set_epi32(0xFFFFFFFFL, 0x08090A0BL, 0x04050607L, 0x00010203L)}, // 3x invalid
};
static const __m128 scale_factors[32] = {
_mm_set_ps1(1. / (1u << 0)), _mm_set_ps1(1. / (1u << 1)), _mm_set_ps1(1. / (1u << 2)),
@ -169,7 +179,7 @@ void VertexLoaderX64::ReadVertex(OpArg data, VertexComponentFormat attribute,
else
MOVD_xmm(coords, data);
PSHUFB(coords, MPIC(&shuffle_lut[u32(format)][count_in - 1]));
PSHUFB(coords, MPIC(&shuffle_lut[format][count_in - 1]));
// Sign-extend.
if (format == ComponentFormat::Byte)
@ -221,6 +231,9 @@ void VertexLoaderX64::ReadVertex(OpArg data, VertexComponentFormat attribute,
PSRLD(coords, 16);
break;
case ComponentFormat::Float:
case ComponentFormat::InvalidFloat5:
case ComponentFormat::InvalidFloat6:
case ComponentFormat::InvalidFloat7:
// Floats don't need to be scaled or converted,
// so we can just load/swap/store them directly
// and return early.
@ -254,7 +267,7 @@ void VertexLoaderX64::ReadVertex(OpArg data, VertexComponentFormat attribute,
}
}
if (format != ComponentFormat::Float)
if (format < ComponentFormat::Float)
{
CVTDQ2PS(coords, R(coords));
@ -458,8 +471,8 @@ void VertexLoaderX64::GenerateVertexLoader()
if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent)
{
static constexpr Common::EnumMap<u8, static_cast<ComponentFormat>(7)> SCALE_MAP = {7, 6, 15, 14,
0, 0, 0, 0};
static constexpr Common::EnumMap<u8, ComponentFormat::InvalidFloat7> SCALE_MAP = {7, 6, 15, 14,
0, 0, 0, 0};
const u8 scaling_exponent = SCALE_MAP[m_VtxAttr.g0.NormalFormat];
// Normal

View File

@ -95,7 +95,7 @@ void Normal_ReadIndex_Indices3(VertexLoader* loader)
}
using Common::EnumMap;
using Formats = EnumMap<TPipelineFunction, ComponentFormat::Float>;
using Formats = EnumMap<TPipelineFunction, ComponentFormat::InvalidFloat7>;
using Elements = EnumMap<Formats, NormalComponentCount::NTB>;
using Indices = std::array<Elements, 2>;
using Types = EnumMap<Indices, VertexComponentFormat::Index16>;
@ -113,11 +113,17 @@ consteval Types InitializeTable()
table[VCF::Direct][false][NCC::N][FMT::UShort] = Normal_ReadDirect<u16, 1>;
table[VCF::Direct][false][NCC::N][FMT::Short] = Normal_ReadDirect<s16, 1>;
table[VCF::Direct][false][NCC::N][FMT::Float] = Normal_ReadDirect<float, 1>;
table[VCF::Direct][false][NCC::N][FMT::InvalidFloat5] = Normal_ReadDirect<float, 1>;
table[VCF::Direct][false][NCC::N][FMT::InvalidFloat6] = Normal_ReadDirect<float, 1>;
table[VCF::Direct][false][NCC::N][FMT::InvalidFloat7] = Normal_ReadDirect<float, 1>;
table[VCF::Direct][false][NCC::NTB][FMT::UByte] = Normal_ReadDirect<u8, 3>;
table[VCF::Direct][false][NCC::NTB][FMT::Byte] = Normal_ReadDirect<s8, 3>;
table[VCF::Direct][false][NCC::NTB][FMT::UShort] = Normal_ReadDirect<u16, 3>;
table[VCF::Direct][false][NCC::NTB][FMT::Short] = Normal_ReadDirect<s16, 3>;
table[VCF::Direct][false][NCC::NTB][FMT::Float] = Normal_ReadDirect<float, 3>;
table[VCF::Direct][false][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadDirect<float, 3>;
table[VCF::Direct][false][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadDirect<float, 3>;
table[VCF::Direct][false][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadDirect<float, 3>;
// Same as above, since there are no indices
table[VCF::Direct][true][NCC::N][FMT::UByte] = Normal_ReadDirect<u8, 1>;
@ -125,22 +131,34 @@ consteval Types InitializeTable()
table[VCF::Direct][true][NCC::N][FMT::UShort] = Normal_ReadDirect<u16, 1>;
table[VCF::Direct][true][NCC::N][FMT::Short] = Normal_ReadDirect<s16, 1>;
table[VCF::Direct][true][NCC::N][FMT::Float] = Normal_ReadDirect<float, 1>;
table[VCF::Direct][true][NCC::N][FMT::InvalidFloat5] = Normal_ReadDirect<float, 1>;
table[VCF::Direct][true][NCC::N][FMT::InvalidFloat6] = Normal_ReadDirect<float, 1>;
table[VCF::Direct][true][NCC::N][FMT::InvalidFloat7] = Normal_ReadDirect<float, 1>;
table[VCF::Direct][true][NCC::NTB][FMT::UByte] = Normal_ReadDirect<u8, 3>;
table[VCF::Direct][true][NCC::NTB][FMT::Byte] = Normal_ReadDirect<s8, 3>;
table[VCF::Direct][true][NCC::NTB][FMT::UShort] = Normal_ReadDirect<u16, 3>;
table[VCF::Direct][true][NCC::NTB][FMT::Short] = Normal_ReadDirect<s16, 3>;
table[VCF::Direct][true][NCC::NTB][FMT::Float] = Normal_ReadDirect<float, 3>;
table[VCF::Direct][true][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadDirect<float, 3>;
table[VCF::Direct][true][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadDirect<float, 3>;
table[VCF::Direct][true][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadDirect<float, 3>;
table[VCF::Index8][false][NCC::N][FMT::UByte] = Normal_ReadIndex<u8, u8, 1>;
table[VCF::Index8][false][NCC::N][FMT::Byte] = Normal_ReadIndex<u8, s8, 1>;
table[VCF::Index8][false][NCC::N][FMT::UShort] = Normal_ReadIndex<u8, u16, 1>;
table[VCF::Index8][false][NCC::N][FMT::Short] = Normal_ReadIndex<u8, s16, 1>;
table[VCF::Index8][false][NCC::N][FMT::Float] = Normal_ReadIndex<u8, float, 1>;
table[VCF::Index8][false][NCC::N][FMT::InvalidFloat5] = Normal_ReadIndex<u8, float, 1>;
table[VCF::Index8][false][NCC::N][FMT::InvalidFloat6] = Normal_ReadIndex<u8, float, 1>;
table[VCF::Index8][false][NCC::N][FMT::InvalidFloat7] = Normal_ReadIndex<u8, float, 1>;
table[VCF::Index8][false][NCC::NTB][FMT::UByte] = Normal_ReadIndex<u8, u8, 3>;
table[VCF::Index8][false][NCC::NTB][FMT::Byte] = Normal_ReadIndex<u8, s8, 3>;
table[VCF::Index8][false][NCC::NTB][FMT::UShort] = Normal_ReadIndex<u8, u16, 3>;
table[VCF::Index8][false][NCC::NTB][FMT::Short] = Normal_ReadIndex<u8, s16, 3>;
table[VCF::Index8][false][NCC::NTB][FMT::Float] = Normal_ReadIndex<u8, float, 3>;
table[VCF::Index8][false][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadIndex<u8, float, 3>;
table[VCF::Index8][false][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadIndex<u8, float, 3>;
table[VCF::Index8][false][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadIndex<u8, float, 3>;
// Same for NormalComponentCount::N; differs for NTB
table[VCF::Index8][true][NCC::N][FMT::UByte] = Normal_ReadIndex<u8, u8, 1>;
@ -148,22 +166,34 @@ consteval Types InitializeTable()
table[VCF::Index8][true][NCC::N][FMT::UShort] = Normal_ReadIndex<u8, u16, 1>;
table[VCF::Index8][true][NCC::N][FMT::Short] = Normal_ReadIndex<u8, s16, 1>;
table[VCF::Index8][true][NCC::N][FMT::Float] = Normal_ReadIndex<u8, float, 1>;
table[VCF::Index8][true][NCC::N][FMT::InvalidFloat5] = Normal_ReadIndex<u8, float, 1>;
table[VCF::Index8][true][NCC::N][FMT::InvalidFloat6] = Normal_ReadIndex<u8, float, 1>;
table[VCF::Index8][true][NCC::N][FMT::InvalidFloat7] = Normal_ReadIndex<u8, float, 1>;
table[VCF::Index8][true][NCC::NTB][FMT::UByte] = Normal_ReadIndex_Indices3<u8, u8>;
table[VCF::Index8][true][NCC::NTB][FMT::Byte] = Normal_ReadIndex_Indices3<u8, s8>;
table[VCF::Index8][true][NCC::NTB][FMT::UShort] = Normal_ReadIndex_Indices3<u8, u16>;
table[VCF::Index8][true][NCC::NTB][FMT::Short] = Normal_ReadIndex_Indices3<u8, s16>;
table[VCF::Index8][true][NCC::NTB][FMT::Float] = Normal_ReadIndex_Indices3<u8, float>;
table[VCF::Index8][true][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadIndex_Indices3<u8, float>;
table[VCF::Index8][true][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadIndex_Indices3<u8, float>;
table[VCF::Index8][true][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadIndex_Indices3<u8, float>;
table[VCF::Index16][false][NCC::N][FMT::UByte] = Normal_ReadIndex<u16, u8, 1>;
table[VCF::Index16][false][NCC::N][FMT::Byte] = Normal_ReadIndex<u16, s8, 1>;
table[VCF::Index16][false][NCC::N][FMT::UShort] = Normal_ReadIndex<u16, u16, 1>;
table[VCF::Index16][false][NCC::N][FMT::Short] = Normal_ReadIndex<u16, s16, 1>;
table[VCF::Index16][false][NCC::N][FMT::Float] = Normal_ReadIndex<u16, float, 1>;
table[VCF::Index16][false][NCC::N][FMT::InvalidFloat5] = Normal_ReadIndex<u16, float, 1>;
table[VCF::Index16][false][NCC::N][FMT::InvalidFloat6] = Normal_ReadIndex<u16, float, 1>;
table[VCF::Index16][false][NCC::N][FMT::InvalidFloat7] = Normal_ReadIndex<u16, float, 1>;
table[VCF::Index16][false][NCC::NTB][FMT::UByte] = Normal_ReadIndex<u16, u8, 3>;
table[VCF::Index16][false][NCC::NTB][FMT::Byte] = Normal_ReadIndex<u16, s8, 3>;
table[VCF::Index16][false][NCC::NTB][FMT::UShort] = Normal_ReadIndex<u16, u16, 3>;
table[VCF::Index16][false][NCC::NTB][FMT::Short] = Normal_ReadIndex<u16, s16, 3>;
table[VCF::Index16][false][NCC::NTB][FMT::Float] = Normal_ReadIndex<u16, float, 3>;
table[VCF::Index16][false][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadIndex<u16, float, 3>;
table[VCF::Index16][false][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadIndex<u16, float, 3>;
table[VCF::Index16][false][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadIndex<u16, float, 3>;
// Same for NormalComponentCount::N; differs for NTB
table[VCF::Index16][true][NCC::N][FMT::UByte] = Normal_ReadIndex<u16, u8, 1>;
@ -171,11 +201,17 @@ consteval Types InitializeTable()
table[VCF::Index16][true][NCC::N][FMT::UShort] = Normal_ReadIndex<u16, u16, 1>;
table[VCF::Index16][true][NCC::N][FMT::Short] = Normal_ReadIndex<u16, s16, 1>;
table[VCF::Index16][true][NCC::N][FMT::Float] = Normal_ReadIndex<u16, float, 1>;
table[VCF::Index16][true][NCC::N][FMT::InvalidFloat5] = Normal_ReadIndex<u16, float, 1>;
table[VCF::Index16][true][NCC::N][FMT::InvalidFloat6] = Normal_ReadIndex<u16, float, 1>;
table[VCF::Index16][true][NCC::N][FMT::InvalidFloat7] = Normal_ReadIndex<u16, float, 1>;
table[VCF::Index16][true][NCC::NTB][FMT::UByte] = Normal_ReadIndex_Indices3<u16, u8>;
table[VCF::Index16][true][NCC::NTB][FMT::Byte] = Normal_ReadIndex_Indices3<u16, s8>;
table[VCF::Index16][true][NCC::NTB][FMT::UShort] = Normal_ReadIndex_Indices3<u16, u16>;
table[VCF::Index16][true][NCC::NTB][FMT::Short] = Normal_ReadIndex_Indices3<u16, s16>;
table[VCF::Index16][true][NCC::NTB][FMT::Float] = Normal_ReadIndex_Indices3<u16, float>;
table[VCF::Index16][true][NCC::NTB][FMT::InvalidFloat5] = Normal_ReadIndex_Indices3<u16, float>;
table[VCF::Index16][true][NCC::NTB][FMT::InvalidFloat6] = Normal_ReadIndex_Indices3<u16, float>;
table[VCF::Index16][true][NCC::NTB][FMT::InvalidFloat7] = Normal_ReadIndex_Indices3<u16, float>;
return table;
}

View File

@ -27,7 +27,8 @@ private:
using EnumMap = typename Common::EnumMap<T, last_member>;
using SizeTable = EnumMap<
std::array<EnumMap<EnumMap<u32, ComponentFormat::Float>, NormalComponentCount::NTB>, 2>,
std::array<EnumMap<EnumMap<u32, ComponentFormat::InvalidFloat7>, NormalComponentCount::NTB>,
2>,
VertexComponentFormat::Index16>;
static constexpr SizeTable s_table_size = []() consteval
@ -43,11 +44,17 @@ private:
table[VCF::Direct][false][NCC::N][FMT::UShort] = 6;
table[VCF::Direct][false][NCC::N][FMT::Short] = 6;
table[VCF::Direct][false][NCC::N][FMT::Float] = 12;
table[VCF::Direct][false][NCC::N][FMT::InvalidFloat5] = 12;
table[VCF::Direct][false][NCC::N][FMT::InvalidFloat6] = 12;
table[VCF::Direct][false][NCC::N][FMT::InvalidFloat7] = 12;
table[VCF::Direct][false][NCC::NTB][FMT::UByte] = 9;
table[VCF::Direct][false][NCC::NTB][FMT::Byte] = 9;
table[VCF::Direct][false][NCC::NTB][FMT::UShort] = 18;
table[VCF::Direct][false][NCC::NTB][FMT::Short] = 18;
table[VCF::Direct][false][NCC::NTB][FMT::Float] = 36;
table[VCF::Direct][false][NCC::NTB][FMT::InvalidFloat5] = 36;
table[VCF::Direct][false][NCC::NTB][FMT::InvalidFloat6] = 36;
table[VCF::Direct][false][NCC::NTB][FMT::InvalidFloat7] = 36;
// Same as above, since there are no indices
table[VCF::Direct][true][NCC::N][FMT::UByte] = 3;
@ -55,22 +62,34 @@ private:
table[VCF::Direct][true][NCC::N][FMT::UShort] = 6;
table[VCF::Direct][true][NCC::N][FMT::Short] = 6;
table[VCF::Direct][true][NCC::N][FMT::Float] = 12;
table[VCF::Direct][true][NCC::N][FMT::InvalidFloat5] = 12;
table[VCF::Direct][true][NCC::N][FMT::InvalidFloat6] = 12;
table[VCF::Direct][true][NCC::N][FMT::InvalidFloat7] = 12;
table[VCF::Direct][true][NCC::NTB][FMT::UByte] = 9;
table[VCF::Direct][true][NCC::NTB][FMT::Byte] = 9;
table[VCF::Direct][true][NCC::NTB][FMT::UShort] = 18;
table[VCF::Direct][true][NCC::NTB][FMT::Short] = 18;
table[VCF::Direct][true][NCC::NTB][FMT::Float] = 36;
table[VCF::Direct][true][NCC::NTB][FMT::InvalidFloat5] = 36;
table[VCF::Direct][true][NCC::NTB][FMT::InvalidFloat6] = 36;
table[VCF::Direct][true][NCC::NTB][FMT::InvalidFloat7] = 36;
table[VCF::Index8][false][NCC::N][FMT::UByte] = 1;
table[VCF::Index8][false][NCC::N][FMT::Byte] = 1;
table[VCF::Index8][false][NCC::N][FMT::UShort] = 1;
table[VCF::Index8][false][NCC::N][FMT::Short] = 1;
table[VCF::Index8][false][NCC::N][FMT::Float] = 1;
table[VCF::Index8][false][NCC::N][FMT::InvalidFloat5] = 1;
table[VCF::Index8][false][NCC::N][FMT::InvalidFloat6] = 1;
table[VCF::Index8][false][NCC::N][FMT::InvalidFloat7] = 1;
table[VCF::Index8][false][NCC::NTB][FMT::UByte] = 1;
table[VCF::Index8][false][NCC::NTB][FMT::Byte] = 1;
table[VCF::Index8][false][NCC::NTB][FMT::UShort] = 1;
table[VCF::Index8][false][NCC::NTB][FMT::Short] = 1;
table[VCF::Index8][false][NCC::NTB][FMT::Float] = 1;
table[VCF::Index8][false][NCC::NTB][FMT::InvalidFloat5] = 1;
table[VCF::Index8][false][NCC::NTB][FMT::InvalidFloat6] = 1;
table[VCF::Index8][false][NCC::NTB][FMT::InvalidFloat7] = 1;
// Same for NormalComponentCount::N; differs for NTB
table[VCF::Index8][true][NCC::N][FMT::UByte] = 1;
@ -78,22 +97,34 @@ private:
table[VCF::Index8][true][NCC::N][FMT::UShort] = 1;
table[VCF::Index8][true][NCC::N][FMT::Short] = 1;
table[VCF::Index8][true][NCC::N][FMT::Float] = 1;
table[VCF::Index8][true][NCC::N][FMT::InvalidFloat5] = 1;
table[VCF::Index8][true][NCC::N][FMT::InvalidFloat6] = 1;
table[VCF::Index8][true][NCC::N][FMT::InvalidFloat7] = 1;
table[VCF::Index8][true][NCC::NTB][FMT::UByte] = 3;
table[VCF::Index8][true][NCC::NTB][FMT::Byte] = 3;
table[VCF::Index8][true][NCC::NTB][FMT::UShort] = 3;
table[VCF::Index8][true][NCC::NTB][FMT::Short] = 3;
table[VCF::Index8][true][NCC::NTB][FMT::Float] = 3;
table[VCF::Index8][true][NCC::NTB][FMT::InvalidFloat5] = 3;
table[VCF::Index8][true][NCC::NTB][FMT::InvalidFloat6] = 3;
table[VCF::Index8][true][NCC::NTB][FMT::InvalidFloat7] = 3;
table[VCF::Index16][false][NCC::N][FMT::UByte] = 2;
table[VCF::Index16][false][NCC::N][FMT::Byte] = 2;
table[VCF::Index16][false][NCC::N][FMT::UShort] = 2;
table[VCF::Index16][false][NCC::N][FMT::Short] = 2;
table[VCF::Index16][false][NCC::N][FMT::Float] = 2;
table[VCF::Index16][false][NCC::N][FMT::InvalidFloat5] = 2;
table[VCF::Index16][false][NCC::N][FMT::InvalidFloat6] = 2;
table[VCF::Index16][false][NCC::N][FMT::InvalidFloat7] = 2;
table[VCF::Index16][false][NCC::NTB][FMT::UByte] = 2;
table[VCF::Index16][false][NCC::NTB][FMT::Byte] = 2;
table[VCF::Index16][false][NCC::NTB][FMT::UShort] = 2;
table[VCF::Index16][false][NCC::NTB][FMT::Short] = 2;
table[VCF::Index16][false][NCC::NTB][FMT::Float] = 2;
table[VCF::Index16][false][NCC::NTB][FMT::InvalidFloat5] = 2;
table[VCF::Index16][false][NCC::NTB][FMT::InvalidFloat6] = 2;
table[VCF::Index16][false][NCC::NTB][FMT::InvalidFloat7] = 2;
// Same for NormalComponentCount::N; differs for NTB
table[VCF::Index16][true][NCC::N][FMT::UByte] = 2;
@ -101,11 +132,17 @@ private:
table[VCF::Index16][true][NCC::N][FMT::UShort] = 2;
table[VCF::Index16][true][NCC::N][FMT::Short] = 2;
table[VCF::Index16][true][NCC::N][FMT::Float] = 2;
table[VCF::Index16][true][NCC::N][FMT::InvalidFloat5] = 2;
table[VCF::Index16][true][NCC::N][FMT::InvalidFloat6] = 2;
table[VCF::Index16][true][NCC::N][FMT::InvalidFloat7] = 2;
table[VCF::Index16][true][NCC::NTB][FMT::UByte] = 6;
table[VCF::Index16][true][NCC::NTB][FMT::Byte] = 6;
table[VCF::Index16][true][NCC::NTB][FMT::UShort] = 6;
table[VCF::Index16][true][NCC::NTB][FMT::Short] = 6;
table[VCF::Index16][true][NCC::NTB][FMT::Float] = 6;
table[VCF::Index16][true][NCC::NTB][FMT::InvalidFloat5] = 6;
table[VCF::Index16][true][NCC::NTB][FMT::InvalidFloat6] = 6;
table[VCF::Index16][true][NCC::NTB][FMT::InvalidFloat7] = 6;
return table;
}

View File

@ -71,7 +71,7 @@ void Pos_ReadIndex(VertexLoader* loader)
}
using ComponentCountRow = Common::EnumMap<TPipelineFunction, CoordComponentCount::XYZ>;
using ComponentFormatTable = Common::EnumMap<ComponentCountRow, ComponentFormat::Float>;
using ComponentFormatTable = Common::EnumMap<ComponentCountRow, ComponentFormat::InvalidFloat7>;
using Table = Common::EnumMap<ComponentFormatTable, VertexComponentFormat::Index16>;
constexpr Table s_table_read_position = {
@ -81,6 +81,9 @@ constexpr Table s_table_read_position = {
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
}),
ComponentFormatTable({
ComponentCountRow(Pos_ReadDirect<u8, 2>, Pos_ReadDirect<u8, 3>),
@ -88,6 +91,9 @@ constexpr Table s_table_read_position = {
ComponentCountRow(Pos_ReadDirect<u16, 2>, Pos_ReadDirect<u16, 3>),
ComponentCountRow(Pos_ReadDirect<s16, 2>, Pos_ReadDirect<s16, 3>),
ComponentCountRow(Pos_ReadDirect<float, 2>, Pos_ReadDirect<float, 3>),
ComponentCountRow(Pos_ReadDirect<float, 2>, Pos_ReadDirect<float, 3>),
ComponentCountRow(Pos_ReadDirect<float, 2>, Pos_ReadDirect<float, 3>),
ComponentCountRow(Pos_ReadDirect<float, 2>, Pos_ReadDirect<float, 3>),
}),
ComponentFormatTable({
ComponentCountRow(Pos_ReadIndex<u8, u8, 2>, Pos_ReadIndex<u8, u8, 3>),
@ -95,6 +101,9 @@ constexpr Table s_table_read_position = {
ComponentCountRow(Pos_ReadIndex<u8, u16, 2>, Pos_ReadIndex<u8, u16, 3>),
ComponentCountRow(Pos_ReadIndex<u8, s16, 2>, Pos_ReadIndex<u8, s16, 3>),
ComponentCountRow(Pos_ReadIndex<u8, float, 2>, Pos_ReadIndex<u8, float, 3>),
ComponentCountRow(Pos_ReadIndex<u8, float, 2>, Pos_ReadIndex<u8, float, 3>),
ComponentCountRow(Pos_ReadIndex<u8, float, 2>, Pos_ReadIndex<u8, float, 3>),
ComponentCountRow(Pos_ReadIndex<u8, float, 2>, Pos_ReadIndex<u8, float, 3>),
}),
ComponentFormatTable({
ComponentCountRow(Pos_ReadIndex<u16, u8, 2>, Pos_ReadIndex<u16, u8, 3>),
@ -102,6 +111,9 @@ constexpr Table s_table_read_position = {
ComponentCountRow(Pos_ReadIndex<u16, u16, 2>, Pos_ReadIndex<u16, u16, 3>),
ComponentCountRow(Pos_ReadIndex<u16, s16, 2>, Pos_ReadIndex<u16, s16, 3>),
ComponentCountRow(Pos_ReadIndex<u16, float, 2>, Pos_ReadIndex<u16, float, 3>),
ComponentCountRow(Pos_ReadIndex<u16, float, 2>, Pos_ReadIndex<u16, float, 3>),
ComponentCountRow(Pos_ReadIndex<u16, float, 2>, Pos_ReadIndex<u16, float, 3>),
ComponentCountRow(Pos_ReadIndex<u16, float, 2>, Pos_ReadIndex<u16, float, 3>),
}),
};
} // Anonymous namespace

View File

@ -26,8 +26,9 @@ private:
template <typename T, auto last_member>
using EnumMap = typename Common::EnumMap<T, last_member>;
using SizeTable = EnumMap<EnumMap<EnumMap<u32, CoordComponentCount::XYZ>, ComponentFormat::Float>,
VertexComponentFormat::Index16>;
using SizeTable =
EnumMap<EnumMap<EnumMap<u32, CoordComponentCount::XYZ>, ComponentFormat::InvalidFloat7>,
VertexComponentFormat::Index16>;
static constexpr SizeTable s_table_size = []() consteval
{
@ -41,18 +42,27 @@ private:
table[VCF::Direct][FMT::UShort] = {4, 6};
table[VCF::Direct][FMT::Short] = {4, 6};
table[VCF::Direct][FMT::Float] = {8, 12};
table[VCF::Direct][FMT::InvalidFloat5] = {8, 12};
table[VCF::Direct][FMT::InvalidFloat6] = {8, 12};
table[VCF::Direct][FMT::InvalidFloat7] = {8, 12};
table[VCF::Index8][FMT::UByte] = {1, 1};
table[VCF::Index8][FMT::Byte] = {1, 1};
table[VCF::Index8][FMT::UShort] = {1, 1};
table[VCF::Index8][FMT::Short] = {1, 1};
table[VCF::Index8][FMT::Float] = {1, 1};
table[VCF::Index8][FMT::InvalidFloat5] = {1, 1};
table[VCF::Index8][FMT::InvalidFloat6] = {1, 1};
table[VCF::Index8][FMT::InvalidFloat7] = {1, 1};
table[VCF::Index16][FMT::UByte] = {2, 2};
table[VCF::Index16][FMT::Byte] = {2, 2};
table[VCF::Index16][FMT::UShort] = {2, 2};
table[VCF::Index16][FMT::Short] = {2, 2};
table[VCF::Index16][FMT::Float] = {2, 2};
table[VCF::Index16][FMT::InvalidFloat5] = {2, 2};
table[VCF::Index16][FMT::InvalidFloat6] = {2, 2};
table[VCF::Index16][FMT::InvalidFloat7] = {2, 2};
return table;
}

View File

@ -60,7 +60,7 @@ void TexCoord_ReadIndex(VertexLoader* loader)
}
using ComponentCountRow = Common::EnumMap<TPipelineFunction, TexComponentCount::ST>;
using ComponentFormatTable = Common::EnumMap<ComponentCountRow, ComponentFormat::Float>;
using ComponentFormatTable = Common::EnumMap<ComponentCountRow, ComponentFormat::InvalidFloat7>;
using Table = Common::EnumMap<ComponentFormatTable, VertexComponentFormat::Index16>;
constexpr Table s_table_read_tex_coord = {
@ -70,6 +70,9 @@ constexpr Table s_table_read_tex_coord = {
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
ComponentCountRow(nullptr, nullptr),
}),
ComponentFormatTable({
ComponentCountRow(TexCoord_ReadDirect<u8, 1>, TexCoord_ReadDirect<u8, 2>),
@ -77,6 +80,9 @@ constexpr Table s_table_read_tex_coord = {
ComponentCountRow(TexCoord_ReadDirect<u16, 1>, TexCoord_ReadDirect<u16, 2>),
ComponentCountRow(TexCoord_ReadDirect<s16, 1>, TexCoord_ReadDirect<s16, 2>),
ComponentCountRow(TexCoord_ReadDirect<float, 1>, TexCoord_ReadDirect<float, 2>),
ComponentCountRow(TexCoord_ReadDirect<float, 1>, TexCoord_ReadDirect<float, 2>),
ComponentCountRow(TexCoord_ReadDirect<float, 1>, TexCoord_ReadDirect<float, 2>),
ComponentCountRow(TexCoord_ReadDirect<float, 1>, TexCoord_ReadDirect<float, 2>),
}),
ComponentFormatTable({
ComponentCountRow(TexCoord_ReadIndex<u8, u8, 1>, TexCoord_ReadIndex<u8, u8, 2>),
@ -84,6 +90,9 @@ constexpr Table s_table_read_tex_coord = {
ComponentCountRow(TexCoord_ReadIndex<u8, u16, 1>, TexCoord_ReadIndex<u8, u16, 2>),
ComponentCountRow(TexCoord_ReadIndex<u8, s16, 1>, TexCoord_ReadIndex<u8, s16, 2>),
ComponentCountRow(TexCoord_ReadIndex<u8, float, 1>, TexCoord_ReadIndex<u8, float, 2>),
ComponentCountRow(TexCoord_ReadIndex<u8, float, 1>, TexCoord_ReadIndex<u8, float, 2>),
ComponentCountRow(TexCoord_ReadIndex<u8, float, 1>, TexCoord_ReadIndex<u8, float, 2>),
ComponentCountRow(TexCoord_ReadIndex<u8, float, 1>, TexCoord_ReadIndex<u8, float, 2>),
}),
ComponentFormatTable({
ComponentCountRow(TexCoord_ReadIndex<u16, u8, 1>, TexCoord_ReadIndex<u16, u8, 2>),
@ -91,6 +100,9 @@ constexpr Table s_table_read_tex_coord = {
ComponentCountRow(TexCoord_ReadIndex<u16, u16, 1>, TexCoord_ReadIndex<u16, u16, 2>),
ComponentCountRow(TexCoord_ReadIndex<u16, s16, 1>, TexCoord_ReadIndex<u16, s16, 2>),
ComponentCountRow(TexCoord_ReadIndex<u16, float, 1>, TexCoord_ReadIndex<u16, float, 2>),
ComponentCountRow(TexCoord_ReadIndex<u16, float, 1>, TexCoord_ReadIndex<u16, float, 2>),
ComponentCountRow(TexCoord_ReadIndex<u16, float, 1>, TexCoord_ReadIndex<u16, float, 2>),
ComponentCountRow(TexCoord_ReadIndex<u16, float, 1>, TexCoord_ReadIndex<u16, float, 2>),
}),
};
} // Anonymous namespace

View File

@ -29,8 +29,9 @@ private:
template <typename T, auto last_member>
using EnumMap = typename Common::EnumMap<T, last_member>;
using SizeTable = EnumMap<EnumMap<EnumMap<u32, TexComponentCount::ST>, ComponentFormat::Float>,
VertexComponentFormat::Index16>;
using SizeTable =
EnumMap<EnumMap<EnumMap<u32, TexComponentCount::ST>, ComponentFormat::InvalidFloat7>,
VertexComponentFormat::Index16>;
static constexpr SizeTable s_table_size = []() consteval
{
@ -44,18 +45,27 @@ private:
table[VCF::Direct][FMT::UShort] = {2, 4};
table[VCF::Direct][FMT::Short] = {2, 4};
table[VCF::Direct][FMT::Float] = {4, 8};
table[VCF::Direct][FMT::InvalidFloat5] = {4, 8};
table[VCF::Direct][FMT::InvalidFloat6] = {4, 8};
table[VCF::Direct][FMT::InvalidFloat7] = {4, 8};
table[VCF::Index8][FMT::UByte] = {1, 1};
table[VCF::Index8][FMT::Byte] = {1, 1};
table[VCF::Index8][FMT::UShort] = {1, 1};
table[VCF::Index8][FMT::Short] = {1, 1};
table[VCF::Index8][FMT::Float] = {1, 1};
table[VCF::Index8][FMT::InvalidFloat5] = {1, 1};
table[VCF::Index8][FMT::InvalidFloat6] = {1, 1};
table[VCF::Index8][FMT::InvalidFloat7] = {1, 1};
table[VCF::Index16][FMT::UByte] = {2, 2};
table[VCF::Index16][FMT::Byte] = {2, 2};
table[VCF::Index16][FMT::UShort] = {2, 2};
table[VCF::Index16][FMT::Short] = {2, 2};
table[VCF::Index16][FMT::Float] = {2, 2};
table[VCF::Index16][FMT::InvalidFloat5] = {2, 2};
table[VCF::Index16][FMT::InvalidFloat6] = {2, 2};
table[VCF::Index16][FMT::InvalidFloat7] = {2, 2};
return table;
}

View File

@ -121,7 +121,9 @@ INSTANTIATE_TEST_SUITE_P(
::testing::Values(VertexComponentFormat::Direct, VertexComponentFormat::Index8,
VertexComponentFormat::Index16),
::testing::Values(ComponentFormat::UByte, ComponentFormat::Byte, ComponentFormat::UShort,
ComponentFormat::Short, ComponentFormat::Float),
ComponentFormat::Short, ComponentFormat::Float,
ComponentFormat::InvalidFloat5, ComponentFormat::InvalidFloat6,
ComponentFormat::InvalidFloat7),
::testing::Values(CoordComponentCount::XY, CoordComponentCount::XYZ),
::testing::Values(0, 1, 31) // frac
));
@ -170,10 +172,12 @@ TEST_P(VertexLoaderParamTest, PositionAll)
{
input_size = addr == VertexComponentFormat::Index8 ? 1 : 2;
for (int i = 0; i < count; i++)
{
if (addr == VertexComponentFormat::Index8)
Input<u8>(i);
else
Input<u16>(i);
}
VertexLoaderManager::cached_arraybases[CPArray::Position] = m_src.GetPointer();
g_main_cp_state.array_strides[CPArray::Position] = elem_count * elem_size;
}
@ -195,6 +199,9 @@ TEST_P(VertexLoaderParamTest, PositionAll)
Input(MathUtil::SaturatingCast<s16>(value));
break;
case ComponentFormat::Float:
case ComponentFormat::InvalidFloat5:
case ComponentFormat::InvalidFloat6:
case ComponentFormat::InvalidFloat7:
Input(value);
break;
}
@ -202,7 +209,7 @@ TEST_P(VertexLoaderParamTest, PositionAll)
RunVertices(count);
float scale = 1.f / (1u << (format == ComponentFormat::Float ? 0 : frac));
float scale = 1.f / (1u << (format >= ComponentFormat::Float ? 0 : frac));
for (auto iter = values.begin(); iter != values.end();)
{
float f, g;
@ -225,6 +232,9 @@ TEST_P(VertexLoaderParamTest, PositionAll)
g = MathUtil::SaturatingCast<s16>(*iter++);
break;
case ComponentFormat::Float:
case ComponentFormat::InvalidFloat5:
case ComponentFormat::InvalidFloat6:
case ComponentFormat::InvalidFloat7:
f = *iter++;
g = *iter++;
break;
@ -543,7 +553,9 @@ INSTANTIATE_TEST_SUITE_P(
::testing::Values(VertexComponentFormat::NotPresent, VertexComponentFormat::Direct,
VertexComponentFormat::Index8, VertexComponentFormat::Index16),
::testing::Values(ComponentFormat::UByte, ComponentFormat::Byte, ComponentFormat::UShort,
ComponentFormat::Short, ComponentFormat::Float),
ComponentFormat::Short, ComponentFormat::Float,
ComponentFormat::InvalidFloat5, ComponentFormat::InvalidFloat6,
ComponentFormat::InvalidFloat7),
::testing::Values(NormalComponentCount::N, NormalComponentCount::NTB),
::testing::Values(false, true)));
@ -609,7 +621,9 @@ TEST_P(VertexLoaderNormalTest, NormalAll)
Input<s16>(value * (1 << 14));
break;
case ComponentFormat::Float:
default:
case ComponentFormat::InvalidFloat5:
case ComponentFormat::InvalidFloat6:
case ComponentFormat::InvalidFloat7:
Input<float>(value);
break;
}