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:
@@ -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 }
|
{ 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
|
struct ranged_storage
|
||||||
{
|
{
|
||||||
std::vector<section_storage_type> data; //Stored data
|
std::vector<section_storage_type> data; //Stored data
|
||||||
@@ -178,6 +248,7 @@ namespace rsx
|
|||||||
|
|
||||||
shared_mutex m_cache_mutex;
|
shared_mutex m_cache_mutex;
|
||||||
std::unordered_map<u32, ranged_storage> m_cache;
|
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 = {};
|
std::atomic<u64> m_cache_update_tag = {};
|
||||||
|
|
||||||
@@ -214,76 +285,6 @@ namespace rsx
|
|||||||
m_cache_update_tag = get_system_time();
|
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:
|
private:
|
||||||
//Internal implementation methods and helpers
|
//Internal implementation methods and helpers
|
||||||
|
|
||||||
@@ -994,6 +995,40 @@ namespace rsx
|
|||||||
m_unreleased_texture_objects = 0;
|
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>
|
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,
|
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)
|
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)
|
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 };
|
is_depth, 1.f, 1.f, rsx::texture_dimension_extended::texture_dimension_cubemap };
|
||||||
|
|
||||||
desc.set_external_cubemap_resources(image_array);
|
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 w = rsx::apply_resolution_scale(internal_width, true);
|
||||||
const auto h = rsx::apply_resolution_scale(internal_height, 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 };
|
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);
|
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,
|
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 };
|
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();
|
auto src_image = surface->get_raw_texture();
|
||||||
f32 scale_y = (extended_dimension == rsx::texture_dimension_extended::texture_dimension_1d) ? 0.f : 1.f;
|
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 };
|
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;
|
dst_area = dst_area * scale;
|
||||||
|
|
||||||
blitter.scale_image(vram_texture, dest_texture, src_area, dst_area, interpolate, is_depth_blit);
|
blitter.scale_image(vram_texture, dest_texture, src_area, dst_area, interpolate, is_depth_blit);
|
||||||
|
notify_surface_changed(dst.rsx_address);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -334,7 +334,8 @@ void GLGSRender::end()
|
|||||||
}
|
}
|
||||||
else if (sampler_state->external_subresource_desc.external_handle)
|
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;
|
sampler_state->flag = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -367,7 +368,8 @@ void GLGSRender::end()
|
|||||||
}
|
}
|
||||||
else if (sampler_state->external_subresource_desc.external_handle)
|
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;
|
sampler_state->flag = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -781,15 +781,6 @@ namespace gl
|
|||||||
m_hw_blitter.destroy();
|
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
|
bool is_depth_texture(const u32 rsx_address, const u32 rsx_size) override
|
||||||
{
|
{
|
||||||
reader_lock lock(m_cache_mutex);
|
reader_lock lock(m_cache_mutex);
|
||||||
@@ -824,6 +815,7 @@ namespace gl
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear_temporary_subresources();
|
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)
|
bool blit(rsx::blit_src_info& src, rsx::blit_dst_info& dst, bool linear_interpolate, gl_render_targets& m_rtts)
|
||||||
|
|||||||
@@ -2424,6 +2424,7 @@ void VKGSRender::prepare_rtts()
|
|||||||
|
|
||||||
surface->aa_mode = aa_mode;
|
surface->aa_mode = aa_mode;
|
||||||
m_texture_cache.tag_framebuffer(surface_addresses[index]);
|
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)
|
if (std::get<0>(m_rtts.m_bound_depth_stencil) != 0)
|
||||||
@@ -2440,6 +2441,7 @@ void VKGSRender::prepare_rtts()
|
|||||||
|
|
||||||
ds->aa_mode = aa_mode;
|
ds->aa_mode = aa_mode;
|
||||||
m_texture_cache.tag_framebuffer(zeta_address);
|
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());
|
m_draw_buffers_count = static_cast<u32>(draw_buffers.size());
|
||||||
|
|||||||
@@ -786,14 +786,6 @@ namespace vk
|
|||||||
purge_cache();
|
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
|
bool is_depth_texture(const u32 rsx_address, const u32 rsx_size) override
|
||||||
{
|
{
|
||||||
reader_lock lock(m_cache_mutex);
|
reader_lock lock(m_cache_mutex);
|
||||||
@@ -849,6 +841,8 @@ namespace vk
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_temporary_subresource_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RsxTextureType>
|
template<typename RsxTextureType>
|
||||||
|
|||||||
Reference in New Issue
Block a user