rsx: Implement workaround for pitch compatibility of overlapping sections with blit engine targets

- Avoid generating surfaces that introduce pitch conflict!
This commit is contained in:
kd-11
2026-08-28 14:55:44 +03:00
committed by kd-11
parent 42cfad20eb
commit 48d2b24813
2 changed files with 92 additions and 1 deletions
+74 -1
View File
@@ -112,11 +112,21 @@ namespace rsx
}
else
{
const bool is_pitch_compatible = Traits::surface_is_pitch_compatible(found->second, prev_surface->get_rsx_pitch());
if (!is_pitch_compatible && found->second->last_use_tag >= prev_surface->last_use_tag) [[unlikely]]
{
// HACK: A newer surface with an incompatible pitch owns the memory, do not evict.
// TODO: Pitch conversion is required to resolve this properly.
rsx_log.warning("[SURFACE CACHE] Discarding block at 0x%x from surface at 0x%x (pitch=%u); block is owned by a newer surface with pitch=%u.",
new_address, prev_surface->base_addr, prev_surface->get_rsx_pitch(), found->second->get_rsx_pitch());
return;
}
invalidate(found->second);
data.erase(new_address);
auto &old = invalidated_resources.back();
if (Traits::surface_is_pitch_compatible(old, prev_surface->get_rsx_pitch()))
if (is_pitch_compatible)
{
if (old->last_use_tag >= prev_surface->last_use_tag) [[unlikely]]
{
@@ -1128,6 +1138,69 @@ namespace rsx
return nullptr;
}
// Workaround to handle overlapping surfaces with differing pitch
// For a surface region defined by range [address, length] and pitch, we return the max length we can write without clobbering a surface of different pitch.
// TODO: Re-evaluate usefulness once pitch-conversion work is completed.
u32 truncate_memory_range_by_pitch(u32 address, u32 pitch, u32 length, u64 reference_tag)
{
if (!length || !pitch)
{
return length;
}
const auto test_range = rsx::address_range32::start_length(address, length);
const auto test_height = static_cast<u16>(utils::aligned_div(length, pitch));
u32 limit = address + length;
auto process_list_function = [&](surface_ranged_map& data)
{
for (auto it = data.begin_range(test_range); it != data.end(); ++it)
{
// Only a surface that begins after us can shorten the length. An exact address match is (hackishly) handled in bind_surface_address instead.
const auto base_address = it->first;
if (base_address <= address || base_address >= limit)
{
continue;
}
const auto surface = Traits::get(it->second);
if (!surface->get_memory_range().overlaps(test_range))
{
continue;
}
if (rsx::pitch_compatible(surface, pitch, test_height))
{
// Normal inheritance resolves this overlap. Nothing to do.
continue;
}
if (surface->last_use_tag <= reference_tag)
{
// Stale data, safe to swallow.
continue;
}
// min() is already handled in the original address bounds check
limit = base_address;
}
};
if (m_render_targets_memory_range.valid() &&
test_range.overlaps(m_render_targets_memory_range))
{
process_list_function(m_render_targets_storage);
}
if (m_depth_stencil_memory_range.valid() &&
test_range.overlaps(m_depth_stencil_memory_range))
{
process_list_function(m_depth_stencil_storage);
}
return limit - address;
}
/**
* Invalidates surface that exists at an address
*/
+18
View File
@@ -1702,6 +1702,24 @@ namespace rsx
{
block_end = write_end;
}
else if (!use_null_region && block_end > write_end)
{
// Before attempting to create any surface that would exceed our bounds, ensure we don't end up in a pitch conflict!
// TODO: Remove this when pitch conversion is implemented or at least revise usefulness. It may still be beneficial to some extent.
const auto prev_surface = m_rtts.get_surface_at(dst_base_address);
const u64 reference_tag = prev_surface ? prev_surface->last_use_tag : 0ull;
const u32 block_length = block_end - dst_base_address;
const u32 safe_length = m_rtts.truncate_memory_range_by_pitch(dst_base_address, dst.pitch, block_length, reference_tag);
if (safe_length < block_length) [[ unlikely ]]
{
// We have pitch conflicts. Play it safe.
const auto aligned_safe_length = (safe_length / dst.pitch) * dst.pitch; // <- Align safe_length down to a multiple of pitch.
const auto proposed_end = aligned_safe_length + dst_base_address;
block_end = std::max(proposed_end, write_end);
}
}
const u32 usable_section_length = std::max(write_end, block_end) - dst_base_address;
dst_dimensions.height = align2(usable_section_length, dst.pitch) / dst.pitch;