From 64ce859a6a6add39c15267a33e6a5085dbdbd86d Mon Sep 17 00:00:00 2001 From: JPikachu Date: Wed, 27 Aug 2025 22:19:17 +0200 Subject: [PATCH 01/44] [VK] Refine VRAM allocation strategy for improved stability and performance (#334) These adjustments enhance memory management, While increasing shader performance across all GPU types, including iGPUs. This commit fixes a bug in Super Mario Odyssey where loading into a new area or pausing the game Would cause the whole game to slow down (Most noticeable on RDNA 2 GPUs like the Steam Deck) Thank you to all of our testers for helping eliminate this bug, And thank you to Camille for the instructions/commit and to Zephyron for addressing this in Citron. Co-authored-by: JPikachu Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/334 Reviewed-by: CamilleLaVey Co-authored-by: JPikachu Co-committed-by: JPikachu --- src/video_core/vulkan_common/vulkan_device.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 6bd6eab009..cfa88850a0 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1378,13 +1378,13 @@ void Device::CollectPhysicalMemoryInfo() { device_access_memory += mem_properties.memoryHeaps[element].size; } if (!is_integrated) { - const u64 reserve_memory = std::min(device_access_memory / 8, 1_GiB); + const u64 reserve_memory = std::min(device_access_memory / 4, 2_GiB); device_access_memory -= reserve_memory; if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) { // Account for resolution scaling in memory limits - const size_t normal_memory = 6_GiB; - const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1); + const size_t normal_memory = 8_GiB; + const size_t scaler_memory = 2_GiB * Settings::values.resolution_info.ScaleUp(1); device_access_memory = std::min(device_access_memory, normal_memory + scaler_memory); } @@ -1393,7 +1393,7 @@ void Device::CollectPhysicalMemoryInfo() { } const s64 available_memory = static_cast(device_access_memory - device_initial_usage); device_access_memory = static_cast(std::max( - std::min(available_memory - 8_GiB, 4_GiB), std::min(local_memory, 4_GiB))); + std::min(available_memory - 4_GiB, 6_GiB), std::min(local_memory, 6_GiB))); } void Device::CollectToolingInfo() { From 169bc44f0b99b6e29b6a0113f23844cf126df13e Mon Sep 17 00:00:00 2001 From: wildcard Date: Wed, 27 Aug 2025 22:20:02 +0200 Subject: [PATCH 02/44] [VK] Very conservative and spec-compliant alignment (#335) spec-compliant alignment: Implement spec-compliant alignment for non-coherent memory and buffer-image granularity revert oom handling Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/335 Reviewed-by: CamilleLaVey Co-authored-by: wildcard Co-committed-by: wildcard --- .../vulkan_common/vulkan_memory_allocator.cpp | 111 +++--------------- 1 file changed, 16 insertions(+), 95 deletions(-) diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 4c92d4bfa0..2e37615f99 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -143,9 +143,6 @@ public: return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0; } - [[nodiscard]] bool IsEmpty() const noexcept { - return commits.empty(); - } private: [[nodiscard]] static constexpr u32 ShiftType(u32 type) { @@ -287,107 +284,31 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsa } MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { - // Find the fastest memory flags we can afford with the current requirements - const u32 type_mask = requirements.memoryTypeBits; - const VkMemoryPropertyFlags usage_flags = MemoryUsagePropertyFlags(usage); - const VkMemoryPropertyFlags flags = MemoryPropertyFlags(type_mask, usage_flags); - if (std::optional commit = TryCommit(requirements, flags)) { - return std::move(*commit); - } - - // Commit has failed, try progressive fallback strategy - u64 chunk_size = AllocationChunkSize(requirements.size); - const u64 minimum_size = std::max(requirements.size, 4ULL << 20); // 4MB minimum - - // try 1: Try allocating with original chunk size - if (TryAllocMemory(flags, type_mask, chunk_size)) { + // Find the fastest memory flags we can afford with the current requirements + const u32 type_mask = requirements.memoryTypeBits; + const VkMemoryPropertyFlags usage_flags = MemoryUsagePropertyFlags(usage); + const VkMemoryPropertyFlags flags = MemoryPropertyFlags(type_mask, usage_flags); + if (std::optional commit = TryCommit(requirements, flags)) { + return std::move(*commit); + } + // Commit has failed, allocate more memory. + const u64 chunk_size = AllocationChunkSize(requirements.size); + if (!TryAllocMemory(flags, type_mask, chunk_size)) { + // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. + throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); + } + // Commit again, this time it won't fail since there's a fresh allocation above. + // If it does, there's a bug. return TryCommit(requirements, flags).value(); } - // try 2: Clean up empty allocations and try again - bool cleaned_up = false; - for (auto it = allocations.begin(); it != allocations.end();) { - if ((*it)->IsEmpty()) { - it = allocations.erase(it); - cleaned_up = true; - } else { - ++it; - } - } - - if (cleaned_up && TryAllocMemory(flags, type_mask, chunk_size)) { - LOG_INFO(Render_Vulkan, "Memory allocation succeeded after cleanup"); - return TryCommit(requirements, flags).value(); - } - - // try 3: Progressive size reduction with cleanup between attempts - while (chunk_size > minimum_size) { - chunk_size >>= 1; // Halve the chunk size - chunk_size = std::max(chunk_size, minimum_size); - - if (TryAllocMemory(flags, type_mask, chunk_size)) { - LOG_WARNING(Render_Vulkan, "Memory allocation succeeded with reduced chunk size: {} MB", - chunk_size >> 20); - return TryCommit(requirements, flags).value(); - } - - // Clean up again between size reduction attempts - for (auto it = allocations.begin(); it != allocations.end();) { - if ((*it)->IsEmpty()) { - it = allocations.erase(it); - } else { - ++it; - } - } - } - - // try 4: Try minimum size allocation - if (chunk_size <= minimum_size && TryAllocMemory(flags, type_mask, minimum_size)) { - LOG_WARNING(Render_Vulkan, "Memory allocation succeeded with minimum size: {} MB", - minimum_size >> 20); - return TryCommit(requirements, flags).value(); - } - // try 5: Fallback to non-device-local memory if original was device-local - if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { - const VkMemoryPropertyFlags fallback_flags = flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - // Try with original chunk size first - u64 fallback_chunk_size = AllocationChunkSize(requirements.size); - if (TryAllocMemory(fallback_flags, type_mask, fallback_chunk_size)) { - if (auto commit = TryCommit(requirements, fallback_flags)) { - LOG_WARNING(Render_Vulkan, "Falling back to non-device-local memory due to OOM"); - return std::move(*commit); - } - } - - // Progressive size reduction for non-device-local memory - while (fallback_chunk_size > minimum_size) { - fallback_chunk_size >>= 1; - fallback_chunk_size = std::max(fallback_chunk_size, minimum_size); - - if (TryAllocMemory(fallback_flags, type_mask, fallback_chunk_size)) { - if (auto commit = TryCommit(requirements, fallback_flags)) { - LOG_WARNING(Render_Vulkan, - "Falling back to non-device-local memory with reduced size: {} MB", - fallback_chunk_size >> 20); - return std::move(*commit); - } - } - } - } - - - LOG_CRITICAL(Render_Vulkan, "Vulkan memory allocation failed - exhausted all strategies"); - throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); -} - bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { const auto type_opt = FindType(flags, type_mask); if (!type_opt) { return false; } - // Adreno requires 4KB alignment(subject to review) + // Adreno stands firm const u64 aligned_size = (device.GetDriverID() == VK_DRIVER_ID_QUALCOMM_PROPRIETARY) ? Common::AlignUp(size, 4096) : size; From f1083a2366b9243443886b0846b02716cccac6c2 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 27 Aug 2025 22:21:04 +0200 Subject: [PATCH 03/44] [common, fs] Use std::string_view instead of std::string&; inline functions that are used rarely (#330) Signed-off-by: lizzie Co-authored-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/330 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/fs/path_util.cpp | 20 ---------- src/common/fs/path_util.h | 12 +++++- src/common/heap_tracker.cpp | 3 +- src/common/string_util.cpp | 46 +++++------------------ src/common/string_util.h | 53 ++++++++++++++++++--------- src/core/file_sys/xts_archive.cpp | 7 +++- src/core/loader/loader.cpp | 19 +++++----- src/frontend_common/content_manager.h | 5 ++- 8 files changed, 76 insertions(+), 89 deletions(-) diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index e032360961..fa1403225e 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -517,24 +517,4 @@ std::string_view GetPathWithoutTop(std::string_view path) { return path.substr(std::min(name_bck_index, name_fwd_index) + 1); } -std::string_view GetFilename(std::string_view path) { - const auto name_index = path.find_last_of("\\/"); - - if (name_index == std::string_view::npos) { - return {}; - } - - return path.substr(name_index + 1); -} - -std::string_view GetExtensionFromFilename(std::string_view name) { - const std::size_t index = name.rfind('.'); - - if (index == std::string_view::npos) { - return {}; - } - - return name.substr(index + 1); -} - } // namespace Common::FS diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index c1f478690a..b34efc472f 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h @@ -352,9 +352,17 @@ enum class DirectorySeparator { [[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path); // Gets the filename of the path -[[nodiscard]] std::string_view GetFilename(std::string_view path); +[[nodiscard]] inline std::string_view GetFilename(const std::string_view path) noexcept { + if (auto const name_index = path.find_last_of("\\/"); name_index != std::string_view::npos) + return path.substr(name_index + 1); + return {}; +} // Gets the extension of the filename -[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name); +[[nodiscard]] inline std::string_view GetExtensionFromFilename(const std::string_view name) noexcept { + if (auto const index = name.rfind('.'); index != std::string_view::npos) + return name.substr(index + 1); + return {}; +} } // namespace Common::FS diff --git a/src/common/heap_tracker.cpp b/src/common/heap_tracker.cpp index d509f2644c..c147c279bd 100644 --- a/src/common/heap_tracker.cpp +++ b/src/common/heap_tracker.cpp @@ -4,10 +4,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include - #include "common/heap_tracker.h" #include "common/logging/log.h" +#include "common/assert.h" namespace Common { diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 1909aced54..7bcbe737b6 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -7,6 +10,7 @@ #include #include #include +#include #include "common/string_util.h" @@ -21,51 +25,21 @@ namespace Common { /// Make a string lowercase -std::string ToLower(std::string str) { +std::string ToLower(const std::string_view sv) { + std::string str{sv}; std::transform(str.begin(), str.end(), str.begin(), - [](unsigned char c) { return static_cast(std::tolower(c)); }); + [](auto const c) { return char(std::tolower(c)); }); return str; } /// Make a string uppercase -std::string ToUpper(std::string str) { +std::string ToUpper(const std::string_view sv) { + std::string str{sv}; std::transform(str.begin(), str.end(), str.begin(), - [](unsigned char c) { return static_cast(std::toupper(c)); }); + [](auto const c) { return char(std::toupper(c)); }); return str; } -std::string StringFromBuffer(std::span data) { - return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); -} - -std::string StringFromBuffer(std::span data) { - return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); -} - -// Turns " hej " into "hej". Also handles tabs. -std::string StripSpaces(const std::string& str) { - const std::size_t s = str.find_first_not_of(" \t\r\n"); - - if (str.npos != s) - return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); - else - return ""; -} - -// "\"hello\"" is turned to "hello" -// This one assumes that the string has already been space stripped in both -// ends, as done by StripSpaces above, for example. -std::string StripQuotes(const std::string& s) { - if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) - return s.substr(1, s.size() - 2); - else - return s; -} - -std::string StringFromBool(bool value) { - return value ? "True" : "False"; -} - bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) { if (full_path.empty()) diff --git a/src/common/string_util.h b/src/common/string_util.h index 53d0549ca7..8ed87cdadc 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -13,18 +16,38 @@ namespace Common { /// Make a string lowercase -[[nodiscard]] std::string ToLower(std::string str); +[[nodiscard]] std::string ToLower(const std::string_view sv); /// Make a string uppercase -[[nodiscard]] std::string ToUpper(std::string str); +[[nodiscard]] std::string ToUpper(const std::string_view sv); -[[nodiscard]] std::string StringFromBuffer(std::span data); -[[nodiscard]] std::string StringFromBuffer(std::span data); +[[nodiscard]] inline std::string StringFromBuffer(std::span data) noexcept { + return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); +} +[[nodiscard]] inline std::string StringFromBuffer(std::span data) noexcept { + return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); +} -[[nodiscard]] std::string StripSpaces(const std::string& s); -[[nodiscard]] std::string StripQuotes(const std::string& s); +/// Turns " hej " into "hej". Also handles tabs. +[[nodiscard]] inline std::string StripSpaces(const std::string_view str) noexcept { + const std::size_t s = str.find_first_not_of(" \t\r\n"); + if (str.npos != s) + return std::string{str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1)}; + return {}; +} -[[nodiscard]] std::string StringFromBool(bool value); +/// "\"hello\"" is turned to "hello" +/// This one assumes that the string has already been space stripped in both +/// ends, as done by StripSpaces above, for example. +[[nodiscard]] inline std::string StripQuotes(const std::string_view s) noexcept { + if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) + return std::string{s.substr(1, s.size() - 2)}; + return std::string{s}; +} + +[[nodiscard]] inline std::string StringFromBool(bool value) noexcept { + return value ? "True" : "False"; +} [[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in); @@ -54,7 +77,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ * `other` for equality. */ template -[[nodiscard]] bool ComparePartialString(InIt begin, InIt end, const char* other) { +[[nodiscard]] inline bool ComparePartialString(InIt begin, InIt end, const char* other) noexcept { for (; begin != end && *other != '\0'; ++begin, ++other) { if (*begin != *other) { return false; @@ -64,18 +87,14 @@ template return (begin == end) == (*other == '\0'); } -/** - * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't - * NUL-terminated then the string ends at max_len characters. - */ +/// Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't +/// NUL-terminated then the string ends at max_len characters. [[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, std::size_t max_len); -/** - * Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't - * null-terminated, then the string ends at the greatest multiple of two less then or equal to - * max_len_bytes. - */ +/// Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't +/// null-terminated, then the string ends at the greatest multiple of two less then or equal to +/// max_len_bytes. [[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, std::size_t max_len); diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index 6692211e1d..fd5342021c 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -56,8 +59,8 @@ NAX::NAX(VirtualFile file_) return; } - const std::string two_dir = Common::ToUpper(match[1]); - const std::string nca_id = Common::ToLower(match[2]); + const std::string two_dir = Common::ToUpper(std::string{match[1]}); + const std::string nca_id = Common::ToLower(std::string{match[2]}); status = Parse(fmt::format("/registered/{}/{}.nca", two_dir, nca_id)); } diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 6aabdc75e1..1f0bc4d2c1 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -61,25 +64,23 @@ FileType IdentifyFile(FileSys::VirtualFile file) { FileType GuessFromFilename(const std::string& name) { if (name == "main") return FileType::DeconstructedRomDirectory; - if (name == "00") + else if (name == "00") return FileType::NCA; - const std::string extension = + auto const extension = Common::ToLower(std::string(Common::FS::GetExtensionFromFilename(name))); - if (extension == "nro") return FileType::NRO; - if (extension == "nso") + else if (extension == "nso") return FileType::NSO; - if (extension == "nca") + else if (extension == "nca") return FileType::NCA; - if (extension == "xci") + else if (extension == "xci") return FileType::XCI; - if (extension == "nsp") + else if (extension == "nsp") return FileType::NSP; - if (extension == "kip") + else if (extension == "kip") return FileType::KIP; - return FileType::Unknown; } diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h index c4e97a47b8..4f3112e3fb 100644 --- a/src/frontend_common/content_manager.h +++ b/src/frontend_common/content_manager.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -160,7 +163,7 @@ inline InstallResult InstallNSP(Core::System& system, FileSys::VfsFilesystem& vf std::shared_ptr nsp; FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::OpenMode::Read); - if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) { + if (boost::to_lower_copy(file->GetName()).ends_with("nsp")) { nsp = std::make_shared(file); if (nsp->IsExtractedType()) { return InstallResult::Failure; From 31b3e3e0ea8a69e69f3ebcf07bd7440a57670f53 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 27 Aug 2025 12:10:53 +0200 Subject: [PATCH 04/44] [jit] Increase x86_64 default code size to full 2GiB hugepage (#318) Abuses the existence of transparent huge pages on Unix. 4*2 = 8GiB virtual memory used total by JIT. May reduce native host TLB trees. Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/318 Reviewed-by: Shinmegumi Co-authored-by: lizzie Co-committed-by: lizzie --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 1731ef1aec..db159388bf 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -215,7 +215,7 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa #ifdef ARCHITECTURE_arm64 config.code_cache_size = std::uint32_t(128_MiB); #else - config.code_cache_size = std::uint32_t(512_MiB); + config.code_cache_size = std::uint32_t(2_GiB); #endif // Allow memory fault handling to work diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 9674e88d9d..dcff0ddf3f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -273,7 +273,7 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa #ifdef ARCHITECTURE_arm64 config.code_cache_size = std::uint32_t(128_MiB); #else - config.code_cache_size = std::uint32_t(512_MiB); + config.code_cache_size = std::uint32_t(2_GiB); #endif // Allow memory fault handling to work From 489ec2dcb684ca262ed91a0cd11632359d8e31fb Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 27 Aug 2025 12:12:32 +0200 Subject: [PATCH 05/44] [jit] Disable fastmem (by default) on FreeBSD, Solaris and OpenBSD due to subpar timings of SIGSEGV (#319) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/319 Reviewed-by: Shinmegumi Co-authored-by: lizzie Co-committed-by: lizzie --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 20 +++++++++++++------- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 20 +++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index db159388bf..798623a5fa 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -269,8 +269,13 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa config.check_halt_on_memory_access = true; } } else { +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; +#endif + switch (Settings::values.cpu_accuracy.GetValue()) { // Unsafe optimizations - if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { + case Settings::CpuAccuracy::Unsafe: config.unsafe_optimizations = true; if (Settings::values.cpuopt_unsafe_unfuse_fma) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; @@ -287,21 +292,22 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa if (Settings::values.cpuopt_unsafe_ignore_global_monitor) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } - } - + break; // Curated optimizations - if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) { + case Settings::CpuAccuracy::Auto: config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; - } - + break; // Paranoia mode for debugging optimizations - if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) { + case Settings::CpuAccuracy::Paranoid: config.unsafe_optimizations = false; config.optimizations = Dynarmic::no_optimizations; + break; + default: + break; } } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index dcff0ddf3f..7b59ce2633 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -327,8 +327,13 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa config.check_halt_on_memory_access = true; } } else { +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; +#endif // Unsafe optimizations - if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { + switch(Settings::values.cpu_accuracy.GetValue()) { + case Settings::CpuAccuracy::Unsafe: config.unsafe_optimizations = true; if (Settings::values.cpuopt_unsafe_unfuse_fma) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; @@ -345,20 +350,21 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa if (Settings::values.cpuopt_unsafe_ignore_global_monitor) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } - } - + break; // Curated optimizations - if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) { + case Settings::CpuAccuracy::Auto: config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.fastmem_address_space_bits = 64; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; - } - + break; // Paranoia mode for debugging optimizations - if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) { + case Settings::CpuAccuracy::Paranoid: config.unsafe_optimizations = false; config.optimizations = Dynarmic::no_optimizations; + break; + default: + break; } } From 5ce16c4b05ff2fb1aa3f9085c02dc5a994534d9f Mon Sep 17 00:00:00 2001 From: Shinmegumi Date: Wed, 27 Aug 2025 15:12:16 +0200 Subject: [PATCH 06/44] revert 22847ec78a4369497855672db71977ead871c49d (#331) revert [jit] Disable fastmem (by default) on FreeBSD, Solaris and OpenBSD due to subpar timings of SIGSEGV (#319) According to MaranBR, this should have never been merged and should have been closed instead as they iterated on it in 324. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/319 Reviewed-by: Shinmegumi Co-authored-by: lizzie Co-committed-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/331 Co-authored-by: Shinmegumi Co-committed-by: Shinmegumi --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 20 +++++++------------- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 20 +++++++------------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 798623a5fa..db159388bf 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -269,13 +269,8 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa config.check_halt_on_memory_access = true; } } else { -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) - config.fastmem_pointer = std::nullopt; - config.fastmem_exclusive_access = false; -#endif - switch (Settings::values.cpu_accuracy.GetValue()) { // Unsafe optimizations - case Settings::CpuAccuracy::Unsafe: + if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { config.unsafe_optimizations = true; if (Settings::values.cpuopt_unsafe_unfuse_fma) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; @@ -292,22 +287,21 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa if (Settings::values.cpuopt_unsafe_ignore_global_monitor) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } - break; + } + // Curated optimizations - case Settings::CpuAccuracy::Auto: + if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) { config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; - break; + } + // Paranoia mode for debugging optimizations - case Settings::CpuAccuracy::Paranoid: + if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) { config.unsafe_optimizations = false; config.optimizations = Dynarmic::no_optimizations; - break; - default: - break; } } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 7b59ce2633..dcff0ddf3f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -327,13 +327,8 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa config.check_halt_on_memory_access = true; } } else { -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) - config.fastmem_pointer = std::nullopt; - config.fastmem_exclusive_access = false; -#endif // Unsafe optimizations - switch(Settings::values.cpu_accuracy.GetValue()) { - case Settings::CpuAccuracy::Unsafe: + if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { config.unsafe_optimizations = true; if (Settings::values.cpuopt_unsafe_unfuse_fma) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; @@ -350,21 +345,20 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa if (Settings::values.cpuopt_unsafe_ignore_global_monitor) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } - break; + } + // Curated optimizations - case Settings::CpuAccuracy::Auto: + if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) { config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.fastmem_address_space_bits = 64; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; - break; + } + // Paranoia mode for debugging optimizations - case Settings::CpuAccuracy::Paranoid: + if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) { config.unsafe_optimizations = false; config.optimizations = Dynarmic::no_optimizations; - break; - default: - break; } } From d461f3af2b398f8b9e2996853ee63244c50507fe Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 27 Aug 2025 21:28:23 +0200 Subject: [PATCH 07/44] revert [jit] Increase x86_64 default code size to full 2GiB hugepage (#318) (#337) revert [jit] Increase x86_64 default code size to full 2GiB hugepage (#318) Abuses the existence of transparent huge pages on Unix. 4*2 = 8GiB virtual memory used total by JIT. May reduce native host TLB trees. -------------- WIP: Wasn't meant to be merged, it's going to be refined to be added later when more data/ testing have been made about this approach. Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/318 Reviewed-by: Shinmegumi Co-authored-by: lizzie Co-committed-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/337 Co-authored-by: CamilleLaVey Co-committed-by: CamilleLaVey --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index db159388bf..1731ef1aec 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -215,7 +215,7 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa #ifdef ARCHITECTURE_arm64 config.code_cache_size = std::uint32_t(128_MiB); #else - config.code_cache_size = std::uint32_t(2_GiB); + config.code_cache_size = std::uint32_t(512_MiB); #endif // Allow memory fault handling to work diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index dcff0ddf3f..9674e88d9d 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -273,7 +273,7 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa #ifdef ARCHITECTURE_arm64 config.code_cache_size = std::uint32_t(128_MiB); #else - config.code_cache_size = std::uint32_t(2_GiB); + config.code_cache_size = std::uint32_t(512_MiB); #endif // Allow memory fault handling to work From ad37d20fc1d98a81eda7140404de2097f11f41ff Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 27 Aug 2025 22:26:08 +0200 Subject: [PATCH 08/44] [common/host_memory] use assert instead of throw on Impl() ctor; abort on error (#316) Rationale: Throwing when running out of memory just creates sad paths for no reason (and at that point, just abort immediately). We are using MAP_NORESERVE, if there isn't enough memory a crash will follow anyways. Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/316 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/host_memory.cpp | 42 +++++------------------ src/core/arm/dynarmic/arm_dynarmic_32.cpp | 1 - 2 files changed, 8 insertions(+), 35 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 949cd188f3..f847ea2a62 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -477,19 +477,9 @@ class HostMemory::Impl { public: explicit Impl(size_t backing_size_, size_t virtual_size_) : backing_size{backing_size_}, virtual_size{virtual_size_} { - bool good = false; - SCOPE_EXIT { - if (!good) { - Release(); - } - }; - long page_size = sysconf(_SC_PAGESIZE); - if (page_size != 0x1000) { - LOG_CRITICAL(HW_Memory, "page size {:#x} is incompatible with 4K paging", page_size); - throw std::bad_alloc{}; - } - + ASSERT_MSG(page_size == 0x1000, "page size {:#x} is incompatible with 4K paging", + page_size); // Backing memory initialization #if defined(__sun__) || defined(__HAIKU__) || defined(__NetBSD__) || defined(__DragonFly__) fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); @@ -501,38 +491,23 @@ public: #else fd = memfd_create("HostMemory", 0); #endif - if (fd < 0) { - LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); - throw std::bad_alloc{}; - } + ASSERT_MSG(fd >= 0, "memfd_create failed: {}", strerror(errno)); // Defined to extend the file with zeros int ret = ftruncate(fd, backing_size); - if (ret != 0) { - LOG_CRITICAL(HW_Memory, "ftruncate failed with {}, are you out-of-memory?", - strerror(errno)); - throw std::bad_alloc{}; - } + ASSERT_MSG(ret == 0, "ftruncate failed with {}, are you out-of-memory?", strerror(errno)); backing_base = static_cast( mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); - if (backing_base == MAP_FAILED) { - LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno)); - throw std::bad_alloc{}; - } + ASSERT_MSG(backing_base != MAP_FAILED, "mmap failed: {}", strerror(errno)); // Virtual memory initialization virtual_base = virtual_map_base = static_cast(ChooseVirtualBase(virtual_size)); - if (virtual_base == MAP_FAILED) { - LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno)); - throw std::bad_alloc{}; - } + ASSERT_MSG(virtual_base != MAP_FAILED, "mmap failed: {}", strerror(errno)); #if defined(__linux__) madvise(virtual_base, virtual_size, MADV_HUGEPAGE); #endif - free_manager.SetAddressSpace(virtual_base, virtual_size); - good = true; } ~Impl() { @@ -673,10 +648,9 @@ private: class HostMemory::Impl { public: - explicit Impl(size_t /*backing_size */, size_t /* virtual_size */) { + explicit Impl([[maybe_unused]] size_t backing_size, [[maybe_unused]] size_t virtual_size) { // This is just a place holder. - // Please implement fastmem in a proper way on your platform. - throw std::bad_alloc{}; + ASSERT_MSG(false, "Please implement fastmem in a proper way on your platform."); } void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm) {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 1731ef1aec..7bb5156147 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -175,7 +175,6 @@ public: Kernel::KProcess* m_process{}; const bool m_debugger_enabled{}; const bool m_check_memory_access{}; - static constexpr u64 MinimumRunCycles = 10000U; }; std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* page_table) const { From 62953003eece9ce8544935cae571519629030ba4 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 27 Aug 2025 22:39:11 +0200 Subject: [PATCH 09/44] [fmt] use {:#X} for format instead of 0x{:X} (#309) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/309 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- src/audio_core/opus/decoder.cpp | 5 +++- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 2 +- src/core/file_sys/program_metadata.cpp | 5 +++- .../hle/kernel/svc/svc_address_arbiter.cpp | 7 +++-- src/core/hle/kernel/svc/svc_code_memory.cpp | 9 ++++--- .../hle/kernel/svc/svc_condition_variable.cpp | 5 +++- src/core/hle/kernel/svc/svc_info.cpp | 2 +- src/core/hle/kernel/svc/svc_lock.cpp | 7 +++-- src/core/hle/kernel/svc/svc_memory.cpp | 11 +++++--- .../hle/kernel/svc/svc_physical_memory.cpp | 13 +++++---- src/core/hle/kernel/svc/svc_process.cpp | 5 +++- .../hle/kernel/svc/svc_process_memory.cpp | 9 ++++--- src/core/hle/kernel/svc/svc_shared_memory.cpp | 5 +++- .../hle/kernel/svc/svc_synchronization.cpp | 5 +++- src/core/hle/kernel/svc/svc_thread.cpp | 5 +++- src/core/hle/service/fatal/fatal.cpp | 7 +++-- .../hle/service/filesystem/fsp/fs_i_file.cpp | 7 +++-- .../filesystem/fsp/fs_i_filesystem.cpp | 5 +++- .../service/filesystem/fsp/fs_i_storage.cpp | 5 +++- src/core/hle/service/hid/applet_resource.cpp | 5 +++- src/core/hle/service/hid/hid_server.cpp | 2 +- .../service/nvdrv/devices/nvhost_as_gpu.cpp | 16 +++++------ .../service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 9 ++++--- .../hle/service/nvdrv/devices/nvhost_gpu.cpp | 6 ++--- src/core/hle/service/nvdrv/devices/nvmap.cpp | 5 +++- .../hle/service/nvdrv/nvdrv_interface.cpp | 5 +++- .../hle/service/psc/time/steady_clock.cpp | 5 +++- src/core/hle/service/service.cpp | 9 ++++--- src/core/loader/kip.cpp | 5 +++- src/core/loader/nso.cpp | 5 +++- src/video_core/cdma_pusher.cpp | 6 ++--- src/video_core/host1x/codecs/decoder.cpp | 4 +-- src/video_core/host1x/control.cpp | 5 +++- src/video_core/host1x/vic.cpp | 27 ++++++++++--------- src/video_core/texture_cache/formatter.cpp | 21 ++++++++------- 36 files changed, 170 insertions(+), 86 deletions(-) diff --git a/src/audio_core/opus/decoder.cpp b/src/audio_core/opus/decoder.cpp index 0c110cbeb6..e60a7d48d4 100644 --- a/src/audio_core/opus/decoder.cpp +++ b/src/audio_core/opus/decoder.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -148,7 +151,7 @@ Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out auto* header_p{reinterpret_cast(input_data.data())}; OpusPacketHeader header{ReverseHeader(*header_p)}; - LOG_TRACE(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}", + LOG_TRACE(Service_Audio, "header size {:#X} input data size 0x{:X} in_data size 0x{:X}", header.size, input_data.size_bytes(), in_data.size_bytes()); R_UNLESS(in_data.size_bytes() >= header.size && diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 7bb5156147..c6e159cc9c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -88,7 +88,7 @@ public: void InterpreterFallback(u32 pc, std::size_t num_instructions) override { m_parent.LogBacktrace(m_process); LOG_ERROR(Core_ARM, - "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, + "Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc, num_instructions, m_memory.Read32(pc)); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 9674e88d9d..ba5c608a03 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -102,7 +102,7 @@ public: void InterpreterFallback(u64 pc, std::size_t num_instructions) override { m_parent.LogBacktrace(m_process); LOG_ERROR(Core_ARM, - "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, + "Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc, num_instructions, m_memory.Read32(pc)); ReturnException(pc, PrefetchAbort); } diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 289969cc4c..f542a09d0e 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -180,7 +183,7 @@ void ProgramMetadata::Print() const { LOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data()); LOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority); LOG_DEBUG(Service_FS, "Main thread core: {}", npdm_header.main_thread_cpu); - LOG_DEBUG(Service_FS, "Main thread stack size: 0x{:X} bytes", npdm_header.main_stack_size); + LOG_DEBUG(Service_FS, "Main thread stack size: {:#X} bytes", npdm_header.main_stack_size); LOG_DEBUG(Service_FS, "Process category: {}", npdm_header.process_category); LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", npdm_header.flags); LOG_DEBUG(Service_FS, " > 64-bit instructions: {}", diff --git a/src/core/hle/kernel/svc/svc_address_arbiter.cpp b/src/core/hle/kernel/svc/svc_address_arbiter.cpp index 90ee435219..ab91d74433 100644 --- a/src/core/hle/kernel/svc/svc_address_arbiter.cpp +++ b/src/core/hle/kernel/svc/svc_address_arbiter.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -40,7 +43,7 @@ constexpr bool IsValidArbitrationType(Svc::ArbitrationType type) { // Wait for an address (via Address Arbiter) Result WaitForAddress(Core::System& system, u64 address, ArbitrationType arb_type, s32 value, s64 timeout_ns) { - LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, arb_type=0x{:X}, value=0x{:X}, timeout_ns={}", + LOG_TRACE(Kernel_SVC, "called, address={:#X}, arb_type=0x{:X}, value=0x{:X}, timeout_ns={}", address, arb_type, value, timeout_ns); // Validate input. @@ -71,7 +74,7 @@ Result WaitForAddress(Core::System& system, u64 address, ArbitrationType arb_typ // Signals to an address (via Address Arbiter) Result SignalToAddress(Core::System& system, u64 address, SignalType signal_type, s32 value, s32 count) { - LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, signal_type=0x{:X}, value=0x{:X}, count=0x{:X}", + LOG_TRACE(Kernel_SVC, "called, address={:#X}, signal_type=0x{:X}, value=0x{:X}, count=0x{:X}", address, signal_type, value, count); // Validate input. diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp index 7be2802f07..4e7af9f575 100644 --- a/src/core/hle/kernel/svc/svc_code_memory.cpp +++ b/src/core/hle/kernel/svc/svc_code_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -30,7 +33,7 @@ constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(MemoryPermission perm) } // namespace Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t size) { - LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, size=0x{:X}", address, size); + LOG_TRACE(Kernel_SVC, "called, address={:#X}, size=0x{:X}", address, size); // Get kernel instance. auto& kernel = system.Kernel(); @@ -70,8 +73,8 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, MemoryPermission perm) { LOG_TRACE(Kernel_SVC, - "called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, " - "permission=0x{:X}", + "called, code_memory_handle={:#X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, " + "permission={:#X}", code_memory_handle, operation, address, size, perm); // Validate the address / size. diff --git a/src/core/hle/kernel/svc/svc_condition_variable.cpp b/src/core/hle/kernel/svc/svc_condition_variable.cpp index bb678e6c56..0f4550a795 100644 --- a/src/core/hle/kernel/svc/svc_condition_variable.cpp +++ b/src/core/hle/kernel/svc/svc_condition_variable.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -45,7 +48,7 @@ Result WaitProcessWideKeyAtomic(Core::System& system, u64 address, u64 cv_key, u /// Signal process wide key void SignalProcessWideKey(Core::System& system, u64 cv_key, s32 count) { - LOG_TRACE(Kernel_SVC, "called, cv_key=0x{:X}, count=0x{:08X}", cv_key, count); + LOG_TRACE(Kernel_SVC, "called, cv_key={:#X}, count=0x{:08X}", cv_key, count); // Signal the condition variable. return GetCurrentProcess(system.Kernel()) diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp index 37f4eba69c..16271883f2 100644 --- a/src/core/hle/kernel/svc/svc_info.cpp +++ b/src/core/hle/kernel/svc/svc_info.cpp @@ -15,7 +15,7 @@ namespace Kernel::Svc { /// Gets system/memory information for the current process Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle handle, u64 info_sub_id) { - LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", + LOG_TRACE(Kernel_SVC, "called info_id={:#X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id_type, info_sub_id, handle); u32 info_id = static_cast(info_id_type); diff --git a/src/core/hle/kernel/svc/svc_lock.cpp b/src/core/hle/kernel/svc/svc_lock.cpp index 5f0833fcbf..c44317617e 100644 --- a/src/core/hle/kernel/svc/svc_lock.cpp +++ b/src/core/hle/kernel/svc/svc_lock.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -10,7 +13,7 @@ namespace Kernel::Svc { /// Attempts to locks a mutex Result ArbitrateLock(Core::System& system, Handle thread_handle, u64 address, u32 tag) { - LOG_TRACE(Kernel_SVC, "called thread_handle=0x{:08X}, address=0x{:X}, tag=0x{:08X}", + LOG_TRACE(Kernel_SVC, "called thread_handle=0x{:08X}, address={:#X}, tag=0x{:08X}", thread_handle, address, tag); // Validate the input address. @@ -22,7 +25,7 @@ Result ArbitrateLock(Core::System& system, Handle thread_handle, u64 address, u3 /// Unlock a mutex Result ArbitrateUnlock(Core::System& system, u64 address) { - LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); + LOG_TRACE(Kernel_SVC, "called address={:#X}", address); // Validate the input address. R_UNLESS(!IsKernelAddress(address), ResultInvalidCurrentMemory); diff --git a/src/core/hle/kernel/svc/svc_memory.cpp b/src/core/hle/kernel/svc/svc_memory.cpp index 4ca62860d5..740e11ff87 100644 --- a/src/core/hle/kernel/svc/svc_memory.cpp +++ b/src/core/hle/kernel/svc/svc_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -77,7 +80,7 @@ Result MapUnmapMemorySanityChecks(const KProcessPageTable& manager, u64 dst_addr } // namespace Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPermission perm) { - LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X}", address, size, + LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size={:#X}, perm=0x{:08X}", address, size, perm); // Validate address / size. @@ -99,7 +102,7 @@ Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPe Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask, u32 attr) { LOG_DEBUG(Kernel_SVC, - "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, + "called, address=0x{:016X}, size={:#X}, mask=0x{:08X}, attribute=0x{:08X}", address, size, mask, attr); // Validate address / size. @@ -130,7 +133,7 @@ Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask, /// Maps a memory range into a different range. Result MapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) { - LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, + LOG_TRACE(Kernel_SVC, "called, dst_addr={:#X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()}; @@ -145,7 +148,7 @@ Result MapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) { /// Unmaps a region that was previously mapped with svcMapMemory Result UnmapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) { - LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, + LOG_TRACE(Kernel_SVC, "called, dst_addr={:#X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()}; diff --git a/src/core/hle/kernel/svc/svc_physical_memory.cpp b/src/core/hle/kernel/svc/svc_physical_memory.cpp index 793e9f8d01..facf8ee638 100644 --- a/src/core/hle/kernel/svc/svc_physical_memory.cpp +++ b/src/core/hle/kernel/svc/svc_physical_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -9,7 +12,7 @@ namespace Kernel::Svc { /// Set the process heap to a given Size. It can both extend and shrink the heap. Result SetHeapSize(Core::System& system, u64* out_address, u64 size) { - LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size); + LOG_TRACE(Kernel_SVC, "called, heap_size={:#X}", size); // Validate size. R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize); @@ -28,7 +31,7 @@ Result SetHeapSize(Core::System& system, u64* out_address, u64 size) { /// Maps memory at a desired address Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) { - LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); + LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size={:#X}", addr, size); if (!Common::Is4KBAligned(addr)) { LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); @@ -36,7 +39,7 @@ Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) { } if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); + LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, {:#X}", size); R_THROW(ResultInvalidSize); } @@ -77,7 +80,7 @@ Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) { /// Unmaps memory previously mapped via MapPhysicalMemory Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) { - LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); + LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size={:#X}", addr, size); if (!Common::Is4KBAligned(addr)) { LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); @@ -85,7 +88,7 @@ Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) { } if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); + LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, {:#X}", size); R_THROW(ResultInvalidSize); } diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp index 5c3e8829ff..87845d64a6 100644 --- a/src/core/hle/kernel/svc/svc_process.cpp +++ b/src/core/hle/kernel/svc/svc_process.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -92,7 +95,7 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc Result GetProcessInfo(Core::System& system, s64* out, Handle process_handle, ProcessInfoType info_type) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, info_type); + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type={:#X}", process_handle, info_type); const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); KScopedAutoObject process = handle_table.GetObject(process_handle); diff --git a/src/core/hle/kernel/svc/svc_process_memory.cpp b/src/core/hle/kernel/svc/svc_process_memory.cpp index e1427947b0..3313118dfa 100644 --- a/src/core/hle/kernel/svc/svc_process_memory.cpp +++ b/src/core/hle/kernel/svc/svc_process_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -29,7 +32,7 @@ constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) { Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, u64 address, u64 size, Svc::MemoryPermission perm) { LOG_TRACE(Kernel_SVC, - "called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", + "called, process_handle={:#X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", process_handle, address, size, perm); // Validate the address/size. @@ -59,7 +62,7 @@ Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, u Result MapProcessMemory(Core::System& system, u64 dst_address, Handle process_handle, u64 src_address, u64 size) { LOG_TRACE(Kernel_SVC, - "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", + "called, dst_address={:#X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", dst_address, process_handle, src_address, size); // Validate the address/size. @@ -100,7 +103,7 @@ Result MapProcessMemory(Core::System& system, u64 dst_address, Handle process_ha Result UnmapProcessMemory(Core::System& system, u64 dst_address, Handle process_handle, u64 src_address, u64 size) { LOG_TRACE(Kernel_SVC, - "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", + "called, dst_address={:#X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", dst_address, process_handle, src_address, size); // Validate the address/size. diff --git a/src/core/hle/kernel/svc/svc_shared_memory.cpp b/src/core/hle/kernel/svc/svc_shared_memory.cpp index 012b1ae2bc..3ca07abe8b 100644 --- a/src/core/hle/kernel/svc/svc_shared_memory.cpp +++ b/src/core/hle/kernel/svc/svc_shared_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -29,7 +32,7 @@ constexpr bool IsValidSharedMemoryPermission(MemoryPermission perm) { Result MapSharedMemory(Core::System& system, Handle shmem_handle, u64 address, u64 size, Svc::MemoryPermission map_perm) { LOG_TRACE(Kernel_SVC, - "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", + "called, shared_memory_handle={:#X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", shmem_handle, address, size, map_perm); // Validate the address/size. diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp index fb03908d73..fdd4408d4d 100644 --- a/src/core/hle/kernel/svc/svc_synchronization.cpp +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -105,7 +108,7 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha /// Resumes a thread waiting on WaitSynchronization Result CancelSynchronization(Core::System& system, Handle handle) { - LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle); + LOG_TRACE(Kernel_SVC, "called handle={:#X}", handle); // Get the thread from its handle. KScopedAutoObject thread = diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp index 7517bb9d39..77cd634c0d 100644 --- a/src/core/hle/kernel/svc/svc_thread.cpp +++ b/src/core/hle/kernel/svc/svc_thread.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -136,7 +139,7 @@ void SleepThread(Core::System& system, s64 ns) { /// Gets the thread context Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_handle) { - LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, + LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle={:#X}", out_context, thread_handle); auto& kernel = system.Kernel(); diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index dfcac1ffda..360abf5da9 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -68,7 +71,7 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F std::string crash_report = fmt::format( "Yuzu {}-{} crash report\n" "Title ID: {:016x}\n" - "Result: 0x{:X} ({:04}-{:04d})\n" + "Result: {:#X} ({:04}-{:04d})\n" "Set flags: 0x{:16X}\n" "Program entry point: 0x{:16X}\n" "\n", @@ -108,7 +111,7 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F static void ThrowFatalError(Core::System& system, Result error_code, FatalType fatal_type, const FatalInfo& info) { - LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", fatal_type, + LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code {:#X}", fatal_type, error_code.raw); switch (fatal_type) { diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp index a355d46ae1..ef9dd60ae1 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -27,7 +30,7 @@ Result IFile::Read( FileSys::ReadOption option, Out out_size, s64 offset, const OutBuffer out_buffer, s64 size) { - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset, + LOG_DEBUG(Service_FS, "called, option={}, offset={:#X}, length={}", option.value, offset, size); // Read the data from the Storage backend @@ -38,7 +41,7 @@ Result IFile::Read( Result IFile::Write( const InBuffer buffer, FileSys::WriteOption option, s64 offset, s64 size) { - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset, + LOG_DEBUG(Service_FS, "called, option={}, offset={:#X}, length={}", option.value, offset, size); R_RETURN(backend->Write(offset, buffer.data(), size, option)); diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp index d881e144d3..352b8f77b0 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -38,7 +41,7 @@ IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGe Result IFileSystem::CreateFile(const InLargeData path, s32 option, s64 size) { - LOG_DEBUG(Service_FS, "called. file={}, option=0x{:X}, size=0x{:08X}", path->str, option, size); + LOG_DEBUG(Service_FS, "called. file={}, option={:#X}, size=0x{:08X}", path->str, option, size); R_RETURN(backend->CreateFile(FileSys::Path(path->str), size)); } diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp index 213f198085..376a8bda29 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -23,7 +26,7 @@ IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_) Result IStorage::Read( OutBuffer out_bytes, s64 offset, s64 length) { - LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); + LOG_DEBUG(Service_FS, "called, offset={:#X}, length={}", offset, length); R_UNLESS(length >= 0, FileSys::ResultInvalidSize); R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset); diff --git a/src/core/hle/service/hid/applet_resource.cpp b/src/core/hle/service/hid/applet_resource.cpp index 4814d7ad51..4c5df44be5 100644 --- a/src/core/hle/service/hid/applet_resource.cpp +++ b/src/core/hle/service/hid/applet_resource.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -27,7 +30,7 @@ Result IAppletResource::GetSharedMemoryHandle( OutCopyHandle out_shared_memory_handle) { const auto result = resource_manager->GetSharedMemoryHandle(out_shared_memory_handle, aruid); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result={:#X}", aruid, result.raw); R_RETURN(result); } diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index ebda7fc3f2..1749c53ca2 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp @@ -200,7 +200,7 @@ Result IHidServer::CreateAppletResource(OutInterface out_applet ClientAppletResourceUserId aruid) { const auto result = GetResourceManager()->CreateAppletResource(aruid.pid); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid.pid, + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result={:#X}", aruid.pid, result.raw); *out_applet_resource = std::make_shared(system, resource_manager, aruid.pid); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 029a9d9cd5..02913a5817 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -93,7 +93,7 @@ void nvhost_as_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_as_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { - LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size); + LOG_DEBUG(Service_NVDRV, "called, big_page_size={:#X}", params.big_page_size); std::scoped_lock lock(mutex); @@ -104,12 +104,12 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { if (params.big_page_size) { if (!std::has_single_bit(params.big_page_size)) { - LOG_ERROR(Service_NVDRV, "Non power-of-2 big page size: 0x{:X}!", params.big_page_size); + LOG_ERROR(Service_NVDRV, "Non power-of-2 big page size: {:#X}!", params.big_page_size); return NvResult::BadValue; } if ((params.big_page_size & VM::SUPPORTED_BIG_PAGE_SIZES) == 0) { - LOG_ERROR(Service_NVDRV, "Unsupported big page size: 0x{:X}!", params.big_page_size); + LOG_ERROR(Service_NVDRV, "Unsupported big page size: {:#X}!", params.big_page_size); return NvResult::BadValue; } @@ -267,7 +267,7 @@ NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) { } NvResult nvhost_as_gpu::Remap(std::span entries) { - LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size()); + LOG_DEBUG(Service_NVDRV, "called, num_entries={:#X}", entries.size()); if (!vm.initialised) { return NvResult::BadValue; @@ -315,7 +315,7 @@ NvResult nvhost_as_gpu::Remap(std::span entries) { NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { LOG_DEBUG(Service_NVDRV, "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" - ", offset=0x{:X}", + ", offset={:#X}", params.flags, params.handle, params.buffer_offset, params.mapping_size, params.offset); @@ -332,7 +332,7 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { if (mapping->size < params.mapping_size) { LOG_WARNING(Service_NVDRV, - "Cannot remap a partially mapped GPU address space region: 0x{:X}", + "Cannot remap a partially mapped GPU address space region: {:#X}", params.offset); return NvResult::BadValue; } @@ -345,7 +345,7 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { return NvResult::Success; } catch (const std::out_of_range&) { - LOG_WARNING(Service_NVDRV, "Cannot remap an unmapped GPU address space region: 0x{:X}", + LOG_WARNING(Service_NVDRV, "Cannot remap an unmapped GPU address space region: {:#X}", params.offset); return NvResult::BadValue; } @@ -416,7 +416,7 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { if (map_buffer_offsets.find(params.offset) != map_buffer_offsets.end()) { - LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); + LOG_DEBUG(Service_NVDRV, "called, offset={:#X}", params.offset); std::scoped_lock lock(mutex); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 45a4a402da..a7551ec154 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -205,7 +208,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics3( } NvResult nvhost_ctrl_gpu::GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params) { - LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); + LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size={:#X}", params.mask_buffer_size); if (params.mask_buffer_size != 0) { params.tcp_mask = 3; } @@ -213,7 +216,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params) { } NvResult nvhost_ctrl_gpu::GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span tpc_mask) { - LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); + LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size={:#X}", params.mask_buffer_size); if (params.mask_buffer_size != 0) { params.tcp_mask = 3; } @@ -312,7 +315,7 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(IoctlZbcQueryTable& params) { } NvResult nvhost_ctrl_gpu::FlushL2(IoctlFlushL2& params) { - LOG_DEBUG(Service_NVDRV, "called 0x{:X}", params.flush); + LOG_DEBUG(Service_NVDRV, "called {:#X}", params.flush); // if ((params.flush & 0x01) != 0) //l2 flush // /* we dont emulate l2 */; // if ((params.flush & 0x04) != 0) //fb flush diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index d01642fe7c..95bf18dbf7 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -360,20 +360,20 @@ NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params, } NvResult nvhost_gpu::GetWaitbase(IoctlGetWaitbase& params) { - LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); + LOG_INFO(Service_NVDRV, "called, unknown={:#X}", params.unknown); params.value = 0; // Seems to be hard coded at 0 return NvResult::Success; } NvResult nvhost_gpu::ChannelSetTimeout(IoctlChannelSetTimeout& params) { - LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); + LOG_INFO(Service_NVDRV, "called, timeout={:#X}", params.timeout); return NvResult::Success; } NvResult nvhost_gpu::ChannelSetTimeslice(IoctlSetTimeslice& params) { - LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); + LOG_INFO(Service_NVDRV, "called, timeslice={:#X}", params.timeslice); channel_timeslice = params.timeslice; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index da61a3bfeb..b9131ee5ce 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -89,7 +92,7 @@ NvResult nvmap::IocCreate(IocCreateParams& params) { } handle_description->orig_size = params.size; // Orig size is the unaligned size params.handle = handle_description->id; - LOG_DEBUG(Service_NVDRV, "handle: {}, size: 0x{:X}", handle_description->id, params.size); + LOG_DEBUG(Service_NVDRV, "handle: {}, size: {:#X}", handle_description->id, params.size); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index 258970fd53..db9467f4d1 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-FileCopyrightText: 2021 Skyline Team and Contributors // SPDX-License-Identifier: GPL-3.0-or-later @@ -209,7 +212,7 @@ void NVDRV::QueryEvent(HLERequestContext& ctx) { void NVDRV::SetAruid(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; pid = rp.Pop(); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); + LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid={:#X}", pid); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp index 78dcf532ce..cfeaf0a653 100644 --- a/src/core/hle/service/psc/time/steady_clock.cpp +++ b/src/core/hle/service/psc/time/steady_clock.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -87,7 +90,7 @@ Result SteadyClock::IsRtcResetDetected(Out out_is_detected) { Result SteadyClock::GetSetupResultValue(Out out_result) { SCOPE_EXIT { - LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw); + LOG_DEBUG(Service_Time, "called. out_result={:#X}", out_result->raw); }; R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index e5779de2fd..d70dc2978f 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -27,7 +30,7 @@ namespace Service { std::string function_string = fmt::format("function '{}': port={}", name, port_name); for (int i = 1; i <= num_params; ++i) { - function_string += fmt::format(", cmd_buff[{}]=0x{:X}", i, cmd_buff[i]); + function_string += fmt::format(", cmd_buff[{}]={:#X}", i, cmd_buff[i]); } return function_string; } @@ -66,10 +69,10 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx, std::string function_name = info == nullptr ? "" : info->name; fmt::memory_buffer buf; - fmt::format_to(std::back_inserter(buf), "function '{}({})': port='{}' cmd_buf={{[0]=0x{:X}", + fmt::format_to(std::back_inserter(buf), "function '{}({})': port='{}' cmd_buf={{[0]={:#X}", ctx.GetCommand(), function_name, service_name, cmd_buf[0]); for (int i = 1; i <= 8; ++i) { - fmt::format_to(std::back_inserter(buf), ", [{}]=0x{:X}", i, cmd_buf[i]); + fmt::format_to(std::back_inserter(buf), ", [{}]={:#X}", i, cmd_buf[i]); } buf.push_back('}'); diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index cd69829217..4dc98040ae 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -101,7 +104,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process, const VAddr base_address = GetInteger(process.GetEntryPoint()); process.LoadModule(std::move(codeset), base_address); - LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address); + LOG_DEBUG(Loader, "loaded module {} @ {:#X}", kip->GetName(), base_address); is_loaded = true; return {ResultStatus::Success, diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 2cd62df072..e3e3f83ca2 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -223,7 +226,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S } modules.insert_or_assign(base_address, file->GetName()); - LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); + LOG_DEBUG(Loader, "loaded module {} @ {:#X}", file->GetName(), base_address); is_loaded = true; return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, diff --git a/src/video_core/cdma_pusher.cpp b/src/video_core/cdma_pusher.cpp index 2a13594719..1b6b4c6d45 100644 --- a/src/video_core/cdma_pusher.cpp +++ b/src/video_core/cdma_pusher.cpp @@ -90,7 +90,7 @@ void CDmaPusher::ProcessEntries(std::stop_token stop_token) { break; } default: - LOG_ERROR(HW_GPU, "Bad command at index {} (bytes 0x{:X}), buffer size {}", i - 1, + LOG_ERROR(HW_GPU, "Bad command at index {} (bytes {:#X}), buffer size {}", i - 1, (i - 1) * sizeof(u32), command_list.size()); UNIMPLEMENTED_MSG("ChSubmission mode {} is not implemented!", static_cast(mode)); @@ -103,7 +103,7 @@ void CDmaPusher::ProcessEntries(std::stop_token stop_token) { void CDmaPusher::ExecuteCommand(u32 method, u32 arg) { switch (current_class) { case ChClassId::Control: - LOG_TRACE(Service_NVDRV, "Class {} method 0x{:X} arg 0x{:X}", + LOG_TRACE(Service_NVDRV, "Class {} method {:#X} arg 0x{:X}", static_cast(current_class), method, arg); host_processor->ProcessMethod(static_cast(method), arg); break; @@ -121,7 +121,7 @@ void CDmaPusher::ExecuteCommand(u32 method, u32 arg) { break; } case ThiMethod::SetMethod1: - LOG_TRACE(Service_NVDRV, "Class {} method 0x{:X} arg 0x{:X}", + LOG_TRACE(Service_NVDRV, "Class {} method {:#X} arg 0x{:X}", static_cast(current_class), static_cast(thi_regs.method_0), arg); ProcessMethod(thi_regs.method_0, arg); break; diff --git a/src/video_core/host1x/codecs/decoder.cpp b/src/video_core/host1x/codecs/decoder.cpp index 391bfabc1e..cb17784b19 100755 --- a/src/video_core/host1x/codecs/decoder.cpp +++ b/src/video_core/host1x/codecs/decoder.cpp @@ -44,7 +44,7 @@ void Decoder::Decode() { if (!frame.get()) { LOG_ERROR(HW_GPU, - "Nvdec {} failed to decode interlaced frame for top 0x{:X} bottom 0x{:X}", id, + "Nvdec {} failed to decode interlaced frame for top {:#X} bottom 0x{:X}", id, luma_top, luma_bottom); } @@ -59,7 +59,7 @@ void Decoder::Decode() { auto [luma_offset, chroma_offset] = GetProgressiveOffsets(); if (!frame.get()) { - LOG_ERROR(HW_GPU, "Nvdec {} failed to decode progressive frame for luma 0x{:X}", id, + LOG_ERROR(HW_GPU, "Nvdec {} failed to decode progressive frame for luma {:#X}", id, luma_offset); } diff --git a/src/video_core/host1x/control.cpp b/src/video_core/host1x/control.cpp index bd0ce91609..53b3063557 100644 --- a/src/video_core/host1x/control.cpp +++ b/src/video_core/host1x/control.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -21,7 +24,7 @@ void Control::ProcessMethod(Method method, u32 argument) { Execute(argument); break; default: - UNIMPLEMENTED_MSG("Control method 0x{:X}", static_cast(method)); + UNIMPLEMENTED_MSG("Control method {:#X}", static_cast(method)); break; } } diff --git a/src/video_core/host1x/vic.cpp b/src/video_core/host1x/vic.cpp index 3ad56bb80c..0f821eb397 100644 --- a/src/video_core/host1x/vic.cpp +++ b/src/video_core/host1x/vic.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -105,7 +108,7 @@ Vic::~Vic() { } void Vic::ProcessMethod(u32 method, u32 arg) { - LOG_TRACE(HW_GPU, "Vic {} method 0x{:X}", id, static_cast(method)); + LOG_TRACE(HW_GPU, "Vic {} method {:#X}", id, static_cast(method)); regs.reg_array[method] = arg; switch (static_cast(method * sizeof(u32))) { @@ -142,7 +145,7 @@ void Vic::Execute() { auto frame = frame_queue.GetFrame(nvdec_id, luma_offset); if (!frame.get()) { - LOG_ERROR(HW_GPU, "Vic {} failed to get frame with offset 0x{:X}", id, luma_offset); + LOG_ERROR(HW_GPU, "Vic {} failed to get frame with offset {:#X}", id, luma_offset); continue; } @@ -999,9 +1002,9 @@ void Vic::WriteY8__V8U8_N420(const OutputSurfaceConfig& output_surface_config) { LOG_TRACE( HW_GPU, "Writing Y8__V8U8_N420 swizzled frame\n" - "\tinput surface {}x{} stride {} size 0x{:X}\n" - "\toutput luma {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}\n", - "\toutput chroma {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}", + "\tinput surface {}x{} stride {} size {:#X}\n" + "\toutput luma {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}\n", + "\toutput chroma {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}", surface_width, surface_height, surface_stride * BytesPerPixel, surface_stride * surface_height * BytesPerPixel, out_luma_width, out_luma_height, out_luma_stride, out_luma_size, block_height, out_luma_swizzle_size, out_chroma_width, @@ -1041,9 +1044,9 @@ void Vic::WriteY8__V8U8_N420(const OutputSurfaceConfig& output_surface_config) { LOG_TRACE( HW_GPU, "Writing Y8__V8U8_N420 swizzled frame\n" - "\tinput surface {}x{} stride {} size 0x{:X}\n" - "\toutput luma {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}\n", - "\toutput chroma {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}", + "\tinput surface {}x{} stride {} size {:#X}\n" + "\toutput luma {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}\n", + "\toutput chroma {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}", surface_width, surface_height, surface_stride * BytesPerPixel, surface_stride * surface_height * BytesPerPixel, out_luma_width, out_luma_height, out_luma_stride, out_luma_size, out_chroma_width, out_chroma_height, out_chroma_stride, @@ -1212,8 +1215,8 @@ void Vic::WriteABGR(const OutputSurfaceConfig& output_surface_config) { LOG_TRACE( HW_GPU, "Writing ABGR swizzled frame\n" - "\tinput surface {}x{} stride {} size 0x{:X}\n" - "\toutput surface {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}", + "\tinput surface {}x{} stride {} size {:#X}\n" + "\toutput surface {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}", surface_width, surface_height, surface_stride * BytesPerPixel, surface_stride * surface_height * BytesPerPixel, out_luma_width, out_luma_height, out_luma_stride, out_luma_size, block_height, out_swizzle_size); @@ -1237,8 +1240,8 @@ void Vic::WriteABGR(const OutputSurfaceConfig& output_surface_config) { case BLK_KIND::PITCH: { LOG_TRACE(HW_GPU, "Writing ABGR pitch frame\n" - "\tinput surface {}x{} stride {} size 0x{:X}" - "\toutput surface {}x{} stride {} size 0x{:X}", + "\tinput surface {}x{} stride {} size {:#X}" + "\toutput surface {}x{} stride {} size {:#X}", surface_width, surface_height, surface_stride, surface_stride * surface_height * BytesPerPixel, out_luma_width, out_luma_height, out_luma_stride, out_luma_size); diff --git a/src/video_core/texture_cache/formatter.cpp b/src/video_core/texture_cache/formatter.cpp index 2b7e0df72a..b48afee0c5 100644 --- a/src/video_core/texture_cache/formatter.cpp +++ b/src/video_core/texture_cache/formatter.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -60,25 +63,25 @@ std::string Name(const ImageViewBase& image_view, GPUVAddr addr) { const std::string level = num_levels > 1 ? fmt::format(":{}", num_levels) : ""; switch (image_view.type) { case ImageViewType::e1D: - return fmt::format("ImageView 1D 0x{:X} {}{}", addr, width, level); + return fmt::format("ImageView 1D {:#X} {}{}", addr, width, level); case ImageViewType::e2D: - return fmt::format("ImageView 2D 0x{:X} {}x{}{}", addr, width, height, level); + return fmt::format("ImageView 2D {:#X} {}x{}{}", addr, width, height, level); case ImageViewType::Cube: - return fmt::format("ImageView Cube 0x{:X} {}x{}{}", addr, width, height, level); + return fmt::format("ImageView Cube {:#X} {}x{}{}", addr, width, height, level); case ImageViewType::e3D: - return fmt::format("ImageView 3D 0x{:X} {}x{}x{}{}", addr, width, height, depth, level); + return fmt::format("ImageView 3D {:#X} {}x{}x{}{}", addr, width, height, depth, level); case ImageViewType::e1DArray: - return fmt::format("ImageView 1DArray 0x{:X} {}{}|{}", addr, width, level, num_layers); + return fmt::format("ImageView 1DArray {:#X} {}{}|{}", addr, width, level, num_layers); case ImageViewType::e2DArray: - return fmt::format("ImageView 2DArray 0x{:X} {}x{}{}|{}", addr, width, height, level, + return fmt::format("ImageView 2DArray {:#X} {}x{}{}|{}", addr, width, height, level, num_layers); case ImageViewType::CubeArray: - return fmt::format("ImageView CubeArray 0x{:X} {}x{}{}|{}", addr, width, height, level, + return fmt::format("ImageView CubeArray {:#X} {}x{}{}|{}", addr, width, height, level, num_layers); case ImageViewType::Rect: - return fmt::format("ImageView Rect 0x{:X} {}x{}{}", addr, width, height, level); + return fmt::format("ImageView Rect {:#X} {}x{}{}", addr, width, height, level); case ImageViewType::Buffer: - return fmt::format("BufferView 0x{:X} {}", addr, width); + return fmt::format("BufferView {:#X} {}", addr, width); } return "Invalid"; } From 59f5c4fa29fcaf007937ba863a16f408292e0919 Mon Sep 17 00:00:00 2001 From: MaranBr Date: Wed, 27 Aug 2025 23:02:46 +0200 Subject: [PATCH 10/44] [core] Add option to control Host MMU Emulation (#324) This adds an option to enable or disable Host MMU Emulation [Android/PC], brings better config per-game handling with Disable Buffer Reorder, disables Flush Debug Lines by Log, option which was enabled by default on Android/PC taxing performance and translates to all supported languages the recent changes. Leaves room for NCE improvements in the foreseable future. Co-authored-by: crueter Co-authored-by: PavelBARABANOV Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/324 Reviewed-by: crueter Reviewed-by: CamilleLaVey Co-authored-by: MaranBr Co-committed-by: MaranBr --- .../features/settings/model/BooleanSetting.kt | 1 + .../settings/model/view/SettingsItem.kt | 7 +++++++ .../settings/ui/SettingsFragmentPresenter.kt | 1 + .../app/src/main/res/values-ar/strings.xml | 2 ++ .../app/src/main/res/values-ckb/strings.xml | 2 ++ .../app/src/main/res/values-cs/strings.xml | 2 ++ .../app/src/main/res/values-de/strings.xml | 2 ++ .../app/src/main/res/values-es/strings.xml | 2 ++ .../app/src/main/res/values-fa/strings.xml | 2 ++ .../app/src/main/res/values-fr/strings.xml | 2 ++ .../app/src/main/res/values-he/strings.xml | 2 ++ .../app/src/main/res/values-hu/strings.xml | 2 ++ .../app/src/main/res/values-id/strings.xml | 2 ++ .../app/src/main/res/values-it/strings.xml | 2 ++ .../app/src/main/res/values-ja/strings.xml | 2 ++ .../app/src/main/res/values-ko/strings.xml | 2 ++ .../app/src/main/res/values-nb/strings.xml | 2 ++ .../app/src/main/res/values-pl/strings.xml | 2 ++ .../src/main/res/values-pt-rBR/strings.xml | 2 ++ .../src/main/res/values-pt-rPT/strings.xml | 2 ++ .../app/src/main/res/values-ru/strings.xml | 2 ++ .../app/src/main/res/values-sr/strings.xml | 2 ++ .../app/src/main/res/values-uk/strings.xml | 2 ++ .../app/src/main/res/values-vi/strings.xml | 2 ++ .../src/main/res/values-zh-rCN/strings.xml | 2 ++ .../src/main/res/values-zh-rTW/strings.xml | 2 ++ .../app/src/main/res/values/strings.xml | 2 ++ src/common/settings.cpp | 6 ++++++ src/common/settings.h | 21 ++++++++++++++++--- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 10 ++++++++- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 8 +++++++ src/yuzu/configuration/configure_cpu.cpp | 14 ++++++------- src/yuzu/configuration/configure_cpu.h | 2 +- src/yuzu/configuration/shared_translation.cpp | 2 ++ 34 files changed, 108 insertions(+), 12 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 21a159676d..d91c026acf 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -18,6 +18,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { USE_FAST_CPU_TIME("use_fast_cpu_time"), USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"), SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"), + CPUOPT_UNSAFE_HOST_MMU("cpuopt_unsafe_host_mmu"), USE_DOCKED_MODE("use_docked_mode"), USE_AUTO_STUB("use_auto_stub"), RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 062038aa44..a689b6ce76 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -673,6 +673,13 @@ abstract class SettingsItem( descriptionId = R.string.skip_cpu_inner_invalidation_description ) ) + put( + SwitchSetting( + BooleanSetting.CPUOPT_UNSAFE_HOST_MMU, + titleId = R.string.cpuopt_unsafe_host_mmu, + descriptionId = R.string.cpuopt_unsafe_host_mmu_description + ) + ) put( SwitchSetting( BooleanSetting.RENDERER_REACTIVE_FLUSHING, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 672bcd492c..14d62ceec3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -466,6 +466,7 @@ class SettingsFragmentPresenter( add(BooleanSetting.USE_CUSTOM_CPU_TICKS.key) add(IntSetting.CPU_TICKS.key) add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key) + add(BooleanSetting.CPUOPT_UNSAFE_HOST_MMU.key) add(BooleanSetting.USE_LRU_CACHE.key) add(BooleanSetting.CORE_SYNC_CORE_SPEED.key) add(BooleanSetting.SYNC_MEMORY_OPERATIONS.key) diff --git a/src/android/app/src/main/res/values-ar/strings.xml b/src/android/app/src/main/res/values-ar/strings.xml index 155d165f2d..7373abdf76 100644 --- a/src/android/app/src/main/res/values-ar/strings.xml +++ b/src/android/app/src/main/res/values-ar/strings.xml @@ -117,6 +117,8 @@ دورات تخطي إبطال ذاكرة التخزين المؤقت الداخلية للوحدة المركزية يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقت أثناء تحديثات الذاكرة، مما يقلل استخدام المعالج ويحسن أدائه. قد يسبب هذا أعطالاً أو تعطلًا في بعض الألعاب. + تمكين محاكاة MMU المضيف + يعمل هذا التحسين على تسريع وصول الذاكرة بواسطة البرنامج الضيف. يؤدي تمكينه إلى إجراء عمليات قراءة/كتابة ذاكرة الضيف مباشرة في الذاكرة والاستفادة من MMU المضيف. يؤدي تعطيل هذا إلى إجبار جميع عمليات الوصول إلى الذاكرة على استخدام محاكاة MMU البرمجية. مستوى DMA يتحكم في دقة تحديد مستوى DMA. الدقة الأعلى يمكنها إصلاح بعض المشاكل في بعض الألعاب، ولكنها قد تؤثر أيضًا على الأداء في بعض الحالات. إذا كنت غير متأكد، اتركه على الوضع الافتراضي. diff --git a/src/android/app/src/main/res/values-ckb/strings.xml b/src/android/app/src/main/res/values-ckb/strings.xml index 1845dbbade..221a197843 100644 --- a/src/android/app/src/main/res/values-ckb/strings.xml +++ b/src/android/app/src/main/res/values-ckb/strings.xml @@ -126,6 +126,8 @@ تیک بازنەکردنی ناوەکی CPU هەندێک لە بازنەکردنەکانی هەڵگر لە کاتی نوێکردنەوەی بیرگە دەنێرێت، کەمکردنەوەی بەکارهێنانی CPU و باشترکردنی کارایی. لەوانەیە لە هەندێک یاری کێشە درووست بکات. + چالاککردنی میمیکردنی MMU میواندە + ئەم باشکردنە خێرایی دەستکەوتنی بیرگە لەلایەن پرۆگرامی میوانەکە زیاد دەکات. چالاککردنی وای لێدەکات کە خوێندنەوە/نووسینەکانی بیرگەی میوانەکە ڕاستەوخۆ لە بیرگە ئەنجام بدرێت و میمیکردنی MMU میواندە بەکاربهێنێت. ناچالاککردنی ئەمە هەموو دەستکەوتنەکانی بیرگە ڕەت دەکاتەوە لە بەکارهێنانی میمیکردنی MMU نەرمەکاڵا. ئاستی DMA کۆنتڕۆڵی وردی ڕێکخستنی DMA دەکات. وردی زیاتر دەتوانێ هەندێک کێشە لە هەندێک یاری چارەسەر بکات، بەڵام لە هەندێک حاڵەتدا کاریگەری لەسەر کارایی هەیە. ئەگەر دڵنیا نیت، بە ڕێکخستنی بنەڕەتی بێڵە. diff --git a/src/android/app/src/main/res/values-cs/strings.xml b/src/android/app/src/main/res/values-cs/strings.xml index 484ba1fc5f..61e389f9fc 100644 --- a/src/android/app/src/main/res/values-cs/strings.xml +++ b/src/android/app/src/main/res/values-cs/strings.xml @@ -125,6 +125,8 @@ Takty Přeskočit vnitřní invalidaci CPU Přeskočí některé invalidace mezipaměti na straně CPU během aktualizací paměti, čímž sníží zatížení CPU a zlepší jeho výkon. Může způsobit chyby nebo pády v některých hrách. + Povolit emulaci hostitelské MMU + Tato optimalizace zrychluje přístup do paměti hostovaného programu. Její povolení způsobí, že čtení a zápisy do paměti hosta se provádějí přímo v paměti a využívají hostitelskou MMU. Zakázání této funkce vynutí použití softwarové emulace MMU pro všechny přístupy do paměti. Úroveň DMA Ovládá přesnost DMA. Vyšší přesnost může opravit problémy v některých hrách, ale může také ovlivnit výkon. Pokud si nejste jisti, ponechejte výchozí nastavení. diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index 821ba56399..bff0b0379e 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml @@ -126,6 +126,8 @@ Ticks CPU-interne Invalidierung überspringen Überspringt bestimmte Cache-Invalidierungen auf CPU-Seite während Speicherupdates, reduziert die CPU-Auslastung und verbessert die Leistung. Kann in einigen Spielen zu Fehlern oder Abstürzen führen. + Host-MMU-Emulation aktivieren + Diese Optimierung beschleunigt Speicherzugriffe durch das Gastprogramm. Wenn aktiviert, erfolgen Speicherlese- und -schreibvorgänge des Gastes direkt im Speicher und nutzen die MMU des Hosts. Das Deaktivieren erzwingt die Verwendung der Software-MMU-Emulation für alle Speicherzugriffe. DMA-Level Steuert die DMA-Präzisionsgenauigkeit. Eine höhere Präzision kann Probleme in einigen Spielen beheben, kann aber in einigen Fällen auch die Leistung beeinträchtigen. Im Zweifel auf „Standard“ belassen. diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 9db08e1425..888d6d1684 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -126,6 +126,8 @@ Ticks Omitir invalidación interna de la CPU Omite ciertas invalidaciones de caché durante actualizaciones de memoria, reduciendo el uso de CPU y mejorando su rendimiento. Puede causar fallos en algunos juegos. + Habilitar emulación de MMU del host + Esta optimización acelera los accesos a la memoria por parte del programa invitado. Al habilitarla, las lecturas/escrituras de memoria del invitado se realizan directamente en la memoria y utilizan la MMU del host. Deshabilitar esto obliga a que todos los accesos a la memoria utilicen la emulación de MMU por software. Nivel de DMA Controla la precisión del DMA. Una mayor precisión puede solucionar problemas en algunos juegos, pero también puede afectar el rendimiento en algunos casos. Si no está seguro, déjelo en Predeterminado. diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml index 91fa4bd5c2..60b1626aa5 100644 --- a/src/android/app/src/main/res/values-fa/strings.xml +++ b/src/android/app/src/main/res/values-fa/strings.xml @@ -126,6 +126,8 @@ تیک‌ها رد کردن ابطال داخلی CPU بعضی ابطال‌های حافظه نهان در هنگام به‌روزرسانی‌های حافظه را رد می‌کند، استفاده از CPU را کاهش داده و عملکرد آن را بهبود می‌بخشد. ممکن است در برخی بازی‌ها باعث مشکلات یا خرابی شود. + فعال‌سازی شبیه‌سازی MMU میزبان + این بهینه‌سازی دسترسی‌های حافظه توسط برنامه میهمان را تسریع می‌کند. فعال‌سازی آن باعث می‌شود خواندن/نوشتن حافظه میهمان مستقیماً در حافظه انجام شود و از MMU میزبان استفاده کند. غیرفعال کردن این قابلیت، همه دسترسی‌های حافظه را مجبور به استفاده از شبیه‌سازی نرم‌افزاری MMU می‌کند. سطح DMA دقت صحت DMA را کنترل می کند. دقت بالاتر می تواند مشکلات برخی بازی ها را برطرف کند، اما در برخی موارد نیز می تواند بر عملکرد تأثیر بگذارد. اگر مطمئن نیستید، آن را روی پیش فرض بگذارید. diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index a7139ddbf6..fde02d1aa8 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -126,6 +126,8 @@ Ticks Ignorer l\'invalidation interne du CPU Ignore certaines invalidations de cache côté CPU lors des mises à jour mémoire, réduisant l\'utilisation du CPU et améliorant ses performances. Peut causer des bugs ou plantages sur certains jeux. + Activer l\'émulation de la MMU hôte + Cette optimisation accélère les accès mémoire par le programme invité. L\'activer entraîne que les lectures/écritures mémoire de l\'invité sont effectuées directement en mémoire et utilisent la MMU de l\'hôte. Désactiver cela force tous les accès mémoire à utiliser l\'émulation logicielle de la MMU. Niveau DMA Contrôle la précision du DMA. Une précision plus élevée peut résoudre les problèmes dans certains jeux, mais peut aussi affecter les performances dans certains cas. Si vous n\'êtes pas sûr, laissez-la sur Défaut. diff --git a/src/android/app/src/main/res/values-he/strings.xml b/src/android/app/src/main/res/values-he/strings.xml index 63aaee043e..59312086e9 100644 --- a/src/android/app/src/main/res/values-he/strings.xml +++ b/src/android/app/src/main/res/values-he/strings.xml @@ -127,6 +127,8 @@ טיקים דלג על איפוס מטמון פנימי של המעבד מדלג על איפוסי מטמון מסוימים במהלך עדכוני זיכרון, מפחית שימוש במעבד ומשפר ביצועים. עלול לגרום לתקלות או קריסות בחלק מהמשחקים. + הפעל אמולציית MMU מארח + אופטימיזציה זו מאיצה את גישת הזיכרון על ידי התוכנית האורחת. הפעלתה גורמת לכך שפעולות קריאה/כתיבה לזיכרון האורח מתבצעות ישירות לזיכרון ומשתמשות ב-MMU של המארח. השבתת זאת מאלצת את כל גישות הזיכרון להשתמש באמולציית MMU תוכנתית. רמת DMA שולטת בדיוק הדיוק של DMA. דיוק גבוה יותר יכול לתקן בעיות בחלק מהמשחקים, אך הוא עלול גם להשפיע על הביצועים במקרים מסוימים. אם אינך בטוח, השאר ברירת מחדל. diff --git a/src/android/app/src/main/res/values-hu/strings.xml b/src/android/app/src/main/res/values-hu/strings.xml index 15dd00997b..f95e2d3f97 100644 --- a/src/android/app/src/main/res/values-hu/strings.xml +++ b/src/android/app/src/main/res/values-hu/strings.xml @@ -126,6 +126,8 @@ Tick-ek CPU belső érvénytelenítés kihagyása Kihagy néhány CPU-oldali gyorsítótár-érvénytelenítést memóriafrissítések közben, csökkentve a CPU használatát és javítva a teljesítményt. Néhány játékban hibákat vagy összeomlást okozhat. + Gazda MMU emuláció engedélyezése + Ez az optimalizáció gyorsítja a vendégprogram memória-hozzáférését. Engedélyezése esetén a vendég memóriaolvasási/írási műveletei közvetlenül a memóriában történnek, és kihasználják a gazda MMU-ját. Letiltás esetén minden memória-hozzáférés a szoftveres MMU emulációt használja. DMA szint Szabályozza a DMA pontosságát. A magasabb pontosság megoldhat néhány játék problémáit, de bizonyos esetekben befolyásolhatja a teljesítményt. Ha bizonytalan, hagyja Alapértelmezett beállításnál. diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index 7daa4a8e94..dae77d53af 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -126,6 +126,8 @@ Ticks Lewati Pembatalan Internal CPU Melewati beberapa pembatalan cache sisi CPU selama pembaruan memori, mengurangi penggunaan CPU dan meningkatkan kinerjanya. Mungkin menyebabkan gangguan atau crash pada beberapa game. + Aktifkan Emulasi MMU Host + Optimasi ini mempercepat akses memori oleh program tamu. Mengaktifkannya menyebabkan pembacaan/penulisan memori tamu dilakukan langsung ke memori dan memanfaatkan MMU Host. Menonaktifkan ini memaksa semua akses memori menggunakan Emulasi MMU Perangkat Lunak. Level DMA Mengontrol akurasi presisi DMA. Presisi yang lebih tinggi dapat memperbaiki masalah di beberapa game, tetapi juga dapat memengaruhi performa dalam beberapa kasus. Jika tidak yakin, biarkan di Bawaan. diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index 66446eae34..dd184e9d9a 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml @@ -126,6 +126,8 @@ Tick Salta invalidamento interno CPU Salta alcuni invalidamenti della cache lato CPU durante gli aggiornamenti di memoria, riducendo l\'uso della CPU e migliorandone le prestazioni. Potrebbe causare glitch o crash in alcuni giochi. + Abilita emulazione MMU host + Questa ottimizzazione accelera gli accessi alla memoria da parte del programma guest. Abilitandola, le letture/scritture della memoria guest vengono eseguite direttamente in memoria e sfruttano la MMU host. Disabilitandola, tutti gli accessi alla memoria sono costretti a utilizzare l\'emulazione software della MMU. Livello DMA Controlla la precisione del DMA. Una precisione più alta può risolvere problemi in alcuni giochi, ma in alcuni casi può influire sulle prestazioni. Se non sei sicuro, lascia su Predefinito. diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index 2090aa5f74..873d433fc0 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml @@ -126,6 +126,8 @@ ティック CPU内部無効化をスキップ メモリ更新時のCPU側キャッシュ無効化をスキップし、CPU使用率を減らして性能を向上させます。一部のゲームで不具合やクラッシュが発生する可能性があります。 + ホストMMUエミュレーションを有効化 + この最適化により、ゲストプログラムによるメモリアクセスが高速化されます。有効にすると、ゲストのメモリ読み書きが直接メモリ内で実行され、ホストのMMUを利用します。無効にすると、すべてのメモリアクセスでソフトウェアMMUエミュレーションが使用されます。 DMAレベル DMAの精度を制御します。精度を高くすると一部のゲームの問題が修正される場合がありますが、場合によってはパフォーマンスに影響を与える可能性もあります。不明な場合は、デフォルトのままにしてください。 diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index d73dc53987..3f3a4a96c0 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml @@ -126,6 +126,8 @@ CPU 내부 무효화 건너뛰기 메모리 업데이트 시 일부 CPU 측 캐시 무효화를 건너뛰어 CPU 사용량을 줄이고 성능을 향상시킵니다. 일부 게임에서 오류 또는 충돌을 일으킬 수 있습니다. + 호스트 MMU 에뮬레이션 사용 + 이 최적화는 게스트 프로그램의 메모리 접근 속도를 높입니다. 활성화하면 게스트의 메모리 읽기/쓰기가 메모리에서 직접 수행되고 호스트의 MMU를 활용합니다. 비활성화하면 모든 메모리 접근에 소프트웨어 MMU 에뮬레이션을 사용하게 됩니다. DMA 수준 DMA 정밀도를 제어합니다. 높은 정밀도는 일부 게임의 문제를 해결할 수 있지만 경우에 따라 성능에 영향을 미칠 수도 있습니다. 확실하지 않다면 기본값으로 두세요. diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index 61fa5792e5..1e898fca79 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml @@ -126,6 +126,8 @@ Takter Hopp over CPU intern invalidering Hopper over enkelte CPU-side cache-invalideringer under minneoppdateringer, reduserer CPU-bruk og forbedrer ytelsen. Kan forårsake feil eller krasj i noen spill. + Aktiver verts-MMU-emulering + Denne optimaliseringen fremskynder minnetilgang av gjesteprogrammet. Hvis aktivert, utføres gjestens minnelesing/skriving direkte i minnet og bruker vertens MMU. Deaktivering tvinger alle minnetilganger til å bruke programvarebasert MMU-emulering. DMA-nivå Styrer DMA-presisjonsnøyaktigheten. Høyere presisjon kan fikse problemer i noen spill, men kan også påvirke ytelsen i noen tilfeller. Hvis du er usikker, la den stå på Standard. diff --git a/src/android/app/src/main/res/values-pl/strings.xml b/src/android/app/src/main/res/values-pl/strings.xml index d640112fca..724d7608b6 100644 --- a/src/android/app/src/main/res/values-pl/strings.xml +++ b/src/android/app/src/main/res/values-pl/strings.xml @@ -126,6 +126,8 @@ Takty Pomiń wewnętrzne unieważnienie CPU Pomija niektóre unieważnienia pamięci podręcznej po stronie CPU podczas aktualizacji pamięci, zmniejszając użycie CPU i poprawiając jego wydajność. Może powodować błędy lub awarie w niektórych grach. + Włącz emulację MMU hosta + Ta optymalizacja przyspiesza dostęp do pamięci przez program gościa. Włączenie powoduje, że odczyty/zapisy pamięci gościa są wykonywane bezpośrednio w pamięci i wykorzystują MMU hosta. Wyłączenie wymusza użycie programowej emulacji MMU dla wszystkich dostępów do pamięci. Poziom DMA Kontroluje dokładność precyzji DMA. Wyższy poziom może naprawić problemy w niektórych grach, ale może również wpłynąć na wydajność. Jeśli nie jesteś pewien, pozostaw wartość «Domyślny». diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index d0ec24f453..a3fd3fe13a 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml @@ -126,6 +126,8 @@ Ticks Pular invalidação interna da CPU Ignora algumas invalidações de cache do lado da CPU durante atualizações de memória, reduzindo o uso da CPU e melhorando seu desempenho. Pode causar falhas ou travamentos em alguns jogos. + Ativar Emulação de MMU do Host + Esta otimização acelera os acessos à memória pelo programa convidado. Ativar isso faz com que as leituras/gravações de memória do convidado sejam feitas diretamente na memória e utilizem a MMU do Host. Desativar isso força todos os acessos à memória a usarem a Emulação de MMU por Software. Nível DMA Controla a precisão do DMA. Maior precisão pode corrigir problemas em alguns jogos, mas também pode impactar o desempenho em alguns casos. Se não tiver certeza, deixe em Padrão. diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index 4e0fc4167a..7adce075cf 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml @@ -126,6 +126,8 @@ Ticks Ignorar invalidação interna da CPU Ignora algumas invalidações de cache do lado da CPU durante atualizações de memória, reduzindo a utilização da CPU e melhorando o desempenho. Pode causar falhas ou crashes em alguns jogos. + Ativar Emulação de MMU do Anfitrião + Esta otimização acelera os acessos à memória pelo programa convidado. Ativar faz com que as leituras/escritas de memória do convidado sejam efetuadas diretamente na memória e utilizem a MMU do Anfitrião. Desativar força todos os acessos à memória a usar a Emulação de MMU por Software. Nível DMA Controla a precisão do DMA. Maior precisão pode corrigir problemas em alguns jogos, mas também pode afetar o desempenho nalguns casos. Se não tiver a certeza, deixe em Predefinido. diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index 658286152b..8d02ff7b58 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -126,6 +126,8 @@ Такты Пропустить внутреннюю инвалидацию ЦП Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх. + Включить эмуляцию MMU хоста + Эта оптимизация ускоряет доступ к памяти гостевой программой. При включении операции чтения/записи памяти гостя выполняются напрямую в памяти с использованием MMU хоста. Отключение заставляет все обращения к памяти использовать программную эмуляцию MMU. Уровень DMA Управляет точностью DMA. Более высокий уровень может исправить проблемы в некоторых играх, но также может повлиять на производительность. Если не уверены, оставьте значение «По умолчанию». diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index 18612333f9..2294033550 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -119,6 +119,8 @@ Тактови Preskoči unutrašnje poništavanje CPU-a Preskače određena poništavanja keša na strani CPU-a tokom ažuriranja memorije, smanjujući opterećenje procesora i poboljšavajući performanse. Može izazvati greške u nekim igrama. + Омогући емулацију MMU домаћина + Ова оптимизација убрзава приступ меморији од стране гостујућег програма. Укључивање изазива да се читања/уписа меморије госта обављају директно у меморији и користе MMU домаћина. Искључивање присиљава све приступе меморији да користе софтверску емулацију MMU. DMA ниво Контролише тачност DMA прецизности. Виши ниво може да поправи проблеме у неким играма, али може и да утиче на перформансе. Ако нисте сигурни, оставите на «Подразумевано». diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index 830e1f0ef9..ebb5493f12 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -126,6 +126,8 @@ Такти Пропустити внутрішнє інвалідування CPU Пропускає деякі інвалідації кешу на стороні CPU під час оновлення пам\'яті, зменшуючи навантаження на процесор і покращуючи продуктивність. Може спричинити збої в деяких іграх. + Увімкнути емуляцію MMU хоста + Ця оптимізація пришвидшує доступ до пам\'яті гостьовою програмою. Увімкнення призводить до того, що читання/запис пам\'яті гостя виконуються безпосередньо в пам\'яті та використовують MMU хоста. Вимкнення змушує всі звернення до пам\'яті використовувати програмну емуляцію MMU. Рівень DMA Керує точністю DMA. Вищий рівень може виправити проблеми в деяких іграх, але також може вплинути на продуктивність. Якщо не впевнені, залиште значення «Типово». diff --git a/src/android/app/src/main/res/values-vi/strings.xml b/src/android/app/src/main/res/values-vi/strings.xml index 1c656fc7bb..102c720835 100644 --- a/src/android/app/src/main/res/values-vi/strings.xml +++ b/src/android/app/src/main/res/values-vi/strings.xml @@ -126,6 +126,8 @@ Tích Bỏ qua vô hiệu hóa bên trong CPU Bỏ qua một số lần vô hiệu hóa bộ nhớ đệm phía CPU trong khi cập nhật bộ nhớ, giảm mức sử dụng CPU và cải thiện hiệu suất. Có thể gây ra lỗi hoặc treo máy trong một số trò chơi. + Bật giả lập MMU Máy chủ + Tối ưu hóa này tăng tốc độ truy cập bộ nhớ của chương trình khách. Bật nó lên khiến các thao tác đọc/ghi bộ nhớ khách được thực hiện trực tiếp vào bộ nhớ và sử dụng MMU của Máy chủ. Tắt tính năng này buộc tất cả quyền truy cập bộ nhớ phải sử dụng Giả lập MMU Phần mềm. Cấp độ DMA Điều khiển độ chính xác của DMA. Độ chính xác cao hơn có thể sửa lỗi trong một số trò chơi, nhưng cũng có thể ảnh hưởng đến hiệu suất trong một số trường hợp. Nếu không chắc chắn, hãy để ở Mặc định. diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index f3e7d9282c..a0dab375d0 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -125,6 +125,8 @@ 时钟 跳过CPU内部无效化 在内存更新期间跳过某些CPU端缓存无效化,减少CPU使用率并提高其性能。可能会导致某些游戏出现故障或崩溃。 + 启用主机 MMU 模拟 + 此优化可加速来宾程序的内存访问。启用后,来宾内存读取/写入将直接在内存中执行并利用主机的 MMU。禁用此功能将强制所有内存访问使用软件 MMU 模拟。 DMA 级别 控制 DMA 精度。更高的精度可以修复某些游戏中的问题,但在某些情况下也可能影响性能。如果不确定,请保留为“默认”。 diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index b6c17745be..851483668a 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -118,6 +118,8 @@ 時脈 跳過CPU內部無效化 在記憶體更新期間跳過某些CPU端快取無效化,減少CPU使用率並提高其性能。可能會導致某些遊戲出現故障或崩潰。 + 啟用主機 MMU 模擬 + 此最佳化可加速來賓程式的記憶體存取。啟用後,來賓記憶體讀取/寫入將直接在記憶體中執行並利用主機的 MMU。停用此功能將強制所有記憶體存取使用軟體 MMU 模擬。 DMA 級別 控制 DMA 精確度。更高的精確度可以修復某些遊戲中的問題,但在某些情況下也可能影響效能。如果不確定,請保留為「預設」。 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 975bd1741a..f73fc1d9aa 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -109,6 +109,8 @@ Ticks Skip CPU Inner Invalidation Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games. + Enable Host MMU Emulation + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host\'s MMU. Disabling this forces all memory accesses to use Software MMU Emulation. CPU Clock Use Boost (1700MHz) to run at the Switch\'s highest native clock, or Fast (2000MHz) to run at 2x clock. Memory Layout diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 63d46722ea..19140bce0d 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -158,6 +158,12 @@ bool IsFastmemEnabled() { if (values.cpu_debug_mode) { return static_cast(values.cpuopt_fastmem); } + if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { + return static_cast(values.cpuopt_unsafe_host_mmu); + } +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + return false; +#endif return true; } diff --git a/src/common/settings.h b/src/common/settings.h index b846f41318..27196fbd69 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -299,6 +299,18 @@ struct Values { Category::CpuDebug}; Setting cpuopt_ignore_memory_aborts{linkage, true, "cpuopt_ignore_memory_aborts", Category::CpuDebug}; + + SwitchableSetting cpuopt_unsafe_host_mmu{linkage, +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + false, +#else + true, +#endif + "cpuopt_unsafe_host_mmu", + Category::CpuUnsafe, + Specialization::Default, + true, + true}; SwitchableSetting cpuopt_unsafe_unfuse_fma{linkage, true, "cpuopt_unsafe_unfuse_fma", Category::CpuUnsafe}; SwitchableSetting cpuopt_unsafe_reduce_fp_error{ @@ -574,8 +586,11 @@ struct Values { linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug}; Setting enable_renderdoc_hotkey{linkage, false, "renderdoc_hotkey", Category::RendererDebug}; - Setting disable_buffer_reorder{linkage, false, "disable_buffer_reorder", - Category::RendererDebug}; + SwitchableSetting disable_buffer_reorder{linkage, false, "disable_buffer_reorder", + Category::RendererDebug, + Specialization::Default, + true, + true}; // System SwitchableSetting language_index{linkage, @@ -741,7 +756,7 @@ struct Values { // Miscellaneous Setting log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous}; - Setting log_flush_lines{linkage, true, "flush_lines", Category::Miscellaneous, Specialization::Default, true, true}; + Setting log_flush_lines{linkage, false, "flush_lines", Category::Miscellaneous, Specialization::Default, true, true}; Setting censor_username{linkage, true, "censor_username", Category::Miscellaneous}; Setting use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous}; Setting first_launch{linkage, true, "first_launch", Category::Miscellaneous}; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index c6e159cc9c..7123497682 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -271,6 +271,10 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa // Unsafe optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { config.unsafe_optimizations = true; + if (!Settings::values.cpuopt_unsafe_host_mmu) { + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; + } if (Settings::values.cpuopt_unsafe_unfuse_fma) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; } @@ -291,13 +295,17 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa // Curated optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) { config.unsafe_optimizations = true; +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; +#endif config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } - // Paranoia mode for debugging optimizations + // Paranoid mode for debugging optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) { config.unsafe_optimizations = false; config.optimizations = Dynarmic::no_optimizations; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index ba5c608a03..2745aeb862 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -330,6 +330,10 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa // Unsafe optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { config.unsafe_optimizations = true; + if (!Settings::values.cpuopt_unsafe_host_mmu) { + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; + } if (Settings::values.cpuopt_unsafe_unfuse_fma) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; } @@ -350,6 +354,10 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa // Curated optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) { config.unsafe_optimizations = true; +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; +#endif config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.fastmem_address_space_bits = 64; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp index 74def6fc60..6407efbb26 100644 --- a/src/yuzu/configuration/configure_cpu.cpp +++ b/src/yuzu/configuration/configure_cpu.cpp @@ -90,15 +90,15 @@ void ConfigureCpu::Setup(const ConfigurationShared::Builder& builder) { unsafe_layout->addWidget(widget); } - UpdateGroup(accuracy_combobox->currentIndex()); - UpdateGroup(backend_combobox->currentIndex()); + UpdateGroup(); } -void ConfigureCpu::UpdateGroup(int index) { - const auto accuracy = static_cast( - combobox_translations.at(Settings::EnumMetadata::Index())[index] - .first); - ui->unsafe_group->setVisible(accuracy == Settings::CpuAccuracy::Unsafe); +void ConfigureCpu::UpdateGroup() +{ + const u32 accuracy = accuracy_combobox->currentIndex(); + const u32 backend = backend_combobox->currentIndex(); + // TODO(crueter): see if this works on NCE + ui->unsafe_group->setVisible(accuracy == (u32) Settings::CpuAccuracy::Unsafe && backend == (u32) Settings::CpuBackend::Dynarmic); } void ConfigureCpu::ApplyConfiguration() { diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index 7bbeac4963..098e0e397b 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -39,7 +39,7 @@ private: void changeEvent(QEvent* event) override; void RetranslateUI(); - void UpdateGroup(int index); + void UpdateGroup(); void Setup(const ConfigurationShared::Builder& builder); diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index f6d590c0ee..fca4c94893 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -118,6 +118,8 @@ std::unique_ptr InitializeTranslations(QWidget* parent) // Cpu Debug // Cpu Unsafe + INSERT(Settings, cpuopt_unsafe_host_mmu, tr("Enable Host MMU Emulation (fastmem)"), + tr("This optimization speeds up memory accesses by the guest program.\nEnabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.\nDisabling this forces all memory accesses to use Software MMU Emulation.")); INSERT( Settings, cpuopt_unsafe_unfuse_fma, From 1f2ab3fbc944498e830d7e047b9d03e024846394 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 28 Aug 2025 01:32:37 +0200 Subject: [PATCH 11/44] [video_core] fix nixOS flake build patch (#339) See https://github.com/NixOS/nixpkgs/pull/406630/files Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/339 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- src/video_core/host1x/vic.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video_core/host1x/vic.cpp b/src/video_core/host1x/vic.cpp index 0f821eb397..18b3077f9a 100644 --- a/src/video_core/host1x/vic.cpp +++ b/src/video_core/host1x/vic.cpp @@ -17,6 +17,8 @@ #elif defined(ARCHITECTURE_arm64) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wimplicit-int-conversion" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wshadow" #include #pragma GCC diagnostic pop #endif From 8a50d18924266e4b0fffc41706ab3fec3fc61101 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 28 Aug 2025 01:34:41 +0200 Subject: [PATCH 12/44] [desktop] fix controls dialog text clipping (#336) Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/336 Reviewed-by: CamilleLaVey --- CMakeLists.txt | 4 +- dist/qt_themes/default/style.qss | 54 +++++++++++++++++++ dist/qt_themes/default_dark/style.qss | 26 +++++++++ dist/qt_themes/qdarkstyle/style.qss | 2 +- .../qdarkstyle_midnight_blue/style.qss | 3 +- 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dacbc73685..6a8401759d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -579,8 +579,8 @@ else() find_package(lz4 REQUIRED) find_package(RenderDoc MODULE) find_package(stb MODULE) - find_package(enet 1.3 MODULE) - find_package(Opus 1.3 MODULE) + find_package(enet 1.3 MODULE REQUIRED) + find_package(Opus 1.3 MODULE REQUIRED) find_package(ZLIB 1.2 REQUIRED) find_package(zstd 1.5 REQUIRED) diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss index db55b9b490..701086299d 100644 --- a/dist/qt_themes/default/style.qss +++ b/dist/qt_themes/default/style.qss @@ -95,6 +95,60 @@ QPushButton#button_reset_defaults { padding: 4px 8px; } +/* QGroupBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox + +--------------------------------------------------------------------------- */ +QGroupBox { + border: 1px solid #32414B; + border-radius: 4px; + margin-top: 20px; + padding: 2px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + padding-left: 3px; + padding-right: 5px; + padding-top: 2px; +} + +QGroupBox::indicator { + margin-left: 2px; + height: 16px; + width: 16px; +} + +QGroupBox::indicator:unchecked { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QGroupBox::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QGroupBox::indicator:checked { + border: none; + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QGroupBox::indicator:checked:disabled { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + QWidget#bottomPerGameInput, QWidget#topControllerApplet, QWidget#bottomControllerApplet, diff --git a/dist/qt_themes/default_dark/style.qss b/dist/qt_themes/default_dark/style.qss index 6a3f517cb6..dd224c3322 100644 --- a/dist/qt_themes/default_dark/style.qss +++ b/dist/qt_themes/default_dark/style.qss @@ -697,3 +697,29 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled, QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled { image: url(:/overlay/osk_button_Y_disabled.png); } + +/* QGroupBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox + +--------------------------------------------------------------------------- */ +QGroupBox { + border: 1px solid #32414B; + border-radius: 4px; + margin-top: 22px; + padding: 2px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; +} + +QGroupBox::indicator { + margin-left: 2px; + height: 16px; + width: 16px; +} diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss index 32610b131e..d018b9b64b 100644 --- a/dist/qt_themes/qdarkstyle/style.qss +++ b/dist/qt_themes/qdarkstyle/style.qss @@ -307,7 +307,7 @@ QAbstractItemView QLineEdit { QGroupBox { border: 1px solid #54575B; border-radius: 2px; - margin-top: 12px; + margin-top: 20px; padding-top: 2px; } diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss index 43db5ad0b5..ca80f8b665 100644 --- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss +++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss @@ -235,10 +235,9 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { - font-weight: bold; border: 1px solid #32414B; border-radius: 4px; - margin-top: 12px; + margin-top: 20px; padding: 2px; } From 782e1cbc3751e18c444ae6d106409dfa29c8420f Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 28 Aug 2025 01:55:27 +0200 Subject: [PATCH 13/44] [audio] fix ringbuffer datarace (#205) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/205 Reviewed-by: CamilleLaVey Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/ring_buffer.h | 42 ++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index b92db6185b..14f6eceeb8 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h @@ -1,3 +1,5 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -37,10 +39,10 @@ public: /// @param slot_count Number of slots to push /// @returns The number of slots actually pushed std::size_t Push(const void* new_slots, std::size_t slot_count) { - const std::size_t write_index = m_write_index.load(); - const std::size_t slots_free = capacity + m_read_index.load() - write_index; - const std::size_t push_count = std::min(slot_count, slots_free); + std::lock_guard lock(rb_mutex); + const std::size_t slots_free = capacity + read_index - write_index; + const std::size_t push_count = std::min(slot_count, slots_free); const std::size_t pos = write_index % capacity; const std::size_t first_copy = std::min(capacity - pos, push_count); const std::size_t second_copy = push_count - first_copy; @@ -50,8 +52,7 @@ public: in += first_copy * slot_size; std::memcpy(m_data.data(), in, second_copy * slot_size); - m_write_index.store(write_index + push_count); - + write_index = write_index + push_count; return push_count; } @@ -64,10 +65,10 @@ public: /// @param max_slots Maximum number of slots to pop /// @returns The number of slots actually popped std::size_t Pop(void* output, std::size_t max_slots = ~std::size_t(0)) { - const std::size_t read_index = m_read_index.load(); - const std::size_t slots_filled = m_write_index.load() - read_index; - const std::size_t pop_count = std::min(slots_filled, max_slots); + std::lock_guard lock(rb_mutex); + const std::size_t slots_filled = write_index - read_index; + const std::size_t pop_count = std::min(slots_filled, max_slots); const std::size_t pos = read_index % capacity; const std::size_t first_copy = std::min(capacity - pos, pop_count); const std::size_t second_copy = pop_count - first_copy; @@ -77,8 +78,7 @@ public: out += first_copy * slot_size; std::memcpy(out, m_data.data(), second_copy * slot_size); - m_read_index.store(read_index + pop_count); - + read_index = read_index + pop_count; return pop_count; } @@ -90,29 +90,21 @@ public: } /// @returns Number of slots used - [[nodiscard]] std::size_t Size() const { - return m_write_index.load() - m_read_index.load(); + [[nodiscard]] inline std::size_t Size() const { + return write_index - read_index; } /// @returns Maximum size of ring buffer - [[nodiscard]] constexpr std::size_t Capacity() const { + [[nodiscard]] consteval std::size_t Capacity() const { return capacity; } private: - // It is important to align the below variables for performance reasons: - // Having them on the same cache-line would result in false-sharing between them. - // TODO: Remove this ifdef whenever clang and GCC support - // std::hardware_destructive_interference_size. -#ifdef __cpp_lib_hardware_interference_size - alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0}; - alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0}; -#else - alignas(128) std::atomic_size_t m_read_index{0}; - alignas(128) std::atomic_size_t m_write_index{0}; -#endif - std::array m_data; + // This is wrong, a thread-safe ringbuffer is impossible. + std::size_t read_index{0}; + std::size_t write_index{0}; + std::mutex rb_mutex; }; } // namespace Common From f390a6ca4cb4c9d66b85fc71072ef755c0bc705d Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 28 Aug 2025 05:14:24 +0200 Subject: [PATCH 14/44] [veil] fix flush log option not being available (#341) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/341 Reviewed-by: CamilleLaVey Co-authored-by: lizzie Co-committed-by: lizzie --- .../org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt | 2 +- src/common/settings.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index d91c026acf..3c5b9003de 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -66,7 +66,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { SHOW_POWER_INFO("show_power_info"), SHOW_SHADERS_BUILDING("show_shaders_building"), - DEBUG_FLUSH_BY_LINE("flush_lines"), + DEBUG_FLUSH_BY_LINE("flush_line"), USE_LRU_CACHE("use_lru_cache"); external fun isRaiiEnabled(): Boolean diff --git a/src/common/settings.h b/src/common/settings.h index 27196fbd69..9ceef99cff 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -756,7 +756,7 @@ struct Values { // Miscellaneous Setting log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous}; - Setting log_flush_lines{linkage, false, "flush_lines", Category::Miscellaneous, Specialization::Default, true, true}; + Setting log_flush_lines{linkage, false, "flush_line", Category::Miscellaneous, Specialization::Default, true, true}; Setting censor_username{linkage, true, "censor_username", Category::Miscellaneous}; Setting use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous}; Setting first_launch{linkage, true, "first_launch", Category::Miscellaneous}; From 780d84e4223cb565407fb1434e684eaa043b5d93 Mon Sep 17 00:00:00 2001 From: wildcard Date: Thu, 28 Aug 2025 05:21:05 +0200 Subject: [PATCH 15/44] [Vulkan][TextureCache] Always use identity-swizzled views for storage images (#321) Validation flagged writes to a VK_DESCRIPTOR_TYPE_STORAGE_IMAGE descriptor because the bound VkImageView had a non-identity component mapping and hence the vuid-00336 error, this fixes the said error. ------ This commit helps to fix some graphical issues on games like Trident's Tale, where game didn't render anything than just plain terrain, helps to stabilize Nier Automata graphical issues, meanwhile the most annoying glitches are gone, there's still remain other issues. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/321 Reviewed-by: CamilleLaVey Co-authored-by: wildcard Co-committed-by: wildcard --- .../renderer_vulkan/vk_texture_cache.cpp | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index ba58060d20..eda9ff2a5a 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -2160,20 +2160,34 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type, if (!image_handle) { return VK_NULL_HANDLE; } - if (image_format == Shader::ImageFormat::Typeless) { - return Handle(texture_type); - } - const bool is_signed{image_format == Shader::ImageFormat::R8_SINT || - image_format == Shader::ImageFormat::R16_SINT}; + if (!storage_views) { storage_views = std::make_unique(); } - auto& views{is_signed ? storage_views->signeds : storage_views->unsigneds}; - auto& view{views[static_cast(texture_type)]}; - if (view) { + + // Storage images MUST use identity component mapping. + // Typeless: use the underlying image's native format. + if (image_format == Shader::ImageFormat::Typeless) { + auto& view = storage_views->unsigneds[static_cast(texture_type)]; + if (view) { + return *view; + } + const auto fmt_info = + MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, /*is_image=*/true, format); + const VkFormat vk_format = fmt_info.format; + // Storage images are color-aspect only + view = MakeView(vk_format, VK_IMAGE_ASPECT_COLOR_BIT); // identity components inside return *view; } - view = MakeView(Format(image_format), VK_IMAGE_ASPECT_COLOR_BIT); + const bool is_signed = (image_format == Shader::ImageFormat::R8_SINT ||image_format == Shader::ImageFormat::R16_SINT); + auto& views = is_signed ? storage_views->signeds : storage_views->unsigneds; + auto& view = views[static_cast(texture_type)]; + if (view) { + return *view; + } + + const VkFormat vk_format = Format(image_format); + view = MakeView(vk_format, VK_IMAGE_ASPECT_COLOR_BIT);// identity components inside return *view; } From 39fd8400eff7f6b3729f14b3fe44ca277253541b Mon Sep 17 00:00:00 2001 From: MaranBr Date: Thu, 28 Aug 2025 16:46:24 +0200 Subject: [PATCH 16/44] [debug] Rename remaining names in accordance with PR 341 (#343) This renames the remaining names in accordance with PR 341. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/343 Reviewed-by: CamilleLaVey Co-authored-by: MaranBr Co-committed-by: MaranBr --- src/common/logging/backend.cpp | 5 ++++- src/common/settings.h | 2 +- src/yuzu/configuration/configure_debug.cpp | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index ff07ab68eb..4621771090 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -121,7 +124,7 @@ public: bytes_written += file->WriteString(message); // Option to log each line rather than 4k buffers - if (Settings::values.log_flush_lines.GetValue()) { + if (Settings::values.log_flush_line.GetValue()) { file->Flush(); } diff --git a/src/common/settings.h b/src/common/settings.h index 9ceef99cff..ce845b31f5 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -756,7 +756,7 @@ struct Values { // Miscellaneous Setting log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous}; - Setting log_flush_lines{linkage, false, "flush_line", Category::Miscellaneous, Specialization::Default, true, true}; + Setting log_flush_line{linkage, false, "flush_line", Category::Miscellaneous, Specialization::Default, true, true}; Setting censor_username{linkage, true, "censor_username", Category::Miscellaneous}; Setting use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous}; Setting first_launch{linkage, true, "first_launch", Category::Miscellaneous}; diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 10607ee233..733c419c4b 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -39,7 +42,7 @@ void ConfigureDebug::SetConfiguration() { ui->toggle_console->setEnabled(runtime_lock); ui->toggle_console->setChecked(UISettings::values.show_console.GetValue()); ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue())); - ui->flush_line->setChecked(Settings::values.log_flush_lines.GetValue()); + ui->flush_line->setChecked(Settings::values.log_flush_line.GetValue()); ui->censor_username->setChecked(Settings::values.censor_username.GetValue()); ui->homebrew_args_edit->setText( QString::fromStdString(Settings::values.program_args.GetValue())); @@ -90,7 +93,7 @@ void ConfigureDebug::ApplyConfiguration() { Settings::values.gdbstub_port = ui->gdbport_spinbox->value(); UISettings::values.show_console = ui->toggle_console->isChecked(); Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); - Settings::values.log_flush_lines = ui->flush_line->isChecked(); + Settings::values.log_flush_line = ui->flush_line->isChecked(); Settings::values.censor_username = ui->censor_username->isChecked(); Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked(); From b598b7c3255894eda8942647a5fb6b7921b9b65f Mon Sep 17 00:00:00 2001 From: MaranBr Date: Fri, 29 Aug 2025 00:07:21 +0200 Subject: [PATCH 17/44] [core] Unsafe toggles cannot be changed at runtime (#344) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/344 Reviewed-by: CamilleLaVey Reviewed-by: crueter Co-authored-by: MaranBr Co-committed-by: MaranBr --- src/common/settings.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/common/settings.h b/src/common/settings.h index ce845b31f5..64545d10ff 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -307,10 +307,7 @@ struct Values { true, #endif "cpuopt_unsafe_host_mmu", - Category::CpuUnsafe, - Specialization::Default, - true, - true}; + Category::CpuUnsafe}; SwitchableSetting cpuopt_unsafe_unfuse_fma{linkage, true, "cpuopt_unsafe_unfuse_fma", Category::CpuUnsafe}; SwitchableSetting cpuopt_unsafe_reduce_fp_error{ From 31d3e97fa2294bf5b1ccbf5e8be040df95ce4f34 Mon Sep 17 00:00:00 2001 From: crueter Date: Fri, 29 Aug 2025 00:18:02 +0200 Subject: [PATCH 18/44] [cmake] refactor: cpmfile, deps prefetch, force system and more (#322) CPM Dependencies are now managed in a singular json file, where each can be properly prefetched at-will via `tools/cpm-fetch.sh `, or all at once via `tools/cpm-fetch-all.sh`. Adds docs for CPMUtil as well. Also adds `_FORCE_{BUNDLED,SYSTEM}` overrides Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/322 Reviewed-by: CamilleLaVey --- .gitignore | 1 + CMakeLists.txt | 297 ++++++--------------- CMakeModules/CPMUtil.cmake | 354 +++++++++++++++++++------- CMakeModules/DownloadExternals.cmake | 1 + CMakeModules/FindSPIRV-Tools.cmake | 19 ++ CMakeModules/Findzstd.cmake | 17 +- cpmfile.json | 147 +++++++++++ docs/CPM.md | 252 ++++++++++++++++++ externals/CMakeLists.txt | 142 +++-------- externals/cpmfile.json | 109 ++++++++ externals/ffmpeg/CMakeLists.txt | 12 +- externals/ffmpeg/cpmfile.json | 8 + externals/nx_tzdb/CMakeLists.txt | 67 +++-- externals/nx_tzdb/cpmfile.json | 8 + src/android/app/build.gradle.kts | 5 +- src/common/CMakeLists.txt | 8 +- src/dynarmic/externals/CMakeLists.txt | 86 ++----- src/dynarmic/externals/cpmfile.json | 47 ++++ src/shader_recompiler/CMakeLists.txt | 2 +- src/yuzu/externals/CMakeLists.txt | 13 +- src/yuzu/externals/cpmfile.json | 12 + tools/cpm-fetch-all.sh | 10 + tools/cpm-fetch.sh | 198 ++++++++++++++ 23 files changed, 1253 insertions(+), 562 deletions(-) create mode 100644 CMakeModules/FindSPIRV-Tools.cmake create mode 100644 cpmfile.json create mode 100644 docs/CPM.md create mode 100644 externals/cpmfile.json create mode 100644 externals/ffmpeg/cpmfile.json create mode 100644 externals/nx_tzdb/cpmfile.json create mode 100644 src/dynarmic/externals/cpmfile.json create mode 100644 src/yuzu/externals/cpmfile.json create mode 100755 tools/cpm-fetch-all.sh create mode 100755 tools/cpm-fetch.sh diff --git a/.gitignore b/.gitignore index 83881117ac..2b342e5145 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,4 @@ Thumbs.db eden-windows-msvc artifacts *.AppImage* +/install* diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a8401759d..d11b58bf1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,6 @@ option(FORCE_DOWNLOAD_WIN_BUNDLES "Forcefully download bundled Windows dependenc if (YUZU_USE_CPM AND ENABLE_SDL2) option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}") - CMAKE_DEPENDENT_OPTION(FORCE_DOWNLOAD_SDL2 "Forcefully download all bundled SDL2 builds (useful for CI)" OFF "YUZU_USE_BUNDLED_SDL2" OFF) endif() CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF) @@ -110,11 +109,7 @@ CMAKE_DEPENDENT_OPTION(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROI CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF) -if (PLATFORM_FREEBSD) - option(YUZU_CHECK_SUBMODULES "Check if submodules are present" OFF) -else() - option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON) -endif() +option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ${EXT_DEFAULT}) option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF) @@ -143,9 +138,8 @@ endif() option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL}) -if (YUZU_USE_CPM AND ENABLE_OPENSSL) +if (ENABLE_OPENSSL) CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" "${MSVC}" "NOT ANDROID" ON) - CMAKE_DEPENDENT_OPTION(FORCE_DOWNLOAD_OPENSSL "Forcefully download all bundled OpenSSL builds (useful for CI)" OFF "YUZU_USE_BUNDLED_OPENSSL" OFF) endif() if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL) @@ -180,12 +174,12 @@ if (YUZU_USE_PRECOMPILED_HEADERS) set(YUZU_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE) endif() endif() + if (YUZU_USE_PRECOMPILED_HEADERS) message(STATUS "Using Precompiled Headers.") set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON) endif() - # Default to a Release build get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) @@ -246,20 +240,24 @@ endfunction() if(EXISTS ${PROJECT_SOURCE_DIR}/.gitmodules AND YUZU_CHECK_SUBMODULES) check_submodules_present() endif() + configure_file(${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.qrc ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc COPYONLY) + if (EXISTS ${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.json) configure_file("${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.json" "${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" COPYONLY) endif() + if (ENABLE_COMPATIBILITY_LIST_DOWNLOAD AND NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) message(STATUS "Downloading compatibility list for yuzu...") file(DOWNLOAD https://api.yuzu-emu.org/gamedb/ "${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" SHOW_PROGRESS) endif() + if (NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) file(WRITE ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json "") endif() @@ -303,8 +301,15 @@ if (NOT DEFINED ARCHITECTURE) set(ARCHITECTURE_GENERIC 1) add_definitions(-DARCHITECTURE_GENERIC=1) endif() + message(STATUS "Target architecture: ${ARCHITECTURE}") +if (MSVC AND ARCHITECTURE_x86) + message(FATAL_ERROR "Attempting to build with the x86 environment is not supported. \ + This can typically happen if you used the Developer Command Prompt from the start menu;\ + instead, run vcvars64.bat directly, located at C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat") +endif() + if (UNIX) add_definitions(-DYUZU_UNIX=1) endif() @@ -367,6 +372,15 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) include(CPMUtil) +# openssl funniness +if (ENABLE_OPENSSL) + if (YUZU_USE_BUNDLED_OPENSSL) + AddJsonPackage(openssl) + endif() + + find_package(OpenSSL 1.1.1 REQUIRED) +endif() + if (YUZU_USE_CPM) message(STATUS "Fetching needed dependencies with CPM") @@ -375,36 +389,9 @@ if (YUZU_USE_CPM) # TODO(crueter): renderdoc? - # openssl funniness - if (ENABLE_OPENSSL) - if (YUZU_USE_BUNDLED_OPENSSL) - AddCIPackage( - PACKAGE OpenSSL - NAME openssl - REPO crueter-ci/OpenSSL - VERSION 3.5.2 - MIN_VERSION 1.1.1 - FORCE_DOWNLOAD ${FORCE_DOWNLOAD_OPENSSL} - ) - endif() - - find_package(OpenSSL 1.1.1 REQUIRED) - endif() - # boost set(BOOST_INCLUDE_LIBRARIES algorithm icl pool container heap asio headers process filesystem crc variant) - AddPackage( - NAME Boost - REPO boostorg/boost - TAG boost-1.88.0 - ARTIFACT boost-1.88.0-cmake.7z - - HASH e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01 - - GIT_VERSION 1.88.0 - VERSION 1.57 - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(boost) # really annoying thing where boost::headers doesn't work with cpm # TODO(crueter) investigate @@ -419,6 +406,10 @@ if (YUZU_USE_CPM) if (NOT MSVC) # boost sucks + if (NOT PLATFORM_LINUX AND NOT ANDROID) + target_compile_definitions(boost_container INTERFACE BOOST_HAS_PTHREADS) + endif() + target_compile_options(boost_heap INTERFACE -Wno-shadow) target_compile_options(boost_icl INTERFACE -Wno-shadow) target_compile_options(boost_asio INTERFACE -Wno-conversion -Wno-implicit-fallthrough) @@ -426,151 +417,46 @@ if (YUZU_USE_CPM) endif() # fmt - AddPackage( - NAME fmt - REPO fmtlib/fmt - SHA 40626af88b - HASH d59f06c24339f223de4ec2afeba1c67b5835a0f350a1ffa86242a72fc3e616a6b8b21798355428d4200c75287308b66634619ffa0b52ba5bd74cc01772ea1a8a - VERSION 8 - OPTIONS - "FMT_INSTALL OFF" - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(fmt) # lz4 - AddPackage( - NAME lz4 - REPO lz4/lz4 - SHA ebb370ca83 - HASH 43600e87b35256005c0f2498fa56a77de6783937ba4cfce38c099f27c03188d097863e8a50c5779ca0a7c63c29c4f7ed0ae526ec798c1fd2e3736861b62e0a37 - SOURCE_SUBDIR build/cmake - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(lz4) if (lz4_ADDED) add_library(lz4::lz4 ALIAS lz4_static) endif() # nlohmann - AddPackage( - NAME nlohmann_json - REPO nlohmann/json - SHA 55f93686c0 - HASH b739749b066800e21154506ea150d2c5cbce8a45344177f46f884547a1399d26753166fd0df8135269ce28cf223552b1b65cd625b88c844d54753f2434900486 - VERSION 3.8 - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(nlohmann) # zlib - AddPackage( - NAME ZLIB - REPO madler/zlib - SHA 51b7f2abda - HASH 16eaf1f3752489d12fd9ce30f7b5f7cbd5cb8ff53d617005a9847ae72d937f65e01e68be747f62d7ac19fd0c9aeba9956e60f16d6b465c5fdc2f3d08b4db2e6c - VERSION 1.2 - OPTIONS - "ZLIB_BUILD_SHARED OFF" - "ZLIB_INSTALL OFF" - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(zlib) if (ZLIB_ADDED) add_library(ZLIB::ZLIB ALIAS zlibstatic) endif() # zstd - AddPackage( - NAME zstd - REPO facebook/zstd - SHA f8745da6ff - HASH 3037007f990040fe32573b46f9bef8762fd5dbeeb07ffffcbfeba51ec98167edae39bb9c87f9299efcd61c4e467c5e84f7c19f0df7799bc1fc04864a278792ee - VERSION 1.5 - SOURCE_SUBDIR build/cmake - OPTIONS - "ZSTD_BUILD_SHARED OFF" - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(zstd) + + if (zstd_ADDED) + add_library(zstd::zstd ALIAS libzstd_static) + endif() # Catch2 if (YUZU_TESTS OR DYNARMIC_TESTS) - AddPackage( - NAME Catch2 - REPO catchorg/Catch2 - SHA 644821ce28 - HASH f8795f98acf2c02c0db8e734cc866d5caebab4b4a306e93598b97cb3c0c728dafe8283dce27ffe8d42460e5ae7302f3f32e7e274a7f991b73511ac88eef21b1f - VERSION 3.0.1 - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(catch2) endif() # ENet - AddPackage( - NAME enet - REPO lsalzman/enet - SHA 2662c0de09 - VERSION 1.3 - HASH 3de1beb4fa3d6b1e03eda8dd1e7580694f854af3ed3975dcdabfdcdf76b97f322b9734d35ea7f185855bb490d957842b938b26da4dd2dfded509390f8d2794dd - FIND_PACKAGE_ARGUMENTS "MODULE" - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(enet) if (enet_ADDED) target_include_directories(enet INTERFACE ${enet_SOURCE_DIR}/include) endif() # Opus - AddPackage( - NAME Opus - VERSION 1.3 - REPO "xiph/opus" - SHA 5ded705cf4 - HASH 0dc89e58ddda1f3bc6a7037963994770c5806c10e66f5cc55c59286fc76d0544fe4eca7626772b888fd719f434bc8a92f792bdb350c807968b2ac14cfc04b203 - FIND_PACKAGE_ARGUMENTS "MODULE" - OPTIONS - "OPUS_BUILD_TESTING OFF" - "OPUS_BUILD_PROGRAMS OFF" - "OPUS_INSTALL_PKG_CONFIG_MODULE OFF" - "OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF" - EXCLUDE_FROM_ALL ON - ) - - if(ENABLE_CUBEB) - AddPackage( - NAME cubeb - REPO "mozilla/cubeb" - SHA fa02160712 - HASH 82d808356752e4064de48c8fecbe7856715ade1e76b53937116bf07129fc1cc5b3de5e4b408de3cd000187ba8dc32ca4109661cb7e0355a52e54bd81b9be1c61 - FIND_PACKAGE_ARGUMENTS "CONFIG" # not sure this works outside of gentoo - OPTIONS - "USE_SANITIZERS OFF" - "BUILD_TESTS OFF" - "BUILD_TOOLS OFF" - "BUNDLE_SPEEX ON" - EXCLUDE_FROM_ALL ON - ) - - if (cubeb_ADDED) - if (NOT MSVC) - if (TARGET speex) - target_compile_options(speex PRIVATE -Wno-sign-compare) - endif() - - set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "") - target_compile_options(cubeb INTERFACE - -Wno-implicit-const-int-float-conversion - -Wno-shadow - -Wno-missing-declarations - -Wno-return-type - -Wno-uninitialized - ) - else() - target_compile_options(cubeb PRIVATE - /wd4456 - /wd4458 - ) - endif() - endif() - endif() + AddJsonPackage(opus) else() # Enforce the search mode of non-required packages for better and shorter failure messages find_package(fmt 8 REQUIRED) @@ -582,11 +468,7 @@ else() find_package(enet 1.3 MODULE REQUIRED) find_package(Opus 1.3 MODULE REQUIRED) find_package(ZLIB 1.2 REQUIRED) - find_package(zstd 1.5 REQUIRED) - - if (ENABLE_CUBEB) - find_package(cubeb CONFIG) - endif() + find_package(zstd 1.5 REQUIRED MODULE) if (YUZU_TESTS) find_package(Catch2 3.0.1 REQUIRED) @@ -602,14 +484,7 @@ else() endif() if(NOT TARGET Boost::headers) - AddPackage( - NAME boost_headers - REPO "boostorg/headers" - SHA 0456900fad - HASH 50cd75dcdfc5f082225cdace058f47b4fb114a47585f7aee1d22236a910a80b667186254c214fa2fcebac67ae6d37ba4b6e695e1faea8affd6fd42a03cf996e3 - BUNDLED_PACKAGE ON - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(boost_headers) endif() if (ENABLE_LIBUSB) @@ -622,45 +497,45 @@ endif() # DiscordRPC if (USE_DISCORD_PRESENCE) - AddPackage( - NAME discord-rpc - REPO "discord/discord-rpc" - SHA 963aa9f3e5 - HASH 386e1344e9a666d730f2d335ee3aef1fd05b1039febefd51aa751b705009cc764411397f3ca08dffd46205c72f75b235c870c737b2091a4ed0c3b061f5919bde - OPTIONS - "BUILD_EXAMPLES OFF" - PATCHES - ${CMAKE_SOURCE_DIR}/.patch/discord-rpc/0001-cmake-version.patch - ${CMAKE_SOURCE_DIR}/.patch/discord-rpc/0002-no-clang-format.patch - ${CMAKE_SOURCE_DIR}/.patch/discord-rpc/0003-fix-cpp17.patch - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(discord-rpc) target_include_directories(discord-rpc INTERFACE ${discord-rpc_SOURCE_DIR}/include) add_library(DiscordRPC::discord-rpc ALIAS discord-rpc) endif() # SimpleIni -AddPackage( - NAME SimpleIni - REPO brofield/simpleini - SHA 09c21bda1d - HASH 99779ca9b6e040d36558cadf484f9ffdab5b47bcc8fc72e4d33639d1d60c0ceb4410d335ba445d72a4324e455167fd6769d99b459943aa135bec085dff2d4b7c - FIND_PACKAGE_ARGUMENTS "MODULE" - EXCLUDE_FROM_ALL ON -) +AddJsonPackage(simpleini) -# TODO(crueter): Work around this -if (NOT YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS) - find_package(PkgConfig REQUIRED) - pkg_check_modules(SPIRV-Tools REQUIRED SPIRV-Tools) +# Most linux distros don't package cubeb, so enable regardless of cpm settings +if(ENABLE_CUBEB) + AddJsonPackage(cubeb) + + if (cubeb_ADDED) + if (NOT MSVC) + if (TARGET speex) + target_compile_options(speex PRIVATE -Wno-sign-compare) + endif() + + set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "") + target_compile_options(cubeb INTERFACE + -Wno-implicit-const-int-float-conversion + -Wno-shadow + -Wno-missing-declarations + -Wno-return-type + -Wno-uninitialized + ) + else() + target_compile_options(cubeb PRIVATE + /wd4456 + /wd4458 + ) + endif() + endif() endif() # find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the YUZU_find_package if (ENABLE_SDL2) - # this was hard to get right, but ultimately I decided to make it so that FORCE_DOWNLOAD_SDL2 also downloads the - # external one. Really silly behavior imo but in the interest of getting something out there I'm leaving it for now - if (YUZU_USE_EXTERNAL_SDL2 OR FORCE_DOWNLOAD_SDL2) + if (YUZU_USE_EXTERNAL_SDL2) message(STATUS "Using SDL2 from externals.") if (NOT WIN32) # Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers @@ -683,37 +558,14 @@ if (ENABLE_SDL2) endif() if ("${YUZU_SYSTEM_PROFILE}" STREQUAL "steamdeck") - set(SDL_HASH cc016b0046) set(SDL_PIPEWIRE OFF) # build errors out with this on - set(SDL_SHA512SUM 34d5ef58da6a4f9efa6689c82f67badcbd741f5a4f562a9c2c30828fa839830fb07681c5dc6a7851520e261c8405a416ac0a2c2513b51984fb3b4fa4dcb3e20b) + AddJsonPackage("sdl2_steamdeck") else() - set(SDL_HASH 54772f345a) - set(SDL_SHA512SUM 2a68a0e01c390043aa9d9df63d8a20a52076c88bb460ac4e0f33194ca7d9bc8fadbbcc04e7506872ac4b6354a73fbc267c036f82200da59465789b87c7d9e3a4) + AddJsonPackage("sdl2_generic") endif() - - AddPackage( - NAME SDL2 - REPO "libsdl-org/SDL" - SHA ${SDL_HASH} - HASH ${SDL_SHA512SUM} - KEY ${YUZU_SYSTEM_PROFILE} - BUNDLED_PACKAGE ON - EXCLUDE_FROM_ALL ON - ) - endif() - - if (YUZU_USE_BUNDLED_SDL2) + elseif (YUZU_USE_BUNDLED_SDL2) message(STATUS "Using bundled SDL2") - AddCIPackage( - PACKAGE SDL2 - NAME SDL2 - REPO crueter-ci/SDL2 - VERSION 2.32.8 - MIN_VERSION 2.26.4 - CMAKE_FILENAME sdl2 - FORCE_DOWNLOAD ${FORCE_DOWNLOAD_SDL2} - TARGET "SDL2::SDL2" - ) + AddJsonPackage(sdl2) endif() find_package(SDL2 2.26.4 REQUIRED) @@ -750,6 +602,7 @@ add_subdirectory(externals) find_package(VulkanHeaders) find_package(VulkanUtilityLibraries) find_package(VulkanMemoryAllocator) +find_package(SPIRV-Tools) if (ENABLE_WEB_SERVICE) find_package(httplib) diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index 519e7e32a8..4d7db6ed61 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -1,28 +1,222 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + # Created-By: crueter # Docs will come at a later date, mostly this is to just reduce boilerplate # and some cmake magic to allow for runtime viewing of dependency versions -include(CMakeDependentOption) +# Future crueter: Wow this was a lie and a half, at this point I might as well make my own CPN +# haha just kidding... unless? + if (MSVC OR ANDROID) - set(SYSTEM_DEFAULT OFF) + set(BUNDLED_DEFAULT OFF) else() - set(SYSTEM_DEFAULT ON) + set(BUNDLED_DEFAULT ON) endif() -CMAKE_DEPENDENT_OPTION(CPMUTIL_DEFAULT_SYSTEM - "Allow usage of system packages for CPM dependencies" ${SYSTEM_DEFAULT} - "NOT ANDROID" OFF) +option(CPMUTIL_FORCE_BUNDLED + "Force bundled packages for all CPM depdendencies" ${BUNDLED_DEFAULT}) + +option(CPMUTIL_FORCE_SYSTEM + "Force system packages for all CPM dependencies (NOT RECOMMENDED)" OFF) cmake_minimum_required(VERSION 3.22) include(CPM) +# TODO(crueter): Better solution for separate cpmfiles e.g. per-directory +set(CPMUTIL_JSON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json" CACHE STRING "Location of cpmfile.json") + +if (EXISTS ${CPMUTIL_JSON_FILE}) + file(READ ${CPMUTIL_JSON_FILE} CPMFILE_CONTENT) +else() + message(WARNING "[CPMUtil] cpmfile ${CPMUTIL_JSON_FILE} does not exist, AddJsonPackage will be a no-op") +endif() + +# utility function(cpm_utils_message level name message) message(${level} "[CPMUtil] ${name}: ${message}") endfunction() +# utility +function(array_to_list array length out) + math(EXPR range "${length} - 1") + + foreach(IDX RANGE ${range}) + string(JSON _element GET "${array}" "${IDX}") + + list(APPEND NEW_LIST ${_element}) + endforeach() + + set("${out}" "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# utility +function(get_json_element object out member default) + string(JSON out_type ERROR_VARIABLE err TYPE "${object}" ${member}) + + if (err) + set("${out}" "${default}" PARENT_SCOPE) + return() + endif() + + string(JSON outvar GET "${object}" ${member}) + + if (out_type STREQUAL "ARRAY") + string(JSON _len LENGTH "${object}" ${member}) + # array_to_list("${outvar}" ${_len} outvar) + set("${out}_LENGTH" "${_len}" PARENT_SCOPE) + endif() + + set("${out}" "${outvar}" PARENT_SCOPE) +endfunction() + +# Kinda cancerous but whatever +function(AddJsonPackage) + set(oneValueArgs + NAME + + # these are overrides that can be generated at runtime, so can be defined separately from the json + DOWNLOAD_ONLY + SYSTEM_PACKAGE + BUNDLED_PACKAGE + ) + + set(multiValueArgs OPTIONS) + + cmake_parse_arguments(JSON "" "${oneValueArgs}" "${multiValueArgs}" + "${ARGN}") + + list(LENGTH ARGN argnLength) + # single name argument + if(argnLength EQUAL 1) + set(JSON_NAME "${ARGV0}") + endif() + + if (NOT DEFINED CPMFILE_CONTENT) + cpm_utils_message(WARNING ${name} "No cpmfile, AddJsonPackage is a no-op") + return() + endif() + + if (NOT DEFINED JSON_NAME) + cpm_utils_message(FATAL_ERROR "json package" "No name specified") + endif() + + string(JSON object ERROR_VARIABLE err GET "${CPMFILE_CONTENT}" "${JSON_NAME}") + + if (err) + cpm_utils_message(FATAL_ERROR ${JSON_NAME} "Not found in cpmfile") + endif() + + get_json_element("${object}" package package ${JSON_NAME}) + get_json_element("${object}" repo repo "") + get_json_element("${object}" ci ci OFF) + get_json_element("${object}" version version "") + + if (ci) + get_json_element("${object}" name name "${JSON_NAME}") + get_json_element("${object}" extension extension "tar.zst") + get_json_element("${object}" min_version min_version "") + get_json_element("${object}" cmake_filename cmake_filename "") + get_json_element("${object}" raw_disabled disabled_platforms "") + + if (raw_disabled) + array_to_list("${raw_disabled}" ${raw_disabled_LENGTH} disabled_platforms) + else() + set(disabled_platforms "") + endif() + + AddCIPackage( + VERSION ${version} + NAME ${name} + REPO ${repo} + PACKAGE ${package} + EXTENSION ${extension} + MIN_VERSION ${min_version} + DISABLED_PLATFORMS ${disabled_platforms} + CMAKE_FILENAME ${cmake_filename} + ) + return() + endif() + + get_json_element("${object}" hash hash "") + get_json_element("${object}" sha sha "") + get_json_element("${object}" url url "") + get_json_element("${object}" key key "") + get_json_element("${object}" tag tag "") + get_json_element("${object}" artifact artifact "") + get_json_element("${object}" git_version git_version "") + get_json_element("${object}" source_subdir source_subdir "") + get_json_element("${object}" bundled bundled "unset") + get_json_element("${object}" find_args find_args "") + get_json_element("${object}" raw_patches patches "") + + # format patchdir + if (raw_patches) + math(EXPR range "${raw_patches_LENGTH} - 1") + + foreach(IDX RANGE ${range}) + string(JSON _patch GET "${raw_patches}" "${IDX}") + + set(full_patch "${CMAKE_SOURCE_DIR}/.patch/${JSON_NAME}/${_patch}") + if (NOT EXISTS ${full_patch}) + cpm_utils_message(FATAL_ERROR ${JSON_NAME} "specifies patch ${full_patch} which does not exist") + endif() + + list(APPEND patches "${full_patch}") + endforeach() + endif() + # end format patchdir + + # options + get_json_element("${object}" raw_options options "") + + if (raw_options) + array_to_list("${raw_options}" ${raw_options_LENGTH} options) + endif() + + set(options ${options} ${JSON_OPTIONS}) + + # end options + + # system/bundled + if (bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE) + set(bundled ${JSON_BUNDLED_PACKAGE}) + else() + set(bundled ON) + endif() + + AddPackage( + NAME "${package}" + VERSION "${version}" + URL "${url}" + HASH "${hash}" + SHA "${sha}" + REPO "${repo}" + KEY "${key}" + PATCHES "${patches}" + OPTIONS "${options}" + FIND_PACKAGE_ARGUMENTS "${find_args}" + BUNDLED_PACKAGE "${bundled}" + SOURCE_SUBDIR "${source_subdir}" + + GIT_VERSION ${git_version} + ARTIFACT ${artifact} + TAG ${tag} + ) + + # pass stuff to parent scope + set(${package}_ADDED "${${package}_ADDED}" + PARENT_SCOPE) + set(${package}_SOURCE_DIR "${${package}_SOURCE_DIR}" + PARENT_SCOPE) + set(${package}_BINARY_DIR "${${package}_BINARY_DIR}" + PARENT_SCOPE) + +endfunction() + function(AddPackage) cpm_set_policies() @@ -64,9 +258,6 @@ function(AddPackage) GIT_URL KEY - DOWNLOAD_ONLY - FIND_PACKAGE_ARGUMENTS - SYSTEM_PACKAGE BUNDLED_PACKAGE ) @@ -79,6 +270,9 @@ function(AddPackage) cpm_utils_message(FATAL_ERROR "package" "No package name defined") endif() + option(${PKG_ARGS_NAME}_FORCE_SYSTEM "Force the system package for ${PKG_ARGS_NAME}") + option(${PKG_ARGS_NAME}_FORCE_BUNDLED "Force the bundled package for ${PKG_ARGS_NAME}") + if (DEFINED PKG_ARGS_URL) set(pkg_url ${PKG_ARGS_URL}) @@ -124,9 +318,9 @@ function(AddPackage) cpm_utils_message(STATUS ${PKG_ARGS_NAME} "Download URL is ${pkg_url}") if (DEFINED PKG_ARGS_GIT_VERSION) - set(git_version ${PKG_ARGS_VERSION}) - elseif(DEFINED PKG_ARGS_VERSION) set(git_version ${PKG_ARGS_GIT_VERSION}) + elseif(DEFINED PKG_ARGS_VERSION) + set(git_version ${PKG_ARGS_VERSION}) endif() if (NOT DEFINED PKG_ARGS_KEY) @@ -178,25 +372,55 @@ function(AddPackage) if (DEFINED hash_url) set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${PKG_ARGS_NAME}.hash) - file(DOWNLOAD ${hash_url} ${outfile}) - file(READ ${outfile} pkg_hash_tmp) - file(REMOVE ${outfile}) + # TODO(crueter): This is kind of a bad solution + # because "technically" the hash is invalidated each week + # but it works for now kjsdnfkjdnfjksdn + string(TOLOWER ${PKG_ARGS_NAME} lowername) + if (NOT EXISTS ${outfile} AND NOT EXISTS ${CPM_SOURCE_CACHE}/${lowername}/${pkg_key}) + file(DOWNLOAD ${hash_url} ${outfile}) + endif() - set(pkg_hash "${hash_algo}=${pkg_hash_tmp}") + if (EXISTS ${outfile}) + file(READ ${outfile} pkg_hash_tmp) + endif() + + if (DEFINED ${pkg_hash_tmp}) + set(pkg_hash "${hash_algo}=${pkg_hash_tmp}") + endif() endif() - if (NOT CPMUTIL_DEFAULT_SYSTEM) - set(CPM_USE_LOCAL_PACKAGES OFF) - elseif (DEFINED PKG_ARGS_SYSTEM_PACKAGE) - set(CPM_USE_LOCAL_PACKAGES ${PKG_ARGS_SYSTEM_PACKAGE}) + macro(set_precedence local force) + set(CPM_USE_LOCAL_PACKAGES ${local}) + set(CPM_LOCAL_PACKAGES_ONLY ${force}) + endmacro() + + #[[ + Precedence: + - package_FORCE_SYSTEM + - package_FORCE_BUNDLED + - CPMUTIL_FORCE_SYSTEM + - CPMUTIL_FORCE_BUNDLED + - BUNDLED_PACKAGE + - default to allow local + ]]# + if (${PKG_ARGS_NAME}_FORCE_SYSTEM) + set_precedence(ON ON) + elseif (${PKG_ARGS_NAME}_FORCE_BUNDLED) + set_precedence(OFF OFF) + elseif (CPMUTIL_FORCE_SYSTEM) + set_precedence(ON ON) + elseif(NOT CPMUTIL_FORCE_BUNDLED) + set_precedence(OFF OFF) elseif (DEFINED PKG_ARGS_BUNDLED_PACKAGE) if (PKG_ARGS_BUNDLED_PACKAGE) - set(CPM_USE_LOCAL_PACKAGES OFF) + set(local OFF) else() - set(CPM_USE_LOCAL_PACKAGES ON) + set(local ON) endif() + + set_precedence(${local} OFF) else() - set(CPM_USE_LOCAL_PACKAGES ON) + set_precedence(ON OFF) endif() CPMAddPackage( @@ -210,6 +434,7 @@ function(AddPackage) OPTIONS ${PKG_ARGS_OPTIONS} PATCHES ${PKG_ARGS_PATCHES} + EXCLUDE_FROM_ALL ON ${PKG_ARGS_UNPARSED_ARGUMENTS} ) @@ -257,7 +482,7 @@ function(add_ci_package key) set(ARTIFACT ${ARTIFACT_NAME}-${key}-${ARTIFACT_VERSION}.${ARTIFACT_EXT}) AddPackage( - NAME ${ARTIFACT_PACKAGE}-${key} + NAME ${ARTIFACT_PACKAGE} REPO ${ARTIFACT_REPO} TAG v${ARTIFACT_VERSION} VERSION ${ARTIFACT_VERSION} @@ -266,15 +491,12 @@ function(add_ci_package key) KEY ${key} HASH_SUFFIX sha512sum BUNDLED_PACKAGE ON - DOWNLOAD_ONLY ON ) - if (NOT ARTIFACT_FORCE_DOWNLOAD OR ARTIFACT_OVERRIDE) - set(ARTIFACT_DIR ${${ARTIFACT_PACKAGE}-${key}_SOURCE_DIR} PARENT_SCOPE) - endif() + set(ARTIFACT_DIR ${${ARTIFACT_PACKAGE}_SOURCE_DIR} PARENT_SCOPE) endfunction() -# TODO(crueter): doc +# name is the artifact name, package is for find_package override function(AddCIPackage) set(oneValueArgs VERSION @@ -282,11 +504,9 @@ function(AddCIPackage) REPO PACKAGE EXTENSION - FORCE_DOWNLOAD MIN_VERSION DISABLED_PLATFORMS CMAKE_FILENAME - TARGET ) cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "" ${ARGN}) @@ -316,12 +536,6 @@ function(AddCIPackage) set(ARTIFACT_EXT ${PKG_ARGS_EXTENSION}) endif() - if(NOT DEFINED PKG_ARGS_FORCE_DOWNLOAD) - set(ARTIFACT_FORCE_DOWNLOAD OFF) - else() - set(ARTIFACT_FORCE_DOWNLOAD ${PKG_ARGS_FORCE_DOWNLOAD}) - endif() - if (DEFINED PKG_ARGS_MIN_VERSION) set(ARTIFACT_MIN_VERSION ${PKG_ARGS_MIN_VERSION}) endif() @@ -336,86 +550,42 @@ function(AddCIPackage) set(ARTIFACT_REPO ${PKG_ARGS_REPO}) set(ARTIFACT_PACKAGE ${PKG_ARGS_PACKAGE}) - if ((MSVC AND ARCHITECTURE_x86_64) OR ARTIFACT_FORCE_DOWNLOAD AND NOT "windows-amd64" IN_LIST DISABLED_PLATFORMS) - # kinda hacky - if(MSVC AND ARCHITECTURE_x86_64) - set(ARTIFACT_OVERRIDE ON) - endif() - + if ((MSVC AND ARCHITECTURE_x86_64) AND NOT "windows-amd64" IN_LIST DISABLED_PLATFORMS) add_ci_package(windows-amd64) - set(ARTIFACT_OVERRIDE OFF) endif() - if ((MSVC AND ARCHITECTURE_arm64) OR ARTIFACT_FORCE_DOWNLOAD AND NOT "windows-arm64" IN_LIST DISABLED_PLATFORMS) - if(MSVC AND ARCHITECTURE_arm64) - set(ARTIFACT_OVERRIDE ON) - endif() - + if ((MSVC AND ARCHITECTURE_arm64) AND NOT "windows-arm64" IN_LIST DISABLED_PLATFORMS) add_ci_package(windows-arm64) - set(ARTIFACT_OVERRIDE OFF) endif() - if (ANDROID OR ARTIFACT_FORCE_DOWNLOAD AND NOT "android" IN_LIST DISABLED_PLATFORMS) - if(ANDROID) - set(ARTIFACT_OVERRIDE ON) - endif() - + if (ANDROID AND NOT "android" IN_LIST DISABLED_PLATFORMS) add_ci_package(android) - set(ARTIFACT_OVERRIDE OFF) endif() - if(PLATFORM_SUN OR ARTIFACT_FORCE_DOWNLOAD AND NOT "solaris" IN_LIST DISABLED_PLATFORMS) - if(PLATFORM_SUN) - set(ARTIFACT_OVERRIDE ON) - endif() - + if(PLATFORM_SUN AND NOT "solaris" IN_LIST DISABLED_PLATFORMS) add_ci_package(solaris) - set(ARTIFACT_OVERRIDE OFF) endif() - if(PLATFORM_FREEBSD OR ARTIFACT_FORCE_DOWNLOAD AND NOT "freebsd" IN_LIST DISABLED_PLATFORMS) - if(PLATFORM_FREEBSD) - set(ARTIFACT_OVERRIDE ON) - endif() - + if(PLATFORM_FREEBSD AND NOT "freebsd" IN_LIST DISABLED_PLATFORMS) add_ci_package(freebsd) - set(ARTIFACT_OVERRIDE OFF) endif() - if((PLATFORM_LINUX AND ARCHITECTURE_x86_64) OR ARTIFACT_FORCE_DOWNLOAD AND NOT "linux" IN_LIST DISABLED_PLATFORMS) - if(PLATFORM_LINUX AND ARCHITECTURE_x86_64) - set(ARTIFACT_OVERRIDE ON) - endif() - + if((PLATFORM_LINUX AND ARCHITECTURE_x86_64) AND NOT "linux" IN_LIST DISABLED_PLATFORMS) add_ci_package(linux) - set(ARTIFACT_OVERRIDE OFF) endif() - if((PLATFORM_LINUX AND ARCHITECTURE_arm64) OR ARTIFACT_FORCE_DOWNLOAD AND NOT "linux-aarch64" IN_LIST DISABLED_PLATFORMS) - if(PLATFORM_LINUX AND ARCHITECTURE_arm64) - set(ARTIFACT_OVERRIDE ON) - endif() - + if((PLATFORM_LINUX AND ARCHITECTURE_arm64) AND NOT "linux-aarch64" IN_LIST DISABLED_PLATFORMS) add_ci_package(linux-aarch64) - set(ARTIFACT_OVERRIDE OFF) endif() if (DEFINED ARTIFACT_DIR) - if (NOT DEFINED PKG_ARGS_TARGET OR NOT TARGET "${PKG_ARGS_TARGET}") - include(${ARTIFACT_DIR}/${ARTIFACT_CMAKE}.cmake) + include(${ARTIFACT_DIR}/${ARTIFACT_CMAKE}.cmake) - # Overrides find package - CPMAddPackage( - NAME ${ARTIFACT_PACKAGE} - SOURCE_DIR ${ARTIFACT_DIR} - ) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES ${ARTIFACT_NAME}) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS "https://github.com/${ARTIFACT_REPO}") # TODO(crueter) other hosts? + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS ${ARTIFACT_VERSION}) - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES ${ARTIFACT_NAME}) - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS "https://github.com/${ARTIFACT_REPO}") # TODO(crueter) other hosts? - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS ${ARTIFACT_VERSION}) - - set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE) - endif() + set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE) else() find_package(${ARTIFACT_PACKAGE} ${ARTIFACT_MIN_VERSION} REQUIRED) endif() diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake index 642d7d0df1..de45d15d2a 100644 --- a/CMakeModules/DownloadExternals.cmake +++ b/CMakeModules/DownloadExternals.cmake @@ -29,6 +29,7 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi set(package_url "${package_base_url}${package_repo}") set(full_url ${package_url}${remote_path}${lib_name}${package_extension}) + # TODO(crueter): DELETE THIS ENTIRELY, GLORY BE TO THE CI! AddPackage( NAME ${cpm_key} VERSION ${version} diff --git a/CMakeModules/FindSPIRV-Tools.cmake b/CMakeModules/FindSPIRV-Tools.cmake new file mode 100644 index 0000000000..aef74df5d9 --- /dev/null +++ b/CMakeModules/FindSPIRV-Tools.cmake @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2022 yuzu Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +include(FindPackageHandleStandardArgs) + +find_package(PkgConfig QUIET) +pkg_search_module(SPIRV-Tools QUIET IMPORTED_TARGET SPIRV-Tools) +find_package_handle_standard_args(SPIRV-Tools + REQUIRED_VARS SPIRV-Tools_LINK_LIBRARIES + VERSION_VAR SPIRV-Tools_VERSION +) + +if (SPIRV-Tools_FOUND AND NOT TARGET SPIRV-Tools::SPIRV-Tools) + if (TARGET SPIRV-Tools) + add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools) + else() + add_library(SPIRV-Tools::SPIRV-Tools ALIAS PkgConfig::SPIRV-Tools) + endif() +endif() diff --git a/CMakeModules/Findzstd.cmake b/CMakeModules/Findzstd.cmake index ae3ea08653..bf38d20fbf 100644 --- a/CMakeModules/Findzstd.cmake +++ b/CMakeModules/Findzstd.cmake @@ -3,17 +3,12 @@ include(FindPackageHandleStandardArgs) -find_package(zstd QUIET CONFIG) -if (zstd_CONSIDERED_CONFIGS) - find_package_handle_standard_args(zstd CONFIG_MODE) -else() - find_package(PkgConfig QUIET) - pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) - find_package_handle_standard_args(zstd - REQUIRED_VARS ZSTD_LINK_LIBRARIES - VERSION_VAR ZSTD_VERSION - ) -endif() +find_package(PkgConfig QUIET) +pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) +find_package_handle_standard_args(zstd + REQUIRED_VARS ZSTD_LINK_LIBRARIES + VERSION_VAR ZSTD_VERSION +) if (zstd_FOUND AND NOT TARGET zstd::zstd) if (TARGET zstd::libzstd_shared) diff --git a/cpmfile.json b/cpmfile.json new file mode 100644 index 0000000000..495382fed0 --- /dev/null +++ b/cpmfile.json @@ -0,0 +1,147 @@ +{ + "openssl": { + "ci": true, + "package": "OpenSSL", + "name": "openssl", + "repo": "crueter-ci/OpenSSL", + "version": "3.5.2", + "min_version": "1.1.1" + }, + "boost": { + "package": "Boost", + "repo": "boostorg/boost", + "tag": "boost-1.88.0", + "artifact": "boost-1.88.0-cmake.7z", + "hash": "e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01", + "git_version": "1.88.0", + "version": "1.57" + }, + "fmt": { + "repo": "fmtlib/fmt", + "sha": "40626af88b", + "hash": "d59f06c24339f223de4ec2afeba1c67b5835a0f350a1ffa86242a72fc3e616a6b8b21798355428d4200c75287308b66634619ffa0b52ba5bd74cc01772ea1a8a", + "version": "8", + "options": [ + "FMT_INSTALL OFF" + ] + }, + "lz4": { + "name": "lz4", + "repo": "lz4/lz4", + "sha": "ebb370ca83", + "hash": "43600e87b35256005c0f2498fa56a77de6783937ba4cfce38c099f27c03188d097863e8a50c5779ca0a7c63c29c4f7ed0ae526ec798c1fd2e3736861b62e0a37", + "source_subdir": "build/cmake" + }, + "nlohmann": { + "package": "nlohmann_json", + "repo": "nlohmann/json", + "sha": "55f93686c0", + "hash": "b739749b066800e21154506ea150d2c5cbce8a45344177f46f884547a1399d26753166fd0df8135269ce28cf223552b1b65cd625b88c844d54753f2434900486", + "version": "3.8" + }, + "zlib": { + "package": "ZLIB", + "repo": "madler/zlib", + "sha": "51b7f2abda", + "hash": "16eaf1f3752489d12fd9ce30f7b5f7cbd5cb8ff53d617005a9847ae72d937f65e01e68be747f62d7ac19fd0c9aeba9956e60f16d6b465c5fdc2f3d08b4db2e6c", + "version": "1.2", + "options": [ + "ZLIB_BUILD_SHARED OFF", + "ZLIB_INSTALL OFF" + ] + }, + "zstd": { + "repo": "facebook/zstd", + "sha": "f8745da6ff", + "hash": "3037007f990040fe32573b46f9bef8762fd5dbeeb07ffffcbfeba51ec98167edae39bb9c87f9299efcd61c4e467c5e84f7c19f0df7799bc1fc04864a278792ee", + "version": "1.5", + "source_subdir": "build/cmake", + "find_args": "MODULE", + "options": [ + "ZSTD_BUILD_SHARED OFF" + ] + }, + "catch2": { + "package": "Catch2", + "repo": "catchorg/Catch2", + "sha": "644821ce28", + "hash": "f8795f98acf2c02c0db8e734cc866d5caebab4b4a306e93598b97cb3c0c728dafe8283dce27ffe8d42460e5ae7302f3f32e7e274a7f991b73511ac88eef21b1f", + "version": "3.0.1" + }, + "enet": { + "repo": "lsalzman/enet", + "sha": "2662c0de09", + "hash": "3de1beb4fa3d6b1e03eda8dd1e7580694f854af3ed3975dcdabfdcdf76b97f322b9734d35ea7f185855bb490d957842b938b26da4dd2dfded509390f8d2794dd", + "version": "1.3", + "find_args": "MODULE" + }, + "opus": { + "package": "Opus", + "repo": "xiph/opus", + "sha": "5ded705cf4", + "hash": "0dc89e58ddda1f3bc6a7037963994770c5806c10e66f5cc55c59286fc76d0544fe4eca7626772b888fd719f434bc8a92f792bdb350c807968b2ac14cfc04b203", + "version": "1.3", + "find_args": "MODULE", + "options": [ + "OPUS_BUILD_TESTING OFF", + "OPUS_BUILD_PROGRAMS OFF", + "OPUS_INSTALL_PKG_CONFIG_MODULE OFF", + "OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF" + ] + }, + "cubeb": { + "repo": "mozilla/cubeb", + "sha": "fa02160712", + "hash": "82d808356752e4064de48c8fecbe7856715ade1e76b53937116bf07129fc1cc5b3de5e4b408de3cd000187ba8dc32ca4109661cb7e0355a52e54bd81b9be1c61", + "find_args": "CONFIG", + "options": [ + "USE_SANITIZERS OFF", + "BUILD_TESTS OFF", + "BUILD_TOOLS OFF", + "BUNDLE_SPEEX ON" + ] + }, + "boost_headers": { + "repo": "boostorg/headers", + "sha": "0456900fad", + "hash": "50cd75dcdfc5f082225cdace058f47b4fb114a47585f7aee1d22236a910a80b667186254c214fa2fcebac67ae6d37ba4b6e695e1faea8affd6fd42a03cf996e3", + "bundled": true + }, + "discord-rpc": { + "repo": "eden-emulator/discord-rpc", + "sha": "1cf7772bb6", + "hash": "e9b35e6f2c075823257bcd59f06fe7bb2ccce1976f44818d2e28810435ef79c712a3c4f20f40da41f691342a4058cf86b078eb7f9d9e4dae83c0547c21ec4f97" + }, + "simpleini": { + "package": "SimpleIni", + "repo": "brofield/simpleini", + "sha": "09c21bda1d", + "hash": "99779ca9b6e040d36558cadf484f9ffdab5b47bcc8fc72e4d33639d1d60c0ceb4410d335ba445d72a4324e455167fd6769d99b459943aa135bec085dff2d4b7c", + "find_args": "MODULE" + }, + "sdl2_generic": { + "package": "SDL2", + "repo": "libsdl-org/SDL", + "sha": "54772f345a", + "hash": "2a68a0e01c390043aa9d9df63d8a20a52076c88bb460ac4e0f33194ca7d9bc8fadbbcc04e7506872ac4b6354a73fbc267c036f82200da59465789b87c7d9e3a4", + "key": "generic", + "bundled": true + }, + "sdl2_steamdeck": { + "package": "SDL2", + "repo": "libsdl-org/SDL", + "sha": "cc016b0046", + "hash": "34d5ef58da6a4f9efa6689c82f67badcbd741f5a4f562a9c2c30828fa839830fb07681c5dc6a7851520e261c8405a416ac0a2c2513b51984fb3b4fa4dcb3e20b", + "key": "steamdeck", + "bundled": true + }, + "sdl2": { + "ci": true, + "package": "SDL2", + "name": "SDL2", + "repo": "crueter-ci/SDL2", + "version": "2.32.8", + "min_version": "2.26.4", + "cmake_filename": "sdl2" + } +} diff --git a/docs/CPM.md b/docs/CPM.md new file mode 100644 index 0000000000..f90002891c --- /dev/null +++ b/docs/CPM.md @@ -0,0 +1,252 @@ +# CPM + +CPM (CMake Package Manager) is the preferred method of managing dependencies within Eden. + +Global Options: + +- `YUZU_USE_CPM` is set by default on MSVC and Android. Other platforms should use this if certain "required" system dependencies (e.g. OpenSSL) are broken or missing + * If this is `OFF`, required system dependencies will be searched via `find_package`, although certain externals use CPM regardless. +- `CPMUTIL_FORCE_SYSTEM` (default `OFF`): Require all CPM dependencies to use system packages. NOT RECOMMENDED! + * Many packages, e.g. mcl, sirit, xbyak, discord-rpc, are not generally available as a system package. + * You may optionally override these (see CPMUtil section) +- `CPMUTIL_FORCE_BUNDLED` (default `ON` on MSVC and Android, `OFF` elsewhere): Require all CPM dependencies to use bundled packages. + +## CPMUtil + +CPMUtil is a wrapper around CPM that aims to reduce boilerplate and add useful utility functions to make dependency management a piece of cake. + +### AddPackage + +`AddPackage` is the core of the CPMUtil wrapper, and is generally the lowest level you will need to go when dealing with dependencies. + +**Identification/Fetching** + +- `NAME` (required): The package name (must be the same as the `find_package` name if applicable) +- `VERSION`: The minimum version of this package that can be used on the system +- `GIT_VERSION`: The version found within git, only used for identification +- `URL`: The URL to fetch. +- `REPO`: The GitHub repo to use (`owner/repo`). + * Only GitHub is supported for now, though other platforms will see support at some point +- `TAG`: The tag to fetch, if applicable. +- `ARTIFACT`: The name of the artifact, if applicable. +- `SHA`: Commit sha to fetch, if applicable. +- `BRANCH`: Branch to fetch, if applicable. + +The following configurations are supported, in descending order of precedence: + +- `URL`: Bare URL download, useful for custom artifacts + * If this is set, `GIT_URL` or `REPO` should be set to allow the dependency viewer to link to the project's Git repository. + * If this is NOT set, `REPO` must be defined. +- `REPO + TAG + ARTIFACT`: GitHub release artifact + * The final download URL will be `https://github.com/${REPO}/releases/download/${TAG}/${ARTIFACT}` + * Useful for prebuilt libraries and prefetched archives +- `REPO + TAG`: GitHub tag archive + * The final download URL will be `https://github.com/${REPO}/archive/refs/tags/${TAG}.tar.gz` + * Useful for pinning to a specific tag, better for build identification +- `REPO + SHA`: GitHub commit archive + * The final download URL will be `https://github.com/${REPO}/archive/${SHA}.zip` + * Useful for pinning to a specific commit +- `REPO + BRANCH`: GitHub branch archive + * The final download URL will be `https://github.com/${REPO}/archive/refs/heads/${BRANCH}.zip` + * Generally not recommended unless the branch is frozen +- `REPO`: GitHub master archive + * The final download URL will be `https://github.com/${REPO}/archive/refs/heads/master.zip` + * Generally not recommended unless the project is dead + +**Hashing** + +Hashing is used for verifying downloads. It's highly recommended to use these. + +- `HASH_ALGO` (default `SHA512`): Hash algorithm to use + +Hashing strategies, descending order of precedence: + +- `HASH`: Bare hash verification, useful for static downloads e.g. commit archives +- `HASH_SUFFIX`: Download the hash as `${DOWNLOAD_URL}.${HASH_SUFFIX}` + * The downloaded hash *must* match the hash algorithm and contain nothing but the hash; no filenames or extra content. +- `HASH_URL`: Download the hash from a separate URL + +**Additional Options** + +- `KEY`: Custom cache key to use (stored as `.cache/cpm/${packagename_lower}/${key}`) + * Default is based on, in descending order of precedence: + - First 4 characters of the sha + - `GIT_VERSION`, or `VERSION` if not specified + - Tag + - Otherwise, CPM defaults will be used. This is not recommended as it doesn't produce reproducible caches +- `DOWNLOAD_ONLY`: Whether or not to configure the downloaded package via CMake + * Useful to turn `OFF` if the project doesn't use CMake +- `SOURCE_SUBDIR`: Subdirectory of the project containing a CMakeLists.txt file +- `FIND_PACKAGE_ARGUMENTS`: Arguments to pass to the `find_package` call +- `BUNDLED_PACKAGE`: Set to `ON` to force the usage of a bundled package +- `OPTIONS`: Options to pass to the configuration of the package +- `PATCHES`: Patches to apply to the package, stored in `.patch/${packagename_lower}/0001-patch-name.patch` and so on +- Other arguments can be passed to CPM as well + +**Extra Variables** + +For each added package, users may additionally force usage of the system/bundled package. + +- `${package}_FORCE_SYSTEM`: Require the package to be installed on the system +- `${package}_FORCE_BUNDLED`: Force the package to be fetched and use the bundled version + +**Bundled/System Switching** + +Descending order of precedence: +- If `${package}_FORCE_SYSTEM` is true, requires the package to be on the system +- If `${package}_FORCE_BUNDLED` is true, forcefully uses the bundled package +- If `CPMUTIL_FORCE_SYSTEM` is true, requires the package to be on the system +- If `CPMUTIL_FORCE_BUNDLED` is true, forcefully uses the bundled package +- If the `BUNDLED_PACKAGE` argument is true, forcefully uses the bundled package +- Otherwise, CPM will search for the package first, and if not found, will use the bundled package + +**Identification** + +All dependencies must be identifiable in some way for usage in the dependency viewer. Lists are provided in descending order of precedence. + +URLs: + +- `GIT_URL` +- `REPO` as a GitHub repository +- `URL` + +Versions (bundled): + +- `SHA` +- `GIT_VERSION` +- `VERSION` +- `TAG` +- "unknown" + +If the package is a system package, AddPackage will attempt to determine the package version and append ` (system)` to the identifier. Otherwise, it will be marked as `unknown (system)` + +### AddCIPackage + +Adds a package that follows crueter's CI repository spec. + +- `VERSION` (required): The version to get (the tag will be `v${VERSION}`) +- `NAME` (required): Name used within the artifacts +- `REPO` (required): CI repository, e.g. `crueter-ci/OpenSSL` +- `PACKAGE` (required): `find_package` package name +- `EXTENSION`: Artifact extension (default `tar.zst`) +- `MIN_VERSION`: Minimum version for `find_package`. Only used if platform does not support this package as a bundled artifact +- `DISABLED_PLATFORMS`: List of platforms that lack artifacts for this package. One of: + * `windows-amd64` + * `windows-arm64` + * `android` + * `solaris` + * `freebsd` + * `linux` + * `linux-aarch64` +- `CMAKE_FILENAME`: Custom CMake filename, relative to the package root (default `${PACKAGE_ROOT}/${NAME}.cmake`) + +### AddJsonPackage + +This is the recommended method of usage for CPMUtil. In each directory that utilizes `CPMUtil`, there must be a `cpmfile.json` that defines dependencies in a similar manner to the individual calls. + +The cpmfile is an object of objects, with each sub-object being named according to the package's identifier, e.g. `openssl`, which can then be fetched with `AddJsonPackage()`. Options are designed to map closely to the argument names, and are always strings unless otherwise specified. + +- `package` -> `NAME` (`PACKAGE` for CI), defaults to the object key +- `repo` -> `REPO` +- `version` -> `VERSION` +- `ci` (bool) + +If `ci` is `false`: + +- `hash` -> `HASH` +- `sha` -> `SHA` +- `tag` -> `TAG` +- `artifact` -> `ARTIFACT` +- `git_version` -> `GIT_VERSION` +- `source_subdir` -> `SOURCE_SUBDIR` +- `bundled` -> `BUNDLED_PACKAGE` +- `find_args` -> `FIND_PACKAGE_ARGUMENTS` +- `patches` -> `PATCHES` (array) +- `options` -> `OPTIONS` (array) + +Other arguments aren't currently supported. If you wish to add them, see the `AddJsonPackage` function in `CMakeModules/CPMUtil.cmake`. + +If `ci` is `true`: + +- `name` -> `NAME`, defaults to the object key +- `extension` -> `EXTENSION`, defaults to `tar.zst` +- `min_version` -> `MIN_VERSION` +- `cmake_filename` -> `CMAKE_FILENAME` +- `extension` -> `EXTENSION` + +### Examples + +In order: OpenSSL CI, Boost (tag + artifact), discord-rpc (sha + options + patches), Opus (options + find_args) + +```json +{ + "openssl": { + "ci": true, + "package": "OpenSSL", + "name": "openssl", + "repo": "crueter-ci/OpenSSL", + "version": "3.5.2", + "min_version": "1.1.1" + }, + "boost": { + "package": "Boost", + "repo": "boostorg/boost", + "tag": "boost-1.88.0", + "artifact": "boost-1.88.0-cmake.7z", + "hash": "e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01", + "git_version": "1.88.0", + "version": "1.57" + }, + "opus": { + "package": "Opus", + "repo": "xiph/opus", + "sha": "5ded705cf4", + "hash": "0dc89e58ddda1f3bc6a7037963994770c5806c10e66f5cc55c59286fc76d0544fe4eca7626772b888fd719f434bc8a92f792bdb350c807968b2ac14cfc04b203", + "version": "1.3", + "find_args": "MODULE", + "options": [ + "OPUS_BUILD_TESTING OFF", + "OPUS_BUILD_PROGRAMS OFF", + "OPUS_INSTALL_PKG_CONFIG_MODULE OFF", + "OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF" + ] + }, + "discord-rpc": { + "repo": "discord/discord-rpc", + "sha": "963aa9f3e5", + "hash": "386e1344e9a666d730f2d335ee3aef1fd05b1039febefd51aa751b705009cc764411397f3ca08dffd46205c72f75b235c870c737b2091a4ed0c3b061f5919bde", + "options": [ + "BUILD_EXAMPLES OFF" + ], + "patches": [ + "0001-cmake-version.patch", + "0002-no-clang-format.patch", + "0003-fix-cpp17.patch" + ] + }, +} +``` + +### Inclusion + +To include CPMUtil: + +```cmake +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) +include(CPMUtil) +``` + +You may omit the first line if you are not utilizing cpmfile. + +## Prefetching + +- To prefetch a CPM dependency (requires cpmfile): + * `tools/cpm-fetch.sh ` +- To prefetch all CPM dependencies: + * `tools/cpm-fetch-all.sh` + +Currently, `cpm-fetch.sh` defines the following directories for cpmfiles: + +`externals src/yuzu/externals externals/ffmpeg src/dynarmic/externals externals/nx_tzdb` + +Whenever you add a new cpmfile, update the script accordingly \ No newline at end of file diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 07e9ae7a8f..b209b48db9 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -7,7 +7,8 @@ # TODO(crueter): A lot of this should be moved to the root. # otherwise we have to do weird shenanigans with library linking and stuff -# cpm +# Explicitly include CPMUtil here since we have a separate cpmfile for externals +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) include(CPMUtil) # Explicitly declare this option here to propagate to the oaknut CPM call @@ -33,32 +34,15 @@ endif() # Xbyak (also used by Dynarmic, so needs to be added first) if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) if (PLATFORM_SUN) - # Fix regset.h collisions - set(XBYAK_HASH 51f507b0b3) - set(XBYAK_SHA512SUM 4a29a3c2f97f7d5adf667a21a008be03c951fb6696b0d7ba27e7e4afa037bc76eb5e059bb84860e01baf741d4d3ac851b840cd54c99d038812fbe0f1fa6d38a4) + AddJsonPackage(xbyak_sun) else() - set(XBYAK_HASH 4e44f4614d) - set(XBYAK_SHA512SUM 5824e92159e07fa36a774aedd3b3ef3541d0241371d522cffa4ab3e1f215fa5097b1b77865b47b2481376c704fa079875557ea463ca63d0a7fd6a8a20a589e70) + AddJsonPackage(xbyak) endif() - - AddPackage( - NAME xbyak - REPO "Lizzie841/xbyak" - SHA ${XBYAK_HASH} - HASH ${XBYAK_SHA512SUM} - BUNDLED_PACKAGE ON - ) endif() # Oaknut (also used by Dynarmic, so needs to be added first) if (ARCHITECTURE_arm64 OR DYNARMIC_TESTS) - AddPackage( - NAME oaknut - VERSION 2.0.1 - REPO "merryhime/oaknut" - SHA 94c726ce03 - HASH d8d082242fa1881abce3c82f8dafa002c4e561e66a69e7fc038af67faa5eff2630f082d3d19579c88c4c9f9488e54552accc8cb90e7ce743efe043b6230c08ac - ) + AddJsonPackage(oaknut) endif() # getopt @@ -70,14 +54,7 @@ endif() add_subdirectory(glad) # mbedtls -AddPackage( - NAME mbedtls - REPO "Mbed-TLS/mbedtls" - SHA "8c88150ca1" - HASH 769ad1e94c570671071e1f2a5c0f1027e0bf6bcdd1a80ea8ac970f2c86bc45ce4e31aa88d6d8110fc1bed1de81c48bc624df1b38a26f8b340a44e109d784a966 - PATCHES - ${CMAKE_SOURCE_DIR}/.patch/mbedtls/0001-cmake-version.patch -) +AddJsonPackage(mbedtls) if (mbedtls_ADDED) target_include_directories(mbedtls PUBLIC ${mbedtls_SOURCE_DIR}/include) @@ -97,23 +74,11 @@ endif() # Sirit # TODO(crueter): spirv-tools doesn't work w/ system set(SPIRV_WERROR OFF) -AddPackage( - NAME SPIRV-Headers - REPO "KhronosGroup/SPIRV-Headers" - SHA 4e209d3d7e - HASH f48bbe18341ed55ea0fe280dbbbc0a44bf222278de6e716e143ca1e95ca320b06d4d23d6583fbf8d03e1428f3dac8fa00e5b82ddcd6b425e6236d85af09550a4 -) +AddJsonPackage(spirv-headers) -AddPackage( - NAME sirit - REPO "eden-emulator/sirit" - SHA db1f1e8ab5 - HASH 73eb3a042848c63a10656545797e85f40d142009dfb7827384548a385e1e28e1ac72f42b25924ce530d58275f8638554281e884d72f9c7aaf4ed08690a414b05 - OPTIONS - "SIRIT_USE_SYSTEM_SPIRV_HEADERS ON" -) +AddJsonPackage(sirit) -if(MSVC AND USE_CCACHE AND TARGET sirit) +if(MSVC AND USE_CCACHE AND sirit_ADDED) get_target_property(_opts sirit COMPILE_OPTIONS) list(FILTER _opts EXCLUDE REGEX "/Zi") list(APPEND _opts "/Z7") @@ -122,33 +87,12 @@ endif() # httplib if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER) - AddPackage( - NAME httplib - REPO "yhirose/cpp-httplib" - SHA a609330e4c - HASH dd3fd0572f8367d8549e1319fd98368b3e75801a293b0c3ac9b4adb806473a4506a484b3d389dc5bee5acc460cb90af7a20e5df705a1696b56496b30b9ce7ed2 - OPTIONS - "HTTPLIB_REQUIRE_OPENSSL ${ENABLE_OPENSSL}" - ) + AddJsonPackage(httplib) endif() # cpp-jwt if (ENABLE_WEB_SERVICE) - AddPackage( - NAME cpp-jwt - VERSION 1.4 - REPO "arun11299/cpp-jwt" - SHA a54fa08a3b - HASH a90f7e594ada0c7e49d5ff9211c71097534e7742a8e44bf0851b0362642a7271d53f5d83d04eeaae2bad17ef3f35e09e6818434d8eaefa038f3d1f7359d0969a - FIND_PACKAGE_ARGUMENTS "CONFIG" - OPTIONS - "CPP_JWT_BUILD_EXAMPLES OFF" - "CPP_JWT_BUILD_TESTS OFF" - "CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF" - PATCHES - ${CMAKE_SOURCE_DIR}/.patch/cpp-jwt/0001-no-install.patch - ${CMAKE_SOURCE_DIR}/.patch/cpp-jwt/0002-missing-decl.patch - ) + AddJsonPackage(cpp-jwt) endif() # unordered_dense @@ -175,47 +119,33 @@ endif() # TODO(crueter): Vk1.4 impl -AddPackage( - NAME VulkanHeaders - VERSION 1.3.274 - REPO "KhronosGroup/Vulkan-Headers" - SHA 89268a6d17 - HASH 3ab349f74298ba72cafb8561015690c0674d428a09fb91ccd3cd3daca83650d190d46d33fd97b0a8fd4223fe6df2bcabae89136fbbf7c0bfeb8776f9448304c8 +AddJsonPackage( + NAME vulkan-headers BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_HEADERS} ) # Vulkan-Utility-Libraries -AddPackage( - NAME VulkanUtilityLibraries - REPO "KhronosGroup/Vulkan-Utility-Libraries" - SHA df2e358152 - HASH 3e468c3d9ff93f6d418d71e5527abe0a12c8c7ab5b0b52278bbbee4d02bb87e99073906729b727e0147242b7e3fd5dedf68b803f1878cb4c0e4f730bc2238d79 +AddJsonPackage( + NAME vulkan-utility-libraries BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES} ) -# SPIRV-Tools -if (YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS) - AddPackage( - NAME SPIRV-Tools - REPO "KhronosGroup/SPIRV-Tools" - SHA 40eb301f32 - HASH 58d0fb1047d69373cf24c73e6f78c73a72a6cca3b4df1d9f083b9dcc0962745ef154abf3dbe9b3623b835be20c6ec769431cf11733349f45e7568b3525f707aa - OPTIONS - "SPIRV_SKIP_EXECUTABLES ON" - ) +# SPIRV Tools +AddJsonPackage( + NAME spirv-tools + BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS} +) + +if (SPIRV-Tools_ADDED) + add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static) + target_link_libraries(SPIRV-Tools-static PRIVATE SPIRV-Tools-opt SPIRV-Tools-link) endif() # TZDB (Time Zone Database) add_subdirectory(nx_tzdb) # VMA -AddPackage( - NAME VulkanMemoryAllocator - REPO "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator" - SHA 1076b348ab - HASH a46b44e4286d08cffda058e856c47f44c7fed3da55fe9555976eb3907fdcc20ead0b1860b0c38319cda01dbf9b1aa5d4b4038c7f1f8fbd97283d837fa9af9772 - FIND_PACKAGE_ARGUMENTS "CONFIG" -) +AddJsonPackage(vulkan-memory-allocator) if (NOT TARGET LLVM::Demangle) add_library(demangle demangle/ItaniumDemangle.cpp) @@ -245,17 +175,8 @@ if (NOT TARGET RenderDoc::API) add_library(RenderDoc::API ALIAS renderdoc) endif() -if (ANDROID) - if (ARCHITECTURE_arm64) - AddPackage( - NAME libadrenotools - REPO "bylaws/libadrenotools" - SHA 8fae8ce254 - HASH c74fa855f0edebbf25c9bce40b00966daa2447bfc5e15f0cf1a95f86cbf70fc6b02590707edbde16328a0a2a4fb9a1fc419d2dfc22a4a4150971be91892d4edb - PATCHES - ${CMAKE_SOURCE_DIR}/.patch/libadrenotools/0001-linkerns-cpm.patch - ) - endif() +if (ANDROID AND ARCHITECTURE_arm64) + AddJsonPackage(libadrenotools) endif() if (UNIX AND NOT APPLE AND NOT TARGET gamemode::headers) @@ -278,6 +199,7 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client) _CRT_NONSTDC_NO_DEPRECATE ) + # TODO AddPackage( NAME breakpad URL "google/breakpad" @@ -378,13 +300,7 @@ endif() # oboe if (ANDROID) - AddPackage( - NAME oboe - REPO "google/oboe" - SHA 2bc873e53c - HASH 02329058a7f9cf7d5039afaae5ab170d9f42f60f4c01e21eaf4f46073886922b057a9ae30eeac040b3ac182f51b9c1bfe9fe1050a2c9f6ce567a1a9a0ec2c768 - BUNDLED_PACKAGE ON - ) + AddJsonPackage(oboe) add_library(oboe::oboe ALIAS oboe) endif() diff --git a/externals/cpmfile.json b/externals/cpmfile.json new file mode 100644 index 0000000000..effcbcc01f --- /dev/null +++ b/externals/cpmfile.json @@ -0,0 +1,109 @@ +{ + "mbedtls": { + "repo": "Mbed-TLS/mbedtls", + "sha": "8c88150ca1", + "hash": "769ad1e94c570671071e1f2a5c0f1027e0bf6bcdd1a80ea8ac970f2c86bc45ce4e31aa88d6d8110fc1bed1de81c48bc624df1b38a26f8b340a44e109d784a966", + "patches": [ + "0001-cmake-version.patch" + ] + }, + "spirv-headers": { + "package": "SPIRV-Headers", + "repo": "KhronosGroup/SPIRV-Headers", + "sha": "4e209d3d7e", + "hash": "f48bbe18341ed55ea0fe280dbbbc0a44bf222278de6e716e143ca1e95ca320b06d4d23d6583fbf8d03e1428f3dac8fa00e5b82ddcd6b425e6236d85af09550a4" + }, + "sirit": { + "repo": "eden-emulator/sirit", + "sha": "db1f1e8ab5", + "hash": "73eb3a042848c63a10656545797e85f40d142009dfb7827384548a385e1e28e1ac72f42b25924ce530d58275f8638554281e884d72f9c7aaf4ed08690a414b05", + "options": [ + "SIRIT_USE_SYSTEM_SPIRV_HEADERS ON" + ] + }, + "httplib": { + "repo": "yhirose/cpp-httplib", + "sha": "a609330e4c", + "hash": "dd3fd0572f8367d8549e1319fd98368b3e75801a293b0c3ac9b4adb806473a4506a484b3d389dc5bee5acc460cb90af7a20e5df705a1696b56496b30b9ce7ed2" + }, + "cpp-jwt": { + "version": "1.4", + "repo": "arun11299/cpp-jwt", + "sha": "a54fa08a3b", + "hash": "a90f7e594ada0c7e49d5ff9211c71097534e7742a8e44bf0851b0362642a7271d53f5d83d04eeaae2bad17ef3f35e09e6818434d8eaefa038f3d1f7359d0969a", + "find_args": "CONFIG", + "options": [ + "CPP_JWT_BUILD_EXAMPLES OFF", + "CPP_JWT_BUILD_TESTS OFF", + "CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF" + ], + "patches": [ + "0001-no-install.patch", + "0002-missing-decl.patch" + ] + }, + "vulkan-headers": { + "package": "VulkanHeaders", + "version": "1.3.274", + "repo": "KhronosGroup/Vulkan-Headers", + "sha": "89268a6d17", + "hash": "3ab349f74298ba72cafb8561015690c0674d428a09fb91ccd3cd3daca83650d190d46d33fd97b0a8fd4223fe6df2bcabae89136fbbf7c0bfeb8776f9448304c8" + }, + "vulkan-utility-libraries": { + "package": "VulkanUtilityLibraries", + "repo": "KhronosGroup/Vulkan-Utility-Libraries", + "sha": "df2e358152", + "hash": "3e468c3d9ff93f6d418d71e5527abe0a12c8c7ab5b0b52278bbbee4d02bb87e99073906729b727e0147242b7e3fd5dedf68b803f1878cb4c0e4f730bc2238d79" + }, + "vulkan-memory-allocator": { + "package": "VulkanMemoryAllocator", + "repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator", + "sha": "1076b348ab", + "hash": "a46b44e4286d08cffda058e856c47f44c7fed3da55fe9555976eb3907fdcc20ead0b1860b0c38319cda01dbf9b1aa5d4b4038c7f1f8fbd97283d837fa9af9772", + "find_args": "CONFIG" + }, + "spirv-tools": { + "package": "SPIRV-Tools", + "repo": "KhronosGroup/SPIRV-Tools", + "sha": "40eb301f32", + "hash": "58d0fb1047d69373cf24c73e6f78c73a72a6cca3b4df1d9f083b9dcc0962745ef154abf3dbe9b3623b835be20c6ec769431cf11733349f45e7568b3525f707aa", + "find_args": "MODULE", + "options": [ + "SPIRV_SKIP_EXECUTABLES ON" + ] + }, + "xbyak_sun": { + "package": "xbyak", + "repo": "Lizzie841/xbyak", + "sha": "51f507b0b3", + "hash": "4a29a3c2f97f7d5adf667a21a008be03c951fb6696b0d7ba27e7e4afa037bc76eb5e059bb84860e01baf741d4d3ac851b840cd54c99d038812fbe0f1fa6d38a4", + "bundled": true + }, + "xbyak": { + "package": "xbyak", + "repo": "Lizzie841/xbyak", + "sha": "4e44f4614d", + "hash": "5824e92159e07fa36a774aedd3b3ef3541d0241371d522cffa4ab3e1f215fa5097b1b77865b47b2481376c704fa079875557ea463ca63d0a7fd6a8a20a589e70", + "bundled": true + }, + "oaknut": { + "version": "2.0.1", + "repo": "merryhime/oaknut", + "sha": "94c726ce03", + "hash": "d8d082242fa1881abce3c82f8dafa002c4e561e66a69e7fc038af67faa5eff2630f082d3d19579c88c4c9f9488e54552accc8cb90e7ce743efe043b6230c08ac" + }, + "libadrenotools": { + "repo": "bylaws/libadrenotools", + "sha": "8fae8ce254", + "hash": "c74fa855f0edebbf25c9bce40b00966daa2447bfc5e15f0cf1a95f86cbf70fc6b02590707edbde16328a0a2a4fb9a1fc419d2dfc22a4a4150971be91892d4edb", + "patches": [ + "0001-linkerns-cpm.patch" + ] + }, + "oboe": { + "repo": "google/oboe", + "sha": "2bc873e53c", + "hash": "02329058a7f9cf7d5039afaae5ab170d9f42f60f4c01e21eaf4f46073886922b057a9ae30eeac040b3ac182f51b9c1bfe9fe1050a2c9f6ce567a1a9a0ec2c768", + "bundled": true + } +} diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 048ab36c17..b514ede3be 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -1,6 +1,10 @@ # SPDX-FileCopyrightText: 2021 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +# Explicitly include CPMUtil here since we have a separate cpmfile for ffmpeg +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) +include(CPMUtil) + if (NOT WIN32 AND NOT ANDROID) # Build FFmpeg from externals message(STATUS "Using FFmpeg from externals") @@ -19,13 +23,7 @@ if (NOT WIN32 AND NOT ANDROID) message(FATAL_ERROR "Required program `autoconf` not found.") endif() - AddPackage( - NAME ffmpeg - REPO "FFmpeg/FFmpeg" - SHA c2184b65d2 - HASH 2a89d664119debbb3c006ab1c48d5d7f26e889f4a65ad2e25c8b0503308295123d5a9c5c78bf683aef5ff09acef8c3fc2837f22d3e8c611528b933bf03bcdd97 - SYSTEM_PACKAGE OFF - ) + AddJsonPackage(ffmpeg) set(FFmpeg_PREFIX ${ffmpeg_SOURCE_DIR}) set(FFmpeg_BUILD_DIR ${ffmpeg_BINARY_DIR}) diff --git a/externals/ffmpeg/cpmfile.json b/externals/ffmpeg/cpmfile.json new file mode 100644 index 0000000000..dd9179703e --- /dev/null +++ b/externals/ffmpeg/cpmfile.json @@ -0,0 +1,8 @@ +{ + "ffmpeg": { + "repo": "FFmpeg/FFmpeg", + "sha": "c2184b65d2", + "hash": "2a89d664119debbb3c006ab1c48d5d7f26e889f4a65ad2e25c8b0503308295123d5a9c5c78bf683aef5ff09acef8c3fc2837f22d3e8c611528b933bf03bcdd97", + "bundled": true + } +} diff --git a/externals/nx_tzdb/CMakeLists.txt b/externals/nx_tzdb/CMakeLists.txt index a86a97b4da..5812a62f98 100644 --- a/externals/nx_tzdb/CMakeLists.txt +++ b/externals/nx_tzdb/CMakeLists.txt @@ -1,6 +1,10 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +# Explicitly include CPMUtil here since we have a separate cpmfile for nx_tzdb +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) +include(CPMUtil) + set(NX_TZDB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include") add_library(nx_tzdb INTERFACE) @@ -28,28 +32,15 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID) endif() set(NX_TZDB_VERSION "250725") -set(NX_TZDB_ARCHIVE "${CPM_SOURCE_CACHE}/nx_tzdb/${NX_TZDB_VERSION}.zip") -set(NX_TZDB_ROMFS_DIR "${CPM_SOURCE_CACHE}/nx_tzdb/tz") +set(NX_TZDB_ROMFS_DIR "${CPM_SOURCE_CACHE}/nx_tzdb/") if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ROMFS_DIR}) - set(NX_TZDB_DOWNLOAD_URL "https://github.com/crueter/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip") - - message(STATUS "Downloading time zone data from ${NX_TZDB_DOWNLOAD_URL}...") - file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE} - STATUS NX_TZDB_DOWNLOAD_STATUS) - list(GET NX_TZDB_DOWNLOAD_STATUS 0 NX_TZDB_DOWNLOAD_STATUS_CODE) - if (NOT NX_TZDB_DOWNLOAD_STATUS_CODE EQUAL 0) - message(FATAL_ERROR "Time zone data download failed (status code ${NX_TZDB_DOWNLOAD_STATUS_CODE})") - endif() - - file(ARCHIVE_EXTRACT - INPUT - ${NX_TZDB_ARCHIVE} - DESTINATION - ${NX_TZDB_ROMFS_DIR}) + message(STATUS "Downloading time zone data...") + AddJsonPackage(tzdb) elseif (CAN_BUILD_NX_TZDB AND NOT YUZU_DOWNLOAD_TIME_ZONE_DATA) # TODO(crueter): this sucked to do with cpm, see if i can get it to work again + message(FATAL_ERROR "Building tzdb is currently unsupported. Check back later.") add_subdirectory(tzdb_to_nx) add_dependencies(nx_tzdb x80e) @@ -79,24 +70,24 @@ function(CreateHeader ZONE_PATH HEADER_NAME) endfunction() CreateHeader(${NX_TZDB_ROMFS_DIR} base) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo zoneinfo) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Africa africa) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America america) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Argentina america_argentina) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Indiana america_indiana) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Kentucky america_kentucky) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/North_Dakota america_north_dakota) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Antarctica antarctica) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Arctic arctic) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Asia asia) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Atlantic atlantic) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Australia australia) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Brazil brazil) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Canada canada) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Chile chile) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Etc etc) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Europe europe) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Indian indian) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Mexico mexico) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Pacific pacific) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/US us) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION} zoneinfo) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Africa africa) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America america) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/Argentina america_argentina) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/Indiana america_indiana) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/Kentucky america_kentucky) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/North_Dakota america_north_dakota) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Antarctica antarctica) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Arctic arctic) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Asia asia) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Atlantic atlantic) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Australia australia) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Brazil brazil) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Canada canada) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Chile chile) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Etc etc) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Europe europe) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Indian indian) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Mexico mexico) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Pacific pacific) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/US us) diff --git a/externals/nx_tzdb/cpmfile.json b/externals/nx_tzdb/cpmfile.json new file mode 100644 index 0000000000..fc7dd77628 --- /dev/null +++ b/externals/nx_tzdb/cpmfile.json @@ -0,0 +1,8 @@ +{ + "tzdb": { + "package": "nx_tzdb", + "url": "https://github.com/crueter/tzdb_to_nx/releases/download/250725/250725.zip", + "hash": "8f60b4b29f285e39c0443f3d5572a73780f3dbfcfd5b35004451fadad77f3a215b2e2aa8d0fffe7e348e2a7b0660882b35228b6178dda8804a14ce44509fd2ca", + "version": "250725" + } +} diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 0cbb29b01b..d907284bb7 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -175,7 +175,10 @@ android { "-DYUZU_USE_CPM=ON", "-DYUZU_USE_BUNDLED_FFMPEG=ON", "-DYUZU_ENABLE_LTO=ON", - "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", + "-DBUILD_TESTING=OFF", + "-DYUZU_TESTS=OFF", + "-DDYNARMIC_TESTS=OFF" ) abiFilters("arm64-v8a") diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index cbe1d35fc5..6173e29f45 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -272,13 +272,7 @@ if (lz4_ADDED) endif() target_link_libraries(common PUBLIC fmt::fmt stb::headers Threads::Threads) -target_link_libraries(common PRIVATE lz4::lz4 LLVM::Demangle) - -if (TARGET libzstd_static) - target_link_libraries(common PRIVATE libzstd_static) -else() - target_link_libraries(common PRIVATE zstd) -endif() +target_link_libraries(common PRIVATE lz4::lz4 LLVM::Demangle zstd::zstd) if (TARGET unordered_dense::unordered_dense) # weird quirk of system installs diff --git a/src/dynarmic/externals/CMakeLists.txt b/src/dynarmic/externals/CMakeLists.txt index 072558a618..23cfd42236 100644 --- a/src/dynarmic/externals/CMakeLists.txt +++ b/src/dynarmic/externals/CMakeLists.txt @@ -1,11 +1,11 @@ +# Explicitly include CPMUtil here since we have a separate cpmfile for dynarmic +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) include(CPMUtil) # Always build externals as static libraries, even when dynarmic is built as shared -if (BUILD_SHARED_LIBS) - set(BUILD_SHARED_LIBS OFF) - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON) -endif() +set(BUILD_SHARED_LIBS OFF) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON) # Allow options shadowing with normal variables when subproject use old cmake policy set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) @@ -22,42 +22,32 @@ set(BUILD_TESTING OFF) if ("riscv" IN_LIST ARCHITECTURE) add_subdirectory(biscuit) - AddPackage( + AddJsonPackage( NAME biscuit - VERSION 0.9.1 - REPO "lioncash/biscuit" - SHA 76b0be8dae - HASH 47d55ed02d032d6cf3dc107c6c0a9aea686d5f25aefb81d1af91db027b6815bd5add1755505e19d76625feeb17aa2db6cd1668fe0dad2e6a411519bde6ca4489 BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) endif() # catch -# TODO(crueter): dedup -if (NOT TARGET Catch2::Catch2WithMain) - if (DYNARMIC_TESTS) - find_package(Catch2 3.0.1 REQUIRED) - endif() -endif() +# if (NOT TARGET Catch2::Catch2WithMain) +# if (DYNARMIC_TESTS) +# find_package(Catch2 3.0.1 REQUIRED) +# endif() +# endif() # fmt -if (NOT TARGET fmt::fmt) - # fmtlib formatting library - set(FMT_INSTALL ON) - add_subdirectory(fmt) -endif() +# if (NOT TARGET fmt::fmt) +# # fmtlib formatting library +# set(FMT_INSTALL ON) +# add_subdirectory(fmt) +# endif() # mcl -AddPackage( +AddJsonPackage( NAME mcl - VERSION 0.1.12 - REPO "azahar-emu/mcl" - SHA 7b08d83418 - HASH f943bac39c1879986decad7a442ff4288eaeca4a2907684c7914e115a55ecc43c2782ded85c0835763fe04e40d5c82220ce864423e489e648e408a84f54dc4f3 - OPTIONS - "MCL_INSTALL OFF" + BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) # oaknut @@ -72,14 +62,9 @@ AddPackage( # unordered_dense -AddPackage( - NAME unordered_dense - REPO "Lizzie841/unordered_dense" - SHA e59d30b7b1 - HASH 71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0 - FIND_PACKAGE_ARGUMENTS "CONFIG" - OPTIONS - "UNORDERED_DENSE_INSTALL OFF" +AddJsonPackage( + NAME unordered-dense + BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) # xbyak @@ -95,31 +80,12 @@ AddPackage( # TODO(crueter): maybe it's just Gentoo but zydis system package really sucks if ("x86_64" IN_LIST ARCHITECTURE) + set(CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON) # TODO(crueter): system zycore doesn't work with zydis - AddPackage( - NAME Zycore - REPO "zyantific/zycore-c" - SHA 75a36c45ae - HASH 15aa399f39713e042c4345bc3175c82f14dca849fde2a21d4f591f62c43e227b70d868d8bb86beb5f4eb68b1d6bd3792cdd638acf89009e787e3d10ee7401924 - OPTIONS - "CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON" - EXCLUDE_FROM_ALL ON - SYSTEM_PACKAGE OFF - ) + AddJsonPackage(zycore) - AddPackage( - NAME Zydis - VERSION 4 - REPO "zyantific/zydis" - SHA c2d2bab025 - HASH 7b48f213ff7aab2926f8c9c65195959143bebbfb2b9a25051ffd8b8b0f1baf1670d9739781de674577d955925f91ac89376e16b476a03828c84e2fd765d45020 - FIND_PACKAGE_ARGUMENTS "CONFIG" - OPTIONS - "ZYDIS_BUILD_TOOLS OFF" - "ZYDIS_BUILD_EXAMPLES OFF" - "ZYDIS_BUILD_DOXYGEN OFF" - "ZYAN_SYSTEM_ZYCORE ON" - "CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON" - EXCLUDE_FROM_ALL ON + AddJsonPackage( + NAME zydis + BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) endif() diff --git a/src/dynarmic/externals/cpmfile.json b/src/dynarmic/externals/cpmfile.json new file mode 100644 index 0000000000..b934856af2 --- /dev/null +++ b/src/dynarmic/externals/cpmfile.json @@ -0,0 +1,47 @@ +{ + "biscuit": { + "version": "0.9.1", + "repo": "lioncash/biscuit", + "sha": "76b0be8dae", + "hash": "47d55ed02d032d6cf3dc107c6c0a9aea686d5f25aefb81d1af91db027b6815bd5add1755505e19d76625feeb17aa2db6cd1668fe0dad2e6a411519bde6ca4489" + }, + "mcl": { + "version": "0.1.12", + "repo": "azahar-emu/mcl", + "sha": "7b08d83418", + "hash": "f943bac39c1879986decad7a442ff4288eaeca4a2907684c7914e115a55ecc43c2782ded85c0835763fe04e40d5c82220ce864423e489e648e408a84f54dc4f3", + "options": [ + "MCL_INSTALL OFF" + ] + }, + "unordered-dense": { + "package": "unordered_dense", + "repo": "Lizzie841/unordered_dense", + "sha": "e59d30b7b1", + "hash": "71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0", + "find_args": "CONFIG", + "options": [ + "UNORDERED_DENSE_INSTALL OFF" + ] + }, + "zycore": { + "package": "Zycore", + "repo": "zyantific/zycore-c", + "sha": "75a36c45ae", + "hash": "15aa399f39713e042c4345bc3175c82f14dca849fde2a21d4f591f62c43e227b70d868d8bb86beb5f4eb68b1d6bd3792cdd638acf89009e787e3d10ee7401924", + "bundled": true + }, + "zydis": { + "package": "Zydis", + "version": "4", + "repo": "zyantific/zydis", + "sha": "c2d2bab025", + "hash": "7b48f213ff7aab2926f8c9c65195959143bebbfb2b9a25051ffd8b8b0f1baf1670d9739781de674577d955925f91ac89376e16b476a03828c84e2fd765d45020", + "options": [ + "ZYDIS_BUILD_TOOLS OFF", + "ZYDIS_BUILD_EXAMPLES OFF", + "ZYDIS_BUILD_DOXYGEN OFF", + "ZYAN_SYSTEM_ZYCORE ON" + ] + } +} diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 5d896db93d..55cdc17c1f 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -246,7 +246,7 @@ add_library(shader_recompiler STATIC ) -target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit SPIRV-Tools-opt SPIRV-Tools SPIRV-Tools-link) +target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit SPIRV-Tools::SPIRV-Tools) if (MSVC) target_compile_options(shader_recompiler PRIVATE diff --git a/src/yuzu/externals/CMakeLists.txt b/src/yuzu/externals/CMakeLists.txt index d7f3f1457a..7de41f6dfd 100644 --- a/src/yuzu/externals/CMakeLists.txt +++ b/src/yuzu/externals/CMakeLists.txt @@ -1,7 +1,8 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -# cpm +# Explicitly include CPMUtil here since we have a separate cpmfile for Qt externals +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) include(CPMUtil) # Disable tests/tools in all externals supporting the standard option name @@ -14,12 +15,4 @@ set(BUILD_SHARED_LIBS OFF) set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON) # QuaZip -AddPackage( - NAME QuaZip-Qt6 - VERSION 1.3 - REPO "crueter/quazip-qt6" - SHA f838774d63 - HASH 9f629a438699801244a106c8df6d5f8f8d19e80df54f530a89403a10c8c4e37a6e95606bbdd307f23636961e8ce34eb37a2186d589a1f227ac9c8e2c678e326e - OPTIONS - "QUAZIP_INSTALL OFF" -) +AddJsonPackage(quazip) diff --git a/src/yuzu/externals/cpmfile.json b/src/yuzu/externals/cpmfile.json new file mode 100644 index 0000000000..e3590d0f7f --- /dev/null +++ b/src/yuzu/externals/cpmfile.json @@ -0,0 +1,12 @@ +{ + "quazip": { + "package": "QuaZip-Qt6", + "repo": "crueter/quazip-qt6", + "sha": "f838774d63", + "hash": "9f629a438699801244a106c8df6d5f8f8d19e80df54f530a89403a10c8c4e37a6e95606bbdd307f23636961e8ce34eb37a2186d589a1f227ac9c8e2c678e326e", + "version": "1.3", + "options": [ + "QUAZIP_INSTALL OFF" + ] + } +} diff --git a/tools/cpm-fetch-all.sh b/tools/cpm-fetch-all.sh new file mode 100755 index 0000000000..38f7b1f941 --- /dev/null +++ b/tools/cpm-fetch-all.sh @@ -0,0 +1,10 @@ +#!/bin/bash -e + +# SPDX-FileCopyrightText: 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +LIBS=$(find . externals externals/nx_tzdb src/yuzu/externals externals/ffmpeg src/dynarmic/externals -maxdepth 1 -name cpmfile.json -exec jq -j 'keys_unsorted | join(" ")' {} \; -printf " ") +tools/cpm-fetch.sh $LIBS \ No newline at end of file diff --git a/tools/cpm-fetch.sh b/tools/cpm-fetch.sh new file mode 100755 index 0000000000..1c2ce007d2 --- /dev/null +++ b/tools/cpm-fetch.sh @@ -0,0 +1,198 @@ +#!/bin/bash -e + +# SPDX-FileCopyrightText: 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +[ -z "$CPM_SOURCE_CACHE" ] && CPM_SOURCE_CACHE=$PWD/.cache/cpm + +mkdir -p $CPM_SOURCE_CACHE + +ROOTDIR="$PWD" + +TMP=$(mktemp -d) + +download_package() { + FILENAME=$(basename "$DOWNLOAD") + + OUTFILE="$TMP/$FILENAME" + + LOWER_PACKAGE=$(tr '[:upper:]' '[:lower:]' <<< "$PACKAGE_NAME") + OUTDIR="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}/${KEY}" + [ -d "$OUTDIR" ] && return + + curl "$DOWNLOAD" -sS -L -o "$OUTFILE" + + ACTUAL_HASH=$(${HASH_ALGO}sum "$OUTFILE" | cut -d" " -f1) + [ "$ACTUAL_HASH" != "$HASH" ] && echo "$FILENAME did not match expected hash; expected $HASH but got $ACTUAL_HASH" && exit 1 + + mkdir -p "$OUTDIR" + + pushd "$OUTDIR" > /dev/null + + case "$FILENAME" in + (*.7z) + 7z x "$OUTFILE" > /dev/null + ;; + (*.tar*) + tar xf "$OUTFILE" > /dev/null + ;; + (*.zip) + unzip "$OUTFILE" > /dev/null + ;; + esac + + # basically if only one real item exists at the top we just move everything from there + # since github and some vendors hate me + DIRS=$(find -maxdepth 1 -type d -o -type f) + + # thanks gnu + if [ $(wc -l <<< "$DIRS") -eq 2 ]; then + SUBDIR=$(find . -maxdepth 1 -type d -not -name ".") + mv "$SUBDIR"/* . + mv "$SUBDIR"/.* . 2>/dev/null || true + rmdir "$SUBDIR" + fi + + if grep -e "patches" <<< "$JSON" > /dev/null; then + PATCHES=$(jq -r '.patches | join(" ")' <<< "$JSON") + for patch in $PATCHES; do + patch -p1 < "$ROOTDIR"/.patch/$package/$patch + done + fi + + popd > /dev/null +} + +ci_package() { + REPO=$(jq -r ".repo" <<< "$JSON") + EXT=$(jq -r '.extension' <<< "$JSON") + [ "$EXT" == null ] && EXT="tar.zst" + + VERSION=$(jq -r ".version" <<< "$JSON") + NAME=$(jq -r ".name | \"$package\"" <<< "$JSON") + PACKAGE=$(jq -r ".package | \"$package\"" <<< "$JSON") + + # TODO(crueter) + # DISABLED=$(jq -j '.disabled_platforms | join(" ")' <<< "$JSON") + + [ "$REPO" == null ] && echo "No repo defined for CI package $package" && return + + echo "CI package $PACKAGE" + + for platform in windows-amd64 windows-arm64 android solaris freebsd linux linux-aarch64; do + FILENAME="${NAME}-${platform}-${VERSION}.${EXT}" + DOWNLOAD="https://github.com/${REPO}/releases/download/v${VERSION}/${FILENAME}" + PACKAGE_NAME="$PACKAGE" + KEY=$platform + + echo "- platform $KEY" + + HASH_ALGO=$(jq -r ".hash_algo" <<< "$JSON") + [ "$HASH_ALGO" == null ] && HASH_ALGO=sha512 + + HASH_SUFFIX="${HASH_ALGO}sum" + HASH_URL="${DOWNLOAD}.${HASH_SUFFIX}" + + HASH=$(curl "$HASH_URL" -sS -q -L -o -) + + download_package + done +} + +for package in $@ +do + # prepare for cancer + JSON=$(find . externals src/yuzu/externals externals/ffmpeg src/dynarmic/externals externals/nx_tzdb -maxdepth 1 -name cpmfile.json -exec jq -r ".\"$package\" | select( . != null )" {} \;) + + [ -z "$JSON" ] && echo "No cpmfile definition for $package" && continue + + PACKAGE_NAME=$(jq -r ".package" <<< "$JSON") + [ "$PACKAGE_NAME" == null ] && PACKAGE_NAME="$package" + + CI=$(jq -r ".ci" <<< "$JSON") + if [ "$CI" != null ]; then + ci_package + continue + fi + + # url parsing WOOOHOOHOHOOHOHOH + URL=$(jq -r ".url" <<< "$JSON") + REPO=$(jq -r ".repo" <<< "$JSON") + SHA=$(jq -r ".sha" <<< "$JSON") + + if [ "$URL" != "null" ]; then + DOWNLOAD="$URL" + elif [ "$REPO" != "null" ]; then + GIT_URL="https://github.com/$REPO" + + TAG=$(jq -r ".tag" <<< "$JSON") + ARTIFACT=$(jq -r ".artifact" <<< "$JSON") + BRANCH=$(jq -r ".branch" <<< "$JSON") + + if [ "$TAG" != "null" ]; then + if [ "$ARTIFACT" != "null" ]; then + DOWNLOAD="${GIT_URL}/releases/download/${TAG}/${ARTIFACT}" + else + DOWNLOAD="${GIT_URL}/archive/refs/tags/${TAG}.tar.gz" + fi + elif [ "$SHA" != "null" ]; then + DOWNLOAD="${GIT_URL}/archive/${SHA}.zip" + else + if [ "$BRANCH" == null ]; then + BRANCH=master + fi + + DOWNLOAD="${GIT_URL}/archive/refs/heads/${BRANCH}.zip" + fi + else + echo "No repo or URL defined for $package" + continue + fi + + # key parsing + KEY=$(jq -r ".key" <<< "$JSON") + + if [ "$KEY" == null ]; then + VERSION=$(jq -r ".version" <<< "$JSON") + GIT_VERSION=$(jq -r ".git_version" <<< "$JSON") + + if [ "$SHA" != null ]; then + KEY=$(cut -c1-4 - <<< "$SHA") + elif [ "$GIT_VERSION" != null ]; then + KEY="$GIT_VERSION" + elif [ "$VERSION" != null ]; then + KEY="$VERSION" + else + echo "No valid key could be determined for $package. Must define one of: key, sha, version, git_version" + continue + fi + fi + + echo $KEY + + echo "Downloading regular package $package, with key $KEY, from $DOWNLOAD" + + # hash parsing + HASH_ALGO=$(jq -r ".hash_algo" <<< "$JSON") + [ "$HASH_ALGO" == null ] && HASH_ALGO=sha512 + + HASH=$(jq -r ".hash" <<< "$JSON") + + if [ "$HASH" == null ]; then + HASH_SUFFIX="${HASH_ALGO}sum" + HASH_URL=$(jq -r ".hash_url" <<< "$JSON") + + if [ "$HASH_URL" == null ]; then + HASH_URL="${DOWNLOAD}.${HASH_SUFFIX}" + fi + + HASH=$(curl "$HASH_URL" -L -o -) + fi + + download_package +done + +rm -rf $TMP \ No newline at end of file From 7f42d111768865d3bddb22c0ee2b7450290f34b9 Mon Sep 17 00:00:00 2001 From: crueter Date: Fri, 29 Aug 2025 01:35:01 +0200 Subject: [PATCH 19/44] [cmake] properly invalidate tzdb cache; require matching version (#346) Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/346 Reviewed-by: CamilleLaVey --- externals/nx_tzdb/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/externals/nx_tzdb/CMakeLists.txt b/externals/nx_tzdb/CMakeLists.txt index 5812a62f98..2d6b2fcc66 100644 --- a/externals/nx_tzdb/CMakeLists.txt +++ b/externals/nx_tzdb/CMakeLists.txt @@ -32,10 +32,9 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID) endif() set(NX_TZDB_VERSION "250725") +set(NX_TZDB_ROMFS_DIR "${CPM_SOURCE_CACHE}/nx_tzdb") -set(NX_TZDB_ROMFS_DIR "${CPM_SOURCE_CACHE}/nx_tzdb/") - -if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ROMFS_DIR}) +if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}) message(STATUS "Downloading time zone data...") AddJsonPackage(tzdb) elseif (CAN_BUILD_NX_TZDB AND NOT YUZU_DOWNLOAD_TIME_ZONE_DATA) From 5553f438d12cfed0a95bb927df7e7decc0e76d9a Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Fri, 29 Aug 2025 01:49:20 +0200 Subject: [PATCH 20/44] [ffmpeg] proper drm inclusion (#328) * this fixes build on ubuntu 25.04 Signed-off-by: Caio Oliveira Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/328 Reviewed-by: CamilleLaVey Co-authored-by: Caio Oliveira Co-committed-by: Caio Oliveira --- docs/build/Linux.md | 2 +- externals/ffmpeg/CMakeLists.txt | 35 ++++++++++++++++++++++----------- src/yuzu/CMakeLists.txt | 5 ----- src/yuzu_cmd/CMakeLists.txt | 5 ----- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/docs/build/Linux.md b/docs/build/Linux.md index ab653dad00..be58b451fa 100644 --- a/docs/build/Linux.md +++ b/docs/build/Linux.md @@ -37,7 +37,7 @@ Dependencies are listed here as commands that can be copied/pasted. Of course, t - GCC 11 or later is required. - Ubuntu / Linux Mint / Debian: - - `sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev` + - `sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev` - Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required. - Users need to manually specify building with QT Web Engine enabled. This is done using the parameter `-DYUZU_USE_QT_WEB_ENGINE=ON` when running CMake. - Users need to manually disable building SDL2 from externals if they intend to use the version provided by their system by adding the parameters `-DYUZU_USE_EXTERNAL_SDL2=OFF` diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index b514ede3be..54c852f831 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -63,32 +63,44 @@ if (NOT WIN32 AND NOT ANDROID) set(FFmpeg_HWACCEL_INCLUDE_DIRS) set(FFmpeg_HWACCEL_LDFLAGS) - if(LIBVA_FOUND) + # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so + if(PLATFORM_SUN) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + X11 + "/usr/lib/xorg/amd64/libdrm.so") + else() pkg_check_modules(LIBDRM libdrm REQUIRED) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + ${LIBDRM_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS + ${LIBDRM_INCLUDE_DIRS}) + endif() + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-libdrm) + + if(LIBVA_FOUND) find_package(X11 REQUIRED) pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) list(APPEND FFmpeg_HWACCEL_LIBRARIES - ${LIBDRM_LIBRARIES} ${X11_LIBRARIES} ${LIBVA-DRM_LIBRARIES} ${LIBVA-X11_LIBRARIES} ${LIBVA_LIBRARIES}) - set(FFmpeg_HWACCEL_FLAGS + list(APPEND FFmpeg_HWACCEL_FLAGS --enable-hwaccel=h264_vaapi --enable-hwaccel=vp8_vaapi - --enable-hwaccel=vp9_vaapi - --enable-libdrm) + --enable-hwaccel=vp9_vaapi) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS - ${LIBDRM_INCLUDE_DIRS} ${X11_INCLUDE_DIRS} ${LIBVA-DRM_INCLUDE_DIRS} ${LIBVA-X11_INCLUDE_DIRS} ${LIBVA_INCLUDE_DIRS} ) - message(STATUS "VA-API found") + message(STATUS "ffmpeg: va-api libraries version ${LIBVA_VERSION} found") else() - set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) + list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi) + message(WARNING "ffmpeg: libva-dev not found, disabling Video Aceleraion API (VA-API)...") endif() if (FFNVCODEC_FOUND) @@ -103,7 +115,7 @@ if (NOT WIN32 AND NOT ANDROID) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS}) - message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") + message(STATUS "ffmpeg: ffnvcodec libraries version ${FFNVCODEC_VERSION} found") # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress # here we handle the hard-linking senario where CUDA is linked during compilation if (CUDA_FOUND) @@ -112,7 +124,7 @@ if (NOT WIN32 AND NOT ANDROID) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS}) - message(STATUS "CUDA libraries found, hard-linking will be performed") + message(STATUS "ffmpeg: CUDA libraries found, hard-linking will be performed") endif(CUDA_FOUND) endif() @@ -125,9 +137,10 @@ if (NOT WIN32 AND NOT ANDROID) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS}) - message(STATUS "vdpau libraries version ${VDPAU_VERSION} found") + message(STATUS "ffmpeg: vdpau libraries version ${VDPAU_VERSION} found") else() list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau) + message(WARNING "ffmpeg: libvdpau-dev not found, disabling Video Decode and Presentation API for Unix (VDPAU)...") endif() find_program(BASH_PROGRAM bash REQUIRED) diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index f979a5c181..0ce8f3b898 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -501,11 +501,6 @@ if (YUZU_ROOM) target_link_libraries(yuzu PRIVATE yuzu-room) endif() -# Explicit linking required -if (PLATFORM_SUN) - target_link_libraries(yuzu PRIVATE X11 "/usr/lib/xorg/amd64/libdrm.so") -endif() - # Extra deps add_subdirectory(externals) target_link_libraries(yuzu PRIVATE QuaZip::QuaZip) diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index afd003a86c..ebd8fd7387 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -40,11 +40,6 @@ target_include_directories(yuzu-cmd PRIVATE ${RESOURCES_DIR}) target_link_libraries(yuzu-cmd PRIVATE SDL2::SDL2 Vulkan::Headers) -# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so -if (PLATFORM_SUN) - target_link_libraries(yuzu-cmd PRIVATE X11 "/usr/lib/xorg/amd64/libdrm.so") -endif() - if(UNIX AND NOT APPLE) install(TARGETS yuzu-cmd) endif() From 3247c53a5562b582ad1d3fa0e3a70f98f3cf8a76 Mon Sep 17 00:00:00 2001 From: MaranBr Date: Fri, 29 Aug 2025 14:20:22 +0200 Subject: [PATCH 21/44] [host_memory] Fix a bunch of memory errors on Windows (#303) This fixes a bunch of memory errors that could happen on Windows. Possibly regression introduced on PR 187. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/303 Reviewed-by: CamilleLaVey Co-authored-by: MaranBr Co-committed-by: MaranBr --- src/common/host_memory.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index f847ea2a62..edb64de8ec 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -417,11 +417,15 @@ static void* ChooseVirtualBase(size_t virtual_size) { #else static void* ChooseVirtualBase(size_t virtual_size) { +#if defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0); - if (virtual_base != MAP_FAILED) + + if (virtual_base != MAP_FAILED) { return virtual_base; - return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); + } +#endif + + return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); } #endif From 5317775538585c3475a9718971a32fee01ca791c Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 06:27:30 +0200 Subject: [PATCH 22/44] [cmake] fix nx_tzdb msvc link error (tmp) (#356) This is an incredibly stupid and nonsensical bug that I have no way of possibly explaining. This is a temporary workaround until I can reproduce it and figure it out. Otherwise MSVC linker crashes during final link phase. thanks microsoft Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/356 Reviewed-by: Shinmegumi Reviewed-by: CamilleLaVey Co-authored-by: crueter Co-committed-by: crueter --- externals/nx_tzdb/CMakeLists.txt | 108 +++++++++++++++++++------------ src/common/ring_buffer.h | 1 + 2 files changed, 68 insertions(+), 41 deletions(-) diff --git a/externals/nx_tzdb/CMakeLists.txt b/externals/nx_tzdb/CMakeLists.txt index 2d6b2fcc66..35d3e6d2a8 100644 --- a/externals/nx_tzdb/CMakeLists.txt +++ b/externals/nx_tzdb/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later @@ -15,35 +18,58 @@ find_program(DATE_PROG date) set(CAN_BUILD_NX_TZDB true) -if (NOT GIT) - set(CAN_BUILD_NX_TZDB false) -endif() -if (NOT GNU_MAKE) - set(CAN_BUILD_NX_TZDB false) -endif() -if (NOT DATE_PROG) - set(CAN_BUILD_NX_TZDB false) -endif() -if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID) +if (NOT (GIT AND GNU_MAKE AND DATE_PROG) OR CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID) # tzdb_to_nx currently requires a posix-compliant host # MinGW and Android are handled here due to the executable format being different from the host system # TODO (lat9nq): cross-compiling support + set(CAN_BUILD_NX_TZDB false) endif() -set(NX_TZDB_VERSION "250725") -set(NX_TZDB_ROMFS_DIR "${CPM_SOURCE_CACHE}/nx_tzdb") - -if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}) - message(STATUS "Downloading time zone data...") - AddJsonPackage(tzdb) -elseif (CAN_BUILD_NX_TZDB AND NOT YUZU_DOWNLOAD_TIME_ZONE_DATA) - # TODO(crueter): this sucked to do with cpm, see if i can get it to work again +if (CAN_BUILD_NX_TZDB AND NOT YUZU_DOWNLOAD_TIME_ZONE_DATA) message(FATAL_ERROR "Building tzdb is currently unsupported. Check back later.") add_subdirectory(tzdb_to_nx) add_dependencies(nx_tzdb x80e) - set(NX_TZDB_ROMFS_DIR "${NX_TZDB_DIR}") + set(NX_TZDB_BASE_DIR "${NX_TZDB_DIR}") + set(NX_TZDB_TZ_DIR "${NX_TZDB_BASE_DIR}/zoneinfo") +endif() + +# TODO(crueter): This is a terrible solution, but MSVC fails to link without it +# Need to investigate further but I still can't reproduce... +if (MSVC) + set(NX_TZDB_VERSION "250725") + set(NX_TZDB_ARCHIVE "${CPM_SOURCE_CACHE}/nx_tzdb/${NX_TZDB_VERSION}.zip") + + set(NX_TZDB_BASE_DIR "${CPM_SOURCE_CACHE}/nx_tzdb/tz") + set(NX_TZDB_TZ_DIR "${NX_TZDB_BASE_DIR}/zoneinfo") + + set(NX_TZDB_DOWNLOAD_URL "https://github.com/crueter/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip") + + message(STATUS "Downloading time zone data from ${NX_TZDB_DOWNLOAD_URL}...") + file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE} + STATUS NX_TZDB_DOWNLOAD_STATUS) + + list(GET NX_TZDB_DOWNLOAD_STATUS 0 NX_TZDB_DOWNLOAD_STATUS_CODE) + if (NOT NX_TZDB_DOWNLOAD_STATUS_CODE EQUAL 0) + message(FATAL_ERROR "Time zone data download failed (status code ${NX_TZDB_DOWNLOAD_STATUS_CODE})") + endif() + + file(ARCHIVE_EXTRACT + INPUT + ${NX_TZDB_ARCHIVE} + DESTINATION + ${NX_TZDB_BASE_DIR}) +else() + message(STATUS "Downloading time zone data...") + AddJsonPackage(tzdb) + + target_include_directories(nx_tzdb + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include + INTERFACE ${NX_TZDB_INCLUDE_DIR}) + + set(NX_TZDB_BASE_DIR "${CPM_SOURCE_CACHE}/nx_tzdb") + set(NX_TZDB_TZ_DIR "${nx_tzdb_SOURCE_DIR}") endif() target_include_directories(nx_tzdb @@ -68,25 +94,25 @@ function(CreateHeader ZONE_PATH HEADER_NAME) target_sources(nx_tzdb PRIVATE ${HEADER_PATH}) endfunction() -CreateHeader(${NX_TZDB_ROMFS_DIR} base) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION} zoneinfo) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Africa africa) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America america) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/Argentina america_argentina) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/Indiana america_indiana) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/Kentucky america_kentucky) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/North_Dakota america_north_dakota) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Antarctica antarctica) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Arctic arctic) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Asia asia) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Atlantic atlantic) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Australia australia) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Brazil brazil) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Canada canada) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Chile chile) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Etc etc) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Europe europe) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Indian indian) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Mexico mexico) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Pacific pacific) -CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/US us) +CreateHeader(${NX_TZDB_BASE_DIR} base) +CreateHeader(${NX_TZDB_TZ_DIR} zoneinfo) +CreateHeader(${NX_TZDB_TZ_DIR}/Africa africa) +CreateHeader(${NX_TZDB_TZ_DIR}/America america) +CreateHeader(${NX_TZDB_TZ_DIR}/America/Argentina america_argentina) +CreateHeader(${NX_TZDB_TZ_DIR}/America/Indiana america_indiana) +CreateHeader(${NX_TZDB_TZ_DIR}/America/Kentucky america_kentucky) +CreateHeader(${NX_TZDB_TZ_DIR}/America/North_Dakota america_north_dakota) +CreateHeader(${NX_TZDB_TZ_DIR}/Antarctica antarctica) +CreateHeader(${NX_TZDB_TZ_DIR}/Arctic arctic) +CreateHeader(${NX_TZDB_TZ_DIR}/Asia asia) +CreateHeader(${NX_TZDB_TZ_DIR}/Atlantic atlantic) +CreateHeader(${NX_TZDB_TZ_DIR}/Australia australia) +CreateHeader(${NX_TZDB_TZ_DIR}/Brazil brazil) +CreateHeader(${NX_TZDB_TZ_DIR}/Canada canada) +CreateHeader(${NX_TZDB_TZ_DIR}/Chile chile) +CreateHeader(${NX_TZDB_TZ_DIR}/Etc etc) +CreateHeader(${NX_TZDB_TZ_DIR}/Europe europe) +CreateHeader(${NX_TZDB_TZ_DIR}/Indian indian) +CreateHeader(${NX_TZDB_TZ_DIR}/Mexico mexico) +CreateHeader(${NX_TZDB_TZ_DIR}/Pacific pacific) +CreateHeader(${NX_TZDB_TZ_DIR}/US us) diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index 14f6eceeb8..86de96b43e 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace Common { From 6ed373f9f2c10ac732e6616a413cfe2800c2a886 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 15:17:30 +0200 Subject: [PATCH 23/44] [settings] fix unreachable code warning in fastmem bool (#347) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/347 Reviewed-by: Shinmegumi Reviewed-by: CamilleLaVey Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/settings.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 19140bce0d..d4f16f4853 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -163,8 +163,9 @@ bool IsFastmemEnabled() { } #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) return false; -#endif +#else return true; +#endif } static bool is_nce_enabled = false; From bf8fdbf1ec43c9a181e826578a3ae706528a9655 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 17:03:56 +0200 Subject: [PATCH 24/44] [compat] fix freebsd mmap virtual base (#354) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/354 Reviewed-by: Shinmegumi Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/host_memory.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index edb64de8ec..e70ac216cb 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -417,14 +417,11 @@ static void* ChooseVirtualBase(size_t virtual_size) { #else static void* ChooseVirtualBase(size_t virtual_size) { -#if defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__) void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0); - - if (virtual_base != MAP_FAILED) { + if (virtual_base != MAP_FAILED) return virtual_base; - } #endif - return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); } From 402704306f1e0de8f5663711678b4fcb8e8ef8fa Mon Sep 17 00:00:00 2001 From: JPikachu Date: Sat, 30 Aug 2025 19:35:53 +0200 Subject: [PATCH 25/44] [VK] Fix asserts with incorrect memory allocations (#357) This fixes many assertions with incorrect memory allocations. Regression introduced in PR 334. Co-authored-by: JPikachu Co-authored-by: MaranBr Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/357 Reviewed-by: Lizzie Reviewed-by: crueter Co-authored-by: JPikachu Co-committed-by: JPikachu --- src/video_core/vulkan_common/vulkan_device.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index cfa88850a0..95c0d974cc 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1378,13 +1378,13 @@ void Device::CollectPhysicalMemoryInfo() { device_access_memory += mem_properties.memoryHeaps[element].size; } if (!is_integrated) { - const u64 reserve_memory = std::min(device_access_memory / 4, 2_GiB); + const u64 reserve_memory = std::min(device_access_memory / 8, 1_GiB); device_access_memory -= reserve_memory; if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) { // Account for resolution scaling in memory limits - const size_t normal_memory = 8_GiB; - const size_t scaler_memory = 2_GiB * Settings::values.resolution_info.ScaleUp(1); + const size_t normal_memory = 6_GiB; + const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1); device_access_memory = std::min(device_access_memory, normal_memory + scaler_memory); } @@ -1393,7 +1393,7 @@ void Device::CollectPhysicalMemoryInfo() { } const s64 available_memory = static_cast(device_access_memory - device_initial_usage); device_access_memory = static_cast(std::max( - std::min(available_memory - 4_GiB, 6_GiB), std::min(local_memory, 6_GiB))); + std::min(available_memory - 8_GiB, 6_GiB), std::min(local_memory, 6_GiB))); } void Device::CollectToolingInfo() { From 5c90a3ab35b293530657d6070b77dd6dc3e427cd Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 20:32:21 +0200 Subject: [PATCH 26/44] [cmake, compat] fix solaris boost build once and for all (#364) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/364 Reviewed-by: CamilleLaVey Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d11b58bf1f..55ed83c929 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -406,8 +406,10 @@ if (YUZU_USE_CPM) if (NOT MSVC) # boost sucks - if (NOT PLATFORM_LINUX AND NOT ANDROID) - target_compile_definitions(boost_container INTERFACE BOOST_HAS_PTHREADS) + # Solaris (and probably other NIXes) need explicit pthread definition + if (PLATFORM_SUN) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthreads") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthreads") endif() target_compile_options(boost_heap INTERFACE -Wno-shadow) From 9a8d02358d31c482fa8450eb65ba95d275d19e14 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 20:32:28 +0200 Subject: [PATCH 27/44] [desktop] only warn on firmware for qlaunch/games (#363) - only warns about too new/missing for home menu - only warns about missing for games that need it (mk8dx) Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/363 Reviewed-by: CamilleLaVey Reviewed-by: MaranBr --- src/yuzu/main.cpp | 58 ++++++++++++++++++++++++++----------------- src/yuzu/main.h | 1 - src/yuzu/uisettings.h | 3 +++ 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2c3c46114d..a080132958 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -553,9 +553,6 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) // Gen keys if necessary OnCheckFirmwareDecryption(); - // Check firmware - OnCheckFirmware(); - game_list->LoadCompatibilityList(); // force reload on first load to ensure add-ons get updated game_list->PopulateAsync(UISettings::values.game_dirs, false); @@ -4459,7 +4456,6 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { progress.close(); OnCheckFirmwareDecryption(); - OnCheckFirmware(); } void GMainWindow::OnInstallFirmware() { @@ -4580,7 +4576,6 @@ void GMainWindow::OnInstallDecryptionKeys() { } OnCheckFirmwareDecryption(); - OnCheckFirmware(); } void GMainWindow::OnAbout() { @@ -4609,6 +4604,7 @@ void GMainWindow::OnToggleStatusBar() { void GMainWindow::OnGameListRefresh() { // force reload add-ons etc game_list->ForceRefreshGameDirectory(); + SetFirmwareVersion(); } void GMainWindow::OnAlbum() { @@ -4707,13 +4703,42 @@ void GMainWindow::OnOpenControllerMenu() { } void GMainWindow::OnHomeMenu() { + auto result = FirmwareManager::VerifyFirmware(*system.get()); + + switch (result) { + case FirmwareManager::ErrorFirmwareMissing: + QMessageBox::warning(this, tr("No firmware available"), + tr("Please install firmware to use the Home Menu.")); + return; + case FirmwareManager::ErrorFirmwareCorrupted: + QMessageBox::warning(this, tr("Firmware Corrupted"), + tr(FirmwareManager::GetFirmwareCheckString(result))); + return; + case FirmwareManager::ErrorFirmwareTooNew: { + if (!UISettings::values.show_fw_warning.GetValue()) break; + + QMessageBox box(QMessageBox::Warning, + tr("Firmware Too New"), + tr(FirmwareManager::GetFirmwareCheckString(result)) + tr("\nContinue anyways?"), + QMessageBox::Yes | QMessageBox::No, + this); + + QCheckBox *checkbox = new QCheckBox(tr("Don't show again")); + box.setCheckBox(checkbox); + + int button = box.exec(); + if (checkbox->isChecked()) { + UISettings::values.show_fw_warning.SetValue(false); + } + + if (button == static_cast(QMessageBox::No)) return; + break; + } default: + break; + } + constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); - if (!bis_system) { - QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Home Menu.")); - return; - } auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); if (!qlaunch_applet_nca) { @@ -5240,19 +5265,6 @@ void GMainWindow::OnCheckFirmwareDecryption() { UpdateMenuState(); } -void GMainWindow::OnCheckFirmware() { - auto result = FirmwareManager::VerifyFirmware(*system.get()); - - switch (result) { - case FirmwareManager::FirmwareGood: - break; - default: - QMessageBox::warning(this, tr("Firmware Read Error"), - tr(FirmwareManager::GetFirmwareCheckString(result))); - break; - } -} - bool GMainWindow::CheckFirmwarePresence() { return FirmwareManager::CheckFirmwarePresence(*system.get()); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8a34a9f075..b1c5669a41 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -424,7 +424,6 @@ private slots: void OnCreateHomeMenuShortcut(GameListShortcutTarget target); void OnCaptureScreenshot(); void OnCheckFirmwareDecryption(); - void OnCheckFirmware(); void OnLanguageChanged(const QString& locale); void OnMouseActivity(); bool OnShutdownBegin(); diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 85de0ae72d..3322b31ca3 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -212,6 +212,9 @@ struct Values { // Play time Setting show_play_time{linkage, true, "show_play_time", Category::UiGameList}; + // misc + Setting show_fw_warning{linkage, true, "show_fw_warning", Category::Miscellaneous}; + bool configuration_applied; bool reset_to_defaults; bool shortcut_already_warned{false}; From e3cbae47845b4c9d3e4ce58beecb1360e5ef1318 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 23:08:04 +0200 Subject: [PATCH 28/44] [qt, compat] fix freedesktop stuffs on Solaris/OpenBSD (#360) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/360 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- src/yuzu/main.cpp | 72 ++++++++++++++++++++---------------------- src/yuzu/util/util.cpp | 5 ++- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a080132958..7600b8b5da 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3091,34 +3091,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::filesystem::path& command, const std::string& arguments, const std::string& categories, const std::string& keywords, const std::string& name) try { -#if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD - std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop"); - std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); - if (!shortcut_stream.is_open()) { - LOG_ERROR(Frontend, "Failed to create shortcut"); - return false; - } - // TODO: Migrate fmt::print to std::print in futures STD C++ 23. - fmt::print(shortcut_stream, "[Desktop Entry]\n"); - fmt::print(shortcut_stream, "Type=Application\n"); - fmt::print(shortcut_stream, "Version=1.0\n"); - fmt::print(shortcut_stream, "Name={}\n", name); - if (!comment.empty()) { - fmt::print(shortcut_stream, "Comment={}\n", comment); - } - if (std::filesystem::is_regular_file(icon_path)) { - fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); - } - fmt::print(shortcut_stream, "TryExec={}\n", command.string()); - fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); - if (!categories.empty()) { - fmt::print(shortcut_stream, "Categories={}\n", categories); - } - if (!keywords.empty()) { - fmt::print(shortcut_stream, "Keywords={}\n", keywords); - } - return true; -#elif defined(_WIN32) // Windows +#ifdef _WIN32 // Windows HRESULT hr = CoInitialize(nullptr); if (FAILED(hr)) { LOG_ERROR(Frontend, "CoInitialize failed"); @@ -3180,7 +3153,34 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, return false; } return true; -#else // Unsupported platform +#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) // Any desktop NIX + std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop"); + std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); + if (!shortcut_stream.is_open()) { + LOG_ERROR(Frontend, "Failed to create shortcut"); + return false; + } + // TODO: Migrate fmt::print to std::print in futures STD C++ 23. + fmt::print(shortcut_stream, "[Desktop Entry]\n"); + fmt::print(shortcut_stream, "Type=Application\n"); + fmt::print(shortcut_stream, "Version=1.0\n"); + fmt::print(shortcut_stream, "Name={}\n", name); + if (!comment.empty()) { + fmt::print(shortcut_stream, "Comment={}\n", comment); + } + if (std::filesystem::is_regular_file(icon_path)) { + fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); + } + fmt::print(shortcut_stream, "TryExec={}\n", command.string()); + fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); + if (!categories.empty()) { + fmt::print(shortcut_stream, "Categories={}\n", categories); + } + if (!keywords.empty()) { + fmt::print(shortcut_stream, "Keywords={}\n", keywords); + } + return true; +#else // Unsupported platform return false; #endif } catch (const std::exception& e) { @@ -3225,7 +3225,7 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi #if defined(_WIN32) out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir); ico_extension = "ico"; -#elif defined(__linux__) || defined(__FreeBSD__) +#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; #endif // Create icons directory if it doesn't exist @@ -4878,7 +4878,7 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program } } -#if defined(__linux__) +#if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) // Special case for AppImages // Warn once if we are making a shortcut to a volatile AppImage if (command.string().ends_with(".AppImage") && !UISettings::values.shortcut_already_warned) { @@ -4888,7 +4888,7 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program } UISettings::values.shortcut_already_warned = true; } -#endif // __linux__ +#endif // Create shortcut std::string arguments{arguments_}; @@ -5742,17 +5742,13 @@ int main(int argc, char* argv[]) { #ifdef _WIN32 // Increases the maximum open file limit to 8192 _setmaxstdio(8192); -#endif - -#ifdef __APPLE__ +#elif defined(__APPLE__) // If you start a bundle (binary) on OSX without the Terminal, the working directory is "/". // But since we require the working directory to be the executable path for the location of // the user folder in the Qt Frontend, we need to cd into that working directory const auto bin_path = Common::FS::GetBundleDirectory() / ".."; chdir(Common::FS::PathToUTF8String(bin_path).c_str()); -#endif - -#ifdef __linux__ +#elif defined(__unix__) && !defined(__ANDROID__) // Set the DISPLAY variable in order to open web browsers // TODO (lat9nq): Find a better solution for AppImages to start external applications if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) { diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp index e22cf84bf1..551df7b4cd 100644 --- a/src/yuzu/util/util.cpp +++ b/src/yuzu/util/util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -138,7 +141,7 @@ bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image) icon_file.Close(); return true; -#elif defined(__linux__) || defined(__FreeBSD__) +#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) // Convert and write the icon as a PNG if (!image.save(QString::fromStdString(icon_path.string()))) { LOG_ERROR(Frontend, "Could not write icon as PNG to file"); From 4ee1edc229d8da207c1278f91260f7b0205a3408 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 00:12:06 +0200 Subject: [PATCH 29/44] [dynarmic] fix annoying gcc/clang error (#365) caused qt creator to crash somehow geg Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/365 Reviewed-by: Lizzie Reviewed-by: MaranBr --- .../src/dynarmic/common/lut_from_list.h | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/dynarmic/src/dynarmic/common/lut_from_list.h b/src/dynarmic/src/dynarmic/common/lut_from_list.h index ed9e3dc046..c904e2c041 100644 --- a/src/dynarmic/src/dynarmic/common/lut_from_list.h +++ b/src/dynarmic/src/dynarmic/common/lut_from_list.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -19,6 +22,16 @@ namespace Dynarmic::Common { +// prevents this function from printing 56,000 character warning messages +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wno-stack-usage" +#endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wno-stack-usage" +#endif + template inline auto GenerateLookupTableFromList(Function f, mcl::mp::list) { #ifdef _MSC_VER @@ -34,4 +47,11 @@ inline auto GenerateLookupTableFromList(Function f, mcl::mp::list) { return MapT(pair_array.begin(), pair_array.end()); } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } // namespace Dynarmic::Common From f8f98da6b04d332a425ee5f0f3f00526130ed563 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 03:10:34 +0200 Subject: [PATCH 30/44] [cmake] fix ffmpeg libdrm on macos (#367) Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/367 Reviewed-by: Shinmegumi Reviewed-by: Lizzie --- externals/ffmpeg/CMakeLists.txt | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 54c852f831..ff35c8dc2c 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -63,20 +63,22 @@ if (NOT WIN32 AND NOT ANDROID) set(FFmpeg_HWACCEL_INCLUDE_DIRS) set(FFmpeg_HWACCEL_LDFLAGS) - # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so - if(PLATFORM_SUN) - list(APPEND FFmpeg_HWACCEL_LIBRARIES - X11 - "/usr/lib/xorg/amd64/libdrm.so") - else() - pkg_check_modules(LIBDRM libdrm REQUIRED) - list(APPEND FFmpeg_HWACCEL_LIBRARIES - ${LIBDRM_LIBRARIES}) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS - ${LIBDRM_INCLUDE_DIRS}) + if (NOT APPLE) + # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so + if(PLATFORM_SUN) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + X11 + "/usr/lib/xorg/amd64/libdrm.so") + else() + pkg_check_modules(LIBDRM libdrm REQUIRED) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + ${LIBDRM_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS + ${LIBDRM_INCLUDE_DIRS}) + endif() + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-libdrm) endif() - list(APPEND FFmpeg_HWACCEL_FLAGS - --enable-libdrm) if(LIBVA_FOUND) find_package(X11 REQUIRED) From ac30b209e51ba958b25ca4c7f4827c6970a007ea Mon Sep 17 00:00:00 2001 From: Producdevity Date: Sun, 31 Aug 2025 03:33:54 +0200 Subject: [PATCH 31/44] [android] fix intent-auto-driver-install (#369) Resolving drivers based on the artifact name was too buggy and inconsistent, this PR improves it. Well, I like to think it does Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/369 Reviewed-by: crueter Reviewed-by: Lizzie Co-authored-by: Producdevity Co-committed-by: Producdevity --- .../yuzu_emu/utils/CustomSettingsHandler.kt | 27 ++++-- .../org/yuzu/yuzu_emu/utils/DriverResolver.kt | 94 +++++++++++++++++-- 2 files changed, 102 insertions(+), 19 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/CustomSettingsHandler.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/CustomSettingsHandler.kt index a317be14d5..377313d0aa 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/CustomSettingsHandler.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/CustomSettingsHandler.kt @@ -124,11 +124,16 @@ object CustomSettingsHandler { // Check for driver requirements if activity and driverViewModel are provided if (activity != null && driverViewModel != null) { - val driverPath = extractDriverPath(customSettings) - if (driverPath != null) { - Log.info("[CustomSettingsHandler] Custom settings specify driver: $driverPath") + val rawDriverPath = extractDriverPath(customSettings) + if (rawDriverPath != null) { + // Normalize to local storage path (we only store drivers under driverStoragePath) + val driverFilename = rawDriverPath.substringAfterLast('/') + .substringAfterLast('\\') + val localDriverPath = "${GpuDriverHelper.driverStoragePath}$driverFilename" + Log.info("[CustomSettingsHandler] Custom settings specify driver: $rawDriverPath (normalized: $localDriverPath)") + // Check if driver exists in the driver storage - val driverFile = File(driverPath) + val driverFile = File(localDriverPath) if (!driverFile.exists()) { Log.info("[CustomSettingsHandler] Driver not found locally: ${driverFile.name}") @@ -182,7 +187,7 @@ object CustomSettingsHandler { } // Attempt to download and install the driver - val driverUri = DriverResolver.ensureDriverAvailable(driverPath, activity) { progress -> + val driverUri = DriverResolver.ensureDriverAvailable(driverFilename, activity) { progress -> progressChannel.trySend(progress.toInt()) } @@ -209,12 +214,12 @@ object CustomSettingsHandler { return null } - // Verify the downloaded driver - val installedFile = File(driverPath) + // Verify the downloaded driver (from normalized local path) + val installedFile = File(localDriverPath) val metadata = GpuDriverHelper.getMetadataFromZip(installedFile) if (metadata.name == null) { Log.error( - "[CustomSettingsHandler] Downloaded driver is invalid: $driverPath" + "[CustomSettingsHandler] Downloaded driver is invalid: $localDriverPath" ) Toast.makeText( activity, @@ -232,7 +237,7 @@ object CustomSettingsHandler { } // Add to driver list - driverViewModel.onDriverAdded(Pair(driverPath, metadata)) + driverViewModel.onDriverAdded(Pair(localDriverPath, metadata)) Log.info( "[CustomSettingsHandler] Successfully downloaded and installed driver: ${metadata.name}" ) @@ -268,7 +273,7 @@ object CustomSettingsHandler { // Driver exists, verify it's valid val metadata = GpuDriverHelper.getMetadataFromZip(driverFile) if (metadata.name == null) { - Log.error("[CustomSettingsHandler] Invalid driver file: $driverPath") + Log.error("[CustomSettingsHandler] Invalid driver file: $localDriverPath") Toast.makeText( activity, activity.getString( @@ -459,6 +464,8 @@ object CustomSettingsHandler { if (inGpuDriverSection && trimmed.startsWith("driver_path=")) { return trimmed.substringAfter("driver_path=") + .trim() + .removeSurrounding("\"", "\"") } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DriverResolver.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DriverResolver.kt index 74f98ccbd2..2072344bdf 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DriverResolver.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DriverResolver.kt @@ -68,6 +68,48 @@ object DriverResolver { val filename: String ) + // Matching helpers + private val KNOWN_SUFFIXES = listOf( + ".adpkg.zip", + ".zip", + ".7z", + ".tar.gz", + ".tar.xz", + ".rar" + ) + + private fun stripKnownSuffixes(name: String): String { + var result = name + var changed: Boolean + do { + changed = false + for (s in KNOWN_SUFFIXES) { + if (result.endsWith(s, ignoreCase = true)) { + result = result.dropLast(s.length) + changed = true + } + } + } while (changed) + return result + } + + private fun normalizeName(name: String): String { + val base = stripKnownSuffixes(name.lowercase()) + // Remove non-alphanumerics to make substring checks resilient + return base.replace(Regex("[^a-z0-9]+"), " ").trim() + } + + private fun tokenize(name: String): Set = + normalizeName(name).split(Regex("\\s+")).filter { it.isNotBlank() }.toSet() + + // Jaccard similarity between two sets + private fun jaccard(a: Set, b: Set): Double { + if (a.isEmpty() || b.isEmpty()) return 0.0 + val inter = a.intersect(b).size.toDouble() + val uni = a.union(b).size.toDouble() + return if (uni == 0.0) 0.0 else inter / uni + } + /** * Resolve a driver download URL from its filename * @param filename The driver filename (e.g., "turnip_mrpurple-T19-toasted.adpkg.zip") @@ -98,7 +140,7 @@ object DriverResolver { async { searchRepository(repoPath, filename) } - }.mapNotNull { it.await() }.firstOrNull().also { resolved -> + }.firstNotNullOfOrNull { it.await() }.also { resolved -> // Cache the result if found resolved?.let { urlCache[filename] = it @@ -119,22 +161,56 @@ object DriverResolver { releaseCache[repoPath] = it } - // Search through all releases and artifacts + // First pass: exact name (case-insensitive) against asset filenames + val target = filename.lowercase() for (release in releases) { for (artifact in release.artifacts) { - if (artifact.name == filename) { - Log.info( - "[DriverResolver] Found $filename in $repoPath/${release.tagName}" - ) + if (artifact.name.equals(filename, ignoreCase = true) || artifact.name.lowercase() == target) { + Log.info("[DriverResolver] Found $filename in $repoPath/${release.tagName}") return@withContext ResolvedDriver( downloadUrl = artifact.url.toString(), repoPath = repoPath, releaseTag = release.tagName, - filename = filename + filename = artifact.name ) } } } + + // Second pass: fuzzy match by asset filenames only + val reqNorm = normalizeName(filename) + val reqTokens = tokenize(filename) + var best: ResolvedDriver? = null + var bestScore = 0.0 + + for (release in releases) { + for (artifact in release.artifacts) { + val artNorm = normalizeName(artifact.name) + val artTokens = tokenize(artifact.name) + + var score = jaccard(reqTokens, artTokens) + // Boost if one normalized name contains the other + if (artNorm.contains(reqNorm) || reqNorm.contains(artNorm)) { + score = maxOf(score, 0.92) + } + + if (score > bestScore) { + bestScore = score + best = ResolvedDriver( + downloadUrl = artifact.url.toString(), + repoPath = repoPath, + releaseTag = release.tagName, + filename = artifact.name + ) + } + } + } + + // Threshold to avoid bad guesses, this worked fine in testing but might need tuning + if (best != null && bestScore >= 0.6) { + Log.info("[DriverResolver] Fuzzy matched $filename -> ${best.filename} in ${best.repoPath} (score=%.2f)".format(bestScore)) + return@withContext best + } null } catch (e: Exception) { Log.error("[DriverResolver] Failed to search $repoPath: ${e.message}") @@ -296,8 +372,8 @@ object DriverResolver { context: Context, onProgress: ((Float) -> Unit)? = null ): Uri? { - // Extract filename from path - val filename = driverPath.substringAfterLast('/') + // Extract filename from path (support both separators) + val filename = driverPath.substringAfterLast('/').substringAfterLast('\\') // Check if driver already exists locally val localPath = "${GpuDriverHelper.driverStoragePath}$filename" From 656ed8a864d4eff8bebbb4b6672d9080fe0441ba Mon Sep 17 00:00:00 2001 From: Guo Yunhe Date: Sun, 31 Aug 2025 04:56:23 +0200 Subject: [PATCH 32/44] [cmake] changed app id from org.eden_emu.eden to dev.eden_emu.eden (#237) it is better to match app id with website domain Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/237 Reviewed-by: crueter Co-authored-by: Guo Yunhe Co-committed-by: Guo Yunhe --- .ci/linux/eden.dwfsprof | 2 +- .ci/linux/package.sh | 8 ++++---- .ci/update-icons.sh | 2 +- CMakeLists.txt | 8 ++++---- ...rg.eden_emu.eden.desktop => dev.eden_emu.eden.desktop} | 2 +- ...u.eden.metainfo.xml => dev.eden_emu.eden.metainfo.xml} | 0 dist/{org.eden_emu.eden.svg => dev.eden_emu.eden.svg} | 0 dist/{org.eden_emu.eden.xml => dev.eden_emu.eden.xml} | 0 src/yuzu/main.cpp | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) rename dist/{org.eden_emu.eden.desktop => dev.eden_emu.eden.desktop} (95%) rename dist/{org.eden_emu.eden.metainfo.xml => dev.eden_emu.eden.metainfo.xml} (100%) rename dist/{org.eden_emu.eden.svg => dev.eden_emu.eden.svg} (100%) rename dist/{org.eden_emu.eden.xml => dev.eden_emu.eden.xml} (100%) diff --git a/.ci/linux/eden.dwfsprof b/.ci/linux/eden.dwfsprof index bc360f0d46..9a3bee6f14 100644 --- a/.ci/linux/eden.dwfsprof +++ b/.ci/linux/eden.dwfsprof @@ -1,6 +1,6 @@ AppRun eden.desktop -org.eden_emu.eden.desktop +dev.eden_emu.eden.desktop shared/bin/eden shared/lib/lib.path shared/lib/ld-linux-x86-64.so.2 diff --git a/.ci/linux/package.sh b/.ci/linux/package.sh index 911fea2f7b..837cfe07ef 100755 --- a/.ci/linux/package.sh +++ b/.ci/linux/package.sh @@ -59,15 +59,15 @@ VERSION="$(echo "$EDEN_TAG")" mkdir -p ./AppDir cd ./AppDir -cp ../dist/org.eden_emu.eden.desktop . -cp ../dist/org.eden_emu.eden.svg . +cp ../dist/dev.eden_emu.eden.desktop . +cp ../dist/dev.eden_emu.eden.svg . -ln -sf ./org.eden_emu.eden.svg ./.DirIcon +ln -sf ./dev.eden_emu.eden.svg ./.DirIcon UPINFO='gh-releases-zsync|eden-emulator|Releases|latest|*.AppImage.zsync' if [ "$DEVEL" = 'true' ]; then - sed -i 's|Name=Eden|Name=Eden Nightly|' ./org.eden_emu.eden.desktop + sed -i 's|Name=Eden|Name=Eden Nightly|' ./dev.eden_emu.eden.desktop UPINFO="$(echo "$UPINFO" | sed 's|Releases|nightly|')" fi diff --git a/.ci/update-icons.sh b/.ci/update-icons.sh index 99adbfae66..4feb2abd24 100755 --- a/.ci/update-icons.sh +++ b/.ci/update-icons.sh @@ -6,7 +6,7 @@ which png2icns || [ which yay && yay libicns ] || exit which magick || exit -export EDEN_SVG_ICO="dist/org.eden_emu.eden.svg" +export EDEN_SVG_ICO="dist/dev.eden_emu.eden.svg" svgo --multipass $EDEN_SVG_ICO magick -density 256x256 -background transparent $EDEN_SVG_ICO \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 55ed83c929..9abca561f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -858,14 +858,14 @@ endif() # https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html # https://www.freedesktop.org/software/appstream/docs/ if(ENABLE_QT AND UNIX AND NOT APPLE) - install(FILES "dist/org.eden_emu.eden.desktop" + install(FILES "dist/dev.eden_emu.eden.desktop" DESTINATION "share/applications") - install(FILES "dist/org.eden_emu.eden.svg" + install(FILES "dist/dev.eden_emu.eden.svg" DESTINATION "share/icons/hicolor/scalable/apps") # TODO: these files need to be updated. - install(FILES "dist/org.eden_emu.eden.xml" + install(FILES "dist/dev.eden_emu.eden.xml" DESTINATION "share/mime/packages") - install(FILES "dist/org.eden_emu.eden.metainfo.xml" + install(FILES "dist/dev.eden_emu.eden.metainfo.xml" DESTINATION "share/metainfo") endif() diff --git a/dist/org.eden_emu.eden.desktop b/dist/dev.eden_emu.eden.desktop similarity index 95% rename from dist/org.eden_emu.eden.desktop rename to dist/dev.eden_emu.eden.desktop index d012ab6d07..5d2d7cd8c5 100644 --- a/dist/org.eden_emu.eden.desktop +++ b/dist/dev.eden_emu.eden.desktop @@ -10,7 +10,7 @@ Type=Application Name=Eden GenericName=Switch Emulator Comment=Nintendo Switch video game console emulator -Icon=org.eden_emu.eden +Icon=dev.eden_emu.eden TryExec=eden Exec=eden %f Categories=Game;Emulator;Qt; diff --git a/dist/org.eden_emu.eden.metainfo.xml b/dist/dev.eden_emu.eden.metainfo.xml similarity index 100% rename from dist/org.eden_emu.eden.metainfo.xml rename to dist/dev.eden_emu.eden.metainfo.xml diff --git a/dist/org.eden_emu.eden.svg b/dist/dev.eden_emu.eden.svg similarity index 100% rename from dist/org.eden_emu.eden.svg rename to dist/dev.eden_emu.eden.svg diff --git a/dist/org.eden_emu.eden.xml b/dist/dev.eden_emu.eden.xml similarity index 100% rename from dist/org.eden_emu.eden.xml rename to dist/dev.eden_emu.eden.xml diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7600b8b5da..4c6b176c56 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -5757,7 +5757,7 @@ int main(int argc, char* argv[]) { // Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop // suffix. - QGuiApplication::setDesktopFileName(QStringLiteral("org.eden_emu.eden")); + QGuiApplication::setDesktopFileName(QStringLiteral("dev.eden_emu.eden")); #endif SetHighDPIAttributes(); From 51201a37e2a746acc07c3ab650c5f6fbdd1526ab Mon Sep 17 00:00:00 2001 From: SDK-Chan Date: Sun, 31 Aug 2025 07:32:54 +0200 Subject: [PATCH 33/44] [gpu/NVDRV] Finalize, improve AllocObjCtx (#333) Improves object allocation per channel, only allowing max amount of 6 objects contexts per channel. Previously objects were stored in a heap allocated vector which is sub-optimal for performance reasons. The new implementation instead uses a stack based array with a O(1) approach. This should boost performance in games which heavily rely on object context creation. Co-authored-by: MaranBr Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/333 Reviewed-by: crueter Reviewed-by: CamilleLaVey Co-authored-by: SDK-Chan Co-committed-by: SDK-Chan --- .../hle/service/nvdrv/devices/nvhost_gpu.cpp | 57 ++++++++++++++----- .../hle/service/nvdrv/devices/nvhost_gpu.h | 5 +- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 95bf18dbf7..5f754650d9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -219,28 +219,55 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(IoctlAllocGpfifoEx& params, DeviceFD fd) { return NvResult::Success; } -NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) { - LOG_DEBUG(Service_NVDRV, "called, class_num={:X}, flags={:X}, obj_id={:X}", params.class_num, - params.flags, params.obj_id); +s32_le nvhost_gpu::GetObjectContextClassNumberIndex(CtxClasses class_number) { + constexpr s32_le invalid_class_number_index = -1; + switch (class_number) { + case CtxClasses::Ctx2D: return 0; + case CtxClasses::Ctx3D: return 1; + case CtxClasses::CtxCompute: return 2; + case CtxClasses::CtxKepler: return 3; + case CtxClasses::CtxDMA: return 4; + case CtxClasses::CtxChannelGPFIFO: return 5; + default: return invalid_class_number_index; + } +} - if (!channel_state->initialized) { +NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) { + LOG_DEBUG(Service_NVDRV, "called, class_num={:#X}, flags={:#X}, obj_id={:#X}", params.class_num, + params.flags, params.obj_id); + + if (!channel_state || !channel_state->initialized) { LOG_CRITICAL(Service_NVDRV, "No address space bound to allocate a object context!"); return NvResult::NotInitialized; } - switch (static_cast(params.class_num)) { - case CtxClasses::Ctx2D: - case CtxClasses::Ctx3D: - case CtxClasses::CtxCompute: - case CtxClasses::CtxKepler: - case CtxClasses::CtxDMA: - case CtxClasses::CtxChannelGPFIFO: - ctxObj_params.push_back(params); - return NvResult::Success; - default: - LOG_ERROR(Service_NVDRV, "Invalid class number for object context: {:X}", params.class_num); + std::scoped_lock lk(channel_mutex); + + if (params.flags) { + LOG_WARNING(Service_NVDRV, "non-zero flags={:#X} for class={:#X}", params.flags, + params.class_num); + + constexpr u32 allowed_mask{}; + params.flags = allowed_mask; + } + + s32_le ctx_class_number_index = + GetObjectContextClassNumberIndex(static_cast(params.class_num)); + if (ctx_class_number_index < 0) { + LOG_ERROR(Service_NVDRV, "Invalid class number for object context: {:#X}", + params.class_num); return NvResult::BadParameter; } + + if (ctxObjs[ctx_class_number_index].has_value()) { + LOG_ERROR(Service_NVDRV, "Object context for class {:#X} already allocated on this channel", + params.class_num); + return NvResult::AlreadyAllocated; + } + + ctxObjs[ctx_class_number_index] = params; + + return NvResult::Success; } static boost::container::small_vector BuildWaitCommandList( diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index a017cc50d0..fb0a5be959 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -172,7 +172,7 @@ private: s32_le nvmap_fd{}; u64_le user_data{}; IoctlZCullBind zcull_params{}; - std::vector ctxObj_params{}; + std::array, 6> ctxObjs{}; u32_le channel_priority{}; u32_le channel_timeslice{}; @@ -184,9 +184,12 @@ private: NvResult SetChannelPriority(IoctlChannelSetPriority& params); NvResult AllocGPFIFOEx(IoctlAllocGpfifoEx& params, DeviceFD fd); NvResult AllocGPFIFOEx2(IoctlAllocGpfifoEx& params, DeviceFD fd); + + s32_le GetObjectContextClassNumberIndex(CtxClasses class_number); NvResult AllocateObjectContext(IoctlAllocObjCtx& params); NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries); + NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params, std::span commands, bool kickoff = false); NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params, From d83fee76ef70b6a0104c4ff1ca715da8af2300d9 Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Sun, 31 Aug 2025 08:40:46 +0200 Subject: [PATCH 34/44] [common, fs] include missing header introduced on #330 (#370) Signed-off-by: Caio Oliveira Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/370 Reviewed-by: crueter Reviewed-by: Lizzie Co-authored-by: Caio Oliveira Co-committed-by: Caio Oliveira --- src/common/string_util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/string_util.h b/src/common/string_util.h index 8ed87cdadc..4358541b14 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include From 0691e532c4ef3aba1ea717853154aef3031c3150 Mon Sep 17 00:00:00 2001 From: wildcard Date: Mon, 1 Sep 2025 00:20:03 +0200 Subject: [PATCH 35/44] [VMA] Phase 3:- Hand all allocation & binding to VMA (#362) This patch completely removes the Custom Sub allocator with VMA and delegates everything to the VMA. Overall, the patch integrates VMA and simplifies memory management. Once these changes pass the testing, it will be used as a base for further improvement. Note to testers, test for stability and performance. Co-authored-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/362 Reviewed-by: crueter Reviewed-by: MaranBr Co-authored-by: wildcard Co-committed-by: wildcard --- externals/CMakeLists.txt | 4 + src/android/app/src/main/jni/CMakeLists.txt | 2 +- src/video_core/vulkan_common/vma.h | 4 +- .../vulkan_common/vulkan_device.cpp | 30 +- .../vulkan_common/vulkan_memory_allocator.cpp | 642 ++++++++---------- .../vulkan_common/vulkan_memory_allocator.h | 203 +++--- 6 files changed, 411 insertions(+), 474 deletions(-) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index b209b48db9..f66423a672 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -147,6 +147,10 @@ add_subdirectory(nx_tzdb) # VMA AddJsonPackage(vulkan-memory-allocator) +if (VulkanMemoryAllocator_ADDED AND MSVC) + target_compile_options(VulkanMemoryAllocator INTERFACE /wd4189) +endif() + if (NOT TARGET LLVM::Demangle) add_library(demangle demangle/ItaniumDemangle.cpp) target_include_directories(demangle PUBLIC ./demangle) diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index 1e30b16d96..9dbee1fcef 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt @@ -17,7 +17,7 @@ add_library(yuzu-android SHARED set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) -target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common Vulkan::Headers) +target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common Vulkan::Headers GPUOpen::VulkanMemoryAllocator) target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log) if (ARCHITECTURE_arm64) target_link_libraries(yuzu-android PRIVATE adrenotools) diff --git a/src/video_core/vulkan_common/vma.h b/src/video_core/vulkan_common/vma.h index 6e25aa1bdf..911c1114b2 100644 --- a/src/video_core/vulkan_common/vma.h +++ b/src/video_core/vulkan_common/vma.h @@ -1,3 +1,5 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -8,4 +10,4 @@ #define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 -#include +#include "vk_mem_alloc.h" diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 95c0d974cc..4d74bf00a5 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -753,18 +753,24 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR functions.vkGetInstanceProcAddr = dld.vkGetInstanceProcAddr; functions.vkGetDeviceProcAddr = dld.vkGetDeviceProcAddr; - const VmaAllocatorCreateInfo allocator_info = { - .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, - .physicalDevice = physical, - .device = *logical, - .preferredLargeHeapBlockSize = 0, - .pAllocationCallbacks = nullptr, - .pDeviceMemoryCallbacks = nullptr, - .pHeapSizeLimit = nullptr, - .pVulkanFunctions = &functions, - .instance = instance, - .vulkanApiVersion = VK_API_VERSION_1_1, - .pTypeExternalMemoryHandleTypes = nullptr, + VmaAllocatorCreateFlags flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT; + if (extensions.memory_budget) { + flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; + } + const VmaAllocatorCreateInfo allocator_info{ + .flags = flags, + .physicalDevice = physical, + .device = *logical, + .preferredLargeHeapBlockSize = is_integrated + ? (64u * 1024u * 1024u) + : (256u * 1024u * 1024u), + .pAllocationCallbacks = nullptr, + .pDeviceMemoryCallbacks = nullptr, + .pHeapSizeLimit = nullptr, + .pVulkanFunctions = &functions, + .instance = instance, + .vulkanApiVersion = ApiVersion(), + .pTypeExternalMemoryHandleTypes = nullptr, }; vk::Check(vmaCreateAllocator(&allocator_info, &allocator)); diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 2e37615f99..4ab420afea 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -6,7 +6,10 @@ #include #include +#include #include +#include +#include #include #include "common/alignment.h" @@ -21,379 +24,302 @@ #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { -namespace { -struct Range { - u64 begin; - u64 end; + namespace { - [[nodiscard]] bool Contains(u64 iterator, u64 size) const noexcept { - return iterator < end && begin < iterator + size; - } -}; +// Helpers translating MemoryUsage to flags/usage -[[nodiscard]] u64 AllocationChunkSize(u64 required_size) { - static constexpr std::array sizes{ - 0x1000ULL << 10, 0x1400ULL << 10, 0x1800ULL << 10, 0x1c00ULL << 10, 0x2000ULL << 10, - 0x3200ULL << 10, 0x4000ULL << 10, 0x6000ULL << 10, 0x8000ULL << 10, 0xA000ULL << 10, - 0x10000ULL << 10, 0x18000ULL << 10, 0x20000ULL << 10, - }; - static_assert(std::is_sorted(sizes.begin(), sizes.end())); - - const auto it = std::ranges::lower_bound(sizes, required_size); - return it != sizes.end() ? *it : Common::AlignUp(required_size, 4ULL << 20); -} - -[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) { - switch (usage) { - case MemoryUsage::DeviceLocal: - return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - case MemoryUsage::Upload: - return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - case MemoryUsage::Download: - return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - case MemoryUsage::Stream: - return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - } - ASSERT_MSG(false, "Invalid memory usage={}", usage); - return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; -} - -[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferredVmaFlags(MemoryUsage usage) { - return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT - : VkMemoryPropertyFlagBits{}; -} - -[[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) { - switch (usage) { - case MemoryUsage::Upload: - case MemoryUsage::Stream: - return VMA_ALLOCATION_CREATE_MAPPED_BIT | - VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; - case MemoryUsage::Download: - return VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; - case MemoryUsage::DeviceLocal: - return {}; - } - return {}; -} - -[[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) { - switch (usage) { - case MemoryUsage::DeviceLocal: - case MemoryUsage::Stream: - return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; - case MemoryUsage::Upload: - case MemoryUsage::Download: - return VMA_MEMORY_USAGE_AUTO_PREFER_HOST; - } - return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; -} - -} // Anonymous namespace - -class MemoryAllocation { -public: - explicit MemoryAllocation(MemoryAllocator* const allocator_, vk::DeviceMemory memory_, - VkMemoryPropertyFlags properties, u64 allocation_size_, u32 type) - : allocator{allocator_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, - property_flags{properties}, shifted_memory_type{1U << type} {} - - MemoryAllocation& operator=(const MemoryAllocation&) = delete; - MemoryAllocation(const MemoryAllocation&) = delete; - - MemoryAllocation& operator=(MemoryAllocation&&) = delete; - MemoryAllocation(MemoryAllocation&&) = delete; - - [[nodiscard]] std::optional Commit(VkDeviceSize size, VkDeviceSize alignment) { - const std::optional alloc = FindFreeRegion(size, alignment); - if (!alloc) { - // Signal out of memory, it'll try to do more allocations. - return std::nullopt; + [[maybe_unused]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::DeviceLocal: + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + case MemoryUsage::Upload: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + case MemoryUsage::Download: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + case MemoryUsage::Stream: + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + } + ASSERT_MSG(false, "Invalid memory usage={}", usage); + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } - const Range range{ - .begin = *alloc, - .end = *alloc + size, + + [[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferredVmaFlags(MemoryUsage usage) { + return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + : VkMemoryPropertyFlagBits{}; + } + + [[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::Upload: + case MemoryUsage::Stream: + return VMA_ALLOCATION_CREATE_MAPPED_BIT | + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + case MemoryUsage::Download: + return VMA_ALLOCATION_CREATE_MAPPED_BIT | + VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; + case MemoryUsage::DeviceLocal: + return {}; + } + return {}; + } + + [[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::DeviceLocal: + case MemoryUsage::Stream: + return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; + case MemoryUsage::Upload: + case MemoryUsage::Download: + return VMA_MEMORY_USAGE_AUTO_PREFER_HOST; + } + return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; + } + + +// This avoids calling vkGetBufferMemoryRequirements* directly. + template + static VkBuffer GetVkHandleFromBuffer(const T &buf) { + if constexpr (requires { static_cast(buf); }) { + return static_cast(buf); + } else if constexpr (requires {{ buf.GetHandle() } -> std::convertible_to; }) { + return buf.GetHandle(); + } else if constexpr (requires {{ buf.Handle() } -> std::convertible_to; }) { + return buf.Handle(); + } else if constexpr (requires {{ buf.vk_handle() } -> std::convertible_to; }) { + return buf.vk_handle(); + } else { + static_assert(sizeof(T) == 0, "Cannot extract VkBuffer handle from vk::Buffer"); + return VK_NULL_HANDLE; + } + } + + } // namespace + +//MemoryCommit is now VMA-backed + MemoryCommit::MemoryCommit(VmaAllocator alloc, VmaAllocation a, + const VmaAllocationInfo &info) noexcept + : allocator{alloc}, allocation{a}, memory{info.deviceMemory}, + offset{info.offset}, size{info.size}, mapped_ptr{info.pMappedData} {} + + MemoryCommit::~MemoryCommit() { Release(); } + + MemoryCommit::MemoryCommit(MemoryCommit &&rhs) noexcept + : allocator{std::exchange(rhs.allocator, nullptr)}, + allocation{std::exchange(rhs.allocation, nullptr)}, + memory{std::exchange(rhs.memory, VK_NULL_HANDLE)}, + offset{std::exchange(rhs.offset, 0)}, + size{std::exchange(rhs.size, 0)}, + mapped_ptr{std::exchange(rhs.mapped_ptr, nullptr)} {} + + MemoryCommit &MemoryCommit::operator=(MemoryCommit &&rhs) noexcept { + if (this != &rhs) { + Release(); + allocator = std::exchange(rhs.allocator, nullptr); + allocation = std::exchange(rhs.allocation, nullptr); + memory = std::exchange(rhs.memory, VK_NULL_HANDLE); + offset = std::exchange(rhs.offset, 0); + size = std::exchange(rhs.size, 0); + mapped_ptr = std::exchange(rhs.mapped_ptr, nullptr); + } + return *this; + } + + std::span MemoryCommit::Map() + { + if (!allocation) return {}; + if (!mapped_ptr) { + if (vmaMapMemory(allocator, allocation, &mapped_ptr) != VK_SUCCESS) return {}; + } + const size_t n = static_cast(std::min(size, + std::numeric_limits::max())); + return std::span{static_cast(mapped_ptr), n}; + } + + std::span MemoryCommit::Map() const + { + if (!allocation) return {}; + if (!mapped_ptr) { + void *p = nullptr; + if (vmaMapMemory(allocator, allocation, &p) != VK_SUCCESS) return {}; + const_cast(this)->mapped_ptr = p; + } + const size_t n = static_cast(std::min(size, + std::numeric_limits::max())); + return std::span{static_cast(mapped_ptr), n}; + } + + void MemoryCommit::Unmap() + { + if (allocation && mapped_ptr) { + vmaUnmapMemory(allocator, allocation); + mapped_ptr = nullptr; + } + } + + void MemoryCommit::Release() { + if (allocation && allocator) { + if (mapped_ptr) { + vmaUnmapMemory(allocator, allocation); + mapped_ptr = nullptr; + } + vmaFreeMemory(allocator, allocation); + } + allocation = nullptr; + allocator = nullptr; + memory = VK_NULL_HANDLE; + offset = 0; + size = 0; + } + + MemoryAllocator::MemoryAllocator(const Device &device_) + : device{device_}, allocator{device.GetAllocator()}, + properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, + buffer_image_granularity{ + device_.GetPhysical().GetProperties().limits.bufferImageGranularity} { + + // Preserve the previous "RenderDoc small heap" trimming behavior that we had in original vma minus the heap bug + if (device.HasDebuggingToolAttached()) + { + using namespace Common::Literals; + ForEachDeviceLocalHostVisibleHeap(device, [this](size_t heap_idx, VkMemoryHeap &heap) { + if (heap.size <= 256_MiB) { + for (u32 t = 0; t < properties.memoryTypeCount; ++t) { + if (properties.memoryTypes[t].heapIndex == heap_idx) { + valid_memory_types &= ~(1u << t); + } + } + } + }); + } + } + + MemoryAllocator::~MemoryAllocator() = default; + + vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo &ci) const + { + const VmaAllocationCreateInfo alloc_ci = { + .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, + .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, + .requiredFlags = 0, + .preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .memoryTypeBits = 0, + .pool = VK_NULL_HANDLE, + .pUserData = nullptr, + .priority = 0.f, }; - commits.insert(std::ranges::upper_bound(commits, *alloc, {}, &Range::begin), range); - return std::make_optional(this, *memory, *alloc, *alloc + size); + + VkImage handle{}; + VmaAllocation allocation{}; + vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr)); + return vk::Image(handle, ci.usage, *device.GetLogical(), allocator, allocation, + device.GetDispatchLoader()); } - void Free(u64 begin) { - const auto it = std::ranges::find(commits, begin, &Range::begin); - ASSERT_MSG(it != commits.end(), "Invalid commit"); - commits.erase(it); - if (commits.empty()) { - // Do not call any code involving 'this' after this call, the object will be destroyed - allocator->ReleaseMemory(this); - } + vk::Buffer + MemoryAllocator::CreateBuffer(const VkBufferCreateInfo &ci, MemoryUsage usage) const + { + const VmaAllocationCreateInfo alloc_ci = { + .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage), + .usage = MemoryUsageVma(usage), + .requiredFlags = 0, + .preferredFlags = MemoryUsagePreferredVmaFlags(usage), + .memoryTypeBits = usage == MemoryUsage::Stream ? 0u : valid_memory_types, + .pool = VK_NULL_HANDLE, + .pUserData = nullptr, + .priority = 0.f, + }; + + VkBuffer handle{}; + VmaAllocationInfo alloc_info{}; + VmaAllocation allocation{}; + VkMemoryPropertyFlags property_flags{}; + + vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info)); + vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags); + + u8 *data = reinterpret_cast(alloc_info.pMappedData); + const std::span mapped_data = data ? std::span{data, ci.size} : std::span{}; + const bool is_coherent = (property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0; + + return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, + is_coherent, + device.GetDispatchLoader()); } - [[nodiscard]] std::span Map() { - if (memory_mapped_span.empty()) { - u8* const raw_pointer = memory.Map(0, allocation_size); - memory_mapped_span = std::span(raw_pointer, allocation_size); - } - return memory_mapped_span; - } + MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements &reqs, MemoryUsage usage) + { + const auto vma_usage = MemoryUsageVma(usage); + VmaAllocationCreateInfo ci{}; + ci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage); + ci.usage = vma_usage; + ci.memoryTypeBits = reqs.memoryTypeBits & valid_memory_types; + ci.requiredFlags = 0; + ci.preferredFlags = MemoryUsagePreferredVmaFlags(usage); - /// Returns whether this allocation is compatible with the arguments. - [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { - return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0; - } + VmaAllocation a{}; + VmaAllocationInfo info{}; + VkResult res = vmaAllocateMemory(allocator, &reqs, &ci, &a, &info); -private: - [[nodiscard]] static constexpr u32 ShiftType(u32 type) { - return 1U << type; - } + if (res != VK_SUCCESS) { + // Relax 1: drop budget constraint + auto ci2 = ci; + ci2.flags &= ~VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT; + res = vmaAllocateMemory(allocator, &reqs, &ci2, &a, &info); - [[nodiscard]] std::optional FindFreeRegion(u64 size, u64 alignment) noexcept { - ASSERT(std::has_single_bit(alignment)); - const u64 alignment_log2 = std::countr_zero(alignment); - std::optional candidate; - u64 iterator = 0; - auto commit = commits.begin(); - while (iterator + size <= allocation_size) { - candidate = candidate.value_or(iterator); - if (commit == commits.end()) { - break; + // Relax 2: if we preferred DEVICE_LOCAL, drop that preference + if (res != VK_SUCCESS && (ci.preferredFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { + auto ci3 = ci2; + ci3.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + res = vmaAllocateMemory(allocator, &reqs, &ci3, &a, &info); } - if (commit->Contains(*candidate, size)) { - candidate = std::nullopt; + } + + vk::Check(res); + return MemoryCommit(allocator, a, info); + } + + MemoryCommit MemoryAllocator::Commit(const vk::Buffer &buffer, MemoryUsage usage) { + // Allocate memory appropriate for this buffer automatically + const auto vma_usage = MemoryUsageVma(usage); + + VmaAllocationCreateInfo ci{}; + ci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage); + ci.usage = vma_usage; + ci.requiredFlags = 0; + ci.preferredFlags = MemoryUsagePreferredVmaFlags(usage); + ci.pool = VK_NULL_HANDLE; + ci.pUserData = nullptr; + ci.priority = 0.0f; + + const VkBuffer raw = *buffer; + + VmaAllocation a{}; + VmaAllocationInfo info{}; + + // Let VMA infer memory requirements from the buffer + VkResult res = vmaAllocateMemoryForBuffer(allocator, raw, &ci, &a, &info); + + if (res != VK_SUCCESS) { + auto ci2 = ci; + ci2.flags &= ~VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT; + res = vmaAllocateMemoryForBuffer(allocator, raw, &ci2, &a, &info); + + if (res != VK_SUCCESS && (ci.preferredFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { + auto ci3 = ci2; + ci3.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + res = vmaAllocateMemoryForBuffer(allocator, raw, &ci3, &a, &info); } - iterator = Common::AlignUpLog2(commit->end, alignment_log2); - ++commit; } - return candidate; + + vk::Check(res); + vk::Check(vmaBindBufferMemory2(allocator, a, 0, raw, nullptr)); + return MemoryCommit(allocator, a, info); } - MemoryAllocator* const allocator; ///< Parent memory allocation. - const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. - const u64 allocation_size; ///< Size of this allocation. - const VkMemoryPropertyFlags property_flags; ///< Vulkan memory property flags. - const u32 shifted_memory_type; ///< Shifted Vulkan memory type. - std::vector commits; ///< All commit ranges done from this allocation. - std::span memory_mapped_span; ///< Memory mapped span. Empty if not queried before. -}; - -MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, - u64 end_) noexcept - : allocation{allocation_}, memory{memory_}, begin{begin_}, end{end_} {} - -MemoryCommit::~MemoryCommit() { - Release(); -} - -MemoryCommit& MemoryCommit::operator=(MemoryCommit&& rhs) noexcept { - Release(); - allocation = std::exchange(rhs.allocation, nullptr); - memory = rhs.memory; - begin = rhs.begin; - end = rhs.end; - span = std::exchange(rhs.span, std::span{}); - return *this; -} - -MemoryCommit::MemoryCommit(MemoryCommit&& rhs) noexcept - : allocation{std::exchange(rhs.allocation, nullptr)}, memory{rhs.memory}, begin{rhs.begin}, - end{rhs.end}, span{std::exchange(rhs.span, std::span{})} {} - -std::span MemoryCommit::Map() { - if (span.empty()) { - span = allocation->Map().subspan(begin, end - begin); - } - return span; -} - -void MemoryCommit::Release() { - if (allocation) { - allocation->Free(begin); - } -} - -MemoryAllocator::MemoryAllocator(const Device& device_) - : device{device_}, allocator{device.GetAllocator()}, - properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, - buffer_image_granularity{ - device_.GetPhysical().GetProperties().limits.bufferImageGranularity} { - // GPUs not supporting rebar may only have a region with less than 256MB host visible/device - // local memory. In that case, opening 2 RenderDoc captures side-by-side is not possible due to - // the heap running out of memory. With RenderDoc attached and only a small host/device region, - // only allow the stream buffer in this memory heap. - if (device.HasDebuggingToolAttached()) { - using namespace Common::Literals; - ForEachDeviceLocalHostVisibleHeap(device, [this](size_t index, VkMemoryHeap& heap) { - if (heap.size <= 256_MiB) { - valid_memory_types &= ~(1u << index); - } - }); - } -} - -MemoryAllocator::~MemoryAllocator() = default; - -vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { - const VmaAllocationCreateInfo alloc_ci = { - .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, - .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, - .requiredFlags = 0, - .preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - .memoryTypeBits = 0, - .pool = VK_NULL_HANDLE, - .pUserData = nullptr, - .priority = 0.f, - }; - - VkImage handle{}; - VmaAllocation allocation{}; - - vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr)); - - return vk::Image(handle, ci.usage, *device.GetLogical(), allocator, allocation, - device.GetDispatchLoader()); -} - -vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const { - const VmaAllocationCreateInfo alloc_ci = { - .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage), - .usage = MemoryUsageVma(usage), - .requiredFlags = 0, - .preferredFlags = MemoryUsagePreferredVmaFlags(usage), - .memoryTypeBits = usage == MemoryUsage::Stream ? 0u : valid_memory_types, - .pool = VK_NULL_HANDLE, - .pUserData = nullptr, - .priority = 0.f, - }; - - VkBuffer handle{}; - VmaAllocationInfo alloc_info{}; - VmaAllocation allocation{}; - VkMemoryPropertyFlags property_flags{}; - - vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info)); - vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags); - - u8* data = reinterpret_cast(alloc_info.pMappedData); - const std::span mapped_data = data ? std::span{data, ci.size} : std::span{}; - const bool is_coherent = property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - - return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, is_coherent, - device.GetDispatchLoader()); -} - -MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { - // Find the fastest memory flags we can afford with the current requirements - const u32 type_mask = requirements.memoryTypeBits; - const VkMemoryPropertyFlags usage_flags = MemoryUsagePropertyFlags(usage); - const VkMemoryPropertyFlags flags = MemoryPropertyFlags(type_mask, usage_flags); - if (std::optional commit = TryCommit(requirements, flags)) { - return std::move(*commit); - } - // Commit has failed, allocate more memory. - const u64 chunk_size = AllocationChunkSize(requirements.size); - if (!TryAllocMemory(flags, type_mask, chunk_size)) { - // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. - throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); - } - // Commit again, this time it won't fail since there's a fresh allocation above. - // If it does, there's a bug. - return TryCommit(requirements, flags).value(); - } - -bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { - const auto type_opt = FindType(flags, type_mask); - if (!type_opt) { - return false; - } - - // Adreno stands firm - const u64 aligned_size = (device.GetDriverID() == VK_DRIVER_ID_QUALCOMM_PROPRIETARY) ? - Common::AlignUp(size, 4096) : - size; - - vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = aligned_size, - .memoryTypeIndex = *type_opt, - }); - - if (!memory) { - return false; - } - - allocations.push_back( - std::make_unique(this, std::move(memory), flags, aligned_size, *type_opt)); - return true; -} - -void MemoryAllocator::ReleaseMemory(MemoryAllocation* alloc) { - const auto it = std::ranges::find(allocations, alloc, &std::unique_ptr::get); - ASSERT(it != allocations.end()); - allocations.erase(it); -} - -std::optional MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags flags) { - // Conservative, spec-compliant alignment for suballocation - VkDeviceSize eff_align = requirements.alignment; - const auto& limits = device.GetPhysical().GetProperties().limits; - if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - !(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { - // Non-coherent memory must be invalidated on atom boundary - if (limits.nonCoherentAtomSize > eff_align) eff_align = limits.nonCoherentAtomSize; - } - // Separate buffers to avoid stalls on tilers - if (buffer_image_granularity > eff_align) { - eff_align = buffer_image_granularity; - } - eff_align = std::bit_ceil(eff_align); - - for (auto& allocation : allocations) { - if (!allocation->IsCompatible(flags, requirements.memoryTypeBits)) { - continue; - } - if (auto commit = allocation->Commit(requirements.size, eff_align)) { - return commit; - } - } - if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) { - // Look for non device local commits on failure - return TryCommit(requirements, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - } - return std::nullopt; -} - -VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, - VkMemoryPropertyFlags flags) const { - if (FindType(flags, type_mask)) { - // Found a memory type with those requirements - return flags; - } - if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0) { - // Remove host cached bit in case it's not supported - return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT); - } - if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) { - // Remove device local, if it's not supported by the requested resource - return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - } - ASSERT_MSG(false, "No compatible memory types found"); - return 0; -} - -std::optional MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const { - for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { - const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags; - if ((type_mask & (1U << type_index)) != 0 && (type_flags & flags) == flags) { - // The type matches in type and in the wanted properties. - return type_index; - } - } - // Failed to find index - return std::nullopt; -} - } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index 38a182bcba..581f2e66d2 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -6,138 +9,134 @@ #include #include #include + #include "common/common_types.h" #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_wrapper.h" - -VK_DEFINE_HANDLE(VmaAllocator) +#include "video_core/vulkan_common/vma.h" namespace Vulkan { -class Device; -class MemoryMap; -class MemoryAllocation; + class Device; /// Hints and requirements for the backing memory type of a commit -enum class MemoryUsage { - DeviceLocal, ///< Requests device local host visible buffer, falling back to device local - ///< memory. - Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads - Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks - Stream, ///< Requests device local host visible buffer, falling back host memory. -}; + enum class MemoryUsage { + DeviceLocal, ///< Requests device local host visible buffer, falling back to device local memory. + Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads + Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks + Stream, ///< Requests device local host visible buffer, falling back host memory. + }; -template -void ForEachDeviceLocalHostVisibleHeap(const Device& device, F&& f) { - auto memory_props = device.GetPhysical().GetMemoryProperties().memoryProperties; - for (size_t i = 0; i < memory_props.memoryTypeCount; i++) { - auto& memory_type = memory_props.memoryTypes[i]; - if ((memory_type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) && - (memory_type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { - f(memory_type.heapIndex, memory_props.memoryHeaps[memory_type.heapIndex]); + template + void ForEachDeviceLocalHostVisibleHeap(const Device &device, F &&f) { + auto memory_props = device.GetPhysical().GetMemoryProperties().memoryProperties; + for (size_t i = 0; i < memory_props.memoryTypeCount; i++) { + auto &memory_type = memory_props.memoryTypes[i]; + if ((memory_type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) && + (memory_type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + f(memory_type.heapIndex, memory_props.memoryHeaps[memory_type.heapIndex]); + } } } -} -/// Ownership handle of a memory commitment. -/// Points to a subregion of a memory allocation. -class MemoryCommit { -public: - explicit MemoryCommit() noexcept = default; - explicit MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, - u64 end_) noexcept; - ~MemoryCommit(); +/// Ownership handle of a memory commitment (real VMA allocation). + class MemoryCommit { + public: + MemoryCommit() noexcept = default; - MemoryCommit& operator=(MemoryCommit&&) noexcept; - MemoryCommit(MemoryCommit&&) noexcept; + MemoryCommit(VmaAllocator allocator, VmaAllocation allocation, + const VmaAllocationInfo &info) noexcept; - MemoryCommit& operator=(const MemoryCommit&) = delete; - MemoryCommit(const MemoryCommit&) = delete; + ~MemoryCommit(); - /// Returns a host visible memory map. - /// It will map the backing allocation if it hasn't been mapped before. - std::span Map(); + MemoryCommit(const MemoryCommit &) = delete; - /// Returns the Vulkan memory handler. - VkDeviceMemory Memory() const { - return memory; - } + MemoryCommit &operator=(const MemoryCommit &) = delete; - /// Returns the start position of the commit relative to the allocation. - VkDeviceSize Offset() const { - return static_cast(begin); - } + MemoryCommit(MemoryCommit &&) noexcept; -private: - void Release(); + MemoryCommit &operator=(MemoryCommit &&) noexcept; - MemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. - VkDeviceMemory memory{}; ///< Vulkan device memory handler. - u64 begin{}; ///< Beginning offset in bytes to where the commit exists. - u64 end{}; ///< Offset in bytes where the commit ends. - std::span span; ///< Host visible memory span. Empty if not queried before. -}; + [[nodiscard]] std::span Map(); + + [[nodiscard]] std::span Map() const; + + void Unmap(); + + explicit operator bool() const noexcept { return allocation != nullptr; } + + VkDeviceMemory Memory() const noexcept { return memory; } + + VkDeviceSize Offset() const noexcept { return offset; } + + VkDeviceSize Size() const noexcept { return size; } + + VmaAllocation Allocation() const noexcept { return allocation; } + + private: + void Release(); + + VmaAllocator allocator{}; ///< VMA allocator + VmaAllocation allocation{}; ///< VMA allocation handle + VkDeviceMemory memory{}; ///< Underlying VkDeviceMemory chosen by VMA + VkDeviceSize offset{}; ///< Offset of this allocation inside VkDeviceMemory + VkDeviceSize size{}; ///< Size of the allocation + void *mapped_ptr{}; ///< Optional persistent mapped pointer + }; /// Memory allocator container. /// Allocates and releases memory allocations on demand. -class MemoryAllocator { - friend MemoryAllocation; + class MemoryAllocator { + public: + /** + * Construct memory allocator + * + * @param device_ Device to allocate from + * + * @throw vk::Exception on failure + */ + explicit MemoryAllocator(const Device &device_); -public: - /** - * Construct memory allocator - * - * @param device_ Device to allocate from - * - * @throw vk::Exception on failure - */ - explicit MemoryAllocator(const Device& device_); - ~MemoryAllocator(); + ~MemoryAllocator(); - MemoryAllocator& operator=(const MemoryAllocator&) = delete; - MemoryAllocator(const MemoryAllocator&) = delete; + MemoryAllocator &operator=(const MemoryAllocator &) = delete; - vk::Image CreateImage(const VkImageCreateInfo& ci) const; + MemoryAllocator(const MemoryAllocator &) = delete; - vk::Buffer CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const; + vk::Image CreateImage(const VkImageCreateInfo &ci) const; - /** - * Commits a memory with the specified requirements. - * - * @param requirements Requirements returned from a Vulkan call. - * @param usage Indicates how the memory will be used. - * - * @returns A memory commit. - */ - MemoryCommit Commit(const VkMemoryRequirements& requirements, MemoryUsage usage); + vk::Buffer CreateBuffer(const VkBufferCreateInfo &ci, MemoryUsage usage) const; - /// Commits memory required by the buffer and binds it. - MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); + /** + * Commits a memory with the specified requirements. + * + * @param requirements Requirements returned from a Vulkan call. + * @param usage Indicates how the memory will be used. + * + * @returns A memory commit. + */ + MemoryCommit Commit(const VkMemoryRequirements &requirements, MemoryUsage usage); -private: - /// Tries to allocate a chunk of memory. - bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); + /// Commits memory required by the buffer and binds it (for buffers created outside VMA). + MemoryCommit Commit(const vk::Buffer &buffer, MemoryUsage usage); - /// Releases a chunk of memory. - void ReleaseMemory(MemoryAllocation* alloc); + private: + static bool IsAutoUsage(VmaMemoryUsage u) noexcept { + switch (u) { + case VMA_MEMORY_USAGE_AUTO: + case VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE: + case VMA_MEMORY_USAGE_AUTO_PREFER_HOST: + return true; + default: + return false; + } + } - /// Tries to allocate a memory commit. - std::optional TryCommit(const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags flags); - - /// Returns the fastest compatible memory property flags from the wanted flags. - VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const; - - /// Returns index to the fastest memory type compatible with the passed requirements. - std::optional FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; - - const Device& device; ///< Device handle. - VmaAllocator allocator; ///< Vma allocator. - const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. - std::vector> allocations; ///< Current allocations. - VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers - // and optimal images - u32 valid_memory_types{~0u}; -}; + const Device &device; ///< Device handle. + VmaAllocator allocator; ///< VMA allocator. + const VkPhysicalDeviceMemoryProperties properties; ///< Physical device memory properties. + VkDeviceSize buffer_image_granularity; ///< Adjacent buffer/image granularity + u32 valid_memory_types{~0u}; + }; } // namespace Vulkan From 7b1f7c21bb5f92625924e6b2342fcb86c04e30c5 Mon Sep 17 00:00:00 2001 From: innix Date: Mon, 1 Sep 2025 09:23:03 +0200 Subject: [PATCH 36/44] [macOS, compat] Allow games to boot in MacOS (#372) This fixes the crashes on game launch caused by MacOS not being present in host_manager.cpp and enables primitiveRestart for MoltenVK to suppress a bunch of errors given in the log about MoltenVK requiring primitiveRestart. Fixes an crash when switching kingdoms in Mario Odyssey as well EDS is forced to 0, otherwise games do not show graphics Note: For now only dynarmicc is working, performance will be slow Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/372 Reviewed-by: Lizzie Reviewed-by: CamilleLaVey Reviewed-by: MaranBr Co-authored-by: innix Co-committed-by: innix --- src/common/host_memory.cpp | 29 ++++++++++--- src/common/settings.h | 2 + src/video_core/renderer_vulkan/blit_image.cpp | 41 ++++++++++++------- .../renderer_vulkan/present/util.cpp | 4 +- .../renderer_vulkan/vk_graphics_pipeline.cpp | 6 ++- .../vulkan_common/vulkan_device.cpp | 16 +++++++- src/video_core/vulkan_common/vulkan_device.h | 4 ++ .../vulkan_common/vulkan_wrapper.cpp | 2 + .../configure_graphics_extensions.cpp | 4 ++ 9 files changed, 82 insertions(+), 26 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index e70ac216cb..15a198e216 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -12,7 +12,7 @@ #include #include "common/dynamic_library.h" -#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) // ^^^ Windows ^^^ vvv Linux vvv +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) || defined(__APPLE__) // ^^^ Windows ^^^ vvv POSIX vvv #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -20,10 +20,18 @@ #include #include #include -#include #include #include "common/scope_exit.h" +#if defined(__linux__) +#include +#elif defined(__APPLE__) +#include +#include +#include +#include +#endif + // FreeBSD #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 @@ -32,8 +40,12 @@ #ifndef MAP_ALIGNED_SUPER #define MAP_ALIGNED_SUPER 0 #endif +// macOS +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif -#endif // ^^^ Linux ^^^ +#endif // ^^^ POSIX ^^^ #include #include @@ -372,7 +384,7 @@ private: std::unordered_map placeholder_host_pointers; ///< Placeholder backing offset }; -#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) // ^^^ Windows ^^^ vvv Linux vvv +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) || defined(__APPLE__) // ^^^ Windows ^^^ vvv POSIX vvv #ifdef ARCHITECTURE_arm64 @@ -489,6 +501,13 @@ public: #elif defined(__FreeBSD__) && __FreeBSD__ < 13 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 fd = shm_open(SHM_ANON, O_RDWR, 0600); +#elif defined(__APPLE__) + // macOS doesn't have memfd_create, use anonymous temporary file + char template_path[] = "/tmp/eden_mem_XXXXXX"; + fd = mkstemp(template_path); + if (fd >= 0) { + unlink(template_path); + } #else fd = memfd_create("HostMemory", 0); #endif @@ -645,7 +664,7 @@ private: FreeRegionManager free_manager{}; }; -#else // ^^^ Linux ^^^ vvv Generic vvv +#else // ^^^ POSIX ^^^ vvv Generic vvv class HostMemory::Impl { public: diff --git a/src/common/settings.h b/src/common/settings.h index 64545d10ff..b657dc8658 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -551,6 +551,8 @@ struct Values { 3, #elif defined (ANDROID) 0, +#elif defined (__APPLE__) + 0, #else 2, #endif diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 596323fb32..37213912e3 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -102,13 +102,16 @@ constexpr VkPipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREAT .vertexAttributeDescriptionCount = 0, .pVertexAttributeDescriptions = nullptr, }; -constexpr VkPipelineInputAssemblyStateCreateInfo PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - .primitiveRestartEnable = VK_FALSE, -}; + +VkPipelineInputAssemblyStateCreateInfo GetPipelineInputAssemblyStateCreateInfo(const Device& device) { + return VkPipelineInputAssemblyStateCreateInfo{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = device.IsMoltenVK() ? VK_TRUE : VK_FALSE, + }; +} constexpr VkPipelineViewportStateCreateInfo PIPELINE_VIEWPORT_STATE_CREATE_INFO{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pNext = nullptr, @@ -802,6 +805,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe .pAttachments = &blend_attachment, .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, }; + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -809,7 +813,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe .stageCount = static_cast(stages.size()), .pStages = stages.data(), .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, @@ -833,6 +837,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip } blit_depth_stencil_keys.push_back(key); const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag); + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -840,7 +845,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip .stageCount = static_cast(stages.size()), .pStages = stages.data(), .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, @@ -885,6 +890,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel .pAttachments = &color_blend_attachment_state, .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, }; + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -892,7 +898,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel .stageCount = static_cast(stages.size()), .pStages = stages.data(), .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, @@ -940,6 +946,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline( .minDepthBounds = 0.0f, .maxDepthBounds = 0.0f, }; + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -947,7 +954,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline( .stageCount = static_cast(stages.size()), .pStages = stages.data(), .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, @@ -970,6 +977,7 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend } VkShaderModule frag_shader = *convert_float_to_depth_frag; const std::array stages = MakeStages(*full_screen_vert, frag_shader); + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); pipeline = device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -977,7 +985,7 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend .stageCount = static_cast(stages.size()), .pStages = stages.data(), .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, @@ -999,6 +1007,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend } VkShaderModule frag_shader = *convert_depth_to_float_frag; const std::array stages = MakeStages(*full_screen_vert, frag_shader); + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); pipeline = device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -1006,7 +1015,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend .stageCount = static_cast(stages.size()), .pStages = stages.data(), .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, @@ -1029,6 +1038,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren return; } const std::array stages = MakeStages(*full_screen_vert, *module); + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); pipeline = device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -1036,7 +1046,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren .stageCount = static_cast(stages.size()), .pStages = stages.data(), .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, @@ -1070,6 +1080,7 @@ void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass rende VkShaderModule frag_shader = is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag; const std::array stages = MakeStages(*full_screen_vert, frag_shader); + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); pipeline = device.GetLogical().CreateGraphicsPipeline({ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, @@ -1077,7 +1088,7 @@ void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass rende .stageCount = static_cast(stages.size()), .pStages = stages.data(), .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pInputAssemblyState = &input_assembly_ci, .pTessellationState = nullptr, .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, diff --git a/src/video_core/renderer_vulkan/present/util.cpp b/src/video_core/renderer_vulkan/present/util.cpp index 6874bbae99..07b6a41c5c 100644 --- a/src/video_core/renderer_vulkan/present/util.cpp +++ b/src/video_core/renderer_vulkan/present/util.cpp @@ -400,12 +400,12 @@ static vk::Pipeline CreateWrappedPipelineImpl( .pVertexAttributeDescriptions = nullptr, }; - constexpr VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .pNext = nullptr, .flags = 0, .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - .primitiveRestartEnable = VK_FALSE, + .primitiveRestartEnable = device.IsMoltenVK() ? VK_TRUE : VK_FALSE, }; constexpr VkPipelineViewportStateCreateInfo viewport_state_ci{ diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 0226eb2c14..dc068c5e52 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -635,14 +635,16 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .flags = 0, .topology = input_assembly_topology, .primitiveRestartEnable = - dynamic.primitive_restart_enable != 0 && + // MoltenVK/Metal always has primitive restart enabled and cannot disable it + device.IsMoltenVK() ? VK_TRUE : + (dynamic.primitive_restart_enable != 0 && ((input_assembly_topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST && device.IsTopologyListPrimitiveRestartSupported()) || SupportsPrimitiveRestart(input_assembly_topology) || (input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST && device.IsPatchListPrimitiveRestartSupported())) ? VK_TRUE - : VK_FALSE, + : VK_FALSE), }; const VkPipelineTessellationStateCreateInfo tessellation_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 4d74bf00a5..6fdf1e7874 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -725,6 +725,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR dynamic_state3_enables = true; } + if (is_mvk && Settings::values.dyna_state.GetValue() != 0) { + LOG_WARNING(Render_Vulkan, "MoltenVK detected: Forcing dynamic state to 0 to prevent black screen issues"); + Settings::values.dyna_state.SetValue(0); + } + if (Settings::values.dyna_state.GetValue() == 0) { must_emulate_scaled_formats = true; LOG_INFO(Render_Vulkan, "Dynamic state is disabled (dyna_state = 0), forcing scaled format emulation ON"); @@ -1096,8 +1101,15 @@ bool Device::GetSuitability(bool requires_swapchain) { // Some features are mandatory. Check those. #define CHECK_FEATURE(feature, name) \ if (!features.feature.name) { \ - LOG_ERROR(Render_Vulkan, "Missing required feature {}", #name); \ - suitable = false; \ + if (IsMoltenVK() && (strcmp(#name, "geometryShader") == 0 || \ + strcmp(#name, "logicOp") == 0 || \ + strcmp(#name, "shaderCullDistance") == 0 || \ + strcmp(#name, "wideLines") == 0)) { \ + LOG_INFO(Render_Vulkan, "MoltenVK missing feature {} - using fallback", #name); \ + } else { \ + LOG_ERROR(Render_Vulkan, "Missing required feature {}", #name); \ + suitable = false; \ + } \ } #define LOG_FEATURE(feature, name) \ diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 9b78f2e599..bd54144480 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -717,6 +717,10 @@ public: return properties.driver.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY; } + bool IsMoltenVK() const noexcept { + return properties.driver.driverID == VK_DRIVER_ID_MOLTENVK; + } + NvidiaArchitecture GetNvidiaArch() const noexcept { return nvidia_arch; } diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 106630182f..949b91499d 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -580,6 +580,7 @@ DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) c case VK_SUCCESS: return DescriptorSets(std::move(sets), num, owner, handle, *dld); case VK_ERROR_OUT_OF_POOL_MEMORY: + case VK_ERROR_FRAGMENTED_POOL: return {}; default: throw Exception(result); @@ -604,6 +605,7 @@ CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLev case VK_SUCCESS: return CommandBuffers(std::move(buffers), num_buffers, owner, handle, *dld); case VK_ERROR_OUT_OF_POOL_MEMORY: + case VK_ERROR_FRAGMENTED_POOL: return {}; default: throw Exception(result); diff --git a/src/yuzu/configuration/configure_graphics_extensions.cpp b/src/yuzu/configuration/configure_graphics_extensions.cpp index c8dee6b073..322fa9ea08 100644 --- a/src/yuzu/configuration/configure_graphics_extensions.cpp +++ b/src/yuzu/configuration/configure_graphics_extensions.cpp @@ -60,6 +60,10 @@ void ConfigureGraphicsExtensions::Setup(const ConfigurationShared::Builder& buil if (setting->Id() == Settings::values.dyna_state.Id()) { widget->slider->setTickInterval(1); widget->slider->setTickPosition(QSlider::TicksAbove); +#ifdef __APPLE__ + widget->setEnabled(false); + widget->setToolTip(tr("Extended Dynamic State is disabled on macOS due to MoltenVK compatibility issues that cause black screens.")); +#endif } } From 3d7bfcfb0a260c12b7d50a1ae4f5ad04ca27672e Mon Sep 17 00:00:00 2001 From: innix Date: Mon, 1 Sep 2025 14:18:30 +0200 Subject: [PATCH 37/44] [android]: Force app to use the displays max set refresh rate (#373) Since Android 15, google automatically forces "games" to be 60 hrz. This ensures the display's max refresh rate is actually used. Tested on a Google Pixel 7 Pro with Android 16 Co-authored-by: innix Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/373 Co-committed-by: innix --- .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index fffaa1e3ba..e8dd566f79 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -38,6 +38,7 @@ import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.InstallResult +import android.os.Build import org.yuzu.yuzu_emu.model.TaskState import org.yuzu.yuzu_emu.model.TaskViewModel import org.yuzu.yuzu_emu.utils.* @@ -47,6 +48,7 @@ import java.io.BufferedOutputStream import java.util.zip.ZipEntry import java.util.zip.ZipInputStream import androidx.core.content.edit +import kotlin.text.compareTo class MainActivity : AppCompatActivity(), ThemeProvider { private lateinit var binding: ActivityMainBinding @@ -110,6 +112,19 @@ class MainActivity : AppCompatActivity(), ThemeProvider { binding = ActivityMainBinding.inflate(layoutInflater) + // Since Android 15, google automatically forces "games" to be 60 hrz + // This ensures the display's max refresh rate is actually used + display?.let { + val supportedModes = it.supportedModes + val maxRefreshRate = supportedModes.maxByOrNull { mode -> mode.refreshRate } + + if (maxRefreshRate != null) { + val layoutParams = window.attributes + layoutParams.preferredDisplayModeId = maxRefreshRate.modeId + window.attributes = layoutParams + } + } + setContentView(binding.root) checkAndRequestBluetoothPermissions() From 837fffccf49e868db022dfc5184dd2b58c1b5053 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Sep 2025 21:14:54 +0200 Subject: [PATCH 38/44] [cmake] fix gh dependencies (#377) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/377 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- .patch/unordered-dense/0001-cmake.patch | 22 ++++++++++++++++++++++ externals/cpmfile.json | 8 ++++---- src/dynarmic/externals/cpmfile.json | 5 ++++- 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 .patch/unordered-dense/0001-cmake.patch diff --git a/.patch/unordered-dense/0001-cmake.patch b/.patch/unordered-dense/0001-cmake.patch new file mode 100644 index 0000000000..39e7794b1f --- /dev/null +++ b/.patch/unordered-dense/0001-cmake.patch @@ -0,0 +1,22 @@ +From e59d30b7b12e1d04cc2fc9c6219e35bda447c17e Mon Sep 17 00:00:00 2001 +From: Lizzie <159065448+Lizzie841@users.noreply.github.com> +Date: Fri, 16 May 2025 04:12:13 +0100 +Subject: [PATCH] Update CMakeLists.txt + +--- + CMakeLists.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b5f4c4f..c5c6f31 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -24,7 +24,7 @@ target_include_directories( + + target_compile_features(unordered_dense INTERFACE cxx_std_17) + +-if(_unordered_dense_is_toplevel_project) ++if(_unordered_dense_is_toplevel_project OR UNORDERED_DENSE_INSTALL) + # locations are provided by GNUInstallDirs + install( + TARGETS unordered_dense diff --git a/externals/cpmfile.json b/externals/cpmfile.json index effcbcc01f..bbc6b056c1 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -74,14 +74,14 @@ }, "xbyak_sun": { "package": "xbyak", - "repo": "Lizzie841/xbyak", - "sha": "51f507b0b3", - "hash": "4a29a3c2f97f7d5adf667a21a008be03c951fb6696b0d7ba27e7e4afa037bc76eb5e059bb84860e01baf741d4d3ac851b840cd54c99d038812fbe0f1fa6d38a4", + "repo": "herumi/xbyak", + "sha": "9bb219333a", + "hash": "303165d45c8c19387ec49d9fda7d7a4e0d86d4c0153898c23f25ce2d58ece567f44c0bbbfe348239b933edb6e1a1e34f4bc1c0ab3a285bee5da0e548879387b0", "bundled": true }, "xbyak": { "package": "xbyak", - "repo": "Lizzie841/xbyak", + "repo": "herumi/xbyak", "sha": "4e44f4614d", "hash": "5824e92159e07fa36a774aedd3b3ef3541d0241371d522cffa4ab3e1f215fa5097b1b77865b47b2481376c704fa079875557ea463ca63d0a7fd6a8a20a589e70", "bundled": true diff --git a/src/dynarmic/externals/cpmfile.json b/src/dynarmic/externals/cpmfile.json index b934856af2..cebcdf5232 100644 --- a/src/dynarmic/externals/cpmfile.json +++ b/src/dynarmic/externals/cpmfile.json @@ -16,12 +16,15 @@ }, "unordered-dense": { "package": "unordered_dense", - "repo": "Lizzie841/unordered_dense", + "repo": "martinus/unordered_dense", "sha": "e59d30b7b1", "hash": "71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0", "find_args": "CONFIG", "options": [ "UNORDERED_DENSE_INSTALL OFF" + ], + "patches": [ + "0001-cmake.patch" ] }, "zycore": { From e3cb1cd134ea6907f4279eb6bda1f1ede817791a Mon Sep 17 00:00:00 2001 From: Bix Date: Mon, 1 Sep 2025 22:25:26 +0200 Subject: [PATCH 39/44] [Hotfix] Update recommended driver from T21 to T22 (#379) Help crueters workload. Signed-off-by: Bix Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/379 Reviewed-by: crueter Co-authored-by: Bix Co-committed-by: Bix --- .../java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt index b8d0f2197e..dea762dc17 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt @@ -79,7 +79,7 @@ class DriverFetcherFragment : Fragment() { IntRange(600, 639) to "Mr. Purple EOL-24.3.4", IntRange(640, 699) to "Mr. Purple T19", IntRange(700, 710) to "KIMCHI 25.2.0_r5", - IntRange(711, 799) to "Mr. Purple T21", + IntRange(711, 799) to "Mr. Purple T22", IntRange(800, 899) to "GameHub Adreno 8xx", IntRange(900, Int.MAX_VALUE) to "Unsupported" ) From 421e5073d2a0200ac9145fd4a8420a7bbac97750 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 2 Sep 2025 03:25:27 +0200 Subject: [PATCH 40/44] [cmake] fix unordered-dense deps (#380) Signed-off-by: lizzie Co-authored-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/380 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- externals/CMakeLists.txt | 10 +--------- externals/cpmfile.json | 13 +++++++++++++ src/dynarmic/externals/CMakeLists.txt | 10 +++++----- src/dynarmic/externals/cpmfile.json | 13 ------------- src/video_core/CMakeLists.txt | 3 ++- 5 files changed, 21 insertions(+), 28 deletions(-) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index f66423a672..e917e4e7d8 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -96,15 +96,7 @@ if (ENABLE_WEB_SERVICE) endif() # unordered_dense -AddPackage( - NAME unordered_dense - REPO "Lizzie841/unordered_dense" - SHA e59d30b7b1 - HASH 71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0 - FIND_PACKAGE_ARGUMENTS "CONFIG" - OPTIONS - "UNORDERED_DENSE_INSTALL OFF" -) +AddJsonPackage(unordered-dense) # FFMpeg if (YUZU_USE_BUNDLED_FFMPEG) diff --git a/externals/cpmfile.json b/externals/cpmfile.json index bbc6b056c1..4bc4a97ca4 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -105,5 +105,18 @@ "sha": "2bc873e53c", "hash": "02329058a7f9cf7d5039afaae5ab170d9f42f60f4c01e21eaf4f46073886922b057a9ae30eeac040b3ac182f51b9c1bfe9fe1050a2c9f6ce567a1a9a0ec2c768", "bundled": true + }, + "unordered-dense": { + "package": "unordered_dense", + "repo": "martinus/unordered_dense", + "sha": "73f3cbb237", + "hash": "c08c03063938339d61392b687562909c1a92615b6ef39ec8df19ea472aa6b6478e70d7d5e33d4a27b5d23f7806daf57fe1bacb8124c8a945c918c7663a9e8532", + "find_args": "CONFIG", + "options": [ + "UNORDERED_DENSE_INSTALL OFF" + ], + "patches": [ + "0001-cmake.patch" + ] } } diff --git a/src/dynarmic/externals/CMakeLists.txt b/src/dynarmic/externals/CMakeLists.txt index 23cfd42236..73c97d8f06 100644 --- a/src/dynarmic/externals/CMakeLists.txt +++ b/src/dynarmic/externals/CMakeLists.txt @@ -60,12 +60,12 @@ AddJsonPackage( # endif() # endif() -# unordered_dense +# unordered_dense - already in root -AddJsonPackage( - NAME unordered-dense - BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} -) +# AddJsonPackage( +# NAME unordered-dense +# BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} +# ) # xbyak # uncomment if in an independent repo diff --git a/src/dynarmic/externals/cpmfile.json b/src/dynarmic/externals/cpmfile.json index cebcdf5232..e9406cbe81 100644 --- a/src/dynarmic/externals/cpmfile.json +++ b/src/dynarmic/externals/cpmfile.json @@ -14,19 +14,6 @@ "MCL_INSTALL OFF" ] }, - "unordered-dense": { - "package": "unordered_dense", - "repo": "martinus/unordered_dense", - "sha": "e59d30b7b1", - "hash": "71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0", - "find_args": "CONFIG", - "options": [ - "UNORDERED_DENSE_INSTALL OFF" - ], - "patches": [ - "0001-cmake.patch" - ] - }, "zycore": { "package": "Zycore", "repo": "zyantific/zycore-c", diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 89fe7a35f9..8131d42aae 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -332,7 +332,8 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS}) add_dependencies(video_core host_shaders) target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) -target_link_libraries(video_core PRIVATE sirit Vulkan::Headers Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator) +target_link_libraries(video_core PRIVATE sirit Vulkan::Headers Vulkan::UtilityHeaders) +target_link_libraries(video_core PUBLIC GPUOpen::VulkanMemoryAllocator) if (ENABLE_NSIGHT_AFTERMATH) if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) From 7a9e7e3bd18ac87686d142fb4c1929f41cc3884b Mon Sep 17 00:00:00 2001 From: xbzk Date: Wed, 3 Sep 2025 03:55:19 +0200 Subject: [PATCH 41/44] [android] minor ui tweaks + translations (#326) CHANGES: fix drawer pause/unpause sync (upon leaving/returning to app) add quick toggle controller overlay to drawer (for players with multiple gear style) added translation for emulation_hide_overlay changed Show overlay to Show controller in all langs added missing translations for values-de WHAT TO TEST: sync of pause/resume when you leave eden (screenshot, home, alt tab, etc). show controller toggle: if it works it works. Co-authored-by: Allison Cunha Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/326 Reviewed-by: crueter Co-authored-by: xbzk Co-committed-by: xbzk --- .../yuzu_emu/fragments/EmulationFragment.kt | 72 +++++++++++++++---- .../app/src/main/res/menu/menu_in_game.xml | 5 ++ .../app/src/main/res/values-ar/strings.xml | 3 +- .../app/src/main/res/values-ckb/strings.xml | 3 +- .../app/src/main/res/values-cs/strings.xml | 3 +- .../app/src/main/res/values-de/strings.xml | 7 ++ .../app/src/main/res/values-es/strings.xml | 3 +- .../app/src/main/res/values-fa/strings.xml | 3 +- .../app/src/main/res/values-fr/strings.xml | 3 +- .../app/src/main/res/values-he/strings.xml | 3 +- .../app/src/main/res/values-hu/strings.xml | 3 +- .../app/src/main/res/values-id/strings.xml | 3 +- .../app/src/main/res/values-it/strings.xml | 3 +- .../app/src/main/res/values-ja/strings.xml | 3 +- .../app/src/main/res/values-ko/strings.xml | 1 + .../app/src/main/res/values-nb/strings.xml | 3 +- .../app/src/main/res/values-pl/strings.xml | 3 +- .../src/main/res/values-pt-rBR/strings.xml | 3 +- .../src/main/res/values-pt-rPT/strings.xml | 3 +- .../app/src/main/res/values-ru/strings.xml | 3 +- .../app/src/main/res/values-sr/strings.xml | 3 +- .../app/src/main/res/values-uk/strings.xml | 3 +- .../app/src/main/res/values-vi/strings.xml | 3 +- .../src/main/res/values-zh-rCN/strings.xml | 3 +- .../src/main/res/values-zh-rTW/strings.xml | 3 +- .../app/src/main/res/values/strings.xml | 3 +- 26 files changed, 117 insertions(+), 34 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 96015e58ec..5cc912fbbe 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -509,6 +509,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { gpuModel = GpuDriverHelper.getGpuModel().toString() fwVersion = NativeLibrary.firmwareVersion() + updateQuickOverlayMenuEntry(BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()) + binding.surfaceEmulation.holder.addCallback(this) binding.doneControlConfig.setOnClickListener { stopConfiguringControls() } @@ -530,6 +532,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) binding.inGameMenu.requestFocus() emulationViewModel.setDrawerOpen(true) + updateQuickOverlayMenuEntry(BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()) } override fun onDrawerClosed(drawerView: View) { @@ -571,25 +574,24 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { R.id.menu_pause_emulation -> { if (emulationState.isPaused) { emulationState.run(false) - it.title = resources.getString(R.string.emulation_pause) - it.icon = ResourcesCompat.getDrawable( - resources, - R.drawable.ic_pause, - requireContext().theme - ) + updatePauseMenuEntry(false) } else { emulationState.pause() - it.title = resources.getString(R.string.emulation_unpause) - it.icon = ResourcesCompat.getDrawable( - resources, - R.drawable.ic_play, - requireContext().theme - ) + updatePauseMenuEntry(true) } binding.inGameMenu.requestFocus() true } + R.id.menu_quick_overlay -> { + val newState = !BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() + BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(newState) + updateQuickOverlayMenuEntry(newState) + binding.surfaceInputOverlay.refreshControls() + NativeConfig.saveGlobalConfig() + true + } + R.id.menu_settings -> { val action = HomeNavigationDirections.actionGlobalSettingsActivity( null, @@ -844,9 +846,50 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } } + private fun updateQuickOverlayMenuEntry(isVisible: Boolean) { + val menu = binding.inGameMenu.menu + val item = menu.findItem(R.id.menu_quick_overlay) + if (isVisible) { + item.title = getString(R.string.emulation_hide_overlay) + item.icon = ResourcesCompat.getDrawable( + resources, + R.drawable.ic_controller_disconnected, + requireContext().theme + ) + } else { + item.title = getString(R.string.emulation_show_overlay) + item.icon = ResourcesCompat.getDrawable( + resources, + R.drawable.ic_controller, + requireContext().theme + ) + } + } + + private fun updatePauseMenuEntry(isPaused: Boolean) { + val menu = binding.inGameMenu.menu + val pauseItem = menu.findItem(R.id.menu_pause_emulation) + if (isPaused) { + pauseItem.title = getString(R.string.emulation_unpause) + pauseItem.icon = ResourcesCompat.getDrawable( + resources, + R.drawable.ic_play, + requireContext().theme + ) + } else { + pauseItem.title = getString(R.string.emulation_pause) + pauseItem.icon = ResourcesCompat.getDrawable( + resources, + R.drawable.ic_pause, + requireContext().theme + ) + } + } + override fun onPause() { if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) { emulationState.pause() + updatePauseMenuEntry(true) } super.onPause() } @@ -869,6 +912,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { val socPosition = IntSetting.SOC_OVERLAY_POSITION.getInt() updateSocPosition(socPosition) + + binding.inGameMenu.post { + emulationState?.isPaused?.let { updatePauseMenuEntry(it) } + } } private fun resetInputOverlay() { @@ -1391,6 +1438,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { R.id.menu_show_overlay -> { it.isChecked = !it.isChecked BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(it.isChecked) + updateQuickOverlayMenuEntry(it.isChecked) binding.surfaceInputOverlay.refreshControls() true } diff --git a/src/android/app/src/main/res/menu/menu_in_game.xml b/src/android/app/src/main/res/menu/menu_in_game.xml index ce3f11f6e6..d45699638c 100644 --- a/src/android/app/src/main/res/menu/menu_in_game.xml +++ b/src/android/app/src/main/res/menu/menu_in_game.xml @@ -8,6 +8,11 @@ android:icon="@drawable/ic_pause" android:title="@string/emulation_pause" /> + + مركز العصا النسبي مزلاق الأسهم الاهتزازات الديناميكية - عرض التراكب + إظهار وحدة التحكم + إخفاء وحدة التحكم الكل ضبط التراكب الحجم diff --git a/src/android/app/src/main/res/values-ckb/strings.xml b/src/android/app/src/main/res/values-ckb/strings.xml index 221a197843..34b1ae6252 100644 --- a/src/android/app/src/main/res/values-ckb/strings.xml +++ b/src/android/app/src/main/res/values-ckb/strings.xml @@ -710,7 +710,8 @@ ناوەندی گێڕ بەنزیکەیی خلیسکانی 4 دوگمەکە لەرینەوەی پەنجەلێدان - نیشاندانی داپۆشەر + نیشاندانی کۆنتڕۆڵەر + پیشاندانی کۆنتڕۆڵەر گۆڕینی سەرجەم ڕێکخستنی داپۆشەر پێوەر diff --git a/src/android/app/src/main/res/values-cs/strings.xml b/src/android/app/src/main/res/values-cs/strings.xml index 61e389f9fc..293524271e 100644 --- a/src/android/app/src/main/res/values-cs/strings.xml +++ b/src/android/app/src/main/res/values-cs/strings.xml @@ -691,7 +691,8 @@ Relativní střed joysticku D-pad slide Haptická odezva - Zobrazit překryv + Zobrazit ovladač + Skrýt ovladač Přepnout vše Upravit překryv Měřítko diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index bff0b0379e..46ae9ba7fe 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml @@ -762,6 +762,13 @@ Wirklich fortfahren? Emulation beenden Fertig FPS Zähler + + Steuerung umschalten + Relativer Stick-Zentrum + D-Pad-Scrollen + Haptisches Feedback + Controller anzeigen + Controller ausblenden Alle umschalten Overlay anpassen Größe diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 888d6d1684..8712f455de 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -806,7 +806,8 @@ Centro relativo del stick Deslizamiento de la cruceta Toques hápticos - Mostrar overlay + Mostrar controlador + Ocultar controlador Alternar todo Ajustar overlay Escala diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml index 60b1626aa5..07ff8ff4e0 100644 --- a/src/android/app/src/main/res/values-fa/strings.xml +++ b/src/android/app/src/main/res/values-fa/strings.xml @@ -805,7 +805,8 @@ مرکز نسبی استیک لغزش دکمه‌های جهتی لرزش لمسی - نشان دادن نمایش روی صفحه + نمایش کنترلر + پنهان کردن کنترلر تغییر همه تنظیم نمایش روی صفحه مقیاس diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index fde02d1aa8..2e06ac98e1 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -854,7 +854,8 @@ Centre du stick relatif Glissement du D-pad Toucher haptique - Afficher l\'overlay + Afficher la manette + Masquer la manette Tout basculer Ajuster l\'overlay Échelle diff --git a/src/android/app/src/main/res/values-he/strings.xml b/src/android/app/src/main/res/values-he/strings.xml index 59312086e9..c0c835d633 100644 --- a/src/android/app/src/main/res/values-he/strings.xml +++ b/src/android/app/src/main/res/values-he/strings.xml @@ -739,7 +739,8 @@ מרכז ג׳ויסטיק יחסי החלקת D-pad רטט מגע - הצג את שכבת-העל + הצג בקר + הסתר בקר החלף הכל התאם את שכבת-העל קנה מידה diff --git a/src/android/app/src/main/res/values-hu/strings.xml b/src/android/app/src/main/res/values-hu/strings.xml index f95e2d3f97..46a5ac7cce 100644 --- a/src/android/app/src/main/res/values-hu/strings.xml +++ b/src/android/app/src/main/res/values-hu/strings.xml @@ -843,7 +843,8 @@ Irányítás átkapcsolása D-pad csúsztatása Érintés haptikája - Átfedés mutatása + Vezérlő megjelenítése + Vezérlő elrejtése Összes átkapcsolása Átfedés testreszabása Skálázás diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index dae77d53af..cffb526ad5 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -798,7 +798,8 @@ Pusat stick relatif Geser Dpad Haptik - Tampilkan Hamparan + Tampilkan Kontroler + Sembunyikan Kontroler Alihkan Semua Menyesuaikan Skala diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index dd184e9d9a..cb234cf61e 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml @@ -770,7 +770,8 @@ Centro relativo degli Stick DPad A Scorrimento Feedback Aptico - Mostra l\'overlay + Mostra l\'controller + Nascondi l\'controller Attiva/Disattiva tutto Regola l\'overlay Scala diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index 873d433fc0..abedb1e0bc 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml @@ -729,7 +729,8 @@ スティックを固定しない 十字キーをスライド操作 タッチ振動 - ボタンを表示 + コントローラーを表示 + コントローラーを非表示 すべて切替 見た目を調整 大きさ diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index 3f3a4a96c0..c6d9457744 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml @@ -798,6 +798,7 @@ 십자키 슬라이드 터치 햅틱 컨트롤러 표시 + 컨트롤러 숨기기 모두 선택 컨트롤러 조정 크기 diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index 1e898fca79..3cc4c6d12c 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml @@ -720,7 +720,8 @@ Relativt pinnesenter D-pad-skyving Berøringshaptikk - Vis overlegg + Vis kontroller + Skjul kontroller Veksle mellom alle Juster overlegg Skaler diff --git a/src/android/app/src/main/res/values-pl/strings.xml b/src/android/app/src/main/res/values-pl/strings.xml index 724d7608b6..b9858838e8 100644 --- a/src/android/app/src/main/res/values-pl/strings.xml +++ b/src/android/app/src/main/res/values-pl/strings.xml @@ -718,7 +718,8 @@ Wycentruj gałki Ruchomy D-pad Wibracje haptyczne - Pokaż przyciski + Pokaż kontroler + Ukryj kontroler Włącz wszystkie Dostosuj nakładkę Skala diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index a3fd3fe13a..1296fad889 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml @@ -855,7 +855,8 @@ uma tentativa de mapeamento automático Centro Relativo do Analógico Deslizamento dos Botões Direcionais Vibração ao tocar - Mostrar overlay + Mostrar controle + Ocultar controle Marcar/Desmarcar tudo Ajustar overlay Escala diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index 7adce075cf..a166907877 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml @@ -855,7 +855,8 @@ uma tentativa de mapeamento automático Centro Relativo de Analógico Deslizamento dos Botões Direcionais Vibração ao tocar - Mostrar overlay + Mostrar comando + Ocultar comando Marcar/Desmarcar tudo Ajustar overlay Escala diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index 8d02ff7b58..dc68c7b817 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -856,7 +856,8 @@ Относительный центр стика Слайд крестовиной Обратная связь от нажатий - Показать оверлей + Показать контроллер + Скрыть контроллер Переключить всё Регулировка оверлея Масштаб diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index 2294033550..c547b3f761 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -812,7 +812,8 @@ Релативни центар за штапић Д-Пад Слиде Додирните ХАптицс - Приказати прекривање + Приказати контролер + Сакрити контролер Пребацивати све Подесити прекривање Скала diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index ebb5493f12..b48a8a4a58 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -749,7 +749,8 @@ Відносний центр джойстика Ковзання D-pad Тактильний відгук - Показати накладання + Показати контролер + Сховати контролер Перемкнути все Налаштувати накладання Масштаб diff --git a/src/android/app/src/main/res/values-vi/strings.xml b/src/android/app/src/main/res/values-vi/strings.xml index 102c720835..b19d437ceb 100644 --- a/src/android/app/src/main/res/values-vi/strings.xml +++ b/src/android/app/src/main/res/values-vi/strings.xml @@ -723,7 +723,8 @@ Trung tâm nút cần xoay tương đối Trượt D-pad Chạm haptics - Hiện lớp phủ + Hiện bộ điều khiển + Ẩn bộ điều khiển Chuyển đổi tất cả Điều chỉnh lớp phủ Tỉ lệ thu phóng diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index a0dab375d0..95ab14abd0 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -848,7 +848,8 @@ 相对摇杆中心 十字方向键滑动 触觉反馈 - 显示虚拟按键 + 显示控制器 + 隐藏控制器 全部切换 调整虚拟按键 缩放 diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index 851483668a..8640875f2c 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -853,7 +853,8 @@ 相對搖桿中心 方向鍵滑動 觸覺回饋技術 - 顯示覆疊 + 顯示控制器 + 隱藏控制器 全部切換 調整覆疊 縮放 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index f73fc1d9aa..7124ba41b4 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -835,7 +835,8 @@ Relative stick center D-pad slide Touch haptics - Show overlay + Show controller + Hide controller Toggle all Adjust overlay Scale From 0f625fc93c87a24b713683b74c729dd74d189584 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 3 Sep 2025 04:36:21 +0200 Subject: [PATCH 42/44] [cmake] fix yuzu_cmd, bundled overrides (#381) Fixes yuzu_cmd not linking to vma (just link to vma for now, but should be linked to video_core maybe?) also fixes the weird precedence of bundled packages esp w.r.t json where an effectively garbage value was passed into the BUNDLED_PACKAGE argument (was forced to on) Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/381 --- CMakeModules/CPMUtil.cmake | 7 +++---- src/android/app/build.gradle.kts | 1 + src/yuzu_cmd/CMakeLists.txt | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index 4d7db6ed61..9daada47ad 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -184,8 +184,6 @@ function(AddJsonPackage) # system/bundled if (bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE) set(bundled ${JSON_BUNDLED_PACKAGE}) - else() - set(bundled ON) endif() AddPackage( @@ -259,6 +257,7 @@ function(AddPackage) KEY BUNDLED_PACKAGE + FIND_PACKAGE_ARGUMENTS ) set(multiValueArgs OPTIONS PATCHES) @@ -409,9 +408,9 @@ function(AddPackage) set_precedence(OFF OFF) elseif (CPMUTIL_FORCE_SYSTEM) set_precedence(ON ON) - elseif(NOT CPMUTIL_FORCE_BUNDLED) + elseif(CPMUTIL_FORCE_BUNDLED) set_precedence(OFF OFF) - elseif (DEFINED PKG_ARGS_BUNDLED_PACKAGE) + elseif (DEFINED PKG_ARGS_BUNDLED_PACKAGE AND NOT PKG_ARGS_BUNDLED_PACKAGE STREQUAL "unset") if (PKG_ARGS_BUNDLED_PACKAGE) set(local OFF) else() diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index d907284bb7..e91d2e8c52 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -173,6 +173,7 @@ android { "-DENABLE_OPENSSL=ON", "-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work "-DYUZU_USE_CPM=ON", + "-DCPMUTIL_FORCE_BUNDLED=ON", "-DYUZU_USE_BUNDLED_FFMPEG=ON", "-DYUZU_ENABLE_LTO=ON", "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index ebd8fd7387..a7cf6d204c 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -39,6 +39,7 @@ create_resource("../../dist/yuzu.bmp" "yuzu_cmd/yuzu_icon.h" "yuzu_icon") target_include_directories(yuzu-cmd PRIVATE ${RESOURCES_DIR}) target_link_libraries(yuzu-cmd PRIVATE SDL2::SDL2 Vulkan::Headers) +target_link_libraries(yuzu-cmd PRIVATE GPUOpen::VulkanMemoryAllocator) if(UNIX AND NOT APPLE) install(TARGETS yuzu-cmd) From b4b361e5e91534f0b1c90f4c97fa99afa090d16f Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 4 Sep 2025 16:04:42 +0200 Subject: [PATCH 43/44] Revert "[heap_tracker] Use ankerl map instead of rb tree (#249)" (#382) This reverts commit c9a3baab5d5ba524778492027ef8961da947df2d. this commit caused issues in ender magnolia or something, need to make sure I didn't mess up the revert Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/382 Reviewed-by: Shinmegumi Reviewed-by: Lizzie Reviewed-by: MaranBr --- src/common/CMakeLists.txt | 11 +- src/common/heap_tracker.cpp | 200 ++++++++++++++++------ src/common/heap_tracker.h | 82 ++++++--- src/core/arm/dynarmic/arm_dynarmic.cpp | 44 ++++- src/core/arm/dynarmic/arm_dynarmic.h | 20 +++ src/core/arm/dynarmic/arm_dynarmic_32.cpp | 5 + src/core/arm/dynarmic/arm_dynarmic_64.cpp | 5 + src/core/hle/kernel/k_process.cpp | 4 + src/core/memory.cpp | 21 ++- src/core/memory.h | 5 + src/dynarmic/externals/CMakeLists.txt | 2 +- 11 files changed, 306 insertions(+), 93 deletions(-) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 6173e29f45..1aa433db32 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -262,23 +262,18 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") endif() if (BOOST_NO_HEADERS) - target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool) + target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool) else() - target_link_libraries(common PUBLIC Boost::headers) + target_link_libraries(common PUBLIC Boost::headers) endif() if (lz4_ADDED) - target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib) + target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib) endif() target_link_libraries(common PUBLIC fmt::fmt stb::headers Threads::Threads) target_link_libraries(common PRIVATE lz4::lz4 LLVM::Demangle zstd::zstd) -if (TARGET unordered_dense::unordered_dense) - # weird quirk of system installs - target_link_libraries(common PUBLIC unordered_dense::unordered_dense) -endif() - if(ANDROID) # For ASharedMemory_create target_link_libraries(common PRIVATE android) diff --git a/src/common/heap_tracker.cpp b/src/common/heap_tracker.cpp index c147c279bd..c875683f0f 100644 --- a/src/common/heap_tracker.cpp +++ b/src/common/heap_tracker.cpp @@ -1,5 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -35,60 +33,68 @@ HeapTracker::~HeapTracker() = default; void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, bool is_separate_heap) { - bool rebuild_required = false; // When mapping other memory, map pages immediately. if (!is_separate_heap) { m_buffer.Map(virtual_offset, host_offset, length, perm, false); return; } + { - // We are mapping part of a separate heap and insert into mappings. + // We are mapping part of a separate heap. std::scoped_lock lk{m_lock}; - m_map_count++; - const auto it = m_mappings.insert_or_assign(virtual_offset, SeparateHeapMap{ + + auto* const map = new SeparateHeapMap{ + .vaddr = virtual_offset, .paddr = host_offset, .size = length, .tick = m_tick++, .perm = perm, .is_resident = false, - }); - // Update tick before possible rebuild. - it.first->second.tick = m_tick++; - // Check if we need to rebuild. - if (m_resident_map_count >= m_max_resident_map_count) - rebuild_required = true; - // Map the area. - m_buffer.Map(it.first->first, it.first->second.paddr, it.first->second.size, it.first->second.perm, false); - // This map is now resident. - it.first->second.is_resident = true; - m_resident_map_count++; - m_resident_mappings.insert(*it.first); + }; + + // Insert into mappings. + m_map_count++; + m_mappings.insert(*map); } - // A rebuild was required, so perform it now. - if (rebuild_required) - this->RebuildSeparateHeapAddressSpace(); + + // Finally, map. + this->DeferredMapSeparateHeap(virtual_offset); } void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) { // If this is a separate heap... if (is_separate_heap) { std::scoped_lock lk{m_lock}; + + const SeparateHeapMap key{ + .vaddr = virtual_offset, + }; + // Split at the boundaries of the region we are removing. this->SplitHeapMapLocked(virtual_offset); this->SplitHeapMapLocked(virtual_offset + size); + // Erase all mappings in range. - auto it = m_mappings.find(virtual_offset); - while (it != m_mappings.end() && it->first < virtual_offset + size) { + auto it = m_mappings.find(key); + while (it != m_mappings.end() && it->vaddr < virtual_offset + size) { + // Get underlying item. + auto* const item = std::addressof(*it); + // If resident, erase from resident map. - if (it->second.is_resident) { + if (item->is_resident) { ASSERT(--m_resident_map_count >= 0); - m_resident_mappings.erase(m_resident_mappings.find(it->first)); + m_resident_mappings.erase(m_resident_mappings.iterator_to(*item)); } + // Erase from map. ASSERT(--m_map_count >= 0); it = m_mappings.erase(it); + + // Free the item. + delete item; } } + // Unmap pages. m_buffer.Unmap(virtual_offset, size, false); } @@ -110,51 +116,110 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p { std::scoped_lock lk2{m_lock}; + + const SeparateHeapMap key{ + .vaddr = next, + }; + // Try to get the next mapping corresponding to this address. - const auto it = m_mappings.find(next); + const auto it = m_mappings.nfind(key); + if (it == m_mappings.end()) { // There are no separate heap mappings remaining. next = end; should_protect = true; - } else if (it->first == cur) { + } else if (it->vaddr == cur) { // We are in range. // Update permission bits. - it->second.perm = perm; + it->perm = perm; // Determine next address and whether we should protect. - next = cur + it->second.size; - should_protect = it->second.is_resident; + next = cur + it->size; + should_protect = it->is_resident; } else /* if (it->vaddr > cur) */ { // We weren't in range, but there is a block coming up that will be. - next = it->first; + next = it->vaddr; should_protect = true; } } // Clamp to end. next = std::min(next, end); + // Reprotect, if we need to. - if (should_protect) + if (should_protect) { m_buffer.Protect(cur, next - cur, perm); + } + // Advance. cur = next; } } +bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) { + if (m_buffer.IsInVirtualRange(fault_address)) { + return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer()); + } + + return false; +} + +bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) { + bool rebuild_required = false; + + { + std::scoped_lock lk{m_lock}; + + // Check to ensure this was a non-resident separate heap mapping. + const auto it = this->GetNearestHeapMapLocked(virtual_offset); + if (it == m_mappings.end() || it->is_resident) { + return false; + } + + // Update tick before possible rebuild. + it->tick = m_tick++; + + // Check if we need to rebuild. + if (m_resident_map_count > m_max_resident_map_count) { + rebuild_required = true; + } + + // Map the area. + m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false); + + // This map is now resident. + it->is_resident = true; + m_resident_map_count++; + m_resident_mappings.insert(*it); + } + + if (rebuild_required) { + // A rebuild was required, so perform it now. + this->RebuildSeparateHeapAddressSpace(); + } + + return true; +} + void HeapTracker::RebuildSeparateHeapAddressSpace() { std::scoped_lock lk{m_rebuild_lock, m_lock}; + ASSERT(!m_resident_mappings.empty()); + // Dump half of the mappings. + // // Despite being worse in theory, this has proven to be better in practice than more // regularly dumping a smaller amount, because it significantly reduces average case // lock contention. - std::size_t const desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2; - std::size_t const evict_count = m_resident_map_count - desired_count; + const size_t desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2; + const size_t evict_count = m_resident_map_count - desired_count; auto it = m_resident_mappings.begin(); - for (std::size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) { + + for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) { // Unmark and unmap. - it->second.is_resident = false; - m_buffer.Unmap(it->first, it->second.size, false); + it->is_resident = false; + m_buffer.Unmap(it->vaddr, it->size, false); + // Advance. ASSERT(--m_resident_map_count >= 0); it = m_resident_mappings.erase(it); @@ -163,32 +228,53 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() { void HeapTracker::SplitHeapMap(VAddr offset, size_t size) { std::scoped_lock lk{m_lock}; + this->SplitHeapMapLocked(offset); this->SplitHeapMapLocked(offset + size); } void HeapTracker::SplitHeapMapLocked(VAddr offset) { - auto it = this->GetNearestHeapMapLocked(offset); - if (it != m_mappings.end() && it->first != offset) { - // Adjust left iterator - auto const orig_size = it->second.size; - auto const left_size = offset - it->first; - it->second.size = left_size; - // Insert the new right map. - auto const right = SeparateHeapMap{ - .paddr = it->second.paddr + left_size, - .size = orig_size - left_size, - .tick = it->second.tick, - .perm = it->second.perm, - .is_resident = it->second.is_resident, - }; - m_map_count++; - auto rit = m_mappings.insert_or_assign(it->first + left_size, right); - if (rit.first->second.is_resident) { - m_resident_map_count++; - m_resident_mappings.insert(*rit.first); - } + const auto it = this->GetNearestHeapMapLocked(offset); + if (it == m_mappings.end() || it->vaddr == offset) { + // Not contained or no split required. + return; + } + + // Cache the original values. + auto* const left = std::addressof(*it); + const size_t orig_size = left->size; + + // Adjust the left map. + const size_t left_size = offset - left->vaddr; + left->size = left_size; + + // Create the new right map. + auto* const right = new SeparateHeapMap{ + .vaddr = left->vaddr + left_size, + .paddr = left->paddr + left_size, + .size = orig_size - left_size, + .tick = left->tick, + .perm = left->perm, + .is_resident = left->is_resident, + }; + + // Insert the new right map. + m_map_count++; + m_mappings.insert(*right); + + // If resident, also insert into resident map. + if (right->is_resident) { + m_resident_map_count++; + m_resident_mappings.insert(*right); } } +HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) { + const SeparateHeapMap key{ + .vaddr = offset, + }; + + return m_mappings.find(key); +} + } // namespace Common diff --git a/src/common/heap_tracker.h b/src/common/heap_tracker.h index 14b5401c18..ee5b0bf43a 100644 --- a/src/common/heap_tracker.h +++ b/src/common/heap_tracker.h @@ -1,55 +1,93 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include #include +#include #include -#include + #include "common/host_memory.h" +#include "common/intrusive_red_black_tree.h" namespace Common { struct SeparateHeapMap { - PAddr paddr{}; //8 - std::size_t size{}; //8 (16) - std::size_t tick{}; //8 (24) - // 4 bits needed, sync with host_memory.h if needed - MemoryPermission perm : 4 = MemoryPermission::Read; - bool is_resident : 1 = false; + Common::IntrusiveRedBlackTreeNode addr_node{}; + Common::IntrusiveRedBlackTreeNode tick_node{}; + VAddr vaddr{}; + PAddr paddr{}; + size_t size{}; + size_t tick{}; + MemoryPermission perm{}; + bool is_resident{}; +}; + +struct SeparateHeapMapAddrComparator { + static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { + if (lhs.vaddr < rhs.vaddr) { + return -1; + } else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) { + return 0; + } else { + return 1; + } + } +}; + +struct SeparateHeapMapTickComparator { + static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { + if (lhs.tick < rhs.tick) { + return -1; + } else if (lhs.tick > rhs.tick) { + return 1; + } else { + return SeparateHeapMapAddrComparator::Compare(lhs, rhs); + } + } }; -static_assert(sizeof(SeparateHeapMap) == 32); //half a cache line! good for coherency class HeapTracker { public: explicit HeapTracker(Common::HostMemory& buffer); ~HeapTracker(); - void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, bool is_separate_heap); + + void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, + bool is_separate_heap); void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap); void Protect(size_t virtual_offset, size_t length, MemoryPermission perm); - inline u8* VirtualBasePointer() noexcept { + u8* VirtualBasePointer() { return m_buffer.VirtualBasePointer(); } + + bool DeferredMapSeparateHeap(u8* fault_address); + bool DeferredMapSeparateHeap(size_t virtual_offset); + private: - // TODO: You may want to "fake-map" the first 2GB of 64-bit address space - // and dedicate it entirely to a recursive PTE mapping :) - // However Ankerl is way better than using an RB tree, in all senses - using AddrTree = ankerl::unordered_dense::map; - AddrTree m_mappings; - using TicksTree = ankerl::unordered_dense::map; - TicksTree m_resident_mappings; + using AddrTreeTraits = + Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>; + using AddrTree = AddrTreeTraits::TreeType; + + using TickTreeTraits = + Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>; + using TickTree = TickTreeTraits::TreeType; + + AddrTree m_mappings{}; + TickTree m_resident_mappings{}; + private: void SplitHeapMap(VAddr offset, size_t size); void SplitHeapMapLocked(VAddr offset); + + AddrTree::iterator GetNearestHeapMapLocked(VAddr offset); + void RebuildSeparateHeapAddressSpace(); - inline HeapTracker::AddrTree::iterator GetNearestHeapMapLocked(VAddr offset) noexcept { - return m_mappings.find(offset); - } + private: Common::HostMemory& m_buffer; const s64 m_max_resident_map_count; + std::shared_mutex m_rebuild_lock{}; std::mutex m_lock{}; s64 m_map_count{}; diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 9d26db51f7..e6e9fc45be 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -3,9 +3,47 @@ #ifdef __linux__ -//#include "common/signal_chain.h" +#include "common/signal_chain.h" + #include "core/arm/dynarmic/arm_dynarmic.h" -//#include "core/hle/kernel/k_process.h" -//#include "core/memory.h" +#include "core/hle/kernel/k_process.h" +#include "core/memory.h" + +namespace Core { + +namespace { + +thread_local Core::Memory::Memory* g_current_memory{}; +std::once_flag g_registered{}; +struct sigaction g_old_segv {}; + +void HandleSigSegv(int sig, siginfo_t* info, void* ctx) { + if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) { + return; + } + + return g_old_segv.sa_sigaction(sig, info, ctx); +} + +} // namespace + +ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) { + g_current_memory = std::addressof(process->GetMemory()); +} + +ScopedJitExecution::~ScopedJitExecution() { + g_current_memory = nullptr; +} + +void ScopedJitExecution::RegisterHandler() { + std::call_once(g_registered, [] { + struct sigaction sa {}; + sa.sa_sigaction = &HandleSigSegv; + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv)); + }); +} + +} // namespace Core #endif diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index eef7c31160..53dd188151 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -26,4 +26,24 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) { return static_cast(hr); } +#ifdef __linux__ + +class ScopedJitExecution { +public: + explicit ScopedJitExecution(Kernel::KProcess* process); + ~ScopedJitExecution(); + static void RegisterHandler(); +}; + +#else + +class ScopedJitExecution { +public: + explicit ScopedJitExecution(Kernel::KProcess* process) {} + ~ScopedJitExecution() {} + static void RegisterHandler() {} +}; + +#endif + } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 7123497682..2c2c54a1ad 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -343,11 +343,15 @@ bool ArmDynarmic32::IsInThumbMode() const { } HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) { + ScopedJitExecution sj(thread->GetOwnerProcess()); + m_jit->ClearExclusiveState(); return TranslateHaltReason(m_jit->Run()); } HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) { + ScopedJitExecution sj(thread->GetOwnerProcess()); + m_jit->ClearExclusiveState(); return TranslateHaltReason(m_jit->Step()); } @@ -389,6 +393,7 @@ ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProc m_cp15(std::make_shared(*this)), m_core_index{core_index} { auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl(); m_jit = MakeJit(&page_table_impl); + ScopedJitExecution::RegisterHandler(); } ArmDynarmic32::~ArmDynarmic32() = default; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 2745aeb862..438b7b691c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -374,11 +374,15 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa } HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) { + ScopedJitExecution sj(thread->GetOwnerProcess()); + m_jit->ClearExclusiveState(); return TranslateHaltReason(m_jit->Run()); } HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) { + ScopedJitExecution sj(thread->GetOwnerProcess()); + m_jit->ClearExclusiveState(); return TranslateHaltReason(m_jit->Step()); } @@ -418,6 +422,7 @@ ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProc auto& page_table = process->GetPageTable().GetBasePageTable(); auto& page_table_impl = page_table.GetImpl(); m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth()); + ScopedJitExecution::RegisterHandler(); } ArmDynarmic64::~ArmDynarmic64() = default; diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index cf03353f84..80566b7e77 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -1266,6 +1266,10 @@ void KProcess::InitializeInterfaces() { #ifdef HAS_NCE if (this->IsApplication() && Settings::IsNceEnabled()) { + // Register the scoped JIT handler before creating any NCE instances + // so that its signal handler will appear first in the signal chain. + Core::ScopedJitExecution::RegisterHandler(); + for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { m_arm_interfaces[i] = std::make_unique(m_kernel.System(), true, i); } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 08391cd815..0035c626e2 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -61,7 +61,8 @@ struct Memory::Impl { } #ifdef __linux__ - buffer.emplace(system.DeviceMemory().buffer); + heap_tracker.emplace(system.DeviceMemory().buffer); + buffer = std::addressof(*heap_tracker); #else buffer = std::addressof(system.DeviceMemory().buffer); #endif @@ -1023,8 +1024,9 @@ struct Memory::Impl { std::span gpu_dirty_managers; std::mutex sys_core_guard; + std::optional heap_tracker; #ifdef __linux__ - std::optional buffer; + Common::HeapTracker* buffer{}; #else Common::HostMemory* buffer{}; #endif @@ -1228,7 +1230,22 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { if (rasterizer) { impl->InvalidateGPUMemory(ptr, size); } + +#ifdef __linux__ + if (!rasterizer && mapped) { + impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr)); + } +#endif + return mapped && ptr != nullptr; } +bool Memory::InvalidateSeparateHeap(void* fault_address) { +#ifdef __linux__ + return impl->buffer->DeferredMapSeparateHeap(static_cast(fault_address)); +#else + return false; +#endif +} + } // namespace Core::Memory diff --git a/src/core/memory.h b/src/core/memory.h index 99108ecf0d..dcca26892b 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -487,8 +487,13 @@ public: * marked as debug or non-debug. */ void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); + void SetGPUDirtyManagers(std::span managers); + bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size); + + bool InvalidateSeparateHeap(void* fault_address); + private: Core::System& system; diff --git a/src/dynarmic/externals/CMakeLists.txt b/src/dynarmic/externals/CMakeLists.txt index 73c97d8f06..ba70797a84 100644 --- a/src/dynarmic/externals/CMakeLists.txt +++ b/src/dynarmic/externals/CMakeLists.txt @@ -60,7 +60,7 @@ AddJsonPackage( # endif() # endif() -# unordered_dense - already in root +# unordered_dense # AddJsonPackage( # NAME unordered-dense From 6045627462be46a19af39afcae648e7aa77fc02c Mon Sep 17 00:00:00 2001 From: Maufeat Date: Fri, 5 Sep 2025 00:04:37 +0200 Subject: [PATCH 44/44] [fs] temporarely disable nca verification (#298) This adds a passthrough to basically disable nca verification for newer NCAs, this fixes (tested) Pokemon 4.0.0 update and other newer SDK games and updates (as reported on the discord) This is implemented as toggle that is default enabled, this needs proper implementation in the future. Co-authored-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/298 Reviewed-by: MaranBr Reviewed-by: crueter Co-authored-by: Maufeat Co-committed-by: Maufeat --- src/android/app/build.gradle.kts | 4 +- .../org/yuzu/yuzu_emu/adapters/GameAdapter.kt | 22 ++ .../features/settings/model/BooleanSetting.kt | 1 + .../features/settings/model/Settings.kt | 1 + .../settings/model/view/SettingsItem.kt | 8 +- .../settings/ui/SettingsFragmentPresenter.kt | 1 + .../org/yuzu/yuzu_emu/model/HomeViewModel.kt | 7 - .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 34 --- src/android/app/src/main/jni/native.cpp | 2 + .../app/src/main/res/values-ar/strings.xml | 2 + .../app/src/main/res/values-ckb/strings.xml | 2 + .../app/src/main/res/values-cs/strings.xml | 2 + .../app/src/main/res/values-de/strings.xml | 2 + .../app/src/main/res/values-es/strings.xml | 2 + .../app/src/main/res/values-fa/strings.xml | 2 + .../app/src/main/res/values-fr/strings.xml | 2 + .../app/src/main/res/values-he/strings.xml | 2 + .../app/src/main/res/values-hu/strings.xml | 2 + .../app/src/main/res/values-id/strings.xml | 2 + .../app/src/main/res/values-it/strings.xml | 2 + .../app/src/main/res/values-ja/strings.xml | 2 + .../app/src/main/res/values-ko/strings.xml | 2 + .../app/src/main/res/values-nb/strings.xml | 2 + .../app/src/main/res/values-pl/strings.xml | 2 + .../src/main/res/values-pt-rBR/strings.xml | 2 + .../src/main/res/values-pt-rPT/strings.xml | 2 + .../app/src/main/res/values-ru/strings.xml | 2 + .../app/src/main/res/values-sr/strings.xml | 2 + .../app/src/main/res/values-uk/strings.xml | 2 + .../app/src/main/res/values-vi/strings.xml | 2 + .../src/main/res/values-zh-rCN/strings.xml | 2 + .../src/main/res/values-zh-rTW/strings.xml | 2 + .../app/src/main/res/values/strings.xml | 5 + src/audio_core/common/feature_support.h | 2 +- src/common/settings.h | 9 +- src/core/CMakeLists.txt | 3 + .../fssystem/fssystem_bucket_tree.cpp | 9 +- .../fssystem_hierarchical_sha256_storage.cpp | 20 +- .../fssystem_hierarchical_sha3_storage.cpp | 57 +++++ .../fssystem_hierarchical_sha3_storage.h | 44 ++++ .../fssystem_nca_file_system_driver.cpp | 221 +++++++++++++----- .../fssystem_nca_file_system_driver.h | 7 + .../file_sys/fssystem/fssystem_nca_header.cpp | 9 +- .../fssystem/fssystem_passthrough_storage.h | 32 +++ src/core/hle/service/am/applet.cpp | 9 +- src/core/hle/service/am/applet.h | 4 + .../all_system_applet_proxies_service.cpp | 10 + .../all_system_applet_proxies_service.h | 1 + .../am/service/applet_common_functions.cpp | 7 + .../am/service/applet_common_functions.h | 1 + .../am/service/application_functions.cpp | 11 + .../am/service/application_functions.h | 4 + .../am/service/library_applet_creator.cpp | 4 +- .../ns/application_manager_interface.cpp | 16 ++ .../ns/application_manager_interface.h | 2 + .../service/pctl/parental_control_service.cpp | 14 +- .../service/pctl/parental_control_service.h | 2 + src/yuzu/applets/qt_web_browser.cpp | 9 +- src/yuzu/configuration/shared_translation.cpp | 6 + src/yuzu/main.cpp | 41 +++- src/yuzu/main.h | 3 + 61 files changed, 559 insertions(+), 129 deletions(-) create mode 100644 src/core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.cpp create mode 100644 src/core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.h create mode 100644 src/core/file_sys/fssystem/fssystem_passthrough_storage.h diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index e91d2e8c52..3f1a7c102b 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -30,8 +30,8 @@ val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toIn android { namespace = "org.yuzu.yuzu_emu" - compileSdkVersion = "android-35" - ndkVersion = "26.1.10909125" + compileSdkVersion = "android-36" + ndkVersion = "28.2.13676358" buildFeatures { viewBinding = true diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index 11b81a01a6..98f342c274 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -36,6 +36,9 @@ import androidx.core.net.toUri import androidx.core.content.edit import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.yuzu.yuzu_emu.NativeLibrary +import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting +import org.yuzu.yuzu_emu.features.settings.model.Settings +import org.yuzu.yuzu_emu.utils.NativeConfig class GameAdapter(private val activity: AppCompatActivity) : AbstractDiffAdapter(exact = false) { @@ -229,6 +232,8 @@ class GameAdapter(private val activity: AppCompatActivity) : binding.root.findNavController().navigate(action) } + val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) + if (NativeLibrary.gameRequiresFirmware(game.programId) && !NativeLibrary.isFirmwareAvailable()) { MaterialAlertDialogBuilder(activity) .setTitle(R.string.loader_requires_firmware) @@ -243,6 +248,23 @@ class GameAdapter(private val activity: AppCompatActivity) : } .setNegativeButton(android.R.string.cancel) { _, _ -> } .show() + } else if (BooleanSetting.DISABLE_NCA_VERIFICATION.getBoolean(false) && !preferences.getBoolean( + Settings.PREF_HIDE_NCA_POPUP, false)) { + MaterialAlertDialogBuilder(activity) + .setTitle(R.string.nca_verification_disabled) + .setMessage(activity.getString(R.string.nca_verification_disabled_description)) + .setPositiveButton(android.R.string.ok) { _, _ -> + launch() + } + .setNeutralButton(R.string.dont_show_again) { _, _ -> + preferences.edit { + putBoolean(Settings.PREF_HIDE_NCA_POPUP, true) + } + + launch() + } + .setNegativeButton(android.R.string.cancel) { _, _ -> } + .show() } else { launch() } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 3c5b9003de..6d4bfd97ac 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -35,6 +35,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_SAMPLE_SHADING("sample_shading"), PICTURE_IN_PICTURE("picture_in_picture"), USE_CUSTOM_RTC("custom_rtc_enabled"), + DISABLE_NCA_VERIFICATION("disable_nca_verification"), BLACK_BACKGROUNDS("black_backgrounds"), JOYSTICK_REL_CENTER("joystick_rel_center"), DPAD_SLIDE("dpad_slide"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index a52f582031..2564849ef4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt @@ -37,6 +37,7 @@ object Settings { const val PREF_SHOULD_SHOW_PRE_ALPHA_WARNING = "ShouldShowPreAlphaWarning" const val PREF_SHOULD_SHOW_EDENS_VEIL_DIALOG = "ShouldShowEdensVeilDialog" const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown" + const val PREF_HIDE_NCA_POPUP = "HideNCAVerificationPopup" const val SECTION_STATS_OVERLAY = "Stats Overlay" // Deprecated input overlay preference keys diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index a689b6ce76..883d8efaef 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -297,7 +297,13 @@ abstract class SettingsItem( descriptionId = R.string.use_custom_rtc_description ) ) - + put( + SwitchSetting( + BooleanSetting.DISABLE_NCA_VERIFICATION, + titleId = R.string.disable_nca_verification, + descriptionId = R.string.disable_nca_verification_description + ) + ) put( StringInputSetting( StringSetting.WEB_TOKEN, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 14d62ceec3..630bcb0d74 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -210,6 +210,7 @@ class SettingsFragmentPresenter( add(IntSetting.LANGUAGE_INDEX.key) add(BooleanSetting.USE_CUSTOM_RTC.key) add(LongSetting.CUSTOM_RTC.key) + add(BooleanSetting.DISABLE_NCA_VERIFICATION.key) add(HeaderSetting(R.string.network)) add(StringSetting.WEB_TOKEN.key) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt index 97a60ee184..a06abb394f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt @@ -31,9 +31,6 @@ class HomeViewModel : ViewModel() { private val _checkKeys = MutableStateFlow(false) val checkKeys = _checkKeys.asStateFlow() - private val _checkFirmware = MutableStateFlow(false) - val checkFirmware = _checkFirmware.asStateFlow() - var navigatedToSetup = false fun setStatusBarShadeVisibility(visible: Boolean) { @@ -66,8 +63,4 @@ class HomeViewModel : ViewModel() { fun setCheckKeys(value: Boolean) { _checkKeys.value = value } - - fun setCheckFirmware(value: Boolean) { - _checkFirmware.value = value - } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index e8dd566f79..cfed4d08ec 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -142,16 +142,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { checkedDecryption = true } - if (!checkedFirmware) { - val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext) - .getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true) - if (!firstTimeSetup) { - checkFirmware() - showPreAlphaWarningDialog() - } - checkedFirmware = true - } - WindowCompat.setDecorFitsSystemWindows(window, false) window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) @@ -198,13 +188,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { if (it) checkKeys() } - homeViewModel.checkFirmware.collect( - this, - resetState = { homeViewModel.setCheckFirmware(false) } - ) { - if (it) checkFirmware() - } - setInsets() } @@ -243,21 +226,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { ).show(supportFragmentManager, MessageDialogFragment.TAG) } } - - private fun checkFirmware() { - val resultCode: Int = NativeLibrary.verifyFirmware() - if (resultCode == 0) return - - val resultString: String = - resources.getStringArray(R.array.verifyFirmwareResults)[resultCode] - - MessageDialogFragment.newInstance( - titleId = R.string.firmware_invalid, - descriptionString = resultString, - helpLinkId = R.string.firmware_missing_help - ).show(supportFragmentManager, MessageDialogFragment.TAG) - } - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putBoolean(CHECKED_DECRYPTION, checkedDecryption) @@ -434,7 +402,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { cacheFirmwareDir.copyRecursively(firmwarePath, true) NativeLibrary.initializeSystem(true) homeViewModel.setCheckKeys(true) - homeViewModel.setCheckFirmware(true) getString(R.string.save_file_imported_success) } } catch (e: Exception) { @@ -464,7 +431,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { // Optionally reinitialize the system or perform other necessary steps NativeLibrary.initializeSystem(true) homeViewModel.setCheckKeys(true) - homeViewModel.setCheckFirmware(true) messageToShow = getString(R.string.firmware_uninstalled_success) } else { messageToShow = getString(R.string.firmware_uninstalled_failure) diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index f8f175d313..306b7e2a4c 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -596,6 +596,8 @@ jstring Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getGpuModel(JNIEnv *env, j const std::string model_name{device.GetModelName()}; + window.release(); + return Common::Android::ToJString(env, model_name); } diff --git a/src/android/app/src/main/res/values-ar/strings.xml b/src/android/app/src/main/res/values-ar/strings.xml index ed3fc76f3b..c705ae08f1 100644 --- a/src/android/app/src/main/res/values-ar/strings.xml +++ b/src/android/app/src/main/res/values-ar/strings.xml @@ -498,6 +498,8 @@ ساعة مخصصة في الوقت الحقيقي يسمح لك بتعيين ساعة مخصصة في الوقت الفعلي منفصلة عن وقت النظام الحالي لديك تعيين ساعة مخصصة في الوقت الحقيقي + تعطيل التحقق من NCA + يعطل التحقق من سلامة أرشيفات محتوى NCA. قد يحسن هذا من سرعة التحميل لكنه يخاطر بتلف البيانات أو تمرير ملفات غير صالحة دون اكتشاف. ضروري لجعل الألعاب والتحديثات التي تتطلب نظامًا أساسيًا 20+ تعمل. توليد diff --git a/src/android/app/src/main/res/values-ckb/strings.xml b/src/android/app/src/main/res/values-ckb/strings.xml index 34b1ae6252..af0eeeaa45 100644 --- a/src/android/app/src/main/res/values-ckb/strings.xml +++ b/src/android/app/src/main/res/values-ckb/strings.xml @@ -482,6 +482,8 @@ RTCی تایبەتمەند ڕێگەت پێدەدات کاتژمێرێکی کاتی ڕاستەقینەی تایبەتمەند دابنێیت کە جیاوازە لە کاتی ئێستای سیستەمەکەت. دانانی RTCی تایبەتمەند + ناچالاککردنی پشکنینی NCA + پشکنینی پێکهاتەی ئارشیڤەکانی ناوەڕۆکی NCA ناچالاک دەکات. ئەمە لەوانەیە خێرایی بارکردن به‌ره‌وپێش ببات، بەڵام مەترسی لەناوچوونی داتا یان ئەوەی فایلە نادروستەکان بەبێ ئەوەی دۆزرایەوە تێپەڕبن زیاتر دەکات. بۆ ئەوەی یاری و نوێکردنەوەکان کار بکەن کە پێویستی بە فریموێری 20+ هەیە زۆر پێویستە. بەرهەم هێنان diff --git a/src/android/app/src/main/res/values-cs/strings.xml b/src/android/app/src/main/res/values-cs/strings.xml index 293524271e..8d42b8303f 100644 --- a/src/android/app/src/main/res/values-cs/strings.xml +++ b/src/android/app/src/main/res/values-cs/strings.xml @@ -458,6 +458,8 @@ Vlastní RTC Vlastní nastavení času Nastavit vlastní RTC + Zakázat ověřování NCA + Zakáže ověřování integrity archivů obsahu NCA. To může zlepšit rychlost načítání, ale hrozí poškození dat nebo neodhalení neplatných souborů. Je nutné, aby fungovaly hry a aktualizace vyžadující firmware 20+. Generovat diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index 46ae9ba7fe..907b114388 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml @@ -486,6 +486,8 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die RTC-Datum auswählen RTC-Zeit auswählen Benutzerdefinierte Echtzeituhr + NCA-Verifizierung deaktivieren + Deaktiviert die Integritätsprüfung von NCA-Inhaltsarchiven. Dies kann die Ladegeschwindigkeit verbessern, riskiert jedoch Datenbeschädigung oder dass ungültige Dateien unentdeckt bleiben. Ist notwendig, um Spiele und Updates, die Firmware 20+ benötigen, zum Laufen zu bringen. Generieren diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 8712f455de..12b7183cae 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -506,6 +506,8 @@ RTC personalizado Te permite tener un reloj personalizado en tiempo real diferente del tiempo del propio sistema. Configurar RTC personalizado + Desactivar verificación NCA + Desactiva la verificación de integridad de los archivos de contenido NCA. Esto puede mejorar la velocidad de carga, pero arriesga corrupción de datos o que archivos inválidos pasen desapercibidos. Es necesario para que funcionen juegos y actualizaciones que requieren firmware 20+. Generar diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml index 07ff8ff4e0..d7ac1b770a 100644 --- a/src/android/app/src/main/res/values-fa/strings.xml +++ b/src/android/app/src/main/res/values-fa/strings.xml @@ -504,6 +504,8 @@ زمان سفارشی به شما امکان می‌دهد یک ساعت سفارشی جدا از زمان فعلی سیستم خود تنظیم کنید. تنظیم زمان سفارشی + غیرفعال کردن تأیید اعتبار NCA + بررسی صحت آرشیوهای محتوای NCA را غیرفعال می‌کند. این ممکن است سرعت بارگذاری را بهبود بخشد اما خطر خرابی داده یا تشخیص داده نشدن فایل‌های نامعتبر را به همراه دارد. برای کار کردن بازی‌ها و به‌روزرسانی‌هایی که به فرمور ۲۰+ نیاز دارند، ضروری است. تولید diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index 2e06ac98e1..62e67a6fee 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -506,6 +506,8 @@ RTC personnalisé Vous permet de définir une horloge en temps réel personnalisée distincte de l\'heure actuelle de votre système. Définir l\'horloge RTC personnalisée + Désactiver la vérification NCA + Désactive la vérification d\'intégrité des archives de contenu NCA. Cela peut améliorer la vitesse de chargement mais risque une corruption des données ou que des fichiers invalides ne soient pas détectés. Est nécessaire pour faire fonctionner les jeux et mises à jour nécessitant un firmware 20+. Générer diff --git a/src/android/app/src/main/res/values-he/strings.xml b/src/android/app/src/main/res/values-he/strings.xml index c0c835d633..ec5b526ce0 100644 --- a/src/android/app/src/main/res/values-he/strings.xml +++ b/src/android/app/src/main/res/values-he/strings.xml @@ -505,6 +505,8 @@ RTC מותאם אישית מאפשר לך לקבוע שעון זמן אמת נפרד משעון המערכת שלך. קבע RTC מותאם אישית + השבת אימות NCA + משבית את אימות השלמות של ארכיוני התוכן של NCA. זה עשוי לשפר את מהירות הטעינה אך מסתכן בשחיקת נתונים או שמא קבצים לא חוקיים יעברו ללא זיהוי. זה הכרחי כדי לגרום למשחקים ועדכונים הדורשים firmware 20+ לעבוד. יצירה diff --git a/src/android/app/src/main/res/values-hu/strings.xml b/src/android/app/src/main/res/values-hu/strings.xml index 46a5ac7cce..b45692f147 100644 --- a/src/android/app/src/main/res/values-hu/strings.xml +++ b/src/android/app/src/main/res/values-hu/strings.xml @@ -501,6 +501,8 @@ Egyéni RTC Megadhatsz egy valós idejű órát, amely eltér a rendszer által használt órától. Egyéni RTC beállítása + NCA ellenőrzés letiltása + Letiltja az NCA tartalomarchívumok integritás-ellenőrzését. Ez javíthatja a betöltési sebességet, de az adatsérülés vagy az érvénytelen fájlok észrevétlen maradásának kockázatával jár. Elengedhetetlen a 20+ firmware-et igénylő játékok és frissítések működtetéséhez. Generálás diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index cffb526ad5..1817fc654a 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -502,6 +502,8 @@ RTC Kustom Memungkinkan Anda untuk mengatur jam waktu nyata kustom yang terpisah dari waktu sistem saat ini Anda. Setel RTC Kustom + Nonaktifkan Verifikasi NCA + Menonaktifkan verifikasi integritas arsip konten NCA. Ini dapat meningkatkan kecepatan pemuatan tetapi berisiko kerusakan data atau file yang tidak valid tidak terdeteksi. Diperlukan untuk membuat game dan pembaruan yang membutuhkan firmware 20+ bekerja. Hasilkan diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index cb234cf61e..ff3706dd40 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml @@ -505,6 +505,8 @@ RTC Personalizzato Ti permette di impostare un orologio in tempo reale personalizzato, completamente separato da quello di sistema. Imposta un orologio in tempo reale personalizzato + Disabilita verifica NCA + Disabilita la verifica dell\'integrità degli archivi di contenuto NCA. Può migliorare la velocità di caricamento ma rischia il danneggiamento dei dati o che file non validi passino inosservati. Necessario per far funzionare giochi e aggiornamenti che richiedono il firmware 20+. Genera diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index abedb1e0bc..a6c1ebf8ab 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml @@ -491,6 +491,8 @@ カスタム RTC 現在のシステム時間とは別に、任意のリアルタイムクロックを設定できます。 カスタムRTCを設定 + NCA検証を無効化 + NCAコンテンツアーカイブの整合性検証を無効にします。読み込み速度が向上する可能性がありますが、データ破損や不正なファイルが検出されないリスクがあります。ファームウェア20以上が必要なゲームや更新を動作させるために必要です。 生成 diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index c6d9457744..01e2c5f4c0 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml @@ -501,6 +501,8 @@ 사용자 지정 RTC 현재 시스템 시간과 별도로 사용자 지정 RTC를 설정할 수 있습니다. 사용자 지정 RTC 설정 + NCA 검증 비활성화 + NCA 콘텐츠 아카이브의 무결성 검증을 비활성화합니다. 로딩 속도를 향상시킬 수 있지만 데이터 손상이나 유효하지 않은 파일이 미검증될 위험이 있습니다. 펌웨어 20+가 필요한 게임 및 업데이트를 실행하려면 필요합니다. 생성 diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index 3cc4c6d12c..90c0dbf05e 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml @@ -482,6 +482,8 @@ Tilpasset Sannhetstidsklokke Gjør det mulig å stille inn en egendefinert sanntidsklokke separat fra den gjeldende systemtiden. Angi tilpasset RTC + Deaktiver NCA-verifisering + Deaktiverer integritetsverifisering av NCA-innholdsarkiv. Dette kan forbedre lastehastigheten, men medfører risiko for datakorrupsjon eller at ugyldige filer ikke oppdages. Er nødvendig for å få spill og oppdateringer som trenger firmware 20+ til å fungere. Generer diff --git a/src/android/app/src/main/res/values-pl/strings.xml b/src/android/app/src/main/res/values-pl/strings.xml index b9858838e8..080064edaf 100644 --- a/src/android/app/src/main/res/values-pl/strings.xml +++ b/src/android/app/src/main/res/values-pl/strings.xml @@ -482,6 +482,8 @@ Niestandardowy RTC Ta opcja pozwala na wybranie własnych ustawień czasu używanych w czasie emulacji, innych niż czas systemu Android. Ustaw niestandardowy czas RTC + Wyłącz weryfikację NCA + Wyłącza weryfikację integralności archiwów zawartości NCA. Może to poprawić szybkość ładowania, ale niesie ryzyko uszkodzenia danych lub niezauważenia nieprawidłowych plików. Konieczne, aby działały gry i aktualizacje wymagające firmware\'u 20+. Generuj diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index 1296fad889..3dc1f83e6e 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml @@ -506,6 +506,8 @@ Data e hora personalizadas Permite a você configurar um relógio em tempo real separado do relógio do seu dispositivo. Definir um relógio em tempo real personalizado + Desativar verificação NCA + Desativa a verificação de integridade de arquivos de conteúdo NCA. Pode melhorar a velocidade de carregamento, mas arrisica corromper dados ou que arquivos inválidos passem despercebidos. É necessário para fazer jogos e atualizações que exigem firmware 20+ funcionarem. Gerar diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index a166907877..feb4950fcb 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml @@ -506,6 +506,8 @@ RTC personalizado Permite a você configurar um relógio em tempo real separado do relógio do seu dispositivo. Defina um relógio em tempo real personalizado + Desativar verificação NCA + Desativa a verificação de integridade dos arquivos de conteúdo NCA. Pode melhorar a velocidade de carregamento, mas arrisca a corrupção de dados ou que ficheiros inválidos passem despercebidos. É necessário para que jogos e atualizações que necessitam de firmware 20+ funcionem. Gerar diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index dc68c7b817..d56c94f10b 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -508,6 +508,8 @@ Пользовательский RTC Позволяет установить пользовательские часы реального времени отдельно от текущего системного времени. Установить пользовательский RTC + Отключить проверку NCA + Отключает проверку целостности архивов содержимого NCA. Может улучшить скорость загрузки, но есть риск повреждения данных или того, что недействительные файлы останутся незамеченными. Необходимо для работы игр и обновлений, требующих прошивку 20+. Создать diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index c547b3f761..5b444f6187 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -457,6 +457,8 @@ Цустом РТЦ Омогућава вам да поставите прилагођени сат у реалном времену одвојено од тренутног времена система. Подесите прилагођени РТЦ + Искључи верификацију НЦА + Искључује верификацију интегритета НЦА архива садржаја. Ово може побољшати брзину учитавања, али ризикује оштећење података или да неважећи фајлови прођу незапажено. Неопходно је да би игре и ажурирања која захтевају firmware 20+ радили. Генериши diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index b48a8a4a58..4ae61340dc 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -495,6 +495,8 @@ Свій RTC Дозволяє встановити власний час (Real-time clock, або RTC), відмінний від системного. Встановити RTC + Вимкнути перевірку NCA + Вимкає перевірку цілісності архівів вмісту NCA. Може покращити швидкість завантаження, але ризикує пошкодженням даних або тим, що недійсні файли залишаться непоміченими. Необхідно для роботи ігор та оновлень, які вимагають прошивки 20+. Створити diff --git a/src/android/app/src/main/res/values-vi/strings.xml b/src/android/app/src/main/res/values-vi/strings.xml index b19d437ceb..dd64fbca55 100644 --- a/src/android/app/src/main/res/values-vi/strings.xml +++ b/src/android/app/src/main/res/values-vi/strings.xml @@ -482,6 +482,8 @@ RTC tuỳ chỉnh Cho phép bạn thiết lập một đồng hồ thời gian thực tùy chỉnh riêng biệt so với thời gian hệ thống hiện tại. Thiết lập RTC tùy chỉnh + Tắt xác minh NCA + Tắt xác minh tính toàn vẹn của kho lưu trữ nội dung NCA. Có thể cải thiện tốc độ tải nhưng có nguy cơ hỏng dữ liệu hoặc các tệp không hợp lệ không bị phát hiện. Cần thiết để các trò chơi và bản cập nhật yêu cầu firmware 20+ hoạt động. Tạo diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index 95ab14abd0..a12c00063f 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -500,6 +500,8 @@ 自定义系统时间 此选项允许您设置与目前系统时间相独立的自定义系统时钟。 设置自定义系统时间 +禁用NCA验证 +禁用NCA内容存档的完整性验证。可能会提高加载速度,但存在数据损坏或无效文件未被检测到的风险。对于需要固件20+的游戏和更新是必需的。 生成 diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index 8640875f2c..a125553102 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -505,6 +505,8 @@ 自訂 RTC 允許您設定與您的目前系統時間相互獨立的自訂即時時鐘。 設定自訂 RTC + 停用NCA驗證 + 停用NCA內容存檔的完整性驗證。可能會提高載入速度,但存在資料損毀或無效檔案未被偵測到的風險。對於需要韌體20+的遊戲和更新是必需的。 生成 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 7124ba41b4..2c7923d5a3 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -474,6 +474,8 @@ Custom RTC Allows you to set a custom real-time clock separate from your current system time. Set custom RTC + Disable NCA Verification + Disables integrity verification of NCA content archives. This may improve loading speed but risks data corruption or invalid files going undetected. Some games that require firmware versions 20+ may need this as well. Generate @@ -782,6 +784,9 @@ Game Requires Firmware dump and install firmware, or press "OK" to launch anyways.]]> + NCA Verification Disabled + This is required to run new games and updates, but may cause instability or crashes if NCA files are corrupt, modified, or tampered with. If unsure, re-enable verification in Advanced Settings -> System, and use firmware versions of 19.0.1 or below. + Searching for game... Game not found for Title ID: %1$s diff --git a/src/audio_core/common/feature_support.h b/src/audio_core/common/feature_support.h index eef2a844ba..cd83df3832 100644 --- a/src/audio_core/common/feature_support.h +++ b/src/audio_core/common/feature_support.h @@ -13,7 +13,7 @@ #include "common/polyfill_ranges.h" namespace AudioCore { -constexpr u32 CurrentRevision = 13; +constexpr u32 CurrentRevision = 15; enum class SupportTags { CommandProcessingTimeEstimatorVersion4, diff --git a/src/common/settings.h b/src/common/settings.h index b657dc8658..047dfc800a 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -217,7 +217,8 @@ struct Values { true, true, &use_speed_limit}; - SwitchableSetting sync_core_speed{linkage, false, "sync_core_speed", Category::Core, Specialization::Default}; + SwitchableSetting sync_core_speed{linkage, false, "sync_core_speed", Category::Core, + Specialization::Default}; // Memory #ifdef HAS_NCE @@ -624,7 +625,11 @@ struct Values { linkage, 0, "rng_seed", Category::System, Specialization::Hex, true, true, &rng_seed_enabled}; Setting device_name{ - linkage, "Eden", "device_name", Category::System, Specialization::Default, true, true}; + linkage, "Eden", "device_name", Category::System, Specialization::Default, true, true}; + SwitchableSetting disable_nca_verification{linkage, true, "disable_nca_verification", + Category::System, Specialization::Default}; + Setting hide_nca_verification_popup{ + linkage, false, "hide_nca_verification_popup", Category::System, Specialization::Default}; Setting current_user{linkage, 0, "current_user", Category::System}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index eab506f194..33990d61a5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -88,6 +88,8 @@ add_library(core STATIC file_sys/fssystem/fssystem_crypto_configuration.h file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.cpp file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h + file_sys/fssystem/fssystem_hierarchical_sha3_storage.cpp + file_sys/fssystem/fssystem_hierarchical_sha3_storage.h file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp file_sys/fssystem/fssystem_hierarchical_sha256_storage.h file_sys/fssystem/fssystem_indirect_storage.cpp @@ -102,6 +104,7 @@ add_library(core STATIC file_sys/fssystem/fssystem_nca_header.cpp file_sys/fssystem/fssystem_nca_header.h file_sys/fssystem/fssystem_nca_reader.cpp + file_sys/fssystem/fssystem_passthrough_storage.h file_sys/fssystem/fssystem_pooled_buffer.cpp file_sys/fssystem/fssystem_pooled_buffer.h file_sys/fssystem/fssystem_sparse_storage.cpp diff --git a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp index af8541009e..615a624f4f 100644 --- a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp +++ b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp @@ -1,6 +1,10 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/settings.h" #include "core/file_sys/errors.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h" @@ -233,7 +237,10 @@ Result BucketTree::Initialize(VirtualFile node_storage, VirtualFile entry_storag void BucketTree::Initialize(size_t node_size, s64 end_offset) { ASSERT(NodeSizeMin <= node_size && node_size <= NodeSizeMax); ASSERT(Common::IsPowerOfTwo(node_size)); - ASSERT(end_offset > 0); + + if (!Settings::values.disable_nca_verification.GetValue()) { + ASSERT(end_offset > 0); + } ASSERT(!this->IsInitialized()); m_node_size = node_size; diff --git a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp index a68fd973c9..e8669a4a7d 100644 --- a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp +++ b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp @@ -5,23 +5,10 @@ #include "common/scope_exit.h" #include "core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h" +#include + namespace FileSys { -namespace { - -s32 Log2(s32 value) { - ASSERT(value > 0); - ASSERT(Common::IsPowerOfTwo(value)); - - s32 log = 0; - while ((value >>= 1) > 0) { - ++log; - } - return log; -} - -} // namespace - Result HierarchicalSha256Storage::Initialize(VirtualFile* base_storages, s32 layer_count, size_t htbs, void* hash_buf, size_t hash_buf_size) { // Validate preconditions. @@ -31,7 +18,8 @@ Result HierarchicalSha256Storage::Initialize(VirtualFile* base_storages, s32 lay // Set size tracking members. m_hash_target_block_size = static_cast(htbs); - m_log_size_ratio = Log2(m_hash_target_block_size / HashSize); + m_log_size_ratio = + static_cast(std::log2(static_cast(m_hash_target_block_size) / HashSize)); // Get the base storage size. m_base_storage_size = base_storages[2]->GetSize(); diff --git a/src/core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.cpp b/src/core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.cpp new file mode 100644 index 0000000000..d58f2ee9be --- /dev/null +++ b/src/core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.cpp @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "common/alignment.h" +#include "common/scope_exit.h" +#include "core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.h" + +#include + +namespace FileSys { + +Result HierarchicalSha3Storage::Initialize(VirtualFile* base_storages, s32 layer_count, size_t htbs, + void* hash_buf, size_t hash_buf_size) { + ASSERT(layer_count == LayerCount); + ASSERT(Common::IsPowerOfTwo(htbs)); + ASSERT(hash_buf != nullptr); + + m_hash_target_block_size = static_cast(htbs); + m_log_size_ratio = + static_cast(std::log2(static_cast(m_hash_target_block_size) / HashSize)); + + m_base_storage_size = base_storages[2]->GetSize(); + { + auto size_guard = SCOPE_GUARD { + m_base_storage_size = 0; + }; + R_UNLESS(m_base_storage_size <= static_cast(HashSize) + << m_log_size_ratio << m_log_size_ratio, + ResultHierarchicalSha256BaseStorageTooLarge); + size_guard.Cancel(); + } + + m_base_storage = base_storages[2]; + m_hash_buffer = static_cast(hash_buf); + m_hash_buffer_size = hash_buf_size; + + std::array master_hash{}; + base_storages[0]->ReadObject(std::addressof(master_hash)); + + s64 hash_storage_size = base_storages[1]->GetSize(); + ASSERT(Common::IsAligned(hash_storage_size, HashSize)); + ASSERT(hash_storage_size <= m_hash_target_block_size); + ASSERT(hash_storage_size <= static_cast(m_hash_buffer_size)); + + base_storages[1]->Read(reinterpret_cast(m_hash_buffer), + static_cast(hash_storage_size), 0); + R_SUCCEED(); +} + +size_t HierarchicalSha3Storage::Read(u8* buffer, size_t size, size_t offset) const { + if (size == 0) + return size; + ASSERT(buffer != nullptr); + return m_base_storage->Read(buffer, size, offset); +} + +} // namespace FileSys diff --git a/src/core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.h b/src/core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.h new file mode 100644 index 0000000000..2db7bb28e1 --- /dev/null +++ b/src/core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "core/file_sys/errors.h" +#include "core/file_sys/fssystem/fs_i_storage.h" +#include "core/file_sys/vfs/vfs.h" + +namespace FileSys { + +class HierarchicalSha3Storage : public IReadOnlyStorage { + YUZU_NON_COPYABLE(HierarchicalSha3Storage); + YUZU_NON_MOVEABLE(HierarchicalSha3Storage); + +public: + static constexpr s32 LayerCount = 3; + static constexpr size_t HashSize = 256 / 8; // SHA3-256 + +public: + HierarchicalSha3Storage() : m_mutex() {} + + Result Initialize(VirtualFile* base_storages, s32 layer_count, size_t htbs, void* hash_buf, + size_t hash_buf_size); + + virtual size_t GetSize() const override { + return m_base_storage->GetSize(); + } + + virtual size_t Read(u8* buffer, size_t length, size_t offset) const override; + +private: + VirtualFile m_base_storage; + s64 m_base_storage_size{}; + char* m_hash_buffer{}; + size_t m_hash_buffer_size{}; + s32 m_hash_target_block_size{}; + s32 m_log_size_ratio{}; + std::mutex m_mutex; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp index ab5a7984e3..1bc7039318 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp @@ -1,6 +1,10 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/settings.h" #include "core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h" #include "core/file_sys/fssystem/fssystem_aes_ctr_storage.h" #include "core/file_sys/fssystem/fssystem_aes_xts_storage.h" @@ -10,10 +14,12 @@ #include "core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h" #include "core/file_sys/fssystem/fssystem_indirect_storage.h" #include "core/file_sys/fssystem/fssystem_integrity_romfs_storage.h" +#include "core/file_sys/fssystem/fssystem_passthrough_storage.h" #include "core/file_sys/fssystem/fssystem_memory_resource_buffer_hold_storage.h" #include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h" #include "core/file_sys/fssystem/fssystem_sparse_storage.h" #include "core/file_sys/fssystem/fssystem_switch_storage.h" +#include "core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.h" #include "core/file_sys/vfs/vfs_offset.h" #include "core/file_sys/vfs/vfs_vector.h" @@ -299,18 +305,24 @@ Result NcaFileSystemDriver::CreateStorageByRawStorage(VirtualFile* out, // Process hash/integrity layer. switch (header_reader->GetHashType()) { case NcaFsHeader::HashType::HierarchicalSha256Hash: - R_TRY(this->CreateSha256Storage(std::addressof(storage), std::move(storage), - header_reader->GetHashData().hierarchical_sha256_data)); + R_TRY(CreateSha256Storage(&storage, std::move(storage), + header_reader->GetHashData().hierarchical_sha256_data)); break; case NcaFsHeader::HashType::HierarchicalIntegrityHash: - R_TRY(this->CreateIntegrityVerificationStorage( - std::addressof(storage), std::move(storage), - header_reader->GetHashData().integrity_meta_info)); + R_TRY(CreateIntegrityVerificationStorage(&storage, std::move(storage), + header_reader->GetHashData().integrity_meta_info)); + break; + case NcaFsHeader::HashType::HierarchicalSha3256Hash: + R_TRY(CreateSha3Storage(&storage, std::move(storage), + header_reader->GetHashData().hierarchical_sha256_data)); break; default: + LOG_ERROR(Loader, "Unhandled Fs HashType enum={}", + static_cast(header_reader->GetHashType())); R_THROW(ResultInvalidNcaFsHeaderHashType); } + // Process compression layer. if (header_reader->ExistsCompressionLayer()) { R_TRY(this->CreateCompressedStorage( @@ -679,6 +691,7 @@ Result NcaFileSystemDriver::CreateSparseStorageMetaStorageWithVerification( // Create the verification storage. VirtualFile integrity_storage; + Result rc = this->CreateIntegrityVerificationStorageForMeta( std::addressof(integrity_storage), out_layer_info_storage, std::move(decrypted_storage), meta_offset, meta_data_hash_data_info); @@ -734,8 +747,26 @@ Result NcaFileSystemDriver::CreateSparseStorageWithVerification( NcaHeader::CtrBlockSize))); // Check the meta data hash type. - R_UNLESS(meta_data_hash_type == NcaFsHeader::MetaDataHashType::HierarchicalIntegrity, - ResultRomNcaInvalidSparseMetaDataHashType); + if (meta_data_hash_type != NcaFsHeader::MetaDataHashType::HierarchicalIntegrity) { + LOG_ERROR(Loader, "Sparse meta hash type {} not supported for verification; mounting sparse data WITHOUT verification (temporary).", static_cast(meta_data_hash_type)); + + R_TRY(this->CreateBodySubStorage(std::addressof(body_substorage), + sparse_info.physical_offset, + sparse_info.GetPhysicalSize())); + + // Create sparse core directly (no meta verification) + std::shared_ptr sparse_storage_fallback; + R_TRY(this->CreateSparseStorageCore(std::addressof(sparse_storage_fallback), + body_substorage, sparse_info.GetPhysicalSize(), + /*meta_storage*/ body_substorage, // dummy; not used + sparse_info, false)); + + if (out_sparse_storage) + *out_sparse_storage = sparse_storage_fallback; + *out_fs_data_offset = fs_offset; + *out = std::move(sparse_storage_fallback); + R_SUCCEED(); + } // Create the meta storage. VirtualFile meta_storage; @@ -1093,6 +1124,56 @@ Result NcaFileSystemDriver::CreatePatchMetaStorage( R_SUCCEED(); } +Result NcaFileSystemDriver::CreateSha3Storage( + VirtualFile* out, VirtualFile base_storage, + const NcaFsHeader::HashData::HierarchicalSha256Data& hash_data) { + ASSERT(out != nullptr); + ASSERT(base_storage != nullptr); + + using VerificationStorage = HierarchicalSha3Storage; + + R_UNLESS(Common::IsPowerOfTwo(hash_data.hash_block_size), + ResultInvalidHierarchicalSha256BlockSize); + R_UNLESS(hash_data.hash_layer_count == VerificationStorage::LayerCount - 1, + ResultInvalidHierarchicalSha256LayerCount); + + const auto& hash_region = hash_data.hash_layer_region[0]; + const auto& data_region = hash_data.hash_layer_region[1]; + + constexpr s32 CacheBlockCount = 2; + const auto hash_buffer_size = static_cast(hash_region.size); + const auto cache_buffer_size = CacheBlockCount * hash_data.hash_block_size; + const auto total_buffer_size = hash_buffer_size + cache_buffer_size; + + auto buffer_hold_storage = std::make_shared( + std::move(base_storage), total_buffer_size); + R_UNLESS(buffer_hold_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); + R_UNLESS(buffer_hold_storage->IsValid(), ResultAllocationMemoryFailedInNcaFileSystemDriverI); + + s64 base_size = buffer_hold_storage->GetSize(); + R_UNLESS(hash_region.offset + hash_region.size <= base_size, ResultNcaBaseStorageOutOfRangeC); + R_UNLESS(data_region.offset + data_region.size <= base_size, ResultNcaBaseStorageOutOfRangeC); + + auto master_hash_storage = + std::make_shared>(hash_data.fs_data_master_hash.value); + + auto verification_storage = std::make_shared(); + R_UNLESS(verification_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); + + std::array layer_storages{ + std::make_shared(master_hash_storage, sizeof(Hash), 0), + std::make_shared(buffer_hold_storage, hash_region.size, hash_region.offset), + std::make_shared(buffer_hold_storage, data_region.size, data_region.offset), + }; + + R_TRY(verification_storage->Initialize(layer_storages.data(), VerificationStorage::LayerCount, + hash_data.hash_block_size, + buffer_hold_storage->GetBuffer(), hash_buffer_size)); + + *out = std::move(verification_storage); + R_SUCCEED(); +} + Result NcaFileSystemDriver::CreateSha256Storage( VirtualFile* out, VirtualFile base_storage, const NcaFsHeader::HashData::HierarchicalSha256Data& hash_data) { @@ -1160,6 +1241,7 @@ Result NcaFileSystemDriver::CreateSha256Storage( Result NcaFileSystemDriver::CreateIntegrityVerificationStorage( VirtualFile* out, VirtualFile base_storage, const NcaFsHeader::HashData::IntegrityMetaInfo& meta_info) { + R_RETURN(this->CreateIntegrityVerificationStorageImpl( out, base_storage, meta_info, 0, IntegrityDataCacheCount, IntegrityHashCacheCount, HierarchicalIntegrityVerificationStorage::GetDefaultDataCacheBufferLevel( @@ -1209,63 +1291,96 @@ Result NcaFileSystemDriver::CreateIntegrityVerificationStorageImpl( VirtualFile* out, VirtualFile base_storage, const NcaFsHeader::HashData::IntegrityMetaInfo& meta_info, s64 layer_info_offset, int max_data_cache_entries, int max_hash_cache_entries, s8 buffer_level) { - // Validate preconditions. + // Preconditions ASSERT(out != nullptr); ASSERT(base_storage != nullptr); ASSERT(layer_info_offset >= 0); - // Define storage types. - using VerificationStorage = HierarchicalIntegrityVerificationStorage; - using StorageInfo = VerificationStorage::HierarchicalStorageInformation; + if (!Settings::values.disable_nca_verification.GetValue()) { + // Define storage types. + using VerificationStorage = HierarchicalIntegrityVerificationStorage; + using StorageInfo = VerificationStorage::HierarchicalStorageInformation; - // Validate the meta info. - HierarchicalIntegrityVerificationInformation level_hash_info; - std::memcpy(std::addressof(level_hash_info), std::addressof(meta_info.level_hash_info), - sizeof(level_hash_info)); + // Validate the meta info. + HierarchicalIntegrityVerificationInformation level_hash_info; + std::memcpy(std::addressof(level_hash_info), std::addressof(meta_info.level_hash_info), + sizeof(level_hash_info)); - R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - // Get the base storage size. - s64 base_storage_size = base_storage->GetSize(); + // Get the base storage size. + s64 base_storage_size = base_storage->GetSize(); - // Create storage info. - StorageInfo storage_info; - for (s32 i = 0; i < static_cast(level_hash_info.max_layers - 2); ++i) { - const auto& layer_info = level_hash_info.info[i]; - R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size, + // Create storage info. + StorageInfo storage_info; + for (s32 i = 0; i < static_cast(level_hash_info.max_layers - 2); ++i) { + const auto& layer_info = level_hash_info.info[i]; + R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size, + ResultNcaBaseStorageOutOfRangeD); + + storage_info[i + 1] = std::make_shared( + base_storage, layer_info.size, layer_info_offset + layer_info.offset); + } + + // Set the last layer info. + const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2]; + const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get(); + R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size, ResultNcaBaseStorageOutOfRangeD); + if (layer_info_offset > 0) { + R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset, + ResultRomNcaInvalidIntegrityLayerInfoOffset); + } + storage_info.SetDataStorage(std::make_shared( + std::move(base_storage), layer_info.size, last_layer_info_offset)); - storage_info[i + 1] = std::make_shared( - base_storage, layer_info.size, layer_info_offset + layer_info.offset); + // Make the integrity romfs storage. + auto integrity_storage = std::make_shared(); + R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); + + // Initialize the integrity storage. + R_TRY(integrity_storage->Initialize(level_hash_info, meta_info.master_hash, storage_info, + max_data_cache_entries, max_hash_cache_entries, + buffer_level)); + + // Set the output. + *out = std::move(integrity_storage); + R_SUCCEED(); + } else { + // Read IVFC layout + HierarchicalIntegrityVerificationInformation lhi{}; + std::memcpy(std::addressof(lhi), std::addressof(meta_info.level_hash_info), sizeof(lhi)); + + R_UNLESS(IntegrityMinLayerCount <= lhi.max_layers, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + R_UNLESS(lhi.max_layers <= IntegrityMaxLayerCount, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + + const auto& data_li = lhi.info[lhi.max_layers - 2]; + + const s64 base_size = base_storage->GetSize(); + + // Compute the data layer window + const s64 data_off = (layer_info_offset > 0) ? 0LL : data_li.offset.Get(); + R_UNLESS(data_off + data_li.size <= base_size, ResultNcaBaseStorageOutOfRangeD); + if (layer_info_offset > 0) { + R_UNLESS(data_off + data_li.size <= layer_info_offset, + ResultRomNcaInvalidIntegrityLayerInfoOffset); + } + + // TODO: Passthrough (temporary compatibility: integrity disabled) + auto data_view = std::make_shared(base_storage, data_li.size, data_off); + R_UNLESS(data_view != nullptr, ResultAllocationMemoryFailedAllocateShared); + + auto passthrough = std::make_shared(std::move(data_view)); + R_UNLESS(passthrough != nullptr, ResultAllocationMemoryFailedAllocateShared); + + *out = std::move(passthrough); + R_SUCCEED(); } - - // Set the last layer info. - const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2]; - const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get(); - R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size, - ResultNcaBaseStorageOutOfRangeD); - if (layer_info_offset > 0) { - R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset, - ResultRomNcaInvalidIntegrityLayerInfoOffset); - } - storage_info.SetDataStorage(std::make_shared( - std::move(base_storage), layer_info.size, last_layer_info_offset)); - - // Make the integrity romfs storage. - auto integrity_storage = std::make_shared(); - R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); - - // Initialize the integrity storage. - R_TRY(integrity_storage->Initialize(level_hash_info, meta_info.master_hash, storage_info, - max_data_cache_entries, max_hash_cache_entries, - buffer_level)); - - // Set the output. - *out = std::move(integrity_storage); - R_SUCCEED(); } Result NcaFileSystemDriver::CreateRegionSwitchStorage(VirtualFile* out, diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h index 5bc838de64..e09bfc588a 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -329,6 +332,10 @@ private: const NcaPatchInfo& patch_info, const NcaMetaDataHashDataInfo& meta_data_hash_data_info); + + Result CreateSha3Storage(VirtualFile* out, VirtualFile base_storage, + const NcaFsHeader::HashData::HierarchicalSha256Data& hash_data); + Result CreateSha256Storage(VirtualFile* out, VirtualFile base_storage, const NcaFsHeader::HashData::HierarchicalSha256Data& sha256_data); diff --git a/src/core/file_sys/fssystem/fssystem_nca_header.cpp b/src/core/file_sys/fssystem/fssystem_nca_header.cpp index bf5742d39f..cef0f0bb94 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_header.cpp +++ b/src/core/file_sys/fssystem/fssystem_nca_header.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -10,11 +13,13 @@ u8 NcaHeader::GetProperKeyGeneration() const { } bool NcaPatchInfo::HasIndirectTable() const { - return this->indirect_size != 0; + static constexpr unsigned char BKTR[4] = {'B', 'K', 'T', 'R'}; + return std::memcmp(indirect_header.data(), BKTR, sizeof(BKTR)) == 0; } bool NcaPatchInfo::HasAesCtrExTable() const { - return this->aes_ctr_ex_size != 0; + static constexpr unsigned char BKTR[4] = {'B', 'K', 'T', 'R'}; + return std::memcmp(aes_ctr_ex_header.data(), BKTR, sizeof(BKTR)) == 0; } } // namespace FileSys diff --git a/src/core/file_sys/fssystem/fssystem_passthrough_storage.h b/src/core/file_sys/fssystem/fssystem_passthrough_storage.h new file mode 100644 index 0000000000..8fc6f4962a --- /dev/null +++ b/src/core/file_sys/fssystem/fssystem_passthrough_storage.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once +#include "core/file_sys/fssystem/fs_i_storage.h" +#include "core/file_sys/vfs/vfs.h" + +namespace FileSys { + +//TODO: No integrity verification. +class PassthroughStorage final : public IReadOnlyStorage { + YUZU_NON_COPYABLE(PassthroughStorage); + YUZU_NON_MOVEABLE(PassthroughStorage); + +public: + explicit PassthroughStorage(VirtualFile base) : base_(std::move(base)) {} + ~PassthroughStorage() override = default; + + size_t Read(u8* buffer, size_t size, size_t offset) const override { + if (!base_ || size == 0) + return 0; + return base_->Read(buffer, size, offset); + } + size_t GetSize() const override { + return base_ ? base_->GetSize() : 0; + } + +private: + VirtualFile base_{}; +}; + +} // namespace FileSys diff --git a/src/core/hle/service/am/applet.cpp b/src/core/hle/service/am/applet.cpp index 59ade29c8e..aa355b06d5 100644 --- a/src/core/hle/service/am/applet.cpp +++ b/src/core/hle/service/am/applet.cpp @@ -1,5 +1,8 @@ -// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator +// Project// SPDX-License-Identifier: GPL-2.0-or-later #include "core/core.h" #include "core/hle/service/am/applet.h" @@ -12,7 +15,7 @@ Applet::Applet(Core::System& system, std::unique_ptr process_, bool is_ process(std::move(process_)), hid_registration(system, *process), gpu_error_detected_event(context), friend_invitation_storage_channel_event(context), notification_storage_channel_event(context), health_warning_disappeared_system_event(context), - acquired_sleep_lock_event(context), pop_from_general_channel_event(context), + unknown_event(context), acquired_sleep_lock_event(context), pop_from_general_channel_event(context), library_applet_launchable_event(context), accumulated_suspended_tick_changed_event(context), sleep_lock_event(context), state_changed_event(context) { diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h index 835cfe6ec8..6cc8cdf741 100644 --- a/src/core/hle/service/am/applet.h +++ b/src/core/hle/service/am/applet.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -120,6 +123,7 @@ struct Applet { Event friend_invitation_storage_channel_event; Event notification_storage_channel_event; Event health_warning_disappeared_system_event; + Event unknown_event; Event acquired_sleep_lock_event; Event pop_from_general_channel_event; Event library_applet_launchable_event; diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp index 5a787494a8..d99482a45c 100644 --- a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp +++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp @@ -18,6 +18,7 @@ IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& sys // clang-format off static const FunctionInfo functions[] = { {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"}, + {110, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxyEx"}, {200, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld>, "OpenLibraryAppletProxyOld"}, {201, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxy>, "OpenLibraryAppletProxy"}, {300, nullptr, "OpenOverlayAppletProxy"}, @@ -25,6 +26,7 @@ IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& sys {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"}, {410, nullptr, "GetSystemAppletControllerForDebug"}, {450, D<&IAllSystemAppletProxiesService::GetSystemProcessCommonFunctions>, "GetSystemProcessCommonFunctions"}, // 19.0.0+ + {460, D<&IAllSystemAppletProxiesService::GetAppletAlternativeFunctions>, "GetAppletAlternativeFunctions"}, // 20.0.0+ {1000, nullptr, "GetDebugFunctions"}, }; // clang-format on @@ -99,6 +101,14 @@ Result IAllSystemAppletProxiesService::GetSystemProcessCommonFunctions() { R_SUCCEED(); } +Result IAllSystemAppletProxiesService::GetAppletAlternativeFunctions() { + LOG_DEBUG(Service_AM, "(STUBBED) called."); + + // TODO (maufeat) + + R_SUCCEED(); +} + std::shared_ptr IAllSystemAppletProxiesService::GetAppletFromProcessId( ProcessId process_id) { return m_window_system.GetByAppletResourceUserId(process_id.pid); diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.h b/src/core/hle/service/am/service/all_system_applet_proxies_service.h index a3111c4c9b..525525c795 100644 --- a/src/core/hle/service/am/service/all_system_applet_proxies_service.h +++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.h @@ -39,6 +39,7 @@ private: InCopyHandle process_handle, InLargeData attribute); Result GetSystemProcessCommonFunctions(); + Result GetAppletAlternativeFunctions(); private: std::shared_ptr GetAppletFromProcessId(ProcessId pid); diff --git a/src/core/hle/service/am/service/applet_common_functions.cpp b/src/core/hle/service/am/service/applet_common_functions.cpp index 1c9cd74533..6a73a896f9 100644 --- a/src/core/hle/service/am/service/applet_common_functions.cpp +++ b/src/core/hle/service/am/service/applet_common_functions.cpp @@ -35,6 +35,7 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_, {310, nullptr, "IsSystemAppletHomeMenu"}, //19.0.0+ {320, nullptr, "SetGpuTimeSliceBoost"}, //19.0.0+ {321, nullptr, "SetGpuTimeSliceBoostDueToApplication"}, //19.0.0+ + {350, D<&IAppletCommonFunctions::Unknown350>, "Unknown350"} //20.0.0+ }; // clang-format on @@ -70,4 +71,10 @@ Result IAppletCommonFunctions::GetCurrentApplicationId(Out out_application_ R_SUCCEED(); } +Result IAppletCommonFunctions::Unknown350(Out out_unknown) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_unknown = 0; + R_SUCCEED(); +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/service/applet_common_functions.h b/src/core/hle/service/am/service/applet_common_functions.h index 376f85acf7..623efdb7fc 100644 --- a/src/core/hle/service/am/service/applet_common_functions.h +++ b/src/core/hle/service/am/service/applet_common_functions.h @@ -20,6 +20,7 @@ private: Result GetHomeButtonDoubleClickEnabled(Out out_home_button_double_click_enabled); Result SetCpuBoostRequestPriority(s32 priority); Result GetCurrentApplicationId(Out out_application_id); + Result Unknown350(Out out_unknown); const std::shared_ptr applet; }; diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp index 560244c714..b736e2821b 100644 --- a/src/core/hle/service/am/service/application_functions.cpp +++ b/src/core/hle/service/am/service/application_functions.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -85,6 +88,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ {181, nullptr, "UpgradeLaunchRequiredVersion"}, {190, nullptr, "SendServerMaintenanceOverlayNotification"}, {200, nullptr, "GetLastApplicationExitReason"}, + {210, D<&IApplicationFunctions::GetUnknownEvent210>, "Unknown210"}, {500, nullptr, "StartContinuousRecordingFlushForDebug"}, {1000, nullptr, "CreateMovieMaker"}, {1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"}, @@ -487,6 +491,13 @@ Result IApplicationFunctions::GetHealthWarningDisappearedSystemEvent( R_SUCCEED(); } +Result IApplicationFunctions::GetUnknownEvent210( + OutCopyHandle out_event) { + LOG_DEBUG(Service_AM, "called"); + *out_event = m_applet->unknown_event.GetHandle(); + R_SUCCEED(); +} + Result IApplicationFunctions::PrepareForJit() { LOG_WARNING(Service_AM, "(STUBBED) called"); diff --git a/src/core/hle/service/am/service/application_functions.h b/src/core/hle/service/am/service/application_functions.h index 10025a152b..35b3e9505d 100644 --- a/src/core/hle/service/am/service/application_functions.h +++ b/src/core/hle/service/am/service/application_functions.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -76,6 +79,7 @@ private: Result TryPopFromFriendInvitationStorageChannel(Out> out_storage); Result GetNotificationStorageChannelEvent(OutCopyHandle out_event); Result GetHealthWarningDisappearedSystemEvent(OutCopyHandle out_event); + Result GetUnknownEvent210(OutCopyHandle out_event); Result PrepareForJit(); const std::shared_ptr m_applet; diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp index 413388d40a..54790838e0 100644 --- a/src/core/hle/service/am/service/library_applet_creator.cpp +++ b/src/core/hle/service/am/service/library_applet_creator.cpp @@ -113,9 +113,11 @@ std::shared_ptr CreateGuestApplet(Core::System& system, Firmware1700 = 17, Firmware1800 = 18, Firmware1900 = 19, + Firmware2000 = 20, + Firmware2100 = 21, }; - auto process = CreateProcess(system, program_id, Firmware1400, Firmware1900); + auto process = CreateProcess(system, program_id, Firmware1400, Firmware2100); if (!process) { // Couldn't initialize the guest process return {}; diff --git a/src/core/hle/service/ns/application_manager_interface.cpp b/src/core/hle/service/ns/application_manager_interface.cpp index f1ddba8231..517ec75743 100644 --- a/src/core/hle/service/ns/application_manager_interface.cpp +++ b/src/core/hle/service/ns/application_manager_interface.cpp @@ -306,6 +306,9 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_ {3013, nullptr, "IsGameCardEnabled"}, {3014, nullptr, "IsLocalContentShareEnabled"}, {3050, nullptr, "ListAssignELicenseTaskResult"}, + {4022, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4022"}, + {4023, D<&IApplicationManagerInterface::Unknown4023>, "Unknown4023"}, + {4088, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4088"}, {9999, nullptr, "GetApplicationCertificate"}, }; // clang-format on @@ -523,4 +526,17 @@ Result IApplicationManagerInterface::GetApplicationTerminateResult(Out o R_SUCCEED(); } +Result IApplicationManagerInterface::Unknown4022( + OutCopyHandle out_event) { + LOG_WARNING(Service_NS, "(STUBBED) called"); + *out_event = gamecard_update_detection_event.GetHandle(); + R_SUCCEED(); +} + +Result IApplicationManagerInterface::Unknown4023(Out out_result) { + LOG_WARNING(Service_NS, "(STUBBED) called."); + *out_result = 0; + R_SUCCEED(); +} + } // namespace Service::NS diff --git a/src/core/hle/service/ns/application_manager_interface.h b/src/core/hle/service/ns/application_manager_interface.h index 2def50bd5c..251f93ee06 100644 --- a/src/core/hle/service/ns/application_manager_interface.h +++ b/src/core/hle/service/ns/application_manager_interface.h @@ -53,6 +53,8 @@ public: u64 application_id); Result CheckApplicationLaunchVersion(u64 application_id); Result GetApplicationTerminateResult(Out out_result, u64 application_id); + Result Unknown4022(OutCopyHandle out_event); + Result Unknown4023(Out out_result); private: KernelHelpers::ServiceContext service_context; diff --git a/src/core/hle/service/pctl/parental_control_service.cpp b/src/core/hle/service/pctl/parental_control_service.cpp index 1d990e66d7..82c65ac1fd 100644 --- a/src/core/hle/service/pctl/parental_control_service.cpp +++ b/src/core/hle/service/pctl/parental_control_service.cpp @@ -80,11 +80,12 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili {1451, D<&IParentalControlService::StartPlayTimer>, "StartPlayTimer"}, {1452, D<&IParentalControlService::StopPlayTimer>, "StopPlayTimer"}, {1453, D<&IParentalControlService::IsPlayTimerEnabled>, "IsPlayTimerEnabled"}, - {1454, nullptr, "GetPlayTimerRemainingTime"}, + {1454, D<&IParentalControlService::GetPlayTimerRemainingTime>, "GetPlayTimerRemainingTime"}, {1455, D<&IParentalControlService::IsRestrictedByPlayTimer>, "IsRestrictedByPlayTimer"}, {1456, D<&IParentalControlService::GetPlayTimerSettingsOld>, "GetPlayTimerSettingsOld"}, {1457, D<&IParentalControlService::GetPlayTimerEventToRequestSuspension>, "GetPlayTimerEventToRequestSuspension"}, {1458, D<&IParentalControlService::IsPlayTimerAlarmDisabled>, "IsPlayTimerAlarmDisabled"}, + {1459, D<&IParentalControlService::GetPlayTimerRemainingTimeDisplayInfo>, "GetPlayTimerRemainingTimeDisplayInfo"}, {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"}, {1472, nullptr, "CancelNetworkRequest"}, {1473, D<&IParentalControlService::GetUnlinkedEvent>, "GetUnlinkedEvent"}, @@ -378,6 +379,12 @@ Result IParentalControlService::IsPlayTimerEnabled(Out out_is_play_timer_e R_SUCCEED(); } +Result IParentalControlService::GetPlayTimerRemainingTime(Out out_remaining_time) { + LOG_WARNING(Service_PCTL, "(STUBBED) called"); + *out_remaining_time = std::numeric_limits::max(); + R_SUCCEED(); +} + Result IParentalControlService::IsRestrictedByPlayTimer(Out out_is_restricted_by_play_timer) { *out_is_restricted_by_play_timer = false; LOG_WARNING(Service_PCTL, "(STUBBED) called, restricted={}", *out_is_restricted_by_play_timer); @@ -412,6 +419,11 @@ Result IParentalControlService::IsPlayTimerAlarmDisabled(Out out_play_time R_SUCCEED(); } +Result IParentalControlService::GetPlayTimerRemainingTimeDisplayInfo(/* Out 0x18 */) { + LOG_INFO(Service_PCTL, "called"); + R_SUCCEED(); +} + Result IParentalControlService::GetUnlinkedEvent(OutCopyHandle out_event) { LOG_INFO(Service_PCTL, "called"); *out_event = unlinked_event.GetHandle(); diff --git a/src/core/hle/service/pctl/parental_control_service.h b/src/core/hle/service/pctl/parental_control_service.h index 1b1884c4de..9d143fe2e2 100644 --- a/src/core/hle/service/pctl/parental_control_service.h +++ b/src/core/hle/service/pctl/parental_control_service.h @@ -49,10 +49,12 @@ private: Result StartPlayTimer(); Result StopPlayTimer(); Result IsPlayTimerEnabled(Out out_is_play_timer_enabled); + Result GetPlayTimerRemainingTime(Out out_remaining_time); Result IsRestrictedByPlayTimer(Out out_is_restricted_by_play_timer); Result GetPlayTimerSettingsOld(Out out_play_timer_settings); Result GetPlayTimerEventToRequestSuspension(OutCopyHandle out_event); Result IsPlayTimerAlarmDisabled(Out out_play_timer_alarm_disabled); + Result GetPlayTimerRemainingTimeDisplayInfo(); Result GetUnlinkedEvent(OutCopyHandle out_event); Result GetStereoVisionRestriction(Out out_stereo_vision_restriction); Result SetStereoVisionRestriction(bool stereo_vision_restriction); diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index 8245c12ba2..a287ea16df 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -17,15 +17,16 @@ #include "yuzu/applets/qt_web_browser_scripts.h" #endif +#include "yuzu/applets/qt_web_browser.h" +#include "yuzu/main.h" + +#ifdef YUZU_USE_QT_WEB_ENGINE + #include "common/fs/path_util.h" #include "core/core.h" #include "input_common/drivers/keyboard.h" -#include "yuzu/applets/qt_web_browser.h" -#include "yuzu/main.h" #include "yuzu/util/url_request_interceptor.h" -#ifdef YUZU_USE_QT_WEB_ENGINE - namespace { constexpr int HIDButtonToKey(Core::HID::NpadButton button) { diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index fca4c94893..1137145659 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -409,6 +409,12 @@ std::unique_ptr InitializeTranslations(QWidget* parent) "their resolution, details and supported controllers and depending on this setting.\n" "Setting to Handheld can help improve performance for low end systems.")); INSERT(Settings, current_user, QString(), QString()); + INSERT(Settings, disable_nca_verification, tr("Disable NCA Verification"), + tr("Disables integrity verification of NCA content archives." + "\nThis may improve loading speed but risks data corruption or invalid files going " + "undetected.\n" + "Is necessary to make games and updates work that needs firmware 20+.")); + INSERT(Settings, hide_nca_verification_popup, QString(), QString()); // Controls diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4c6b176c56..4604a7b904 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2036,6 +2036,10 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa } } + if (!OnCheckNcaVerification()) { + return false; + } + /** Exec */ const Core::SystemResultStatus result{ system->Load(*render_window, filename.toStdString(), params)}; @@ -5265,6 +5269,41 @@ void GMainWindow::OnCheckFirmwareDecryption() { UpdateMenuState(); } +bool GMainWindow::OnCheckNcaVerification() { + if (!Settings::values.disable_nca_verification.GetValue()) + return true; + + const bool currently_hidden = Settings::values.hide_nca_verification_popup.GetValue(); + LOG_INFO(Frontend, "NCA Verification is disabled. Popup State={}", currently_hidden); + if (currently_hidden) + return true; + + QMessageBox msgbox(this); + msgbox.setWindowTitle(tr("NCA Verification Disabled")); + msgbox.setText(tr("NCA Verification is disabled.\n" + "This is required to run new games and updates.\n" + "Running without verification can cause instability or crashes if NCA files " + "are corrupt, modified, or tampered.\n" + "If unsure, re-enable verification in Eden's Settings and use firmware " + "version 19.0.1 or below.")); + msgbox.setIcon(QMessageBox::Warning); + msgbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msgbox.setDefaultButton(QMessageBox::Ok); + + QCheckBox* cb = new QCheckBox(tr("Don't show again"), &msgbox); + cb->setChecked(currently_hidden); + msgbox.setCheckBox(cb); + + int result = msgbox.exec(); + + const bool hide = cb->isChecked(); + if (hide != currently_hidden) { + Settings::values.hide_nca_verification_popup.SetValue(hide); + } + + return result == static_cast(QMessageBox::Ok); +} + bool GMainWindow::CheckFirmwarePresence() { return FirmwareManager::CheckFirmwarePresence(*system.get()); } @@ -5285,7 +5324,7 @@ void GMainWindow::SetFirmwareVersion() { const std::string display_version(firmware_data.display_version.data()); const std::string display_title(firmware_data.display_title.data()); - LOG_INFO(Frontend, "Installed firmware: {}", display_title); + LOG_INFO(Frontend, "Installed firmware: {}", display_version); firmware_label->setText(QString::fromStdString(display_version)); firmware_label->setToolTip(QString::fromStdString(display_title)); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b1c5669a41..7857788fcf 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -485,6 +485,9 @@ private: const std::filesystem::path& command, const std::string& arguments, const std::string& categories, const std::string& keywords, const std::string& name); + + bool OnCheckNcaVerification(); + /** * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog * The only difference is that it returns a boolean.