diff options
| author | néo Luigi <85024393+neoluigi4123@users.noreply.github.com> | 2026-10-31 15:33:09 +0100 |
|---|---|---|
| committer | kraibse <33869366+kraibse@users.noreply.github.com> | 2026-10-31 18:04:23 +0100 |
| commit | 82963e6750cef756d2ad4d1115dc9dca420d4313 (patch) | |
| tree | 8378304104c807b5d08f2985d6e7b75c57c0ae06 | |
| parent | 2065b1431c0ecfeade61a7e7511889c4800b6bb9 (diff) | |
1st pass of review: code cleanup & windows test
Assisted-by: Claude Opus 5.5 (review, cleanup and log analysis)
| -rw-r--r-- | src/common/settings.cpp | 10 | ||||
| -rw-r--r-- | src/common/settings.h | 6 | ||||
| -rw-r--r-- | src/core/core.cpp | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/maxwell_to_vk.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 33 | ||||
| -rw-r--r-- | src/video_core/surface.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/texture_cache/util.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_device.cpp | 48 |
9 files changed, 67 insertions, 53 deletions
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 7ce410b99c..c63943a9d3 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -235,6 +235,16 @@ bool CurrentProgramIsSwitch2() { return current_program_is_switch2; } +static std::optional<AstcRecompression> astc_recompression_override; + +AstcRecompression GetAstcRecompression() { + return astc_recompression_override.value_or(values.astc_recompression.GetValue()); +} + +void SetAstcRecompressionOverride(std::optional<AstcRecompression> recompression) { + astc_recompression_override = recompression; +} + bool IsDockedMode() { return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked; } diff --git a/src/common/settings.h b/src/common/settings.h index e703254f12..97103f457d 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -10,6 +10,7 @@ #include <array> #include <map> #include <memory> +#include <optional> #include <stdexcept> #include <string> #include <utility> @@ -990,6 +991,11 @@ u64 GetCurrentProgramID(); void SetCurrentProgramIsSwitch2(bool is_switch2); bool CurrentProgramIsSwitch2(); +// The ASTC recompression in effect: astc_recompression, unless the renderer picked another one +// for the running program (the configuration is left as is). The core clears it on load. +AstcRecompression GetAstcRecompression(); +void SetAstcRecompressionOverride(std::optional<AstcRecompression> recompression); + bool IsOpenGL(); bool IsDockedMode(); diff --git a/src/core/core.cpp b/src/core/core.cpp index ac5e23e9c0..41871df870 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -319,6 +319,7 @@ struct System::Impl { virtual_filesystem != nullptr && IsSwitch2Program(GetGameFileFromPath(virtual_filesystem, filepath)); Settings::SetCurrentProgramIsSwitch2(switch2_program); + Settings::SetAstcRecompressionOverride(std::nullopt); // Switch 2 titles size their heap from the total memory and need the 12 GiB layout. Set it // as a per-game value, so RestoreGlobalState brings back the configured layout afterwards. diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 680cb2179f..8cca26aee9 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -236,8 +236,7 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4 const VideoCommon::ImageInfo& info) { if (IsPixelFormatASTC(info.format) && info.size.depth == 1 && !runtime.HasNativeASTC()) { return Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu && - Settings::values.astc_recompression.GetValue() == - Settings::AstcRecompression::Uncompressed; + Settings::GetAstcRecompression() == Settings::AstcRecompression::Uncompressed; } // Disable other accelerated uploads for now as they don't implement swizzled uploads return false; @@ -443,12 +442,11 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form } [[nodiscard]] bool IsAstcRecompressionEnabled() { - return Settings::values.astc_recompression.GetValue() != - Settings::AstcRecompression::Uncompressed; + return Settings::GetAstcRecompression() != Settings::AstcRecompression::Uncompressed; } [[nodiscard]] GLenum SelectAstcFormat(PixelFormat format, bool is_srgb) { - switch (Settings::values.astc_recompression.GetValue()) { + switch (Settings::GetAstcRecompression()) { case Settings::AstcRecompression::Bc1: return is_srgb ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 6c18ade926..c8e43d0650 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -246,7 +246,7 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with bool const is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format); // Transcode on hardware that doesn't support ASTC natively if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { - switch (Settings::values.astc_recompression.GetValue()) { + switch (Settings::GetAstcRecompression()) { case Settings::AstcRecompression::Uncompressed: if (is_srgb) { tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index f3b28c12b7..5ba36feee9 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -240,7 +240,7 @@ constexpr std::array<VkFormat, 2> OpaqueAstcViewFormats{VK_FORMAT_BC1_RGBA_UNORM return false; } return Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu && - Settings::values.astc_recompression.GetValue() != Settings::AstcRecompression::Uncompressed; + Settings::GetAstcRecompression() != Settings::AstcRecompression::Uncompressed; } [[nodiscard]] bool WillUseAcceleratedAstcDecode(const Device& device, const ImageInfo& info) { @@ -253,9 +253,8 @@ constexpr std::array<VkFormat, 2> OpaqueAstcViewFormats{VK_FORMAT_BC1_RGBA_UNORM if (Settings::values.accelerate_astc.GetValue() != Settings::AstcDecodeMode::Gpu) { return false; } - return Settings::values.astc_recompression.GetValue() == - Settings::AstcRecompression::Uncompressed && - info.size.depth == 1; + return Settings::GetAstcRecompression() == Settings::AstcRecompression::Uncompressed && + info.size.depth == 1; } // The host shape of an image whose decoded copy would not fit in VRAM: a GPU-decoded ASTC array @@ -1084,13 +1083,13 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const }); } -// Uncompressed ASTC needs more video memory than a Switch 2 title leaves on cards under 12 GiB -// (Mario Kart World filled a 16 GB card's 13.5 GB budget): there the textures went unbacked -// (garbage) and the game crashed. Use BC3 for this session; the configuration is left as is. +// Uncompressed ASTC needs more video memory than a Switch 2 title leaves under a 12 GiB budget +// (Mario Kart World filled a 16 GB card's 13.5 GB budget; a 12 GB card has ~11.2 GB): there the +// textures went unbacked (garbage) and the game crashed. Use BC3 for this session. void UseBc3ForSwitch2OnSmallCards(const Device& device) { using namespace Common::Literals; if (!Settings::CurrentProgramIsSwitch2() || device.IsOptimalAstcSupported() || - Settings::values.astc_recompression.GetValue() != Settings::AstcRecompression::Uncompressed) { + Settings::GetAstcRecompression() != Settings::AstcRecompression::Uncompressed) { return; } const u64 budget = device.GetDeviceMemoryBudget(); @@ -1100,13 +1099,11 @@ void UseBc3ForSwitch2OnSmallCards(const Device& device) { return; } LOG_WARNING(Render_Vulkan, - "Switch 2 program with {} MiB of video memory: ASTC textures are re-compressed to " - "BC3 for this session (uncompressed ASTC needs 12 GiB or more). Set " - "EDEN_NX2_KEEP_ASTC=1 to keep them uncompressed", + "Switch 2 program with a {} MiB video memory budget: ASTC textures are " + "re-compressed to BC3 for this session (uncompressed ASTC needs a 12 GiB budget). " + "Set EDEN_NX2_KEEP_ASTC=1 to keep them uncompressed", memory >> 20); - // Per-game value, like the Switch 2 memory layout: RestoreGlobalState undoes it. - Settings::values.astc_recompression.SetGlobal(false); - Settings::values.astc_recompression.SetValue(Settings::AstcRecompression::Bc3); + Settings::SetAstcRecompressionOverride(Settings::AstcRecompression::Bc3); } } // Anonymous namespace @@ -1127,8 +1124,7 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched !device.IsOptimalAstcSupported()) { astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, compute_pass_descriptor_queue, memory_allocator); - if (Settings::values.astc_recompression.GetValue() != - Settings::AstcRecompression::Uncompressed) { + if (Settings::GetAstcRecompression() != Settings::AstcRecompression::Uncompressed) { bc_encoder_pass.emplace(device, scheduler, descriptor_pool, compute_pass_descriptor_queue); } @@ -2016,7 +2012,7 @@ bool TextureCacheRuntime::UseOpaqueAstcFormat() const { return value == nullptr || value[0] != '0'; }(); return enabled && !device.IsOptimalAstcSupported() && - Settings::values.astc_recompression.GetValue() == Settings::AstcRecompression::Bc3; + Settings::GetAstcRecompression() == Settings::AstcRecompression::Bc3; } void TextureCacheRuntime::FlushDeferredClear() { @@ -3702,8 +3698,7 @@ void TextureCacheRuntime::TranscodeAstcToBcn( // Encode every level into one buffer, then copy it into the image. const bool bc3 = !IsOpaqueBc1Astc(device, info) && - Settings::values.astc_recompression.GetValue() != - Settings::AstcRecompression::Bc1; + Settings::GetAstcRecompression() != Settings::AstcRecompression::Bc1; const u64 block_bytes = bc3 ? 16 : 8; boost::container::small_vector<VideoCommon::BufferImageCopy, 16> copies; u64 total = 0; diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 4603870bfa..66b9577cb5 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -469,7 +469,7 @@ u64 TranscodedAstcSize(u64 base_size, PixelFormat format) { static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE; const u64 uncompressed_size = (base_size * base_block_size) / BytesPerBlock(format); - switch (Settings::values.astc_recompression.GetValue()) { + switch (Settings::GetAstcRecompression()) { case Settings::AstcRecompression::Bc1: return uncompressed_size / 8; case Settings::AstcRecompression::Bc3: diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index ffc1d59ec3..ef34019a08 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -613,10 +613,10 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept { return info.size.width * BytesPerBlock(info.format); } static constexpr Extent2D TILE_SIZE{1, 1}; - if (IsPixelFormatASTC(info.format) && Settings::values.astc_recompression.GetValue() != - Settings::AstcRecompression::Uncompressed) { + if (IsPixelFormatASTC(info.format) && + Settings::GetAstcRecompression() != Settings::AstcRecompression::Uncompressed) { const u32 bpp_div = - Settings::values.astc_recompression.GetValue() == Settings::AstcRecompression::Bc1 || + Settings::GetAstcRecompression() == Settings::AstcRecompression::Bc1 || info.astc_opaque ? 2 : 1; @@ -931,7 +931,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory void ConvertedLayout(const ImageInfo& info, std::span<BufferImageCopy> copies) { // Same offsets and sizes as ConvertImage below. - const auto recompression = Settings::values.astc_recompression.GetValue(); + const auto recompression = Settings::GetAstcRecompression(); const bool astc = IsPixelFormatASTC(info.format); u64 output_offset = 0; for (BufferImageCopy& copy : copies) { @@ -976,7 +976,7 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8 const auto input_offset = input.subspan(copy.buffer_offset); copy.buffer_offset = output_offset; - const auto recompression_setting = Settings::values.astc_recompression.GetValue(); + const auto recompression_setting = Settings::GetAstcRecompression(); const bool astc = IsPixelFormatASTC(info.format); if (astc && recompression_setting == Settings::AstcRecompression::Uncompressed) { diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 915b22aaf5..623ab7c30d 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -411,6 +411,16 @@ std::filesystem::path StaticPipelineCacheFilename() { return shader_dir / "vulkan_static_pipelines.bin"; } +// What a heap's allocations use. The driver also counts the space in VMA's blocks no allocation +// uses, but freeing an image gives its share back only once its whole block is empty: the caches, +// collecting until the usage dropped, evicted thousands of textures in a row without lowering it +// (title 1). +u64 AllocatedUsage(VkDeviceSize driver_usage, const VmaBudget& vma_budget) { + const VmaStatistics& statistics = vma_budget.statistics; + const u64 unused = statistics.blockBytes - statistics.allocationBytes; + return driver_usage - (std::min)(driver_usage, unused); +} + } // Anonymous namespace void Device::RemoveExtension(bool& extension, const std::string& extension_name) { @@ -1615,26 +1625,16 @@ void Device::ReleaseCustomBorderColorSamplers(size_t count) const { } u64 Device::GetDeviceMemoryUsage() const { - VkPhysicalDeviceMemoryBudgetPropertiesEXT budget; + VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{}; budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; - budget.pNext = nullptr; physical.GetMemoryProperties(&budget); - u64 result{}; - for (const size_t heap : valid_heap_memory) { - result += budget.heapUsage[heap]; - } - // Space in VMA's blocks that no allocation uses counts as used, but freeing an image gives - // its share back only once its whole block is empty: the caches, collecting until this drops, - // evicted thousands of textures in a row without lowering it (title 1). Count only what - // allocations use. + std::array<VmaBudget, VK_MAX_MEMORY_HEAPS> heap_budgets{}; if (allocator != nullptr) { - std::array<VmaBudget, VK_MAX_MEMORY_HEAPS> heap_budgets{}; vmaGetHeapBudgets(allocator, heap_budgets.data()); - for (const size_t heap : valid_heap_memory) { - const VmaStatistics& statistics = heap_budgets[heap].statistics; - const u64 unused = statistics.blockBytes - statistics.allocationBytes; - result -= (std::min)(result, unused); - } + } + u64 result{}; + for (const size_t heap : valid_heap_memory) { + result += AllocatedUsage(budget.heapUsage[heap], heap_budgets[heap]); } return result; } @@ -1652,16 +1652,15 @@ u64 Device::GetDeviceMemoryBudget() const { } // Only the main heap's budget: summing every heap's counted VRAM twice on AMD (an 8 GB card // reported 8.5 GB) and kept the collector's thresholds above the heap the images fill. What - // the other heaps use is added, as GetDeviceMemoryUsage() counts it too. + // the other heaps use is added the way GetDeviceMemoryUsage() counts it, so the usage reaches + // this when the main heap's does its budget. u64 result = budget.heapBudget[main_heap]; if (heap_size_limit != 0) { result = (std::min)(result, heap_size_limit); } for (const size_t heap : valid_heap_memory) { if (heap != main_heap) { - const VmaStatistics& statistics = heap_budgets[heap].statistics; - const u64 unused = statistics.blockBytes - statistics.allocationBytes; - result += budget.heapUsage[heap] - (std::min)(budget.heapUsage[heap], unused); + result += AllocatedUsage(budget.heapUsage[heap], heap_budgets[heap]); } } return result; @@ -1681,8 +1680,13 @@ void Device::CollectPhysicalMemoryInfo() { // EDEN_NX2_VRAM_LIMIT_MIB=<n>: treat every device-local heap as n MiB (small card tests). if (const char* value = std::getenv("EDEN_NX2_VRAM_LIMIT_MIB")) { heap_size_limit = std::strtoull(value, nullptr, 10) << 20; - LOG_INFO(Render_Vulkan, "EDEN_NX2_VRAM_LIMIT_MIB: device-local heaps limited to {} MiB", - heap_size_limit >> 20); + if (heap_size_limit != 0) { + LOG_INFO(Render_Vulkan, "EDEN_NX2_VRAM_LIMIT_MIB: device-local heaps limited to {} MiB", + heap_size_limit >> 20); + } else { + LOG_WARNING(Render_Vulkan, "EDEN_NX2_VRAM_LIMIT_MIB={} is not a size in MiB, ignored", + value); + } } const auto limit = [this](u64 size) { return heap_size_limit != 0 ? (std::min)(size, heap_size_limit) : size; |
