mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-03-10 11:48:14 -07:00
Merge pull request #9497 from Pokechu22/better-fifo-analyzer
Graphics refactoring + add names and descriptions in FIFO analyzer
This commit is contained in:
@@ -32,6 +32,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <fmt/format.h>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -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 <std::size_t position, std::size_t bits, typename T>
|
||||
template <std::size_t position, std::size_t bits, typename T,
|
||||
// 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<T>::type directly.
|
||||
typename StorageType = typename std::conditional_t<
|
||||
std::is_enum<T>::value, std::underlying_type<T>, std::enable_if<true, T>>::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<T>::type directly.
|
||||
using StorageType = typename std::conditional_t<std::is_enum<T>::value, std::underlying_type<T>,
|
||||
std::enable_if<true, T>>::type;
|
||||
|
||||
// Unsigned version of StorageType
|
||||
using StorageTypeU = std::make_unsigned_t<StorageType>;
|
||||
|
||||
constexpr T Value(std::true_type) const
|
||||
{
|
||||
using shift_amount = std::integral_constant<size_t, 8 * sizeof(T) - bits>;
|
||||
return static_cast<T>((storage << (shift_amount() - position)) >> shift_amount());
|
||||
const size_t shift_amount = 8 * sizeof(StorageType) - bits;
|
||||
return static_cast<T>((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<StorageTypeU>::max() >> (8 * sizeof(T) - bits)) << position;
|
||||
return (std::numeric_limits<StorageTypeU>::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 <std::size_t position, std::size_t bits, typename T, typename S>
|
||||
struct fmt::formatter<BitField<position, bits, T, S>>
|
||||
{
|
||||
fmt::formatter<T> m_formatter;
|
||||
constexpr auto parse(format_parse_context& ctx) { return m_formatter.parse(ctx); }
|
||||
template <typename FormatContext>
|
||||
auto format(const BitField<position, bits, T, S>& bitfield, FormatContext& ctx)
|
||||
{
|
||||
return m_formatter.format(bitfield.Value(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
// Language limitations require the following to make these formattable
|
||||
// (formatter<BitFieldArray<position, bits, size, T>::Ref> is not legal)
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayConstRef;
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayRef;
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayConstIterator;
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayIterator;
|
||||
|
||||
#pragma pack(1)
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T,
|
||||
// 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<T>::type directly.
|
||||
typename StorageType = typename std::conditional_t<
|
||||
std::is_enum<T>::value, std::underlying_type<T>, std::enable_if<true, T>>::type>
|
||||
struct BitFieldArray
|
||||
{
|
||||
using Ref = BitFieldArrayRef<position, bits, size, T, StorageType>;
|
||||
using ConstRef = BitFieldArrayConstRef<position, bits, size, T, StorageType>;
|
||||
using Iterator = BitFieldArrayIterator<position, bits, size, T, StorageType>;
|
||||
using ConstIterator = BitFieldArrayConstIterator<position, bits, size, T, StorageType>;
|
||||
|
||||
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<T>(), index); }
|
||||
void SetValue(size_t index, T value)
|
||||
{
|
||||
const size_t pos = position + bits * index;
|
||||
storage = (storage & ~GetElementMask(index)) |
|
||||
((static_cast<StorageType>(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<StorageType>;
|
||||
|
||||
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<T>((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<T>((storage & GetElementMask(index)) >> pos);
|
||||
}
|
||||
|
||||
static constexpr StorageType GetElementMask(size_t index)
|
||||
{
|
||||
const size_t pos = position + bits * index;
|
||||
return (std::numeric_limits<StorageTypeU>::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 <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayConstRef
|
||||
{
|
||||
friend struct BitFieldArray<position, bits, size, T, S>;
|
||||
friend class BitFieldArrayConstIterator<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
constexpr T Value() const { return m_array->Value(m_index); };
|
||||
constexpr operator T() const { return Value(); }
|
||||
|
||||
private:
|
||||
constexpr BitFieldArrayConstRef(const BitFieldArray<position, bits, size, T, S>* array,
|
||||
size_t index)
|
||||
: m_array(array), m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
const BitFieldArray<position, bits, size, T, S>* const m_array;
|
||||
const size_t m_index;
|
||||
};
|
||||
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayRef
|
||||
{
|
||||
friend struct BitFieldArray<position, bits, size, T, S>;
|
||||
friend class BitFieldArrayIterator<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
constexpr T Value() const { return m_array->Value(m_index); };
|
||||
constexpr operator T() const { return Value(); }
|
||||
T operator=(const BitFieldArrayRef<position, bits, size, T, S>& 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<position, bits, size, T, S>* array, size_t index)
|
||||
: m_array(array), m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
BitFieldArray<position, bits, size, T, S>* 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 <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayIterator
|
||||
{
|
||||
friend struct BitFieldArray<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = BitFieldArrayRef<position, bits, size, T, S>;
|
||||
|
||||
private:
|
||||
constexpr BitFieldArrayIterator(BitFieldArray<position, bits, size, T, S>* 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<position, bits, size, T, S>* 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 <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayConstIterator
|
||||
{
|
||||
friend struct BitFieldArray<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = BitFieldArrayConstRef<position, bits, size, T, S>;
|
||||
|
||||
private:
|
||||
constexpr BitFieldArrayConstIterator(const BitFieldArray<position, bits, size, T, S>* 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<position, bits, size, T, S>* m_array;
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
struct fmt::formatter<BitFieldArrayRef<position, bits, size, T, S>>
|
||||
{
|
||||
fmt::formatter<T> m_formatter;
|
||||
constexpr auto parse(format_parse_context& ctx) { return m_formatter.parse(ctx); }
|
||||
template <typename FormatContext>
|
||||
auto format(const BitFieldArrayRef<position, bits, size, T, S>& ref, FormatContext& ctx)
|
||||
{
|
||||
return m_formatter.format(ref.Value(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
struct fmt::formatter<BitFieldArrayConstRef<position, bits, size, T, S>>
|
||||
{
|
||||
fmt::formatter<T> m_formatter;
|
||||
constexpr auto parse(format_parse_context& ctx) { return m_formatter.parse(ctx); }
|
||||
template <typename FormatContext>
|
||||
auto format(const BitFieldArrayConstRef<position, bits, size, T, S>& ref, FormatContext& ctx)
|
||||
{
|
||||
return m_formatter.format(ref.Value(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,6 +42,7 @@ add_library(common
|
||||
DynamicLibrary.h
|
||||
ENetUtil.cpp
|
||||
ENetUtil.h
|
||||
EnumFormatter.h
|
||||
Event.h
|
||||
FileSearch.cpp
|
||||
FileSearch.h
|
||||
|
||||
91
Source/Core/Common/EnumFormatter.h
Normal file
91
Source/Core/Common/EnumFormatter.h
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright 2021 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <fmt/format.h>
|
||||
#include <type_traits>
|
||||
|
||||
/*
|
||||
* Helper for using enums with fmt.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* enum class Foo
|
||||
* {
|
||||
* A = 0,
|
||||
* B = 1,
|
||||
* C = 2,
|
||||
* };
|
||||
*
|
||||
* template <>
|
||||
* struct fmt::formatter<Foo> : EnumFormatter<Foo::C>
|
||||
* {
|
||||
* formatter() : EnumFormatter({"A", "B", "C"}) {}
|
||||
* };
|
||||
*
|
||||
* enum class Bar
|
||||
* {
|
||||
* D = 0,
|
||||
* E = 1,
|
||||
* F = 3,
|
||||
* };
|
||||
*
|
||||
* template <>
|
||||
* struct fmt::formatter<Bar> : EnumFormatter<Bar::F>
|
||||
* {
|
||||
* // 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 <auto last_member, typename T = decltype(last_member),
|
||||
size_t size = static_cast<size_t>(last_member) + 1,
|
||||
std::enable_if_t<std::is_enum_v<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 <typename FormatContext>
|
||||
auto format(const T& e, FormatContext& ctx)
|
||||
{
|
||||
const auto value = static_cast<std::underlying_type_t<T>>(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<std::make_unsigned_t<T>>(value));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// This is needed because std::array deduces incorrectly if nullptr is included in the list
|
||||
using array_type = std::array<const char*, size>;
|
||||
|
||||
constexpr explicit EnumFormatter(const array_type names) : m_names(std::move(names)) {}
|
||||
|
||||
private:
|
||||
const array_type m_names;
|
||||
bool formatting_for_shader = false;
|
||||
};
|
||||
@@ -49,21 +49,17 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
|
||||
const VAT& vtxAttr = cpMem.vtxAttr[vatIndex];
|
||||
|
||||
// Colors
|
||||
const std::array<u64, 2> colDesc{
|
||||
vtxDesc.Color0,
|
||||
vtxDesc.Color1,
|
||||
};
|
||||
const std::array<u32, 2> colComp{
|
||||
const std::array<ColorFormat, 2> colComp{
|
||||
vtxAttr.g0.Color0Comp,
|
||||
vtxAttr.g0.Color1Comp,
|
||||
};
|
||||
|
||||
const std::array<u32, 8> tcElements{
|
||||
const std::array<TexComponentCount, 8> tcElements{
|
||||
vtxAttr.g0.Tex0CoordElements, vtxAttr.g1.Tex1CoordElements, vtxAttr.g1.Tex2CoordElements,
|
||||
vtxAttr.g1.Tex3CoordElements, vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements,
|
||||
vtxAttr.g2.Tex6CoordElements, vtxAttr.g2.Tex7CoordElements,
|
||||
};
|
||||
const std::array<u32, 8> tcFormat{
|
||||
const std::array<ComponentFormat, 8> tcFormat{
|
||||
vtxAttr.g0.Tex0CoordFormat, vtxAttr.g1.Tex1CoordFormat, vtxAttr.g1.Tex2CoordFormat,
|
||||
vtxAttr.g1.Tex3CoordFormat, vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat,
|
||||
vtxAttr.g2.Tex6CoordFormat, vtxAttr.g2.Tex7CoordFormat,
|
||||
@@ -72,21 +68,20 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
|
||||
std::array<int, 21> sizes{};
|
||||
|
||||
// Add position and texture matrix indices
|
||||
u64 vtxDescHex = cpMem.vtxDesc.Hex;
|
||||
for (int i = 0; i < 9; ++i)
|
||||
sizes[0] = vtxDesc.low.PosMatIdx;
|
||||
for (size_t i = 0; i < vtxDesc.low.TexMatIdx.Size(); ++i)
|
||||
{
|
||||
sizes[i] = vtxDescHex & 1;
|
||||
vtxDescHex >>= 1;
|
||||
sizes[i + 1] = vtxDesc.low.TexMatIdx[i];
|
||||
}
|
||||
|
||||
// Position
|
||||
sizes[9] = VertexLoader_Position::GetSize(vtxDesc.Position, vtxAttr.g0.PosFormat,
|
||||
sizes[9] = VertexLoader_Position::GetSize(vtxDesc.low.Position, vtxAttr.g0.PosFormat,
|
||||
vtxAttr.g0.PosElements);
|
||||
|
||||
// Normals
|
||||
if (vtxDesc.Normal != NOT_PRESENT)
|
||||
if (vtxDesc.low.Normal != VertexComponentFormat::NotPresent)
|
||||
{
|
||||
sizes[10] = VertexLoader_Normal::GetSize(vtxDesc.Normal, vtxAttr.g0.NormalFormat,
|
||||
sizes[10] = VertexLoader_Normal::GetSize(vtxDesc.low.Normal, vtxAttr.g0.NormalFormat,
|
||||
vtxAttr.g0.NormalElements, vtxAttr.g0.NormalIndex3);
|
||||
}
|
||||
else
|
||||
@@ -95,33 +90,33 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
|
||||
}
|
||||
|
||||
// Colors
|
||||
for (size_t i = 0; i < colDesc.size(); i++)
|
||||
for (size_t i = 0; i < vtxDesc.low.Color.Size(); i++)
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
switch (colDesc[i])
|
||||
switch (vtxDesc.low.Color[i])
|
||||
{
|
||||
case NOT_PRESENT:
|
||||
case VertexComponentFormat::NotPresent:
|
||||
break;
|
||||
case DIRECT:
|
||||
case VertexComponentFormat::Direct:
|
||||
switch (colComp[i])
|
||||
{
|
||||
case FORMAT_16B_565:
|
||||
case ColorFormat::RGB565:
|
||||
size = 2;
|
||||
break;
|
||||
case FORMAT_24B_888:
|
||||
case ColorFormat::RGB888:
|
||||
size = 3;
|
||||
break;
|
||||
case FORMAT_32B_888x:
|
||||
case ColorFormat::RGB888x:
|
||||
size = 4;
|
||||
break;
|
||||
case FORMAT_16B_4444:
|
||||
case ColorFormat::RGBA4444:
|
||||
size = 2;
|
||||
break;
|
||||
case FORMAT_24B_6666:
|
||||
case ColorFormat::RGBA6666:
|
||||
size = 3;
|
||||
break;
|
||||
case FORMAT_32B_8888:
|
||||
case ColorFormat::RGBA8888:
|
||||
size = 4;
|
||||
break;
|
||||
default:
|
||||
@@ -129,10 +124,10 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case INDEX8:
|
||||
case VertexComponentFormat::Index8:
|
||||
size = 1;
|
||||
break;
|
||||
case INDEX16:
|
||||
case VertexComponentFormat::Index16:
|
||||
size = 2;
|
||||
break;
|
||||
}
|
||||
@@ -141,11 +136,10 @@ std::array<int, 21> CalculateVertexElementSizes(int vatIndex, const CPMemory& cp
|
||||
}
|
||||
|
||||
// Texture coordinates
|
||||
vtxDescHex = vtxDesc.Hex >> 17;
|
||||
for (size_t i = 0; i < tcFormat.size(); i++)
|
||||
{
|
||||
sizes[13 + i] = VertexLoader_TextCoord::GetSize(vtxDescHex & 3, tcFormat[i], tcElements[i]);
|
||||
vtxDescHex >>= 2;
|
||||
sizes[13 + i] =
|
||||
VertexLoader_TextCoord::GetSize(vtxDesc.high.TexCoord[i], tcFormat[i], tcElements[i]);
|
||||
}
|
||||
|
||||
return sizes;
|
||||
@@ -267,13 +261,11 @@ void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem)
|
||||
switch (subCmd & 0xF0)
|
||||
{
|
||||
case 0x50:
|
||||
cpMem.vtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits
|
||||
cpMem.vtxDesc.Hex |= value;
|
||||
cpMem.vtxDesc.low.Hex = value;
|
||||
break;
|
||||
|
||||
case 0x60:
|
||||
cpMem.vtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits
|
||||
cpMem.vtxDesc.Hex |= (u64)value << 17;
|
||||
cpMem.vtxDesc.high.Hex = value;
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Core/FifoPlayer/FifoAnalyzer.h"
|
||||
#include "Core/FifoPlayer/FifoRecorder.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
@@ -44,14 +45,28 @@ void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, const u8* vertexData,
|
||||
int numVertices)
|
||||
{
|
||||
// Skip if not indexed array
|
||||
int arrayType = (s_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3;
|
||||
if (arrayType < 2)
|
||||
VertexComponentFormat arrayType;
|
||||
if (arrayIndex == ARRAY_POSITION)
|
||||
arrayType = s_CpMem.vtxDesc.low.Position;
|
||||
else if (arrayIndex == ARRAY_NORMAL)
|
||||
arrayType = s_CpMem.vtxDesc.low.Normal;
|
||||
else if (arrayIndex == ARRAY_COLOR || arrayIndex == ARRAY_COLOR2)
|
||||
arrayType = s_CpMem.vtxDesc.low.Color[arrayIndex - ARRAY_COLOR];
|
||||
else if (arrayIndex >= ARRAY_POSITION && arrayIndex < ARRAY_POSITION + 8)
|
||||
arrayType = s_CpMem.vtxDesc.high.TexCoord[arrayIndex - ARRAY_POSITION];
|
||||
else
|
||||
{
|
||||
PanicAlertFmt("Invalid arrayIndex {}", arrayIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsIndexed(arrayType))
|
||||
return;
|
||||
|
||||
int maxIndex = 0;
|
||||
|
||||
// Determine min and max indices
|
||||
if (arrayType == INDEX8)
|
||||
if (arrayType == VertexComponentFormat::Index8)
|
||||
{
|
||||
for (int i = 0; i < numVertices; ++i)
|
||||
{
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
<ClInclude Include="Common\DebugInterface.h" />
|
||||
<ClInclude Include="Common\DynamicLibrary.h" />
|
||||
<ClInclude Include="Common\ENetUtil.h" />
|
||||
<ClInclude Include="Common\EnumFormatter.h" />
|
||||
<ClInclude Include="Common\Event.h" />
|
||||
<ClInclude Include="Common\FileSearch.h" />
|
||||
<ClInclude Include="Common\FileUtil.h" />
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// 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 <X11/X.h>
|
||||
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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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<ID3D11BlendState1> 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<ID3D11RasterizerState> 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
|
||||
{
|
||||
|
||||
@@ -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())];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(bpmem.zmode.func));
|
||||
ERROR_LOG_FMT(VIDEO, "Bad Z compare mode {}", bpmem.zmode.func);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<s32>(tm1.max_lod))
|
||||
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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]);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <cmath>
|
||||
|
||||
#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<TextureFormat>(ti0.format);
|
||||
const TLUTFormat tlutfmt = static_cast<TLUTFormat>(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,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user