Large diffs are not rendered by default.

@@ -3,10 +3,90 @@

#pragma once

#include <array>

#include "Common/EnumMap.h"
#include "VideoCommon/BPMemory.h"

class Tev
{
struct TevColor
{
constexpr TevColor() = default;
constexpr explicit TevColor(s16 a, s16 b, s16 g, s16 r) : a(a), b(b), g(g), r(r) {}

s16 a = 0;
s16 b = 0;
s16 g = 0;
s16 r = 0;

constexpr static TevColor All(s16 value) { return TevColor(value, value, value, value); }

constexpr s16& operator[](int index)
{
switch (index)
{
case ALP_C:
return a;
case BLU_C:
return b;
case GRN_C:
return g;
case RED_C:
return r;
default:
// invalid
return a;
}
}
};

struct TevColorRef
{
constexpr explicit TevColorRef(const s16& r, const s16& g, const s16& b) : r(r), g(g), b(b) {}

const s16& r;
const s16& g;
const s16& b;

constexpr static TevColorRef Color(const TevColor& color)
{
return TevColorRef(color.r, color.g, color.b);
}
constexpr static TevColorRef All(const s16& value) { return TevColorRef(value, value, value); }
constexpr static TevColorRef Alpha(const TevColor& color) { return All(color.a); }
};

struct TevAlphaRef
{
constexpr explicit TevAlphaRef(const TevColor& color) : a(color.a) {}
constexpr explicit TevAlphaRef(const s16& a) : a(a) {}

const s16& a;
};

struct TevKonstRef
{
constexpr explicit TevKonstRef(const s16& a, const s16& r, const s16& g, const s16& b)
: a(a), r(r), g(g), b(b)
{
}

const s16& a;
const s16& r;
const s16& g;
const s16& b;

constexpr static TevKonstRef Value(const s16& value)
{
return TevKonstRef(value, value, value, value);
}
constexpr static TevKonstRef Konst(const s16& alpha, const TevColor& color)
{
return TevKonstRef(alpha, color.r, color.g, color.b);
}
};

struct InputRegType
{
unsigned a : 8;
@@ -22,32 +102,96 @@ class Tev
};

// color order: ABGR
s16 Reg[4][4];
s16 KonstantColors[4][4];
s16 TexColor[4];
s16 RasColor[4];
s16 StageKonst[4];
s16 Zero16[4];

s16 FixedConstants[9];
Common::EnumMap<TevColor, TevOutput::Color2> Reg;
std::array<TevColor, 4> KonstantColors;
TevColor TexColor;
TevColor RasColor;
TevColor StageKonst;

// Fixed constants, corresponding to KonstSel
static constexpr s16 V0 = 0;
static constexpr s16 V1_8 = 32;
static constexpr s16 V1_4 = 64;
static constexpr s16 V3_8 = 96;
static constexpr s16 V1_2 = 128;
static constexpr s16 V5_8 = 159;
static constexpr s16 V3_4 = 191;
static constexpr s16 V7_8 = 223;
static constexpr s16 V1 = 255;

u8 AlphaBump;
u8 IndirectTex[4][4];
TextureCoordinateType TexCoord;

s16* m_ColorInputLUT[16][3];
s16* m_AlphaInputLUT[8]; // values must point to ABGR color
s16* m_KonstLUT[32][4];
s16 m_BiasLUT[4];
u8 m_ScaleLShiftLUT[4];
u8 m_ScaleRShiftLUT[4];

// enumeration for color input LUT
enum
{
BLU_INP,
GRN_INP,
RED_INP
const Common::EnumMap<TevColorRef, TevColorArg::Zero> m_ColorInputLUT{
TevColorRef::Color(Reg[TevOutput::Prev]), // prev.rgb
TevColorRef::Alpha(Reg[TevOutput::Prev]), // prev.aaa
TevColorRef::Color(Reg[TevOutput::Color0]), // c0.rgb
TevColorRef::Alpha(Reg[TevOutput::Color0]), // c0.aaa
TevColorRef::Color(Reg[TevOutput::Color1]), // c1.rgb
TevColorRef::Alpha(Reg[TevOutput::Color1]), // c1.aaa
TevColorRef::Color(Reg[TevOutput::Color2]), // c2.rgb
TevColorRef::Alpha(Reg[TevOutput::Color2]), // c2.aaa
TevColorRef::Color(TexColor), // tex.rgb
TevColorRef::Alpha(TexColor), // tex.aaa
TevColorRef::Color(RasColor), // ras.rgb
TevColorRef::Alpha(RasColor), // ras.aaa
TevColorRef::All(V1), // one
TevColorRef::All(V1_2), // half
TevColorRef::Color(StageKonst), // konst
TevColorRef::All(V0), // zero
};
const Common::EnumMap<TevAlphaRef, TevAlphaArg::Zero> m_AlphaInputLUT{
TevAlphaRef(Reg[TevOutput::Prev]), // prev
TevAlphaRef(Reg[TevOutput::Color0]), // c0
TevAlphaRef(Reg[TevOutput::Color1]), // c1
TevAlphaRef(Reg[TevOutput::Color2]), // c2
TevAlphaRef(TexColor), // tex
TevAlphaRef(RasColor), // ras
TevAlphaRef(StageKonst), // konst
TevAlphaRef(V0), // zero
};
const Common::EnumMap<TevKonstRef, KonstSel::K3_A> m_KonstLUT{
TevKonstRef::Value(V1), // 1
TevKonstRef::Value(V7_8), // 7/8
TevKonstRef::Value(V3_4), // 3/4
TevKonstRef::Value(V5_8), // 5/8
TevKonstRef::Value(V1_2), // 1/2
TevKonstRef::Value(V3_8), // 3/8
TevKonstRef::Value(V1_4), // 1/4
TevKonstRef::Value(V1_8), // 1/8

// These are "invalid" values, not meant to be used. On hardware,
// they all output zero.
TevKonstRef::Value(V0), TevKonstRef::Value(V0), TevKonstRef::Value(V0),
TevKonstRef::Value(V0),

// These values are valid for RGB only; they're invalid for alpha
TevKonstRef::Konst(V0, KonstantColors[0]), // Konst 0 RGB
TevKonstRef::Konst(V0, KonstantColors[1]), // Konst 1 RGB
TevKonstRef::Konst(V0, KonstantColors[2]), // Konst 2 RGB
TevKonstRef::Konst(V0, KonstantColors[3]), // Konst 3 RGB

TevKonstRef::Value(KonstantColors[0].r), // Konst 0 Red
TevKonstRef::Value(KonstantColors[1].r), // Konst 1 Red
TevKonstRef::Value(KonstantColors[2].r), // Konst 2 Red
TevKonstRef::Value(KonstantColors[3].r), // Konst 3 Red
TevKonstRef::Value(KonstantColors[0].g), // Konst 0 Green
TevKonstRef::Value(KonstantColors[1].g), // Konst 1 Green
TevKonstRef::Value(KonstantColors[2].g), // Konst 2 Green
TevKonstRef::Value(KonstantColors[3].g), // Konst 3 Green
TevKonstRef::Value(KonstantColors[0].b), // Konst 0 Blue
TevKonstRef::Value(KonstantColors[1].b), // Konst 1 Blue
TevKonstRef::Value(KonstantColors[2].b), // Konst 2 Blue
TevKonstRef::Value(KonstantColors[3].b), // Konst 3 Blue
TevKonstRef::Value(KonstantColors[0].a), // Konst 0 Alpha
TevKonstRef::Value(KonstantColors[1].a), // Konst 1 Alpha
TevKonstRef::Value(KonstantColors[2].a), // Konst 2 Alpha
TevKonstRef::Value(KonstantColors[3].a), // Konst 3 Alpha
};
static constexpr Common::EnumMap<s16, TevBias::Compare> s_BiasLUT{0, 128, -128, 0};
static constexpr Common::EnumMap<u8, TevScale::Divide2> s_ScaleLShiftLUT{0, 1, 2, 0};
static constexpr Common::EnumMap<u8, TevScale::Divide2> s_ScaleRShiftLUT{0, 0, 0, 1};

enum BufferBase
{
@@ -56,7 +200,7 @@ class Tev
INDIRECT = 32
};

void SetRasColor(RasColorChan colorChan, int swaptable);
void SetRasColor(RasColorChan colorChan, u32 swaptable);

void DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);
void DrawColorCompare(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);
@@ -82,9 +226,6 @@ class Tev
RED_C
};

void Init();

void SetKonstColors();
void Draw();

void SetRegColor(int reg, int comp, s16 color);
};

Large diffs are not rendered by default.

@@ -811,7 +811,7 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
case BPMEM_IND_CMD + 13:
case BPMEM_IND_CMD + 14:
case BPMEM_IND_CMD + 15:
return std::make_pair(fmt::format("BPMEM_IND_CMD command {}", cmd - BPMEM_IND_CMD),
return std::make_pair(fmt::format("BPMEM_IND_CMD number {}", cmd - BPMEM_IND_CMD),
fmt::to_string(TevStageIndirect{.fullhex = cmddata}));

case BPMEM_SCISSORTL: // 0x20
@@ -832,14 +832,12 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
// TODO: Description

case BPMEM_RAS1_SS0: // 0x25
return std::make_pair(
RegName(BPMEM_RAS1_SS0),
fmt::format("Indirect texture stages 0 and 1:\n{}", TEXSCALE{.hex = cmddata}));
return std::make_pair(RegName(BPMEM_RAS1_SS0),
fmt::to_string(std::make_pair(cmd, TEXSCALE{.hex = cmddata})));

case BPMEM_RAS1_SS1: // 0x26
return std::make_pair(
RegName(BPMEM_RAS1_SS1),
fmt::format("Indirect texture stages 2 and 3:\n{}", TEXSCALE{.hex = cmddata}));
return std::make_pair(RegName(BPMEM_RAS1_SS1),
fmt::to_string(std::make_pair(cmd, TEXSCALE{.hex = cmddata})));

case BPMEM_IREF: // 0x27
return std::make_pair(RegName(BPMEM_IREF), fmt::to_string(RAS1_IREF{.hex = cmddata}));
@@ -853,7 +851,7 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
case BPMEM_TREF + 6:
case BPMEM_TREF + 7:
return std::make_pair(fmt::format("BPMEM_TREF number {}", cmd - BPMEM_TREF),
fmt::to_string(TwoTevStageOrders{.hex = cmddata}));
fmt::to_string(std::make_pair(cmd, TwoTevStageOrders{.hex = cmddata})));

case BPMEM_SU_SSIZE: // 0x30
case BPMEM_SU_SSIZE + 2:
@@ -864,7 +862,7 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
case BPMEM_SU_SSIZE + 12:
case BPMEM_SU_SSIZE + 14:
return std::make_pair(fmt::format("BPMEM_SU_SSIZE number {}", (cmd - BPMEM_SU_SSIZE) / 2),
fmt::format("S size info:\n{}", TCInfo{.hex = cmddata}));
fmt::to_string(std::make_pair(true, TCInfo{.hex = cmddata})));

case BPMEM_SU_TSIZE: // 0x31
case BPMEM_SU_TSIZE + 2:
@@ -875,7 +873,7 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
case BPMEM_SU_TSIZE + 12:
case BPMEM_SU_TSIZE + 14:
return std::make_pair(fmt::format("BPMEM_SU_TSIZE number {}", (cmd - BPMEM_SU_TSIZE) / 2),
fmt::format("T size info:\n{}", TCInfo{.hex = cmddata}));
fmt::to_string(std::make_pair(false, TCInfo{.hex = cmddata})));

case BPMEM_ZMODE: // 0x40
return std::make_pair(RegName(BPMEM_ZMODE), fmt::format("Z mode: {}", ZMode{.hex = cmddata}));
@@ -1249,7 +1247,7 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
case BPMEM_TEV_KSEL + 6:
case BPMEM_TEV_KSEL + 7:
return std::make_pair(fmt::format("BPMEM_TEV_KSEL number {}", cmd - BPMEM_TEV_KSEL),
fmt::to_string(TevKSel{.hex = cmddata}));
fmt::to_string(std::make_pair(cmd, TevKSel{.hex = cmddata})));

case BPMEM_BP_MASK: // 0xFE
return std::make_pair(RegName(BPMEM_BP_MASK),
@@ -167,6 +167,8 @@ constexpr Common::EnumMap<const char*, TevOutput::Color2> tev_a_output_table{
"c2.a",
};

constexpr Common::EnumMap<char, ColorChannel::Alpha> rgba_swizzle{'r', 'g', 'b', 'a'};

PixelShaderUid GetPixelShaderUid()
{
PixelShaderUid out;
@@ -254,31 +256,31 @@ PixelShaderUid GetPixelShaderUid()
ac.a == TevAlphaArg::RasAlpha || ac.b == TevAlphaArg::RasAlpha ||
ac.c == TevAlphaArg::RasAlpha || ac.d == TevAlphaArg::RasAlpha)
{
const int i = bpmem.combiners[n].alphaC.rswap;
uid_data->stagehash[n].tevksel_swap1a = bpmem.tevksel[i * 2].swap1;
uid_data->stagehash[n].tevksel_swap2a = bpmem.tevksel[i * 2].swap2;
uid_data->stagehash[n].tevksel_swap1b = bpmem.tevksel[i * 2 + 1].swap1;
uid_data->stagehash[n].tevksel_swap2b = bpmem.tevksel[i * 2 + 1].swap2;
const auto ras_swap_table = bpmem.tevksel.GetSwapTable(bpmem.combiners[n].alphaC.rswap);
uid_data->stagehash[n].ras_swap_r = ras_swap_table[ColorChannel::Red];
uid_data->stagehash[n].ras_swap_g = ras_swap_table[ColorChannel::Green];
uid_data->stagehash[n].ras_swap_b = ras_swap_table[ColorChannel::Blue];
uid_data->stagehash[n].ras_swap_a = ras_swap_table[ColorChannel::Alpha];
uid_data->stagehash[n].tevorders_colorchan = bpmem.tevorders[n / 2].getColorChan(n & 1);
}

uid_data->stagehash[n].tevorders_enable = bpmem.tevorders[n / 2].getEnable(n & 1);
if (uid_data->stagehash[n].tevorders_enable)
{
const int i = bpmem.combiners[n].alphaC.tswap;
uid_data->stagehash[n].tevksel_swap1c = bpmem.tevksel[i * 2].swap1;
uid_data->stagehash[n].tevksel_swap2c = bpmem.tevksel[i * 2].swap2;
uid_data->stagehash[n].tevksel_swap1d = bpmem.tevksel[i * 2 + 1].swap1;
uid_data->stagehash[n].tevksel_swap2d = bpmem.tevksel[i * 2 + 1].swap2;
const auto tex_swap_table = bpmem.tevksel.GetSwapTable(bpmem.combiners[n].alphaC.tswap);
uid_data->stagehash[n].tex_swap_r = tex_swap_table[ColorChannel::Red];
uid_data->stagehash[n].tex_swap_g = tex_swap_table[ColorChannel::Green];
uid_data->stagehash[n].tex_swap_b = tex_swap_table[ColorChannel::Blue];
uid_data->stagehash[n].tex_swap_a = tex_swap_table[ColorChannel::Alpha];
uid_data->stagehash[n].tevorders_texmap = bpmem.tevorders[n / 2].getTexMap(n & 1);
}

if (cc.a == TevColorArg::Konst || cc.b == TevColorArg::Konst || cc.c == TevColorArg::Konst ||
cc.d == TevColorArg::Konst || ac.a == TevAlphaArg::Konst || ac.b == TevAlphaArg::Konst ||
ac.c == TevAlphaArg::Konst || ac.d == TevAlphaArg::Konst)
{
uid_data->stagehash[n].tevksel_kc = bpmem.tevksel[n / 2].getKC(n & 1);
uid_data->stagehash[n].tevksel_ka = bpmem.tevksel[n / 2].getKA(n & 1);
uid_data->stagehash[n].tevksel_kc = bpmem.tevksel.GetKonstColor(n);
uid_data->stagehash[n].tevksel_ka = bpmem.tevksel.GetKonstAlpha(n);
}
}

@@ -1412,30 +1414,18 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
ac.c == TevAlphaArg::RasAlpha || ac.d == TevAlphaArg::RasAlpha)
{
// Generate swizzle string to represent the Ras color channel swapping
const char rasswap[5] = {
"rgba"[stage.tevksel_swap1a],
"rgba"[stage.tevksel_swap2a],
"rgba"[stage.tevksel_swap1b],
"rgba"[stage.tevksel_swap2b],
'\0',
};

out.Write("\trastemp = {}.{};\n", tev_ras_table[stage.tevorders_colorchan], rasswap);
out.Write("\trastemp = {}.{}{}{}{};\n", tev_ras_table[stage.tevorders_colorchan],
rgba_swizzle[stage.ras_swap_r], rgba_swizzle[stage.ras_swap_g],
rgba_swizzle[stage.ras_swap_b], rgba_swizzle[stage.ras_swap_a]);
}

if (stage.tevorders_enable && uid_data->genMode_numtexgens > 0)
{
// Generate swizzle string to represent the texture color channel swapping
const char texswap[5] = {
"rgba"[stage.tevksel_swap1c],
"rgba"[stage.tevksel_swap2c],
"rgba"[stage.tevksel_swap1d],
"rgba"[stage.tevksel_swap2d],
'\0',
};

out.Write("\ttextemp = sampleTextureWrapper({0}u, tevcoord.xy, layer).{1};\n",
stage.tevorders_texmap, texswap);
out.Write("\ttextemp = sampleTextureWrapper({}u, tevcoord.xy, layer).{}{}{}{};\n",
stage.tevorders_texmap, rgba_swizzle[stage.tex_swap_r],
rgba_swizzle[stage.tex_swap_g], rgba_swizzle[stage.tex_swap_b],
rgba_swizzle[stage.tex_swap_a]);
}
else if (uid_data->genMode_numtexgens == 0)
{
@@ -125,26 +125,27 @@ struct pixel_shader_uid_data
{
// TODO: Can save a lot space by removing the padding bits
u32 cc : 24;
u32 ac : 24; // tswap and rswap are left blank (encoded into the tevksel fields below)
u32 ac : 24; // tswap and rswap are left blank (decoded into the swap fields below)

u32 tevorders_texmap : 3;
u32 tevorders_texcoord : 3;
u32 tevorders_enable : 1;
RasColorChan tevorders_colorchan : 3;
u32 pad1 : 7;

// TODO: Clean up the swapXY mess
// TODO: We could save space by storing the 4 swap tables elsewhere and only storing references
// to which table is used (the tswap and rswap fields), instead of duplicating them here
u32 tevind : 21;
u32 tevksel_swap1a : 2;
u32 tevksel_swap2a : 2;
u32 tevksel_swap1b : 2;
u32 tevksel_swap2b : 2;
ColorChannel ras_swap_r : 2;
ColorChannel ras_swap_g : 2;
ColorChannel ras_swap_b : 2;
ColorChannel ras_swap_a : 2;
u32 pad2 : 2;

u32 tevksel_swap1c : 2;
u32 tevksel_swap2c : 2;
u32 tevksel_swap1d : 2;
u32 tevksel_swap2d : 2;
ColorChannel tex_swap_r : 2;
ColorChannel tex_swap_g : 2;
ColorChannel tex_swap_b : 2;
ColorChannel tex_swap_a : 2;
KonstSel tevksel_kc : 5;
KonstSel tevksel_ka : 5;
u32 pad3 : 14;
@@ -271,12 +271,12 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" // AKA: Color Channel Swapping\n"
"\n"
" int4 ret;\n");
out.Write(" ret.r = color[{}];\n", BitfieldExtract<&TevKSel::swap1>("bpmem_tevksel(s * 2u)"));
out.Write(" ret.g = color[{}];\n", BitfieldExtract<&TevKSel::swap2>("bpmem_tevksel(s * 2u)"));
out.Write(" ret.r = color[{}];\n", BitfieldExtract<&TevKSel::swap_rb>("bpmem_tevksel(s * 2u)"));
out.Write(" ret.g = color[{}];\n", BitfieldExtract<&TevKSel::swap_ga>("bpmem_tevksel(s * 2u)"));
out.Write(" ret.b = color[{}];\n",
BitfieldExtract<&TevKSel::swap1>("bpmem_tevksel(s * 2u + 1u)"));
BitfieldExtract<&TevKSel::swap_rb>("bpmem_tevksel(s * 2u + 1u)"));
out.Write(" ret.a = color[{}];\n",
BitfieldExtract<&TevKSel::swap2>("bpmem_tevksel(s * 2u + 1u)"));
BitfieldExtract<&TevKSel::swap_ga>("bpmem_tevksel(s * 2u + 1u)"));
out.Write(" return ret;\n"
"}}\n\n");

@@ -581,7 +581,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" ss.order = bpmem_tevorder(stage>>1);\n"
" if ((stage & 1u) == 1u)\n"
" ss.order = ss.order >> {};\n\n",
int(TwoTevStageOrders().enable1.StartBit() - TwoTevStageOrders().enable0.StartBit()));
int(TwoTevStageOrders().enable_tex_odd.StartBit() -
TwoTevStageOrders().enable_tex_even.StartBit()));

// Disable texturing when there are no texgens (for now)
if (numTexgen != 0)
@@ -596,11 +597,11 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,

out.Write("\n"
" uint tex_coord = {};\n",
BitfieldExtract<&TwoTevStageOrders::texcoord0>("ss.order"));
BitfieldExtract<&TwoTevStageOrders::texcoord_even>("ss.order"));
out.Write(" int2 fixedPoint_uv = getTexCoord(tex_coord);\n"
"\n"
" bool texture_enabled = (ss.order & {}u) != 0u;\n",
1 << TwoTevStageOrders().enable0.StartBit());
1 << TwoTevStageOrders().enable_tex_even.StartBit());
out.Write("\n"
" // Indirect textures\n"
" uint tevind = bpmem_tevind(stage);\n"
@@ -712,7 +713,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" // Sample texture for stage\n"
" if (texture_enabled) {{\n"
" uint sampler_num = {};\n",
BitfieldExtract<&TwoTevStageOrders::texmap0>("ss.order"));
BitfieldExtract<&TwoTevStageOrders::texmap_even>("ss.order"));
out.Write("\n"
" int4 color = sampleTextureWrapper(sampler_num, tevcoord.xy, layer);\n"
" uint swap = {};\n",
@@ -1216,13 +1217,13 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
"int4 getRasColor(State s, StageState ss, float4 colors_0, float4 colors_1) {{\n"
" // Select Ras for stage\n"
" uint ras = {};\n",
BitfieldExtract<&TwoTevStageOrders::colorchan0>("ss.order"));
BitfieldExtract<&TwoTevStageOrders::colorchan_even>("ss.order"));
out.Write(" if (ras < 2u) {{ // Lighting Channel 0 or 1\n"
" int4 color = iround(((ras == 0u) ? colors_0 : colors_1) * 255.0);\n"
" uint swap = {};\n",
BitfieldExtract<&TevStageCombiner::AlphaCombiner::rswap>("ss.ac"));
out.Write(" return Swizzle(swap, color);\n");
out.Write(" }} else if (ras == 5u) {{ // Alpha Bumb\n"
out.Write(" }} else if (ras == 5u) {{ // Alpha Bump\n"
" return int4(s.AlphaBump, s.AlphaBump, s.AlphaBump, s.AlphaBump);\n"
" }} else if (ras == 6u) {{ // Normalzied Alpha Bump\n"
" int normalized = s.AlphaBump | s.AlphaBump >> 5;\n"
@@ -1239,12 +1240,12 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" uint tevksel = bpmem_tevksel(ss.stage>>1);\n"
" if ((ss.stage & 1u) == 0u)\n"
" return int4(konstLookup[{}].rgb, konstLookup[{}].a);\n",
BitfieldExtract<&TevKSel::kcsel0>("tevksel"),
BitfieldExtract<&TevKSel::kasel0>("tevksel"));
BitfieldExtract<&TevKSel::kcsel_even>("tevksel"),
BitfieldExtract<&TevKSel::kasel_even>("tevksel"));
out.Write(" else\n"
" return int4(konstLookup[{}].rgb, konstLookup[{}].a);\n",
BitfieldExtract<&TevKSel::kcsel1>("tevksel"),
BitfieldExtract<&TevKSel::kasel1>("tevksel"));
BitfieldExtract<&TevKSel::kcsel_odd>("tevksel"),
BitfieldExtract<&TevKSel::kasel_odd>("tevksel"));
out.Write("}}\n");

return out;
@@ -321,17 +321,17 @@ std::pair<std::string, std::string> GetXFRegInfo(u32 address, u32 value)

case XFMEM_SETCHAN0_AMBCOLOR:
return std::make_pair(RegName(XFMEM_SETCHAN0_AMBCOLOR),
fmt::format("Channel 0 Ambient Color: {:06x}", value));
fmt::format("Channel 0 Ambient Color: {:08x}", value));
case XFMEM_SETCHAN1_AMBCOLOR:
return std::make_pair(RegName(XFMEM_SETCHAN1_AMBCOLOR),
fmt::format("Channel 1 Ambient Color: {:06x}", value));
fmt::format("Channel 1 Ambient Color: {:08x}", value));

case XFMEM_SETCHAN0_MATCOLOR:
return std::make_pair(RegName(XFMEM_SETCHAN0_MATCOLOR),
fmt::format("Channel 0 Material Color: {:06x}", value));
fmt::format("Channel 0 Material Color: {:08x}", value));
case XFMEM_SETCHAN1_MATCOLOR:
return std::make_pair(RegName(XFMEM_SETCHAN1_MATCOLOR),
fmt::format("Channel 1 Material Color: {:06x}", value));
fmt::format("Channel 1 Material Color: {:08x}", value));

case XFMEM_SETCHAN0_COLOR: // Channel Color
return std::make_pair(RegName(XFMEM_SETCHAN0_COLOR),
@@ -474,8 +474,8 @@ std::string GetXFMemName(u32 address)
}
else if (address >= XFMEM_POSTMATRICES && address < XFMEM_POSTMATRICES_END)
{
const u32 row = (address - XFMEM_POSMATRICES) / 4;
const u32 col = (address - XFMEM_POSMATRICES) % 4;
const u32 row = (address - XFMEM_POSTMATRICES) / 4;
const u32 col = (address - XFMEM_POSTMATRICES) % 4;
return fmt::format("Post matrix row {:2d} col {:2d}", row, col);
}
else if (address >= XFMEM_LIGHTS && address < XFMEM_LIGHTS_END)
@@ -508,9 +508,9 @@ std::string GetXFMemName(u32 address)
case 15:
// Yagcd says light dir or "1/2 angle", dolphin has union for ddir or shalfangle.
// It would make sense if d stood for direction and s for specular, but it's ddir and
// shalfhangle that have the comment "specular lights only", both at the same offset,
// shalfangle that have the comment "specular lights only", both at the same offset,
// while dpos and sdir have none...
return fmt::format("Light {0} {1} direction or half hangle {1}", light, "xyz"[offset - 13]);
return fmt::format("Light {0} {1} direction or half angle {1}", light, "xyz"[offset - 13]);
}
}
else