PixelShaderGen: Convert to EnumMap

This commit is contained in:
Pokechu22 2021-04-27 15:29:39 -07:00
parent 2b1d1038a6
commit 380b333387
1 changed files with 104 additions and 107 deletions

View File

@ -8,6 +8,7 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/EnumMap.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "VideoCommon/BPMemory.h" #include "VideoCommon/BPMemory.h"
#include "VideoCommon/BoundingBox.h" #include "VideoCommon/BoundingBox.h"
@ -40,7 +41,7 @@ enum : u32
C_PENVCONST_END = C_EFBSCALE + 1 C_PENVCONST_END = C_EFBSCALE + 1
}; };
constexpr std::array<const char*, 32> tev_ksel_table_c{ constexpr Common::EnumMap<const char*, KonstSel::K3_A> tev_ksel_table_c{
"255,255,255", // 1 = 0x00 "255,255,255", // 1 = 0x00
"223,223,223", // 7_8 = 0x01 "223,223,223", // 7_8 = 0x01
"191,191,191", // 3_4 = 0x02 "191,191,191", // 3_4 = 0x02
@ -75,7 +76,7 @@ constexpr std::array<const char*, 32> tev_ksel_table_c{
I_KCOLORS "[3].aaa", // K3_A = 0x1F I_KCOLORS "[3].aaa", // K3_A = 0x1F
}; };
constexpr std::array<const char*, 32> tev_ksel_table_a{ constexpr Common::EnumMap<const char*, KonstSel::K3_A> tev_ksel_table_a{
"255", // 1 = 0x00 "255", // 1 = 0x00
"223", // 7_8 = 0x01 "223", // 7_8 = 0x01
"191", // 3_4 = 0x02 "191", // 3_4 = 0x02
@ -110,7 +111,7 @@ constexpr std::array<const char*, 32> tev_ksel_table_a{
I_KCOLORS "[3].a", // K3_A = 0x1F I_KCOLORS "[3].a", // K3_A = 0x1F
}; };
constexpr std::array<const char*, 16> tev_c_input_table{ constexpr Common::EnumMap<const char*, TevColorArg::Zero> tev_c_input_table{
"prev.rgb", // CPREV, "prev.rgb", // CPREV,
"prev.aaa", // APREV, "prev.aaa", // APREV,
"c0.rgb", // C0, "c0.rgb", // C0,
@ -129,7 +130,7 @@ constexpr std::array<const char*, 16> tev_c_input_table{
"int3(0,0,0)", // ZERO "int3(0,0,0)", // ZERO
}; };
constexpr std::array<const char*, 8> tev_a_input_table{ constexpr Common::EnumMap<const char*, TevAlphaArg::Zero> tev_a_input_table{
"prev.a", // APREV, "prev.a", // APREV,
"c0.a", // A0, "c0.a", // A0,
"c1.a", // A1, "c1.a", // A1,
@ -140,7 +141,7 @@ constexpr std::array<const char*, 8> tev_a_input_table{
"0", // ZERO "0", // ZERO
}; };
constexpr std::array<const char*, 8> tev_ras_table{ constexpr Common::EnumMap<const char*, RasColorChan::Zero> tev_ras_table{
"iround(col0 * 255.0)", "iround(col0 * 255.0)",
"iround(col1 * 255.0)", "iround(col1 * 255.0)",
"ERROR13", // 2 "ERROR13", // 2
@ -151,14 +152,14 @@ constexpr std::array<const char*, 8> tev_ras_table{
"int4(0, 0, 0, 0)", // zero "int4(0, 0, 0, 0)", // zero
}; };
constexpr std::array<const char*, 4> tev_c_output_table{ constexpr Common::EnumMap<const char*, TevOutput::Color2> tev_c_output_table{
"prev.rgb", "prev.rgb",
"c0.rgb", "c0.rgb",
"c1.rgb", "c1.rgb",
"c2.rgb", "c2.rgb",
}; };
constexpr std::array<const char*, 4> tev_a_output_table{ constexpr Common::EnumMap<const char*, TevOutput::Color2> tev_a_output_table{
"prev.a", "prev.a",
"c0.a", "c0.a",
"c1.a", "c1.a",
@ -1160,11 +1161,11 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
last_ac.hex = uid_data->stagehash[uid_data->genMode_numtevstages].ac; last_ac.hex = uid_data->stagehash[uid_data->genMode_numtevstages].ac;
if (last_cc.dest != TevOutput::Prev) if (last_cc.dest != TevOutput::Prev)
{ {
out.Write("\tprev.rgb = {};\n", tev_c_output_table[u32(last_cc.dest.Value())]); out.Write("\tprev.rgb = {};\n", tev_c_output_table[last_cc.dest]);
} }
if (last_ac.dest != TevOutput::Prev) if (last_ac.dest != TevOutput::Prev)
{ {
out.Write("\tprev.a = {};\n", tev_a_output_table[u32(last_ac.dest.Value())]); out.Write("\tprev.a = {};\n", tev_a_output_table[last_ac.dest]);
} }
} }
out.Write("\tprev = prev & 255;\n"); out.Write("\tprev = prev & 255;\n");
@ -1277,6 +1278,8 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n, static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n,
APIType api_type, bool stereo) APIType api_type, bool stereo)
{ {
using Common::EnumMap;
const auto& stage = uid_data->stagehash[n]; const auto& stage = uid_data->stagehash[n];
out.Write("\n\t// TEV stage {}\n", n); out.Write("\n\t// TEV stage {}\n", n);
@ -1303,7 +1306,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
// using iindtex{} as the offset coords // using iindtex{} as the offset coords
if (has_ind_stage && tevind.bs != IndTexBumpAlpha::Off) if (has_ind_stage && tevind.bs != IndTexBumpAlpha::Off)
{ {
static constexpr std::array<const char*, 4> tev_ind_alpha_sel{ static constexpr EnumMap<const char*, IndTexBumpAlpha::U> tev_ind_alpha_sel{
"", "",
"x", "x",
"y", "y",
@ -1316,16 +1319,15 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
// https://github.com/devkitPro/libogc/blob/bd24a9b3f59502f9b30d6bac0ae35fc485045f78/gc/ogc/gx.h#L3038-L3041 // https://github.com/devkitPro/libogc/blob/bd24a9b3f59502f9b30d6bac0ae35fc485045f78/gc/ogc/gx.h#L3038-L3041
// https://github.com/devkitPro/libogc/blob/bd24a9b3f59502f9b30d6bac0ae35fc485045f78/gc/ogc/gx.h#L790-L800 // https://github.com/devkitPro/libogc/blob/bd24a9b3f59502f9b30d6bac0ae35fc485045f78/gc/ogc/gx.h#L790-L800
static constexpr std::array<char, 4> tev_ind_alpha_shift{ static constexpr EnumMap<char, IndTexFormat::ITF_3> tev_ind_alpha_shift{
'0', // ITF_8: 0bXXXXXYYY -> 0bXXXXX000? No shift? '0', // ITF_8: 0bXXXXXYYY -> 0bXXXXX000? No shift?
'5', // ITF_5: 0bIIIIIAAA -> 0bAAA00000, shift of 5 '5', // ITF_5: 0bIIIIIAAA -> 0bAAA00000, shift of 5
'4', // ITF_4: 0bIIIIAAAA -> 0bAAAA0000, shift of 4 '4', // ITF_4: 0bIIIIAAAA -> 0bAAAA0000, shift of 4
'3', // ITF_3: 0bIIIAAAAA -> 0bAAAAA000, shift of 3 '3', // ITF_3: 0bIIIAAAAA -> 0bAAAAA000, shift of 3
}; };
out.Write("\talphabump = (iindtex{}.{} << {}) & 248;\n", tevind.bt.Value(), out.Write("\talphabump = (iindtex{}.{} << {}) & 248;\n", tevind.bt,
tev_ind_alpha_sel[u32(tevind.bs.Value())], tev_ind_alpha_sel[tevind.bs], tev_ind_alpha_shift[tevind.fmt]);
tev_ind_alpha_shift[u32(tevind.fmt.Value())]);
} }
else else
{ {
@ -1335,23 +1337,23 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
if (has_ind_stage && tevind.matrix_index != IndMtxIndex::Off) if (has_ind_stage && tevind.matrix_index != IndMtxIndex::Off)
{ {
// format // format
static constexpr std::array<char, 4> tev_ind_fmt_shift{ static constexpr EnumMap<char, IndTexFormat::ITF_3> tev_ind_fmt_shift{
'0', // ITF_8: 0bXXXXXXXX -> 0bXXXXXXXX, no shift '0', // ITF_8: 0bXXXXXXXX -> 0bXXXXXXXX, no shift
'3', // ITF_5: 0bIIIIIAAA -> 0b000IIIII, shift of 3 '3', // ITF_5: 0bIIIIIAAA -> 0b000IIIII, shift of 3
'4', // ITF_4: 0bIIIIAAAA -> 0b0000IIII, shift of 4 '4', // ITF_4: 0bIIIIAAAA -> 0b0000IIII, shift of 4
'5', // ITF_3: 0bIIIAAAAA -> 0b00000III, shift of 5 '5', // ITF_3: 0bIIIAAAAA -> 0b00000III, shift of 5
}; };
out.Write("\tint3 iindtevcrd{} = iindtex{} >> {};\n", n, tevind.bt.Value(), out.Write("\tint3 iindtevcrd{} = iindtex{} >> {};\n", n, tevind.bt,
tev_ind_fmt_shift[u32(tevind.fmt.Value())]); tev_ind_fmt_shift[tevind.fmt]);
// bias - TODO: Check if this needs to be this complicated... // bias - TODO: Check if this needs to be this complicated...
// indexed by bias // indexed by bias
static constexpr std::array<const char*, 8> tev_ind_bias_field{ static constexpr EnumMap<const char*, IndTexBias::STU> tev_ind_bias_field{
"", "x", "y", "xy", "z", "xz", "yz", "xyz", "", "x", "y", "xy", "z", "xz", "yz", "xyz",
}; };
// indexed by fmt // indexed by fmt
static constexpr std::array<const char*, 4> tev_ind_bias_add{ static constexpr EnumMap<const char*, IndTexFormat::ITF_3> tev_ind_bias_add{
"-128", "-128",
"1", "1",
"1", "1",
@ -1361,22 +1363,19 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
if (tevind.bias == IndTexBias::S || tevind.bias == IndTexBias::T || if (tevind.bias == IndTexBias::S || tevind.bias == IndTexBias::T ||
tevind.bias == IndTexBias::U) tevind.bias == IndTexBias::U)
{ {
out.Write("\tiindtevcrd{}.{} += int({});\n", n, out.Write("\tiindtevcrd{}.{} += int({});\n", n, tev_ind_bias_field[tevind.bias],
tev_ind_bias_field[u32(tevind.bias.Value())], tev_ind_bias_add[tevind.fmt]);
tev_ind_bias_add[u32(tevind.fmt.Value())]);
} }
else if (tevind.bias == IndTexBias::ST || tevind.bias == IndTexBias::SU || else if (tevind.bias == IndTexBias::ST || tevind.bias == IndTexBias::SU ||
tevind.bias == IndTexBias::TU_) tevind.bias == IndTexBias::TU_)
{ {
out.Write("\tiindtevcrd{0}.{1} += int2({2}, {2});\n", n, out.Write("\tiindtevcrd{0}.{1} += int2({2}, {2});\n", n, tev_ind_bias_field[tevind.bias],
tev_ind_bias_field[u32(tevind.bias.Value())], tev_ind_bias_add[tevind.fmt]);
tev_ind_bias_add[u32(tevind.fmt.Value())]);
} }
else if (tevind.bias == IndTexBias::STU) else if (tevind.bias == IndTexBias::STU)
{ {
out.Write("\tiindtevcrd{0}.{1} += int3({2}, {2}, {2});\n", n, out.Write("\tiindtevcrd{0}.{1} += int3({2}, {2}, {2});\n", n,
tev_ind_bias_field[u32(tevind.bias.Value())], tev_ind_bias_field[tevind.bias], tev_ind_bias_add[tevind.fmt]);
tev_ind_bias_add[u32(tevind.fmt.Value())]);
} }
// Multiplied by 2 because each matrix has two rows. // Multiplied by 2 because each matrix has two rows.
@ -1535,7 +1534,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
'\0', '\0',
}; };
out.Write("\trastemp = {}.{};\n", tev_ras_table[u32(stage.tevorders_colorchan)], rasswap); out.Write("\trastemp = {}.{};\n", tev_ras_table[stage.tevorders_colorchan], rasswap);
} }
if (stage.tevorders_enable && uid_data->genMode_numtexgens > 0) if (stage.tevorders_enable && uid_data->genMode_numtexgens > 0)
@ -1567,8 +1566,8 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
cc.d == TevColorArg::Konst || ac.a == TevAlphaArg::Konst || ac.b == TevAlphaArg::Konst || cc.d == TevColorArg::Konst || ac.a == TevAlphaArg::Konst || ac.b == TevAlphaArg::Konst ||
ac.c == TevAlphaArg::Konst || ac.d == TevAlphaArg::Konst) ac.c == TevAlphaArg::Konst || ac.d == TevAlphaArg::Konst)
{ {
out.Write("\tkonsttemp = int4({}, {});\n", tev_ksel_table_c[u32(stage.tevksel_kc)], out.Write("\tkonsttemp = int4({}, {});\n", tev_ksel_table_c[stage.tevksel_kc],
tev_ksel_table_a[u32(stage.tevksel_ka)]); tev_ksel_table_a[stage.tevksel_ka]);
if (u32(stage.tevksel_kc) > 7) if (u32(stage.tevksel_kc) > 7)
{ {
@ -1599,51 +1598,50 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VECTOR_BITWISE_AND)) if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VECTOR_BITWISE_AND))
{ {
out.Write("\ttevin_a = int4({} & 255, {} & 255);\n", tev_c_input_table[u32(cc.a.Value())], out.Write("\ttevin_a = int4({} & 255, {} & 255);\n", tev_c_input_table[cc.a],
tev_a_input_table[u32(ac.a.Value())]); tev_a_input_table[ac.a]);
out.Write("\ttevin_b = int4({} & 255, {} & 255);\n", tev_c_input_table[u32(cc.b.Value())], out.Write("\ttevin_b = int4({} & 255, {} & 255);\n", tev_c_input_table[cc.b],
tev_a_input_table[u32(ac.b.Value())]); tev_a_input_table[ac.b]);
out.Write("\ttevin_c = int4({} & 255, {} & 255);\n", tev_c_input_table[u32(cc.c.Value())], out.Write("\ttevin_c = int4({} & 255, {} & 255);\n", tev_c_input_table[cc.c],
tev_a_input_table[u32(ac.c.Value())]); tev_a_input_table[ac.c]);
} }
else else
{ {
out.Write("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n", out.Write("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.a],
tev_c_input_table[u32(cc.a.Value())], tev_a_input_table[u32(ac.a.Value())]); tev_a_input_table[ac.a]);
out.Write("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n", out.Write("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.b],
tev_c_input_table[u32(cc.b.Value())], tev_a_input_table[u32(ac.b.Value())]); tev_a_input_table[ac.b]);
out.Write("\ttevin_c = int4({}, {})&int4(255, 255, 255, 255);\n", out.Write("\ttevin_c = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.c],
tev_c_input_table[u32(cc.c.Value())], tev_a_input_table[u32(ac.c.Value())]); tev_a_input_table[ac.c]);
} }
out.Write("\ttevin_d = int4({}, {});\n", tev_c_input_table[u32(cc.d.Value())], out.Write("\ttevin_d = int4({}, {});\n", tev_c_input_table[cc.d], tev_a_input_table[ac.d]);
tev_a_input_table[u32(ac.d.Value())]);
out.Write("\t// color combine\n"); out.Write("\t// color combine\n");
out.Write("\t{} = clamp(", tev_c_output_table[u32(cc.dest.Value())]); out.Write("\t{} = clamp(", tev_c_output_table[cc.dest]);
if (cc.bias != TevBias::Compare) if (cc.bias != TevBias::Compare)
{ {
WriteTevRegular(out, "rgb", cc.bias, cc.op, cc.clamp, cc.scale, false); WriteTevRegular(out, "rgb", cc.bias, cc.op, cc.clamp, cc.scale, false);
} }
else else
{ {
static constexpr std::array<const char*, 8> function_table{ static constexpr EnumMap<const char*, TevCompareMode::RGB8> tev_rgb_comparison_gt{
"((tevin_a.r > tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TevCompareMode::R8, GT "((tevin_a.r > tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TevCompareMode::R8
"((tevin_a.r == tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // R8, TevComparison::EQ "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : int3(0,0,0))", // GR16
"((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : " "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : int3(0,0,0))", // BGR24
"int3(0,0,0))", // GR16, GT "(max(sign(tevin_a.rgb - tevin_b.rgb), int3(0,0,0)) * tevin_c.rgb)", // RGB8
"((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : "
"int3(0,0,0))", // GR16, EQ
"((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : "
"int3(0,0,0))", // BGR24, GT
"((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : "
"int3(0,0,0))", // BGR24, EQ
"(max(sign(tevin_a.rgb - tevin_b.rgb), int3(0,0,0)) * tevin_c.rgb)", // RGB8, GT
"((int3(1,1,1) - sign(abs(tevin_a.rgb - tevin_b.rgb))) * tevin_c.rgb)" // RGB8, EQ
}; };
const u32 mode = (u32(cc.compare_mode.Value()) << 1) | u32(cc.comparison.Value()); static constexpr EnumMap<const char*, TevCompareMode::RGB8> tev_rgb_comparison_eq{
out.Write(" tevin_d.rgb + "); "((tevin_a.r == tevin_b.r) ? tevin_c.rgb : int3(0))", // TevCompareMode::R8
out.Write("{}", function_table[mode]); "((idot(tevin_a.rgb,comp16) == idot(tevin_b.rgb,comp16)) ? tevin_c.rgb : int3(0,0,0))", // GR16
"((idot(tevin_a.rgb,comp24) == idot(tevin_b.rgb,comp24)) ? tevin_c.rgb : int3(0,0,0))", // BGR24
"((int3(1,1,1) - sign(abs(tevin_a.rgb - tevin_b.rgb))) * tevin_c.rgb)" // RGB8
};
if (cc.comparison == TevComparison::EQ)
out.Write(" tevin_d.rgb + {}", tev_rgb_comparison_eq[cc.compare_mode]);
else
out.Write(" tevin_d.rgb + {}", tev_rgb_comparison_gt[cc.compare_mode]);
} }
if (cc.clamp) if (cc.clamp)
out.Write(", int3(0,0,0), int3(255,255,255))"); out.Write(", int3(0,0,0), int3(255,255,255))");
@ -1652,27 +1650,31 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
out.Write(";\n"); out.Write(";\n");
out.Write("\t// alpha combine\n"); out.Write("\t// alpha combine\n");
out.Write("\t{} = clamp(", tev_a_output_table[u32(ac.dest.Value())]); out.Write("\t{} = clamp(", tev_a_output_table[ac.dest]);
if (ac.bias != TevBias::Compare) if (ac.bias != TevBias::Compare)
{ {
WriteTevRegular(out, "a", ac.bias, ac.op, ac.clamp, ac.scale, true); WriteTevRegular(out, "a", ac.bias, ac.op, ac.clamp, ac.scale, true);
} }
else else
{ {
static constexpr std::array<const char*, 8> function_table{ static constexpr EnumMap<const char*, TevCompareMode::A8> tev_a_comparison_gt{
"((tevin_a.r > tevin_b.r) ? tevin_c.a : 0)", // TevCompareMode::R8, GT "((tevin_a.r > tevin_b.r) ? tevin_c.a : 0)", // TevCompareMode::R8
"((tevin_a.r == tevin_b.r) ? tevin_c.a : 0)", // R8, TevComparison::EQ "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // GR16
"((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // GR16, GT "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // BGR24
"((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // GR16, EQ "((tevin_a.a > tevin_b.a) ? tevin_c.a : 0)", // A8
"((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // BGR24, GT
"((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // BGR24, EQ
"((tevin_a.a > tevin_b.a) ? tevin_c.a : 0)", // A8, GT
"((tevin_a.a == tevin_b.a) ? tevin_c.a : 0)" // A8, EQ
}; };
const u32 mode = (u32(ac.compare_mode.Value()) << 1) | u32(ac.comparison.Value()); static constexpr EnumMap<const char*, TevCompareMode::A8> tev_a_comparison_eq{
out.Write(" tevin_d.a + "); "((tevin_a.r == tevin_b.r) ? tevin_c.a : 0)", // TevCompareMode::R8
out.Write("{}", function_table[mode]); "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // GR16,
"((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // BGR24,
"((tevin_a.a == tevin_b.a) ? tevin_c.a : 0)", // A8
};
if (ac.comparison == TevComparison::EQ)
out.Write(" tevin_d.a + {}", tev_a_comparison_eq[ac.compare_mode]);
else
out.Write(" tevin_d.a + {}", tev_a_comparison_gt[ac.compare_mode]);
} }
if (ac.clamp) if (ac.clamp)
out.Write(", 0, 255)"); out.Write(", 0, 255)");
@ -1685,36 +1687,33 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op, static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBias bias, TevOp op,
bool clamp, TevScale scale, bool alpha) bool clamp, TevScale scale, bool alpha)
{ {
static constexpr std::array<const char*, 4> tev_scale_table_left{ static constexpr Common::EnumMap<const char*, TevScale::Divide2> tev_scale_table_left{
"", // Scale1 "", // Scale1
" << 1", // Scale2 " << 1", // Scale2
" << 2", // Scale4 " << 2", // Scale4
"", // Divide2 "", // Divide2
}; };
static constexpr std::array<const char*, 4> tev_scale_table_right{ static constexpr Common::EnumMap<const char*, TevScale::Divide2> tev_scale_table_right{
"", // Scale1 "", // Scale1
"", // Scale2 "", // Scale2
"", // Scale4 "", // Scale4
" >> 1", // Divide2 " >> 1", // Divide2
}; };
// indexed by 2*op+(scale==Divide2) static constexpr Common::EnumMap<const char*, TevOp::Sub> tev_lerp_bias{
static constexpr std::array<const char*, 4> tev_lerp_bias{
"",
" + 128", " + 128",
"",
" + 127", " + 127",
}; };
static constexpr std::array<const char*, 4> tev_bias_table{ static constexpr Common::EnumMap<const char*, TevBias::Compare> tev_bias_table{
"", // Zero, "", // Zero,
" + 128", // AddHalf, " + 128", // AddHalf,
" - 128", // SubHalf, " - 128", // SubHalf,
"", "",
}; };
static constexpr std::array<char, 2> tev_op_table{ static constexpr Common::EnumMap<char, TevOp::Sub> tev_op_table{
'+', // TevOp::Add = 0, '+', // TevOp::Add = 0,
'-', // TevOp::Sub = 1, '-', // TevOp::Sub = 1,
}; };
@ -1724,17 +1723,16 @@ static void WriteTevRegular(ShaderCode& out, std::string_view components, TevBia
// - c is scaled from 0..255 to 0..256, which allows dividing the result by 256 instead of 255 // - c is scaled from 0..255 to 0..256, which allows dividing the result by 256 instead of 255
// - if scale is bigger than one, it is moved inside the lerp calculation for increased accuracy // - if scale is bigger than one, it is moved inside the lerp calculation for increased accuracy
// - a rounding bias is added before dividing by 256 // - a rounding bias is added before dividing by 256
out.Write("(((tevin_d.{}{}){})", components, tev_bias_table[u32(bias)], out.Write("(((tevin_d.{}{}){})", components, tev_bias_table[bias], tev_scale_table_left[scale]);
tev_scale_table_left[u32(scale)]); out.Write(" {} ", tev_op_table[op]);
out.Write(" {} ", tev_op_table[u32(op)]); out.Write("(((((tevin_a.{0}<<8) + "
out.Write("(((((tevin_a.{}<<8) + (tevin_b.{}-tevin_a.{})*(tevin_c.{}+(tevin_c.{}>>7))){}){})>>8)", "(tevin_b.{0}-tevin_a.{0})*(tevin_c.{0}+(tevin_c.{0}>>7))){1}){2})>>8)",
components, components, components, components, components, components, tev_scale_table_left[scale],
tev_scale_table_left[u32(scale)], ((scale == TevScale::Divide2) == alpha) ? tev_lerp_bias[op] : "");
tev_lerp_bias[2 * u32(op) + ((scale == TevScale::Divide2) == alpha)]); out.Write("){}", tev_scale_table_right[scale]);
out.Write("){}", tev_scale_table_right[u32(scale)]);
} }
constexpr std::array<const char*, 8> tev_alpha_funcs_table{ constexpr Common::EnumMap<const char*, CompareMode::Always> tev_alpha_funcs_table{
"(false)", // CompareMode::Never "(false)", // CompareMode::Never
"(prev.a < {})", // CompareMode::Less "(prev.a < {})", // CompareMode::Less
"(prev.a == {})", // CompareMode::Equal "(prev.a == {})", // CompareMode::Equal
@ -1745,7 +1743,7 @@ constexpr std::array<const char*, 8> tev_alpha_funcs_table{
"(true)" // CompareMode::Always "(true)" // CompareMode::Always
}; };
constexpr std::array<const char*, 4> tev_alpha_funclogic_table{ constexpr Common::EnumMap<const char*, AlphaTestOp::Xnor> tev_alpha_funclogic_table{
" && ", // and " && ", // and
" || ", // or " || ", // or
" != ", // xor " != ", // xor
@ -1763,9 +1761,9 @@ static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_dat
const auto write_alpha_func = [&out](CompareMode mode, std::string_view ref) { const auto write_alpha_func = [&out](CompareMode mode, std::string_view ref) {
const bool has_no_arguments = mode == CompareMode::Never || mode == CompareMode::Always; const bool has_no_arguments = mode == CompareMode::Never || mode == CompareMode::Always;
if (has_no_arguments) if (has_no_arguments)
out.Write("{}", tev_alpha_funcs_table[u32(mode)]); out.Write("{}", tev_alpha_funcs_table[mode]);
else else
out.Write(tev_alpha_funcs_table[u32(mode)], ref); out.Write(tev_alpha_funcs_table[mode], ref);
}; };
out.SetConstantsUsed(C_ALPHA, C_ALPHA); out.SetConstantsUsed(C_ALPHA, C_ALPHA);
@ -1779,7 +1777,7 @@ static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_dat
write_alpha_func(uid_data->alpha_test_comp0, alpha_ref[0]); write_alpha_func(uid_data->alpha_test_comp0, alpha_ref[0]);
// Lookup the logic op // Lookup the logic op
out.Write("{}", tev_alpha_funclogic_table[u32(uid_data->alpha_test_logic)]); out.Write("{}", tev_alpha_funclogic_table[uid_data->alpha_test_logic]);
// Lookup the second component from the alpha function table // Lookup the second component from the alpha function table
write_alpha_func(uid_data->alpha_test_comp1, alpha_ref[1]); write_alpha_func(uid_data->alpha_test_comp1, alpha_ref[1]);
@ -1809,7 +1807,7 @@ static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_dat
out.Write("\t}}\n"); out.Write("\t}}\n");
} }
constexpr std::array<const char*, 8> tev_fog_funcs_table{ constexpr Common::EnumMap<const char*, FogType::BackwardsExpSq> tev_fog_funcs_table{
"", // No Fog "", // No Fog
"", // ? "", // ?
"", // Linear "", // Linear
@ -1866,7 +1864,7 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data)
if (uid_data->fog_fsel >= FogType::Exp) if (uid_data->fog_fsel >= FogType::Exp)
{ {
out.Write("{}", tev_fog_funcs_table[u32(uid_data->fog_fsel)]); out.Write("{}", tev_fog_funcs_table[uid_data->fog_fsel]);
} }
else else
{ {
@ -1919,7 +1917,8 @@ static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data)
{ {
if (uid_data->blend_enable) if (uid_data->blend_enable)
{ {
static constexpr std::array<const char*, 8> blend_src_factor{ using Common::EnumMap;
static constexpr EnumMap<const char*, SrcBlendFactor::InvDstAlpha> blend_src_factor{
"float3(0,0,0);", // ZERO "float3(0,0,0);", // ZERO
"float3(1,1,1);", // ONE "float3(1,1,1);", // ONE
"initial_ocol0.rgb;", // DSTCLR "initial_ocol0.rgb;", // DSTCLR
@ -1929,7 +1928,7 @@ static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data)
"initial_ocol0.aaa;", // DSTALPHA "initial_ocol0.aaa;", // DSTALPHA
"float3(1,1,1) - initial_ocol0.aaa;", // INVDSTALPHA "float3(1,1,1) - initial_ocol0.aaa;", // INVDSTALPHA
}; };
static constexpr std::array<const char*, 8> blend_src_factor_alpha{ static constexpr EnumMap<const char*, SrcBlendFactor::InvDstAlpha> blend_src_factor_alpha{
"0.0;", // ZERO "0.0;", // ZERO
"1.0;", // ONE "1.0;", // ONE
"initial_ocol0.a;", // DSTCLR "initial_ocol0.a;", // DSTCLR
@ -1939,7 +1938,7 @@ static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data)
"initial_ocol0.a;", // DSTALPHA "initial_ocol0.a;", // DSTALPHA
"1.0 - initial_ocol0.a;", // INVDSTALPHA "1.0 - initial_ocol0.a;", // INVDSTALPHA
}; };
static constexpr std::array<const char*, 8> blend_dst_factor{ static constexpr EnumMap<const char*, DstBlendFactor::InvDstAlpha> blend_dst_factor{
"float3(0,0,0);", // ZERO "float3(0,0,0);", // ZERO
"float3(1,1,1);", // ONE "float3(1,1,1);", // ONE
"ocol0.rgb;", // SRCCLR "ocol0.rgb;", // SRCCLR
@ -1949,7 +1948,7 @@ static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data)
"initial_ocol0.aaa;", // DSTALPHA "initial_ocol0.aaa;", // DSTALPHA
"float3(1,1,1) - initial_ocol0.aaa;", // INVDSTALPHA "float3(1,1,1) - initial_ocol0.aaa;", // INVDSTALPHA
}; };
static constexpr std::array<const char*, 8> blend_dst_factor_alpha{ static constexpr EnumMap<const char*, DstBlendFactor::InvDstAlpha> blend_dst_factor_alpha{
"0.0;", // ZERO "0.0;", // ZERO
"1.0;", // ONE "1.0;", // ONE
"ocol0.a;", // SRCCLR "ocol0.a;", // SRCCLR
@ -1960,13 +1959,11 @@ static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data)
"1.0 - initial_ocol0.a;", // INVDSTALPHA "1.0 - initial_ocol0.a;", // INVDSTALPHA
}; };
out.Write("\tfloat4 blend_src;\n"); out.Write("\tfloat4 blend_src;\n");
out.Write("\tblend_src.rgb = {}\n", blend_src_factor[u32(uid_data->blend_src_factor)]); out.Write("\tblend_src.rgb = {}\n", blend_src_factor[uid_data->blend_src_factor]);
out.Write("\tblend_src.a = {}\n", out.Write("\tblend_src.a = {}\n", blend_src_factor_alpha[uid_data->blend_src_factor_alpha]);
blend_src_factor_alpha[u32(uid_data->blend_src_factor_alpha)]);
out.Write("\tfloat4 blend_dst;\n"); out.Write("\tfloat4 blend_dst;\n");
out.Write("\tblend_dst.rgb = {}\n", blend_dst_factor[u32(uid_data->blend_dst_factor)]); out.Write("\tblend_dst.rgb = {}\n", blend_dst_factor[uid_data->blend_dst_factor]);
out.Write("\tblend_dst.a = {}\n", out.Write("\tblend_dst.a = {}\n", blend_dst_factor_alpha[uid_data->blend_dst_factor_alpha]);
blend_dst_factor_alpha[u32(uid_data->blend_dst_factor_alpha)]);
out.Write("\tfloat4 blend_result;\n"); out.Write("\tfloat4 blend_result;\n");
if (uid_data->blend_subtract) if (uid_data->blend_subtract)