From 6653bd71994d7866ce79de61b12a2261e6451ea0 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 10 Feb 2021 12:46:32 -0800 Subject: [PATCH 01/17] Create EnumFormatter --- Source/Core/Common/CMakeLists.txt | 1 + Source/Core/Common/EnumFormatter.h | 91 +++++++++++++++++++ Source/Core/DolphinLib.props | 1 + Source/UnitTests/Common/CMakeLists.txt | 1 + Source/UnitTests/Common/EnumFormatterTest.cpp | 67 ++++++++++++++ Source/UnitTests/UnitTests.vcxproj | 1 + 6 files changed, 162 insertions(+) create mode 100644 Source/Core/Common/EnumFormatter.h create mode 100644 Source/UnitTests/Common/EnumFormatterTest.cpp diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 4a3623d4e8..9f7486a571 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -42,6 +42,7 @@ add_library(common DynamicLibrary.h ENetUtil.cpp ENetUtil.h + EnumFormatter.h Event.h FileSearch.cpp FileSearch.h diff --git a/Source/Core/Common/EnumFormatter.h b/Source/Core/Common/EnumFormatter.h new file mode 100644 index 0000000000..2ca1bb114e --- /dev/null +++ b/Source/Core/Common/EnumFormatter.h @@ -0,0 +1,91 @@ +// Copyright 2021 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +/* + * Helper for using enums with fmt. + * + * Usage example: + * + * enum class Foo + * { + * A = 0, + * B = 1, + * C = 2, + * }; + * + * template <> + * struct fmt::formatter : EnumFormatter + * { + * formatter() : EnumFormatter({"A", "B", "C"}) {} + * }; + * + * enum class Bar + * { + * D = 0, + * E = 1, + * F = 3, + * }; + * + * template <> + * struct fmt::formatter : EnumFormatter + * { + * // using std::array here fails due to nullptr not being const char*, at least in MSVC + * // (but only when a field is used; directly in the constructor is OK) + * static constexpr array_type names = {"D", "E", nullptr, "F"}; + * formatter() : EnumFormatter(names) {} + * }; + */ +template (last_member) + 1, + std::enable_if_t, bool> = true> +class EnumFormatter +{ +public: + constexpr auto parse(fmt::format_parse_context& ctx) + { + auto it = ctx.begin(), end = ctx.end(); + // 'u' for user display, 's' for shader generation + if (it != end && (*it == 'u' || *it == 's')) + formatting_for_shader = (*it++ == 's'); + return it; + } + + template + auto format(const T& e, FormatContext& ctx) + { + const auto value = static_cast>(e); + + if (!formatting_for_shader) + { + if (value >= 0 && value < size && m_names[value] != nullptr) + return fmt::format_to(ctx.out(), "{} ({})", m_names[value], value); + else + return fmt::format_to(ctx.out(), "Invalid ({})", value); + } + else + { + if (value >= 0 && value < size && m_names[value] != nullptr) + return fmt::format_to(ctx.out(), "{:#x}u /* {} */", value, m_names[value]); + else + return fmt::format_to(ctx.out(), "{:#x}u /* Invalid */", + static_cast>(value)); + } + } + +protected: + // This is needed because std::array deduces incorrectly if nullptr is included in the list + using array_type = std::array; + + constexpr explicit EnumFormatter(const array_type names) : m_names(std::move(names)) {} + +private: + const array_type m_names; + bool formatting_for_shader = false; +}; diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index d78534993a..638e6734e2 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -45,6 +45,7 @@ + diff --git a/Source/UnitTests/Common/CMakeLists.txt b/Source/UnitTests/Common/CMakeLists.txt index 120fee6c33..86d9dedfcf 100644 --- a/Source/UnitTests/Common/CMakeLists.txt +++ b/Source/UnitTests/Common/CMakeLists.txt @@ -5,6 +5,7 @@ add_dolphin_test(BlockingLoopTest BlockingLoopTest.cpp) add_dolphin_test(BusyLoopTest BusyLoopTest.cpp) add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp) add_dolphin_test(CryptoEcTest Crypto/EcTest.cpp) +add_dolphin_test(EnumFormatterTest EnumFormatterTest.cpp) add_dolphin_test(EventTest EventTest.cpp) add_dolphin_test(FixedSizeQueueTest FixedSizeQueueTest.cpp) add_dolphin_test(FlagTest FlagTest.cpp) diff --git a/Source/UnitTests/Common/EnumFormatterTest.cpp b/Source/UnitTests/Common/EnumFormatterTest.cpp new file mode 100644 index 0000000000..fb713db2f2 --- /dev/null +++ b/Source/UnitTests/Common/EnumFormatterTest.cpp @@ -0,0 +1,67 @@ +// Copyright 2021 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include + +#include "Common/CommonTypes.h" +#include "Common/EnumFormatter.h" + +enum class Enum1 : u32 +{ + A = 0, + B = 1, + C = 2, +}; + +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"A", "B", "C"}) {} +}; + +enum class Enum2 : s32 +{ + D = 0, + E = 1, + F = 3, +}; + +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = {"D", "E", nullptr, "F"}; + formatter() : EnumFormatter(names) {} +}; + +TEST(EnumUtil, Enum1) +{ + EXPECT_EQ(fmt::to_string(Enum1::A), "A (0)"); + EXPECT_EQ(fmt::to_string(Enum1::B), "B (1)"); + EXPECT_EQ(fmt::to_string(Enum1::C), "C (2)"); + EXPECT_EQ(fmt::to_string(static_cast(3)), "Invalid (3)"); + EXPECT_EQ(fmt::to_string(static_cast(4)), "Invalid (4)"); + + EXPECT_EQ(fmt::format("{:s}", Enum1::A), "0x0u /* A */"); + EXPECT_EQ(fmt::format("{:s}", Enum1::B), "0x1u /* B */"); + EXPECT_EQ(fmt::format("{:s}", Enum1::C), "0x2u /* C */"); + EXPECT_EQ(fmt::format("{:s}", static_cast(3)), "0x3u /* Invalid */"); + EXPECT_EQ(fmt::format("{:s}", static_cast(4)), "0x4u /* Invalid */"); +} + +TEST(EnumUtil, Enum2) +{ + EXPECT_EQ(fmt::to_string(Enum2::D), "D (0)"); + EXPECT_EQ(fmt::to_string(Enum2::E), "E (1)"); + EXPECT_EQ(fmt::to_string(static_cast(2)), "Invalid (2)"); + EXPECT_EQ(fmt::to_string(Enum2::F), "F (3)"); + EXPECT_EQ(fmt::to_string(static_cast(4)), "Invalid (4)"); + EXPECT_EQ(fmt::to_string(static_cast(-1)), "Invalid (-1)"); + + EXPECT_EQ(fmt::format("{:s}", Enum2::D), "0x0u /* D */"); + EXPECT_EQ(fmt::format("{:s}", Enum2::E), "0x1u /* E */"); + EXPECT_EQ(fmt::format("{:s}", static_cast(2)), "0x2u /* Invalid */"); + EXPECT_EQ(fmt::format("{:s}", Enum2::F), "0x3u /* F */"); + EXPECT_EQ(fmt::format("{:s}", static_cast(4)), "0x4u /* Invalid */"); + EXPECT_EQ(fmt::format("{:s}", static_cast(-1)), "0xffffffffu /* Invalid */"); +} diff --git a/Source/UnitTests/UnitTests.vcxproj b/Source/UnitTests/UnitTests.vcxproj index 230ac50412..d0b0c27fb6 100644 --- a/Source/UnitTests/UnitTests.vcxproj +++ b/Source/UnitTests/UnitTests.vcxproj @@ -49,6 +49,7 @@ + From cf95deaf6ddbcbd1cf649e1cba189f836023b23b Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 17 Feb 2021 20:23:06 -0800 Subject: [PATCH 02/17] Allow specifying StorageType for BitField This is useful for BitFields that are bools. --- Source/Core/Common/BitField.h | 27 ++++++++++++------------ Source/UnitTests/Common/BitFieldTest.cpp | 13 ++++++++++++ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Source/Core/Common/BitField.h b/Source/Core/Common/BitField.h index 00c5345533..045509ef07 100644 --- a/Source/Core/Common/BitField.h +++ b/Source/Core/Common/BitField.h @@ -110,7 +110,13 @@ * symptoms. */ #pragma pack(1) -template +template ::type directly. + typename StorageType = typename std::conditional_t< + std::is_enum::value, std::underlying_type, std::enable_if>::type> struct BitField { private: @@ -149,20 +155,13 @@ public: constexpr std::size_t NumBits() const { return bits; } private: - // StorageType is T for non-enum types and the underlying type of T if - // T is an enumeration. Note that T is wrapped within an enable_if in the - // former case to workaround compile errors which arise when using - // std::underlying_type::type directly. - using StorageType = typename std::conditional_t::value, std::underlying_type, - std::enable_if>::type; - // Unsigned version of StorageType using StorageTypeU = std::make_unsigned_t; constexpr T Value(std::true_type) const { - using shift_amount = std::integral_constant; - return static_cast((storage << (shift_amount() - position)) >> shift_amount()); + const size_t shift_amount = 8 * sizeof(StorageType) - bits; + return static_cast((storage << (shift_amount - position)) >> shift_amount); } constexpr T Value(std::false_type) const @@ -172,15 +171,17 @@ private: static constexpr StorageType GetMask() { - return (std::numeric_limits::max() >> (8 * sizeof(T) - bits)) << position; + return (std::numeric_limits::max() >> (8 * sizeof(StorageType) - bits)) + << position; } StorageType storage; - static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); + static_assert(bits + position <= 8 * sizeof(StorageType), "Bitfield out of range"); + static_assert(sizeof(T) <= sizeof(StorageType), "T must fit in StorageType"); // And, you know, just in case people specify something stupid like bits=position=0x80000000 - static_assert(position < 8 * sizeof(T), "Invalid position"); + static_assert(position < 8 * sizeof(StorageType), "Invalid position"); static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); static_assert(bits > 0, "Invalid number of bits"); }; diff --git a/Source/UnitTests/Common/BitFieldTest.cpp b/Source/UnitTests/Common/BitFieldTest.cpp index 32b587469f..cb82a33911 100644 --- a/Source/UnitTests/Common/BitFieldTest.cpp +++ b/Source/UnitTests/Common/BitFieldTest.cpp @@ -21,6 +21,8 @@ union TestUnion BitField<30, 4, s64> at_dword_boundary; // goes over the boundary of two u32 values BitField<15, 1, s64> signed_1bit; // allowed values: -1 and 0 + + BitField<63, 1, bool, u64> flag; }; // table of raw numbers to test with @@ -51,6 +53,7 @@ TEST(BitField, Storage) EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_signed)); EXPECT_EQ(sizeof(TestUnion), sizeof(object.at_dword_boundary)); EXPECT_EQ(sizeof(TestUnion), sizeof(object.signed_1bit)); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.flag)); // Now write some values to one field and check if this reflects properly // in the others. @@ -82,6 +85,7 @@ TEST(BitField, Read) EXPECT_EQ(object.regular_field_signed, (s64)object.regular_field_signed); EXPECT_EQ(object.at_dword_boundary, (s64)object.at_dword_boundary); EXPECT_EQ(object.signed_1bit, (s64)object.signed_1bit); + EXPECT_EQ(object.flag, (bool)object.flag); // Now make sure the value is indeed correct EXPECT_EQ(val, object.full_u64); @@ -91,6 +95,7 @@ TEST(BitField, Read) EXPECT_EQ(((s64)(object.hex << 52)) >> 61, object.regular_field_signed); EXPECT_EQ(((s64)(object.hex << 30)) >> 60, object.at_dword_boundary); EXPECT_EQ(((object.hex >> 15) & 1) ? -1 : 0, object.signed_1bit); + EXPECT_EQ((bool)object.flag, ((object.hex >> 63) & 1)); } } @@ -122,6 +127,10 @@ TEST(BitField, Assignment) // Assignment from other BitField object.at_dword_boundary = object.regular_field_signed; EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary); + + // Assignment to field of a type with a size smaller than the underlying type + object.flag = (val & 2); + EXPECT_EQ(object.flag, (val & 2) != 0); } } @@ -165,5 +174,9 @@ TEST(BitField, Alignment) // Assignment from other BitField object.at_dword_boundary = object.regular_field_signed; EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary); + + // Assignment to field of a type with a size smaller than the underlying type + object.flag = (val & 2); + EXPECT_EQ(object.flag, (val & 2) != 0); } } From 1273c5e3953e61e93ac67531285a766b5356fe3d Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 9 Feb 2021 14:46:27 -0800 Subject: [PATCH 03/17] Add fmt support to BitField --- Source/Core/Common/BitField.h | 16 ++++++ Source/UnitTests/Common/BitFieldTest.cpp | 71 ++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/Source/Core/Common/BitField.h b/Source/Core/Common/BitField.h index 045509ef07..caaf91dc3d 100644 --- a/Source/Core/Common/BitField.h +++ b/Source/Core/Common/BitField.h @@ -32,6 +32,7 @@ #pragma once #include +#include #include #include @@ -99,6 +100,8 @@ * explicit cast must be performed on the BitField object to make sure it gets * passed correctly, e.g.: * printf("Value: %d", (s32)some_register.some_signed_fields); + * Note that this does not apply when using fmt, as a formatter is provided that + * handles this conversion automatically. * * 2) * Not really a caveat, but potentially irritating: This class is used in some @@ -186,3 +189,16 @@ private: static_assert(bits > 0, "Invalid number of bits"); }; #pragma pack() + +// Use the underlying type's formatter for BitFields, if one exists +template +struct fmt::formatter> +{ + fmt::formatter m_formatter; + constexpr auto parse(format_parse_context& ctx) { return m_formatter.parse(ctx); } + template + auto format(const BitField& bitfield, FormatContext& ctx) + { + return m_formatter.format(bitfield.Value(), ctx); + } +}; diff --git a/Source/UnitTests/Common/BitFieldTest.cpp b/Source/UnitTests/Common/BitFieldTest.cpp index cb82a33911..d68b18b4c6 100644 --- a/Source/UnitTests/Common/BitFieldTest.cpp +++ b/Source/UnitTests/Common/BitFieldTest.cpp @@ -6,6 +6,15 @@ #include "Common/BitField.h" #include "Common/CommonTypes.h" +#include "Common/EnumFormatter.h" + +enum class TestEnum : u64 +{ + A, + B, + C, + D, +}; union TestUnion { @@ -23,6 +32,9 @@ union TestUnion BitField<15, 1, s64> signed_1bit; // allowed values: -1 and 0 BitField<63, 1, bool, u64> flag; + + BitField<16, 2, TestEnum> enum_1; + BitField<48, 2, TestEnum> enum_2; }; // table of raw numbers to test with @@ -54,6 +66,8 @@ TEST(BitField, Storage) EXPECT_EQ(sizeof(TestUnion), sizeof(object.at_dword_boundary)); EXPECT_EQ(sizeof(TestUnion), sizeof(object.signed_1bit)); EXPECT_EQ(sizeof(TestUnion), sizeof(object.flag)); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.enum_1)); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.enum_2)); // Now write some values to one field and check if this reflects properly // in the others. @@ -86,6 +100,8 @@ TEST(BitField, Read) EXPECT_EQ(object.at_dword_boundary, (s64)object.at_dword_boundary); EXPECT_EQ(object.signed_1bit, (s64)object.signed_1bit); EXPECT_EQ(object.flag, (bool)object.flag); + EXPECT_EQ(object.enum_1, static_cast(object.enum_1)); + EXPECT_EQ(object.enum_2, static_cast(object.enum_2)); // Now make sure the value is indeed correct EXPECT_EQ(val, object.full_u64); @@ -96,6 +112,8 @@ TEST(BitField, Read) EXPECT_EQ(((s64)(object.hex << 30)) >> 60, object.at_dword_boundary); EXPECT_EQ(((object.hex >> 15) & 1) ? -1 : 0, object.signed_1bit); EXPECT_EQ((bool)object.flag, ((object.hex >> 63) & 1)); + EXPECT_EQ(static_cast((object.hex >> 16) & 3), object.enum_1); + EXPECT_EQ(static_cast((object.hex >> 48) & 3), object.enum_2); } } @@ -180,3 +198,56 @@ TEST(BitField, Alignment) EXPECT_EQ(object.flag, (val & 2) != 0); } } + +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"A", "B", "C", "D"}) {} +}; + +// Test behavior of using BitFields with fmt +TEST(BitField, Fmt) +{ + TestUnion object; + + for (u64 val : table) + { + object.hex = val; + + // Formatting the BitField should be the same as formatting its value + EXPECT_EQ(fmt::to_string(object.full_u64), fmt::to_string(object.full_u64.Value())); + EXPECT_EQ(fmt::to_string(object.full_s64), fmt::to_string(object.full_s64.Value())); + EXPECT_EQ(fmt::to_string(object.regular_field_unsigned), + fmt::to_string(object.regular_field_unsigned.Value())); + EXPECT_EQ(fmt::to_string(object.regular_field_unsigned2), + fmt::to_string(object.regular_field_unsigned2.Value())); + EXPECT_EQ(fmt::to_string(object.regular_field_signed), + fmt::to_string(object.regular_field_signed.Value())); + EXPECT_EQ(fmt::to_string(object.at_dword_boundary), + fmt::to_string(object.at_dword_boundary.Value())); + EXPECT_EQ(fmt::to_string(object.signed_1bit), fmt::to_string(object.signed_1bit.Value())); + EXPECT_EQ(fmt::to_string(object.flag), fmt::to_string(object.flag.Value())); + // The custom enum formatter should be used properly. + EXPECT_EQ(fmt::to_string(object.enum_1), fmt::to_string(object.enum_1.Value())); + EXPECT_EQ(fmt::to_string(object.enum_2), fmt::to_string(object.enum_2.Value())); + + // Formatting the BitField should respect the format spec + EXPECT_EQ(fmt::format("{:02x}", object.full_u64), + fmt::format("{:02x}", object.full_u64.Value())); + EXPECT_EQ(fmt::format("{:02x}", object.full_s64), + fmt::format("{:02x}", object.full_s64.Value())); + EXPECT_EQ(fmt::format("{:02x}", object.regular_field_unsigned), + fmt::format("{:02x}", object.regular_field_unsigned.Value())); + EXPECT_EQ(fmt::format("{:02x}", object.regular_field_unsigned2), + fmt::format("{:02x}", object.regular_field_unsigned2.Value())); + EXPECT_EQ(fmt::format("{:02x}", object.regular_field_signed), + fmt::format("{:02x}", object.regular_field_signed.Value())); + EXPECT_EQ(fmt::format("{:02x}", object.at_dword_boundary), + fmt::format("{:02x}", object.at_dword_boundary.Value())); + EXPECT_EQ(fmt::format("{:02x}", object.signed_1bit), + fmt::format("{:02x}", object.signed_1bit.Value())); + EXPECT_EQ(fmt::format("{:02x}", object.flag), fmt::format("{:02x}", object.flag.Value())); + EXPECT_EQ(fmt::format("{:s}", object.enum_1), fmt::format("{:s}", object.enum_1.Value())); + EXPECT_EQ(fmt::format("{:s}", object.enum_2), fmt::format("{:s}", object.enum_2.Value())); + } +} From f697e17dd1005eeea172f6a34497cae47bdfc8d6 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 16 Feb 2021 22:49:30 -0800 Subject: [PATCH 04/17] Create BitFieldArray --- Source/Core/Common/BitField.h | 303 +++++++++++++++++++++++ Source/UnitTests/Common/BitFieldTest.cpp | 292 ++++++++++++++++++++++ 2 files changed, 595 insertions(+) diff --git a/Source/Core/Common/BitField.h b/Source/Core/Common/BitField.h index caaf91dc3d..e7af066d2f 100644 --- a/Source/Core/Common/BitField.h +++ b/Source/Core/Common/BitField.h @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -202,3 +203,305 @@ struct fmt::formatter> return m_formatter.format(bitfield.Value(), ctx); } }; + +// Language limitations require the following to make these formattable +// (formatter::Ref> is not legal) +template +class BitFieldArrayConstRef; +template +class BitFieldArrayRef; +template +class BitFieldArrayConstIterator; +template +class BitFieldArrayIterator; + +#pragma pack(1) +template ::type directly. + typename StorageType = typename std::conditional_t< + std::is_enum::value, std::underlying_type, std::enable_if>::type> +struct BitFieldArray +{ + using Ref = BitFieldArrayRef; + using ConstRef = BitFieldArrayConstRef; + using Iterator = BitFieldArrayIterator; + using ConstIterator = BitFieldArrayConstIterator; + +private: + // This constructor might be considered ambiguous: + // Would it initialize the storage or just the bitfield? + // Hence, delete it. Use the assignment operator to set bitfield values! + BitFieldArray(T val) = delete; + +public: + // Force default constructor to be created + // so that we can use this within unions + constexpr BitFieldArray() = default; + +// Visual Studio (as of VS2017) considers BitField to not be trivially +// copyable if we delete this copy assignment operator. +// https://developercommunity.visualstudio.com/content/problem/101208/c-compiler-is-overly-strict-regarding-whether-a-cl.html +#ifndef _MSC_VER + // We explicitly delete the copy assignment operator here, because the + // default copy assignment would copy the full storage value, rather than + // just the bits relevant to this particular bit field. + // Ideally, we would just implement the copy assignment to copy only the + // relevant bits, but we're prevented from doing that because the savestate + // code expects that this class is trivially copyable. + BitFieldArray& operator=(const BitFieldArray&) = delete; +#endif + +public: + constexpr std::size_t StartBit() const { return position; } + constexpr std::size_t NumBits() const { return bits; } + constexpr std::size_t Size() const { return size; } + constexpr std::size_t TotalNumBits() const { return bits * size; } + + constexpr T Value(size_t index) const { return Value(std::is_signed(), index); } + void SetValue(size_t index, T value) + { + const size_t pos = position + bits * index; + storage = (storage & ~GetElementMask(index)) | + ((static_cast(value) << pos) & GetElementMask(index)); + } + Ref operator[](size_t index) { return Ref(this, index); } + constexpr const ConstRef operator[](size_t index) const { return ConstRef(this, index); } + + constexpr Iterator begin() { return Iterator(this, 0); } + constexpr Iterator end() { return Iterator(this, size); } + constexpr ConstIterator begin() const { return ConstIterator(this, 0); } + constexpr ConstIterator end() const { return ConstIterator(this, size); } + constexpr ConstIterator cbegin() const { return begin(); } + constexpr ConstIterator cend() const { return end(); } + +private: + // Unsigned version of StorageType + using StorageTypeU = std::make_unsigned_t; + + constexpr T Value(std::true_type, size_t index) const + { + const size_t pos = position + bits * index; + const size_t shift_amount = 8 * sizeof(StorageType) - bits; + return static_cast((storage << (shift_amount - pos)) >> shift_amount); + } + + constexpr T Value(std::false_type, size_t index) const + { + const size_t pos = position + bits * index; + return static_cast((storage & GetElementMask(index)) >> pos); + } + + static constexpr StorageType GetElementMask(size_t index) + { + const size_t pos = position + bits * index; + return (std::numeric_limits::max() >> (8 * sizeof(StorageType) - bits)) << pos; + } + + StorageType storage; + + static_assert(bits * size + position <= 8 * sizeof(StorageType), "Bitfield array out of range"); + static_assert(sizeof(T) <= sizeof(StorageType), "T must fit in StorageType"); + + // And, you know, just in case people specify something stupid like bits=position=0x80000000 + static_assert(position < 8 * sizeof(StorageType), "Invalid position"); + static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); + static_assert(bits > 0, "Invalid number of bits"); + static_assert(size <= 8 * sizeof(StorageType), "Invalid size"); + static_assert(size > 0, "Invalid size"); +}; +#pragma pack() + +template +class BitFieldArrayConstRef +{ + friend struct BitFieldArray; + friend class BitFieldArrayConstIterator; + +public: + constexpr T Value() const { return m_array->Value(m_index); }; + constexpr operator T() const { return Value(); } + +private: + constexpr BitFieldArrayConstRef(const BitFieldArray* array, + size_t index) + : m_array(array), m_index(index) + { + } + + const BitFieldArray* const m_array; + const size_t m_index; +}; + +template +class BitFieldArrayRef +{ + friend struct BitFieldArray; + friend class BitFieldArrayIterator; + +public: + constexpr T Value() const { return m_array->Value(m_index); }; + constexpr operator T() const { return Value(); } + T operator=(const BitFieldArrayRef& value) const + { + m_array->SetValue(m_index, value); + return value; + } + T operator=(T value) const + { + m_array->SetValue(m_index, value); + return value; + } + +private: + constexpr BitFieldArrayRef(BitFieldArray* array, size_t index) + : m_array(array), m_index(index) + { + } + + BitFieldArray* const m_array; + const size_t m_index; +}; + +// Satisfies LegacyOutputIterator / std::output_iterator. +// Does not satisfy LegacyInputIterator / std::input_iterator as std::output_iterator_tag does not +// extend std::input_iterator_tag. +// Does not satisfy LegacyForwardIterator / std::forward_iterator, as that requires use of real +// references instead of proxy objects. +// This iterator allows use of BitFieldArray in range-based for loops, and with fmt::join. +template +class BitFieldArrayIterator +{ + friend struct BitFieldArray; + +public: + using iterator_category = std::output_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = void; + using reference = BitFieldArrayRef; + +private: + constexpr BitFieldArrayIterator(BitFieldArray* array, size_t index) + : m_array(array), m_index(index) + { + } + +public: + // Required by std::input_or_output_iterator + constexpr BitFieldArrayIterator() = default; + // Required by LegacyIterator + constexpr BitFieldArrayIterator(const BitFieldArrayIterator& other) = default; + // Required by LegacyIterator + BitFieldArrayIterator& operator=(const BitFieldArrayIterator& other) = default; + // Move constructor and assignment operators, explicitly defined for completeness + constexpr BitFieldArrayIterator(BitFieldArrayIterator&& other) = default; + BitFieldArrayIterator& operator=(BitFieldArrayIterator&& other) = default; + +public: + BitFieldArrayIterator& operator++() + { + m_index++; + return *this; + } + BitFieldArrayIterator operator++(int) + { + BitFieldArrayIterator other(*this); + ++*this; + return other; + } + constexpr reference operator*() const { return reference(m_array, m_index); } + constexpr bool operator==(BitFieldArrayIterator other) const { return m_index == other.m_index; } + constexpr bool operator!=(BitFieldArrayIterator other) const { return m_index != other.m_index; } + +private: + BitFieldArray* m_array; + size_t m_index; +}; + +// Satisfies LegacyInputIterator / std::input_iterator. +// Does not satisfy LegacyForwardIterator / std::forward_iterator, as that requires use of real +// references instead of proxy objects. +// This iterator allows use of BitFieldArray in range-based for loops, and with fmt::join. +template +class BitFieldArrayConstIterator +{ + friend struct BitFieldArray; + +public: + using iterator_category = std::input_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = void; + using reference = BitFieldArrayConstRef; + +private: + constexpr BitFieldArrayConstIterator(const BitFieldArray* array, + size_t index) + : m_array(array), m_index(index) + { + } + +public: + // Required by std::input_or_output_iterator + constexpr BitFieldArrayConstIterator() = default; + // Required by LegacyIterator + constexpr BitFieldArrayConstIterator(const BitFieldArrayConstIterator& other) = default; + // Required by LegacyIterator + BitFieldArrayConstIterator& operator=(const BitFieldArrayConstIterator& other) = default; + // Move constructor and assignment operators, explicitly defined for completeness + constexpr BitFieldArrayConstIterator(BitFieldArrayConstIterator&& other) = default; + BitFieldArrayConstIterator& operator=(BitFieldArrayConstIterator&& other) = default; + +public: + BitFieldArrayConstIterator& operator++() + { + m_index++; + return *this; + } + BitFieldArrayConstIterator operator++(int) + { + BitFieldArrayConstIterator other(*this); + ++*this; + return other; + } + constexpr reference operator*() const { return reference(m_array, m_index); } + constexpr bool operator==(BitFieldArrayConstIterator other) const + { + return m_index == other.m_index; + } + constexpr bool operator!=(BitFieldArrayConstIterator other) const + { + return m_index != other.m_index; + } + +private: + const BitFieldArray* m_array; + size_t m_index; +}; + +template +struct fmt::formatter> +{ + fmt::formatter m_formatter; + constexpr auto parse(format_parse_context& ctx) { return m_formatter.parse(ctx); } + template + auto format(const BitFieldArrayRef& ref, FormatContext& ctx) + { + return m_formatter.format(ref.Value(), ctx); + } +}; + +template +struct fmt::formatter> +{ + fmt::formatter m_formatter; + constexpr auto parse(format_parse_context& ctx) { return m_formatter.parse(ctx); } + template + auto format(const BitFieldArrayConstRef& ref, FormatContext& ctx) + { + return m_formatter.format(ref.Value(), ctx); + } +}; diff --git a/Source/UnitTests/Common/BitFieldTest.cpp b/Source/UnitTests/Common/BitFieldTest.cpp index d68b18b4c6..e7a7bb764c 100644 --- a/Source/UnitTests/Common/BitFieldTest.cpp +++ b/Source/UnitTests/Common/BitFieldTest.cpp @@ -251,3 +251,295 @@ TEST(BitField, Fmt) EXPECT_EQ(fmt::format("{:s}", object.enum_2), fmt::format("{:s}", object.enum_2.Value())); } } + +union TestUnion2 +{ + u32 hex; + BitField<0, 2, u32> a; + BitField<2, 2, u32> b; + BitField<4, 2, u32> c; + BitFieldArray<0, 2, 3, u32> arr; +}; + +TEST(BitFieldArray, Unsigned) +{ + TestUnion2 object; + object.hex = 0; + const TestUnion2& objectc = object; + + for (u32 value : object.arr) + { + EXPECT_EQ(value, 0u); + } + + object.arr[0] = 2; + EXPECT_EQ(object.arr[0], 2u); + EXPECT_EQ(object.a, 2u); + EXPECT_EQ(object.hex, 0b00'00'10u); + + object.arr[1] = 3; + EXPECT_EQ(object.arr[1], 3u); + EXPECT_EQ(object.b, 3u); + EXPECT_EQ(object.hex, 0b00'11'10u); + + object.arr[2] = object.arr[1]; + EXPECT_EQ(object.arr[2], 3u); + EXPECT_EQ(object.c, 3u); + EXPECT_EQ(object.hex, 0b11'11'10u); + + object.arr[1] = objectc.arr[0]; + EXPECT_EQ(object.arr[1], 2u); + EXPECT_EQ(object.b, 2u); + EXPECT_EQ(object.hex, 0b11'10'10u); + + for (auto ref : object.arr) + { + ref = 1; + } + EXPECT_EQ(object.a, 1u); + EXPECT_EQ(object.b, 1u); + EXPECT_EQ(object.c, 1u); + EXPECT_EQ(object.hex, 0b01'01'01u); + + std::fill_n(object.arr.begin(), object.arr.Size(), 3); + EXPECT_EQ(object.arr[0], 3u); + EXPECT_EQ(object.arr[1], 3u); + EXPECT_EQ(object.arr[2], 3u); + EXPECT_EQ(object.hex, 0b11'11'11u); + + for (u32 i = 0; i < object.arr.Size(); i++) + { + object.arr[i] = i; + } + EXPECT_EQ(object.hex, 0b10'01'00u); + + EXPECT_EQ(objectc.arr[0], 0u); + EXPECT_EQ(objectc.arr[1], 1u); + EXPECT_EQ(objectc.arr[2], 2u); + + u32 counter = 0; + for (u32 value : objectc.arr) + { + EXPECT_EQ(value, counter); + counter++; + } + + EXPECT_EQ("[0, 1, 2]", fmt::format("[{}]", fmt::join(object.arr, ", "))); + EXPECT_EQ("[0b00, 0b01, 0b10]", fmt::format("[{:#04b}]", fmt::join(object.arr, ", "))); +} + +union TestUnion3 +{ + s32 hex; + BitField<5, 2, s32> a; + BitField<7, 2, s32> b; + BitField<9, 2, s32> c; + BitFieldArray<5, 2, 3, s32> arr; +}; + +TEST(BitFieldArray, Signed) +{ + TestUnion3 object; + object.hex = 0; + const TestUnion3& objectc = object; + + for (s32 value : object.arr) + { + EXPECT_EQ(value, 0); + } + + object.arr[0] = -2; + EXPECT_EQ(object.arr[0], -2); + EXPECT_EQ(object.a, -2); + EXPECT_EQ(object.hex, 0b00'00'10'00000); + + object.arr[1] = -1; + EXPECT_EQ(object.arr[1], -1); + EXPECT_EQ(object.b, -1); + EXPECT_EQ(object.hex, 0b00'11'10'00000); + + object.arr[2] = object.arr[1]; + EXPECT_EQ(object.arr[2], -1); + EXPECT_EQ(object.c, -1); + EXPECT_EQ(object.hex, 0b11'11'10'00000); + + object.arr[1] = objectc.arr[0]; + EXPECT_EQ(object.arr[1], -2); + EXPECT_EQ(object.b, -2); + EXPECT_EQ(object.hex, 0b11'10'10'00000); + + for (auto ref : object.arr) + { + ref = 1; + } + EXPECT_EQ(object.a, 1); + EXPECT_EQ(object.b, 1); + EXPECT_EQ(object.c, 1); + EXPECT_EQ(object.hex, 0b01'01'01'00000); + + std::fill_n(object.arr.begin(), object.arr.Size(), -1); + EXPECT_EQ(object.arr[0], -1); + EXPECT_EQ(object.arr[1], -1); + EXPECT_EQ(object.arr[2], -1); + EXPECT_EQ(object.hex, 0b11'11'11'00000); + + for (u32 i = 0; i < object.arr.Size(); i++) + { + object.arr[i] = i; + } + EXPECT_EQ(object.hex, 0b10'01'00'00000); + + EXPECT_EQ(objectc.arr[0], 0); + EXPECT_EQ(objectc.arr[1], 1); + EXPECT_EQ(objectc.arr[2], -2); + + u32 counter = 0; + for (s32 value : objectc.arr) + { + EXPECT_EQ(value, object.arr[counter++]); + } + + EXPECT_EQ("[0, 1, -2]", fmt::format("[{}]", fmt::join(object.arr, ", "))); + EXPECT_EQ("[+0b00, +0b01, -0b10]", fmt::format("[{:+#05b}]", fmt::join(object.arr, ", "))); +} + +union TestUnion4 +{ + u64 hex; + BitField<30, 2, TestEnum> a; + BitField<32, 2, TestEnum> b; + BitField<34, 2, TestEnum> c; + BitField<36, 2, TestEnum> d; + BitFieldArray<30, 2, 4, TestEnum> arr; +}; + +TEST(BitFieldArray, Enum) +{ + TestUnion4 object; + object.hex = 0; + const TestUnion4& objectc = object; + + for (TestEnum value : object.arr) + { + EXPECT_EQ(value, TestEnum::A); + } + + object.arr[0] = TestEnum::B; + EXPECT_EQ(object.arr[0], TestEnum::B); + EXPECT_EQ(object.a, TestEnum::B); + EXPECT_EQ(object.hex, 0b00'00'00'01ull << 30); + + object.arr[1] = TestEnum::C; + EXPECT_EQ(object.arr[1], TestEnum::C); + EXPECT_EQ(object.b, TestEnum::C); + EXPECT_EQ(object.hex, 0b00'00'10'01ull << 30); + + object.arr[2] = object.arr[1]; + EXPECT_EQ(object.arr[2], TestEnum::C); + EXPECT_EQ(object.c, TestEnum::C); + EXPECT_EQ(object.hex, 0b00'10'10'01ull << 30); + + object.arr[3] = objectc.arr[0]; + EXPECT_EQ(object.arr[3], TestEnum::B); + EXPECT_EQ(object.d, TestEnum::B); + EXPECT_EQ(object.hex, 0b01'10'10'01ull << 30); + + for (auto ref : object.arr) + { + ref = TestEnum::D; + } + EXPECT_EQ(object.a, TestEnum::D); + EXPECT_EQ(object.b, TestEnum::D); + EXPECT_EQ(object.c, TestEnum::D); + EXPECT_EQ(object.d, TestEnum::D); + EXPECT_EQ(object.hex, 0b11'11'11'11ull << 30); + + std::fill_n(object.arr.begin(), object.arr.Size(), TestEnum::C); + EXPECT_EQ(object.a, TestEnum::C); + EXPECT_EQ(object.b, TestEnum::C); + EXPECT_EQ(object.c, TestEnum::C); + EXPECT_EQ(object.d, TestEnum::C); + EXPECT_EQ(object.hex, 0b10'10'10'10ull << 30); + + for (u32 i = 0; i < object.arr.Size(); i++) + { + object.arr[i] = static_cast(i); + } + EXPECT_EQ(object.hex, 0b11'10'01'00ull << 30); + + EXPECT_EQ(objectc.arr[0], TestEnum::A); + EXPECT_EQ(objectc.arr[1], TestEnum::B); + EXPECT_EQ(objectc.arr[2], TestEnum::C); + EXPECT_EQ(objectc.arr[3], TestEnum::D); + + u32 counter = 0; + for (TestEnum value : objectc.arr) + { + EXPECT_EQ(value, object.arr[counter++]); + } + + EXPECT_EQ("[A (0), B (1), C (2), D (3)]", fmt::format("[{}]", fmt::join(object.arr, ", "))); + EXPECT_EQ("[0x0u /* A */, 0x1u /* B */, 0x2u /* C */, 0x3u /* D */]", + fmt::format("[{:s}]", fmt::join(object.arr, ", "))); +} + +union TestUnion5 +{ + u64 hex; + BitFieldArray<0, 5, 6, u8, u64> arr1; + BitFieldArray<30, 1, 4, bool, u64> arr2; +}; + +TEST(BitFieldArray, StorageType) +{ + TestUnion5 object; + const u64 arr2_hex_1 = 0b1010ull << 30; + object.hex = arr2_hex_1; + const TestUnion5& objectc = object; + + EXPECT_FALSE(object.arr2[0]); + EXPECT_TRUE(object.arr2[1]); + EXPECT_FALSE(object.arr2[2]); + EXPECT_TRUE(object.arr2[3]); + + object.arr1[0] = 0; + object.arr1[1] = 1; + object.arr1[2] = 2; + object.arr1[3] = 4; + object.arr1[4] = 8; + object.arr1[5] = 16; + const u64 arr1_hex = 0b10000'01000'00100'00010'00001'00000; + EXPECT_EQ(object.hex, arr1_hex | arr2_hex_1); + + object.arr2[2] = object.arr2[0] = true; + object.arr2[3] = object.arr2[1] = false; + const u64 arr2_hex_2 = 0b0101ull << 30; + EXPECT_EQ(object.hex, arr1_hex | arr2_hex_2); + + object.arr2[2] = object.arr2[1]; + object.arr2[3] = objectc.arr2[0]; + const u64 arr2_hex_3 = 0b1001ull << 30; + EXPECT_EQ(object.hex, arr1_hex | arr2_hex_3); + + u32 counter = 0; + for (u8 value : object.arr1) + { + EXPECT_EQ(value, object.arr1[counter++]); + } + counter = 0; + for (bool value : object.arr2) + { + EXPECT_EQ(value, object.arr2[counter++]); + } + + counter = 0; + for (u8 value : objectc.arr1) + { + EXPECT_EQ(value, object.arr1[counter++]); + } + counter = 0; + for (bool value : objectc.arr2) + { + EXPECT_EQ(value, object.arr2[counter++]); + } +} From d702f3b4ad803735d9bb709ef050ba5ebc35b1db Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Thu, 11 Feb 2021 22:48:46 -0800 Subject: [PATCH 05/17] DolphinNoGUI/PlatformX11: Work around X.h's None being undefined --- Source/Core/DolphinNoGUI/PlatformX11.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/Core/DolphinNoGUI/PlatformX11.cpp b/Source/Core/DolphinNoGUI/PlatformX11.cpp index b44620a048..f09a16ba1a 100644 --- a/Source/Core/DolphinNoGUI/PlatformX11.cpp +++ b/Source/Core/DolphinNoGUI/PlatformX11.cpp @@ -4,6 +4,12 @@ #include +// X.h defines None to be 0L, but other parts of Dolphin undef that so that +// None can be used in enums. Work around that here by copying the definition +// before it is undefined. +#include +static constexpr auto X_None = None; + #include "DolphinNoGUI/Platform.h" #include "Common/MsgHandler.h" @@ -47,7 +53,7 @@ private: Display* m_display = nullptr; Window m_window = {}; - Cursor m_blank_cursor = None; + Cursor m_blank_cursor = X_None; #ifdef HAVE_XRANDR X11Utils::XRRConfiguration* m_xrr_config = nullptr; #endif From c27efb3f1fefa49db7962532865fbbe483f248f1 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sun, 28 Feb 2021 13:53:32 -0800 Subject: [PATCH 06/17] Create constants for CP registers and masks --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 22 +++--- Source/Core/VideoCommon/CPMemory.h | 40 +++++++++- .../Core/VideoCommon/VertexLoaderManager.cpp | 77 +++++++++++-------- 3 files changed, 90 insertions(+), 49 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index b2d95a5fe1..0ed9c94630 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -467,22 +467,22 @@ void FifoPlayer::LoadRegisters() } regs = m_File->GetCPMem(); - LoadCPReg(0x30, regs[0x30]); - LoadCPReg(0x40, regs[0x40]); - LoadCPReg(0x50, regs[0x50]); - LoadCPReg(0x60, regs[0x60]); + LoadCPReg(MATINDEX_A, regs[MATINDEX_A]); + LoadCPReg(MATINDEX_B, regs[MATINDEX_B]); + LoadCPReg(VCD_LO, regs[VCD_LO]); + LoadCPReg(VCD_HI, regs[VCD_HI]); - for (int i = 0; i < 8; ++i) + for (int i = 0; i < CP_NUM_VAT_REG; ++i) { - LoadCPReg(0x70 + i, regs[0x70 + i]); - LoadCPReg(0x80 + i, regs[0x80 + i]); - LoadCPReg(0x90 + i, regs[0x90 + i]); + LoadCPReg(CP_VAT_REG_A + i, regs[CP_VAT_REG_A + i]); + LoadCPReg(CP_VAT_REG_B + i, regs[CP_VAT_REG_B + i]); + LoadCPReg(CP_VAT_REG_C + i, regs[CP_VAT_REG_C + i]); } - for (int i = 0; i < 16; ++i) + for (int i = 0; i < CP_NUM_ARRAYS; ++i) { - LoadCPReg(0xa0 + i, regs[0xa0 + i]); - LoadCPReg(0xb0 + i, regs[0xb0 + i]); + LoadCPReg(ARRAY_BASE + i, regs[ARRAY_BASE + i]); + LoadCPReg(ARRAY_STRIDE + i, regs[ARRAY_STRIDE + i]); } regs = m_File->GetXFMem(); diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h index aeab4977b2..03794a7e0d 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -7,6 +7,38 @@ #include "Common/BitSet.h" #include "Common/CommonTypes.h" +enum +{ + // These commands use the high nybble for the command itself, and the lower nybble is an argument. + // TODO: However, Dolphin's implementation (in LoadCPReg) and YAGCD disagree about what values are + // valid for the lower nybble. + + // YAGCD says 0x30 only; LoadCPReg allows any + MATINDEX_A = 0x30, + // YAGCD says 0x40 only; LoadCPReg allows any + MATINDEX_B = 0x40, + // YAGCD says 0x50-0x57 for distinct VCDs; LoadCPReg allows any for a single VCD + VCD_LO = 0x50, + // YAGCD says 0x60-0x67 for distinct VCDs; LoadCPReg allows any for a single VCD + VCD_HI = 0x60, + // YAGCD and LoadCPReg both agree that only 0x70-0x77 are valid + CP_VAT_REG_A = 0x70, + // YAGCD and LoadCPReg both agree that only 0x80-0x87 are valid + CP_VAT_REG_B = 0x80, + // YAGCD and LoadCPReg both agree that only 0x90-0x97 are valid + CP_VAT_REG_C = 0x90, + // YAGCD and LoadCPReg agree that 0xa0-0xaf are valid + ARRAY_BASE = 0xa0, + // YAGCD and LoadCPReg agree that 0xb0-0xbf are valid + ARRAY_STRIDE = 0xb0, + + CP_COMMAND_MASK = 0xf0, + CP_NUM_VAT_REG = 0x08, + CP_VAT_MASK = 0x07, + CP_NUM_ARRAYS = 0x10, + CP_ARRAY_MASK = 0x0f, +}; + // Vertex array numbers enum { @@ -242,18 +274,18 @@ class VertexLoaderBase; // STATE_TO_SAVE struct CPState final { - u32 array_bases[16]; - u32 array_strides[16]; + u32 array_bases[CP_NUM_ARRAYS]; + u32 array_strides[CP_NUM_ARRAYS]; TMatrixIndexA matrix_index_a; TMatrixIndexB matrix_index_b; TVtxDesc vtx_desc; // Most games only use the first VtxAttr and simply reconfigure it all the time as needed. - VAT vtx_attr[8]; + VAT vtx_attr[CP_NUM_VAT_REG]; // Attributes that actually belong to VertexLoaderManager: BitSet32 attr_dirty; bool bases_dirty; - VertexLoaderBase* vertex_loaders[8]; + VertexLoaderBase* vertex_loaders[CP_NUM_VAT_REG]; int last_id; }; diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index bcbf64d3d4..93322de512 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -15,9 +15,11 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Core/HW/Memmap.h" #include "VideoCommon/BPMemory.h" +#include "VideoCommon/CPMemory.h" #include "VideoCommon/CommandProcessor.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/IndexGenerator.h" @@ -302,79 +304,86 @@ void LoadCPReg(u32 sub_cmd, u32 value, bool is_preprocess) { bool update_global_state = !is_preprocess; CPState* state = is_preprocess ? &g_preprocess_cp_state : &g_main_cp_state; - switch (sub_cmd & 0xF0) + switch (sub_cmd & CP_COMMAND_MASK) { - case 0x30: + case MATINDEX_A: if (update_global_state) VertexShaderManager::SetTexMatrixChangedA(value); break; - case 0x40: + case MATINDEX_B: if (update_global_state) VertexShaderManager::SetTexMatrixChangedB(value); break; - case 0x50: + case VCD_LO: state->vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits state->vtx_desc.Hex |= value; - state->attr_dirty = BitSet32::AllTrue(8); + state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG); state->bases_dirty = true; break; - case 0x60: + case VCD_HI: state->vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits state->vtx_desc.Hex |= (u64)value << 17; - state->attr_dirty = BitSet32::AllTrue(8); + state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG); state->bases_dirty = true; break; - case 0x70: - ASSERT((sub_cmd & 0x0F) < 8); - state->vtx_attr[sub_cmd & 7].g0.Hex = value; - state->attr_dirty[sub_cmd & 7] = true; + case CP_VAT_REG_A: + if ((sub_cmd - CP_VAT_REG_A) >= CP_NUM_VAT_REG) + WARN_LOG_FMT(VIDEO, "CP_VAT_REG_A: Invalid VAT {}", sub_cmd - CP_VAT_REG_A); + state->vtx_attr[sub_cmd & CP_VAT_MASK].g0.Hex = value; + state->attr_dirty[sub_cmd & CP_VAT_MASK] = true; break; - case 0x80: - ASSERT((sub_cmd & 0x0F) < 8); - state->vtx_attr[sub_cmd & 7].g1.Hex = value; - state->attr_dirty[sub_cmd & 7] = true; + case CP_VAT_REG_B: + if ((sub_cmd - CP_VAT_REG_B) >= CP_NUM_VAT_REG) + WARN_LOG_FMT(VIDEO, "CP_VAT_REG_B: Invalid VAT {}", sub_cmd - CP_VAT_REG_B); + state->vtx_attr[sub_cmd & CP_VAT_MASK].g1.Hex = value; + state->attr_dirty[sub_cmd & CP_VAT_MASK] = true; break; - case 0x90: - ASSERT((sub_cmd & 0x0F) < 8); - state->vtx_attr[sub_cmd & 7].g2.Hex = value; - state->attr_dirty[sub_cmd & 7] = true; + case CP_VAT_REG_C: + if ((sub_cmd - CP_VAT_REG_C) >= CP_NUM_VAT_REG) + WARN_LOG_FMT(VIDEO, "CP_VAT_REG_C: Invalid VAT {}", sub_cmd - CP_VAT_REG_C); + state->vtx_attr[sub_cmd & CP_VAT_MASK].g2.Hex = value; + state->attr_dirty[sub_cmd & CP_VAT_MASK] = true; break; // Pointers to vertex arrays in GC RAM - case 0xA0: - state->array_bases[sub_cmd & 0xF] = value & CommandProcessor::GetPhysicalAddressMask(); + case ARRAY_BASE: + state->array_bases[sub_cmd & CP_ARRAY_MASK] = + value & CommandProcessor::GetPhysicalAddressMask(); state->bases_dirty = true; break; - case 0xB0: - state->array_strides[sub_cmd & 0xF] = value & 0xFF; + case ARRAY_STRIDE: + state->array_strides[sub_cmd & CP_ARRAY_MASK] = value & 0xFF; break; + + default: + WARN_LOG_FMT(VIDEO, "Unknown CP register {:02x} set to {:08x}", sub_cmd, value); } } void FillCPMemoryArray(u32* memory) { - memory[0x30] = g_main_cp_state.matrix_index_a.Hex; - memory[0x40] = g_main_cp_state.matrix_index_b.Hex; - memory[0x50] = (u32)g_main_cp_state.vtx_desc.Hex; - memory[0x60] = (u32)(g_main_cp_state.vtx_desc.Hex >> 17); + 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); - for (int i = 0; i < 8; ++i) + for (int i = 0; i < CP_NUM_VAT_REG; ++i) { - memory[0x70 + i] = g_main_cp_state.vtx_attr[i].g0.Hex; - memory[0x80 + i] = g_main_cp_state.vtx_attr[i].g1.Hex; - memory[0x90 + i] = g_main_cp_state.vtx_attr[i].g2.Hex; + memory[CP_VAT_REG_A + i] = g_main_cp_state.vtx_attr[i].g0.Hex; + memory[CP_VAT_REG_B + i] = g_main_cp_state.vtx_attr[i].g1.Hex; + memory[CP_VAT_REG_C + i] = g_main_cp_state.vtx_attr[i].g2.Hex; } - for (int i = 0; i < 16; ++i) + for (int i = 0; i < CP_NUM_ARRAYS; ++i) { - memory[0xA0 + i] = g_main_cp_state.array_bases[i]; - memory[0xB0 + i] = g_main_cp_state.array_strides[i]; + memory[ARRAY_BASE + i] = g_main_cp_state.array_bases[i]; + memory[ARRAY_STRIDE + i] = g_main_cp_state.array_strides[i]; } } From f749fcfa9f42cda679ff7f4288c8418d2b56b08d Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Mon, 8 Feb 2021 15:22:10 -0800 Subject: [PATCH 07/17] 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. --- Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp | 58 ++- .../Core/FifoPlayer/FifoRecordAnalyzer.cpp | 21 +- .../VideoBackends/Software/SWVertexLoader.cpp | 4 +- Source/Core/VideoCommon/CPMemory.cpp | 4 +- Source/Core/VideoCommon/CPMemory.h | 385 +++++++++++------- Source/Core/VideoCommon/VertexLoader.cpp | 148 ++++--- Source/Core/VideoCommon/VertexLoaderARM64.cpp | 145 ++++--- Source/Core/VideoCommon/VertexLoaderARM64.h | 14 +- Source/Core/VideoCommon/VertexLoaderBase.cpp | 64 +-- Source/Core/VideoCommon/VertexLoaderBase.h | 4 +- .../Core/VideoCommon/VertexLoaderManager.cpp | 33 +- Source/Core/VideoCommon/VertexLoaderX64.cpp | 125 +++--- Source/Core/VideoCommon/VertexLoaderX64.h | 13 +- .../Core/VideoCommon/VertexLoader_Normal.cpp | 11 +- Source/Core/VideoCommon/VertexLoader_Normal.h | 10 +- .../VideoCommon/VertexLoader_Position.cpp | 11 +- .../Core/VideoCommon/VertexLoader_Position.h | 10 +- .../VideoCommon/VertexLoader_TextCoord.cpp | 11 +- .../Core/VideoCommon/VertexLoader_TextCoord.h | 10 +- .../Core/VideoCommon/VertexShaderManager.cpp | 6 +- .../VideoCommon/VertexLoaderTest.cpp | 221 +++++----- 21 files changed, 705 insertions(+), 603 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp index 35305bcff3..bf435d32b2 100644 --- a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp @@ -49,21 +49,17 @@ std::array CalculateVertexElementSizes(int vatIndex, const CPMemory& cp const VAT& vtxAttr = cpMem.vtxAttr[vatIndex]; // Colors - const std::array colDesc{ - vtxDesc.Color0, - vtxDesc.Color1, - }; - const std::array colComp{ + const std::array colComp{ vtxAttr.g0.Color0Comp, vtxAttr.g0.Color1Comp, }; - const std::array tcElements{ + const std::array 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 tcFormat{ + const std::array 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 CalculateVertexElementSizes(int vatIndex, const CPMemory& cp std::array 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 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 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 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: diff --git a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp index 284ecba620..992df015a9 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp @@ -6,6 +6,7 @@ #include +#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) { diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp index 3e90f69614..fdcafc71bf 100644 --- a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp +++ b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp @@ -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; diff --git a/Source/Core/VideoCommon/CPMemory.cpp b/Source/Core/VideoCommon/CPMemory.cpp index 52384cddaf..b4d118bbb4 100644 --- a/Source/Core/VideoCommon/CPMemory.cpp +++ b/Source/Core/VideoCommon/CPMemory.cpp @@ -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) diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h index 03794a7e0d..83550eb5f2 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -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 : EnumFormatter +{ + 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 : EnumFormatter +{ + 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 : EnumFormatter +{ + formatter() : EnumFormatter({"2 (x, y)", "3 (x, y, z)"}) {} +}; + +enum class NormalComponentCount +{ + N = 0, + NBT = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"1 (n)", "3 (n, b, t)"}) {} +}; + +enum class ColorComponentCount +{ + RGB = 0, + RGBA = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + 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 : EnumFormatter +{ + 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 : EnumFormatter +{ + 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(GetLegacyHex()); } + // Only *1* bit is used in this + u32 GetLegacyHex1() const { return static_cast(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; diff --git a/Source/Core/VideoCommon/VertexLoader.cpp b/Source/Core/VideoCommon/VertexLoader.cpp index d3584ddbeb..f06b60a430 100644 --- a/Source/Core/VideoCommon/VertexLoader.cpp +++ b/Source/Core/VideoCommon/VertexLoader.cpp @@ -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); } diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.cpp b/Source/Core/VideoCommon/VertexLoaderARM64.cpp index 06c3fe2340..f56314f6c1 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderARM64.cpp @@ -3,6 +3,9 @@ // Refer to the license.txt file included. #include "VideoCommon/VertexLoaderARM64.h" + +#include + #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 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); diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.h b/Source/Core/VideoCommon/VertexLoaderARM64.h index 3df60a9685..b7faec0239 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.h +++ b/Source/Core/VideoCommon/VertexLoaderARM64.h @@ -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(); }; diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index c5baa503e6..483d46dd08 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -81,64 +81,33 @@ std::string VertexLoaderBase::ToString() const dest += GetName(); dest += ": "; - static constexpr std::array pos_mode{{ - "Inv", - "Dir", - "I8", - "I16", - }}; - static constexpr std::array pos_formats{{ - "u8", - "s8", - "u16", - "s16", - "flt", - "Inv", - "Inv", - "Inv", - }}; - static constexpr std::array 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 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 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); diff --git a/Source/Core/VideoCommon/VertexLoaderBase.h b/Source/Core/VideoCommon/VertexLoaderBase.h index 29b53d3c58..77b66f629b 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.h +++ b/Source/Core/VideoCommon/VertexLoaderBase.h @@ -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; diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index 93322de512..4dcc211178 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -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) { diff --git a/Source/Core/VideoCommon/VertexLoaderX64.cpp b/Source/Core/VideoCommon/VertexLoaderX64.cpp index 96832e3449..44d85c42e4 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderX64.cpp @@ -2,6 +2,9 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoCommon/VertexLoaderX64.h" + +#include #include #include @@ -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 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(); diff --git a/Source/Core/VideoCommon/VertexLoaderX64.h b/Source/Core/VideoCommon/VertexLoaderX64.h index 8bd1e777ff..0344d7f1c9 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.h +++ b/Source/Core/VideoCommon/VertexLoaderX64.h @@ -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(); }; diff --git a/Source/Core/VideoCommon/VertexLoader_Normal.cpp b/Source/Core/VideoCommon/VertexLoader_Normal.cpp index b5caee8a72..c59b3bc13e 100644 --- a/Source/Core/VideoCommon/VertexLoader_Normal.cpp +++ b/Source/Core/VideoCommon/VertexLoader_Normal.cpp @@ -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; } diff --git a/Source/Core/VideoCommon/VertexLoader_Normal.h b/Source/Core/VideoCommon/VertexLoader_Normal.h index c2f782af7a..49aa1defa2 100644 --- a/Source/Core/VideoCommon/VertexLoader_Normal.h +++ b/Source/Core/VideoCommon/VertexLoader_Normal.h @@ -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); }; diff --git a/Source/Core/VideoCommon/VertexLoader_Position.cpp b/Source/Core/VideoCommon/VertexLoader_Position.cpp index 9808c76e65..6bdbb39d35 100644 --- a/Source/Core/VideoCommon/VertexLoader_Position.cpp +++ b/Source/Core/VideoCommon/VertexLoader_Position.cpp @@ -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)]; } diff --git a/Source/Core/VideoCommon/VertexLoader_Position.h b/Source/Core/VideoCommon/VertexLoader_Position.h index a38d277278..74208c2f8d 100644 --- a/Source/Core/VideoCommon/VertexLoader_Position.h +++ b/Source/Core/VideoCommon/VertexLoader_Position.h @@ -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); }; diff --git a/Source/Core/VideoCommon/VertexLoader_TextCoord.cpp b/Source/Core/VideoCommon/VertexLoader_TextCoord.cpp index 26c1c7f256..7f1de2f487 100644 --- a/Source/Core/VideoCommon/VertexLoader_TextCoord.cpp +++ b/Source/Core/VideoCommon/VertexLoader_TextCoord.cpp @@ -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() diff --git a/Source/Core/VideoCommon/VertexLoader_TextCoord.h b/Source/Core/VideoCommon/VertexLoader_TextCoord.h index 48b9a8e136..dc5e62f648 100644 --- a/Source/Core/VideoCommon/VertexLoader_TextCoord.h +++ b/Source/Core/VideoCommon/VertexLoader_TextCoord.h @@ -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(); diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index 9c82d9b431..121d6f1a21 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -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; diff --git a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp index 666476dfce..bb09b1608e 100644 --- a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp +++ b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp @@ -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 m_loader; }; -class VertexLoaderParamTest : public VertexLoaderTest, - public ::testing::WithParamInterface> +class VertexLoaderParamTest + : public VertexLoaderTest, + public ::testing::WithParamInterface< + std::tuple> { }; -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 values = { std::numeric_limits::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(i); else Input(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(1); Input(0); @@ -246,47 +253,49 @@ TEST_F(VertexLoaderTest, PositionIndex16FloatXY) } class VertexLoaderSpeedTest : public VertexLoaderTest, - public ::testing::WithParamInterface> + public ::testing::WithParamInterface> { }; -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(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(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(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(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); From 953e09428fac6384038c80b7337a71dbb8c00fbb Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Mon, 8 Feb 2021 15:22:48 -0800 Subject: [PATCH 08/17] Add names and descriptions for CP registers to the FIFO analyzer --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 21 ++- Source/Core/VideoCommon/CPMemory.cpp | 41 +++++ Source/Core/VideoCommon/CPMemory.h | 173 ++++++++++++++++++++ 3 files changed, 233 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 8e806bef6f..4db865b069 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -23,6 +23,7 @@ #include "DolphinQt/Settings.h" #include "VideoCommon/BPMemory.h" +#include "VideoCommon/CPMemory.h" #include "VideoCommon/OpcodeDecoding.h" constexpr int FRAME_ROLE = Qt::UserRole; @@ -224,10 +225,13 @@ void FIFOAnalyzer::UpdateDetails() u32 cmd2 = *objectdata++; u32 value = Common::swap32(objectdata); objectdata += 4; + const auto [name, desc] = GetCPRegInfo(cmd2, value); + ASSERT(!name.empty()); - new_label = QStringLiteral("CP %1 %2") + new_label = QStringLiteral("CP %1 %2 %3") .arg(cmd2, 2, 16, QLatin1Char('0')) - .arg(value, 8, 16, QLatin1Char('0')); + .arg(value, 8, 16, QLatin1Char('0')) + .arg(QString::fromStdString(name)); } break; @@ -484,7 +488,20 @@ void FIFOAnalyzer::UpdateDescription() } else if (*cmddata == OpcodeDecoder::GX_LOAD_CP_REG) { + const u8 cmd = *(cmddata + 1); + const u32 value = Common::swap32(cmddata + 2); + + const auto [name, desc] = GetCPRegInfo(cmd, value); + ASSERT(!name.empty()); + text = tr("CP register "); + text += QString::fromStdString(name); + text += QLatin1Char{'\n'}; + + if (desc.empty()) + text += tr("No description available"); + else + text += QString::fromStdString(desc); } else if (*cmddata == OpcodeDecoder::GX_LOAD_XF_REG) { diff --git a/Source/Core/VideoCommon/CPMemory.cpp b/Source/Core/VideoCommon/CPMemory.cpp index b4d118bbb4..eb59869368 100644 --- a/Source/Core/VideoCommon/CPMemory.cpp +++ b/Source/Core/VideoCommon/CPMemory.cpp @@ -33,3 +33,44 @@ void CopyPreprocessCPStateFromMain() { memcpy(&g_preprocess_cp_state, &g_main_cp_state, sizeof(CPState)); } + +std::pair GetCPRegInfo(u8 cmd, u32 value) +{ + switch (cmd & CP_COMMAND_MASK) + { + case MATINDEX_A: + return std::make_pair("MATINDEX_A", fmt::to_string(TMatrixIndexA{.Hex = value})); + case MATINDEX_B: + return std::make_pair("MATINDEX_B", fmt::to_string(TMatrixIndexB{.Hex = value})); + case VCD_LO: + return std::make_pair("VCD_LO", fmt::to_string(TVtxDesc::Low{.Hex = value})); + case VCD_HI: + return std::make_pair("VCD_HI", fmt::to_string(TVtxDesc::High{.Hex = value})); + case CP_VAT_REG_A: + if (cmd - CP_VAT_REG_A >= CP_NUM_VAT_REG) + return std::make_pair("CP_VAT_REG_A invalid", ""); + + return std::make_pair(fmt::format("CP_VAT_REG_A - Format {}", cmd & CP_VAT_MASK), + fmt::to_string(UVAT_group0{.Hex = value})); + case CP_VAT_REG_B: + if (cmd - CP_VAT_REG_B >= CP_NUM_VAT_REG) + return std::make_pair("CP_VAT_REG_B invalid", ""); + + return std::make_pair(fmt::format("CP_VAT_REG_B - Format {}", cmd & CP_VAT_MASK), + fmt::to_string(UVAT_group1{.Hex = value})); + case CP_VAT_REG_C: + if (cmd - CP_VAT_REG_C >= CP_NUM_VAT_REG) + return std::make_pair("CP_VAT_REG_C invalid", ""); + + return std::make_pair(fmt::format("CP_VAT_REG_C - Format {}", cmd & CP_VAT_MASK), + fmt::to_string(UVAT_group2{.Hex = value})); + case ARRAY_BASE: + return std::make_pair(fmt::format("ARRAY_BASE Array {}", cmd & CP_ARRAY_MASK), + fmt::format("Base address {:08x}", value)); + case ARRAY_STRIDE: + return std::make_pair(fmt::format("ARRAY_STRIDE Array {}", cmd - ARRAY_STRIDE), + fmt::format("Stride {:02x}", value & 0xff)); + default: + return std::make_pair(fmt::format("Invalid CP register {:02x} = {:08x}", cmd, value), ""); + } +} diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h index 83550eb5f2..3b22992f15 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -4,6 +4,10 @@ #pragma once +#include +#include +#include + #include "Common/BitField.h" #include "Common/BitSet.h" #include "Common/CommonTypes.h" @@ -222,6 +226,65 @@ struct TVtxDesc high.Hex = value >> 17; } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TVtxDesc::Low& desc, FormatContext& ctx) + { + static constexpr std::array present = {"Not present", "Present"}; + + return format_to(ctx.out(), + "Position and normal matrix index: {}\n" + "Texture Coord 0 matrix index: {}\n" + "Texture Coord 1 matrix index: {}\n" + "Texture Coord 2 matrix index: {}\n" + "Texture Coord 3 matrix index: {}\n" + "Texture Coord 4 matrix index: {}\n" + "Texture Coord 5 matrix index: {}\n" + "Texture Coord 6 matrix index: {}\n" + "Texture Coord 7 matrix index: {}\n" + "Position: {}\n" + "Normal: {}\n" + "Color 0: {}\n" + "Color 1: {}", + present[desc.PosMatIdx], present[desc.Tex0MatIdx], present[desc.Tex1MatIdx], + present[desc.Tex2MatIdx], present[desc.Tex3MatIdx], present[desc.Tex4MatIdx], + present[desc.Tex5MatIdx], present[desc.Tex6MatIdx], present[desc.Tex7MatIdx], + desc.Position, desc.Normal, desc.Color0, desc.Color1); + } +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TVtxDesc::High& desc, FormatContext& ctx) + { + return format_to(ctx.out(), + "Texture Coord 0: {}\n" + "Texture Coord 1: {}\n" + "Texture Coord 2: {}\n" + "Texture Coord 3: {}\n" + "Texture Coord 4: {}\n" + "Texture Coord 5: {}\n" + "Texture Coord 6: {}\n" + "Texture Coord 7: {}", + desc.Tex0Coord, desc.Tex1Coord, desc.Tex2Coord, desc.Tex3Coord, desc.Tex4Coord, + desc.Tex5Coord, desc.Tex6Coord, desc.Tex7Coord); + } +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TVtxDesc& desc, FormatContext& ctx) + { + return format_to(ctx.out(), "{}\n{}", desc.low, desc.high); + } +}; union UVAT_group0 { @@ -247,6 +310,40 @@ union UVAT_group0 BitField<30, 1, u32> ByteDequant; BitField<31, 1, u32> NormalIndex3; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const UVAT_group0& g0, FormatContext& ctx) + { + static constexpr std::array byte_dequant = { + "shift does not apply to u8/s8 components", "shift applies to u8/s8 components"}; + static constexpr std::array normalindex3 = {"single index per normal", + "triple-index per nine-normal"}; + + return format_to(ctx.out(), + "Position elements: {}\n" + "Position format: {}\n" + "Position shift: {} ({})\n" + "Normal elements: {}\n" + "Normal format: {}\n" + "Color 0 elements: {}\n" + "Color 0 format: {}\n" + "Color 1 elements: {}\n" + "Color 1 format: {}\n" + "Texture coord 0 elements: {}\n" + "Texture coord 0 format: {}\n" + "Texture coord 0 shift: {} ({})\n" + "Byte dequant: {}\n" + "Normal index 3: {}", + g0.PosElements, g0.PosFormat, g0.PosFrac, 1.f / (1 << g0.PosFrac), + g0.NormalElements, g0.NormalFormat, g0.Color0Elements, g0.Color0Comp, + g0.Color1Elements, g0.Color1Comp, g0.Tex0CoordElements, g0.Tex0CoordFormat, + g0.Tex0Frac, 1.f / (1 << g0.Tex0Frac), byte_dequant[g0.ByteDequant], + normalindex3[g0.NormalIndex3]); + } +}; union UVAT_group1 { @@ -269,6 +366,33 @@ union UVAT_group1 // 31 BitField<31, 1, u32> VCacheEnhance; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const UVAT_group1& g1, FormatContext& ctx) + { + return format_to(ctx.out(), + "Texture coord 1 elements: {}\n" + "Texture coord 1 format: {}\n" + "Texture coord 1 shift: {} ({})\n" + "Texture coord 2 elements: {}\n" + "Texture coord 2 format: {}\n" + "Texture coord 2 shift: {} ({})\n" + "Texture coord 3 elements: {}\n" + "Texture coord 3 format: {}\n" + "Texture coord 3 shift: {} ({})\n" + "Texture coord 4 elements: {}\n" + "Texture coord 4 format: {}\n" + "Enhance VCache (must always be on): {}", + g1.Tex1CoordElements, g1.Tex1CoordFormat, g1.Tex1Frac, + 1.f / (1 << g1.Tex1Frac), g1.Tex2CoordElements, g1.Tex2CoordFormat, + g1.Tex2Frac, 1.f / (1 << g1.Tex2Frac), g1.Tex3CoordElements, + g1.Tex3CoordFormat, g1.Tex3Frac, 1.f / (1 << g1.Tex3Frac), + g1.Tex4CoordElements, g1.Tex4CoordFormat, g1.VCacheEnhance ? "Yes" : "No"); + } +}; union UVAT_group2 { @@ -288,6 +412,31 @@ union UVAT_group2 BitField<24, 3, ComponentFormat> Tex7CoordFormat; BitField<27, 5, u32> Tex7Frac; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const UVAT_group2& g2, FormatContext& ctx) + { + return format_to(ctx.out(), + "Texture coord 4 shift: {} ({})\n" + "Texture coord 5 elements: {}\n" + "Texture coord 5 format: {}\n" + "Texture coord 5 shift: {} ({})\n" + "Texture coord 6 elements: {}\n" + "Texture coord 6 format: {}\n" + "Texture coord 6 shift: {} ({})\n" + "Texture coord 7 elements: {}\n" + "Texture coord 7 format: {}\n" + "Texture coord 7 shift: {} ({})", + g2.Tex4Frac, 1.f / (1 << g2.Tex4Frac), g2.Tex5CoordElements, + g2.Tex5CoordFormat, g2.Tex5Frac, 1.f / (1 << g2.Tex5Frac), + g2.Tex6CoordElements, g2.Tex6CoordFormat, g2.Tex6Frac, + 1.f / (1 << g2.Tex6Frac), g2.Tex7CoordElements, g2.Tex7CoordFormat, + g2.Tex7Frac, 1.f / (1 << g2.Tex7Frac)); + } +}; struct ColorAttr { @@ -325,6 +474,17 @@ union TMatrixIndexA BitField<24, 6, u32> Tex3MtxIdx; u32 Hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TMatrixIndexA& m, FormatContext& ctx) + { + return format_to(ctx.out(), "PosNormal: {}\nTex0: {}\nTex1: {}\nTex2: {}\nTex3: {}", + m.PosNormalMtxIdx, m.Tex0MtxIdx, m.Tex1MtxIdx, m.Tex2MtxIdx, m.Tex3MtxIdx); + } +}; union TMatrixIndexB { @@ -334,6 +494,17 @@ union TMatrixIndexB BitField<18, 6, u32> Tex7MtxIdx; u32 Hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TMatrixIndexB& m, FormatContext& ctx) + { + return format_to(ctx.out(), "Tex4: {}\nTex5: {}\nTex6: {}\nTex7: {}", m.Tex4MtxIdx, + m.Tex5MtxIdx, m.Tex6MtxIdx, m.Tex7MtxIdx); + } +}; struct VAT { @@ -376,3 +547,5 @@ void FillCPMemoryArray(u32* memory); void DoCPState(PointerWrap& p); void CopyPreprocessCPStateFromMain(); + +std::pair GetCPRegInfo(u8 cmd, u32 value); From aab81d5aa0a1bd6a467c91d0dbba04a9dc40998f Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 10 Feb 2021 16:01:42 -0800 Subject: [PATCH 09/17] Convert XFMemory to BitField and enum class Additionally a new ClipDisable union has been added (though it is not currently used by Dolphin). --- .../VideoBackends/Software/TransformUnit.cpp | 88 +++---- .../VideoCommon/GeometryShaderManager.cpp | 2 +- Source/Core/VideoCommon/LightingShaderGen.cpp | 41 +-- Source/Core/VideoCommon/PixelShaderGen.cpp | 3 +- Source/Core/VideoCommon/UberShaderCommon.cpp | 16 +- Source/Core/VideoCommon/UberShaderVertex.cpp | 34 +-- Source/Core/VideoCommon/VertexManagerBase.cpp | 8 +- Source/Core/VideoCommon/VertexShaderGen.cpp | 52 ++-- Source/Core/VideoCommon/VertexShaderGen.h | 9 +- .../Core/VideoCommon/VertexShaderManager.cpp | 6 +- Source/Core/VideoCommon/XFMemory.h | 240 ++++++++++++------ Source/Core/VideoCommon/XFStructs.cpp | 2 +- 12 files changed, 299 insertions(+), 202 deletions(-) diff --git a/Source/Core/VideoBackends/Software/TransformUnit.cpp b/Source/Core/VideoBackends/Software/TransformUnit.cpp index 387903f117..0c7fccaf0b 100644 --- a/Source/Core/VideoBackends/Software/TransformUnit.cpp +++ b/Source/Core/VideoBackends/Software/TransformUnit.cpp @@ -80,7 +80,7 @@ void TransformPosition(const InputVertexData* src, OutputVertexData* dst) const float* mat = &xfmem.posMatrices[src->posMtx * 4]; MultiplyVec3Mat34(src->position, mat, dst->mvPosition); - if (xfmem.projection.type == GX_PERSPECTIVE) + if (xfmem.projection.type == ProjectionType::Perspective) { MultipleVec3Perspective(dst->mvPosition, xfmem.projection.rawProjection, dst->projectedPosition); @@ -115,39 +115,42 @@ static void TransformTexCoordRegular(const TexMtxInfo& texinfo, int coordNum, Vec3 src; switch (texinfo.sourcerow) { - case XF_SRCGEOM_INROW: + case SourceRow::Geom: src = srcVertex->position; break; - case XF_SRCNORMAL_INROW: + case SourceRow::Normal: src = srcVertex->normal[0]; break; - case XF_SRCBINORMAL_T_INROW: + case SourceRow::BinormalT: src = srcVertex->normal[1]; break; - case XF_SRCBINORMAL_B_INROW: + case SourceRow::BinormalB: src = srcVertex->normal[2]; break; default: - ASSERT(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW); - src.x = srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW][0]; - src.y = srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW][1]; + { + ASSERT(texinfo.sourcerow >= SourceRow::Tex0 && texinfo.sourcerow <= SourceRow::Tex7); + u32 texnum = static_cast(texinfo.sourcerow.Value()) - static_cast(SourceRow::Tex0); + src.x = srcVertex->texCoords[texnum][0]; + src.y = srcVertex->texCoords[texnum][1]; src.z = 1.0f; break; } + } const float* mat = &xfmem.posMatrices[srcVertex->texMtx[coordNum] * 4]; Vec3* dst = &dstVertex->texCoords[coordNum]; - if (texinfo.projection == XF_TEXPROJ_ST) + if (texinfo.projection == TexSize::ST) { - if (texinfo.inputform == XF_TEXINPUT_AB11) + if (texinfo.inputform == TexInputForm::AB11) MultiplyVec2Mat24(src, mat, *dst); else MultiplyVec3Mat24(src, mat, *dst); } - else // texinfo.projection == XF_TEXPROJ_STQ + else // texinfo.projection == TexSize::STQ { - if (texinfo.inputform == XF_TEXINPUT_AB11) + if (texinfo.inputform == TexInputForm::AB11) MultiplyVec2Mat34(src, mat, *dst); else MultiplyVec3Mat34(src, mat, *dst); @@ -209,28 +212,28 @@ static float CalculateLightAttn(const LightPointer* light, Vec3* _ldir, const Ve switch (chan.attnfunc) { - case LIGHTATTN_NONE: - case LIGHTATTN_DIR: + case AttenuationFunc::None: + case AttenuationFunc::Dir: { ldir = ldir.Normalized(); if (ldir == Vec3(0.0f, 0.0f, 0.0f)) ldir = normal; break; } - case LIGHTATTN_SPEC: + case AttenuationFunc::Spec: { ldir = ldir.Normalized(); attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0; Vec3 attLen = Vec3(1.0, attn, attn * attn); Vec3 cosAttn = light->cosatt; Vec3 distAttn = light->distatt; - if (chan.diffusefunc != LIGHTDIF_NONE) + if (chan.diffusefunc != DiffuseFunc::None) distAttn = distAttn.Normalized(); attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn); break; } - case LIGHTATTN_SPOT: + case AttenuationFunc::Spot: { float dist2 = ldir.Length2(); float dist = sqrtf(dist2); @@ -243,7 +246,7 @@ static float CalculateLightAttn(const LightPointer* light, Vec3* _ldir, const Ve break; } default: - PanicAlertFmt("LightColor"); + PanicAlertFmt("Invalid attnfunc: {}", chan.attnfunc); } return attn; @@ -260,18 +263,18 @@ static void LightColor(const Vec3& pos, const Vec3& normal, u8 lightNum, const L float difAttn = ldir * normal; switch (chan.diffusefunc) { - case LIGHTDIF_NONE: + case DiffuseFunc::None: AddScaledIntegerColor(light->color, attn, lightCol); break; - case LIGHTDIF_SIGN: + case DiffuseFunc::Sign: AddScaledIntegerColor(light->color, attn * difAttn, lightCol); break; - case LIGHTDIF_CLAMP: + case DiffuseFunc::Clamp: difAttn = std::max(0.0f, difAttn); AddScaledIntegerColor(light->color, attn * difAttn, lightCol); break; default: - ASSERT(0); + PanicAlertFmt("Invalid diffusefunc: {}", chan.attnfunc); } } @@ -286,18 +289,18 @@ static void LightAlpha(const Vec3& pos, const Vec3& normal, u8 lightNum, const L float difAttn = ldir * normal; switch (chan.diffusefunc) { - case LIGHTDIF_NONE: + case DiffuseFunc::None: lightCol += light->color[0] * attn; break; - case LIGHTDIF_SIGN: + case DiffuseFunc::Sign: lightCol += light->color[0] * attn * difAttn; break; - case LIGHTDIF_CLAMP: + case DiffuseFunc::Clamp: difAttn = std::max(0.0f, difAttn); lightCol += light->color[0] * attn * difAttn; break; default: - ASSERT(0); + PanicAlertFmt("Invalid diffusefunc: {}", chan.attnfunc); } } @@ -311,17 +314,16 @@ void TransformColor(const InputVertexData* src, OutputVertexData* dst) // color const LitChannel& colorchan = xfmem.color[chan]; - if (colorchan.matsource) - matcolor = src->color[chan]; // vertex + if (colorchan.matsource == MatSource::Vertex) + matcolor = src->color[chan]; else std::memcpy(matcolor.data(), &xfmem.matColor[chan], sizeof(u32)); if (colorchan.enablelighting) { Vec3 lightCol; - if (colorchan.ambsource) + if (colorchan.ambsource == AmbSource::Vertex) { - // vertex lightCol.x = src->color[chan][1]; lightCol.y = src->color[chan][2]; lightCol.z = src->color[chan][3]; @@ -355,16 +357,16 @@ void TransformColor(const InputVertexData* src, OutputVertexData* dst) // alpha const LitChannel& alphachan = xfmem.alpha[chan]; - if (alphachan.matsource) - matcolor[0] = src->color[chan][0]; // vertex + if (alphachan.matsource == MatSource::Vertex) + matcolor[0] = src->color[chan][0]; else matcolor[0] = xfmem.matColor[chan] & 0xff; if (xfmem.alpha[chan].enablelighting) { float lightCol; - if (alphachan.ambsource) - lightCol = src->color[chan][0]; // vertex + if (alphachan.ambsource == AmbSource::Vertex) + lightCol = src->color[chan][0]; else lightCol = static_cast(xfmem.ambColor[chan] & 0xff); @@ -397,10 +399,10 @@ void TransformTexCoord(const InputVertexData* src, OutputVertexData* dst) switch (texinfo.texgentype) { - case XF_TEXGEN_REGULAR: + case TexGenType::Regular: TransformTexCoordRegular(texinfo, coordNum, src, dst); break; - case XF_TEXGEN_EMBOSS_MAP: + case TexGenType::EmbossMap: { const LightPointer* light = (const LightPointer*)&xfmem.lights[texinfo.embosslightshift]; @@ -413,22 +415,22 @@ void TransformTexCoord(const InputVertexData* src, OutputVertexData* dst) dst->texCoords[coordNum].z = dst->texCoords[texinfo.embosssourceshift].z; } break; - case XF_TEXGEN_COLOR_STRGBC0: - ASSERT(texinfo.sourcerow == XF_SRCCOLORS_INROW); - ASSERT(texinfo.inputform == XF_TEXINPUT_AB11); + case TexGenType::Color0: + ASSERT(texinfo.sourcerow == SourceRow::Colors); + ASSERT(texinfo.inputform == TexInputForm::AB11); dst->texCoords[coordNum].x = (float)dst->color[0][0] / 255.0f; dst->texCoords[coordNum].y = (float)dst->color[0][1] / 255.0f; dst->texCoords[coordNum].z = 1.0f; break; - case XF_TEXGEN_COLOR_STRGBC1: - ASSERT(texinfo.sourcerow == XF_SRCCOLORS_INROW); - ASSERT(texinfo.inputform == XF_TEXINPUT_AB11); + case TexGenType::Color1: + ASSERT(texinfo.sourcerow == SourceRow::Colors); + ASSERT(texinfo.inputform == TexInputForm::AB11); dst->texCoords[coordNum].x = (float)dst->color[1][0] / 255.0f; dst->texCoords[coordNum].y = (float)dst->color[1][1] / 255.0f; dst->texCoords[coordNum].z = 1.0f; break; default: - ERROR_LOG_FMT(VIDEO, "Bad tex gen type {}", texinfo.texgentype.Value()); + ERROR_LOG_FMT(VIDEO, "Bad tex gen type {}", texinfo.texgentype); break; } } diff --git a/Source/Core/VideoCommon/GeometryShaderManager.cpp b/Source/Core/VideoCommon/GeometryShaderManager.cpp index ca1dc992be..3b5300eb4a 100644 --- a/Source/Core/VideoCommon/GeometryShaderManager.cpp +++ b/Source/Core/VideoCommon/GeometryShaderManager.cpp @@ -45,7 +45,7 @@ void GeometryShaderManager::SetConstants() { s_projection_changed = false; - if (xfmem.projection.type == GX_PERSPECTIVE) + if (xfmem.projection.type == ProjectionType::Perspective) { float offset = (g_ActiveConfig.iStereoDepth / 1000.0f) * (g_ActiveConfig.iStereoDepthPercentage / 100.0f); diff --git a/Source/Core/VideoCommon/LightingShaderGen.cpp b/Source/Core/VideoCommon/LightingShaderGen.cpp index d84ff49e4d..7235e6a4e5 100644 --- a/Source/Core/VideoCommon/LightingShaderGen.cpp +++ b/Source/Core/VideoCommon/LightingShaderGen.cpp @@ -17,29 +17,32 @@ static void GenerateLightShader(ShaderCode& object, const LightingUidData& uid_d const char* swizzle = alpha ? "a" : "rgb"; const char* swizzle_components = (alpha) ? "" : "3"; - const u32 attnfunc = (uid_data.attnfunc >> (2 * litchan_index)) & 0x3; - const u32 diffusefunc = (uid_data.diffusefunc >> (2 * litchan_index)) & 0x3; + const auto attnfunc = + static_cast((uid_data.attnfunc >> (2 * litchan_index)) & 0x3); + const auto diffusefunc = + static_cast((uid_data.diffusefunc >> (2 * litchan_index)) & 0x3); switch (attnfunc) { - case LIGHTATTN_NONE: - case LIGHTATTN_DIR: + case AttenuationFunc::None: + case AttenuationFunc::Dir: object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); object.Write("attn = 1.0;\n"); object.Write("if (length(ldir) == 0.0)\n\t ldir = _norm0;\n"); break; - case LIGHTATTN_SPEC: + case AttenuationFunc::Spec: object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); object.Write("attn = (dot(_norm0, ldir) >= 0.0) ? max(0.0, dot(_norm0, " LIGHT_DIR ".xyz)) : 0.0;\n", LIGHT_DIR_PARAMS(index)); object.Write("cosAttn = " LIGHT_COSATT ".xyz;\n", LIGHT_COSATT_PARAMS(index)); object.Write("distAttn = {}(" LIGHT_DISTATT ".xyz);\n", - (diffusefunc == LIGHTDIF_NONE) ? "" : "normalize", LIGHT_DISTATT_PARAMS(index)); + (diffusefunc == DiffuseFunc::None) ? "" : "normalize", + LIGHT_DISTATT_PARAMS(index)); object.Write("attn = max(0.0f, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, " "float3(1.0, attn, attn*attn));\n"); break; - case LIGHTATTN_SPOT: + case AttenuationFunc::Spot: object.Write("ldir = " LIGHT_POS ".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(index)); object.Write("dist2 = dot(ldir, ldir);\n" "dist = sqrt(dist2);\n" @@ -56,14 +59,14 @@ static void GenerateLightShader(ShaderCode& object, const LightingUidData& uid_d switch (diffusefunc) { - case LIGHTDIF_NONE: + case DiffuseFunc::None: object.Write("lacc.{} += int{}(round(attn * float{}(" LIGHT_COL ")));\n", swizzle, swizzle_components, swizzle_components, LIGHT_COL_PARAMS(index, swizzle)); break; - case LIGHTDIF_SIGN: - case LIGHTDIF_CLAMP: + case DiffuseFunc::Sign: + case DiffuseFunc::Clamp: object.Write("lacc.{} += int{}(round(attn * {}dot(ldir, _norm0)) * float{}(" LIGHT_COL ")));\n", - swizzle, swizzle_components, diffusefunc != LIGHTDIF_SIGN ? "max(0.0," : "(", + swizzle, swizzle_components, diffusefunc != DiffuseFunc::Sign ? "max(0.0," : "(", swizzle_components, LIGHT_COL_PARAMS(index, swizzle)); break; default: @@ -151,23 +154,23 @@ void GetLightingShaderUid(LightingUidData& uid_data) { for (u32 j = 0; j < NUM_XF_COLOR_CHANNELS; j++) { - uid_data.matsource |= xfmem.color[j].matsource << j; - uid_data.matsource |= xfmem.alpha[j].matsource << (j + 2); + uid_data.matsource |= static_cast(xfmem.color[j].matsource.Value()) << j; + uid_data.matsource |= static_cast(xfmem.alpha[j].matsource.Value()) << (j + 2); uid_data.enablelighting |= xfmem.color[j].enablelighting << j; uid_data.enablelighting |= xfmem.alpha[j].enablelighting << (j + 2); if ((uid_data.enablelighting & (1 << j)) != 0) // Color lights { - uid_data.ambsource |= xfmem.color[j].ambsource << j; - uid_data.attnfunc |= xfmem.color[j].attnfunc << (2 * j); - uid_data.diffusefunc |= xfmem.color[j].diffusefunc << (2 * j); + uid_data.ambsource |= static_cast(xfmem.color[j].ambsource.Value()) << j; + uid_data.attnfunc |= static_cast(xfmem.color[j].attnfunc.Value()) << (2 * j); + uid_data.diffusefunc |= static_cast(xfmem.color[j].diffusefunc.Value()) << (2 * j); uid_data.light_mask |= xfmem.color[j].GetFullLightMask() << (8 * j); } if ((uid_data.enablelighting & (1 << (j + 2))) != 0) // Alpha lights { - uid_data.ambsource |= xfmem.alpha[j].ambsource << (j + 2); - uid_data.attnfunc |= xfmem.alpha[j].attnfunc << (2 * (j + 2)); - uid_data.diffusefunc |= xfmem.alpha[j].diffusefunc << (2 * (j + 2)); + uid_data.ambsource |= static_cast(xfmem.alpha[j].ambsource.Value()) << (j + 2); + uid_data.attnfunc |= static_cast(xfmem.alpha[j].attnfunc.Value()) << (2 * (j + 2)); + uid_data.diffusefunc |= static_cast(xfmem.alpha[j].diffusefunc.Value()) << (2 * (j + 2)); uid_data.light_mask |= xfmem.alpha[j].GetFullLightMask() << (8 * (j + 2)); } } diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 30bd725cb7..fe5fcd1190 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -212,7 +212,8 @@ PixelShaderUid GetPixelShaderUid() for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i) { // optional perspective divides - uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i; + uid_data->texMtxInfo_n_projection |= static_cast(xfmem.texMtxInfo[i].projection.Value()) + << i; } } diff --git a/Source/Core/VideoCommon/UberShaderCommon.cpp b/Source/Core/VideoCommon/UberShaderCommon.cpp index 36403d3f5b..e26fd13bf8 100644 --- a/Source/Core/VideoCommon/UberShaderCommon.cpp +++ b/Source/Core/VideoCommon/UberShaderCommon.cpp @@ -39,26 +39,26 @@ void WriteLightingFunction(ShaderCode& out) " float dist, dist2, attn;\n" "\n" " switch (attnfunc) {{\n"); - out.Write(" case {}u: // LIGNTATTN_NONE\n", LIGHTATTN_NONE); - out.Write(" case {}u: // LIGHTATTN_DIR\n", LIGHTATTN_DIR); + out.Write(" case {:s}:\n", AttenuationFunc::None); + out.Write(" case {:s}:\n", AttenuationFunc::Dir); out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n" " attn = 1.0;\n" " if (length(ldir) == 0.0)\n" " ldir = normal;\n" " break;\n\n"); - out.Write(" case {}u: // LIGHTATTN_SPEC\n", LIGHTATTN_SPEC); + out.Write(" case {:s}:\n", AttenuationFunc::Spec); out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n" " attn = (dot(normal, ldir) >= 0.0) ? max(0.0, dot(normal, " I_LIGHTS "[index].dir.xyz)) : 0.0;\n" " cosAttn = " I_LIGHTS "[index].cosatt.xyz;\n"); - out.Write(" if (diffusefunc == {}u) // LIGHTDIF_NONE\n", LIGHTDIF_NONE); + out.Write(" if (diffusefunc == {:s})\n", DiffuseFunc::None); out.Write(" distAttn = " I_LIGHTS "[index].distatt.xyz;\n" " else\n" " distAttn = normalize(" I_LIGHTS "[index].distatt.xyz);\n" " attn = max(0.0, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, " "float3(1.0, attn, attn*attn));\n" " break;\n\n"); - out.Write(" case {}u: // LIGHTATTN_SPOT\n", LIGHTATTN_SPOT); + out.Write(" case {:s}:\n", AttenuationFunc::Spot); out.Write(" ldir = " I_LIGHTS "[index].pos.xyz - pos.xyz;\n" " dist2 = dot(ldir, ldir);\n" " dist = sqrt(dist2);\n" @@ -75,12 +75,12 @@ void WriteLightingFunction(ShaderCode& out) " }}\n" "\n" " switch (diffusefunc) {{\n"); - out.Write(" case {}u: // LIGHTDIF_NONE\n", LIGHTDIF_NONE); + out.Write(" case {:s}:\n", DiffuseFunc::None); out.Write(" return int4(round(attn * float4(" I_LIGHTS "[index].color)));\n\n"); - out.Write(" case {}u: // LIGHTDIF_SIGN\n", LIGHTDIF_SIGN); + out.Write(" case {:s}:\n", DiffuseFunc::Sign); out.Write(" return int4(round(attn * dot(ldir, normal) * float4(" I_LIGHTS "[index].color)));\n\n"); - out.Write(" case {}u: // LIGHTDIF_CLAMP\n", LIGHTDIF_CLAMP); + out.Write(" case {:s}:\n", DiffuseFunc::Clamp); out.Write(" return int4(round(attn * max(0.0, dot(ldir, normal)) * float4(" I_LIGHTS "[index].color)));\n\n"); out.Write(" default:\n" diff --git a/Source/Core/VideoCommon/UberShaderVertex.cpp b/Source/Core/VideoCommon/UberShaderVertex.cpp index 71363bd456..cbc423dd5a 100644 --- a/Source/Core/VideoCommon/UberShaderVertex.cpp +++ b/Source/Core/VideoCommon/UberShaderVertex.cpp @@ -403,27 +403,27 @@ static void GenVertexShaderTexGens(APIType api_type, u32 num_texgen, ShaderCode& out.Write(" float4 coord = float4(0.0, 0.0, 1.0, 1.0);\n" " uint texMtxInfo = xfmem_texMtxInfo(texgen);\n"); out.Write(" switch ({}) {{\n", BitfieldExtract("texMtxInfo", TexMtxInfo().sourcerow)); - out.Write(" case {}u: // XF_SRCGEOM_INROW\n", XF_SRCGEOM_INROW); + out.Write(" case {:s}:\n", SourceRow::Geom); out.Write(" coord.xyz = rawpos.xyz;\n"); out.Write(" break;\n\n"); - out.Write(" case {}u: // XF_SRCNORMAL_INROW\n", XF_SRCNORMAL_INROW); + out.Write(" case {:s}:\n", SourceRow::Normal); out.Write( " coord.xyz = ((components & {}u /* VB_HAS_NRM0 */) != 0u) ? rawnorm0.xyz : coord.xyz;", VB_HAS_NRM0); out.Write(" break;\n\n"); - out.Write(" case {}u: // XF_SRCBINORMAL_T_INROW\n", XF_SRCBINORMAL_T_INROW); + out.Write(" case {:s}:\n", SourceRow::BinormalT); out.Write( " coord.xyz = ((components & {}u /* VB_HAS_NRM1 */) != 0u) ? rawnorm1.xyz : coord.xyz;", VB_HAS_NRM1); out.Write(" break;\n\n"); - out.Write(" case {}u: // XF_SRCBINORMAL_B_INROW\n", XF_SRCBINORMAL_B_INROW); + out.Write(" case {:s}:\n", SourceRow::BinormalB); out.Write( " coord.xyz = ((components & {}u /* VB_HAS_NRM2 */) != 0u) ? rawnorm2.xyz : coord.xyz;", VB_HAS_NRM2); out.Write(" break;\n\n"); for (u32 i = 0; i < 8; i++) { - out.Write(" case {}u: // XF_SRCTEX{}_INROW\n", XF_SRCTEX0_INROW + i, i); + out.Write(" case {:s}:\n", static_cast(static_cast(SourceRow::Tex0) + i)); out.Write( " coord = ((components & {}u /* VB_HAS_UV{} */) != 0u) ? float4(rawtex{}.x, rawtex{}.y, " "1.0, 1.0) : coord;\n", @@ -434,8 +434,8 @@ static void GenVertexShaderTexGens(APIType api_type, u32 num_texgen, ShaderCode& "\n"); out.Write(" // Input form of AB11 sets z element to 1.0\n"); - out.Write(" if ({} == {}u) // inputform == XF_TEXINPUT_AB11\n", - BitfieldExtract("texMtxInfo", TexMtxInfo().inputform), XF_TEXINPUT_AB11); + out.Write(" if ({} == {:s}) // inputform == AB11\n", + BitfieldExtract("texMtxInfo", TexMtxInfo().inputform), TexInputForm::AB11); out.Write(" coord.z = 1.0f;\n" "\n"); @@ -444,7 +444,7 @@ static void GenVertexShaderTexGens(APIType api_type, u32 num_texgen, ShaderCode& out.Write(" float3 output_tex;\n" " switch (texgentype)\n" " {{\n"); - out.Write(" case {}u: // XF_TEXGEN_EMBOSS_MAP\n", XF_TEXGEN_EMBOSS_MAP); + out.Write(" case {:s}:\n", TexGenType::EmbossMap); out.Write(" {{\n"); out.Write(" uint light = {};\n", BitfieldExtract("texMtxInfo", TexMtxInfo().embosslightshift)); @@ -462,13 +462,14 @@ static void GenVertexShaderTexGens(APIType api_type, u32 num_texgen, ShaderCode& " }}\n" " }}\n" " break;\n\n"); - out.Write(" case {}u: // XF_TEXGEN_COLOR_STRGBC0\n", XF_TEXGEN_COLOR_STRGBC0); + out.Write(" case {:s}:\n", TexGenType::Color0); out.Write(" output_tex.xyz = float3(o.colors_0.x, o.colors_0.y, 1.0);\n" " break;\n\n"); - out.Write(" case {}u: // XF_TEXGEN_COLOR_STRGBC1\n", XF_TEXGEN_COLOR_STRGBC1); + out.Write(" case {:s}:\n", TexGenType::Color1); out.Write(" output_tex.xyz = float3(o.colors_1.x, o.colors_1.y, 1.0);\n" " break;\n\n"); - out.Write(" default: // Also XF_TEXGEN_REGULAR\n" + out.Write(" case {:s}:\n", TexGenType::Regular); + out.Write(" default:\n" " {{\n"); out.Write(" if ((components & ({}u /* VB_HAS_TEXMTXIDX0 */ << texgen)) != 0u) {{\n", VB_HAS_TEXMTXIDX0); @@ -480,8 +481,8 @@ static void GenVertexShaderTexGens(APIType api_type, u32 num_texgen, ShaderCode& out.Write(" case {}u: tmp = int(rawtex{}.z); break;\n", i, i); out.Write(" }}\n" "\n"); - out.Write(" if ({} == {}u) {{\n", BitfieldExtract("texMtxInfo", TexMtxInfo().projection), - XF_TEXPROJ_STQ); + out.Write(" if ({} == {:s}) {{\n", BitfieldExtract("texMtxInfo", TexMtxInfo().projection), + TexSize::STQ); out.Write(" output_tex.xyz = float3(dot(coord, " I_TRANSFORMMATRICES "[tmp]),\n" " dot(coord, " I_TRANSFORMMATRICES "[tmp + 1]),\n" " dot(coord, " I_TRANSFORMMATRICES "[tmp + 2]));\n" @@ -491,8 +492,8 @@ static void GenVertexShaderTexGens(APIType api_type, u32 num_texgen, ShaderCode& " 1.0);\n" " }}\n" " }} else {{\n"); - out.Write(" if ({} == {}u) {{\n", BitfieldExtract("texMtxInfo", TexMtxInfo().projection), - XF_TEXPROJ_STQ); + out.Write(" if ({} == {:s}) {{\n", BitfieldExtract("texMtxInfo", TexMtxInfo().projection), + TexSize::STQ); out.Write(" output_tex.xyz = float3(dot(coord, " I_TEXMATRICES "[3u * texgen]),\n" " dot(coord, " I_TEXMATRICES "[3u * texgen + 1u]),\n" " dot(coord, " I_TEXMATRICES "[3u * texgen + 2u]));\n" @@ -526,8 +527,7 @@ static void GenVertexShaderTexGens(APIType api_type, u32 num_texgen, ShaderCode& // When q is 0, the GameCube appears to have a special case // This can be seen in devkitPro's neheGX Lesson08 example for Wii // Makes differences in Rogue Squadron 3 (Hoth sky) and The Last Story (shadow culling) - out.Write(" if (texgentype == {}u && output_tex.z == 0.0) // XF_TEXGEN_REGULAR\n", - XF_TEXGEN_REGULAR); + out.Write(" if (texgentype == {:s} && output_tex.z == 0.0)\n", TexGenType::Regular); out.Write( " output_tex.xy = clamp(output_tex.xy / 2.0f, float2(-1.0f,-1.0f), float2(1.0f,1.0f));\n" "\n"); diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 59d351018f..26d9fc9dc9 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -408,10 +408,10 @@ void VertexManagerBase::Flush() for (u32 i = 0; i < xfmem.numTexGen.numTexGens; ++i) { TexMtxInfo tinfo = xfmem.texMtxInfo[i]; - if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP) + if (tinfo.texgentype != TexGenType::EmbossMap) tinfo.hex &= 0x7ff; - if (tinfo.texgentype != XF_TEXGEN_REGULAR) - tinfo.projection = 0; + if (tinfo.texgentype != TexGenType::Regular) + tinfo.projection = TexSize::ST; PRIM_LOG("txgen{}: proj={}, input={}, gentype={}, srcrow={}, embsrc={}, emblght={}, " "postmtx={}, postnorm={}", @@ -430,7 +430,7 @@ void VertexManagerBase::Flush() // Track some stats used elsewhere by the anamorphic widescreen heuristic. if (!SConfig::GetInstance().bWii) { - const bool is_perspective = xfmem.projection.type == GX_PERSPECTIVE; + const bool is_perspective = xfmem.projection.type == ProjectionType::Perspective; auto& counts = is_perspective ? m_flush_statistics.perspective : m_flush_statistics.orthographic; diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 584f55b5e3..cf400a21ba 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -39,7 +39,7 @@ VertexShaderUid GetVertexShaderUid() // first transformation switch (texinfo.texgentype) { - case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map + case TexGenType::EmbossMap: // calculate tex coords into bump map if ((uid_data->components & (VB_HAS_NRM1 | VB_HAS_NRM2)) != 0) { // transform the light dir into tangent space @@ -51,18 +51,19 @@ VertexShaderUid GetVertexShaderUid() texinfo.embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift; } break; - case XF_TEXGEN_COLOR_STRGBC0: - case XF_TEXGEN_COLOR_STRGBC1: + case TexGenType::Color0: + case TexGenType::Color1: break; - case XF_TEXGEN_REGULAR: + case TexGenType::Regular: default: - uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i; + uid_data->texMtxInfo_n_projection |= static_cast(xfmem.texMtxInfo[i].projection.Value()) + << i; break; } uid_data->dualTexTrans_enabled = xfmem.dualTexTrans.enabled; // CHECKME: does this only work for regular tex gen types? - if (uid_data->dualTexTrans_enabled && texinfo.texgentype == XF_TEXGEN_REGULAR) + if (uid_data->dualTexTrans_enabled && texinfo.texgentype == TexGenType::Regular) { auto& postInfo = uid_data->postMtxInfo[i]; postInfo.index = xfmem.postMtxInfo[i].index; @@ -297,49 +298,48 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho out.Write("coord = float4(0.0, 0.0, 1.0, 1.0);\n"); switch (texinfo.sourcerow) { - case XF_SRCGEOM_INROW: + case SourceRow::Geom: out.Write("coord.xyz = rawpos.xyz;\n"); break; - case XF_SRCNORMAL_INROW: + case SourceRow::Normal: if ((uid_data->components & VB_HAS_NRM0) != 0) { out.Write("coord.xyz = rawnorm0.xyz;\n"); } break; - case XF_SRCCOLORS_INROW: - ASSERT(texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC0 || - texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1); + case SourceRow::Colors: + ASSERT(texinfo.texgentype == TexGenType::Color0 || texinfo.texgentype == TexGenType::Color1); break; - case XF_SRCBINORMAL_T_INROW: + case SourceRow::BinormalT: if ((uid_data->components & VB_HAS_NRM1) != 0) { out.Write("coord.xyz = rawnorm1.xyz;\n"); } break; - case XF_SRCBINORMAL_B_INROW: + case SourceRow::BinormalB: if ((uid_data->components & VB_HAS_NRM2) != 0) { out.Write("coord.xyz = rawnorm2.xyz;\n"); } break; default: - ASSERT(texinfo.sourcerow <= XF_SRCTEX7_INROW); - if ((uid_data->components & (VB_HAS_UV0 << (texinfo.sourcerow - XF_SRCTEX0_INROW))) != 0) + ASSERT(texinfo.sourcerow >= SourceRow::Tex0 && texinfo.sourcerow <= SourceRow::Tex7); + u32 texnum = static_cast(texinfo.sourcerow) - static_cast(SourceRow::Tex0); + if ((uid_data->components & (VB_HAS_UV0 << (texnum))) != 0) { - out.Write("coord = float4(rawtex{}.x, rawtex{}.y, 1.0, 1.0);\n", - texinfo.sourcerow - XF_SRCTEX0_INROW, texinfo.sourcerow - XF_SRCTEX0_INROW); + out.Write("coord = float4(rawtex{}.x, rawtex{}.y, 1.0, 1.0);\n", texnum, texnum); } break; } // Input form of AB11 sets z element to 1.0 - if (texinfo.inputform == XF_TEXINPUT_AB11) + if (texinfo.inputform == TexInputForm::AB11) out.Write("coord.z = 1.0;\n"); // first transformation switch (texinfo.texgentype) { - case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map + case TexGenType::EmbossMap: // calculate tex coords into bump map if ((uid_data->components & (VB_HAS_NRM1 | VB_HAS_NRM2)) != 0) { @@ -359,18 +359,18 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho } break; - case XF_TEXGEN_COLOR_STRGBC0: + case TexGenType::Color0: out.Write("o.tex{}.xyz = float3(o.colors_0.x, o.colors_0.y, 1);\n", i); break; - case XF_TEXGEN_COLOR_STRGBC1: + case TexGenType::Color1: out.Write("o.tex{}.xyz = float3(o.colors_1.x, o.colors_1.y, 1);\n", i); break; - case XF_TEXGEN_REGULAR: + case TexGenType::Regular: default: if ((uid_data->components & (VB_HAS_TEXMTXIDX0 << i)) != 0) { out.Write("int tmp = int(rawtex{}.z);\n", i); - if (((uid_data->texMtxInfo_n_projection >> i) & 1) == XF_TEXPROJ_STQ) + if (static_cast((uid_data->texMtxInfo_n_projection >> i) & 1) == TexSize::STQ) { out.Write("o.tex{}.xyz = float3(dot(coord, " I_TRANSFORMMATRICES "[tmp]), dot(coord, " I_TRANSFORMMATRICES @@ -386,7 +386,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho } else { - if (((uid_data->texMtxInfo_n_projection >> i) & 1) == XF_TEXPROJ_STQ) + if (static_cast((uid_data->texMtxInfo_n_projection >> i) & 1) == TexSize::STQ) { out.Write("o.tex{}.xyz = float3(dot(coord, " I_TEXMATRICES "[{}]), dot(coord, " I_TEXMATRICES "[{}]), dot(coord, " I_TEXMATRICES @@ -404,7 +404,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho } // CHECKME: does this only work for regular tex gen types? - if (uid_data->dualTexTrans_enabled && texinfo.texgentype == XF_TEXGEN_REGULAR) + if (uid_data->dualTexTrans_enabled && texinfo.texgentype == TexGenType::Regular) { auto& postInfo = uid_data->postMtxInfo[i]; @@ -427,7 +427,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho // This can be seen in devkitPro's neheGX Lesson08 example for Wii // Makes differences in Rogue Squadron 3 (Hoth sky) and The Last Story (shadow culling) // TODO: check if this only affects XF_TEXGEN_REGULAR - if (texinfo.texgentype == XF_TEXGEN_REGULAR) + if (texinfo.texgentype == TexGenType::Regular) { out.Write( "if(o.tex{0}.z == 0.0f)\n" diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h index cfb47b35c6..2768200cf2 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.h +++ b/Source/Core/VideoCommon/VertexShaderGen.h @@ -9,6 +9,9 @@ #include "VideoCommon/ShaderGenCommon.h" enum class APIType; +enum class TexInputForm : u32; +enum class TexGenType : u32; +enum class SourceRow : u32; // TODO should be reordered enum : int @@ -47,9 +50,9 @@ struct vertex_shader_uid_data struct { - u32 inputform : 2; - u32 texgentype : 3; - u32 sourcerow : 5; + TexInputForm inputform : 2; + TexGenType texgentype : 3; + SourceRow sourcerow : 5; u32 embosssourceshift : 3; u32 embosslightshift : 3; } texMtxInfo[8]; diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index 121d6f1a21..8047714f61 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -353,7 +353,7 @@ void VertexShaderManager::SetConstants() switch (xfmem.projection.type) { - case GX_PERSPECTIVE: + case ProjectionType::Perspective: { const Common::Vec2 fov = g_freelook_camera.IsActive() ? g_freelook_camera.GetFieldOfView() : Common::Vec2{1, 1}; @@ -382,7 +382,7 @@ void VertexShaderManager::SetConstants() } break; - case GX_ORTHOGRAPHIC: + case ProjectionType::Orthographic: { g_fProjectionMatrix[0] = rawProjection[0]; g_fProjectionMatrix[1] = 0.0f; @@ -419,7 +419,7 @@ void VertexShaderManager::SetConstants() auto corrected_matrix = s_viewportCorrection * Common::Matrix44::FromArray(g_fProjectionMatrix); - if (g_freelook_camera.IsActive() && xfmem.projection.type == GX_PERSPECTIVE) + if (g_freelook_camera.IsActive() && xfmem.projection.type == ProjectionType::Perspective) corrected_matrix *= g_freelook_camera.GetView(); memcpy(constants.projection.data(), corrected_matrix.data.data(), 4 * sizeof(float4)); diff --git a/Source/Core/VideoCommon/XFMemory.h b/Source/Core/VideoCommon/XFMemory.h index 1c860c704d..8dc94937f1 100644 --- a/Source/Core/VideoCommon/XFMemory.h +++ b/Source/Core/VideoCommon/XFMemory.h @@ -4,10 +4,14 @@ #pragma once +// X.h defines None to be 0, which causes problems with some of the enums +#undef None + #include #include "Common/BitField.h" #include "Common/CommonTypes.h" +#include "Common/EnumFormatter.h" #include "VideoCommon/CPMemory.h" class DataReader; @@ -17,75 +21,164 @@ constexpr size_t NUM_XF_COLOR_CHANNELS = 2; // Lighting // Projection -enum : u32 +enum class TexSize : u32 { - XF_TEXPROJ_ST = 0, - XF_TEXPROJ_STQ = 1 + ST = 0, + STQ = 1 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"ST (2x4 matrix)", "STQ (3x4 matrix)"}) {} }; // Input form -enum : u32 +enum class TexInputForm : u32 { - XF_TEXINPUT_AB11 = 0, - XF_TEXINPUT_ABC1 = 1 + AB11 = 0, + ABC1 = 1 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"AB11", "ABC1"}) {} +}; + +enum class NormalCount : u32 +{ + None = 0, + Normals = 1, + NormalsBinormals = 2 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"None", "Normals only", "Normals and binormals"}) {} }; // Texture generation type -enum : u32 +enum class TexGenType : u32 { - XF_TEXGEN_REGULAR = 0, - XF_TEXGEN_EMBOSS_MAP = 1, // Used when bump mapping - XF_TEXGEN_COLOR_STRGBC0 = 2, - XF_TEXGEN_COLOR_STRGBC1 = 3 + Regular = 0, + EmbossMap = 1, // Used when bump mapping + Color0 = 2, + Color1 = 3 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "Regular", + "Emboss map (used when bump mapping)", + "Color channel 0", + "Color channel 1", + }; + formatter() : EnumFormatter(names) {} }; // Source row -enum : u32 +enum class SourceRow : u32 { - XF_SRCGEOM_INROW = 0, // Input is abc - XF_SRCNORMAL_INROW = 1, // Input is abc - XF_SRCCOLORS_INROW = 2, - XF_SRCBINORMAL_T_INROW = 3, // Input is abc - XF_SRCBINORMAL_B_INROW = 4, // Input is abc - XF_SRCTEX0_INROW = 5, - XF_SRCTEX1_INROW = 6, - XF_SRCTEX2_INROW = 7, - XF_SRCTEX3_INROW = 8, - XF_SRCTEX4_INROW = 9, - XF_SRCTEX5_INROW = 10, - XF_SRCTEX6_INROW = 11, - XF_SRCTEX7_INROW = 12 + Geom = 0, // Input is abc + Normal = 1, // Input is abc + Colors = 2, + BinormalT = 3, // Input is abc + BinormalB = 4, // Input is abc + Tex0 = 5, + Tex1 = 6, + Tex2 = 7, + Tex3 = 8, + Tex4 = 9, + Tex5 = 10, + Tex6 = 11, + Tex7 = 12 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "Geometry (input is ABC1)", + "Normal (input is ABC1)", + "Colors", + "Binormal T (input is ABC1)", + "Binormal B (input is ABC1)", + "Tex 0", + "Tex 1", + "Tex 2", + "Tex 3", + "Tex 4", + "Tex 5", + "Tex 6", + "Tex 7", + }; + formatter() : EnumFormatter(names) {} }; -// Control source -enum : u32 +enum class MatSource : u32 { - GX_SRC_REG = 0, - GX_SRC_VTX = 1 + MatColorRegister = 0, + Vertex = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Material color register", "Vertex color"}) {} +}; + +enum class AmbSource : u32 +{ + AmbColorRegister = 0, + Vertex = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Ambient color register", "Vertex color"}) {} }; // Light diffuse attenuation function -enum : u32 +enum class DiffuseFunc : u32 { - LIGHTDIF_NONE = 0, - LIGHTDIF_SIGN = 1, - LIGHTDIF_CLAMP = 2 + None = 0, + Sign = 1, + Clamp = 2 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"None", "Sign", "Clamp"}) {} }; // Light attenuation function -enum : u32 +enum class AttenuationFunc : u32 { - LIGHTATTN_NONE = 0, // No attenuation - LIGHTATTN_SPEC = 1, // Point light attenuation - LIGHTATTN_DIR = 2, // Directional light attenuation - LIGHTATTN_SPOT = 3 // Spot light attenuation + None = 0, // No attenuation + Spec = 1, // Point light attenuation + Dir = 2, // Directional light attenuation + Spot = 3 // Spot light attenuation +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "No attenuation", + "Point light attenuation", + "Directional light attenuation", + "Spot light attenuation", + }; + formatter() : EnumFormatter(names) {} }; // Projection type -enum : u32 +enum class ProjectionType : u32 { - GX_PERSPECTIVE = 0, - GX_ORTHOGRAPHIC = 1 + Perspective = 0, + Orthographic = 1 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Perspective", "Orthographic"}) {} }; // Registers and register ranges @@ -137,12 +230,12 @@ enum union LitChannel { - BitField<0, 1, u32> matsource; - BitField<1, 1, u32> enablelighting; + BitField<0, 1, MatSource> matsource; + BitField<1, 1, bool, u32> enablelighting; BitField<2, 4, u32> lightMask0_3; - BitField<6, 1, u32> ambsource; - BitField<7, 2, u32> diffusefunc; // LIGHTDIF_X - BitField<9, 2, u32> attnfunc; // LIGHTATTN_X + BitField<6, 1, AmbSource> ambsource; + BitField<7, 2, DiffuseFunc> diffusefunc; + BitField<9, 2, AttenuationFunc> attnfunc; BitField<11, 4, u32> lightMask4_7; u32 hex; @@ -152,26 +245,30 @@ union LitChannel } }; +union ClipDisable +{ + BitField<0, 1, bool, u32> disable_clipping_detection; + BitField<1, 1, bool, u32> disable_trivial_rejection; + BitField<2, 1, bool, u32> disable_cpoly_clipping_acceleration; + u32 hex; +}; + union INVTXSPEC { - struct - { - u32 numcolors : 2; - u32 numnormals : 2; // 0 - nothing, 1 - just normal, 2 - normals and binormals - u32 numtextures : 4; - u32 unused : 24; - }; + BitField<0, 2, u32> numcolors; + BitField<2, 2, NormalCount> numnormals; + BitField<4, 4, u32> numtextures; u32 hex; }; union TexMtxInfo { - BitField<0, 1, u32> unknown; // - BitField<1, 1, u32> projection; // XF_TEXPROJ_X - BitField<2, 1, u32> inputform; // XF_TEXINPUT_X - BitField<3, 1, u32> unknown2; // - BitField<4, 3, u32> texgentype; // XF_TEXGEN_X - BitField<7, 5, u32> sourcerow; // XF_SRCGEOM_X + BitField<0, 1, u32> unknown; + BitField<1, 1, TexSize> projection; + BitField<2, 1, TexInputForm> inputform; + BitField<3, 1, u32> unknown2; + BitField<4, 3, TexGenType> texgentype; + BitField<7, 5, SourceRow> sourcerow; BitField<12, 3, u32> embosssourceshift; // what generated texcoord to use BitField<15, 3, u32> embosslightshift; // light index that is used u32 hex; @@ -179,36 +276,27 @@ union TexMtxInfo union PostMtxInfo { - BitField<0, 6, u32> index; // base row of dual transform matrix - BitField<6, 2, u32> unused; // - BitField<8, 1, u32> normalize; // normalize before send operation + BitField<0, 6, u32> index; // base row of dual transform matrix + BitField<6, 2, u32> unused; // + BitField<8, 1, bool, u32> normalize; // normalize before send operation u32 hex; }; union NumColorChannel { - struct - { - u32 numColorChans : 2; - }; + BitField<0, 2, u32> numColorChans; u32 hex; }; union NumTexGen { - struct - { - u32 numTexGens : 4; - }; + BitField<0, 4, u32> numTexGens; u32 hex; }; union DualTexInfo { - struct - { - u32 enabled : 1; - }; + BitField<0, 1, bool, u32> enabled; u32 hex; }; @@ -250,7 +338,7 @@ struct Projection using Raw = std::array; Raw rawProjection; - u32 type; // only GX_PERSPECTIVE or GX_ORTHOGRAPHIC are allowed + ProjectionType type; }; struct XFMemory @@ -267,7 +355,7 @@ struct XFMemory u32 state0; // 0x1002 u32 state1; // 0x1003 u32 xfClock; // 0x1004 - u32 clipDisable; // 0x1005 + ClipDisable clipDisable; // 0x1005 u32 perf0; // 0x1006 u32 perf1; // 0x1007 INVTXSPEC hostinfo; // 0x1008 number of textures,colors,normals from vertex input diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index 4fda86a8e0..3d02ca19bf 100644 --- a/Source/Core/VideoCommon/XFStructs.cpp +++ b/Source/Core/VideoCommon/XFStructs.cpp @@ -93,7 +93,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) break; case XFMEM_DUALTEX: - if (xfmem.dualTexTrans.enabled != (newValue & 1)) + if (xfmem.dualTexTrans.enabled != bool(newValue & 1)) g_vertex_manager->Flush(); VertexShaderManager::SetTexMatrixInfoChanged(-1); break; From 2d6ec7457dc4540ab539c585d004dedb676bf455 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sat, 6 Feb 2021 21:14:21 -0800 Subject: [PATCH 10/17] Add names and descriptions for XF registers to the FIFO analyzer --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 15 ++ Source/Core/VideoCommon/XFMemory.h | 69 ++++++ Source/Core/VideoCommon/XFStructs.cpp | 242 ++++++++++++++++++++ Source/Core/VideoCommon/XFStructs.h | 6 + 4 files changed, 332 insertions(+) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 4db865b069..8764e30b19 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -25,6 +25,7 @@ #include "VideoCommon/BPMemory.h" #include "VideoCommon/CPMemory.h" #include "VideoCommon/OpcodeDecoding.h" +#include "VideoCommon/XFStructs.h" constexpr int FRAME_ROLE = Qt::UserRole; constexpr int OBJECT_ROLE = Qt::UserRole + 1; @@ -237,8 +238,10 @@ void FIFOAnalyzer::UpdateDetails() case OpcodeDecoder::GX_LOAD_XF_REG: { + const auto [name, desc] = GetXFTransferInfo(objectdata); u32 cmd2 = Common::swap32(objectdata); objectdata += 4; + ASSERT(!name.empty()); u8 streamSize = ((cmd2 >> 16) & 15) + 1; @@ -253,6 +256,8 @@ void FIFOAnalyzer::UpdateDetails() if (((objectdata - stream_start) % 4) == 0) new_label += QLatin1Char(' '); } + + new_label += QStringLiteral(" ") + QString::fromStdString(name); } break; @@ -505,7 +510,17 @@ void FIFOAnalyzer::UpdateDescription() } else if (*cmddata == OpcodeDecoder::GX_LOAD_XF_REG) { + const auto [name, desc] = GetXFTransferInfo(cmddata + 1); + ASSERT(!name.empty()); + text = tr("XF register "); + text += QString::fromStdString(name); + text += QLatin1Char{'\n'}; + + if (desc.empty()) + text += tr("No description available"); + else + text += QString::fromStdString(desc); } else { diff --git a/Source/Core/VideoCommon/XFMemory.h b/Source/Core/VideoCommon/XFMemory.h index 8dc94937f1..7efd3d2209 100644 --- a/Source/Core/VideoCommon/XFMemory.h +++ b/Source/Core/VideoCommon/XFMemory.h @@ -192,6 +192,7 @@ enum XFMEM_POSTMATRICES_END = 0x600, XFMEM_LIGHTS = 0x600, XFMEM_LIGHTS_END = 0x680, + XFMEM_REGISTERS_START = 0x1000, XFMEM_ERROR = 0x1000, XFMEM_DIAG = 0x1001, XFMEM_STATE0 = 0x1002, @@ -226,6 +227,7 @@ enum XFMEM_SETNUMTEXGENS = 0x103f, XFMEM_SETTEXMTXINFO = 0x1040, XFMEM_SETPOSTMTXINFO = 0x1050, + XFMEM_REGISTERS_END = 0x1058, }; union LitChannel @@ -244,6 +246,20 @@ union LitChannel return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0; } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const LitChannel& chan, FormatContext& ctx) + { + return format_to(ctx.out(), + "Material source: {0}\nEnable lighting: {1}\nLight mask: {2:x} ({2:08b})\n" + "Ambient source: {3}\nDiffuse function: {4}\nAttenuation function: {5}", + chan.matsource, chan.enablelighting ? "Yes" : "No", chan.GetFullLightMask(), + chan.ambsource, chan.diffusefunc, chan.attnfunc); + } +}; union ClipDisable { @@ -252,6 +268,22 @@ union ClipDisable BitField<2, 1, bool, u32> disable_cpoly_clipping_acceleration; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const ClipDisable& cd, FormatContext& ctx) + { + return format_to(ctx.out(), + "Disable clipping detection: {}\n" + "Disable trivial rejection: {}\n" + "Disable cpoly clipping acceleration: {}", + cd.disable_clipping_detection ? "Yes" : "No", + cd.disable_trivial_rejection ? "Yes" : "No", + cd.disable_cpoly_clipping_acceleration ? "Yes" : "No"); + } +}; union INVTXSPEC { @@ -260,6 +292,17 @@ union INVTXSPEC BitField<4, 4, u32> numtextures; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const INVTXSPEC& spec, FormatContext& ctx) + { + return format_to(ctx.out(), "Num colors: {}\nNum normals: {}\nNum textures: {}", spec.numcolors, + spec.numnormals, spec.numtextures); + } +}; union TexMtxInfo { @@ -273,6 +316,20 @@ union TexMtxInfo BitField<15, 3, u32> embosslightshift; // light index that is used u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TexMtxInfo& i, FormatContext& ctx) + { + return format_to(ctx.out(), + "Projection: {}\nInput form: {}\nTex gen type: {}\n" + "Source row: {}\nEmboss source shift: {}\nEmboss light shift: {}", + i.projection, i.inputform, i.texgentype, i.sourcerow, i.embosssourceshift, + i.embosslightshift); + } +}; union PostMtxInfo { @@ -282,6 +339,18 @@ union PostMtxInfo u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const PostMtxInfo& i, FormatContext& ctx) + { + return format_to(ctx.out(), "Index: {}\nNormalize before send operation: {}", i.index, + i.normalize ? "Yes" : "No"); + } +}; + union NumColorChannel { BitField<0, 2, u32> numColorChans; diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index 3d02ca19bf..0e9667c509 100644 --- a/Source/Core/VideoCommon/XFStructs.cpp +++ b/Source/Core/VideoCommon/XFStructs.cpp @@ -2,6 +2,9 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoCommon/XFStructs.h" + +#include "Common/BitUtils.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Common/Swap.h" @@ -300,3 +303,242 @@ void PreprocessIndexedXF(u32 val, int refarray) const size_t buf_size = size * sizeof(u32); Fifo::PushFifoAuxBuffer(new_data, buf_size); } + +std::pair GetXFRegInfo(u32 address, u32 value) +{ +// Macro to set the register name and make sure it was written correctly via compile time assertion +#define RegName(reg) ((void)(reg), #reg) +#define DescriptionlessReg(reg) std::make_pair(RegName(reg), ""); + + switch (address) + { + case XFMEM_ERROR: + return DescriptionlessReg(XFMEM_ERROR); + case XFMEM_DIAG: + return DescriptionlessReg(XFMEM_DIAG); + case XFMEM_STATE0: // internal state 0 + return std::make_pair(RegName(XFMEM_STATE0), "internal state 0"); + case XFMEM_STATE1: // internal state 1 + return std::make_pair(RegName(XFMEM_STATE1), "internal state 1"); + case XFMEM_CLOCK: + return DescriptionlessReg(XFMEM_CLOCK); + case XFMEM_SETGPMETRIC: + return DescriptionlessReg(XFMEM_SETGPMETRIC); + + case XFMEM_CLIPDISABLE: + return std::make_pair(RegName(XFMEM_CLIPDISABLE), fmt::to_string(ClipDisable{.hex = value})); + + case XFMEM_VTXSPECS: + return std::make_pair(RegName(XFMEM_VTXSPECS), fmt::to_string(INVTXSPEC{.hex = value})); + + case XFMEM_SETNUMCHAN: + return std::make_pair(RegName(XFMEM_SETNUMCHAN), + fmt::format("Number of color channels: {}", value & 3)); + break; + + case XFMEM_SETCHAN0_AMBCOLOR: + return std::make_pair(RegName(XFMEM_SETCHAN0_AMBCOLOR), + fmt::format("Channel 0 Ambient Color: {:06x}", value)); + case XFMEM_SETCHAN1_AMBCOLOR: + return std::make_pair(RegName(XFMEM_SETCHAN1_AMBCOLOR), + fmt::format("Channel 1 Ambient Color: {:06x}", value)); + + case XFMEM_SETCHAN0_MATCOLOR: + return std::make_pair(RegName(XFMEM_SETCHAN0_MATCOLOR), + fmt::format("Channel 0 Material Color: {:06x}", value)); + case XFMEM_SETCHAN1_MATCOLOR: + return std::make_pair(RegName(XFMEM_SETCHAN1_MATCOLOR), + fmt::format("Channel 1 Material Color: {:06x}", value)); + + case XFMEM_SETCHAN0_COLOR: // Channel Color + return std::make_pair(RegName(XFMEM_SETCHAN0_COLOR), + fmt::format("Channel 0 Color config:\n{}", LitChannel{.hex = value})); + case XFMEM_SETCHAN1_COLOR: + return std::make_pair(RegName(XFMEM_SETCHAN1_COLOR), + fmt::format("Channel 1 Color config:\n{}", LitChannel{.hex = value})); + case XFMEM_SETCHAN0_ALPHA: // Channel Alpha + return std::make_pair(RegName(XFMEM_SETCHAN0_ALPHA), + fmt::format("Channel 0 Alpha config:\n{}", LitChannel{.hex = value})); + case XFMEM_SETCHAN1_ALPHA: + return std::make_pair(RegName(XFMEM_SETCHAN1_ALPHA), + fmt::format("Channel 1 Alpha config:\n{}", LitChannel{.hex = value})); + + case XFMEM_DUALTEX: + return std::make_pair(RegName(XFMEM_DUALTEX), + fmt::format("Dual Tex Trans {}", (value & 1) ? "enabled" : "disabled")); + + case XFMEM_SETMATRIXINDA: + return std::make_pair(RegName(XFMEM_SETMATRIXINDA), + fmt::format("Matrix index A:\n{}", TMatrixIndexA{.Hex = value})); + case XFMEM_SETMATRIXINDB: + return std::make_pair(RegName(XFMEM_SETMATRIXINDB), + fmt::format("Matrix index B:\n{}", TMatrixIndexB{.Hex = value})); + + case XFMEM_SETVIEWPORT: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 0), + fmt::format("Viewport width: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 1: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 1), + fmt::format("Viewport height: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 2: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 2), + fmt::format("Viewport z range: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 3: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 3), + fmt::format("Viewport x origin: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 4: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 4), + fmt::format("Viewport y origin: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 5: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 5), + fmt::format("Viewport far z: {}", Common::BitCast(value))); + break; + + case XFMEM_SETPROJECTION: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 0), + fmt::format("Projection[0]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 1: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 1), + fmt::format("Projection[1]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 2: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 2), + fmt::format("Projection[2]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 3: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 3), + fmt::format("Projection[3]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 4: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 4), + fmt::format("Projection[4]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 5: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 5), + fmt::format("Projection[5]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 6: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 6), + fmt::to_string(static_cast(value))); + + case XFMEM_SETNUMTEXGENS: + return std::make_pair(RegName(XFMEM_SETNUMTEXGENS), + fmt::format("Number of tex gens: {}", value & 15)); + + case XFMEM_SETTEXMTXINFO: + case XFMEM_SETTEXMTXINFO + 1: + case XFMEM_SETTEXMTXINFO + 2: + case XFMEM_SETTEXMTXINFO + 3: + case XFMEM_SETTEXMTXINFO + 4: + case XFMEM_SETTEXMTXINFO + 5: + case XFMEM_SETTEXMTXINFO + 6: + case XFMEM_SETTEXMTXINFO + 7: + return std::make_pair( + fmt::format("XFMEM_SETTEXMTXINFO Matrix {}", address - XFMEM_SETTEXMTXINFO), + fmt::to_string(TexMtxInfo{.hex = value})); + + case XFMEM_SETPOSTMTXINFO: + case XFMEM_SETPOSTMTXINFO + 1: + case XFMEM_SETPOSTMTXINFO + 2: + case XFMEM_SETPOSTMTXINFO + 3: + case XFMEM_SETPOSTMTXINFO + 4: + case XFMEM_SETPOSTMTXINFO + 5: + case XFMEM_SETPOSTMTXINFO + 6: + case XFMEM_SETPOSTMTXINFO + 7: + return std::make_pair( + fmt::format("XFMEM_SETPOSTMTXINFO Matrix {}", address - XFMEM_SETPOSTMTXINFO), + fmt::to_string(PostMtxInfo{.hex = value})); + + // -------------- + // Unknown Regs + // -------------- + + // Maybe these are for Normals? + case 0x1048: // xfmem.texcoords[0].nrmmtxinfo.hex = data; break; ?? + case 0x1049: + case 0x104a: + case 0x104b: + case 0x104c: + case 0x104d: + case 0x104e: + case 0x104f: + return std::make_pair( + fmt::format("Possible Normal Mtx XF reg?: {:x}={:x}", address, value), + "Maybe these are for Normals? xfmem.texcoords[0].nrmmtxinfo.hex = data; break; ??"); + break; + + case 0x1013: + case 0x1014: + case 0x1015: + case 0x1016: + case 0x1017: + + default: + return std::make_pair(fmt::format("Unknown XF Reg: {:x}={:x}", address, value), ""); + } +#undef RegName +#undef DescriptionlessReg +} + +std::pair GetXFTransferInfo(const u8* data) +{ + const u32 cmd = Common::swap32(data); + data += 4; + u32 base_address = cmd & 0xFFFF; + const u32 transfer_size = ((cmd >> 16) & 15) + 1; + + if (base_address > XFMEM_REGISTERS_END) + { + return std::make_pair("Invalid XF Transfer", "Base address past end of address space"); + } + else if (transfer_size == 1 && base_address >= XFMEM_REGISTERS_START) + { + // Write directly to a single register + const u32 value = Common::swap32(data); + return GetXFRegInfo(base_address, value); + } + + // More complicated cases + fmt::memory_buffer name, desc; + u32 end_address = base_address + transfer_size; // exclusive + + // do not allow writes past registers + if (end_address > XFMEM_REGISTERS_END) + { + fmt::format_to(name, "Invalid XF Transfer "); + fmt::format_to(desc, "Transfer ends past end of address space\n\n"); + end_address = XFMEM_REGISTERS_END; + } + + // write to XF mem + if (base_address < XFMEM_REGISTERS_START) + { + const u32 xf_mem_base = base_address; + u32 xf_mem_transfer_size = transfer_size; + + if (end_address > XFMEM_REGISTERS_START) + { + xf_mem_transfer_size = XFMEM_REGISTERS_START - base_address; + base_address = XFMEM_REGISTERS_START; + data += 4 * xf_mem_transfer_size; + } + + fmt::format_to(name, "Write {} XF mem words at {:04x}", xf_mem_transfer_size, xf_mem_base); + + if (end_address > XFMEM_REGISTERS_START) + fmt::format_to(name, "; "); + } + + // write to XF regs + if (base_address >= XFMEM_REGISTERS_START) + { + fmt::format_to(name, "Write {} XF regs at {:04x}", end_address - base_address, base_address); + + for (u32 address = base_address; address < end_address; address++) + { + const u32 value = Common::swap32(data); + + const auto [regname, regdesc] = GetXFRegInfo(address, value); + fmt::format_to(desc, "{}\n{}\n", regname, regdesc); + + data += 4; + } + } + + return std::make_pair(fmt::to_string(name), fmt::to_string(desc)); +} diff --git a/Source/Core/VideoCommon/XFStructs.h b/Source/Core/VideoCommon/XFStructs.h index d6f8d48d46..25b2e5fccc 100644 --- a/Source/Core/VideoCommon/XFStructs.h +++ b/Source/Core/VideoCommon/XFStructs.h @@ -4,4 +4,10 @@ #pragma once +#include +#include + #include "VideoCommon/XFMemory.h" + +std::pair GetXFRegInfo(u32 address, u32 value); +std::pair GetXFTransferInfo(const u8* data); From 8c80369373706b2750067822d8d90a8ca719291a Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sat, 6 Feb 2021 23:30:01 -0800 Subject: [PATCH 11/17] Add names and descriptions for regular XF memory --- Source/Core/VideoCommon/XFStructs.cpp | 100 +++++++++++++++++++++++++- Source/Core/VideoCommon/XFStructs.h | 2 + 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index 0e9667c509..a4658b96de 100644 --- a/Source/Core/VideoCommon/XFStructs.cpp +++ b/Source/Core/VideoCommon/XFStructs.cpp @@ -475,6 +475,98 @@ std::pair GetXFRegInfo(u32 address, u32 value) #undef DescriptionlessReg } +std::string GetXFMemName(u32 address) +{ + if (address >= XFMEM_POSMATRICES && address < XFMEM_POSMATRICES_END) + { + const u32 row = (address - XFMEM_POSMATRICES) / 4; + const u32 col = (address - XFMEM_POSMATRICES) % 4; + return fmt::format("Position matrix row {:2d} col {:2d}", row, col); + } + else if (address >= XFMEM_NORMALMATRICES && address < XFMEM_NORMALMATRICES_END) + { + const u32 row = (address - XFMEM_NORMALMATRICES) / 3; + const u32 col = (address - XFMEM_NORMALMATRICES) % 3; + return fmt::format("Normal matrix row {:2d} col {:2d}", row, col); + } + else if (address >= XFMEM_POSTMATRICES && address < XFMEM_POSTMATRICES_END) + { + const u32 row = (address - XFMEM_POSMATRICES) / 4; + const u32 col = (address - XFMEM_POSMATRICES) % 4; + return fmt::format("Post matrix row {:2d} col {:2d}", row, col); + } + else if (address >= XFMEM_LIGHTS && address < XFMEM_LIGHTS_END) + { + const u32 light = (address - XFMEM_LIGHTS) / 16; + const u32 offset = (address - XFMEM_LIGHTS) % 16; + switch (offset) + { + default: + return fmt::format("Light {} unused param {}", light, offset); + case 3: + return fmt::format("Light {} color", light); + case 4: + case 5: + case 6: + return fmt::format("Light {} cosine attenuation {}", light, offset - 4); + case 7: + case 8: + case 9: + return fmt::format("Light {} distance attenuation {}", light, offset - 7); + case 10: + case 11: + case 12: + // Yagcd says light pos or "inf ldir", while dolphin has a union for dpos and sdir with only + // dpos being used nowadays. As far as I can tell only the DX9 engine once at + // Source/Plugins/Plugin_VideoDX9/Src/TransformEngine.cpp used sdir directly... + return fmt::format("Light {0} {1} position or inf ldir {1}", light, "xyz"[offset - 10]); + case 13: + case 14: + case 15: + // Yagcd says light dir or "1/2 angle", dolphin has union for ddir or shalfangle. + // It would make sense if d stood for direction and s for specular, but it's ddir and + // shalfhangle that have the comment "specular lights only", both at the same offset, + // while dpos and sdir have none... + return fmt::format("Light {0} {1} direction or half hangle {1}", light, "xyz"[offset - 13]); + } + } + else + { + return fmt::format("Unknown memory {:04x}", address); + } +} + +std::string GetXFMemDescription(u32 address, u32 value) +{ + if ((address >= XFMEM_POSMATRICES && address < XFMEM_POSMATRICES_END) || + (address >= XFMEM_NORMALMATRICES && address < XFMEM_NORMALMATRICES_END) || + (address >= XFMEM_POSTMATRICES && address < XFMEM_POSTMATRICES_END)) + { + // The matrices all use floats + return fmt::format("{} = {}", GetXFMemName(address), Common::BitCast(value)); + } + else if (address >= XFMEM_LIGHTS && address < XFMEM_LIGHTS_END) + { + // Each light is 16 words; for this function we don't care which light it is + const u32 offset = (address - XFMEM_LIGHTS) % 16; + if (offset <= 3) + { + // The unused parameters (0, 1, 2) and the color (3) should be hex-formatted + return fmt::format("{} = {:08x}", GetXFMemName(address), value); + } + else + { + // Everything else is a float + return fmt::format("{} = {}", GetXFMemName(address), Common::BitCast(value)); + } + } + else + { + // Unknown address + return fmt::format("{} = {:08x}", GetXFMemName(address), value); + } +} + std::pair GetXFTransferInfo(const u8* data) { const u32 cmd = Common::swap32(data); @@ -515,11 +607,17 @@ std::pair GetXFTransferInfo(const u8* data) { xf_mem_transfer_size = XFMEM_REGISTERS_START - base_address; base_address = XFMEM_REGISTERS_START; - data += 4 * xf_mem_transfer_size; } fmt::format_to(name, "Write {} XF mem words at {:04x}", xf_mem_transfer_size, xf_mem_base); + for (u32 i = 0; i < xf_mem_transfer_size; i++) + { + const auto mem_desc = GetXFMemDescription(xf_mem_base + i, Common::swap32(data)); + fmt::format_to(desc, i == 0 ? "{}" : "\n{}", mem_desc); + data += 4; + } + if (end_address > XFMEM_REGISTERS_START) fmt::format_to(name, "; "); } diff --git a/Source/Core/VideoCommon/XFStructs.h b/Source/Core/VideoCommon/XFStructs.h index 25b2e5fccc..5aac1f059b 100644 --- a/Source/Core/VideoCommon/XFStructs.h +++ b/Source/Core/VideoCommon/XFStructs.h @@ -10,4 +10,6 @@ #include "VideoCommon/XFMemory.h" std::pair GetXFRegInfo(u32 address, u32 value); +std::string GetXFMemName(u32 address); +std::string GetXFMemDescription(u32 address, u32 value); std::pair GetXFTransferInfo(const u8* data); From 81b84a5ebefb7396283b49412304544667966d6e Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Mon, 8 Feb 2021 22:15:33 -0800 Subject: [PATCH 12/17] Use XFMEM_REGISTERS_START/END in XFRegWritten and LoadXFReg --- Source/Core/VideoCommon/XFStructs.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index a4658b96de..741680b826 100644 --- a/Source/Core/VideoCommon/XFStructs.cpp +++ b/Source/Core/VideoCommon/XFStructs.cpp @@ -31,7 +31,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) u32 address = baseAddress; u32 dataIndex = 0; - while (transferSize > 0 && address < 0x1058) + while (transferSize > 0 && address < XFMEM_REGISTERS_END) { u32 newValue = src.Peek(dataIndex * sizeof(u32)); u32 nextAddress = address + 1; @@ -208,30 +208,30 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) void LoadXFReg(u32 transferSize, u32 baseAddress, DataReader src) { // do not allow writes past registers - if (baseAddress + transferSize > 0x1058) + if (baseAddress + transferSize > XFMEM_REGISTERS_END) { WARN_LOG_FMT(VIDEO, "XF load exceeds address space: {:x} {} bytes", baseAddress, transferSize); - if (baseAddress >= 0x1058) + if (baseAddress >= XFMEM_REGISTERS_END) transferSize = 0; else - transferSize = 0x1058 - baseAddress; + transferSize = XFMEM_REGISTERS_END - baseAddress; } // write to XF mem - if (baseAddress < 0x1000 && transferSize > 0) + if (baseAddress < XFMEM_REGISTERS_START && transferSize > 0) { u32 end = baseAddress + transferSize; u32 xfMemBase = baseAddress; u32 xfMemTransferSize = transferSize; - if (end >= 0x1000) + if (end >= XFMEM_REGISTERS_START) { - xfMemTransferSize = 0x1000 - baseAddress; + xfMemTransferSize = XFMEM_REGISTERS_START - baseAddress; - baseAddress = 0x1000; - transferSize = end - 0x1000; + baseAddress = XFMEM_REGISTERS_START; + transferSize = end - XFMEM_REGISTERS_START; } else { From 762fe33a3db823685aa5636bfe5ca372b46f9df7 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sun, 7 Feb 2021 12:32:45 -0800 Subject: [PATCH 13/17] Rename BPMEM_EFB_BR to BPMEM_EFB_WH --- Source/Core/VideoCommon/BPMemory.h | 2 +- Source/Core/VideoCommon/BPStructs.cpp | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Source/Core/VideoCommon/BPMemory.h b/Source/Core/VideoCommon/BPMemory.h index ad107382e4..86cc11f7d8 100644 --- a/Source/Core/VideoCommon/BPMemory.h +++ b/Source/Core/VideoCommon/BPMemory.h @@ -45,7 +45,7 @@ enum BPMEM_PE_TOKEN_ID = 0x47, BPMEM_PE_TOKEN_INT_ID = 0x48, BPMEM_EFB_TL = 0x49, - BPMEM_EFB_BR = 0x4A, + BPMEM_EFB_WH = 0x4A, BPMEM_EFB_ADDR = 0x4B, BPMEM_MIPMAP_STRIDE = 0x4D, BPMEM_COPYYSCALE = 0x4E, diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index 2376fd0840..896aafca30 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -432,7 +432,7 @@ static void BPWritten(const BPCmd& bp) // EFB Copy config // ---------------- case BPMEM_EFB_TL: // EFB Source Rect. Top, Left - case BPMEM_EFB_BR: // EFB Source Rect. Bottom, Right (w, h - 1) + case BPMEM_EFB_WH: // EFB Source Rect. Width, Height - 1 case BPMEM_EFB_ADDR: // EFB Target Address return; // -------------- @@ -995,10 +995,9 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) } break; - case BPMEM_EFB_BR: // 0x4A + case BPMEM_EFB_WH: // 0x4A { - // TODO: Misleading name, should be BPMEM_EFB_WH instead - SetRegName(BPMEM_EFB_BR); + SetRegName(BPMEM_EFB_WH); X10Y10 width_height; width_height.hex = cmddata; *desc = fmt::format("Width: {}\nHeight: {}", width_height.x + 1, width_height.y + 1); From f2bea6770966e6b69e4d005fbf1dc9de5c854a57 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 16 Feb 2021 00:35:45 -0800 Subject: [PATCH 14/17] Fix typo with ztex2 op in UseVertexDepthRange --- Source/Core/VideoCommon/RenderBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index fbba9fc12f..1a9af2f232 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -1697,7 +1697,7 @@ bool Renderer::UseVertexDepthRange() const return false; // We need a full depth range if a ztexture is used. - if (bpmem.ztex2.type != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest) + if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest) return true; // If an inverted depth range is unsupported, we also need to check if the range is inverted. From db8ced7e4e4724c38f148ee449c346e447dd3942 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Thu, 11 Feb 2021 22:38:07 -0800 Subject: [PATCH 15/17] Add FogParam0::FloatValue and FogParam3::FloatValue This value will be used in the register description; so expose it in a way that can be re-used instead of calculating it in 2 places later. --- Source/Core/VideoCommon/BPMemory.cpp | 26 ++++++++++++++++---------- Source/Core/VideoCommon/BPMemory.h | 2 ++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Source/Core/VideoCommon/BPMemory.cpp b/Source/Core/VideoCommon/BPMemory.cpp index cb510e9e6a..e3887327d3 100644 --- a/Source/Core/VideoCommon/BPMemory.cpp +++ b/Source/Core/VideoCommon/BPMemory.cpp @@ -47,16 +47,26 @@ bool FogParams::IsNaNCase() const return a.exp == 255 && c_proj_fsel.c_exp == 255; } +float FogParam0::FloatValue() const +{ + // scale mantissa from 11 to 23 bits + const u32 integral = (sign << 31) | (exp << 23) | (mant << 12); + return Common::BitCast(integral); +} + +float FogParam3::FloatValue() const +{ + // scale mantissa from 11 to 23 bits + const u32 integral = (c_sign << 31) | (c_exp << 23) | (c_mant << 12); + return Common::BitCast(integral); +} + float FogParams::GetA() const { if (IsNaNCase()) return 0.0f; - // scale mantissa from 11 to 23 bits - const u32 integral = (static_cast(a.sign) << 31) | (static_cast(a.exp) << 23) | - (static_cast(a.mant) << 12); - - return Common::BitCast(integral); + return a.FloatValue(); } float FogParams::GetC() const @@ -67,9 +77,5 @@ float FogParams::GetC() const return !a.sign && !c_proj_fsel.c_sign ? -inf : inf; } - // scale mantissa from 11 to 23 bits - const u32 integral = (c_proj_fsel.c_sign.Value() << 31) | (c_proj_fsel.c_exp.Value() << 23) | - (c_proj_fsel.c_mant.Value() << 12); - - return Common::BitCast(integral); + return c_proj_fsel.FloatValue(); } diff --git a/Source/Core/VideoCommon/BPMemory.h b/Source/Core/VideoCommon/BPMemory.h index 86cc11f7d8..f6d54a6e74 100644 --- a/Source/Core/VideoCommon/BPMemory.h +++ b/Source/Core/VideoCommon/BPMemory.h @@ -661,6 +661,7 @@ union FogParam0 BitField<19, 1, u32> sign; u32 hex; + float FloatValue() const; }; union FogParam3 @@ -673,6 +674,7 @@ union FogParam3 // backward exp, 7 - backward exp2 u32 hex; + float FloatValue() const; }; union FogRangeKElement From 70f9fc4e7526fc9cfc008a43cd33229f62be99b6 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 10 Feb 2021 18:11:31 -0800 Subject: [PATCH 16/17] Convert BPMemory to BitField and enum class Additional changes: - For TevStageCombiner's ColorCombiner and AlphaCombiner, op/comparison and scale/compare_mode have been split as there are different meanings and enums if bias is set to compare. (Shift has also been renamed to scale) - In TexMode0, min_filter has been split into min_mip and min_filter. - In TexImage1, image_type is now cache_manually_managed. - The unused bit in GenMode is now exposed. - LPSize's lineaspect is now named adjust_for_aspect_ratio. --- Source/Core/VideoBackends/D3D/D3DState.cpp | 14 +- .../Core/VideoBackends/D3D12/DX12Pipeline.cpp | 22 +- Source/Core/VideoBackends/OGL/OGLRender.cpp | 14 +- .../Core/VideoBackends/Software/Clipper.cpp | 7 +- .../VideoBackends/Software/EfbInterface.cpp | 156 +-- .../VideoBackends/Software/Rasterizer.cpp | 5 +- Source/Core/VideoBackends/Software/Tev.cpp | 329 ++--- Source/Core/VideoBackends/Software/Tev.h | 2 +- .../VideoBackends/Software/TextureEncoder.cpp | 28 +- .../VideoBackends/Software/TextureSampler.cpp | 28 +- .../Core/VideoBackends/Vulkan/VKPipeline.cpp | 50 +- .../Core/VideoBackends/Vulkan/VKRenderer.cpp | 6 +- Source/Core/VideoCommon/BPFunctions.cpp | 48 +- Source/Core/VideoCommon/BPMemory.cpp | 2 +- Source/Core/VideoCommon/BPMemory.h | 1221 +++++++++++------ Source/Core/VideoCommon/BPStructs.cpp | 148 +- Source/Core/VideoCommon/ConstantManager.h | 11 +- Source/Core/VideoCommon/PixelShaderGen.cpp | 310 +++-- Source/Core/VideoCommon/PixelShaderGen.h | 41 +- .../Core/VideoCommon/PixelShaderManager.cpp | 16 +- Source/Core/VideoCommon/RenderBase.cpp | 20 +- Source/Core/VideoCommon/RenderBase.h | 6 +- Source/Core/VideoCommon/RenderState.cpp | 152 +- Source/Core/VideoCommon/RenderState.h | 14 +- Source/Core/VideoCommon/SamplerCommon.h | 4 +- Source/Core/VideoCommon/ShaderCache.cpp | 2 +- Source/Core/VideoCommon/TextureCacheBase.cpp | 8 +- Source/Core/VideoCommon/TextureCacheBase.h | 6 +- .../VideoCommon/TextureConversionShader.cpp | 6 +- .../VideoCommon/TextureConverterShaderGen.cpp | 2 +- Source/Core/VideoCommon/TextureDecoder.h | 27 + Source/Core/VideoCommon/UberShaderPixel.cpp | 82 +- .../Core/VideoCommon/VertexLoaderManager.cpp | 2 +- 33 files changed, 1553 insertions(+), 1236 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index b345de0a38..b542c2b3de 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -378,7 +378,7 @@ ID3D11BlendState* StateCache::Get(BlendingState state) D3D11_LOGIC_OP_COPY_INVERTED, D3D11_LOGIC_OP_OR_INVERTED, D3D11_LOGIC_OP_NAND, D3D11_LOGIC_OP_SET}}; tdesc.LogicOpEnable = TRUE; - tdesc.LogicOp = logic_ops[state.logicmode]; + tdesc.LogicOp = logic_ops[u32(state.logicmode.Value())]; ComPtr res; HRESULT hr = D3D::device1->CreateBlendState1(&desc, res.GetAddressOf()); @@ -416,10 +416,10 @@ ID3D11BlendState* StateCache::Get(BlendingState state) use_dual_source ? D3D11_BLEND_INV_SRC1_ALPHA : D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_INV_DEST_ALPHA}}; - tdesc.SrcBlend = src_factors[state.srcfactor]; - tdesc.SrcBlendAlpha = src_factors[state.srcfactoralpha]; - tdesc.DestBlend = dst_factors[state.dstfactor]; - tdesc.DestBlendAlpha = dst_factors[state.dstfactoralpha]; + tdesc.SrcBlend = src_factors[u32(state.srcfactor.Value())]; + tdesc.SrcBlendAlpha = src_factors[u32(state.srcfactoralpha.Value())]; + tdesc.DestBlend = dst_factors[u32(state.dstfactor.Value())]; + tdesc.DestBlendAlpha = dst_factors[u32(state.dstfactoralpha.Value())]; tdesc.BlendOp = state.subtract ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD; tdesc.BlendOpAlpha = state.subtractAlpha ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD; @@ -441,7 +441,7 @@ ID3D11RasterizerState* StateCache::Get(RasterizationState state) D3D11_RASTERIZER_DESC desc = {}; desc.FillMode = D3D11_FILL_SOLID; - desc.CullMode = cull_modes[state.cullmode]; + desc.CullMode = cull_modes[u32(state.cullmode.Value())]; desc.ScissorEnable = TRUE; ComPtr res; @@ -477,7 +477,7 @@ ID3D11DepthStencilState* StateCache::Get(DepthState state) depthdc.DepthEnable = TRUE; depthdc.DepthWriteMask = state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - depthdc.DepthFunc = d3dCmpFuncs[state.func]; + depthdc.DepthFunc = d3dCmpFuncs[u32(state.func.Value())]; } else { diff --git a/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp b/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp index dfce47a2fb..4cd75c10e5 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp +++ b/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp @@ -66,7 +66,7 @@ static void GetD3DRasterizerDesc(D3D12_RASTERIZER_DESC* desc, const Rasterizatio {D3D12_CULL_MODE_NONE, D3D12_CULL_MODE_BACK, D3D12_CULL_MODE_FRONT, D3D12_CULL_MODE_FRONT}}; desc->FillMode = D3D12_FILL_MODE_SOLID; - desc->CullMode = cull_modes[rs_state.cullmode]; + desc->CullMode = cull_modes[u32(rs_state.cullmode.Value())]; desc->MultisampleEnable = fb_state.samples > 1; } @@ -80,7 +80,7 @@ static void GetD3DDepthDesc(D3D12_DEPTH_STENCIL_DESC* desc, const DepthState& st D3D12_COMPARISON_FUNC_ALWAYS}}; desc->DepthEnable = state.testenable; - desc->DepthFunc = compare_funcs[state.func]; + desc->DepthFunc = compare_funcs[u32(state.func.Value())]; desc->DepthWriteMask = state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; } @@ -135,24 +135,24 @@ static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state) rtblend->BlendOpAlpha = state.subtractAlpha ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD; if (state.usedualsrc) { - rtblend->SrcBlend = src_dual_src_factors[state.srcfactor]; - rtblend->SrcBlendAlpha = src_dual_src_factors[state.srcfactoralpha]; - rtblend->DestBlend = dst_dual_src_factors[state.dstfactor]; - rtblend->DestBlendAlpha = dst_dual_src_factors[state.dstfactoralpha]; + rtblend->SrcBlend = src_dual_src_factors[u32(state.srcfactor.Value())]; + rtblend->SrcBlendAlpha = src_dual_src_factors[u32(state.srcfactoralpha.Value())]; + rtblend->DestBlend = dst_dual_src_factors[u32(state.dstfactor.Value())]; + rtblend->DestBlendAlpha = dst_dual_src_factors[u32(state.dstfactoralpha.Value())]; } else { - rtblend->SrcBlend = src_factors[state.srcfactor]; - rtblend->SrcBlendAlpha = src_factors[state.srcfactoralpha]; - rtblend->DestBlend = dst_factors[state.dstfactor]; - rtblend->DestBlendAlpha = dst_factors[state.dstfactoralpha]; + rtblend->SrcBlend = src_factors[u32(state.srcfactor.Value())]; + rtblend->SrcBlendAlpha = src_factors[u32(state.srcfactoralpha.Value())]; + rtblend->DestBlend = dst_factors[u32(state.dstfactor.Value())]; + rtblend->DestBlendAlpha = dst_factors[u32(state.dstfactoralpha.Value())]; } } else { rtblend->LogicOpEnable = state.logicopenable; if (state.logicopenable) - rtblend->LogicOp = logic_ops[state.logicmode]; + rtblend->LogicOp = logic_ops[u32(state.logicmode.Value())]; } } diff --git a/Source/Core/VideoBackends/OGL/OGLRender.cpp b/Source/Core/VideoBackends/OGL/OGLRender.cpp index 6b99327fee..3bcf38c2ae 100644 --- a/Source/Core/VideoBackends/OGL/OGLRender.cpp +++ b/Source/Core/VideoBackends/OGL/OGLRender.cpp @@ -1140,11 +1140,11 @@ void Renderer::ApplyRasterizationState(const RasterizationState state) return; // none, ccw, cw, ccw - if (state.cullmode != GenMode::CULL_NONE) + if (state.cullmode != CullMode::None) { // TODO: GX_CULL_ALL not supported, yet! glEnable(GL_CULL_FACE); - glFrontFace(state.cullmode == GenMode::CULL_FRONT ? GL_CCW : GL_CW); + glFrontFace(state.cullmode == CullMode::Front ? GL_CCW : GL_CW); } else { @@ -1166,7 +1166,7 @@ void Renderer::ApplyDepthState(const DepthState state) { glEnable(GL_DEPTH_TEST); glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE); - glDepthFunc(glCmpFuncs[state.func]); + glDepthFunc(glCmpFuncs[u32(state.func.Value())]); } else { @@ -1229,8 +1229,10 @@ void Renderer::ApplyBlendingState(const BlendingState state) GLenum equation = state.subtract ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD; GLenum equationAlpha = state.subtractAlpha ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD; glBlendEquationSeparate(equation, equationAlpha); - glBlendFuncSeparate(src_factors[state.srcfactor], dst_factors[state.dstfactor], - src_factors[state.srcfactoralpha], dst_factors[state.dstfactoralpha]); + glBlendFuncSeparate(src_factors[u32(state.srcfactor.Value())], + dst_factors[u32(state.dstfactor.Value())], + src_factors[u32(state.srcfactoralpha.Value())], + dst_factors[u32(state.dstfactoralpha.Value())]); } const GLenum logic_op_codes[16] = { @@ -1244,7 +1246,7 @@ void Renderer::ApplyBlendingState(const BlendingState state) if (state.logicopenable) { glEnable(GL_COLOR_LOGIC_OP); - glLogicOp(logic_op_codes[state.logicmode]); + glLogicOp(logic_op_codes[u32(state.logicmode.Value())]); } else { diff --git a/Source/Core/VideoBackends/Software/Clipper.cpp b/Source/Core/VideoBackends/Software/Clipper.cpp index 4c4e0db52d..417bc63fa3 100644 --- a/Source/Core/VideoBackends/Software/Clipper.cpp +++ b/Source/Core/VideoBackends/Software/Clipper.cpp @@ -489,13 +489,16 @@ bool CullTest(const OutputVertexData* v0, const OutputVertexData* v1, const Outp backface = normalZDir <= 0.0f; - if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing + // TODO: Are these tests / the definition of backface above backwards? + if ((bpmem.genMode.cullmode == CullMode::Back || bpmem.genMode.cullmode == CullMode::All) && + !backface) // cull frontfacing { INCSTAT(g_stats.this_frame.num_triangles_culled) return false; } - if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing + if ((bpmem.genMode.cullmode == CullMode::Front || bpmem.genMode.cullmode == CullMode::All) && + backface) // cull backfacing { INCSTAT(g_stats.this_frame.num_triangles_culled) return false; diff --git a/Source/Core/VideoBackends/Software/EfbInterface.cpp b/Source/Core/VideoBackends/Software/EfbInterface.cpp index 0bd2f0343d..8ef62d5b03 100644 --- a/Source/Core/VideoBackends/Software/EfbInterface.cpp +++ b/Source/Core/VideoBackends/Software/EfbInterface.cpp @@ -41,12 +41,12 @@ static void SetPixelAlphaOnly(u32 offset, u8 a) { switch (bpmem.zcontrol.pixel_format) { - case PEControl::RGB8_Z24: - case PEControl::Z24: - case PEControl::RGB565_Z16: + case PixelFormat::RGB8_Z24: + case PixelFormat::Z24: + case PixelFormat::RGB565_Z16: // do nothing break; - case PEControl::RGBA6_Z24: + case PixelFormat::RGBA6_Z24: { u32 a32 = a; u32* dst = (u32*)&efb[offset]; @@ -56,8 +56,7 @@ static void SetPixelAlphaOnly(u32 offset, u8 a) } break; default: - ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", - static_cast(bpmem.zcontrol.pixel_format)); + ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format); break; } } @@ -66,8 +65,8 @@ static void SetPixelColorOnly(u32 offset, u8* rgb) { switch (bpmem.zcontrol.pixel_format) { - case PEControl::RGB8_Z24: - case PEControl::Z24: + case PixelFormat::RGB8_Z24: + case PixelFormat::Z24: { u32 src = *(u32*)rgb; u32* dst = (u32*)&efb[offset]; @@ -76,7 +75,7 @@ static void SetPixelColorOnly(u32 offset, u8* rgb) *dst = val; } break; - case PEControl::RGBA6_Z24: + case PixelFormat::RGBA6_Z24: { u32 src = *(u32*)rgb; u32* dst = (u32*)&efb[offset]; @@ -87,7 +86,7 @@ static void SetPixelColorOnly(u32 offset, u8* rgb) *dst = val; } break; - case PEControl::RGB565_Z16: + case PixelFormat::RGB565_Z16: { INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); u32 src = *(u32*)rgb; @@ -98,8 +97,7 @@ static void SetPixelColorOnly(u32 offset, u8* rgb) } break; default: - ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", - static_cast(bpmem.zcontrol.pixel_format)); + ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format); break; } } @@ -108,8 +106,8 @@ static void SetPixelAlphaColor(u32 offset, u8* color) { switch (bpmem.zcontrol.pixel_format) { - case PEControl::RGB8_Z24: - case PEControl::Z24: + case PixelFormat::RGB8_Z24: + case PixelFormat::Z24: { u32 src = *(u32*)color; u32* dst = (u32*)&efb[offset]; @@ -118,7 +116,7 @@ static void SetPixelAlphaColor(u32 offset, u8* color) *dst = val; } break; - case PEControl::RGBA6_Z24: + case PixelFormat::RGBA6_Z24: { u32 src = *(u32*)color; u32* dst = (u32*)&efb[offset]; @@ -130,7 +128,7 @@ static void SetPixelAlphaColor(u32 offset, u8* color) *dst = val; } break; - case PEControl::RGB565_Z16: + case PixelFormat::RGB565_Z16: { INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); u32 src = *(u32*)color; @@ -141,8 +139,7 @@ static void SetPixelAlphaColor(u32 offset, u8* color) } break; default: - ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", - static_cast(bpmem.zcontrol.pixel_format)); + ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format); break; } } @@ -154,23 +151,22 @@ static u32 GetPixelColor(u32 offset) switch (bpmem.zcontrol.pixel_format) { - case PEControl::RGB8_Z24: - case PEControl::Z24: + case PixelFormat::RGB8_Z24: + case PixelFormat::Z24: return 0xff | ((src & 0x00ffffff) << 8); - case PEControl::RGBA6_Z24: + case PixelFormat::RGBA6_Z24: return Convert6To8(src & 0x3f) | // Alpha Convert6To8((src >> 6) & 0x3f) << 8 | // Blue Convert6To8((src >> 12) & 0x3f) << 16 | // Green Convert6To8((src >> 18) & 0x3f) << 24; // Red - case PEControl::RGB565_Z16: + case PixelFormat::RGB565_Z16: INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); return 0xff | ((src & 0x00ffffff) << 8); default: - ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", - static_cast(bpmem.zcontrol.pixel_format)); + ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format); return 0; } } @@ -179,9 +175,9 @@ static void SetPixelDepth(u32 offset, u32 depth) { switch (bpmem.zcontrol.pixel_format) { - case PEControl::RGB8_Z24: - case PEControl::RGBA6_Z24: - case PEControl::Z24: + case PixelFormat::RGB8_Z24: + case PixelFormat::RGBA6_Z24: + case PixelFormat::Z24: { u32* dst = (u32*)&efb[offset]; u32 val = *dst & 0xff000000; @@ -189,7 +185,7 @@ static void SetPixelDepth(u32 offset, u32 depth) *dst = val; } break; - case PEControl::RGB565_Z16: + case PixelFormat::RGB565_Z16: { INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); u32* dst = (u32*)&efb[offset]; @@ -199,8 +195,7 @@ static void SetPixelDepth(u32 offset, u32 depth) } break; default: - ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", - static_cast(bpmem.zcontrol.pixel_format)); + ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format); break; } } @@ -211,59 +206,58 @@ static u32 GetPixelDepth(u32 offset) switch (bpmem.zcontrol.pixel_format) { - case PEControl::RGB8_Z24: - case PEControl::RGBA6_Z24: - case PEControl::Z24: + case PixelFormat::RGB8_Z24: + case PixelFormat::RGBA6_Z24: + case PixelFormat::Z24: { depth = (*(u32*)&efb[offset]) & 0x00ffffff; } break; - case PEControl::RGB565_Z16: + case PixelFormat::RGB565_Z16: { INFO_LOG_FMT(VIDEO, "RGB565_Z16 is not supported correctly yet"); depth = (*(u32*)&efb[offset]) & 0x00ffffff; } break; default: - ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", - static_cast(bpmem.zcontrol.pixel_format)); + ERROR_LOG_FMT(VIDEO, "Unsupported pixel format: {}", bpmem.zcontrol.pixel_format); break; } return depth; } -static u32 GetSourceFactor(u8* srcClr, u8* dstClr, BlendMode::BlendFactor mode) +static u32 GetSourceFactor(u8* srcClr, u8* dstClr, SrcBlendFactor mode) { switch (mode) { - case BlendMode::ZERO: + case SrcBlendFactor::Zero: return 0; - case BlendMode::ONE: + case SrcBlendFactor::One: return 0xffffffff; - case BlendMode::DSTCLR: + case SrcBlendFactor::DstClr: return *(u32*)dstClr; - case BlendMode::INVDSTCLR: + case SrcBlendFactor::InvDstClr: return 0xffffffff - *(u32*)dstClr; - case BlendMode::SRCALPHA: + case SrcBlendFactor::SrcAlpha: { u8 alpha = srcClr[ALP_C]; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; return factor; } - case BlendMode::INVSRCALPHA: + case SrcBlendFactor::InvSrcAlpha: { u8 alpha = 0xff - srcClr[ALP_C]; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; return factor; } - case BlendMode::DSTALPHA: + case SrcBlendFactor::DstAlpha: { u8 alpha = dstClr[ALP_C]; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; return factor; } - case BlendMode::INVDSTALPHA: + case SrcBlendFactor::InvDstAlpha: { u8 alpha = 0xff - dstClr[ALP_C]; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; @@ -274,37 +268,37 @@ static u32 GetSourceFactor(u8* srcClr, u8* dstClr, BlendMode::BlendFactor mode) return 0; } -static u32 GetDestinationFactor(u8* srcClr, u8* dstClr, BlendMode::BlendFactor mode) +static u32 GetDestinationFactor(u8* srcClr, u8* dstClr, DstBlendFactor mode) { switch (mode) { - case BlendMode::ZERO: + case DstBlendFactor::Zero: return 0; - case BlendMode::ONE: + case DstBlendFactor::One: return 0xffffffff; - case BlendMode::SRCCLR: + case DstBlendFactor::SrcClr: return *(u32*)srcClr; - case BlendMode::INVSRCCLR: + case DstBlendFactor::InvSrcClr: return 0xffffffff - *(u32*)srcClr; - case BlendMode::SRCALPHA: + case DstBlendFactor::SrcAlpha: { u8 alpha = srcClr[ALP_C]; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; return factor; } - case BlendMode::INVSRCALPHA: + case DstBlendFactor::InvSrcAlpha: { u8 alpha = 0xff - srcClr[ALP_C]; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; return factor; } - case BlendMode::DSTALPHA: + case DstBlendFactor::DstAlpha: { u8 alpha = dstClr[ALP_C] & 0xff; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; return factor; } - case BlendMode::INVDSTALPHA: + case DstBlendFactor::InvDstAlpha: { u8 alpha = 0xff - dstClr[ALP_C]; u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; @@ -337,56 +331,56 @@ static void BlendColor(u8* srcClr, u8* dstClr) } } -static void LogicBlend(u32 srcClr, u32* dstClr, BlendMode::LogicOp op) +static void LogicBlend(u32 srcClr, u32* dstClr, LogicOp op) { switch (op) { - case BlendMode::CLEAR: + case LogicOp::Clear: *dstClr = 0; break; - case BlendMode::AND: + case LogicOp::And: *dstClr = srcClr & *dstClr; break; - case BlendMode::AND_REVERSE: + case LogicOp::AndReverse: *dstClr = srcClr & (~*dstClr); break; - case BlendMode::COPY: + case LogicOp::Copy: *dstClr = srcClr; break; - case BlendMode::AND_INVERTED: + case LogicOp::AndInverted: *dstClr = (~srcClr) & *dstClr; break; - case BlendMode::NOOP: + case LogicOp::NoOp: // Do nothing break; - case BlendMode::XOR: + case LogicOp::Xor: *dstClr = srcClr ^ *dstClr; break; - case BlendMode::OR: + case LogicOp::Or: *dstClr = srcClr | *dstClr; break; - case BlendMode::NOR: + case LogicOp::Nor: *dstClr = ~(srcClr | *dstClr); break; - case BlendMode::EQUIV: + case LogicOp::Equiv: *dstClr = ~(srcClr ^ *dstClr); break; - case BlendMode::INVERT: + case LogicOp::Invert: *dstClr = ~*dstClr; break; - case BlendMode::OR_REVERSE: + case LogicOp::OrReverse: *dstClr = srcClr | (~*dstClr); break; - case BlendMode::COPY_INVERTED: + case LogicOp::CopyInverted: *dstClr = ~srcClr; break; - case BlendMode::OR_INVERTED: + case LogicOp::OrInverted: *dstClr = (~srcClr) | *dstClr; break; - case BlendMode::NAND: + case LogicOp::Nand: *dstClr = ~(srcClr & *dstClr); break; - case BlendMode::SET: + case LogicOp::Set: *dstClr = 0xffffffff; break; } @@ -404,7 +398,7 @@ static void SubtractBlend(u8* srcClr, u8* dstClr) static void Dither(u16 x, u16 y, u8* color) { // No blending for RGB8 mode - if (!bpmem.blendmode.dither || bpmem.zcontrol.pixel_format != PEControl::PixelFormat::RGBA6_Z24) + if (!bpmem.blendmode.dither || bpmem.zcontrol.pixel_format != PixelFormat::RGBA6_Z24) return; // Flipper uses a standard 2x2 Bayer Matrix for 6 bit dithering @@ -662,33 +656,33 @@ bool ZCompare(u16 x, u16 y, u32 z) switch (bpmem.zmode.func) { - case ZMode::NEVER: + case CompareMode::Never: pass = false; break; - case ZMode::LESS: + case CompareMode::Less: pass = z < depth; break; - case ZMode::EQUAL: + case CompareMode::Equal: pass = z == depth; break; - case ZMode::LEQUAL: + case CompareMode::LEqual: pass = z <= depth; break; - case ZMode::GREATER: + case CompareMode::Greater: pass = z > depth; break; - case ZMode::NEQUAL: + case CompareMode::NEqual: pass = z != depth; break; - case ZMode::GEQUAL: + case CompareMode::GEqual: pass = z >= depth; break; - case ZMode::ALWAYS: + case CompareMode::Always: pass = true; break; default: pass = false; - ERROR_LOG_FMT(VIDEO, "Bad Z compare mode {}", static_cast(bpmem.zmode.func)); + ERROR_LOG_FMT(VIDEO, "Bad Z compare mode {}", bpmem.zmode.func); break; } diff --git a/Source/Core/VideoBackends/Software/Rasterizer.cpp b/Source/Core/VideoBackends/Software/Rasterizer.cpp index 394bfea41e..e987817c8c 100644 --- a/Source/Core/VideoBackends/Software/Rasterizer.cpp +++ b/Source/Core/VideoBackends/Software/Rasterizer.cpp @@ -173,7 +173,7 @@ static inline void CalculateLOD(s32* lodp, bool* linear, u32 texmap, u32 texcoor const TexMode1& tm1 = texUnit.texMode1[subTexmap]; float sDelta, tDelta; - if (tm0.diag_lod) + if (tm0.diag_lod == LODType::Diagonal) { float* uv0 = rasterBlock.Pixel[0][0].Uv[texcoord]; float* uv1 = rasterBlock.Pixel[1][1].Uv[texcoord]; @@ -199,7 +199,8 @@ static inline void CalculateLOD(s32* lodp, bool* linear, u32 texmap, u32 texcoor bias >>= 1; lod += bias; - *linear = ((lod > 0 && (tm0.min_filter & 4)) || (lod <= 0 && tm0.mag_filter)); + *linear = ((lod > 0 && tm0.min_filter == FilterMode::Linear) || + (lod <= 0 && tm0.mag_filter == FilterMode::Linear)); // NOTE: The order of comparisons for this clamp check matters. if (lod > static_cast(tm1.max_lod)) diff --git a/Source/Core/VideoBackends/Software/Tev.cpp b/Source/Core/VideoBackends/Software/Tev.cpp index fed65d2bec..65227339e4 100644 --- a/Source/Core/VideoBackends/Software/Tev.cpp +++ b/Source/Core/VideoBackends/Software/Tev.cpp @@ -172,11 +172,11 @@ static inline s16 Clamp1024(s16 in) return in > 1023 ? 1023 : (in < -1024 ? -1024 : in); } -void Tev::SetRasColor(int colorChan, int swaptable) +void Tev::SetRasColor(RasColorChan colorChan, int swaptable) { switch (colorChan) { - case 0: // Color0 + case RasColorChan::Color0: { const u8* color = Color[0]; RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1]; @@ -186,7 +186,7 @@ void Tev::SetRasColor(int colorChan, int swaptable) RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2]; } break; - case 1: // Color1 + case RasColorChan::Color1: { const u8* color = Color[1]; RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1]; @@ -196,7 +196,7 @@ void Tev::SetRasColor(int colorChan, int swaptable) RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2]; } break; - case 5: // alpha bump + case RasColorChan::AlphaBump: { for (s16& comp : RasColor) { @@ -204,7 +204,7 @@ void Tev::SetRasColor(int colorChan, int swaptable) } } break; - case 6: // alpha bump normalized + case RasColorChan::NormalizedAlphaBump: { const u8 normalized = AlphaBump | AlphaBump >> 5; for (s16& comp : RasColor) @@ -213,8 +213,11 @@ void Tev::SetRasColor(int colorChan, int swaptable) } } break; - default: // zero + default: { + if (colorChan != RasColorChan::Zero) + PanicAlertFmt("Invalid ras color channel: {}", colorChan); + for (s16& comp : RasColor) { comp = 0; @@ -226,22 +229,24 @@ void Tev::SetRasColor(int colorChan, int swaptable) void Tev::DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]) { - for (int i = 0; i < 3; i++) + for (int i = BLU_C; i <= RED_C; i++) { - const InputRegType& InputReg = inputs[BLU_C + i]; + const InputRegType& InputReg = inputs[i]; const u16 c = InputReg.c + (InputReg.c >> 7); s32 temp = InputReg.a * (256 - c) + (InputReg.b * c); - temp <<= m_ScaleLShiftLUT[cc.shift]; - temp += (cc.shift == 3) ? 0 : (cc.op == 1) ? 127 : 128; + temp <<= m_ScaleLShiftLUT[u32(cc.scale.Value())]; + temp += (cc.scale == TevScale::Divide2) ? 0 : (cc.op == TevOp::Sub) ? 127 : 128; temp >>= 8; - temp = cc.op ? -temp : temp; + temp = cc.op == TevOp::Sub ? -temp : temp; - s32 result = ((InputReg.d + m_BiasLUT[cc.bias]) << m_ScaleLShiftLUT[cc.shift]) + temp; - result = result >> m_ScaleRShiftLUT[cc.shift]; + s32 result = ((InputReg.d + m_BiasLUT[u32(cc.bias.Value())]) + << m_ScaleLShiftLUT[u32(cc.scale.Value())]) + + temp; + result = result >> m_ScaleRShiftLUT[u32(cc.scale.Value())]; - Reg[cc.dest][BLU_C + i] = result; + Reg[u32(cc.dest.Value())][i] = result; } } @@ -249,56 +254,38 @@ void Tev::DrawColorCompare(const TevStageCombiner::ColorCombiner& cc, const Inpu { for (int i = BLU_C; i <= RED_C; i++) { - switch ((cc.shift << 1) | cc.op | 8) // encoded compare mode + u32 a, b; + switch (cc.compare_mode) { - case TEVCMP_R8_GT: - Reg[cc.dest][i] = inputs[i].d + ((inputs[RED_C].a > inputs[RED_C].b) ? inputs[i].c : 0); + case TevCompareMode::R8: + a = inputs[RED_C].a; + b = inputs[RED_C].b; break; - case TEVCMP_R8_EQ: - Reg[cc.dest][i] = inputs[i].d + ((inputs[RED_C].a == inputs[RED_C].b) ? inputs[i].c : 0); + case TevCompareMode::GR16: + a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; + b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; break; - case TEVCMP_GR16_GT: - { - const u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; - const u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0); - } - break; - - case TEVCMP_GR16_EQ: - { - const u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; - const u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0); - } - break; - - case TEVCMP_BGR24_GT: - { - const u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; - const u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0); - } - break; - - case TEVCMP_BGR24_EQ: - { - const u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; - const u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0); - } - break; - - case TEVCMP_RGB8_GT: - Reg[cc.dest][i] = inputs[i].d + ((inputs[i].a > inputs[i].b) ? inputs[i].c : 0); + case TevCompareMode::BGR24: + a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; + b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; break; - case TEVCMP_RGB8_EQ: - Reg[cc.dest][i] = inputs[i].d + ((inputs[i].a == inputs[i].b) ? inputs[i].c : 0); + case TevCompareMode::RGB8: + a = inputs[i].a; + b = inputs[i].b; break; + + default: + PanicAlertFmt("Invalid compare mode {}", cc.compare_mode); + continue; } + + if (cc.comparison == TevComparison::GT) + Reg[u32(cc.dest.Value())][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0); + else + Reg[u32(cc.dest.Value())][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0); } } @@ -309,95 +296,76 @@ void Tev::DrawAlphaRegular(const TevStageCombiner::AlphaCombiner& ac, const Inpu const u16 c = InputReg.c + (InputReg.c >> 7); s32 temp = InputReg.a * (256 - c) + (InputReg.b * c); - temp <<= m_ScaleLShiftLUT[ac.shift]; - temp += (ac.shift != 3) ? 0 : (ac.op == 1) ? 127 : 128; - temp = ac.op ? (-temp >> 8) : (temp >> 8); + temp <<= m_ScaleLShiftLUT[u32(ac.scale.Value())]; + temp += (ac.scale != TevScale::Divide2) ? 0 : (ac.op == TevOp::Sub) ? 127 : 128; + temp = ac.op == TevOp::Sub ? (-temp >> 8) : (temp >> 8); - s32 result = ((InputReg.d + m_BiasLUT[ac.bias]) << m_ScaleLShiftLUT[ac.shift]) + temp; - result = result >> m_ScaleRShiftLUT[ac.shift]; + s32 result = + ((InputReg.d + m_BiasLUT[u32(ac.bias.Value())]) << m_ScaleLShiftLUT[u32(ac.scale.Value())]) + + temp; + result = result >> m_ScaleRShiftLUT[u32(ac.scale.Value())]; - Reg[ac.dest][ALP_C] = result; + Reg[u32(ac.dest.Value())][ALP_C] = result; } void Tev::DrawAlphaCompare(const TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]) { - switch ((ac.shift << 1) | ac.op | 8) // encoded compare mode + u32 a, b; + switch (ac.compare_mode) { - case TEVCMP_R8_GT: - Reg[ac.dest][ALP_C] = - inputs[ALP_C].d + ((inputs[RED_C].a > inputs[RED_C].b) ? inputs[ALP_C].c : 0); + case TevCompareMode::R8: + a = inputs[RED_C].a; + b = inputs[RED_C].b; break; - case TEVCMP_R8_EQ: - Reg[ac.dest][ALP_C] = - inputs[ALP_C].d + ((inputs[RED_C].a == inputs[RED_C].b) ? inputs[ALP_C].c : 0); + case TevCompareMode::GR16: + a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; + b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; break; - case TEVCMP_GR16_GT: - { - const u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; - const u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0); - } - break; - - case TEVCMP_GR16_EQ: - { - const u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; - const u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0); - } - break; - - case TEVCMP_BGR24_GT: - { - const u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; - const u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0); - } - break; - - case TEVCMP_BGR24_EQ: - { - const u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; - const u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0); - } - break; - - case TEVCMP_A8_GT: - Reg[ac.dest][ALP_C] = - inputs[ALP_C].d + ((inputs[ALP_C].a > inputs[ALP_C].b) ? inputs[ALP_C].c : 0); + case TevCompareMode::BGR24: + a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; + b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; break; - case TEVCMP_A8_EQ: - Reg[ac.dest][ALP_C] = - inputs[ALP_C].d + ((inputs[ALP_C].a == inputs[ALP_C].b) ? inputs[ALP_C].c : 0); + case TevCompareMode::A8: + a = inputs[ALP_C].a; + b = inputs[ALP_C].b; break; + + default: + PanicAlertFmt("Invalid compare mode {}", ac.compare_mode); + return; } + + if (ac.comparison == TevComparison::GT) + Reg[u32(ac.dest.Value())][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0); + else + Reg[u32(ac.dest.Value())][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0); } -static bool AlphaCompare(int alpha, int ref, AlphaTest::CompareMode comp) +static bool AlphaCompare(int alpha, int ref, CompareMode comp) { switch (comp) { - case AlphaTest::ALWAYS: + case CompareMode::Always: return true; - case AlphaTest::NEVER: + case CompareMode::Never: return false; - case AlphaTest::LEQUAL: + case CompareMode::LEqual: return alpha <= ref; - case AlphaTest::LESS: + case CompareMode::Less: return alpha < ref; - case AlphaTest::GEQUAL: + case CompareMode::GEqual: return alpha >= ref; - case AlphaTest::GREATER: + case CompareMode::Greater: return alpha > ref; - case AlphaTest::EQUAL: + case CompareMode::Equal: return alpha == ref; - case AlphaTest::NEQUAL: + case CompareMode::NEqual: return alpha != ref; default: + PanicAlertFmt("Invalid compare mode {}", comp); return true; } } @@ -409,38 +377,40 @@ static bool TevAlphaTest(int alpha) switch (bpmem.alpha_test.logic) { - case 0: - return comp0 && comp1; // and - case 1: - return comp0 || comp1; // or - case 2: - return comp0 ^ comp1; // xor - case 3: - return !(comp0 ^ comp1); // xnor + case AlphaTestOp::And: + return comp0 && comp1; + case AlphaTestOp::Or: + return comp0 || comp1; + case AlphaTestOp::Xor: + return comp0 ^ comp1; + case AlphaTestOp::Xnor: + return !(comp0 ^ comp1); default: + PanicAlertFmt("Invalid AlphaTestOp {}", bpmem.alpha_test.logic); return true; } } -static inline s32 WrapIndirectCoord(s32 coord, int wrapMode) +static inline s32 WrapIndirectCoord(s32 coord, IndTexWrap wrapMode) { switch (wrapMode) { - case ITW_OFF: + case IndTexWrap::ITW_OFF: return coord; - case ITW_256: + case IndTexWrap::ITW_256: return (coord & ((256 << 7) - 1)); - case ITW_128: + case IndTexWrap::ITW_128: return (coord & ((128 << 7) - 1)); - case ITW_64: + case IndTexWrap::ITW_64: return (coord & ((64 << 7) - 1)); - case ITW_32: + case IndTexWrap::ITW_32: return (coord & ((32 << 7) - 1)); - case ITW_16: + case IndTexWrap::ITW_16: return (coord & ((16 << 7) - 1)); - case ITW_0: + case IndTexWrap::ITW_0: return 0; default: + PanicAlertFmt("Invalid indirect wrap mode {}", wrapMode); return 0; } } @@ -455,56 +425,59 @@ void Tev::Indirect(unsigned int stageNum, s32 s, s32 t) // alpha bump select switch (indirect.bs) { - case ITBA_OFF: + case IndTexBumpAlpha::Off: AlphaBump = 0; break; - case ITBA_S: + case IndTexBumpAlpha::S: AlphaBump = indmap[TextureSampler::ALP_SMP]; break; - case ITBA_T: + case IndTexBumpAlpha::T: AlphaBump = indmap[TextureSampler::BLU_SMP]; break; - case ITBA_U: + case IndTexBumpAlpha::U: AlphaBump = indmap[TextureSampler::GRN_SMP]; break; + default: + PanicAlertFmt("Invalid alpha bump {}", indirect.bs); + return; } // bias select - const s16 biasValue = indirect.fmt == ITF_8 ? -128 : 1; + const s16 biasValue = indirect.fmt == IndTexFormat::ITF_8 ? -128 : 1; s16 bias[3]; - bias[0] = indirect.bias & 1 ? biasValue : 0; - bias[1] = indirect.bias & 2 ? biasValue : 0; - bias[2] = indirect.bias & 4 ? biasValue : 0; + bias[0] = indirect.bias_s ? biasValue : 0; + bias[1] = indirect.bias_t ? biasValue : 0; + bias[2] = indirect.bias_u ? biasValue : 0; // format switch (indirect.fmt) { - case ITF_8: + case IndTexFormat::ITF_8: indcoord[0] = indmap[TextureSampler::ALP_SMP] + bias[0]; indcoord[1] = indmap[TextureSampler::BLU_SMP] + bias[1]; indcoord[2] = indmap[TextureSampler::GRN_SMP] + bias[2]; AlphaBump = AlphaBump & 0xf8; break; - case ITF_5: + case IndTexFormat::ITF_5: indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x1f) + bias[0]; indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x1f) + bias[1]; indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x1f) + bias[2]; AlphaBump = AlphaBump & 0xe0; break; - case ITF_4: + case IndTexFormat::ITF_4: indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x0f) + bias[0]; indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x0f) + bias[1]; indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x0f) + bias[2]; AlphaBump = AlphaBump & 0xf0; break; - case ITF_3: + case IndTexFormat::ITF_3: indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x07) + bias[0]; indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x07) + bias[1]; indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x07) + bias[2]; AlphaBump = AlphaBump & 0xf8; break; default: - PanicAlertFmt("Tev::Indirect"); + PanicAlertFmt("Invalid indirect format {}", indirect.fmt); return; } @@ -648,8 +621,8 @@ void Tev::Draw() } // set konst for this stage - const int kc = kSel.getKC(stageOdd); - const int ka = kSel.getKA(stageOdd); + const auto kc = u32(kSel.getKC(stageOdd)); + const auto ka = u32(kSel.getKA(stageOdd)); StageKonst[RED_C] = *(m_KonstLUT[kc][RED_C]); StageKonst[GRN_C] = *(m_KonstLUT[kc][GRN_C]); StageKonst[BLU_C] = *(m_KonstLUT[kc][BLU_C]); @@ -662,43 +635,43 @@ void Tev::Draw() InputRegType inputs[4]; for (int i = 0; i < 3; i++) { - inputs[BLU_C + i].a = *m_ColorInputLUT[cc.a][i]; - inputs[BLU_C + i].b = *m_ColorInputLUT[cc.b][i]; - inputs[BLU_C + i].c = *m_ColorInputLUT[cc.c][i]; - inputs[BLU_C + i].d = *m_ColorInputLUT[cc.d][i]; + inputs[BLU_C + i].a = *m_ColorInputLUT[u32(cc.a.Value())][i]; + inputs[BLU_C + i].b = *m_ColorInputLUT[u32(cc.b.Value())][i]; + inputs[BLU_C + i].c = *m_ColorInputLUT[u32(cc.c.Value())][i]; + inputs[BLU_C + i].d = *m_ColorInputLUT[u32(cc.d.Value())][i]; } - inputs[ALP_C].a = *m_AlphaInputLUT[ac.a]; - inputs[ALP_C].b = *m_AlphaInputLUT[ac.b]; - inputs[ALP_C].c = *m_AlphaInputLUT[ac.c]; - inputs[ALP_C].d = *m_AlphaInputLUT[ac.d]; + inputs[ALP_C].a = *m_AlphaInputLUT[u32(ac.a.Value())]; + inputs[ALP_C].b = *m_AlphaInputLUT[u32(ac.b.Value())]; + inputs[ALP_C].c = *m_AlphaInputLUT[u32(ac.c.Value())]; + inputs[ALP_C].d = *m_AlphaInputLUT[u32(ac.d.Value())]; - if (cc.bias != 3) + if (cc.bias != TevBias::Compare) DrawColorRegular(cc, inputs); else DrawColorCompare(cc, inputs); if (cc.clamp) { - Reg[cc.dest][RED_C] = Clamp255(Reg[cc.dest][RED_C]); - Reg[cc.dest][GRN_C] = Clamp255(Reg[cc.dest][GRN_C]); - Reg[cc.dest][BLU_C] = Clamp255(Reg[cc.dest][BLU_C]); + Reg[u32(cc.dest.Value())][RED_C] = Clamp255(Reg[u32(cc.dest.Value())][RED_C]); + Reg[u32(cc.dest.Value())][GRN_C] = Clamp255(Reg[u32(cc.dest.Value())][GRN_C]); + Reg[u32(cc.dest.Value())][BLU_C] = Clamp255(Reg[u32(cc.dest.Value())][BLU_C]); } else { - Reg[cc.dest][RED_C] = Clamp1024(Reg[cc.dest][RED_C]); - Reg[cc.dest][GRN_C] = Clamp1024(Reg[cc.dest][GRN_C]); - Reg[cc.dest][BLU_C] = Clamp1024(Reg[cc.dest][BLU_C]); + Reg[u32(cc.dest.Value())][RED_C] = Clamp1024(Reg[u32(cc.dest.Value())][RED_C]); + Reg[u32(cc.dest.Value())][GRN_C] = Clamp1024(Reg[u32(cc.dest.Value())][GRN_C]); + Reg[u32(cc.dest.Value())][BLU_C] = Clamp1024(Reg[u32(cc.dest.Value())][BLU_C]); } - if (ac.bias != 3) + if (ac.bias != TevBias::Compare) DrawAlphaRegular(ac, inputs); else DrawAlphaCompare(ac, inputs); if (ac.clamp) - Reg[ac.dest][ALP_C] = Clamp255(Reg[ac.dest][ALP_C]); + Reg[u32(ac.dest.Value())][ALP_C] = Clamp255(Reg[u32(ac.dest.Value())][ALP_C]); else - Reg[ac.dest][ALP_C] = Clamp1024(Reg[ac.dest][ALP_C]); + Reg[u32(ac.dest.Value())][ALP_C] = Clamp1024(Reg[u32(ac.dest.Value())][ALP_C]); #if ALLOW_TEV_DUMPS if (g_ActiveConfig.bDumpTevStages) @@ -712,8 +685,8 @@ void Tev::Draw() // convert to 8 bits per component // the results of the last tev stage are put onto the screen, // regardless of the used destination register - TODO: Verify! - const u32 color_index = bpmem.combiners[bpmem.genMode.numtevstages].colorC.dest; - const u32 alpha_index = bpmem.combiners[bpmem.genMode.numtevstages].alphaC.dest; + const u32 color_index = u32(bpmem.combiners[bpmem.genMode.numtevstages].colorC.dest.Value()); + const u32 alpha_index = u32(bpmem.combiners[bpmem.genMode.numtevstages].alphaC.dest.Value()); u8 output[4] = {(u8)Reg[alpha_index][ALP_C], (u8)Reg[color_index][BLU_C], (u8)Reg[color_index][GRN_C], (u8)Reg[color_index][RED_C]}; @@ -721,34 +694,36 @@ void Tev::Draw() return; // z texture - if (bpmem.ztex2.op) + if (bpmem.ztex2.op != ZTexOp::Disabled) { u32 ztex = bpmem.ztex1.bias; switch (bpmem.ztex2.type) { - case 0: // 8 bit + case ZTexFormat::U8: ztex += TexColor[ALP_C]; break; - case 1: // 16 bit + case ZTexFormat::U16: ztex += TexColor[ALP_C] << 8 | TexColor[RED_C]; break; - case 2: // 24 bit + case ZTexFormat::U24: ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C]; break; + default: + PanicAlertFmt("Invalid ztex format {}", bpmem.ztex2.type); } - if (bpmem.ztex2.op == ZTEXTURE_ADD) + if (bpmem.ztex2.op == ZTexOp::Add) ztex += Position[2]; Position[2] = ztex & 0x00ffffff; } // fog - if (bpmem.fog.c_proj_fsel.fsel) + if (bpmem.fog.c_proj_fsel.fsel != FogType::Off) { float ze; - if (bpmem.fog.c_proj_fsel.proj == 0) + if (bpmem.fog.c_proj_fsel.proj == FogProjection::Perspective) { // perspective // ze = A/(B - (Zs >> B_SHF)) @@ -804,17 +779,17 @@ void Tev::Draw() switch (bpmem.fog.c_proj_fsel.fsel) { - case 4: // exp + case FogType::Exp: fog = 1.0f - pow(2.0f, -8.0f * fog); break; - case 5: // exp2 + case FogType::ExpSq: fog = 1.0f - pow(2.0f, -8.0f * fog * fog); break; - case 6: // backward exp + case FogType::BackwardsExp: fog = 1.0f - fog; fog = pow(2.0f, -8.0f * fog); break; - case 7: // backward exp2 + case FogType::BackwardsExpSq: fog = 1.0f - fog; fog = pow(2.0f, -8.0f * fog * fog); break; diff --git a/Source/Core/VideoBackends/Software/Tev.h b/Source/Core/VideoBackends/Software/Tev.h index 41d880be86..119ab91bd1 100644 --- a/Source/Core/VideoBackends/Software/Tev.h +++ b/Source/Core/VideoBackends/Software/Tev.h @@ -57,7 +57,7 @@ class Tev INDIRECT = 32 }; - void SetRasColor(int colorChan, int swaptable); + void SetRasColor(RasColorChan colorChan, int swaptable); void DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]); void DrawColorCompare(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]); diff --git a/Source/Core/VideoBackends/Software/TextureEncoder.cpp b/Source/Core/VideoBackends/Software/TextureEncoder.cpp index ff1dd97b96..5ca84558dd 100644 --- a/Source/Core/VideoBackends/Software/TextureEncoder.cpp +++ b/Source/Core/VideoBackends/Software/TextureEncoder.cpp @@ -504,7 +504,7 @@ static void EncodeRGBA6(u8* dst, const u8* src, EFBCopyFormat format, bool yuv) break; default: - PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); + PanicAlertFmt("Unknown texture copy format: {}\n", format); break; } } @@ -743,7 +743,7 @@ static void EncodeRGBA6halfscale(u8* dst, const u8* src, EFBCopyFormat format, b break; default: - PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); + PanicAlertFmt("Unknown texture copy format: {}\n", format); break; } } @@ -960,7 +960,7 @@ static void EncodeRGB8(u8* dst, const u8* src, EFBCopyFormat format, bool yuv) break; default: - PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); + PanicAlertFmt("Unknown texture copy format: {}\n", format); break; } } @@ -1192,7 +1192,7 @@ static void EncodeRGB8halfscale(u8* dst, const u8* src, EFBCopyFormat format, bo break; default: - PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); + PanicAlertFmt("Unknown texture copy format: {}\n", format); break; } } @@ -1300,7 +1300,7 @@ static void EncodeZ24(u8* dst, const u8* src, EFBCopyFormat format) break; default: - PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); + PanicAlertFmt("Unknown texture copy format: {}\n", format); break; } } @@ -1414,7 +1414,7 @@ static void EncodeZ24halfscale(u8* dst, const u8* src, EFBCopyFormat format) break; default: - PanicAlertFmt("Unknown texture copy format: {:#x}\n", format); + PanicAlertFmt("Unknown texture copy format: {}\n", format); break; } } @@ -1431,16 +1431,16 @@ void EncodeEfbCopy(u8* dst, const EFBCopyParams& params, u32 native_width, u32 b { switch (params.efb_format) { - case PEControl::RGBA6_Z24: + case PixelFormat::RGBA6_Z24: EncodeRGBA6halfscale(dst, src, params.copy_format, params.yuv); break; - case PEControl::RGB8_Z24: + case PixelFormat::RGB8_Z24: EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv); break; - case PEControl::RGB565_Z16: + case PixelFormat::RGB565_Z16: EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv); break; - case PEControl::Z24: + case PixelFormat::Z24: EncodeZ24halfscale(dst, src, params.copy_format); break; default: @@ -1451,16 +1451,16 @@ void EncodeEfbCopy(u8* dst, const EFBCopyParams& params, u32 native_width, u32 b { switch (params.efb_format) { - case PEControl::RGBA6_Z24: + case PixelFormat::RGBA6_Z24: EncodeRGBA6(dst, src, params.copy_format, params.yuv); break; - case PEControl::RGB8_Z24: + case PixelFormat::RGB8_Z24: EncodeRGB8(dst, src, params.copy_format, params.yuv); break; - case PEControl::RGB565_Z16: + case PixelFormat::RGB565_Z16: EncodeRGB8(dst, src, params.copy_format, params.yuv); break; - case PEControl::Z24: + case PixelFormat::Z24: EncodeZ24(dst, src, params.copy_format); break; default: diff --git a/Source/Core/VideoBackends/Software/TextureSampler.cpp b/Source/Core/VideoBackends/Software/TextureSampler.cpp index 93ff4ba44e..799db7c49b 100644 --- a/Source/Core/VideoBackends/Software/TextureSampler.cpp +++ b/Source/Core/VideoBackends/Software/TextureSampler.cpp @@ -8,6 +8,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/MsgHandler.h" #include "Core/HW/Memmap.h" #include "VideoCommon/BPMemory.h" @@ -18,27 +19,29 @@ namespace TextureSampler { -static inline void WrapCoord(int* coordp, int wrapMode, int imageSize) +static inline void WrapCoord(int* coordp, WrapMode wrapMode, int imageSize) { int coord = *coordp; switch (wrapMode) { - case 0: // clamp + case WrapMode::Clamp: coord = (coord > imageSize) ? imageSize : (coord < 0) ? 0 : coord; break; - case 1: // wrap + case WrapMode::Repeat: coord = coord % (imageSize + 1); coord = (coord < 0) ? imageSize + coord : coord; break; - case 2: // mirror + case WrapMode::Mirror: { const int sizePlus1 = imageSize + 1; const int div = coord / sizePlus1; coord = coord - (div * sizePlus1); coord = (coord < 0) ? -coord : coord; coord = (div & 1) ? imageSize - coord : coord; + break; } - break; + default: + PanicAlertFmt("Invalid wrap mode: {}", wrapMode); } *coordp = coord; } @@ -74,10 +77,11 @@ void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8* sample) { // use mipmap baseMip = lod >> 4; - mipLinear = (lodFract && tm0.min_filter & TexMode0::TEXF_LINEAR); + mipLinear = (lodFract && tm0.mipmap_filter == MipMode::Linear); // if using nearest mip filter and lodFract >= 0.5 round up to next mip - baseMip += (lodFract >> 3) & (tm0.min_filter & TexMode0::TEXF_POINT); + if (tm0.mipmap_filter == MipMode::Point && lodFract >= 8) + baseMip++; } if (mipLinear) @@ -111,12 +115,12 @@ void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample) const TexMode0& tm0 = texUnit.texMode0[subTexmap]; const TexImage0& ti0 = texUnit.texImage0[subTexmap]; const TexTLUT& texTlut = texUnit.texTlut[subTexmap]; - const TextureFormat texfmt = static_cast(ti0.format); - const TLUTFormat tlutfmt = static_cast(texTlut.tlut_format); + const TextureFormat texfmt = ti0.format; + const TLUTFormat tlutfmt = texTlut.tlut_format; const u8* imageSrc; const u8* imageSrcOdd = nullptr; - if (texUnit.texImage1[subTexmap].image_type) + if (texUnit.texImage1[subTexmap].cache_manually_managed) { imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE]; if (texfmt == TextureFormat::RGBA8) @@ -188,7 +192,7 @@ void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample) WrapCoord(&imageSPlus1, tm0.wrap_s, imageWidth); WrapCoord(&imageTPlus1, tm0.wrap_t, imageHeight); - if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].image_type)) + if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].cache_manually_managed)) { TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, texfmt, tlut, tlutfmt); @@ -240,7 +244,7 @@ void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample) WrapCoord(&imageS, tm0.wrap_s, imageWidth); WrapCoord(&imageT, tm0.wrap_t, imageHeight); - if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].image_type)) + if (!(texfmt == TextureFormat::RGBA8 && texUnit.texImage1[subTexmap].cache_manually_managed)) TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, texfmt, tlut, tlutfmt); else TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT, diff --git a/Source/Core/VideoBackends/Vulkan/VKPipeline.cpp b/Source/Core/VideoBackends/Vulkan/VKPipeline.cpp index b7c656bec9..048f84b9b9 100644 --- a/Source/Core/VideoBackends/Vulkan/VKPipeline.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKPipeline.cpp @@ -52,13 +52,13 @@ GetVulkanRasterizationState(const RasterizationState& state) depth_clamp, // VkBool32 depthClampEnable VK_FALSE, // VkBool32 rasterizerDiscardEnable VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode - cull_modes[state.cullmode], // VkCullModeFlags cullMode - VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace - VK_FALSE, // VkBool32 depthBiasEnable - 0.0f, // float depthBiasConstantFactor - 0.0f, // float depthBiasClamp - 0.0f, // float depthBiasSlopeFactor - 1.0f // float lineWidth + cull_modes[u32(state.cullmode.Value())], // VkCullModeFlags cullMode + VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace + VK_FALSE, // VkBool32 depthBiasEnable + 0.0f, // float depthBiasConstantFactor + 0.0f, // float depthBiasClamp + 0.0f, // float depthBiasSlopeFactor + 1.0f // float lineWidth }; } @@ -85,31 +85,32 @@ static VkPipelineDepthStencilStateCreateInfo GetVulkanDepthStencilState(const De bool inverted_depth = !g_ActiveConfig.backend_info.bSupportsReversedDepthRange; switch (state.func) { - case ZMode::NEVER: + case CompareMode::Never: compare_op = VK_COMPARE_OP_NEVER; break; - case ZMode::LESS: + case CompareMode::Less: compare_op = inverted_depth ? VK_COMPARE_OP_GREATER : VK_COMPARE_OP_LESS; break; - case ZMode::EQUAL: + case CompareMode::Equal: compare_op = VK_COMPARE_OP_EQUAL; break; - case ZMode::LEQUAL: + case CompareMode::LEqual: compare_op = inverted_depth ? VK_COMPARE_OP_GREATER_OR_EQUAL : VK_COMPARE_OP_LESS_OR_EQUAL; break; - case ZMode::GREATER: + case CompareMode::Greater: compare_op = inverted_depth ? VK_COMPARE_OP_LESS : VK_COMPARE_OP_GREATER; break; - case ZMode::NEQUAL: + case CompareMode::NEqual: compare_op = VK_COMPARE_OP_NOT_EQUAL; break; - case ZMode::GEQUAL: + case CompareMode::GEqual: compare_op = inverted_depth ? VK_COMPARE_OP_LESS_OR_EQUAL : VK_COMPARE_OP_GREATER_OR_EQUAL; break; - case ZMode::ALWAYS: + case CompareMode::Always: compare_op = VK_COMPARE_OP_ALWAYS; break; default: + PanicAlertFmt("Invalid compare mode {}", state.func); compare_op = VK_COMPARE_OP_ALWAYS; break; } @@ -150,10 +151,10 @@ static VkPipelineColorBlendAttachmentState GetVulkanAttachmentBlendState(const B VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, VK_BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}}; - vk_state.srcColorBlendFactor = src_factors[state.srcfactor]; - vk_state.srcAlphaBlendFactor = src_factors[state.srcfactoralpha]; - vk_state.dstColorBlendFactor = dst_factors[state.dstfactor]; - vk_state.dstAlphaBlendFactor = dst_factors[state.dstfactoralpha]; + vk_state.srcColorBlendFactor = src_factors[u32(state.srcfactor.Value())]; + vk_state.srcAlphaBlendFactor = src_factors[u32(state.srcfactoralpha.Value())]; + vk_state.dstColorBlendFactor = dst_factors[u32(state.dstfactor.Value())]; + vk_state.dstAlphaBlendFactor = dst_factors[u32(state.dstfactoralpha.Value())]; } else { @@ -169,10 +170,10 @@ static VkPipelineColorBlendAttachmentState GetVulkanAttachmentBlendState(const B VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}}; - vk_state.srcColorBlendFactor = src_factors[state.srcfactor]; - vk_state.srcAlphaBlendFactor = src_factors[state.srcfactoralpha]; - vk_state.dstColorBlendFactor = dst_factors[state.dstfactor]; - vk_state.dstAlphaBlendFactor = dst_factors[state.dstfactoralpha]; + vk_state.srcColorBlendFactor = src_factors[u32(state.srcfactor.Value())]; + vk_state.srcAlphaBlendFactor = src_factors[u32(state.srcfactoralpha.Value())]; + vk_state.dstColorBlendFactor = dst_factors[u32(state.dstfactor.Value())]; + vk_state.dstAlphaBlendFactor = dst_factors[u32(state.dstfactoralpha.Value())]; } if (state.colorupdate) @@ -211,7 +212,8 @@ GetVulkanColorBlendState(const BlendingState& state, vk_logic_op_enable = VK_FALSE; } - VkLogicOp vk_logic_op = vk_logic_op_enable ? vk_logic_ops[state.logicmode] : VK_LOGIC_OP_CLEAR; + VkLogicOp vk_logic_op = + vk_logic_op_enable ? vk_logic_ops[u32(state.logicmode.Value())] : VK_LOGIC_OP_CLEAR; VkPipelineColorBlendStateCreateInfo vk_state = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType diff --git a/Source/Core/VideoBackends/Vulkan/VKRenderer.cpp b/Source/Core/VideoBackends/Vulkan/VKRenderer.cpp index b2f3f45072..489ee8b8df 100644 --- a/Source/Core/VideoBackends/Vulkan/VKRenderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKRenderer.cpp @@ -166,9 +166,9 @@ void Renderer::ClearScreen(const MathUtil::Rectangle& rc, bool color_enable // Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha // channel to 0xFF. This hopefully allows us to use the fast path in most cases. - if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16 || - bpmem.zcontrol.pixel_format == PEControl::RGB8_Z24 || - bpmem.zcontrol.pixel_format == PEControl::Z24) + if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16 || + bpmem.zcontrol.pixel_format == PixelFormat::RGB8_Z24 || + bpmem.zcontrol.pixel_format == PixelFormat::Z24) { // Force alpha writes, and clear the alpha channel. This is different to the other backends, // where the existing values of the alpha channel are preserved. diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index 52cd8375fd..1242c8e853 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -184,8 +184,8 @@ void ClearScreen(const MathUtil::Rectangle& rc) auto pixel_format = bpmem.zcontrol.pixel_format; // (1): Disable unused color channels - if (pixel_format == PEControl::RGB8_Z24 || pixel_format == PEControl::RGB565_Z16 || - pixel_format == PEControl::Z24) + if (pixel_format == PixelFormat::RGB8_Z24 || pixel_format == PixelFormat::RGB565_Z16 || + pixel_format == PixelFormat::Z24) { alphaEnable = false; } @@ -196,11 +196,11 @@ void ClearScreen(const MathUtil::Rectangle& rc) u32 z = bpmem.clearZValue; // (2) drop additional accuracy - if (pixel_format == PEControl::RGBA6_Z24) + if (pixel_format == PixelFormat::RGBA6_Z24) { color = RGBA8ToRGBA6ToRGBA8(color); } - else if (pixel_format == PEControl::RGB565_Z16) + else if (pixel_format == PixelFormat::RGB565_Z16) { color = RGBA8ToRGB565ToRGBA8(color); z = Z24ToZ16ToZ24(z); @@ -228,29 +228,28 @@ void OnPixelFormatChange() const auto new_format = bpmem.zcontrol.pixel_format; g_renderer->StorePixelFormat(new_format); - DEBUG_LOG_FMT(VIDEO, "pixelfmt: pixel={}, zc={}", static_cast(new_format), - static_cast(bpmem.zcontrol.zformat)); + DEBUG_LOG_FMT(VIDEO, "pixelfmt: pixel={}, zc={}", new_format, bpmem.zcontrol.zformat); // no need to reinterpret pixel data in these cases - if (new_format == old_format || old_format == PEControl::INVALID_FMT) + if (new_format == old_format || old_format == PixelFormat::INVALID_FMT) return; // Check for pixel format changes switch (old_format) { - case PEControl::RGB8_Z24: - case PEControl::Z24: + case PixelFormat::RGB8_Z24: + case PixelFormat::Z24: { // Z24 and RGB8_Z24 are treated equal, so just return in this case - if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) + if (new_format == PixelFormat::RGB8_Z24 || new_format == PixelFormat::Z24) return; - if (new_format == PEControl::RGBA6_Z24) + if (new_format == PixelFormat::RGBA6_Z24) { g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB8ToRGBA6); return; } - else if (new_format == PEControl::RGB565_Z16) + else if (new_format == PixelFormat::RGB565_Z16) { g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB8ToRGB565); return; @@ -258,14 +257,14 @@ void OnPixelFormatChange() } break; - case PEControl::RGBA6_Z24: + case PixelFormat::RGBA6_Z24: { - if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) + if (new_format == PixelFormat::RGB8_Z24 || new_format == PixelFormat::Z24) { g_renderer->ReinterpretPixelData(EFBReinterpretType::RGBA6ToRGB8); return; } - else if (new_format == PEControl::RGB565_Z16) + else if (new_format == PixelFormat::RGB565_Z16) { g_renderer->ReinterpretPixelData(EFBReinterpretType::RGBA6ToRGB565); return; @@ -273,14 +272,14 @@ void OnPixelFormatChange() } break; - case PEControl::RGB565_Z16: + case PixelFormat::RGB565_Z16: { - if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) + if (new_format == PixelFormat::RGB8_Z24 || new_format == PixelFormat::Z24) { g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB565ToRGB8); return; } - else if (new_format == PEControl::RGBA6_Z24) + else if (new_format == PixelFormat::RGBA6_Z24) { g_renderer->ReinterpretPixelData(EFBReinterpretType::RGB565ToRGBA6); return; @@ -292,8 +291,7 @@ void OnPixelFormatChange() break; } - ERROR_LOG_FMT(VIDEO, "Unhandled EFB format change: {} to {}", static_cast(old_format), - static_cast(new_format)); + ERROR_LOG_FMT(VIDEO, "Unhandled EFB format change: {} to {}", old_format, new_format); } void SetInterlacingMode(const BPCmd& bp) @@ -305,17 +303,15 @@ void SetInterlacingMode(const BPCmd& bp) { // SDK always sets bpmem.lineptwidth.lineaspect via BPMEM_LINEPTWIDTH // just before this cmd - static constexpr std::string_view action[] = {"don't adjust", "adjust"}; - DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMODE texLOD:{} lineaspect:{}", action[bpmem.fieldmode.texLOD], - action[bpmem.lineptwidth.lineaspect]); + DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMODE texLOD:{} lineaspect:{}", bpmem.fieldmode.texLOD, + bpmem.lineptwidth.adjust_for_aspect_ratio); } break; case BPMEM_FIELDMASK: { // Determines if fields will be written to EFB (always computed) - static constexpr std::string_view action[] = {"skip", "write"}; - DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMASK even:{} odd:{}", action[bpmem.fieldmask.even], - action[bpmem.fieldmask.odd]); + DEBUG_LOG_FMT(VIDEO, "BPMEM_FIELDMASK even:{} odd:{}", bpmem.fieldmask.even, + bpmem.fieldmask.odd); } break; default: diff --git a/Source/Core/VideoCommon/BPMemory.cpp b/Source/Core/VideoCommon/BPMemory.cpp index e3887327d3..c5749a7bb4 100644 --- a/Source/Core/VideoCommon/BPMemory.cpp +++ b/Source/Core/VideoCommon/BPMemory.cpp @@ -17,7 +17,7 @@ bool BlendMode::UseLogicOp() const return false; // Fast path for Kirby's Return to Dreamland, they use it with dstAlpha. - if (logicmode == BlendMode::NOOP) + if (logicmode == LogicOp::NoOp) return false; return true; diff --git a/Source/Core/VideoCommon/BPMemory.h b/Source/Core/VideoCommon/BPMemory.h index f6d54a6e74..2a8d8ba0dd 100644 --- a/Source/Core/VideoCommon/BPMemory.h +++ b/Source/Core/VideoCommon/BPMemory.h @@ -9,9 +9,16 @@ #include "Common/BitField.h" #include "Common/CommonTypes.h" +#include "Common/EnumFormatter.h" #include "Common/Inline.h" +// X.h defines None to be 0 and Always to be 2, which causes problems with some of the enums +#undef None +#undef Always + +enum class TextureFormat; enum class EFBCopyFormat; +enum class TLUTFormat; #pragma pack(4) @@ -104,140 +111,209 @@ enum // Tev/combiner things // TEV scaling type -enum : u32 +enum class TevScale : u32 { - TEVSCALE_1 = 0, - TEVSCALE_2 = 1, - TEVSCALE_4 = 2, - TEVDIVIDE_2 = 3 + Scale1 = 0, + Scale2 = 1, + Scale4 = 2, + Divide2 = 3 }; - -enum : u32 +template <> +struct fmt::formatter : EnumFormatter { - TEVCMP_R8 = 0, - TEVCMP_GR16 = 1, - TEVCMP_BGR24 = 2, - TEVCMP_RGB8 = 3 + formatter() : EnumFormatter({"1", "2", "4", "0.5"}) {} }; // TEV combiner operator -enum : u32 +enum class TevOp : u32 { - TEVOP_ADD = 0, - TEVOP_SUB = 1, - TEVCMP_R8_GT = 8, - TEVCMP_R8_EQ = 9, - TEVCMP_GR16_GT = 10, - TEVCMP_GR16_EQ = 11, - TEVCMP_BGR24_GT = 12, - TEVCMP_BGR24_EQ = 13, - TEVCMP_RGB8_GT = 14, - TEVCMP_RGB8_EQ = 15, - TEVCMP_A8_GT = TEVCMP_RGB8_GT, - TEVCMP_A8_EQ = TEVCMP_RGB8_EQ + Add = 0, + Sub = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Add", "Subtract"}) {} +}; + +enum class TevCompareMode : u32 +{ + R8 = 0, + GR16 = 1, + BGR24 = 2, + RGB8 = 3, + A8 = RGB8, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"R8", "GR16", "BGR24", "RGB8 / A8"}) {} +}; + +enum class TevComparison : u32 +{ + GT = 0, + EQ = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Greater than", "Equal to"}) {} }; // TEV color combiner input -enum : u32 +enum class TevColorArg : u32 { - TEVCOLORARG_CPREV = 0, - TEVCOLORARG_APREV = 1, - TEVCOLORARG_C0 = 2, - TEVCOLORARG_A0 = 3, - TEVCOLORARG_C1 = 4, - TEVCOLORARG_A1 = 5, - TEVCOLORARG_C2 = 6, - TEVCOLORARG_A2 = 7, - TEVCOLORARG_TEXC = 8, - TEVCOLORARG_TEXA = 9, - TEVCOLORARG_RASC = 10, - TEVCOLORARG_RASA = 11, - TEVCOLORARG_ONE = 12, - TEVCOLORARG_HALF = 13, - TEVCOLORARG_KONST = 14, - TEVCOLORARG_ZERO = 15 + PrevColor = 0, + PrevAlpha = 1, + Color0 = 2, + Alpha0 = 3, + Color1 = 4, + Alpha1 = 5, + Color2 = 6, + Alpha2 = 7, + TexColor = 8, + TexAlpha = 9, + RasColor = 10, + RasAlpha = 11, + One = 12, + Half = 13, + Konst = 14, + Zero = 15 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "prev.rgb", "prev.aaa", "c0.rgb", "c0.aaa", "c1.rgb", "c1.aaa", "c2.rgb", "c2.aaa", + "tex.rgb", "tex.aaa", "ras.rgb", "ras.aaa", "ONE", "HALF", "konst.rgb", "ZERO", + }; + formatter() : EnumFormatter(names) {} }; // TEV alpha combiner input -enum : u32 +enum class TevAlphaArg : u32 { - TEVALPHAARG_APREV = 0, - TEVALPHAARG_A0 = 1, - TEVALPHAARG_A1 = 2, - TEVALPHAARG_A2 = 3, - TEVALPHAARG_TEXA = 4, - TEVALPHAARG_RASA = 5, - TEVALPHAARG_KONST = 6, - TEVALPHAARG_ZERO = 7 + PrevAlpha = 0, + Alpha0 = 1, + Alpha1 = 2, + Alpha2 = 3, + TexAlpha = 4, + RasAlpha = 5, + Konst = 6, + Zero = 7 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "prev", "c0", "c1", "c2", "tex", "ras", "konst", "ZERO", + }; + formatter() : EnumFormatter(names) {} }; // TEV output registers -enum : u32 +enum class TevOutput : u32 { - GX_TEVPREV = 0, - GX_TEVREG0 = 1, - GX_TEVREG1 = 2, - GX_TEVREG2 = 3 + Prev = 0, + Color0 = 1, + Color1 = 2, + Color2 = 3, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"prev", "c0", "c1", "c2"}) {} }; // Z-texture formats -enum : u32 +enum class ZTexFormat : u32 { - TEV_ZTEX_TYPE_U8 = 0, - TEV_ZTEX_TYPE_U16 = 1, - TEV_ZTEX_TYPE_U24 = 2 + U8 = 0, + U16 = 1, + U24 = 2 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"u8", "u16", "u24"}) {} }; // Z texture operator -enum : u32 +enum ZTexOp : u32 { - ZTEXTURE_DISABLE = 0, - ZTEXTURE_ADD = 1, - ZTEXTURE_REPLACE = 2 + Disabled = 0, + Add = 1, + Replace = 2 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Disabled", "Add", "Replace"}) {} }; // TEV bias value -enum : u32 +enum class TevBias : u32 { - TEVBIAS_ZERO = 0, - TEVBIAS_ADDHALF = 1, - TEVBIAS_SUBHALF = 2, - TEVBIAS_COMPARE = 3 + Zero = 0, + AddHalf = 1, + Subhalf = 2, + Compare = 3 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"0", "+0.5", "-0.5", "compare"}) {} }; // Indirect texture format -enum : u32 +enum class IndTexFormat : u32 { ITF_8 = 0, ITF_5 = 1, ITF_4 = 2, ITF_3 = 3 }; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"ITF_8", "ITF_5", "ITF_4", "ITF_3"}) {} +}; // Indirect texture bias -enum : u32 +enum class IndTexBias : u32 { - ITB_NONE = 0, - ITB_S = 1, - ITB_T = 2, - ITB_ST = 3, - ITB_U = 4, - ITB_SU = 5, - ITB_TU = 6, - ITB_STU = 7 + None = 0, + S = 1, + T = 2, + ST = 3, + U = 4, + SU = 5, + TU_ = 6, // conflicts with define in PowerPC.h + STU = 7 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"None", "S", "T", "ST", "U", "SU", "TU", "STU"}) {} }; // Indirect texture bump alpha -enum : u32 +enum class IndTexBumpAlpha : u32 { - ITBA_OFF = 0, - ITBA_S = 1, - ITBA_T = 2, - ITBA_U = 3 + Off = 0, + S = 1, + T = 2, + U = 3 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Off", "S", "T", "U"}) {} }; // Indirect texture wrap value -enum : u32 +enum class IndTexWrap : u32 { ITW_OFF = 0, ITW_256 = 1, @@ -247,40 +323,33 @@ enum : u32 ITW_16 = 5, ITW_0 = 6 }; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Off", "256", "128", "64", "32", "16", "0"}) {} +}; union IND_MTXA { - struct - { - s32 ma : 11; - s32 mb : 11; - u32 s0 : 2; // bits 0-1 of scale factor - u32 rid : 8; - }; + BitField<0, 11, s32> ma; + BitField<11, 11, s32> mb; + BitField<22, 2, u32> s0; // bits 0-1 of scale factor u32 hex; }; union IND_MTXB { - struct - { - s32 mc : 11; - s32 md : 11; - u32 s1 : 2; // bits 2-3 of scale factor - u32 rid : 8; - }; + BitField<0, 11, s32> mc; + BitField<11, 11, s32> md; + BitField<22, 2, u32> s1; // bits 2-3 of scale factor u32 hex; }; union IND_MTXC { - struct - { - s32 me : 11; - s32 mf : 11; - u32 s2 : 2; // bits 4-5 of scale factor - u32 rid : 8; - }; + BitField<0, 11, s32> me; + BitField<11, 11, s32> mf; + BitField<22, 2, u32> s2; // bits 4-5 of scale factor u32 hex; }; @@ -293,11 +362,7 @@ struct IND_MTX union IND_IMASK { - struct - { - u32 mask : 24; - u32 rid : 8; - }; + BitField<0, 24, u32> mask; u32 hex; }; @@ -306,17 +371,19 @@ struct TevStageCombiner union ColorCombiner { // abc=8bit,d=10bit - BitField<0, 4, u32> d; // TEVSELCC_X - BitField<4, 4, u32> c; // TEVSELCC_X - BitField<8, 4, u32> b; // TEVSELCC_X - BitField<12, 4, u32> a; // TEVSELCC_X + BitField<0, 4, TevColorArg> d; + BitField<4, 4, TevColorArg> c; + BitField<8, 4, TevColorArg> b; + BitField<12, 4, TevColorArg> a; - BitField<16, 2, u32> bias; - BitField<18, 1, u32> op; - BitField<19, 1, u32> clamp; + BitField<16, 2, TevBias> bias; + BitField<18, 1, TevOp> op; // Applies when bias is not compare + BitField<18, 1, TevComparison> comparison; // Applies when bias is compare + BitField<19, 1, bool, u32> clamp; - BitField<20, 2, u32> shift; - BitField<22, 2, u32> dest; // 1,2,3 + BitField<20, 2, TevScale> scale; // Applies when bias is not compare + BitField<20, 2, TevCompareMode> compare_mode; // Applies when bias is compare + BitField<22, 2, TevOutput> dest; u32 hex; }; @@ -324,17 +391,19 @@ struct TevStageCombiner { BitField<0, 2, u32> rswap; BitField<2, 2, u32> tswap; - BitField<4, 3, u32> d; // TEVSELCA_ - BitField<7, 3, u32> c; // TEVSELCA_ - BitField<10, 3, u32> b; // TEVSELCA_ - BitField<13, 3, u32> a; // TEVSELCA_ + BitField<4, 3, TevAlphaArg> d; + BitField<7, 3, TevAlphaArg> c; + BitField<10, 3, TevAlphaArg> b; + BitField<13, 3, TevAlphaArg> a; - BitField<16, 2, u32> bias; // GXTevBias - BitField<18, 1, u32> op; - BitField<19, 1, u32> clamp; + BitField<16, 2, TevBias> bias; + BitField<18, 1, TevOp> op; // Applies when bias is not compare + BitField<18, 1, TevComparison> comparison; // Applies when bias is compare + BitField<19, 1, bool, u32> clamp; - BitField<20, 2, u32> shift; - BitField<22, 2, u32> dest; // 1,2,3 + BitField<20, 2, TevScale> scale; // Applies when bias is not compare + BitField<20, 2, TevCompareMode> compare_mode; // Applies when bias is compare + BitField<22, 2, TevOutput> dest; u32 hex; }; @@ -354,17 +423,20 @@ struct TevStageCombiner union TevStageIndirect { - BitField<0, 2, u32> bt; // Indirect tex stage ID - BitField<2, 2, u32> fmt; // Format: ITF_X - BitField<4, 3, u32> bias; // ITB_X - BitField<7, 2, u32> bs; // ITBA_X, indicates which coordinate will become the 'bump alpha' - BitField<9, 4, u32> mid; // Matrix ID to multiply offsets with - BitField<13, 3, u32> sw; // ITW_X, wrapping factor for S of regular coord - BitField<16, 3, u32> tw; // ITW_X, wrapping factor for T of regular coord - BitField<19, 1, u32> lb_utclod; // Use modified or unmodified texture - // coordinates for LOD computation - BitField<20, 1, u32> fb_addprev; // 1 if the texture coordinate results from the previous TEV - // stage should be added + BitField<0, 2, u32> bt; // Indirect tex stage ID + BitField<2, 2, IndTexFormat> fmt; + BitField<4, 3, IndTexBias> bias; + BitField<4, 1, bool, u32> bias_s; + BitField<5, 1, bool, u32> bias_t; + BitField<6, 1, bool, u32> bias_u; + BitField<7, 2, IndTexBumpAlpha> bs; // Indicates which coordinate will become the 'bump alpha' + BitField<9, 4, u32> mid; // Matrix ID to multiply offsets with + BitField<13, 3, IndTexWrap> sw; // Wrapping factor for S of regular coord + BitField<16, 3, IndTexWrap> tw; // Wrapping factor for T of regular coord + BitField<19, 1, bool, u32> lb_utclod; // Use modified or unmodified texture + // coordinates for LOD computation + BitField<20, 1, bool, u32> fb_addprev; // true if the texture coordinate results from the + // previous TEV stage should be added struct { @@ -374,58 +446,65 @@ union TevStageIndirect // If bs and mid are zero, the result of the stage is independent of // the texture sample data, so we can skip sampling the texture. - bool IsActive() const { return bs != ITBA_OFF || mid != 0; } + bool IsActive() const { return bs != IndTexBumpAlpha::Off || mid != 0; } +}; + +enum class RasColorChan : u32 +{ + Color0 = 0, + Color1 = 1, + AlphaBump = 5, + NormalizedAlphaBump = 6, + Zero = 7, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "Color chan 0", "Color chan 1", nullptr, nullptr, + nullptr, "Alpha bump", "Norm alpha bump", "Zero", + }; + formatter() : EnumFormatter(names) {} }; union TwoTevStageOrders { BitField<0, 3, u32> texmap0; // Indirect tex stage texmap BitField<3, 3, u32> texcoord0; - BitField<6, 1, u32> enable0; // 1 if should read from texture - BitField<7, 3, u32> colorchan0; // RAS1_CC_X + BitField<6, 1, bool, u32> enable0; // true if should read from texture + BitField<7, 3, RasColorChan> colorchan0; BitField<12, 3, u32> texmap1; BitField<15, 3, u32> texcoord1; - BitField<18, 1, u32> enable1; // 1 if should read from texture - BitField<19, 3, u32> colorchan1; // RAS1_CC_X - - BitField<24, 8, u32> rid; + BitField<18, 1, bool, u32> enable1; // true if should read from texture + BitField<19, 3, RasColorChan> colorchan1; u32 hex; u32 getTexMap(int i) const { return i ? texmap1.Value() : texmap0.Value(); } u32 getTexCoord(int i) const { return i ? texcoord1.Value() : texcoord0.Value(); } u32 getEnable(int i) const { return i ? enable1.Value() : enable0.Value(); } - u32 getColorChan(int i) const { return i ? colorchan1.Value() : colorchan0.Value(); } + RasColorChan getColorChan(int i) const { return i ? colorchan1.Value() : colorchan0.Value(); } }; union TEXSCALE { - struct - { - u32 ss0 : 4; // Indirect tex stage 0, 2^(-ss0) - u32 ts0 : 4; // Indirect tex stage 0 - u32 ss1 : 4; // Indirect tex stage 1 - u32 ts1 : 4; // Indirect tex stage 1 - u32 pad : 8; - u32 rid : 8; - }; + BitField<0, 4, u32> ss0; // Indirect tex stage 0, 2^(-ss0) + BitField<4, 4, u32> ts0; // Indirect tex stage 0 + BitField<8, 4, u32> ss1; // Indirect tex stage 1 + BitField<12, 4, u32> ts1; // Indirect tex stage 1 u32 hex; }; union RAS1_IREF { - struct - { - u32 bi0 : 3; // Indirect tex stage 0 ntexmap - u32 bc0 : 3; // Indirect tex stage 0 ntexcoord - u32 bi1 : 3; - u32 bc1 : 3; - u32 bi2 : 3; - u32 bc3 : 3; - u32 bi4 : 3; - u32 bc4 : 3; - u32 rid : 8; - }; + BitField<0, 3, u32> bi0; // Indirect tex stage 0 ntexmap + BitField<3, 3, u32> bc0; // Indirect tex stage 0 ntexmap + BitField<6, 3, u32> bi1; + BitField<9, 3, u32> bc1; + BitField<12, 3, u32> bi2; + BitField<15, 3, u32> bc3; // Typo? + BitField<18, 3, u32> bi4; + BitField<21, 3, u32> bc4; u32 hex; u32 getTexCoord(int i) const { return (hex >> (6 * i + 3)) & 7; } @@ -433,88 +512,118 @@ union RAS1_IREF }; // Texture structs +enum class WrapMode : u32 +{ + Clamp = 0, + Repeat = 1, + Mirror = 2, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Clamp", "Repeat", "Mirror"}) {} +}; + +enum class MipMode : u32 +{ + None = 0, + Point = 1, + Linear = 2, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"None", "Mip point", "Mip linear"}) {} +}; + +enum class FilterMode : u32 +{ + Near = 0, + Linear = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Near", "Linear"}) {} +}; + +enum class LODType : u32 +{ + Edge = 0, + Diagonal = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Edge LOD", "Diagonal LOD"}) {} +}; + +enum class MaxAnsio +{ + One = 0, + Two = 1, + Four = 2, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"1", "2 (requires edge LOD)", "4 (requires edge LOD)"}) {} +}; union TexMode0 { - enum TextureFilter : u32 - { - TEXF_NONE = 0, - TEXF_POINT = 1, - TEXF_LINEAR = 2 - }; - - struct - { - u32 wrap_s : 2; - u32 wrap_t : 2; - u32 mag_filter : 1; - u32 min_filter : 3; - u32 diag_lod : 1; - s32 lod_bias : 8; - u32 pad0 : 2; - u32 max_aniso : 2; - u32 lod_clamp : 1; - }; + BitField<0, 2, WrapMode> wrap_s; + BitField<2, 2, WrapMode> wrap_t; + BitField<4, 1, FilterMode> mag_filter; + BitField<5, 2, MipMode> mipmap_filter; + BitField<7, 1, FilterMode> min_filter; + BitField<8, 1, LODType> diag_lod; + BitField<9, 8, s32> lod_bias; + BitField<19, 2, MaxAnsio> max_aniso; + BitField<21, 1, bool, u32> lod_clamp; u32 hex; }; union TexMode1 { - struct - { - u32 min_lod : 8; - u32 max_lod : 8; - }; + BitField<0, 8, u32> min_lod; + BitField<8, 8, u32> max_lod; u32 hex; }; union TexImage0 { - struct - { - u32 width : 10; // Actually w-1 - u32 height : 10; // Actually h-1 - u32 format : 4; - }; + BitField<0, 10, u32> width; // Actually w-1 + BitField<10, 10, u32> height; // Actually h-1 + BitField<20, 4, TextureFormat> format; u32 hex; }; union TexImage1 { - struct - { - u32 tmem_even : 15; // TMEM line index for even LODs - u32 cache_width : 3; - u32 cache_height : 3; - u32 image_type : 1; // 1 if this texture is managed manually (0 means we'll autofetch the - // texture data whenever it changes) - }; + BitField<0, 15, u32> tmem_even; // TMEM line index for even LODs + BitField<15, 3, u32> cache_width; + BitField<18, 3, u32> cache_height; + // true if this texture is managed manually (false means we'll + // autofetch the texture data whenever it changes) + BitField<21, 1, bool, u32> cache_manually_managed; u32 hex; }; union TexImage2 { - struct - { - u32 tmem_odd : 15; // tmem line index for odd LODs - u32 cache_width : 3; - u32 cache_height : 3; - }; + BitField<0, 15, u32> tmem_odd; // tmem line index for odd LODs + BitField<15, 3, u32> cache_width; + BitField<18, 3, u32> cache_height; u32 hex; }; union TexImage3 { - struct - { - u32 image_base : 24; // address in memory >> 5 (was 20 for GC) - }; + BitField<0, 24, u32> image_base; // address in memory >> 5 (was 20 for GC) u32 hex; }; union TexTLUT { - struct - { - u32 tmem_offset : 10; - u32 tlut_format : 2; - }; + BitField<0, 10, u32> tmem_offset; + BitField<10, 2, TLUTFormat> tlut_format; u32 hex; }; @@ -526,8 +635,8 @@ union ZTex1 union ZTex2 { - BitField<0, 2, u32> type; // TEV_Z_TYPE_X - BitField<2, 2, u32> op; // GXZTexOp + BitField<0, 2, ZTexFormat> type; + BitField<2, 2, ZTexOp> op; u32 hex; }; @@ -544,109 +653,167 @@ struct FourTexUnits }; // Geometry/other structs +enum class CullMode : u32 +{ + None = 0, + Back = 1, // cull back-facing primitives + Front = 2, // cull front-facing primitives + All = 3, // cull all primitives +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "None", + "Back-facing primitives only", + "Front-facing primitives only", + "All primitives", + }; + formatter() : EnumFormatter(names) {} +}; union GenMode { - enum CullMode : u32 - { - CULL_NONE = 0, - CULL_BACK = 1, // cull back-facing primitives - CULL_FRONT = 2, // cull front-facing primitives - CULL_ALL = 3, // cull all primitives - }; - BitField<0, 4, u32> numtexgens; BitField<4, 3, u32> numcolchans; - // 1 bit unused? - BitField<8, 1, u32> flat_shading; // unconfirmed - BitField<9, 1, u32> multisampling; + BitField<7, 1, u32> unused; // 1 bit unused? + BitField<8, 1, bool, u32> flat_shading; // unconfirmed + BitField<9, 1, bool, u32> multisampling; BitField<10, 4, u32> numtevstages; BitField<14, 2, CullMode> cullmode; BitField<16, 3, u32> numindstages; - BitField<19, 1, u32> zfreeze; + BitField<19, 1, bool, u32> zfreeze; u32 hex; }; +enum class AspectRatioAdjustment +{ + DontAdjust = 0, + Adjust = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Don't adjust", "Adjust"}) {} +}; + union LPSize { - struct - { - u32 linesize : 8; // in 1/6th pixels - u32 pointsize : 8; // in 1/6th pixels - u32 lineoff : 3; - u32 pointoff : 3; - u32 lineaspect : 1; // interlacing: adjust for pixels having AR of 1/2 - u32 padding : 1; - }; + BitField<0, 8, u32> linesize; // in 1/6th pixels + BitField<8, 8, u32> pointsize; // in 1/6th pixels + BitField<16, 3, u32> lineoff; + BitField<19, 3, u32> pointoff; + // interlacing: adjust for pixels having AR of 1/2 + BitField<22, 1, AspectRatioAdjustment> adjust_for_aspect_ratio; u32 hex; }; union X12Y12 { - struct - { - u32 y : 12; - u32 x : 12; - }; + BitField<0, 12, u32> y; + BitField<12, 12, u32> x; u32 hex; }; union X10Y10 { - struct - { - u32 x : 10; - u32 y : 10; - }; + BitField<0, 10, u32> x; + BitField<10, 10, u32> y; u32 hex; }; // Framebuffer/pixel stuff (incl fog) +enum class SrcBlendFactor : u32 +{ + Zero = 0, + One = 1, + DstClr = 2, + InvDstClr = 3, + SrcAlpha = 4, + InvSrcAlpha = 5, + DstAlpha = 6, + InvDstAlpha = 7 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = {"0", "1", "dst_color", "1-dst_color", + "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha"}; + formatter() : EnumFormatter(names) {} +}; + +enum class DstBlendFactor : u32 +{ + Zero = 0, + One = 1, + SrcClr = 2, + InvSrcClr = 3, + SrcAlpha = 4, + InvSrcAlpha = 5, + DstAlpha = 6, + InvDstAlpha = 7 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = {"0", "1", "src_color", "1-src_color", + "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha"}; + formatter() : EnumFormatter(names) {} +}; + +enum class LogicOp : u32 +{ + Clear = 0, + And = 1, + AndReverse = 2, + Copy = 3, + AndInverted = 4, + NoOp = 5, + Xor = 6, + Or = 7, + Nor = 8, + Equiv = 9, + Invert = 10, + OrReverse = 11, + CopyInverted = 12, + OrInverted = 13, + Nand = 14, + Set = 15 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "Clear (0)", + "And (src & dst)", + "And Reverse (src & ~dst)", + "Copy (src)", + "And Inverted (~src & dst)", + "NoOp (dst)", + "Xor (src ^ dst)", + "Or (src | dst)", + "Nor (~(src | dst))", + "Equiv (~(src ^ dst))", + "Invert (~dst)", + "Or Reverse (src | ~dst)", + "Copy Inverted (~src)", + "Or Inverted (~src | dst)", + "Nand (~(src & dst))", + "Set (1)", + }; + formatter() : EnumFormatter(names) {} +}; union BlendMode { - enum BlendFactor : u32 - { - ZERO = 0, - ONE = 1, - SRCCLR = 2, // for dst factor - INVSRCCLR = 3, // for dst factor - DSTCLR = SRCCLR, // for src factor - INVDSTCLR = INVSRCCLR, // for src factor - SRCALPHA = 4, - INVSRCALPHA = 5, - DSTALPHA = 6, - INVDSTALPHA = 7 - }; - - enum LogicOp : u32 - { - CLEAR = 0, - AND = 1, - AND_REVERSE = 2, - COPY = 3, - AND_INVERTED = 4, - NOOP = 5, - XOR = 6, - OR = 7, - NOR = 8, - EQUIV = 9, - INVERT = 10, - OR_REVERSE = 11, - COPY_INVERTED = 12, - OR_INVERTED = 13, - NAND = 14, - SET = 15 - }; - - BitField<0, 1, u32> blendenable; - BitField<1, 1, u32> logicopenable; - BitField<2, 1, u32> dither; - BitField<3, 1, u32> colorupdate; - BitField<4, 1, u32> alphaupdate; - BitField<5, 3, BlendFactor> dstfactor; - BitField<8, 3, BlendFactor> srcfactor; - BitField<11, 1, u32> subtract; + BitField<0, 1, bool, u32> blendenable; + BitField<1, 1, bool, u32> logicopenable; + BitField<2, 1, bool, u32> dither; + BitField<3, 1, bool, u32> colorupdate; + BitField<4, 1, bool, u32> alphaupdate; + BitField<5, 3, DstBlendFactor> dstfactor; + BitField<8, 3, SrcBlendFactor> srcfactor; + BitField<11, 1, bool, u32> subtract; BitField<12, 4, LogicOp> logicmode; u32 hex; @@ -664,14 +831,49 @@ union FogParam0 float FloatValue() const; }; +enum class FogProjection : u32 +{ + Perspective = 0, + Orthographic = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Perspective", "Orthographic"}) {} +}; + +enum class FogType : u32 +{ + Off = 0, + Linear = 2, + Exp = 4, + ExpSq = 5, + BackwardsExp = 6, + BackwardsExpSq = 7, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "Off (no fog)", + nullptr, + "Linear fog", + nullptr, + "Exponential fog", + "Exponential-squared fog", + "Backwards exponential fog", + "Backwards exponenential-sequared fog", + }; + formatter() : EnumFormatter(names) {} +}; + union FogParam3 { BitField<0, 11, u32> c_mant; BitField<11, 8, u32> c_exp; BitField<19, 1, u32> c_sign; - BitField<20, 1, u32> proj; // 0 - perspective, 1 - orthographic - BitField<21, 3, u32> fsel; // 0 - off, 2 - linear, 4 - exp, 5 - exp2, 6 - - // backward exp, 7 - backward exp2 + BitField<20, 1, FogProjection> proj; + BitField<21, 3, FogType> fsel; u32 hex; float FloatValue() const; @@ -681,7 +883,6 @@ union FogRangeKElement { BitField<0, 12, u32> HI; BitField<12, 12, u32> LO; - BitField<24, 8, u32> regid; // TODO: Which scaling coefficient should we use here? This is just a guess! float GetValue(int i) const { return (i ? HI.Value() : LO.Value()) / 256.f; } @@ -693,8 +894,7 @@ struct FogRangeParams union RangeBase { BitField<0, 10, u32> Center; // viewport center + 342 - BitField<10, 1, u32> Enabled; - BitField<24, 8, u32> regid; + BitField<10, 1, bool, u32> Enabled; u32 hex; }; RangeBase Base; @@ -726,23 +926,30 @@ struct FogParams float GetC() const; }; +enum class CompareMode : u32 +{ + Never = 0, + Less = 1, + Equal = 2, + LEqual = 3, + Greater = 4, + NEqual = 5, + GEqual = 6, + Always = 7 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = {"Never", "Less", "Equal", "LEqual", + "Greater", "NEqual", "GEqual", "Always"}; + formatter() : EnumFormatter(names) {} +}; + union ZMode { - enum CompareMode : u32 - { - NEVER = 0, - LESS = 1, - EQUAL = 2, - LEQUAL = 3, - GREATER = 4, - NEQUAL = 5, - GEQUAL = 6, - ALWAYS = 7 - }; - - BitField<0, 1, u32> testenable; + BitField<0, 1, bool, u32> testenable; BitField<1, 3, CompareMode> func; - BitField<4, 1, u32> updateenable; + BitField<4, 1, bool, u32> updateenable; u32 hex; }; @@ -750,62 +957,84 @@ union ZMode union ConstantAlpha { BitField<0, 8, u32> alpha; - BitField<8, 1, u32> enable; + BitField<8, 1, bool, u32> enable; u32 hex; }; union FieldMode { - struct - { - u32 texLOD : 1; // adjust vert tex LOD computation to account for interlacing - }; + // adjust vertex tex LOD computation to account for interlacing + BitField<0, 1, AspectRatioAdjustment> texLOD; u32 hex; }; +enum class FieldMaskState : u32 +{ + Skip = 0, + Write = 1, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Skipped", "Written"}) {} +}; + union FieldMask { - struct - { - // If bit is not set, do not write field to EFB - u32 odd : 1; - u32 even : 1; - }; + // Fields are written to the EFB only if their bit is set to write. + BitField<0, 1, FieldMaskState> odd; + BitField<1, 1, FieldMaskState> even; u32 hex; }; +enum class PixelFormat : u32 +{ + RGB8_Z24 = 0, + RGBA6_Z24 = 1, + RGB565_Z16 = 2, + Z24 = 3, + Y8 = 4, + U8 = 5, + V8 = 6, + YUV420 = 7, + INVALID_FMT = 0xffffffff, // Used by Dolphin to represent a missing value. +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = {"RGB8_Z24", "RGBA6_Z24", "RGB565_Z16", "Z24", + "Y8", "U8", "V8", "YUV420"}; + formatter() : EnumFormatter(names) {} +}; + +enum class DepthFormat : u32 +{ + ZLINEAR = 0, + ZNEAR = 1, + ZMID = 2, + ZFAR = 3, + + // It seems these Z formats aren't supported/were removed ? + ZINV_LINEAR = 4, + ZINV_NEAR = 5, + ZINV_MID = 6, + ZINV_FAR = 7 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "linear", "compressed (near)", "compressed (mid)", "compressed (far)", + "inv linear", "compressed (inv near)", "compressed (inv mid)", "compressed (inv far)", + }; + formatter() : EnumFormatter(names) {} +}; + union PEControl { - enum PixelFormat : u32 - { - RGB8_Z24 = 0, - RGBA6_Z24 = 1, - RGB565_Z16 = 2, - Z24 = 3, - Y8 = 4, - U8 = 5, - V8 = 6, - YUV420 = 7, - INVALID_FMT = 0xffffffff, // Used by Dolphin to represent a missing value. - }; - - enum DepthFormat : u32 - { - ZLINEAR = 0, - ZNEAR = 1, - ZMID = 2, - ZFAR = 3, - - // It seems these Z formats aren't supported/were removed ? - ZINV_LINEAR = 4, - ZINV_NEAR = 5, - ZINV_MID = 6, - ZINV_FAR = 7 - }; - BitField<0, 3, PixelFormat> pixel_format; BitField<3, 3, DepthFormat> zformat; - BitField<6, 1, u32> early_ztest; + BitField<6, 1, bool, u32> early_ztest; u32 hex; }; @@ -814,15 +1043,12 @@ union PEControl union TCInfo { - struct - { - u32 scale_minus_1 : 16; - u32 range_bias : 1; - u32 cylindric_wrap : 1; - // These bits only have effect in the s field of TCoordInfo - u32 line_offset : 1; - u32 point_offset : 1; - }; + BitField<0, 16, u32> scale_minus_1; + BitField<16, 1, bool, u32> range_bias; + BitField<17, 1, bool, u32> cylindric_wrap; + // These bits only have effect in the s field of TCoordInfo + BitField<18, 1, bool, u32> line_offset; + BitField<19, 1, bool, u32> point_offset; u32 hex; }; struct TCoordInfo @@ -831,139 +1057,229 @@ struct TCoordInfo TCInfo t; }; -union TevReg +enum class TevRegType : u32 { - u64 hex; - - // Access to individual registers - BitField<0, 32, u64> low; - BitField<32, 32, u64> high; + Color = 0, + Constant = 1, +}; +struct TevReg +{ // TODO: Check if Konst uses all 11 bits or just 8 + union RA + { + u32 hex; - // Low register - BitField<0, 11, s64> red; + BitField<0, 11, s32> red; + BitField<12, 11, s32> alpha; + BitField<23, 1, TevRegType, u32> type; + }; + union BG + { + u32 hex; - BitField<12, 11, s64> alpha; - BitField<23, 1, u64> type_ra; + BitField<0, 11, s32> blue; + BitField<12, 11, s32> green; + BitField<23, 1, TevRegType, u32> type; + }; - // High register - BitField<32, 11, s64> blue; + RA ra; + BG bg; +}; - BitField<44, 11, s64> green; - BitField<55, 1, u64> type_bg; +enum class KonstSel : u32 +{ + V1 = 0, + V7_8 = 1, + V3_4 = 2, + V5_8 = 3, + V1_2 = 4, + V3_8 = 5, + V1_4 = 6, + V1_8 = 7, + // 8-11 are invalid values that output 0 (8-15 for alpha) + K0 = 12, // Color only + K1 = 13, // Color only + K2 = 14, // Color only + K3 = 15, // Color only + K0_R = 16, + K1_R = 17, + K2_R = 18, + K3_R = 19, + K0_G = 20, + K1_G = 21, + K2_G = 22, + K3_G = 23, + K0_B = 24, + K1_B = 25, + K2_B = 26, + K3_B = 27, + K0_A = 28, + K1_A = 29, + K2_A = 30, + K3_A = 31, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "1", + "7/8", + "3/4", + "5/8", + "1/2", + "3/8", + "1/4", + "1/8", + nullptr, + nullptr, + nullptr, + nullptr, + "Konst 0 RGB (invalid for alpha)", + "Konst 1 RGB (invalid for alpha)", + "Konst 2 RGB (invalid for alpha)", + "Konst 3 RGB (invalid for alpha)", + "Konst 0 Red", + "Konst 1 Red", + "Konst 2 Red", + "Konst 3 Red", + "Konst 0 Green", + "Konst 1 Green", + "Konst 2 Green", + "Konst 3 Green", + "Konst 0 Blue", + "Konst 1 Blue", + "Konst 2 Blue", + "Konst 3 Blue", + "Konst 0 Alpha", + "Konst 1 Alpha", + "Konst 2 Alpha", + "Konst 3 Alpha", + }; + formatter() : EnumFormatter(names) {} }; union TevKSel { BitField<0, 2, u32> swap1; BitField<2, 2, u32> swap2; - BitField<4, 5, u32> kcsel0; - BitField<9, 5, u32> kasel0; - BitField<14, 5, u32> kcsel1; - BitField<19, 5, u32> kasel1; + BitField<4, 5, KonstSel> kcsel0; + BitField<9, 5, KonstSel> kasel0; + BitField<14, 5, KonstSel> kcsel1; + BitField<19, 5, KonstSel> kasel1; u32 hex; - u32 getKC(int i) const { return i ? kcsel1.Value() : kcsel0.Value(); } - u32 getKA(int i) const { return i ? kasel1.Value() : kasel0.Value(); } + KonstSel getKC(int i) const { return i ? kcsel1.Value() : kcsel0.Value(); } + KonstSel getKA(int i) const { return i ? kasel1.Value() : kasel0.Value(); } +}; + +enum class AlphaTestOp : u32 +{ + And = 0, + Or = 1, + Xor = 2, + Xnor = 3 +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"And", "Or", "Xor", "Xnor"}) {} +}; + +enum class AlphaTestResult +{ + Undetermined = 0, + Fail = 1, + Pass = 2, }; union AlphaTest { - enum CompareMode : u32 - { - NEVER = 0, - LESS = 1, - EQUAL = 2, - LEQUAL = 3, - GREATER = 4, - NEQUAL = 5, - GEQUAL = 6, - ALWAYS = 7 - }; - - enum Op : u32 - { - AND = 0, - OR = 1, - XOR = 2, - XNOR = 3 - }; - BitField<0, 8, u32> ref0; BitField<8, 8, u32> ref1; BitField<16, 3, CompareMode> comp0; BitField<19, 3, CompareMode> comp1; - BitField<22, 2, Op> logic; + BitField<22, 2, AlphaTestOp> logic; u32 hex; - enum TEST_RESULT - { - UNDETERMINED = 0, - FAIL = 1, - PASS = 2, - }; - - DOLPHIN_FORCE_INLINE TEST_RESULT TestResult() const + DOLPHIN_FORCE_INLINE AlphaTestResult TestResult() const { switch (logic) { - case AND: - if (comp0 == ALWAYS && comp1 == ALWAYS) - return PASS; - if (comp0 == NEVER || comp1 == NEVER) - return FAIL; + case AlphaTestOp::And: + if (comp0 == CompareMode::Always && comp1 == CompareMode::Always) + return AlphaTestResult::Pass; + if (comp0 == CompareMode::Never || comp1 == CompareMode::Never) + return AlphaTestResult::Fail; break; - case OR: - if (comp0 == ALWAYS || comp1 == ALWAYS) - return PASS; - if (comp0 == NEVER && comp1 == NEVER) - return FAIL; + case AlphaTestOp::Or: + if (comp0 == CompareMode::Always || comp1 == CompareMode::Always) + return AlphaTestResult::Pass; + if (comp0 == CompareMode::Never && comp1 == CompareMode::Never) + return AlphaTestResult::Fail; break; - case XOR: - if ((comp0 == ALWAYS && comp1 == NEVER) || (comp0 == NEVER && comp1 == ALWAYS)) - return PASS; - if ((comp0 == ALWAYS && comp1 == ALWAYS) || (comp0 == NEVER && comp1 == NEVER)) - return FAIL; + case AlphaTestOp::Xor: + if ((comp0 == CompareMode::Always && comp1 == CompareMode::Never) || + (comp0 == CompareMode::Never && comp1 == CompareMode::Always)) + return AlphaTestResult::Pass; + if ((comp0 == CompareMode::Always && comp1 == CompareMode::Always) || + (comp0 == CompareMode::Never && comp1 == CompareMode::Never)) + return AlphaTestResult::Fail; break; - case XNOR: - if ((comp0 == ALWAYS && comp1 == NEVER) || (comp0 == NEVER && comp1 == ALWAYS)) - return FAIL; - if ((comp0 == ALWAYS && comp1 == ALWAYS) || (comp0 == NEVER && comp1 == NEVER)) - return PASS; + case AlphaTestOp::Xnor: + if ((comp0 == CompareMode::Always && comp1 == CompareMode::Never) || + (comp0 == CompareMode::Never && comp1 == CompareMode::Always)) + return AlphaTestResult::Fail; + if ((comp0 == CompareMode::Always && comp1 == CompareMode::Always) || + (comp0 == CompareMode::Never && comp1 == CompareMode::Never)) + return AlphaTestResult::Pass; break; default: - return UNDETERMINED; + return AlphaTestResult::Undetermined; } - return UNDETERMINED; + return AlphaTestResult::Undetermined; } }; +enum class FrameToField : u32 +{ + Progressive = 0, + InterlacedEven = 2, + InterlacedOdd = 3, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = {"Progressive", nullptr, "Interlaced (even lines)", + "Interlaced (odd lines)"}; + formatter() : EnumFormatter(names) {} +}; + union UPE_Copy { u32 Hex; - BitField<0, 1, u32> clamp_top; // if set clamp top - BitField<1, 1, u32> clamp_bottom; // if set clamp bottom - BitField<2, 1, u32> yuv; // if set, color conversion from RGB to YUV + BitField<0, 1, bool, u32> clamp_top; // if set clamp top + BitField<1, 1, bool, u32> clamp_bottom; // if set clamp bottom + BitField<2, 1, bool, u32> yuv; // if set, color conversion from RGB to YUV BitField<3, 4, u32> target_pixel_format; // realformat is (fmt/2)+((fmt&1)*8).... for some reason // the msb is the lsb (pattern: cycling right shift) - BitField<7, 2, u32> gamma; // gamma correction.. 0 = 1.0 ; 1 = 1.7 ; 2 = 2.2 ; 3 is reserved - BitField<9, 1, u32> - half_scale; // "mipmap" filter... 0 = no filter (scale 1:1) ; 1 = box filter (scale 2:1) - BitField<10, 1, u32> scale_invert; // if set vertical scaling is on - BitField<11, 1, u32> clear; - BitField<12, 2, u32> frame_to_field; // 0 progressive ; 1 is reserved ; 2 = interlaced (even - // lines) ; 3 = interlaced 1 (odd lines) - BitField<14, 1, u32> copy_to_xfb; - BitField<15, 1, u32> intensity_fmt; // if set, is an intensity format (I4,I8,IA4,IA8) - BitField<16, 1, u32> - auto_conv; // if 0 automatic color conversion by texture format and pixel type + // gamma correction.. 0 = 1.0 ; 1 = 1.7 ; 2 = 2.2 ; 3 is reserved + BitField<7, 2, u32> gamma; + // "mipmap" filter... false = no filter (scale 1:1) ; true = box filter (scale 2:1) + BitField<9, 1, bool, u32> half_scale; + BitField<10, 1, bool, u32> scale_invert; // if set vertical scaling is on + BitField<11, 1, bool, u32> clear; + BitField<12, 2, FrameToField> frame_to_field; + BitField<14, 1, bool, u32> copy_to_xfb; + BitField<15, 1, bool, u32> intensity_fmt; // if set, is an intensity format (I4,I8,IA4,IA8) + // if false automatic color conversion by texture format and pixel type + BitField<16, 1, bool, u32> auto_conv; EFBCopyFormat tp_realFormat() const { @@ -1001,12 +1317,9 @@ union CopyFilterCoefficients union BPU_PreloadTileInfo { + BitField<0, 15, u32> count; + BitField<15, 2, u32> type; u32 hex; - struct - { - u32 count : 15; - u32 type : 2; - }; }; struct BPS_TmemConfig diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index 896aafca30..d0418e9289 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -91,10 +91,9 @@ static void BPWritten(const BPCmd& bp) { case BPMEM_GENMODE: // Set the Generation Mode PRIM_LOG("genmode: texgen={}, col={}, multisampling={}, tev={}, cullmode={}, ind={}, zfeeze={}", - bpmem.genMode.numtexgens.Value(), bpmem.genMode.numcolchans.Value(), - bpmem.genMode.multisampling.Value(), bpmem.genMode.numtevstages.Value() + 1, - static_cast(bpmem.genMode.cullmode), bpmem.genMode.numindstages.Value(), - bpmem.genMode.zfreeze.Value()); + bpmem.genMode.numtexgens, bpmem.genMode.numcolchans, bpmem.genMode.multisampling, + bpmem.genMode.numtevstages + 1, bpmem.genMode.cullmode, bpmem.genMode.numindstages, + bpmem.genMode.zfreeze); if (bp.changes) PixelShaderManager::SetGenModeChanged(); @@ -138,8 +137,8 @@ static void BPWritten(const BPCmd& bp) GeometryShaderManager::SetLinePtWidthChanged(); return; case BPMEM_ZMODE: // Depth Control - PRIM_LOG("zmode: test={}, func={}, upd={}", bpmem.zmode.testenable.Value(), - bpmem.zmode.func.Value(), bpmem.zmode.updateenable.Value()); + PRIM_LOG("zmode: test={}, func={}, upd={}", bpmem.zmode.testenable, bpmem.zmode.func, + bpmem.zmode.updateenable); SetDepthMode(); PixelShaderManager::SetZModeControl(); return; @@ -147,10 +146,9 @@ static void BPWritten(const BPCmd& bp) if (bp.changes & 0xFFFF) { PRIM_LOG("blendmode: en={}, open={}, colupd={}, alphaupd={}, dst={}, src={}, sub={}, mode={}", - bpmem.blendmode.blendenable.Value(), bpmem.blendmode.logicopenable.Value(), - bpmem.blendmode.colorupdate.Value(), bpmem.blendmode.alphaupdate.Value(), - bpmem.blendmode.dstfactor.Value(), bpmem.blendmode.srcfactor.Value(), - bpmem.blendmode.subtract.Value(), bpmem.blendmode.logicmode.Value()); + bpmem.blendmode.blendenable, bpmem.blendmode.logicopenable, + bpmem.blendmode.colorupdate, bpmem.blendmode.alphaupdate, bpmem.blendmode.dstfactor, + bpmem.blendmode.srcfactor, bpmem.blendmode.subtract, bpmem.blendmode.logicmode); SetBlendMode(); @@ -158,8 +156,7 @@ static void BPWritten(const BPCmd& bp) } return; case BPMEM_CONSTANTALPHA: // Set Destination Alpha - PRIM_LOG("constalpha: alp={}, en={}", bpmem.dstalpha.alpha.Value(), - bpmem.dstalpha.enable.Value()); + PRIM_LOG("constalpha: alp={}, en={}", bpmem.dstalpha.alpha, bpmem.dstalpha.enable); if (bp.changes) { PixelShaderManager::SetAlpha(); @@ -264,14 +261,14 @@ static void BPWritten(const BPCmd& bp) const UPE_Copy PE_copy = bpmem.triggerEFBCopy; if (PE_copy.copy_to_xfb == 0) { - // bpmem.zcontrol.pixel_format to PEControl::Z24 is when the game wants to copy from ZBuffer + // bpmem.zcontrol.pixel_format to PixelFormat::Z24 is when the game wants to copy from ZBuffer // (Zbuffer uses 24-bit Format) static constexpr CopyFilterCoefficients::Values filter_coefficients = { {0, 0, 21, 22, 21, 0, 0}}; - bool is_depth_copy = bpmem.zcontrol.pixel_format == PEControl::Z24; + bool is_depth_copy = bpmem.zcontrol.pixel_format == PixelFormat::Z24; g_texture_cache->CopyRenderTargetToTexture( destAddr, PE_copy.tp_realFormat(), copy_width, copy_height, destStride, is_depth_copy, - srcRect, !!PE_copy.intensity_fmt, !!PE_copy.half_scale, 1.0f, 1.0f, + srcRect, PE_copy.intensity_fmt, PE_copy.half_scale, 1.0f, 1.0f, bpmem.triggerEFBCopy.clamp_top, bpmem.triggerEFBCopy.clamp_bottom, filter_coefficients); } else @@ -297,7 +294,7 @@ static void BPWritten(const BPCmd& bp) destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, bpmem.copyTexSrcWH.x + 1, destStride, height, yScale); - bool is_depth_copy = bpmem.zcontrol.pixel_format == PEControl::Z24; + bool is_depth_copy = bpmem.zcontrol.pixel_format == PixelFormat::Z24; g_texture_cache->CopyRenderTargetToTexture( destAddr, EFBCopyFormat::XFB, copy_width, height, destStride, is_depth_copy, srcRect, false, false, yScale, s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top, @@ -370,10 +367,9 @@ static void BPWritten(const BPCmd& bp) PixelShaderManager::SetFogColorChanged(); return; case BPMEM_ALPHACOMPARE: // Compare Alpha Values - PRIM_LOG("alphacmp: ref0={}, ref1={}, comp0={}, comp1={}, logic={}", - bpmem.alpha_test.ref0.Value(), bpmem.alpha_test.ref1.Value(), - static_cast(bpmem.alpha_test.comp0), static_cast(bpmem.alpha_test.comp1), - static_cast(bpmem.alpha_test.logic)); + PRIM_LOG("alphacmp: ref0={}, ref1={}, comp0={}, comp1={}, logic={}", bpmem.alpha_test.ref0, + bpmem.alpha_test.ref1, bpmem.alpha_test.comp0, bpmem.alpha_test.comp1, + bpmem.alpha_test.logic); if (bp.changes & 0xFFFF) PixelShaderManager::SetAlpha(); if (bp.changes) @@ -383,7 +379,7 @@ static void BPWritten(const BPCmd& bp) } return; case BPMEM_BIAS: // BIAS - PRIM_LOG("ztex bias={:#x}", bpmem.ztex1.bias.Value()); + PRIM_LOG("ztex bias={:#x}", bpmem.ztex1.bias); if (bp.changes) PixelShaderManager::SetZTextureBias(); return; @@ -393,11 +389,7 @@ static void BPWritten(const BPCmd& bp) PixelShaderManager::SetZTextureTypeChanged(); if (bp.changes & 12) PixelShaderManager::SetZTextureOpChanged(); -#if defined(_DEBUG) || defined(DEBUGFAST) - static constexpr std::string_view pzop[] = {"DISABLE", "ADD", "REPLACE", "?"}; - static constexpr std::string_view pztype[] = {"Z8", "Z16", "Z24", "?"}; - PRIM_LOG("ztex op={}, type={}", pzop[bpmem.ztex2.op], pztype[bpmem.ztex2.type]); -#endif + PRIM_LOG("ztex op={}, type={}", bpmem.ztex2.op, bpmem.ztex2.type); } return; // ---------------------------------- @@ -588,15 +580,15 @@ static void BPWritten(const BPCmd& bp) case BPMEM_TEV_COLOR_RA + 6: { int num = (bp.address >> 1) & 0x3; - if (bpmem.tevregs[num].type_ra) + if (bpmem.tevregs[num].ra.type == TevRegType::Constant) { - PixelShaderManager::SetTevKonstColor(num, 0, (s32)bpmem.tevregs[num].red); - PixelShaderManager::SetTevKonstColor(num, 3, (s32)bpmem.tevregs[num].alpha); + PixelShaderManager::SetTevKonstColor(num, 0, bpmem.tevregs[num].ra.red); + PixelShaderManager::SetTevKonstColor(num, 3, bpmem.tevregs[num].ra.alpha); } else { - PixelShaderManager::SetTevColor(num, 0, (s32)bpmem.tevregs[num].red); - PixelShaderManager::SetTevColor(num, 3, (s32)bpmem.tevregs[num].alpha); + PixelShaderManager::SetTevColor(num, 0, bpmem.tevregs[num].ra.red); + PixelShaderManager::SetTevColor(num, 3, bpmem.tevregs[num].ra.alpha); } return; } @@ -607,15 +599,15 @@ static void BPWritten(const BPCmd& bp) case BPMEM_TEV_COLOR_BG + 6: { int num = (bp.address >> 1) & 0x3; - if (bpmem.tevregs[num].type_bg) + if (bpmem.tevregs[num].bg.type == TevRegType::Constant) { - PixelShaderManager::SetTevKonstColor(num, 1, (s32)bpmem.tevregs[num].green); - PixelShaderManager::SetTevKonstColor(num, 2, (s32)bpmem.tevregs[num].blue); + PixelShaderManager::SetTevKonstColor(num, 1, bpmem.tevregs[num].bg.green); + PixelShaderManager::SetTevKonstColor(num, 2, bpmem.tevregs[num].bg.blue); } else { - PixelShaderManager::SetTevColor(num, 1, (s32)bpmem.tevregs[num].green); - PixelShaderManager::SetTevColor(num, 2, (s32)bpmem.tevregs[num].blue); + PixelShaderManager::SetTevColor(num, 1, bpmem.tevregs[num].bg.green); + PixelShaderManager::SetTevColor(num, 2, bpmem.tevregs[num].bg.blue); } return; } @@ -915,26 +907,18 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) SetRegName(BPMEM_BLENDMODE); BlendMode mode; mode.hex = cmddata; - const char* dstfactors[] = {"0", "1", "src_color", "1-src_color", - "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha"}; - const char* srcfactors[] = {"0", "1", "dst_color", "1-dst_color", - "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha"}; - const char* logicmodes[] = {"0", "s & d", "s & ~d", "s", "~s & d", "d", - "s ^ d", "s | d", "~(s | d)", "~(s ^ d)", "~d", "s | ~d", - "~s", "~s | d", "~(s & d)", "1"}; - *desc = - fmt::format("Enable: {}\n" - "Logic ops: {}\n" - "Dither: {}\n" - "Color write: {}\n" - "Alpha write: {}\n" - "Dest factor: {}\n" - "Source factor: {}\n" - "Subtract: {}\n" - "Logic mode: {}\n", - no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither], - no_yes[mode.colorupdate], no_yes[mode.alphaupdate], dstfactors[mode.dstfactor], - srcfactors[mode.srcfactor], no_yes[mode.subtract], logicmodes[mode.logicmode]); + *desc = fmt::format("Enable: {}\n" + "Logic ops: {}\n" + "Dither: {}\n" + "Color write: {}\n" + "Alpha write: {}\n" + "Dest factor: {}\n" + "Source factor: {}\n" + "Subtract: {}\n" + "Logic mode: {}\n", + no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither], + no_yes[mode.colorupdate], no_yes[mode.alphaupdate], mode.dstfactor, + mode.srcfactor, no_yes[mode.subtract], mode.logicmode); } break; @@ -948,16 +932,10 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) SetRegName(BPMEM_ZCOMPARE); PEControl config; config.hex = cmddata; - const char* pixel_formats[] = {"RGB8_Z24", "RGBA6_Z24", "RGB565_Z16", "Z24", - "Y8", "U8", "V8", "YUV420"}; - const char* zformats[] = { - "linear", "compressed (near)", "compressed (mid)", "compressed (far)", - "inv linear", "compressed (inv near)", "compressed (inv mid)", "compressed (inv far)"}; *desc = fmt::format("EFB pixel format: {}\n" "Depth format: {}\n" "Early depth test: {}\n", - pixel_formats[config.pixel_format], zformats[config.zformat], - no_yes[config.early_ztest]); + config.pixel_format, config.zformat, no_yes[config.early_ztest]); } break; @@ -1048,7 +1026,7 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) "Mipmap filter: {}\n" "Vertical scaling: {}\n" "Clear: {}\n" - "Frame to field: 0x{:01X}\n" + "Frame to field: {}\n" "Copy to XFB: {}\n" "Intensity format: {}\n" "Automatic color conversion: {}", @@ -1059,9 +1037,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) (copy.gamma == 0) ? "1.0" : (copy.gamma == 1) ? "1.7" : (copy.gamma == 2) ? "2.2" : "Invalid value 0x3?", - no_yes[copy.half_scale], no_yes[copy.scale_invert], no_yes[copy.clear], - static_cast(copy.frame_to_field), no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], - no_yes[copy.auto_conv]); + no_yes[copy.half_scale], no_yes[copy.scale_invert], no_yes[copy.clear], copy.frame_to_field, + no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], no_yes[copy.auto_conv]); } break; @@ -1183,8 +1160,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) *desc = fmt::format("Texture Unit: {}\n" "Width: {}\n" "Height: {}\n" - "Format: {:x}\n", - texnum, u32(teximg.width) + 1, u32(teximg.height) + 1, u32(teximg.format)); + "Format: {}\n", + texnum, u32(teximg.width) + 1, u32(teximg.height) + 1, teximg.format); } break; @@ -1208,7 +1185,7 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) "Even TMEM Height: {}\n" "Cache is manually managed: {}\n", texnum, u32(teximg.tmem_even), u32(teximg.cache_width), - u32(teximg.cache_height), no_yes[teximg.image_type]); + u32(teximg.cache_height), no_yes[teximg.cache_manually_managed]); } break; @@ -1285,14 +1262,6 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) SetRegName(BPMEM_TEV_COLOR_ENV); TevStageCombiner::ColorCombiner cc; cc.hex = cmddata; - const char* tevin[] = { - "prev.rgb", "prev.aaa", "c0.rgb", "c0.aaa", "c1.rgb", "c1.aaa", "c2.rgb", "c2.aaa", - "tex.rgb", "tex.aaa", "ras.rgb", "ras.aaa", "ONE", "HALF", "konst.rgb", "ZERO", - }; - const char* tevbias[] = {"0", "+0.5", "-0.5", "compare"}; - const char* tevop[] = {"add", "sub"}; - const char* tevscale[] = {"1", "2", "4", "0.5"}; - const char* tevout[] = {"prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb"}; *desc = fmt::format("Tev stage: {}\n" "a: {}\n" "b: {}\n" @@ -1303,9 +1272,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) "Clamp: {}\n" "Scale factor: {}\n" "Dest: {}\n", - (data[0] - BPMEM_TEV_COLOR_ENV) / 2, tevin[cc.a], tevin[cc.b], tevin[cc.c], - tevin[cc.d], tevbias[cc.bias], tevop[cc.op], no_yes[cc.clamp], - tevscale[cc.shift], tevout[cc.dest]); + (data[0] - BPMEM_TEV_COLOR_ENV) / 2, cc.a, cc.b, cc.c, cc.d, cc.bias, cc.op, + no_yes[cc.clamp], cc.scale, cc.dest); break; } @@ -1329,13 +1297,6 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) SetRegName(BPMEM_TEV_ALPHA_ENV); TevStageCombiner::AlphaCombiner ac; ac.hex = cmddata; - const char* tevin[] = { - "prev", "c0", "c1", "c2", "tex", "ras", "konst", "ZERO", - }; - const char* tevbias[] = {"0", "+0.5", "-0.5", "compare"}; - const char* tevop[] = {"add", "sub"}; - const char* tevscale[] = {"1", "2", "4", "0.5"}; - const char* tevout[] = {"prev", "c0", "c1", "c2"}; *desc = fmt::format("Tev stage: {}\n" "a: {}\n" "b: {}\n" @@ -1348,9 +1309,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) "Dest: {}\n" "Ras sel: {}\n" "Tex sel: {}\n", - (data[0] - BPMEM_TEV_ALPHA_ENV) / 2, tevin[ac.a], tevin[ac.b], tevin[ac.c], - tevin[ac.d], tevbias[ac.bias], tevop[ac.op], no_yes[ac.clamp], - tevscale[ac.shift], tevout[ac.dest], ac.rswap.Value(), ac.tswap.Value()); + (data[0] - BPMEM_TEV_ALPHA_ENV) / 2, ac.a, ac.b, ac.c, ac.d, ac.bias, ac.op, + no_yes[ac.clamp], ac.scale, ac.dest, ac.rswap.Value(), ac.tswap.Value()); break; } @@ -1410,14 +1370,10 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) SetRegName(BPMEM_ALPHACOMPARE); AlphaTest test; test.hex = cmddata; - const char* functions[] = {"NEVER", "LESS", "EQUAL", "LEQUAL", - "GREATER", "NEQUAL", "GEQUAL", "ALWAYS"}; - const char* logic[] = {"AND", "OR", "XOR", "XNOR"}; *desc = fmt::format("Test 1: {} (ref: 0x{:02x})\n" "Test 2: {} (ref: 0x{:02x})\n" "Logic: {}\n", - functions[test.comp0], test.ref0.Value(), functions[test.comp1], - test.ref1.Value(), logic[test.logic]); + test.comp0, test.ref0.Value(), test.comp1, test.ref1.Value(), test.logic); break; } diff --git a/Source/Core/VideoCommon/ConstantManager.h b/Source/Core/VideoCommon/ConstantManager.h index 1ad385b0ee..ad21821052 100644 --- a/Source/Core/VideoCommon/ConstantManager.h +++ b/Source/Core/VideoCommon/ConstantManager.h @@ -13,6 +13,9 @@ using float4 = std::array; using uint4 = std::array; using int4 = std::array; +enum class SrcBlendFactor : u32; +enum class DstBlendFactor : u32; + struct PixelShaderConstants { std::array colors; @@ -45,10 +48,10 @@ struct PixelShaderConstants std::array konst; // .rgba // The following are used in ubershaders when using shader_framebuffer_fetch blending u32 blend_enable; - u32 blend_src_factor; - u32 blend_src_factor_alpha; - u32 blend_dst_factor; - u32 blend_dst_factor_alpha; + SrcBlendFactor blend_src_factor; + SrcBlendFactor blend_src_factor_alpha; + DstBlendFactor blend_dst_factor; + DstBlendFactor blend_dst_factor_alpha; u32 blend_subtract; u32 blend_subtract_alpha; }; diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index fe5fcd1190..b4e99cd3c6 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -174,14 +174,14 @@ PixelShaderUid GetPixelShaderUid() pixel_shader_uid_data* const uid_data = out.GetUidData(); uid_data->useDstAlpha = bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && - bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24; uid_data->genMode_numindstages = bpmem.genMode.numindstages; uid_data->genMode_numtevstages = bpmem.genMode.numtevstages; uid_data->genMode_numtexgens = bpmem.genMode.numtexgens; uid_data->bounding_box = g_ActiveConfig.bBBoxEnable && BoundingBox::IsEnabled(); uid_data->rgba6_format = - bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor; + bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor; uid_data->dither = bpmem.blendmode.dither && uid_data->rgba6_format; uid_data->uint_output = bpmem.blendmode.UseLogicOp(); @@ -189,12 +189,13 @@ PixelShaderUid GetPixelShaderUid() const bool forced_early_z = bpmem.UseEarlyDepthTest() && - (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) + (g_ActiveConfig.bFastDepthCalc || + bpmem.alpha_test.TestResult() == AlphaTestResult::Undetermined) // We can't allow early_ztest for zfreeze because depth is overridden per-pixel. // This means it's impossible for zcomploc to be emulated on a zfrozen polygon. && !(bpmem.zmode.testenable && bpmem.genMode.zfreeze); const bool per_pixel_depth = - (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || + (bpmem.ztex2.op != ZTexOp::Disabled && bpmem.UseLateDepthTest()) || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z) || (bpmem.zmode.testenable && bpmem.genMode.zfreeze); @@ -253,10 +254,12 @@ PixelShaderUid GetPixelShaderUid() uid_data->stagehash[n].cc = cc.hex & 0xFFFFFF; uid_data->stagehash[n].ac = ac.hex & 0xFFFFF0; // Storing rswap and tswap later - if (cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || cc.b == TEVCOLORARG_RASA || - cc.b == TEVCOLORARG_RASC || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC || - cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC || ac.a == TEVALPHAARG_RASA || - ac.b == TEVALPHAARG_RASA || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) + if (cc.a == TevColorArg::RasAlpha || cc.a == TevColorArg::RasColor || + cc.b == TevColorArg::RasAlpha || cc.b == TevColorArg::RasColor || + cc.c == TevColorArg::RasAlpha || cc.c == TevColorArg::RasColor || + cc.d == TevColorArg::RasAlpha || cc.d == TevColorArg::RasColor || + ac.a == TevAlphaArg::RasAlpha || ac.b == TevAlphaArg::RasAlpha || + ac.c == TevAlphaArg::RasAlpha || ac.d == TevAlphaArg::RasAlpha) { const int i = bpmem.combiners[n].alphaC.rswap; uid_data->stagehash[n].tevksel_swap1a = bpmem.tevksel[i * 2].swap1; @@ -277,9 +280,9 @@ PixelShaderUid GetPixelShaderUid() uid_data->stagehash[n].tevorders_texmap = bpmem.tevorders[n / 2].getTexMap(n & 1); } - if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || - cc.d == TEVCOLORARG_KONST || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || - ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) + if (cc.a == TevColorArg::Konst || cc.b == TevColorArg::Konst || cc.c == TevColorArg::Konst || + cc.d == TevColorArg::Konst || ac.a == TevAlphaArg::Konst || ac.b == TevAlphaArg::Konst || + ac.c == TevAlphaArg::Konst || ac.d == TevAlphaArg::Konst) { uid_data->stagehash[n].tevksel_kc = bpmem.tevksel[n / 2].getKC(n & 1); uid_data->stagehash[n].tevksel_ka = bpmem.tevksel[n / 2].getKA(n & 1); @@ -291,15 +294,14 @@ PixelShaderUid GetPixelShaderUid() sizeof(*uid_data) : MY_STRUCT_OFFSET(*uid_data, stagehash[numStages]); - AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult(); - uid_data->Pretest = Pretest; + uid_data->Pretest = bpmem.alpha_test.TestResult(); uid_data->late_ztest = bpmem.UseLateDepthTest(); // NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled // (in this case we need to write a depth value if depth test passes regardless of the alpha // testing result) - if (uid_data->Pretest == AlphaTest::UNDETERMINED || - (uid_data->Pretest == AlphaTest::FAIL && uid_data->late_ztest)) + if (uid_data->Pretest == AlphaTestResult::Undetermined || + (uid_data->Pretest == AlphaTestResult::Fail && uid_data->late_ztest)) { uid_data->alpha_test_comp0 = bpmem.alpha_test.comp0; uid_data->alpha_test_comp1 = bpmem.alpha_test.comp1; @@ -320,7 +322,7 @@ PixelShaderUid GetPixelShaderUid() uid_data->zfreeze = bpmem.genMode.zfreeze; uid_data->ztex_op = bpmem.ztex2.op; uid_data->early_ztest = bpmem.UseEarlyDepthTest(); - uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel; + uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel; uid_data->fog_proj = bpmem.fog.c_proj_fsel.proj; uid_data->fog_RangeBaseEnabled = bpmem.fogRange.Base.Enabled; @@ -517,8 +519,8 @@ void UpdateBoundingBox(float2 rawpos) {{ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n, APIType api_type, bool stereo); -static void WriteTevRegular(ShaderCode& out, std::string_view components, int bias, int op, - int clamp, int shift, bool alpha); +static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op, + bool clamp, TevScale scale, bool alpha); static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::string_view texswap, int texmap, bool stereo, APIType api_type); static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, APIType api_type, @@ -826,13 +828,13 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos TevStageCombiner::AlphaCombiner last_ac; last_cc.hex = uid_data->stagehash[uid_data->genMode_numtevstages].cc; last_ac.hex = uid_data->stagehash[uid_data->genMode_numtevstages].ac; - if (last_cc.dest != 0) + if (last_cc.dest != TevOutput::Prev) { - out.Write("\tprev.rgb = {};\n", tev_c_output_table[last_cc.dest]); + out.Write("\tprev.rgb = {};\n", tev_c_output_table[u32(last_cc.dest.Value())]); } - if (last_ac.dest != 0) + if (last_ac.dest != TevOutput::Prev) { - out.Write("\tprev.a = {};\n", tev_a_output_table[last_ac.dest]); + out.Write("\tprev.a = {};\n", tev_a_output_table[u32(last_ac.dest.Value())]); } } out.Write("\tprev = prev & 255;\n"); @@ -840,8 +842,8 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos // NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled // (in this case we need to write a depth value if depth test passes regardless of the alpha // testing result) - if (uid_data->Pretest == AlphaTest::UNDETERMINED || - (uid_data->Pretest == AlphaTest::FAIL && uid_data->late_ztest)) + if (uid_data->Pretest == AlphaTestResult::Undetermined || + (uid_data->Pretest == AlphaTestResult::Fail && uid_data->late_ztest)) { WriteAlphaTest(out, uid_data, api_type, uid_data->per_pixel_depth, use_dual_source || use_shader_blend); @@ -884,7 +886,7 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos // depth texture can safely be ignored if the result won't be written to the depth buffer // (early_ztest) and isn't used for fog either - const bool skip_ztexture = !uid_data->per_pixel_depth && !uid_data->fog_fsel; + const bool skip_ztexture = !uid_data->per_pixel_depth && uid_data->fog_fsel == FogType::Off; // Note: z-textures are not written to depth buffer if early depth test is used if (uid_data->per_pixel_depth && uid_data->early_ztest) @@ -898,13 +900,13 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos // Note: depth texture output is only written to depth buffer if late depth test is used // theoretical final depth value is used for fog calculation, though, so we have to emulate // ztextures anyway - if (uid_data->ztex_op != ZTEXTURE_DISABLE && !skip_ztexture) + if (uid_data->ztex_op != ZTexOp::Disabled && !skip_ztexture) { // use the texture input of the last texture stage (textemp), hopefully this has been read and // is in correct format... out.SetConstantsUsed(C_ZBIAS, C_ZBIAS + 1); out.Write("\tzCoord = idot(" I_ZBIAS "[0].xyzw, textemp.xyzw) + " I_ZBIAS "[1].w {};\n", - (uid_data->ztex_op == ZTEXTURE_ADD) ? "+ zCoord" : ""); + (uid_data->ztex_op == ZTexOp::Add) ? "+ zCoord" : ""); out.Write("\tzCoord = zCoord & 0xFFFFFF;\n"); } @@ -963,7 +965,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i // Perform the indirect op on the incoming regular coordinates // using iindtex{} as the offset coords - if (tevind.bs != ITBA_OFF) + if (tevind.bs != IndTexBumpAlpha::Off) { static constexpr std::array tev_ind_alpha_sel{ "", @@ -980,8 +982,9 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i "248", }; - out.Write("alphabump = iindtex{}.{} & {};\n", tevind.bt.Value(), tev_ind_alpha_sel[tevind.bs], - tev_ind_alpha_mask[tevind.fmt]); + out.Write("alphabump = iindtex{}.{} & {};\n", tevind.bt.Value(), + tev_ind_alpha_sel[u32(tevind.bs.Value())], + tev_ind_alpha_mask[u32(tevind.fmt.Value())]); } else { @@ -998,7 +1001,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i "7", }; out.Write("\tint3 iindtevcrd{} = iindtex{} & {};\n", n, tevind.bt.Value(), - tev_ind_fmt_mask[tevind.fmt]); + tev_ind_fmt_mask[u32(tevind.fmt.Value())]); // bias - TODO: Check if this needs to be this complicated... // indexed by bias @@ -1014,21 +1017,25 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i "1", }; - if (tevind.bias == ITB_S || tevind.bias == ITB_T || tevind.bias == ITB_U) + if (tevind.bias == IndTexBias::S || tevind.bias == IndTexBias::T || + tevind.bias == IndTexBias::U) { - out.Write("\tiindtevcrd{}.{} += int({});\n", n, tev_ind_bias_field[tevind.bias], - tev_ind_bias_add[tevind.fmt]); + out.Write("\tiindtevcrd{}.{} += int({});\n", n, + tev_ind_bias_field[u32(tevind.bias.Value())], + tev_ind_bias_add[u32(tevind.fmt.Value())]); } - else if (tevind.bias == ITB_ST || tevind.bias == ITB_SU || tevind.bias == ITB_TU) + else if (tevind.bias == IndTexBias::ST || tevind.bias == IndTexBias::SU || + tevind.bias == IndTexBias::TU_) { - out.Write("\tiindtevcrd{}.{} += int2({}, {});\n", n, tev_ind_bias_field[tevind.bias], - tev_ind_bias_add[tevind.fmt], tev_ind_bias_add[tevind.fmt]); + out.Write("\tiindtevcrd{0}.{1} += int2({2}, {2});\n", n, + tev_ind_bias_field[u32(tevind.bias.Value())], + tev_ind_bias_add[u32(tevind.fmt.Value())]); } - else if (tevind.bias == ITB_STU) + else if (tevind.bias == IndTexBias::STU) { - out.Write("\tiindtevcrd{}.{} += int3({}, {}, {});\n", n, tev_ind_bias_field[tevind.bias], - tev_ind_bias_add[tevind.fmt], tev_ind_bias_add[tevind.fmt], - tev_ind_bias_add[tevind.fmt]); + out.Write("\tiindtevcrd{0}.{1} += int3({2}, {2}, {2});\n", n, + tev_ind_bias_field[u32(tevind.bias.Value())], + tev_ind_bias_add[u32(tevind.fmt.Value())]); } // multiply by offset matrix and scale - calculations are likely to overflow badly, @@ -1122,33 +1129,33 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i }; // wrap S - if (tevind.sw == ITW_OFF) + if (tevind.sw == IndTexWrap::ITW_OFF) { out.Write("\twrappedcoord.x = fixpoint_uv{}.x;\n", texcoord); } - else if (tevind.sw == ITW_0) + else if (tevind.sw == IndTexWrap::ITW_0) { out.Write("\twrappedcoord.x = 0;\n"); } else { out.Write("\twrappedcoord.x = fixpoint_uv{}.x & ({} - 1);\n", texcoord, - tev_ind_wrap_start[tevind.sw]); + tev_ind_wrap_start[u32(tevind.sw.Value())]); } // wrap T - if (tevind.tw == ITW_OFF) + if (tevind.tw == IndTexWrap::ITW_OFF) { out.Write("\twrappedcoord.y = fixpoint_uv{}.y;\n", texcoord); } - else if (tevind.tw == ITW_0) + else if (tevind.tw == IndTexWrap::ITW_0) { out.Write("\twrappedcoord.y = 0;\n"); } else { out.Write("\twrappedcoord.y = fixpoint_uv{}.y & ({} - 1);\n", texcoord, - tev_ind_wrap_start[tevind.tw]); + tev_ind_wrap_start[u32(tevind.tw.Value())]); } if (tevind.fb_addprev) // add previous tevcoord @@ -1165,10 +1172,12 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i cc.hex = stage.cc; ac.hex = stage.ac; - if (cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || cc.b == TEVCOLORARG_RASA || - cc.b == TEVCOLORARG_RASC || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC || - cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC || ac.a == TEVALPHAARG_RASA || - ac.b == TEVALPHAARG_RASA || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) + if (cc.a == TevColorArg::RasAlpha || cc.a == TevColorArg::RasColor || + cc.b == TevColorArg::RasAlpha || cc.b == TevColorArg::RasColor || + cc.c == TevColorArg::RasAlpha || cc.c == TevColorArg::RasColor || + cc.d == TevColorArg::RasAlpha || cc.d == TevColorArg::RasColor || + ac.a == TevAlphaArg::RasAlpha || ac.b == TevAlphaArg::RasAlpha || + ac.c == TevAlphaArg::RasAlpha || ac.d == TevAlphaArg::RasAlpha) { // Generate swizzle string to represent the Ras color channel swapping const char rasswap[5] = { @@ -1179,7 +1188,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i '\0', }; - out.Write("\trastemp = {}.{};\n", tev_ras_table[stage.tevorders_colorchan], rasswap); + out.Write("\trastemp = {}.{};\n", tev_ras_table[u32(stage.tevorders_colorchan)], rasswap); } if (stage.tevorders_enable) @@ -1209,72 +1218,73 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i out.Write("\ttextemp = int4(255, 255, 255, 255);\n"); } - if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || - cc.d == TEVCOLORARG_KONST || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || - ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) + if (cc.a == TevColorArg::Konst || cc.b == TevColorArg::Konst || cc.c == TevColorArg::Konst || + cc.d == TevColorArg::Konst || ac.a == TevAlphaArg::Konst || ac.b == TevAlphaArg::Konst || + ac.c == TevAlphaArg::Konst || ac.d == TevAlphaArg::Konst) { - out.Write("\tkonsttemp = int4({}, {});\n", tev_ksel_table_c[stage.tevksel_kc], - tev_ksel_table_a[stage.tevksel_ka]); + out.Write("\tkonsttemp = int4({}, {});\n", tev_ksel_table_c[u32(stage.tevksel_kc)], + tev_ksel_table_a[u32(stage.tevksel_ka)]); - if (stage.tevksel_kc > 7) + if (u32(stage.tevksel_kc) > 7) { - out.SetConstantsUsed(C_KCOLORS + ((stage.tevksel_kc - 0xc) % 4), - C_KCOLORS + ((stage.tevksel_kc - 0xc) % 4)); + out.SetConstantsUsed(C_KCOLORS + ((u32(stage.tevksel_kc) - 0xc) % 4), + C_KCOLORS + ((u32(stage.tevksel_kc) - 0xc) % 4)); } - if (stage.tevksel_ka > 7) + if (u32(stage.tevksel_ka) > 7) { - out.SetConstantsUsed(C_KCOLORS + ((stage.tevksel_ka - 0xc) % 4), - C_KCOLORS + ((stage.tevksel_ka - 0xc) % 4)); + out.SetConstantsUsed(C_KCOLORS + ((u32(stage.tevksel_ka) - 0xc) % 4), + C_KCOLORS + ((u32(stage.tevksel_ka) - 0xc) % 4)); } } - if (cc.d == TEVCOLORARG_C0 || cc.d == TEVCOLORARG_A0 || ac.d == TEVALPHAARG_A0) + if (cc.d == TevColorArg::Color0 || cc.d == TevColorArg::Alpha0 || ac.d == TevAlphaArg::Alpha0) out.SetConstantsUsed(C_COLORS + 1, C_COLORS + 1); - if (cc.d == TEVCOLORARG_C1 || cc.d == TEVCOLORARG_A1 || ac.d == TEVALPHAARG_A1) + if (cc.d == TevColorArg::Color1 || cc.d == TevColorArg::Alpha1 || ac.d == TevAlphaArg::Alpha1) out.SetConstantsUsed(C_COLORS + 2, C_COLORS + 2); - if (cc.d == TEVCOLORARG_C2 || cc.d == TEVCOLORARG_A2 || ac.d == TEVALPHAARG_A2) + if (cc.d == TevColorArg::Color2 || cc.d == TevColorArg::Alpha2 || ac.d == TevAlphaArg::Alpha2) out.SetConstantsUsed(C_COLORS + 3, C_COLORS + 3); - if (cc.dest >= GX_TEVREG0) - out.SetConstantsUsed(C_COLORS + cc.dest, C_COLORS + cc.dest); + if (cc.dest >= TevOutput::Color0) + out.SetConstantsUsed(C_COLORS + u32(cc.dest.Value()), C_COLORS + u32(cc.dest.Value())); - if (ac.dest >= GX_TEVREG0) - out.SetConstantsUsed(C_COLORS + ac.dest, C_COLORS + ac.dest); + if (ac.dest >= TevOutput::Color0) + out.SetConstantsUsed(C_COLORS + u32(ac.dest.Value()), C_COLORS + u32(ac.dest.Value())); - out.Write("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.a], - tev_a_input_table[ac.a]); - out.Write("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.b], - tev_a_input_table[ac.b]); - out.Write("\ttevin_c = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.c], - tev_a_input_table[ac.c]); - out.Write("\ttevin_d = int4({}, {});\n", tev_c_input_table[cc.d], tev_a_input_table[ac.d]); + out.Write("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n", + tev_c_input_table[u32(cc.a.Value())], tev_a_input_table[u32(ac.a.Value())]); + out.Write("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n", + tev_c_input_table[u32(cc.b.Value())], tev_a_input_table[u32(ac.b.Value())]); + out.Write("\ttevin_c = int4({}, {})&int4(255, 255, 255, 255);\n", + tev_c_input_table[u32(cc.c.Value())], tev_a_input_table[u32(ac.c.Value())]); + out.Write("\ttevin_d = int4({}, {});\n", tev_c_input_table[u32(cc.d.Value())], + tev_a_input_table[u32(ac.d.Value())]); out.Write("\t// color combine\n"); - out.Write("\t{} = clamp(", tev_c_output_table[cc.dest]); - if (cc.bias != TEVBIAS_COMPARE) + out.Write("\t{} = clamp(", tev_c_output_table[u32(cc.dest.Value())]); + if (cc.bias != TevBias::Compare) { - WriteTevRegular(out, "rgb", cc.bias, cc.op, cc.clamp, cc.shift, false); + WriteTevRegular(out, "rgb", cc.bias, cc.op, cc.clamp, cc.scale, false); } else { static constexpr std::array function_table{ - "((tevin_a.r > tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_R8_GT - "((tevin_a.r == tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_R8_EQ + "((tevin_a.r > tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TevCompareMode::R8, GT + "((tevin_a.r == tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // R8, TevComparison::EQ "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : " - "int3(0,0,0))", // TEVCMP_GR16_GT + "int3(0,0,0))", // GR16, GT "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : " - "int3(0,0,0))", // TEVCMP_GR16_EQ + "int3(0,0,0))", // GR16, EQ "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : " - "int3(0,0,0))", // TEVCMP_BGR24_GT + "int3(0,0,0))", // BGR24, GT "((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : " - "int3(0,0,0))", // TEVCMP_BGR24_EQ - "(max(sign(tevin_a.rgb - tevin_b.rgb), int3(0,0,0)) * tevin_c.rgb)", // TEVCMP_RGB8_GT - "((int3(1,1,1) - sign(abs(tevin_a.rgb - tevin_b.rgb))) * tevin_c.rgb)" // TEVCMP_RGB8_EQ + "int3(0,0,0))", // BGR24, EQ + "(max(sign(tevin_a.rgb - tevin_b.rgb), int3(0,0,0)) * tevin_c.rgb)", // RGB8, GT + "((int3(1,1,1) - sign(abs(tevin_a.rgb - tevin_b.rgb))) * tevin_c.rgb)" // RGB8, EQ }; - const u32 mode = (cc.shift << 1) | cc.op; + const u32 mode = (u32(cc.compare_mode.Value()) << 1) | u32(cc.comparison.Value()); out.Write(" tevin_d.rgb + "); out.Write("{}", function_table[mode]); } @@ -1285,25 +1295,25 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i out.Write(";\n"); out.Write("\t// alpha combine\n"); - out.Write("\t{} = clamp(", tev_a_output_table[ac.dest]); - if (ac.bias != TEVBIAS_COMPARE) + out.Write("\t{} = clamp(", tev_a_output_table[u32(ac.dest.Value())]); + if (ac.bias != TevBias::Compare) { - WriteTevRegular(out, "a", ac.bias, ac.op, ac.clamp, ac.shift, true); + WriteTevRegular(out, "a", ac.bias, ac.op, ac.clamp, ac.scale, true); } else { static constexpr std::array function_table{ - "((tevin_a.r > tevin_b.r) ? tevin_c.a : 0)", // TEVCMP_R8_GT - "((tevin_a.r == tevin_b.r) ? tevin_c.a : 0)", // TEVCMP_R8_EQ - "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // TEVCMP_GR16_GT - "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // TEVCMP_GR16_EQ - "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // TEVCMP_BGR24_GT - "((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // TEVCMP_BGR24_EQ - "((tevin_a.a > tevin_b.a) ? tevin_c.a : 0)", // TEVCMP_A8_GT - "((tevin_a.a == tevin_b.a) ? tevin_c.a : 0)" // TEVCMP_A8_EQ + "((tevin_a.r > tevin_b.r) ? tevin_c.a : 0)", // TevCompareMode::R8, GT + "((tevin_a.r == tevin_b.r) ? tevin_c.a : 0)", // R8, TevComparison::EQ + "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // GR16, GT + "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // GR16, EQ + "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // BGR24, GT + "((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // BGR24, EQ + "((tevin_a.a > tevin_b.a) ? tevin_c.a : 0)", // A8, GT + "((tevin_a.a == tevin_b.a) ? tevin_c.a : 0)" // A8, EQ }; - const u32 mode = (ac.shift << 1) | ac.op; + const u32 mode = (u32(ac.compare_mode.Value()) << 1) | u32(ac.comparison.Value()); out.Write(" tevin_d.a + "); out.Write("{}", function_table[mode]); } @@ -1315,24 +1325,24 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i out.Write(";\n"); } -static void WriteTevRegular(ShaderCode& out, std::string_view components, int bias, int op, - int clamp, int shift, bool alpha) +static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op, + bool clamp, TevScale scale, bool alpha) { static constexpr std::array tev_scale_table_left{ - "", // SCALE_1 - " << 1", // SCALE_2 - " << 2", // SCALE_4 - "", // DIVIDE_2 + "", // Scale1 + " << 1", // Scale2 + " << 2", // Scale4 + "", // Divide2 }; static constexpr std::array tev_scale_table_right{ - "", // SCALE_1 - "", // SCALE_2 - "", // SCALE_4 - " >> 1", // DIVIDE_2 + "", // Scale1 + "", // Scale2 + "", // Scale4 + " >> 1", // Divide2 }; - // indexed by 2*op+(shift==3) + // indexed by 2*op+(scale==Divide2) static constexpr std::array tev_lerp_bias{ "", " + 128", @@ -1341,15 +1351,15 @@ static void WriteTevRegular(ShaderCode& out, std::string_view components, int bi }; static constexpr std::array tev_bias_table{ - "", // ZERO, - " + 128", // ADDHALF, - " - 128", // SUBHALF, + "", // Zero, + " + 128", // AddHalf, + " - 128", // SubHalf, "", }; static constexpr std::array tev_op_table{ - '+', // TEVOP_ADD = 0, - '-', // TEVOP_SUB = 1, + '+', // TevOp::Add = 0, + '-', // TevOp::Sub = 1, }; // Regular TEV stage: (d + bias + lerp(a,b,c)) * scale @@ -1357,12 +1367,14 @@ static void WriteTevRegular(ShaderCode& out, std::string_view components, int bi // - c is scaled from 0..255 to 0..256, which allows dividing the result by 256 instead of 255 // - if scale is bigger than one, it is moved inside the lerp calculation for increased accuracy // - a rounding bias is added before dividing by 256 - out.Write("(((tevin_d.{}{}){})", components, tev_bias_table[bias], tev_scale_table_left[shift]); - out.Write(" {} ", tev_op_table[op]); + out.Write("(((tevin_d.{}{}){})", components, tev_bias_table[u32(bias)], + tev_scale_table_left[u32(scale)]); + out.Write(" {} ", tev_op_table[u32(op)]); out.Write("(((((tevin_a.{}<<8) + (tevin_b.{}-tevin_a.{})*(tevin_c.{}+(tevin_c.{}>>7))){}){})>>8)", - components, components, components, components, components, tev_scale_table_left[shift], - tev_lerp_bias[2 * op + ((shift == 3) == alpha)]); - out.Write("){}", tev_scale_table_right[shift]); + components, components, components, components, components, + tev_scale_table_left[u32(scale)], + tev_lerp_bias[2 * u32(op) + ((scale == TevScale::Divide2) == alpha)]); + out.Write("){}", tev_scale_table_right[u32(scale)]); } static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::string_view texswap, @@ -1384,14 +1396,14 @@ static void SampleTexture(ShaderCode& out, std::string_view texcoords, std::stri } constexpr std::array tev_alpha_funcs_table{ - "(false)", // NEVER - "(prev.a < {})", // LESS - "(prev.a == {})", // EQUAL - "(prev.a <= {})", // LEQUAL - "(prev.a > {})", // GREATER - "(prev.a != {})", // NEQUAL - "(prev.a >= {})", // GEQUAL - "(true)" // ALWAYS + "(false)", // CompareMode::Never + "(prev.a < {})", // CompareMode::Less + "(prev.a == {})", // CompareMode::Equal + "(prev.a <= {})", // CompareMode::LEqual + "(prev.a > {})", // CompareMode::Greater + "(prev.a != {})", // CompareMode::NEqual + "(prev.a >= {})", // CompareMode::GEqual + "(true)" // CompareMode::Always }; constexpr std::array tev_alpha_funclogic_table{ @@ -1409,12 +1421,12 @@ static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_dat I_ALPHA ".g", }; - const auto write_alpha_func = [&out](int index, std::string_view ref) { - const bool has_no_arguments = index == 0 || index == tev_alpha_funcs_table.size() - 1; + const auto write_alpha_func = [&out](CompareMode mode, std::string_view ref) { + const bool has_no_arguments = mode == CompareMode::Never || mode == CompareMode::Always; if (has_no_arguments) - out.Write("{}", tev_alpha_funcs_table[index]); + out.Write("{}", tev_alpha_funcs_table[u32(mode)]); else - out.Write(tev_alpha_funcs_table[index], ref); + out.Write(tev_alpha_funcs_table[u32(mode)], ref); }; out.SetConstantsUsed(C_ALPHA, C_ALPHA); @@ -1425,15 +1437,13 @@ static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_dat out.Write("\tif(!( "); // Lookup the first component from the alpha function table - const int comp0_index = uid_data->alpha_test_comp0; - write_alpha_func(comp0_index, alpha_ref[0]); + write_alpha_func(uid_data->alpha_test_comp0, alpha_ref[0]); // Lookup the logic op - out.Write("{}", tev_alpha_funclogic_table[uid_data->alpha_test_logic]); + out.Write("{}", tev_alpha_funclogic_table[u32(uid_data->alpha_test_logic)]); // Lookup the second component from the alpha function table - const int comp1_index = uid_data->alpha_test_comp1; - write_alpha_func(comp1_index, alpha_ref[1]); + write_alpha_func(uid_data->alpha_test_comp1, alpha_ref[1]); if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_NEGATED_BOOLEAN)) out.Write(") == false) {{\n"); @@ -1473,13 +1483,13 @@ constexpr std::array tev_fog_funcs_table{ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data) { - if (uid_data->fog_fsel == 0) + if (uid_data->fog_fsel == FogType::Off) return; // no Fog out.SetConstantsUsed(C_FOGCOLOR, C_FOGCOLOR); out.SetConstantsUsed(C_FOGI, C_FOGI); out.SetConstantsUsed(C_FOGF, C_FOGF + 1); - if (uid_data->fog_proj == 0) + if (uid_data->fog_proj == FogProjection::Perspective) { // perspective // ze = A/(B - (Zs >> B_SHF) @@ -1515,14 +1525,14 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data) out.Write("\tfloat fog = clamp(ze - " I_FOGF ".y, 0.0, 1.0);\n"); - if (uid_data->fog_fsel > 3) + if (uid_data->fog_fsel >= FogType::Exp) { - out.Write("{}", tev_fog_funcs_table[uid_data->fog_fsel]); + out.Write("{}", tev_fog_funcs_table[u32(uid_data->fog_fsel)]); } else { - if (uid_data->fog_fsel != 2) - WARN_LOG_FMT(VIDEO, "Unknown Fog Type! {:08x}", uid_data->fog_fsel); + if (uid_data->fog_fsel != FogType::Linear) + WARN_LOG_FMT(VIDEO, "Unknown Fog Type! {}", uid_data->fog_fsel); } out.Write("\tint ifog = iround(fog * 256.0);\n"); @@ -1611,11 +1621,13 @@ static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data) "1.0 - initial_ocol0.a;", // INVDSTALPHA }; out.Write("\tfloat4 blend_src;\n"); - out.Write("\tblend_src.rgb = {}\n", blend_src_factor[uid_data->blend_src_factor]); - out.Write("\tblend_src.a = {}\n", blend_src_factor_alpha[uid_data->blend_src_factor_alpha]); + out.Write("\tblend_src.rgb = {}\n", blend_src_factor[u32(uid_data->blend_src_factor)]); + out.Write("\tblend_src.a = {}\n", + blend_src_factor_alpha[u32(uid_data->blend_src_factor_alpha)]); out.Write("\tfloat4 blend_dst;\n"); - out.Write("\tblend_dst.rgb = {}\n", blend_dst_factor[uid_data->blend_dst_factor]); - out.Write("\tblend_dst.a = {}\n", blend_dst_factor_alpha[uid_data->blend_dst_factor_alpha]); + out.Write("\tblend_dst.rgb = {}\n", blend_dst_factor[u32(uid_data->blend_dst_factor)]); + out.Write("\tblend_dst.a = {}\n", + blend_dst_factor_alpha[u32(uid_data->blend_dst_factor_alpha)]); out.Write("\tfloat4 blend_result;\n"); if (uid_data->blend_subtract) diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h index 08704bda0a..a9ffa25498 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.h +++ b/Source/Core/VideoCommon/PixelShaderGen.h @@ -9,6 +9,15 @@ #include "VideoCommon/ShaderGenCommon.h" enum class APIType; +enum class AlphaTestResult; +enum class SrcBlendFactor : u32; +enum class DstBlendFactor : u32; +enum class CompareMode : u32; +enum class AlphaTestOp : u32; +enum class RasColorChan : u32; +enum class KonstSel : u32; +enum class FogProjection : u32; +enum class FogType : u32; #pragma pack(1) struct pixel_shader_uid_data @@ -19,18 +28,18 @@ struct pixel_shader_uid_data u32 NumValues() const { return num_values; } u32 pad0 : 4; u32 useDstAlpha : 1; - u32 Pretest : 2; + AlphaTestResult Pretest : 2; u32 nIndirectStagesUsed : 4; u32 genMode_numtexgens : 4; u32 genMode_numtevstages : 4; u32 genMode_numindstages : 3; - u32 alpha_test_comp0 : 3; - u32 alpha_test_comp1 : 3; - u32 alpha_test_logic : 2; + CompareMode alpha_test_comp0 : 3; + CompareMode alpha_test_comp1 : 3; + AlphaTestOp alpha_test_logic : 2; u32 alpha_test_use_zcomploc_hack : 1; - u32 fog_proj : 1; + FogProjection fog_proj : 1; - u32 fog_fsel : 3; + FogType fog_fsel : 3; u32 fog_RangeBaseEnabled : 1; u32 ztex_op : 2; u32 per_pixel_depth : 1; @@ -43,13 +52,13 @@ struct pixel_shader_uid_data u32 rgba6_format : 1; u32 dither : 1; u32 uint_output : 1; - u32 blend_enable : 1; // Only used with shader_framebuffer_fetch blend - u32 blend_src_factor : 3; // Only used with shader_framebuffer_fetch blend - u32 blend_src_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend - u32 blend_dst_factor : 3; // Only used with shader_framebuffer_fetch blend - u32 blend_dst_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend - u32 blend_subtract : 1; // Only used with shader_framebuffer_fetch blend - u32 blend_subtract_alpha : 1; // Only used with shader_framebuffer_fetch blend + u32 blend_enable : 1; // Only used with shader_framebuffer_fetch blend + SrcBlendFactor blend_src_factor : 3; // Only used with shader_framebuffer_fetch blend + SrcBlendFactor blend_src_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend + DstBlendFactor blend_dst_factor : 3; // Only used with shader_framebuffer_fetch blend + DstBlendFactor blend_dst_factor_alpha : 3; // Only used with shader_framebuffer_fetch blend + u32 blend_subtract : 1; // Only used with shader_framebuffer_fetch blend + u32 blend_subtract_alpha : 1; // Only used with shader_framebuffer_fetch blend u32 texMtxInfo_n_projection : 8; // 8x1 bit u32 tevindref_bi0 : 3; @@ -136,7 +145,7 @@ struct pixel_shader_uid_data u32 tevorders_texmap : 3; u32 tevorders_texcoord : 3; u32 tevorders_enable : 1; - u32 tevorders_colorchan : 3; + RasColorChan tevorders_colorchan : 3; u32 pad1 : 6; // TODO: Clean up the swapXY mess @@ -152,8 +161,8 @@ struct pixel_shader_uid_data u32 tevksel_swap2c : 2; u32 tevksel_swap1d : 2; u32 tevksel_swap2d : 2; - u32 tevksel_kc : 5; - u32 tevksel_ka : 5; + KonstSel tevksel_kc : 5; + KonstSel tevksel_ka : 5; u32 pad3 : 14; } stagehash[16]; diff --git a/Source/Core/VideoCommon/PixelShaderManager.cpp b/Source/Core/VideoCommon/PixelShaderManager.cpp index c2aca3e2f6..bae48623c7 100644 --- a/Source/Core/VideoCommon/PixelShaderManager.cpp +++ b/Source/Core/VideoCommon/PixelShaderManager.cpp @@ -182,7 +182,7 @@ void PixelShaderManager::SetConstants() // Destination alpha is only enabled if alpha writes are enabled. Force entire uniform to zero // when disabled. u32 dstalpha = bpmem.blendmode.alphaupdate && bpmem.dstalpha.enable && - bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 ? + bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24 ? bpmem.dstalpha.hex : 0; @@ -270,7 +270,7 @@ void PixelShaderManager::SetAlphaTestChanged() // TODO: we could optimize this further and check the actual constants, // i.e. "a <= 0" and "a >= 255" will always pass. u32 alpha_test = - bpmem.alpha_test.TestResult() != AlphaTest::PASS ? bpmem.alpha_test.hex | 1 << 31 : 0; + bpmem.alpha_test.TestResult() != AlphaTestResult::Pass ? bpmem.alpha_test.hex | 1 << 31 : 0; if (constants.alphaTest != alpha_test) { constants.alphaTest = alpha_test; @@ -362,25 +362,26 @@ void PixelShaderManager::SetZTextureTypeChanged() { switch (bpmem.ztex2.type) { - case TEV_ZTEX_TYPE_U8: + case ZTexFormat::U8: constants.zbias[0][0] = 0; constants.zbias[0][1] = 0; constants.zbias[0][2] = 0; constants.zbias[0][3] = 1; break; - case TEV_ZTEX_TYPE_U16: + case ZTexFormat::U16: constants.zbias[0][0] = 1; constants.zbias[0][1] = 0; constants.zbias[0][2] = 0; constants.zbias[0][3] = 256; break; - case TEV_ZTEX_TYPE_U24: + case ZTexFormat::U24: constants.zbias[0][0] = 65536; constants.zbias[0][1] = 256; constants.zbias[0][2] = 1; constants.zbias[0][3] = 0; break; default: + PanicAlertFmt("Invalid ztex format {}", bpmem.ztex2.type); break; } dirty = true; @@ -457,8 +458,9 @@ void PixelShaderManager::SetZModeControl() { u32 late_ztest = bpmem.UseLateDepthTest(); u32 rgba6_format = - (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor) ? 1 : - 0; + (bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor) ? + 1 : + 0; u32 dither = rgba6_format && bpmem.blendmode.dither; if (constants.late_ztest != late_ztest || constants.rgba6_format != rgba6_format || constants.dither != dither) diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 1a9af2f232..ba91c0551e 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -171,7 +171,7 @@ void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, bool Renderer::EFBHasAlphaChannel() const { - return m_prev_efb_format == PEControl::RGBA6_Z24; + return m_prev_efb_format == PixelFormat::RGBA6_Z24; } void Renderer::ClearScreen(const MathUtil::Rectangle& rc, bool colorEnable, bool alphaEnable, @@ -197,15 +197,15 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) // check what to do with the alpha channel (GX_PokeAlphaRead) PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); - if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) + if (bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24) { color = RGBA8ToRGBA6ToRGBA8(color); } - else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + else if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16) { color = RGBA8ToRGB565ToRGBA8(color); } - if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) + if (bpmem.zcontrol.pixel_format != PixelFormat::RGBA6_Z24) { color |= 0xFF000000; } @@ -231,7 +231,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) depth = 1.0f - depth; u32 ret = 0; - if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16) { // if Z is in 16 bit format you must return a 16 bit integer ret = std::clamp(static_cast(depth * 65536.0f), 0, 0xFFFF); @@ -994,10 +994,10 @@ bool Renderer::RecompileImGuiPipeline() pconfig.depth_state = RenderState::GetNoDepthTestingDepthState(); pconfig.blending_state = RenderState::GetNoBlendingBlendState(); pconfig.blending_state.blendenable = true; - pconfig.blending_state.srcfactor = BlendMode::SRCALPHA; - pconfig.blending_state.dstfactor = BlendMode::INVSRCALPHA; - pconfig.blending_state.srcfactoralpha = BlendMode::ZERO; - pconfig.blending_state.dstfactoralpha = BlendMode::ONE; + pconfig.blending_state.srcfactor = SrcBlendFactor::SrcAlpha; + pconfig.blending_state.dstfactor = DstBlendFactor::InvSrcAlpha; + pconfig.blending_state.srcfactoralpha = SrcBlendFactor::Zero; + pconfig.blending_state.dstfactoralpha = DstBlendFactor::One; pconfig.framebuffer_state.color_texture_format = m_backbuffer_format; pconfig.framebuffer_state.depth_texture_format = AbstractTextureFormat::Undefined; pconfig.framebuffer_state.samples = 1; @@ -1697,7 +1697,7 @@ bool Renderer::UseVertexDepthRange() const return false; // We need a full depth range if a ztexture is used. - if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest) + if (bpmem.ztex2.op != ZTexOp::Disabled && !bpmem.zcontrol.early_ztest) return true; // If an inverted depth range is unsupported, we also need to check if the range is inverted. diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 91be0e358c..48cef0bdad 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -232,8 +232,8 @@ public: // Called when the configuration changes, and backend structures need to be updated. virtual void OnConfigChanged(u32 bits) {} - PEControl::PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; } - void StorePixelFormat(PEControl::PixelFormat new_format) { m_prev_efb_format = new_format; } + PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; } + void StorePixelFormat(PixelFormat new_format) { m_prev_efb_format = new_format; } bool EFBHasAlphaChannel() const; VideoCommon::PostProcessing* GetPostProcessor() const { return m_post_processor.get(); } // Final surface changing @@ -343,7 +343,7 @@ protected: private: std::tuple CalculateOutputDimensions(int width, int height) const; - PEControl::PixelFormat m_prev_efb_format = PEControl::INVALID_FMT; + PixelFormat m_prev_efb_format = PixelFormat::INVALID_FMT; unsigned int m_efb_scale = 1; // These will be set on the first call to SetWindowSize. diff --git a/Source/Core/VideoCommon/RenderState.cpp b/Source/Core/VideoCommon/RenderState.cpp index 6d6f892979..2cf339d397 100644 --- a/Source/Core/VideoCommon/RenderState.cpp +++ b/Source/Core/VideoCommon/RenderState.cpp @@ -15,7 +15,7 @@ void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_ty // Back-face culling should be disabled for points/lines. if (primitive_type != PrimitiveType::Triangles && primitive_type != PrimitiveType::TriangleStrip) - cullmode = GenMode::CULL_NONE; + cullmode = CullMode::None; } RasterizationState& RasterizationState::operator=(const RasterizationState& rhs) @@ -47,14 +47,27 @@ DepthState& DepthState::operator=(const DepthState& rhs) // ONE on blending. As the backends may emulate this framebuffer // configuration with an alpha channel, we just drop all references // to the destination alpha channel. -static BlendMode::BlendFactor RemoveDstAlphaUsage(BlendMode::BlendFactor factor) +static SrcBlendFactor RemoveDstAlphaUsage(SrcBlendFactor factor) { switch (factor) { - case BlendMode::DSTALPHA: - return BlendMode::ONE; - case BlendMode::INVDSTALPHA: - return BlendMode::ZERO; + case SrcBlendFactor::DstAlpha: + return SrcBlendFactor::One; + case SrcBlendFactor::InvDstAlpha: + return SrcBlendFactor::Zero; + default: + return factor; + } +} + +static DstBlendFactor RemoveDstAlphaUsage(DstBlendFactor factor) +{ + switch (factor) + { + case DstBlendFactor::DstAlpha: + return DstBlendFactor::One; + case DstBlendFactor::InvDstAlpha: + return DstBlendFactor::Zero; default: return factor; } @@ -64,14 +77,14 @@ static BlendMode::BlendFactor RemoveDstAlphaUsage(BlendMode::BlendFactor factor) // the alpha component, CLR and ALPHA are indentical. So just always // use ALPHA as this makes it easier for the backends to use the second // alpha value of dual source blending. -static BlendMode::BlendFactor RemoveSrcColorUsage(BlendMode::BlendFactor factor) +static DstBlendFactor RemoveSrcColorUsage(DstBlendFactor factor) { switch (factor) { - case BlendMode::SRCCLR: - return BlendMode::SRCALPHA; - case BlendMode::INVSRCCLR: - return BlendMode::INVSRCALPHA; + case DstBlendFactor::SrcClr: + return DstBlendFactor::SrcAlpha; + case DstBlendFactor::InvSrcClr: + return DstBlendFactor::InvSrcAlpha; default: return factor; } @@ -79,14 +92,14 @@ static BlendMode::BlendFactor RemoveSrcColorUsage(BlendMode::BlendFactor factor) // Same as RemoveSrcColorUsage, but because of the overlapping enum, // this must be written as another function. -static BlendMode::BlendFactor RemoveDstColorUsage(BlendMode::BlendFactor factor) +static SrcBlendFactor RemoveDstColorUsage(SrcBlendFactor factor) { switch (factor) { - case BlendMode::DSTCLR: - return BlendMode::DSTALPHA; - case BlendMode::INVDSTCLR: - return BlendMode::INVDSTALPHA; + case SrcBlendFactor::DstClr: + return SrcBlendFactor::DstAlpha; + case SrcBlendFactor::InvDstClr: + return SrcBlendFactor::InvDstAlpha; default: return factor; } @@ -97,11 +110,11 @@ void BlendingState::Generate(const BPMemory& bp) // Start with everything disabled. hex = 0; - bool target_has_alpha = bp.zcontrol.pixel_format == PEControl::RGBA6_Z24; - bool alpha_test_may_success = bp.alpha_test.TestResult() != AlphaTest::FAIL; + bool target_has_alpha = bp.zcontrol.pixel_format == PixelFormat::RGBA6_Z24; + bool alpha_test_may_succeed = bp.alpha_test.TestResult() != AlphaTestResult::Fail; - colorupdate = bp.blendmode.colorupdate && alpha_test_may_success; - alphaupdate = bp.blendmode.alphaupdate && target_has_alpha && alpha_test_may_success; + colorupdate = bp.blendmode.colorupdate && alpha_test_may_succeed; + alphaupdate = bp.blendmode.alphaupdate && target_has_alpha && alpha_test_may_succeed; dstalpha = bp.dstalpha.enable && alphaupdate; usedualsrc = true; @@ -110,14 +123,14 @@ void BlendingState::Generate(const BPMemory& bp) { blendenable = true; subtractAlpha = subtract = true; - srcfactoralpha = srcfactor = BlendMode::ONE; - dstfactoralpha = dstfactor = BlendMode::ONE; + srcfactoralpha = srcfactor = SrcBlendFactor::One; + dstfactoralpha = dstfactor = DstBlendFactor::One; if (dstalpha) { subtractAlpha = false; - srcfactoralpha = BlendMode::ONE; - dstfactoralpha = BlendMode::ZERO; + srcfactoralpha = SrcBlendFactor::One; + dstfactoralpha = DstBlendFactor::Zero; } } @@ -133,22 +146,22 @@ void BlendingState::Generate(const BPMemory& bp) srcfactor = RemoveDstAlphaUsage(srcfactor); dstfactor = RemoveDstAlphaUsage(dstfactor); } - // replaces SRCCLR with SRCALPHA and DSTCLR with DSTALPHA, it is important to + // replaces SrcClr with SrcAlpha and DstClr with DstAlpha, it is important to // use the dst function for the src factor and vice versa srcfactoralpha = RemoveDstColorUsage(srcfactor); dstfactoralpha = RemoveSrcColorUsage(dstfactor); if (dstalpha) { - srcfactoralpha = BlendMode::ONE; - dstfactoralpha = BlendMode::ZERO; + srcfactoralpha = SrcBlendFactor::One; + dstfactoralpha = DstBlendFactor::Zero; } } // The logicop bit has the lowest priority else if (bp.blendmode.logicopenable) { - if (bp.blendmode.logicmode == BlendMode::NOOP) + if (bp.blendmode.logicmode == LogicOp::NoOp) { // Fast path for Kirby's Return to Dreamland, they use it with dstAlpha. colorupdate = false; @@ -169,38 +182,39 @@ void BlendingState::Generate(const BPMemory& bp) void BlendingState::ApproximateLogicOpWithBlending() { - // Any of these which use SRC as srcFactor or DST as dstFactor won't be correct. - // This is because the two are aliased to one another (see the enum). struct LogicOpApproximation { bool subtract; - BlendMode::BlendFactor srcfactor; - BlendMode::BlendFactor dstfactor; + SrcBlendFactor srcfactor; + DstBlendFactor dstfactor; }; + // TODO: This previously had a warning about SRC and DST being aliased and not to mix them, + // but INVSRCCLR and INVDSTCLR were also aliased and were mixed. + // Thus, NOR, EQUIV, INVERT, COPY_INVERTED, and OR_INVERTED duplicate(d) other values. static constexpr std::array approximations = {{ - {false, BlendMode::ZERO, BlendMode::ZERO}, // CLEAR - {false, BlendMode::DSTCLR, BlendMode::ZERO}, // AND - {true, BlendMode::ONE, BlendMode::INVSRCCLR}, // AND_REVERSE - {false, BlendMode::ONE, BlendMode::ZERO}, // COPY - {true, BlendMode::DSTCLR, BlendMode::ONE}, // AND_INVERTED - {false, BlendMode::ZERO, BlendMode::ONE}, // NOOP - {false, BlendMode::INVDSTCLR, BlendMode::INVSRCCLR}, // XOR - {false, BlendMode::INVDSTCLR, BlendMode::ONE}, // OR - {false, BlendMode::INVSRCCLR, BlendMode::INVDSTCLR}, // NOR - {false, BlendMode::INVSRCCLR, BlendMode::ZERO}, // EQUIV - {false, BlendMode::INVDSTCLR, BlendMode::INVDSTCLR}, // INVERT - {false, BlendMode::ONE, BlendMode::INVDSTALPHA}, // OR_REVERSE - {false, BlendMode::INVSRCCLR, BlendMode::INVSRCCLR}, // COPY_INVERTED - {false, BlendMode::INVSRCCLR, BlendMode::ONE}, // OR_INVERTED - {false, BlendMode::INVDSTCLR, BlendMode::INVSRCCLR}, // NAND - {false, BlendMode::ONE, BlendMode::ONE}, // SET + {false, SrcBlendFactor::Zero, DstBlendFactor::Zero}, // CLEAR + {false, SrcBlendFactor::DstClr, DstBlendFactor::Zero}, // AND + {true, SrcBlendFactor::One, DstBlendFactor::InvSrcClr}, // AND_REVERSE + {false, SrcBlendFactor::One, DstBlendFactor::Zero}, // COPY + {true, SrcBlendFactor::DstClr, DstBlendFactor::One}, // AND_INVERTED + {false, SrcBlendFactor::Zero, DstBlendFactor::One}, // NOOP + {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // XOR + {false, SrcBlendFactor::InvDstClr, DstBlendFactor::One}, // OR + {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // NOR + {false, SrcBlendFactor::InvDstClr, DstBlendFactor::Zero}, // EQUIV + {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // INVERT + {false, SrcBlendFactor::One, DstBlendFactor::InvDstAlpha}, // OR_REVERSE + {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // COPY_INVERTED + {false, SrcBlendFactor::InvDstClr, DstBlendFactor::One}, // OR_INVERTED + {false, SrcBlendFactor::InvDstClr, DstBlendFactor::InvSrcClr}, // NAND + {false, SrcBlendFactor::One, DstBlendFactor::One}, // SET }}; logicopenable = false; blendenable = true; - subtract = approximations[logicmode].subtract; - srcfactor = approximations[logicmode].srcfactor; - dstfactor = approximations[logicmode].dstfactor; + subtract = approximations[u32(logicmode.Value())].subtract; + srcfactor = approximations[u32(logicmode.Value())].srcfactor; + dstfactor = approximations[u32(logicmode.Value())].dstfactor; } BlendingState& BlendingState::operator=(const BlendingState& rhs) @@ -217,20 +231,20 @@ void SamplerState::Generate(const BPMemory& bp, u32 index) // GX can configure the mip filter to none. However, D3D and Vulkan can't express this in their // sampler states. Therefore, we set the min/max LOD to zero if this option is used. - min_filter = (tm0.min_filter & 4) != 0 ? Filter::Linear : Filter::Point; - mipmap_filter = (tm0.min_filter & 3) == TexMode0::TEXF_LINEAR ? Filter::Linear : Filter::Point; - mag_filter = tm0.mag_filter != 0 ? Filter::Linear : Filter::Point; + min_filter = tm0.min_filter == FilterMode::Linear ? Filter::Linear : Filter::Point; + mipmap_filter = tm0.mipmap_filter == MipMode::Linear ? Filter::Linear : Filter::Point; + mag_filter = tm0.mag_filter == FilterMode::Linear ? Filter::Linear : Filter::Point; // If mipmaps are disabled, clamp min/max lod - max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod : 0; + max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod.Value() : 0; min_lod = std::min(max_lod.Value(), static_cast(tm1.min_lod)); lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias * (256 / 32) : 0; // Address modes static constexpr std::array address_modes = { {AddressMode::Clamp, AddressMode::Repeat, AddressMode::MirroredRepeat, AddressMode::Repeat}}; - wrap_u = address_modes[tm0.wrap_s]; - wrap_v = address_modes[tm0.wrap_t]; + wrap_u = address_modes[u32(tm0.wrap_s.Value())]; + wrap_v = address_modes[u32(tm0.wrap_t.Value())]; anisotropic_filtering = 0; } @@ -252,7 +266,7 @@ RasterizationState GetInvalidRasterizationState() RasterizationState GetNoCullRasterizationState(PrimitiveType primitive) { RasterizationState state = {}; - state.cullmode = GenMode::CULL_NONE; + state.cullmode = CullMode::None; state.primitive = primitive; return state; } @@ -260,7 +274,7 @@ RasterizationState GetNoCullRasterizationState(PrimitiveType primitive) RasterizationState GetCullBackFaceRasterizationState(PrimitiveType primitive) { RasterizationState state = {}; - state.cullmode = GenMode::CULL_BACK; + state.cullmode = CullMode::Back; state.primitive = primitive; return state; } @@ -277,7 +291,7 @@ DepthState GetNoDepthTestingDepthState() DepthState state = {}; state.testenable = false; state.updateenable = false; - state.func = ZMode::ALWAYS; + state.func = CompareMode::Always; return state; } @@ -286,7 +300,7 @@ DepthState GetAlwaysWriteDepthState() DepthState state = {}; state.testenable = true; state.updateenable = true; - state.func = ZMode::ALWAYS; + state.func = CompareMode::Always; return state; } @@ -302,10 +316,10 @@ BlendingState GetNoBlendingBlendState() BlendingState state = {}; state.usedualsrc = false; state.blendenable = false; - state.srcfactor = BlendMode::ONE; - state.srcfactoralpha = BlendMode::ONE; - state.dstfactor = BlendMode::ZERO; - state.dstfactoralpha = BlendMode::ZERO; + state.srcfactor = SrcBlendFactor::One; + state.srcfactoralpha = SrcBlendFactor::One; + state.dstfactor = DstBlendFactor::Zero; + state.dstfactoralpha = DstBlendFactor::Zero; state.logicopenable = false; state.colorupdate = true; state.alphaupdate = true; @@ -317,10 +331,10 @@ BlendingState GetNoColorWriteBlendState() BlendingState state = {}; state.usedualsrc = false; state.blendenable = false; - state.srcfactor = BlendMode::ONE; - state.srcfactoralpha = BlendMode::ONE; - state.dstfactor = BlendMode::ZERO; - state.dstfactoralpha = BlendMode::ZERO; + state.srcfactor = SrcBlendFactor::One; + state.srcfactoralpha = SrcBlendFactor::One; + state.dstfactor = DstBlendFactor::Zero; + state.dstfactoralpha = DstBlendFactor::Zero; state.logicopenable = false; state.colorupdate = false; state.alphaupdate = false; diff --git a/Source/Core/VideoCommon/RenderState.h b/Source/Core/VideoCommon/RenderState.h index f5bf085d72..1cc87eea51 100644 --- a/Source/Core/VideoCommon/RenderState.h +++ b/Source/Core/VideoCommon/RenderState.h @@ -28,7 +28,7 @@ union RasterizationState bool operator==(const RasterizationState& rhs) const { return hex == rhs.hex; } bool operator!=(const RasterizationState& rhs) const { return hex != rhs.hex; } bool operator<(const RasterizationState& rhs) const { return hex < rhs.hex; } - BitField<0, 2, GenMode::CullMode> cullmode; + BitField<0, 2, CullMode> cullmode; BitField<3, 2, PrimitiveType> primitive; u32 hex; @@ -59,7 +59,7 @@ union DepthState bool operator<(const DepthState& rhs) const { return hex < rhs.hex; } BitField<0, 1, u32> testenable; BitField<1, 1, u32> updateenable; - BitField<2, 3, ZMode::CompareMode> func; + BitField<2, 3, CompareMode> func; u32 hex; }; @@ -85,11 +85,11 @@ union BlendingState BitField<5, 1, u32> subtract; BitField<6, 1, u32> subtractAlpha; BitField<7, 1, u32> usedualsrc; - BitField<8, 3, BlendMode::BlendFactor> dstfactor; - BitField<11, 3, BlendMode::BlendFactor> srcfactor; - BitField<14, 3, BlendMode::BlendFactor> dstfactoralpha; - BitField<17, 3, BlendMode::BlendFactor> srcfactoralpha; - BitField<20, 4, BlendMode::LogicOp> logicmode; + BitField<8, 3, DstBlendFactor> dstfactor; + BitField<11, 3, SrcBlendFactor> srcfactor; + BitField<14, 3, DstBlendFactor> dstfactoralpha; + BitField<17, 3, SrcBlendFactor> srcfactoralpha; + BitField<20, 4, LogicOp> logicmode; u32 hex; }; diff --git a/Source/Core/VideoCommon/SamplerCommon.h b/Source/Core/VideoCommon/SamplerCommon.h index a16ba0fcd4..3b36eab09c 100644 --- a/Source/Core/VideoCommon/SamplerCommon.h +++ b/Source/Core/VideoCommon/SamplerCommon.h @@ -16,13 +16,13 @@ namespace SamplerCommon template constexpr bool IsBpTexMode0PointFiltering(const T& tm0) { - return tm0.min_filter < 4 && !tm0.mag_filter; + return tm0.min_filter == FilterMode::Near && tm0.mag_filter == FilterMode::Near; } // Check if the minification filter has mipmap based filtering modes enabled. template constexpr bool AreBpTexMode0MipmapsEnabled(const T& tm0) { - return (tm0.min_filter & 3) != 0; + return tm0.mipmap_filter != MipMode::None; } } // namespace SamplerCommon diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp index 7383dc6595..a0b809adf0 100644 --- a/Source/Core/VideoCommon/ShaderCache.cpp +++ b/Source/Core/VideoCommon/ShaderCache.cpp @@ -1115,7 +1115,7 @@ void ShaderCache::QueueUberShaderPipelines() { // uint_output is only ever enabled when logic ops are enabled. config.blending_state.logicopenable = true; - config.blending_state.logicmode = BlendMode::AND; + config.blending_state.logicmode = LogicOp::And; } auto iter = m_gx_uber_pipeline_cache.find(config); diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index ed9450465a..b791d259f1 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -1187,12 +1187,12 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) const u32 address = (tex.texImage3[id].image_base /* & 0x1FFFFF*/) << 5; u32 width = tex.texImage0[id].width + 1; u32 height = tex.texImage0[id].height + 1; - const TextureFormat texformat = static_cast(tex.texImage0[id].format); + const TextureFormat texformat = tex.texImage0[id].format; const u32 tlutaddr = tex.texTlut[id].tmem_offset << 9; - const TLUTFormat tlutfmt = static_cast(tex.texTlut[id].tlut_format); + const TLUTFormat tlutfmt = tex.texTlut[id].tlut_format; const bool use_mipmaps = SamplerCommon::AreBpTexMode0MipmapsEnabled(tex.texMode0[id]); u32 tex_levels = use_mipmaps ? ((tex.texMode1[id].max_lod + 0xf) / 0x10 + 1) : 1; - const bool from_tmem = tex.texImage1[id].image_type != 0; + const bool from_tmem = tex.texImage1[id].cache_manually_managed != 0; const u32 tmem_address_even = from_tmem ? tex.texImage1[id].tmem_even * TMEM_LINE_SIZE : 0; const u32 tmem_address_odd = from_tmem ? tex.texImage2[id].tmem_odd * TMEM_LINE_SIZE : 0; @@ -2204,7 +2204,7 @@ void TextureCacheBase::CopyRenderTargetToTexture( if (copy_to_ram) { EFBCopyFilterCoefficients coefficients = GetRAMCopyFilterCoefficients(filter_coefficients); - PEControl::PixelFormat srcFormat = bpmem.zcontrol.pixel_format; + PixelFormat srcFormat = bpmem.zcontrol.pixel_format; EFBCopyParams format(srcFormat, dstFormat, is_depth_copy, isIntensity, NeedsCopyFilterInShader(coefficients)); diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index 9245f7bf3f..599f1c2a79 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -50,8 +50,8 @@ struct TextureAndTLUTFormat struct EFBCopyParams { - EFBCopyParams(PEControl::PixelFormat efb_format_, EFBCopyFormat copy_format_, bool depth_, - bool yuv_, bool copy_filter_) + EFBCopyParams(PixelFormat efb_format_, EFBCopyFormat copy_format_, bool depth_, bool yuv_, + bool copy_filter_) : efb_format(efb_format_), copy_format(copy_format_), depth(depth_), yuv(yuv_), copy_filter(copy_filter_) { @@ -63,7 +63,7 @@ struct EFBCopyParams std::tie(rhs.efb_format, rhs.copy_format, rhs.depth, rhs.yuv, rhs.copy_filter); } - PEControl::PixelFormat efb_format; + PixelFormat efb_format; EFBCopyFormat copy_format; bool depth; bool yuv; diff --git a/Source/Core/VideoCommon/TextureConversionShader.cpp b/Source/Core/VideoCommon/TextureConversionShader.cpp index 66607da4dc..1bddf9cf30 100644 --- a/Source/Core/VideoCommon/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/TextureConversionShader.cpp @@ -127,13 +127,13 @@ static void WriteSampleFunction(ShaderCode& code, const EFBCopyParams& params, A { switch (params.efb_format) { - case PEControl::RGB8_Z24: + case PixelFormat::RGB8_Z24: code.Write("RGBA8ToRGB8("); break; - case PEControl::RGBA6_Z24: + case PixelFormat::RGBA6_Z24: code.Write("RGBA8ToRGBA6("); break; - case PEControl::RGB565_Z16: + case PixelFormat::RGB565_Z16: code.Write("RGBA8ToRGB565("); break; default: diff --git a/Source/Core/VideoCommon/TextureConverterShaderGen.cpp b/Source/Core/VideoCommon/TextureConverterShaderGen.cpp index 9c0ccfe268..5dfae8212d 100644 --- a/Source/Core/VideoCommon/TextureConverterShaderGen.cpp +++ b/Source/Core/VideoCommon/TextureConverterShaderGen.cpp @@ -19,7 +19,7 @@ TCShaderUid GetShaderUid(EFBCopyFormat dst_format, bool is_depth_copy, bool is_i UidData* const uid_data = out.GetUidData(); uid_data->dst_format = dst_format; - uid_data->efb_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + uid_data->efb_has_alpha = bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24; uid_data->is_depth_copy = is_depth_copy; uid_data->is_intensity = is_intensity; uid_data->scale_by_half = scale_by_half; diff --git a/Source/Core/VideoCommon/TextureDecoder.h b/Source/Core/VideoCommon/TextureDecoder.h index 7a08a6514a..e4b25e50ec 100644 --- a/Source/Core/VideoCommon/TextureDecoder.h +++ b/Source/Core/VideoCommon/TextureDecoder.h @@ -6,6 +6,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/EnumFormatter.h" enum { @@ -32,8 +33,17 @@ enum class TextureFormat // Special texture format used to represent YUVY xfb copies. // They aren't really textures, but they share so much hardware and usecases that it makes sense // to emulate them as part of texture cache. + // This isn't a real value that can be used on console; it only exists for ease of implementation. XFB = 0xF, }; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = {"I4", "I8", "IA4", "IA8", "RGB565", + "RGB5A3", "RGBA8", nullptr, "C4", "C8", + "C14X2", nullptr, nullptr, nullptr, "CMPR"}; + formatter() : EnumFormatter(names) {} +}; static inline bool IsColorIndexed(TextureFormat format) { @@ -82,8 +92,20 @@ enum class EFBCopyFormat // Special texture format used to represent YUVY xfb copies. // They aren't really textures, but they share so much hardware and usecases that it makes sense // to emulate them as part of texture cache. + // This isn't a real value that can be used on console; it only exists for ease of implementation. XFB = 0xF, }; +template <> +struct fmt::formatter : EnumFormatter +{ + static constexpr array_type names = { + "R4/I4/Z4", "R8/I8/Z8H (?)", "RA4/IA4", "RA8/IA8 (Z16 too?)", + "RGB565", "RGB5A3", "RGBA8", "A8", + "R8/I8/Z8H", "G8/Z8M", "B8/Z8L", "RG8/Z16R (Note: G and R are reversed)", + "GB8/Z16L", + }; + formatter() : EnumFormatter(names) {} +}; enum class TLUTFormat { @@ -92,6 +114,11 @@ enum class TLUTFormat RGB565 = 0x1, RGB5A3 = 0x2, }; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"IA8", "RGB565", "RGB5A3"}) {} +}; static inline bool IsValidTLUTFormat(TLUTFormat tlutfmt) { diff --git a/Source/Core/VideoCommon/UberShaderPixel.cpp b/Source/Core/VideoCommon/UberShaderPixel.cpp index 721912a3f3..c15ab12cc8 100644 --- a/Source/Core/VideoCommon/UberShaderPixel.cpp +++ b/Source/Core/VideoCommon/UberShaderPixel.cpp @@ -22,12 +22,12 @@ PixelShaderUid GetPixelShaderUid() pixel_ubershader_uid_data* const uid_data = out.GetUidData(); uid_data->num_texgens = xfmem.numTexGen.numTexGens; - uid_data->early_depth = - bpmem.UseEarlyDepthTest() && - (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) && - !(bpmem.zmode.testenable && bpmem.genMode.zfreeze); + uid_data->early_depth = bpmem.UseEarlyDepthTest() && + (g_ActiveConfig.bFastDepthCalc || + bpmem.alpha_test.TestResult() == AlphaTestResult::Undetermined) && + !(bpmem.zmode.testenable && bpmem.genMode.zfreeze); uid_data->per_pixel_depth = - (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || + (bpmem.ztex2.op != ZTexOp::Disabled && bpmem.UseLateDepthTest()) || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !uid_data->early_depth) || (bpmem.zmode.testenable && bpmem.genMode.zfreeze); uid_data->uint_output = bpmem.blendmode.UseLogicOp(); @@ -367,21 +367,21 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, "// which are common to both color and alpha channels\n" "bool tevCompare(uint op, int3 color_A, int3 color_B) {{\n" " switch (op) {{\n" - " case 0u: // TEVCMP_R8_GT\n" + " case 0u: // TevCompareMode::R8, TevComparison::GT\n" " return (color_A.r > color_B.r);\n" - " case 1u: // TEVCMP_R8_EQ\n" + " case 1u: // TevCompareMode::R8, TevComparison::EQ\n" " return (color_A.r == color_B.r);\n" - " case 2u: // TEVCMP_GR16_GT\n" + " case 2u: // TevCompareMode::GR16, TevComparison::GT\n" " int A_16 = (color_A.r | (color_A.g << 8));\n" " int B_16 = (color_B.r | (color_B.g << 8));\n" " return A_16 > B_16;\n" - " case 3u: // TEVCMP_GR16_EQ\n" + " case 3u: // TevCompareMode::GR16, TevComparison::EQ\n" " return (color_A.r == color_B.r && color_A.g == color_B.g);\n" - " case 4u: // TEVCMP_BGR24_GT\n" + " case 4u: // TevCompareMode::BGR24, TevComparison::GT\n" " int A_24 = (color_A.r | (color_A.g << 8) | (color_A.b << 16));\n" " int B_24 = (color_B.r | (color_B.g << 8) | (color_B.b << 16));\n" " return A_24 > B_24;\n" - " case 5u: // TEVCMP_BGR24_EQ\n" + " case 5u: // TevCompareMode::BGR24, TevComparison::EQ\n" " return (color_A.r == color_B.r && color_A.g == color_B.g && color_A.b == color_B.b);\n" " default:\n" " return false;\n" @@ -814,29 +814,29 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, " s.AlphaBump = indcoord[bs - 1u];\n" " switch(fmt)\n" " {{\n" - " case {}u:\n", - ITF_8); + " case {:s}:\n", + IndTexFormat::ITF_8); out.Write(" indcoord.x = indcoord.x + ((bias & 1u) != 0u ? -128 : 0);\n" " indcoord.y = indcoord.y + ((bias & 2u) != 0u ? -128 : 0);\n" " indcoord.z = indcoord.z + ((bias & 4u) != 0u ? -128 : 0);\n" " s.AlphaBump = s.AlphaBump & 0xf8;\n" " break;\n" - " case {}u:\n", - ITF_5); + " case {:s}:\n", + IndTexFormat::ITF_5); out.Write(" indcoord.x = (indcoord.x & 0x1f) + ((bias & 1u) != 0u ? 1 : 0);\n" " indcoord.y = (indcoord.y & 0x1f) + ((bias & 2u) != 0u ? 1 : 0);\n" " indcoord.z = (indcoord.z & 0x1f) + ((bias & 4u) != 0u ? 1 : 0);\n" " s.AlphaBump = s.AlphaBump & 0xe0;\n" " break;\n" - " case {}u:\n", - ITF_4); + " case {:s}:\n", + IndTexFormat::ITF_4); out.Write(" indcoord.x = (indcoord.x & 0x0f) + ((bias & 1u) != 0u ? 1 : 0);\n" " indcoord.y = (indcoord.y & 0x0f) + ((bias & 2u) != 0u ? 1 : 0);\n" " indcoord.z = (indcoord.z & 0x0f) + ((bias & 4u) != 0u ? 1 : 0);\n" " s.AlphaBump = s.AlphaBump & 0xf0;\n" " break;\n" - " case {}u:\n", - ITF_3); + " case {:s}:\n", + IndTexFormat::ITF_3); out.Write(" indcoord.x = (indcoord.x & 0x07) + ((bias & 1u) != 0u ? 1 : 0);\n" " indcoord.y = (indcoord.y & 0x07) + ((bias & 2u) != 0u ? 1 : 0);\n" " indcoord.z = (indcoord.z & 0x07) + ((bias & 4u) != 0u ? 1 : 0);\n" @@ -924,7 +924,7 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, out.Write(" bool color_clamp = bool({});\n", BitfieldExtract("ss.cc", TevStageCombiner().colorC.clamp)); out.Write(" uint color_shift = {};\n", - BitfieldExtract("ss.cc", TevStageCombiner().colorC.shift)); + BitfieldExtract("ss.cc", TevStageCombiner().colorC.scale)); out.Write(" uint color_dest = {};\n", BitfieldExtract("ss.cc", TevStageCombiner().colorC.dest)); @@ -949,12 +949,12 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, " }} else {{ // Compare mode\n" " // op 6 and 7 do a select per color channel\n" " if (color_compare_op == 6u) {{\n" - " // TEVCMP_RGB8_GT\n" + " // TevCompareMode::RGB8, TevComparison::GT\n" " color.r = (color_A.r > color_B.r) ? color_C.r : 0;\n" " color.g = (color_A.g > color_B.g) ? color_C.g : 0;\n" " color.b = (color_A.b > color_B.b) ? color_C.b : 0;\n" " }} else if (color_compare_op == 7u) {{\n" - " // TEVCMP_RGB8_EQ\n" + " // TevCompareMode::RGB8, TevComparison::EQ\n" " color.r = (color_A.r == color_B.r) ? color_C.r : 0;\n" " color.g = (color_A.g == color_B.g) ? color_C.g : 0;\n" " color.b = (color_A.b == color_B.b) ? color_C.b : 0;\n" @@ -990,7 +990,7 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, out.Write(" bool alpha_clamp = bool({});\n", BitfieldExtract("ss.ac", TevStageCombiner().alphaC.clamp)); out.Write(" uint alpha_shift = {};\n", - BitfieldExtract("ss.ac", TevStageCombiner().alphaC.shift)); + BitfieldExtract("ss.ac", TevStageCombiner().alphaC.scale)); out.Write(" uint alpha_dest = {};\n", BitfieldExtract("ss.ac", TevStageCombiner().alphaC.dest)); @@ -1016,10 +1016,10 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, "true, alpha_shift);\n" " }} else {{ // Compare mode\n" " if (alpha_compare_op == 6u) {{\n" - " // TEVCMP_A8_GT\n" + " // TevCompareMode::A8, TevComparison::GT\n" " alpha = (alpha_A > alpha_B) ? alpha_C : 0;\n" " }} else if (alpha_compare_op == 7u) {{\n" - " // TEVCMP_A8_EQ\n" + " // TevCompareMode::A8, TevComparison::EQ\n" " alpha = (alpha_A == alpha_B) ? alpha_C : 0;\n" " }} else {{\n" " // All remaining alpha compare ops actually compare the color channels\n" @@ -1157,8 +1157,8 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, out.Write(" // Fog\n" " uint fog_function = {};\n", BitfieldExtract("bpmem_fogParam3", FogParam3().fsel)); - out.Write(" if (fog_function != 0u) {{\n" - " // TODO: This all needs to be converted from float to fixed point\n" + out.Write(" if (fog_function != {:s}) {{\n", FogType::Off); + out.Write(" // TODO: This all needs to be converted from float to fixed point\n" " float ze;\n" " if ({} == 0u) {{\n", BitfieldExtract("bpmem_fogParam3", FogParam3().proj)); @@ -1188,23 +1188,27 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, " }}\n" "\n" " float fog = clamp(ze - " I_FOGF ".y, 0.0, 1.0);\n" - "\n" - " if (fog_function > 3u) {{\n" - " switch (fog_function) {{\n" - " case 4u:\n" + "\n"); + out.Write(" if (fog_function >= {:s}) {{\n", FogType::Exp); + out.Write(" switch (fog_function) {{\n" + " case {:s}:\n" " fog = 1.0 - exp2(-8.0 * fog);\n" - " break;\n" - " case 5u:\n" + " break;\n", + FogType::Exp); + out.Write(" case {:s}:\n" " fog = 1.0 - exp2(-8.0 * fog * fog);\n" - " break;\n" - " case 6u:\n" + " break;\n", + FogType::ExpSq); + out.Write(" case {:s}:\n" " fog = exp2(-8.0 * (1.0 - fog));\n" - " break;\n" - " case 7u:\n" + " break;\n", + FogType::BackwardsExp); + out.Write(" case {:s}:\n" " fog = 1.0 - fog;\n" " fog = exp2(-8.0 * fog * fog);\n" - " break;\n" - " }}\n" + " break;\n", + FogType::BackwardsExpSq); + out.Write(" }}\n" " }}\n" "\n" " int ifog = iround(fog * 256.0);\n" diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index 4dcc211178..fdb63679f5 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -293,7 +293,7 @@ int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bo // if cull mode is CULL_ALL, tell VertexManager to skip triangles and quads. // They still need to go through vertex loading, because we need to calculate a zfreeze refrence // slope. - bool cullall = (bpmem.genMode.cullmode == GenMode::CULL_ALL && primitive < 5); + bool cullall = (bpmem.genMode.cullmode == CullMode::All && primitive < 5); DataReader dst = g_vertex_manager->PrepareForAdditionalData( primitive, count, loader->m_native_vtx_decl.stride, cullall); From df81210e96c6603d3aeb6c76f51b030d06cd06ac Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sun, 7 Feb 2021 15:25:11 -0800 Subject: [PATCH 17/17] Use formatters in GetBPRegInfo; add missing commands BPMEM_TEV_COLOR_ENV + 6 (0xC6) was missing due to a typo. BPMEM_BP_MASK (0xFE) does not lend itself well to documentation with the current FIFO analyzer implementation (since it requires remembering the values in BP memory) but still shouldn't be treated as unknown. BPMEM_TX_SETMODE0_4 and BPMEM_TX_SETMODE1_4 (0xA4-0xAB) were missing entirely. --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 28 +- Source/Core/VideoCommon/BPMemory.h | 561 +++++++++++++++++- Source/Core/VideoCommon/BPStructs.cpp | 610 ++++++++------------ 3 files changed, 821 insertions(+), 378 deletions(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 8764e30b19..4b9020ab8f 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -287,11 +287,17 @@ void FIFOAnalyzer::UpdateDetails() case OpcodeDecoder::GX_LOAD_BP_REG: { - u32 cmd2 = Common::swap32(objectdata); - objectdata += 4; - new_label = QStringLiteral("BP %1 %2") - .arg(cmd2 >> 24, 2, 16, QLatin1Char('0')) - .arg(cmd2 & 0xFFFFFF, 6, 16, QLatin1Char('0')); + const u8 cmd2 = *objectdata++; + const u32 cmddata = Common::swap24(objectdata); + objectdata += 3; + + const auto [name, desc] = GetBPRegInfo(cmd2, cmddata); + ASSERT(!name.empty()); + + new_label = QStringLiteral("BP %1 %2 %3") + .arg(cmd2, 2, 16, QLatin1Char('0')) + .arg(cmddata, 6, 16, QLatin1Char('0')) + .arg(QString::fromStdString(name)); } break; @@ -476,14 +482,14 @@ void FIFOAnalyzer::UpdateDescription() QString text; if (*cmddata == OpcodeDecoder::GX_LOAD_BP_REG) { - std::string name; - std::string desc; - GetBPRegInfo(cmddata + 1, &name, &desc); + const u8 cmd = *(cmddata + 1); + const u32 value = Common::swap24(cmddata + 2); + + const auto [name, desc] = GetBPRegInfo(cmd, value); + ASSERT(!name.empty()); text = tr("BP register "); - text += name.empty() ? - QStringLiteral("UNKNOWN_%1").arg(*(cmddata + 1), 2, 16, QLatin1Char('0')) : - QString::fromStdString(name); + text += QString::fromStdString(name); text += QLatin1Char{'\n'}; if (desc.empty()) diff --git a/Source/Core/VideoCommon/BPMemory.h b/Source/Core/VideoCommon/BPMemory.h index 2a8d8ba0dd..035fa5531e 100644 --- a/Source/Core/VideoCommon/BPMemory.h +++ b/Source/Core/VideoCommon/BPMemory.h @@ -6,8 +6,10 @@ #include #include +#include #include "Common/BitField.h" +#include "Common/BitUtils.h" #include "Common/CommonTypes.h" #include "Common/EnumFormatter.h" #include "Common/Inline.h" @@ -411,6 +413,50 @@ struct TevStageCombiner ColorCombiner colorC; AlphaCombiner alphaC; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TevStageCombiner::ColorCombiner& cc, FormatContext& ctx) + { + return format_to(ctx.out(), + "a: {}\n" + "b: {}\n" + "c: {}\n" + "d: {}\n" + "Bias: {}\n" + "Op: {} / Comparison: {}\n" + "Clamp: {}\n" + "Scale factor: {} / Compare mode: {}\n" + "Dest: {}", + cc.a, cc.b, cc.c, cc.d, cc.bias, cc.op, cc.comparison, cc.clamp ? "Yes" : "No", + cc.scale, cc.compare_mode, cc.dest); + } +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TevStageCombiner::AlphaCombiner& ac, FormatContext& ctx) + { + return format_to(ctx.out(), + "a: {}\n" + "b: {}\n" + "c: {}\n" + "d: {}\n" + "Bias: {}\n" + "Op: {} / Comparison: {}\n" + "Clamp: {}\n" + "Scale factor: {} / Compare mode: {}\n" + "Dest: {}\n" + "Ras sel: {}\n" + "Tex sel: {}", + ac.a, ac.b, ac.c, ac.d, ac.bias, ac.op, ac.comparison, ac.clamp ? "Yes" : "No", + ac.scale, ac.compare_mode, ac.dest, ac.rswap, ac.tswap); + } +}; // several discoveries: // GXSetTevIndBumpST(tevstage, indstage, matrixind) @@ -444,10 +490,33 @@ union TevStageIndirect u32 unused : 11; }; + u32 fullhex; + // If bs and mid are zero, the result of the stage is independent of // the texture sample data, so we can skip sampling the texture. bool IsActive() const { return bs != IndTexBumpAlpha::Off || mid != 0; } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TevStageIndirect& tevind, FormatContext& ctx) + { + return format_to(ctx.out(), + "Indirect tex stage ID: {}\n" + "Format: {}\n" + "Bias: {}\n" + "Bump alpha: {}\n" + "Offset matrix ID: {}\n" + "Regular coord S wrapping factor: {}\n" + "Regular coord T wrapping factor: {}\n" + "Use modified texture coordinates for LOD computation: {}\n" + "Add texture coordinates from previous TEV stage: {}", + tevind.bt, tevind.fmt, tevind.bias, tevind.bs, tevind.mid, tevind.sw, + tevind.tw, tevind.lb_utclod ? "Yes" : "No", tevind.fb_addprev ? "Yes" : "No"); + } +}; enum class RasColorChan : u32 { @@ -485,6 +554,23 @@ union TwoTevStageOrders u32 getEnable(int i) const { return i ? enable1.Value() : enable0.Value(); } RasColorChan getColorChan(int i) const { return i ? colorchan1.Value() : colorchan0.Value(); } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TwoTevStageOrders& stages, FormatContext& ctx) + { + return format_to(ctx.out(), + "Stage 0 texmap: {}\nStage 0 tex coord: {}\n" + "Stage 0 enable texmap: {}\nStage 0 color channel: {}\n" + "Stage 1 texmap: {}\nStage 1 tex coord: {}\n" + "Stage 1 enable texmap: {}\nStage 1 color channel: {}\n", + stages.texmap0, stages.texcoord0, stages.enable0 ? "Yes" : "No", + stages.colorchan0, stages.texmap1, stages.texcoord1, + stages.enable1 ? "Yes" : "No", stages.colorchan1); + } +}; union TEXSCALE { @@ -494,6 +580,22 @@ union TEXSCALE BitField<12, 4, u32> ts1; // Indirect tex stage 1 u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TEXSCALE& scale, FormatContext& ctx) + { + return format_to(ctx.out(), + "Even stage S scale: {} ({})\n" + "Even stage T scale: {} ({})\n" + "Odd stage S scale: {} ({})\n" + "Odd stage T scale: {} ({})", + scale.ss0, 1.f / (1 << scale.ss0), scale.ts0, 1.f / (1 << scale.ts0), + scale.ss1, 1.f / (1 << scale.ss1), scale.ts1, 1.f / (1 << scale.ts1)); + } +}; union RAS1_IREF { @@ -510,6 +612,23 @@ union RAS1_IREF u32 getTexCoord(int i) const { return (hex >> (6 * i + 3)) & 7; } u32 getTexMap(int i) const { return (hex >> (6 * i)) & 7; } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const RAS1_IREF& indref, FormatContext& ctx) + { + // The field names here are suspicious, since there is no bi3 or bc2 + return format_to(ctx.out(), + "Stage 0 ntexmap: {}\nStage 0 ntexcoord: {}\n" + "Stage 1 ntexmap: {}\nStage 1 ntexcoord: {}\n" + "Stage 2 ntexmap: {}\nStage 2 ntexcoord: {}\n" + "Stage 3 ntexmap: {}\nStage 3 ntexcoord: {}", + indref.bi0, indref.bc0, indref.bi1, indref.bc1, indref.bi2, indref.bc3, + indref.bi4, indref.bc4); + } +}; // Texture structs enum class WrapMode : u32 @@ -583,12 +702,47 @@ union TexMode0 BitField<21, 1, bool, u32> lod_clamp; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TexMode0& mode, FormatContext& ctx) + { + return format_to(ctx.out(), + "Wrap S: {}\n" + "Wrap T: {}\n" + "Mag filter: {}\n" + "Mipmap filter: {}\n" + "Min filter: {}\n" + "LOD type: {}\n" + "LOD bias: {} ({})\n" + "Max aniso: {}\n" + "LOD/bias clamp: {}", + mode.wrap_s, mode.wrap_t, mode.mag_filter, mode.mipmap_filter, mode.min_filter, + mode.diag_lod, mode.lod_bias, mode.lod_bias / 32.f, mode.max_aniso, + mode.lod_clamp ? "Yes" : "No"); + } +}; + union TexMode1 { BitField<0, 8, u32> min_lod; BitField<8, 8, u32> max_lod; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TexMode1& mode, FormatContext& ctx) + { + return format_to(ctx.out(), "Min LOD: {} ({})\nMax LOD: {} ({})", mode.min_lod, + mode.min_lod / 16.f, mode.max_lod, mode.max_lod / 16.f); + } +}; + union TexImage0 { BitField<0, 10, u32> width; // Actually w-1 @@ -596,6 +750,21 @@ union TexImage0 BitField<20, 4, TextureFormat> format; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TexImage0& teximg, FormatContext& ctx) + { + return format_to(ctx.out(), + "Width: {}\n" + "Height: {}\n" + "Format: {}", + teximg.width + 1, teximg.height + 1, teximg.format); + } +}; + union TexImage1 { BitField<0, 15, u32> tmem_even; // TMEM line index for even LODs @@ -606,6 +775,22 @@ union TexImage1 BitField<21, 1, bool, u32> cache_manually_managed; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TexImage1& teximg, FormatContext& ctx) + { + return format_to(ctx.out(), + "Even TMEM Offset: {:x}\n" + "Even TMEM Width: {}\n" + "Even TMEM Height: {}\n" + "Cache is manually managed: {}", + teximg.tmem_even, teximg.cache_width, teximg.cache_height, + teximg.cache_manually_managed ? "Yes" : "No"); + } +}; union TexImage2 { @@ -614,18 +799,55 @@ union TexImage2 BitField<18, 3, u32> cache_height; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TexImage2& teximg, FormatContext& ctx) + { + return format_to(ctx.out(), + "Odd TMEM Offset: {:x}\n" + "Odd TMEM Width: {}\n" + "Odd TMEM Height: {}", + teximg.tmem_odd, teximg.cache_width, teximg.cache_height); + } +}; union TexImage3 { BitField<0, 24, u32> image_base; // address in memory >> 5 (was 20 for GC) u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TexImage3& teximg, FormatContext& ctx) + { + return format_to(ctx.out(), "Source address (32 byte aligned): 0x{:06X}", + teximg.image_base << 5); + } +}; + union TexTLUT { BitField<0, 10, u32> tmem_offset; BitField<10, 2, TLUTFormat> tlut_format; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TexTLUT& tlut, FormatContext& ctx) + { + return format_to(ctx.out(), "Address: {:08x}\nFormat: {}", tlut.tmem_offset << 9, + tlut.tlut_format); + } +}; union ZTex1 { @@ -639,6 +861,16 @@ union ZTex2 BitField<2, 2, ZTexOp> op; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const ZTex2& ztex2, FormatContext& ctx) + { + return format_to(ctx.out(), "Type: {}\nOperation: {}", ztex2.type, ztex2.op); + } +}; struct FourTexUnits { @@ -686,6 +918,29 @@ union GenMode u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const GenMode& mode, FormatContext& ctx) + { + return format_to(ctx.out(), + "Num tex gens: {}\n" + "Num color channels: {}\n" + "Unused bit: {}\n" + "Flat shading (unconfirmed): {}\n" + "Multisampling: {}\n" + "Num TEV stages: {}\n" + "Cull mode: {}\n" + "Num indirect stages: {}\n" + "ZFreeze: {}", + mode.numtexgens, mode.numcolchans, mode.unused, + mode.flat_shading ? "Yes" : "No", mode.multisampling ? "Yes" : "No", + mode.numtevstages, mode.cullmode, mode.numindstages, + mode.zfreeze ? "Yes" : "No"); + } +}; enum class AspectRatioAdjustment { @@ -708,6 +963,23 @@ union LPSize BitField<22, 1, AspectRatioAdjustment> adjust_for_aspect_ratio; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const LPSize& lp, FormatContext& ctx) + { + return format_to(ctx.out(), + "Line size: {} ({:.3} pixels)\n" + "Point size: {} ({:.3} pixels)\n" + "Line offset: {}\n" + "Point offset: {}\n" + "Adjust line aspect ratio: {}", + lp.linesize, lp.linesize / 6.f, lp.pointsize, lp.pointsize / 6.f, lp.lineoff, + lp.pointoff, lp.adjust_for_aspect_ratio); + } +}; union X12Y12 { @@ -820,6 +1092,29 @@ union BlendMode bool UseLogicOp() const; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const BlendMode& mode, FormatContext& ctx) + { + static constexpr std::array no_yes = {"No", "Yes"}; + return format_to(ctx.out(), + "Enable: {}\n" + "Logic ops: {}\n" + "Dither: {}\n" + "Color write: {}\n" + "Alpha write: {}\n" + "Dest factor: {}\n" + "Source factor: {}\n" + "Subtract: {}\n" + "Logic mode: {}", + no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither], + no_yes[mode.colorupdate], no_yes[mode.alphaupdate], mode.dstfactor, + mode.srcfactor, no_yes[mode.subtract], mode.logicmode); + } +}; union FogParam0 { @@ -830,6 +1125,17 @@ union FogParam0 u32 hex; float FloatValue() const; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const FogParam0& param, FormatContext& ctx) + { + return format_to(ctx.out(), "A value: {}\nMantissa: {}\nExponent: {}\nSign: {}", + param.FloatValue(), param.mant, param.exp, param.sign ? '-' : '+'); + } +}; enum class FogProjection : u32 { @@ -878,6 +1184,19 @@ union FogParam3 u32 hex; float FloatValue() const; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const FogParam3& param, FormatContext& ctx) + { + return format_to(ctx.out(), + "C value: {}\nMantissa: {}\nExponent: {}\nSign: {}\nProjection: {}\nFsel: {}", + param.FloatValue(), param.c_mant, param.c_exp, param.c_sign ? '-' : '+', + param.proj, param.fsel); + } +}; union FogRangeKElement { @@ -900,6 +1219,28 @@ struct FogRangeParams RangeBase Base; FogRangeKElement K[5]; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const FogRangeParams::RangeBase& range, FormatContext& ctx) + { + return format_to(ctx.out(), "Center: {}\nEnabled: {}", range.Center, + range.Enabled ? "Yes" : "No"); + } +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const FogRangeKElement& range, FormatContext& ctx) + { + return format_to(ctx.out(), "High: {}\nLow: {}", range.HI, range.LO); + } +}; + // final eq: ze = A/(B_MAG - (Zs>>B_SHF)); struct FogParams { @@ -925,6 +1266,16 @@ struct FogParams // amount to subtract from eyespacez after range adjustment float GetC() const; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const FogParams::FogColor& color, FormatContext& ctx) + { + return format_to(ctx.out(), "Red: {}\nGreen: {}\nBlue: {}", color.r, color.g, color.b); + } +}; enum class CompareMode : u32 { @@ -953,6 +1304,20 @@ union ZMode u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const ZMode& mode, FormatContext& ctx) + { + return format_to(ctx.out(), + "Enable test: {}\n" + "Compare function: {}\n" + "Enable updates: {}", + mode.testenable ? "Yes" : "No", mode.func, mode.updateenable ? "Yes" : "No"); + } +}; union ConstantAlpha { @@ -960,6 +1325,19 @@ union ConstantAlpha BitField<8, 1, bool, u32> enable; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const ConstantAlpha& c, FormatContext& ctx) + { + return format_to(ctx.out(), + "Enable: {}\n" + "Alpha value: {:02x}", + c.enable ? "Yes" : "No", c.alpha); + } +}; union FieldMode { @@ -967,6 +1345,17 @@ union FieldMode BitField<0, 1, AspectRatioAdjustment> texLOD; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const FieldMode& mode, FormatContext& ctx) + { + return format_to(ctx.out(), "Adjust vertex tex LOD computation to account for interlacing: {}", + mode.texLOD); + } +}; enum class FieldMaskState : u32 { @@ -986,6 +1375,16 @@ union FieldMask BitField<1, 1, FieldMaskState> even; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const FieldMask& mask, FormatContext& ctx) + { + return format_to(ctx.out(), "Odd field: {}\nEven field: {}", mask.odd, mask.even); + } +}; enum class PixelFormat : u32 { @@ -1038,6 +1437,20 @@ union PEControl u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const PEControl& config, FormatContext& ctx) + { + return format_to(ctx.out(), + "EFB pixel format: {}\n" + "Depth format: {}\n" + "Early depth test: {}", + config.pixel_format, config.zformat, config.early_ztest ? "Yes" : "No"); + } +}; // Texture coordinate stuff @@ -1051,6 +1464,25 @@ union TCInfo BitField<19, 1, bool, u32> point_offset; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TCInfo& info, FormatContext& ctx) + { + return format_to(ctx.out(), + "Scale: {}\n" + "Range bias: {}\n" + "Cylindric wrap: {}\n" + "Use line offset: {} (s only)\n" + "Use point offset: {} (s only)", + info.scale_minus_1 + 1, info.range_bias ? "Yes" : "No", + info.cylindric_wrap ? "Yes" : "No", info.line_offset ? "Yes" : "No", + info.point_offset ? "Yes" : "No"); + } +}; + struct TCoordInfo { TCInfo s; @@ -1062,6 +1494,11 @@ enum class TevRegType : u32 Color = 0, Constant = 1, }; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Color", "Constant"}) {} +}; struct TevReg { @@ -1086,6 +1523,37 @@ struct TevReg RA ra; BG bg; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TevReg::RA& ra, FormatContext& ctx) + { + return format_to(ctx.out(), "Type: {}\nAlpha: {:03x}\nRed: {:03x}", ra.type, ra.alpha, ra.red); + } +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TevReg::BG& bg, FormatContext& ctx) + { + return format_to(ctx.out(), "Type: {}\nGreen: {:03x}\nBlue: {:03x}", bg.type, bg.green, + bg.blue); + } +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TevReg& reg, FormatContext& ctx) + { + return format_to(ctx.out(), "{}\n{}", reg.ra, reg.bg); + } +}; enum class KonstSel : u32 { @@ -1172,6 +1640,19 @@ union TevKSel KonstSel getKC(int i) const { return i ? kcsel1.Value() : kcsel0.Value(); } KonstSel getKA(int i) const { return i ? kasel1.Value() : kasel0.Value(); } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TevKSel& ksel, FormatContext& ctx) + { + return format_to(ctx.out(), + "Swap 1: {}\nSwap 2: {}\nColor sel 0: {}\nAlpha sel 0: {}\n" + "Color sel 1: {}\nAlpha sel 1: {}", + ksel.swap1, ksel.swap2, ksel.kcsel0, ksel.kasel0, ksel.kcsel1, ksel.kasel1); + } +}; enum class AlphaTestOp : u32 { @@ -1245,6 +1726,20 @@ union AlphaTest return AlphaTestResult::Undetermined; } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const AlphaTest& test, FormatContext& ctx) + { + return format_to(ctx.out(), + "Test 1: {} (ref: 0x{:02x})\n" + "Test 2: {} (ref: 0x{:02x})\n" + "Logic: {}\n", + test.comp0, test.ref0, test.comp1, test.ref1, test.logic); + } +}; enum class FrameToField : u32 { @@ -1286,6 +1781,60 @@ union UPE_Copy return static_cast(target_pixel_format / 2 + (target_pixel_format & 1) * 8); } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const UPE_Copy& copy, FormatContext& ctx) + { + static constexpr std::array no_yes = {"No", "Yes"}; + std::string_view clamp; + if (copy.clamp_top) + { + if (copy.clamp_bottom) + clamp = "Top and Bottom"; + else + clamp = "Top only"; + } + else + { + if (copy.clamp_bottom) + clamp = "Bottom only"; + else + clamp = "None"; + } + std::string_view gamma = "Invalid"; + switch (copy.gamma) + { + case 0: + gamma = "1.0"; + break; + case 1: + gamma = "1.7"; + break; + case 2: + gamma = "2.2"; + break; + } + + return format_to(ctx.out(), + "Clamping: {}\n" + "Converting from RGB to YUV: {}\n" + "Target pixel format: {}\n" + "Gamma correction: {}\n" + "Mipmap filter: {}\n" + "Vertical scaling: {}\n" + "Clear: {}\n" + "Frame to field: {}\n" + "Copy to XFB: {}\n" + "Intensity format: {}\n" + "Automatic color conversion: {}", + clamp, no_yes[copy.yuv], copy.tp_realFormat(), gamma, no_yes[copy.half_scale], + no_yes[copy.scale_invert], no_yes[copy.clear], copy.frame_to_field, + no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], no_yes[copy.auto_conv]); + } +}; union CopyFilterCoefficients { @@ -1321,6 +1870,16 @@ union BPU_PreloadTileInfo BitField<15, 2, u32> type; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const BPU_PreloadTileInfo& info, FormatContext& ctx) + { + return format_to(ctx.out(), "Type: {}\nCount: {}", info.type, info.count); + } +}; struct BPS_TmemConfig { @@ -1420,4 +1979,4 @@ extern BPMemory bpmem; void LoadBPReg(u32 value0); void LoadBPRegPreprocess(u32 value0); -void GetBPRegInfo(const u8* data, std::string* name, std::string* desc); +std::pair GetBPRegInfo(u8 cmd, u32 cmddata); diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index d0418e9289..2ad90a350a 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -745,61 +745,59 @@ void LoadBPRegPreprocess(u32 value0) } } -void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) +std::pair GetBPRegInfo(u8 cmd, u32 cmddata) { - const char* no_yes[2] = {"No", "Yes"}; +// Macro to set the register name and make sure it was written correctly via compile time assertion +#define RegName(reg) ((void)(reg), #reg) +#define DescriptionlessReg(reg) std::make_pair(RegName(reg), ""); - u8 cmd = data[0]; - u32 cmddata = Common::swap32(data) & 0xFFFFFF; switch (cmd) { -// Macro to set the register name and make sure it was written correctly via compile time assertion -#define SetRegName(reg) \ - *name = #reg; \ - (void)(reg); - case BPMEM_GENMODE: // 0x00 - SetRegName(BPMEM_GENMODE); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_GENMODE), fmt::to_string(GenMode{.hex = cmddata})); case BPMEM_DISPLAYCOPYFILTER: // 0x01 + case BPMEM_DISPLAYCOPYFILTER + 1: + case BPMEM_DISPLAYCOPYFILTER + 2: + case BPMEM_DISPLAYCOPYFILTER + 3: // TODO: This is actually the sample pattern used for copies from an antialiased EFB - SetRegName(BPMEM_DISPLAYCOPYFILTER); + return DescriptionlessReg(BPMEM_DISPLAYCOPYFILTER); // TODO: Description - break; - - case 0x02: // 0x02 - case 0x03: // 0x03 - case 0x04: // 0x04 - // TODO: same as BPMEM_DISPLAYCOPYFILTER - break; case BPMEM_IND_MTXA: // 0x06 - case BPMEM_IND_MTXA + 3: - case BPMEM_IND_MTXA + 6: - SetRegName(BPMEM_IND_MTXA); - // TODO: Description - break; - case BPMEM_IND_MTXB: // 0x07 - case BPMEM_IND_MTXB + 3: - case BPMEM_IND_MTXB + 6: - SetRegName(BPMEM_IND_MTXB); - // TODO: Descriptio - break; - case BPMEM_IND_MTXC: // 0x08 + case BPMEM_IND_MTXA + 3: + case BPMEM_IND_MTXB + 3: case BPMEM_IND_MTXC + 3: + case BPMEM_IND_MTXA + 6: + case BPMEM_IND_MTXB + 6: case BPMEM_IND_MTXC + 6: - SetRegName(BPMEM_IND_MTXC); - // TODO: Description - break; + { + const u32 matrix_num = (cmd - BPMEM_IND_MTXA) / 3; + const u32 matrix_col = (cmd - BPMEM_IND_MTXA) % 3; + // These all use the same structure, though the meaning is *slightly* different; + // for conveninece implement it only once + const s32 row0 = cmddata & 0x0007ff; // ma or mc or me + const s32 row1 = (cmddata & 0x3ff800) >> 11; // mb or md or mf + const u32 scale = (cmddata & 0xc00000) >> 22; // 2 bits of a 6-bit field for each column + + const float row0f = static_cast(row0) / (1 << 10); + const float row1f = static_cast(row0) / (1 << 10); + + return std::make_pair(fmt::format("BPMEM_IND_MTX{} Matrix {}", "ABC"[matrix_col], matrix_num), + fmt::format("Matrix {} column {} ({})\n" + "Row 0 (m{}): {} ({})\n" + "Row 1 (m{}): {} ({})\n" + "Scale bits: {} (shifted: {})", + matrix_num, matrix_col, "ABC"[matrix_col], "ace"[matrix_col], + row0f, row0, "bdf"[matrix_col], row1f, row1, scale, + scale << (2 * matrix_col))); + } case BPMEM_IND_IMASK: // 0x0F - SetRegName(BPMEM_IND_IMASK); + return DescriptionlessReg(BPMEM_IND_IMASK); // TODO: Description - break; case BPMEM_IND_CMD: // 0x10 case BPMEM_IND_CMD + 1: @@ -817,49 +815,47 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) case BPMEM_IND_CMD + 13: case BPMEM_IND_CMD + 14: case BPMEM_IND_CMD + 15: - SetRegName(BPMEM_IND_CMD); - // TODO: Description - break; + return std::make_pair(fmt::format("BPMEM_IND_CMD command {}", cmd - BPMEM_IND_CMD), + fmt::to_string(TevStageIndirect{.fullhex = cmddata})); case BPMEM_SCISSORTL: // 0x20 - SetRegName(BPMEM_SCISSORTL); - // TODO: Description - break; + { + const X12Y12 top_left{.hex = cmddata}; + return std::make_pair(RegName(BPMEM_SCISSORTL), + fmt::format("Scissor Top: {}\nScissor Left: {}", top_left.y, top_left.x)); + } case BPMEM_SCISSORBR: // 0x21 - SetRegName(BPMEM_SCISSORBR); - // TODO: Description - break; + { + const X12Y12 bottom_right{.hex = cmddata}; + return std::make_pair( + RegName(BPMEM_SCISSORBR), + fmt::format("Scissor Bottom: {}\nScissor Right: {}", bottom_right.y, bottom_right.x)); + } case BPMEM_LINEPTWIDTH: // 0x22 - SetRegName(BPMEM_LINEPTWIDTH); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_LINEPTWIDTH), fmt::to_string(LPSize{.hex = cmddata})); case BPMEM_PERF0_TRI: // 0x23 - SetRegName(BPMEM_PERF0_TRI); + return DescriptionlessReg(BPMEM_PERF0_TRI); // TODO: Description - break; case BPMEM_PERF0_QUAD: // 0x24 - SetRegName(BPMEM_PERF0_QUAD); + return DescriptionlessReg(BPMEM_PERF0_QUAD); // TODO: Description - break; case BPMEM_RAS1_SS0: // 0x25 - SetRegName(BPMEM_RAS1_SS0); - // TODO: Description - break; + return std::make_pair( + RegName(BPMEM_RAS1_SS0), + fmt::format("Indirect texture stages 0 and 1:\n{}", TEXSCALE{.hex = cmddata})); case BPMEM_RAS1_SS1: // 0x26 - SetRegName(BPMEM_RAS1_SS1); - // TODO: Description - break; + return std::make_pair( + RegName(BPMEM_RAS1_SS1), + fmt::format("Indirect texture stages 2 and 3:\n{}", TEXSCALE{.hex = cmddata})); case BPMEM_IREF: // 0x27 - SetRegName(BPMEM_IREF); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_IREF), fmt::to_string(RAS1_IREF{.hex = cmddata})); case BPMEM_TREF: // 0x28 case BPMEM_TREF + 1: @@ -869,9 +865,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) case BPMEM_TREF + 5: case BPMEM_TREF + 6: case BPMEM_TREF + 7: - SetRegName(BPMEM_TREF); - // TODO: Description - break; + return std::make_pair(fmt::format("BPMEM_TREF number {}", cmd - BPMEM_TREF), + fmt::to_string(TwoTevStageOrders{.hex = cmddata})); case BPMEM_SU_SSIZE: // 0x30 case BPMEM_SU_SSIZE + 2: @@ -881,9 +876,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) case BPMEM_SU_SSIZE + 10: case BPMEM_SU_SSIZE + 12: case BPMEM_SU_SSIZE + 14: - SetRegName(BPMEM_SU_SSIZE); - // TODO: Description - break; + return std::make_pair(fmt::format("BPMEM_SU_SSIZE number {}", (cmd - BPMEM_SU_SSIZE) / 2), + fmt::format("S size info:\n{}", TCInfo{.hex = cmddata})); case BPMEM_SU_TSIZE: // 0x31 case BPMEM_SU_TSIZE + 2: @@ -893,359 +887,283 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) case BPMEM_SU_TSIZE + 10: case BPMEM_SU_TSIZE + 12: case BPMEM_SU_TSIZE + 14: - SetRegName(BPMEM_SU_TSIZE); - // TODO: Description - break; + return std::make_pair(fmt::format("BPMEM_SU_TSIZE number {}", (cmd - BPMEM_SU_TSIZE) / 2), + fmt::format("T size info:\n{}", TCInfo{.hex = cmddata})); case BPMEM_ZMODE: // 0x40 - SetRegName(BPMEM_ZMODE); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_ZMODE), fmt::format("Z mode: {}", ZMode{.hex = cmddata})); case BPMEM_BLENDMODE: // 0x41 - { - SetRegName(BPMEM_BLENDMODE); - BlendMode mode; - mode.hex = cmddata; - *desc = fmt::format("Enable: {}\n" - "Logic ops: {}\n" - "Dither: {}\n" - "Color write: {}\n" - "Alpha write: {}\n" - "Dest factor: {}\n" - "Source factor: {}\n" - "Subtract: {}\n" - "Logic mode: {}\n", - no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither], - no_yes[mode.colorupdate], no_yes[mode.alphaupdate], mode.dstfactor, - mode.srcfactor, no_yes[mode.subtract], mode.logicmode); - } - break; + return std::make_pair(RegName(BPMEM_BLENDMODE), fmt::to_string(BlendMode{.hex = cmddata})); case BPMEM_CONSTANTALPHA: // 0x42 - SetRegName(BPMEM_CONSTANTALPHA); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_CONSTANTALPHA), + fmt::to_string(ConstantAlpha{.hex = cmddata})); case BPMEM_ZCOMPARE: // 0x43 - { - SetRegName(BPMEM_ZCOMPARE); - PEControl config; - config.hex = cmddata; - *desc = fmt::format("EFB pixel format: {}\n" - "Depth format: {}\n" - "Early depth test: {}\n", - config.pixel_format, config.zformat, no_yes[config.early_ztest]); - } - break; + return std::make_pair(RegName(BPMEM_ZCOMPARE), fmt::to_string(PEControl{.hex = cmddata})); case BPMEM_FIELDMASK: // 0x44 - SetRegName(BPMEM_FIELDMASK); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_FIELDMASK), fmt::to_string(FieldMask{.hex = cmddata})); case BPMEM_SETDRAWDONE: // 0x45 - SetRegName(BPMEM_SETDRAWDONE); + return DescriptionlessReg(BPMEM_SETDRAWDONE); // TODO: Description - break; case BPMEM_BUSCLOCK0: // 0x46 - SetRegName(BPMEM_BUSCLOCK0); + return DescriptionlessReg(BPMEM_BUSCLOCK0); // TODO: Description - break; case BPMEM_PE_TOKEN_ID: // 0x47 - SetRegName(BPMEM_PE_TOKEN_ID); + return DescriptionlessReg(BPMEM_PE_TOKEN_ID); // TODO: Description - break; case BPMEM_PE_TOKEN_INT_ID: // 0x48 - SetRegName(BPMEM_PE_TOKEN_INT_ID); + return DescriptionlessReg(BPMEM_PE_TOKEN_INT_ID); // TODO: Description - break; case BPMEM_EFB_TL: // 0x49 { - SetRegName(BPMEM_EFB_TL); - X10Y10 left_top; - left_top.hex = cmddata; - *desc = fmt::format("Left: {}\nTop: {}", u32(left_top.x), u32(left_top.y)); + const X10Y10 left_top{.hex = cmddata}; + return std::make_pair(RegName(BPMEM_EFB_TL), + fmt::format("EFB Left: {}\nEFB Top: {}", left_top.x, left_top.y)); } - break; case BPMEM_EFB_WH: // 0x4A { - SetRegName(BPMEM_EFB_WH); - X10Y10 width_height; - width_height.hex = cmddata; - *desc = fmt::format("Width: {}\nHeight: {}", width_height.x + 1, width_height.y + 1); + const X10Y10 width_height{.hex = cmddata}; + return std::make_pair( + RegName(BPMEM_EFB_WH), + fmt::format("EFB Width: {}\nEFB Height: {}", width_height.x + 1, width_height.y + 1)); } - break; case BPMEM_EFB_ADDR: // 0x4B - SetRegName(BPMEM_EFB_ADDR); - *desc = fmt::format("Target address (32 byte aligned): 0x{:06X}", cmddata << 5); - break; + return std::make_pair( + RegName(BPMEM_EFB_ADDR), + fmt::format("EFB Target address (32 byte aligned): 0x{:06X}", cmddata << 5)); case BPMEM_MIPMAP_STRIDE: // 0x4D - SetRegName(BPMEM_MIPMAP_STRIDE); + return DescriptionlessReg(BPMEM_MIPMAP_STRIDE); // TODO: Description - break; case BPMEM_COPYYSCALE: // 0x4E - SetRegName(BPMEM_COPYYSCALE); - *desc = fmt::format("Scaling factor (XFB copy only): 0x{:X} ({} or inverted {})", cmddata, - static_cast(cmddata) / 256.f, 256.f / static_cast(cmddata)); - break; + return std::make_pair( + RegName(BPMEM_COPYYSCALE), + fmt::format("Y scaling factor (XFB copy only): 0x{:X} ({}, reciprocal {})", cmddata, + static_cast(cmddata) / 256.f, 256.f / static_cast(cmddata))); case BPMEM_CLEAR_AR: // 0x4F - SetRegName(BPMEM_CLEAR_AR); - *desc = fmt::format("Alpha: 0x{:02X}\nRed: 0x{:02X}", (cmddata & 0xFF00) >> 8, cmddata & 0xFF); - break; + return std::make_pair(RegName(BPMEM_CLEAR_AR), + fmt::format("Clear color alpha: 0x{:02X}\nClear color red: 0x{:02X}", + (cmddata & 0xFF00) >> 8, cmddata & 0xFF)); case BPMEM_CLEAR_GB: // 0x50 - SetRegName(BPMEM_CLEAR_GB); - *desc = fmt::format("Green: 0x{:02X}\nBlue: 0x{:02X}", (cmddata & 0xFF00) >> 8, cmddata & 0xFF); - break; + return std::make_pair(RegName(BPMEM_CLEAR_GB), + fmt::format("Clear color green: 0x{:02X}\nClear color blue: 0x{:02X}", + (cmddata & 0xFF00) >> 8, cmddata & 0xFF)); case BPMEM_CLEAR_Z: // 0x51 - SetRegName(BPMEM_CLEAR_Z); - *desc = fmt::format("Z value: 0x{:06X}", cmddata); - break; + return std::make_pair(RegName(BPMEM_CLEAR_Z), fmt::format("Clear Z value: 0x{:06X}", cmddata)); case BPMEM_TRIGGER_EFB_COPY: // 0x52 - { - SetRegName(BPMEM_TRIGGER_EFB_COPY); - UPE_Copy copy; - copy.Hex = cmddata; - *desc = fmt::format( - "Clamping: {}\n" - "Converting from RGB to YUV: {}\n" - "Target pixel format: 0x{:X}\n" - "Gamma correction: {}\n" - "Mipmap filter: {}\n" - "Vertical scaling: {}\n" - "Clear: {}\n" - "Frame to field: {}\n" - "Copy to XFB: {}\n" - "Intensity format: {}\n" - "Automatic color conversion: {}", - (copy.clamp_top && copy.clamp_bottom) ? - "Top and Bottom" : - (copy.clamp_top) ? "Top only" : (copy.clamp_bottom) ? "Bottom only" : "None", - no_yes[copy.yuv], static_cast(copy.tp_realFormat()), - (copy.gamma == 0) ? - "1.0" : - (copy.gamma == 1) ? "1.7" : (copy.gamma == 2) ? "2.2" : "Invalid value 0x3?", - no_yes[copy.half_scale], no_yes[copy.scale_invert], no_yes[copy.clear], copy.frame_to_field, - no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], no_yes[copy.auto_conv]); - } - break; + return std::make_pair(RegName(BPMEM_TRIGGER_EFB_COPY), + fmt::to_string(UPE_Copy{.Hex = cmddata})); case BPMEM_COPYFILTER0: // 0x53 - SetRegName(BPMEM_COPYFILTER0); - // TODO: Description - break; + { + const u32 w0 = (cmddata & 0x00003f); + const u32 w1 = (cmddata & 0x000fc0) >> 6; + const u32 w2 = (cmddata & 0x03f000) >> 12; + const u32 w3 = (cmddata & 0xfc0000) >> 18; + return std::make_pair(RegName(BPMEM_COPYFILTER0), + fmt::format("w0: {}\nw1: {}\nw2: {}\nw3: {}", w0, w1, w2, w3)); + } case BPMEM_COPYFILTER1: // 0x54 - SetRegName(BPMEM_COPYFILTER1); - // TODO: Description - break; + { + const u32 w4 = (cmddata & 0x00003f); + const u32 w5 = (cmddata & 0x000fc0) >> 6; + const u32 w6 = (cmddata & 0x03f000) >> 12; + // There is no w7 + return std::make_pair(RegName(BPMEM_COPYFILTER1), + fmt::format("w4: {}\nw5: {}\nw6: {}", w4, w5, w6)); + } case BPMEM_CLEARBBOX1: // 0x55 - SetRegName(BPMEM_CLEARBBOX1); + return DescriptionlessReg(BPMEM_CLEARBBOX1); // TODO: Description - break; case BPMEM_CLEARBBOX2: // 0x56 - SetRegName(BPMEM_CLEARBBOX2); + return DescriptionlessReg(BPMEM_CLEARBBOX2); // TODO: Description - break; case BPMEM_CLEAR_PIXEL_PERF: // 0x57 - SetRegName(BPMEM_CLEAR_PIXEL_PERF); + return DescriptionlessReg(BPMEM_CLEAR_PIXEL_PERF); // TODO: Description - break; case BPMEM_REVBITS: // 0x58 - SetRegName(BPMEM_REVBITS); + return DescriptionlessReg(BPMEM_REVBITS); // TODO: Description - break; case BPMEM_SCISSOROFFSET: // 0x59 - SetRegName(BPMEM_SCISSOROFFSET); - // TODO: Description - break; + { + const X10Y10 xy{.hex = cmddata}; + return std::make_pair(RegName(BPMEM_EFB_TL), + fmt::format("Scissor X offset: {}\nScissor Y offset: {}", xy.x, xy.y)); + } case BPMEM_PRELOAD_ADDR: // 0x60 - SetRegName(BPMEM_PRELOAD_ADDR); + return DescriptionlessReg(BPMEM_PRELOAD_ADDR); // TODO: Description - break; case BPMEM_PRELOAD_TMEMEVEN: // 0x61 - SetRegName(BPMEM_PRELOAD_TMEMEVEN); + return DescriptionlessReg(BPMEM_PRELOAD_TMEMEVEN); // TODO: Description - break; case BPMEM_PRELOAD_TMEMODD: // 0x62 - SetRegName(BPMEM_PRELOAD_TMEMODD); + return DescriptionlessReg(BPMEM_PRELOAD_TMEMODD); // TODO: Description - break; case BPMEM_PRELOAD_MODE: // 0x63 - SetRegName(BPMEM_PRELOAD_MODE); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_PRELOAD_MODE), + fmt::to_string(BPU_PreloadTileInfo{.hex = cmddata})); case BPMEM_LOADTLUT0: // 0x64 - SetRegName(BPMEM_LOADTLUT0); + return DescriptionlessReg(BPMEM_LOADTLUT0); // TODO: Description - break; case BPMEM_LOADTLUT1: // 0x65 - SetRegName(BPMEM_LOADTLUT1); + return DescriptionlessReg(BPMEM_LOADTLUT1); // TODO: Description - break; case BPMEM_TEXINVALIDATE: // 0x66 - SetRegName(BPMEM_TEXINVALIDATE); + return DescriptionlessReg(BPMEM_TEXINVALIDATE); // TODO: Description - break; case BPMEM_PERF1: // 0x67 - SetRegName(BPMEM_PERF1); + return DescriptionlessReg(BPMEM_PERF1); // TODO: Description - break; case BPMEM_FIELDMODE: // 0x68 - SetRegName(BPMEM_FIELDMODE); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_FIELDMODE), fmt::to_string(FieldMode{.hex = cmddata})); case BPMEM_BUSCLOCK1: // 0x69 - SetRegName(BPMEM_BUSCLOCK1); + return DescriptionlessReg(BPMEM_BUSCLOCK1); // TODO: Description - break; case BPMEM_TX_SETMODE0: // 0x80 case BPMEM_TX_SETMODE0 + 1: case BPMEM_TX_SETMODE0 + 2: case BPMEM_TX_SETMODE0 + 3: - SetRegName(BPMEM_TX_SETMODE0); - // TODO: Description - break; + return std::make_pair(fmt::format("BPMEM_TX_SETMODE0 Texture Unit {}", cmd - BPMEM_TX_SETMODE0), + fmt::to_string(TexMode0{.hex = cmddata})); case BPMEM_TX_SETMODE1: // 0x84 case BPMEM_TX_SETMODE1 + 1: case BPMEM_TX_SETMODE1 + 2: case BPMEM_TX_SETMODE1 + 3: - SetRegName(BPMEM_TX_SETMODE1); - // TODO: Description - break; + return std::make_pair(fmt::format("BPMEM_TX_SETMODE1 Texture Unit {}", cmd - BPMEM_TX_SETMODE1), + fmt::to_string(TexMode1{.hex = cmddata})); case BPMEM_TX_SETIMAGE0: // 0x88 case BPMEM_TX_SETIMAGE0 + 1: case BPMEM_TX_SETIMAGE0 + 2: case BPMEM_TX_SETIMAGE0 + 3: - case BPMEM_TX_SETIMAGE0_4: // 0xA8 - case BPMEM_TX_SETIMAGE0_4 + 1: - case BPMEM_TX_SETIMAGE0_4 + 2: - case BPMEM_TX_SETIMAGE0_4 + 3: - { - SetRegName(BPMEM_TX_SETIMAGE0); - int texnum = - (cmd < BPMEM_TX_SETIMAGE0_4) ? cmd - BPMEM_TX_SETIMAGE0 : cmd - BPMEM_TX_SETIMAGE0_4 + 4; - TexImage0 teximg; - teximg.hex = cmddata; - *desc = fmt::format("Texture Unit: {}\n" - "Width: {}\n" - "Height: {}\n" - "Format: {}\n", - texnum, u32(teximg.width) + 1, u32(teximg.height) + 1, teximg.format); - } - break; + return std::make_pair( + fmt::format("BPMEM_TX_SETIMAGE0 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE0), + fmt::to_string(TexImage0{.hex = cmddata})); case BPMEM_TX_SETIMAGE1: // 0x8C case BPMEM_TX_SETIMAGE1 + 1: case BPMEM_TX_SETIMAGE1 + 2: case BPMEM_TX_SETIMAGE1 + 3: - case BPMEM_TX_SETIMAGE1_4: // 0xAC - case BPMEM_TX_SETIMAGE1_4 + 1: - case BPMEM_TX_SETIMAGE1_4 + 2: - case BPMEM_TX_SETIMAGE1_4 + 3: - { - SetRegName(BPMEM_TX_SETIMAGE1); - int texnum = - (cmd < BPMEM_TX_SETIMAGE1_4) ? cmd - BPMEM_TX_SETIMAGE1 : cmd - BPMEM_TX_SETIMAGE1_4 + 4; - TexImage1 teximg; - teximg.hex = cmddata; - *desc = fmt::format("Texture Unit: {}\n" - "Even TMEM Offset: {:x}\n" - "Even TMEM Width: {}\n" - "Even TMEM Height: {}\n" - "Cache is manually managed: {}\n", - texnum, u32(teximg.tmem_even), u32(teximg.cache_width), - u32(teximg.cache_height), no_yes[teximg.cache_manually_managed]); - } - break; + return std::make_pair( + fmt::format("BPMEM_TX_SETIMAGE1 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE1), + fmt::to_string(TexImage1{.hex = cmddata})); case BPMEM_TX_SETIMAGE2: // 0x90 case BPMEM_TX_SETIMAGE2 + 1: case BPMEM_TX_SETIMAGE2 + 2: case BPMEM_TX_SETIMAGE2 + 3: - case BPMEM_TX_SETIMAGE2_4: // 0xB0 - case BPMEM_TX_SETIMAGE2_4 + 1: - case BPMEM_TX_SETIMAGE2_4 + 2: - case BPMEM_TX_SETIMAGE2_4 + 3: - { - SetRegName(BPMEM_TX_SETIMAGE2); - int texnum = - (cmd < BPMEM_TX_SETIMAGE2_4) ? cmd - BPMEM_TX_SETIMAGE2 : cmd - BPMEM_TX_SETIMAGE2_4 + 4; - TexImage2 teximg; - teximg.hex = cmddata; - *desc = fmt::format("Texture Unit: {}\n" - "Odd TMEM Offset: {:x}\n" - "Odd TMEM Width: {}\n" - "Odd TMEM Height: {}\n", - texnum, u32(teximg.tmem_odd), u32(teximg.cache_width), - u32(teximg.cache_height)); - } - break; + return std::make_pair( + fmt::format("BPMEM_TX_SETIMAGE2 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE2), + fmt::to_string(TexImage2{.hex = cmddata})); case BPMEM_TX_SETIMAGE3: // 0x94 case BPMEM_TX_SETIMAGE3 + 1: case BPMEM_TX_SETIMAGE3 + 2: case BPMEM_TX_SETIMAGE3 + 3: - case BPMEM_TX_SETIMAGE3_4: // 0xB4 - case BPMEM_TX_SETIMAGE3_4 + 1: - case BPMEM_TX_SETIMAGE3_4 + 2: - case BPMEM_TX_SETIMAGE3_4 + 3: - { - SetRegName(BPMEM_TX_SETIMAGE3); - int texnum = - (cmd < BPMEM_TX_SETIMAGE3_4) ? cmd - BPMEM_TX_SETIMAGE3 : cmd - BPMEM_TX_SETIMAGE3_4 + 4; - TexImage3 teximg; - teximg.hex = cmddata; - *desc = fmt::format("Texture {} source address (32 byte aligned): 0x{:06X}", texnum, - teximg.image_base << 5); - } - break; + return std::make_pair( + fmt::format("BPMEM_TX_SETIMAGE3 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE3), + fmt::to_string(TexImage3{.hex = cmddata})); case BPMEM_TX_SETTLUT: // 0x98 case BPMEM_TX_SETTLUT + 1: case BPMEM_TX_SETTLUT + 2: case BPMEM_TX_SETTLUT + 3: + return std::make_pair(fmt::format("BPMEM_TX_SETTLUT Texture Unit {}", cmd - BPMEM_TX_SETTLUT), + fmt::to_string(TexTLUT{.hex = cmddata})); + + case BPMEM_TX_SETMODE0_4: // 0xA0 + case BPMEM_TX_SETMODE0_4 + 1: + case BPMEM_TX_SETMODE0_4 + 2: + case BPMEM_TX_SETMODE0_4 + 3: + return std::make_pair( + fmt::format("BPMEM_TX_SETMODE0_4 Texture Unit {}", cmd - BPMEM_TX_SETMODE0_4 + 4), + fmt::to_string(TexMode0{.hex = cmddata})); + + case BPMEM_TX_SETMODE1_4: // 0xA4 + case BPMEM_TX_SETMODE1_4 + 1: + case BPMEM_TX_SETMODE1_4 + 2: + case BPMEM_TX_SETMODE1_4 + 3: + return std::make_pair( + fmt::format("BPMEM_TX_SETMODE1_4 Texture Unit {}", cmd - BPMEM_TX_SETMODE1_4 + 4), + fmt::to_string(TexMode1{.hex = cmddata})); + + case BPMEM_TX_SETIMAGE0_4: // 0xA8 + case BPMEM_TX_SETIMAGE0_4 + 1: + case BPMEM_TX_SETIMAGE0_4 + 2: + case BPMEM_TX_SETIMAGE0_4 + 3: + return std::make_pair( + fmt::format("BPMEM_TX_SETIMAGE0_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE0_4 + 4), + fmt::to_string(TexImage0{.hex = cmddata})); + + case BPMEM_TX_SETIMAGE1_4: // 0xAC + case BPMEM_TX_SETIMAGE1_4 + 1: + case BPMEM_TX_SETIMAGE1_4 + 2: + case BPMEM_TX_SETIMAGE1_4 + 3: + return std::make_pair( + fmt::format("BPMEM_TX_SETIMAGE1_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE1_4 + 4), + fmt::to_string(TexImage1{.hex = cmddata})); + + case BPMEM_TX_SETIMAGE2_4: // 0xB0 + case BPMEM_TX_SETIMAGE2_4 + 1: + case BPMEM_TX_SETIMAGE2_4 + 2: + case BPMEM_TX_SETIMAGE2_4 + 3: + return std::make_pair( + fmt::format("BPMEM_TX_SETIMAGE2_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE2_4 + 4), + fmt::to_string(TexImage2{.hex = cmddata})); + + case BPMEM_TX_SETIMAGE3_4: // 0xB4 + case BPMEM_TX_SETIMAGE3_4 + 1: + case BPMEM_TX_SETIMAGE3_4 + 2: + case BPMEM_TX_SETIMAGE3_4 + 3: + return std::make_pair( + fmt::format("BPMEM_TX_SETIMAGE3_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE3_4 + 4), + fmt::to_string(TexImage3{.hex = cmddata})); + case BPMEM_TX_SETTLUT_4: // 0xB8 case BPMEM_TX_SETTLUT_4 + 1: case BPMEM_TX_SETTLUT_4 + 2: case BPMEM_TX_SETTLUT_4 + 3: - SetRegName(BPMEM_TX_SETTLUT); - // TODO: Description - break; + return std::make_pair( + fmt::format("BPMEM_TX_SETTLUT_4 Texture Unit {}", cmd - BPMEM_TX_SETTLUT_4 + 4), + fmt::to_string(TexTLUT{.hex = cmddata})); case BPMEM_TEV_COLOR_ENV: // 0xC0 case BPMEM_TEV_COLOR_ENV + 2: case BPMEM_TEV_COLOR_ENV + 4: + case BPMEM_TEV_COLOR_ENV + 6: case BPMEM_TEV_COLOR_ENV + 8: case BPMEM_TEV_COLOR_ENV + 10: case BPMEM_TEV_COLOR_ENV + 12: @@ -1258,24 +1176,9 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) case BPMEM_TEV_COLOR_ENV + 26: case BPMEM_TEV_COLOR_ENV + 28: case BPMEM_TEV_COLOR_ENV + 30: - { - SetRegName(BPMEM_TEV_COLOR_ENV); - TevStageCombiner::ColorCombiner cc; - cc.hex = cmddata; - *desc = fmt::format("Tev stage: {}\n" - "a: {}\n" - "b: {}\n" - "c: {}\n" - "d: {}\n" - "Bias: {}\n" - "Op: {}\n" - "Clamp: {}\n" - "Scale factor: {}\n" - "Dest: {}\n", - (data[0] - BPMEM_TEV_COLOR_ENV) / 2, cc.a, cc.b, cc.c, cc.d, cc.bias, cc.op, - no_yes[cc.clamp], cc.scale, cc.dest); - break; - } + return std::make_pair( + fmt::format("BPMEM_TEV_COLOR_ENV Tev stage {}", (cmd - BPMEM_TEV_COLOR_ENV) / 2), + fmt::to_string(TevStageCombiner::ColorCombiner{.hex = cmddata})); case BPMEM_TEV_ALPHA_ENV: // 0xC1 case BPMEM_TEV_ALPHA_ENV + 2: @@ -1293,99 +1196,65 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) case BPMEM_TEV_ALPHA_ENV + 26: case BPMEM_TEV_ALPHA_ENV + 28: case BPMEM_TEV_ALPHA_ENV + 30: - { - SetRegName(BPMEM_TEV_ALPHA_ENV); - TevStageCombiner::AlphaCombiner ac; - ac.hex = cmddata; - *desc = fmt::format("Tev stage: {}\n" - "a: {}\n" - "b: {}\n" - "c: {}\n" - "d: {}\n" - "Bias: {}\n" - "Op: {}\n" - "Clamp: {}\n" - "Scale factor: {}\n" - "Dest: {}\n" - "Ras sel: {}\n" - "Tex sel: {}\n", - (data[0] - BPMEM_TEV_ALPHA_ENV) / 2, ac.a, ac.b, ac.c, ac.d, ac.bias, ac.op, - no_yes[ac.clamp], ac.scale, ac.dest, ac.rswap.Value(), ac.tswap.Value()); - break; - } + return std::make_pair( + fmt::format("BPMEM_TEV_ALPHA_ENV Tev stage {}", (cmd - BPMEM_TEV_ALPHA_ENV) / 2), + fmt::to_string(TevStageCombiner::AlphaCombiner{.hex = cmddata})); case BPMEM_TEV_COLOR_RA: // 0xE0 case BPMEM_TEV_COLOR_RA + 2: // 0xE2 case BPMEM_TEV_COLOR_RA + 4: // 0xE4 case BPMEM_TEV_COLOR_RA + 6: // 0xE6 - SetRegName(BPMEM_TEV_COLOR_RA); - // TODO: Description - break; + return std::make_pair( + fmt::format("BPMEM_TEV_COLOR_RA Tev register {}", (cmd - BPMEM_TEV_COLOR_RA) / 2), + fmt::to_string(TevReg::RA{.hex = cmddata})); case BPMEM_TEV_COLOR_BG: // 0xE1 case BPMEM_TEV_COLOR_BG + 2: // 0xE3 case BPMEM_TEV_COLOR_BG + 4: // 0xE5 case BPMEM_TEV_COLOR_BG + 6: // 0xE7 - SetRegName(BPMEM_TEV_COLOR_BG); - // TODO: Description - break; + return std::make_pair( + fmt::format("BPMEM_TEV_COLOR_BG Tev register {}", (cmd - BPMEM_TEV_COLOR_BG) / 2), + fmt::to_string(TevReg::BG{.hex = cmddata})); case BPMEM_FOGRANGE: // 0xE8 + return std::make_pair("BPMEM_FOGRANGE Base", + fmt::to_string(FogRangeParams::RangeBase{.hex = cmddata})); + case BPMEM_FOGRANGE + 1: case BPMEM_FOGRANGE + 2: case BPMEM_FOGRANGE + 3: case BPMEM_FOGRANGE + 4: case BPMEM_FOGRANGE + 5: - SetRegName(BPMEM_FOGRANGE); - // TODO: Description - break; + return std::make_pair(fmt::format("BPMEM_FOGRANGE K element {}", cmd - BPMEM_FOGRANGE), + fmt::to_string(FogRangeKElement{.HEX = cmddata})); case BPMEM_FOGPARAM0: // 0xEE - SetRegName(BPMEM_FOGPARAM0); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_FOGPARAM0), fmt::to_string(FogParam0{.hex = cmddata})); case BPMEM_FOGBMAGNITUDE: // 0xEF - SetRegName(BPMEM_FOGBMAGNITUDE); + return DescriptionlessReg(BPMEM_FOGBMAGNITUDE); // TODO: Description - break; case BPMEM_FOGBEXPONENT: // 0xF0 - SetRegName(BPMEM_FOGBEXPONENT); + return DescriptionlessReg(BPMEM_FOGBEXPONENT); // TODO: Description - break; case BPMEM_FOGPARAM3: // 0xF1 - SetRegName(BPMEM_FOGPARAM3); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_FOGPARAM3), fmt::to_string(FogParam3{.hex = cmddata})); case BPMEM_FOGCOLOR: // 0xF2 - SetRegName(BPMEM_FOGCOLOR); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_FOGCOLOR), + fmt::to_string(FogParams::FogColor{.hex = cmddata})); case BPMEM_ALPHACOMPARE: // 0xF3 - { - SetRegName(BPMEM_ALPHACOMPARE); - AlphaTest test; - test.hex = cmddata; - *desc = fmt::format("Test 1: {} (ref: 0x{:02x})\n" - "Test 2: {} (ref: 0x{:02x})\n" - "Logic: {}\n", - test.comp0, test.ref0.Value(), test.comp1, test.ref1.Value(), test.logic); - break; - } + return std::make_pair(RegName(BPMEM_ALPHACOMPARE), fmt::to_string(AlphaTest{.hex = cmddata})); case BPMEM_BIAS: // 0xF4 - SetRegName(BPMEM_BIAS); + return DescriptionlessReg(BPMEM_BIAS); // TODO: Description - break; case BPMEM_ZTEX2: // 0xF5 - SetRegName(BPMEM_ZTEX2); - // TODO: Description - break; + return std::make_pair(RegName(BPMEM_ZTEX2), fmt::to_string(ZTex2{.hex = cmddata})); case BPMEM_TEV_KSEL: // 0xF6 case BPMEM_TEV_KSEL + 1: @@ -1395,11 +1264,20 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) case BPMEM_TEV_KSEL + 5: case BPMEM_TEV_KSEL + 6: case BPMEM_TEV_KSEL + 7: - SetRegName(BPMEM_TEV_KSEL); - // TODO: Description - break; + return std::make_pair(fmt::format("BPMEM_TEV_KSEL number {}", cmd - BPMEM_TEV_KSEL), + fmt::to_string(TevKSel{.hex = cmddata})); -#undef SetRegName + case BPMEM_BP_MASK: // 0xFE + return std::make_pair(RegName(BPMEM_BP_MASK), + fmt::format("The next BP command will only update these bits; others " + "will retain their prior values: {:06x}", + cmddata)); + + default: + return std::make_pair(fmt::format("Unknown BP Reg: {:02x}={:06x}", cmd, cmddata), ""); + +#undef DescriptionlessReg +#undef RegName } }