This commit is contained in:
lizzie 2026-03-11 23:44:55 +00:00 committed by crueter
parent 5e10da3cac
commit ec254a3adb
22 changed files with 215 additions and 207 deletions

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -1,81 +1,77 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "audio_core/audio_manager.h" #include "audio_core/audio_manager.h"
#include "common/thread.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/service/audio/errors.h" #include "core/hle/service/audio/errors.h"
namespace AudioCore { namespace AudioCore {
AudioManager::AudioManager() { AudioManager::AudioManager() {
thread = std::jthread([this]() { ThreadFunc(); }); thread = std::jthread([this](std::stop_token stop_token) {
Common::SetCurrentThreadName("AudioManager");
std::unique_lock l{events.GetAudioEventLock()};
events.ClearEvents();
while (!stop_token.stop_requested()) {
const auto timed_out{events.Wait(l, std::chrono::seconds(2))};
if (events.CheckAudioEventSet(Event::Type::Max)) {
break;
}
for (size_t i = 0; i < buffer_events.size(); i++) {
const auto event_type = Event::Type(i);
if (events.CheckAudioEventSet(event_type) || timed_out) {
if (buffer_events[i]) {
buffer_events[i]();
}
}
events.SetAudioEvent(event_type, false);
}
}
});
} }
void AudioManager::Shutdown() { void AudioManager::Shutdown() {
running = false;
events.SetAudioEvent(Event::Type::Max, true); events.SetAudioEvent(Event::Type::Max, true);
thread.join(); if (thread.joinable()) {
thread.request_stop();
thread.join();
}
} }
Result AudioManager::SetOutManager(BufferEventFunc buffer_func) { Result AudioManager::SetOutManager(BufferEventFunc buffer_func) {
if (!running) { if (thread.joinable()) {
return Service::Audio::ResultOperationFailed; std::scoped_lock l{lock};
const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioOutManager, true);
}
return ResultSuccess;
} }
return Service::Audio::ResultOperationFailed;
std::scoped_lock l{lock};
const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioOutManager, true);
}
return ResultSuccess;
} }
Result AudioManager::SetInManager(BufferEventFunc buffer_func) { Result AudioManager::SetInManager(BufferEventFunc buffer_func) {
if (!running) { if (thread.joinable()) {
return Service::Audio::ResultOperationFailed; std::scoped_lock l{lock};
const auto index{events.GetManagerIndex(Event::Type::AudioInManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioInManager, true);
}
return ResultSuccess;
} }
return Service::Audio::ResultOperationFailed;
std::scoped_lock l{lock};
const auto index{events.GetManagerIndex(Event::Type::AudioInManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioInManager, true);
}
return ResultSuccess;
} }
void AudioManager::SetEvent(const Event::Type type, const bool signalled) { void AudioManager::SetEvent(const Event::Type type, const bool signalled) {
events.SetAudioEvent(type, signalled); events.SetAudioEvent(type, signalled);
} }
void AudioManager::ThreadFunc() {
std::unique_lock l{events.GetAudioEventLock()};
events.ClearEvents();
running = true;
while (running) {
const auto timed_out{events.Wait(l, std::chrono::seconds(2))};
if (events.CheckAudioEventSet(Event::Type::Max)) {
break;
}
for (size_t i = 0; i < buffer_events.size(); i++) {
const auto event_type = static_cast<Event::Type>(i);
if (events.CheckAudioEventSet(event_type) || timed_out) {
if (buffer_events[i]) {
buffer_events[i]();
}
}
events.SetAudioEvent(event_type, false);
}
}
}
} // namespace AudioCore } // namespace AudioCore

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -66,13 +69,6 @@ public:
void SetEvent(Event::Type type, bool signalled); void SetEvent(Event::Type type, bool signalled);
private: private:
/**
* Main thread, waiting on a manager signal and calling the registered function.
*/
void ThreadFunc();
/// Is the main thread running?
std::atomic<bool> running{};
/// Unused /// Unused
bool needs_update{}; bool needs_update{};
/// Events to be set and signalled /// Events to be set and signalled

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -1,9 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/thread.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/service/am/am_types.h" #include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/button_poller.h" #include "core/hle/service/am/button_poller.h"
@ -34,16 +36,15 @@ ButtonPressDuration ClassifyPressDuration(std::chrono::steady_clock::time_point
} // namespace } // namespace
ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system) ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system) {
: m_window_system(window_system) {
// TODO: am reads this from the home button state in hid, which is controller-agnostic. // TODO: am reads this from the home button state in hid, which is controller-agnostic.
Core::HID::ControllerUpdateCallback engine_callback{ Core::HID::ControllerUpdateCallback engine_callback{
.on_change = .on_change = [this, &window_system](Core::HID::ControllerTriggerType type) {
[this](Core::HID::ControllerTriggerType type) { if (type == Core::HID::ControllerTriggerType::Button) {
if (type == Core::HID::ControllerTriggerType::Button) { std::unique_lock lk{m_mutex};
this->OnButtonStateChanged(); OnButtonStateChanged(window_system);
} }
}, },
.is_npad_service = true, .is_npad_service = true,
}; };
@ -52,25 +53,35 @@ ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system)
m_player1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); m_player1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
m_player1_key = m_player1->SetCallback(engine_callback); m_player1_key = m_player1->SetCallback(engine_callback);
m_thread = std::thread([this] { this->ThreadLoop(); }); m_thread = std::jthread([this, &window_system](std::stop_token stop_token) {
Common::SetCurrentThreadName("ButtonPoller");
while (!stop_token.stop_requested()) {
using namespace std::chrono_literals;
std::unique_lock lk{m_mutex};
m_cv.wait_for(lk, 50ms);
if (stop_token.stop_requested())
break;
OnButtonStateChanged(window_system);
std::this_thread::sleep_for(5ms);
}
});
} }
ButtonPoller::~ButtonPoller() { ButtonPoller::~ButtonPoller() {
m_handheld->DeleteCallback(m_handheld_key); m_handheld->DeleteCallback(m_handheld_key);
m_player1->DeleteCallback(m_player1_key); m_player1->DeleteCallback(m_player1_key);
m_stop = true;
m_cv.notify_all(); m_cv.notify_all();
if (m_thread.joinable()) { if (m_thread.joinable()) {
m_thread.request_stop();
m_thread.join(); m_thread.join();
} }
} }
void ButtonPoller::OnButtonStateChanged() { void ButtonPoller::OnButtonStateChanged(WindowSystem& window_system) {
std::lock_guard lk{m_mutex}; auto const home_button = m_handheld->GetHomeButtons().home.Value()
const bool home_button = || m_player1->GetHomeButtons().home.Value();
m_handheld->GetHomeButtons().home.Value() || m_player1->GetHomeButtons().home.Value(); auto const capture_button = m_handheld->GetCaptureButtons().capture.Value()
const bool capture_button = m_handheld->GetCaptureButtons().capture.Value() || || m_player1->GetCaptureButtons().capture.Value();
m_player1->GetCaptureButtons().capture.Value();
// Buttons pressed which were not previously pressed // Buttons pressed which were not previously pressed
if (home_button && !m_home_button_press_start) { if (home_button && !m_home_button_press_start) {
@ -90,7 +101,7 @@ void ButtonPoller::OnButtonStateChanged() {
if (home_button && m_home_button_press_start && !m_home_button_long_sent) { if (home_button && m_home_button_press_start && !m_home_button_long_sent) {
const auto duration = ClassifyPressDuration(*m_home_button_press_start); const auto duration = ClassifyPressDuration(*m_home_button_press_start);
if (duration != ButtonPressDuration::ShortPressing) { if (duration != ButtonPressDuration::ShortPressing) {
m_window_system.OnSystemButtonPress(SystemButtonType::HomeButtonLongPressing); window_system.OnSystemButtonPress(SystemButtonType::HomeButtonLongPressing);
m_home_button_long_sent = true; m_home_button_long_sent = true;
} }
} }
@ -98,7 +109,7 @@ void ButtonPoller::OnButtonStateChanged() {
if (capture_button && m_capture_button_press_start && !m_capture_button_long_sent) { if (capture_button && m_capture_button_press_start && !m_capture_button_long_sent) {
const auto duration = ClassifyPressDuration(*m_capture_button_press_start); const auto duration = ClassifyPressDuration(*m_capture_button_press_start);
if (duration != ButtonPressDuration::ShortPressing) { if (duration != ButtonPressDuration::ShortPressing) {
m_window_system.OnSystemButtonPress(SystemButtonType::CaptureButtonLongPressing); window_system.OnSystemButtonPress(SystemButtonType::CaptureButtonLongPressing);
m_capture_button_long_sent = true; m_capture_button_long_sent = true;
} }
} }
@ -107,9 +118,8 @@ void ButtonPoller::OnButtonStateChanged() {
if (!home_button && m_home_button_press_start) { if (!home_button && m_home_button_press_start) {
if(!m_home_button_long_sent) { if(!m_home_button_long_sent) {
const auto duration = ClassifyPressDuration(*m_home_button_press_start); const auto duration = ClassifyPressDuration(*m_home_button_press_start);
m_window_system.OnSystemButtonPress( window_system.OnSystemButtonPress(duration == ButtonPressDuration::ShortPressing
duration == ButtonPressDuration::ShortPressing ? SystemButtonType::HomeButtonShortPressing ? SystemButtonType::HomeButtonShortPressing : SystemButtonType::HomeButtonLongPressing);
: SystemButtonType::HomeButtonLongPressing);
} }
m_home_button_press_start = std::nullopt; m_home_button_press_start = std::nullopt;
m_home_button_long_sent = false; m_home_button_long_sent = false;
@ -117,9 +127,8 @@ void ButtonPoller::OnButtonStateChanged() {
if (!capture_button && m_capture_button_press_start) { if (!capture_button && m_capture_button_press_start) {
if (!m_capture_button_long_sent) { if (!m_capture_button_long_sent) {
const auto duration = ClassifyPressDuration(*m_capture_button_press_start); const auto duration = ClassifyPressDuration(*m_capture_button_press_start);
m_window_system.OnSystemButtonPress( window_system.OnSystemButtonPress(duration == ButtonPressDuration::ShortPressing
duration == ButtonPressDuration::ShortPressing ? SystemButtonType::CaptureButtonShortPressing ? SystemButtonType::CaptureButtonShortPressing : SystemButtonType::CaptureButtonLongPressing);
: SystemButtonType::CaptureButtonLongPressing);
} }
m_capture_button_press_start = std::nullopt; m_capture_button_press_start = std::nullopt;
m_capture_button_long_sent = false; m_capture_button_long_sent = false;
@ -130,16 +139,4 @@ void ButtonPoller::OnButtonStateChanged() {
// } // }
} }
void ButtonPoller::ThreadLoop() {
using namespace std::chrono_literals;
std::unique_lock lk{m_mutex};
while (!m_stop) {
m_cv.wait_for(lk, 50ms);
if (m_stop) break;
lk.unlock();
OnButtonStateChanged();
lk.lock();
}
}
} // namespace Service::AM } // namespace Service::AM

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@ -30,31 +30,23 @@ class ButtonPoller {
public: public:
explicit ButtonPoller(Core::System& system, WindowSystem& window_system); explicit ButtonPoller(Core::System& system, WindowSystem& window_system);
~ButtonPoller(); ~ButtonPoller();
void OnButtonStateChanged(WindowSystem& window_system);
private: private:
void OnButtonStateChanged(); std::mutex m_mutex;
void ThreadLoop(); std::condition_variable m_cv;
std::jthread m_thread;
private:
WindowSystem& m_window_system;
Core::HID::EmulatedController* m_handheld{};
int m_handheld_key{};
Core::HID::EmulatedController* m_player1{};
int m_player1_key{};
std::optional<std::chrono::steady_clock::time_point> m_home_button_press_start{}; std::optional<std::chrono::steady_clock::time_point> m_home_button_press_start{};
std::optional<std::chrono::steady_clock::time_point> m_capture_button_press_start{}; std::optional<std::chrono::steady_clock::time_point> m_capture_button_press_start{};
std::optional<std::chrono::steady_clock::time_point> m_power_button_press_start{}; std::optional<std::chrono::steady_clock::time_point> m_power_button_press_start{};
bool m_home_button_long_sent{}; Core::HID::EmulatedController* m_handheld{};
bool m_capture_button_long_sent{}; Core::HID::EmulatedController* m_player1{};
bool m_power_button_long_sent{}; int32_t m_handheld_key{};
int32_t m_player1_key{};
std::thread m_thread; bool m_home_button_long_sent : 1 = false;
std::atomic<bool> m_stop{false}; bool m_capture_button_long_sent : 1 = false;
std::condition_variable m_cv; bool m_power_button_long_sent : 1 = false;
std::mutex m_mutex;
}; };
} // namespace Service::AM } // namespace Service::AM

View file

@ -15,12 +15,24 @@ enum class UserDataTag : u32 {
}; };
EventObserver::EventObserver(Core::System& system, WindowSystem& window_system) EventObserver::EventObserver(Core::System& system, WindowSystem& window_system)
: m_system(system), m_context(system, "am:EventObserver"), m_window_system(window_system), : m_system(system), m_context(system, "am:EventObserver")
m_wakeup_event(m_context), m_wakeup_holder(m_wakeup_event.GetHandle()) { , m_window_system(window_system)
, m_wakeup_event(m_context)
, m_wakeup_holder(m_wakeup_event.GetHandle())
{
m_window_system.SetEventObserver(this); m_window_system.SetEventObserver(this);
m_wakeup_holder.SetUserData(static_cast<uintptr_t>(UserDataTag::WakeupEvent)); m_wakeup_holder.SetUserData(static_cast<uintptr_t>(UserDataTag::WakeupEvent));
m_wakeup_holder.LinkToMultiWait(std::addressof(m_multi_wait)); m_wakeup_holder.LinkToMultiWait(std::addressof(m_multi_wait));
m_thread = std::thread([&] { this->ThreadFunc(); }); m_thread = std::thread([this] {
Common::SetCurrentThreadName("am:EventObserver");
while (true) {
auto* signaled_holder = this->WaitSignaled();
if (!signaled_holder) {
break;
}
this->Process(signaled_holder);
}
});
} }
EventObserver::~EventObserver() { EventObserver::~EventObserver() {
@ -146,17 +158,4 @@ void EventObserver::DestroyAppletProcessHolderLocked(ProcessHolder* holder) {
delete holder; delete holder;
} }
void EventObserver::ThreadFunc() {
Common::SetCurrentThreadName("am:EventObserver");
while (true) {
auto* signaled_holder = this->WaitSignaled();
if (!signaled_holder) {
break;
}
this->Process(signaled_holder);
}
}
} // namespace Service::AM } // namespace Service::AM

View file

@ -41,9 +41,6 @@ private:
private: private:
void DestroyAppletProcessHolderLocked(ProcessHolder* holder); void DestroyAppletProcessHolderLocked(ProcessHolder* holder);
private:
void ThreadFunc();
private: private:
// System reference and context. // System reference and context.
Core::System& m_system; Core::System& m_system;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -17,7 +20,7 @@ namespace Service::AM {
namespace { namespace {
FileSys::StorageId GetStorageIdForFrontendSlot( [[nodiscard]] FileSys::StorageId GetStorageIdForFrontendSlot(
std::optional<FileSys::ContentProviderUnionSlot> slot) { std::optional<FileSys::ContentProviderUnionSlot> slot) {
if (!slot.has_value()) { if (!slot.has_value()) {
return FileSys::StorageId::None; return FileSys::StorageId::None;
@ -37,13 +40,13 @@ FileSys::StorageId GetStorageIdForFrontendSlot(
} }
} }
std::optional<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) { [[nodiscard]] inline std::optional<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
// Get the appropriate loader to parse this NCA. // Get the appropriate loader to parse this NCA.
out_loader = Loader::GetLoader(system, file, program_id, program_index); out_loader = Loader::GetLoader(system, file, program_id, program_index);
// Ensure we have a loader which can parse the NCA. // Ensure we have a loader which can parse the NCA.
if (out_loader) { if (out_loader) {
// Try to load the process. // Try to load the process.
auto process = std::optional<Process>(system); auto process = std::make_optional<Process>(system);
if (process->Initialize(*out_loader, out_load_result)) { if (process->Initialize(*out_loader, out_load_result)) {
return process; return process;
} }
@ -83,33 +86,31 @@ std::optional<Process> CreateProcess(Core::System& system, u64 program_id, u8 mi
} }
std::optional<Process> CreateApplicationProcess(std::vector<u8>& out_control, std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) { std::optional<Process> CreateApplicationProcess(std::vector<u8>& out_control, std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
auto process = CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index); if (auto process = CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index); process) {
if (!process) { FileSys::NACP nacp;
return std::nullopt; if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
out_control = nacp.GetRawBytes();
} else {
out_control.resize(sizeof(FileSys::RawNACP));
std::fill(out_control.begin(), out_control.end(), (u8) 0);
}
auto& storage = system.GetContentProviderUnion();
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process->GetProgramId();
FileSys::PatchManager pm{launch.title_id, system.GetFileSystemController(), storage};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
return process;
} }
return std::nullopt;
FileSys::NACP nacp;
if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
out_control = nacp.GetRawBytes();
} else {
out_control.resize(sizeof(FileSys::RawNACP));
std::fill(out_control.begin(), out_control.end(), (u8) 0);
}
auto& storage = system.GetContentProviderUnion();
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process->GetProgramId();
FileSys::PatchManager pm{launch.title_id, system.GetFileSystemController(), storage};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
return process;
} }
} // namespace Service::AM } // namespace Service::AM

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -12,6 +12,7 @@
#include "common/logging.h" #include "common/logging.h"
#include "common/param_package.h" #include "common/param_package.h"
#include "common/settings.h" #include "common/settings.h"
#include "common/thread.h"
#include "input_common/drivers/udp_client.h" #include "input_common/drivers/udp_client.h"
#include "input_common/helpers/udp_protocol.h" #include "input_common/helpers/udp_protocol.h"
@ -135,6 +136,7 @@ private:
}; };
static void SocketLoop(Socket* socket) { static void SocketLoop(Socket* socket) {
Common::SetCurrentThreadName("cemuhookWorker");
socket->StartReceive(); socket->StartReceive();
socket->StartSend(Socket::clock::now()); socket->StartSend(Socket::clock::now());
socket->Loop(); socket->Loop();
@ -330,9 +332,11 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) {
} }
void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) { void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) {
SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, SocketCallback callback{
[this](Response::PortInfo info) { OnPortInfo(info); }, [this](Response::Version version) { OnVersion(version); },
[this, client](Response::PadData data) { OnPadData(data, client); }}; [this](Response::PortInfo info) { OnPortInfo(info); },
[this, client](Response::PadData data) { OnPadData(data, client); }
};
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
clients[client].uuid = GetHostUUID(host); clients[client].uuid = GetHostUUID(host);
clients[client].host = host; clients[client].host = host;
@ -570,9 +574,7 @@ bool UDPClient::IsStickInverted(const Common::ParamPackage& params) {
return true; return true;
} }
void TestCommunication(const std::string& host, u16 port, void TestCommunication(const std::string& host, u16 port, const std::function<void()>& success_callback, const std::function<void()>& failure_callback) {
const std::function<void()>& success_callback,
const std::function<void()>& failure_callback) {
std::thread([=] { std::thread([=] {
Common::Event success_event; Common::Event success_event;
SocketCallback callback{ SocketCallback callback{
@ -605,40 +607,38 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
u16 max_y{}; u16 max_y{};
Status current_status{Status::Initialized}; Status current_status{Status::Initialized};
SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, [&](Response::PadData data) {
[&](Response::PadData data) { constexpr u16 CALIBRATION_THRESHOLD = 100;
constexpr u16 CALIBRATION_THRESHOLD = 100;
if (current_status == Status::Initialized) { if (current_status == Status::Initialized) {
// Receiving data means the communication is ready now // Receiving data means the communication is ready now
current_status = Status::Ready; current_status = Status::Ready;
status_callback(current_status); status_callback(current_status);
} }
if (data.touch[0].is_active == 0) { if (data.touch[0].is_active == 0) {
return; return;
} }
LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, data.touch[0].y);
data.touch[0].y); min_x = (std::min)(min_x, u16(data.touch[0].x));
min_x = (std::min)(min_x, static_cast<u16>(data.touch[0].x)); min_y = (std::min)(min_y, u16(data.touch[0].y));
min_y = (std::min)(min_y, static_cast<u16>(data.touch[0].y)); if (current_status == Status::Ready) {
if (current_status == Status::Ready) { // First touch - min data (min_x/min_y)
// First touch - min data (min_x/min_y) current_status = Status::Stage1Completed;
current_status = Status::Stage1Completed; status_callback(current_status);
status_callback(current_status); }
} if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD &&
if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD && data.touch[0].y - min_y > CALIBRATION_THRESHOLD) {
data.touch[0].y - min_y > CALIBRATION_THRESHOLD) { // Set the current position as max value and finishes
// Set the current position as max value and finishes // configuration
// configuration max_x = data.touch[0].x;
max_x = data.touch[0].x; max_y = data.touch[0].y;
max_y = data.touch[0].y; current_status = Status::Completed;
current_status = Status::Completed; data_callback(min_x, min_y, max_x, max_y);
data_callback(min_x, min_y, max_x, max_y); status_callback(current_status);
status_callback(current_status);
complete_event.Set(); complete_event.Set();
} }
}}; }};
Socket socket{host, port, std::move(callback)}; Socket socket{host, port, std::move(callback)};
std::thread worker_thread{SocketLoop, &socket}; std::thread worker_thread{SocketLoop, &socket};
complete_event.Wait(); complete_event.Wait();

View file

@ -1,10 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <array> #include <array>
#include <variant>
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {