gl: Implement MSAA transparency (sample-to-coverage)

This commit is contained in:
kd-11 2025-02-09 21:15:23 +03:00
parent 5c1552f797
commit a69d0a23d4
8 changed files with 85 additions and 10 deletions

View file

@ -667,7 +667,23 @@ namespace rsx
rop_control.enable_polygon_stipple();
}
if (REGS(m_ctx)->msaa_alpha_to_coverage_enabled() && !RSX(m_ctx)->get_backend_config().supports_hw_a2c)
auto can_use_hw_a2c = [&]() -> bool
{
const auto& config = RSX(m_ctx)->get_backend_config();
if (!config.supports_hw_a2c)
{
return false;
}
if (config.supports_hw_a2c_1spp)
{
return true;
}
return REGS(m_ctx)->surface_antialias() != rsx::surface_antialiasing::center_1_sample;
};
if (REGS(m_ctx)->msaa_alpha_to_coverage_enabled() && !can_use_hw_a2c())
{
// TODO: Properly support alpha-to-coverage and alpha-to-one behavior in shaders
// Alpha values generate a coverage mask for order independent blending

View file

@ -3,6 +3,8 @@
#include "../rsx_methods.h"
#include "../Common/BufferUtils.h"
#include "Emu/RSX/NV47/HW/context_accessors.define.h"
namespace gl
{
GLenum comparison_op(rsx::comparison_function op)
@ -256,6 +258,32 @@ void GLGSRender::update_draw_state()
gl_state.enablei(mrt_blend_enabled[2], GL_BLEND, 2);
gl_state.enablei(mrt_blend_enabled[3], GL_BLEND, 3);
}
// Antialias control
if (backend_config.supports_hw_msaa)
{
gl_state.enable(/*REGS(m_ctx)->msaa_enabled()*/GL_MULTISAMPLE);
gl_state.enable(GL_SAMPLE_MASK);
gl_state.sample_mask(REGS(m_ctx)->msaa_sample_mask());
gl_state.enable(GL_SAMPLE_SHADING);
gl_state.min_sample_shading_rate(1.f);
gl_state.enable(GL_SAMPLE_COVERAGE);
gl_state.sample_coverage(1.f);
}
if (backend_config.supports_hw_a2c)
{
const bool hw_enable = backend_config.supports_hw_a2c_1spp || REGS(m_ctx)->surface_antialias() != rsx::surface_antialiasing::center_1_sample;
gl_state.enable(hw_enable && REGS(m_ctx)->msaa_alpha_to_coverage_enabled(), GL_SAMPLE_ALPHA_TO_COVERAGE);
}
if (backend_config.supports_hw_a2one)
{
gl_state.enable(REGS(m_ctx)->msaa_alpha_to_one_enabled(), GL_SAMPLE_ALPHA_TO_ONE);
}
}
switch (rsx::method_registers.current_draw_clause.primitive)
@ -307,12 +335,6 @@ void GLGSRender::update_draw_state()
// Clip planes
gl_state.clip_planes((current_vertex_program.output_mask >> CELL_GCM_ATTRIB_OUTPUT_UC0) & 0x3F);
// Sample control
// TODO: MinSampleShading
//gl_state.enable(rsx::method_registers.msaa_enabled(), GL_MULTISAMPLE);
//gl_state.enable(rsx::method_registers.msaa_alpha_to_coverage_enabled(), GL_SAMPLE_ALPHA_TO_COVERAGE);
//gl_state.enable(rsx::method_registers.msaa_alpha_to_one_enabled(), GL_SAMPLE_ALPHA_TO_ONE);
//TODO
//NV4097_SET_ANISO_SPREAD
//NV4097_SET_SPECULAR_ENABLE

View file

@ -5,6 +5,7 @@
#include "GLCommonDecompiler.h"
#include "../GCM.h"
#include "../Program/GLSLCommon.h"
#include "../RSXThread.h"
std::string GLFragmentDecompilerThread::getFloatTypeName(usz elementCount)
{
@ -218,7 +219,7 @@ void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
m_shader_props.require_srgb_to_linear = properties.has_upg;
m_shader_props.require_linear_to_srgb = properties.has_pkg;
m_shader_props.require_fog_read = properties.in_register_mask & in_fogc;
m_shader_props.emulate_coverage_tests = true; // g_cfg.video.antialiasing_level == msaa_level::none;
m_shader_props.emulate_coverage_tests = !rsx::get_renderer_backend_config().supports_hw_a2c_1spp;
m_shader_props.emulate_shadow_compare = device_props.emulate_depth_compare;
m_shader_props.low_precision_tests = ::gl::get_driver_caps().vendor_NVIDIA && !(m_prog.ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION);
m_shader_props.disable_early_discard = !::gl::get_driver_caps().vendor_NVIDIA;

View file

@ -47,8 +47,6 @@ GLGSRender::GLGSRender(utils::serial* ar) noexcept : GSRender(ar)
else
m_vertex_cache = std::make_unique<gl::weak_vertex_cache>();
backend_config.supports_hw_a2c = false;
backend_config.supports_hw_a2one = false;
backend_config.supports_multidraw = true;
backend_config.supports_normalized_barycentrics = true;
@ -56,6 +54,8 @@ GLGSRender::GLGSRender(utils::serial* ar) noexcept : GSRender(ar)
{
backend_config.supports_hw_msaa = true;
backend_config.supports_hw_a2c = true;
backend_config.supports_hw_a2c_1spp = false; // In OGL A2C is implicitly disabled at 1spp
backend_config.supports_hw_a2one = true;
}
}

View file

@ -262,6 +262,9 @@ OPENGL_PROC(PFNGLTEXSTORAGE3DPROC, TexStorage3D);
// ARB_texture_multisample
OPENGL_PROC(PFNGLTEXSTORAGE2DMULTISAMPLEPROC, TexStorage2DMultisample);
OPENGL_PROC(PFNGLTEXSTORAGE3DMULTISAMPLEPROC, TexStorage3DMultisample);
OPENGL_PROC(PFNGLSAMPLEMASKIPROC, SampleMaski);
OPENGL_PROC(PFNGLMINSAMPLESHADINGPROC, MinSampleShading);
OPENGL_PROC(PFNGLSAMPLECOVERAGEPROC, SampleCoverage);
// Texture_View
OPENGL_PROC(PFNGLTEXTUREVIEWPROC, TextureView);

View file

@ -309,6 +309,32 @@ namespace gl
}
}
void sample_mask(GLbitfield mask)
{
if (!test_and_set_property(GL_SAMPLE_MASK_VALUE, mask))
{
glSampleMaski(0, mask);
}
}
void sample_coverage(GLclampf coverage)
{
const u32 value = std::bit_cast<u32>(coverage);
if (!test_and_set_property(GL_SAMPLE_COVERAGE_VALUE, value))
{
glSampleCoverage(coverage, GL_FALSE);
}
}
void min_sample_shading_rate(GLclampf rate)
{
const u32 value = std::bit_cast<u32>(rate);
if (!test_and_set_property(GL_MIN_SAMPLE_SHADING_VALUE, value))
{
glMinSampleShading(rate);
}
}
void clip_planes(GLuint mask)
{
if (!test_and_set_property(CLIP_PLANES, mask))

View file

@ -87,6 +87,7 @@ namespace rsx
{
bool supports_multidraw; // Draw call batching
bool supports_hw_a2c; // Alpha to coverage
bool supports_hw_a2c_1spp; // Alpha to coverage at 1 sample per pixel
bool supports_hw_renormalization; // Should be true on NV hardware which matches PS3 texture renormalization behaviour
bool supports_hw_msaa; // MSAA support
bool supports_hw_a2one; // Alpha to one
@ -466,4 +467,9 @@ namespace rsx
{
return g_fxo->try_get<rsx::thread>();
}
inline const backend_configuration& get_renderer_backend_config()
{
return g_fxo->get<rsx::thread>().get_backend_config();
}
}

View file

@ -630,6 +630,7 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
{
backend_config.supports_hw_msaa = true;
backend_config.supports_hw_a2c = true;
backend_config.supports_hw_a2c_1spp = true;
backend_config.supports_hw_a2one = m_device->get_alpha_to_one_support();
}