From b76df62c00c28244f2fdd657b809853907f0070f Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Tue, 21 May 2019 20:28:09 -0300 Subject: [PATCH] gl_rasterizer: Move alpha testing to the OpenGL pipeline Removes the alpha testing code from each fragment shader invocation. --- .../renderer_opengl/gl_rasterizer.cpp | 14 ++++++---- .../renderer_opengl/gl_rasterizer.h | 4 +-- .../renderer_opengl/gl_shader_decompiler.cpp | 20 +------------- .../renderer_opengl/gl_shader_gen.cpp | 27 ------------------- .../renderer_opengl/gl_shader_manager.cpp | 11 -------- .../renderer_opengl/gl_shader_manager.h | 8 +----- src/video_core/renderer_opengl/gl_state.cpp | 13 +++++++++ src/video_core/renderer_opengl/gl_state.h | 7 +++++ 8 files changed, 33 insertions(+), 71 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 5087d94063..ca410287a8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -663,13 +663,10 @@ void RasterizerOpenGL::DrawArrays() { SyncCullMode(); SyncPrimitiveRestart(); SyncScissorTest(state); - // Alpha Testing is synced on shaders. SyncTransformFeedback(); SyncPointState(); - CheckAlphaTests(); SyncPolygonOffset(); - // TODO(bunnei): Sync framebuffer_scale uniform here - // TODO(bunnei): Sync scissorbox uniform(s) here + SyncAlphaTest(); // Draw the vertex batch const bool is_indexed = accelerate_draw == AccelDraw::Indexed; @@ -1121,10 +1118,17 @@ void RasterizerOpenGL::SyncPolygonOffset() { state.polygon_offset.clamp = regs.polygon_offset_clamp; } -void RasterizerOpenGL::CheckAlphaTests() { +void RasterizerOpenGL::SyncAlphaTest() { const auto& regs = system.GPU().Maxwell3D().regs; UNIMPLEMENTED_IF_MSG(regs.alpha_test_enabled != 0 && regs.rt_control.count > 1, "Alpha Testing is enabled with more than one rendertarget"); + + state.alpha_test.enabled = regs.alpha_test_enabled; + if (!state.alpha_test.enabled) { + return; + } + state.alpha_test.func = MaxwellToGL::ComparisonOp(regs.alpha_test_func); + state.alpha_test.ref = regs.alpha_test_ref; } } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index f2643f26f8..2817f65c96 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -166,8 +166,8 @@ private: /// Syncs the polygon offsets void SyncPolygonOffset(); - /// Check asserts for alpha testing. - void CheckAlphaTests(); + /// Syncs the alpha test state to match the guest state + void SyncAlphaTest(); /// Check for extension that are not strictly required /// but are needed for correct emulation diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e9f8d40dbb..ab75bb795e 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -1447,27 +1447,9 @@ private: UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented"); - code.AddLine("if (alpha_test[0] != 0) {{"); - ++code.scope; - // We start on the register containing the alpha value in the first RT. - u32 current_reg = 3; - for (u32 render_target = 0; render_target < Maxwell::NumRenderTargets; ++render_target) { - // TODO(Blinkhawk): verify the behavior of alpha testing on hardware when - // multiple render targets are used. - if (header.ps.IsColorComponentOutputEnabled(render_target, 0) || - header.ps.IsColorComponentOutputEnabled(render_target, 1) || - header.ps.IsColorComponentOutputEnabled(render_target, 2) || - header.ps.IsColorComponentOutputEnabled(render_target, 3)) { - code.AddLine("if (!AlphaFunc({})) discard;", SafeGetRegister(current_reg)); - current_reg += 4; - } - } - --code.scope; - code.AddLine("}}"); - // Write the color outputs using the data in the shader registers, disabled // rendertargets/components are skipped in the register assignment. - current_reg = 0; + u32 current_reg = 0; for (u32 render_target = 0; render_target < Maxwell::NumRenderTargets; ++render_target) { // TODO(Subv): Figure out how dual-source blending is configured in the Switch. for (u32 component = 0; component < 4; ++component) { diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index d2bb705a9f..269dda1222 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -28,7 +28,6 @@ layout (location = 0) out vec4 position; layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { vec4 viewport_flip; uvec4 config_pack; // instance_id, flip_stage, y_direction, padding - uvec4 alpha_test; }; )"; @@ -91,7 +90,6 @@ layout (location = 0) out vec4 position; layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { vec4 viewport_flip; uvec4 config_pack; // instance_id, flip_stage, y_direction, padding - uvec4 alpha_test; }; )"; @@ -129,33 +127,8 @@ layout (location = 0) in noperspective vec4 position; layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { vec4 viewport_flip; uvec4 config_pack; // instance_id, flip_stage, y_direction, padding - uvec4 alpha_test; }; -bool AlphaFunc(in float value) { - float ref = uintBitsToFloat(alpha_test[2]); - switch (alpha_test[1]) { - case 1: - return false; - case 2: - return value < ref; - case 3: - return value == ref; - case 4: - return value <= ref; - case 5: - return value > ref; - case 6: - return value != ref; - case 7: - return value >= ref; - case 8: - return true; - default: - return false; - } -} - )"; const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); ProgramResult program = diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 05ab01dcbc..b05f90f20d 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -48,17 +48,6 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell, std::size_t shade viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f; viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f; - auto func{static_cast(regs.alpha_test_func)}; - // Normalize the gl variants of opCompare to be the same as the normal variants - const u32 op_gl_variant_base = static_cast(Maxwell3D::Regs::ComparisonOp::Never); - if (func >= op_gl_variant_base) { - func = func - op_gl_variant_base + 1U; - } - - alpha_test.enabled = regs.alpha_test_enabled; - alpha_test.func = func; - alpha_test.ref = regs.alpha_test_ref; - instance_id = state.current_instance; // Assign in which stage the position has to be flipped diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index cec18a8321..6961e702a2 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -27,14 +27,8 @@ struct MaxwellUniformData { GLuint flip_stage; GLfloat y_direction; }; - struct alignas(16) { - GLuint enabled; - GLuint func; - GLfloat ref; - GLuint padding; - } alpha_test; }; -static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect"); +static_assert(sizeof(MaxwellUniformData) == 32, "MaxwellUniformData structure size is incorrect"); static_assert(sizeof(MaxwellUniformData) < 16384, "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 7425fbe5dd..d86e137ac1 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -156,6 +156,10 @@ OpenGLState::OpenGLState() { polygon_offset.factor = 0.0f; polygon_offset.units = 0.0f; polygon_offset.clamp = 0.0f; + + alpha_test.enabled = false; + alpha_test.func = GL_ALWAYS; + alpha_test.ref = 0.0f; } void OpenGLState::ApplyDefaultState() { @@ -461,6 +465,14 @@ void OpenGLState::ApplyPolygonOffset() const { } } +void OpenGLState::ApplyAlphaTest() const { + Enable(GL_ALPHA_TEST, cur_state.alpha_test.enabled, alpha_test.enabled); + if (UpdateTie(std::tie(cur_state.alpha_test.func, cur_state.alpha_test.ref), + std::tie(alpha_test.func, alpha_test.ref))) { + glAlphaFunc(alpha_test.func, alpha_test.ref); + } +} + void OpenGLState::ApplyTextures() const { bool has_delta{}; std::size_t first{}; @@ -533,6 +545,7 @@ void OpenGLState::Apply() const { ApplyTextures(); ApplySamplers(); ApplyPolygonOffset(); + ApplyAlphaTest(); } void OpenGLState::EmulateViewportWithScissor() { diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 41418a7b84..b0140495df 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -172,6 +172,12 @@ public: GLfloat clamp; } polygon_offset; + struct { + bool enabled; // GL_ALPHA_TEST + GLenum func; // GL_ALPHA_TEST_FUNC + GLfloat ref; // GL_ALPHA_TEST_REF + } alpha_test; + std::array clip_distance; // GL_CLIP_DISTANCE OpenGLState(); @@ -215,6 +221,7 @@ public: void ApplySamplers() const; void ApplyDepthClamp() const; void ApplyPolygonOffset() const; + void ApplyAlphaTest() const; /// Set the initial OpenGL state static void ApplyDefaultState();