Просмотр исходного кода

gl_rasterizer: Implement stencil test.

- Used by Splatoon 2.
bunnei 8 лет назад
Родитель
Сommit
a4ac3bed6c

+ 31 - 4
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -316,16 +316,14 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c
         using_color_fb = false;
         using_color_fb = false;
     }
     }
 
 
-    // TODO(bunnei): Implement this
-    const bool has_stencil = false;
-
+    const bool has_stencil = regs.stencil_enable;
     const bool write_color_fb =
     const bool write_color_fb =
         state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
         state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
         state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE;
         state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE;
 
 
     const bool write_depth_fb =
     const bool write_depth_fb =
         (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) ||
         (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) ||
-        (has_stencil && state.stencil.test_enabled && state.stencil.write_mask != 0);
+        (has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask));
 
 
     Surface color_surface;
     Surface color_surface;
     Surface depth_surface;
     Surface depth_surface;
@@ -481,6 +479,7 @@ void RasterizerOpenGL::DrawArrays() {
         ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0, true);
         ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0, true);
 
 
     SyncDepthTestState();
     SyncDepthTestState();
+    SyncStencilTestState();
     SyncBlendState();
     SyncBlendState();
     SyncLogicOpState();
     SyncLogicOpState();
     SyncCullMode();
     SyncCullMode();
@@ -871,6 +870,34 @@ void RasterizerOpenGL::SyncDepthTestState() {
     state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func);
     state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func);
 }
 }
 
 
+void RasterizerOpenGL::SyncStencilTestState() {
+    const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+    state.stencil.test_enabled = regs.stencil_enable != 0;
+
+    if (!regs.stencil_enable) {
+        return;
+    }
+
+    // TODO(bunnei): Verify behavior when this is not set
+    ASSERT(regs.stencil_two_side_enable);
+
+    state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func);
+    state.stencil.front.test_ref = regs.stencil_front_func_ref;
+    state.stencil.front.test_mask = regs.stencil_front_func_mask;
+    state.stencil.front.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_fail);
+    state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail);
+    state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass);
+    state.stencil.front.write_mask = regs.stencil_front_mask;
+
+    state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func);
+    state.stencil.back.test_ref = regs.stencil_back_func_ref;
+    state.stencil.back.test_mask = regs.stencil_back_func_mask;
+    state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail);
+    state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail);
+    state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass);
+    state.stencil.back.write_mask = regs.stencil_back_mask;
+}
+
 void RasterizerOpenGL::SyncBlendState() {
 void RasterizerOpenGL::SyncBlendState() {
     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
 
 

+ 3 - 0
src/video_core/renderer_opengl/gl_rasterizer.h

@@ -141,6 +141,9 @@ private:
     /// Syncs the depth test state to match the guest state
     /// Syncs the depth test state to match the guest state
     void SyncDepthTestState();
     void SyncDepthTestState();
 
 
+    /// Syncs the stencil test state to match the guest state
+    void SyncStencilTestState();
+
     /// Syncs the blend state to match the guest state
     /// Syncs the blend state to match the guest state
     void SyncBlendState();
     void SyncBlendState();
 
 

+ 24 - 0
src/video_core/renderer_opengl/maxwell_to_gl.h

@@ -295,6 +295,30 @@ inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) {
     return {};
     return {};
 }
 }
 
 
+inline GLenum StencilOp(Maxwell::StencilOp stencil) {
+    switch (stencil) {
+    case Maxwell::StencilOp::Keep:
+        return GL_KEEP;
+    case Maxwell::StencilOp::Zero:
+        return GL_ZERO;
+    case Maxwell::StencilOp::Replace:
+        return GL_REPLACE;
+    case Maxwell::StencilOp::Incr:
+        return GL_INCR;
+    case Maxwell::StencilOp::Decr:
+        return GL_DECR;
+    case Maxwell::StencilOp::Invert:
+        return GL_INVERT;
+    case Maxwell::StencilOp::IncrWrap:
+        return GL_INCR_WRAP;
+    case Maxwell::StencilOp::DecrWrap:
+        return GL_DECR_WRAP;
+    }
+    LOG_CRITICAL(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil));
+    UNREACHABLE();
+    return {};
+}
+
 inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) {
 inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) {
     switch (front_face) {
     switch (front_face) {
     case Maxwell::Cull::FrontFace::ClockWise:
     case Maxwell::Cull::FrontFace::ClockWise: