From 82fd6778ab69f70a903834854bf22fb87fdbef21 Mon Sep 17 00:00:00 2001 From: Zephyron Date: Tue, 3 Feb 2026 18:40:18 +1000 Subject: [PATCH] feat(video_core): add native ASTC texture cache optimization for Adreno 740+ - Add AndroidAstcMode enum to settings_enums.h (Auto/Native/Decompress) - Add android_astc_mode setting to settings.h - Add Adreno 7xx+ GPU detection in vulkan_device (IsAdrenoGpu, IsAdreno7xxOrNewer, SupportsNativeAstc) - Add compressed_size_bytes field to ImageBase for accurate ASTC VRAM tracking - Add use_compressed_eviction flag to texture cache for Android-optimized eviction - Increase VRAM budget to 90% for Android devices with native ASTC support - Add SupportsNativeAstc() to Vulkan and OpenGL texture cache runtimes This improves performance on high-end Android devices by allowing more ASTC textures to be cached when using compressed size for eviction calculations. Co-Authored-By: FDT --- src/common/settings.h | 10 ++++ src/common/settings_enums.h | 22 +++++++++ .../renderer_opengl/gl_texture_cache.h | 6 +++ .../renderer_vulkan/vk_texture_cache.h | 6 +++ src/video_core/texture_cache/image_base.cpp | 9 +++- src/video_core/texture_cache/image_base.h | 3 ++ src/video_core/texture_cache/texture_cache.h | 46 +++++++++++++++++-- .../texture_cache/texture_cache_base.h | 4 ++ .../vulkan_common/vulkan_device.cpp | 16 +++++++ src/video_core/vulkan_common/vulkan_device.h | 21 +++++++++ 10 files changed, 138 insertions(+), 5 deletions(-) diff --git a/src/common/settings.h b/src/common/settings.h index afefe1334..122154499 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -560,6 +560,16 @@ struct Values { SwitchableSetting log_vram_usage{linkage, false, "log_vram_usage", Category::RendererAdvanced}; + // FIXED: Android Adreno 740 native ASTC eviction + // Controls texture cache eviction strategy on Android devices with native ASTC support + // Auto = detect based on GPU, Native = use compressed size, Decompress = use decompressed size + SwitchableSetting android_astc_mode{linkage, + AndroidAstcMode::Auto, + AndroidAstcMode::Auto, + AndroidAstcMode::Decompress, + "android_astc_mode", + Category::RendererAdvanced}; + SwitchableSetting async_presentation{linkage, #ifdef ANDROID true, diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index e7dbd5497..489b8850c 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -896,6 +896,28 @@ inline u32 EnumMetadata::Index() { return 27; } +// FIXED: Android Adreno 740 native ASTC eviction +// Controls texture cache eviction strategy on Android devices with native ASTC support +enum class AndroidAstcMode : u32 { + Auto = 0, // Auto-detect based on GPU capabilities (recommended) + Native = 1, // Force native ASTC - use compressed size for eviction + Decompress = 2, // Force decompression - use decompressed size (PC-style eviction) +}; + +template <> +inline std::vector> +EnumMetadata::Canonicalizations() { + return { + {"Auto", AndroidAstcMode::Auto}, + {"Native", AndroidAstcMode::Native}, + {"Decompress", AndroidAstcMode::Decompress}, + }; +} + +template <> +inline u32 EnumMetadata::Index() { + return 28; +} template inline std::string CanonicalizeEnum(Type id) { diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index d4165d8e4..b080ae5d3 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -145,6 +145,12 @@ public: // OpenGL does not require a barrier for attachment feedback loops. } + // FIXED: Android Adreno 740 native ASTC eviction + // OpenGL does not have the same Adreno-specific optimizations as Vulkan + [[nodiscard]] bool SupportsNativeAstc() const noexcept { + return false; // No Adreno-specific detection in OpenGL + } + private: const Device& device; StateTracker& state_tracker; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 21667f82c..4a3dacfb5 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -113,6 +113,12 @@ public: void BarrierFeedbackLoop(); + // FIXED: Android Adreno 740 native ASTC eviction + // Returns true if the device supports native ASTC and compressed size eviction + [[nodiscard]] bool SupportsNativeAstc() const noexcept { + return device.SupportsNativeAstc(); + } + const Device& device; Scheduler& scheduler; MemoryAllocator& memory_allocator; diff --git a/src/video_core/texture_cache/image_base.cpp b/src/video_core/texture_cache/image_base.cpp index d79594ce5..99664a62e 100644 --- a/src/video_core/texture_cache/image_base.cpp +++ b/src/video_core/texture_cache/image_base.cpp @@ -60,7 +60,14 @@ namespace { ImageBase::ImageBase(const ImageInfo& info_, GPUVAddr gpu_addr_, VAddr cpu_addr_) : info{info_}, guest_size_bytes{CalculateGuestSizeInBytes(info)}, unswizzled_size_bytes{CalculateUnswizzledSizeBytes(info)}, - converted_size_bytes{CalculateConvertedSizeBytes(info)}, scale_rating{}, scale_tick{}, + converted_size_bytes{CalculateConvertedSizeBytes(info)}, + // FIXED: Android Adreno 740 native ASTC eviction + // For ASTC textures, compressed size = guest_size_bytes (raw ASTC blocks remain compressed) + // For non-ASTC, compressed_size = unswizzled_size_bytes (needs full decompression) + compressed_size_bytes{VideoCore::Surface::IsPixelFormatASTC(info.format) + ? guest_size_bytes + : unswizzled_size_bytes}, + scale_rating{}, scale_tick{}, has_scaled{}, gpu_addr{gpu_addr_}, cpu_addr{cpu_addr_}, cpu_addr_end{cpu_addr + guest_size_bytes}, mip_level_offsets{CalculateMipLevelOffsets(info)} { if (info.type == ImageType::e3D) { diff --git a/src/video_core/texture_cache/image_base.h b/src/video_core/texture_cache/image_base.h index 0587d7b72..b48b55f2b 100644 --- a/src/video_core/texture_cache/image_base.h +++ b/src/video_core/texture_cache/image_base.h @@ -89,6 +89,9 @@ struct ImageBase { u32 guest_size_bytes = 0; u32 unswizzled_size_bytes = 0; u32 converted_size_bytes = 0; + // FIXED: Android Adreno 740 native ASTC eviction + // Size in VRAM when using native ASTC (compressed) vs when decompressed + u32 compressed_size_bytes = 0; u32 scale_rating = 0; u64 scale_tick = 0; bool has_scaled = false; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 00f2aac0e..2043c6e81 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -89,6 +89,32 @@ TextureCache

::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag "VRAM Management initialized: limit={}MB, expected={}MB, critical={}MB, gc_level={}", vram_limit_bytes / 1_MiB, expected_memory / 1_MiB, critical_memory / 1_MiB, static_cast(gc_level)); + + // FIXED: Android Adreno 740 native ASTC eviction + // Determine eviction strategy based on android_astc_mode setting and device capabilities + const auto astc_mode = Settings::values.android_astc_mode.GetValue(); + if (astc_mode == Settings::AndroidAstcMode::Native) { + use_compressed_eviction = true; + } else if (astc_mode == Settings::AndroidAstcMode::Decompress) { + use_compressed_eviction = false; + } else { + // Auto mode: detect based on runtime device capabilities + use_compressed_eviction = runtime.SupportsNativeAstc(); + } + + if (use_compressed_eviction) { + // Android devices with native ASTC can use higher VRAM budget (90% instead of 80%) + // since textures stay compressed in GPU memory + const u64 android_vram_limit = static_cast(static_cast(runtime.GetDeviceLocalMemory()) * 0.90); + if (configured_limit_mb == 0 && android_vram_limit > vram_limit_bytes) { + vram_limit_bytes = android_vram_limit; + expected_memory = static_cast(static_cast(vram_limit_bytes) * expected_ratio); + critical_memory = static_cast(static_cast(vram_limit_bytes) * critical_ratio); + } + LOG_INFO(Render_Vulkan, + "Android native ASTC enabled: using compressed size eviction, VRAM budget={}MB", + vram_limit_bytes / 1_MiB); + } } else { vram_limit_bytes = configured_limit_mb > 0 ? static_cast(configured_limit_mb) * 1_MiB : 6_GiB; // Default 6GB if no info @@ -171,9 +197,13 @@ void TextureCache

::RunGarbageCollector() { return false; } - // FIXED: VRAM leak prevention - Prioritize sparse textures if enabled + // FIXED: Android Adreno 740 native ASTC eviction + // Prioritize sparse textures if enabled const bool is_sparse = True(image.flags & ImageFlagBits::Sparse); - const u64 image_size = std::max(image.guest_size_bytes, image.unswizzled_size_bytes); + // Use compressed size for eviction on Android with native ASTC support + const u64 image_size = use_compressed_eviction + ? image.compressed_size_bytes + : std::max(image.guest_size_bytes, image.unswizzled_size_bytes); const bool is_large = image_size >= LARGE_TEXTURE_THRESHOLD; // Skip costly loads unless aggressive/emergency mode, unless it's a large sparse texture @@ -426,7 +456,11 @@ u64 TextureCache

::EvictToFreeMemory(u64 target_bytes) { return false; } - const u64 image_size = std::max(image.guest_size_bytes, image.unswizzled_size_bytes); + // FIXED: Android Adreno 740 native ASTC eviction + // Use compressed size for eviction on Android with native ASTC support + const u64 image_size = use_compressed_eviction + ? image.compressed_size_bytes + : std::max(image.guest_size_bytes, image.unswizzled_size_bytes); if (True(image.flags & ImageFlagBits::Tracked)) { UntrackImage(image, image_id); @@ -455,7 +489,11 @@ u64 TextureCache

::EvictSparseTexturesPriority(u64 target_bytes) { auto& image = slot_images[image_id]; if (True(image.flags & ImageFlagBits::Sparse) && False(image.flags & ImageFlagBits::IsDecoding)) { - const u64 size = std::max(image.guest_size_bytes, image.unswizzled_size_bytes); + // FIXED: Android Adreno 740 native ASTC eviction + // Use compressed size for eviction on Android with native ASTC support + const u64 size = use_compressed_eviction + ? image.compressed_size_bytes + : std::max(image.guest_size_bytes, image.unswizzled_size_bytes); sparse_textures.emplace_back(image_id, size); } return false; diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 70a91e5d4..849507fdf 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -506,6 +506,10 @@ public: u64 last_gc_frame = 0; // Last frame GC was run bool emergency_gc_triggered = false; // Emergency GC flag + // FIXED: Android Adreno 740 native ASTC eviction + // When true, use compressed_size_bytes for eviction calculations on Android + Adreno 7xx + bool use_compressed_eviction = false; + struct BufferDownload { GPUVAddr address; size_t size; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index f1318a045..e89108300 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -441,6 +441,22 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR nvidia_arch = GetNvidiaArchitecture(physical, supported_extensions); } + // FIXED: Android Adreno 740 native ASTC eviction + // Detect Adreno GPUs and check for native ASTC support + is_adreno = is_qualcomm || is_turnip; + if (is_adreno) { + // Adreno 7xx series devices (Adreno 730, 740, 750+) support native ASTC + // Device IDs: 0x43050a01 (SD8 Gen 2), 0x43052c01 (SD8 Elite), etc. + // Generally 0x43050000+ indicates Adreno 7xx series + is_adreno_7xx_or_newer = (device_id >= 0x43050000); + supports_native_astc = is_adreno_7xx_or_newer && is_optimal_astc_supported; + + if (supports_native_astc) { + LOG_INFO(Render_Vulkan, + "Adreno 7xx detected — using native ASTC, eviction on compressed size"); + } + } + SetupFamilies(surface); const auto queue_cis = GetDeviceQueueCreateInfos(); diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 03b19a084..49c4b238c 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -722,6 +722,22 @@ public: return nvidia_arch; } + // FIXED: Android Adreno 740 native ASTC eviction + /// Returns true if the device is an Adreno GPU (Qualcomm or Turnip driver) + [[nodiscard]] bool IsAdrenoGpu() const noexcept { + return is_adreno; + } + + /// Returns true if the device is Adreno 7xx series or newer (Adreno 730, 740, 750+) + [[nodiscard]] bool IsAdreno7xxOrNewer() const noexcept { + return is_adreno_7xx_or_newer; + } + + /// Returns true if the device supports native ASTC decoding and compressed size eviction + [[nodiscard]] bool SupportsNativeAstc() const noexcept { + return supports_native_astc; + } + private: /// Checks if the physical device is suitable and configures the object state /// with all necessary info about its properties. @@ -843,6 +859,11 @@ private: u32 sets_per_pool{}; ///< Sets per Description Pool NvidiaArchitecture nvidia_arch{NvidiaArchitecture::Arch_AmpereOrNewer}; + // FIXED: Android Adreno 740 native ASTC eviction + bool is_adreno{}; ///< Is Adreno GPU (Qualcomm or Turnip driver) + bool is_adreno_7xx_or_newer{}; ///< Is Adreno 7xx series or newer + bool supports_native_astc{}; ///< Supports native ASTC with compressed eviction + // Telemetry parameters std::set> supported_extensions; ///< Reported Vulkan extensions. std::set> loaded_extensions; ///< Loaded Vulkan extensions.