summaryrefslogtreecommitdiff
path: root/Source/UnitTests/VideoCommon
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2022-09-19 19:47:37 -0400
committerGitHub <noreply@github.com>2022-09-19 19:47:37 -0400
commit3b10bf04ac74bff9ce11e6140ddc552f94eb2b3e (patch)
treefe34d1ffeb5b8548ebf56fd6f427f153f7cd5526 /Source/UnitTests/VideoCommon
parent91b1faa36a04151ea1ffc813eb3539626633c34c (diff)
parentd80201a57f6433bf660be2a1aecd60b97ddb6599 (diff)
Merge pull request #10808 from Pokechu22/vertex-loader-direct-normals-with-index3
VideoCommon: Fix direct normal+tangent+binormal with index3 set
Diffstat (limited to 'Source/UnitTests/VideoCommon')
-rw-r--r--Source/UnitTests/VideoCommon/VertexLoaderTest.cpp410
1 files changed, 410 insertions, 0 deletions
diff --git a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp
index b12dad1661..5e3898ed28 100644
--- a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp
+++ b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp
@@ -366,3 +366,413 @@ TEST_F(VertexLoaderTest, LargeFloatVertexSpeed)
for (int i = 0; i < 100; ++i)
RunVertices(100000);
}
+
+TEST_F(VertexLoaderTest, DirectAllComponents)
+{
+ 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::Direct;
+ m_vtx_desc.low.Normal = VertexComponentFormat::Direct;
+ m_vtx_desc.low.Color0 = VertexComponentFormat::Direct;
+ m_vtx_desc.low.Color1 = VertexComponentFormat::Direct;
+ m_vtx_desc.high.Tex0Coord = VertexComponentFormat::Direct;
+ m_vtx_desc.high.Tex1Coord = VertexComponentFormat::Direct;
+ m_vtx_desc.high.Tex2Coord = VertexComponentFormat::Direct;
+ m_vtx_desc.high.Tex3Coord = VertexComponentFormat::Direct;
+ m_vtx_desc.high.Tex4Coord = VertexComponentFormat::Direct;
+ m_vtx_desc.high.Tex5Coord = VertexComponentFormat::Direct;
+ m_vtx_desc.high.Tex6Coord = VertexComponentFormat::Direct;
+ m_vtx_desc.high.Tex7Coord = VertexComponentFormat::Direct;
+
+ m_vtx_attr.g0.PosElements = CoordComponentCount::XYZ;
+ m_vtx_attr.g0.PosFormat = ComponentFormat::Float;
+ m_vtx_attr.g0.NormalElements = NormalComponentCount::NTB;
+ 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(129, 39 * sizeof(float));
+
+ // Pos matrix idx
+ Input<u8>(20);
+ // Tex matrix idx
+ Input<u8>(0);
+ Input<u8>(1);
+ Input<u8>(2);
+ Input<u8>(3);
+ Input<u8>(4);
+ Input<u8>(5);
+ Input<u8>(6);
+ Input<u8>(7);
+ // Position
+ Input(-1.0f);
+ Input(-2.0f);
+ Input(-3.0f);
+ // Normal
+ Input(-4.0f);
+ Input(-5.0f);
+ Input(-6.0f);
+ // Tangent
+ Input(-7.0f);
+ Input(-8.0f);
+ Input(-9.0f);
+ // Binormal
+ Input(-10.0f);
+ Input(-11.0f);
+ Input(-12.0f);
+ // Colors
+ Input<u32>(0x01234567);
+ Input<u32>(0x89abcdef);
+ // Texture coordinates
+ Input(0.1f);
+ Input(-0.9f);
+ Input(1.1f);
+ Input(-1.9f);
+ Input(2.1f);
+ Input(-2.9f);
+ Input(3.1f);
+ Input(-3.9f);
+ Input(4.1f);
+ Input(-4.9f);
+ Input(5.1f);
+ Input(-5.9f);
+ Input(6.1f);
+ Input(-6.9f);
+ Input(7.1f);
+ Input(-7.9f);
+
+ RunVertices(1);
+
+ // Position matrix
+ ASSERT_EQ(m_loader->m_native_vtx_decl.posmtx.offset, 0 * sizeof(float));
+ EXPECT_EQ((m_dst.Read<u32, false>()), 20u);
+ // Position
+ ASSERT_EQ(m_loader->m_native_vtx_decl.position.offset, 1 * sizeof(float));
+ ExpectOut(-1.0f);
+ ExpectOut(-2.0f);
+ ExpectOut(-3.0f);
+ // Normal
+ ASSERT_EQ(m_loader->m_native_vtx_decl.normals[0].offset, 4 * sizeof(float));
+ ExpectOut(-4.0f);
+ ExpectOut(-5.0f);
+ ExpectOut(-6.0f);
+ // Tangent
+ ASSERT_EQ(m_loader->m_native_vtx_decl.normals[1].offset, 7 * sizeof(float));
+ ExpectOut(-7.0f);
+ ExpectOut(-8.0f);
+ ExpectOut(-9.0f);
+ // Binormal
+ ASSERT_EQ(m_loader->m_native_vtx_decl.normals[2].offset, 10 * sizeof(float));
+ ExpectOut(-10.0f);
+ ExpectOut(-11.0f);
+ ExpectOut(-12.0f);
+ // Colors
+ ASSERT_EQ(m_loader->m_native_vtx_decl.colors[0].offset, 13 * sizeof(float));
+ EXPECT_EQ((m_dst.Read<u32, true>()), 0x01234567u);
+ ASSERT_EQ(m_loader->m_native_vtx_decl.colors[1].offset, 14 * sizeof(float));
+ EXPECT_EQ((m_dst.Read<u32, true>()), 0x89abcdefu);
+ // Texture coordinates and matrices (interleaved)
+ ASSERT_EQ(m_loader->m_native_vtx_decl.texcoords[0].offset, 15 * sizeof(float));
+ ExpectOut(0.1f); // S
+ ExpectOut(-0.9f); // T
+ ExpectOut(0.0f); // matrix (yes, a float)
+ ASSERT_EQ(m_loader->m_native_vtx_decl.texcoords[1].offset, 18 * sizeof(float));
+ ExpectOut(1.1f);
+ ExpectOut(-1.9f);
+ ExpectOut(1.0f);
+ ASSERT_EQ(m_loader->m_native_vtx_decl.texcoords[2].offset, 21 * sizeof(float));
+ ExpectOut(2.1f);
+ ExpectOut(-2.9f);
+ ExpectOut(2.0f);
+ ASSERT_EQ(m_loader->m_native_vtx_decl.texcoords[3].offset, 24 * sizeof(float));
+ ExpectOut(3.1f);
+ ExpectOut(-3.9f);
+ ExpectOut(3.0f);
+ ASSERT_EQ(m_loader->m_native_vtx_decl.texcoords[4].offset, 27 * sizeof(float));
+ ExpectOut(4.1f);
+ ExpectOut(-4.9f);
+ ExpectOut(4.0f);
+ ASSERT_EQ(m_loader->m_native_vtx_decl.texcoords[5].offset, 30 * sizeof(float));
+ ExpectOut(5.1f);
+ ExpectOut(-5.9f);
+ ExpectOut(5.0f);
+ ASSERT_EQ(m_loader->m_native_vtx_decl.texcoords[6].offset, 33 * sizeof(float));
+ ExpectOut(6.1f);
+ ExpectOut(-6.9f);
+ ExpectOut(6.0f);
+ ASSERT_EQ(m_loader->m_native_vtx_decl.texcoords[7].offset, 36 * sizeof(float));
+ ExpectOut(7.1f);
+ ExpectOut(-7.9f);
+ ExpectOut(7.0f);
+}
+
+class VertexLoaderNormalTest
+ : public VertexLoaderTest,
+ public ::testing::WithParamInterface<
+ std::tuple<VertexComponentFormat, ComponentFormat, NormalComponentCount, bool>>
+{
+};
+INSTANTIATE_TEST_CASE_P(
+ AllCombinations, VertexLoaderNormalTest,
+ ::testing::Combine(
+ ::testing::Values(VertexComponentFormat::NotPresent, VertexComponentFormat::Direct,
+ VertexComponentFormat::Index8, VertexComponentFormat::Index16),
+ ::testing::Values(ComponentFormat::UByte, ComponentFormat::Byte, ComponentFormat::UShort,
+ ComponentFormat::Short, ComponentFormat::Float),
+ ::testing::Values(NormalComponentCount::N, NormalComponentCount::NTB),
+ ::testing::Values(false, true)));
+
+TEST_P(VertexLoaderNormalTest, NormalAll)
+{
+ VertexComponentFormat addr;
+ ComponentFormat format;
+ NormalComponentCount elements;
+ bool index3;
+ std::tie(addr, format, elements, index3) = GetParam();
+
+ m_vtx_desc.low.Position = VertexComponentFormat::Direct;
+ m_vtx_attr.g0.PosFormat = ComponentFormat::Float;
+ m_vtx_attr.g0.PosElements = CoordComponentCount::XY;
+ m_vtx_attr.g0.PosFrac = 0;
+ m_vtx_desc.low.Normal = addr;
+ m_vtx_attr.g0.NormalFormat = format;
+ m_vtx_attr.g0.NormalElements = elements;
+ m_vtx_attr.g0.NormalIndex3 = index3;
+
+ const u32 in_size = [&]() -> u32 {
+ if (addr == VertexComponentFormat::NotPresent)
+ return 0;
+
+ if (IsIndexed(addr))
+ {
+ const u32 base_size = (addr == VertexComponentFormat::Index8) ? 1 : 2;
+ if (elements == NormalComponentCount::NTB)
+ return (index3 ? 3 : 1) * base_size;
+ else
+ return 1 * base_size;
+ }
+ else
+ {
+ const u32 base_count = (elements == NormalComponentCount::NTB) ? 9 : 3;
+ const u32 base_size = GetElementSize(format);
+ return base_count * base_size;
+ }
+ }();
+ const u32 out_size = [&]() -> u32 {
+ if (addr == VertexComponentFormat::NotPresent)
+ return 0;
+
+ const u32 base_count = (elements == NormalComponentCount::NTB) ? 9 : 3;
+ return base_count * sizeof(float);
+ }();
+
+ CreateAndCheckSizes(2 * sizeof(float) + in_size, 2 * sizeof(float) + out_size);
+
+ auto input_with_expected_type = [&](float value) {
+ switch (format)
+ {
+ case ComponentFormat::UByte:
+ Input<u8>(value * (1 << 7));
+ break;
+ case ComponentFormat::Byte:
+ Input<s8>(value * (1 << 6));
+ break;
+ case ComponentFormat::UShort:
+ Input<u16>(value * (1 << 15));
+ break;
+ case ComponentFormat::Short:
+ Input<s16>(value * (1 << 14));
+ break;
+ case ComponentFormat::Float:
+ default:
+ Input<float>(value);
+ break;
+ }
+ };
+
+ auto create_normal = [&](int counter_base) {
+ if (addr == VertexComponentFormat::Direct)
+ {
+ input_with_expected_type(counter_base / 32.f);
+ input_with_expected_type((counter_base + 1) / 32.f);
+ input_with_expected_type((counter_base + 2) / 32.f);
+ }
+ else if (addr == VertexComponentFormat::Index8)
+ {
+ // We set up arrays so that this works
+ Input<u8>(counter_base);
+ }
+ else if (addr == VertexComponentFormat::Index16)
+ {
+ Input<u16>(counter_base);
+ }
+ // Do nothing for NotPresent
+ };
+ auto create_tangent_and_binormal = [&](int counter_base) {
+ if (IsIndexed(addr))
+ {
+ // With NormalIndex3, specifying the same index 3 times should give the same result
+ // as specifying one index in non-index3 mode (as the index is biased by bytes).
+ // If index3 is disabled, we don't want to write any more indices.
+ if (index3)
+ {
+ // Tangent
+ create_normal(counter_base);
+ // Binormal
+ create_normal(counter_base);
+ }
+ }
+ else
+ {
+ // Tangent
+ create_normal(counter_base + 3);
+ // Binormal
+ create_normal(counter_base + 6);
+ }
+ };
+
+ // Create our two vertices
+ // Position 1
+ Input(4.0f);
+ Input(8.0f);
+ // Normal 1
+ create_normal(1);
+ if (elements == NormalComponentCount::NTB)
+ {
+ create_tangent_and_binormal(1);
+ }
+
+ // Position 2
+ Input(6.0f);
+ Input(12.0f);
+ // Normal 1
+ create_normal(10);
+ if (elements == NormalComponentCount::NTB)
+ {
+ create_tangent_and_binormal(10);
+ }
+
+ // Create an array for indexed representations
+ for (int i = 0; i < NUM_VERTEX_COMPONENT_ARRAYS; i++)
+ {
+ VertexLoaderManager::cached_arraybases[static_cast<CPArray>(i)] = m_src.GetPointer();
+ g_main_cp_state.array_strides[static_cast<CPArray>(i)] = GetElementSize(format);
+ }
+
+ for (int i = 0; i < 32; i++)
+ input_with_expected_type(i / 32.f);
+
+ // Pre-fill these values to detect if they're modified
+ VertexLoaderManager::binormal_cache = {42.f, 43.f, 44.f, 45.f};
+ VertexLoaderManager::tangent_cache = {46.f, 47.f, 48.f, 49.f};
+
+ RunVertices(2);
+
+ // First vertex, position
+ ExpectOut(4.0f);
+ ExpectOut(8.0f);
+ if (addr != VertexComponentFormat::NotPresent)
+ {
+ // Normal
+ ExpectOut(1 / 32.f);
+ ExpectOut(2 / 32.f);
+ ExpectOut(3 / 32.f);
+ if (elements == NormalComponentCount::NTB)
+ {
+ // Tangent
+ ExpectOut(4 / 32.f);
+ ExpectOut(5 / 32.f);
+ ExpectOut(6 / 32.f);
+ // Binormal
+ ExpectOut(7 / 32.f);
+ ExpectOut(8 / 32.f);
+ ExpectOut(9 / 32.f);
+ }
+ }
+
+ // Second vertex, position
+ ExpectOut(6.0f);
+ ExpectOut(12.0f);
+ if (addr != VertexComponentFormat::NotPresent)
+ {
+ // Normal
+ ExpectOut(10 / 32.f);
+ ExpectOut(11 / 32.f);
+ ExpectOut(12 / 32.f);
+ if (elements == NormalComponentCount::NTB)
+ {
+ // Tangent
+ ExpectOut(13 / 32.f);
+ ExpectOut(14 / 32.f);
+ ExpectOut(15 / 32.f);
+ // Binormal
+ ExpectOut(16 / 32.f);
+ ExpectOut(17 / 32.f);
+ ExpectOut(18 / 32.f);
+
+ EXPECT_EQ(VertexLoaderManager::tangent_cache[0], 13 / 32.f);
+ EXPECT_EQ(VertexLoaderManager::tangent_cache[1], 14 / 32.f);
+ EXPECT_EQ(VertexLoaderManager::tangent_cache[2], 15 / 32.f);
+ // Last index is padding/junk
+ EXPECT_EQ(VertexLoaderManager::binormal_cache[0], 16 / 32.f);
+ EXPECT_EQ(VertexLoaderManager::binormal_cache[1], 17 / 32.f);
+ EXPECT_EQ(VertexLoaderManager::binormal_cache[2], 18 / 32.f);
+ }
+ }
+
+ if (addr == VertexComponentFormat::NotPresent || elements == NormalComponentCount::N)
+ {
+ // Expect these to not be written
+ EXPECT_EQ(VertexLoaderManager::binormal_cache[0], 42.f);
+ EXPECT_EQ(VertexLoaderManager::binormal_cache[1], 43.f);
+ EXPECT_EQ(VertexLoaderManager::binormal_cache[2], 44.f);
+ EXPECT_EQ(VertexLoaderManager::binormal_cache[3], 45.f);
+ EXPECT_EQ(VertexLoaderManager::tangent_cache[0], 46.f);
+ EXPECT_EQ(VertexLoaderManager::tangent_cache[1], 47.f);
+ EXPECT_EQ(VertexLoaderManager::tangent_cache[2], 48.f);
+ EXPECT_EQ(VertexLoaderManager::tangent_cache[3], 49.f);
+ }
+}
+
+// For gtest, which doesn't know about our fmt::formatters by default
+static void PrintTo(const VertexComponentFormat& t, std::ostream* os)
+{
+ *os << fmt::to_string(t);
+}
+static void PrintTo(const ComponentFormat& t, std::ostream* os)
+{
+ *os << fmt::to_string(t);
+}
+static void PrintTo(const CoordComponentCount& t, std::ostream* os)
+{
+ *os << fmt::to_string(t);
+}
+static void PrintTo(const NormalComponentCount& t, std::ostream* os)
+{
+ *os << fmt::to_string(t);
+}