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:
parent
10a17feda2
commit
6fdc0fd7f0
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user