From 4a19a2dd24f18b02e8a36a117f4ee3e386c57b82 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Wed, 2 Oct 2019 19:27:48 +0300 Subject: [PATCH] rsx: Explicity describe transfer regions for both source and destination blocks --- Utilities/geometry.h | 8 +++- rpcs3/Emu/RSX/Common/surface_store.h | 51 +++++++++++--------- rpcs3/Emu/RSX/Common/surface_utils.h | 18 +------- rpcs3/Emu/RSX/Common/texture_cache.h | 69 ++++++++++++++-------------- rpcs3/Emu/RSX/GL/GLTextureCache.h | 15 +++++- rpcs3/Emu/RSX/VK/VKTextureCache.h | 32 +++++++++---- 6 files changed, 110 insertions(+), 83 deletions(-) diff --git a/Utilities/geometry.h b/Utilities/geometry.h index e11ebd2a98..0dd57b3baa 100644 --- a/Utilities/geometry.h +++ b/Utilities/geometry.h @@ -618,7 +618,13 @@ struct coord_base { } - constexpr coord_base(T x, T y, T width, T height) : x{ x }, y{ y }, width{ width }, height{ height } + constexpr coord_base(const coord_base& other) + : position{ other.position }, size{ other.size } + { + } + + constexpr coord_base(T x, T y, T width, T height) + : x{ x }, y{ y }, width{ width }, height{ height } { } diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index 667350e6cb..6266b9d3d1 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -768,7 +768,7 @@ namespace rsx auto process_list_function = [&](std::unordered_map& data, bool is_depth) { - for (auto &tex_info : data) + for (auto& tex_info : data) { const auto range = tex_info.second->get_memory_range(); if (!range.overlaps(test_range)) @@ -782,48 +782,49 @@ namespace rsx continue; surface_overlap_info info; + u32 width, height; info.surface = surface; info.base_address = range.start; info.is_depth = is_depth; - const auto normalized_surface_width = surface->get_surface_width(rsx::surface_metrics::bytes) / required_bpp; - const auto normalized_surface_height = surface->get_surface_height(rsx::surface_metrics::samples); + const u32 normalized_surface_width = surface->get_surface_width(rsx::surface_metrics::bytes) / required_bpp; + const u32 normalized_surface_height = surface->get_surface_height(rsx::surface_metrics::samples); if (LIKELY(range.start >= texaddr)) { const auto offset = range.start - texaddr; - info.dst_y = (offset / required_pitch); - info.dst_x = (offset % required_pitch) / required_bpp; + info.dst_area.y = (offset / required_pitch); + info.dst_area.x = (offset % required_pitch) / required_bpp; - if (UNLIKELY(info.dst_x >= required_width || info.dst_y >= required_height)) + if (UNLIKELY(info.dst_area.x >= required_width || info.dst_area.y >= required_height)) { // Out of bounds continue; } - info.src_x = 0; - info.src_y = 0; - info.width = std::min(normalized_surface_width, required_width - info.dst_x); - info.height = std::min(normalized_surface_height, required_height - info.dst_y); + info.src_area.x = 0; + info.src_area.y = 0; + width = std::min(normalized_surface_width, required_width - info.dst_area.x); + height = std::min(normalized_surface_height, required_height - info.dst_area.y); } else { const auto pitch = surface->get_rsx_pitch(); const auto offset = texaddr - range.start; - info.src_y = (offset / pitch); - info.src_x = (offset % pitch) / required_bpp; + info.src_area.y = (offset / pitch); + info.src_area.x = (offset % pitch) / required_bpp; - if (UNLIKELY(info.src_x >= normalized_surface_width || info.src_y >= normalized_surface_height)) + if (UNLIKELY(info.src_area.x >= normalized_surface_width || info.src_area.y >= normalized_surface_height)) { // Region lies outside the actual texture area, but inside the 'tile' // In this case, a small region lies to the top-left corner, partially occupying the target continue; } - info.dst_x = 0; - info.dst_y = 0; - info.width = std::min(required_width, normalized_surface_width - info.src_x); - info.height = std::min(required_height, normalized_surface_height - info.src_y); + info.dst_area.x = 0; + info.dst_area.y = 0; + width = std::min(required_width, normalized_surface_width - info.src_area.x); + height = std::min(required_height, normalized_surface_height - info.src_area.y); } // Delay this as much as possible to avoid side-effects of spamming barrier @@ -833,13 +834,19 @@ namespace rsx continue; } - info.is_clipped = (info.width < required_width || info.height < required_height); + info.is_clipped = (width < required_width || height < required_height); + info.src_area.height = info.dst_area.height = height; + info.dst_area.width = width; if (auto surface_bpp = surface->get_bpp(); UNLIKELY(surface_bpp != required_bpp)) { // Width is calculated in the coordinate-space of the requester; normalize - info.src_x = (info.src_x * required_bpp) / surface_bpp; - info.width = align(info.width * required_bpp, surface_bpp) / surface_bpp; + info.src_area.x = (info.src_area.x * required_bpp) / surface_bpp; + info.src_area.width = align(width * required_bpp, surface_bpp) / surface_bpp; + } + else + { + info.src_area.width = width; } result.push_back(info); @@ -872,8 +879,8 @@ namespace rsx { if (a.surface->last_use_tag == b.surface->last_use_tag) { - const auto area_a = a.width * a.height; - const auto area_b = b.width * b.height; + const auto area_a = a.dst_area.width * a.dst_area.height; + const auto area_b = b.dst_area.width * b.dst_area.height; return area_a < area_b; } diff --git a/rpcs3/Emu/RSX/Common/surface_utils.h b/rpcs3/Emu/RSX/Common/surface_utils.h index 03fdb4deea..090aac66f1 100644 --- a/rpcs3/Emu/RSX/Common/surface_utils.h +++ b/rpcs3/Emu/RSX/Common/surface_utils.h @@ -32,22 +32,8 @@ namespace rsx bool is_depth = false; bool is_clipped = false; - u16 src_x = 0; - u16 src_y = 0; - u16 dst_x = 0; - u16 dst_y = 0; - u16 width = 0; - u16 height = 0; - - areai get_src_area() const - { - return coordi{ {src_x, src_y}, {width, height} }; - } - - areai get_dst_area() const - { - return coordi{ {dst_x, dst_y}, {width, height} }; - } + coordu src_area; + coordu dst_area; }; template diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 743c9ec9b2..0fc2b6cc60 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -136,13 +136,14 @@ namespace rsx enum surface_transform : u32 { identity = 0, - argb_to_bgra = 1 + argb_to_bgra = 1, + coordinate_transform = 2 }; struct copy_region_descriptor { image_resource_type src; - surface_transform xform; + flags32_t xform; u16 src_x; u16 src_y; u16 dst_x; @@ -1476,7 +1477,7 @@ namespace rsx sections[n] = { desc.external_handle, - surface_transform::identity, + surface_transform::coordinate_transform, 0, (u16)(desc.slice_h * n), 0, 0, n, desc.width, desc.height, @@ -1501,7 +1502,7 @@ namespace rsx sections[n] = { desc.external_handle, - surface_transform::identity, + surface_transform::coordinate_transform, 0, (u16)(desc.slice_h * n), 0, 0, n, desc.width, desc.height, @@ -1602,22 +1603,22 @@ namespace rsx return; } - const auto slice_begin = (slice * src_slice_h); - const auto slice_end = (slice_begin + slice_h); + const u32 slice_begin = (slice * src_slice_h); + const u32 slice_end = (slice_begin + slice_h); - const auto section_end = section.dst_y + section.height; - if (section.dst_y >= slice_end || section_end <= slice_begin) + const u32 section_end = section.dst_area.y + section.dst_area.height; + if (section.dst_area.y >= slice_end || section_end <= slice_begin) { // Belongs to a different slice return; } // How much of this slice to read? - int rebased = int(section.dst_y) - slice_begin; - const auto src_x = section.src_x; - const auto dst_x = section.dst_x; - auto src_y = section.src_y; - auto dst_y = section.dst_y; + int rebased = int(section.dst_area.y) - slice_begin; + const auto src_x = section.src_area.x; + const auto dst_x = section.dst_area.x; + auto src_y = section.src_area.y; + auto dst_y = section.dst_area.y; if (rebased < 0) { @@ -1629,10 +1630,10 @@ namespace rsx verify(HERE), dst_y >= slice_begin; dst_y = (dst_y - slice_begin); - const auto h = std::min(section_end, slice_end) - section.dst_y; - const auto src_width = rsx::apply_resolution_scale(section.width, true); + const auto h = std::min(section_end, slice_end) - section.dst_area.y; + const auto src_width = rsx::apply_resolution_scale(section.src_area.width, true); const auto src_height = rsx::apply_resolution_scale(h, true); - const auto dst_width = src_width; + const auto dst_width = rsx::apply_resolution_scale(section.dst_area.width, true); const auto dst_height = src_height; surfaces.push_back @@ -1687,7 +1688,10 @@ namespace rsx return; } - const u16 internal_clip_width = u16(std::get<2>(clipped).width * bpp) / section_bpp; + const u16 dst_w = (u16)std::get<2>(clipped).width; + const u16 src_w = u16(dst_w * bpp) / section_bpp; + const u16 height = (u16)std::get<2>(clipped).height; + if (scaling) { // Since output is upscaled, also upscale on dst @@ -1700,16 +1704,14 @@ namespace rsx rsx::apply_resolution_scale((u16)std::get<1>(clipped).x, true), rsx::apply_resolution_scale((u16)std::get<1>(clipped).y, true), slice, - internal_clip_width, - (u16)std::get<2>(clipped).height, - rsx::apply_resolution_scale(internal_clip_width, true), - rsx::apply_resolution_scale((u16)std::get<2>(clipped).height, true), + src_w, + height, + rsx::apply_resolution_scale(dst_w, true), + rsx::apply_resolution_scale(height, true), }); } else { - const auto src_width = internal_clip_width, dst_width = src_width; - const auto src_height = (u16)std::get<2>(clipped).height, dst_height = src_height; surfaces.push_back ({ section->get_raw_texture(), @@ -1719,10 +1721,10 @@ namespace rsx (u16)std::get<1>(clipped).x, (u16)std::get<1>(clipped).y, 0, - src_width, - src_height, - dst_width, - dst_height, + src_w, + height, + dst_w, + height, }); } }; @@ -2136,10 +2138,9 @@ namespace rsx { // Surface cache data is newer, check if this thing fits our search parameters const auto& last = overlapping_fbos.back(); - if (last.src_x == 0 && last.src_y == 0) + if (last.src_area.x == 0 && last.src_area.y == 0) { - u16 normalized_width = u16(last.width * last.surface->get_bpp()) / bpp; - if (normalized_width >= tex_width && last.height >= required_surface_height) + if (last.dst_area.width >= tex_width && last.dst_area.height >= required_surface_height) { return process_framebuffer_resource_fast(cmd, last.surface, texaddr, format, tex_width, tex_height, depth, slice_h, scale_x, scale_y, extended_dimension, tex.remap(), tex.decoded_remap(), false); @@ -2405,8 +2406,8 @@ namespace rsx return *It; } - auto _w = u32(It->width * It->surface->get_bpp()) / bpp; - auto _h = u32(It->height); + const auto _w = It->dst_area.width; + const auto _h = It->dst_area.height; if (_w < width) { @@ -2629,7 +2630,7 @@ namespace rsx else { // Destination dimensions are relaxed (true) - dst_area = dst_subres.get_src_area(); + dst_area = dst_subres.src_area; dest_texture = dst_subres.surface->get_surface(rsx::surface_access::transfer); typeless_info.dst_context = texture_upload_context::framebuffer_storage; @@ -2812,7 +2813,7 @@ namespace rsx } else { - src_area = src_subres.get_src_area(); + src_area = src_subres.src_area; vram_texture = src_subres.surface->get_surface(rsx::surface_access::read); typeless_info.src_context = texture_upload_context::framebuffer_storage; } diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index e4faf28cf0..e0dfc11c53 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -529,7 +529,7 @@ namespace gl std::vector region = {{ src, - surface_transform::identity, + surface_transform::coordinate_transform, x, y, 0, 0, 0, width, height, width, height }}; @@ -612,6 +612,14 @@ namespace gl auto src_w = slice.src_w; auto src_h = slice.src_h; + if (slice.xform == surface_transform::coordinate_transform) + { + // Dimensions were given in 'dst' space. Work out the real source coordinates + const auto src_bpp = slice.src->pitch() / slice.src->width(); + src_x = (src_x * dst_bpp) / src_bpp; + src_w = (src_w * dst_bpp) / src_bpp; + } + if (auto surface = dynamic_cast(slice.src)) { surface->transform_samples_to_pixels(src_x, src_w, src_y, src_h); @@ -624,8 +632,11 @@ namespace gl tmp = std::make_unique(GL_TEXTURE_2D, convert_w, slice.src->height(), 1, 1, (GLenum)dst_image->get_internal_format()); src_image = tmp.get(); - src_x = u16(src_x * src_bpp) / dst_bpp; gl::copy_typeless(src_image, slice.src); + + // Compute src region in dst format layout + src_x = u16(src_x * src_bpp) / dst_bpp; + src_w = u16(src_w * src_bpp) / dst_bpp; } if (src_w == slice.dst_w && src_h == slice.dst_h) diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 0258426f35..7f7dd79bf9 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -579,6 +579,17 @@ namespace vk auto src_w = section.src_w; auto src_h = section.src_h; + rsx::flags32_t transform = section.xform; + if (section.xform == surface_transform::coordinate_transform) + { + // Dimensions were given in 'dst' space. Work out the real source coordinates + const auto src_bpp = vk::get_format_texel_width(section.src->format()); + src_x = (src_x * dst_bpp) / src_bpp; + src_w = (src_w * dst_bpp) / src_bpp; + + transform &= ~(surface_transform::coordinate_transform); + } + if (auto surface = dynamic_cast(section.src)) { surface->transform_samples_to_pixels(src_x, src_w, src_y, src_h); @@ -586,15 +597,20 @@ namespace vk if (UNLIKELY(typeless)) { - src_image = vk::get_typeless_helper(dst->info.format, src_x + src_w, src_y + src_h); + const auto src_bpp = vk::get_format_texel_width(section.src->format()); + const u16 convert_w = u16(src_w * src_bpp) / dst_bpp; + const u16 convert_x = u16(src_x * src_bpp) / dst_bpp; + + src_image = vk::get_typeless_helper(dst->info.format, convert_x + convert_w, src_y + src_h); src_image->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - const auto src_bpp = vk::get_format_texel_width(section.src->format()); - const u16 convert_w = u16(src_w * dst_bpp) / src_bpp; - const areai src_rect = coordi{{ src_x, src_y }, { convert_w, src_h }}; - const areai dst_rect = coordi{{ src_x, src_y }, { src_w, src_h }}; + const areai src_rect = coordi{{ src_x, src_y }, { src_w, src_h }}; + const areai dst_rect = coordi{{ convert_x, src_y }, { convert_w, src_h }}; vk::copy_image_typeless(cmd, section.src, src_image, src_rect, dst_rect, 1, section.src->aspect(), dst_aspect); src_image->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + src_x = convert_x; + src_w = convert_w; } verify(HERE), src_image->current_layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; @@ -641,7 +657,7 @@ namespace vk _dst->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } - if (section.xform == surface_transform::identity) + if (transform == surface_transform::identity) { vk::copy_scaled_image(cmd, src_image->value, _dst->value, section.src->current_layout, _dst->current_layout, coordi{ { src_x, src_y }, { src_w, src_h } }, @@ -649,7 +665,7 @@ namespace vk 1, src_image->aspect(), src_image->info.format == _dst->info.format, VK_FILTER_NEAREST, src_image->info.format, _dst->info.format); } - else if (section.xform == surface_transform::argb_to_bgra) + else if (transform == surface_transform::argb_to_bgra) { VkBufferImageCopy copy{}; copy.imageExtent = { src_w, src_h, 1 }; @@ -838,7 +854,7 @@ namespace vk std::vector region = {{ source, - surface_transform::identity, + surface_transform::coordinate_transform, x, y, 0, 0, 0, w, h, w, h }};