mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-21 01:42:29 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 74b5e10dc5 |
@@ -788,7 +788,7 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
|
|||||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
|
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
|
||||||
jstring jprogramId,
|
jstring jprogramId,
|
||||||
jstring jupdatePath) {
|
jstring jupdatePath) {
|
||||||
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
const u64 program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
|
||||||
std::string updatePath = Common::Android::GetJString(env, jupdatePath);
|
std::string updatePath = Common::Android::GetJString(env, jupdatePath);
|
||||||
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
|
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
|
||||||
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
|
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
|
||||||
@@ -796,7 +796,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
|
|||||||
for (const auto& item : nsp->GetNCAs()) {
|
for (const auto& item : nsp->GetNCAs()) {
|
||||||
for (const auto& nca_details : item.second) {
|
for (const auto& nca_details : item.second) {
|
||||||
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
|
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
|
||||||
auto update_id = nca_details.second->GetTitleId() & ~0xFFFULL;
|
const auto update_id = FileSys::GetBaseTitleID(nca_details.second->GetTitleId());
|
||||||
if (update_id == program_id) {
|
if (update_id == program_id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
@@ -19,10 +19,6 @@ ADSP::ADSP(Core::System& system, Sink::Sink& sink) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADSP::NotifyShutdown() {
|
|
||||||
opus_decoder->NotifyShutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioRenderer::AudioRenderer& ADSP::AudioRenderer() {
|
AudioRenderer::AudioRenderer& ADSP::AudioRenderer() {
|
||||||
return *audio_renderer;
|
return *audio_renderer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
@@ -45,7 +45,6 @@ public:
|
|||||||
explicit ADSP(Core::System& system, Sink::Sink& sink);
|
explicit ADSP(Core::System& system, Sink::Sink& sink);
|
||||||
~ADSP() = default;
|
~ADSP() = default;
|
||||||
|
|
||||||
void NotifyShutdown();
|
|
||||||
AudioRenderer::AudioRenderer& AudioRenderer();
|
AudioRenderer::AudioRenderer& AudioRenderer();
|
||||||
OpusDecoder::OpusDecoder& OpusDecoder();
|
OpusDecoder::OpusDecoder& OpusDecoder();
|
||||||
|
|
||||||
|
|||||||
@@ -82,9 +82,6 @@ void OpusDecoder::Main(std::stop_token stop_token) {
|
|||||||
|
|
||||||
while (!stop_token.stop_requested()) {
|
while (!stop_token.stop_requested()) {
|
||||||
auto msg = Receive(Direction::DSP, stop_token);
|
auto msg = Receive(Direction::DSP, stop_token);
|
||||||
if (stop_token.stop_requested())
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case Shutdown:
|
case Shutdown:
|
||||||
Send(Direction::Host, Message::ShutdownOK);
|
Send(Direction::Host, Message::ShutdownOK);
|
||||||
@@ -269,9 +266,4 @@ void OpusDecoder::Main(std::stop_token stop_token) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpusDecoder::NotifyShutdown() {
|
|
||||||
init_thread.request_stop();
|
|
||||||
main_thread.request_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace AudioCore::ADSP::OpusDecoder
|
} // namespace AudioCore::ADSP::OpusDecoder
|
||||||
|
|||||||
@@ -67,8 +67,6 @@ public:
|
|||||||
shared_memory = &shared_memory_;
|
shared_memory = &shared_memory_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyShutdown();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Initializing thread, launched at audio_core boot to avoid blocking the main emu boot thread.
|
* Initializing thread, launched at audio_core boot to avoid blocking the main emu boot thread.
|
||||||
|
|||||||
@@ -31,11 +31,6 @@ void AudioCore::CreateSinks() {
|
|||||||
input_sink = Sink::CreateSinkFromID(sink_id.GetValue(), audio_input_device_id.GetValue());
|
input_sink = Sink::CreateSinkFromID(sink_id.GetValue(), audio_input_device_id.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioCore::NotifyShutdown() {
|
|
||||||
audio_manager->NotifyShutdown();
|
|
||||||
adsp->NotifyShutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioCore::Shutdown() {
|
void AudioCore::Shutdown() {
|
||||||
audio_manager->Shutdown();
|
audio_manager->Shutdown();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ public:
|
|||||||
explicit AudioCore(Core::System& system);
|
explicit AudioCore(Core::System& system);
|
||||||
~AudioCore();
|
~AudioCore();
|
||||||
|
|
||||||
void NotifyShutdown();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shutdown the audio core.
|
* Shutdown the audio core.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ AudioManager::AudioManager() {
|
|||||||
std::unique_lock l{events.GetAudioEventLock()};
|
std::unique_lock l{events.GetAudioEventLock()};
|
||||||
events.ClearEvents();
|
events.ClearEvents();
|
||||||
while (!stop_token.stop_requested()) {
|
while (!stop_token.stop_requested()) {
|
||||||
const auto timed_out = events.Wait(l, std::chrono::seconds{2});
|
const auto timed_out{events.Wait(l, std::chrono::seconds(2))};
|
||||||
if (events.CheckAudioEventSet(Event::Type::Max)) {
|
if (events.CheckAudioEventSet(Event::Type::Max)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -34,11 +34,6 @@ AudioManager::AudioManager() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioManager::NotifyShutdown() {
|
|
||||||
events.SetAudioEvent(Event::Type::Max, true);
|
|
||||||
thread.request_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioManager::Shutdown() {
|
void AudioManager::Shutdown() {
|
||||||
events.SetAudioEvent(Event::Type::Max, true);
|
events.SetAudioEvent(Event::Type::Max, true);
|
||||||
if (thread.joinable()) {
|
if (thread.joinable()) {
|
||||||
|
|||||||
@@ -39,10 +39,9 @@ class AudioManager {
|
|||||||
public:
|
public:
|
||||||
explicit AudioManager();
|
explicit AudioManager();
|
||||||
|
|
||||||
/// @brief Notify of impending shutdown
|
/**
|
||||||
void NotifyShutdown();
|
* Shutdown the audio manager.
|
||||||
|
*/
|
||||||
/// @brief Shutdown the audio manager.
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// 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
|
||||||
|
|
||||||
@@ -38,7 +35,7 @@ void CircularBufferSinkInfo::Update(BehaviorInfo::ErrorInfo& error_info, OutStat
|
|||||||
auto current_params{reinterpret_cast<CircularBufferInParameter*>(parameter.data())};
|
auto current_params{reinterpret_cast<CircularBufferInParameter*>(parameter.data())};
|
||||||
auto current_state{reinterpret_cast<CircularBufferState*>(state.data())};
|
auto current_state{reinterpret_cast<CircularBufferState*>(state.data())};
|
||||||
|
|
||||||
if (in_use == bool(buffer_params->in_use) && !buffer_unmapped) {
|
if (in_use == buffer_params->in_use && !buffer_unmapped) {
|
||||||
error_info.error_code = ResultSuccess;
|
error_info.error_code = ResultSuccess;
|
||||||
error_info.address = CpuAddr(0);
|
error_info.address = CpuAddr(0);
|
||||||
out_status.writeOffset = current_state->last_pos2;
|
out_status.writeOffset = current_state->last_pos2;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
@@ -31,10 +31,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct DeviceInParameter {
|
struct DeviceInParameter {
|
||||||
/* 0x000 */ u8 name[0x100];
|
/* 0x000 */ char name[0x100];
|
||||||
/* 0x100 */ u32 input_count;
|
/* 0x100 */ u32 input_count;
|
||||||
/* 0x104 */ std::array<s8, MaxChannels> inputs;
|
/* 0x104 */ std::array<s8, MaxChannels> inputs;
|
||||||
/* 0x10A */ u8 unk10A[0x1];
|
/* 0x10A */ char unk10A[0x1];
|
||||||
/* 0x10B */ bool downmix_enabled;
|
/* 0x10B */ bool downmix_enabled;
|
||||||
/* 0x10C */ std::array<f32, 4> downmix_coeff;
|
/* 0x10C */ std::array<f32, 4> downmix_coeff;
|
||||||
};
|
};
|
||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
struct DeviceState {
|
struct DeviceState {
|
||||||
/* 0x00 */ UpsamplerInfo* upsampler_info;
|
/* 0x00 */ UpsamplerInfo* upsampler_info;
|
||||||
/* 0x08 */ std::array<Common::FixedPoint<16, 16>, 4> downmix_coeff;
|
/* 0x08 */ std::array<Common::FixedPoint<16, 16>, 4> downmix_coeff;
|
||||||
/* 0x18 */ u8 unk18[0x18];
|
/* 0x18 */ char unk18[0x18];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(DeviceState) == 0x30, "DeviceState has the wrong size!");
|
static_assert(sizeof(DeviceState) == 0x30, "DeviceState has the wrong size!");
|
||||||
|
|
||||||
@@ -55,8 +55,8 @@ public:
|
|||||||
/* 0x14 */ u32 previous_pos;
|
/* 0x14 */ u32 previous_pos;
|
||||||
/* 0x18 */ SampleFormat format;
|
/* 0x18 */ SampleFormat format;
|
||||||
/* 0x1C */ std::array<s8, MaxChannels> inputs;
|
/* 0x1C */ std::array<s8, MaxChannels> inputs;
|
||||||
/* 0x22 */ u8 in_use;
|
/* 0x22 */ bool in_use;
|
||||||
/* 0x23 */ u8 unk23[0x5];
|
/* 0x23 */ char unk23[0x5];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(CircularBufferInParameter) == 0x28,
|
static_assert(sizeof(CircularBufferInParameter) == 0x28,
|
||||||
"CircularBufferInParameter has the wrong size!");
|
"CircularBufferInParameter has the wrong size!");
|
||||||
@@ -65,16 +65,16 @@ public:
|
|||||||
/* 0x00 */ u32 last_pos2;
|
/* 0x00 */ u32 last_pos2;
|
||||||
/* 0x04 */ s32 current_pos;
|
/* 0x04 */ s32 current_pos;
|
||||||
/* 0x08 */ u32 last_pos;
|
/* 0x08 */ u32 last_pos;
|
||||||
/* 0x0C */ u8 unk0C[0x4];
|
/* 0x0C */ char unk0C[0x4];
|
||||||
/* 0x10 */ AddressInfo address_info;
|
/* 0x10 */ AddressInfo address_info;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(CircularBufferState) == 0x30, "CircularBufferState has the wrong size!");
|
static_assert(sizeof(CircularBufferState) == 0x30, "CircularBufferState has the wrong size!");
|
||||||
|
|
||||||
struct InParameter {
|
struct InParameter {
|
||||||
/* 0x000 */ Type type;
|
/* 0x000 */ Type type;
|
||||||
/* 0x001 */ u8 in_use;
|
/* 0x001 */ bool in_use;
|
||||||
/* 0x004 */ u32 node_id;
|
/* 0x004 */ u32 node_id;
|
||||||
/* 0x008 */ u8 unk08[0x18];
|
/* 0x008 */ char unk08[0x18];
|
||||||
union {
|
union {
|
||||||
/* 0x020 */ DeviceInParameter device;
|
/* 0x020 */ DeviceInParameter device;
|
||||||
/* 0x020 */ CircularBufferInParameter circular_buffer;
|
/* 0x020 */ CircularBufferInParameter circular_buffer;
|
||||||
@@ -84,7 +84,7 @@ public:
|
|||||||
|
|
||||||
struct OutStatus {
|
struct OutStatus {
|
||||||
/* 0x00 */ u32 writeOffset;
|
/* 0x00 */ u32 writeOffset;
|
||||||
/* 0x04 */ u8 unk04[0x1C];
|
/* 0x04 */ char unk04[0x1C];
|
||||||
}; // size == 0x20
|
}; // size == 0x20
|
||||||
static_assert(sizeof(OutStatus) == 0x20, "SinkInfoBase::OutStatus has the wrong size!");
|
static_assert(sizeof(OutStatus) == 0x20, "SinkInfoBase::OutStatus has the wrong size!");
|
||||||
|
|
||||||
@@ -162,18 +162,19 @@ public:
|
|||||||
u8* GetParameter();
|
u8* GetParameter();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/// Type of this sink
|
||||||
|
Type type{Type::Invalid};
|
||||||
|
/// Is this sink in use?
|
||||||
|
bool in_use{};
|
||||||
|
/// Is this sink's buffer unmapped? Circular only
|
||||||
|
bool buffer_unmapped{};
|
||||||
|
/// Node id for this sink
|
||||||
|
u32 node_id{};
|
||||||
/// State buffer for this sink
|
/// State buffer for this sink
|
||||||
std::array<u8, (std::max)(sizeof(DeviceState), sizeof(CircularBufferState))> state{};
|
std::array<u8, (std::max)(sizeof(DeviceState), sizeof(CircularBufferState))> state{};
|
||||||
/// Parameter buffer for this sink
|
/// Parameter buffer for this sink
|
||||||
std::array<u8, (std::max)(sizeof(DeviceInParameter), sizeof(CircularBufferInParameter))> parameter{};
|
std::array<u8, (std::max)(sizeof(DeviceInParameter), sizeof(CircularBufferInParameter))>
|
||||||
/// Type of this sink
|
parameter{};
|
||||||
Type type{Type::Invalid};
|
|
||||||
/// Node id for this sink
|
|
||||||
u32 node_id{};
|
|
||||||
/// Is this sink in use?
|
|
||||||
bool in_use : 1 = false;
|
|
||||||
/// Is this sink's buffer unmapped? Circular only
|
|
||||||
bool buffer_unmapped : 1 = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AudioCore::Renderer
|
} // namespace AudioCore::Renderer
|
||||||
|
|||||||
+21
-46
@@ -110,13 +110,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
|||||||
|
|
||||||
struct System::Impl {
|
struct System::Impl {
|
||||||
explicit Impl(System& system)
|
explicit Impl(System& system)
|
||||||
: kernel{system}
|
: kernel{system}, fs_controller{system}, hid_core{kernel}, cpu_manager{system},
|
||||||
, fs_controller{system}
|
reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {}
|
||||||
, hid_core{kernel}
|
|
||||||
, cpu_manager{system}
|
|
||||||
, reporter{system}
|
|
||||||
, profile_manager{}
|
|
||||||
{}
|
|
||||||
|
|
||||||
u64 program_id;
|
u64 program_id;
|
||||||
|
|
||||||
@@ -129,12 +124,6 @@ struct System::Impl {
|
|||||||
core_timing.SetMulticore(is_multicore);
|
core_timing.SetMulticore(is_multicore);
|
||||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||||
|
|
||||||
applet_manager.emplace(system);
|
|
||||||
frontend_applets.emplace(system);
|
|
||||||
apm_controller.emplace(core_timing);
|
|
||||||
arp_manager.emplace();
|
|
||||||
profile_manager.emplace();
|
|
||||||
|
|
||||||
// Create a default fs if one doesn't already exist.
|
// Create a default fs if one doesn't already exist.
|
||||||
if (virtual_filesystem == nullptr) {
|
if (virtual_filesystem == nullptr) {
|
||||||
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
|
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||||
@@ -144,7 +133,7 @@ struct System::Impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create default implementations of applets if one is not provided.
|
// Create default implementations of applets if one is not provided.
|
||||||
frontend_applets->SetDefaultAppletsIfMissing();
|
frontend_applets.SetDefaultAppletsIfMissing();
|
||||||
|
|
||||||
auto const is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
|
auto const is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
|
||||||
|
|
||||||
@@ -387,7 +376,7 @@ struct System::Impl {
|
|||||||
|
|
||||||
// Register with applet manager
|
// Register with applet manager
|
||||||
// All threads are started, begin main process execution, now that we're in the clear
|
// All threads are started, begin main process execution, now that we're in the clear
|
||||||
applet_manager->CreateAndInsertByFrontendAppletParameters(std::move(process), params);
|
applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params);
|
||||||
|
|
||||||
if (Settings::values.gamecard_inserted) {
|
if (Settings::values.gamecard_inserted) {
|
||||||
if (Settings::values.gamecard_current_game) {
|
if (Settings::values.gamecard_current_game) {
|
||||||
@@ -439,27 +428,13 @@ struct System::Impl {
|
|||||||
core_timing.SyncPause(false);
|
core_timing.SyncPause(false);
|
||||||
Network::CancelPendingSocketOperations();
|
Network::CancelPendingSocketOperations();
|
||||||
kernel.SuspendEmulation(true);
|
kernel.SuspendEmulation(true);
|
||||||
kernel.ShutdownCores();
|
|
||||||
|
|
||||||
// Notify services helpers of shutdown
|
|
||||||
audio_core->NotifyShutdown();
|
|
||||||
|
|
||||||
// Wait for threads/services to join
|
|
||||||
kernel.CloseServices();
|
kernel.CloseServices();
|
||||||
|
kernel.ShutdownCores();
|
||||||
// service shutdown
|
|
||||||
services.reset();
|
services.reset();
|
||||||
service_manager.reset();
|
service_manager.reset();
|
||||||
frontend_applets.reset();
|
|
||||||
applet_manager.reset();
|
|
||||||
apm_controller.reset();
|
|
||||||
arp_manager.reset();
|
|
||||||
profile_manager.reset();
|
|
||||||
|
|
||||||
fs_controller.Reset();
|
fs_controller.Reset();
|
||||||
cheat_engine.reset();
|
cheat_engine.reset();
|
||||||
core_timing.ClearPendingEvents();
|
core_timing.ClearPendingEvents();
|
||||||
core_timing.Reset();
|
|
||||||
app_loader.reset();
|
app_loader.reset();
|
||||||
audio_core.reset();
|
audio_core.reset();
|
||||||
gpu_core.reset();
|
gpu_core.reset();
|
||||||
@@ -477,7 +452,7 @@ struct System::Impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset all glue registrations
|
// Reset all glue registrations
|
||||||
arp_manager->ResetAll();
|
arp_manager.ResetAll();
|
||||||
|
|
||||||
LOG_DEBUG(Core, "Shutdown OK");
|
LOG_DEBUG(Core, "Shutdown OK");
|
||||||
}
|
}
|
||||||
@@ -507,13 +482,13 @@ struct System::Impl {
|
|||||||
CpuManager cpu_manager;
|
CpuManager cpu_manager;
|
||||||
Reporter reporter;
|
Reporter reporter;
|
||||||
/// Applets
|
/// Applets
|
||||||
std::optional<Service::AM::AppletManager> applet_manager;
|
Service::AM::AppletManager applet_manager;
|
||||||
std::optional<Service::AM::Frontend::FrontendAppletHolder> frontend_applets;
|
Service::AM::Frontend::FrontendAppletHolder frontend_applets;
|
||||||
/// APM (Performance) services
|
/// APM (Performance) services
|
||||||
std::optional<Service::APM::Controller> apm_controller;
|
Service::APM::Controller apm_controller{core_timing};
|
||||||
/// Service State
|
/// Service State
|
||||||
std::optional<Service::Glue::ARPManager> arp_manager;
|
Service::Glue::ARPManager arp_manager;
|
||||||
std::optional<Service::Account::ProfileManager> profile_manager;
|
Service::Account::ProfileManager profile_manager;
|
||||||
/// Network instance
|
/// Network instance
|
||||||
Network::NetworkInstance network_instance;
|
Network::NetworkInstance network_instance;
|
||||||
Core::SpeedLimiter speed_limiter;
|
Core::SpeedLimiter speed_limiter;
|
||||||
@@ -840,19 +815,19 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
|
void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
|
||||||
impl->frontend_applets->SetFrontendAppletSet(std::move(set));
|
impl->frontend_applets.SetFrontendAppletSet(std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() {
|
Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() {
|
||||||
return *impl->frontend_applets;
|
return impl->frontend_applets;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const {
|
const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const {
|
||||||
return *impl->frontend_applets;
|
return impl->frontend_applets;
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::AM::AppletManager& System::GetAppletManager() {
|
Service::AM::AppletManager& System::GetAppletManager() {
|
||||||
return *impl->applet_manager;
|
return impl->applet_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) {
|
void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) {
|
||||||
@@ -893,27 +868,27 @@ const Reporter& System::GetReporter() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Service::Glue::ARPManager& System::GetARPManager() {
|
Service::Glue::ARPManager& System::GetARPManager() {
|
||||||
return *impl->arp_manager;
|
return impl->arp_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Service::Glue::ARPManager& System::GetARPManager() const {
|
const Service::Glue::ARPManager& System::GetARPManager() const {
|
||||||
return *impl->arp_manager;
|
return impl->arp_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::APM::Controller& System::GetAPMController() {
|
Service::APM::Controller& System::GetAPMController() {
|
||||||
return *impl->apm_controller;
|
return impl->apm_controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Service::APM::Controller& System::GetAPMController() const {
|
const Service::APM::Controller& System::GetAPMController() const {
|
||||||
return *impl->apm_controller;
|
return impl->apm_controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::Account::ProfileManager& System::GetProfileManager() {
|
Service::Account::ProfileManager& System::GetProfileManager() {
|
||||||
return *impl->profile_manager;
|
return impl->profile_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Service::Account::ProfileManager& System::GetProfileManager() const {
|
const Service::Account::ProfileManager& System::GetProfileManager() const {
|
||||||
return *impl->profile_manager;
|
return impl->profile_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::SetExitLocked(bool locked) {
|
void System::SetExitLocked(bool locked) {
|
||||||
|
|||||||
@@ -304,10 +304,10 @@ std::optional<s64> CoreTiming::Advance() {
|
|||||||
|
|
||||||
void CoreTiming::Reset() {
|
void CoreTiming::Reset() {
|
||||||
paused = true;
|
paused = true;
|
||||||
|
pause_event.Set();
|
||||||
|
event.Set();
|
||||||
if (timer_thread.joinable()) {
|
if (timer_thread.joinable()) {
|
||||||
timer_thread.request_stop();
|
timer_thread.request_stop();
|
||||||
pause_event.Set();
|
|
||||||
event.Set();
|
|
||||||
timer_thread.join();
|
timer_thread.join();
|
||||||
}
|
}
|
||||||
has_started = false;
|
has_started = false;
|
||||||
|
|||||||
@@ -72,9 +72,11 @@ void GlobalSchedulerContext::UnregisterDummyThreadForWakeup(KThread* thread) noe
|
|||||||
|
|
||||||
void GlobalSchedulerContext::WakeupWaitingDummyThreads(KernelCore& kernel) noexcept {
|
void GlobalSchedulerContext::WakeupWaitingDummyThreads(KernelCore& kernel) noexcept {
|
||||||
ASSERT(this->IsLocked());
|
ASSERT(this->IsLocked());
|
||||||
for (auto* thread : m_woken_dummy_threads)
|
if (m_woken_dummy_threads.size() > 0) {
|
||||||
thread->DummyThreadEndWait(kernel);
|
for (auto* thread : m_woken_dummy_threads)
|
||||||
m_woken_dummy_threads.clear();
|
thread->DummyThreadEndWait(kernel);
|
||||||
|
m_woken_dummy_threads.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ Result TerminateChildren(KernelCore& kernel, KProcess* process, const KThread* t
|
|||||||
KThread* cur_child = nullptr;
|
KThread* cur_child = nullptr;
|
||||||
{
|
{
|
||||||
KScopedLightLock proc_lk(process->GetListLock());
|
KScopedLightLock proc_lk(process->GetListLock());
|
||||||
|
|
||||||
auto& thread_list = process->GetThreadList();
|
auto& thread_list = process->GetThreadList();
|
||||||
for (auto it = thread_list.begin(); it != thread_list.end(); ++it) {
|
for (auto it = thread_list.begin(); it != thread_list.end(); ++it) {
|
||||||
if (KThread* thread = std::addressof(*it); thread != thread_to_not_terminate) {
|
if (KThread* thread = std::addressof(*it); thread != thread_to_not_terminate) {
|
||||||
|
|||||||
@@ -1236,10 +1236,14 @@ namespace Kernel {
|
|||||||
KScopedSchedulerLock sl{kernel};
|
KScopedSchedulerLock sl{kernel};
|
||||||
|
|
||||||
// Determine if this is the first termination request.
|
// Determine if this is the first termination request.
|
||||||
// Perform an atomic compare-and-swap from false to true.
|
const bool first_request = [&]() -> bool {
|
||||||
bool expected = false;
|
// Perform an atomic compare-and-swap from false to true.
|
||||||
|
bool expected = false;
|
||||||
|
return m_termination_requested.compare_exchange_strong(expected, true);
|
||||||
|
}();
|
||||||
|
|
||||||
// If this is the first request, start termination procedure.
|
// If this is the first request, start termination procedure.
|
||||||
if (m_termination_requested.compare_exchange_strong(expected, true)) {
|
if (first_request) {
|
||||||
// If the thread is in initialized state, just change state to terminated.
|
// If the thread is in initialized state, just change state to terminated.
|
||||||
if (this->GetState() == ThreadState::Initialized) {
|
if (this->GetState() == ThreadState::Initialized) {
|
||||||
m_thread_state = ThreadState::Terminated;
|
m_thread_state = ThreadState::Terminated;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
// 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 <thread>
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
@@ -27,15 +26,7 @@ void KWorkerTask::DoWorkerTask(KernelCore& kernel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KWorkerTaskManager::KWorkerTaskManager() {}
|
KWorkerTaskManager::KWorkerTaskManager() : m_waiting_thread(1, "KWorkerTaskManager") {}
|
||||||
|
|
||||||
KWorkerTaskManager::~KWorkerTaskManager() {
|
|
||||||
if (m_waiting_thread.joinable()) {
|
|
||||||
m_waiting_thread.request_stop();
|
|
||||||
m_task_cv.notify_one();
|
|
||||||
m_waiting_thread.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWorkerTaskManager::AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task) {
|
void KWorkerTaskManager::AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task) {
|
||||||
ASSERT(type <= WorkerType::Count);
|
ASSERT(type <= WorkerType::Count);
|
||||||
@@ -44,31 +35,10 @@ void KWorkerTaskManager::AddTask(KernelCore& kernel, WorkerType type, KWorkerTas
|
|||||||
|
|
||||||
void KWorkerTaskManager::AddTask(KernelCore& kernel, KWorkerTask* task) {
|
void KWorkerTaskManager::AddTask(KernelCore& kernel, KWorkerTask* task) {
|
||||||
KScopedSchedulerLock sl(kernel);
|
KScopedSchedulerLock sl(kernel);
|
||||||
|
m_waiting_thread.QueueWork([&kernel, task]() {
|
||||||
// spawn thread on demand
|
// Do the task.
|
||||||
if (!m_waiting_thread.joinable()) {
|
task->DoWorkerTask(kernel);
|
||||||
LOG_INFO(Kernel, "spawning KWorkerTaskManager thread");
|
});
|
||||||
m_waiting_thread = std::jthread([&kernel, this](std::stop_token stop_token) {
|
|
||||||
while (!stop_token.stop_requested()) {
|
|
||||||
KWorkerTask* t;
|
|
||||||
{
|
|
||||||
std::unique_lock lk{m_task_mutex};
|
|
||||||
m_task_cv.wait(lk);
|
|
||||||
if (stop_token.stop_requested())
|
|
||||||
break;
|
|
||||||
t = m_task_queue.back();
|
|
||||||
m_task_queue.pop_back();
|
|
||||||
}
|
|
||||||
t->DoWorkerTask(kernel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
std::scoped_lock lk{m_task_mutex};
|
|
||||||
m_task_queue.emplace_back(task);
|
|
||||||
}
|
|
||||||
m_task_cv.notify_one();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
// 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
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <thread>
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/thread_worker.h"
|
#include "common/thread_worker.h"
|
||||||
|
|
||||||
@@ -24,16 +19,14 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
KWorkerTaskManager();
|
KWorkerTaskManager();
|
||||||
~KWorkerTaskManager();
|
|
||||||
|
|
||||||
static void AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task);
|
static void AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AddTask(KernelCore& kernel, KWorkerTask* task);
|
void AddTask(KernelCore& kernel, KWorkerTask* task);
|
||||||
std::jthread m_waiting_thread;
|
|
||||||
|
|
||||||
std::mutex m_task_mutex;
|
private:
|
||||||
std::condition_variable m_task_cv;
|
Common::ThreadWorker m_waiting_thread;
|
||||||
std::vector<KWorkerTask*> m_task_queue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|||||||
@@ -967,16 +967,12 @@ Kernel::KHardwareTimer& KernelCore::HardwareTimer() {
|
|||||||
return *impl->hardware_timer;
|
return *impl->hardware_timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
KAutoObjectWithListContainer* KernelCore::ObjectListContainer() {
|
KAutoObjectWithListContainer& KernelCore::ObjectListContainer() {
|
||||||
if (!impl->global_object_list_container)
|
return *impl->global_object_list_container;
|
||||||
return nullptr;
|
|
||||||
return std::addressof(*impl->global_object_list_container);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const KAutoObjectWithListContainer* KernelCore::ObjectListContainer() const {
|
const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
|
||||||
if (!impl->global_object_list_container)
|
return *impl->global_object_list_container;
|
||||||
return nullptr;
|
|
||||||
return std::addressof(*impl->global_object_list_container);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelCore::PrepareReschedule(std::size_t id) {
|
void KernelCore::PrepareReschedule(std::size_t id) {
|
||||||
@@ -1005,10 +1001,16 @@ void KernelCore::UnregisterInUseObject(KAutoObject* object) {
|
|||||||
|
|
||||||
void KernelCore::RunServer(std::unique_ptr<Service::ServerManager>&& server_manager) {
|
void KernelCore::RunServer(std::unique_ptr<Service::ServerManager>&& server_manager) {
|
||||||
auto* manager = server_manager.get();
|
auto* manager = server_manager.get();
|
||||||
if (!impl->is_shutting_down) {
|
|
||||||
|
{
|
||||||
std::scoped_lock lk{impl->server_lock};
|
std::scoped_lock lk{impl->server_lock};
|
||||||
|
if (impl->is_shutting_down) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
impl->server_managers.emplace_back(std::move(server_manager));
|
impl->server_managers.emplace_back(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
manager->LoopProcess();
|
manager->LoopProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1253,11 +1255,6 @@ void KernelCore::SuspendEmulation(bool suspended) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KernelCore::ShutdownCores() {
|
void KernelCore::ShutdownCores() {
|
||||||
// Notify shutdown (pre-emptively)
|
|
||||||
for (auto& sm : impl->server_managers) {
|
|
||||||
sm->NotifyShutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl->TerminateAllProcesses();
|
impl->TerminateAllProcesses();
|
||||||
KScopedSchedulerLock lk{*this};
|
KScopedSchedulerLock lk{*this};
|
||||||
for (auto* thread : impl->shutdown_threads)
|
for (auto* thread : impl->shutdown_threads)
|
||||||
|
|||||||
@@ -175,8 +175,9 @@ public:
|
|||||||
/// Stops execution of 'id' core, in order to reschedule a new thread.
|
/// Stops execution of 'id' core, in order to reschedule a new thread.
|
||||||
void PrepareReschedule(std::size_t id);
|
void PrepareReschedule(std::size_t id);
|
||||||
|
|
||||||
KAutoObjectWithListContainer* ObjectListContainer();
|
KAutoObjectWithListContainer& ObjectListContainer();
|
||||||
const KAutoObjectWithListContainer* ObjectListContainer() const;
|
|
||||||
|
const KAutoObjectWithListContainer& ObjectListContainer() const;
|
||||||
|
|
||||||
/// Registers all kernel objects with the global emulation state, this is purely for tracking
|
/// Registers all kernel objects with the global emulation state, this is purely for tracking
|
||||||
/// leaks after emulation has been shutdown.
|
/// leaks after emulation has been shutdown.
|
||||||
|
|||||||
@@ -151,8 +151,7 @@ public:
|
|||||||
const bool is_initialized = this->IsInitialized();
|
const bool is_initialized = this->IsInitialized();
|
||||||
uintptr_t arg = 0;
|
uintptr_t arg = 0;
|
||||||
if (is_initialized) {
|
if (is_initialized) {
|
||||||
if (auto const olc = kernel.ObjectListContainer(); olc)
|
kernel.ObjectListContainer().Unregister(this);
|
||||||
olc->Unregister(this);
|
|
||||||
arg = this->GetPostDestroyArgument();
|
arg = this->GetPostDestroyArgument();
|
||||||
this->Finalize(kernel);
|
this->Finalize(kernel);
|
||||||
}
|
}
|
||||||
@@ -176,7 +175,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) {
|
static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) {
|
||||||
kernel.SlabHeap<Derived>().Initialize(memory, memory_size);
|
kernel.SlabHeap<Derived>().Initialize(memory, memory_size);
|
||||||
kernel.ObjectListContainer()->Initialize();
|
kernel.ObjectListContainer().Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Derived* Create(KernelCore& kernel) {
|
static Derived* Create(KernelCore& kernel) {
|
||||||
@@ -187,7 +186,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void Register(KernelCore& kernel, Derived* obj) {
|
static void Register(KernelCore& kernel, Derived* obj) {
|
||||||
return kernel.ObjectListContainer()->Register(obj);
|
return kernel.ObjectListContainer().Register(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t GetObjectSize(KernelCore& kernel) {
|
static size_t GetObjectSize(KernelCore& kernel) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
@@ -90,9 +90,10 @@ static Service::PSC::Time::LocationName GetTimeZoneString(
|
|||||||
}
|
}
|
||||||
|
|
||||||
TimeManager::TimeManager(Core::System& system)
|
TimeManager::TimeManager(Core::System& system)
|
||||||
: m_steady_clock_resource{system}, m_time_zone_binary{system}
|
: m_steady_clock_resource{system}, m_time_zone_binary{system}, m_worker{
|
||||||
, m_worker{system, m_steady_clock_resource, m_file_timestamp_worker}
|
system,
|
||||||
{
|
m_steady_clock_resource,
|
||||||
|
m_file_timestamp_worker} {
|
||||||
m_time_m =
|
m_time_m =
|
||||||
system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
|
system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
|
||||||
|
|
||||||
|
|||||||
@@ -20,17 +20,15 @@
|
|||||||
|
|
||||||
namespace Service::Glue::Time {
|
namespace Service::Glue::Time {
|
||||||
|
|
||||||
TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource, FileTimestampWorker& file_timestamp_worker)
|
TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource,
|
||||||
: m_system{system}
|
FileTimestampWorker& file_timestamp_worker)
|
||||||
, m_ctx{m_system, "Glue:TimeWorker"}
|
: m_system{system}, m_ctx{m_system, "Glue:TimeWorker"}, m_event{m_ctx.CreateEvent(
|
||||||
, m_event{m_ctx.CreateEvent("Glue:TimeWorker:Event")}
|
"Glue:TimeWorker:Event")},
|
||||||
, m_steady_clock_resource{steady_clock_resource}
|
m_steady_clock_resource{steady_clock_resource},
|
||||||
, m_file_timestamp_worker{file_timestamp_worker}
|
m_file_timestamp_worker{file_timestamp_worker}, m_timer_steady_clock{m_ctx.CreateEvent(
|
||||||
, m_timer_steady_clock{m_ctx.CreateEvent("Glue:TimeWorker:SteadyClockTimerEvent")}
|
"Glue:TimeWorker:SteadyClockTimerEvent")},
|
||||||
, m_timer_file_system{m_ctx.CreateEvent("Glue:TimeWorker:FileTimeTimerEvent")}
|
m_timer_file_system{m_ctx.CreateEvent("Glue:TimeWorker:FileTimeTimerEvent")},
|
||||||
, m_alarm_worker{m_system, m_steady_clock_resource}
|
m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} {
|
||||||
, m_pm_state_change_handler{m_alarm_worker}
|
|
||||||
{
|
|
||||||
m_timer_steady_clock_timing_event = Core::Timing::CreateEvent(
|
m_timer_steady_clock_timing_event = Core::Timing::CreateEvent(
|
||||||
"Time::SteadyClockEvent",
|
"Time::SteadyClockEvent",
|
||||||
[this](s64 time,
|
[this](s64 time,
|
||||||
@@ -52,12 +50,11 @@ TimeWorker::~TimeWorker() {
|
|||||||
m_local_clock_event->Signal(m_system.Kernel());
|
m_local_clock_event->Signal(m_system.Kernel());
|
||||||
m_network_clock_event->Signal(m_system.Kernel());
|
m_network_clock_event->Signal(m_system.Kernel());
|
||||||
m_ephemeral_clock_event->Signal(m_system.Kernel());
|
m_ephemeral_clock_event->Signal(m_system.Kernel());
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
||||||
|
|
||||||
if (m_thread.joinable()) {
|
m_thread.request_stop();
|
||||||
m_thread.request_stop();
|
m_event->Signal(m_system.Kernel());
|
||||||
m_event->Signal(m_system.Kernel());
|
m_thread.join();
|
||||||
m_thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ctx.CloseEvent(m_event);
|
m_ctx.CloseEvent(m_event);
|
||||||
m_system.CoreTiming().UnscheduleEvent(m_timer_steady_clock_timing_event);
|
m_system.CoreTiming().UnscheduleEvent(m_timer_steady_clock_timing_event);
|
||||||
@@ -125,164 +122,166 @@ void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> t
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TimeWorker::StartThread() {
|
void TimeWorker::StartThread() {
|
||||||
m_thread = m_system.Kernel().RunOnHostCoreThread("TimeWorker", [this]() {
|
m_thread = std::jthread(std::bind_front(&TimeWorker::ThreadFunc, this));
|
||||||
auto const stop_token = m_thread.get_stop_token();
|
}
|
||||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::Low);
|
|
||||||
while (!stop_token.stop_requested()) {
|
|
||||||
enum class EventType : s32 {
|
|
||||||
Exit = 0,
|
|
||||||
PowerStateChange = 1,
|
|
||||||
SignalAlarms = 2,
|
|
||||||
UpdateLocalSystemClock = 3,
|
|
||||||
UpdateNetworkSystemClock = 4,
|
|
||||||
UpdateEphemeralSystemClock = 5,
|
|
||||||
UpdateSteadyClock = 6,
|
|
||||||
UpdateFileTimestamp = 7,
|
|
||||||
AutoCorrect = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
s32 index{};
|
void TimeWorker::ThreadFunc(std::stop_token stop_token) {
|
||||||
|
Common::SetCurrentThreadName("TimeWorker");
|
||||||
|
Common::SetCurrentThreadPriority(Common::ThreadPriority::Low);
|
||||||
|
|
||||||
if (m_pm_state_change_handler.m_priority != 0) {
|
while (!stop_token.stop_requested()) {
|
||||||
// TODO: gIPmModuleService::GetEvent() 1
|
enum class EventType : s32 {
|
||||||
index = WaitAny(
|
Exit = 0,
|
||||||
m_system.Kernel(),
|
PowerStateChange = 1,
|
||||||
&m_event->GetReadableEvent(), // 0
|
SignalAlarms = 2,
|
||||||
&m_alarm_worker.GetEvent() // 1
|
UpdateLocalSystemClock = 3,
|
||||||
);
|
UpdateNetworkSystemClock = 4,
|
||||||
} else {
|
UpdateEphemeralSystemClock = 5,
|
||||||
// TODO: gIPmModuleService::GetEvent() 1
|
UpdateSteadyClock = 6,
|
||||||
index = WaitAny(
|
UpdateFileTimestamp = 7,
|
||||||
m_system.Kernel(),
|
AutoCorrect = 8,
|
||||||
&m_event->GetReadableEvent(), // 0
|
};
|
||||||
&m_alarm_worker.GetEvent(), // 1
|
|
||||||
&m_alarm_worker.GetTimerEvent().GetReadableEvent(), // 2
|
|
||||||
m_local_clock_event, // 3
|
|
||||||
m_network_clock_event, // 4
|
|
||||||
m_ephemeral_clock_event, // 5
|
|
||||||
&m_timer_steady_clock->GetReadableEvent(), // 6
|
|
||||||
&m_timer_file_system->GetReadableEvent(), // 7
|
|
||||||
m_standard_user_auto_correct_clock_event // 8
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stop_token.stop_requested())
|
s32 index{};
|
||||||
break;
|
|
||||||
|
|
||||||
switch (EventType(index)) {
|
if (m_pm_state_change_handler.m_priority != 0) {
|
||||||
case EventType::Exit:
|
// TODO: gIPmModuleService::GetEvent() 1
|
||||||
return;
|
index = WaitAny(m_system.Kernel(),
|
||||||
|
&m_event->GetReadableEvent(), // 0
|
||||||
case EventType::PowerStateChange:
|
&m_alarm_worker.GetEvent() // 1
|
||||||
m_alarm_worker.GetEvent().Clear(m_system.Kernel());
|
);
|
||||||
if (m_pm_state_change_handler.m_priority <= 1) {
|
} else {
|
||||||
m_alarm_worker.OnPowerStateChanged();
|
// TODO: gIPmModuleService::GetEvent() 1
|
||||||
}
|
index = WaitAny(m_system.Kernel(),
|
||||||
break;
|
&m_event->GetReadableEvent(), // 0
|
||||||
|
&m_alarm_worker.GetEvent(), // 1
|
||||||
case EventType::SignalAlarms:
|
&m_alarm_worker.GetTimerEvent().GetReadableEvent(), // 2
|
||||||
m_alarm_worker.GetTimerEvent().Clear(m_system.Kernel());
|
m_local_clock_event, // 3
|
||||||
m_time_m->CheckAndSignalAlarms();
|
m_network_clock_event, // 4
|
||||||
break;
|
m_ephemeral_clock_event, // 5
|
||||||
|
&m_timer_steady_clock->GetReadableEvent(), // 6
|
||||||
case EventType::UpdateLocalSystemClock: {
|
&m_timer_file_system->GetReadableEvent(), // 7
|
||||||
m_local_clock_event->Clear(m_system.Kernel());
|
m_standard_user_auto_correct_clock_event // 8
|
||||||
|
);
|
||||||
Service::PSC::Time::SystemClockContext context{};
|
|
||||||
R_ASSERT(m_local_clock->GetSystemClockContext(&context));
|
|
||||||
|
|
||||||
m_set_sys->SetUserSystemClockContext(context);
|
|
||||||
m_file_timestamp_worker.SetFilesystemPosixTime();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EventType::UpdateNetworkSystemClock: {
|
|
||||||
m_network_clock_event->Clear(m_system.Kernel());
|
|
||||||
|
|
||||||
Service::PSC::Time::SystemClockContext context{};
|
|
||||||
R_ASSERT(m_network_clock->GetSystemClockContext(&context));
|
|
||||||
|
|
||||||
m_set_sys->SetNetworkSystemClockContext(context);
|
|
||||||
|
|
||||||
s64 time{};
|
|
||||||
if (m_network_clock->GetCurrentTime(&time) != ResultSuccess) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]] auto offset_before{
|
|
||||||
m_ig_report_network_clock_context_set ? m_report_network_clock_context.offset : 0};
|
|
||||||
// TODO system report "standard_netclock_operation"
|
|
||||||
// "clock_time" = time
|
|
||||||
// "context_offset_before" = offset_before
|
|
||||||
// "context_offset_after" = context.offset
|
|
||||||
m_report_network_clock_context = context;
|
|
||||||
if (!m_ig_report_network_clock_context_set) {
|
|
||||||
m_ig_report_network_clock_context_set = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_file_timestamp_worker.SetFilesystemPosixTime();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EventType::UpdateEphemeralSystemClock: {
|
|
||||||
m_ephemeral_clock_event->Clear(m_system.Kernel());
|
|
||||||
|
|
||||||
Service::PSC::Time::SystemClockContext context{};
|
|
||||||
auto res = m_ephemeral_clock->GetSystemClockContext(&context);
|
|
||||||
if (res != ResultSuccess) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
s64 time{};
|
|
||||||
res = m_ephemeral_clock->GetCurrentTime(&time);
|
|
||||||
if (res != ResultSuccess) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]] auto offset_before{m_ig_report_ephemeral_clock_context_set
|
|
||||||
? m_report_ephemeral_clock_context.offset
|
|
||||||
: 0};
|
|
||||||
// TODO system report "ephemeral_netclock_operation"
|
|
||||||
// "clock_time" = time
|
|
||||||
// "context_offset_before" = offset_before
|
|
||||||
// "context_offset_after" = context.offset
|
|
||||||
m_report_ephemeral_clock_context = context;
|
|
||||||
if (!m_ig_report_ephemeral_clock_context_set) {
|
|
||||||
m_ig_report_ephemeral_clock_context_set = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EventType::UpdateSteadyClock:
|
|
||||||
m_timer_steady_clock->Clear(m_system.Kernel());
|
|
||||||
|
|
||||||
m_steady_clock_resource.UpdateTime();
|
|
||||||
m_time_m->SetStandardSteadyClockBaseTime(m_steady_clock_resource.GetTime());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EventType::UpdateFileTimestamp:
|
|
||||||
m_timer_file_system->Clear(m_system.Kernel());
|
|
||||||
m_file_timestamp_worker.SetFilesystemPosixTime();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EventType::AutoCorrect: {
|
|
||||||
m_standard_user_auto_correct_clock_event->Clear(m_system.Kernel());
|
|
||||||
|
|
||||||
bool automatic_correction{};
|
|
||||||
R_ASSERT(m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled(&automatic_correction));
|
|
||||||
|
|
||||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
|
||||||
R_ASSERT(m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point));
|
|
||||||
|
|
||||||
m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
|
|
||||||
m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
switch (static_cast<EventType>(index)) {
|
||||||
|
case EventType::Exit:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case EventType::PowerStateChange:
|
||||||
|
m_alarm_worker.GetEvent().Clear(m_system.Kernel());
|
||||||
|
if (m_pm_state_change_handler.m_priority <= 1) {
|
||||||
|
m_alarm_worker.OnPowerStateChanged();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EventType::SignalAlarms:
|
||||||
|
m_alarm_worker.GetTimerEvent().Clear(m_system.Kernel());
|
||||||
|
m_time_m->CheckAndSignalAlarms();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EventType::UpdateLocalSystemClock: {
|
||||||
|
m_local_clock_event->Clear(m_system.Kernel());
|
||||||
|
|
||||||
|
Service::PSC::Time::SystemClockContext context{};
|
||||||
|
R_ASSERT(m_local_clock->GetSystemClockContext(&context));
|
||||||
|
|
||||||
|
m_set_sys->SetUserSystemClockContext(context);
|
||||||
|
m_file_timestamp_worker.SetFilesystemPosixTime();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EventType::UpdateNetworkSystemClock: {
|
||||||
|
m_network_clock_event->Clear(m_system.Kernel());
|
||||||
|
|
||||||
|
Service::PSC::Time::SystemClockContext context{};
|
||||||
|
R_ASSERT(m_network_clock->GetSystemClockContext(&context));
|
||||||
|
|
||||||
|
m_set_sys->SetNetworkSystemClockContext(context);
|
||||||
|
|
||||||
|
s64 time{};
|
||||||
|
if (m_network_clock->GetCurrentTime(&time) != ResultSuccess) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] auto offset_before{
|
||||||
|
m_ig_report_network_clock_context_set ? m_report_network_clock_context.offset : 0};
|
||||||
|
// TODO system report "standard_netclock_operation"
|
||||||
|
// "clock_time" = time
|
||||||
|
// "context_offset_before" = offset_before
|
||||||
|
// "context_offset_after" = context.offset
|
||||||
|
m_report_network_clock_context = context;
|
||||||
|
if (!m_ig_report_network_clock_context_set) {
|
||||||
|
m_ig_report_network_clock_context_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_file_timestamp_worker.SetFilesystemPosixTime();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EventType::UpdateEphemeralSystemClock: {
|
||||||
|
m_ephemeral_clock_event->Clear(m_system.Kernel());
|
||||||
|
|
||||||
|
Service::PSC::Time::SystemClockContext context{};
|
||||||
|
auto res = m_ephemeral_clock->GetSystemClockContext(&context);
|
||||||
|
if (res != ResultSuccess) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 time{};
|
||||||
|
res = m_ephemeral_clock->GetCurrentTime(&time);
|
||||||
|
if (res != ResultSuccess) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] auto offset_before{m_ig_report_ephemeral_clock_context_set
|
||||||
|
? m_report_ephemeral_clock_context.offset
|
||||||
|
: 0};
|
||||||
|
// TODO system report "ephemeral_netclock_operation"
|
||||||
|
// "clock_time" = time
|
||||||
|
// "context_offset_before" = offset_before
|
||||||
|
// "context_offset_after" = context.offset
|
||||||
|
m_report_ephemeral_clock_context = context;
|
||||||
|
if (!m_ig_report_ephemeral_clock_context_set) {
|
||||||
|
m_ig_report_ephemeral_clock_context_set = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EventType::UpdateSteadyClock:
|
||||||
|
m_timer_steady_clock->Clear(m_system.Kernel());
|
||||||
|
|
||||||
|
m_steady_clock_resource.UpdateTime();
|
||||||
|
m_time_m->SetStandardSteadyClockBaseTime(m_steady_clock_resource.GetTime());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EventType::UpdateFileTimestamp:
|
||||||
|
m_timer_file_system->Clear(m_system.Kernel());
|
||||||
|
|
||||||
|
m_file_timestamp_worker.SetFilesystemPosixTime();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EventType::AutoCorrect: {
|
||||||
|
m_standard_user_auto_correct_clock_event->Clear(m_system.Kernel());
|
||||||
|
|
||||||
|
bool automatic_correction{};
|
||||||
|
R_ASSERT(m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||||
|
&automatic_correction));
|
||||||
|
|
||||||
|
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||||
|
R_ASSERT(
|
||||||
|
m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point));
|
||||||
|
|
||||||
|
m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
|
||||||
|
m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Glue::Time
|
} // namespace Service::Glue::Time
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -36,6 +33,7 @@ public:
|
|||||||
|
|
||||||
void StartThread();
|
void StartThread();
|
||||||
|
|
||||||
|
private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T GetSettingsItemValue(const std::string& category, const std::string& name);
|
T GetSettingsItemValue(const std::string& category, const std::string& name);
|
||||||
|
|
||||||
|
|||||||
@@ -253,13 +253,6 @@ void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_thre
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Notifies that the system is shutting down (pre-emptively terminate threads)
|
|
||||||
void ServerManager::NotifyShutdown() {
|
|
||||||
m_stop_source.request_stop();
|
|
||||||
// Wake them up regardless
|
|
||||||
m_wakeup_event->Signal(m_system.Kernel());
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ServerManager::LoopProcess() {
|
Result ServerManager::LoopProcess() {
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT {
|
||||||
m_stopped.Set();
|
m_stopped.Set();
|
||||||
@@ -292,8 +285,9 @@ MultiWaitHolder* ServerManager::WaitSignaled() {
|
|||||||
this->LinkDeferred();
|
this->LinkDeferred();
|
||||||
|
|
||||||
// If we're done, return before we start waiting.
|
// If we're done, return before we start waiting.
|
||||||
if (m_stop_source.stop_requested())
|
if (m_stop_source.stop_requested()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto* selected = m_multi_wait.WaitAny(m_system.Kernel());
|
auto* selected = m_multi_wait.WaitAny(m_system.Kernel());
|
||||||
if (selected == std::addressof(*m_wakeup_holder)) {
|
if (selected == std::addressof(*m_wakeup_holder)) {
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -52,7 +49,6 @@ public:
|
|||||||
|
|
||||||
Result LoopProcess();
|
Result LoopProcess();
|
||||||
void StartAdditionalHostThreads(const char* name, size_t num_threads);
|
void StartAdditionalHostThreads(const char* name, size_t num_threads);
|
||||||
void NotifyShutdown();
|
|
||||||
|
|
||||||
static void RunServer(std::unique_ptr<ServerManager>&& server);
|
static void RunServer(std::unique_ptr<ServerManager>&& server);
|
||||||
|
|
||||||
|
|||||||
@@ -94,9 +94,6 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
|||||||
{"ldn", &LDN::LoopProcess},
|
{"ldn", &LDN::LoopProcess},
|
||||||
{"nvservices", &Nvidia::LoopProcess},
|
{"nvservices", &Nvidia::LoopProcess},
|
||||||
{"bsdsocket", &Sockets::LoopProcess},
|
{"bsdsocket", &Sockets::LoopProcess},
|
||||||
// TODO: glue is only required here as otherwise the dummythread doesn't close
|
|
||||||
// TODO: rework sched so this isn't needed
|
|
||||||
{"glue", &Glue::LoopProcess},
|
|
||||||
})
|
})
|
||||||
kernel.RunOnHostCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); }).detach();
|
kernel.RunOnHostCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); }).detach();
|
||||||
kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach();
|
kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach();
|
||||||
@@ -120,6 +117,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
|||||||
{"friends", &Friend::LoopProcess},
|
{"friends", &Friend::LoopProcess},
|
||||||
{"settings", &Set::LoopProcess},
|
{"settings", &Set::LoopProcess},
|
||||||
{"psc", &PSC::LoopProcess},
|
{"psc", &PSC::LoopProcess},
|
||||||
|
{"glue", &Glue::LoopProcess},
|
||||||
{"grc", &GRC::LoopProcess},
|
{"grc", &GRC::LoopProcess},
|
||||||
{"hid", &HID::LoopProcess},
|
{"hid", &HID::LoopProcess},
|
||||||
{"jit", &JIT::LoopProcess},
|
{"jit", &JIT::LoopProcess},
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
|
||||||
#include "core/hle/service/vi/conductor.h"
|
#include "core/hle/service/vi/conductor.h"
|
||||||
#include "core/hle/service/vi/container.h"
|
#include "core/hle/service/vi/container.h"
|
||||||
#include "core/hle/service/vi/display_list.h"
|
#include "core/hle/service/vi/display_list.h"
|
||||||
@@ -39,18 +38,7 @@ Conductor::Conductor(Core::System& system, Container& container, DisplayList& di
|
|||||||
});
|
});
|
||||||
|
|
||||||
system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
|
system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
|
||||||
m_thread = system.Kernel().RunOnHostCoreThread("VSyncThread", [this]() {
|
m_thread = std::jthread([this](std::stop_token token) { this->VsyncThread(token); });
|
||||||
auto const stop_token = m_thread.get_stop_token();
|
|
||||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::VeryHigh);
|
|
||||||
Common::SetCurrentThreadToPerformanceCores();
|
|
||||||
while (!stop_token.stop_requested()) {
|
|
||||||
m_signal.Wait();
|
|
||||||
if (stop_token.stop_requested() || m_system.IsShuttingDown()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this->ProcessVsync();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
m_event = Core::Timing::CreateEvent(
|
m_event = Core::Timing::CreateEvent(
|
||||||
"ScreenComposition",
|
"ScreenComposition",
|
||||||
@@ -66,10 +54,10 @@ Conductor::Conductor(Core::System& system, Container& container, DisplayList& di
|
|||||||
|
|
||||||
Conductor::~Conductor() {
|
Conductor::~Conductor() {
|
||||||
m_system.CoreTiming().UnscheduleEvent(m_event);
|
m_system.CoreTiming().UnscheduleEvent(m_event);
|
||||||
if (m_thread.joinable()) {
|
|
||||||
|
if (m_system.IsMulticore()) {
|
||||||
m_thread.request_stop();
|
m_thread.request_stop();
|
||||||
m_signal.Set();
|
m_signal.Set();
|
||||||
m_thread.join();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +83,22 @@ void Conductor::ProcessVsync() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Conductor::VsyncThread(std::stop_token token) {
|
||||||
|
Common::SetCurrentThreadName("VSyncThread");
|
||||||
|
Common::SetCurrentThreadPriority(Common::ThreadPriority::VeryHigh);
|
||||||
|
Common::SetCurrentThreadToPerformanceCores();
|
||||||
|
|
||||||
|
while (!token.stop_requested()) {
|
||||||
|
m_signal.Wait();
|
||||||
|
|
||||||
|
if (m_system.IsShuttingDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->ProcessVsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s64 Conductor::GetNextTicks() const {
|
s64 Conductor::GetNextTicks() const {
|
||||||
const auto& settings = Settings::values;
|
const auto& settings = Settings::values;
|
||||||
auto speed_scale = 1.f;
|
auto speed_scale = 1.f;
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
// 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
|
||||||
|
|
||||||
// gcc14 bug
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "core/memory/dmnt_cheat_types.h"
|
#include "core/memory/dmnt_cheat_types.h"
|
||||||
@@ -232,10 +223,7 @@ DmntCheatVm::Callbacks::~Callbacks() = default;
|
|||||||
bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
|
bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
|
||||||
// If we've ever seen a decode failure, return false.
|
// If we've ever seen a decode failure, return false.
|
||||||
bool valid = decode_success;
|
bool valid = decode_success;
|
||||||
CheatVmOpcode opcode = {
|
CheatVmOpcode opcode = {};
|
||||||
.begin_conditional_block = false,
|
|
||||||
.opcode = {}
|
|
||||||
};
|
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT {
|
||||||
decode_success &= valid;
|
decode_success &= valid;
|
||||||
if (valid) {
|
if (valid) {
|
||||||
@@ -1278,8 +1266,3 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Memory
|
} // namespace Core::Memory
|
||||||
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
@@ -254,16 +254,14 @@ struct UnrecognizedInstruction {
|
|||||||
|
|
||||||
struct CheatVmOpcode {
|
struct CheatVmOpcode {
|
||||||
bool begin_conditional_block{};
|
bool begin_conditional_block{};
|
||||||
std::variant<
|
std::variant<StoreStaticOpcode, BeginConditionalOpcode, EndConditionalOpcode, ControlLoopOpcode,
|
||||||
std::monostate,
|
LoadRegisterStaticOpcode, LoadRegisterMemoryOpcode, StoreStaticToAddressOpcode,
|
||||||
StoreStaticOpcode, BeginConditionalOpcode, EndConditionalOpcode, ControlLoopOpcode,
|
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
|
||||||
LoadRegisterStaticOpcode, LoadRegisterMemoryOpcode, StoreStaticToAddressOpcode,
|
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
|
||||||
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
|
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
|
||||||
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
|
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode,
|
||||||
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
|
ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction>
|
||||||
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode,
|
opcode{};
|
||||||
ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction
|
|
||||||
> opcode{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DmntCheatVm {
|
class DmntCheatVm {
|
||||||
|
|||||||
@@ -170,19 +170,13 @@ template<>
|
|||||||
|
|
||||||
// check for marked bit, use as unmapped if marked
|
// check for marked bit, use as unmapped if marked
|
||||||
if (ctx.conf.page_table_marked_bit) {
|
if (ctx.conf.page_table_marked_bit) {
|
||||||
auto const marked_bit = *ctx.conf.page_table_marked_bit;
|
code.bt(page, *ctx.conf.page_table_marked_bit);
|
||||||
if (s64(s32(1 << marked_bit)) == s64(1 << marked_bit)) {
|
code.jc(abort, code.T_NEAR);
|
||||||
code.test(page, s32(1 << marked_bit));
|
|
||||||
code.jnz(abort, code.T_NEAR);
|
|
||||||
} else {
|
|
||||||
code.bt(page, marked_bit);
|
|
||||||
code.jc(abort, code.T_NEAR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// mask away attributes
|
// mask away attributes
|
||||||
if (ctx.conf.page_table_pointer_mask == 0) {
|
if (ctx.conf.page_table_pointer_mask == 0) {
|
||||||
code.test(page, page);
|
code.test(page, page);
|
||||||
} else if (s64(s32(ctx.conf.page_table_pointer_mask)) == s64(ctx.conf.page_table_pointer_mask)) {
|
} else if (std::in_range<s32>(ctx.conf.page_table_pointer_mask)) {
|
||||||
code.and_(page, ctx.conf.page_table_pointer_mask);
|
code.and_(page, ctx.conf.page_table_pointer_mask);
|
||||||
} else {
|
} else {
|
||||||
code.mov(tmp, ctx.conf.page_table_pointer_mask);
|
code.mov(tmp, ctx.conf.page_table_pointer_mask);
|
||||||
|
|||||||
@@ -79,10 +79,8 @@ void NpadAbstractButtonHandler::UpdateAllButtonLifo() {
|
|||||||
Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
|
Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
|
||||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||||
auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
|
auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
|
||||||
if (auto const shfmt = data->shared_memory_format; shfmt) {
|
auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
||||||
auto& npad_entry = shfmt->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
UpdateButtonLifo(npad_entry, data->aruid);
|
||||||
UpdateButtonLifo(npad_entry, data->aruid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,19 +88,19 @@ void NpadAbstractButtonHandler::UpdateCoreBatteryState() {
|
|||||||
Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
|
Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
|
||||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||||
auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
|
auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
|
||||||
if (auto const shfmt = data->shared_memory_format; shfmt) {
|
auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
||||||
auto& npad_entry = shfmt->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
UpdateButtonLifo(npad_entry, data->aruid);
|
||||||
UpdateButtonLifo(npad_entry, data->aruid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpadAbstractButtonHandler::UpdateButtonState(u64 aruid) {
|
void NpadAbstractButtonHandler::UpdateButtonState(u64 aruid) {
|
||||||
Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
|
Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
|
||||||
if (auto data = applet_resource_holder->applet_resource->GetAruidData(aruid); data) {
|
auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid);
|
||||||
auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
if (data == nullptr) {
|
||||||
UpdateButtonLifo(npad_entry, aruid);
|
return;
|
||||||
}
|
}
|
||||||
|
auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
||||||
|
UpdateButtonLifo(npad_entry, aruid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result NpadAbstractButtonHandler::SetHomeProtection(bool is_enabled, u64 aruid) {
|
Result NpadAbstractButtonHandler::SetHomeProtection(bool is_enabled, u64 aruid) {
|
||||||
|
|||||||
@@ -496,30 +496,31 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
|
void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
|
||||||
// Flatten all leading PHIs from each block into a vector
|
// Flatten all leading PHIs from each block into a vector
|
||||||
std::vector<IR::Inst*> phi_instructions;
|
std::vector<IR::Inst*> phi_instructions;
|
||||||
for (IR::Block* block : program.blocks) {
|
for (IR::Block* block : program.blocks) {
|
||||||
for (auto it = block->begin(); it != block->end(); ++it) {
|
for (auto it = block->begin(); it != block->end(); ++it) {
|
||||||
if (it->GetOpcode() != IR::Opcode::Phi)
|
if (it->GetOpcode() != IR::Opcode::Phi)
|
||||||
break;
|
break;
|
||||||
phi_instructions.push_back(&*it);
|
phi_instructions.push_back(&*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phi_instructions.empty()) {
|
if (phi_instructions.empty()) {
|
||||||
return; // nothing to patch
|
return; // nothing to patch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start "before" first PHI; advance on phi_arg == 0
|
// Start "before" first PHI; advance on phi_arg == 0
|
||||||
size_t phi_index = size_t(-1);
|
size_t phi_index = static_cast<size_t>(-1);
|
||||||
ctx.PatchDeferredPhi([&ctx, &phi_index, phi_insts = std::move(phi_instructions)](size_t phi_arg, Id parent) -> std::pair<Id, Id> {
|
|
||||||
if (phi_arg == 0) {
|
ctx.PatchDeferredPhi([&](size_t phi_arg, Id parent) -> std::pair<Id, Id> {
|
||||||
++phi_index;
|
if (phi_arg == 0) {
|
||||||
|
++phi_index;
|
||||||
|
}
|
||||||
|
IR::Inst* phi = phi_instructions[phi_index];
|
||||||
|
return { ctx.Def(phi->Arg(phi_arg)), parent };
|
||||||
|
});
|
||||||
}
|
}
|
||||||
IR::Inst* phi = phi_insts[phi_index];
|
|
||||||
return { ctx.Def(phi->Arg(phi_arg)), parent };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, Bindings& bindings) {
|
std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, Bindings& bindings) {
|
||||||
|
|||||||
Reference in New Issue
Block a user