From ca721fdb908f5167daed4a314cd8d94a4e4656f3 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 07:02:04 +0000 Subject: [PATCH 01/37] [breakpad] enable Solaris crash dumps Signed-off-by: lizzie --- CMakeLists.txt | 2 +- src/yuzu/CMakeLists.txt | 2 -- src/yuzu/breakpad.cpp | 8 ++++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d11b58bf1f..bf1c72f357 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -707,7 +707,7 @@ if(ENABLE_QT) set_target_properties(Qt6::Platform PROPERTIES INTERFACE_COMPILE_FEATURES "") endif() -if (WIN32 AND YUZU_CRASH_DUMPS) +if (YUZU_CRASH_DUMPS) set(BREAKPAD_VER "breakpad-c89f9dd") download_bundled_external("breakpad/" ${BREAKPAD_VER} "breakpad-win" BREAKPAD_PREFIX "c89f9dd") diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 0ce8f3b898..42242fd035 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -251,9 +251,7 @@ if (YUZU_CRASH_DUMPS) breakpad.cpp breakpad.h ) - target_link_libraries(yuzu PRIVATE libbreakpad_client) - target_compile_definitions(yuzu PRIVATE YUZU_CRASH_DUMPS) endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") diff --git a/src/yuzu/breakpad.cpp b/src/yuzu/breakpad.cpp index 82b5deb51e..0cb04dc3c8 100644 --- a/src/yuzu/breakpad.cpp +++ b/src/yuzu/breakpad.cpp @@ -8,6 +8,8 @@ #include #elif defined(__linux__) #include +#elif defined(__sun__) +#include #else #error Minidump creation not supported on this platform #endif @@ -49,7 +51,7 @@ static void PruneDumpDirectory(const std::filesystem::path& dump_path) { } } -#if defined(__linux__) +#ifdef __linux__ [[noreturn]] bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { // Prevent time- and space-consuming core dumps from being generated, as we have @@ -63,7 +65,7 @@ void InstallCrashHandler() { const auto dump_path = GetEdenPath(Common::FS::EdenPath::CrashDumpsDir); PruneDumpDirectory(dump_path); -#if defined(_WIN32) +#ifdef _WIN32 // TODO: If we switch to MinGW builds for Windows, this needs to be wrapped in a C API. static google_breakpad::ExceptionHandler eh{dump_path, nullptr, nullptr, nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL}; @@ -71,6 +73,8 @@ void InstallCrashHandler() { static google_breakpad::MinidumpDescriptor descriptor{dump_path}; static google_breakpad::ExceptionHandler eh{descriptor, nullptr, DumpCallback, nullptr, true, -1}; +#elif defined(__sun__) + static google_breakpad::ExceptionHandler eh{dump_path, nullptr, DumpCallback, nullptr, true}; #endif } From 77b3066729c3dd72769740b9355496281b05851a Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 07:02:48 +0000 Subject: [PATCH 02/37] Fix license headers --- src/yuzu/breakpad.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/yuzu/breakpad.cpp b/src/yuzu/breakpad.cpp index 0cb04dc3c8..d7aed569b7 100644 --- a/src/yuzu/breakpad.cpp +++ b/src/yuzu/breakpad.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 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 From 47b703067e51b6d418f561eae261529442d13f28 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 15:17:30 +0200 Subject: [PATCH 03/37] [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 f005f6a3abcf59641af47f420569457d20c58d05 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 17:03:56 +0200 Subject: [PATCH 04/37] [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 ab015bc7305d7eec23451ec2f7b577e26f1e1ba1 Mon Sep 17 00:00:00 2001 From: JPikachu Date: Sat, 30 Aug 2025 19:35:53 +0200 Subject: [PATCH 05/37] [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 76de9d6c8c5adf73170d99ba74f8d0c61f0c60dd Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 20:32:21 +0200 Subject: [PATCH 06/37] [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 3b4c1beb0c400c566058063b9a77af033532d080 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 20:32:28 +0200 Subject: [PATCH 07/37] [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 7ca197d90084406b07fe3b9b1b65780a6c7147ff Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 23:08:04 +0200 Subject: [PATCH 08/37] [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 1c3ca17cfb0beaf4696598115ca0c80473a929d0 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 00:12:06 +0200 Subject: [PATCH 09/37] [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 21c77bdcac2390c6b15091296786a9239c6ca529 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 03:10:34 +0200 Subject: [PATCH 10/37] [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 39e27bc954dd16d296266eaa08ea613e8e5da38d Mon Sep 17 00:00:00 2001 From: Producdevity Date: Sun, 31 Aug 2025 03:33:54 +0200 Subject: [PATCH 11/37] [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 4b5a8e06219ad0de3d27faac19b7ecb986175bbc Mon Sep 17 00:00:00 2001 From: Guo Yunhe Date: Sun, 31 Aug 2025 04:56:23 +0200 Subject: [PATCH 12/37] [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 8dba6a2cb46baf14c8c8f9c44a24f94fa26ecfe0 Mon Sep 17 00:00:00 2001 From: SDK-Chan Date: Sun, 31 Aug 2025 07:32:54 +0200 Subject: [PATCH 13/37] [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 10c76568b89d1cf2b8bc950a6b633443bd2bb728 Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Sun, 31 Aug 2025 08:40:46 +0200 Subject: [PATCH 14/37] [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 e60fd4b68bc8d43d141bfba73086518861044678 Mon Sep 17 00:00:00 2001 From: wildcard Date: Mon, 1 Sep 2025 00:20:03 +0200 Subject: [PATCH 15/37] [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 6fcfe7f4f38f7f411ce8aa0a7752e272c65dc1f3 Mon Sep 17 00:00:00 2001 From: innix Date: Mon, 1 Sep 2025 09:23:03 +0200 Subject: [PATCH 16/37] [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 e28b0d2590f9f0bd81d22c3410e254620e8fbd87 Mon Sep 17 00:00:00 2001 From: innix Date: Mon, 1 Sep 2025 14:18:30 +0200 Subject: [PATCH 17/37] [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 6aa8be1da8af896a0413290625690ec9b63f9ef6 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Sep 2025 21:14:54 +0200 Subject: [PATCH 18/37] [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 be7a3e1e86431728b86a33ef7de0a587771d11be Mon Sep 17 00:00:00 2001 From: Bix Date: Mon, 1 Sep 2025 22:25:26 +0200 Subject: [PATCH 19/37] [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 84fadd1506e3b5f8f4ad4e283bbcd8b77d8309b8 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 2 Sep 2025 03:25:27 +0200 Subject: [PATCH 20/37] [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 e7560183fa39c961dd87355c7c61827c5c745bc5 Mon Sep 17 00:00:00 2001 From: xbzk Date: Wed, 3 Sep 2025 03:55:19 +0200 Subject: [PATCH 21/37] [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 2bc792e211a157c69b809adf11762a68a343f343 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 3 Sep 2025 04:36:21 +0200 Subject: [PATCH 22/37] [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 bbcd8aded6ad61b02277d34a782cbcaedbc46ee2 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 4 Sep 2025 16:04:42 +0200 Subject: [PATCH 23/37] 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 718891d11f53a8496ce1462ce37a3c0d4083ba33 Mon Sep 17 00:00:00 2001 From: Maufeat Date: Fri, 5 Sep 2025 00:04:37 +0200 Subject: [PATCH 24/37] [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. From 37e0b80766f03ae3eb052f2eaa95506b34419bbe Mon Sep 17 00:00:00 2001 From: Gamer64 Date: Sun, 7 Sep 2025 19:20:45 +0200 Subject: [PATCH 25/37] [hle] Added missing error codes and increased audio renderer revision (#390) Co-authored-by: Jarrod Norwell Fixes Animal Well Co-authored-by: Gamer64 <76565986+Gamer64ytb@users.noreply.github.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/390 Reviewed-by: MaranBr Reviewed-by: crueter Co-authored-by: Gamer64 Co-committed-by: Gamer64 --- src/audio_core/common/feature_support.h | 6 +++++- src/core/hle/result.h | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/audio_core/common/feature_support.h b/src/audio_core/common/feature_support.h index cd83df3832..39d50746b8 100644 --- a/src/audio_core/common/feature_support.h +++ b/src/audio_core/common/feature_support.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -13,7 +16,7 @@ #include "common/polyfill_ranges.h" namespace AudioCore { -constexpr u32 CurrentRevision = 15; +constexpr u32 CurrentRevision = 16; enum class SupportTags { CommandProcessingTimeEstimatorVersion4, @@ -54,6 +57,7 @@ constexpr u32 GetRevisionNum(u32 user_revision) { user_revision -= Common::MakeMagic('R', 'E', 'V', '0'); user_revision >>= 24; } + return user_revision; }; diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 316370266d..495e6e32c2 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -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 @@ -24,6 +27,7 @@ enum class ErrorModule : u32 { HTCS = 4, NCM = 5, DD = 6, + OSDBG = 7, LR = 8, Loader = 9, CMIF = 10, @@ -51,6 +55,7 @@ enum class ErrorModule : u32 { Util = 33, TIPC = 35, ANIF = 37, + CRT = 39, ETHC = 100, I2C = 101, GPIO = 102, @@ -106,6 +111,7 @@ enum class ErrorModule : u32 { Audio = 153, NPNS = 154, NPNSHTTPSTREAM = 155, + IDLE = 156, ARP = 157, SWKBD = 158, BOOT = 159, @@ -115,6 +121,7 @@ enum class ErrorModule : u32 { Fatal = 163, NIMShop = 164, SPSM = 165, + AOC = 166, BGTC = 167, UserlandCrash = 168, SASBUS = 169, @@ -176,13 +183,22 @@ enum class ErrorModule : u32 { DP2HDMI = 244, Cradle = 245, SProfile = 246, + Icm42607p = 248, NDRM = 250, + Fst2 = 251, + Nex = 306, + NPLN = 321, TSPM = 499, DevMenu = 500, + Nverpt = 520, + Am_StuckMonitor = 521, + Pia = 618, + Eagle = 623, GeneralWebApplet = 800, WifiWebAuthApplet = 809, WhitelistedApplet = 810, ShopN = 811, + Coral = 815 }; /// Encapsulates a Horizon OS error code, allowing it to be separated into its constituent fields. From 10dd003d0fe69d8ce015113a30327d96f164b9fa Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 8 Sep 2025 00:49:46 +0200 Subject: [PATCH 26/37] [dynarmic, cmake] allow LTO build for dynarmic (#252) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/252 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- .ci/linux/build.sh | 1 + .ci/windows/build.sh | 1 + src/android/app/build.gradle.kts | 3 ++- src/dynarmic/CMakeLists.txt | 1 + src/dynarmic/src/dynarmic/CMakeLists.txt | 4 ++++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.ci/linux/build.sh b/.ci/linux/build.sh index 7c8bed1279..8e3a452809 100755 --- a/.ci/linux/build.sh +++ b/.ci/linux/build.sh @@ -104,6 +104,7 @@ cmake .. -G Ninja \ -DYUZU_USE_QT_WEB_ENGINE=$WEBENGINE \ -DYUZU_USE_FASTER_LD=ON \ -DYUZU_ENABLE_LTO=ON \ + -DDYNARMIC_ENABLE_LTO=ON \ "${EXTRA_CMAKE_FLAGS[@]}" ninja -j${NPROC} diff --git a/.ci/windows/build.sh b/.ci/windows/build.sh index 7504630a57..681f327793 100644 --- a/.ci/windows/build.sh +++ b/.ci/windows/build.sh @@ -52,6 +52,7 @@ cmake .. -G Ninja \ -DYUZU_USE_QT_MULTIMEDIA=$MULTIMEDIA \ -DYUZU_USE_QT_WEB_ENGINE=$WEBENGINE \ -DYUZU_ENABLE_LTO=ON \ + -DDYNARMIC_ENABLE_LTO=ON \ "${EXTRA_CMAKE_FLAGS[@]}" ninja diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 3f1a7c102b..c76b5e7162 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -179,7 +179,8 @@ android { "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", "-DBUILD_TESTING=OFF", "-DYUZU_TESTS=OFF", - "-DDYNARMIC_TESTS=OFF" + "-DDYNARMIC_TESTS=OFF", + "-DDYNARMIC_ENABLE_LTO=ON" ) abiFilters("arm64-v8a") diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index 5c28435f72..d505d16553 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -23,6 +23,7 @@ option(DYNARMIC_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON) option(DYNARMIC_INSTALL "Install dynarmic headers and CMake files" OFF) option(DYNARMIC_USE_BUNDLED_EXTERNALS "Use all bundled externals (useful when e.g. cross-compiling)" OFF) option(DYNARMIC_WARNINGS_AS_ERRORS "Warnings as errors" ${MASTER_PROJECT}) +option(DYNARMIC_ENABLE_LTO "Enable LTO" OFF) if (NOT DEFINED DYNARMIC_FRONTENDS) set(DYNARMIC_FRONTENDS "A32;A64" CACHE STRING "Selects which frontends to enable") endif() diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index e060989f82..7ec92206f9 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -440,6 +440,10 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") endif() target_compile_definitions(dynarmic PRIVATE FMT_USE_USER_DEFINED_LITERALS=1) +if (DYNARMIC_ENABLE_LTO) + set_property(TARGET dynarmic PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) +endif() + if (DYNARMIC_USE_PRECOMPILED_HEADERS) set(PRECOMPILED_HEADERS "$<$:${CMAKE_CURRENT_SOURCE_DIR}/ir/ir_emitter.h>") if ("x86_64" IN_LIST ARCHITECTURE) From 43c41e4db5596e12ce63b002c8d1543c3e26ccca Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 8 Sep 2025 00:54:48 +0200 Subject: [PATCH 27/37] [compat] openbsd port fixes (#273) Signed-off-by: lizzie Co-authored-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/273 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- CMakeLists.txt | 4 +++- README.md | 1 + docs/Development.md | 1 + docs/build/OpenBSD.md | 10 ++++++++++ externals/CMakeLists.txt | 2 +- src/core/debugger/debugger.cpp | 2 +- src/dynarmic/CMakeLists.txt | 16 ++++++++++++++-- src/dynarmic/externals/CMakeLists.txt | 7 ------- .../src/dynarmic/backend/x64/block_of_code.cpp | 8 +++++++- .../src/dynarmic/common/spin_lock_x64.cpp | 2 +- 10 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 docs/build/OpenBSD.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 9abca561f3..03f97eb7e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,9 @@ CMAKE_DEPENDENT_OPTION(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" O set(EXT_DEFAULT ON) -if (PLATFORM_FREEBSD) +# See https://github.com/llvm/llvm-project/issues/123946 +# OpenBSD va_list doesn't play nice with precompiled headers +if (PLATFORM_FREEBSD OR PLATFORM_OPENBSD) set(EXT_DEFAULT OFF) endif() diff --git a/README.md b/README.md index 70f2c81296..e1f0b50b37 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ If you would like to contribute, we are open to new developers and pull requests * **Solaris**: [Solaris Building Guide](./docs/build/Solaris.md) * **FreeBSD**: [FreeBSD Building Guide](./docs/build/FreeBSD.md) * **macOS**: [macOS Building Guide](./docs/build/macOS.md) +* **OpenBSD**: [OpenBSD Building Guide](./docs/build/OpenBSD.md) ## Download diff --git a/docs/Development.md b/docs/Development.md index e60384e8ab..e4816cd1ec 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -6,6 +6,7 @@ * **Solaris**: [Solaris Building Guide](./build/Solaris.md) * **FreeBSD**: [FreeBSD Building Guide](./build/FreeBSD.md) * **macOS**: [macOS Building Guide](./build/macOS.md) +* **OpenBSD**: [OpenBSD Building Guide](./build/OpenBSD.md) # CPM diff --git a/docs/build/OpenBSD.md b/docs/build/OpenBSD.md new file mode 100644 index 0000000000..6a55fd269d --- /dev/null +++ b/docs/build/OpenBSD.md @@ -0,0 +1,10 @@ +# Building for OpenBSD + +```sh +pkg_add -u +pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake llvm-19.1.7p3 qt6 jq +git --recursive https://git.eden-emu.dev/eden-emu/eden +cmake -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19 -DDYNARMIC_USE_PRECOMPILED_HEADERS=OFF -DCMAKE_BUILD_TYPE=Debug -DENABLE_QT=OFF -DENABLE_OPENSSL=OFF -DENABLE_WEB_SERVICE=OFF -B /usr/obj/eden +``` + +- Modify `externals/ffmpeg/CMakeFiles/ffmpeg-build/build.make` to use `-j$(nproc)` instead of just `-j`. diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index e917e4e7d8..25886021e2 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -33,7 +33,7 @@ endif() # Xbyak (also used by Dynarmic, so needs to be added first) if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) - if (PLATFORM_SUN) + if (PLATFORM_SUN OR PLATFORM_OPENBSD) AddJsonPackage(xbyak_sun) else() AddJsonPackage(xbyak) diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 7fe22fdce2..460e0d19b4 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp @@ -7,7 +7,7 @@ #include #include -#if BOOST_VERSION > 108300 && (!defined(_WINDOWS) && !defined(ANDROID)) || defined(YUZU_BOOST_v1) +#if BOOST_VERSION > 108400 && (!defined(_WINDOWS) && !defined(ANDROID)) || defined(YUZU_BOOST_v1) #define USE_BOOST_v1 #endif diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index d505d16553..842eb91a88 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -14,12 +14,24 @@ endif() # Dynarmic project options option(DYNARMIC_ENABLE_CPU_FEATURE_DETECTION "Turning this off causes dynarmic to assume the host CPU doesn't support anything later than SSE3" ON) -option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" OFF) + +if (PLATFORM_OPENBSD) + option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" ON) +else() + option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" OFF) +endif() + option(DYNARMIC_FATAL_ERRORS "Errors are fatal" OFF) option(DYNARMIC_IGNORE_ASSERTS "Ignore asserts" OFF) option(DYNARMIC_TESTS_USE_UNICORN "Enable fuzzing tests against unicorn" OFF) option(DYNARMIC_USE_LLVM "Support disassembly of jitted x86_64 code using LLVM" OFF) -option(DYNARMIC_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON) + +if (PLATFORM_OPENBSD) + option(DYNARMIC_USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF) +else() + option(DYNARMIC_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON) +endif() + option(DYNARMIC_INSTALL "Install dynarmic headers and CMake files" OFF) option(DYNARMIC_USE_BUNDLED_EXTERNALS "Use all bundled externals (useful when e.g. cross-compiling)" OFF) option(DYNARMIC_WARNINGS_AS_ERRORS "Warnings as errors" ${MASTER_PROJECT}) diff --git a/src/dynarmic/externals/CMakeLists.txt b/src/dynarmic/externals/CMakeLists.txt index ba70797a84..26f9290ed8 100644 --- a/src/dynarmic/externals/CMakeLists.txt +++ b/src/dynarmic/externals/CMakeLists.txt @@ -60,13 +60,6 @@ AddJsonPackage( # endif() # endif() -# unordered_dense - -# AddJsonPackage( -# NAME unordered-dense -# BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} -# ) - # xbyak # uncomment if in an independent repo diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp index 5a33ac7727..d5d5f089ff 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -225,8 +225,14 @@ bool IsUnderRosetta() { } // anonymous namespace +#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT +static const auto default_cg_mode = Xbyak::DontSetProtectRWE; +#else +static const auto default_cg_mode = nullptr; //Allow RWE +#endif + BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function rcp) - : Xbyak::CodeGenerator(total_code_size, nullptr, &s_allocator) + : Xbyak::CodeGenerator(total_code_size, default_cg_mode, &s_allocator) , cb(std::move(cb)) , jsi(jsi) , constant_pool(*this, CONSTANT_POOL_SIZE) diff --git a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp index 474c2f8404..7c0ba8a890 100644 --- a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp +++ b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp @@ -37,7 +37,7 @@ namespace { struct SpinLockImpl { void Initialize(); - Xbyak::CodeGenerator code; + Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096, Xbyak::DontSetProtectRWE); void (*lock)(volatile int*); void (*unlock)(volatile int*); From 2f82b63e6ad4f26544e74f86224f4e240933d602 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 8 Sep 2025 00:57:08 +0200 Subject: [PATCH 28/37] [user] prioritize 'user' directory if it exists (without needing a portable build) + docs (#338) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/338 Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- CMakeLists.txt | 2 -- docs/User.md | 11 +++++++++++ src/common/CMakeLists.txt | 4 ---- src/common/fs/fs_paths.h | 4 ++-- src/common/fs/path_util.cpp | 30 +++++++++++------------------- 5 files changed, 24 insertions(+), 27 deletions(-) create mode 100644 docs/User.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 03f97eb7e5..5e3a45d8c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,8 +117,6 @@ option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF) option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" ON) -option(YUZU_ENABLE_PORTABLE "Allow yuzu to enable portable mode if a user folder is found in the CWD" ON) - CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF) CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF) diff --git a/docs/User.md b/docs/User.md new file mode 100644 index 0000000000..cfc81063f8 --- /dev/null +++ b/docs/User.md @@ -0,0 +1,11 @@ +# User configuration + +## Configuration directories + +Eden will store configuration in the following directories: + +- **Windows**: `%AppData%\Roaming`. +- **Android**: Data is stored internally. +- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`. + +If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use that instead. diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 1aa433db32..9b898837bc 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -162,10 +162,6 @@ add_library( zstd_compression.h ) -if(YUZU_ENABLE_PORTABLE) - add_compile_definitions(YUZU_ENABLE_PORTABLE) -endif() - if(WIN32) target_sources(common PRIVATE windows/timer_resolution.cpp windows/timer_resolution.h) diff --git a/src/common/fs/fs_paths.h b/src/common/fs/fs_paths.h index 40891380c9..5cdf9be39d 100644 --- a/src/common/fs/fs_paths.h +++ b/src/common/fs/fs_paths.h @@ -12,7 +12,6 @@ #define PORTABLE_DIR "user" // Sub-directories contained within a yuzu data directory - #define AMIIBO_DIR "amiibo" #define CACHE_DIR "cache" #define CONFIG_DIR "config" @@ -28,11 +27,12 @@ #define SHADER_DIR "shader" #define TAS_DIR "tas" #define ICONS_DIR "icons" + +// Compatibility with other emulators #define CITRON_DIR "citron" #define SUDACHI_DIR "sudachi" #define YUZU_DIR "yuzu" #define SUYU_DIR "suyu" // yuzu-specific files - #define LOG_FILE "eden_log.txt" diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index fa1403225e..a2f5cb92ff 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -101,61 +101,53 @@ public: legacy_paths.insert_or_assign(legacy_path, new_path); } + /// In non-android devices, the current directory will first search for "user" + /// if such directory (and it must be a directory) is found, that takes priority + /// over the global configuration directory (in other words, portable directories + /// take priority over the global ones, always) + /// On Android, the behaviour is to look for the current directory only. void Reinitialize(fs::path eden_path = {}) { fs::path eden_path_cache; fs::path eden_path_config; - #ifdef _WIN32 -#ifdef YUZU_ENABLE_PORTABLE + // User directory takes priority over global %AppData% directory eden_path = GetExeDirectory() / PORTABLE_DIR; -#endif - if (!IsDir(eden_path)) { + if (!Exists(eden_path) || !IsDir(eden_path)) { eden_path = GetAppDataRoamingDirectory() / EDEN_DIR; } - eden_path_cache = eden_path / CACHE_DIR; eden_path_config = eden_path / CONFIG_DIR; - #define LEGACY_PATH(titleName, upperName) GenerateLegacyPath(LegacyPath::titleName##Dir, GetAppDataRoamingDirectory() / upperName##_DIR); \ GenerateLegacyPath(LegacyPath::titleName##ConfigDir, GetAppDataRoamingDirectory() / upperName##_DIR / CONFIG_DIR); \ GenerateLegacyPath(LegacyPath::titleName##CacheDir, GetAppDataRoamingDirectory() / upperName##_DIR / CACHE_DIR); - LEGACY_PATH(Citron, CITRON) LEGACY_PATH(Sudachi, SUDACHI) LEGACY_PATH(Yuzu, YUZU) LEGACY_PATH(Suyu, SUYU) #undef LEGACY_PATH - #elif ANDROID ASSERT(!eden_path.empty()); eden_path_cache = eden_path / CACHE_DIR; eden_path_config = eden_path / CONFIG_DIR; #else -#ifdef YUZU_ENABLE_PORTABLE eden_path = GetCurrentDir() / PORTABLE_DIR; -#endif - if (Exists(eden_path) && IsDir(eden_path)) { - eden_path_cache = eden_path / CACHE_DIR; - eden_path_config = eden_path / CONFIG_DIR; - } else { + if (!Exists(eden_path) || !IsDir(eden_path)) { eden_path = GetDataDirectory("XDG_DATA_HOME") / EDEN_DIR; eden_path_cache = GetDataDirectory("XDG_CACHE_HOME") / EDEN_DIR; eden_path_config = GetDataDirectory("XDG_CONFIG_HOME") / EDEN_DIR; + } else { + eden_path_cache = eden_path / CACHE_DIR; + eden_path_config = eden_path / CONFIG_DIR; } - #define LEGACY_PATH(titleName, upperName) GenerateLegacyPath(LegacyPath::titleName##Dir, GetDataDirectory("XDG_DATA_HOME") / upperName##_DIR); \ GenerateLegacyPath(LegacyPath::titleName##ConfigDir, GetDataDirectory("XDG_CONFIG_HOME") / upperName##_DIR); \ GenerateLegacyPath(LegacyPath::titleName##CacheDir, GetDataDirectory("XDG_CACHE_HOME") / upperName##_DIR); - LEGACY_PATH(Citron, CITRON) LEGACY_PATH(Sudachi, SUDACHI) LEGACY_PATH(Yuzu, YUZU) LEGACY_PATH(Suyu, SUYU) - #undef LEGACY_PATH - #endif - GenerateEdenPath(EdenPath::EdenDir, eden_path); GenerateEdenPath(EdenPath::AmiiboDir, eden_path / AMIIBO_DIR); GenerateEdenPath(EdenPath::CacheDir, eden_path_cache); From 8cb98b0c410ae2dbff3f289fe28b8b4b119e35a8 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 07:02:04 +0000 Subject: [PATCH 29/37] [breakpad] enable Solaris crash dumps Signed-off-by: lizzie --- CMakeLists.txt | 2 +- src/yuzu/CMakeLists.txt | 2 -- src/yuzu/breakpad.cpp | 8 ++++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e3a45d8c5..ef39020add 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -709,7 +709,7 @@ if(ENABLE_QT) set_target_properties(Qt6::Platform PROPERTIES INTERFACE_COMPILE_FEATURES "") endif() -if (WIN32 AND YUZU_CRASH_DUMPS) +if (YUZU_CRASH_DUMPS) set(BREAKPAD_VER "breakpad-c89f9dd") download_bundled_external("breakpad/" ${BREAKPAD_VER} "breakpad-win" BREAKPAD_PREFIX "c89f9dd") diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 0ce8f3b898..42242fd035 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -251,9 +251,7 @@ if (YUZU_CRASH_DUMPS) breakpad.cpp breakpad.h ) - target_link_libraries(yuzu PRIVATE libbreakpad_client) - target_compile_definitions(yuzu PRIVATE YUZU_CRASH_DUMPS) endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") diff --git a/src/yuzu/breakpad.cpp b/src/yuzu/breakpad.cpp index 82b5deb51e..0cb04dc3c8 100644 --- a/src/yuzu/breakpad.cpp +++ b/src/yuzu/breakpad.cpp @@ -8,6 +8,8 @@ #include #elif defined(__linux__) #include +#elif defined(__sun__) +#include #else #error Minidump creation not supported on this platform #endif @@ -49,7 +51,7 @@ static void PruneDumpDirectory(const std::filesystem::path& dump_path) { } } -#if defined(__linux__) +#ifdef __linux__ [[noreturn]] bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { // Prevent time- and space-consuming core dumps from being generated, as we have @@ -63,7 +65,7 @@ void InstallCrashHandler() { const auto dump_path = GetEdenPath(Common::FS::EdenPath::CrashDumpsDir); PruneDumpDirectory(dump_path); -#if defined(_WIN32) +#ifdef _WIN32 // TODO: If we switch to MinGW builds for Windows, this needs to be wrapped in a C API. static google_breakpad::ExceptionHandler eh{dump_path, nullptr, nullptr, nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL}; @@ -71,6 +73,8 @@ void InstallCrashHandler() { static google_breakpad::MinidumpDescriptor descriptor{dump_path}; static google_breakpad::ExceptionHandler eh{descriptor, nullptr, DumpCallback, nullptr, true, -1}; +#elif defined(__sun__) + static google_breakpad::ExceptionHandler eh{dump_path, nullptr, DumpCallback, nullptr, true}; #endif } From f6e47c8c9764aec3e11956c5a16ddb0b8f426e00 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 30 Aug 2025 07:02:48 +0000 Subject: [PATCH 30/37] Fix license headers --- src/yuzu/breakpad.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/yuzu/breakpad.cpp b/src/yuzu/breakpad.cpp index 0cb04dc3c8..d7aed569b7 100644 --- a/src/yuzu/breakpad.cpp +++ b/src/yuzu/breakpad.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 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 From 48ee7afce13dbfa1dbef64c4fb1464aeb487b010 Mon Sep 17 00:00:00 2001 From: SDK Chan Date: Fri, 5 Sep 2025 06:58:46 +0000 Subject: [PATCH 31/37] [cmake] Fix FreeBSD building process again --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef39020add..e663f3517c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,7 @@ option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF) CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF) -option(YUZU_USE_CPM "Use CPM to fetch Eden dependencies if needed" ON) +option(YUZU_USE_CPM "Use CPM to fetch Eden dependencies if needed" ${EXT_DEFAULT}) option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) option(ENABLE_WIFI_SCAN "Enable WiFi scanning" OFF) From da0823f46f8bb791e38a56351e595f6b7d442e94 Mon Sep 17 00:00:00 2001 From: crueter Date: Fri, 5 Sep 2025 13:41:56 -0400 Subject: [PATCH 32/37] [cmake, doc] update freebsd docs & fix ext and bundled defaults Signed-off-by: crueter --- CMakeLists.txt | 11 +++++------ CMakeModules/CPMUtil.cmake | 5 +++-- docs/build/FreeBSD.md | 12 ++++-------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e663f3517c..431c7faec8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,12 +48,10 @@ endif() # On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion CMAKE_DEPENDENT_OPTION(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" OFF) -set(EXT_DEFAULT ON) +set(EXT_DEFAULT OFF) -# See https://github.com/llvm/llvm-project/issues/123946 -# OpenBSD va_list doesn't play nice with precompiled headers -if (PLATFORM_FREEBSD OR PLATFORM_OPENBSD) - set(EXT_DEFAULT OFF) +if (MSVC OR ANDROID) + set(EXT_DEFAULT ON) endif() CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ${EXT_DEFAULT} "ENABLE_SDL2;NOT MSVC" OFF) @@ -69,7 +67,7 @@ option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF) CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF) -option(YUZU_USE_CPM "Use CPM to fetch Eden dependencies if needed" ${EXT_DEFAULT}) +option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if needed. Externals will still be fetched." ${EXT_DEFAULT}) option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) option(ENABLE_WIFI_SCAN "Enable WiFi scanning" OFF) @@ -95,6 +93,7 @@ option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}") option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ${EXT_DEFAULT}) +# TODO(crueter): CI this? option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON) option(FORCE_DOWNLOAD_WIN_BUNDLES "Forcefully download bundled Windows dependencies (useful for CI)" OFF) diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index 9daada47ad..956255f01f 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -11,10 +11,11 @@ # 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? +# TODO(crueter): Remember to get more than 6 hours of sleep whenever making giant cmake changes if (MSVC OR ANDROID) - set(BUNDLED_DEFAULT OFF) -else() set(BUNDLED_DEFAULT ON) +else() + set(BUNDLED_DEFAULT OFF) endif() option(CPMUTIL_FORCE_BUNDLED diff --git a/docs/build/FreeBSD.md b/docs/build/FreeBSD.md index 475378125c..b4510225a3 100644 --- a/docs/build/FreeBSD.md +++ b/docs/build/FreeBSD.md @@ -1,13 +1,7 @@ -## One word of caution before proceeding. - -This is not the usual or preferred way to build programs on FreeBSD. -As of writing there is no official fresh port available for Eden, but it is in the works. -After it is available you can find a link to the eden-emu fresh port here and on Escary's github repo. -See this build as an AppImage alternative for FreeBSD. +Eden is not currently available as a port on FreeBSD, though it is in the works. For now, the recommended method of usage is to compile it yourself. Check back often, as the build process frequently changes. ## Dependencies. -Before we start we need some dependencies. -These dependencies are generally needed to build Eden on FreeBSD. +Eden needs the following dependencies: ``` devel/cmake @@ -22,6 +16,8 @@ devel/autoconf devel/pkgconf devel/qt6-base +net/enet + multimedia/ffnvcodec-headers multimedia/ffmpeg From 32024e4708c8f0c7d30e061c00d28f7f8926d69e Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 4 Sep 2025 10:28:54 -0400 Subject: [PATCH 33/37] [cmake] chore: clean up linking, definitions, etc general clean up of the currently very poorly organized linking/compile def system. This is very incomplete and needs further work, but chances are qt_common will mess with it so I will probably merge this into qt_common. Signed-off-by: crueter --- CMakeLists.txt | 15 ++++++++------- externals/CMakeLists.txt | 2 +- src/CMakeLists.txt | 14 +++++++------- src/audio_core/CMakeLists.txt | 9 +++++---- src/core/CMakeLists.txt | 4 ++-- src/dedicated_room/CMakeLists.txt | 2 +- src/network/CMakeLists.txt | 2 +- src/video_core/CMakeLists.txt | 6 ++++-- src/yuzu/CMakeLists.txt | 30 +++++++++++++++--------------- src/yuzu_cmd/CMakeLists.txt | 5 ++--- 10 files changed, 46 insertions(+), 43 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 431c7faec8..99a2fe2f23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,7 @@ option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" option(FORCE_DOWNLOAD_WIN_BUNDLES "Forcefully download bundled Windows dependencies (useful for CI)" OFF) +# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system if (YUZU_USE_CPM AND ENABLE_SDL2) option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}") endif() @@ -106,7 +107,7 @@ CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Enable dedicated room functionality" ON "NOT A CMAKE_DEPENDENT_OPTION(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF) -CMAKE_DEPENDENT_OPTION(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROID" OFF) +CMAKE_DEPENDENT_OPTION(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL2;NOT ANDROID" OFF) CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF) @@ -276,7 +277,7 @@ function(detect_architecture symbol arch) if (ARCHITECTURE_${arch}) set(ARCHITECTURE "${arch}" PARENT_SCOPE) set(ARCHITECTURE_${arch} 1 PARENT_SCOPE) - add_definitions(-DARCHITECTURE_${arch}=1) + add_compile_definitions(ARCHITECTURE_${arch}=1) endif() endif() endfunction() @@ -298,7 +299,7 @@ endif() if (NOT DEFINED ARCHITECTURE) set(ARCHITECTURE "GENERIC") set(ARCHITECTURE_GENERIC 1) - add_definitions(-DARCHITECTURE_GENERIC=1) + add_compile_definitions(ARCHITECTURE_GENERIC=1) endif() message(STATUS "Target architecture: ${ARCHITECTURE}") @@ -310,16 +311,16 @@ if (MSVC AND ARCHITECTURE_x86) endif() if (UNIX) - add_definitions(-DYUZU_UNIX=1) + add_compile_definitions(YUZU_UNIX=1) endif() if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX)) set(HAS_NCE 1) - add_definitions(-DHAS_NCE=1) + add_compile_definitions(HAS_NCE=1) endif() if (YUZU_ROOM) - add_definitions(-DYUZU_ROOM) + add_compile_definitions(YUZU_ROOM) endif() # Build/optimization presets @@ -735,7 +736,7 @@ if (APPLE) list(APPEND PLATFORM_LIBRARIES ${ICONV_LIBRARY}) elseif (WIN32) # Target Windows 10 - add_definitions(-D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00) + add_compile_definitions(_WIN32_WINNT=0x0A00 WINVER=0x0A00) set(PLATFORM_LIBRARIES winmm ws2_32 iphlpapi) if (MINGW) # PSAPI is the Process Status API diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 25886021e2..4f0f79786b 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -239,7 +239,7 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client) file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES ${breakpad_SOURCE_DIR}/src/client/mac/*.cc ${breakpad_SOURCE_DIR}/src/common/mac/*.cc) list(APPEND LIBBREAKPAD_CLIENT_SOURCES ${breakpad_SOURCE_DIR}/src/common/mac/MachIPC.mm) else() - target_compile_definitions(libbreakpad_client PUBLIC -DHAVE_A_OUT_H) + target_compile_definitions(libbreakpad_client PUBLIC HAVE_A_OUT_H) file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES ${breakpad_SOURCE_DIR}/src/client/linux/*.cc ${breakpad_SOURCE_DIR}/src/common/linux/*.cc) endif() list(APPEND LIBBREAKPAD_CLIENT_SOURCES ${LIBBREAKPAD_COMMON_SOURCES}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd1285b2bc..b1fbab6a59 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,16 +22,16 @@ if (MSVC) set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE) # Silence "deprecation" warnings - add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE _SCL_SECURE_NO_WARNINGS) # Avoid windows.h junk - add_definitions(-DNOMINMAX) + add_compile_definitions(NOMINMAX) # Avoid windows.h from including some usually unused libs like winsocks.h, since this might cause some redefinition errors. - add_definitions(-DWIN32_LEAN_AND_MEAN) + add_compile_definitions(WIN32_LEAN_AND_MEAN) # Ensure that projects are built with Unicode support. - add_definitions(-DUNICODE -D_UNICODE) + add_compile_definitions(UNICODE _UNICODE) # /W4 - Level 4 warnings # /MP - Multi-threaded compilation @@ -169,15 +169,15 @@ else() # glibc, which may default to 32 bits. glibc allows this to be configured # by setting _FILE_OFFSET_BITS. if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW) - add_definitions(-D_FILE_OFFSET_BITS=64) + add_compile_definitions(_FILE_OFFSET_BITS=64) endif() if (MINGW) - add_definitions(-DMINGW_HAS_SECURE_API) + add_compile_definitions(MINGW_HAS_SECURE_API) add_compile_options("-msse4.1") if (MINGW_STATIC_BUILD) - add_definitions(-DQT_STATICPLUGIN) + add_compile_definitions(QT_STATICPLUGIN) add_compile_options("-static") endif() endif() diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index e040ec756d..b48f886702 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -229,9 +229,10 @@ endif() target_include_directories(audio_core PRIVATE ${OPUS_INCLUDE_DIRS}) target_link_libraries(audio_core PUBLIC common core opus) -if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) - target_link_libraries(audio_core PRIVATE dynarmic::dynarmic) -endif() +# what? +# if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) +# target_link_libraries(audio_core PRIVATE dynarmic::dynarmic) +# endif() if (ENABLE_CUBEB) target_sources(audio_core PRIVATE @@ -240,7 +241,7 @@ if (ENABLE_CUBEB) ) target_link_libraries(audio_core PRIVATE cubeb) - target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1) + target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1) endif() if (ENABLE_SDL2) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 33990d61a5..ddb45d406e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1155,7 +1155,7 @@ add_library(core STATIC if (ENABLE_WIFI_SCAN) # find_package(libiw REQUIRED) - target_compile_definitions(core PRIVATE -DENABLE_WIFI_SCAN) + target_compile_definitions(core PRIVATE ENABLE_WIFI_SCAN) target_link_libraries(core PRIVATE iw) endif() @@ -1202,7 +1202,7 @@ if (MINGW) endif() if (ENABLE_WEB_SERVICE) - target_compile_definitions(core PUBLIC -DENABLE_WEB_SERVICE) + target_compile_definitions(core PUBLIC ENABLE_WEB_SERVICE) target_link_libraries(core PUBLIC web_service) endif() diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index 9391a71b6c..374fb2dc5b 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -13,7 +13,7 @@ add_library(yuzu-room STATIC EXCLUDE_FROM_ALL target_link_libraries(yuzu-room PRIVATE common network) if (ENABLE_WEB_SERVICE) - target_compile_definitions(yuzu-room PRIVATE -DENABLE_WEB_SERVICE) + target_compile_definitions(yuzu-room PRIVATE ENABLE_WEB_SERVICE) target_link_libraries(yuzu-room PRIVATE web_service) endif() diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index d0787b0936..8195ea29dd 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -21,7 +21,7 @@ create_target_directory_groups(network) target_link_libraries(network PRIVATE common enet Boost::headers) if (ENABLE_WEB_SERVICE) - target_compile_definitions(network PRIVATE -DENABLE_WEB_SERVICE) + target_compile_definitions(network PRIVATE ENABLE_WEB_SERVICE) target_link_libraries(network PRIVATE web_service) endif() diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 8131d42aae..b608542d84 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -332,8 +332,10 @@ 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) -target_link_libraries(video_core PUBLIC GPUOpen::VulkanMemoryAllocator) +target_link_libraries(video_core PRIVATE sirit) + +# Header-only stuff needed by all dependent targets +target_link_libraries(video_core PUBLIC Vulkan::Headers Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator) if (ENABLE_NSIGHT_AFTERMATH) if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 42242fd035..cf87d5c997 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -399,7 +399,6 @@ target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json) target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) -target_link_libraries(yuzu PRIVATE Vulkan::Headers) if (NOT WIN32) target_include_directories(yuzu PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) endif() @@ -414,24 +413,24 @@ endif() target_compile_definitions(yuzu PRIVATE # Use QStringBuilder for string concatenation to reduce # the overall number of temporary strings created. - -DQT_USE_QSTRINGBUILDER + QT_USE_QSTRINGBUILDER # Disable implicit conversions from/to C strings - -DQT_NO_CAST_FROM_ASCII - -DQT_NO_CAST_TO_ASCII + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII # Disable implicit type narrowing in signal/slot connect() calls. - -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT + QT_NO_NARROWING_CONVERSIONS_IN_CONNECT # Disable unsafe overloads of QProcess' start() function. - -DQT_NO_PROCESS_COMBINED_ARGUMENT_START + QT_NO_PROCESS_COMBINED_ARGUMENT_START # Disable implicit QString->QUrl conversions to enforce use of proper resolving functions. - -DQT_NO_URL_CAST_FROM_STRING + QT_NO_URL_CAST_FROM_STRING ) if (YUZU_ENABLE_COMPATIBILITY_REPORTING) - target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_COMPATIBILITY_REPORTING) + target_compile_definitions(yuzu PRIVATE YUZU_ENABLE_COMPATIBILITY_REPORTING) endif() if (USE_DISCORD_PRESENCE) @@ -439,22 +438,22 @@ if (USE_DISCORD_PRESENCE) discord_impl.cpp discord_impl.h ) - target_link_libraries(yuzu PRIVATE DiscordRPC::discord-rpc httplib::httplib Qt${QT_MAJOR_VERSION}::Network) - target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE) + target_link_libraries(yuzu PRIVATE DiscordRPC::discord-rpc httplib::httplib Qt6::Network) + target_compile_definitions(yuzu PRIVATE USE_DISCORD_PRESENCE) endif() if (ENABLE_WEB_SERVICE) - target_compile_definitions(yuzu PRIVATE -DENABLE_WEB_SERVICE) + target_compile_definitions(yuzu PRIVATE ENABLE_WEB_SERVICE) endif() if (YUZU_USE_QT_MULTIMEDIA) - target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::Multimedia) - target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_MULTIMEDIA) + target_link_libraries(yuzu PRIVATE Qt6::Multimedia) + target_compile_definitions(yuzu PRIVATE YUZU_USE_QT_MULTIMEDIA) endif () if (YUZU_USE_QT_WEB_ENGINE) - target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::WebEngineCore Qt${QT_MAJOR_VERSION}::WebEngineWidgets) - target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) + target_link_libraries(yuzu PRIVATE Qt6::WebEngineCore Qt6::WebEngineWidgets) + target_compile_definitions(yuzu PRIVATE YUZU_USE_QT_WEB_ENGINE) endif () if(UNIX AND NOT APPLE) @@ -466,6 +465,7 @@ if (WIN32 AND NOT YUZU_USE_BUNDLED_QT AND QT_VERSION VERSION_GREATER_EQUAL 6) add_custom_command(TARGET yuzu POST_BUILD COMMAND ${WINDEPLOYQT_EXECUTABLE} "${YUZU_EXE_DIR}/eden.exe" --dir "${YUZU_EXE_DIR}" --libdir "${YUZU_EXE_DIR}" --plugindir "${YUZU_EXE_DIR}/plugins" --no-compiler-runtime --no-opengl-sw --no-system-d3d-compiler --no-translations --verbose 0) endif() +# TODO(crueter): this can be done with system qt in a better way if (YUZU_USE_BUNDLED_QT) include(CopyYuzuQt6Deps) copy_yuzu_Qt6_deps(yuzu) diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index a7cf6d204c..33d4267614 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -28,7 +28,7 @@ add_executable(yuzu-cmd yuzu.rc ) -target_link_libraries(yuzu-cmd PRIVATE common core input_common frontend_common) +target_link_libraries(yuzu-cmd PRIVATE common core input_common frontend_common video_core) target_link_libraries(yuzu-cmd PRIVATE glad) if (MSVC) target_link_libraries(yuzu-cmd PRIVATE getopt) @@ -38,8 +38,7 @@ target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 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) +target_link_libraries(yuzu-cmd PRIVATE SDL2::SDL2) if(UNIX AND NOT APPLE) install(TARGETS yuzu-cmd) From 1399f32cf37ad9094a4610886d610cad5bf51baf Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 4 Sep 2025 10:47:14 -0400 Subject: [PATCH 34/37] [ci] update header script for cmake Signed-off-by: crueter --- .ci/license-header.sh | 79 ++++++++++++++++++++++++++----- externals/CMakeLists.txt | 3 ++ src/audio_core/CMakeLists.txt | 3 ++ src/core/CMakeLists.txt | 3 ++ src/dedicated_room/CMakeLists.txt | 3 ++ src/network/CMakeLists.txt | 3 ++ src/yuzu_cmd/CMakeLists.txt | 3 ++ 7 files changed, 86 insertions(+), 11 deletions(-) diff --git a/.ci/license-header.sh b/.ci/license-header.sh index d14d5adf42..fecffaa7d3 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -1,6 +1,7 @@ #!/bin/sh -e HEADER="$(cat "$PWD/.ci/license/header.txt")" +HEADER_HASH="$(cat "$PWD/.ci/license/header-hash.txt")" echo "Getting branch changes" @@ -13,41 +14,86 @@ FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` echo "Done" +check_header() { + CONTENT="`head -n3 < $1`" + case "$CONTENT" in + "$HEADER"*) ;; + *) BAD_FILES="$BAD_FILES $1" ;; + esac +} + +check_cmake_header() { + CONTENT="`head -n3 < $1`" + + case "$CONTENT" in + "$HEADER_HASH"*) ;; + *) + BAD_CMAKE="$BAD_CMAKE $1" ;; + esac +} for file in $FILES; do [ -f "$file" ] || continue + if [ `basename -- "$file"` = "CMakeLists.txt" ]; then + check_cmake_header "$file" + continue + fi + EXTENSION="${file##*.}" case "$EXTENSION" in kts|kt|cpp|h) - CONTENT="`cat $file`" - case "$CONTENT" in - "$HEADER"*) ;; - *) BAD_FILES="$BAD_FILES $file" ;; - esac + check_header "$file" + ;; + cmake) + check_cmake_header "$file" ;; esac done -if [ "$BAD_FILES" = "" ]; then +if [ "$BAD_FILES" = "" ] && [ "$BAD_CMAKE" = "" ]; then echo echo "All good." exit fi -echo "The following files have incorrect license headers:" -echo +if [ "$BAD_FILES" != "" ]; then + echo "The following source files have incorrect license headers:" + echo -for file in $BAD_FILES; do echo $file; done + for file in $BAD_FILES; do echo $file; done -cat << EOF + cat << EOF -The following license header should be added to the start of all offending files: +The following license header should be added to the start of all offending SOURCE files: === BEGIN === $HEADER === END === +EOF + +fi + +if [ "$BAD_CMAKE" != "" ]; then + echo "The following CMake files have incorrect license headers:" + echo + + for file in $BAD_CMAKE; do echo $file; done + + cat << EOF + +The following license header should be added to the start of all offending CMake files: + +=== BEGIN === +$HEADER_HASH +=== END === + +EOF + +fi + +cat << EOF If some of the code in this PR is not being contributed by the original author, the files which have been exclusively changed by that code can be ignored. If this happens, this PR requirement can be bypassed once all other files are addressed. @@ -70,6 +116,17 @@ if [ "$FIX" = "true" ]; then git add $file done + for file in $BAD_CMAKE; do + cat $file > $file.bak + + cat .ci/license/header-hash.txt > $file + echo >> $file + cat $file.bak >> $file + + rm $file.bak + + git add $file + done echo "License headers fixed." if [ "$COMMIT" = "true" ]; then diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 4f0f79786b..793750c2f2 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index b48f886702..389b1044e9 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2018 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ddb45d406e..26d6aa62a7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2018 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index 374fb2dc5b..e5934c941a 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2017 Citra Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 8195ea29dd..1487033b22 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2022 yuzu Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 33d4267614..a60650bc19 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2018 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later From 9e313227bee106c8cfa3e13256b3c111b537d992 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 4 Sep 2025 10:48:04 -0400 Subject: [PATCH 35/37] oops Signed-off-by: crueter --- .ci/license/header-hash.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .ci/license/header-hash.txt diff --git a/.ci/license/header-hash.txt b/.ci/license/header-hash.txt new file mode 100644 index 0000000000..91bc195e23 --- /dev/null +++ b/.ci/license/header-hash.txt @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later From 911ace690fda9506436bbc6e65cbe0a4dcd0f15b Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 7 Sep 2025 18:29:28 -0400 Subject: [PATCH 36/37] [cmake] CPMUtil: formatting, git_host, and more I promise I'm a UI developer - mbedtls can now be used as a system package - zycore can now be used as a system package - cleaned up dynarmic externals - fixed libusb incorrectly showing as bundled - add version/tag formatting to JSON - add custom GIT_HOST option for packages - moved some of my repos to my new git - slightly better version identification - combined VUL/VH since they are codependent (using my combo vendor) This PR succeeds #383 since it includes it Signed-off-by: crueter --- CMakeLists.txt | 53 +--------------------- CMakeModules/CPMUtil.cmake | 58 ++++++++++++++++++------ CMakeModules/Findmbedtls.cmake | 17 +++++++ cpmfile.json | 4 +- docs/CPM.md | 5 +- externals/CMakeLists.txt | 54 +++++++++++++++++----- externals/cpmfile.json | 18 +++----- externals/nx_tzdb/cpmfile.json | 5 +- src/core/CMakeLists.txt | 2 +- src/core/crypto/key_manager.cpp | 7 +++ src/dynarmic/CMakeLists.txt | 19 +++----- src/dynarmic/externals/CMakeLists.txt | 48 +++----------------- src/dynarmic/externals/cpmfile.json | 7 ++- src/dynarmic/src/dynarmic/CMakeLists.txt | 2 +- src/video_core/CMakeLists.txt | 2 +- tools/cpm-fetch-all.sh | 3 +- tools/cpm-fetch.sh | 37 ++++++++++----- 17 files changed, 176 insertions(+), 165 deletions(-) create mode 100644 CMakeModules/Findmbedtls.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 99a2fe2f23..00dd5237be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,8 +73,7 @@ option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) option(ENABLE_WIFI_SCAN "Enable WiFi scanning" OFF) option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" ${EXT_DEFAULT}) -option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ${EXT_DEFAULT}) -option(YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES "Use Vulkan-Utility-Libraries from externals" ${EXT_DEFAULT}) +option(YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES "Use Vulkan Utility Headers from externals" ${EXT_DEFAULT}) option(YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS "Use SPIRV-Tools from externals" ${EXT_DEFAULT}) option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF) @@ -111,8 +110,6 @@ CMAKE_DEPENDENT_OPTION(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF) -option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ${EXT_DEFAULT}) - option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF) option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" ON) @@ -194,53 +191,6 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/hooks/pre-commit AND NOT EXISTS ${PROJECT_SOURCE endif() endif() -# Sanity check : Check that all submodules are present -# ======================================================================= - -function(check_submodules_present) - file(READ "${PROJECT_SOURCE_DIR}/.gitmodules" gitmodules) - string(REGEX MATCHALL "path *= *[^ \t\r\n]*" gitmodules ${gitmodules}) - foreach(module ${gitmodules}) - string(REGEX REPLACE "path *= *" "" module ${module}) - - file(GLOB RESULT "${PROJECT_SOURCE_DIR}/${module}/*") - list(LENGTH RESULT RES_LEN) - if(RES_LEN EQUAL 0) - message(FATAL_ERROR "Git submodule ${module} not found. " - "Please run: \ngit submodule update --init --recursive") - endif() - if (EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git") - set(SUBMODULE_DIR "${PROJECT_SOURCE_DIR}/${module}") - - execute_process( - COMMAND git rev-parse --short=10 HEAD - WORKING_DIRECTORY ${SUBMODULE_DIR} - OUTPUT_VARIABLE SUBMODULE_SHA - ) - - # would probably be better to do string parsing, but whatever - execute_process( - COMMAND git remote get-url origin - WORKING_DIRECTORY ${SUBMODULE_DIR} - OUTPUT_VARIABLE SUBMODULE_URL - ) - - string(REGEX REPLACE "\n|\r" "" SUBMODULE_SHA ${SUBMODULE_SHA}) - string(REGEX REPLACE "\n|\r|\\.git" "" SUBMODULE_URL ${SUBMODULE_URL}) - - get_filename_component(SUBMODULE_NAME ${SUBMODULE_DIR} NAME) - - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES ${SUBMODULE_NAME}) - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS ${SUBMODULE_SHA}) - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS ${SUBMODULE_URL}) - endif() - endforeach() -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) @@ -601,7 +551,6 @@ endfunction() add_subdirectory(externals) # pass targets from externals -find_package(VulkanHeaders) find_package(VulkanUtilityLibraries) find_package(VulkanMemoryAllocator) find_package(SPIRV-Tools) diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index 956255f01f..0fa37b9765 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -149,11 +149,32 @@ function(AddJsonPackage) get_json_element("${object}" tag tag "") get_json_element("${object}" artifact artifact "") get_json_element("${object}" git_version git_version "") + get_json_element("${object}" git_host git_host "") 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 "") + # okay here comes the fun part: REPLACEMENTS! + # first: tag gets %VERSION% replaced if applicable, with either git_version (preferred) or version + # second: artifact gets %VERSION% and %TAG% replaced accordingly (same rules for VERSION) + + if (git_version) + set(version_replace ${git_version}) + else() + set(version_replace ${version}) + endif() + + # TODO(crueter): fmt module for cmake + if (tag) + string(REPLACE "%VERSION%" "${version_replace}" tag ${tag}) + endif() + + if (artifact) + string(REPLACE "%VERSION%" "${version_replace}" artifact ${artifact}) + string(REPLACE "%TAG%" "${tag}" artifact ${artifact}) + endif() + # format patchdir if (raw_patches) math(EXPR range "${raw_patches_LENGTH} - 1") @@ -202,6 +223,8 @@ function(AddJsonPackage) SOURCE_SUBDIR "${source_subdir}" GIT_VERSION ${git_version} + GIT_HOST ${git_host} + ARTIFACT ${artifact} TAG ${tag} ) @@ -241,6 +264,7 @@ function(AddPackage) NAME VERSION GIT_VERSION + GIT_HOST REPO TAG @@ -273,11 +297,17 @@ function(AddPackage) 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 (NOT DEFINED PKG_ARGS_GIT_HOST) + set(git_host github.com) + else() + set(git_host ${PKG_ARGS_GIT_HOST}) + endif() + if (DEFINED PKG_ARGS_URL) set(pkg_url ${PKG_ARGS_URL}) if (DEFINED PKG_ARGS_REPO) - set(pkg_git_url https://github.com/${PKG_ARGS_REPO}) + set(pkg_git_url https://${git_host}/${PKG_ARGS_REPO}) else() if (DEFINED PKG_ARGS_GIT_URL) set(pkg_git_url ${PKG_ARGS_GIT_URL}) @@ -286,7 +316,7 @@ function(AddPackage) endif() endif() elseif (DEFINED PKG_ARGS_REPO) - set(pkg_git_url https://github.com/${PKG_ARGS_REPO}) + set(pkg_git_url https://${git_host}/${PKG_ARGS_REPO}) if (DEFINED PKG_ARGS_TAG) set(pkg_key ${PKG_ARGS_TAG}) @@ -317,25 +347,23 @@ 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_GIT_VERSION}) - elseif(DEFINED PKG_ARGS_VERSION) - set(git_version ${PKG_ARGS_VERSION}) - endif() - if (NOT DEFINED PKG_ARGS_KEY) if (DEFINED PKG_ARGS_SHA) string(SUBSTRING ${PKG_ARGS_SHA} 0 4 pkg_key) cpm_utils_message(DEBUG ${PKG_ARGS_NAME} "No custom key defined, using ${pkg_key} from sha") - elseif (DEFINED git_version) - set(pkg_key ${git_version}) + elseif(DEFINED PKG_ARGS_GIT_VERSION) + set(pkg_key ${PKG_ARGS_GIT_VERSION}) cpm_utils_message(DEBUG ${PKG_ARGS_NAME} "No custom key defined, using ${pkg_key}") elseif (DEFINED PKG_ARGS_TAG) set(pkg_key ${PKG_ARGS_TAG}) cpm_utils_message(DEBUG ${PKG_ARGS_NAME} "No custom key defined, using ${pkg_key}") + elseif (DEFINED PKG_ARGS_VERSION) + set(pkg_key ${PKG_ARGS_VERSION}) + cpm_utils_message(DEBUG ${PKG_ARGS_NAME} + "No custom key defined, using ${pkg_key}") else() cpm_utils_message(WARNING ${PKG_ARGS_NAME} "Could not determine cache key, using CPM defaults") @@ -446,12 +474,15 @@ function(AddPackage) if (DEFINED PKG_ARGS_SHA) set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS ${PKG_ARGS_SHA}) - elseif(DEFINED git_version) - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS - ${git_version}) + elseif (DEFINED PKG_ARGS_GIT_VERSION) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS + ${PKG_ARGS_GIT_VERSION}) elseif (DEFINED PKG_ARGS_TAG) set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS ${PKG_ARGS_TAG}) + elseif(DEFINED PKG_ARGS_VERSION) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS + ${PKG_ARGS_VERSION}) else() cpm_utils_message(WARNING ${PKG_ARGS_NAME} "Package has no specified sha, tag, or version") @@ -496,6 +527,7 @@ function(add_ci_package key) set(ARTIFACT_DIR ${${ARTIFACT_PACKAGE}_SOURCE_DIR} PARENT_SCOPE) endfunction() +# TODO(crueter): we could do an AddMultiArchPackage, multiplatformpackage? # name is the artifact name, package is for find_package override function(AddCIPackage) set(oneValueArgs diff --git a/CMakeModules/Findmbedtls.cmake b/CMakeModules/Findmbedtls.cmake new file mode 100644 index 0000000000..f5ebf1abdc --- /dev/null +++ b/CMakeModules/Findmbedtls.cmake @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +include(FindPackageHandleStandardArgs) + +find_package(PkgConfig QUIET) +pkg_search_module(mbedtls QUIET IMPORTED_TARGET mbedtls) +find_package_handle_standard_args(mbedtls + REQUIRED_VARS mbedtls_LINK_LIBRARIES + VERSION_VAR mbedtls_VERSION +) + +pkg_search_module(mbedcrypto QUIET IMPORTED_TARGET mbedcrypto) +find_package_handle_standard_args(mbedcrypto + REQUIRED_VARS mbedcrypto_LINK_LIBRARIES + VERSION_VAR mbedcrypto_VERSION +) diff --git a/cpmfile.json b/cpmfile.json index 495382fed0..c720b69e89 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -10,8 +10,8 @@ "boost": { "package": "Boost", "repo": "boostorg/boost", - "tag": "boost-1.88.0", - "artifact": "boost-1.88.0-cmake.7z", + "tag": "boost-%VERSION%", + "artifact": "%TAG%-cmake.7z", "hash": "e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01", "git_version": "1.88.0", "version": "1.57" diff --git a/docs/CPM.md b/docs/CPM.md index f90002891c..7f69cf669e 100644 --- a/docs/CPM.md +++ b/docs/CPM.md @@ -23,7 +23,7 @@ CPMUtil is a wrapper around CPM that aims to reduce boilerplate and add useful u - `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 +- `GIT_VERSION`: The "version" found within git - `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 @@ -71,8 +71,9 @@ Hashing strategies, descending order of precedence: - `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 + - `GIT_VERSION` - Tag + - `VERSION` - 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 diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 793750c2f2..d613201566 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -70,7 +70,43 @@ if (mbedtls_ADDED) endif() # libusb +# TODO(crueter): remove entirely, replace with cpm if (ENABLE_LIBUSB AND NOT TARGET libusb::usb) + set(module externals/libusb) + + file(GLOB RESULT "${PROJECT_SOURCE_DIR}/${module}/") + list(LENGTH RESULT RES_LEN) + if(RES_LEN EQUAL 0) + message(FATAL_ERROR "libusb not found. " + "Please run: \ngit submodule update --init") + endif() + + if (EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git") + set(SUBMODULE_DIR "${PROJECT_SOURCE_DIR}/${module}") + + execute_process( + COMMAND git rev-parse --short=10 HEAD + WORKING_DIRECTORY ${SUBMODULE_DIR} + OUTPUT_VARIABLE SUBMODULE_SHA + ) + + # would probably be better to do string parsing, but whatever + execute_process( + COMMAND git remote get-url origin + WORKING_DIRECTORY ${SUBMODULE_DIR} + OUTPUT_VARIABLE SUBMODULE_URL + ) + + string(REGEX REPLACE "\n|\r" "" SUBMODULE_SHA ${SUBMODULE_SHA}) + string(REGEX REPLACE "\n|\r|\\.git" "" SUBMODULE_URL ${SUBMODULE_URL}) + + get_filename_component(SUBMODULE_NAME ${SUBMODULE_DIR} NAME) + + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES ${SUBMODULE_NAME}) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS ${SUBMODULE_SHA}) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS ${SUBMODULE_URL}) + endif() + add_subdirectory(libusb) endif() @@ -110,21 +146,17 @@ if (YUZU_USE_BUNDLED_FFMPEG) set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE) endif() -# Vulkan-Headers - -# TODO(crueter): Vk1.4 impl - +# VulkanUtilityHeaders - pulls in headers and utility libs AddJsonPackage( - NAME vulkan-headers - BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_HEADERS} -) - -# Vulkan-Utility-Libraries -AddJsonPackage( - NAME vulkan-utility-libraries + NAME vulkan-utility-headers BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES} ) +# small hack +if (NOT VulkanUtilityLibraries_ADDED) + find_package(VulkanHeaders 1.3.274 REQUIRED) +endif() + # SPIRV Tools AddJsonPackage( NAME spirv-tools diff --git a/externals/cpmfile.json b/externals/cpmfile.json index 4bc4a97ca4..f8ca528951 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -3,6 +3,7 @@ "repo": "Mbed-TLS/mbedtls", "sha": "8c88150ca1", "hash": "769ad1e94c570671071e1f2a5c0f1027e0bf6bcdd1a80ea8ac970f2c86bc45ce4e31aa88d6d8110fc1bed1de81c48bc624df1b38a26f8b340a44e109d784a966", + "find_args": "MODULE", "patches": [ "0001-cmake-version.patch" ] @@ -42,18 +43,13 @@ "0002-missing-decl.patch" ] }, - "vulkan-headers": { - "package": "VulkanHeaders", - "version": "1.3.274", - "repo": "KhronosGroup/Vulkan-Headers", - "sha": "89268a6d17", - "hash": "3ab349f74298ba72cafb8561015690c0674d428a09fb91ccd3cd3daca83650d190d46d33fd97b0a8fd4223fe6df2bcabae89136fbbf7c0bfeb8776f9448304c8" - }, - "vulkan-utility-libraries": { + "vulkan-utility-headers": { "package": "VulkanUtilityLibraries", - "repo": "KhronosGroup/Vulkan-Utility-Libraries", - "sha": "df2e358152", - "hash": "3e468c3d9ff93f6d418d71e5527abe0a12c8c7ab5b0b52278bbbee4d02bb87e99073906729b727e0147242b7e3fd5dedf68b803f1878cb4c0e4f730bc2238d79" + "repo": "scripts/VulkanUtilityHeaders", + "tag": "1.4.326", + "artifact": "VulkanUtilityHeaders.tar.zst", + "git_host": "git.crueter.xyz", + "hash": "5924629755cb1605c4aa4eee20ef7957a9dd8d61e4df548be656d98054f2730c4109693c1bd35811f401f4705d2ccff9fc849be32b0d8480bc3f73541a5e0964" }, "vulkan-memory-allocator": { "package": "VulkanMemoryAllocator", diff --git a/externals/nx_tzdb/cpmfile.json b/externals/nx_tzdb/cpmfile.json index fc7dd77628..feb9daf7da 100644 --- a/externals/nx_tzdb/cpmfile.json +++ b/externals/nx_tzdb/cpmfile.json @@ -1,7 +1,10 @@ { "tzdb": { "package": "nx_tzdb", - "url": "https://github.com/crueter/tzdb_to_nx/releases/download/250725/250725.zip", + "repo": "misc/tzdb_to_nx", + "git_host": "git.crueter.xyz", + "artifact": "%VERSION%.zip", + "tag": "%VERSION%", "hash": "8f60b4b29f285e39c0443f3d5572a73780f3dbfcfd5b35004451fadad77f3a215b2e2aa8d0fffe7e348e2a7b0660882b35228b6178dda8804a14ce44509fd2ca", "version": "250725" } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 26d6aa62a7..1979d427b5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1199,7 +1199,7 @@ else() target_link_libraries(core PUBLIC Boost::headers) endif() -target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API) +target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API mbedtls) if (MINGW) target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) endif() diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 74b1ca04b1..04b75d5e8f 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.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 @@ -31,6 +34,10 @@ #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" +#ifndef MBEDTLS_CMAC_C +#error mbedtls was compiled without CMAC support. Check your USE flags (Gentoo) or contact your package maintainer. +#endif + namespace Core::Crypto { namespace { diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index 842eb91a88..11a8b620ae 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + cmake_minimum_required(VERSION 3.12) project(dynarmic LANGUAGES C CXX ASM VERSION 6.7.0) @@ -147,21 +150,9 @@ else() endif() endif() -# Forced use of individual bundled libraries for non-REQUIRED library is possible with e.g. cmake -DCMAKE_DISABLE_FIND_PACKAGE_fmt=ON ... - -if (DYNARMIC_USE_BUNDLED_EXTERNALS) - set(CMAKE_DISABLE_FIND_PACKAGE_biscuit ON) - set(CMAKE_DISABLE_FIND_PACKAGE_fmt ON) - set(CMAKE_DISABLE_FIND_PACKAGE_mcl ON) - set(CMAKE_DISABLE_FIND_PACKAGE_oaknut ON) - set(CMAKE_DISABLE_FIND_PACKAGE_unordered_dense ON) - set(CMAKE_DISABLE_FIND_PACKAGE_xbyak ON) - set(CMAKE_DISABLE_FIND_PACKAGE_Zydis ON) - set(CMAKE_DISABLE_FIND_PACKAGE_Zycore ON) -endif() - find_package(Boost 1.57 REQUIRED) find_package(fmt 9 CONFIG) +find_package(mcl 0.1.12 REQUIRED) if ("arm64" IN_LIST ARCHITECTURE OR DYNARMIC_TESTS) find_package(oaknut 2.0.1 CONFIG) @@ -169,6 +160,8 @@ endif() if ("x86_64" IN_LIST ARCHITECTURE) find_package(xbyak 7 CONFIG) + find_package(zycore REQUIRED) + find_package(zydis 4 REQUIRED) endif() if (DYNARMIC_USE_LLVM) diff --git a/src/dynarmic/externals/CMakeLists.txt b/src/dynarmic/externals/CMakeLists.txt index 26f9290ed8..a413d04f25 100644 --- a/src/dynarmic/externals/CMakeLists.txt +++ b/src/dynarmic/externals/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # Explicitly include CPMUtil here since we have a separate cpmfile for dynarmic set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) include(CPMUtil) @@ -20,62 +23,25 @@ set(BUILD_TESTING OFF) # biscuit if ("riscv" IN_LIST ARCHITECTURE) - add_subdirectory(biscuit) - AddJsonPackage( NAME biscuit BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) endif() -# catch - -# 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() - # mcl AddJsonPackage( NAME mcl BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) -# oaknut - -# if (NOT TARGET merry::oaknut) -# if ("arm64" IN_LIST ARCHITECTURE) -# add_subdirectory(oaknut) -# elseif (DYNARMIC_TESTS) -# add_subdirectory(oaknut EXCLUDE_FROM_ALL) -# endif() -# endif() - -# xbyak -# uncomment if in an independent repo - -# if (NOT TARGET xbyak::xbyak) -# if ("x86_64" IN_LIST ARCHITECTURE) -# add_subdirectory(xbyak) -# endif() -# endif() - -# zydis - # 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 - AddJsonPackage(zycore) + AddJsonPackage( + NAME zycore + BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} + ) AddJsonPackage( NAME zydis diff --git a/src/dynarmic/externals/cpmfile.json b/src/dynarmic/externals/cpmfile.json index e9406cbe81..718163baf5 100644 --- a/src/dynarmic/externals/cpmfile.json +++ b/src/dynarmic/externals/cpmfile.json @@ -15,14 +15,13 @@ ] }, "zycore": { - "package": "Zycore", + "package": "zycore", "repo": "zyantific/zycore-c", "sha": "75a36c45ae", - "hash": "15aa399f39713e042c4345bc3175c82f14dca849fde2a21d4f591f62c43e227b70d868d8bb86beb5f4eb68b1d6bd3792cdd638acf89009e787e3d10ee7401924", - "bundled": true + "hash": "15aa399f39713e042c4345bc3175c82f14dca849fde2a21d4f591f62c43e227b70d868d8bb86beb5f4eb68b1d6bd3792cdd638acf89009e787e3d10ee7401924" }, "zydis": { - "package": "Zydis", + "package": "zydis", "version": "4", "repo": "zyantific/zydis", "sha": "c2d2bab025", diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index 7ec92206f9..efae44d917 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -164,7 +164,7 @@ if ("x86_64" IN_LIST ARCHITECTURE) target_link_libraries(dynarmic PRIVATE xbyak::xbyak - Zydis + Zydis::Zydis ) target_architecture_specific_sources(dynarmic "x86_64" diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index b608542d84..e0f7f82fbe 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -335,7 +335,7 @@ target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) target_link_libraries(video_core PRIVATE sirit) # Header-only stuff needed by all dependent targets -target_link_libraries(video_core PUBLIC Vulkan::Headers Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator) +target_link_libraries(video_core PUBLIC Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator) if (ENABLE_NSIGHT_AFTERMATH) if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) diff --git a/tools/cpm-fetch-all.sh b/tools/cpm-fetch-all.sh index 38f7b1f941..eac0f861a4 100755 --- a/tools/cpm-fetch-all.sh +++ b/tools/cpm-fetch-all.sh @@ -6,5 +6,6 @@ # 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 " ") +LIBS=$(find . externals src/yuzu/externals src/dynarmic -maxdepth 2 -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 index 1c2ce007d2..f9614b1904 100755 --- a/tools/cpm-fetch.sh +++ b/tools/cpm-fetch.sh @@ -84,7 +84,7 @@ ci_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}" + DOWNLOAD="https://$GIT_URL/${REPO}/releases/download/v${VERSION}/${FILENAME}" PACKAGE_NAME="$PACKAGE" KEY=$platform @@ -122,14 +122,32 @@ do URL=$(jq -r ".url" <<< "$JSON") REPO=$(jq -r ".repo" <<< "$JSON") SHA=$(jq -r ".sha" <<< "$JSON") + GIT_URL=$(jq -r ".git_url" <<< "$JSON") + + [ "$GIT_URL" == null ] && GIT_URL=github.com + + VERSION=$(jq -r ".version" <<< "$JSON") + GIT_VERSION=$(jq -r ".git_version" <<< "$JSON") + + if [ "$GIT_VERSION" != null ]; then + VERSION_REPLACE="$GIT_VERSION" + else + VERSION_REPLACE="$VERSION" + fi + + TAG=$(jq -r ".tag" <<< "$JSON") + + TAG=$(sed "s/%VERSION%/$VERSION_REPLACE/" <<< $TAG) + + ARTIFACT=$(jq -r ".artifact" <<< "$JSON") + ARTIFACT=$(sed "s/%VERSION%/$VERSION_REPLACE/" <<< $ARTIFACT) + ARTIFACT=$(sed "s/%TAG%/$TAG/" <<< $ARTIFACT) if [ "$URL" != "null" ]; then DOWNLOAD="$URL" elif [ "$REPO" != "null" ]; then - GIT_URL="https://github.com/$REPO" + GIT_URL="https://$GIT_URL/$REPO" - TAG=$(jq -r ".tag" <<< "$JSON") - ARTIFACT=$(jq -r ".artifact" <<< "$JSON") BRANCH=$(jq -r ".branch" <<< "$JSON") if [ "$TAG" != "null" ]; then @@ -155,24 +173,21 @@ do # key parsing KEY=$(jq -r ".key" <<< "$JSON") - if [ "$KEY" == null ]; then - VERSION=$(jq -r ".version" <<< "$JSON") - GIT_VERSION=$(jq -r ".git_version" <<< "$JSON") - + if [ "$KEY" == null ]; then if [ "$SHA" != null ]; then KEY=$(cut -c1-4 - <<< "$SHA") elif [ "$GIT_VERSION" != null ]; then KEY="$GIT_VERSION" + elif [ "$TAG" != null ]; then + KEY="$TAG" 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" + echo "No valid key could be determined for $package. Must define one of: key, sha, tag, version, git_version" continue fi fi - echo $KEY - echo "Downloading regular package $package, with key $KEY, from $DOWNLOAD" # hash parsing From 2ca36e1bd7cf7cf839bffc23659fb17b14434bb8 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 7 Sep 2025 18:45:02 -0400 Subject: [PATCH 37/37] [doc] fix line endings and update macos Signed-off-by: crueter --- docs/build/Android.md | 84 ++++----- docs/build/FreeBSD.md | 160 ++++++++--------- docs/build/Linux.md | 276 +++++++++++++++--------------- docs/build/Solaris.md | 100 +++++------ docs/build/Windows.md | 386 +++++++++++++++++++++--------------------- docs/build/macOS.md | 183 +++++++++----------- 6 files changed, 581 insertions(+), 608 deletions(-) diff --git a/docs/build/Android.md b/docs/build/Android.md index 4bb1c868b6..0538d351ea 100644 --- a/docs/build/Android.md +++ b/docs/build/Android.md @@ -1,42 +1,42 @@ -# Note: These build instructions are a work-in-progress. - -## Dependencies -* [Android Studio](https://developer.android.com/studio) -* [NDK 25.2.9519653 and CMake 3.22.1](https://developer.android.com/studio/projects/install-ndk#default-version) -* [Git](https://git-scm.com/download) - -### WINDOWS ONLY - Additional Dependencies - * **[Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/)** - **Make sure to select "Desktop development with C++" support in the installer. Make sure to update to the latest version if already installed.** - * **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** - **Make sure to select Latest SDK.** - - A convenience script to install the latest SDK is provided in `.ci\windows\install-vulkan-sdk.ps1`. - -## Cloning Eden with Git -``` -git clone --recursive https://git.eden-emu.dev/eden-emu/eden.git -``` -Eden by default will be cloned into - -* `C:\Users\\eden` on Windows -* `~/eden` on Linux -* And wherever on macOS - -## Building -1. Start Android Studio, on the startup dialog select `Open`. -2. Navigate to the `eden/src/android` directory and click on `OK`. -3. In `Build > Select Build Variant`, select `release` or `relWithDebInfo` as the "Active build variant". -4. Build the project with `Build > Make Project` or run it on an Android device with `Run > Run 'app'`. - -## Building with Terminal -1. Download the SDK and NDK from Android Studio. -2. Navigate to SDK and NDK paths. -3. Then set ANDROID_SDK_ROOT and ANDROID_NDK_ROOT in terminal via -`export ANDROID_SDK_ROOT=path/to/sdk` -`export ANDROID_NDK_ROOT=path/to/ndk`. -4. Navigate to `eden/src/android`. -5. Then Build with `./gradlew assemblerelWithDebInfo`. -6. To build the optimised build use `./gradlew assembleGenshinSpoofRelWithDebInfo`. - -### Script -A convenience script for building is provided in `.ci/android/build.sh`. The built APK can be put into an `artifacts` directory via `.ci/android/package.sh`. On Windows, these must be done in the Git Bash or MinGW terminal. - -### Additional Resources -https://developer.android.com/studio/intro +# Note: These build instructions are a work-in-progress. + +## Dependencies +* [Android Studio](https://developer.android.com/studio) +* [NDK 25.2.9519653 and CMake 3.22.1](https://developer.android.com/studio/projects/install-ndk#default-version) +* [Git](https://git-scm.com/download) + +### WINDOWS ONLY - Additional Dependencies + * **[Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/)** - **Make sure to select "Desktop development with C++" support in the installer. Make sure to update to the latest version if already installed.** + * **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** - **Make sure to select Latest SDK.** + - A convenience script to install the latest SDK is provided in `.ci\windows\install-vulkan-sdk.ps1`. + +## Cloning Eden with Git +``` +git clone --recursive https://git.eden-emu.dev/eden-emu/eden.git +``` +Eden by default will be cloned into - +* `C:\Users\\eden` on Windows +* `~/eden` on Linux +* And wherever on macOS + +## Building +1. Start Android Studio, on the startup dialog select `Open`. +2. Navigate to the `eden/src/android` directory and click on `OK`. +3. In `Build > Select Build Variant`, select `release` or `relWithDebInfo` as the "Active build variant". +4. Build the project with `Build > Make Project` or run it on an Android device with `Run > Run 'app'`. + +## Building with Terminal +1. Download the SDK and NDK from Android Studio. +2. Navigate to SDK and NDK paths. +3. Then set ANDROID_SDK_ROOT and ANDROID_NDK_ROOT in terminal via +`export ANDROID_SDK_ROOT=path/to/sdk` +`export ANDROID_NDK_ROOT=path/to/ndk`. +4. Navigate to `eden/src/android`. +5. Then Build with `./gradlew assemblerelWithDebInfo`. +6. To build the optimised build use `./gradlew assembleGenshinSpoofRelWithDebInfo`. + +### Script +A convenience script for building is provided in `.ci/android/build.sh`. The built APK can be put into an `artifacts` directory via `.ci/android/package.sh`. On Windows, these must be done in the Git Bash or MinGW terminal. + +### Additional Resources +https://developer.android.com/studio/intro diff --git a/docs/build/FreeBSD.md b/docs/build/FreeBSD.md index b4510225a3..97eef8f9d8 100644 --- a/docs/build/FreeBSD.md +++ b/docs/build/FreeBSD.md @@ -1,81 +1,81 @@ -Eden is not currently available as a port on FreeBSD, though it is in the works. For now, the recommended method of usage is to compile it yourself. Check back often, as the build process frequently changes. - -## Dependencies. -Eden needs the following dependencies: - -``` -devel/cmake -devel/sdl20 -devel/boost-libs -devel/catch2 -devel/libfmt -devel/nlohmann-json -devel/ninja -devel/nasm -devel/autoconf -devel/pkgconf -devel/qt6-base - -net/enet - -multimedia/ffnvcodec-headers -multimedia/ffmpeg - -audio/opus - -archivers/liblz4 - -lang/gcc12 - -graphics/glslang -graphics/vulkan-utility-libraries -``` - -If using FreeBSD 12 or prior, use `devel/pkg-config` instead. - ---- - -### Build preparations: -Run the following command to clone eden with git: -```sh -git clone --recursive https://git.eden-emu.dev/eden-emu/eden -``` -You usually want to add the `--recursive` parameter as it also takes care of the external dependencies for you. - -Now change into the eden directory and create a build directory there: -```sh -cd eden -mkdir build -``` - -Change into that build directory: -```sh -cd build -``` - -#### 1. Building in Release Mode (usually preferred and the most performant choice): -```sh -cmake .. -GNinja -DYUZU_TESTS=OFF -``` - -#### 2. Building in Release Mode with debugging symbols (useful if you want to debug errors for a eventual fix): -```sh -cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_TESTS=ON -``` - -Build the emulator locally: -```sh -ninja -``` - -Optional: If you wish to install eden globally onto your system issue the following command: -```sh -sudo ninja install -``` -OR -```sh -doas -- ninja install -``` - -## OpenSSL +Eden is not currently available as a port on FreeBSD, though it is in the works. For now, the recommended method of usage is to compile it yourself. Check back often, as the build process frequently changes. + +## Dependencies. +Eden needs the following dependencies: + +``` +devel/cmake +devel/sdl20 +devel/boost-libs +devel/catch2 +devel/libfmt +devel/nlohmann-json +devel/ninja +devel/nasm +devel/autoconf +devel/pkgconf +devel/qt6-base + +net/enet + +multimedia/ffnvcodec-headers +multimedia/ffmpeg + +audio/opus + +archivers/liblz4 + +lang/gcc12 + +graphics/glslang +graphics/vulkan-utility-libraries +``` + +If using FreeBSD 12 or prior, use `devel/pkg-config` instead. + +--- + +### Build preparations: +Run the following command to clone eden with git: +```sh +git clone --recursive https://git.eden-emu.dev/eden-emu/eden +``` +You usually want to add the `--recursive` parameter as it also takes care of the external dependencies for you. + +Now change into the eden directory and create a build directory there: +```sh +cd eden +mkdir build +``` + +Change into that build directory: +```sh +cd build +``` + +#### 1. Building in Release Mode (usually preferred and the most performant choice): +```sh +cmake .. -GNinja -DYUZU_TESTS=OFF +``` + +#### 2. Building in Release Mode with debugging symbols (useful if you want to debug errors for a eventual fix): +```sh +cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_TESTS=ON +``` + +Build the emulator locally: +```sh +ninja +``` + +Optional: If you wish to install eden globally onto your system issue the following command: +```sh +sudo ninja install +``` +OR +```sh +doas -- ninja install +``` + +## OpenSSL The available OpenSSL port (3.0.17) is out-of-date, and using a bundled static library instead is recommended; to do so, add `-DYUZU_USE_CPM=ON` to your CMake configure command. \ No newline at end of file diff --git a/docs/build/Linux.md b/docs/build/Linux.md index be58b451fa..a6b7b2dda7 100644 --- a/docs/build/Linux.md +++ b/docs/build/Linux.md @@ -1,138 +1,138 @@ -### Dependencies - -You'll need to download and install the following to build Eden: - - * [GCC](https://gcc.gnu.org/) v11+ (for C++20 support) & misc - * If GCC 12 is installed, [Clang](https://clang.llvm.org/) v14+ is required for compiling - * [CMake](https://www.cmake.org/) 3.22+ - -The following are handled by Eden's externals: - - * [FFmpeg](https://ffmpeg.org/) - * [SDL2](https://www.libsdl.org/download-2.0.php) 2.0.18+ - * [opus](https://opus-codec.org/downloads/) 1.3+ - -All other dependencies will be downloaded and built by [CPM](https://github.com/cpm-cmake/CPM.cmake/) if `YUZU_USE_CPM` is on, but will always use system dependencies if available: - - * [Boost](https://www.boost.org/users/download/) 1.79.0+ - * [Catch2](https://github.com/catchorg/Catch2) 2.13.7 - 2.13.9 - * [fmt](https://fmt.dev/) 8.0.1+ - * [lz4](http://www.lz4.org) 1.8+ - * [nlohmann_json](https://github.com/nlohmann/json) 3.8+ - * [OpenSSL](https://www.openssl.org/source/) 1.1.1+ - * [ZLIB](https://www.zlib.net/) 1.2+ - * [zstd](https://facebook.github.io/zstd/) 1.5+ - * [enet](http://enet.bespin.org/) 1.3+ - * [cubeb](https://github.com/mozilla/cubeb) - * [SimpleIni](https://github.com/brofield/simpleini) - -Certain other dependencies (httplib, jwt, sirit, etc.) will be fetched by CPM regardless. System packages *can* be used for these libraries but this is generally not recommended. - -Dependencies are listed here as commands that can be copied/pasted. Of course, they should be inspected before being run. - -- Arch / Manjaro: - - `sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 mbedtls ninja nlohmann-json openssl opus qt6-base qt6-multimedia sdl2 zlib zstd zip unzip` - - Building with QT Web Engine requires `qt6-webengine` as well. - - Proper wayland support requires `qt6-wayland` - - 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 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` - -```sh -git submodule update --init --recursive -cmake .. -GNinja -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11 -``` - -- Fedora: - - `sudo dnf install autoconf ccache cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt6-linguist qt6-qtbase{-private,}-devel qt6-qtwebengine-devel qt6-qtmultimedia-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel` - - Fedora 32 or later is required. - - Due to GCC 12, Fedora 36 or later users need to install `clang`, and configure CMake to use it via `-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang` - - CMake arguments to force system libraries: - - SDL2: `-DYUZU_USE_BUNDLED_SDL2=OFF -DYUZU_USE_EXTERNAL_SDL2=OFF` - - FFmpeg: `-DYUZU_USE_EXTERNAL_FFMPEG=OFF` - - [RPM Fusion](https://rpmfusion.org/) (free) is required to install `ffmpeg-devel` - -### Cloning Eden with Git - -**Master:** - -```bash -git clone --recursive https://git.eden-emu.dev/eden-emu/eden -cd eden -``` - -The `--recursive` option automatically clones the required Git submodules. - -### Building Eden in Release Mode (Optimised) - -If you need to run ctests, you can disable `-DYUZU_TESTS=OFF` and install Catch2. - -```bash -mkdir build && cd build -cmake .. -GNinja -DYUZU_TESTS=OFF -ninja -sudo ninja install -``` -You may also want to include support for Discord Rich Presence by adding `-DUSE_DISCORD_PRESENCE=ON` after `cmake ..` - -`-DYUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS=OFF` might be needed if ninja command failed with `undefined reference to symbol 'spvOptimizerOptionsCreate`, reason currently unknown - -Optionally, you can use `cmake-gui ..` to adjust various options (e.g. disable the Qt GUI). - -### Building Eden in Debug Mode (Slow) - -```bash -mkdir build && cd build -cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DYUZU_TESTS=OFF -ninja -``` - -### Building with debug symbols - -```bash -mkdir build && cd build -cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU -DYUZU_TESTS=OFF -ninja -``` - -### Building with Scripts -A convenience script for building is provided in `.ci/linux/build.sh`. You must provide an arch target for optimization, e.g. `.ci/linux/build.sh amd64`. Valid targets: -- `legacy`: x86_64 generic, only needed for CPUs older than 2013 or so -- `amd64`: x86_64-v3, for CPUs newer than 2013 or so -- `steamdeck` / `zen2`: For Steam Deck or Zen >= 2 AMD CPUs (untested on Intel) -- `rog-ally` / `allyx` / `zen4`: For ROG Ally X or Zen >= 4 AMD CPUs (untested on Intel) -- `aarch64`: For armv8-a CPUs, older than mid-2021 or so -- `armv9`: For armv9-a CPUs, newer than mid-2021 or so -- `native`: Optimize to your native host architecture - -Extra flags to pass to CMake should be passed after the arch target. - -Additional environment variables can be used to control building: -- `NPROC`: Number of threads to use for compilation (defaults to all) -- `TARGET`: Set to `appimage` to disable standalone `eden-cli` and `eden-room` executables -- `BUILD_TYPE`: Sets the build type to use. Defaults to `Release` - -The following environment variables are boolean flags. Set to `true` to enable or `false` to disable: -- `DEVEL` (default FALSE): Disable Qt update checker -- `USE_WEBENGINE` (default FALSE): Enable Qt WebEngine -- `USE_MULTIMEDIA` (default TRUE): Enable Qt Multimedia - -After building, an AppImage can be packaged via `.ci/linux/package.sh`. This script takes the same arch targets as the build script. If the build was created in a different directory, you can specify its path relative to the source directory, e.g. `.ci/linux/package.sh amd64 build-appimage`. Additionally, set the `DEVEL` environment variable to `true` to change the app name to `Eden Nightly`. - -### Running without installing - -After building, the binaries `eden` and `eden-cmd` (depending on your build options) will end up in `build/bin/`. - -```bash -# SDL -cd build/bin/ -./eden-cmd - -# Qt -cd build/bin/ -./eden -``` +### Dependencies + +You'll need to download and install the following to build Eden: + + * [GCC](https://gcc.gnu.org/) v11+ (for C++20 support) & misc + * If GCC 12 is installed, [Clang](https://clang.llvm.org/) v14+ is required for compiling + * [CMake](https://www.cmake.org/) 3.22+ + +The following are handled by Eden's externals: + + * [FFmpeg](https://ffmpeg.org/) + * [SDL2](https://www.libsdl.org/download-2.0.php) 2.0.18+ + * [opus](https://opus-codec.org/downloads/) 1.3+ + +All other dependencies will be downloaded and built by [CPM](https://github.com/cpm-cmake/CPM.cmake/) if `YUZU_USE_CPM` is on, but will always use system dependencies if available: + + * [Boost](https://www.boost.org/users/download/) 1.79.0+ + * [Catch2](https://github.com/catchorg/Catch2) 2.13.7 - 2.13.9 + * [fmt](https://fmt.dev/) 8.0.1+ + * [lz4](http://www.lz4.org) 1.8+ + * [nlohmann_json](https://github.com/nlohmann/json) 3.8+ + * [OpenSSL](https://www.openssl.org/source/) 1.1.1+ + * [ZLIB](https://www.zlib.net/) 1.2+ + * [zstd](https://facebook.github.io/zstd/) 1.5+ + * [enet](http://enet.bespin.org/) 1.3+ + * [cubeb](https://github.com/mozilla/cubeb) + * [SimpleIni](https://github.com/brofield/simpleini) + +Certain other dependencies (httplib, jwt, sirit, etc.) will be fetched by CPM regardless. System packages *can* be used for these libraries but this is generally not recommended. + +Dependencies are listed here as commands that can be copied/pasted. Of course, they should be inspected before being run. + +- Arch / Manjaro: + - `sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 mbedtls ninja nlohmann-json openssl opus qt6-base qt6-multimedia sdl2 zlib zstd zip unzip` + - Building with QT Web Engine requires `qt6-webengine` as well. + - Proper wayland support requires `qt6-wayland` + - 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 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` + +```sh +git submodule update --init --recursive +cmake .. -GNinja -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11 +``` + +- Fedora: + - `sudo dnf install autoconf ccache cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt6-linguist qt6-qtbase{-private,}-devel qt6-qtwebengine-devel qt6-qtmultimedia-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel` + - Fedora 32 or later is required. + - Due to GCC 12, Fedora 36 or later users need to install `clang`, and configure CMake to use it via `-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang` + - CMake arguments to force system libraries: + - SDL2: `-DYUZU_USE_BUNDLED_SDL2=OFF -DYUZU_USE_EXTERNAL_SDL2=OFF` + - FFmpeg: `-DYUZU_USE_EXTERNAL_FFMPEG=OFF` + - [RPM Fusion](https://rpmfusion.org/) (free) is required to install `ffmpeg-devel` + +### Cloning Eden with Git + +**Master:** + +```bash +git clone --recursive https://git.eden-emu.dev/eden-emu/eden +cd eden +``` + +The `--recursive` option automatically clones the required Git submodules. + +### Building Eden in Release Mode (Optimised) + +If you need to run ctests, you can disable `-DYUZU_TESTS=OFF` and install Catch2. + +```bash +mkdir build && cd build +cmake .. -GNinja -DYUZU_TESTS=OFF +ninja +sudo ninja install +``` +You may also want to include support for Discord Rich Presence by adding `-DUSE_DISCORD_PRESENCE=ON` after `cmake ..` + +`-DYUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS=OFF` might be needed if ninja command failed with `undefined reference to symbol 'spvOptimizerOptionsCreate`, reason currently unknown + +Optionally, you can use `cmake-gui ..` to adjust various options (e.g. disable the Qt GUI). + +### Building Eden in Debug Mode (Slow) + +```bash +mkdir build && cd build +cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DYUZU_TESTS=OFF +ninja +``` + +### Building with debug symbols + +```bash +mkdir build && cd build +cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU -DYUZU_TESTS=OFF +ninja +``` + +### Building with Scripts +A convenience script for building is provided in `.ci/linux/build.sh`. You must provide an arch target for optimization, e.g. `.ci/linux/build.sh amd64`. Valid targets: +- `legacy`: x86_64 generic, only needed for CPUs older than 2013 or so +- `amd64`: x86_64-v3, for CPUs newer than 2013 or so +- `steamdeck` / `zen2`: For Steam Deck or Zen >= 2 AMD CPUs (untested on Intel) +- `rog-ally` / `allyx` / `zen4`: For ROG Ally X or Zen >= 4 AMD CPUs (untested on Intel) +- `aarch64`: For armv8-a CPUs, older than mid-2021 or so +- `armv9`: For armv9-a CPUs, newer than mid-2021 or so +- `native`: Optimize to your native host architecture + +Extra flags to pass to CMake should be passed after the arch target. + +Additional environment variables can be used to control building: +- `NPROC`: Number of threads to use for compilation (defaults to all) +- `TARGET`: Set to `appimage` to disable standalone `eden-cli` and `eden-room` executables +- `BUILD_TYPE`: Sets the build type to use. Defaults to `Release` + +The following environment variables are boolean flags. Set to `true` to enable or `false` to disable: +- `DEVEL` (default FALSE): Disable Qt update checker +- `USE_WEBENGINE` (default FALSE): Enable Qt WebEngine +- `USE_MULTIMEDIA` (default TRUE): Enable Qt Multimedia + +After building, an AppImage can be packaged via `.ci/linux/package.sh`. This script takes the same arch targets as the build script. If the build was created in a different directory, you can specify its path relative to the source directory, e.g. `.ci/linux/package.sh amd64 build-appimage`. Additionally, set the `DEVEL` environment variable to `true` to change the app name to `Eden Nightly`. + +### Running without installing + +After building, the binaries `eden` and `eden-cmd` (depending on your build options) will end up in `build/bin/`. + +```bash +# SDL +cd build/bin/ +./eden-cmd + +# Qt +cd build/bin/ +./eden +``` diff --git a/docs/build/Solaris.md b/docs/build/Solaris.md index d4cfdbb6a9..f7174c2869 100644 --- a/docs/build/Solaris.md +++ b/docs/build/Solaris.md @@ -1,51 +1,51 @@ -# Building for Solaris - -## Dependencies. -Always consult [the OpenIndiana package list](https://pkg.openindiana.org/hipster/en/index.shtml) to cross-verify availability. - -Run the usual update + install of essential toolings: `sudo pkg update && sudo pkg install git cmake`. - -- **gcc**: `sudo pkg install developer/gcc-14`. -- **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`. - -Then install the libraies: `sudo pkg install qt6 boost glslang libzip library/lz4 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt`. - -### Building - -Clone eden with git `git clone --recursive https://git.eden-emu.dev/eden-emu/eden` - -```sh -# Needed for some dependencies that call cc directly (tz) -echo '#!/bin/sh' >cc -echo 'gcc $@' >>cc -chmod +x cc -export PATH="$PATH:$PWD" -``` - -Patch for FFmpeg: -```sh -sed -i 's/ make / gmake /' externals/ffmpeg/CMakeFiles/ffmpeg-build.dir/build.make -``` - -- **Configure**: `cmake -B build -DYUZU_USE_CPM=ON -DCMAKE_CXX_FLAGS="-I/usr/include/SDL2" -DCMAKE_C_FLAGS="-I/usr/include/SDL2"`. -- **Build**: `cmake --build build`. -- **Installing**: `sudo cmake --install build`. - -### Running - -Default Mesa is a bit outdated, the following environment variables should be set for a smoother experience: -```sh -export MESA_GL_VERSION_OVERRIDE=4.6 -export MESA_GLSL_VERSION_OVERRIDE=460 -export MESA_EXTENSION_MAX_YEAR=2025 -export MESA_DEBUG=1 -export MESA_VK_VERSION_OVERRIDE=1.3 -# Only if nvidia/intel drm drivers cause crashes, will severely hinder performance -export LIBGL_ALWAYS_SOFTWARE=1 -``` - -### Notes - -- Modify the generated ffmpeg.make (in build dir) if using multiple threads (base system `make` doesn't use `-j4`, so change for `gmake`). -- If using OpenIndiana, due to a bug in SDL2 cmake configuration; Audio driver defaults to SunOS ``, which does not exist on OpenIndiana. +# Building for Solaris + +## Dependencies. +Always consult [the OpenIndiana package list](https://pkg.openindiana.org/hipster/en/index.shtml) to cross-verify availability. + +Run the usual update + install of essential toolings: `sudo pkg update && sudo pkg install git cmake`. + +- **gcc**: `sudo pkg install developer/gcc-14`. +- **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`. + +Then install the libraies: `sudo pkg install qt6 boost glslang libzip library/lz4 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt`. + +### Building + +Clone eden with git `git clone --recursive https://git.eden-emu.dev/eden-emu/eden` + +```sh +# Needed for some dependencies that call cc directly (tz) +echo '#!/bin/sh' >cc +echo 'gcc $@' >>cc +chmod +x cc +export PATH="$PATH:$PWD" +``` + +Patch for FFmpeg: +```sh +sed -i 's/ make / gmake /' externals/ffmpeg/CMakeFiles/ffmpeg-build.dir/build.make +``` + +- **Configure**: `cmake -B build -DYUZU_USE_CPM=ON -DCMAKE_CXX_FLAGS="-I/usr/include/SDL2" -DCMAKE_C_FLAGS="-I/usr/include/SDL2"`. +- **Build**: `cmake --build build`. +- **Installing**: `sudo cmake --install build`. + +### Running + +Default Mesa is a bit outdated, the following environment variables should be set for a smoother experience: +```sh +export MESA_GL_VERSION_OVERRIDE=4.6 +export MESA_GLSL_VERSION_OVERRIDE=460 +export MESA_EXTENSION_MAX_YEAR=2025 +export MESA_DEBUG=1 +export MESA_VK_VERSION_OVERRIDE=1.3 +# Only if nvidia/intel drm drivers cause crashes, will severely hinder performance +export LIBGL_ALWAYS_SOFTWARE=1 +``` + +### Notes + +- Modify the generated ffmpeg.make (in build dir) if using multiple threads (base system `make` doesn't use `-j4`, so change for `gmake`). +- If using OpenIndiana, due to a bug in SDL2 cmake configuration; Audio driver defaults to SunOS ``, which does not exist on OpenIndiana. - System OpenSSL generally does not work. Instead, use `-DYUZU_USE_CPM=ON` to use a bundled static OpenSSL, or build a system dependency from source. \ No newline at end of file diff --git a/docs/build/Windows.md b/docs/build/Windows.md index 3b8c459073..c1792983aa 100644 --- a/docs/build/Windows.md +++ b/docs/build/Windows.md @@ -1,193 +1,193 @@ -# THIS GUIDE IS INTENDED FOR DEVELOPERS ONLY, SUPPORT WILL ONLY BE GIVEN IF YOU'RE A DEVELOPER. - -## Method I: MSVC Build for Windows - -### Minimal Dependencies - -On Windows, all library dependencies are automatically included within the `externals` folder, or can be downloaded on-demand. To build Eden, you need to install: - - * **[Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/)** - **Make sure to select C++ support in the installer. Make sure to update to the latest version if already installed.** - * **[CMake](https://cmake.org/download/)** - Used to generate Visual Studio project files. Does not matter if either 32-bit or 64-bit version is installed. - * **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** - **Make sure to select Latest SDK.** - - A convenience script to install the latest SDK is provided in `.ci\windows\install-vulkan-sdk.ps1`. - - ![2](https://i.imgur.com/giDwuTm.png) - - * **Git** - We recommend [Git for Windows](https://gitforwindows.org). - - ![3](https://i.imgur.com/UeSzkBw.png) - - * While installing Git Bash, you should tell it to include Git in your system path. (Choose the "Git from the command line and also from 3rd-party software" option.) If you missed that, don't worry, you'll just have to manually tell CMake where your git.exe is, since it's used to include version info into the built executable. - - ![4](https://i.imgur.com/x0rRs1t.png) - -### Cloning Eden with Git - -**Master:** - ```cmd - git clone --recursive https://git.eden-emu.dev/eden-emu/eden - cd eden - ``` - - ![9](https://i.imgur.com/CcxIAht.png) - -* *(Note: eden by default downloads to `C:\Users\\eden` (Master) - -### Building - -* Open the CMake GUI application and point it to the `eden` (Master) - - ![10](https://i.imgur.com/qOslIWv.png) - -* For the build directory, use a `/build` subdirectory inside the source directory or some other directory of your choice. (Tell CMake to create it.) - -* Click the "Configure" button and choose `Visual Studio 17 2022`, with `x64` for the optional platform. - - ![12](https://i.imgur.com/DKiREaK.png) - - * *(Note: If you used GitHub's own app to clone, run `git submodule update --init --recursive` to get the remaining dependencies)* - - * *(You may also want to disable `YUZU_TESTS` in this case since Catch2 is not yet supported with this.)* - - ![13](https://user-images.githubusercontent.com/22451773/180585999-07316d6e-9751-4d11-b957-1cf57cd7cd58.png) - -* Click "Generate" to create the project files. - - ![15](https://i.imgur.com/5LKg92k.png) - -* Open the solution file `yuzu.sln` in Visual Studio 2022, which is located in the build folder. - - ![16](https://i.imgur.com/208yMml.png) - -* Depending if you want a graphical user interface or not (`eden` has the graphical user interface, while `eden-cmd` doesn't), select `eden` or `eden-cmd` in the Solution Explorer, right-click and `Set as StartUp Project`. - - ![17](https://i.imgur.com/nPMajnn.png) ![18](https://i.imgur.com/BDMLzRZ.png) - -* Select the appropriate build type, Debug for debug purposes or Release for performance (in case of doubt choose Release). - - ![19](https://i.imgur.com/qxg4roC.png) - -* Right-click the project you want to build and press Build in the submenu or press F5. - - ![20](https://i.imgur.com/CkQgOFW.png) - -## Method II: MinGW-w64 Build with MSYS2 - -### Prerequisites to install - -* [MSYS2](https://www.msys2.org) -* [Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows) - **Make sure to select Latest SDK.** -* Make sure to follow the instructions and update to the latest version by running `pacman -Syu` as many times as needed. - -### Install eden dependencies for MinGW-w64 - -* Open the `MSYS2 MinGW 64-bit` (mingw64.exe) shell -* Download and install all dependencies using: `pacman -Syu git make mingw-w64-x86_64-SDL2 mingw-w64-x86_64-cmake mingw-w64-x86_64-python-pip mingw-w64-x86_64-qt6 mingw-w64-x86_64-toolchain autoconf libtool automake-wrapper` -* Add MinGW binaries to the PATH: `echo 'PATH=/mingw64/bin:$PATH' >> ~/.bashrc` -* Add glslangValidator to the PATH: `echo 'PATH=$(readlink -e /c/VulkanSDK/*/Bin/):$PATH' >> ~/.bashrc` - -### Clone the eden repository with Git - - ```bash - git clone --recursive https://git.eden-emu.dev/eden-emu/eden - cd eden - ``` - -### Run the following commands to build eden (dynamically linked build) - -```bash -mkdir build && cd build -cmake -G "MSYS Makefiles" -DYUZU_TESTS=OFF .. -make -j$(nproc) -# test eden out with -./bin/eden.exe -``` - -* *(Note: This build is not a static build meaning that you need to include all of the DLLs with the .exe in order to use it!)* - -e.g. -```Bash -cp externals/ffmpeg-*/bin/*.dll bin/ -``` - -Bonus Note: Running programs from inside `MSYS2 MinGW x64` shell has a different %PATH% than directly from explorer. This different %PATH% has the locations of the other DLLs required. -![image](https://user-images.githubusercontent.com/190571/165000848-005e8428-8a82-41b1-bb4d-4ce7797cdac8.png) - - -### Building without Qt (Optional) - -Doesn't require the rather large Qt dependency, but you will lack a GUI frontend: - - * Pass the `-DENABLE_QT=no` flag to cmake - -## Method III: CLion Environment Setup - -### Minimal Dependencies - -To build eden, you need to install the following: - -* [CLion](https://www.jetbrains.com/clion/) - This IDE is not free; for a free alternative, check Method I -* [Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows) - Make sure to select the Latest SDK. - -### Cloning eden with CLion - -* Clone the Repository: - -![1](https://user-images.githubusercontent.com/42481638/216899046-0d41d7d6-8e4d-4ed2-9587-b57088af5214.png) -![2](https://user-images.githubusercontent.com/42481638/216899061-b2ea274a-e88c-40ae-bf0b-4450b46e9fea.png) -![3](https://user-images.githubusercontent.com/42481638/216899076-0e5988c4-d431-4284-a5ff-9ecff973db76.png) - - - -### Building & Setup - -* Once Cloned, You will be taken to a prompt like the image below: - -![4](https://user-images.githubusercontent.com/42481638/216899092-3fe4cec6-a540-44e3-9e1e-3de9c2fffc2f.png) - -* Set the settings to the image below: -* Change `Build type: Release` -* Change `Name: Release` -* Change `Toolchain Visual Studio` -* Change `Generator: Let CMake decide` -* Change `Build directory: build` - -![5](https://user-images.githubusercontent.com/42481638/216899164-6cee8482-3d59-428f-b1bc-e6dc793c9b20.png) - -* Click OK; now Clion will build a directory and index your code to allow for IntelliSense. Please be patient. -* Once this process has been completed (No loading bar bottom right), you can now build eden -* In the top right, click on the drop-down menu, select all configurations, then select eden - -![6](https://user-images.githubusercontent.com/42481638/216899226-975048e9-bc6d-4ec1-bc2d-bd8a1e15ed04.png) - -* Now run by clicking the play button or pressing Shift+F10, and eden will auto-launch once built. - -![7](https://user-images.githubusercontent.com/42481638/216899275-d514ec6a-e563-470e-81e2-3e04f0429b68.png) - -## Building from the command line with MSVC - -```cmd -git clone --recursive https://git.eden-emu.dev/eden-emu/eden -cd eden -mkdir build -cd build -cmake .. -G "Visual Studio 17 2022" -A x64 -cmake --build . --config Release -``` - -### Building with Scripts -A convenience script for building is provided in `.ci/windows/build.sh`. You must run this with Bash, e.g. Git Bash or MinGW TTY. To use this script, you must have windeployqt installed (usually bundled with Qt) and set the `WINDEPLOYQT` environment variable to its canonical Bash location, e.g. `WINDEPLOYQT="/c/Qt/6.9.1/msvc2022_64/bin/windeployqt6.exe" .ci/windows/build.sh`. - -Extra CMake flags should be placed in the arguments of the script. - -Additional environment variables can be used to control building: -- `BUILD_TYPE`: Sets the build type to use. Defaults to `Release` - -The following environment variables are boolean flags. Set to `true` to enable or `false` to disable: -- `DEVEL` (default FALSE): Disable Qt update checker -- `USE_WEBENGINE` (default FALSE): Enable Qt WebEngine -- `USE_MULTIMEDIA` (default TRUE): Enable Qt Multimedia -- `BUNDLE_QT` (default FALSE): Use bundled Qt - * Note that using system Qt requires you to include the Qt CMake directory in `CMAKE_PREFIX_PATH`, e.g. `.ci/windows/build.sh -DCMAKE_PREFIX_PATH=C:/Qt/6.9.0/msvc2022_64/lib/cmake/Qt6` - -After building, a zip can be packaged via `.ci/windows/package.sh`. Note that you must have 7-zip installed and in your PATH. The resulting zip will be placed into `artifacts` in the source directory. +# THIS GUIDE IS INTENDED FOR DEVELOPERS ONLY, SUPPORT WILL ONLY BE GIVEN IF YOU'RE A DEVELOPER. + +## Method I: MSVC Build for Windows + +### Minimal Dependencies + +On Windows, all library dependencies are automatically included within the `externals` folder, or can be downloaded on-demand. To build Eden, you need to install: + + * **[Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/)** - **Make sure to select C++ support in the installer. Make sure to update to the latest version if already installed.** + * **[CMake](https://cmake.org/download/)** - Used to generate Visual Studio project files. Does not matter if either 32-bit or 64-bit version is installed. + * **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** - **Make sure to select Latest SDK.** + - A convenience script to install the latest SDK is provided in `.ci\windows\install-vulkan-sdk.ps1`. + + ![2](https://i.imgur.com/giDwuTm.png) + + * **Git** - We recommend [Git for Windows](https://gitforwindows.org). + + ![3](https://i.imgur.com/UeSzkBw.png) + + * While installing Git Bash, you should tell it to include Git in your system path. (Choose the "Git from the command line and also from 3rd-party software" option.) If you missed that, don't worry, you'll just have to manually tell CMake where your git.exe is, since it's used to include version info into the built executable. + + ![4](https://i.imgur.com/x0rRs1t.png) + +### Cloning Eden with Git + +**Master:** + ```cmd + git clone --recursive https://git.eden-emu.dev/eden-emu/eden + cd eden + ``` + + ![9](https://i.imgur.com/CcxIAht.png) + +* *(Note: eden by default downloads to `C:\Users\\eden` (Master) + +### Building + +* Open the CMake GUI application and point it to the `eden` (Master) + + ![10](https://i.imgur.com/qOslIWv.png) + +* For the build directory, use a `/build` subdirectory inside the source directory or some other directory of your choice. (Tell CMake to create it.) + +* Click the "Configure" button and choose `Visual Studio 17 2022`, with `x64` for the optional platform. + + ![12](https://i.imgur.com/DKiREaK.png) + + * *(Note: If you used GitHub's own app to clone, run `git submodule update --init --recursive` to get the remaining dependencies)* + + * *(You may also want to disable `YUZU_TESTS` in this case since Catch2 is not yet supported with this.)* + + ![13](https://user-images.githubusercontent.com/22451773/180585999-07316d6e-9751-4d11-b957-1cf57cd7cd58.png) + +* Click "Generate" to create the project files. + + ![15](https://i.imgur.com/5LKg92k.png) + +* Open the solution file `yuzu.sln` in Visual Studio 2022, which is located in the build folder. + + ![16](https://i.imgur.com/208yMml.png) + +* Depending if you want a graphical user interface or not (`eden` has the graphical user interface, while `eden-cmd` doesn't), select `eden` or `eden-cmd` in the Solution Explorer, right-click and `Set as StartUp Project`. + + ![17](https://i.imgur.com/nPMajnn.png) ![18](https://i.imgur.com/BDMLzRZ.png) + +* Select the appropriate build type, Debug for debug purposes or Release for performance (in case of doubt choose Release). + + ![19](https://i.imgur.com/qxg4roC.png) + +* Right-click the project you want to build and press Build in the submenu or press F5. + + ![20](https://i.imgur.com/CkQgOFW.png) + +## Method II: MinGW-w64 Build with MSYS2 + +### Prerequisites to install + +* [MSYS2](https://www.msys2.org) +* [Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows) - **Make sure to select Latest SDK.** +* Make sure to follow the instructions and update to the latest version by running `pacman -Syu` as many times as needed. + +### Install eden dependencies for MinGW-w64 + +* Open the `MSYS2 MinGW 64-bit` (mingw64.exe) shell +* Download and install all dependencies using: `pacman -Syu git make mingw-w64-x86_64-SDL2 mingw-w64-x86_64-cmake mingw-w64-x86_64-python-pip mingw-w64-x86_64-qt6 mingw-w64-x86_64-toolchain autoconf libtool automake-wrapper` +* Add MinGW binaries to the PATH: `echo 'PATH=/mingw64/bin:$PATH' >> ~/.bashrc` +* Add glslangValidator to the PATH: `echo 'PATH=$(readlink -e /c/VulkanSDK/*/Bin/):$PATH' >> ~/.bashrc` + +### Clone the eden repository with Git + + ```bash + git clone --recursive https://git.eden-emu.dev/eden-emu/eden + cd eden + ``` + +### Run the following commands to build eden (dynamically linked build) + +```bash +mkdir build && cd build +cmake -G "MSYS Makefiles" -DYUZU_TESTS=OFF .. +make -j$(nproc) +# test eden out with +./bin/eden.exe +``` + +* *(Note: This build is not a static build meaning that you need to include all of the DLLs with the .exe in order to use it!)* + +e.g. +```Bash +cp externals/ffmpeg-*/bin/*.dll bin/ +``` + +Bonus Note: Running programs from inside `MSYS2 MinGW x64` shell has a different %PATH% than directly from explorer. This different %PATH% has the locations of the other DLLs required. +![image](https://user-images.githubusercontent.com/190571/165000848-005e8428-8a82-41b1-bb4d-4ce7797cdac8.png) + + +### Building without Qt (Optional) + +Doesn't require the rather large Qt dependency, but you will lack a GUI frontend: + + * Pass the `-DENABLE_QT=no` flag to cmake + +## Method III: CLion Environment Setup + +### Minimal Dependencies + +To build eden, you need to install the following: + +* [CLion](https://www.jetbrains.com/clion/) - This IDE is not free; for a free alternative, check Method I +* [Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows) - Make sure to select the Latest SDK. + +### Cloning eden with CLion + +* Clone the Repository: + +![1](https://user-images.githubusercontent.com/42481638/216899046-0d41d7d6-8e4d-4ed2-9587-b57088af5214.png) +![2](https://user-images.githubusercontent.com/42481638/216899061-b2ea274a-e88c-40ae-bf0b-4450b46e9fea.png) +![3](https://user-images.githubusercontent.com/42481638/216899076-0e5988c4-d431-4284-a5ff-9ecff973db76.png) + + + +### Building & Setup + +* Once Cloned, You will be taken to a prompt like the image below: + +![4](https://user-images.githubusercontent.com/42481638/216899092-3fe4cec6-a540-44e3-9e1e-3de9c2fffc2f.png) + +* Set the settings to the image below: +* Change `Build type: Release` +* Change `Name: Release` +* Change `Toolchain Visual Studio` +* Change `Generator: Let CMake decide` +* Change `Build directory: build` + +![5](https://user-images.githubusercontent.com/42481638/216899164-6cee8482-3d59-428f-b1bc-e6dc793c9b20.png) + +* Click OK; now Clion will build a directory and index your code to allow for IntelliSense. Please be patient. +* Once this process has been completed (No loading bar bottom right), you can now build eden +* In the top right, click on the drop-down menu, select all configurations, then select eden + +![6](https://user-images.githubusercontent.com/42481638/216899226-975048e9-bc6d-4ec1-bc2d-bd8a1e15ed04.png) + +* Now run by clicking the play button or pressing Shift+F10, and eden will auto-launch once built. + +![7](https://user-images.githubusercontent.com/42481638/216899275-d514ec6a-e563-470e-81e2-3e04f0429b68.png) + +## Building from the command line with MSVC + +```cmd +git clone --recursive https://git.eden-emu.dev/eden-emu/eden +cd eden +mkdir build +cd build +cmake .. -G "Visual Studio 17 2022" -A x64 +cmake --build . --config Release +``` + +### Building with Scripts +A convenience script for building is provided in `.ci/windows/build.sh`. You must run this with Bash, e.g. Git Bash or MinGW TTY. To use this script, you must have windeployqt installed (usually bundled with Qt) and set the `WINDEPLOYQT` environment variable to its canonical Bash location, e.g. `WINDEPLOYQT="/c/Qt/6.9.1/msvc2022_64/bin/windeployqt6.exe" .ci/windows/build.sh`. + +Extra CMake flags should be placed in the arguments of the script. + +Additional environment variables can be used to control building: +- `BUILD_TYPE`: Sets the build type to use. Defaults to `Release` + +The following environment variables are boolean flags. Set to `true` to enable or `false` to disable: +- `DEVEL` (default FALSE): Disable Qt update checker +- `USE_WEBENGINE` (default FALSE): Enable Qt WebEngine +- `USE_MULTIMEDIA` (default TRUE): Enable Qt Multimedia +- `BUNDLE_QT` (default FALSE): Use bundled Qt + * Note that using system Qt requires you to include the Qt CMake directory in `CMAKE_PREFIX_PATH`, e.g. `.ci/windows/build.sh -DCMAKE_PREFIX_PATH=C:/Qt/6.9.0/msvc2022_64/lib/cmake/Qt6` + +After building, a zip can be packaged via `.ci/windows/package.sh`. Note that you must have 7-zip installed and in your PATH. The resulting zip will be placed into `artifacts` in the source directory. diff --git a/docs/build/macOS.md b/docs/build/macOS.md index 6cb62273cb..fd1873b849 100644 --- a/docs/build/macOS.md +++ b/docs/build/macOS.md @@ -1,105 +1,78 @@ -Please note this article is intended for development, and eden on macOS is not currently ready for regular use. - -This article was written for developers. eden support for macOS is not ready for casual use. - -## Method I: ninja ---- -If you are compiling on Intel Mac or are using a Rosetta Homebrew installation, you must replace all references of `/opt/homebrew` to `/usr/local`. - -Install dependencies from Homebrew: -```sh -brew install autoconf automake boost ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@6 sdl2 speexdsp zlib zlib zstd cmake Catch2 molten-vk vulkan-loader -``` - -Clone the repo -```sh -git clone --recursive https://git.eden-emu.dev/eden-emu/eden - -cd eden -``` - -Build for release -```sh -mkdir build && cd build - -export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake" - -export LIBVULKAN_PATH=/opt/homebrew/lib/libvulkan.dylib - -cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_USE_BUNDLED_VCPKG=OFF -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=ON -DENABLE_LIBUSB=OFF -DCLANG_FORMAT=ON -DSDL2_DISABLE_INSTALL=ON -DSDL_ALTIVEC=ON - -ninja -``` - -You may also want to include support for Discord Rich Presence by adding `-DUSE_DISCORD_PRESENCE=ON` after `cmake ..` - -Build with debug symbols (vcpkg is not currently used due to broken boost-context library): -```sh -mkdir build && cd build -export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake" -cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_USE_BUNDLED_VCPKG=OFF -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=OFF -DENABLE_LIBUSB=OFF -ninja -``` - -Run the output: -``` -bin/eden.app/Contents/MacOS/eden -``` - -## Method II: Xcode - ---- -If you are compiling on Intel Mac or are using a Rosetta Homebrew installation, you must replace all references of `/opt/homebrew` to `/usr/local`. - -Install dependencies from Homebrew: -```sh -brew install autoconf automake boost ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@6 sdl2 speexdsp zlib zlib zstd cmake Catch2 molten-vk vulkan-loader -``` - -Clone the repo -```sh -git clone --recursive https://git.eden-emu.dev/eden-emu/eden - -cd eden -``` - -Build for release -```sh -mkdir build && cd build - -export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake" - -export LIBVULKAN_PATH=/opt/homebrew/lib/libvulkan.dylib - -cmake .. -GXcode -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_USE_BUNDLED_VCPKG=OFF -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=ON -DENABLE_LIBUSB=OFF -DCLANG_FORMAT=ON -DSDL2_DISABLE_INSTALL=ON -DSDL_ALTIVEC=ON - -xcodebuild build -project eden.xcodeproj -scheme "eden" -configuration "RelWithDebInfo" -``` - -You may also want to include support for Discord Rich Presence by adding `-DUSE_DISCORD_PRESENCE=ON` after `cmake ..` - -Build with debug symbols (vcpkg is not currently used due to broken boost-context library): -```sh -mkdir build && cd build -export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake" -cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_USE_BUNDLED_VCPKG=OFF -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=OFF -DENABLE_LIBUSB=OFF -ninja -``` - -Run the output: -``` -bin/eden.app/Contents/MacOS/eden -``` - ---- - -To run with MoltenVK, install additional dependencies: -```sh -brew install molten-vk vulkan-loader -``` - -Run with Vulkan loader path: -```sh -export LIBVULKAN_PATH=/opt/homebrew/lib/libvulkan.dylib -bin/eden.app/Contents/MacOS/eden -``` \ No newline at end of file +Please note this article is intended for development, and Eden on macOS is not currently ready for regular use. + +This article was written for developers. Eden support for macOS is not ready for casual use. + +## Dependencies +Install dependencies from Homebrew: +```sh +brew install autoconf automake boost ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@6 sdl2 speexdsp zlib zstd cmake Catch2 molten-vk vulkan-loader spirv-tools +``` + +If you are compiling on Intel Mac, or are using a Rosetta Homebrew installation, you must replace all references of `/opt/homebrew` with `/usr/local`. + +Now, clone the repo: +```sh +git clone --recursive https://git.eden-emu.dev/eden-emu/eden +cd eden +``` + +## Method I: ninja + +--- +Build for release +```sh +export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake" +export LIBVULKAN_PATH=/opt/homebrew/lib/libvulkan.dylib +cmake -B build -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=ON -DENABLE_LIBUSB=OFF -DCLANG_FORMAT=ON -DSDL2_DISABLE_INSTALL=ON -DSDL_ALTIVEC=ON +ninja +``` + +You may also want to include support for Discord Rich Presence by adding `-DUSE_DISCORD_PRESENCE=ON` +```sh +export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake" +cmake -B build -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=OFF -DENABLE_LIBUSB=OFF +ninja +``` + +Run the output: +``` +bin/eden.app/Contents/MacOS/eden +``` + +## Method II: Xcode + +--- +Build for release +```sh +export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake" +export LIBVULKAN_PATH=/opt/homebrew/lib/libvulkan.dylib +# Only if having errors about Xcode 15.0 +sudo /usr/bin/xcode-select --switch /Users/admin/Downloads/Xcode.ap +cmake -B build -GXcode -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=ON -DENABLE_LIBUSB=OFF -DCLANG_FORMAT=ON -DSDL2_DISABLE_INSTALL=ON -DSDL_ALTIVEC=ON +xcodebuild build -project yuzu.xcodeproj -scheme "yuzu" -configuration "RelWithDebInfo" +``` + +Build with debug symbols: +```sh +export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake" +cmake -B build -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=OFF -DENABLE_LIBUSB=OFF +ninja +``` + +Run the output: +``` +bin/eden.app/Contents/MacOS/eden +``` + +--- + +To run with MoltenVK, install additional dependencies: +```sh +brew install molten-vk vulkan-loader +``` + +Run with Vulkan loader path: +```sh +export LIBVULKAN_PATH=/opt/homebrew/lib/libvulkan.dylib +bin/eden.app/Contents/MacOS/eden +```