aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornéo Luigi <85024393+neoluigi4123@users.noreply.github.com>2026-10-31 15:33:09 +0100
committerkraibse <33869366+kraibse@users.noreply.github.com>2026-10-31 18:04:23 +0100
commit82963e6750cef756d2ad4d1115dc9dca420d4313 (patch)
tree8378304104c807b5d08f2985d6e7b75c57c0ae06
parent2065b1431c0ecfeade61a7e7511889c4800b6bb9 (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.cpp10
-rw-r--r--src/common/settings.h6
-rw-r--r--src/core/core.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp8
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp33
-rw-r--r--src/video_core/surface.cpp2
-rw-r--r--src/video_core/texture_cache/util.cpp10
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp48
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;