From edb2b60f2fd46647022d0261b2522814335a265d Mon Sep 17 00:00:00 2001 From: kd-11 Date: Wed, 17 May 2023 18:22:58 +0300 Subject: [PATCH] rsx: Perform region clipping in a normalized coordinate space - Depending on what the caller wants to do, the scaling will be different for src vs dst calculations. We cannot reliably handle this in the callee --- rpcs3/Emu/RSX/Common/surface_utils.h | 2 +- rpcs3/Emu/RSX/Common/texture_cache_helpers.h | 37 +++++++++++--------- rpcs3/Emu/RSX/rsx_utils.h | 8 ++--- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/surface_utils.h b/rpcs3/Emu/RSX/Common/surface_utils.h index 7b2b251fcf..d1c5f79bfc 100644 --- a/rpcs3/Emu/RSX/Common/surface_utils.h +++ b/rpcs3/Emu/RSX/Common/surface_utils.h @@ -560,7 +560,7 @@ namespace rsx const auto parent_w = surface->template get_surface_width(); const auto parent_h = surface->template get_surface_height(); - const auto [src_offset, dst_offset, size] = rsx::intersect_region(surface->base_addr, parent_w, parent_h, 1, base_addr, child_w, child_h, 1, get_rsx_pitch()); + const auto [src_offset, dst_offset, size] = rsx::intersect_region(surface->base_addr, parent_w, parent_h, base_addr, child_w, child_h, get_rsx_pitch()); if (!size.width || !size.height) { diff --git a/rpcs3/Emu/RSX/Common/texture_cache_helpers.h b/rpcs3/Emu/RSX/Common/texture_cache_helpers.h index 0a26b36e3c..8764551b9d 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache_helpers.h +++ b/rpcs3/Emu/RSX/Common/texture_cache_helpers.h @@ -323,50 +323,55 @@ namespace rsx slice, src_width, src_height, dst_width, dst_height - }); + }); }; auto add_local_resource = [&](auto& section, u32 address, u16 slice, bool scaling = true) { - // Intersect this resource with the original one + // Intersect this resource with the original one. + // Note that intersection takes place in a normalized coordinate space (bpp = 1) const u32 section_bpp = get_format_block_size_in_bytes(section->get_gcm_format()); - const u32 normalized_width = (section->get_width() * section_bpp) / attr.bpp; + const u32 normalized_section_width = (section->get_width() * section_bpp); + const u32 normalized_attr_width = (attr.width * attr.bpp); - const auto [src_offset, dst_offset, dst_size] = rsx::intersect_region( - section->get_section_base(), normalized_width, section->get_height(), section_bpp, /* parent region (extractee) */ - address, attr.width, attr.slice_h, attr.bpp, /* child region (extracted) */ + auto [src_offset, dst_offset, dimensions] = rsx::intersect_region( + section->get_section_base(), normalized_section_width, section->get_height(), /* parent region (extractee) */ + address, normalized_attr_width, attr.slice_h, /* child region (extracted) */ attr.pitch); - if (!dst_size.width || !dst_size.height) + if (!dimensions.width || !dimensions.height) { // Out of bounds, invalid intersection return; } - ensure(src_offset.x < normalized_width && src_offset.y < section->get_height()); - ensure(dst_offset.x < attr.width && dst_offset.y < attr.slice_h); + // The intersection takes place in a normalized coordinate space. Now we convert back to domain-specific + src_offset.x /= section_bpp; + dst_offset.x /= attr.bpp; + const size2u dst_size = { dimensions.width / attr.bpp, dimensions.height }; + const size2u src_size = { dimensions.width / section_bpp, dimensions.height }; - const u32 slice_begin = slice * attr.slice_h; - const u32 slice_end = slice_begin + attr.height; + const u32 dst_slice_begin = slice * attr.slice_h; // Output slice low watermark + const u32 dst_slice_end = slice_begin + attr.height; // Output slice high watermark const auto dst_y = dst_offset.y; const auto dst_h = dst_size.height; - const auto section_end = dst_y + dst_h; - if (dst_y >= slice_end || section_end <= slice_begin) + const auto write_section_end = dst_y + dst_h; + if (dst_y >= dst_slice_end || write_section_end <= dst_slice_begin) { // Belongs to a different slice return; } const u16 dst_w = static_cast(dst_size.width); - const u16 src_w = static_cast(dst_w * attr.bpp) / section_bpp; - const u16 height = std::min(slice_end, section_end) - dst_y; + const u16 src_w = static_cast(src_size.width); + const u16 height = std::min(dst_slice_end, write_section_end) - dst_y; if (scaling) { // Since output is upscaled, also upscale on dst - const auto [_dst_x, _dst_y] = rsx::apply_resolution_scale(static_cast(dst_offset.x), static_cast(dst_y - slice_begin), attr.width, attr.height); + const auto [_dst_x, _dst_y] = rsx::apply_resolution_scale(static_cast(dst_offset.x), static_cast(dst_y - dst_slice_begin), attr.width, attr.height); const auto [_dst_w, _dst_h] = rsx::apply_resolution_scale(dst_w, height, attr.width, attr.height); out.push_back diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index a8bf25c5bf..0f303c989b 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -559,8 +559,8 @@ namespace rsx * Extracts from 'parent' a region that fits in 'child' */ static inline std::tuple intersect_region( - u32 parent_address, u16 parent_w, u16 parent_h, u16 parent_bpp, - u32 child_address, u16 child_w, u16 child_h, u32 child_bpp, + u32 parent_address, u16 parent_w, u16 parent_h, + u32 child_address, u16 child_w, u16 child_h, u32 pitch) { if (child_address < parent_address) @@ -569,7 +569,7 @@ namespace rsx const auto src_x = 0u; const auto src_y = 0u; const auto dst_y = (offset / pitch); - const auto dst_x = (offset % pitch) / child_bpp; + const auto dst_x = (offset % pitch); const auto w = std::min(parent_w, std::max(child_w, dst_x) - dst_x); // Clamp negatives to 0! const auto h = std::min(parent_h, std::max(child_h, dst_y) - dst_y); @@ -579,7 +579,7 @@ namespace rsx { const auto offset = child_address - parent_address; const auto src_y = (offset / pitch); - const auto src_x = (offset % pitch) / parent_bpp; + const auto src_x = (offset % pitch); const auto dst_x = 0u; const auto dst_y = 0u; const auto w = std::min(child_w, std::max(parent_w, src_x) - src_x);