rsx: Add duplicate section detection when there are too many sections in the surface cache

- Check for useless sections.
  Helps in games that create a bunch of sections randomly for one-time use
This commit is contained in:
kd-11 2021-02-13 17:35:36 +03:00 committed by kd-11
parent b8311caa6b
commit eba7d3b172
2 changed files with 64 additions and 0 deletions

View File

@ -956,6 +956,49 @@ namespace rsx
return result;
}
void check_for_duplicates(std::vector<surface_overlap_info>& sections, const rsx::address_range& range)
{
// Generic painter's algorithm to detect obsolete sections
ensure(range.length() < 64 * 0x100000);
std::vector<u8> marker(range.length());
std::memset(marker.data(), 0, range.length());
for (auto it = sections.crbegin(); it != sections.crend(); ++it)
{
if (it->base_address < range.start)
{
continue;
}
const auto true_pitch_in_bytes = it->surface->get_surface_width(rsx::surface_metrics::bytes);
const auto true_height_in_rows = it->surface->get_surface_height(rsx::surface_metrics::samples);
bool valid = false;
auto addr = it->base_address - range.start;
auto data = marker.data();
for (usz row = 0; row < true_height_in_rows; ++row)
{
for (usz col = 0; col < true_pitch_in_bytes; ++col)
{
if (const auto loc = col + addr; !data[loc])
{
valid = true;
data[loc] = 1;
}
}
addr += true_pitch_in_bytes;
}
if (!valid)
{
rsx_log.error("Stale surface at address 0x%x will be deleted", it->base_address);
invalidate_surface_address(it->base_address, it->is_depth);
}
}
}
void on_write(const bool* color, bool z)
{
if (write_tag == cache_tag && m_skip_write_updates)

View File

@ -1783,6 +1783,26 @@ namespace rsx
if (result_is_valid)
{
// Check for possible duplicates
usz max_safe_sections = UINT32_MAX;
switch (result.external_subresource_desc.op)
{
case deferred_request_command::atlas_gather:
max_safe_sections = 8 + attr.mipmaps; break;
case deferred_request_command::cubemap_gather:
max_safe_sections = 8 * attr.mipmaps; break;
case deferred_request_command::_3d_gather:
max_safe_sections = (attr.depth * attr.mipmaps * 110) / 100; break; // 10% factor of safety
default:
break;
}
if (overlapping_fbos.size() > max_safe_sections)
{
rsx_log.error("[Performance warning] Texture gather routine encountered too many objects!");
m_rtts.check_for_duplicates(overlapping_fbos, memory_range);
}
// Optionally disallow caching if resource is being written to as it is being read from
for (const auto& section : overlapping_fbos)
{
@ -1855,6 +1875,7 @@ namespace rsx
attributes.bpp = get_format_block_size_in_bytes(attributes.gcm_format);
attributes.width = tex.width();
attributes.height = tex.height();
attributes.mipmaps = tex.get_exact_mipmap_count();
attributes.swizzled = !(tex.format() & CELL_GCM_TEXTURE_LN);
const bool is_unnormalized = !!(tex.format() & CELL_GCM_TEXTURE_UN);