From 67a54e735759a9186d5cb493c63d2bc77bf813e8 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Mon, 3 Aug 2026 17:29:31 -0400 Subject: [PATCH] Some adjustments on overlapped images not recoverted, relaxed due dynamic resolution --- src/video_core/texture_cache/texture_cache.h | 47 +++++++++++++------ .../texture_cache/texture_cache_base.h | 4 +- src/video_core/texture_cache/types.h | 1 + src/video_core/texture_cache/util.cpp | 29 ++++++++++++ src/video_core/texture_cache/util.h | 3 ++ 5 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 4d100b67bd..decc17687f 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1610,7 +1610,7 @@ ImageId TextureCache

::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr, } } ASSERT_MSG(cpu_addr, "Tried to insert an image to an invalid gpu_addr=0x{:x}", gpu_addr); - const ImageId image_id = JoinImages(info, gpu_addr, *cpu_addr); + const ImageId image_id = JoinImages(info, gpu_addr, *cpu_addr, options); const Image& image = slot_images[image_id]; // Using "image.gpu_addr" instead of "gpu_addr" is important because it might be different const auto [it, is_new] = image_allocs_table.try_emplace(image.gpu_addr); @@ -1622,7 +1622,8 @@ ImageId TextureCache

::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr, } template -ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DAddr cpu_addr) { +ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DAddr cpu_addr, + RelaxedOptions options) { EnsureHeadroom(false); ImageInfo new_info = info; const size_t size_bytes = CalculateGuestSizeInBytes(new_info); @@ -1634,9 +1635,11 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA join_right_aliased_ids.clear(); join_ignore_textures.clear(); join_bad_overlap_ids.clear(); + join_stale_ids.clear(); join_copies_to_do.clear(); join_alias_indices.clear(); const bool this_is_linear = info.type == ImageType::Linear; + const bool is_render_target = True(options & RelaxedOptions::RenderTarget); const auto region_check = [&](ImageId overlap_id, ImageBase& overlap) { if (True(overlap.flags & ImageFlagBits::Remapped)) { join_ignore_textures.insert(overlap_id); @@ -1676,6 +1679,9 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA join_right_aliased_ids.push_back(overlap_id); overlap.flags |= ImageFlagBits::Alias; join_copies_to_do.emplace_back(JoinCopy{true, overlap_id}); + } else if (is_render_target && IsStaleReallocation(new_info, overlap, gpu_addr) && + slot_images[overlap_id].allocation_tick != frame_tick) { + join_stale_ids.push_back(overlap_id); } else { join_bad_overlap_ids.push_back(overlap_id); } @@ -1769,6 +1775,19 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA DeleteImage(overlap_id); } + for (const ImageId stale_id : join_stale_ids) { + Image& stale = slot_images[stale_id]; + LOG_DEBUG(HW_GPU, + "Retiring resized image: gpu_addr=0x{:x} fmt={} {}x{} -> {}x{}", stale.gpu_addr, + static_cast(stale.info.format), stale.info.size.width, + stale.info.size.height, new_image.info.size.width, new_image.info.size.height); + if (True(stale.flags & ImageFlagBits::Tracked)) { + UntrackImage(stale, stale_id); + } + UnregisterImage(stale_id); + DeleteImage(stale_id); + } + // TODO: Only upload what we need RefreshContents(new_image, new_image_id); @@ -1820,17 +1839,17 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA const bool aliased_is_bad = True(aliased.flags & ImageFlagBits::BadOverlap); const bool new_is_bad = True(new_image.flags & ImageFlagBits::BadOverlap); if ((!aliased_was_bad && aliased_is_bad) || (!new_was_bad && new_is_bad)) { - LOG_WARNING(HW_GPU, - "Bad overlap: existing gpu_addr={:#x} {}x{}x{} fmt={} type={} rt={} | " - "incoming gpu_addr={:#x} {}x{}x{} fmt={} type={} rt={}", - aliased.gpu_addr, aliased.info.size.width, aliased.info.size.height, - aliased.info.size.depth, static_cast(aliased.info.format), - static_cast(aliased.info.type), - True(aliased.flags & ImageFlagBits::GpuModified), - new_image.gpu_addr, new_image.info.size.width, new_image.info.size.height, - new_image.info.size.depth, static_cast(new_image.info.format), - static_cast(new_image.info.type), - True(new_image.flags & ImageFlagBits::GpuModified)); + LOG_DEBUG(HW_GPU, + "Bad overlap: existing gpu_addr={:#x} {}x{}x{} fmt={} type={} rt={} | " + "incoming gpu_addr={:#x} {}x{}x{} fmt={} type={} rt={}", + aliased.gpu_addr, aliased.info.size.width, aliased.info.size.height, + aliased.info.size.depth, static_cast(aliased.info.format), + static_cast(aliased.info.type), + True(aliased.flags & ImageFlagBits::GpuModified), + new_image.gpu_addr, new_image.info.size.width, new_image.info.size.height, + new_image.info.size.depth, static_cast(new_image.info.format), + static_cast(new_image.info.type), + True(new_image.flags & ImageFlagBits::GpuModified)); } } @@ -2122,7 +2141,7 @@ ImageViewId TextureCache

::FindRenderTargetView(const ImageInfo& info, GPUVAdd bool delete_state = has_deleted_images; do { has_deleted_images = false; - image_id = FindOrInsertImage(info, gpu_addr); + image_id = FindOrInsertImage(info, gpu_addr, RelaxedOptions::RenderTarget); delete_state |= has_deleted_images; } while (has_deleted_images); has_deleted_images = delete_state; diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 59132db9b3..0e5cc3c44d 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -342,7 +342,8 @@ private: /// Create a new image and join perfectly matching existing images /// Remove joined images from the cache - [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DAddr cpu_addr); + [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DAddr cpu_addr, + RelaxedOptions options); [[nodiscard]] ImageId FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr); @@ -547,6 +548,7 @@ private: boost::container::small_vector join_right_aliased_ids; ankerl::unordered_dense::set join_ignore_textures; boost::container::small_vector join_bad_overlap_ids; + boost::container::small_vector join_stale_ids; struct JoinCopy { bool is_alias; ImageId id; diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h index ecacd8c6bd..6a9f161faa 100644 --- a/src/video_core/texture_cache/types.h +++ b/src/video_core/texture_cache/types.h @@ -57,6 +57,7 @@ enum class RelaxedOptions : u32 { Format = 1 << 1, Samples = 1 << 2, ForceBrokenViews = 1 << 3, + RenderTarget = 1 << 4, }; DECLARE_ENUM_FLAG_OPERATORS(RelaxedOptions) diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index e5afcd1a47..ba2044dcfb 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -1194,6 +1194,35 @@ bool IsLayerStrideCompatible(const ImageInfo& lhs, const ImageInfo& rhs) { return false; } +bool IsStaleReallocation(const ImageInfo& new_info, const ImageBase& overlap, + GPUVAddr gpu_addr) noexcept { + if (overlap.gpu_addr != gpu_addr) { + return false; + } + const ImageInfo& info = overlap.info; + if (new_info.type != ImageType::e2D || info.type != ImageType::e2D) { + return false; + } + if (new_info.resources.levels != 1 || info.resources.levels != 1) { + return false; + } + if (new_info.resources.layers != info.resources.layers) { + return false; + } + if (new_info.block != info.block || new_info.num_samples != info.num_samples) { + return false; + } + if (new_info.tile_width_spacing != info.tile_width_spacing) { + return false; + } + if (BytesPerBlock(new_info.format) != BytesPerBlock(info.format) || + DefaultBlockWidth(new_info.format) != DefaultBlockWidth(info.format) || + DefaultBlockHeight(new_info.format) != DefaultBlockHeight(info.format)) { + return false; + } + return new_info.size.width != info.size.width || new_info.size.height != info.size.height; +} + std::optional FindSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr candidate_addr, RelaxedOptions options, bool broken_views, bool native_bgr) { diff --git a/src/video_core/texture_cache/util.h b/src/video_core/texture_cache/util.h index 3e8bb00032..2ca7df0217 100644 --- a/src/video_core/texture_cache/util.h +++ b/src/video_core/texture_cache/util.h @@ -104,6 +104,9 @@ void SwizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const Ima [[nodiscard]] bool IsLayerStrideCompatible(const ImageInfo& lhs, const ImageInfo& rhs); +[[nodiscard]] bool IsStaleReallocation(const ImageInfo& new_info, const ImageBase& overlap, + GPUVAddr gpu_addr) noexcept; + [[nodiscard]] std::optional FindSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr candidate_addr,