diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 60c9d9180..62c9af28c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -211,6 +211,27 @@ void RasterizerOpenGL::DrawTriangles() { uniform_block_data.dirty = true; } + // Scissor checks are window-, not viewport-relative, which means that if the cached texture + // sub-rect changes, the scissor bounds also need to be updated. + GLint scissor_x1 = rect.left + regs.scissor_test.x1 * color_surface->res_scale_width; + GLint scissor_y1 = rect.bottom + regs.scissor_test.y1 * color_surface->res_scale_height; + // x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when + // scaling or doing multisampling. + GLint scissor_x2 = rect.left + (regs.scissor_test.x2 + 1) * color_surface->res_scale_width; + GLint scissor_y2 = rect.bottom + (regs.scissor_test.y2 + 1) * color_surface->res_scale_height; + + if (uniform_block_data.data.scissor_x1 != scissor_x1 || + uniform_block_data.data.scissor_x2 != scissor_x2 || + uniform_block_data.data.scissor_y1 != scissor_y1 || + uniform_block_data.data.scissor_y2 != scissor_y2) { + + uniform_block_data.data.scissor_x1 = scissor_x1; + uniform_block_data.data.scissor_x2 = scissor_x2; + uniform_block_data.data.scissor_y1 = scissor_y1; + uniform_block_data.data.scissor_y2 = scissor_y2; + uniform_block_data.dirty = true; + } + // Sync and bind the texture surfaces const auto pica_textures = regs.GetTextures(); for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) { @@ -374,10 +395,6 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { case PICA_REG_INDEX(scissor_test.mode): shader_dirty = true; break; - case PICA_REG_INDEX(scissor_test.x1): // and y1 - case PICA_REG_INDEX(scissor_test.x2): // and y2 - SyncScissorTest(); - break; // Logic op case PICA_REG_INDEX(output_merger.logic_op): @@ -1061,7 +1078,6 @@ void RasterizerOpenGL::SetShader() { SyncDepthOffset(); SyncAlphaTest(); SyncCombinerColor(); - SyncScissorTest(); auto& tev_stages = Pica::g_state.regs.GetTevStages(); for (int index = 0; index < tev_stages.size(); ++index) SyncTevConstColor(index, tev_stages[index]); @@ -1236,22 +1252,6 @@ void RasterizerOpenGL::SyncDepthTest() { : GL_ALWAYS; } -void RasterizerOpenGL::SyncScissorTest() { - const auto& regs = Pica::g_state.regs; - - 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_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; - } -} - void RasterizerOpenGL::SyncCombinerColor() { auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 24fefed1b..7b4ce2ac5 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -393,9 +393,6 @@ private: /// Syncs the depth test states to match the PICA register void SyncDepthTest(); - /// Syncs the scissor test state to match the PICA register - void SyncScissorTest(); - /// Syncs the TEV combiner color buffer to match the PICA register void SyncCombinerColor(); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 1808ee0a9..8f278722d 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -645,11 +645,10 @@ vec4 secondary_fragment_color = vec4(0.0); // Negate the condition if we have to keep only the pixels outside the scissor box if (state.scissor_test_mode == Regs::ScissorMode::Include) out += "!"; - // x2,y2 have +1 added to cover the entire pixel area - out += "(gl_FragCoord.x >= scissor_x1 * framebuffer_scale.x && " - "gl_FragCoord.y >= scissor_y1 * framebuffer_scale.y && " - "gl_FragCoord.x < (scissor_x2 + 1) * framebuffer_scale.x && " - "gl_FragCoord.y < (scissor_y2 + 1) * framebuffer_scale.y)) discard;\n"; + out += "(gl_FragCoord.x >= scissor_x1 && " + "gl_FragCoord.y >= scissor_y1 && " + "gl_FragCoord.x < scissor_x2 && " + "gl_FragCoord.y < scissor_y2)) discard;\n"; } out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";