From 64a4908ea60ceccaa4feb145da9f55e98af2263e Mon Sep 17 00:00:00 2001 From: wildcard Date: Tue, 7 Apr 2026 21:13:48 +0200 Subject: [PATCH] [texture_cache] 1st phase optimizations --- src/video_core/texture_cache/texture_cache.h | 81 ++++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index efae825885..f7471f2e72 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -264,6 +264,12 @@ template typename P::ImageView& TextureCache

::GetImageView(u32 index) noexcept { const auto image_view_id = VisitImageView(channel_state->graphics_image_table, channel_state->graphics_image_view_ids, index); + if (image_view_id != NULL_IMAGE_VIEW_ID) { + const ImageViewBase& image_view = slot_image_views[image_view_id]; + if (!image_view.IsBuffer()) { + PrepareImage(image_view.image_id, false, false); + } + } return slot_image_views[image_view_id]; } @@ -619,20 +625,88 @@ template void TextureCache

::FillImageViews(DescriptorTable& table, std::span cached_image_view_ids, std::span views) { + if (views.empty()) { + return; + } + bool has_blacklisted = false; do { has_deleted_images = false; if constexpr (has_blacklists) { has_blacklisted = false; } + + // descriptors often reuse TIC indices in one bind pass + // use a tiny size cache to avoid expensive descriptor repeat reads + constexpr size_t RECENT_VIEW_CACHE_SIZE = 8; + std::array, RECENT_VIEW_CACHE_SIZE> recent_indices{}; + std::array recent_valid{}; + size_t recent_insert = 0; + boost::container::small_vector prepared_image_ids; + [[maybe_unused]] boost::container::small_vector blacklisted_image_ids; + for (ImageViewInOut& view : views) { - view.id = VisitImageView(table, cached_image_view_ids, view.index); + bool found_cached = false; + for (size_t cache_index = 0; cache_index < RECENT_VIEW_CACHE_SIZE; ++cache_index) { + if (recent_valid[cache_index] && + recent_indices[cache_index].first == view.index) { + view.id = recent_indices[cache_index].second; + found_cached = true; + break; + } + } + if (!found_cached) { + view.id = VisitImageView(table, cached_image_view_ids, view.index); + recent_indices[recent_insert] = {view.index, view.id}; + recent_valid[recent_insert] = true; + recent_insert = (recent_insert + 1) % RECENT_VIEW_CACHE_SIZE; + } + if (has_deleted_images) { + break; + } + if (view.id != NULL_IMAGE_VIEW_ID) { + const ImageViewBase& image_view{slot_image_views[view.id]}; + if (!image_view.IsBuffer()) { + const ImageId image_id = image_view.image_id; + const bool already_queued = + std::ranges::find(prepared_image_ids, image_id) != prepared_image_ids.end(); + if (!already_queued) { + prepared_image_ids.push_back(image_id); + } + } + } if constexpr (has_blacklists) { if (view.blacklist && view.id != NULL_IMAGE_VIEW_ID) { const ImageViewBase& image_view{slot_image_views[view.id]}; - auto& image = slot_images[image_view.image_id]; + const ImageId image_id = image_view.image_id; + const bool already_queued = + std::ranges::find(blacklisted_image_ids, image_id) != + blacklisted_image_ids.end(); + if (!already_queued) { + blacklisted_image_ids.push_back(image_id); + } + } + } + } + + if (!has_deleted_images) { + for (const ImageId image_id : prepared_image_ids) { + PrepareImage(image_id, false, false); + if (has_deleted_images) { + break; + } + } + } + + if constexpr (has_blacklists) { + if (!has_deleted_images) { + for (const ImageId image_id : blacklisted_image_ids) { + auto& image = slot_images[image_id]; has_blacklisted |= ScaleDown(image); image.scale_rating = 0; + if (has_deleted_images) { + break; + } } } } @@ -652,9 +726,6 @@ ImageViewId TextureCache

::VisitImageView(DescriptorTable& table, if (is_new) { image_view_id = FindImageView(descriptor); } - if (image_view_id != NULL_IMAGE_VIEW_ID) { - PrepareImageView(image_view_id, false, false); - } return image_view_id; }