Skip to content

Commit

Permalink
rsx: Unify composite texture creation and management
Browse files Browse the repository at this point in the history
- Some texture accesses require image compositing steps to assemble the requested image from existing subresources.
  Handle all the common routines in a unified manner to avoid having one broken path (e.g mipmap gather not supporting bitcast operations)
  • Loading branch information
kd-11 committed Aug 10, 2020
1 parent 4ce2ad5 commit 6850533
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 150 deletions.
73 changes: 19 additions & 54 deletions rpcs3/Emu/RSX/GL/GLTextureCache.h
Expand Up @@ -515,14 +515,14 @@ namespace gl
}

gl::texture_view* create_temporary_subresource_impl(gl::command_context& cmd, gl::texture* src, GLenum sized_internal_fmt, GLenum dst_type, u32 gcm_format,
u16 x, u16 y, u16 width, u16 height, const rsx::texture_channel_remap_t& remap, bool copy)
u16 x, u16 y, u16 width, u16 height, u16 depth, u8 mipmaps, const rsx::texture_channel_remap_t& remap, bool copy)
{
if (sized_internal_fmt == GL_NONE)
{
sized_internal_fmt = gl::get_sized_internal_format(gcm_format);
}

std::unique_ptr<gl::texture> dst = std::make_unique<gl::viewable_image>(dst_type, width, height, 1, 1, sized_internal_fmt);
std::unique_ptr<gl::texture> dst = std::make_unique<gl::viewable_image>(dst_type, width, height, depth, mipmaps, sized_internal_fmt);

if (copy)
{
Expand Down Expand Up @@ -736,88 +736,53 @@ namespace gl
gl::texture_view* create_temporary_subresource_view(gl::command_context &cmd, gl::texture** src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h,
const rsx::texture_channel_remap_t& remap_vector) override
{
return create_temporary_subresource_impl(cmd, *src, GL_NONE, GL_TEXTURE_2D, gcm_format, x, y, w, h, remap_vector, true);
return create_temporary_subresource_impl(cmd, *src, GL_NONE, GL_TEXTURE_2D, gcm_format, x, y, w, h, 1, 1, remap_vector, true);
}

gl::texture_view* create_temporary_subresource_view(gl::command_context &cmd, gl::texture* src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h,
const rsx::texture_channel_remap_t& remap_vector) override
{
return create_temporary_subresource_impl(cmd, src, static_cast<GLenum>(src->get_internal_format()),
GL_TEXTURE_2D, gcm_format, x, y, w, h, remap_vector, true);
GL_TEXTURE_2D, gcm_format, x, y, w, h, 1, 1, remap_vector, true);
}

gl::texture_view* generate_cubemap_from_images(gl::command_context& cmd, u32 gcm_format, u16 size, const std::vector<copy_region_descriptor>& sources, const rsx::texture_channel_remap_t& /*remap_vector*/) override
gl::texture_view* generate_cubemap_from_images(gl::command_context& cmd, u32 gcm_format, u16 size, const std::vector<copy_region_descriptor>& sources, const rsx::texture_channel_remap_t& remap_vector) override
{
const GLenum ifmt = gl::get_sized_internal_format(gcm_format);
std::unique_ptr<gl::texture> dst_image = std::make_unique<gl::viewable_image>(GL_TEXTURE_CUBE_MAP, size, size, 1, 1, ifmt);
auto view = std::make_unique<gl::texture_view>(dst_image.get(), GL_TEXTURE_CUBE_MAP, ifmt);
auto _template = get_template_from_collection_impl(sources);
auto result = create_temporary_subresource_impl(cmd, _template, GL_NONE, GL_TEXTURE_3D, gcm_format, 0, 0, size, size, 1, 1, remap_vector, false);

//Empty GL_ERROR
glGetError();

copy_transfer_regions_impl(cmd, dst_image.get(), sources);

if (GLenum err = glGetError())
{
rsx_log.warning("Failed to copy image subresource with GL error 0x%X", err);
return nullptr;
}

auto result = view.get();
m_temporary_surfaces.emplace_back(dst_image, view);
copy_transfer_regions_impl(cmd, result->image(), sources);
return result;
}

gl::texture_view* generate_3d_from_2d_images(gl::command_context& cmd, u32 gcm_format, u16 width, u16 height, u16 depth, const std::vector<copy_region_descriptor>& sources, const rsx::texture_channel_remap_t& /*remap_vector*/) override
gl::texture_view* generate_3d_from_2d_images(gl::command_context& cmd, u32 gcm_format, u16 width, u16 height, u16 depth, const std::vector<copy_region_descriptor>& sources, const rsx::texture_channel_remap_t& remap_vector) override
{
const GLenum ifmt = gl::get_sized_internal_format(gcm_format);
std::unique_ptr<gl::texture> dst_image = std::make_unique<gl::viewable_image>(GL_TEXTURE_3D, width, height, depth, 1, ifmt);
auto view = std::make_unique<gl::texture_view>(dst_image.get(), GL_TEXTURE_3D, ifmt);

//Empty GL_ERROR
glGetError();

copy_transfer_regions_impl(cmd, dst_image.get(), sources);
auto _template = get_template_from_collection_impl(sources);
auto result = create_temporary_subresource_impl(cmd, _template, GL_NONE, GL_TEXTURE_3D, gcm_format, 0, 0, width, height, depth, 1, remap_vector, false);

if (GLenum err = glGetError())
{
rsx_log.warning("Failed to copy image subresource with GL error 0x%X", err);
return nullptr;
}

auto result = view.get();
m_temporary_surfaces.emplace_back(dst_image, view);
copy_transfer_regions_impl(cmd, result->image(), sources);
return result;
}

gl::texture_view* generate_atlas_from_images(gl::command_context& cmd, u32 gcm_format, u16 width, u16 height, const std::vector<copy_region_descriptor>& sections_to_copy,
const rsx::texture_channel_remap_t& remap_vector) override
{
auto _template = get_template_from_collection_impl(sections_to_copy);
auto result = create_temporary_subresource_impl(cmd, _template, GL_NONE, GL_TEXTURE_2D, gcm_format, 0, 0, width, height, remap_vector, false);
auto result = create_temporary_subresource_impl(cmd, _template, GL_NONE, GL_TEXTURE_2D, gcm_format, 0, 0, width, height, 1, 1, remap_vector, false);

copy_transfer_regions_impl(cmd, result->image(), sections_to_copy);
return result;
}

gl::texture_view* generate_2d_mipmaps_from_images(gl::command_context& cmd, u32 /*gcm_format*/, u16 width, u16 height, const std::vector<copy_region_descriptor>& sections_to_copy,
gl::texture_view* generate_2d_mipmaps_from_images(gl::command_context& cmd, u32 gcm_format, u16 width, u16 height, const std::vector<copy_region_descriptor>& sections_to_copy,
const rsx::texture_channel_remap_t& remap_vector) override
{
const auto _template = sections_to_copy.front().src;
const GLenum ifmt = static_cast<GLenum>(_template->get_internal_format());
const u8 mipmaps = ::narrow<u8>(sections_to_copy.size());
const auto swizzle = _template->get_native_component_layout();

auto image_ptr = new gl::viewable_image(GL_TEXTURE_2D, width, height, 1, mipmaps, ifmt);
image_ptr->set_native_component_layout(swizzle);

copy_transfer_regions_impl(cmd, image_ptr, sections_to_copy);

auto view = image_ptr->get_view(get_remap_encoding(remap_vector), remap_vector);
const auto mipmaps = ::narrow<u8>(sections_to_copy.size());
auto _template = get_template_from_collection_impl(sections_to_copy);
auto result = create_temporary_subresource_impl(cmd, _template, GL_NONE, GL_TEXTURE_2D, gcm_format, 0, 0, width, height, 1, mipmaps, remap_vector, false);

std::unique_ptr<gl::texture> dst_image(image_ptr);
m_temporary_surfaces.emplace_back(dst_image);
return view;
copy_transfer_regions_impl(cmd, result->image(), sections_to_copy);
return result;
}

void release_temporary_subresource(gl::texture_view* view) override
Expand Down
143 changes: 47 additions & 96 deletions rpcs3/Emu/RSX/VK/VKTextureCache.h
Expand Up @@ -866,28 +866,30 @@ namespace vk

protected:
vk::image_view* create_temporary_subresource_view_impl(vk::command_buffer& cmd, vk::image* source, VkImageType image_type, VkImageViewType view_type,
u32 gcm_format, u16 x, u16 y, u16 w, u16 h, const rsx::texture_channel_remap_t& remap_vector, bool copy)
u32 gcm_format, u16 x, u16 y, u16 w, u16 h, u16 d, u8 mips, const rsx::texture_channel_remap_t& remap_vector, bool copy)
{
std::unique_ptr<vk::viewable_image> image;

VkImageCreateFlags image_flags = (view_type == VK_IMAGE_VIEW_TYPE_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format);
u16 layers = 1;

if (!image_flags) [[likely]]
{
image = find_temporary_image(dst_format, w, h, 1, 1);
image = find_temporary_image(dst_format, w, h, 1, mips);
}
else
{
image = find_temporary_cubemap(dst_format, w);
layers = 6;
}

if (!image)
{
image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
image_type,
dst_format,
w, h, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
w, h, d, mips, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, image_flags);
}

Expand Down Expand Up @@ -938,7 +940,7 @@ namespace vk
u16 x, u16 y, u16 w, u16 h, const rsx::texture_channel_remap_t& remap_vector) override
{
return create_temporary_subresource_view_impl(cmd, source, source->info.imageType, VK_IMAGE_VIEW_TYPE_2D,
gcm_format, x, y, w, h, remap_vector, true);
gcm_format, x, y, w, h, 1, 1, remap_vector, true);
}

vk::image_view* create_temporary_subresource_view(vk::command_buffer& cmd, vk::image** source, u32 gcm_format,
Expand All @@ -948,33 +950,16 @@ namespace vk
}

vk::image_view* generate_cubemap_from_images(vk::command_buffer& cmd, u32 gcm_format, u16 size,
const std::vector<copy_region_descriptor>& sections_to_copy, const rsx::texture_channel_remap_t& /*remap_vector*/) override
const std::vector<copy_region_descriptor>& sections_to_copy, const rsx::texture_channel_remap_t& remap_vector) override
{
std::unique_ptr<vk::viewable_image> image;
VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format);
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(dst_format);

if (image = find_temporary_cubemap(dst_format, size); !image)
{
image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D,
dst_format,
size, size, 1, 1, 6, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT);
}
else if (auto src = sections_to_copy[0].src; src && src->format() == dst_format)
{
image->set_native_component_layout(src->native_component_map);
}
else
{
image->set_native_component_layout({ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A });
}

auto view = image->get_view(0xAAE4, rsx::default_remap_vector);
auto _template = get_template_from_collection_impl(sections_to_copy);
auto result = create_temporary_subresource_view_impl(cmd, _template, VK_IMAGE_TYPE_2D,
VK_IMAGE_VIEW_TYPE_CUBE, gcm_format, 0, 0, size, size, 1, 1, remap_vector, false);

const auto image = result->image();
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(result->info.format);
VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 6 };
vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range);
vk::change_image_layout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range);

if (!(dst_aspect & VK_IMAGE_ASPECT_DEPTH_BIT))
{
Expand All @@ -987,46 +972,23 @@ namespace vk
vkCmdClearDepthStencilImage(cmd, image->value, image->current_layout, &clear, 1, &dst_range);
}

copy_transfer_regions_impl(cmd, image.get(), sections_to_copy);

vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, dst_range);

const u32 resource_memory = size * size * 6 * 4; //Rough approximate
m_temporary_storage.emplace_back(image);
m_temporary_storage.back().block_size = resource_memory;
m_temporary_memory_size += resource_memory;
copy_transfer_regions_impl(cmd, image, sections_to_copy);

return view;
vk::change_image_layout(cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, dst_range);
return result;
}

vk::image_view* generate_3d_from_2d_images(vk::command_buffer& cmd, u32 gcm_format, u16 width, u16 height, u16 depth,
const std::vector<copy_region_descriptor>& sections_to_copy, const rsx::texture_channel_remap_t& /*remap_vector*/) override
const std::vector<copy_region_descriptor>& sections_to_copy, const rsx::texture_channel_remap_t& remap_vector) override
{
std::unique_ptr<vk::viewable_image> image;
VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format);
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(dst_format);

if (image = find_temporary_image(dst_format, width, height, depth, 1); !image)
{
image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_3D,
dst_format,
width, height, depth, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0);
}
else if (auto src = sections_to_copy[0].src; src && src->format() == dst_format)
{
image->set_native_component_layout(src->native_component_map);
}
else
{
image->set_native_component_layout({ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A });
}

auto view = image->get_view(0xAAE4, rsx::default_remap_vector);
auto _template = get_template_from_collection_impl(sections_to_copy);
auto result = create_temporary_subresource_view_impl(cmd, _template, VK_IMAGE_TYPE_3D,
VK_IMAGE_VIEW_TYPE_3D, gcm_format, 0, 0, width, height, depth, 1, remap_vector, false);

const auto image = result->image();
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(result->info.format);
VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 1 };
vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range);
vk::change_image_layout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range);

if (!(dst_aspect & VK_IMAGE_ASPECT_DEPTH_BIT))
{
Expand All @@ -1039,24 +1001,18 @@ namespace vk
vkCmdClearDepthStencilImage(cmd, image->value, image->current_layout, &clear, 1, &dst_range);
}

copy_transfer_regions_impl(cmd, image.get(), sections_to_copy);

vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, dst_range);

const u32 resource_memory = width * height * depth * 4; //Rough approximate
m_temporary_storage.emplace_back(image);
m_temporary_storage.back().block_size = resource_memory;
m_temporary_memory_size += resource_memory;
copy_transfer_regions_impl(cmd, image, sections_to_copy);

return view;
vk::change_image_layout(cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, dst_range);
return result;
}

vk::image_view* generate_atlas_from_images(vk::command_buffer& cmd, u32 gcm_format, u16 width, u16 height,
const std::vector<copy_region_descriptor>& sections_to_copy, const rsx::texture_channel_remap_t& remap_vector) override
{
auto _template = get_template_from_collection_impl(sections_to_copy);
auto result = create_temporary_subresource_view_impl(cmd, _template, VK_IMAGE_TYPE_2D,
VK_IMAGE_VIEW_TYPE_2D, gcm_format, 0, 0, width, height, remap_vector, false);
VK_IMAGE_VIEW_TYPE_2D, gcm_format, 0, 0, width, height, 1, 1, remap_vector, false);

const auto image = result->image();
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(result->info.format);
Expand All @@ -1080,39 +1036,34 @@ namespace vk
return result;
}

vk::image_view* generate_2d_mipmaps_from_images(vk::command_buffer& cmd, u32 /*gcm_format*/, u16 width, u16 height,
vk::image_view* generate_2d_mipmaps_from_images(vk::command_buffer& cmd, u32 gcm_format, u16 width, u16 height,
const std::vector<copy_region_descriptor>& sections_to_copy, const rsx::texture_channel_remap_t& remap_vector) override
{
const auto _template = sections_to_copy.front().src;
const auto mipmaps = ::narrow<u8>(sections_to_copy.size());
auto _template = get_template_from_collection_impl(sections_to_copy);
auto result = create_temporary_subresource_view_impl(cmd, _template, VK_IMAGE_TYPE_2D,
VK_IMAGE_VIEW_TYPE_2D, gcm_format, 0, 0, width, height, 1, mipmaps, remap_vector, false);

std::unique_ptr<vk::viewable_image> image;
if (image = find_temporary_image(_template->format(), width, height, 1, mipmaps); !image)
{
image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
_template->info.imageType,
_template->info.format,
width, height, 1, mipmaps, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0);
const auto image = result->image();
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(result->info.format);
VkImageSubresourceRange dst_range = { dst_aspect, 0, mipmaps, 0, 1 };
vk::change_image_layout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range);

image->set_native_component_layout(_template->native_component_map);
if (!(dst_aspect & VK_IMAGE_ASPECT_DEPTH_BIT))
{
VkClearColorValue clear = {};
vkCmdClearColorImage(cmd, image->value, image->current_layout, &clear, 1, &dst_range);
}
else
{
VkClearDepthStencilValue clear = { 1.f, 0 };
vkCmdClearDepthStencilImage(cmd, image->value, image->current_layout, &clear, 1, &dst_range);
}

auto view = image->get_view(get_remap_encoding(remap_vector), remap_vector);

VkImageSubresourceRange dst_range = { _template->aspect(), 0, mipmaps, 0, 1 };
vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range);

copy_transfer_regions_impl(cmd, image.get(), sections_to_copy);

vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, dst_range);

const u32 resource_memory = width * height * 2 * 4; // Rough approximate
m_temporary_storage.emplace_back(image);
m_temporary_storage.back().block_size = resource_memory;
m_temporary_memory_size += resource_memory;
copy_transfer_regions_impl(cmd, image, sections_to_copy);

return view;
vk::change_image_layout(cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, dst_range);
return result;
}

void release_temporary_subresource(vk::image_view* view) override
Expand Down

0 comments on commit 6850533

Please sign in to comment.