2015-05-24 04:55:12 +00:00
|
|
|
// Copyright 2009 Dolphin Emulator Project
|
2021-07-05 01:22:19 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2014-02-10 18:54:46 +00:00
|
|
|
#pragma once
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2016-05-17 20:21:02 +00:00
|
|
|
#include <array>
|
2014-05-25 01:55:13 +00:00
|
|
|
#include <string>
|
2021-02-07 23:25:11 +00:00
|
|
|
#include <utility>
|
2014-05-25 01:55:13 +00:00
|
|
|
|
2014-03-10 15:15:40 +00:00
|
|
|
#include "Common/BitField.h"
|
2021-02-07 23:25:11 +00:00
|
|
|
#include "Common/BitUtils.h"
|
2014-09-08 01:06:58 +00:00
|
|
|
#include "Common/CommonTypes.h"
|
2021-02-11 02:11:31 +00:00
|
|
|
#include "Common/EnumFormatter.h"
|
2020-05-03 17:42:12 +00:00
|
|
|
#include "Common/Inline.h"
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
// 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;
|
2017-07-30 19:45:55 +00:00
|
|
|
enum class EFBCopyFormat;
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class TLUTFormat;
|
2017-07-30 19:45:55 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
#pragma pack(4)
|
|
|
|
|
2015-09-01 14:56:51 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
BPMEM_GENMODE = 0x00,
|
|
|
|
BPMEM_DISPLAYCOPYFILTER = 0x01, // 0x01 + 4
|
|
|
|
BPMEM_IND_MTXA = 0x06, // 0x06 + (3 * 3)
|
|
|
|
BPMEM_IND_MTXB = 0x07, // 0x07 + (3 * 3)
|
|
|
|
BPMEM_IND_MTXC = 0x08, // 0x08 + (3 * 3)
|
|
|
|
BPMEM_IND_IMASK = 0x0F,
|
|
|
|
BPMEM_IND_CMD = 0x10, // 0x10 + 16
|
|
|
|
BPMEM_SCISSORTL = 0x20,
|
|
|
|
BPMEM_SCISSORBR = 0x21,
|
|
|
|
BPMEM_LINEPTWIDTH = 0x22,
|
|
|
|
BPMEM_PERF0_TRI = 0x23,
|
|
|
|
BPMEM_PERF0_QUAD = 0x24,
|
|
|
|
BPMEM_RAS1_SS0 = 0x25,
|
|
|
|
BPMEM_RAS1_SS1 = 0x26,
|
|
|
|
BPMEM_IREF = 0x27,
|
|
|
|
BPMEM_TREF = 0x28, // 0x28 + 8
|
|
|
|
BPMEM_SU_SSIZE = 0x30, // 0x30 + (2 * 8)
|
|
|
|
BPMEM_SU_TSIZE = 0x31, // 0x31 + (2 * 8)
|
|
|
|
BPMEM_ZMODE = 0x40,
|
|
|
|
BPMEM_BLENDMODE = 0x41,
|
|
|
|
BPMEM_CONSTANTALPHA = 0x42,
|
|
|
|
BPMEM_ZCOMPARE = 0x43,
|
|
|
|
BPMEM_FIELDMASK = 0x44,
|
|
|
|
BPMEM_SETDRAWDONE = 0x45,
|
|
|
|
BPMEM_BUSCLOCK0 = 0x46,
|
|
|
|
BPMEM_PE_TOKEN_ID = 0x47,
|
|
|
|
BPMEM_PE_TOKEN_INT_ID = 0x48,
|
|
|
|
BPMEM_EFB_TL = 0x49,
|
2021-02-07 20:32:45 +00:00
|
|
|
BPMEM_EFB_WH = 0x4A,
|
2015-09-01 14:56:51 +00:00
|
|
|
BPMEM_EFB_ADDR = 0x4B,
|
|
|
|
BPMEM_MIPMAP_STRIDE = 0x4D,
|
|
|
|
BPMEM_COPYYSCALE = 0x4E,
|
|
|
|
BPMEM_CLEAR_AR = 0x4F,
|
|
|
|
BPMEM_CLEAR_GB = 0x50,
|
|
|
|
BPMEM_CLEAR_Z = 0x51,
|
|
|
|
BPMEM_TRIGGER_EFB_COPY = 0x52,
|
|
|
|
BPMEM_COPYFILTER0 = 0x53,
|
|
|
|
BPMEM_COPYFILTER1 = 0x54,
|
|
|
|
BPMEM_CLEARBBOX1 = 0x55,
|
|
|
|
BPMEM_CLEARBBOX2 = 0x56,
|
|
|
|
BPMEM_CLEAR_PIXEL_PERF = 0x57,
|
|
|
|
BPMEM_REVBITS = 0x58,
|
|
|
|
BPMEM_SCISSOROFFSET = 0x59,
|
|
|
|
BPMEM_PRELOAD_ADDR = 0x60,
|
|
|
|
BPMEM_PRELOAD_TMEMEVEN = 0x61,
|
|
|
|
BPMEM_PRELOAD_TMEMODD = 0x62,
|
|
|
|
BPMEM_PRELOAD_MODE = 0x63,
|
|
|
|
BPMEM_LOADTLUT0 = 0x64,
|
|
|
|
BPMEM_LOADTLUT1 = 0x65,
|
|
|
|
BPMEM_TEXINVALIDATE = 0x66,
|
|
|
|
BPMEM_PERF1 = 0x67,
|
|
|
|
BPMEM_FIELDMODE = 0x68,
|
|
|
|
BPMEM_BUSCLOCK1 = 0x69,
|
|
|
|
BPMEM_TX_SETMODE0 = 0x80, // 0x80 + 4
|
|
|
|
BPMEM_TX_SETMODE1 = 0x84, // 0x84 + 4
|
|
|
|
BPMEM_TX_SETIMAGE0 = 0x88, // 0x88 + 4
|
|
|
|
BPMEM_TX_SETIMAGE1 = 0x8C, // 0x8C + 4
|
|
|
|
BPMEM_TX_SETIMAGE2 = 0x90, // 0x90 + 4
|
|
|
|
BPMEM_TX_SETIMAGE3 = 0x94, // 0x94 + 4
|
|
|
|
BPMEM_TX_SETTLUT = 0x98, // 0x98 + 4
|
|
|
|
BPMEM_TX_SETMODE0_4 = 0xA0, // 0xA0 + 4
|
|
|
|
BPMEM_TX_SETMODE1_4 = 0xA4, // 0xA4 + 4
|
|
|
|
BPMEM_TX_SETIMAGE0_4 = 0xA8, // 0xA8 + 4
|
|
|
|
BPMEM_TX_SETIMAGE1_4 = 0xAC, // 0xA4 + 4
|
|
|
|
BPMEM_TX_SETIMAGE2_4 = 0xB0, // 0xB0 + 4
|
|
|
|
BPMEM_TX_SETIMAGE3_4 = 0xB4, // 0xB4 + 4
|
|
|
|
BPMEM_TX_SETTLUT_4 = 0xB8, // 0xB8 + 4
|
|
|
|
BPMEM_TEV_COLOR_ENV = 0xC0, // 0xC0 + (2 * 16)
|
|
|
|
BPMEM_TEV_ALPHA_ENV = 0xC1, // 0xC1 + (2 * 16)
|
|
|
|
BPMEM_TEV_COLOR_RA = 0xE0, // 0xE0 + (2 * 4)
|
|
|
|
BPMEM_TEV_COLOR_BG = 0xE1, // 0xE1 + (2 * 4)
|
|
|
|
BPMEM_FOGRANGE = 0xE8, // 0xE8 + 6
|
|
|
|
BPMEM_FOGPARAM0 = 0xEE,
|
|
|
|
BPMEM_FOGBMAGNITUDE = 0xEF,
|
|
|
|
BPMEM_FOGBEXPONENT = 0xF0,
|
|
|
|
BPMEM_FOGPARAM3 = 0xF1,
|
|
|
|
BPMEM_FOGCOLOR = 0xF2,
|
|
|
|
BPMEM_ALPHACOMPARE = 0xF3,
|
|
|
|
BPMEM_BIAS = 0xF4,
|
|
|
|
BPMEM_ZTEX2 = 0xF5,
|
|
|
|
BPMEM_TEV_KSEL = 0xF6, // 0xF6 + 8
|
|
|
|
BPMEM_BP_MASK = 0xFE,
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
|
|
|
// Tev/combiner things
|
2009-09-02 21:00:45 +00:00
|
|
|
|
2015-09-01 14:56:51 +00:00
|
|
|
// TEV scaling type
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class TevScale : u32
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
Scale1 = 0,
|
|
|
|
Scale2 = 1,
|
|
|
|
Scale4 = 2,
|
|
|
|
Divide2 = 3
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
2021-02-11 02:11:31 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevScale> : EnumFormatter<TevScale::Divide2>
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
formatter() : EnumFormatter({"1", "2", "4", "0.5"}) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TEV combiner operator
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class TevOp : u32
|
|
|
|
{
|
|
|
|
Add = 0,
|
|
|
|
Sub = 1,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevOp> : EnumFormatter<TevOp::Sub>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Add", "Subtract"}) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class TevCompareMode : u32
|
|
|
|
{
|
|
|
|
R8 = 0,
|
|
|
|
GR16 = 1,
|
|
|
|
BGR24 = 2,
|
|
|
|
RGB8 = 3,
|
|
|
|
A8 = RGB8,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevCompareMode> : EnumFormatter<TevCompareMode::RGB8>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"R8", "GR16", "BGR24", "RGB8 / A8"}) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class TevComparison : u32
|
|
|
|
{
|
|
|
|
GT = 0,
|
|
|
|
EQ = 1,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevComparison> : EnumFormatter<TevComparison::EQ>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Greater than", "Equal to"}) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TEV color combiner input
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class TevColorArg : u32
|
|
|
|
{
|
|
|
|
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<TevColorArg> : EnumFormatter<TevColorArg::Zero>
|
|
|
|
{
|
|
|
|
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) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TEV alpha combiner input
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class TevAlphaArg : u32
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
PrevAlpha = 0,
|
|
|
|
Alpha0 = 1,
|
|
|
|
Alpha1 = 2,
|
|
|
|
Alpha2 = 3,
|
|
|
|
TexAlpha = 4,
|
|
|
|
RasAlpha = 5,
|
|
|
|
Konst = 6,
|
|
|
|
Zero = 7
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevAlphaArg> : EnumFormatter<TevAlphaArg::Zero>
|
|
|
|
{
|
|
|
|
static constexpr array_type names = {
|
|
|
|
"prev", "c0", "c1", "c2", "tex", "ras", "konst", "ZERO",
|
|
|
|
};
|
|
|
|
formatter() : EnumFormatter(names) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TEV output registers
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class TevOutput : u32
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
Prev = 0,
|
|
|
|
Color0 = 1,
|
|
|
|
Color1 = 2,
|
|
|
|
Color2 = 3,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevOutput> : EnumFormatter<TevOutput::Color2>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"prev", "c0", "c1", "c2"}) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Z-texture formats
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class ZTexFormat : u32
|
|
|
|
{
|
|
|
|
U8 = 0,
|
|
|
|
U16 = 1,
|
|
|
|
U24 = 2
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<ZTexFormat> : EnumFormatter<ZTexFormat::U24>
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
formatter() : EnumFormatter({"u8", "u16", "u24"}) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Z texture operator
|
2021-02-11 02:11:31 +00:00
|
|
|
enum ZTexOp : u32
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
Disabled = 0,
|
|
|
|
Add = 1,
|
|
|
|
Replace = 2
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<ZTexOp> : EnumFormatter<ZTexOp::Replace>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Disabled", "Add", "Replace"}) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TEV bias value
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class TevBias : u32
|
|
|
|
{
|
|
|
|
Zero = 0,
|
|
|
|
AddHalf = 1,
|
|
|
|
Subhalf = 2,
|
|
|
|
Compare = 3
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevBias> : EnumFormatter<TevBias::Compare>
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
formatter() : EnumFormatter({"0", "+0.5", "-0.5", "compare"}) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Indirect texture format
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class IndTexFormat : u32
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
|
|
|
ITF_8 = 0,
|
|
|
|
ITF_5 = 1,
|
|
|
|
ITF_4 = 2,
|
|
|
|
ITF_3 = 3
|
|
|
|
};
|
2021-02-11 02:11:31 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<IndTexFormat> : EnumFormatter<IndTexFormat::ITF_3>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"ITF_8", "ITF_5", "ITF_4", "ITF_3"}) {}
|
|
|
|
};
|
2015-09-01 14:56:51 +00:00
|
|
|
|
|
|
|
// Indirect texture bias
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class IndTexBias : u32
|
|
|
|
{
|
|
|
|
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<IndTexBias> : EnumFormatter<IndTexBias::STU>
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
formatter() : EnumFormatter({"None", "S", "T", "ST", "U", "SU", "TU", "STU"}) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
2021-04-11 00:41:06 +00:00
|
|
|
enum class IndMtxIndex : u32
|
|
|
|
{
|
|
|
|
Off = 0,
|
|
|
|
Matrix0 = 1,
|
|
|
|
Matrix1 = 2,
|
|
|
|
Matrix2 = 3,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<IndMtxIndex> : EnumFormatter<IndMtxIndex::Matrix2>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Off", "Matrix 0", "Matrix 1", "Matrix 2"}) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class IndMtxId : u32
|
|
|
|
{
|
|
|
|
Indirect = 0,
|
|
|
|
S = 1,
|
|
|
|
T = 2,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<IndMtxId> : EnumFormatter<IndMtxId::T>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Indirect", "S", "T"}) {}
|
|
|
|
};
|
|
|
|
|
2015-09-01 14:56:51 +00:00
|
|
|
// Indirect texture bump alpha
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class IndTexBumpAlpha : u32
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
Off = 0,
|
|
|
|
S = 1,
|
|
|
|
T = 2,
|
|
|
|
U = 3
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<IndTexBumpAlpha> : EnumFormatter<IndTexBumpAlpha::U>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Off", "S", "T", "U"}) {}
|
2015-09-01 14:56:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Indirect texture wrap value
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class IndTexWrap : u32
|
2015-09-01 14:56:51 +00:00
|
|
|
{
|
|
|
|
ITW_OFF = 0,
|
|
|
|
ITW_256 = 1,
|
|
|
|
ITW_128 = 2,
|
|
|
|
ITW_64 = 3,
|
|
|
|
ITW_32 = 4,
|
|
|
|
ITW_16 = 5,
|
|
|
|
ITW_0 = 6
|
|
|
|
};
|
2021-02-11 02:11:31 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<IndTexWrap> : EnumFormatter<IndTexWrap::ITW_0>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Off", "256", "128", "64", "32", "16", "0"}) {}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union IND_MTXA
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 11, s32> ma;
|
|
|
|
BitField<11, 11, s32> mb;
|
2021-04-11 00:41:06 +00:00
|
|
|
BitField<22, 2, u8, u32> s0; // bits 0-1 of scale factor
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union IND_MTXB
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 11, s32> mc;
|
|
|
|
BitField<11, 11, s32> md;
|
2021-04-11 00:41:06 +00:00
|
|
|
BitField<22, 2, u8, u32> s1; // bits 2-3 of scale factor
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union IND_MTXC
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 11, s32> me;
|
|
|
|
BitField<11, 11, s32> mf;
|
2021-04-11 00:41:06 +00:00
|
|
|
BitField<22, 2, u8, u32> s2; // bits 4-5 of scale factor
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct IND_MTX
|
|
|
|
{
|
|
|
|
IND_MTXA col0;
|
|
|
|
IND_MTXB col1;
|
|
|
|
IND_MTXC col2;
|
2021-04-11 00:41:06 +00:00
|
|
|
u8 GetScale() const { return (col0.s0 << 0) | (col1.s1 << 2) | (col2.s2 << 4); }
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union IND_IMASK
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 24, u32> mask;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TevStageCombiner
|
|
|
|
{
|
2017-01-04 11:45:40 +00:00
|
|
|
union ColorCombiner
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
// abc=8bit,d=10bit
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 4, TevColorArg> d;
|
|
|
|
BitField<4, 4, TevColorArg> c;
|
|
|
|
BitField<8, 4, TevColorArg> b;
|
|
|
|
BitField<12, 4, TevColorArg> a;
|
2015-10-11 00:37:41 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2015-10-11 00:37:41 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2015-10-11 00:37:41 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2017-01-04 11:45:40 +00:00
|
|
|
union AlphaCombiner
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<0, 2, u32> rswap;
|
|
|
|
BitField<2, 2, u32> tswap;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<4, 3, TevAlphaArg> d;
|
|
|
|
BitField<7, 3, TevAlphaArg> c;
|
|
|
|
BitField<10, 3, TevAlphaArg> b;
|
|
|
|
BitField<13, 3, TevAlphaArg> a;
|
2015-10-11 00:37:41 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2015-10-11 00:37:41 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2015-10-11 00:37:41 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
ColorCombiner colorC;
|
|
|
|
AlphaCombiner alphaC;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevStageCombiner::ColorCombiner>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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<TevStageCombiner::AlphaCombiner>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
|
|
|
// several discoveries:
|
|
|
|
// GXSetTevIndBumpST(tevstage, indstage, matrixind)
|
2014-03-10 11:30:55 +00:00
|
|
|
// if ( matrix == 2 ) realmat = 6; // 10
|
|
|
|
// else if ( matrix == 3 ) realmat = 7; // 11
|
|
|
|
// else if ( matrix == 1 ) realmat = 5; // 9
|
2009-06-22 09:31:30 +00:00
|
|
|
// GXSetTevIndirect(tevstage, indstage, 0, 3, realmat, 6, 6, 0, 0, 0)
|
|
|
|
// GXSetTevIndirect(tevstage+1, indstage, 0, 3, realmat+4, 6, 6, 1, 0, 0)
|
|
|
|
// GXSetTevIndirect(tevstage+2, indstage, 0, 0, 0, 0, 0, 1, 0, 0)
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TevStageIndirect
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2021-04-11 00:41:06 +00:00
|
|
|
BitField<7, 2, IndTexBumpAlpha> bs; // Indicates which coordinate will become the 'bump alpha'
|
|
|
|
// Indicates which indirect matrix is used when matrix_id is Indirect.
|
|
|
|
// Also always indicates which indirect matrix to use for the scale factor, even with S or T.
|
|
|
|
BitField<9, 2, IndMtxIndex> matrix_index;
|
|
|
|
// Should be set to Indirect (0) if matrix_index is Off (0)
|
|
|
|
BitField<11, 2, IndMtxId> matrix_id;
|
2021-02-11 02:11:31 +00:00
|
|
|
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
|
2015-10-11 00:37:41 +00:00
|
|
|
|
2015-10-10 20:43:31 +00:00
|
|
|
struct
|
|
|
|
{
|
2010-09-27 04:29:51 +00:00
|
|
|
u32 hex : 21;
|
|
|
|
u32 unused : 11;
|
2016-06-24 08:43:46 +00:00
|
|
|
};
|
|
|
|
|
2021-02-07 23:25:11 +00:00
|
|
|
u32 fullhex;
|
|
|
|
|
2021-04-11 00:41:06 +00:00
|
|
|
// If bs and matrix are zero, the result of the stage is independent of
|
2010-09-27 04:29:51 +00:00
|
|
|
// the texture sample data, so we can skip sampling the texture.
|
2021-04-11 00:41:06 +00:00
|
|
|
bool IsActive() const { return bs != IndTexBumpAlpha::Off || matrix_index != IndMtxIndex::Off; }
|
2021-02-11 02:11:31 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevStageIndirect>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const TevStageIndirect& tevind, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(),
|
|
|
|
"Indirect tex stage ID: {}\n"
|
|
|
|
"Format: {}\n"
|
|
|
|
"Bias: {}\n"
|
|
|
|
"Bump alpha: {}\n"
|
2021-04-11 00:41:06 +00:00
|
|
|
"Offset matrix index: {}\n"
|
2021-02-07 23:25:11 +00:00
|
|
|
"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: {}",
|
2021-04-11 00:41:06 +00:00
|
|
|
tevind.bt, tevind.fmt, tevind.bias, tevind.bs, tevind.matrix_index,
|
|
|
|
tevind.matrix_id, tevind.sw, tevind.tw, tevind.lb_utclod ? "Yes" : "No",
|
|
|
|
tevind.fb_addprev ? "Yes" : "No");
|
2021-02-07 23:25:11 +00:00
|
|
|
}
|
|
|
|
};
|
2021-02-11 02:11:31 +00:00
|
|
|
|
|
|
|
enum class RasColorChan : u32
|
|
|
|
{
|
|
|
|
Color0 = 0,
|
|
|
|
Color1 = 1,
|
|
|
|
AlphaBump = 5,
|
|
|
|
NormalizedAlphaBump = 6,
|
|
|
|
Zero = 7,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<RasColorChan> : EnumFormatter<RasColorChan::Zero>
|
|
|
|
{
|
|
|
|
static constexpr array_type names = {
|
|
|
|
"Color chan 0", "Color chan 1", nullptr, nullptr,
|
|
|
|
nullptr, "Alpha bump", "Norm alpha bump", "Zero",
|
|
|
|
};
|
|
|
|
formatter() : EnumFormatter(names) {}
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TwoTevStageOrders
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<0, 3, u32> texmap0; // Indirect tex stage texmap
|
|
|
|
BitField<3, 3, u32> texcoord0;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<6, 1, bool, u32> enable0; // true if should read from texture
|
|
|
|
BitField<7, 3, RasColorChan> colorchan0;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<12, 3, u32> texmap1;
|
|
|
|
BitField<15, 3, u32> texcoord1;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<18, 1, bool, u32> enable1; // true if should read from texture
|
|
|
|
BitField<19, 3, RasColorChan> colorchan1;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
|
|
|
u32 hex;
|
2015-10-11 00:37:41 +00:00
|
|
|
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(); }
|
2021-02-11 02:11:31 +00:00
|
|
|
RasColorChan getColorChan(int i) const { return i ? colorchan1.Value() : colorchan0.Value(); }
|
2016-06-24 08:43:46 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TwoTevStageOrders>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TEXSCALE
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
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
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TEXSCALE>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union RAS1_IREF
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 3, u32> bi0; // Indirect tex stage 0 ntexmap
|
2021-04-10 22:17:42 +00:00
|
|
|
BitField<3, 3, u32> bc0; // Indirect tex stage 0 ntexcoord
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<6, 3, u32> bi1;
|
|
|
|
BitField<9, 3, u32> bc1;
|
|
|
|
BitField<12, 3, u32> bi2;
|
2021-04-10 22:17:42 +00:00
|
|
|
BitField<15, 3, u32> bc2;
|
|
|
|
BitField<18, 3, u32> bi3;
|
|
|
|
BitField<21, 3, u32> bc3;
|
2016-06-24 08:43:46 +00:00
|
|
|
u32 hex;
|
|
|
|
|
2017-01-23 20:49:34 +00:00
|
|
|
u32 getTexCoord(int i) const { return (hex >> (6 * i + 3)) & 7; }
|
|
|
|
u32 getTexMap(int i) const { return (hex >> (6 * i)) & 7; }
|
2016-06-24 08:43:46 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<RAS1_IREF>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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: {}",
|
2021-04-10 22:17:42 +00:00
|
|
|
indref.bi0, indref.bc0, indref.bi1, indref.bc1, indref.bi2, indref.bc2,
|
|
|
|
indref.bi3, indref.bc3);
|
2021-02-07 23:25:11 +00:00
|
|
|
}
|
|
|
|
};
|
2009-09-02 21:00:45 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
// Texture structs
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class WrapMode : u32
|
|
|
|
{
|
|
|
|
Clamp = 0,
|
|
|
|
Repeat = 1,
|
|
|
|
Mirror = 2,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<WrapMode> : EnumFormatter<WrapMode::Mirror>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Clamp", "Repeat", "Mirror"}) {}
|
|
|
|
};
|
2009-09-02 21:00:45 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class MipMode : u32
|
2017-01-04 11:45:40 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
None = 0,
|
|
|
|
Point = 1,
|
|
|
|
Linear = 2,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<MipMode> : EnumFormatter<MipMode::Linear>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"None", "Mip point", "Mip linear"}) {}
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class FilterMode : u32
|
|
|
|
{
|
|
|
|
Near = 0,
|
|
|
|
Linear = 1,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FilterMode> : EnumFormatter<FilterMode::Linear>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Near", "Linear"}) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class LODType : u32
|
|
|
|
{
|
|
|
|
Edge = 0,
|
|
|
|
Diagonal = 1,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<LODType> : EnumFormatter<LODType::Diagonal>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Edge LOD", "Diagonal LOD"}) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class MaxAnsio
|
|
|
|
{
|
|
|
|
One = 0,
|
|
|
|
Two = 1,
|
|
|
|
Four = 2,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<MaxAnsio> : EnumFormatter<MaxAnsio::Four>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"1", "2 (requires edge LOD)", "4 (requires edge LOD)"}) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
union TexMode0
|
|
|
|
{
|
|
|
|
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;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TexMode0>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TexMode1
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 8, u32> min_lod;
|
|
|
|
BitField<8, 8, u32> max_lod;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TexMode1>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TexImage0
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 10, u32> width; // Actually w-1
|
|
|
|
BitField<10, 10, u32> height; // Actually h-1
|
|
|
|
BitField<20, 4, TextureFormat> format;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TexImage0>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TexImage1
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TexImage1>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TexImage2
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 15, u32> tmem_odd; // tmem line index for odd LODs
|
|
|
|
BitField<15, 3, u32> cache_width;
|
|
|
|
BitField<18, 3, u32> cache_height;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TexImage2>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TexImage3
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 24, u32> image_base; // address in memory >> 5 (was 20 for GC)
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TexImage3>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const TexImage3& teximg, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(), "Source address (32 byte aligned): 0x{:06X}",
|
|
|
|
teximg.image_base << 5);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TexTLUT
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 10, u32> tmem_offset;
|
|
|
|
BitField<10, 2, TLUTFormat> tlut_format;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TexTLUT>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const TexTLUT& tlut, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(), "Address: {:08x}\nFormat: {}", tlut.tmem_offset << 9,
|
|
|
|
tlut.tlut_format);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union ZTex1
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<0, 24, u32> bias;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union ZTex2
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 2, ZTexFormat> type;
|
|
|
|
BitField<2, 2, ZTexOp> op;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<ZTex2>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const ZTex2& ztex2, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(), "Type: {}\nOperation: {}", ztex2.type, ztex2.op);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
|
|
|
struct FourTexUnits
|
|
|
|
{
|
|
|
|
TexMode0 texMode0[4];
|
|
|
|
TexMode1 texMode1[4];
|
|
|
|
TexImage0 texImage0[4];
|
|
|
|
TexImage1 texImage1[4];
|
|
|
|
TexImage2 texImage2[4];
|
|
|
|
TexImage3 texImage3[4];
|
|
|
|
TexTLUT texTlut[4];
|
|
|
|
u32 unknown[4];
|
|
|
|
};
|
|
|
|
|
|
|
|
// Geometry/other structs
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class CullMode : u32
|
2017-01-04 11:45:40 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
None = 0,
|
|
|
|
Back = 1, // cull back-facing primitives
|
|
|
|
Front = 2, // cull front-facing primitives
|
|
|
|
All = 3, // cull all primitives
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<CullMode> : EnumFormatter<CullMode::All>
|
|
|
|
{
|
|
|
|
static constexpr array_type names = {
|
|
|
|
"None",
|
|
|
|
"Back-facing primitives only",
|
|
|
|
"Front-facing primitives only",
|
|
|
|
"All primitives",
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
2021-02-11 02:11:31 +00:00
|
|
|
formatter() : EnumFormatter(names) {}
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
union GenMode
|
|
|
|
{
|
2014-04-21 20:34:23 +00:00
|
|
|
BitField<0, 4, u32> numtexgens;
|
2014-04-21 20:38:08 +00:00
|
|
|
BitField<4, 3, u32> numcolchans;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<7, 1, u32> unused; // 1 bit unused?
|
|
|
|
BitField<8, 1, bool, u32> flat_shading; // unconfirmed
|
|
|
|
BitField<9, 1, bool, u32> multisampling;
|
2021-04-13 20:12:38 +00:00
|
|
|
// This value is 1 less than the actual number (0-15 map to 1-16).
|
|
|
|
// In other words there is always at least 1 tev stage
|
2014-04-21 20:34:23 +00:00
|
|
|
BitField<10, 4, u32> numtevstages;
|
|
|
|
BitField<14, 2, CullMode> cullmode;
|
|
|
|
BitField<16, 3, u32> numindstages;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<19, 1, bool, u32> zfreeze;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<GenMode>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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",
|
2021-04-13 20:12:38 +00:00
|
|
|
mode.numtevstages + 1, mode.cullmode, mode.numindstages,
|
2021-02-07 23:25:11 +00:00
|
|
|
mode.zfreeze ? "Yes" : "No");
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class AspectRatioAdjustment
|
|
|
|
{
|
|
|
|
DontAdjust = 0,
|
|
|
|
Adjust = 1,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<AspectRatioAdjustment> : EnumFormatter<AspectRatioAdjustment::Adjust>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Don't adjust", "Adjust"}) {}
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union LPSize
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<LPSize>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union X12Y12
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 12, u32> y;
|
|
|
|
BitField<12, 12, u32> x;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2017-01-04 11:45:40 +00:00
|
|
|
union X10Y10
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 10, u32> x;
|
|
|
|
BitField<10, 10, u32> y;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-04-19 12:20:37 +00:00
|
|
|
union S32X10Y10
|
|
|
|
{
|
|
|
|
BitField<0, 10, s32> x;
|
|
|
|
BitField<10, 10, s32> y;
|
|
|
|
u32 hex;
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
|
|
|
// Framebuffer/pixel stuff (incl fog)
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class SrcBlendFactor : u32
|
|
|
|
{
|
|
|
|
Zero = 0,
|
|
|
|
One = 1,
|
|
|
|
DstClr = 2,
|
|
|
|
InvDstClr = 3,
|
|
|
|
SrcAlpha = 4,
|
|
|
|
InvSrcAlpha = 5,
|
|
|
|
DstAlpha = 6,
|
|
|
|
InvDstAlpha = 7
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<SrcBlendFactor> : EnumFormatter<SrcBlendFactor::InvDstAlpha>
|
|
|
|
{
|
|
|
|
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) {}
|
|
|
|
};
|
2009-09-02 21:00:45 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class DstBlendFactor : u32
|
2017-01-04 11:45:40 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
Zero = 0,
|
|
|
|
One = 1,
|
|
|
|
SrcClr = 2,
|
|
|
|
InvSrcClr = 3,
|
|
|
|
SrcAlpha = 4,
|
|
|
|
InvSrcAlpha = 5,
|
|
|
|
DstAlpha = 6,
|
|
|
|
InvDstAlpha = 7
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<DstBlendFactor> : EnumFormatter<DstBlendFactor::InvDstAlpha>
|
|
|
|
{
|
|
|
|
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) {}
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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<LogicOp> : EnumFormatter<LogicOp::Set>
|
|
|
|
{
|
|
|
|
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)",
|
2014-03-24 19:21:34 +00:00
|
|
|
};
|
2021-02-11 02:11:31 +00:00
|
|
|
formatter() : EnumFormatter(names) {}
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
union BlendMode
|
|
|
|
{
|
|
|
|
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;
|
2014-03-24 19:21:34 +00:00
|
|
|
BitField<12, 4, LogicOp> logicmode;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
2017-09-03 06:32:37 +00:00
|
|
|
|
|
|
|
bool UseLogicOp() const;
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<BlendMode>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const BlendMode& mode, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
static constexpr std::array<const char*, 2> 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);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union FogParam0
|
|
|
|
{
|
2018-02-01 07:36:30 +00:00
|
|
|
BitField<0, 11, u32> mant;
|
|
|
|
BitField<11, 8, u32> exp;
|
|
|
|
BitField<19, 1, u32> sign;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
2021-02-12 06:38:07 +00:00
|
|
|
float FloatValue() const;
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FogParam0>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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 ? '-' : '+');
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class FogProjection : u32
|
|
|
|
{
|
|
|
|
Perspective = 0,
|
|
|
|
Orthographic = 1,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FogProjection> : EnumFormatter<FogProjection::Orthographic>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Perspective", "Orthographic"}) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class FogType : u32
|
|
|
|
{
|
|
|
|
Off = 0,
|
|
|
|
Linear = 2,
|
|
|
|
Exp = 4,
|
|
|
|
ExpSq = 5,
|
|
|
|
BackwardsExp = 6,
|
|
|
|
BackwardsExpSq = 7,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FogType> : EnumFormatter<FogType::BackwardsExpSq>
|
|
|
|
{
|
|
|
|
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) {}
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union FogParam3
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<0, 11, u32> c_mant;
|
|
|
|
BitField<11, 8, u32> c_exp;
|
|
|
|
BitField<19, 1, u32> c_sign;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<20, 1, FogProjection> proj;
|
|
|
|
BitField<21, 3, FogType> fsel;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
2021-02-12 06:38:07 +00:00
|
|
|
float FloatValue() const;
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FogParam3>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union FogRangeKElement
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<0, 12, u32> HI;
|
|
|
|
BitField<12, 12, u32> LO;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2013-01-19 11:57:55 +00:00
|
|
|
// TODO: Which scaling coefficient should we use here? This is just a guess!
|
2015-10-11 00:37:41 +00:00
|
|
|
float GetValue(int i) const { return (i ? HI.Value() : LO.Value()) / 256.f; }
|
2011-01-29 04:31:56 +00:00
|
|
|
u32 HEX;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct FogRangeParams
|
|
|
|
{
|
2017-01-04 11:45:40 +00:00
|
|
|
union RangeBase
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<0, 10, u32> Center; // viewport center + 342
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<10, 1, bool, u32> Enabled;
|
2011-01-29 04:31:56 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
RangeBase Base;
|
|
|
|
FogRangeKElement K[5];
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FogRangeParams::RangeBase>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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<FogRangeKElement>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const FogRangeKElement& range, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(), "High: {}\nLow: {}", range.HI, range.LO);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
// final eq: ze = A/(B_MAG - (Zs>>B_SHF));
|
|
|
|
struct FogParams
|
|
|
|
{
|
|
|
|
FogParam0 a;
|
|
|
|
u32 b_magnitude;
|
|
|
|
u32 b_shift; // b's exp + 1?
|
|
|
|
FogParam3 c_proj_fsel;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union FogColor
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<0, 8, u32> b;
|
|
|
|
BitField<8, 8, u32> g;
|
|
|
|
BitField<16, 8, u32> r;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
FogColor color; // 0:b 8:g 16:r - nice!
|
2018-02-01 07:36:30 +00:00
|
|
|
|
|
|
|
// Special case where a and c are infinite and the sign matches, resulting in a result of NaN.
|
|
|
|
bool IsNaNCase() const;
|
|
|
|
float GetA() const;
|
|
|
|
|
|
|
|
// amount to subtract from eyespacez after range adjustment
|
|
|
|
float GetC() const;
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FogParams::FogColor>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const FogParams::FogColor& color, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(), "Red: {}\nGreen: {}\nBlue: {}", color.r, color.g, color.b);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class CompareMode : u32
|
2017-01-04 11:45:40 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
Never = 0,
|
|
|
|
Less = 1,
|
|
|
|
Equal = 2,
|
|
|
|
LEqual = 3,
|
|
|
|
Greater = 4,
|
|
|
|
NEqual = 5,
|
|
|
|
GEqual = 6,
|
|
|
|
Always = 7
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<CompareMode> : EnumFormatter<CompareMode::Always>
|
|
|
|
{
|
|
|
|
static constexpr array_type names = {"Never", "Less", "Equal", "LEqual",
|
|
|
|
"Greater", "NEqual", "GEqual", "Always"};
|
|
|
|
formatter() : EnumFormatter(names) {}
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
union ZMode
|
|
|
|
{
|
|
|
|
BitField<0, 1, bool, u32> testenable;
|
2014-03-24 19:21:34 +00:00
|
|
|
BitField<1, 3, CompareMode> func;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<4, 1, bool, u32> updateenable;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<ZMode>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union ConstantAlpha
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<0, 8, u32> alpha;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<8, 1, bool, u32> enable;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<ConstantAlpha>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const ConstantAlpha& c, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(),
|
|
|
|
"Enable: {}\n"
|
|
|
|
"Alpha value: {:02x}",
|
|
|
|
c.enable ? "Yes" : "No", c.alpha);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union FieldMode
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
// adjust vertex tex LOD computation to account for interlacing
|
|
|
|
BitField<0, 1, AspectRatioAdjustment> texLOD;
|
2011-07-18 08:27:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FieldMode>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const FieldMode& mode, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(), "Adjust vertex tex LOD computation to account for interlacing: {}",
|
|
|
|
mode.texLOD);
|
|
|
|
}
|
|
|
|
};
|
2011-07-18 08:27:30 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class FieldMaskState : u32
|
|
|
|
{
|
|
|
|
Skip = 0,
|
|
|
|
Write = 1,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FieldMaskState> : EnumFormatter<FieldMaskState::Write>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Skipped", "Written"}) {}
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union FieldMask
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
// Fields are written to the EFB only if their bit is set to write.
|
|
|
|
BitField<0, 1, FieldMaskState> odd;
|
|
|
|
BitField<1, 1, FieldMaskState> even;
|
2011-07-18 08:27:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FieldMask>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const FieldMask& mask, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(), "Odd field: {}\nEven field: {}", mask.odd, mask.even);
|
|
|
|
}
|
|
|
|
};
|
2011-07-18 08:27:30 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class PixelFormat : u32
|
2017-01-04 11:45:40 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
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<PixelFormat> : EnumFormatter<PixelFormat::YUV420>
|
|
|
|
{
|
|
|
|
static constexpr array_type names = {"RGB8_Z24", "RGBA6_Z24", "RGB565_Z16", "Z24",
|
|
|
|
"Y8", "U8", "V8", "YUV420"};
|
|
|
|
formatter() : EnumFormatter(names) {}
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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<DepthFormat> : EnumFormatter<DepthFormat::ZINV_FAR>
|
|
|
|
{
|
|
|
|
static constexpr array_type names = {
|
|
|
|
"linear", "compressed (near)", "compressed (mid)", "compressed (far)",
|
|
|
|
"inv linear", "compressed (inv near)", "compressed (inv mid)", "compressed (inv far)",
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
2021-02-11 02:11:31 +00:00
|
|
|
formatter() : EnumFormatter(names) {}
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
union PEControl
|
|
|
|
{
|
2014-03-23 20:44:23 +00:00
|
|
|
BitField<0, 3, PixelFormat> pixel_format;
|
|
|
|
BitField<3, 3, DepthFormat> zformat;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<6, 1, bool, u32> early_ztest;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<PEControl>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
|
|
|
// Texture coordinate stuff
|
2009-09-02 21:00:45 +00:00
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TCInfo
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TCInfo>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
struct TCoordInfo
|
|
|
|
{
|
|
|
|
TCInfo s;
|
|
|
|
TCInfo t;
|
|
|
|
};
|
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class TevRegType : u32
|
2017-01-04 11:45:40 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
Color = 0,
|
|
|
|
Constant = 1,
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevRegType> : EnumFormatter<TevRegType::Constant>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"Color", "Constant"}) {}
|
|
|
|
};
|
2014-03-10 15:15:40 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
struct TevReg
|
|
|
|
{
|
2014-09-17 16:46:23 +00:00
|
|
|
// TODO: Check if Konst uses all 11 bits or just 8
|
2021-02-11 02:11:31 +00:00
|
|
|
union RA
|
|
|
|
{
|
|
|
|
u32 hex;
|
2014-09-17 16:46:23 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 11, s32> red;
|
|
|
|
BitField<12, 11, s32> alpha;
|
|
|
|
BitField<23, 1, TevRegType, u32> type;
|
|
|
|
};
|
|
|
|
union BG
|
|
|
|
{
|
|
|
|
u32 hex;
|
2014-03-10 15:15:40 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 11, s32> blue;
|
|
|
|
BitField<12, 11, s32> green;
|
|
|
|
BitField<23, 1, TevRegType, u32> type;
|
|
|
|
};
|
2014-03-10 15:15:40 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
RA ra;
|
|
|
|
BG bg;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevReg::RA>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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<TevReg::BG>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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<TevReg>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const TevReg& reg, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(), "{}\n{}", reg.ra, reg.bg);
|
|
|
|
}
|
|
|
|
};
|
2014-03-10 15:15:40 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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<KonstSel> : EnumFormatter<KonstSel::K3_A>
|
|
|
|
{
|
|
|
|
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) {}
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union TevKSel
|
|
|
|
{
|
2015-10-11 00:37:41 +00:00
|
|
|
BitField<0, 2, u32> swap1;
|
|
|
|
BitField<2, 2, u32> swap2;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<4, 5, KonstSel> kcsel0;
|
|
|
|
BitField<9, 5, KonstSel> kasel0;
|
|
|
|
BitField<14, 5, KonstSel> kcsel1;
|
|
|
|
BitField<19, 5, KonstSel> kasel1;
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
KonstSel getKC(int i) const { return i ? kcsel1.Value() : kcsel0.Value(); }
|
|
|
|
KonstSel getKA(int i) const { return i ? kasel1.Value() : kasel0.Value(); }
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<TevKSel>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class AlphaTestOp : u32
|
2017-01-04 11:45:40 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
And = 0,
|
|
|
|
Or = 1,
|
|
|
|
Xor = 2,
|
|
|
|
Xnor = 3
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<AlphaTestOp> : EnumFormatter<AlphaTestOp::Xnor>
|
|
|
|
{
|
|
|
|
formatter() : EnumFormatter({"And", "Or", "Xor", "Xnor"}) {}
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class AlphaTestResult
|
|
|
|
{
|
|
|
|
Undetermined = 0,
|
|
|
|
Fail = 1,
|
|
|
|
Pass = 2,
|
|
|
|
};
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
union AlphaTest
|
|
|
|
{
|
2014-03-24 19:21:34 +00:00
|
|
|
BitField<0, 8, u32> ref0;
|
|
|
|
BitField<8, 8, u32> ref1;
|
|
|
|
BitField<16, 3, CompareMode> comp0;
|
|
|
|
BitField<19, 3, CompareMode> comp1;
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<22, 2, AlphaTestOp> logic;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 hex;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
DOLPHIN_FORCE_INLINE AlphaTestResult TestResult() const
|
2013-08-12 10:52:28 +00:00
|
|
|
{
|
2014-03-10 11:30:55 +00:00
|
|
|
switch (logic)
|
2013-08-12 10:52:28 +00:00
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
case AlphaTestOp::And:
|
|
|
|
if (comp0 == CompareMode::Always && comp1 == CompareMode::Always)
|
|
|
|
return AlphaTestResult::Pass;
|
|
|
|
if (comp0 == CompareMode::Never || comp1 == CompareMode::Never)
|
|
|
|
return AlphaTestResult::Fail;
|
2013-08-12 10:52:28 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
case AlphaTestOp::Or:
|
|
|
|
if (comp0 == CompareMode::Always || comp1 == CompareMode::Always)
|
|
|
|
return AlphaTestResult::Pass;
|
|
|
|
if (comp0 == CompareMode::Never && comp1 == CompareMode::Never)
|
|
|
|
return AlphaTestResult::Fail;
|
2013-08-12 10:52:28 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2013-08-12 10:52:28 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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;
|
2013-08-12 10:52:28 +00:00
|
|
|
break;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2014-12-03 00:20:52 +00:00
|
|
|
default:
|
2021-02-11 02:11:31 +00:00
|
|
|
return AlphaTestResult::Undetermined;
|
2013-08-12 10:52:28 +00:00
|
|
|
}
|
2021-02-11 02:11:31 +00:00
|
|
|
return AlphaTestResult::Undetermined;
|
2013-08-12 10:52:28 +00:00
|
|
|
}
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<AlphaTest>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
enum class FrameToField : u32
|
|
|
|
{
|
|
|
|
Progressive = 0,
|
|
|
|
InterlacedEven = 2,
|
|
|
|
InterlacedOdd = 3,
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct fmt::formatter<FrameToField> : EnumFormatter<FrameToField::InterlacedOdd>
|
|
|
|
{
|
|
|
|
static constexpr array_type names = {"Progressive", nullptr, "Interlaced (even lines)",
|
|
|
|
"Interlaced (odd lines)"};
|
|
|
|
formatter() : EnumFormatter(names) {}
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union UPE_Copy
|
|
|
|
{
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 Hex;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2021-02-11 02:11:31 +00:00
|
|
|
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
|
2014-03-10 15:15:40 +00:00
|
|
|
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)
|
2021-02-11 02:11:31 +00:00
|
|
|
// 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;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2017-07-30 19:45:55 +00:00
|
|
|
EFBCopyFormat tp_realFormat() const
|
|
|
|
{
|
|
|
|
return static_cast<EFBCopyFormat>(target_pixel_format / 2 + (target_pixel_format & 1) * 8);
|
|
|
|
}
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<UPE_Copy>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const UPE_Copy& copy, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
static constexpr std::array<const char*, 2> 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]);
|
|
|
|
}
|
|
|
|
};
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2016-05-17 20:21:02 +00:00
|
|
|
union CopyFilterCoefficients
|
|
|
|
{
|
2018-04-29 08:52:30 +00:00
|
|
|
using Values = std::array<u8, 7>;
|
|
|
|
|
2016-05-17 20:21:02 +00:00
|
|
|
u64 Hex;
|
|
|
|
|
|
|
|
BitField<0, 6, u64> w0;
|
|
|
|
BitField<6, 6, u64> w1;
|
|
|
|
BitField<12, 6, u64> w2;
|
|
|
|
BitField<18, 6, u64> w3;
|
|
|
|
BitField<32, 6, u64> w4;
|
|
|
|
BitField<38, 6, u64> w5;
|
|
|
|
BitField<44, 6, u64> w6;
|
|
|
|
|
2018-04-29 08:52:30 +00:00
|
|
|
Values GetCoefficients() const
|
2016-05-17 20:21:02 +00:00
|
|
|
{
|
2018-05-28 18:46:24 +00:00
|
|
|
return {{
|
|
|
|
static_cast<u8>(w0),
|
|
|
|
static_cast<u8>(w1),
|
|
|
|
static_cast<u8>(w2),
|
|
|
|
static_cast<u8>(w3),
|
|
|
|
static_cast<u8>(w4),
|
|
|
|
static_cast<u8>(w5),
|
|
|
|
static_cast<u8>(w6),
|
|
|
|
}};
|
2016-05-17 20:21:02 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-04 11:45:40 +00:00
|
|
|
union BPU_PreloadTileInfo
|
|
|
|
{
|
2021-02-11 02:11:31 +00:00
|
|
|
BitField<0, 15, u32> count;
|
|
|
|
BitField<15, 2, u32> type;
|
2012-01-29 20:17:22 +00:00
|
|
|
u32 hex;
|
|
|
|
};
|
2021-02-07 23:25:11 +00:00
|
|
|
template <>
|
|
|
|
struct fmt::formatter<BPU_PreloadTileInfo>
|
|
|
|
{
|
|
|
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const BPU_PreloadTileInfo& info, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
return format_to(ctx.out(), "Type: {}\nCount: {}", info.type, info.count);
|
|
|
|
}
|
|
|
|
};
|
2012-01-29 20:17:22 +00:00
|
|
|
|
|
|
|
struct BPS_TmemConfig
|
|
|
|
{
|
|
|
|
u32 preload_addr;
|
|
|
|
u32 preload_tmem_even;
|
|
|
|
u32 preload_tmem_odd;
|
|
|
|
BPU_PreloadTileInfo preload_tile_info;
|
|
|
|
u32 tlut_src;
|
|
|
|
u32 tlut_dest;
|
|
|
|
u32 texinvalidate;
|
|
|
|
};
|
2009-09-02 21:00:45 +00:00
|
|
|
|
2009-06-22 09:31:30 +00:00
|
|
|
// All of BP memory
|
2009-09-02 21:00:45 +00:00
|
|
|
|
2009-07-26 09:52:35 +00:00
|
|
|
struct BPCmd
|
2009-06-22 09:31:30 +00:00
|
|
|
{
|
|
|
|
int address;
|
|
|
|
int changes;
|
|
|
|
int newvalue;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct BPMemory
|
|
|
|
{
|
|
|
|
GenMode genMode;
|
|
|
|
u32 display_copy_filter[4]; // 01-04
|
|
|
|
u32 unknown; // 05
|
2021-04-11 00:41:06 +00:00
|
|
|
// indirect matrices (set by GXSetIndTexMtx, selected by TevStageIndirect::matrix_index)
|
2009-06-22 09:31:30 +00:00
|
|
|
// abc form a 2x3 offset matrix, there's 3 such matrices
|
|
|
|
// the 3 offset matrices can either be indirect type, S-type, or T-type
|
|
|
|
// 6bit scale factor s is distributed across IND_MTXA/B/C.
|
|
|
|
// before using matrices scale by 2^-(s-17)
|
|
|
|
IND_MTX indmtx[3]; // 06-0e GXSetIndTexMtx, 2x3 matrices
|
|
|
|
IND_IMASK imask; // 0f
|
|
|
|
TevStageIndirect tevind[16]; // 10 GXSetTevIndirect
|
|
|
|
X12Y12 scissorTL; // 20
|
|
|
|
X12Y12 scissorBR; // 21
|
|
|
|
LPSize lineptwidth; // 22 line and point width
|
|
|
|
u32 sucounter; // 23
|
|
|
|
u32 rascounter; // 24
|
|
|
|
TEXSCALE texscale[2]; // 25-26 GXSetIndTexCoordScale
|
|
|
|
RAS1_IREF tevindref; // 27 GXSetIndTexOrder
|
|
|
|
TwoTevStageOrders tevorders[8]; // 28-2F
|
|
|
|
TCoordInfo texcoords[8]; // 0x30 s,t,s,t,s,t,s,t...
|
|
|
|
ZMode zmode; // 40
|
|
|
|
BlendMode blendmode; // 41
|
|
|
|
ConstantAlpha dstalpha; // 42
|
2014-03-23 20:44:23 +00:00
|
|
|
PEControl zcontrol; // 43 GXSetZCompLoc, GXPixModeSync
|
2011-07-18 08:27:30 +00:00
|
|
|
FieldMask fieldmask; // 44
|
2009-06-22 09:31:30 +00:00
|
|
|
u32 drawdone; // 45, bit1=1 if end of list
|
|
|
|
u32 unknown5; // 46 clock?
|
|
|
|
u32 petoken; // 47
|
|
|
|
u32 petokenint; // 48
|
|
|
|
X10Y10 copyTexSrcXY; // 49
|
|
|
|
X10Y10 copyTexSrcWH; // 4a
|
|
|
|
u32 copyTexDest; // 4b// 4b == CopyAddress (GXDispCopy and GXTexCopy use it)
|
|
|
|
u32 unknown6; // 4c
|
|
|
|
u32 copyMipMapStrideChannels; // 4d usually set to 4 when dest is single channel, 8 when dest is
|
|
|
|
// 2 channel, 16 when dest is RGBA
|
|
|
|
// also, doubles whenever mipmap box filter option is set (excent on RGBA). Probably to do with
|
|
|
|
// number of bytes to look at when smoothing
|
2016-05-17 20:21:02 +00:00
|
|
|
u32 dispcopyyscale; // 4e
|
|
|
|
u32 clearcolorAR; // 4f
|
|
|
|
u32 clearcolorGB; // 50
|
|
|
|
u32 clearZValue; // 51
|
|
|
|
UPE_Copy triggerEFBCopy; // 52
|
|
|
|
CopyFilterCoefficients copyfilter; // 53,54
|
|
|
|
u32 boundbox0; // 55
|
|
|
|
u32 boundbox1; // 56
|
|
|
|
u32 unknown7[2]; // 57,58
|
2021-04-19 12:20:37 +00:00
|
|
|
S32X10Y10 scissorOffset; // 59
|
2016-05-17 20:21:02 +00:00
|
|
|
u32 unknown8[6]; // 5a,5b,5c,5d, 5e,5f
|
|
|
|
BPS_TmemConfig tmem_config; // 60-66
|
|
|
|
u32 metric; // 67
|
|
|
|
FieldMode fieldmode; // 68
|
|
|
|
u32 unknown10[7]; // 69-6F
|
|
|
|
u32 unknown11[16]; // 70-7F
|
|
|
|
FourTexUnits tex[2]; // 80-bf
|
|
|
|
TevStageCombiner combiners[16]; // 0xC0-0xDF
|
|
|
|
TevReg tevregs[4]; // 0xE0
|
|
|
|
FogRangeParams fogRange; // 0xE8
|
|
|
|
FogParams fog; // 0xEE,0xEF,0xF0,0xF1,0xF2
|
|
|
|
AlphaTest alpha_test; // 0xF3
|
|
|
|
ZTex1 ztex1; // 0xf4,0xf5
|
2009-06-22 09:31:30 +00:00
|
|
|
ZTex2 ztex2;
|
|
|
|
TevKSel tevksel[8]; // 0xf6,0xf7,f8,f9,fa,fb,fc,fd
|
|
|
|
u32 bpMask; // 0xFE
|
|
|
|
u32 unknown18; // ff
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2013-07-22 12:38:09 +00:00
|
|
|
bool UseEarlyDepthTest() const { return zcontrol.early_ztest && zmode.testenable; }
|
|
|
|
bool UseLateDepthTest() const { return !zcontrol.early_ztest && zmode.testenable; }
|
2009-06-22 09:31:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#pragma pack()
|
|
|
|
|
|
|
|
extern BPMemory bpmem;
|
|
|
|
|
|
|
|
void LoadBPReg(u32 value0);
|
Add the 'desynced GPU thread' mode.
It's a relatively big commit (less big with -w), but it's hard to test
any of this separately...
The basic problem is that in netplay or movies, the state of the CPU
must be deterministic, including when the game receives notification
that the GPU has processed FIFO data. Dual core mode notifies the game
whenever the GPU thread actually gets around to doing the work, so it
isn't deterministic. Single core mode is because it notifies the game
'instantly' (after processing the data synchronously), but it's too slow
for many systems and games.
My old dc-netplay branch worked as follows: everything worked as normal
except the state of the CP registers was a lie, and the CPU thread only
delivered results when idle detection triggered (waiting for the GPU if
they weren't ready at that point). Usually, a game is idle iff all the
work for the frame has been done, except for a small amount of work
depending on the GPU result, so neither the CPU or the GPU waiting on
the other affected performance much. However, it's possible that the
game could be waiting for some earlier interrupt, and any of several
games which, for whatever reason, never went into a detectable idle
(even when I tried to improve the detection) would never receive results
at all. (The current method should have better compatibility, but it
also has slightly higher overhead and breaks some other things, so I
want to reimplement this, hopefully with less impact on the code, in the
future.)
With this commit, the basic idea is that the CPU thread acts as if the
work has been done instantly, like single core mode, but actually hands
it off asynchronously to the GPU thread (after backing up some data that
the game might change in memory before it's actually done). Since the
work isn't done, any feedback from the GPU to the CPU, such as real
XFB/EFB copies (virtual are OK), EFB pokes, performance queries, etc. is
broken; but most games work with these options disabled, and there is no
need to try to detect what the CPU thread is doing.
Technically: when the flag g_use_deterministic_gpu_thread (currently
stuck on) is on, the CPU thread calls RunGpu like in single core mode.
This function synchronously copies the data from the FIFO to the
internal video buffer and updates the CP registers, interrupts, etc.
However, instead of the regular ReadDataFromFifo followed by running the
opcode decoder, it runs ReadDataFromFifoOnCPU ->
OpcodeDecoder_Preprocess, which relatively quickly scans through the
FIFO data, detects SetFinish calls etc., which are immediately fired,
and saves certain associated data from memory (e.g. display lists) in
AuxBuffers (a parallel stream to the main FIFO, which is a bit slow at
the moment), before handing the data off to the GPU thread to actually
render. That makes up the bulk of this commit.
In various circumstances, including the aforementioned EFB pokes and
performance queries as well as swap requests (i.e. the end of a frame -
we don't want the CPU potentially pumping out frames too quickly and the
GPU falling behind*), SyncGPU is called to wait for actual completion.
The overhead mainly comes from OpcodeDecoder_Preprocess (which is,
again, synchronous), as well as the actual copying.
Currently, display lists and such are escrowed from main memory even
though they usually won't change over the course of a frame, and
textures are not even though they might, resulting in a small chance of
graphical glitches. When the texture locking (i.e. fault on write) code
lands, I can make this all correct and maybe a little faster.
* This suggests an alternate determinism method of just delaying results
until a short time before the end of each frame. For all I know this
might mostly work - I haven't tried it - but if any significant work
hinges on the competion of render to texture etc., the frame will be
missed.
2014-08-28 02:56:19 +00:00
|
|
|
void LoadBPRegPreprocess(u32 value0);
|
2009-06-22 09:31:30 +00:00
|
|
|
|
2021-02-07 23:25:11 +00:00
|
|
|
std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata);
|