vk: Reuse discarded memory whenever possible instead of recreating new

objects
- Memory allocations are surprisingly expensive when spammed
This commit is contained in:
kd-11 2019-07-01 14:09:44 +03:00 committed by kd-11
parent 71e809a78b
commit ad10eb391e
5 changed files with 155 additions and 88 deletions

View file

@ -796,3 +796,17 @@ size_t get_texture_size(const rsx::vertex_texture &texture)
return get_texture_size(texture.format(), texture.width(), texture.height(), texture.depth(), return get_texture_size(texture.format(), texture.width(), texture.height(), texture.depth(),
texture.pitch(), texture.get_exact_mipmap_count(), texture.cubemap() ? 6 : 1); texture.pitch(), texture.get_exact_mipmap_count(), texture.cubemap() ? 6 : 1);
} }
u32 get_remap_encoding(const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap)
{
u32 encode = 0;
encode |= (remap.first[0] << 0);
encode |= (remap.first[1] << 2);
encode |= (remap.first[2] << 4);
encode |= (remap.first[3] << 6);
encode |= (remap.second[0] << 8);
encode |= (remap.second[1] << 10);
encode |= (remap.second[2] << 12);
encode |= (remap.second[3] << 14);
return encode;
}

View file

@ -139,3 +139,8 @@ size_t get_texture_size(const rsx::vertex_texture &texture);
* Get packed pitch * Get packed pitch
*/ */
u32 get_format_packed_pitch(u32 format, u16 width); u32 get_format_packed_pitch(u32 format, u16 width);
/**
* Reverse encoding
*/
u32 get_remap_encoding(const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap);

View file

@ -1298,11 +1298,19 @@ private:
} }
} }
VkComponentMapping real_mapping = vk::apply_swizzle_remap VkComponentMapping real_mapping;
( if (remap_encoding == 0xAAE4)
{native_component_map.a, native_component_map.r, native_component_map.g, native_component_map.b }, {
remap real_mapping = native_component_map;
); }
else
{
real_mapping = vk::apply_swizzle_remap
(
{ native_component_map.a, native_component_map.r, native_component_map.g, native_component_map.b },
remap
);
}
const auto range = vk::get_image_subresource_range(0, 0, info.arrayLayers, info.mipLevels, aspect() & mask); const auto range = vk::get_image_subresource_range(0, 0, info.arrayLayers, info.mipLevels, aspect() & mask);

View file

@ -138,7 +138,7 @@ namespace vk
return fs_inputs; return fs_inputs;
} }
virtual void get_dynamic_state_entries(VkDynamicState* state_descriptors, VkPipelineDynamicStateCreateInfo& info) virtual void get_dynamic_state_entries(VkDynamicState* /*state_descriptors*/, VkPipelineDynamicStateCreateInfo& /*info*/)
{} {}
virtual std::vector<VkPushConstantRange> get_push_constants() virtual std::vector<VkPushConstantRange> get_push_constants()

View file

@ -292,7 +292,7 @@ namespace vk
verify(HERE), miss; verify(HERE), miss;
// Replace the wait event with a new one to avoid premature signaling! // Replace the wait event with a new one to avoid premature signaling!
vk::get_resource_manager->dispose(dma_fence); vk::get_resource_manager()->dispose(dma_fence);
VkEventCreateInfo createInfo = {}; VkEventCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
@ -369,35 +369,22 @@ namespace vk
} }
}; };
struct discarded_storage struct temporary_storage
{ {
std::unique_ptr<vk::viewable_image> combined_image; std::unique_ptr<vk::viewable_image> combined_image;
std::unique_ptr<vk::image_view> view;
std::unique_ptr<vk::image> img;
//Memory held by this temp storage object // Memory held by this temp storage object
u32 block_size = 0; u32 block_size = 0;
//Frame id tag // Frame id tag
const u64 frame_tag = vk::get_current_frame_id(); const u64 frame_tag = vk::get_current_frame_id();
discarded_storage(std::unique_ptr<vk::image_view>& _view) temporary_storage(std::unique_ptr<vk::viewable_image>& _img)
{ {
view = std::move(_view); combined_image = std::move(_img);
} }
discarded_storage(std::unique_ptr<vk::image>& _img) temporary_storage(vk::cached_texture_section& tex)
{
img = std::move(_img);
}
discarded_storage(std::unique_ptr<vk::image>& _img, std::unique_ptr<vk::image_view>& _view)
{
img = std::move(_img);
view = std::move(_view);
}
discarded_storage(vk::cached_texture_section& tex)
{ {
combined_image = std::move(tex.get_texture()); combined_image = std::move(tex.get_texture());
block_size = tex.get_section_size(); block_size = tex.get_section_size();
@ -407,6 +394,21 @@ namespace vk
{ {
return ref_frame > 0 && frame_tag <= ref_frame; return ref_frame > 0 && frame_tag <= ref_frame;
} }
bool matches(VkFormat format, u16 w, u16 h, u16 d, VkFlags flags) const
{
if (combined_image &&
combined_image->info.flags == flags &&
combined_image->format() == format &&
combined_image->width() == w &&
combined_image->height() == h &&
combined_image->depth() == d)
{
return true;
}
return false;
}
}; };
class texture_cache : public rsx::texture_cache<vk::texture_cache, vk::texture_cache_traits> class texture_cache : public rsx::texture_cache<vk::texture_cache, vk::texture_cache_traits>
@ -420,8 +422,8 @@ namespace vk
{ {
if (tex.is_managed()) if (tex.is_managed())
{ {
m_discarded_memory_size += tex.get_section_size(); m_temporary_memory_size += tex.get_section_size();
m_discardable_storage.emplace_back(tex); m_temporary_storage.emplace_back(tex);
} }
} }
@ -435,15 +437,15 @@ namespace vk
vk::data_heap* m_texture_upload_heap; vk::data_heap* m_texture_upload_heap;
//Stuff that has been dereferenced goes into these //Stuff that has been dereferenced goes into these
std::list<discarded_storage> m_discardable_storage; std::list<temporary_storage> m_temporary_storage;
std::atomic<u32> m_discarded_memory_size = { 0 }; std::atomic<u32> m_temporary_memory_size = { 0 };
void clear() void clear()
{ {
baseclass::clear(); baseclass::clear();
m_discardable_storage.clear(); m_temporary_storage.clear();
m_discarded_memory_size = 0; m_temporary_memory_size = 0;
} }
VkComponentMapping apply_component_mapping_flags(u32 gcm_format, rsx::texture_create_flags flags, const texture_channel_remap_t& remap_vector) const VkComponentMapping apply_component_mapping_flags(u32 gcm_format, rsx::texture_create_flags flags, const texture_channel_remap_t& remap_vector) const
@ -678,22 +680,64 @@ namespace vk
return result; return result;
} }
std::unique_ptr<vk::viewable_image> find_temporary_image(VkFormat format, u16 w, u16 h, u16 d)
{
const auto current_frame = vk::get_current_frame_id();
for (auto &e : m_temporary_storage)
{
if (e.frame_tag != current_frame && e.matches(format, w, h, d, 0))
{
m_temporary_memory_size -= e.block_size;
e.block_size = 0;
return std::move(e.combined_image);
}
}
return {};
}
std::unique_ptr<vk::viewable_image> find_temporary_cubemap(VkFormat format, u16 size)
{
const auto current_frame = vk::get_current_frame_id();
for (auto &e : m_temporary_storage)
{
if (e.frame_tag != current_frame && e.matches(format, size, size, 1, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT))
{
m_temporary_memory_size -= e.block_size;
e.block_size = 0;
return std::move(e.combined_image);
}
}
return {};
}
protected: protected:
vk::image_view* create_temporary_subresource_view_impl(vk::command_buffer& cmd, vk::image* source, VkImageType image_type, VkImageViewType view_type, 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 texture_channel_remap_t& remap_vector, bool copy) u32 gcm_format, u16 x, u16 y, u16 w, u16 h, const texture_channel_remap_t& remap_vector, bool copy)
{ {
std::unique_ptr<vk::image> image; std::unique_ptr<vk::viewable_image> image;
std::unique_ptr<vk::image_view> view;
VkImageCreateFlags image_flags = (view_type == VK_IMAGE_VIEW_TYPE_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0; 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); VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format);
VkImageAspectFlags aspect = vk::get_aspect_flags(dst_format);
image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, if (LIKELY(!image_flags))
image_type, {
dst_format, image = find_temporary_image(dst_format, w, h, 1);
w, h, 1, 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, image_flags); else
{
image = find_temporary_cubemap(dst_format, w);
}
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,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, image_flags);
}
//This method is almost exclusively used to work on framebuffer resources //This method is almost exclusively used to work on framebuffer resources
//Keep the original swizzle layout unless there is data format conversion //Keep the original swizzle layout unless there is data format conversion
@ -711,12 +755,8 @@ namespace vk
view_swizzle = source->native_component_map; view_swizzle = source->native_component_map;
} }
if (memcmp(remap_vector.first.data(), rsx::default_remap_vector.first.data(), 4) || image->set_native_component_layout(view_swizzle);
memcmp(remap_vector.second.data(), rsx::default_remap_vector.second.data(), 4)) auto view = image->get_view(get_remap_encoding(remap_vector), remap_vector);
view_swizzle = vk::apply_swizzle_remap({view_swizzle.a, view_swizzle.r, view_swizzle.g, view_swizzle.b}, remap_vector);
VkImageSubresourceRange view_range = { aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 1 };
view = std::make_unique<vk::image_view>(*vk::get_current_renderer(), image.get(), view_swizzle, view_range);
if (copy) if (copy)
{ {
@ -734,11 +774,11 @@ namespace vk
} }
const u32 resource_memory = w * h * 4; //Rough approximate const u32 resource_memory = w * h * 4; //Rough approximate
m_discardable_storage.emplace_back(image, view); m_temporary_storage.emplace_back(image);
m_discardable_storage.back().block_size = resource_memory; m_temporary_storage.back().block_size = resource_memory;
m_discarded_memory_size += resource_memory; m_temporary_memory_size += resource_memory;
return m_discardable_storage.back().view.get(); return view;
} }
vk::image_view* create_temporary_subresource_view(vk::command_buffer& cmd, vk::image* source, u32 gcm_format, vk::image_view* create_temporary_subresource_view(vk::command_buffer& cmd, vk::image* source, u32 gcm_format,
@ -757,20 +797,20 @@ namespace vk
vk::image_view* generate_cubemap_from_images(vk::command_buffer& cmd, u32 gcm_format, u16 size, 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 texture_channel_remap_t& /*remap_vector*/) override const std::vector<copy_region_descriptor>& sections_to_copy, const texture_channel_remap_t& /*remap_vector*/) override
{ {
std::unique_ptr<vk::image> image; std::unique_ptr<vk::viewable_image> image;
std::unique_ptr<vk::image_view> view;
VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format); VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format);
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(dst_format); VkImageAspectFlags dst_aspect = vk::get_aspect_flags(dst_format);
image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, if (image = find_temporary_cubemap(dst_format, size); !image)
VK_IMAGE_TYPE_2D, {
dst_format, image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
size, size, 1, 1, 6, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT); 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);
}
VkImageSubresourceRange view_range = { dst_aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 6 }; auto view = image->get_view(0xAAE4, rsx::default_remap_vector);
view = std::make_unique<vk::image_view>(*vk::get_current_renderer(), image.get(), image->native_component_map, view_range);
VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 6 }; 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.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range);
@ -791,30 +831,30 @@ namespace vk
vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, dst_range); 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 const u32 resource_memory = size * size * 6 * 4; //Rough approximate
m_discardable_storage.emplace_back(image, view); m_temporary_storage.emplace_back(image);
m_discardable_storage.back().block_size = resource_memory; m_temporary_storage.back().block_size = resource_memory;
m_discarded_memory_size += resource_memory; m_temporary_memory_size += resource_memory;
return m_discardable_storage.back().view.get(); return view;
} }
vk::image_view* generate_3d_from_2d_images(vk::command_buffer& cmd, u32 gcm_format, u16 width, u16 height, u16 depth, 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 texture_channel_remap_t& /*remap_vector*/) override const std::vector<copy_region_descriptor>& sections_to_copy, const texture_channel_remap_t& /*remap_vector*/) override
{ {
std::unique_ptr<vk::image> image; std::unique_ptr<vk::viewable_image> image;
std::unique_ptr<vk::image_view> view;
VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format); VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format);
VkImageAspectFlags dst_aspect = vk::get_aspect_flags(dst_format); VkImageAspectFlags dst_aspect = vk::get_aspect_flags(dst_format);
image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, if (image = find_temporary_image(dst_format, width, height, depth); !image)
VK_IMAGE_TYPE_3D, {
dst_format, image = std::make_unique<vk::viewable_image>(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
width, height, depth, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TYPE_3D,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0); 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);
}
VkImageSubresourceRange view_range = { dst_aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 1 }; auto view = image->get_view(0xAAE4, rsx::default_remap_vector);
view = std::make_unique<vk::image_view>(*vk::get_current_renderer(), image.get(), image->native_component_map, view_range);
VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 1 }; 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.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range);
@ -835,11 +875,11 @@ namespace vk
vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, dst_range); 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 const u32 resource_memory = width * height * depth * 4; //Rough approximate
m_discardable_storage.emplace_back(image, view); m_temporary_storage.emplace_back(image);
m_discardable_storage.back().block_size = resource_memory; m_temporary_storage.back().block_size = resource_memory;
m_discarded_memory_size += resource_memory; m_temporary_memory_size += resource_memory;
return m_discardable_storage.back().view.get(); return view;
} }
vk::image_view* generate_atlas_from_images(vk::command_buffer& cmd, u32 gcm_format, u16 width, u16 height, vk::image_view* generate_atlas_from_images(vk::command_buffer& cmd, u32 gcm_format, u16 width, u16 height,
@ -1189,17 +1229,17 @@ namespace vk
void on_frame_end() override void on_frame_end() override
{ {
if (m_storage.m_unreleased_texture_objects >= m_max_zombie_objects || if (m_storage.m_unreleased_texture_objects >= m_max_zombie_objects ||
m_discarded_memory_size > 0x4000000) //If already holding over 64M in discardable memory, be frugal with memory resources m_temporary_memory_size > 0x4000000) //If already holding over 64M in discardable memory, be frugal with memory resources
{ {
purge_unreleased_sections(); purge_unreleased_sections();
} }
const u64 last_complete_frame = vk::get_last_completed_frame_id(); const u64 last_complete_frame = vk::get_last_completed_frame_id();
m_discardable_storage.remove_if([&](const discarded_storage& o) m_temporary_storage.remove_if([&](const temporary_storage& o)
{ {
if (o.test(last_complete_frame)) if (!o.block_size || o.test(last_complete_frame))
{ {
m_discarded_memory_size -= o.block_size; m_temporary_memory_size -= o.block_size;
return true; return true;
} }
return false; return false;
@ -1219,7 +1259,7 @@ namespace vk
} }
// Uploads a linear memory range as a BGRA8 texture // Uploads a linear memory range as a BGRA8 texture
auto image = std::make_unique<vk::image>(*m_device, m_memory_types.host_visible_coherent, auto image = std::make_unique<vk::viewable_image>(*m_device, m_memory_types.host_visible_coherent,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_2D,
VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM,
@ -1257,9 +1297,9 @@ namespace vk
auto result = image.get(); auto result = image.get();
const u32 resource_memory = width * height * 4; //Rough approximate const u32 resource_memory = width * height * 4; //Rough approximate
m_discardable_storage.emplace_back(image); m_temporary_storage.emplace_back(image);
m_discardable_storage.back().block_size = resource_memory; m_temporary_storage.back().block_size = resource_memory;
m_discarded_memory_size += resource_memory; m_temporary_memory_size += resource_memory;
return result; return result;
} }
@ -1284,12 +1324,12 @@ namespace vk
const u32 get_unreleased_textures_count() const override const u32 get_unreleased_textures_count() const override
{ {
return baseclass::get_unreleased_textures_count() + (u32)m_discardable_storage.size(); return baseclass::get_unreleased_textures_count() + (u32)m_temporary_storage.size();
} }
const u32 get_temporary_memory_in_use() const u32 get_temporary_memory_in_use()
{ {
return m_discarded_memory_size; return m_temporary_memory_size;
} }
}; };
} }