Compare commits

..

2 commits

Author SHA1 Message Date
Ribbit
c316ebbc80 asdfasdfasdfasdfsadf
All checks were successful
eden-license / license-header (pull_request) Successful in 27s
2025-10-07 18:49:28 -07:00
Ribbit
2700929161 [vk] Unify RAII in Vulkan
Some checks failed
eden-license / license-header (pull_request) Failing after 24s
2025-10-05 20:30:01 -07:00
17 changed files with 29 additions and 165 deletions

View file

@ -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}"

View file

@ -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.

View file

@ -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"

View file

@ -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 <filesystem>
#include <functional>
#include "common/common_funcs.h"

View file

@ -4,6 +4,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <memory>
#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]);

View file

@ -4,17 +4,13 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <cstring>
#include <filesystem>
#include <iostream>
#include <random>
#include <fmt/ranges.h>
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/fs/fs_types.h"
#include "common/fs/path_util.h"
#include <ranges>
#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<std::string> ProfileManager::FindOrphanedProfiles()
{
std::vector<std::string> 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<std::string> 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)

View file

@ -103,15 +103,10 @@ public:
void WriteUserSaveFile();
void ResetUserSaveFile();
std::vector<std::string> FindOrphanedProfiles();
private:
void ParseUserSaveFile();
std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile);
bool RemoveProfileAtIndex(std::size_t index);
void RemoveAllProfiles();
bool is_save_needed{};
std::array<ProfileInfo, MAX_USERS> profiles{};

View file

@ -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<std::string> 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

View file

@ -45,8 +45,5 @@ void InstallKeys();
// Content //
void VerifyGameContents(const std::string &game_path);
void VerifyInstalledContents();
// Profiles //
void FixProfiles();
}
#endif // QT_CONTENT_UTIL_H

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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

View file

@ -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();

View file

@ -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);
});

View file

@ -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();
}

View file

@ -7,6 +7,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <filesystem>
#include <qdebug.h>
#include "common/fs/path_util.h"