mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-26 15:55:31 +01:00
Merge pull request #10394 from Pokechu22/alpha-1-blend
Revert TEV alpha lerp change and special-case alpha=1 in blending
This commit is contained in:
commit
30a9777c5a
@ -297,7 +297,7 @@ void Tev::DrawAlphaRegular(const TevStageCombiner::AlphaCombiner& ac, const Inpu
|
|||||||
|
|
||||||
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
|
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
|
||||||
temp <<= m_ScaleLShiftLUT[u32(ac.scale.Value())];
|
temp <<= m_ScaleLShiftLUT[u32(ac.scale.Value())];
|
||||||
temp += (ac.scale != TevScale::Divide2) ? 0 : (ac.op == TevOp::Sub) ? 127 : 128;
|
temp += (ac.scale == TevScale::Divide2) ? 0 : (ac.op == TevOp::Sub) ? 127 : 128;
|
||||||
temp = ac.op == TevOp::Sub ? (-temp >> 8) : (temp >> 8);
|
temp = ac.op == TevOp::Sub ? (-temp >> 8) : (temp >> 8);
|
||||||
|
|
||||||
s32 result =
|
s32 result =
|
||||||
@ -714,6 +714,19 @@ void Tev::Draw()
|
|||||||
if (!TevAlphaTest(output[ALP_C]))
|
if (!TevAlphaTest(output[ALP_C]))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Hardware testing indicates that an alpha of 1 can pass an alpha test,
|
||||||
|
// but doesn't do anything in blending
|
||||||
|
// This situation is important for Mario Kart Wii's menus (they will render incorrectly if the
|
||||||
|
// alpha test for the FMV in the background fails, since they depend on depth for drawing a yellow
|
||||||
|
// border) and Fortune Street's gameplay (where a rectangle with an alpha value of 1 is drawn over
|
||||||
|
// the center of the screen several times, but those rectangles shouldn't be visible).
|
||||||
|
// Blending seems to result in no changes to the output with an alpha of 1, even if the input
|
||||||
|
// color is white.
|
||||||
|
// TODO: Investigate this further: we might be handling blending incorrectly in general (though
|
||||||
|
// there might not be any good way of changing blending behavior)
|
||||||
|
if (output[ALP_C] == 1)
|
||||||
|
output[ALP_C] = 0;
|
||||||
|
|
||||||
// z texture
|
// z texture
|
||||||
if (bpmem.ztex2.op != ZTexOp::Disabled)
|
if (bpmem.ztex2.op != ZTexOp::Disabled)
|
||||||
{
|
{
|
||||||
|
@ -852,7 +852,7 @@ uint WrapCoord(int coord, uint wrap, int size) {{
|
|||||||
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);
|
||||||
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);
|
||||||
static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, APIType api_type,
|
static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_data, APIType api_type,
|
||||||
bool per_pixel_depth, bool use_dual_source);
|
bool per_pixel_depth, bool use_dual_source);
|
||||||
static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data);
|
static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data);
|
||||||
@ -1234,6 +1234,18 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
|||||||
use_dual_source || use_shader_blend);
|
use_dual_source || use_shader_blend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This situation is important for Mario Kart Wii's menus (they will render incorrectly if the
|
||||||
|
// alpha test for the FMV in the background fails, since they depend on depth for drawing a yellow
|
||||||
|
// border) and Fortune Street's gameplay (where a rectangle with an alpha value of 1 is drawn over
|
||||||
|
// the center of the screen several times, but those rectangles shouldn't be visible).
|
||||||
|
// Blending seems to result in no changes to the output with an alpha of 1, even if the input
|
||||||
|
// color is white.
|
||||||
|
// TODO: Investigate this further: we might be handling blending incorrectly in general (though
|
||||||
|
// there might not be any good way of changing blending behavior)
|
||||||
|
out.Write("\t// Hardware testing indicates that an alpha of 1 can pass an alpha test,\n"
|
||||||
|
"\t// but doesn't do anything in blending\n"
|
||||||
|
"\tif (prev.a == 1) prev.a = 0;\n");
|
||||||
|
|
||||||
if (uid_data->zfreeze)
|
if (uid_data->zfreeze)
|
||||||
{
|
{
|
||||||
out.SetConstantsUsed(C_ZSLOPE, C_ZSLOPE);
|
out.SetConstantsUsed(C_ZSLOPE, C_ZSLOPE);
|
||||||
@ -1677,7 +1689,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
|
|||||||
out.Write("\t{} = clamp(", tev_c_output_table[cc.dest]);
|
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);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1710,7 +1722,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
|
|||||||
out.Write("\t{} = clamp(", tev_a_output_table[ac.dest]);
|
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);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1742,7 +1754,7 @@ 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)
|
||||||
{
|
{
|
||||||
static constexpr Common::EnumMap<const char*, TevScale::Divide2> tev_scale_table_left{
|
static constexpr Common::EnumMap<const char*, TevScale::Divide2> tev_scale_table_left{
|
||||||
"", // Scale1
|
"", // Scale1
|
||||||
@ -1780,12 +1792,14 @@ 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
|
||||||
|
// TODO: Is the rounding bias still added when the scale is divide by 2? Currently we do not
|
||||||
|
// apply it.
|
||||||
out.Write("(((tevin_d.{}{}){})", components, tev_bias_table[bias], tev_scale_table_left[scale]);
|
out.Write("(((tevin_d.{}{}){})", components, tev_bias_table[bias], tev_scale_table_left[scale]);
|
||||||
out.Write(" {} ", tev_op_table[op]);
|
out.Write(" {} ", tev_op_table[op]);
|
||||||
out.Write("(((((tevin_a.{0}<<8) + "
|
out.Write("(((((tevin_a.{0}<<8) + "
|
||||||
"(tevin_b.{0}-tevin_a.{0})*(tevin_c.{0}+(tevin_c.{0}>>7))){1}){2})>>8)",
|
"(tevin_b.{0}-tevin_a.{0})*(tevin_c.{0}+(tevin_c.{0}>>7))){1}){2})>>8)",
|
||||||
components, tev_scale_table_left[scale],
|
components, tev_scale_table_left[scale],
|
||||||
((scale == TevScale::Divide2) == alpha) ? tev_lerp_bias[op] : "");
|
(scale != TevScale::Divide2) ? tev_lerp_bias[op] : "");
|
||||||
out.Write("){}", tev_scale_table_right[scale]);
|
out.Write("){}", tev_scale_table_right[scale]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,8 +334,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||||||
const auto WriteTevLerp = [&out](std::string_view components) {
|
const auto WriteTevLerp = [&out](std::string_view components) {
|
||||||
out.Write(
|
out.Write(
|
||||||
"// TEV's Linear Interpolate, plus bias, add/subtract and scale\n"
|
"// TEV's Linear Interpolate, plus bias, add/subtract and scale\n"
|
||||||
"int{0} tevLerp{0}(int{0} A, int{0} B, int{0} C, int{0} D, uint bias, bool op, bool alpha, "
|
"int{0} tevLerp{0}(int{0} A, int{0} B, int{0} C, int{0} D, uint bias, bool op, "
|
||||||
"uint shift) {{\n"
|
"uint scale) {{\n"
|
||||||
" // Scale C from 0..255 to 0..256\n"
|
" // Scale C from 0..255 to 0..256\n"
|
||||||
" C += C >> 7;\n"
|
" C += C >> 7;\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -344,12 +344,14 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||||||
" else if (bias == 2u) D -= 128;\n"
|
" else if (bias == 2u) D -= 128;\n"
|
||||||
"\n"
|
"\n"
|
||||||
" int{0} lerp = (A << 8) + (B - A)*C;\n"
|
" int{0} lerp = (A << 8) + (B - A)*C;\n"
|
||||||
" if (shift != 3u) {{\n"
|
" if (scale != 3u) {{\n"
|
||||||
" lerp = lerp << shift;\n"
|
" lerp = lerp << scale;\n"
|
||||||
" D = D << shift;\n"
|
" D = D << scale;\n"
|
||||||
" }}\n"
|
" }}\n"
|
||||||
"\n"
|
"\n"
|
||||||
" if ((shift == 3u) == alpha)\n"
|
" // TODO: Is this rounding bias still added when the scale is divide by 2? Currently we "
|
||||||
|
"do not apply it.\n"
|
||||||
|
" if (scale != 3u)\n"
|
||||||
" lerp = lerp + (op ? 127 : 128);\n"
|
" lerp = lerp + (op ? 127 : 128);\n"
|
||||||
"\n"
|
"\n"
|
||||||
" int{0} result = lerp >> 8;\n"
|
" int{0} result = lerp >> 8;\n"
|
||||||
@ -360,9 +362,9 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||||||
" else // Add\n"
|
" else // Add\n"
|
||||||
" result = D + result;\n"
|
" result = D + result;\n"
|
||||||
"\n"
|
"\n"
|
||||||
" // Most of the Shift was moved inside the lerp for improved precision\n"
|
" // Most of the Scale was moved inside the lerp for improved precision\n"
|
||||||
" // But we still do the divide by 2 here\n"
|
" // But we still do the divide by 2 here\n"
|
||||||
" if (shift == 3u)\n"
|
" if (scale == 3u)\n"
|
||||||
" result = result >> 1;\n"
|
" result = result >> 1;\n"
|
||||||
" return result;\n"
|
" return result;\n"
|
||||||
"}}\n\n",
|
"}}\n\n",
|
||||||
@ -810,13 +812,13 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||||||
BitfieldExtract<&TevStageCombiner::ColorCombiner::op>("ss.cc"));
|
BitfieldExtract<&TevStageCombiner::ColorCombiner::op>("ss.cc"));
|
||||||
out.Write(" bool color_clamp = bool({});\n",
|
out.Write(" bool color_clamp = bool({});\n",
|
||||||
BitfieldExtract<&TevStageCombiner::ColorCombiner::clamp>("ss.cc"));
|
BitfieldExtract<&TevStageCombiner::ColorCombiner::clamp>("ss.cc"));
|
||||||
out.Write(" uint color_shift = {};\n",
|
out.Write(" uint color_scale = {};\n",
|
||||||
BitfieldExtract<&TevStageCombiner::ColorCombiner::scale>("ss.cc"));
|
BitfieldExtract<&TevStageCombiner::ColorCombiner::scale>("ss.cc"));
|
||||||
out.Write(" uint color_dest = {};\n",
|
out.Write(" uint color_dest = {};\n",
|
||||||
BitfieldExtract<&TevStageCombiner::ColorCombiner::dest>("ss.cc"));
|
BitfieldExtract<&TevStageCombiner::ColorCombiner::dest>("ss.cc"));
|
||||||
|
|
||||||
out.Write(
|
out.Write(
|
||||||
" uint color_compare_op = color_shift << 1 | uint(color_op);\n"
|
" uint color_compare_op = color_scale << 1 | uint(color_op);\n"
|
||||||
"\n"
|
"\n"
|
||||||
" int3 color_A = selectColorInput(s, ss, {0}colors_0, {0}colors_1, color_a) & "
|
" int3 color_A = selectColorInput(s, ss, {0}colors_0, {0}colors_1, color_a) & "
|
||||||
"int3(255, 255, 255);\n"
|
"int3(255, 255, 255);\n"
|
||||||
@ -831,8 +833,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||||||
out.Write(
|
out.Write(
|
||||||
" int3 color;\n"
|
" int3 color;\n"
|
||||||
" if (color_bias != 3u) {{ // Normal mode\n"
|
" if (color_bias != 3u) {{ // Normal mode\n"
|
||||||
" color = tevLerp3(color_A, color_B, color_C, color_D, color_bias, color_op, false, "
|
" color = tevLerp3(color_A, color_B, color_C, color_D, color_bias, color_op, "
|
||||||
"color_shift);\n"
|
"color_scale);\n"
|
||||||
" }} else {{ // Compare mode\n"
|
" }} else {{ // Compare mode\n"
|
||||||
" // op 6 and 7 do a select per color channel\n"
|
" // op 6 and 7 do a select per color channel\n"
|
||||||
" if (color_compare_op == 6u) {{\n"
|
" if (color_compare_op == 6u) {{\n"
|
||||||
@ -880,13 +882,13 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||||||
BitfieldExtract<&TevStageCombiner::AlphaCombiner::op>("ss.ac"));
|
BitfieldExtract<&TevStageCombiner::AlphaCombiner::op>("ss.ac"));
|
||||||
out.Write(" bool alpha_clamp = bool({});\n",
|
out.Write(" bool alpha_clamp = bool({});\n",
|
||||||
BitfieldExtract<&TevStageCombiner::AlphaCombiner::clamp>("ss.ac"));
|
BitfieldExtract<&TevStageCombiner::AlphaCombiner::clamp>("ss.ac"));
|
||||||
out.Write(" uint alpha_shift = {};\n",
|
out.Write(" uint alpha_scale = {};\n",
|
||||||
BitfieldExtract<&TevStageCombiner::AlphaCombiner::scale>("ss.ac"));
|
BitfieldExtract<&TevStageCombiner::AlphaCombiner::scale>("ss.ac"));
|
||||||
out.Write(" uint alpha_dest = {};\n",
|
out.Write(" uint alpha_dest = {};\n",
|
||||||
BitfieldExtract<&TevStageCombiner::AlphaCombiner::dest>("ss.ac"));
|
BitfieldExtract<&TevStageCombiner::AlphaCombiner::dest>("ss.ac"));
|
||||||
|
|
||||||
out.Write(
|
out.Write(
|
||||||
" uint alpha_compare_op = alpha_shift << 1 | uint(alpha_op);\n"
|
" uint alpha_compare_op = alpha_scale << 1 | uint(alpha_op);\n"
|
||||||
"\n"
|
"\n"
|
||||||
" int alpha_A;\n"
|
" int alpha_A;\n"
|
||||||
" int alpha_B;\n"
|
" int alpha_B;\n"
|
||||||
@ -904,7 +906,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||||||
" int alpha;\n"
|
" int alpha;\n"
|
||||||
" if (alpha_bias != 3u) {{ // Normal mode\n"
|
" if (alpha_bias != 3u) {{ // Normal mode\n"
|
||||||
" alpha = tevLerp(alpha_A, alpha_B, alpha_C, alpha_D, alpha_bias, alpha_op, "
|
" alpha = tevLerp(alpha_A, alpha_B, alpha_C, alpha_D, alpha_bias, alpha_op, "
|
||||||
"true, alpha_shift);\n"
|
"alpha_scale);\n"
|
||||||
" }} else {{ // Compare mode\n"
|
" }} else {{ // Compare mode\n"
|
||||||
" if (alpha_compare_op == 6u) {{\n"
|
" if (alpha_compare_op == 6u) {{\n"
|
||||||
" // TevCompareMode::A8, TevComparison::GT\n"
|
" // TevCompareMode::A8, TevComparison::GT\n"
|
||||||
@ -1030,6 +1032,9 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
|||||||
" }}\n"
|
" }}\n"
|
||||||
"\n");
|
"\n");
|
||||||
|
|
||||||
|
out.Write(" // Hardware testing indicates that an alpha of 1 can pass an alpha test,\n"
|
||||||
|
" // but doesn't do anything in blending\n"
|
||||||
|
" if (TevResult.a == 1) TevResult.a = 0;\n");
|
||||||
// =========
|
// =========
|
||||||
// Dithering
|
// Dithering
|
||||||
// =========
|
// =========
|
||||||
|
Loading…
x
Reference in New Issue
Block a user