rsx: Explicity describe transfer regions for both source and destination blocks

This commit is contained in:
kd-11 2019-10-02 19:27:48 +03:00 committed by kd-11
parent 08e674aa28
commit 4a19a2dd24
6 changed files with 110 additions and 83 deletions

View file

@ -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<T>& 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 }
{ {
} }

View file

@ -768,7 +768,7 @@ namespace rsx
auto process_list_function = [&](std::unordered_map<u32, surface_storage_type>& data, bool is_depth) auto process_list_function = [&](std::unordered_map<u32, surface_storage_type>& data, bool is_depth)
{ {
for (auto &tex_info : data) for (auto& tex_info : data)
{ {
const auto range = tex_info.second->get_memory_range(); const auto range = tex_info.second->get_memory_range();
if (!range.overlaps(test_range)) if (!range.overlaps(test_range))
@ -782,48 +782,49 @@ namespace rsx
continue; continue;
surface_overlap_info info; surface_overlap_info info;
u32 width, height;
info.surface = surface; info.surface = surface;
info.base_address = range.start; info.base_address = range.start;
info.is_depth = is_depth; info.is_depth = is_depth;
const auto normalized_surface_width = surface->get_surface_width(rsx::surface_metrics::bytes) / required_bpp; const u32 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_height = surface->get_surface_height(rsx::surface_metrics::samples);
if (LIKELY(range.start >= texaddr)) if (LIKELY(range.start >= texaddr))
{ {
const auto offset = range.start - texaddr; const auto offset = range.start - texaddr;
info.dst_y = (offset / required_pitch); info.dst_area.y = (offset / required_pitch);
info.dst_x = (offset % required_pitch) / required_bpp; 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 // Out of bounds
continue; continue;
} }
info.src_x = 0; info.src_area.x = 0;
info.src_y = 0; info.src_area.y = 0;
info.width = std::min<u32>(normalized_surface_width, required_width - info.dst_x); width = std::min<u32>(normalized_surface_width, required_width - info.dst_area.x);
info.height = std::min<u32>(normalized_surface_height, required_height - info.dst_y); height = std::min<u32>(normalized_surface_height, required_height - info.dst_area.y);
} }
else else
{ {
const auto pitch = surface->get_rsx_pitch(); const auto pitch = surface->get_rsx_pitch();
const auto offset = texaddr - range.start; const auto offset = texaddr - range.start;
info.src_y = (offset / pitch); info.src_area.y = (offset / pitch);
info.src_x = (offset % pitch) / required_bpp; 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' // 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 // In this case, a small region lies to the top-left corner, partially occupying the target
continue; continue;
} }
info.dst_x = 0; info.dst_area.x = 0;
info.dst_y = 0; info.dst_area.y = 0;
info.width = std::min<u32>(required_width, normalized_surface_width - info.src_x); width = std::min<u32>(required_width, normalized_surface_width - info.src_area.x);
info.height = std::min<u32>(required_height, normalized_surface_height - info.src_y); height = std::min<u32>(required_height, normalized_surface_height - info.src_area.y);
} }
// Delay this as much as possible to avoid side-effects of spamming barrier // Delay this as much as possible to avoid side-effects of spamming barrier
@ -833,13 +834,19 @@ namespace rsx
continue; 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)) if (auto surface_bpp = surface->get_bpp(); UNLIKELY(surface_bpp != required_bpp))
{ {
// Width is calculated in the coordinate-space of the requester; normalize // Width is calculated in the coordinate-space of the requester; normalize
info.src_x = (info.src_x * required_bpp) / surface_bpp; info.src_area.x = (info.src_area.x * required_bpp) / surface_bpp;
info.width = align(info.width * required_bpp, surface_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); result.push_back(info);
@ -872,8 +879,8 @@ namespace rsx
{ {
if (a.surface->last_use_tag == b.surface->last_use_tag) if (a.surface->last_use_tag == b.surface->last_use_tag)
{ {
const auto area_a = a.width * a.height; const auto area_a = a.dst_area.width * a.dst_area.height;
const auto area_b = b.width * b.height; const auto area_b = b.dst_area.width * b.dst_area.height;
return area_a < area_b; return area_a < area_b;
} }

View file

@ -32,22 +32,8 @@ namespace rsx
bool is_depth = false; bool is_depth = false;
bool is_clipped = false; bool is_clipped = false;
u16 src_x = 0; coordu src_area;
u16 src_y = 0; coordu dst_area;
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} };
}
}; };
template <typename surface_type> template <typename surface_type>

View file

@ -136,13 +136,14 @@ namespace rsx
enum surface_transform : u32 enum surface_transform : u32
{ {
identity = 0, identity = 0,
argb_to_bgra = 1 argb_to_bgra = 1,
coordinate_transform = 2
}; };
struct copy_region_descriptor struct copy_region_descriptor
{ {
image_resource_type src; image_resource_type src;
surface_transform xform; flags32_t xform;
u16 src_x; u16 src_x;
u16 src_y; u16 src_y;
u16 dst_x; u16 dst_x;
@ -1476,7 +1477,7 @@ namespace rsx
sections[n] = sections[n] =
{ {
desc.external_handle, desc.external_handle,
surface_transform::identity, surface_transform::coordinate_transform,
0, (u16)(desc.slice_h * n), 0, (u16)(desc.slice_h * n),
0, 0, n, 0, 0, n,
desc.width, desc.height, desc.width, desc.height,
@ -1501,7 +1502,7 @@ namespace rsx
sections[n] = sections[n] =
{ {
desc.external_handle, desc.external_handle,
surface_transform::identity, surface_transform::coordinate_transform,
0, (u16)(desc.slice_h * n), 0, (u16)(desc.slice_h * n),
0, 0, n, 0, 0, n,
desc.width, desc.height, desc.width, desc.height,
@ -1602,22 +1603,22 @@ namespace rsx
return; return;
} }
const auto slice_begin = (slice * src_slice_h); const u32 slice_begin = (slice * src_slice_h);
const auto slice_end = (slice_begin + slice_h); const u32 slice_end = (slice_begin + slice_h);
const auto section_end = section.dst_y + section.height; const u32 section_end = section.dst_area.y + section.dst_area.height;
if (section.dst_y >= slice_end || section_end <= slice_begin) if (section.dst_area.y >= slice_end || section_end <= slice_begin)
{ {
// Belongs to a different slice // Belongs to a different slice
return; return;
} }
// How much of this slice to read? // How much of this slice to read?
int rebased = int(section.dst_y) - slice_begin; int rebased = int(section.dst_area.y) - slice_begin;
const auto src_x = section.src_x; const auto src_x = section.src_area.x;
const auto dst_x = section.dst_x; const auto dst_x = section.dst_area.x;
auto src_y = section.src_y; auto src_y = section.src_area.y;
auto dst_y = section.dst_y; auto dst_y = section.dst_area.y;
if (rebased < 0) if (rebased < 0)
{ {
@ -1629,10 +1630,10 @@ namespace rsx
verify(HERE), dst_y >= slice_begin; verify(HERE), dst_y >= slice_begin;
dst_y = (dst_y - slice_begin); dst_y = (dst_y - slice_begin);
const auto h = std::min(section_end, slice_end) - section.dst_y; const auto h = std::min(section_end, slice_end) - section.dst_area.y;
const auto src_width = rsx::apply_resolution_scale(section.width, true); 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 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; const auto dst_height = src_height;
surfaces.push_back surfaces.push_back
@ -1687,7 +1688,10 @@ namespace rsx
return; 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) if (scaling)
{ {
// Since output is upscaled, also upscale on dst // 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).x, true),
rsx::apply_resolution_scale((u16)std::get<1>(clipped).y, true), rsx::apply_resolution_scale((u16)std::get<1>(clipped).y, true),
slice, slice,
internal_clip_width, src_w,
(u16)std::get<2>(clipped).height, height,
rsx::apply_resolution_scale(internal_clip_width, true), rsx::apply_resolution_scale(dst_w, true),
rsx::apply_resolution_scale((u16)std::get<2>(clipped).height, true), rsx::apply_resolution_scale(height, true),
}); });
} }
else 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 surfaces.push_back
({ ({
section->get_raw_texture(), section->get_raw_texture(),
@ -1719,10 +1721,10 @@ namespace rsx
(u16)std::get<1>(clipped).x, (u16)std::get<1>(clipped).x,
(u16)std::get<1>(clipped).y, (u16)std::get<1>(clipped).y,
0, 0,
src_width, src_w,
src_height, height,
dst_width, dst_w,
dst_height, height,
}); });
} }
}; };
@ -2136,10 +2138,9 @@ namespace rsx
{ {
// Surface cache data is newer, check if this thing fits our search parameters // Surface cache data is newer, check if this thing fits our search parameters
const auto& last = overlapping_fbos.back(); 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 (last.dst_area.width >= tex_width && last.dst_area.height >= required_surface_height)
if (normalized_width >= tex_width && last.height >= required_surface_height)
{ {
return process_framebuffer_resource_fast(cmd, last.surface, texaddr, format, tex_width, tex_height, depth, slice_h, 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); scale_x, scale_y, extended_dimension, tex.remap(), tex.decoded_remap(), false);
@ -2405,8 +2406,8 @@ namespace rsx
return *It; return *It;
} }
auto _w = u32(It->width * It->surface->get_bpp()) / bpp; const auto _w = It->dst_area.width;
auto _h = u32(It->height); const auto _h = It->dst_area.height;
if (_w < width) if (_w < width)
{ {
@ -2629,7 +2630,7 @@ namespace rsx
else else
{ {
// Destination dimensions are relaxed (true) // 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); dest_texture = dst_subres.surface->get_surface(rsx::surface_access::transfer);
typeless_info.dst_context = texture_upload_context::framebuffer_storage; typeless_info.dst_context = texture_upload_context::framebuffer_storage;
@ -2812,7 +2813,7 @@ namespace rsx
} }
else 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); vram_texture = src_subres.surface->get_surface(rsx::surface_access::read);
typeless_info.src_context = texture_upload_context::framebuffer_storage; typeless_info.src_context = texture_upload_context::framebuffer_storage;
} }

View file

@ -529,7 +529,7 @@ namespace gl
std::vector<copy_region_descriptor> region = std::vector<copy_region_descriptor> region =
{{ {{
src, src,
surface_transform::identity, surface_transform::coordinate_transform,
x, y, 0, 0, 0, x, y, 0, 0, 0,
width, height, width, height width, height, width, height
}}; }};
@ -612,6 +612,14 @@ namespace gl
auto src_w = slice.src_w; auto src_w = slice.src_w;
auto src_h = slice.src_h; 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<gl::render_target*>(slice.src)) if (auto surface = dynamic_cast<gl::render_target*>(slice.src))
{ {
surface->transform_samples_to_pixels(src_x, src_w, src_y, src_h); surface->transform_samples_to_pixels(src_x, src_w, src_y, src_h);
@ -624,8 +632,11 @@ namespace gl
tmp = std::make_unique<texture>(GL_TEXTURE_2D, convert_w, slice.src->height(), 1, 1, (GLenum)dst_image->get_internal_format()); tmp = std::make_unique<texture>(GL_TEXTURE_2D, convert_w, slice.src->height(), 1, 1, (GLenum)dst_image->get_internal_format());
src_image = tmp.get(); src_image = tmp.get();
src_x = u16(src_x * src_bpp) / dst_bpp;
gl::copy_typeless(src_image, slice.src); 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) if (src_w == slice.dst_w && src_h == slice.dst_h)

View file

@ -579,6 +579,17 @@ namespace vk
auto src_w = section.src_w; auto src_w = section.src_w;
auto src_h = section.src_h; 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<vk::render_target*>(section.src)) if (auto surface = dynamic_cast<vk::render_target*>(section.src))
{ {
surface->transform_samples_to_pixels(src_x, src_w, src_y, src_h); surface->transform_samples_to_pixels(src_x, src_w, src_y, src_h);
@ -586,15 +597,20 @@ namespace vk
if (UNLIKELY(typeless)) 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); src_image->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
const auto src_bpp = vk::get_format_texel_width(section.src->format()); const areai src_rect = coordi{{ src_x, src_y }, { src_w, src_h }};
const u16 convert_w = u16(src_w * dst_bpp) / src_bpp; const areai dst_rect = coordi{{ convert_x, src_y }, { convert_w, src_h }};
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 }};
vk::copy_image_typeless(cmd, section.src, src_image, src_rect, dst_rect, 1, section.src->aspect(), dst_aspect); 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_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; 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); _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, 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 } }, 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, 1, src_image->aspect(), src_image->info.format == _dst->info.format,
VK_FILTER_NEAREST, 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{}; VkBufferImageCopy copy{};
copy.imageExtent = { src_w, src_h, 1 }; copy.imageExtent = { src_w, src_h, 1 };
@ -838,7 +854,7 @@ namespace vk
std::vector<copy_region_descriptor> region = std::vector<copy_region_descriptor> region =
{{ {{
source, source,
surface_transform::identity, surface_transform::coordinate_transform,
x, y, 0, 0, 0, x, y, 0, 0, 0,
w, h, w, h w, h, w, h
}}; }};