Przeglądaj źródła

Implemented Alpha Testing

FernandoS27 7 lat temu
rodzic
commit
aa620c14af

+ 3 - 1
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;

+ 11 - 0
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -323,6 +323,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
         current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(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<u32>(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<s32> viewport_rect{regs.viewport_transform[0].GetRect()};

+ 2 - 0
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();
 

+ 12 - 0
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)};
 

+ 5 - 0
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,

+ 26 - 2
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<std::string> declr_predicates;
-}; // namespace Decompiler
+}; // namespace OpenGL::GLShader::Decompiler
 
 std::string GetCommonDeclarations() {
     return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n",