Parcourir la source

Merge pull request #1124 from Subv/logic_ops

GPU: Implemented logic ops.
bunnei il y a 8 ans
Parent
commit
125d7122ac

+ 28 - 1
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);

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

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

+ 15 - 5
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

+ 4 - 1
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 {

+ 40 - 0
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<u32>(operation));
+    UNREACHABLE();
+    return {};
+}
+
 } // namespace MaxwellToGL