diff --git a/rpcs3/Emu/RSX/VK/VKTexture.cpp b/rpcs3/Emu/RSX/VK/VKTexture.cpp index cb8628854d..f7e904b79c 100644 --- a/rpcs3/Emu/RSX/VK/VKTexture.cpp +++ b/rpcs3/Emu/RSX/VK/VKTexture.cpp @@ -1061,20 +1061,23 @@ namespace vk if (format != src->format()) { - const auto internal_width = src->width() * xfer_info.src_scaling_hint; - const auto aspect = vk::get_aspect_flags(format); + // Normalize input region (memory optimization) + const auto old_src_area = src_area; + src_area.y2 -= src_area.y1; + src_area.y1 = 0; + src_area.x2 = static_cast(src_area.width() * xfer_info.src_scaling_hint); + src_area.x1 = 0; // Transfer bits from src to typeless src - real_src = vk::get_typeless_helper(format, rsx::classify_format(xfer_info.src_gcm_format), static_cast(internal_width), src->height()); - vk::change_image_layout(cmd, real_src, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, { aspect, 0, 1, 0, 1 }); - - vk::copy_image_typeless(cmd, src, real_src, { 0, 0, static_cast(src->width()), static_cast(src->height()) }, { 0, 0, static_cast(internal_width), static_cast(src->height()) }, 1); - - src_area.x1 = static_cast(src_area.x1 * xfer_info.src_scaling_hint); - src_area.x2 = static_cast(src_area.x2 * xfer_info.src_scaling_hint); + real_src = vk::get_typeless_helper(format, rsx::classify_format(xfer_info.src_gcm_format), src_area.width(), src_area.height()); + real_src->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + vk::copy_image_typeless(cmd, src, real_src, old_src_area, src_area, 1); } } + // Save output region descriptor + const auto old_dst_area = dst_area; + if (xfer_info.dst_is_typeless) { const auto format = xfer_info.dst_native_format_override ? @@ -1083,20 +1086,39 @@ namespace vk if (format != dst->format()) { - const auto internal_width = dst->width() * xfer_info.dst_scaling_hint; - const auto aspect = vk::get_aspect_flags(format); + // Normalize output region (memory optimization) + dst_area.y2 -= dst_area.y1; + dst_area.y1 = 0; + dst_area.x2 = static_cast(dst_area.width() * xfer_info.dst_scaling_hint); + dst_area.x1 = 0; - // Transfer bits from dst to typeless dst - real_dst = vk::get_typeless_helper(format, rsx::classify_format(xfer_info.dst_gcm_format), static_cast(internal_width), dst->height()); - vk::change_image_layout(cmd, real_dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, { aspect, 0, 1, 0, 1 }); + // Account for possibility where SRC is typeless and DST is typeless and both map to the same format + auto required_height = dst_area.height(); + if (real_src != src && real_src->format() == format) + { + required_height += src_area.height(); - vk::copy_image_typeless(cmd, dst, real_dst, { 0, 0, static_cast(dst->width()), static_cast(dst->height()) }, { 0, 0, static_cast(internal_width), static_cast(dst->height()) }, 1); + // Move the dst area just below the src area + dst_area.y1 += src_area.y2; + dst_area.y2 += src_area.y2; + } - dst_area.x1 = static_cast(dst_area.x1 * xfer_info.dst_scaling_hint); - dst_area.x2 = static_cast(dst_area.x2 * xfer_info.dst_scaling_hint); + real_dst = vk::get_typeless_helper(format, rsx::classify_format(xfer_info.dst_gcm_format), dst_area.width(), required_height); } } + // Prepare typeless resources for the operation if needed + if (real_src != src) + { + const auto layout = ((real_src == real_dst) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + real_src->change_layout(cmd, layout); + } + + if (real_dst != dst && real_dst != real_src) + { + real_dst->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + } + // Checks if (src_area.x2 <= src_area.x1 || src_area.y2 <= src_area.y1 || dst_area.x2 <= dst_area.x1 || dst_area.y2 <= dst_area.y1) { @@ -1134,8 +1156,7 @@ namespace vk if (real_dst != dst) { - auto internal_width = dst->width() * xfer_info.dst_scaling_hint; - vk::copy_image_typeless(cmd, real_dst, dst, { 0, 0, static_cast(internal_width), static_cast(dst->height()) }, { 0, 0, static_cast(dst->width()), static_cast(dst->height()) }, 1); + vk::copy_image_typeless(cmd, real_dst, dst, dst_area, old_dst_area, 1); } } }