From 1881e86c434edfc17f78f68f07443bef1120cda1 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Tue, 13 Nov 2018 20:13:16 -0300 Subject: [PATCH 01/11] fix viewport and scissor behavior --- src/video_core/engines/maxwell_3d.cpp | 4 +- src/video_core/engines/maxwell_3d.h | 26 ++++--- .../renderer_opengl/gl_rasterizer.cpp | 33 ++++----- .../renderer_opengl/gl_shader_manager.h | 1 + src/video_core/renderer_opengl/gl_state.cpp | 67 ++++++++++++------- src/video_core/renderer_opengl/gl_state.h | 22 +++--- 6 files changed, 89 insertions(+), 64 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 6de07ea56d..58b598c7ff 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -34,8 +34,8 @@ void Maxwell3D::InitializeRegisterDefaults() { // Depth range near/far is not always set, but is expected to be the default 0.0f, 1.0f. This is // needed for ARMS. for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) { - regs.viewport[viewport].depth_range_near = 0.0f; - regs.viewport[viewport].depth_range_far = 1.0f; + regs.viewports[viewport].depth_range_near = 0.0f; + regs.viewports[viewport].depth_range_far = 1.0f; } // Doom and Bomberman seems to use the uninitialized registers and just enable blend // so initialize blend registers with sane values diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 91ca578830..32780fa9a7 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -505,9 +505,9 @@ public: INSERT_PADDING_WORDS(0x2E); - RenderTargetConfig rt[NumRenderTargets]; + std::array rt; - struct { + struct ViewportTransform { f32 scale_x; f32 scale_y; f32 scale_z; @@ -540,9 +540,11 @@ public: s32 GetHeight() const { return static_cast(translate_y + std::fabs(scale_y)) - GetY(); } - } viewport_transform[NumViewports]; + }; - struct { + std::array viewport_transform; + + struct ViewPort { union { BitField<0, 16, u32> x; BitField<16, 16, u32> width; @@ -553,7 +555,9 @@ public: }; float depth_range_near; float depth_range_far; - } viewport[NumViewports]; + }; + + std::array viewports; INSERT_PADDING_WORDS(0x1D); @@ -571,7 +575,7 @@ public: INSERT_PADDING_WORDS(0x17); - struct { + struct ScissorTest { u32 enable; union { BitField<0, 16, u32> min_x; @@ -581,9 +585,11 @@ public: BitField<0, 16, u32> min_y; BitField<16, 16, u32> max_y; }; - } scissor_test; + u32 fill; + }; + std::array scissor_test; - INSERT_PADDING_WORDS(0x52); + INSERT_PADDING_WORDS(0x15); s32 stencil_back_func_ref; u32 stencil_back_mask; @@ -1100,8 +1106,8 @@ private: ASSERT_REG_POSITION(macros, 0x45); ASSERT_REG_POSITION(tfb_enabled, 0x1D1); ASSERT_REG_POSITION(rt, 0x200); -ASSERT_REG_POSITION(viewport_transform[0], 0x280); -ASSERT_REG_POSITION(viewport, 0x300); +ASSERT_REG_POSITION(viewport_transform, 0x280); +ASSERT_REG_POSITION(viewports, 0x300); ASSERT_REG_POSITION(vertex_buffer, 0x35D); ASSERT_REG_POSITION(clear_color[0], 0x360); ASSERT_REG_POSITION(clear_depth, 0x364); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 54cc47a9bb..0bf434b45a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -642,7 +642,7 @@ void RasterizerOpenGL::DrawArrays() { params.DispatchDraw(); // Disable scissor test - state.scissor.enabled = false; + state.viewports[0].scissor.enabled = false; accelerate_draw = AccelDraw::Disabled; @@ -923,15 +923,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { + for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { const MathUtil::Rectangle viewport_rect{regs.viewport_transform[i].GetRect()}; auto& viewport = current_state.viewports[i]; viewport.x = viewport_rect.left; viewport.y = viewport_rect.bottom; viewport.width = static_cast(viewport_rect.GetWidth()); viewport.height = static_cast(viewport_rect.GetHeight()); - viewport.depth_range_far = regs.viewport[i].depth_range_far; - viewport.depth_range_near = regs.viewport[i].depth_range_near; + viewport.depth_range_far = regs.viewports[i].depth_range_far; + viewport.depth_range_near = regs.viewports[i].depth_range_near; } } @@ -1079,7 +1079,6 @@ void RasterizerOpenGL::SyncBlendState() { void RasterizerOpenGL::SyncLogicOpState() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - // TODO(Subv): Support more than just render target 0. state.logic_op.enabled = regs.logic_op.enable != 0; if (!state.logic_op.enabled) @@ -1092,19 +1091,21 @@ void RasterizerOpenGL::SyncLogicOpState() { } void RasterizerOpenGL::SyncScissorTest() { - // TODO: what is the correct behavior here, a single scissor for all targets - // or scissor disabled for the rest of the targets? const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - state.scissor.enabled = (regs.scissor_test.enable != 0); - if (regs.scissor_test.enable == 0) { - return; + for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { + const auto& src = regs.scissor_test[i]; + auto& dst = state.viewports[i].scissor; + dst.enabled = (src.enable != 0); + if (dst.enabled == 0) { + return; + } + const u32 width = src.max_x - src.min_x; + const u32 height = src.max_y - src.min_y; + dst.x = src.min_x; + dst.y = src.min_y; + dst.width = width; + dst.height = height; } - const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x; - const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y; - state.scissor.x = regs.scissor_test.min_x; - state.scissor.y = regs.scissor_test.min_y; - state.scissor.width = width; - state.scissor.height = height; } void RasterizerOpenGL::SyncTransformFeedback() { diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 2a069cdd81..9a5d7e2898 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -67,6 +67,7 @@ public: glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs); state.draw.shader_program = 0; state.draw.program_pipeline = pipeline.handle; + state.geometry_shaders.enabled = (gs != 0); } private: diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 98622a0580..dd6d946e58 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -14,6 +14,7 @@ OpenGLState OpenGLState::cur_state; bool OpenGLState::s_rgb_used; OpenGLState::OpenGLState() { // These all match default OpenGL values + geometry_shaders.enabled = false; framebuffer_srgb.enabled = false; cull.enabled = false; cull.mode = GL_BACK; @@ -50,12 +51,12 @@ OpenGLState::OpenGLState() { item.height = 0; item.depth_range_near = 0.0f; item.depth_range_far = 1.0f; + item.scissor.enabled = false; + item.scissor.x = 0; + item.scissor.y = 0; + item.scissor.width = 0; + item.scissor.height = 0; } - scissor.enabled = false; - scissor.x = 0; - scissor.y = 0; - scissor.width = 0; - scissor.height = 0; for (auto& item : blend) { item.enabled = true; item.rgb_equation = GL_FUNC_ADD; @@ -136,7 +137,7 @@ void OpenGLState::ApplyCulling() const { } void OpenGLState::ApplyColorMask() const { - if (GLAD_GL_ARB_viewport_array) { + if (GLAD_GL_ARB_viewport_array && independant_blend.enabled) { 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]; @@ -230,26 +231,10 @@ void OpenGLState::ApplyStencilTest() const { } } -void OpenGLState::ApplyScissor() const { - const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled; - if (scissor_changed) { - if (scissor.enabled) { - glEnable(GL_SCISSOR_TEST); - } else { - glDisable(GL_SCISSOR_TEST); - } - } - if (scissor.enabled && - (scissor_changed || scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y || - scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height)) { - glScissor(scissor.x, scissor.y, scissor.width, scissor.height); - } -} - void OpenGLState::ApplyViewport() const { - if (GLAD_GL_ARB_viewport_array) { - for (GLuint i = 0; - i < static_cast(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) { + if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) { + for (GLuint i = 0; i < static_cast(Tegra::Engines::Maxwell3D::Regs::NumViewports); + i++) { const auto& current = cur_state.viewports[i]; const auto& updated = viewports[i]; if (updated.x != current.x || updated.y != current.y || @@ -260,6 +245,22 @@ void OpenGLState::ApplyViewport() const { updated.depth_range_far != current.depth_range_far) { glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far); } + const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled; + if (scissor_changed) { + if (updated.scissor.enabled) { + glEnablei(GL_SCISSOR_TEST, i); + } else { + glDisablei(GL_SCISSOR_TEST, i); + } + } + if (updated.scissor.enabled && + (scissor_changed || updated.scissor.x != current.scissor.x || + updated.scissor.y != current.scissor.y || + updated.scissor.width != current.scissor.width || + updated.scissor.height != current.scissor.height)) { + glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width, + updated.scissor.height); + } } } else { const auto& current = cur_state.viewports[0]; @@ -273,6 +274,21 @@ void OpenGLState::ApplyViewport() const { updated.depth_range_far != current.depth_range_far) { glDepthRange(updated.depth_range_near, updated.depth_range_far); } + const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled; + if (scissor_changed) { + if (updated.scissor.enabled) { + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + } + } + if (updated.scissor.enabled && (scissor_changed || updated.scissor.x != current.scissor.x || + updated.scissor.y != current.scissor.y || + updated.scissor.width != current.scissor.width || + updated.scissor.height != current.scissor.height)) { + glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width, + updated.scissor.height); + } } } @@ -483,7 +499,6 @@ void OpenGLState::Apply() const { } ApplyColorMask(); ApplyViewport(); - ApplyScissor(); ApplyStencilTest(); ApplySRgb(); ApplyCulling(); diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index e5d1baae6e..da487461f0 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -39,6 +39,10 @@ public: bool enabled; // GL_FRAMEBUFFER_SRGB } framebuffer_srgb; + struct { + bool enabled; // viewports arrays are only supported when geometry shaders are enabled. + } geometry_shaders; + struct { bool enabled; // GL_CULL_FACE GLenum mode; // GL_CULL_FACE_MODE @@ -150,16 +154,15 @@ public: GLfloat height; GLfloat depth_range_near; // GL_DEPTH_RANGE GLfloat depth_range_far; // GL_DEPTH_RANGE + struct { + bool enabled; // GL_SCISSOR_TEST + GLint x; + GLint y; + GLsizei width; + GLsizei height; + } scissor; }; - std::array viewports; - - struct { - bool enabled; // GL_SCISSOR_TEST - GLint x; - GLint y; - GLsizei width; - GLsizei height; - } scissor; + std::array viewports; struct { float size; // GL_POINT_SIZE @@ -214,7 +217,6 @@ private: void ApplyLogicOp() const; void ApplyTextures() const; void ApplySamplers() const; - void ApplyScissor() const; }; } // namespace OpenGL From 6a2aa6dbdbe50abe8447db4e9d93dacecf39f269 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Tue, 13 Nov 2018 20:15:13 -0300 Subject: [PATCH 02/11] set default value for point size register --- src/video_core/engines/maxwell_3d.cpp | 3 +++ src/video_core/renderer_opengl/gl_rasterizer.cpp | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 58b598c7ff..a04e00ecb7 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -66,6 +66,9 @@ void Maxwell3D::InitializeRegisterDefaults() { regs.stencil_back_func_func = Regs::ComparisonOp::Always; regs.stencil_back_func_mask = 0xFFFFFFFF; regs.stencil_back_mask = 0xFFFFFFFF; + // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a + // register carrying a default value. Assume it's OpenGL's default (1). + regs.point_size = 1.0f; } void Maxwell3D::CallMacroMethod(u32 method, std::vector parameters) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 0bf434b45a..0e55bee11e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1119,11 +1119,7 @@ void RasterizerOpenGL::SyncTransformFeedback() { void RasterizerOpenGL::SyncPointState() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - - // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a - // register carrying a default value. For now, if the point size is zero, assume it's - // OpenGL's default (1). - state.point.size = regs.point_size == 0 ? 1 : regs.point_size; + state.point.size = regs.point_size; } void RasterizerOpenGL::CheckAlphaTests() { From 1d60bb65447686f8e6acd947bab8a23f05be033d Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Tue, 13 Nov 2018 21:23:23 -0300 Subject: [PATCH 03/11] set border color not depending on the wrap mode only enable color mask for the first framebuffer id independent blending is disabled --- .../renderer_opengl/gl_rasterizer.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 0e55bee11e..10d407bd29 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -777,15 +777,13 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTex MaxwellToGL::DepthCompareFunc(depth_compare_func)); } - if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border || - wrap_p == Tegra::Texture::WrapMode::Border) { - const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, - config.border_color_b, config.border_color_a}}; - if (border_color != new_border_color) { - border_color = new_border_color; - glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); - } + const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, + config.border_color_b, config.border_color_a}}; + if (border_color != new_border_color) { + border_color = new_border_color; + glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); } + if (info.tic.use_header_opt_control == 0) { if (GLAD_GL_ARB_texture_filter_anisotropic) { glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, @@ -1022,7 +1020,9 @@ void RasterizerOpenGL::SyncStencilTestState() { void RasterizerOpenGL::SyncColorMask() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { + size_t count = + regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1; + for (size_t i = 0; i < count; 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; From 02c22a3440cbb9d264a1d260a93601f5b893c64c Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Tue, 13 Nov 2018 21:26:29 -0300 Subject: [PATCH 04/11] add missing MirrorOnceBorder support where supported --- src/video_core/renderer_opengl/maxwell_to_gl.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 3ce2cc6d27..065b3929c1 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -180,6 +180,12 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { return GL_CLAMP_TO_BORDER; case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: return GL_MIRROR_CLAMP_TO_EDGE; + case Tegra::Texture::WrapMode::MirrorOnceBorder: + if (GL_EXT_texture_mirror_clamp) { + return GL_MIRROR_CLAMP_TO_BORDER_EXT; + } else { + return GL_MIRROR_CLAMP_TO_EDGE; + } } LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast(wrap_mode)); return GL_REPEAT; From 8ed7e1af2c8d859ca5e1bd05e199b1f14099c8b4 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Tue, 13 Nov 2018 22:09:01 -0300 Subject: [PATCH 05/11] add support for fragment_color_clamp --- src/video_core/engines/maxwell_3d.h | 5 ++++- src/video_core/renderer_opengl/gl_rasterizer.cpp | 6 ++++++ src/video_core/renderer_opengl/gl_rasterizer.h | 3 +++ src/video_core/renderer_opengl/gl_state.cpp | 7 +++++++ src/video_core/renderer_opengl/gl_state.h | 4 ++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 32780fa9a7..f2d69814ee 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -706,7 +706,9 @@ public: u32 stencil_front_func_mask; u32 stencil_front_mask; - INSERT_PADDING_WORDS(0x3); + INSERT_PADDING_WORDS(0x2); + + u32 frag_color_clamp; union { BitField<4, 1, u32> triangle_rast_flip; @@ -1142,6 +1144,7 @@ ASSERT_REG_POSITION(stencil_front_func_func, 0x4E4); ASSERT_REG_POSITION(stencil_front_func_ref, 0x4E5); ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6); ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); +ASSERT_REG_POSITION(frag_color_clamp, 0x4EA); ASSERT_REG_POSITION(screen_y_control, 0x4EB); ASSERT_REG_POSITION(vb_element_base, 0x50D); ASSERT_REG_POSITION(point_size, 0x546); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 10d407bd29..98799056c4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -582,6 +582,7 @@ void RasterizerOpenGL::DrawArrays() { ConfigureFramebuffers(state); SyncColorMask(); + SyncFragmentColorClampState(); SyncDepthTestState(); SyncStencilTestState(); SyncBlendState(); @@ -1032,6 +1033,11 @@ void RasterizerOpenGL::SyncColorMask() { } } +void RasterizerOpenGL::SyncFragmentColorClampState() { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; + state.fragment_color_clamp.enabled = regs.frag_color_clamp != 0; +} + void RasterizerOpenGL::SyncBlendState() { 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 8ef0f6c129..d3fa0b6fcb 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -160,6 +160,9 @@ private: /// Syncs the LogicOp state to match the guest state void SyncLogicOpState(); + /// Syncs the the color clamp state + void SyncFragmentColorClampState(); + /// Syncs the scissor test state to match the guest state void SyncScissorTest(); diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index dd6d946e58..6998dd92b9 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -89,6 +89,7 @@ OpenGLState::OpenGLState() { clip_distance = {}; point.size = 1; + fragment_color_clamp.enabled = false; } void OpenGLState::ApplyDefaultState() { @@ -497,6 +498,12 @@ void OpenGLState::Apply() const { if (point.size != cur_state.point.size) { glPointSize(point.size); } + if (GLAD_GL_ARB_color_buffer_float) { + if (fragment_color_clamp.enabled != cur_state.fragment_color_clamp.enabled) { + glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, + fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE); + } + } ApplyColorMask(); ApplyViewport(); ApplyStencilTest(); diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index da487461f0..6079f6e0b0 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -39,6 +39,10 @@ public: bool enabled; // GL_FRAMEBUFFER_SRGB } framebuffer_srgb; + struct { + bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB + } fragment_color_clamp; + struct { bool enabled; // viewports arrays are only supported when geometry shaders are enabled. } geometry_shaders; From 53b4a1af0f8a8c1e7c0ad27c76adf3b0e86bef13 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Wed, 14 Nov 2018 00:02:54 -0300 Subject: [PATCH 06/11] add AlphaToCoverage and AlphaToOne --- src/video_core/engines/maxwell_3d.h | 8 +++++++- .../renderer_opengl/gl_rasterizer.cpp | 7 +++++++ src/video_core/renderer_opengl/gl_rasterizer.h | 3 +++ src/video_core/renderer_opengl/gl_state.cpp | 17 +++++++++++++++++ src/video_core/renderer_opengl/gl_state.h | 5 +++++ 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index f2d69814ee..753aff57f6 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -726,7 +726,12 @@ public: u32 zeta_enable; - INSERT_PADDING_WORDS(0x8); + union { + BitField<1, 1, u32> alpha_to_coverage; + BitField<2, 1, u32> alpha_to_one; + } multisample_control; + + INSERT_PADDING_WORDS(0x7); struct { u32 tsc_address_high; @@ -1149,6 +1154,7 @@ ASSERT_REG_POSITION(screen_y_control, 0x4EB); ASSERT_REG_POSITION(vb_element_base, 0x50D); ASSERT_REG_POSITION(point_size, 0x546); ASSERT_REG_POSITION(zeta_enable, 0x54E); +ASSERT_REG_POSITION(multisample_control, 0x54F); ASSERT_REG_POSITION(tsc, 0x557); ASSERT_REG_POSITION(tic, 0x55D); ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 98799056c4..d2e3fde655 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -583,6 +583,7 @@ void RasterizerOpenGL::DrawArrays() { ConfigureFramebuffers(state); SyncColorMask(); SyncFragmentColorClampState(); + SyncMultiSampleState(); SyncDepthTestState(); SyncStencilTestState(); SyncBlendState(); @@ -1033,6 +1034,12 @@ void RasterizerOpenGL::SyncColorMask() { } } +void RasterizerOpenGL::SyncMultiSampleState() { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; + state.multisample_control.alpha_to_coverage = regs.multisample_control.alpha_to_coverage != 0; + state.multisample_control.alpha_to_one = regs.multisample_control.alpha_to_one != 0; +} + void RasterizerOpenGL::SyncFragmentColorClampState() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; state.fragment_color_clamp.enabled = regs.frag_color_clamp != 0; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index d3fa0b6fcb..8994e134a6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -163,6 +163,9 @@ private: /// Syncs the the color clamp state void SyncFragmentColorClampState(); + /// Syncs the alpha coverage and alpha to one + void SyncMultiSampleState(); + /// Syncs the scissor test state to match the guest state void SyncScissorTest(); diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 6998dd92b9..f6d80614bb 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -16,6 +16,8 @@ OpenGLState::OpenGLState() { // These all match default OpenGL values geometry_shaders.enabled = false; framebuffer_srgb.enabled = false; + multisample_control.alpha_to_coverage = false; + multisample_control.alpha_to_one = false; cull.enabled = false; cull.mode = GL_BACK; cull.front_face = GL_CCW; @@ -504,6 +506,21 @@ void OpenGLState::Apply() const { fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE); } } + if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) { + if (multisample_control.alpha_to_coverage) { + glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } else { + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + } + if (multisample_control.alpha_to_one != cur_state.multisample_control.alpha_to_one) { + if (multisample_control.alpha_to_one) { + glEnable(GL_SAMPLE_ALPHA_TO_ONE); + } else { + glDisable(GL_SAMPLE_ALPHA_TO_ONE); + } + } + ApplyColorMask(); ApplyViewport(); ApplyStencilTest(); diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 6079f6e0b0..c8d951a7fb 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -39,6 +39,11 @@ public: bool enabled; // GL_FRAMEBUFFER_SRGB } framebuffer_srgb; + struct { + bool alpha_to_coverage; // GL_ALPHA_TO_COVERAGE + bool alpha_to_one; // GL_ALPHA_TO_ONE + } multisample_control; + struct { bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB } fragment_color_clamp; From e69eb3c7609bdb632e4c3e979562325b7a0b4610 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Wed, 14 Nov 2018 14:34:02 -0300 Subject: [PATCH 07/11] fix for gcc compilation --- src/video_core/engines/maxwell_3d.h | 121 ++++++++++++++-------------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 753aff57f6..1af948d24a 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -480,6 +480,67 @@ public: }; }; + struct ViewportTransform { + f32 scale_x; + f32 scale_y; + f32 scale_z; + f32 translate_x; + f32 translate_y; + f32 translate_z; + INSERT_PADDING_WORDS(2); + + MathUtil::Rectangle GetRect() const { + return { + GetX(), // left + GetY() + GetHeight(), // top + GetX() + GetWidth(), // right + GetY() // bottom + }; + }; + + s32 GetX() const { + return static_cast(std::max(0.0f, translate_x - std::fabs(scale_x))); + } + + s32 GetY() const { + return static_cast(std::max(0.0f, translate_y - std::fabs(scale_y))); + } + + s32 GetWidth() const { + return static_cast(translate_x + std::fabs(scale_x)) - GetX(); + } + + s32 GetHeight() const { + return static_cast(translate_y + std::fabs(scale_y)) - GetY(); + } + }; + + struct ScissorTest { + u32 enable; + union { + BitField<0, 16, u32> min_x; + BitField<16, 16, u32> max_x; + }; + union { + BitField<0, 16, u32> min_y; + BitField<16, 16, u32> max_y; + }; + u32 fill; + }; + + struct ViewPort { + union { + BitField<0, 16, u32> x; + BitField<16, 16, u32> width; + }; + union { + BitField<0, 16, u32> y; + BitField<16, 16, u32> height; + }; + float depth_range_near; + float depth_range_far; + }; + bool IsShaderConfigEnabled(std::size_t index) const { // The VertexB is always enabled. if (index == static_cast(Regs::ShaderProgram::VertexB)) { @@ -507,56 +568,8 @@ public: std::array rt; - struct ViewportTransform { - f32 scale_x; - f32 scale_y; - f32 scale_z; - f32 translate_x; - f32 translate_y; - f32 translate_z; - INSERT_PADDING_WORDS(2); - - MathUtil::Rectangle GetRect() const { - return { - GetX(), // left - GetY() + GetHeight(), // top - GetX() + GetWidth(), // right - GetY() // bottom - }; - }; - - s32 GetX() const { - return static_cast(std::max(0.0f, translate_x - std::fabs(scale_x))); - } - - s32 GetY() const { - return static_cast(std::max(0.0f, translate_y - std::fabs(scale_y))); - } - - s32 GetWidth() const { - return static_cast(translate_x + std::fabs(scale_x)) - GetX(); - } - - s32 GetHeight() const { - return static_cast(translate_y + std::fabs(scale_y)) - GetY(); - } - }; - std::array viewport_transform; - struct ViewPort { - union { - BitField<0, 16, u32> x; - BitField<16, 16, u32> width; - }; - union { - BitField<0, 16, u32> y; - BitField<16, 16, u32> height; - }; - float depth_range_near; - float depth_range_far; - }; - std::array viewports; INSERT_PADDING_WORDS(0x1D); @@ -575,18 +588,6 @@ public: INSERT_PADDING_WORDS(0x17); - struct ScissorTest { - u32 enable; - union { - BitField<0, 16, u32> min_x; - BitField<16, 16, u32> max_x; - }; - union { - BitField<0, 16, u32> min_y; - BitField<16, 16, u32> max_y; - }; - u32 fill; - }; std::array scissor_test; INSERT_PADDING_WORDS(0x15); From 5297495c871b7907f1ad03b4ef24f60e2c08daca Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Wed, 14 Nov 2018 17:31:47 -0300 Subject: [PATCH 08/11] small fix for alphaToOne bit location --- src/video_core/engines/maxwell_3d.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 1af948d24a..9e480dc39a 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -728,8 +728,8 @@ public: u32 zeta_enable; union { - BitField<1, 1, u32> alpha_to_coverage; - BitField<2, 1, u32> alpha_to_one; + BitField<0, 1, u32> alpha_to_coverage; + BitField<4, 1, u32> alpha_to_one; } multisample_control; INSERT_PADDING_WORDS(0x7); From b312cca756ef3ab9451233425f552af50d40ab60 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Fri, 16 Nov 2018 13:48:10 -0300 Subject: [PATCH 09/11] small type fix --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d2e3fde655..1d992b3018 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -923,7 +923,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { + for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { const MathUtil::Rectangle viewport_rect{regs.viewport_transform[i].GetRect()}; auto& viewport = current_state.viewports[i]; viewport.x = viewport_rect.left; @@ -1022,9 +1022,9 @@ void RasterizerOpenGL::SyncStencilTestState() { void RasterizerOpenGL::SyncColorMask() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - size_t count = + const std::size_t count = regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1; - for (size_t i = 0; i < count; i++) { + for (std::size_t i = 0; i < count; 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; @@ -1066,13 +1066,13 @@ void RasterizerOpenGL::SyncBlendState() { blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a); blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a); } - for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { + for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { state.blend[i].enabled = false; } return; } - for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { + for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { auto& blend = state.blend[i]; blend.enabled = regs.blend.enable[i] != 0; if (!blend.enabled) @@ -1105,7 +1105,7 @@ void RasterizerOpenGL::SyncLogicOpState() { void RasterizerOpenGL::SyncScissorTest() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { + for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { const auto& src = regs.scissor_test[i]; auto& dst = state.viewports[i].scissor; dst.enabled = (src.enable != 0); From 81a9c5fe6f3750914fa4a4fe4bd425ea6e398333 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Sat, 17 Nov 2018 19:58:48 -0300 Subject: [PATCH 10/11] fix sampler configuration, thanks to Marcos for his investigation --- .../renderer_opengl/gl_rasterizer.cpp | 55 +++++++++++++------ .../renderer_opengl/gl_rasterizer.h | 6 +- src/video_core/textures/texture.h | 15 ++++- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 1d992b3018..3fe8ceb416 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -735,9 +735,8 @@ void RasterizerOpenGL::SamplerInfo::Create() { glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); } -void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTextureInfo& info) { +void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { const GLuint s = sampler.handle; - const Tegra::Texture::TSCEntry& config = info.tsc; if (mag_filter != config.mag_filter) { mag_filter = config.mag_filter; glSamplerParameteri( @@ -779,28 +778,50 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTex MaxwellToGL::DepthCompareFunc(depth_compare_func)); } - const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, - config.border_color_b, config.border_color_a}}; + GLvec4 new_border_color; + if (config.srgb_conversion) { + new_border_color[0] = config.srgb_border_color_r / 255.0f; + new_border_color[1] = config.srgb_border_color_g / 255.0f; + new_border_color[2] = config.srgb_border_color_g / 255.0f; + } else { + new_border_color[0] = config.border_color_r; + new_border_color[1] = config.border_color_g; + new_border_color[2] = config.border_color_b; + } + new_border_color[3] = config.border_color_a; + if (border_color != new_border_color) { border_color = new_border_color; glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); } - if (info.tic.use_header_opt_control == 0) { + const float anisotropic_max = static_cast(1 << config.max_anisotropy.Value()); + if (anisotropic_max != max_anisotropic) { + max_anisotropic = anisotropic_max; if (GLAD_GL_ARB_texture_filter_anisotropic) { - glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, - static_cast(1 << info.tic.max_anisotropy.Value())); + glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, max_anisotropic); } else if (GLAD_GL_EXT_texture_filter_anisotropic) { - glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, - static_cast(1 << info.tic.max_anisotropy.Value())); + glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropic); } - glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, - static_cast(info.tic.res_min_mip_level.Value())); - glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, - static_cast(info.tic.res_max_mip_level.Value() == 0 - ? 16 - : info.tic.res_max_mip_level.Value())); - glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, info.tic.mip_lod_bias.Value() / 256.f); + } + const float lod_min = static_cast(config.min_lod_clamp.Value()) / 256.0f; + if (lod_min != min_lod) { + min_lod = lod_min; + glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, min_lod); + } + + const float lod_max = static_cast(config.max_lod_clamp.Value()) / 256.0f; + if (lod_max != max_lod) { + max_lod = lod_max; + glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, max_lod); + } + const u32 bias = config.mip_lod_bias.Value(); + // Sign extend the 13-bit value. + const u32 mask = 1U << (13 - 1); + const float bias_lod = static_cast((bias ^ mask) - mask) / 256.f; + if (lod_bias != bias_lod) { + lod_bias = bias_lod; + glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, lod_bias); } } @@ -899,7 +920,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, continue; } - texture_samplers[current_bindpoint].SyncWithConfig(texture); + texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); Surface surface = res_cache.GetTextureSurface(texture, entry); if (surface != nullptr) { state.texture_units[current_bindpoint].texture = surface->Texture().handle; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 8994e134a6..6e78ab4cd8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -88,7 +88,7 @@ private: /// SamplerInfo struct. void Create(); /// Syncs the sampler object with the config, updating any necessary state. - void SyncWithConfig(const Tegra::Texture::FullTextureInfo& info); + void SyncWithConfig(const Tegra::Texture::TSCEntry& info); private: Tegra::Texture::TextureFilter mag_filter; @@ -100,6 +100,10 @@ private: bool uses_depth_compare; Tegra::Texture::DepthCompareFunc depth_compare_func; GLvec4 border_color; + float min_lod; + float max_lod; + float lod_bias; + float max_anisotropic; }; /** diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index e199d019a6..ffa08f5c13 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -190,6 +190,7 @@ struct TICEntry { union { BitField<0, 4, u32> res_min_mip_level; BitField<4, 4, u32> res_max_mip_level; + BitField<12, 12, u32> min_lod_clamp; }; GPUVAddr Address() const { @@ -284,13 +285,25 @@ struct TSCEntry { BitField<6, 3, WrapMode> wrap_p; BitField<9, 1, u32> depth_compare_enabled; BitField<10, 3, DepthCompareFunc> depth_compare_func; + BitField<13, 1, u32> srgb_conversion; + BitField<20, 3, u32> max_anisotropy; }; union { BitField<0, 2, TextureFilter> mag_filter; BitField<4, 2, TextureFilter> min_filter; BitField<6, 2, TextureMipmapFilter> mip_filter; + BitField<9, 1, u32> cubemap_interface_filtering; + BitField<12, 13, u32> mip_lod_bias; + }; + union { + BitField<0, 12, u32> min_lod_clamp; + BitField<12, 12, u32> max_lod_clamp; + BitField<24, 8, u32> srgb_border_color_r; + }; + union { + BitField<12, 8, u32> srgb_border_color_g; + BitField<20, 8, u32> srgb_border_color_b; }; - INSERT_PADDING_BYTES(8); float border_color_r; float border_color_g; float border_color_b; From 4d1a0a24cc753d6655b07b74f3f0f098a4d588d1 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Sun, 18 Nov 2018 03:44:48 -0300 Subject: [PATCH 11/11] drop support for non separate alpha as it seems to cause issues in some games --- .../renderer_opengl/gl_rasterizer.cpp | 34 +++++------ src/video_core/renderer_opengl/gl_state.cpp | 61 ++++++------------- src/video_core/renderer_opengl/gl_state.h | 1 - 3 files changed, 35 insertions(+), 61 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 3fe8ceb416..8c92ceb217 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1077,15 +1077,15 @@ 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); - blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb); - if (blend.separate_alpha) { - blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a); - blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a); - blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a); + const auto& src = regs.blend; + blend.enabled = src.enable[0] != 0; + if (blend.enabled) { + blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb); + blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb); + blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb); + blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a); + blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a); + blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a); } for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { state.blend[i].enabled = false; @@ -1095,18 +1095,16 @@ void RasterizerOpenGL::SyncBlendState() { for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { auto& blend = state.blend[i]; + const auto& src = regs.independent_blend[i]; blend.enabled = regs.blend.enable[i] != 0; if (!blend.enabled) continue; - blend.separate_alpha = regs.independent_blend[i].separate_alpha; - blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb); - blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb); - blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb); - if (blend.separate_alpha) { - blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a); - blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_a); - blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_a); - } + blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb); + blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb); + blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb); + blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a); + blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a); + blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a); } } diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index f6d80614bb..d9910c6e83 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -309,27 +309,16 @@ void OpenGLState::ApplyGlobalBlending() const { if (!updated.enabled) { return; } - if (updated.separate_alpha) { - if (blend_changed || updated.src_rgb_func != current.src_rgb_func || - updated.dst_rgb_func != current.dst_rgb_func || - updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) { - glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, - updated.dst_a_func); - } + if (blend_changed || updated.src_rgb_func != current.src_rgb_func || + updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || + updated.dst_a_func != current.dst_a_func) { + glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, + updated.dst_a_func); + } - if (blend_changed || updated.rgb_equation != current.rgb_equation || - updated.a_equation != current.a_equation) { - glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); - } - } else { - if (blend_changed || updated.src_rgb_func != current.src_rgb_func || - updated.dst_rgb_func != current.dst_rgb_func) { - glBlendFunc(updated.src_rgb_func, updated.dst_rgb_func); - } - - if (blend_changed || updated.rgb_equation != current.rgb_equation) { - glBlendEquation(updated.rgb_equation); - } + if (blend_changed || updated.rgb_equation != current.rgb_equation || + updated.a_equation != current.a_equation) { + glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); } } @@ -347,29 +336,17 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { if (!updated.enabled) { return; } - if (updated.separate_alpha) { - if (blend_changed || updated.src_rgb_func != current.src_rgb_func || - updated.dst_rgb_func != current.dst_rgb_func || - updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) { - glBlendFuncSeparateiARB(static_cast(target), updated.src_rgb_func, - updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); - } + if (blend_changed || updated.src_rgb_func != current.src_rgb_func || + updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || + updated.dst_a_func != current.dst_a_func) { + glBlendFuncSeparateiARB(static_cast(target), updated.src_rgb_func, + updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); + } - if (blend_changed || updated.rgb_equation != current.rgb_equation || - updated.a_equation != current.a_equation) { - glBlendEquationSeparateiARB(static_cast(target), updated.rgb_equation, - updated.a_equation); - } - } else { - if (blend_changed || updated.src_rgb_func != current.src_rgb_func || - updated.dst_rgb_func != current.dst_rgb_func) { - glBlendFunciARB(static_cast(target), updated.src_rgb_func, - updated.dst_rgb_func); - } - - if (blend_changed || updated.rgb_equation != current.rgb_equation) { - glBlendEquationiARB(static_cast(target), updated.rgb_equation); - } + if (blend_changed || updated.rgb_equation != current.rgb_equation || + updated.a_equation != current.a_equation) { + glBlendEquationSeparateiARB(static_cast(target), updated.rgb_equation, + updated.a_equation); } } diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index c8d951a7fb..bdc743b0f0 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -92,7 +92,6 @@ public: struct Blend { bool enabled; // GL_BLEND - bool separate_alpha; // Independent blend enabled GLenum rgb_equation; // GL_BLEND_EQUATION_RGB GLenum a_equation; // GL_BLEND_EQUATION_ALPHA GLenum src_rgb_func; // GL_BLEND_SRC_RGB