From 19038db4898bc059fe78d21ba9a400b5277dd2dd Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Sun, 4 Nov 2018 23:46:06 -0300 Subject: Add support to color mask to avoid issues in blending caused by wrong values in the alpha channel in some render targets. --- src/video_core/engines/maxwell_3d.h | 23 ++++++++++-- src/video_core/renderer_opengl/gl_rasterizer.cpp | 23 +++++++++--- src/video_core/renderer_opengl/gl_rasterizer.h | 3 ++ src/video_core/renderer_opengl/gl_state.cpp | 47 +++++++++++++++++------- src/video_core/renderer_opengl/gl_state.h | 8 ++-- 5 files changed, 79 insertions(+), 25 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 33eb57360..0509ba3a2 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -462,6 +462,16 @@ public: } }; + struct ColorMask { + union { + u32 raw; + BitField<0, 4, u32> R; + BitField<4, 4, u32> G; + BitField<8, 4, u32> B; + BitField<12, 4, u32> A; + }; + }; + bool IsShaderConfigEnabled(std::size_t index) const { // The VertexB is always enabled. if (index == static_cast(Regs::ShaderProgram::VertexB)) { @@ -571,7 +581,11 @@ public: u32 stencil_back_mask; u32 stencil_back_func_mask; - INSERT_PADDING_WORDS(0x13); + INSERT_PADDING_WORDS(0xC); + + u32 color_mask_common; + + INSERT_PADDING_WORDS(0x6); u32 rt_separate_frag_data; @@ -847,8 +861,9 @@ public: BitField<6, 4, u32> RT; BitField<10, 11, u32> layer; } clear_buffers; - - INSERT_PADDING_WORDS(0x4B); + INSERT_PADDING_WORDS(0xB); + std::array color_mask; + INSERT_PADDING_WORDS(0x38); struct { u32 query_address_high; @@ -1081,6 +1096,7 @@ ASSERT_REG_POSITION(scissor_test, 0x380); ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); +ASSERT_REG_POSITION(color_mask_common, 0x3E4); ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); ASSERT_REG_POSITION(zeta, 0x3F8); ASSERT_REG_POSITION(vertex_attrib_format, 0x458); @@ -1127,6 +1143,7 @@ ASSERT_REG_POSITION(instanced_arrays, 0x620); ASSERT_REG_POSITION(cull, 0x646); ASSERT_REG_POSITION(logic_op, 0x671); ASSERT_REG_POSITION(clear_buffers, 0x674); +ASSERT_REG_POSITION(color_mask, 0x680); ASSERT_REG_POSITION(query, 0x6C0); ASSERT_REG_POSITION(vertex_array[0], 0x700); ASSERT_REG_POSITION(independent_blend, 0x780); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 73770ff69..bb263b6aa 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -511,10 +511,10 @@ void RasterizerOpenGL::Clear() { OpenGLState clear_state; clear_state.draw.draw_framebuffer = framebuffer.handle; - clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; - clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; - clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; - clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || regs.clear_buffers.A) { @@ -573,7 +573,7 @@ void RasterizerOpenGL::DrawArrays() { ScopeAcquireGLContext acquire_context{emu_window}; ConfigureFramebuffers(); - + SyncColorMask(); SyncDepthTestState(); SyncStencilTestState(); SyncBlendState(); @@ -989,6 +989,18 @@ void RasterizerOpenGL::SyncStencilTestState() { state.stencil.back.write_mask = regs.stencil_back_mask; } +void RasterizerOpenGL::SyncColorMask() { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; + for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { + const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i]; + auto& dest = state.color_mask[i]; + dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE; + dest.green_enabled = (source.G == 0) ? GL_FALSE : GL_TRUE; + dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE; + dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE; + } +} + void RasterizerOpenGL::SyncBlendState() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; @@ -1000,6 +1012,7 @@ void RasterizerOpenGL::SyncBlendState() { state.independant_blend.enabled = regs.independent_blend_enable; if (!state.independant_blend.enabled) { auto& blend = state.blend[0]; + blend.enabled = regs.blend.enable[0] != 0; blend.separate_alpha = regs.blend.separate_alpha; blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb); blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 8ec22df8d..60e783803 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -169,6 +169,9 @@ private: /// Syncs the point state to match the guest state void SyncPointState(); + /// Syncs Color Mask + void SyncColorMask(); + /// Check asserts for alpha testing. void CheckAlphaTests(); diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 2e1f81e26..9517285e5 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -25,12 +25,12 @@ OpenGLState::OpenGLState() { primitive_restart.enabled = false; primitive_restart.index = 0; - - color_mask.red_enabled = GL_TRUE; - color_mask.green_enabled = GL_TRUE; - color_mask.blue_enabled = GL_TRUE; - color_mask.alpha_enabled = GL_TRUE; - + for (auto& item : color_mask) { + item.red_enabled = GL_TRUE; + item.green_enabled = GL_TRUE; + item.blue_enabled = GL_TRUE; + item.alpha_enabled = GL_TRUE; + } stencil.test_enabled = false; auto reset_stencil = [](auto& config) { config.test_func = GL_ALWAYS; @@ -135,6 +135,32 @@ void OpenGLState::ApplyCulling() const { } } +void OpenGLState::ApplyColorMask() const { + if (GLAD_GL_ARB_viewport_array) { + for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { + const auto& updated = color_mask[i]; + const auto& current = cur_state.color_mask[i]; + if (updated.red_enabled != current.red_enabled || + updated.green_enabled != current.green_enabled || + updated.blue_enabled != current.blue_enabled || + updated.alpha_enabled != current.alpha_enabled) { + glColorMaski(static_cast(i), updated.red_enabled, updated.green_enabled, + updated.blue_enabled, updated.alpha_enabled); + } + } + } else { + const auto& updated = color_mask[0]; + const auto& current = cur_state.color_mask[0]; + if (updated.red_enabled != current.red_enabled || + updated.green_enabled != current.green_enabled || + updated.blue_enabled != current.blue_enabled || + updated.alpha_enabled != current.alpha_enabled) { + glColorMask(updated.red_enabled, updated.green_enabled, updated.blue_enabled, + updated.alpha_enabled); + } + } +} + void OpenGLState::ApplyDepth() const { // Depth test const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled; @@ -444,18 +470,11 @@ void OpenGLState::Apply() const { } } } - // Color mask - if (color_mask.red_enabled != cur_state.color_mask.red_enabled || - color_mask.green_enabled != cur_state.color_mask.green_enabled || - color_mask.blue_enabled != cur_state.color_mask.blue_enabled || - color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) { - glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled, - color_mask.alpha_enabled); - } // Point if (point.size != cur_state.point.size) { glPointSize(point.size); } + ApplyColorMask(); ApplyViewport(); ApplyScissor(); ApplyStencilTest(); diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index a027ca33c..b8cf1f637 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -56,13 +56,14 @@ public: GLuint index; } primitive_restart; // GL_PRIMITIVE_RESTART - struct { + struct ColorMask { GLboolean red_enabled; GLboolean green_enabled; GLboolean blue_enabled; GLboolean alpha_enabled; - } color_mask; // GL_COLOR_WRITEMASK - + }; + std::array + color_mask; // GL_COLOR_WRITEMASK struct { bool test_enabled; // GL_STENCIL_TEST struct { @@ -198,6 +199,7 @@ private: static bool s_rgb_used; void ApplySRgb() const; void ApplyCulling() const; + void ApplyColorMask() const; void ApplyDepth() const; void ApplyPrimitiveRestart() const; void ApplyStencilTest() const; -- cgit v1.2.3