diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 065a3fd0c..7099c31a0 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -128,22 +128,14 @@ struct Regs { BitField<0, 2, ScissorMode> mode; union { - BitField< 0, 16, u32> right; - BitField<16, 16, u32> bottom; + BitField< 0, 16, u32> x1; + BitField<16, 16, u32> y1; }; union { - BitField< 0, 16, u32> left_minus_1; - BitField<16, 16, u32> top_minus_1; + BitField< 0, 16, u32> x2; + BitField<16, 16, u32> y2; }; - - u32 GetTop() const { - return top_minus_1 + 1; - } - - u32 GetLeft() const { - return left_minus_1 + 1; - } } scissor_test; union { diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 514d64208..6f369a00e 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -344,17 +344,18 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); // Convert the scissor box coordinates to 12.4 fixed point - u16 scissor_left = (u16)(regs.scissor_test.GetLeft() << 4); - u16 scissor_top = (u16)(regs.scissor_test.GetTop() << 4); - u16 scissor_right = (u16)(regs.scissor_test.right << 4); - u16 scissor_bottom = (u16)(regs.scissor_test.bottom << 4); + u16 scissor_x1 = (u16)( regs.scissor_test.x1 << 4); + u16 scissor_y1 = (u16)( regs.scissor_test.y1 << 4); + // x2,y2 have +1 added to cover the entire sub-pixel area + u16 scissor_x2 = (u16)((regs.scissor_test.x2 + 1) << 4); + u16 scissor_y2 = (u16)((regs.scissor_test.y2 + 1) << 4); if (regs.scissor_test.mode == Regs::ScissorMode::Include) { // Calculate the new bounds - min_x = std::max(min_x, scissor_right); - min_y = std::max(min_y, scissor_bottom); - max_x = std::min(max_x, scissor_left); - max_y = std::min(max_y, scissor_top); + min_x = std::max(min_x, scissor_x1); + min_y = std::max(min_y, scissor_y1); + max_x = std::min(max_x, scissor_x2); + max_y = std::min(max_y, scissor_y2); } min_x &= Fix12P4::IntMask(); @@ -397,10 +398,10 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, for (u16 x = min_x + 8; x < max_x; x += 0x10) { // Do not process the pixel if it's inside the scissor box and the scissor mode is set to Exclude - if (regs.scissor_test.mode == Regs::ScissorMode::Exclude && - x >= scissor_right && x <= scissor_left && - y >= scissor_bottom && y <= scissor_top) { - continue; + if (regs.scissor_test.mode == Regs::ScissorMode::Exclude) { + if (x >= scissor_x1 && x < scissor_x2 && + y >= scissor_y1 && y < scissor_y2) + continue; } // Calculate the barycentric coordinates w0, w1 and w2 diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 14ee97d57..ab02aadc9 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -357,8 +357,8 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { case PICA_REG_INDEX(scissor_test.mode): shader_dirty = true; break; - case PICA_REG_INDEX(scissor_test.right): - case PICA_REG_INDEX(scissor_test.left_minus_1): + case PICA_REG_INDEX(scissor_test.x1): // and y1 + case PICA_REG_INDEX(scissor_test.x2): // and y2 SyncScissorTest(); break; @@ -1179,15 +1179,15 @@ void RasterizerOpenGL::SyncDepthTest() { void RasterizerOpenGL::SyncScissorTest() { const auto& regs = Pica::g_state.regs; - if (uniform_block_data.data.scissor_right != regs.scissor_test.right || - uniform_block_data.data.scissor_bottom != regs.scissor_test.bottom || - uniform_block_data.data.scissor_left != regs.scissor_test.GetLeft() || - uniform_block_data.data.scissor_top != regs.scissor_test.GetTop()) { + if (uniform_block_data.data.scissor_x1 != regs.scissor_test.x1 || + uniform_block_data.data.scissor_y1 != regs.scissor_test.y1 || + uniform_block_data.data.scissor_x2 != regs.scissor_test.x2 || + uniform_block_data.data.scissor_y2 != regs.scissor_test.y2) { - uniform_block_data.data.scissor_right = regs.scissor_test.right; - uniform_block_data.data.scissor_bottom = regs.scissor_test.bottom; - uniform_block_data.data.scissor_left = regs.scissor_test.GetLeft(); - uniform_block_data.data.scissor_top = regs.scissor_test.GetTop(); + uniform_block_data.data.scissor_x1 = regs.scissor_test.x1; + uniform_block_data.data.scissor_y1 = regs.scissor_test.y1; + uniform_block_data.data.scissor_x2 = regs.scissor_test.x2; + uniform_block_data.data.scissor_y2 = regs.scissor_test.y2; uniform_block_data.dirty = true; } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 193c10291..653ac9cd9 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -331,10 +331,10 @@ private: GLint alphatest_ref; GLfloat depth_scale; GLfloat depth_offset; - GLint scissor_right; - GLint scissor_bottom; - GLint scissor_left; - GLint scissor_top; + GLint scissor_x1; + GLint scissor_y1; + GLint scissor_x2; + GLint scissor_y2; alignas(16) GLvec3 fog_color; alignas(16) GLvec3 lighting_global_ambient; LightSrc light_src[8]; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 10bb44210..b2e452afe 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -557,10 +557,10 @@ layout (std140) uniform shader_data { int alphatest_ref; float depth_scale; float depth_offset; - int scissor_right; - int scissor_bottom; - int scissor_left; - int scissor_top; + int scissor_x1; + int scissor_y1; + int scissor_x2; + int scissor_y2; vec3 fog_color; vec3 lighting_global_ambient; LightSrc light_src[NUM_LIGHTS]; @@ -589,13 +589,14 @@ vec4 secondary_fragment_color = vec4(0.0); } // Append the scissor test - if (state.scissor_test_mode == Regs::ScissorMode::Include || state.scissor_test_mode == Regs::ScissorMode::Exclude) { - out += "if (scissor_left <= scissor_right || scissor_top <= scissor_bottom) discard;\n"; + if (state.scissor_test_mode != Regs::ScissorMode::Disabled) { out += "if ("; // Negate the condition if we have to keep only the pixels outside the scissor box if (state.scissor_test_mode == Regs::ScissorMode::Include) out += "!"; - out += "(gl_FragCoord.x >= scissor_right && gl_FragCoord.x <= scissor_left && gl_FragCoord.y >= scissor_bottom && gl_FragCoord.y <= scissor_top)) discard;\n"; + // x2,y2 have +1 added to cover the entire pixel area + out += "(gl_FragCoord.x >= scissor_x1 && gl_FragCoord.x < scissor_x2 + 1 && " + "gl_FragCoord.y >= scissor_y1 && gl_FragCoord.y < scissor_y2 + 1)) discard;\n"; } out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";