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(),
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
*/
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
(
{native_component_map.a, native_component_map.r, native_component_map.g, native_component_map.b },
remap
);
VkComponentMapping real_mapping;
if (remap_encoding == 0xAAE4)
{
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);

View File

@ -138,7 +138,7 @@ namespace vk
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()

View File

@ -292,7 +292,7 @@ namespace vk
verify(HERE), miss;
// 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 = {};
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::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;
//Frame id tag
// Frame id tag
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)
{
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)
temporary_storage(vk::cached_texture_section& tex)
{
combined_image = std::move(tex.get_texture());
block_size = tex.get_section_size();
@ -407,6 +394,21 @@ namespace vk
{
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>
@ -420,8 +422,8 @@ namespace vk
{
if (tex.is_managed())
{
m_discarded_memory_size += tex.get_section_size();
m_discardable_storage.emplace_back(tex);
m_temporary_memory_size += tex.get_section_size();
m_temporary_storage.emplace_back(tex);
}
}
@ -435,15 +437,15 @@ namespace vk
vk::data_heap* m_texture_upload_heap;
//Stuff that has been dereferenced goes into these
std::list<discarded_storage> m_discardable_storage;
std::atomic<u32> m_discarded_memory_size = { 0 };
std::list<temporary_storage> m_temporary_storage;
std::atomic<u32> m_temporary_memory_size = { 0 };
void clear()
{
baseclass::clear();
m_discardable_storage.clear();
m_discarded_memory_size = 0;
m_temporary_storage.clear();
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
@ -678,22 +680,64 @@ namespace vk
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:
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)
{
std::unique_ptr<vk::image> image;
std::unique_ptr<vk::image_view> view;
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);
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,
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);
if (LIKELY(!image_flags))
{
image = find_temporary_image(dst_format, w, h, 1);
}
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
//Keep the original swizzle layout unless there is data format conversion
@ -711,12 +755,8 @@ namespace vk
view_swizzle = source->native_component_map;
}
if (memcmp(remap_vector.first.data(), rsx::default_remap_vector.first.data(), 4) ||
memcmp(remap_vector.second.data(), rsx::default_remap_vector.second.data(), 4))
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);
image->set_native_component_layout(view_swizzle);
auto view = image->get_view(get_remap_encoding(remap_vector), remap_vector);
if (copy)
{
@ -734,11 +774,11 @@ namespace vk
}
const u32 resource_memory = w * h * 4; //Rough approximate
m_discardable_storage.emplace_back(image, view);
m_discardable_storage.back().block_size = resource_memory;
m_discarded_memory_size += resource_memory;
m_temporary_storage.emplace_back(image);
m_temporary_storage.back().block_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,
@ -757,20 +797,20 @@ 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 texture_channel_remap_t& /*remap_vector*/) override
{
std::unique_ptr<vk::image> image;
std::unique_ptr<vk::image_view> view;
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);
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);
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);
}
VkImageSubresourceRange view_range = { dst_aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 6 };
view = std::make_unique<vk::image_view>(*vk::get_current_renderer(), image.get(), image->native_component_map, view_range);
auto view = image->get_view(0xAAE4, rsx::default_remap_vector);
VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 6 };
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);
const u32 resource_memory = size * size * 6 * 4; //Rough approximate
m_discardable_storage.emplace_back(image, view);
m_discardable_storage.back().block_size = resource_memory;
m_discarded_memory_size += resource_memory;
m_temporary_storage.emplace_back(image);
m_temporary_storage.back().block_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,
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::image_view> view;
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);
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);
if (image = find_temporary_image(dst_format, width, height, depth); !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);
}
VkImageSubresourceRange view_range = { dst_aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 1 };
view = std::make_unique<vk::image_view>(*vk::get_current_renderer(), image.get(), image->native_component_map, view_range);
auto view = image->get_view(0xAAE4, rsx::default_remap_vector);
VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 1 };
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);
const u32 resource_memory = width * height * depth * 4; //Rough approximate
m_discardable_storage.emplace_back(image, view);
m_discardable_storage.back().block_size = resource_memory;
m_discarded_memory_size += resource_memory;
m_temporary_storage.emplace_back(image);
m_temporary_storage.back().block_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,
@ -1189,17 +1229,17 @@ namespace vk
void on_frame_end() override
{
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();
}
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 false;
@ -1219,7 +1259,7 @@ namespace vk
}
// 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_IMAGE_TYPE_2D,
VK_FORMAT_B8G8R8A8_UNORM,
@ -1257,9 +1297,9 @@ namespace vk
auto result = image.get();
const u32 resource_memory = width * height * 4; //Rough approximate
m_discardable_storage.emplace_back(image);
m_discardable_storage.back().block_size = resource_memory;
m_discarded_memory_size += resource_memory;
m_temporary_storage.emplace_back(image);
m_temporary_storage.back().block_size = resource_memory;
m_temporary_memory_size += resource_memory;
return result;
}
@ -1284,12 +1324,12 @@ namespace vk
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()
{
return m_discarded_memory_size;
return m_temporary_memory_size;
}
};
}