rsx: Refactor create_subresource_view(deferred_subresource&) and implement a subresource cache

- This limits the number of times an image is copied and improves performance
This commit is contained in:
kd-11 2017-11-03 14:16:55 +03:00
parent 1fa18757fc
commit 60c7a508a7
5 changed files with 121 additions and 95 deletions

View file

@ -132,8 +132,78 @@ namespace rsx
{ CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP }
};
protected:
public:
//Struct to hold data on sections to be paged back onto cpu memory
struct thrashed_set
{
bool violation_handled = false;
std::vector<section_storage_type*> affected_sections; //Always laid out with flushable sections first then other affected sections last
int num_flushable = 0;
u64 cache_tag = 0;
u32 address_base = 0;
u32 address_range = 0;
};
struct deferred_subresource
{
image_resource_type external_handle = 0;
std::array<image_resource_type, 6> external_cubemap_sources;
u32 base_address = 0;
u32 gcm_format = 0;
u16 x = 0;
u16 y = 0;
u16 width = 0;
u16 height = 0;
bool is_cubemap = false;
deferred_subresource()
{}
deferred_subresource(image_resource_type _res, u32 _addr, u32 _fmt, u16 _x, u16 _y, u16 _w, u16 _h) :
external_handle(_res), base_address(_addr), gcm_format(_fmt), x(_x), y(_y), width(_w), height(_h)
{}
};
struct sampled_image_descriptor : public sampled_image_descriptor_base
{
image_view_type image_handle = 0;
deferred_subresource external_subresource_desc = {};
bool flag = false;
sampled_image_descriptor()
{}
sampled_image_descriptor(image_view_type handle, const texture_upload_context ctx, const bool is_depth, const f32 x_scale, const f32 y_scale, const rsx::texture_dimension_extended type)
{
image_handle = handle;
upload_context = ctx;
is_depth_texture = is_depth;
scale_x = x_scale;
scale_y = y_scale;
image_type = type;
}
sampled_image_descriptor(image_resource_type external_handle, u32 base_address, u32 gcm_format, u16 x_offset, u16 y_offset, u16 width, u16 height,
const texture_upload_context ctx, const bool is_depth, const f32 x_scale, const f32 y_scale, const rsx::texture_dimension_extended type)
{
external_subresource_desc = { external_handle, base_address, gcm_format, x_offset, y_offset, width, height };
image_handle = 0;
upload_context = ctx;
is_depth_texture = is_depth;
scale_x = x_scale;
scale_y = y_scale;
image_type = type;
}
void set_external_cubemap_resources(std::array<image_resource_type, 6> images)
{
external_subresource_desc.external_cubemap_sources = images;
external_subresource_desc.is_cubemap = true;
}
};
protected:
struct ranged_storage
{
std::vector<section_storage_type> data; //Stored data
@ -178,6 +248,7 @@ namespace rsx
shared_mutex m_cache_mutex;
std::unordered_map<u32, ranged_storage> m_cache;
std::unordered_multimap<u32, std::pair<deferred_subresource, image_view_type>> m_temporary_subresource_cache;
std::atomic<u64> m_cache_update_tag = {};
@ -214,76 +285,6 @@ namespace rsx
m_cache_update_tag = get_system_time();
}
public:
//Struct to hold data on sections to be paged back onto cpu memory
struct thrashed_set
{
bool violation_handled = false;
std::vector<section_storage_type*> affected_sections; //Always laid out with flushable sections first then other affected sections last
int num_flushable = 0;
u64 cache_tag = 0;
u32 address_base = 0;
u32 address_range = 0;
};
struct deferred_subresource
{
image_resource_type external_handle = 0;
std::array<image_resource_type, 6> external_cubemap_sources;
u32 gcm_format = 0;
u16 x = 0;
u16 y = 0;
u16 width = 0;
u16 height = 0;
bool is_cubemap = false;
deferred_subresource()
{}
deferred_subresource(image_resource_type _res, u32 _fmt, u16 _x, u16 _y, u16 _w, u16 _h):
external_handle(_res), gcm_format(_fmt), x(_x), y(_y), width(_w), height(_h)
{}
};
struct sampled_image_descriptor : public sampled_image_descriptor_base
{
image_view_type image_handle = 0;
deferred_subresource external_subresource_desc = {};
bool flag = false;
sampled_image_descriptor()
{}
sampled_image_descriptor(image_view_type handle, const texture_upload_context ctx, const bool is_depth, const f32 x_scale, const f32 y_scale, const rsx::texture_dimension_extended type)
{
image_handle = handle;
upload_context = ctx;
is_depth_texture = is_depth;
scale_x = x_scale;
scale_y = y_scale;
image_type = type;
}
sampled_image_descriptor(image_resource_type external_handle, u32 gcm_format, u16 x_offset, u16 y_offset, u16 width, u16 height,
const texture_upload_context ctx, const bool is_depth, const f32 x_scale, const f32 y_scale, const rsx::texture_dimension_extended type)
{
external_subresource_desc = {external_handle, gcm_format, x_offset, y_offset, width, height};
image_handle = 0;
upload_context = ctx;
is_depth_texture = is_depth;
scale_x = x_scale;
scale_y = y_scale;
image_type = type;
}
void set_external_cubemap_resources(std::array<image_resource_type, 6> images)
{
external_subresource_desc.external_cubemap_sources = images;
external_subresource_desc.is_cubemap = true;
}
};
private:
//Internal implementation methods and helpers
@ -994,6 +995,40 @@ namespace rsx
m_unreleased_texture_objects = 0;
}
image_view_type create_temporary_subresource(commandbuffer_type &cmd, deferred_subresource& desc)
{
const auto found = m_temporary_subresource_cache.equal_range(desc.base_address);
for (auto It = found.first; It != found.second; ++It)
{
const auto& found_desc = It->second.first;
if (found_desc.external_handle != desc.external_handle ||
found_desc.is_cubemap != desc.is_cubemap ||
found_desc.x != desc.x || found_desc.y != desc.y ||
found_desc.width != desc.width || found_desc.height != desc.height)
continue;
return It->second.second;
}
image_view_type result = 0;
if (!desc.is_cubemap)
result = create_temporary_subresource_view(cmd, &desc.external_handle, desc.gcm_format, desc.x, desc.y, desc.width, desc.height);
else
result = generate_cubemap_from_images(cmd, desc.gcm_format, desc.width, desc.external_cubemap_sources);
if (result)
{
m_temporary_subresource_cache.insert({ desc.base_address,{ desc, result } });
}
return result;
}
void notify_surface_changed(u32 base_address)
{
m_temporary_subresource_cache.erase(base_address);
}
template <typename render_target_type, typename surface_store_type>
sampled_image_descriptor process_framebuffer_resource(render_target_type texptr, const u32 texaddr, const u32 gcm_format, surface_store_type& m_rtts,
const u16 tex_width, const u16 tex_height, const rsx::texture_dimension_extended extended_dimension, const bool is_depth)
@ -1046,7 +1081,7 @@ namespace rsx
if (can_cast)
{
sampled_image_descriptor desc = { texptr->get_surface(), format, 0, 0, surface_width, surface_height, texture_upload_context::framebuffer_storage,
sampled_image_descriptor desc = { texptr->get_surface(), texaddr, format, 0, 0, surface_width, surface_height, texture_upload_context::framebuffer_storage,
is_depth, 1.f, 1.f, rsx::texture_dimension_extended::texture_dimension_cubemap };
desc.set_external_cubemap_resources(image_array);
@ -1139,7 +1174,7 @@ namespace rsx
{
const auto w = rsx::apply_resolution_scale(internal_width, true);
const auto h = rsx::apply_resolution_scale(internal_height, true);
return{ texptr->get_surface(), format, 0, 0, w, h, texture_upload_context::framebuffer_storage,
return{ texptr->get_surface(), texaddr, format, 0, 0, w, h, texture_upload_context::framebuffer_storage,
is_depth, scale_x, scale_y, rsx::texture_dimension_extended::texture_dimension_2d };
}
@ -1274,7 +1309,7 @@ namespace rsx
LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr);
}
return{ rsc.surface->get_surface(), format, rsx::apply_resolution_scale(rsc.x, false), rsx::apply_resolution_scale(rsc.y, false),
return{ rsc.surface->get_surface(), rsc.base_address, format, rsx::apply_resolution_scale(rsc.x, false), rsx::apply_resolution_scale(rsc.y, false),
rsx::apply_resolution_scale(rsc.w, true), internal_height, texture_upload_context::framebuffer_storage,
rsc.is_depth_surface, scale_x, scale_y, rsx::texture_dimension_extended::texture_dimension_2d };
}
@ -1337,7 +1372,7 @@ namespace rsx
auto src_image = surface->get_raw_texture();
f32 scale_y = (extended_dimension == rsx::texture_dimension_extended::texture_dimension_1d) ? 0.f : 1.f;
return{ src_image, format, offset_x, offset_y, tex_width, tex_height, texture_upload_context::blit_engine_dst,
return{ src_image, surface->get_section_base(), format, offset_x, offset_y, tex_width, tex_height, texture_upload_context::blit_engine_dst,
surface->is_depth_texture(), 1.f, scale_y, rsx::texture_dimension_extended::texture_dimension_2d };
}
}
@ -1686,6 +1721,7 @@ namespace rsx
dst_area = dst_area * scale;
blitter.scale_image(vram_texture, dest_texture, src_area, dst_area, interpolate, is_depth_blit);
notify_surface_changed(dst.rsx_address);
return true;
}

View file

@ -334,7 +334,8 @@ void GLGSRender::end()
}
else if (sampler_state->external_subresource_desc.external_handle)
{
glBindTexture(target, m_gl_texture_cache.create_temporary_subresource(sampler_state->external_subresource_desc));
void *unused = nullptr;
glBindTexture(target, m_gl_texture_cache.create_temporary_subresource(unused, sampler_state->external_subresource_desc));
sampler_state->flag = false;
}
else
@ -367,7 +368,8 @@ void GLGSRender::end()
}
else if (sampler_state->external_subresource_desc.external_handle)
{
glBindTexture(GL_TEXTURE_2D, m_gl_texture_cache.create_temporary_subresource(sampler_state->external_subresource_desc));
void *unused = nullptr;
glBindTexture(GL_TEXTURE_2D, m_gl_texture_cache.create_temporary_subresource(unused, sampler_state->external_subresource_desc));
sampler_state->flag = false;
}
else

View file

@ -781,15 +781,6 @@ namespace gl
m_hw_blitter.destroy();
}
inline u32 create_temporary_subresource(deferred_subresource& desc)
{
void* unused = nullptr;
if (!desc.is_cubemap)
return create_temporary_subresource_view(unused, &desc.external_handle, desc.gcm_format, desc.x, desc.y, desc.width, desc.height);
else
return generate_cubemap_from_images(unused, desc.gcm_format, desc.width, desc.external_cubemap_sources);
}
bool is_depth_texture(const u32 rsx_address, const u32 rsx_size) override
{
reader_lock lock(m_cache_mutex);
@ -824,6 +815,7 @@ namespace gl
}
clear_temporary_subresources();
m_temporary_subresource_cache.clear();
}
bool blit(rsx::blit_src_info& src, rsx::blit_dst_info& dst, bool linear_interpolate, gl_render_targets& m_rtts)

View file

@ -2424,6 +2424,7 @@ void VKGSRender::prepare_rtts()
surface->aa_mode = aa_mode;
m_texture_cache.tag_framebuffer(surface_addresses[index]);
m_texture_cache.notify_surface_changed(surface_addresses[index]);
}
if (std::get<0>(m_rtts.m_bound_depth_stencil) != 0)
@ -2440,6 +2441,7 @@ void VKGSRender::prepare_rtts()
ds->aa_mode = aa_mode;
m_texture_cache.tag_framebuffer(zeta_address);
m_texture_cache.notify_surface_changed(zeta_address);
}
m_draw_buffers_count = static_cast<u32>(draw_buffers.size());

View file

@ -411,7 +411,7 @@ namespace vk
//Stuff that has been dereferenced goes into these
std::list<discarded_storage> m_discardable_storage;
std::atomic<u32> m_discarded_memory_size = { 0 };
void purge_cache()
{
for (auto &address_range : m_cache)
@ -786,14 +786,6 @@ namespace vk
purge_cache();
}
inline vk::image_view* create_temporary_subresource(vk::command_buffer &cmd, deferred_subresource& desc)
{
if (!desc.is_cubemap)
return create_temporary_subresource_view(cmd, desc.external_handle, desc.gcm_format, desc.x, desc.y, desc.width, desc.height);
else
return generate_cubemap_from_images(cmd, desc.gcm_format, desc.width, desc.external_cubemap_sources);
}
bool is_depth_texture(const u32 rsx_address, const u32 rsx_size) override
{
reader_lock lock(m_cache_mutex);
@ -849,6 +841,8 @@ namespace vk
}
return false;
});
m_temporary_subresource_cache.clear();
}
template<typename RsxTextureType>