mirror of
https://git.eden-emu.dev/archive/citron
synced 2026-03-22 17:46:08 -04:00
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 <fdt@citron-emu.org>
This commit is contained in:
@@ -560,6 +560,16 @@ struct Values {
|
|||||||
SwitchableSetting<bool> log_vram_usage{linkage, false, "log_vram_usage",
|
SwitchableSetting<bool> log_vram_usage{linkage, false, "log_vram_usage",
|
||||||
Category::RendererAdvanced};
|
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<AndroidAstcMode, true> android_astc_mode{linkage,
|
||||||
|
AndroidAstcMode::Auto,
|
||||||
|
AndroidAstcMode::Auto,
|
||||||
|
AndroidAstcMode::Decompress,
|
||||||
|
"android_astc_mode",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
|
||||||
SwitchableSetting<bool> async_presentation{linkage,
|
SwitchableSetting<bool> async_presentation{linkage,
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -896,6 +896,28 @@ inline u32 EnumMetadata<GCAggressiveness>::Index() {
|
|||||||
return 27;
|
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<std::pair<std::string, AndroidAstcMode>>
|
||||||
|
EnumMetadata<AndroidAstcMode>::Canonicalizations() {
|
||||||
|
return {
|
||||||
|
{"Auto", AndroidAstcMode::Auto},
|
||||||
|
{"Native", AndroidAstcMode::Native},
|
||||||
|
{"Decompress", AndroidAstcMode::Decompress},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline u32 EnumMetadata<AndroidAstcMode>::Index() {
|
||||||
|
return 28;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
inline std::string CanonicalizeEnum(Type id) {
|
inline std::string CanonicalizeEnum(Type id) {
|
||||||
|
|||||||
@@ -145,6 +145,12 @@ public:
|
|||||||
// OpenGL does not require a barrier for attachment feedback loops.
|
// 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:
|
private:
|
||||||
const Device& device;
|
const Device& device;
|
||||||
StateTracker& state_tracker;
|
StateTracker& state_tracker;
|
||||||
|
|||||||
@@ -113,6 +113,12 @@ public:
|
|||||||
|
|
||||||
void BarrierFeedbackLoop();
|
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;
|
const Device& device;
|
||||||
Scheduler& scheduler;
|
Scheduler& scheduler;
|
||||||
MemoryAllocator& memory_allocator;
|
MemoryAllocator& memory_allocator;
|
||||||
|
|||||||
@@ -60,7 +60,14 @@ namespace {
|
|||||||
ImageBase::ImageBase(const ImageInfo& info_, GPUVAddr gpu_addr_, VAddr cpu_addr_)
|
ImageBase::ImageBase(const ImageInfo& info_, GPUVAddr gpu_addr_, VAddr cpu_addr_)
|
||||||
: info{info_}, guest_size_bytes{CalculateGuestSizeInBytes(info)},
|
: info{info_}, guest_size_bytes{CalculateGuestSizeInBytes(info)},
|
||||||
unswizzled_size_bytes{CalculateUnswizzledSizeBytes(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_},
|
has_scaled{}, gpu_addr{gpu_addr_}, cpu_addr{cpu_addr_},
|
||||||
cpu_addr_end{cpu_addr + guest_size_bytes}, mip_level_offsets{CalculateMipLevelOffsets(info)} {
|
cpu_addr_end{cpu_addr + guest_size_bytes}, mip_level_offsets{CalculateMipLevelOffsets(info)} {
|
||||||
if (info.type == ImageType::e3D) {
|
if (info.type == ImageType::e3D) {
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ struct ImageBase {
|
|||||||
u32 guest_size_bytes = 0;
|
u32 guest_size_bytes = 0;
|
||||||
u32 unswizzled_size_bytes = 0;
|
u32 unswizzled_size_bytes = 0;
|
||||||
u32 converted_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;
|
u32 scale_rating = 0;
|
||||||
u64 scale_tick = 0;
|
u64 scale_tick = 0;
|
||||||
bool has_scaled = false;
|
bool has_scaled = false;
|
||||||
|
|||||||
@@ -89,6 +89,32 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
|
|||||||
"VRAM Management initialized: limit={}MB, expected={}MB, critical={}MB, gc_level={}",
|
"VRAM Management initialized: limit={}MB, expected={}MB, critical={}MB, gc_level={}",
|
||||||
vram_limit_bytes / 1_MiB, expected_memory / 1_MiB, critical_memory / 1_MiB,
|
vram_limit_bytes / 1_MiB, expected_memory / 1_MiB, critical_memory / 1_MiB,
|
||||||
static_cast<u32>(gc_level));
|
static_cast<u32>(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<u64>(static_cast<double>(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<u64>(static_cast<f32>(vram_limit_bytes) * expected_ratio);
|
||||||
|
critical_memory = static_cast<u64>(static_cast<f32>(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 {
|
} else {
|
||||||
vram_limit_bytes = configured_limit_mb > 0 ? static_cast<u64>(configured_limit_mb) * 1_MiB
|
vram_limit_bytes = configured_limit_mb > 0 ? static_cast<u64>(configured_limit_mb) * 1_MiB
|
||||||
: 6_GiB; // Default 6GB if no info
|
: 6_GiB; // Default 6GB if no info
|
||||||
@@ -171,9 +197,13 @@ void TextureCache<P>::RunGarbageCollector() {
|
|||||||
return false;
|
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 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;
|
const bool is_large = image_size >= LARGE_TEXTURE_THRESHOLD;
|
||||||
|
|
||||||
// Skip costly loads unless aggressive/emergency mode, unless it's a large sparse texture
|
// Skip costly loads unless aggressive/emergency mode, unless it's a large sparse texture
|
||||||
@@ -426,7 +456,11 @@ u64 TextureCache<P>::EvictToFreeMemory(u64 target_bytes) {
|
|||||||
return false;
|
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)) {
|
if (True(image.flags & ImageFlagBits::Tracked)) {
|
||||||
UntrackImage(image, image_id);
|
UntrackImage(image, image_id);
|
||||||
@@ -455,7 +489,11 @@ u64 TextureCache<P>::EvictSparseTexturesPriority(u64 target_bytes) {
|
|||||||
auto& image = slot_images[image_id];
|
auto& image = slot_images[image_id];
|
||||||
if (True(image.flags & ImageFlagBits::Sparse) &&
|
if (True(image.flags & ImageFlagBits::Sparse) &&
|
||||||
False(image.flags & ImageFlagBits::IsDecoding)) {
|
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);
|
sparse_textures.emplace_back(image_id, size);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -506,6 +506,10 @@ public:
|
|||||||
u64 last_gc_frame = 0; // Last frame GC was run
|
u64 last_gc_frame = 0; // Last frame GC was run
|
||||||
bool emergency_gc_triggered = false; // Emergency GC flag
|
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 {
|
struct BufferDownload {
|
||||||
GPUVAddr address;
|
GPUVAddr address;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|||||||
@@ -441,6 +441,22 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
nvidia_arch = GetNvidiaArchitecture(physical, supported_extensions);
|
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);
|
SetupFamilies(surface);
|
||||||
const auto queue_cis = GetDeviceQueueCreateInfos();
|
const auto queue_cis = GetDeviceQueueCreateInfos();
|
||||||
|
|
||||||
|
|||||||
@@ -722,6 +722,22 @@ public:
|
|||||||
return nvidia_arch;
|
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:
|
private:
|
||||||
/// Checks if the physical device is suitable and configures the object state
|
/// Checks if the physical device is suitable and configures the object state
|
||||||
/// with all necessary info about its properties.
|
/// with all necessary info about its properties.
|
||||||
@@ -843,6 +859,11 @@ private:
|
|||||||
u32 sets_per_pool{}; ///< Sets per Description Pool
|
u32 sets_per_pool{}; ///< Sets per Description Pool
|
||||||
NvidiaArchitecture nvidia_arch{NvidiaArchitecture::Arch_AmpereOrNewer};
|
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
|
// Telemetry parameters
|
||||||
std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions.
|
std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions.
|
||||||
std::set<std::string, std::less<>> loaded_extensions; ///< Loaded Vulkan extensions.
|
std::set<std::string, std::less<>> loaded_extensions; ///< Loaded Vulkan extensions.
|
||||||
|
|||||||
Reference in New Issue
Block a user