diff --git a/Source/Core/Common/BitField.h b/Source/Core/Common/BitField.h index 00c5345533..e7af066d2f 100644 --- a/Source/Core/Common/BitField.h +++ b/Source/Core/Common/BitField.h @@ -32,6 +32,8 @@ #pragma once #include +#include +#include #include #include @@ -99,6 +101,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 @@ -110,7 +114,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 +159,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,16 +175,333 @@ 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"); }; #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); + } +}; + +// 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/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/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/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/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/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/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 diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 8e806bef6f..4b9020ab8f 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -23,7 +23,9 @@ #include "DolphinQt/Settings.h" #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; @@ -224,17 +226,22 @@ 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; 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; @@ -249,6 +256,8 @@ void FIFOAnalyzer::UpdateDetails() if (((objectdata - stream_start) % 4) == 0) new_label += QLatin1Char(' '); } + + new_label += QStringLiteral(" ") + QString::fromStdString(name); } break; @@ -278,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; @@ -467,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()) @@ -484,11 +499,34 @@ 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) { + 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/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/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/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/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/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 cb510e9e6a..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; @@ -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 ad107382e4..035fa5531e 100644 --- a/Source/Core/VideoCommon/BPMemory.h +++ b/Source/Core/VideoCommon/BPMemory.h @@ -6,12 +6,21 @@ #include #include +#include #include "Common/BitField.h" +#include "Common/BitUtils.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) @@ -45,7 +54,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, @@ -104,140 +113,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 +325,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 +364,7 @@ struct IND_MTX union IND_IMASK { - struct - { - u32 mask : 24; - u32 rid : 8; - }; + BitField<0, 24, u32> mask; u32 hex; }; @@ -306,17 +373,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 +393,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; }; @@ -342,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) @@ -354,17 +469,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 { @@ -372,151 +490,364 @@ 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 != ITBA_OFF || mid != 0; } + 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 +{ + 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(); } +}; +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 { - 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; }; +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 { - 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; } 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 +{ + 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; }; +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 { - struct - { - u32 min_lod : 8; - u32 max_lod : 8; - }; + 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 { - 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; }; +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 { - 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; }; +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 { - 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; }; +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 { - 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; }; +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 { - struct - { - u32 tmem_offset : 10; - u32 tlut_format : 2; - }; + 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 { @@ -526,10 +857,20 @@ 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; }; +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 { @@ -544,115 +885,236 @@ 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; }; +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 +{ + 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; }; +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 { - 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; 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 { @@ -661,6 +1123,54 @@ union FogParam0 BitField<19, 1, u32> sign; 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 +{ + 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 @@ -668,18 +1178,30 @@ 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; +}; +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 { 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; } @@ -691,13 +1213,34 @@ 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; 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 { @@ -723,251 +1266,575 @@ 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 +{ + 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; }; +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 { BitField<0, 8, u32> alpha; - BitField<8, 1, u32> enable; + 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 { - 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; }; +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 +{ + 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; }; +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 +{ + 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; }; +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 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; }; +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; 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, +}; +template <> +struct fmt::formatter : EnumFormatter +{ + formatter() : EnumFormatter({"Color", "Constant"}) {} +}; +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; +}; +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); + } +}; - 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(); } +}; +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 +{ + 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; } }; +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 +{ + 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 { 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 { @@ -999,12 +1866,19 @@ union CopyFilterCoefficients union BPU_PreloadTileInfo { + BitField<0, 15, u32> count; + BitField<15, 2, u32> type; u32 hex; - struct +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const BPU_PreloadTileInfo& info, FormatContext& ctx) { - u32 count : 15; - u32 type : 2; - }; + return format_to(ctx.out(), "Type: {}\nCount: {}", info.type, info.count); + } }; struct BPS_TmemConfig @@ -1105,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 2376fd0840..2ad90a350a 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; // ---------------------------------- @@ -432,7 +424,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; // -------------- @@ -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; } @@ -753,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: @@ -825,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: @@ -877,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: @@ -889,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: @@ -901,375 +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; - 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]); - } - 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; - 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]); - } - 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_BR: // 0x4A + case BPMEM_EFB_WH: // 0x4A { - // TODO: Misleading name, should be BPMEM_EFB_WH instead - SetRegName(BPMEM_EFB_BR); - 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: 0x{:01X}\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], - static_cast(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: {:x}\n", - texnum, u32(teximg.width) + 1, u32(teximg.height) + 1, u32(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.image_type]); - } - 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: @@ -1282,33 +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; - 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" - "c: {}\n" - "d: {}\n" - "Bias: {}\n" - "Op: {}\n" - "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]); - 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: @@ -1326,111 +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; - 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" - "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, 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()); - 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; - 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]); - 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: @@ -1440,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 } } diff --git a/Source/Core/VideoCommon/CPMemory.cpp b/Source/Core/VideoCommon/CPMemory.cpp index 52384cddaf..eb59869368 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) @@ -31,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 aeab4977b2..3b22992f15 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -4,8 +4,47 @@ #pragma once +#include +#include +#include + +#include "Common/BitField.h" #include "Common/BitSet.h" #include "Common/CommonTypes.h" +#include "Common/EnumFormatter.h" +#include "Common/MsgHandler.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 @@ -18,176 +57,407 @@ 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; + } +}; +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 { u32 Hex; - struct + // 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; +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const UVAT_group0& g0, FormatContext& ctx) { - // 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; - }; + 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 { u32 Hex; - struct + // 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; +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const UVAT_group1& g1, FormatContext& ctx) { - // 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; - }; + 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 { u32 Hex; - struct + // 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; +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const UVAT_group2& g2, FormatContext& ctx) { - // 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; - }; + 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 { - 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; @@ -197,38 +467,44 @@ struct TVtxAttr // Matrix indices union TMatrixIndexA { - struct + 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; +}; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TMatrixIndexA& m, FormatContext& ctx) { - u32 PosNormalMtxIdx : 6; - u32 Tex0MtxIdx : 6; - u32 Tex1MtxIdx : 6; - u32 Tex2MtxIdx : 6; - u32 Tex3MtxIdx : 6; - }; - struct - { - u32 Hex : 30; - u32 unused : 2; - }; + return format_to(ctx.out(), "PosNormal: {}\nTex0: {}\nTex1: {}\nTex2: {}\nTex3: {}", + m.PosNormalMtxIdx, m.Tex0MtxIdx, m.Tex1MtxIdx, m.Tex2MtxIdx, m.Tex3MtxIdx); + } }; 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; +}; +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); + } }; - -#pragma pack() struct VAT { @@ -242,18 +518,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; }; @@ -271,3 +547,5 @@ void FillCPMemoryArray(u32* memory); void DoCPState(PointerWrap& p); void CopyPreprocessCPStateFromMain(); + +std::pair GetCPRegInfo(u8 cmd, u32 value); 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/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..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); @@ -212,7 +213,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; } } @@ -252,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; @@ -276,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); @@ -290,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; @@ -319,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; @@ -516,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, @@ -825,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"); @@ -839,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); @@ -883,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) @@ -897,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"); } @@ -962,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{ "", @@ -979,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 { @@ -997,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 @@ -1013,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, @@ -1121,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 @@ -1164,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] = { @@ -1178,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) @@ -1208,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]); } @@ -1284,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]); } @@ -1314,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", @@ -1340,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 @@ -1356,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, @@ -1383,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{ @@ -1408,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); @@ -1424,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"); @@ -1472,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) @@ -1514,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"); @@ -1610,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 fbba9fc12f..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.type != 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/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/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/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/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 bcbf64d3d4..fdb63679f5 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" @@ -75,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; @@ -276,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); @@ -302,79 +319,84 @@ 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: - state->vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits - state->vtx_desc.Hex |= value; - state->attr_dirty = BitSet32::AllTrue(8); + case VCD_LO: + state->vtx_desc.low.Hex = value; + state->attr_dirty = BitSet32::AllTrue(CP_NUM_VAT_REG); state->bases_dirty = true; break; - case 0x60: - state->vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits - state->vtx_desc.Hex |= (u64)value << 17; - state->attr_dirty = BitSet32::AllTrue(8); + case VCD_HI: + state->vtx_desc.high.Hex = value; + 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] = g_main_cp_state.vtx_desc.low.Hex; + memory[VCD_HI] = g_main_cp_state.vtx_desc.high.Hex; - 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]; } } 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/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 9c82d9b431..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)); @@ -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/Core/VideoCommon/XFMemory.h b/Source/Core/VideoCommon/XFMemory.h index 1c860c704d..7efd3d2209 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 @@ -99,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, @@ -133,16 +227,17 @@ enum XFMEM_SETNUMTEXGENS = 0x103f, XFMEM_SETTEXMTXINFO = 0x1040, XFMEM_SETPOSTMTXINFO = 0x1050, + XFMEM_REGISTERS_END = 0x1058, }; 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; @@ -151,64 +246,126 @@ 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 +{ + 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; +}; +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 { - 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; }; +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 { - 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; }; +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 { - 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; }; +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 { - 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 +407,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 +424,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..741680b826 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" @@ -28,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; @@ -93,7 +96,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; @@ -205,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 { @@ -300,3 +303,340 @@ 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::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); + 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; + } + + 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, "; "); + } + + // 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..5aac1f059b 100644 --- a/Source/Core/VideoCommon/XFStructs.h +++ b/Source/Core/VideoCommon/XFStructs.h @@ -4,4 +4,12 @@ #pragma once +#include +#include + #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); diff --git a/Source/UnitTests/Common/BitFieldTest.cpp b/Source/UnitTests/Common/BitFieldTest.cpp index 32b587469f..e7a7bb764c 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 { @@ -21,6 +30,11 @@ 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; + + BitField<16, 2, TestEnum> enum_1; + BitField<48, 2, TestEnum> enum_2; }; // table of raw numbers to test with @@ -51,6 +65,9 @@ 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)); + 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. @@ -82,6 +99,9 @@ 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); + 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); @@ -91,6 +111,9 @@ 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)); + EXPECT_EQ(static_cast((object.hex >> 16) & 3), object.enum_1); + EXPECT_EQ(static_cast((object.hex >> 48) & 3), object.enum_2); } } @@ -122,6 +145,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 +192,354 @@ 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); + } +} + +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())); + } +} + +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++]); } } 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 @@ + 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);