diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 3c869d3a1..d03bc1c0c 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -311,6 +311,25 @@ public: AlwaysOld = 8, }; + enum class LogicOperation : u32 { + Clear = 0x1500, + And = 0x1501, + AndReverse = 0x1502, + Copy = 0x1503, + AndInverted = 0x1504, + NoOp = 0x1505, + Xor = 0x1506, + Or = 0x1507, + Nor = 0x1508, + Equiv = 0x1509, + Invert = 0x150A, + OrReverse = 0x150B, + CopyInverted = 0x150C, + OrInverted = 0x150D, + Nand = 0x150E, + Set = 0x150F, + }; + struct Cull { enum class FrontFace : u32 { ClockWise = 0x0900, @@ -695,7 +714,14 @@ public: Cull cull; - INSERT_PADDING_WORDS(0x2B); + INSERT_PADDING_WORDS(0x28); + + struct { + u32 enable; + LogicOperation operation; + } logic_op; + + INSERT_PADDING_WORDS(0x1); union { u32 raw; @@ -942,6 +968,7 @@ ASSERT_REG_POSITION(draw, 0x585); ASSERT_REG_POSITION(index_array, 0x5F2); 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(query, 0x6C0); ASSERT_REG_POSITION(vertex_array[0], 0x700); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index b653bb479..35056d9bd 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -450,6 +450,7 @@ void RasterizerOpenGL::DrawArrays() { SyncDepthTestState(); SyncBlendState(); + SyncLogicOpState(); SyncCullMode(); // TODO(bunnei): Sync framebuffer_scale uniform here @@ -847,6 +848,9 @@ void RasterizerOpenGL::SyncBlendState() { if (!state.blend.enabled) return; + ASSERT_MSG(regs.logic_op.enable == 0, + "Blending and logic op can't be enabled at the same time."); + ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); @@ -856,3 +860,17 @@ void RasterizerOpenGL::SyncBlendState() { state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a); state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a); } + +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) + return; + + ASSERT_MSG(regs.blend.enable == 0, "Blending and logic op can't be enabled at the same time."); + + state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); +} diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 394fc59f1..f40e70bf4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -142,6 +142,9 @@ private: /// Syncs the blend state to match the guest state void SyncBlendState(); + /// Syncs the LogicOp state to match the guest state + void SyncLogicOpState(); + bool has_ARB_direct_state_access = false; bool has_ARB_separate_shader_objects = false; bool has_ARB_vertex_attrib_binding = false; diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 1d1975179..13399ceb8 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -45,7 +45,8 @@ OpenGLState::OpenGLState() { blend.color.blue = 0.0f; blend.color.alpha = 0.0f; - logic_op = GL_COPY; + logic_op.enabled = false; + logic_op.operation = GL_COPY; for (auto& texture_unit : texture_units) { texture_unit.Reset(); @@ -148,11 +149,10 @@ void OpenGLState::Apply() const { // Blending if (blend.enabled != cur_state.blend.enabled) { if (blend.enabled) { + ASSERT(!logic_op.enabled); glEnable(GL_BLEND); - glDisable(GL_COLOR_LOGIC_OP); } else { glDisable(GL_BLEND); - glEnable(GL_COLOR_LOGIC_OP); } } @@ -176,8 +176,18 @@ void OpenGLState::Apply() const { glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); } - if (logic_op != cur_state.logic_op) { - glLogicOp(logic_op); + // Logic Operation + if (logic_op.enabled != cur_state.logic_op.enabled) { + if (logic_op.enabled) { + ASSERT(!blend.enabled); + glEnable(GL_COLOR_LOGIC_OP); + } else { + glDisable(GL_COLOR_LOGIC_OP); + } + } + + if (logic_op.operation != cur_state.logic_op.operation) { + glLogicOp(logic_op.operation); } // Textures diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index bdb02ba25..219b65a8a 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -83,7 +83,10 @@ public: } color; // GL_BLEND_COLOR } blend; - GLenum logic_op; // GL_LOGIC_OP_MODE + struct { + bool enabled; // GL_LOGIC_OP_MODE + GLenum operation; + } logic_op; // 3 texture units - one for each that is used in PICA fragment shader emulation struct TextureUnit { diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 5d91a0c2f..ff2f7b8b6 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -317,4 +317,44 @@ inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) { return {}; } +inline GLenum LogicOp(Maxwell::LogicOperation operation) { + switch (operation) { + case Maxwell::LogicOperation::Clear: + return GL_CLEAR; + case Maxwell::LogicOperation::And: + return GL_AND; + case Maxwell::LogicOperation::AndReverse: + return GL_AND_REVERSE; + case Maxwell::LogicOperation::Copy: + return GL_COPY; + case Maxwell::LogicOperation::AndInverted: + return GL_AND_INVERTED; + case Maxwell::LogicOperation::NoOp: + return GL_NOOP; + case Maxwell::LogicOperation::Xor: + return GL_XOR; + case Maxwell::LogicOperation::Or: + return GL_OR; + case Maxwell::LogicOperation::Nor: + return GL_NOR; + case Maxwell::LogicOperation::Equiv: + return GL_EQUIV; + case Maxwell::LogicOperation::Invert: + return GL_INVERT; + case Maxwell::LogicOperation::OrReverse: + return GL_OR_REVERSE; + case Maxwell::LogicOperation::CopyInverted: + return GL_COPY_INVERTED; + case Maxwell::LogicOperation::OrInverted: + return GL_OR_INVERTED; + case Maxwell::LogicOperation::Nand: + return GL_NAND; + case Maxwell::LogicOperation::Set: + return GL_SET; + } + LOG_CRITICAL(Render_OpenGL, "Unimplemented logic operation={}", static_cast(operation)); + UNREACHABLE(); + return {}; +} + } // namespace MaxwellToGL