From aa620c14af0a9bc2bf7784ed096298fc3c8899c3 Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Mon, 8 Oct 2018 23:34:11 -0400 Subject: [PATCH 1/6] Implemented Alpha Testing --- src/video_core/engines/maxwell_3d.h | 4 ++- .../renderer_opengl/gl_rasterizer.cpp | 11 ++++++++ .../renderer_opengl/gl_rasterizer.h | 2 ++ .../renderer_opengl/gl_shader_cache.cpp | 12 ++++++++ .../renderer_opengl/gl_shader_cache.h | 5 ++++ .../renderer_opengl/gl_shader_decompiler.cpp | 28 +++++++++++++++++-- 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index c8af1c6b67..0e09a7ee55 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -643,8 +643,10 @@ public: u32 d3d_cull_mode; ComparisonOp depth_test_func; + float alpha_test_ref; + ComparisonOp alpha_test_func; - INSERT_PADDING_WORDS(0xB); + INSERT_PADDING_WORDS(0x9); struct { u32 separate_alpha; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 3daccf82f0..e2a4220525 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -323,6 +323,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { current_texture_bindpoint = SetupTextures(static_cast(stage), shader, primitive_mode, current_texture_bindpoint); + SetupAlphaTesting(shader); + // When VertexA is enabled, we have dual vertex shaders if (program == Maxwell::ShaderProgram::VertexA) { // VertexB was combined with VertexA, so we skip the VertexB iteration @@ -880,6 +882,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, return current_unit + static_cast(entries.size()); } +void RasterizerOpenGL::SetupAlphaTesting(Shader& shader) { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; + + glProgramUniform1i(shader->GetProgramHandle(), shader->GetAlphaTestingEnableLocation(), + regs.alpha_test_enabled); + glProgramUniform1f(shader->GetProgramHandle(), shader->GetAlphaTestingRefLocation(), + regs.alpha_test_ref); +} + void RasterizerOpenGL::SyncViewport() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; const MathUtil::Rectangle viewport_rect{regs.viewport_transform[0].GetRect()}; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index b1f7ccc7e7..06ba23f48a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -132,6 +132,8 @@ private: u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, GLenum primitive_mode, u32 current_unit); + void SetupAlphaTesting(Shader& shader); + /// Syncs the viewport to match the guest state void SyncViewport(); diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 1a03a677f9..f4e99e5f46 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -134,6 +134,18 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, return target_program.handle; }; +GLint CachedShader::GetAlphaTestingEnableLocation() { + return glGetUniformLocation(program.handle, "alpha_testing_enable"); +} + +GLint CachedShader::GetAlphaTestingFuncLocation() { + return glGetUniformLocation(program.handle, "alpha_testing_func"); +} + +GLint CachedShader::GetAlphaTestingRefLocation() { + return glGetUniformLocation(program.handle, "alpha_testing_ref"); +} + Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { const VAddr program_addr{GetShaderAddress(program)}; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index a210f1731d..9333f423fe 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -73,6 +73,11 @@ public: /// Gets the GL uniform location for the specified resource, caching as needed GLint GetUniformLocation(const GLShader::SamplerEntry& sampler); + + GLint GetAlphaTestingEnableLocation(); + GLint GetAlphaTestingFuncLocation(); + GLint GetAlphaTestingRefLocation(); + private: /// Generates a geometry shader or returns one that already exists. GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology, diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index b0eb879cc7..e890cfe576 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -643,6 +643,13 @@ private: ';'); } declarations.AddNewLine(); + + if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { + declarations.AddLine("uniform bool alpha_testing_active;"); + declarations.AddLine("uniform float alpha_testing_ref;"); + declarations.AddLine("uniform uint alpha_testing_func;"); + } + declarations.AddNewLine(); } /// Generates declarations used for geometry shaders. @@ -1264,9 +1271,26 @@ private: ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented"); + shader.AddLine("if (alpha_testing_active) {"); + ++shader.scope; + u32 current_reg = 3; + for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets; + ++render_target) { + 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)) { + shader.AddLine(fmt::format("if ({} < alpha_testing_ref) discard;", + regs.GetRegisterAsFloat(current_reg))); + current_reg += 4; + } + } + --shader.scope; + shader.AddLine("}"); + // Write the color outputs using the data in the shader registers, disabled // rendertargets/components are skipped in the register assignment. - u32 current_reg = 0; + current_reg = 0; for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets; ++render_target) { // TODO(Subv): Figure out how dual-source blending is configured in the Switch. @@ -3497,7 +3521,7 @@ private: // Declarations std::set declr_predicates; -}; // namespace Decompiler +}; // namespace OpenGL::GLShader::Decompiler std::string GetCommonDeclarations() { return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n", From 7b39107e3ae056a857e1780b2123e757b8deab26 Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Wed, 10 Oct 2018 09:20:13 -0400 Subject: [PATCH 2/6] Added Alpha Func --- .../renderer_opengl/gl_rasterizer.cpp | 10 +++++- .../renderer_opengl/gl_shader_decompiler.cpp | 36 +++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e2a4220525..17860d4479 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -885,10 +885,18 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, void RasterizerOpenGL::SetupAlphaTesting(Shader& shader) { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - glProgramUniform1i(shader->GetProgramHandle(), shader->GetAlphaTestingEnableLocation(), + glProgramUniform1ui(shader->GetProgramHandle(), shader->GetAlphaTestingEnableLocation(), regs.alpha_test_enabled); glProgramUniform1f(shader->GetProgramHandle(), shader->GetAlphaTestingRefLocation(), regs.alpha_test_ref); + + u32 func = static_cast(regs.alpha_test_func); + // Normalize the gl variants of opCompare to be the same as the normal variants + if (func >= 0x200) { + func = func - 0x200 + 1U; + } + + glProgramUniform1ui(shader->GetProgramHandle(), shader->GetAlphaTestingFuncLocation(), func); } void RasterizerOpenGL::SyncViewport() { diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e890cfe576..cbf501cc72 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -1280,13 +1280,13 @@ private: header.ps.IsColorComponentOutputEnabled(render_target, 1) || header.ps.IsColorComponentOutputEnabled(render_target, 2) || header.ps.IsColorComponentOutputEnabled(render_target, 3)) { - shader.AddLine(fmt::format("if ({} < alpha_testing_ref) discard;", + shader.AddLine(fmt::format("if (AlphaFunc({}, alpha_testing_ref, alpha_testing_func)) discard;", regs.GetRegisterAsFloat(current_reg))); current_reg += 4; } } --shader.scope; - shader.AddLine("}"); + shader.AddLine('}'); // Write the color outputs using the data in the shader registers, disabled // rendertargets/components are skipped in the register assignment. @@ -3505,6 +3505,38 @@ private: declarations.AddLine("bool " + pred + " = false;"); } declarations.AddNewLine(); + GenerateFunctionDeclarations(); + } + + void GenerateFunctionDeclarations() { + if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { + declarations.AddLine("bool AlphaFunc(in float value, in float ref, in uint func) {"); + declarations.scope++; + declarations.AddLine("switch (func) {"); + declarations.scope++; + declarations.AddLine("case 1:"); + declarations.AddLine("return false;"); + declarations.AddLine("case 2:"); + declarations.AddLine("return value < ref;"); + declarations.AddLine("case 3:"); + declarations.AddLine("return value == ref;"); + declarations.AddLine("case 4:"); + declarations.AddLine("return value <= ref;"); + declarations.AddLine("case 5:"); + declarations.AddLine("return value > ref;"); + declarations.AddLine("case 6:"); + declarations.AddLine("return value != ref;"); + declarations.AddLine("case 7:"); + declarations.AddLine("return value >= ref;"); + declarations.AddLine("case 8:"); + declarations.AddLine("return true;"); + declarations.AddLine("default:"); + declarations.AddLine("return false;"); + declarations.scope--; + declarations.AddLine('}'); + declarations.scope--; + declarations.AddLine('}'); + } } private: From bcb5b924fd10183fb8fdbbbbe3ba909f8b9fc346 Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Wed, 10 Oct 2018 09:45:22 -0400 Subject: [PATCH 3/6] Remove SyncAlphaTest and clang format --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 7 +++++-- src/video_core/renderer_opengl/gl_rasterizer.h | 4 +--- src/video_core/renderer_opengl/gl_shader_cache.h | 1 - src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 5 +++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 17860d4479..e5fc6e8f54 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -572,8 +572,8 @@ void RasterizerOpenGL::DrawArrays() { SyncBlendState(); SyncLogicOpState(); SyncCullMode(); - SyncAlphaTest(); SyncScissorTest(); + // Alpha Testing is synced on shaders. SyncTransformFeedback(); SyncPointState(); @@ -886,7 +886,7 @@ void RasterizerOpenGL::SetupAlphaTesting(Shader& shader) { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; glProgramUniform1ui(shader->GetProgramHandle(), shader->GetAlphaTestingEnableLocation(), - regs.alpha_test_enabled); + regs.alpha_test_enabled); glProgramUniform1f(shader->GetProgramHandle(), shader->GetAlphaTestingRefLocation(), regs.alpha_test_ref); @@ -1026,6 +1026,7 @@ void RasterizerOpenGL::SyncLogicOpState() { state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); } +<<<<<<< HEAD void RasterizerOpenGL::SyncAlphaTest() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; @@ -1053,6 +1054,8 @@ void RasterizerOpenGL::SyncScissorTest() { } } +======= +>>>>>>> Remove SyncAlphaTest and clang format void RasterizerOpenGL::SyncTransformFeedback() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 06ba23f48a..32a30e1b6a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -132,6 +132,7 @@ private: u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, GLenum primitive_mode, u32 current_unit); + /// Syncs the alpha test state to match the guest state void SetupAlphaTesting(Shader& shader); /// Syncs the viewport to match the guest state @@ -164,9 +165,6 @@ private: /// Syncs the LogicOp state to match the guest state void SyncLogicOpState(); - /// Syncs the alpha test state to match the guest state - void SyncAlphaTest(); - /// Syncs the scissor test state to match the guest state void SyncScissorTest(); diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 9333f423fe..2eaa638046 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -73,7 +73,6 @@ public: /// Gets the GL uniform location for the specified resource, caching as needed GLint GetUniformLocation(const GLShader::SamplerEntry& sampler); - GLint GetAlphaTestingEnableLocation(); GLint GetAlphaTestingFuncLocation(); GLint GetAlphaTestingRefLocation(); diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index cbf501cc72..7bd4d2d95c 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -1280,8 +1280,9 @@ private: header.ps.IsColorComponentOutputEnabled(render_target, 1) || header.ps.IsColorComponentOutputEnabled(render_target, 2) || header.ps.IsColorComponentOutputEnabled(render_target, 3)) { - shader.AddLine(fmt::format("if (AlphaFunc({}, alpha_testing_ref, alpha_testing_func)) discard;", - regs.GetRegisterAsFloat(current_reg))); + shader.AddLine(fmt::format( + "if (AlphaFunc({}, alpha_testing_ref, alpha_testing_func)) discard;", + regs.GetRegisterAsFloat(current_reg))); current_reg += 4; } } From 17315cee16df0848ed095ba3bc3fc1460465a682 Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Wed, 10 Oct 2018 15:06:32 -0400 Subject: [PATCH 4/6] Cache uniform locations and restructure the implementation --- .../renderer_opengl/gl_rasterizer.cpp | 26 +++---------------- .../renderer_opengl/gl_shader_cache.cpp | 24 +++++++++++------ .../renderer_opengl/gl_shader_cache.h | 12 ++++++--- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e5fc6e8f54..0f8227f7bf 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -885,18 +885,14 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, void RasterizerOpenGL::SetupAlphaTesting(Shader& shader) { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - glProgramUniform1ui(shader->GetProgramHandle(), shader->GetAlphaTestingEnableLocation(), - regs.alpha_test_enabled); - glProgramUniform1f(shader->GetProgramHandle(), shader->GetAlphaTestingRefLocation(), - regs.alpha_test_ref); - u32 func = static_cast(regs.alpha_test_func); // Normalize the gl variants of opCompare to be the same as the normal variants - if (func >= 0x200) { - func = func - 0x200 + 1U; + u32 op = static_cast(Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never); + if (func >= op) { + func = func - op + 1U; } - glProgramUniform1ui(shader->GetProgramHandle(), shader->GetAlphaTestingFuncLocation(), func); + shader->SetAlphaTesting(regs.alpha_test_enabled == 1, regs.alpha_test_ref, func); } void RasterizerOpenGL::SyncViewport() { @@ -1026,18 +1022,6 @@ void RasterizerOpenGL::SyncLogicOpState() { state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); } -<<<<<<< HEAD -void RasterizerOpenGL::SyncAlphaTest() { - const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - - // TODO(Rodrigo): Alpha testing is a legacy OpenGL feature, but it can be - // implemented with a test+discard in fragment shaders. - if (regs.alpha_test_enabled != 0) { - LOG_CRITICAL(Render_OpenGL, "Alpha testing is not implemented"); - UNREACHABLE(); - } -} - void RasterizerOpenGL::SyncScissorTest() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; @@ -1054,8 +1038,6 @@ void RasterizerOpenGL::SyncScissorTest() { } } -======= ->>>>>>> Remove SyncAlphaTest and clang format void RasterizerOpenGL::SyncTransformFeedback() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index f4e99e5f46..ccb8b4805f 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -94,6 +94,10 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type) // Store shader's code to lazily build it on draw geometry_programs.code = program_result.first; } + + if (program_type == Maxwell::ShaderProgram::Fragment) { + SaveAlphaTestingLocations(); + } } GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) { @@ -134,16 +138,20 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, return target_program.handle; }; -GLint CachedShader::GetAlphaTestingEnableLocation() { - return glGetUniformLocation(program.handle, "alpha_testing_enable"); +void CachedShader::SetAlphaTesting(const bool enable, const float ref, const u32 func) { + if (program_type == Maxwell::ShaderProgram::Fragment) { + glProgramUniform1ui(program.handle, alpha_test.enable_loc, + (enable ? 1 : 0)); + glProgramUniform1f(program.handle, alpha_test.ref_loc, + ref); + glProgramUniform1ui(program.handle, alpha_test.func_loc, func); + } } -GLint CachedShader::GetAlphaTestingFuncLocation() { - return glGetUniformLocation(program.handle, "alpha_testing_func"); -} - -GLint CachedShader::GetAlphaTestingRefLocation() { - return glGetUniformLocation(program.handle, "alpha_testing_ref"); +void CachedShader::SaveAlphaTestingLocations() { + alpha_test.enable_loc = glGetUniformLocation(program.handle, "alpha_testing_enable"); + alpha_test.ref_loc = glGetUniformLocation(program.handle, "alpha_testing_ref"); + alpha_test.func_loc = glGetUniformLocation(program.handle, "alpha_testing_func"); } Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 2eaa638046..7c80ee86b5 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -73,15 +73,15 @@ public: /// Gets the GL uniform location for the specified resource, caching as needed GLint GetUniformLocation(const GLShader::SamplerEntry& sampler); - GLint GetAlphaTestingEnableLocation(); - GLint GetAlphaTestingFuncLocation(); - GLint GetAlphaTestingRefLocation(); + void SetAlphaTesting(const bool enable, const float ref, const u32 func); private: /// Generates a geometry shader or returns one that already exists. GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology, const std::string& debug_name); + void SaveAlphaTestingLocations(); + VAddr addr; Maxwell::ShaderProgram program_type; GLShader::ShaderSetup setup; @@ -102,6 +102,12 @@ private: OGLProgram triangles_adjacency; } geometry_programs; + struct { + GLint enable_loc; + GLint ref_loc; + GLint func_loc; + } alpha_test; + std::map resource_cache; std::map uniform_cache; }; From 59a004f915e84fec4a4fed125661eb486e1de198 Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Wed, 10 Oct 2018 16:34:15 -0400 Subject: [PATCH 5/6] Use standard UBO and fix/stylize the code --- .../renderer_opengl/gl_rasterizer.cpp | 15 ------ .../renderer_opengl/gl_rasterizer.h | 3 -- .../renderer_opengl/gl_shader_cache.cpp | 20 -------- .../renderer_opengl/gl_shader_cache.h | 10 ---- .../renderer_opengl/gl_shader_decompiler.cpp | 46 ++----------------- .../renderer_opengl/gl_shader_gen.cpp | 29 +++++++++++- .../renderer_opengl/gl_shader_manager.cpp | 11 +++++ .../renderer_opengl/gl_shader_manager.h | 8 +++- 8 files changed, 51 insertions(+), 91 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 0f8227f7bf..d936818138 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -323,8 +323,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { current_texture_bindpoint = SetupTextures(static_cast(stage), shader, primitive_mode, current_texture_bindpoint); - SetupAlphaTesting(shader); - // When VertexA is enabled, we have dual vertex shaders if (program == Maxwell::ShaderProgram::VertexA) { // VertexB was combined with VertexA, so we skip the VertexB iteration @@ -882,19 +880,6 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, return current_unit + static_cast(entries.size()); } -void RasterizerOpenGL::SetupAlphaTesting(Shader& shader) { - const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - - u32 func = static_cast(regs.alpha_test_func); - // Normalize the gl variants of opCompare to be the same as the normal variants - u32 op = static_cast(Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never); - if (func >= op) { - func = func - op + 1U; - } - - shader->SetAlphaTesting(regs.alpha_test_enabled == 1, regs.alpha_test_ref, func); -} - void RasterizerOpenGL::SyncViewport() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; const MathUtil::Rectangle viewport_rect{regs.viewport_transform[0].GetRect()}; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 32a30e1b6a..ece5cb2c44 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -132,9 +132,6 @@ private: u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, GLenum primitive_mode, u32 current_unit); - /// Syncs the alpha test state to match the guest state - void SetupAlphaTesting(Shader& shader); - /// Syncs the viewport to match the guest state void SyncViewport(); diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index ccb8b4805f..1a03a677f9 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -94,10 +94,6 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type) // Store shader's code to lazily build it on draw geometry_programs.code = program_result.first; } - - if (program_type == Maxwell::ShaderProgram::Fragment) { - SaveAlphaTestingLocations(); - } } GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) { @@ -138,22 +134,6 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, return target_program.handle; }; -void CachedShader::SetAlphaTesting(const bool enable, const float ref, const u32 func) { - if (program_type == Maxwell::ShaderProgram::Fragment) { - glProgramUniform1ui(program.handle, alpha_test.enable_loc, - (enable ? 1 : 0)); - glProgramUniform1f(program.handle, alpha_test.ref_loc, - ref); - glProgramUniform1ui(program.handle, alpha_test.func_loc, func); - } -} - -void CachedShader::SaveAlphaTestingLocations() { - alpha_test.enable_loc = glGetUniformLocation(program.handle, "alpha_testing_enable"); - alpha_test.ref_loc = glGetUniformLocation(program.handle, "alpha_testing_ref"); - alpha_test.func_loc = glGetUniformLocation(program.handle, "alpha_testing_func"); -} - Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { const VAddr program_addr{GetShaderAddress(program)}; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 7c80ee86b5..a210f1731d 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -73,15 +73,11 @@ public: /// Gets the GL uniform location for the specified resource, caching as needed GLint GetUniformLocation(const GLShader::SamplerEntry& sampler); - void SetAlphaTesting(const bool enable, const float ref, const u32 func); - private: /// Generates a geometry shader or returns one that already exists. GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology, const std::string& debug_name); - void SaveAlphaTestingLocations(); - VAddr addr; Maxwell::ShaderProgram program_type; GLShader::ShaderSetup setup; @@ -102,12 +98,6 @@ private: OGLProgram triangles_adjacency; } geometry_programs; - struct { - GLint enable_loc; - GLint ref_loc; - GLint func_loc; - } alpha_test; - std::map resource_cache; std::map uniform_cache; }; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 7bd4d2d95c..6fdfc742bf 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -643,13 +643,6 @@ private: ';'); } declarations.AddNewLine(); - - if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { - declarations.AddLine("uniform bool alpha_testing_active;"); - declarations.AddLine("uniform float alpha_testing_ref;"); - declarations.AddLine("uniform uint alpha_testing_func;"); - } - declarations.AddNewLine(); } /// Generates declarations used for geometry shaders. @@ -1271,17 +1264,20 @@ private: ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented"); - shader.AddLine("if (alpha_testing_active) {"); + shader.AddLine("if (alpha_test[0] != 0) {"); ++shader.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 < Maxwell3D::Regs::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)) { shader.AddLine(fmt::format( - "if (AlphaFunc({}, alpha_testing_ref, alpha_testing_func)) discard;", + "if (AlphaFunc({})) discard;", regs.GetRegisterAsFloat(current_reg))); current_reg += 4; } @@ -3506,38 +3502,6 @@ private: declarations.AddLine("bool " + pred + " = false;"); } declarations.AddNewLine(); - GenerateFunctionDeclarations(); - } - - void GenerateFunctionDeclarations() { - if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { - declarations.AddLine("bool AlphaFunc(in float value, in float ref, in uint func) {"); - declarations.scope++; - declarations.AddLine("switch (func) {"); - declarations.scope++; - declarations.AddLine("case 1:"); - declarations.AddLine("return false;"); - declarations.AddLine("case 2:"); - declarations.AddLine("return value < ref;"); - declarations.AddLine("case 3:"); - declarations.AddLine("return value == ref;"); - declarations.AddLine("case 4:"); - declarations.AddLine("return value <= ref;"); - declarations.AddLine("case 5:"); - declarations.AddLine("return value > ref;"); - declarations.AddLine("case 6:"); - declarations.AddLine("return value != ref;"); - declarations.AddLine("case 7:"); - declarations.AddLine("return value >= ref;"); - declarations.AddLine("case 8:"); - declarations.AddLine("return true;"); - declarations.AddLine("default:"); - declarations.AddLine("return false;"); - declarations.scope--; - declarations.AddLine('}'); - declarations.scope--; - declarations.AddLine('}'); - } } private: diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index ecbc9d8ed3..e883ffb1df 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -29,6 +29,7 @@ layout(std140) uniform vs_config { vec4 viewport_flip; uvec4 instance_id; uvec4 flip_stage; + uvec4 alpha_test; }; )"; @@ -105,6 +106,7 @@ layout (std140) uniform gs_config { vec4 viewport_flip; uvec4 instance_id; uvec4 flip_stage; + uvec4 alpha_test; }; void main() { @@ -142,8 +144,33 @@ layout (std140) uniform fs_config { vec4 viewport_flip; uvec4 instance_id; uvec4 flip_stage; + 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; + } +} + void main() { exec_fragment(); } @@ -152,4 +179,4 @@ void main() { out += program.first; return {out, program.second}; } -} // namespace OpenGL::GLShader \ No newline at end of file +} // namespace OpenGL::GLShader diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 010857ec62..8b8869ecbf 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -16,6 +16,17 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh 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; + u32 func = static_cast(regs.alpha_test_func); + // Normalize the gl variants of opCompare to be the same as the normal variants + u32 op_gl_variant_base = static_cast(Tegra::Engines::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; + // We only assign the instance to the first component of the vector, the rest is just padding. instance_id[0] = state.current_instance; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index b3a191cf2c..36fe1f04ce 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -22,8 +22,14 @@ struct MaxwellUniformData { alignas(16) GLvec4 viewport_flip; alignas(16) GLuvec4 instance_id; alignas(16) GLuvec4 flip_stage; + 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) == 64, "MaxwellUniformData structure size is incorrect"); static_assert(sizeof(MaxwellUniformData) < 16384, "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); From 8e1239fbc59325f5a9898329af869ae575ec983f Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Thu, 11 Oct 2018 20:29:11 -0400 Subject: [PATCH 6/6] Assert that multiple render targets are not set while alpha testing --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 12 ++++++++++++ src/video_core/renderer_opengl/gl_rasterizer.h | 3 +++ .../renderer_opengl/gl_shader_decompiler.cpp | 5 ++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d936818138..be51c5215f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -574,6 +574,7 @@ void RasterizerOpenGL::DrawArrays() { // Alpha Testing is synced on shaders. SyncTransformFeedback(); SyncPointState(); + CheckAlphaTests(); // TODO(bunnei): Sync framebuffer_scale uniform here // TODO(bunnei): Sync scissorbox uniform(s) here @@ -1041,4 +1042,15 @@ void RasterizerOpenGL::SyncPointState() { state.point.size = regs.point_size == 0 ? 1 : regs.point_size; } +void RasterizerOpenGL::CheckAlphaTests() { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; + + if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) { + LOG_CRITICAL( + Render_OpenGL, + "Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined."); + UNREACHABLE(); + } +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index ece5cb2c44..0e90a31f5e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -171,6 +171,9 @@ private: /// Syncs the point state to match the guest state void SyncPointState(); + /// Check asserts for alpha testing. + void CheckAlphaTests(); + bool has_ARB_direct_state_access = false; bool has_ARB_multi_bind = false; bool has_ARB_separate_shader_objects = false; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 6fdfc742bf..f224cb5b2c 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -1276,9 +1276,8 @@ private: header.ps.IsColorComponentOutputEnabled(render_target, 1) || header.ps.IsColorComponentOutputEnabled(render_target, 2) || header.ps.IsColorComponentOutputEnabled(render_target, 3)) { - shader.AddLine(fmt::format( - "if (AlphaFunc({})) discard;", - regs.GetRegisterAsFloat(current_reg))); + shader.AddLine(fmt::format("if (!AlphaFunc({})) discard;", + regs.GetRegisterAsFloat(current_reg))); current_reg += 4; } }