diff --git a/.ci/android/build.sh b/.ci/android/build.sh index 836faa38d5..4b4c9c0834 100755 --- a/.ci/android/build.sh +++ b/.ci/android/build.sh @@ -13,8 +13,8 @@ fi cd src/android chmod +x ./gradlew -./gradlew assembleMainlineRelease -./gradlew bundleMainlineRelease +./gradlew assembleRelease +./gradlew bundleRelease if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then rm "${ANDROID_KEYSTORE_FILE}" diff --git a/docs/user/Architectures.md b/docs/user/Architectures.md index 240feb666d..6d60716684 100644 --- a/docs/user/Architectures.md +++ b/docs/user/Architectures.md @@ -63,8 +63,6 @@ While all modern Linux distributions are supported (Fedora >40, Ubuntu >24.04, D Intel and Nvidia GPU support is limited. AMD (RADV) drivers receive first-class testing and are known to provide the most stable Eden experience possible. -Wayland is not recommended. Testing has shown significantly worse performance on most Wayland compositors compared to X11, alongside mysterious bugs and compatibility errors. For now, set `QT_QPA_PLATFORM=xcb` when running Eden, or pass `-platform xcb` to the launch arguments. - ## Windows Windows 10 and 11 are supported. Support for Windows 8.x is unknown, and Windows 7 support is unlikely to ever be added. diff --git a/externals/cpmfile.json b/externals/cpmfile.json index dde8c22d5f..aa3a97c128 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -117,9 +117,9 @@ }, "spirv-tools": { "package": "SPIRV-Tools", - "repo": "crueter/SPIRV-Tools", - "sha": "2fa2d44485", - "hash": "45b198be1d09974ccb2438e8bfa5683f23a0421b058297c28eacfd77e454ec2cf87e77850eddd202efff34b004d8d6b4d12e9615e59bd72be904c196f5eb2169", + "repo": "KhronosGroup/SPIRV-Tools", + "tag": "v%VERSION%", + "hash": "b17940433ced72e004c5eeffd7dd411b6afcc6a52ee31de6427d88edceb8172369be8ec8bf5b65708a78bf41fdae264d554aa7750b2209831679ab36bc867567", "git_version": "2025.4", "options": [ "SPIRV_SKIP_EXECUTABLES ON" diff --git a/src/common/fs/fs_types.h b/src/common/fs/fs_types.h index 7b7359fa6f..900f85d24e 100644 --- a/src/common/fs/fs_types.h +++ b/src/common/fs/fs_types.h @@ -1,12 +1,8 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include #include #include "common/common_funcs.h" diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index dda8d526d3..edf51e74de 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -4,6 +4,7 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" @@ -128,6 +129,10 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir, std::string out = GetSaveDataSpaceIdPath(space); + LOG_INFO(Common_Filesystem, "Save ID: {:016X}", save_id); + LOG_INFO(Common_Filesystem, "User ID[1]: {:016X}", user_id[1]); + LOG_INFO(Common_Filesystem, "User ID[0]: {:016X}", user_id[0]); + switch (type) { case SaveDataType::System: return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 4a892f7c65..a4394046fa 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -4,17 +4,13 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include #include -#include -#include #include #include #include "common/fs/file.h" #include "common/fs/fs.h" -#include "common/fs/fs_types.h" #include "common/fs/path_util.h" #include #include "common/settings.h" @@ -94,11 +90,6 @@ bool ProfileManager::RemoveProfileAtIndex(std::size_t index) { return true; } -void ProfileManager::RemoveAllProfiles() -{ - profiles = {}; -} - /// Helper function to register a user to the system Result ProfileManager::AddUser(const ProfileInfo& user) { if (!AddToProfiles(user)) { @@ -268,9 +259,8 @@ void ProfileManager::CloseUser(UUID uuid) { /// Gets all valid user ids on the system UserIDArray ProfileManager::GetAllUsers() const { UserIDArray output{}; - std::ranges::transform(profiles, output.begin(), [](const ProfileInfo& p) { - return p.user_uuid; - }); + std::ranges::transform(profiles, output.begin(), + [](const ProfileInfo& p) { return p.user_uuid; }); return output; } @@ -397,19 +387,18 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& void ProfileManager::ParseUserSaveFile() { const auto save_path(FS::GetEdenPath(FS::EdenPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH / "profiles.dat"); - const FS::IOFile save(save_path, FS::FileAccessMode::Read, FS::FileType::BinaryFile); if (!save.IsOpen()) { LOG_WARNING(Service_ACC, "Failed to load profile data from save data... Generating new " - "user 'Eden' with random UUID."); + "user 'eden' with random UUID."); return; } ProfileDataRaw data; if (!save.ReadObject(data)) { LOG_WARNING(Service_ACC, "profiles.dat is smaller than expected... Generating new user " - "'Eden' with random UUID."); + "'eden' with random UUID."); return; } @@ -482,79 +471,6 @@ void ProfileManager::WriteUserSaveFile() { is_save_needed = false; } -void ProfileManager::ResetUserSaveFile() -{ - RemoveAllProfiles(); - ParseUserSaveFile(); -} - -std::vector ProfileManager::FindOrphanedProfiles() -{ - std::vector good_uuids; - - for (const ProfileInfo& p : profiles) { - std::string uuid_string = [p]() -> std::string { - auto uuid = p.user_uuid; - - // "ignore" invalid uuids - if (uuid.IsInvalid()) { - return "0"; - } - - auto user_id = uuid.AsU128(); - - return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]); - }(); - - good_uuids.emplace_back(uuid_string); - } - - // TODO: fetch save_id programmatically - const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) - / "user/save/0000000000000000"; - - std::vector orphaned_profiles; - - Common::FS::IterateDirEntries( - path, - [&good_uuids, &orphaned_profiles](const std::filesystem::directory_entry& entry) -> bool { - const std::string uuid = entry.path().stem().string(); - - // first off, we should always clear empty profiles - // 99% of the time these are useless. If not, they are recreated anyways... - namespace fs = std::filesystem; - - const auto is_empty = [&entry]() -> bool { - try { - for (const auto& file : fs::recursive_directory_iterator(entry.path())) { - if (file.is_regular_file()) { - return true; - } - } - } catch (const fs::filesystem_error& e) { - // if we get an error--no worries, just pretend it's not empty - return false; - } - return false; - }(); - - if (!is_empty) { - fs::remove_all(entry); - return true; - } - - // if profiles.dat contains the UUID--all good - // if not--it's an orphaned profile and should be resolved by the user - if (std::find(good_uuids.begin(), good_uuids.end(), uuid) == good_uuids.end()) { - orphaned_profiles.emplace_back(uuid); - } - return true; - }, - Common::FS::DirEntryFilter::Directory); - - return orphaned_profiles; -} - void ProfileManager::SetUserPosition(u64 position, Common::UUID uuid) { auto idxOpt = GetUserIndex(uuid); if (!idxOpt) diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index b164ed011a..d64e42715c 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h @@ -103,15 +103,10 @@ public: void WriteUserSaveFile(); - void ResetUserSaveFile(); - - std::vector FindOrphanedProfiles(); - private: void ParseUserSaveFile(); std::optional AddToProfiles(const ProfileInfo& profile); bool RemoveProfileAtIndex(std::size_t index); - void RemoveAllProfiles(); bool is_save_needed{}; std::array profiles{}; diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 2f659cf1b2..e4625aa423 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -1,10 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include "qt_common/qt_game_util.h" #include "qt_content_util.h" #include "common/fs/fs.h" -#include "core/hle/service/acc/profile_manager.h" #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" #include "qt_common/qt_common.h" @@ -312,40 +310,4 @@ void VerifyInstalledContents() { } } -void FixProfiles() -{ - // Reset user save files after config is initialized and migration is done. - // Doing it at init time causes profiles to read from the wrong place entirely if NAND dir is not default - // TODO: better solution - system->GetProfileManager().ResetUserSaveFile(); - std::vector orphaned = system->GetProfileManager().FindOrphanedProfiles(); - - // no orphaned dirs--all good :) - if (orphaned.empty()) - return; - - // otherwise, let the user know - QString qorphaned; - - // max. of 8 orphaned profiles is fair, I think - // 33 = 32 (UUID) + 1 (\n) - qorphaned.reserve(8 * 33); - - for (const std::string& s : orphaned) { - qorphaned += "\n" + QString::fromStdString(s); - } - - QtCommon::Frontend::Critical( - tr("Orphaned Profiles Detected!"), - tr("UNEXPECTED BAD THINGS MAY HAPPEN IF YOU DON'T READ THIS!\n" - "Eden has detected the following save directories with no attached profile:\n" - "%1\n\n" - "Click \"OK\" to open your save folder and fix up your profiles.\n" - "Hint: copy the contents of the largest or last-modified folder elsewhere, " - "delete all orphaned profiles, and move your copied contents to the good profile.") - .arg(qorphaned)); - - QtCommon::Game::OpenSaveFolder(); -} - } // namespace QtCommon::Content diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index b95e78c0a0..b572c1c4a3 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -45,8 +45,5 @@ void InstallKeys(); // Content // void VerifyGameContents(const std::string &game_path); void VerifyInstalledContents(); - -// Profiles // -void FixProfiles(); } #endif // QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index ac922ea967..5d0b4d8ae7 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -178,12 +178,6 @@ void OpenNANDFolder() OpenEdenFolder(Common::FS::EdenPath::NANDDir); } -void OpenSaveFolder() -{ - const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "user/save/0000000000000000"; - QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(path.string()))); -} - void OpenSDMCFolder() { OpenEdenFolder(Common::FS::EdenPath::SDMCDir); @@ -385,21 +379,21 @@ void RemoveCacheStorage(u64 program_id) } // Metadata // -void ResetMetadata(bool show_message) +void ResetMetadata() { const QString title = tr("Reset Metadata Cache"); if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list/")) { - if (show_message) QtCommon::Frontend::Warning(rootObject, title, tr("The metadata cache is already empty.")); + QtCommon::Frontend::Warning(rootObject, title, tr("The metadata cache is already empty.")); } else if (Common::FS::RemoveDirRecursively( Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - if (show_message) QtCommon::Frontend::Information(rootObject, + QtCommon::Frontend::Information(rootObject, title, tr("The operation completed successfully.")); UISettings::values.is_game_list_reload_pending.exchange(true); } else { - if (show_message) QtCommon::Frontend::Warning( + QtCommon::Frontend::Warning( rootObject, title, tr("The metadata cache couldn't be deleted. It might be in use or non-existent.")); @@ -579,4 +573,5 @@ void CreateHomeMenuShortcut(ShortcutTarget target) { CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); } + } // namespace QtCommon::Game diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 5c6bb24910..0a21208659 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -52,7 +52,6 @@ bool MakeShortcutIcoPath(const u64 program_id, void OpenEdenFolder(const Common::FS::EdenPath &path); void OpenRootDataFolder(); void OpenNANDFolder(); -void OpenSaveFolder(); void OpenSDMCFolder(); void OpenModFolder(); void OpenLogFolder(); @@ -68,7 +67,7 @@ void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); void RemoveCacheStorage(u64 program_id); // Metadata // -void ResetMetadata(bool show_message = true); +void ResetMetadata(); // Shortcuts // void CreateShortcut(const std::string& game_path, diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp index fee19a69c2..5676dfe62a 100644 --- a/src/video_core/renderer_vulkan/present/layer.cpp +++ b/src/video_core/renderer_vulkan/present/layer.cpp @@ -332,7 +332,7 @@ void Layer::UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t i write_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; write_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, read_barrier); cmdbuf.CopyBufferToImage(*buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 4bc013131d..4fb88b29de 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -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 diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 161f6c8b9f..0b29ad1389 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -412,7 +412,7 @@ void PresentManager::CopyToSwapchainImpl(Frame* frame) { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = 0, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, @@ -460,7 +460,7 @@ void PresentManager::CopyToSwapchainImpl(Frame* frame) { MakeImageCopy(frame->width, frame->height, extent.width, extent.height)); } - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, {}, {}, {}, post_barriers); cmdbuf.End(); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 50a73ea76d..575651905e 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1068,7 +1068,7 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER, {}, middle_out_barrier); - cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_out_copies); + cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies); cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, {}, {}, post_barriers); }); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 44ed29f141..901a39cc9f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -545,9 +545,6 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) // Gen keys if necessary OnCheckFirmwareDecryption(); - // Check for orphaned profiles and reset profile data if necessary - QtCommon::Content::FixProfiles(); - game_list->LoadCompatibilityList(); // force reload on first load to ensure add-ons get updated game_list->PopulateAsync(UISettings::values.game_dirs); @@ -3950,7 +3947,7 @@ void GMainWindow::OnToggleStatusBar() { void GMainWindow::OnGameListRefresh() { // Resets metadata cache and reloads - QtCommon::Game::ResetMetadata(false); + QtCommon::Game::ResetMetadata(); game_list->RefreshGameDirectory(); SetFirmwareVersion(); } diff --git a/src/yuzu/migration_worker.cpp b/src/yuzu/migration_worker.cpp index 95f205ec0c..42ec006026 100644 --- a/src/yuzu/migration_worker.cpp +++ b/src/yuzu/migration_worker.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "common/fs/path_util.h"