mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 08:11:51 +00:00
vk: Reuse discarded memory whenever possible instead of recreating new
objects - Memory allocations are surprisingly expensive when spammed
This commit is contained in:
parent
71e809a78b
commit
ad10eb391e
@ -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;
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user