diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 6067a356a8..422e656f83 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -476,7 +476,7 @@ void D3D12GSRender::end() }; get_current_resource_storage().command_list->RSSetViewports(1, &viewport); - get_current_resource_storage().command_list->RSSetScissorRects(1, &get_scissor(rsx::method_registers.scissor_origin_x(), rsx::method_registers.scissor_origin_y(), + get_current_resource_storage().command_list->RSSetScissorRects(1, &::get_scissor(rsx::method_registers.scissor_origin_x(), rsx::method_registers.scissor_origin_y(), rsx::method_registers.scissor_width(), rsx::method_registers.scissor_height())); get_current_resource_storage().command_list->IASetPrimitiveTopology(get_primitive_topology(rsx::method_registers.current_draw_clause.primitive)); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp index e89caeb9d6..554f1f8568 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp @@ -125,12 +125,12 @@ void D3D12GSRender::clear_surface(u32 arg) u32 clear_depth = rsx::method_registers.z_clear_value(depth_format == rsx::surface_depth_format::z24s8); u32 max_depth_value = get_max_depth_value(depth_format); get_current_resource_storage().command_list->ClearDepthStencilView(m_rtts.current_ds_handle, D3D12_CLEAR_FLAG_DEPTH, clear_depth / (float)max_depth_value, 0, - 1, &get_scissor(rsx::method_registers.scissor_origin_x(), rsx::method_registers.scissor_origin_y(), rsx::method_registers.scissor_width(), rsx::method_registers.scissor_height())); + 1, &::get_scissor(rsx::method_registers.scissor_origin_x(), rsx::method_registers.scissor_origin_y(), rsx::method_registers.scissor_width(), rsx::method_registers.scissor_height())); } if (arg & 0x2) get_current_resource_storage().command_list->ClearDepthStencilView(m_rtts.current_ds_handle, D3D12_CLEAR_FLAG_STENCIL, 0.f, get_clear_stencil(rsx::method_registers.stencil_clear_value()), - 1, &get_scissor(rsx::method_registers.scissor_origin_x(), rsx::method_registers.scissor_origin_y(), rsx::method_registers.scissor_width(), rsx::method_registers.scissor_height())); + 1, &::get_scissor(rsx::method_registers.scissor_origin_x(), rsx::method_registers.scissor_origin_y(), rsx::method_registers.scissor_width(), rsx::method_registers.scissor_height())); } if (arg & 0xF0) @@ -147,7 +147,7 @@ void D3D12GSRender::clear_surface(u32 arg) }; for (unsigned i = 0; i < rtt_index; i++) get_current_resource_storage().command_list->ClearRenderTargetView(handle.Offset(i, m_descriptor_stride_rtv), clear_color.data(), - 1, &get_scissor(rsx::method_registers.scissor_origin_x(), rsx::method_registers.scissor_origin_y(), rsx::method_registers.scissor_width(), rsx::method_registers.scissor_height())); + 1, &::get_scissor(rsx::method_registers.scissor_origin_x(), rsx::method_registers.scissor_origin_y(), rsx::method_registers.scissor_width(), rsx::method_registers.scissor_height())); } std::chrono::time_point end_duration = steady_clock::now(); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 1d240068e3..f5b390ef73 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -651,43 +651,14 @@ void GLGSRender::set_viewport() void GLGSRender::set_scissor() { - if (m_graphics_state & rsx::pipeline_state::scissor_config_state_dirty) + areau scissor; + if (get_scissor(scissor)) { - // Optimistic that the new config will allow us to render - framebuffer_status_valid = true; + // NOTE: window origin does not affect scissor region (probably only affects viewport matrix; already applied) + // See LIMBO [NPUB-30373] which uses shader window origin = top + glScissor(scissor.x1, scissor.y1, scissor.width(), scissor.height()); + gl_state.enable(GL_TRUE, GL_SCISSOR_TEST); } - else if (!(m_graphics_state & rsx::pipeline_state::scissor_config_state_dirty)) - { - // Nothing to do - return; - } - - m_graphics_state &= ~(rsx::pipeline_state::scissor_config_state_dirty | rsx::pipeline_state::scissor_setup_invalid); - - const auto clip_width = rsx::apply_resolution_scale(rsx::method_registers.surface_clip_width(), true); - const auto clip_height = rsx::apply_resolution_scale(rsx::method_registers.surface_clip_height(), true); - - u16 scissor_x = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_x(), false); - u16 scissor_w = rsx::apply_resolution_scale(rsx::method_registers.scissor_width(), true); - u16 scissor_y = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_y(), false); - u16 scissor_h = rsx::apply_resolution_scale(rsx::method_registers.scissor_height(), true); - - // Do not bother drawing anything if output is zero sized - // TODO: Clip scissor region - if (scissor_x >= clip_width || scissor_y >= clip_height || scissor_w == 0 || scissor_h == 0) - { - if (!g_cfg.video.strict_rendering_mode) - { - m_graphics_state |= rsx::pipeline_state::scissor_setup_invalid; - framebuffer_status_valid = false; - return; - } - } - - // NOTE: window origin does not affect scissor region (probably only affects viewport matrix; already applied) - // See LIMBO [NPUB-30373] which uses shader window origin = top - glScissor(scissor_x, scissor_y, scissor_w, scissor_h); - gl_state.enable(GL_TRUE, GL_SCISSOR_TEST); } void GLGSRender::on_init_thread() diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index bce2b5ec1c..9f5feb3068 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1293,6 +1293,56 @@ namespace rsx return layout; } + bool thread::get_scissor(areau& region) + { + if (!(m_graphics_state & rsx::pipeline_state::scissor_config_state_dirty)) + { + // Nothing to do + return false; + } + + m_graphics_state &= ~rsx::pipeline_state::scissor_config_state_dirty; + + u16 scissor_x = rsx::method_registers.scissor_origin_x(); + u16 scissor_w = rsx::method_registers.scissor_width(); + u16 scissor_y = rsx::method_registers.scissor_origin_y(); + u16 scissor_h = rsx::method_registers.scissor_height(); + + u16 raster_x = rsx::method_registers.viewport_origin_x(); + u16 raster_w = rsx::method_registers.viewport_width(); + u16 raster_y = rsx::method_registers.viewport_origin_y(); + u16 raster_h = rsx::method_registers.viewport_height(); + + // Get the minimum area between these two + u16 x1 = std::max(scissor_x, raster_x); + u16 y1 = std::max(scissor_y, raster_y); + u16 x2 = std::min(scissor_x + scissor_w, raster_x + raster_w); + u16 y2 = std::min(scissor_y + scissor_h, raster_y + raster_h); + + if (x2 <= x1 || + y2 <= y1 || + x1 >= rsx::method_registers.window_clip_horizontal() || + y1 >= rsx::method_registers.window_clip_vertical()) + { + m_graphics_state |= rsx::pipeline_state::scissor_setup_invalid; + framebuffer_status_valid = false; + return false; + } + + if (m_graphics_state & rsx::pipeline_state::scissor_setup_invalid) + { + m_graphics_state &= ~rsx::pipeline_state::scissor_setup_invalid; + framebuffer_status_valid = true; + } + + region.x1 = rsx::apply_resolution_scale(x1, false); + region.x2 = rsx::apply_resolution_scale(x2, true); + region.y1 = rsx::apply_resolution_scale(y1, false); + region.y2 = rsx::apply_resolution_scale(y2, true); + + return true; + } + void thread::get_current_vertex_program(const std::array, rsx::limits::vertex_textures_count>& sampler_descriptors, bool skip_textures, bool skip_vertex_inputs) { if (!(m_graphics_state & rsx::pipeline_state::vertex_program_dirty)) diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index b164bbe6c8..ef090cbb3f 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -520,6 +520,7 @@ namespace rsx u32 get_zeta_surface_address() const; framebuffer_layout get_framebuffer_layout(rsx::framebuffer_creation_context context); + bool get_scissor(areau& region); /** * Analyze vertex inputs and group all interleaved blocks diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 4c2d7c5b2c..207237413a 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1796,37 +1796,13 @@ void VKGSRender::set_viewport() void VKGSRender::set_scissor() { - if (m_graphics_state & rsx::pipeline_state::scissor_config_state_dirty) + areau scissor; + if (get_scissor(scissor)) { - // Optimistic that the new config will allow us to render - framebuffer_status_valid = true; - } - else if (!(m_graphics_state & rsx::pipeline_state::scissor_config_state_dirty)) - { - // Nothing to do - return; - } - - m_graphics_state &= ~(rsx::pipeline_state::scissor_config_state_dirty | rsx::pipeline_state::scissor_setup_invalid); - - u16 scissor_x = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_x(), false); - u16 scissor_w = rsx::apply_resolution_scale(rsx::method_registers.scissor_width(), true); - u16 scissor_y = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_y(), false); - u16 scissor_h = rsx::apply_resolution_scale(rsx::method_registers.scissor_height(), true); - - m_scissor.extent.height = scissor_h; - m_scissor.extent.width = scissor_w; - m_scissor.offset.x = scissor_x; - m_scissor.offset.y = scissor_y; - - if (scissor_x >= m_viewport.width || scissor_y >= m_viewport.height || scissor_w == 0 || scissor_h == 0) - { - if (!g_cfg.video.strict_rendering_mode) - { - m_graphics_state |= rsx::pipeline_state::scissor_setup_invalid; - framebuffer_status_valid = false; - return; - } + m_scissor.extent.height = scissor.height(); + m_scissor.extent.width = scissor.width(); + m_scissor.offset.x = scissor.x1; + m_scissor.offset.y = scissor.y1; } } diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 56454a2958..97fb6fd1ef 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -2790,6 +2790,8 @@ namespace rsx bind(); bind(); bind(); + bind(); + bind(); bind_array(); bind_range(); bind_range();