mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-14 02:38:37 +12:00
vk: Implement typeless image transport
This commit is contained in:
parent
dd4c13b625
commit
0d5c071eee
4 changed files with 118 additions and 9 deletions
|
@ -9,6 +9,7 @@ namespace vk
|
|||
|
||||
std::unique_ptr<image> g_null_texture;
|
||||
std::unique_ptr<image_view> g_null_image_view;
|
||||
std::unique_ptr<buffer> g_scratch_buffer;
|
||||
std::unordered_map<u32, std::unique_ptr<image>> g_typeless_textures;
|
||||
|
||||
VkSampler g_null_sampler = nullptr;
|
||||
|
@ -187,6 +188,19 @@ namespace vk
|
|||
return ptr.get();
|
||||
}
|
||||
|
||||
vk::buffer* get_scratch_buffer()
|
||||
{
|
||||
if (!g_scratch_buffer)
|
||||
{
|
||||
// 32M disposable scratch memory
|
||||
g_scratch_buffer = std::make_unique<vk::buffer>(*g_current_renderer, 32 * 0x100000,
|
||||
g_current_renderer->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, 0);
|
||||
}
|
||||
|
||||
return g_scratch_buffer.get();
|
||||
}
|
||||
|
||||
void acquire_global_submit_lock()
|
||||
{
|
||||
g_submit_mutex.lock();
|
||||
|
@ -201,6 +215,7 @@ namespace vk
|
|||
{
|
||||
g_null_texture.reset();
|
||||
g_null_image_view.reset();
|
||||
g_scratch_buffer.reset();
|
||||
|
||||
g_typeless_textures.clear();
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace vk
|
|||
class physical_device;
|
||||
class command_buffer;
|
||||
struct image;
|
||||
struct buffer;
|
||||
struct vk_data_heap;
|
||||
class mem_allocator_base;
|
||||
struct memory_type_mapping;
|
||||
|
@ -100,6 +101,7 @@ namespace vk
|
|||
VkSampler null_sampler();
|
||||
VkImageView null_image_view(vk::command_buffer&);
|
||||
image* get_typeless_helper(VkFormat format);
|
||||
buffer* get_scratch_buffer();
|
||||
|
||||
memory_type_mapping get_memory_mapping(const physical_device& dev);
|
||||
gpu_formats_support get_optimal_tiling_supported_formats(const physical_device& dev);
|
||||
|
@ -124,6 +126,10 @@ namespace vk
|
|||
void change_image_layout(VkCommandBuffer cmd, vk::image *image, VkImageLayout new_layout, VkImageSubresourceRange range);
|
||||
void change_image_layout(VkCommandBuffer cmd, vk::image *image, VkImageLayout new_layout);
|
||||
|
||||
void copy_image_typeless(VkCommandBuffer cmd, VkImage &src, VkImage &dst, VkImageLayout srcLayout, VkImageLayout dstLayout,
|
||||
const areai& src_rect, const areai& dst_rect, u32 mipmaps, VkImageAspectFlags src_aspect, VkImageAspectFlags dst_aspect,
|
||||
VkImageAspectFlags src_transfer_mask = 0xFF, VkImageAspectFlags dst_transfer_mask = 0xFF);
|
||||
|
||||
void copy_image(VkCommandBuffer cmd, VkImage &src, VkImage &dst, VkImageLayout srcLayout, VkImageLayout dstLayout,
|
||||
const areai& src_rect, const areai& dst_rect, u32 mipmaps, VkImageAspectFlags src_aspect, VkImageAspectFlags dst_aspect,
|
||||
VkImageAspectFlags src_transfer_mask = 0xFF, VkImageAspectFlags dst_transfer_mask = 0xFF);
|
||||
|
@ -701,7 +707,7 @@ namespace vk
|
|||
VkBufferCreateInfo info = {};
|
||||
std::unique_ptr<vk::memory_block> memory;
|
||||
|
||||
buffer(vk::render_device& dev, u64 size, uint32_t memory_type_index, uint32_t access_flags, VkBufferUsageFlagBits usage, VkBufferCreateFlags flags)
|
||||
buffer(const vk::render_device& dev, u64 size, uint32_t memory_type_index, uint32_t access_flags, VkBufferUsageFlags usage, VkBufferCreateFlags flags)
|
||||
: m_device(dev)
|
||||
{
|
||||
info.size = size;
|
||||
|
|
|
@ -55,6 +55,51 @@ namespace vk
|
|||
}
|
||||
}
|
||||
|
||||
void copy_image_typeless(VkCommandBuffer cmd, VkImage &src, VkImage &dst, VkImageLayout srcLayout, VkImageLayout dstLayout,
|
||||
const areai& src_rect, const areai& dst_rect, u32 mipmaps, VkImageAspectFlags src_aspect, VkImageAspectFlags dst_aspect,
|
||||
VkImageAspectFlags src_transfer_mask, VkImageAspectFlags dst_transfer_mask)
|
||||
{
|
||||
if (src == dst)
|
||||
{
|
||||
copy_image(cmd, src, dst, srcLayout, dstLayout, src_rect, dst_rect, mipmaps, src_aspect, dst_aspect, src_transfer_mask, dst_transfer_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
auto preferred_src_format = (src == dst) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
auto preferred_dst_format = (src == dst) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
|
||||
if (srcLayout != preferred_src_format)
|
||||
change_image_layout(cmd, src, srcLayout, preferred_src_format, vk::get_image_subresource_range(0, 0, 1, 1, src_aspect));
|
||||
|
||||
if (dstLayout != preferred_dst_format)
|
||||
change_image_layout(cmd, dst, dstLayout, preferred_dst_format, vk::get_image_subresource_range(0, 0, 1, 1, dst_aspect));
|
||||
|
||||
auto scratch_buf = vk::get_scratch_buffer();
|
||||
VkBufferImageCopy src_copy{}, dst_copy{};
|
||||
src_copy.imageExtent = { u32(src_rect.x2 - src_rect.x1), u32(src_rect.y2 - src_rect.y1), 1 };
|
||||
src_copy.imageOffset = { src_rect.x1, src_rect.y1, 0 };
|
||||
src_copy.imageSubresource = { src_aspect & src_transfer_mask, 0, 0, 1 };
|
||||
|
||||
dst_copy.imageExtent = { u32(dst_rect.x2 - dst_rect.x1), u32(dst_rect.y2 - dst_rect.y1), 1 };
|
||||
dst_copy.imageOffset = { dst_rect.x1, dst_rect.y1, 0 };
|
||||
dst_copy.imageSubresource = { dst_aspect & dst_transfer_mask, 0, 0, 1 };
|
||||
|
||||
for (u32 mip_level = 0; mip_level < mipmaps; ++mip_level)
|
||||
{
|
||||
vkCmdCopyImageToBuffer(cmd, src, preferred_src_format, scratch_buf->value, 1, &src_copy);
|
||||
vkCmdCopyBufferToImage(cmd, scratch_buf->value, dst, preferred_dst_format, 1, &dst_copy);
|
||||
|
||||
src_copy.imageSubresource.mipLevel++;
|
||||
dst_copy.imageSubresource.mipLevel++;
|
||||
}
|
||||
|
||||
if (srcLayout != preferred_src_format)
|
||||
change_image_layout(cmd, src, preferred_src_format, srcLayout, vk::get_image_subresource_range(0, 0, 1, 1, src_aspect));
|
||||
|
||||
if (dstLayout != preferred_dst_format)
|
||||
change_image_layout(cmd, dst, preferred_dst_format, dstLayout, vk::get_image_subresource_range(0, 0, 1, 1, dst_aspect));
|
||||
}
|
||||
|
||||
void copy_image(VkCommandBuffer cmd, VkImage &src, VkImage &dst, VkImageLayout srcLayout, VkImageLayout dstLayout,
|
||||
const areai& src_rect, const areai& dst_rect, u32 mipmaps, VkImageAspectFlags src_aspect, VkImageAspectFlags dst_aspect,
|
||||
VkImageAspectFlags src_transfer_mask, VkImageAspectFlags dst_transfer_mask)
|
||||
|
|
|
@ -1177,8 +1177,44 @@ namespace vk
|
|||
VkFormat format;
|
||||
blit_helper(vk::command_buffer *c) : commands(c) {}
|
||||
|
||||
void scale_image(vk::image* src, vk::image* dst, areai src_area, areai dst_area, bool interpolate, bool /*is_depth*/, const rsx::typeless_xfer& /*typeless*/)
|
||||
void scale_image(vk::image* src, vk::image* dst, areai src_area, areai dst_area, bool interpolate, bool /*is_depth*/, const rsx::typeless_xfer& xfer_info)
|
||||
{
|
||||
const auto src_aspect = vk::get_aspect_flags(src->info.format);
|
||||
const auto dst_aspect = vk::get_aspect_flags(dst->info.format);
|
||||
|
||||
vk::image* real_src = src;
|
||||
vk::image* real_dst = dst;
|
||||
|
||||
if (xfer_info.src_is_typeless)
|
||||
{
|
||||
auto internal_width = src->width() * xfer_info.src_scaling_hint;
|
||||
auto format = vk::get_compatible_sampler_format(vk::get_current_renderer()->get_formats_support(), xfer_info.src_gcm_format);
|
||||
|
||||
// Transfer bits from src to typeless src
|
||||
real_src = vk::get_typeless_helper(format);
|
||||
src_area.x1 = (u16)(src_area.x1 * xfer_info.src_scaling_hint);
|
||||
src_area.x2 = (u16)(src_area.x2 * xfer_info.src_scaling_hint);
|
||||
|
||||
vk::copy_image_typeless(*commands, src->value, real_src->value, src->current_layout, real_src->current_layout,
|
||||
{ 0, 0, (s32)src->width(), (s32)src->height() }, { 0, 0, (s32)internal_width, (s32)src->height() }, 1,
|
||||
vk::get_aspect_flags(src->info.format), vk::get_aspect_flags(format));
|
||||
}
|
||||
|
||||
if (xfer_info.dst_is_typeless)
|
||||
{
|
||||
auto internal_width = dst->width() * xfer_info.dst_scaling_hint;
|
||||
auto format = vk::get_compatible_sampler_format(vk::get_current_renderer()->get_formats_support(), xfer_info.dst_gcm_format);
|
||||
|
||||
// Transfer bits from dst to typeless dst
|
||||
real_dst = vk::get_typeless_helper(format);
|
||||
dst_area.x1 = (u16)(dst_area.x1 * xfer_info.dst_scaling_hint);
|
||||
dst_area.x2 = (u16)(dst_area.x2 * xfer_info.dst_scaling_hint);
|
||||
|
||||
vk::copy_image_typeless(*commands, dst->value, real_dst->value, dst->current_layout, real_dst->current_layout,
|
||||
{ 0, 0, (s32)dst->width(), (s32)dst->height() }, { 0, 0, (s32)internal_width, (s32)dst->height() }, 1,
|
||||
vk::get_aspect_flags(dst->info.format), vk::get_aspect_flags(format));
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
|
@ -1186,29 +1222,36 @@ namespace vk
|
|||
return;
|
||||
}
|
||||
|
||||
if (src_area.x1 < 0 || src_area.x2 > (s32)src->width() || src_area.y1 < 0 || src_area.y2 > (s32)src->height())
|
||||
if (src_area.x1 < 0 || src_area.x2 >(s32)real_src->width() || src_area.y1 < 0 || src_area.y2 >(s32)real_src->height())
|
||||
{
|
||||
LOG_ERROR(RSX, "Blit request denied because the source region does not fit!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dst_area.x1 < 0 || dst_area.x2 > (s32)dst->width() || dst_area.y1 < 0 || dst_area.y2 > (s32)dst->height())
|
||||
if (dst_area.x1 < 0 || dst_area.x2 >(s32)real_dst->width() || dst_area.y1 < 0 || dst_area.y2 >(s32)real_dst->height())
|
||||
{
|
||||
LOG_ERROR(RSX, "Blit request denied because the destination region does not fit!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto aspect = vk::get_aspect_flags(src->info.format);
|
||||
const auto src_width = src_area.x2 - src_area.x1;
|
||||
const auto src_height = src_area.y2 - src_area.y1;
|
||||
const auto dst_width = dst_area.x2 - dst_area.x1;
|
||||
const auto dst_height = dst_area.y2 - dst_area.y1;
|
||||
|
||||
copy_scaled_image(*commands, src->value, dst->value, src->current_layout, dst->current_layout, src_area.x1, src_area.y1, src_width, src_height,
|
||||
dst_area.x1, dst_area.y1, dst_width, dst_height, 1, aspect, src->info.format == dst->info.format,
|
||||
interpolate? VK_FILTER_LINEAR : VK_FILTER_NEAREST, src->info.format, dst->info.format);
|
||||
copy_scaled_image(*commands, real_src->value, real_dst->value, real_src->current_layout, real_dst->current_layout, src_area.x1, src_area.y1, src_width, src_height,
|
||||
dst_area.x1, dst_area.y1, dst_width, dst_height, 1, dst_aspect, real_src->info.format == real_dst->info.format,
|
||||
interpolate ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, real_src->info.format, real_dst->info.format);
|
||||
|
||||
change_image_layout(*commands, dst, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, {(VkImageAspectFlags)aspect, 0, dst->info.mipLevels, 0, dst->info.arrayLayers});
|
||||
if (real_dst != dst)
|
||||
{
|
||||
auto internal_width = dst->width() * xfer_info.dst_scaling_hint;
|
||||
vk::copy_image_typeless(*commands, real_dst->value, dst->value, real_dst->current_layout, dst->current_layout,
|
||||
{ 0, 0, (s32)internal_width, (s32)dst->height() }, { 0, 0, (s32)dst->width(), (s32)dst->height() }, 1,
|
||||
vk::get_aspect_flags(real_dst->info.format), vk::get_aspect_flags(dst->info.format));
|
||||
}
|
||||
|
||||
change_image_layout(*commands, dst, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, {(VkImageAspectFlags)dst_aspect, 0, dst->info.mipLevels, 0, dst->info.arrayLayers});
|
||||
format = dst->info.format;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue