Merge branch 'edge' of github.com:has207/xenia-edge into edge

This commit is contained in:
Herman S.
2025-11-01 19:03:18 +09:00
4 changed files with 118 additions and 38 deletions
+2 -6
View File
@@ -49,13 +49,9 @@ fatalwarnings("All")
-- TODO(DrChat): Find a way to disable this on other architectures.
if ARCH ~= "ppc64" then
filter({"architecture:x86_64", "platforms:Windows"})
-- Use AVX instead of AVX2 on Windows to prevent MSVC from emitting BMI2 instructions
-- MSVC with /arch:AVX2 generates BMI2 unconditionally, breaking Sandy/Ivy Bridge CPUs
filter({"architecture:x86_64"})
-- AVX2 requires Haswell (2013+) or newer
vectorextensions("AVX")
filter({"architecture:x86_64", "platforms:not Windows"})
-- On non-Windows (Linux/Clang), AVX2 is safe as it can be combined with -mno-bmi2
vectorextensions("AVX2")
filter({})
end
+5
View File
@@ -308,6 +308,11 @@ void copy_and_swap_32_aligned(void* dest_ptr, const void* src_ptr,
}
}
// Enable AVX2 for this function even when building with -mavx
// The function has runtime detection to only use AVX2 on supported CPUs
#if defined(__GNUC__) || defined(__clang__)
__attribute__((target("avx2")))
#endif
void copy_and_swap_32_unaligned(void* dest_ptr, const void* src_ptr,
size_t count) {
auto dest = reinterpret_cast<uint32_t*>(dest_ptr);
+27 -11
View File
@@ -162,30 +162,46 @@ void ProfileManager::SyncProfilesWithConfig() {
LoadAccount(account_xuid);
}
// Then logout all currently logged in profiles
std::vector<uint8_t> slots_to_logout;
for (const auto& [slot, profile] : logged_profiles_) {
slots_to_logout.push_back(slot);
}
for (uint8_t slot : slots_to_logout) {
Logout(slot, false);
}
// Now login profiles based on the current cvar values
// Build desired login state from current cvar values
const std::string* profile_cvars[4] = {
&cvars::logged_profile_slot_0_xuid, &cvars::logged_profile_slot_1_xuid,
&cvars::logged_profile_slot_2_xuid, &cvars::logged_profile_slot_3_xuid};
std::map<uint8_t, uint64_t> desired_profiles;
for (uint8_t slot = 0; slot < 4; slot++) {
if (!profile_cvars[slot]->empty()) {
uint64_t xuid =
xe::string_util::from_string<uint64_t>(*profile_cvars[slot], true);
if (xuid != 0) {
Login(xuid, slot, false);
desired_profiles[slot] = xuid;
}
}
}
// Logout profiles that shouldn't be logged in anymore
std::vector<uint8_t> slots_to_logout;
for (const auto& [slot, profile] : logged_profiles_) {
auto desired_it = desired_profiles.find(slot);
if (desired_it == desired_profiles.end() ||
desired_it->second != profile->xuid()) {
// This slot should be logged out (either empty or different profile)
slots_to_logout.push_back(slot);
}
}
for (uint8_t slot : slots_to_logout) {
Logout(slot, false);
}
// Login profiles that aren't already logged in
for (const auto& [slot, xuid] : desired_profiles) {
auto current_profile = logged_profiles_.find(slot);
if (current_profile == logged_profiles_.end() ||
current_profile->second->xuid() != xuid) {
// This slot needs to be logged in (either empty or different profile)
Login(xuid, slot, false);
}
}
// Send a single notification after all changes
kernel_state_->BroadcastNotification(kXNotificationSystemSignInChanged,
GetUsedUserSlots().to_ulong());
+84 -21
View File
@@ -805,35 +805,80 @@ void GameListDialogQt::OnGameRightClicked(const QPoint& pos) {
launch_action = context_menu.addAction("Open");
}
// Achievements option (enabled if user is logged in)
QAction* achievements_action = nullptr;
// Get the primary profile (same one shown in profile button)
bool is_signedin = false;
uint64_t xuid = 0;
// TODO: Handle multiple signed-in profiles better
// For now, just use the first logged-in profile we find
for (uint8_t user_index = 0; user_index < XUserMaxUserCount; user_index++) {
const auto profile = profile_manager->GetProfile(user_index);
if (profile) {
is_signedin = true;
xuid = profile->xuid();
break;
// Use the profile from slot 0 as primary (matches profile button logic)
const auto primary_profile =
profile_manager->GetProfile(static_cast<uint8_t>(0));
if (primary_profile) {
is_signedin = true;
xuid = primary_profile->xuid();
}
// Saves folder option (enabled if user is logged in, we have a valid
// title_id, and saves exist)
QAction* saves_action = nullptr;
if (title_id != 0) {
saves_action = context_menu.addAction("Saves");
if (!is_signedin) {
saves_action->setEnabled(false);
} else {
// Check if saves folder exists
auto saves_path = profile_manager->GetProfileContentPath(
xuid, title_id, XContentType::kSavedGame);
if (!std::filesystem::exists(saves_path)) {
saves_action->setEnabled(false);
}
}
}
if (is_signedin && title_id != 0) {
// Title Updates folder option (enabled if we have a valid title_id and
// updates exist)
QAction* title_updates_action = nullptr;
if (title_id != 0) {
title_updates_action = context_menu.addAction("Title Updates");
// Title updates use xuid=0 and content type kInstaller
auto tu_path = profile_manager->GetProfileContentPath(
0, title_id, XContentType::kInstaller);
if (!std::filesystem::exists(tu_path)) {
title_updates_action->setEnabled(false);
}
}
// DLC folder option (enabled if we have a valid title_id and DLC exists)
QAction* dlc_action = nullptr;
if (title_id != 0) {
dlc_action = context_menu.addAction("DLC");
// DLC uses xuid=0 and content type kMarketplaceContent
auto dlc_path = profile_manager->GetProfileContentPath(
0, title_id, XContentType::kMarketplaceContent);
if (!std::filesystem::exists(dlc_path)) {
dlc_action->setEnabled(false);
}
}
// Achievements option (enabled if user is logged in and we have a valid
// title_id)
QAction* achievements_action = nullptr;
if (title_id != 0) {
achievements_action = context_menu.addAction("Achievements");
connect(achievements_action, &QAction::triggered, [=, this]() {
// Get the title name from the game entry
QString title_name;
for (const auto& entry : game_entries_) {
if (entry.title_id == title_id) {
title_name = QString::fromStdString(entry.title_name);
break;
if (!is_signedin) {
achievements_action->setEnabled(false);
} else {
connect(achievements_action, &QAction::triggered, [=, this]() {
// Get the title name from the game entry
QString title_name;
for (const auto& entry : game_entries_) {
if (entry.title_id == title_id) {
title_name = QString::fromStdString(entry.title_name);
break;
}
}
}
ShowAchievementsDialog(xuid, title_id, title_name);
});
ShowAchievementsDialog(xuid, title_id, title_name);
});
}
}
// Game config overrides option (enabled if we have a valid title_id)
@@ -868,6 +913,24 @@ void GameListDialogQt::OnGameRightClicked(const QPoint& pos) {
}
} else if (selected == open_folder_action && open_folder_action) {
OpenContainingFolder(path);
} else if (selected == saves_action && saves_action) {
// Open the saves folder for the primary profile
auto saves_path = profile_manager->GetProfileContentPath(
xuid, title_id, XContentType::kSavedGame);
std::thread path_open(LaunchFileExplorer, saves_path);
path_open.detach();
} else if (selected == title_updates_action && title_updates_action) {
// Open the title updates folder
auto tu_path = profile_manager->GetProfileContentPath(
0, title_id, XContentType::kInstaller);
std::thread path_open(LaunchFileExplorer, tu_path);
path_open.detach();
} else if (selected == dlc_action && dlc_action) {
// Open the DLC folder
auto dlc_path = profile_manager->GetProfileContentPath(
0, title_id, XContentType::kMarketplaceContent);
std::thread path_open(LaunchFileExplorer, dlc_path);
path_open.detach();
} else if (selected == achievements_action && achievements_action) {
// Achievements dialog will open in a separate call
} else if (selected == config_action && config_action) {