1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-23 03:02:53 +01:00

rsx: Reimplement MSAA transparency

- Apply dither to edges that almost fail the straight-up alpha test
- Significantly improves alpha tested geometry far from the camera
- Also removes blend factor overrides/hacks as they give incorrect results due to background bleeding
This commit is contained in:
kd-11 2019-01-16 20:06:45 +03:00 committed by kd-11
parent 10a17feda2
commit 6fdc0fd7f0
4 changed files with 54 additions and 70 deletions

View File

@ -383,12 +383,17 @@ namespace glsl
OS <<
" if ((rop_control & 0xFF) != 0)\n"
" {\n"
" bool alpha_test = (rop_control & 0x11) > 0;\n"
" bool alpha_test = (rop_control & 0x1) > 0;\n"
" uint alpha_func = ((rop_control >> 16) & 0x7);\n"
" bool srgb_convert = (rop_control & 0x2) > 0;\n\n"
" bool a2c_enabled = (rop_control & 0x10) > 0;\n"
" if (alpha_test && !comparison_passes(" << reg0 << ".a, alpha_ref, alpha_func))\n"
" {\n"
" discard;\n"
" }\n"
" else if (a2c_enabled && !coverage_test_passes(" << reg0 << ", rop_control >> 5))\n"
" {\n"
" discard;\n"
" }\n";
if (!_32_bit_exports)
@ -415,7 +420,9 @@ namespace glsl
static void insert_glsl_legacy_function(std::ostream& OS, glsl::program_domain domain, bool require_lit_emulation, bool require_depth_conversion = false, bool require_wpos = false, bool require_texture_ops = true)
{
OS << "#define _select mix\n\n";
OS << "#define _select mix\n";
OS << "#define _saturate(x) clamp(x, 0., 1.)\n";
OS << "#define _rand(seed) fract(sin(dot(seed.xy, vec2(12.9898f, 78.233f))) * 43758.5453f)\n\n";
if (require_lit_emulation)
{
@ -456,6 +463,23 @@ namespace glsl
program_common::insert_compare_op(OS);
// NOTES:
// Lowers alpha accuracy down to 2 bits, to mimic A2C banding
// Alpha lower than the real threshold (e.g 0.25 for 4 samples) gets a randomized chance to make it to the lowest transparency state
// Helps to avoid A2C tested foliage disappearing in the distance
OS <<
"bool coverage_test_passes(inout vec4 _sample, uint control)\n"
"{\n"
" if ((control & 0x1) == 0) return false;\n"
"\n"
" float samples = ((control & 0x2) != 0)? 4.f : 2.f;\n"
" float hash = _saturate(_rand(gl_FragCoord) + 0.5f) * 0.9f;\n"
" float epsilon = hash / samples;\n"
" float alpha = trunc((_sample.a + epsilon) * samples) / samples;\n"
" //_sample.a = min(_sample.a, alpha);\n" // Cannot blend A2C samples naively as they are order independent! Causes background bleeding
" return (alpha > 0.f);\n"
"}\n\n";
if (require_depth_conversion)
{
//NOTE: Memory layout is fetched as byteswapped BGRA [GBAR] (GOW collection, DS2, DeS)

View File

@ -1499,38 +1499,18 @@ void GLGSRender::update_draw_state()
rsx::method_registers.blend_enabled_surface_3()
};
bool blend_equation_override = false;
if (rsx::method_registers.msaa_alpha_to_coverage_enabled() &&
!rsx::method_registers.alpha_test_enabled())
{
if (rsx::method_registers.msaa_enabled() &&
rsx::method_registers.msaa_sample_mask() &&
rsx::method_registers.surface_antialias() != rsx::surface_antialiasing::center_1_sample)
{
//fake alpha-to-coverage
//blend used in conjunction with alpha test to fake order-independent edge transparency
mrt_blend_enabled[0] = mrt_blend_enabled[1] = mrt_blend_enabled[2] = mrt_blend_enabled[3] = true;
blend_equation_override = true;
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
}
}
if (mrt_blend_enabled[0] || mrt_blend_enabled[1] || mrt_blend_enabled[2] || mrt_blend_enabled[3])
{
if (!blend_equation_override)
{
glBlendFuncSeparate(blend_factor(rsx::method_registers.blend_func_sfactor_rgb()),
blend_factor(rsx::method_registers.blend_func_dfactor_rgb()),
blend_factor(rsx::method_registers.blend_func_sfactor_a()),
blend_factor(rsx::method_registers.blend_func_dfactor_a()));
glBlendFuncSeparate(blend_factor(rsx::method_registers.blend_func_sfactor_rgb()),
blend_factor(rsx::method_registers.blend_func_dfactor_rgb()),
blend_factor(rsx::method_registers.blend_func_sfactor_a()),
blend_factor(rsx::method_registers.blend_func_dfactor_a()));
auto blend_colors = rsx::get_constant_blend_colors();
glBlendColor(blend_colors[0], blend_colors[1], blend_colors[2], blend_colors[3]);
auto blend_colors = rsx::get_constant_blend_colors();
glBlendColor(blend_colors[0], blend_colors[1], blend_colors[2], blend_colors[3]);
glBlendEquationSeparate(blend_equation(rsx::method_registers.blend_equation_rgb()),
blend_equation(rsx::method_registers.blend_equation_a()));
}
glBlendEquationSeparate(blend_equation(rsx::method_registers.blend_equation_rgb()),
blend_equation(rsx::method_registers.blend_equation_a()));
}
gl_state.enablei(mrt_blend_enabled[0], GL_BLEND, 0);

View File

@ -648,20 +648,21 @@ namespace rsx
//TODO: Properly support alpha-to-coverage and alpha-to-one behavior in shaders
auto fragment_alpha_func = rsx::method_registers.alpha_func();
auto alpha_ref = rsx::method_registers.alpha_ref() / 255.f;
auto rop_control = (u32)rsx::method_registers.alpha_test_enabled();
auto rop_control = rsx::method_registers.alpha_test_enabled()? 1u : 0u;
if (rsx::method_registers.msaa_alpha_to_coverage_enabled() && !rop_control)
if (rsx::method_registers.msaa_alpha_to_coverage_enabled() &&
rsx::method_registers.msaa_enabled() &&
rsx::method_registers.surface_antialias() != rsx::surface_antialiasing::center_1_sample)
{
if (rsx::method_registers.msaa_enabled() &&
rsx::method_registers.surface_antialias() != rsx::surface_antialiasing::center_1_sample)
{
//alpha values generate a coverage mask for order independent blending
//requires hardware AA to work properly (or just fragment sample stage in fragment shaders)
//simulated using combined alpha blend and alpha test
fragment_alpha_func = rsx::comparison_function::greater;
alpha_ref = rsx::method_registers.msaa_sample_mask()? 0.25f : 0.f;
rop_control |= (1 << 4);
}
// Alpha values generate a coverage mask for order independent blending
// Requires hardware AA to work properly (or just fragment sample stage in fragment shaders)
// Simulated using combined alpha blend and alpha test
const u32 mask_bit = rsx::method_registers.msaa_sample_mask() ? 1u : 0u;
const u32 samples_bit = rsx::method_registers.surface_antialias() != rsx::surface_antialiasing::diagonal_centered_2_samples ? 1u : 0u;
rop_control |= (1u << 4); // CSAA enable bit
rop_control |= (mask_bit << 5); // MSAA mask enable bit
rop_control |= (samples_bit << 6); // Sample configuration bit
}
const f32 fog0 = rsx::method_registers.fog_params_0();
@ -681,7 +682,7 @@ namespace rsx
case rsx::surface_color_format::x32:
break;
default:
rop_control |= 0x2;
rop_control |= (1u << 1);
break;
}
}

View File

@ -2518,38 +2518,17 @@ bool VKGSRender::load_program()
rsx::method_registers.blend_enabled_surface_3()
};
bool blend_equation_override = false;
VkBlendFactor sfactor_rgb, sfactor_a, dfactor_rgb, dfactor_a;
VkBlendOp equation_rgb, equation_a;
if (rsx::method_registers.msaa_alpha_to_coverage_enabled() &&
!rsx::method_registers.alpha_test_enabled())
{
if (rsx::method_registers.msaa_enabled() &&
rsx::method_registers.msaa_sample_mask() &&
rsx::method_registers.surface_antialias() != rsx::surface_antialiasing::center_1_sample)
{
//fake alpha-to-coverage
//blend used in conjunction with alpha test to fake order-independent edge transparency
mrt_blend_enabled[0] = mrt_blend_enabled[1] = mrt_blend_enabled[2] = mrt_blend_enabled[3] = true;
blend_equation_override = true;
sfactor_rgb = sfactor_a = VK_BLEND_FACTOR_SRC_ALPHA;
dfactor_rgb = dfactor_a = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
equation_rgb = equation_a = VK_BLEND_OP_ADD;
}
}
if (mrt_blend_enabled[0] || mrt_blend_enabled[1] || mrt_blend_enabled[2] || mrt_blend_enabled[3])
{
if (!blend_equation_override)
{
sfactor_rgb = vk::get_blend_factor(rsx::method_registers.blend_func_sfactor_rgb());
sfactor_a = vk::get_blend_factor(rsx::method_registers.blend_func_sfactor_a());
dfactor_rgb = vk::get_blend_factor(rsx::method_registers.blend_func_dfactor_rgb());
dfactor_a = vk::get_blend_factor(rsx::method_registers.blend_func_dfactor_a());
equation_rgb = vk::get_blend_op(rsx::method_registers.blend_equation_rgb());
equation_a = vk::get_blend_op(rsx::method_registers.blend_equation_a());
}
sfactor_rgb = vk::get_blend_factor(rsx::method_registers.blend_func_sfactor_rgb());
sfactor_a = vk::get_blend_factor(rsx::method_registers.blend_func_sfactor_a());
dfactor_rgb = vk::get_blend_factor(rsx::method_registers.blend_func_dfactor_rgb());
dfactor_a = vk::get_blend_factor(rsx::method_registers.blend_func_dfactor_a());
equation_rgb = vk::get_blend_op(rsx::method_registers.blend_equation_rgb());
equation_a = vk::get_blend_op(rsx::method_registers.blend_equation_a());
for (u8 idx = 0; idx < m_draw_buffers.size(); ++idx)
{