From eba7d3b172a9b92b80db39a7eee1b6cecd0eaeea Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 13 Feb 2021 17:35:36 +0300 Subject: [PATCH] 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 --- rpcs3/Emu/RSX/Common/surface_store.h | 43 ++++++++++++++++++++++++++++ rpcs3/Emu/RSX/Common/texture_cache.h | 21 ++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index 61023bde9a..9e1dbd6eb5 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -956,6 +956,49 @@ namespace rsx return result; } + void check_for_duplicates(std::vector& sections, const rsx::address_range& range) + { + // Generic painter's algorithm to detect obsolete sections + ensure(range.length() < 64 * 0x100000); + std::vector 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) diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 8aae3217fa..0facf92ca0 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -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);