diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.cpp b/rpcs3/Emu/RSX/GL/GLTextureCache.cpp index e5a2888708..45ab652d32 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.cpp +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.cpp @@ -258,14 +258,12 @@ namespace gl } else { - ensure(dst_image->get_target() == gl::texture::target::texture2D); - auto _blitter = gl::g_hw_blitter; const areai src_rect = { src_x, src_y, src_x + src_w, src_y + src_h }; const areai dst_rect = { slice.dst_x, slice.dst_y, slice.dst_x + slice.dst_w, slice.dst_y + slice.dst_h }; gl::texture* _dst; - if (src_image->get_internal_format() == dst_image->get_internal_format() && slice.level == 0) + if (src_image->get_internal_format() == dst_image->get_internal_format() && slice.level == 0 && slice.dst_z == 0) { _dst = dst_image; } diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp index b0344fc9e6..4d85eb437a 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp @@ -276,7 +276,32 @@ namespace vk for (const auto& section : sections_to_transfer) { if (!section.src) + { continue; + } + + // Generates a region to write data to the final destination + const auto get_output_region = [&](s32 in_x, s32 in_y, u32 w, u32 h, vk::image* data_src) + { + VkImageCopy copy_rgn = { + .srcSubresource = { data_src->aspect(), 0, 0, 1}, + .srcOffset = { in_x, in_y, 0 }, + .dstSubresource = { dst_aspect, section.level, 0, 1 }, + .dstOffset = { section.dst_x, section.dst_y, 0 }, + .extent = { w, h, 1 } + }; + + if (dst->info.imageType == VK_IMAGE_TYPE_3D) + { + copy_rgn.dstOffset.z = section.dst_z; + } + else + { + copy_rgn.dstSubresource.baseArrayLayer = section.dst_z; + } + + return copy_rgn; + }; const bool typeless = section.src->aspect() != dst_aspect || !formats_are_bitcast_compatible(dst, section.src); @@ -333,11 +358,12 @@ namespace vk src_image->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 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 }}; + const areai dst_rect = coordi{{ 0, 0 }, { convert_w, src_h }}; vk::copy_image_typeless(cmd, section.src, src_image, src_rect, dst_rect, 1); src_image->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - src_x = convert_x; + src_x = 0; + src_y = 0; src_w = convert_w; } @@ -345,51 +371,47 @@ namespace vk // Final aspect mask of the 'final' transfer source const auto new_src_aspect = src_image->aspect(); + const bool require_scaling = src_w != section.dst_w || src_h != section.dst_h; - if (src_w == section.dst_w && src_h == section.dst_h && transform == rsx::surface_transform::identity) [[likely]] + if (!require_scaling && transform == rsx::surface_transform::identity) [[likely]] { - VkImageCopy copy_rgn; - copy_rgn.srcOffset = { src_x, src_y, 0 }; - copy_rgn.dstOffset = { section.dst_x, section.dst_y, 0 }; - copy_rgn.dstSubresource = { dst_aspect, 0, 0, 1 }; - copy_rgn.srcSubresource = { new_src_aspect, 0, 0, 1 }; - copy_rgn.extent = { src_w, src_h, 1 }; - - if (dst->info.imageType == VK_IMAGE_TYPE_3D) - { - copy_rgn.dstOffset.z = section.dst_z; - } - else - { - copy_rgn.dstSubresource.baseArrayLayer = section.dst_z; - copy_rgn.dstSubresource.mipLevel = section.level; - } - + const auto copy_rgn = get_output_region(src_x, src_y, src_w, src_h, src_image); vkCmdCopyImage(cmd, src_image->value, src_image->current_layout, dst->value, dst->current_layout, 1, ©_rgn); } else { - ensure(section.dst_z == 0); - u16 dst_x = section.dst_x, dst_y = section.dst_y; vk::image* _dst; - if (src_image->info.format == dst->info.format && section.level == 0) [[likely]] + // Check for best-case scenario - we write directly to the output in this case + if (src_image->info.format == dst->info.format && + section.level == 0 && + section.dst_z == 0) [[likely]] { _dst = dst; } else { // Either a bitcast is required or a scale+copy to mipmap level - _dst = vk::get_typeless_helper(src_image->format(), src_image->format_class(), dst->width(), dst->height() * 2); + const u32 requested_width = dst->width(); + const u32 requested_height = src_y + src_h + section.dst_h; + _dst = vk::get_typeless_helper(src_image->format(), src_image->format_class(), requested_width, requested_height); _dst->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } + if (_dst == src_image) + { + // Write-to-self situation. Account for the initial typeless copy. + ensure(dst != _dst); + dst_x = 0; + dst_y = src_y + src_h; + } + if (transform == rsx::surface_transform::identity) { vk::copy_scaled_image(cmd, src_image, _dst, coordi{ { src_x, src_y }, { src_w, src_h } }, - coordi{ { section.dst_x, section.dst_y }, { section.dst_w, section.dst_h } }, + coordi{ { dst_x, dst_y }, { section.dst_w, section.dst_h } }, 1, src_image->format() == _dst->format(), VK_FILTER_NEAREST); } @@ -413,23 +435,16 @@ namespace vk vk::insert_buffer_memory_barrier(cmd, scratch_buf->value, 0, mem_length, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); - auto tmp = vk::get_typeless_helper(src_image->format(), src_image->format_class(), section.dst_x + section.dst_w, section.dst_y + section.dst_h); + auto tmp = vk::get_typeless_helper(src_image->format(), src_image->format_class(), section.dst_w, section.dst_h); tmp->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + dst_x = dst_y = 0; copy.imageOffset = { 0, 0, 0 }; vkCmdCopyBufferToImage(cmd, scratch_buf->value, tmp->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); - dst_x = 0; - dst_y = 0; - - if (src_w != section.dst_w || src_h != section.dst_h) + if (require_scaling) { // Optionally scale if needed - if (tmp == _dst) [[unlikely]] - { - dst_y = src_h; - } - vk::copy_scaled_image(cmd, tmp, _dst, areai{ 0, 0, src_w, static_cast(src_h) }, coordi{ { dst_x, dst_y }, { section.dst_w, section.dst_h } }, @@ -449,13 +464,7 @@ namespace vk if (_dst != dst) [[unlikely]] { // Casting comes after the scaling! - VkImageCopy copy_rgn; - copy_rgn.srcOffset = { s32(dst_x), s32(dst_y), 0 }; - copy_rgn.dstOffset = { section.dst_x, section.dst_y, 0 }; - copy_rgn.dstSubresource = { dst_aspect, section.level, 0, 1 }; - copy_rgn.srcSubresource = { _dst->aspect(), 0, 0, 1 }; - copy_rgn.extent = { section.dst_w, section.dst_h, 1 }; - + const auto copy_rgn = get_output_region(dst_x, dst_y, section.dst_w, section.dst_h, _dst); _dst->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); vkCmdCopyImage(cmd, _dst->value, _dst->current_layout, dst->value, dst->current_layout, 1, ©_rgn); }