aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/core.cpp11
-rw-r--r--src/core/core.h6
-rw-r--r--src/core/frontend/emu_window.h3
-rw-r--r--src/core/frontend/framebuffer_layout.h1
-rw-r--r--src/core/frontend/scope_acquire_context.cpp18
-rw-r--r--src/core/frontend/scope_acquire_context.h (renamed from src/core/frontend/scope_acquire_window_context.h)10
-rw-r--r--src/core/frontend/scope_acquire_window_context.cpp18
-rw-r--r--src/core/hardware_properties.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp121
-rw-r--r--src/core/hle/kernel/kernel.h37
-rw-r--r--src/core/hle/kernel/scheduler.cpp56
-rw-r--r--src/core/hle/kernel/scheduler.h46
-rw-r--r--src/core/hle/kernel/thread.cpp12
-rw-r--r--src/core/hle/kernel/thread.h6
-rw-r--r--src/core/hle/kernel/time_manager.cpp44
-rw-r--r--src/core/hle/kernel/time_manager.h43
-rw-r--r--src/core/hle/service/am/am.cpp15
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp10
-rw-r--r--src/core/settings.cpp1
-rw-r--r--src/core/settings.h1
-rw-r--r--src/core/telemetry_session.cpp1
23 files changed, 400 insertions, 69 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 26612e692..54be7dc0c 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -131,8 +131,8 @@ add_library(core STATIC
frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h
frontend/input.h
- frontend/scope_acquire_window_context.cpp
- frontend/scope_acquire_window_context.h
+ frontend/scope_acquire_context.cpp
+ frontend/scope_acquire_context.h
gdbstub/gdbstub.cpp
gdbstub/gdbstub.h
hardware_interrupt_manager.cpp
@@ -187,6 +187,8 @@ add_library(core STATIC
hle/kernel/synchronization.h
hle/kernel/thread.cpp
hle/kernel/thread.h
+ hle/kernel/time_manager.cpp
+ hle/kernel/time_manager.h
hle/kernel/transfer_memory.cpp
hle/kernel/transfer_memory.h
hle/kernel/vm_manager.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 0eb0c0dca..a82faf127 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -24,6 +24,7 @@
#include "core/file_sys/sdmc_factory.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
+#include "core/frontend/scope_acquire_context.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hardware_interrupt_manager.h"
#include "core/hle/kernel/client_port.h"
@@ -184,6 +185,8 @@ struct System::Impl {
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath) {
+ Core::Frontend::ScopeAcquireContext acquire_context{emu_window};
+
app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
@@ -707,4 +710,12 @@ const Service::SM::ServiceManager& System::ServiceManager() const {
return *impl->service_manager;
}
+void System::RegisterCoreThread(std::size_t id) {
+ impl->kernel.RegisterCoreThread(id);
+}
+
+void System::RegisterHostThread() {
+ impl->kernel.RegisterHostThread();
+}
+
} // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index e69d68fcf..8d862a8e6 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -360,6 +360,12 @@ public:
const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
+ /// Register a host thread as an emulated CPU Core.
+ void RegisterCoreThread(std::size_t id);
+
+ /// Register a host thread as an auxiliary thread.
+ void RegisterHostThread();
+
private:
System();
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 3376eedc5..5eb87fb63 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -26,9 +26,6 @@ public:
/// Releases (dunno if this is the "right" word) the context from the caller thread
virtual void DoneCurrent() = 0;
-
- /// Swap buffers to display the next frame
- virtual void SwapBuffers() = 0;
};
/**
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h
index 1d39c1faf..e9d0a40d3 100644
--- a/src/core/frontend/framebuffer_layout.h
+++ b/src/core/frontend/framebuffer_layout.h
@@ -29,6 +29,7 @@ enum class AspectRatio {
struct FramebufferLayout {
u32 width{ScreenUndocked::Width};
u32 height{ScreenUndocked::Height};
+ bool is_srgb{};
Common::Rectangle<u32> screen;
diff --git a/src/core/frontend/scope_acquire_context.cpp b/src/core/frontend/scope_acquire_context.cpp
new file mode 100644
index 000000000..878c3157c
--- /dev/null
+++ b/src/core/frontend/scope_acquire_context.cpp
@@ -0,0 +1,18 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/frontend/emu_window.h"
+#include "core/frontend/scope_acquire_context.h"
+
+namespace Core::Frontend {
+
+ScopeAcquireContext::ScopeAcquireContext(Core::Frontend::GraphicsContext& context)
+ : context{context} {
+ context.MakeCurrent();
+}
+ScopeAcquireContext::~ScopeAcquireContext() {
+ context.DoneCurrent();
+}
+
+} // namespace Core::Frontend
diff --git a/src/core/frontend/scope_acquire_window_context.h b/src/core/frontend/scope_acquire_context.h
index 2d9f6e825..7a65c0623 100644
--- a/src/core/frontend/scope_acquire_window_context.h
+++ b/src/core/frontend/scope_acquire_context.h
@@ -8,16 +8,16 @@
namespace Core::Frontend {
-class EmuWindow;
+class GraphicsContext;
/// Helper class to acquire/release window context within a given scope
-class ScopeAcquireWindowContext : NonCopyable {
+class ScopeAcquireContext : NonCopyable {
public:
- explicit ScopeAcquireWindowContext(Core::Frontend::EmuWindow& window);
- ~ScopeAcquireWindowContext();
+ explicit ScopeAcquireContext(Core::Frontend::GraphicsContext& context);
+ ~ScopeAcquireContext();
private:
- Core::Frontend::EmuWindow& emu_window;
+ Core::Frontend::GraphicsContext& context;
};
} // namespace Core::Frontend
diff --git a/src/core/frontend/scope_acquire_window_context.cpp b/src/core/frontend/scope_acquire_window_context.cpp
deleted file mode 100644
index 3663dad17..000000000
--- a/src/core/frontend/scope_acquire_window_context.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2019 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/frontend/emu_window.h"
-#include "core/frontend/scope_acquire_window_context.h"
-
-namespace Core::Frontend {
-
-ScopeAcquireWindowContext::ScopeAcquireWindowContext(Core::Frontend::EmuWindow& emu_window_)
- : emu_window{emu_window_} {
- emu_window.MakeCurrent();
-}
-ScopeAcquireWindowContext::~ScopeAcquireWindowContext() {
- emu_window.DoneCurrent();
-}
-
-} // namespace Core::Frontend
diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h
index 213461b6a..b04e046ed 100644
--- a/src/core/hardware_properties.h
+++ b/src/core/hardware_properties.h
@@ -20,6 +20,8 @@ constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
} // namespace Hardware
+constexpr u32 INVALID_HOST_THREAD_ID = 0xFFFFFFFF;
+
struct EmuThreadHandle {
u32 host_handle;
u32 guest_handle;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4eb1d8703..9232f4d7e 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -3,9 +3,12 @@
// Refer to the license.txt file included.
#include <atomic>
+#include <bitset>
#include <functional>
#include <memory>
#include <mutex>
+#include <thread>
+#include <unordered_map>
#include <utility>
#include "common/assert.h"
@@ -15,6 +18,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
@@ -25,6 +29,7 @@
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/synchronization.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/time_manager.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/memory.h"
@@ -44,7 +49,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
std::lock_guard lock{HLE::g_hle_lock};
std::shared_ptr<Thread> thread =
- system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle);
+ system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
if (thread == nullptr) {
LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
return;
@@ -97,8 +102,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
}
struct KernelCore::Impl {
- explicit Impl(Core::System& system)
- : system{system}, global_scheduler{system}, synchronization{system} {}
+ explicit Impl(Core::System& system, KernelCore& kernel)
+ : system{system}, global_scheduler{kernel}, synchronization{system}, time_manager{system} {}
void Initialize(KernelCore& kernel) {
Shutdown();
@@ -120,7 +125,7 @@ struct KernelCore::Impl {
system_resource_limit = nullptr;
- thread_wakeup_callback_handle_table.Clear();
+ global_handle_table.Clear();
thread_wakeup_event_type = nullptr;
preemption_event = nullptr;
@@ -138,8 +143,8 @@ struct KernelCore::Impl {
void InitializePhysicalCores() {
exclusive_monitor =
- Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount());
- for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) {
+ Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
+ for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
cores.emplace_back(system, i, *exclusive_monitor);
}
}
@@ -184,6 +189,50 @@ struct KernelCore::Impl {
system.Memory().SetCurrentPageTable(*process);
}
+ void RegisterCoreThread(std::size_t core_id) {
+ std::unique_lock lock{register_thread_mutex};
+ const std::thread::id this_id = std::this_thread::get_id();
+ const auto it = host_thread_ids.find(this_id);
+ ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
+ ASSERT(it == host_thread_ids.end());
+ ASSERT(!registered_core_threads[core_id]);
+ host_thread_ids[this_id] = static_cast<u32>(core_id);
+ registered_core_threads.set(core_id);
+ }
+
+ void RegisterHostThread() {
+ std::unique_lock lock{register_thread_mutex};
+ const std::thread::id this_id = std::this_thread::get_id();
+ const auto it = host_thread_ids.find(this_id);
+ ASSERT(it == host_thread_ids.end());
+ host_thread_ids[this_id] = registered_thread_ids++;
+ }
+
+ u32 GetCurrentHostThreadID() const {
+ const std::thread::id this_id = std::this_thread::get_id();
+ const auto it = host_thread_ids.find(this_id);
+ if (it == host_thread_ids.end()) {
+ return Core::INVALID_HOST_THREAD_ID;
+ }
+ return it->second;
+ }
+
+ Core::EmuThreadHandle GetCurrentEmuThreadID() const {
+ Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
+ result.host_handle = GetCurrentHostThreadID();
+ if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) {
+ return result;
+ }
+ const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler();
+ const Kernel::Thread* current = sched.GetCurrentThread();
+ if (current != nullptr) {
+ result.guest_handle = current->GetGlobalHandle();
+ } else {
+ result.guest_handle = InvalidHandle;
+ }
+ return result;
+ }
+
std::atomic<u32> next_object_id{0};
std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
@@ -194,15 +243,16 @@ struct KernelCore::Impl {
Process* current_process = nullptr;
Kernel::GlobalScheduler global_scheduler;
Kernel::Synchronization synchronization;
+ Kernel::TimeManager time_manager;
std::shared_ptr<ResourceLimit> system_resource_limit;
std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type;
std::shared_ptr<Core::Timing::EventType> preemption_event;
- // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
- // allowing us to simply use a pool index or similar.
- Kernel::HandleTable thread_wakeup_callback_handle_table;
+ // This is the kernel's handle table or supervisor handle table which
+ // stores all the objects in place.
+ Kernel::HandleTable global_handle_table;
/// Map of named ports managed by the kernel, which can be retrieved using
/// the ConnectToPort SVC.
@@ -211,11 +261,17 @@ struct KernelCore::Impl {
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::vector<Kernel::PhysicalCore> cores;
+ // 0-3 IDs represent core threads, >3 represent others
+ std::unordered_map<std::thread::id, u32> host_thread_ids;
+ u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
+ std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
+ std::mutex register_thread_mutex;
+
// System context
Core::System& system;
};
-KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system)} {}
+KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {}
KernelCore::~KernelCore() {
Shutdown();
}
@@ -232,9 +288,8 @@ std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
return impl->system_resource_limit;
}
-std::shared_ptr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(
- Handle handle) const {
- return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle);
+std::shared_ptr<Thread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
+ return impl->global_handle_table.Get<Thread>(handle);
}
void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
@@ -265,6 +320,14 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const {
return impl->global_scheduler;
}
+Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) {
+ return impl->cores[id].Scheduler();
+}
+
+const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const {
+ return impl->cores[id].Scheduler();
+}
+
Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
return impl->cores[id];
}
@@ -281,6 +344,14 @@ const Kernel::Synchronization& KernelCore::Synchronization() const {
return impl->synchronization;
}
+Kernel::TimeManager& KernelCore::TimeManager() {
+ return impl->time_manager;
+}
+
+const Kernel::TimeManager& KernelCore::TimeManager() const {
+ return impl->time_manager;
+}
+
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
return *impl->exclusive_monitor;
}
@@ -338,12 +409,28 @@ const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallback
return impl->thread_wakeup_event_type;
}
-Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() {
- return impl->thread_wakeup_callback_handle_table;
+Kernel::HandleTable& KernelCore::GlobalHandleTable() {
+ return impl->global_handle_table;
+}
+
+const Kernel::HandleTable& KernelCore::GlobalHandleTable() const {
+ return impl->global_handle_table;
+}
+
+void KernelCore::RegisterCoreThread(std::size_t core_id) {
+ impl->RegisterCoreThread(core_id);
+}
+
+void KernelCore::RegisterHostThread() {
+ impl->RegisterHostThread();
+}
+
+u32 KernelCore::GetCurrentHostThreadID() const {
+ return impl->GetCurrentHostThreadID();
}
-const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const {
- return impl->thread_wakeup_callback_handle_table;
+Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const {
+ return impl->GetCurrentEmuThreadID();
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 1eede3063..c4f78ab71 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,6 +11,7 @@
#include "core/hle/kernel/object.h"
namespace Core {
+struct EmuThreadHandle;
class ExclusiveMonitor;
class System;
} // namespace Core
@@ -29,8 +30,10 @@ class HandleTable;
class PhysicalCore;
class Process;
class ResourceLimit;
+class Scheduler;
class Synchronization;
class Thread;
+class TimeManager;
/// Represents a single instance of the kernel.
class KernelCore {
@@ -64,7 +67,7 @@ public:
std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const;
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
- std::shared_ptr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
+ std::shared_ptr<Thread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
/// Adds the given shared pointer to an internal list of active processes.
void AppendNewProcess(std::shared_ptr<Process> process);
@@ -87,6 +90,12 @@ public:
/// Gets the sole instance of the global scheduler
const Kernel::GlobalScheduler& GlobalScheduler() const;
+ /// Gets the sole instance of the Scheduler assoviated with cpu core 'id'
+ Kernel::Scheduler& Scheduler(std::size_t id);
+
+ /// Gets the sole instance of the Scheduler assoviated with cpu core 'id'
+ const Kernel::Scheduler& Scheduler(std::size_t id) const;
+
/// Gets the an instance of the respective physical CPU core.
Kernel::PhysicalCore& PhysicalCore(std::size_t id);
@@ -99,6 +108,12 @@ public:
/// Gets the an instance of the Synchronization Interface.
const Kernel::Synchronization& Synchronization() const;
+ /// Gets the an instance of the TimeManager Interface.
+ Kernel::TimeManager& TimeManager();
+
+ /// Gets the an instance of the TimeManager Interface.
+ const Kernel::TimeManager& TimeManager() const;
+
/// Stops execution of 'id' core, in order to reschedule a new thread.
void PrepareReschedule(std::size_t id);
@@ -120,6 +135,18 @@ public:
/// Determines whether or not the given port is a valid named port.
bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
+ /// Gets the current host_thread/guest_thread handle.
+ Core::EmuThreadHandle GetCurrentEmuThreadID() const;
+
+ /// Gets the current host_thread handle.
+ u32 GetCurrentHostThreadID() const;
+
+ /// Register the current thread as a CPU Core Thread.
+ void RegisterCoreThread(std::size_t core_id);
+
+ /// Register the current thread as a non CPU core thread.
+ void RegisterHostThread();
+
private:
friend class Object;
friend class Process;
@@ -140,11 +167,11 @@ private:
/// Retrieves the event type used for thread wakeup callbacks.
const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const;
- /// Provides a reference to the thread wakeup callback handle table.
- Kernel::HandleTable& ThreadWakeupCallbackHandleTable();
+ /// Provides a reference to the global handle table.
+ Kernel::HandleTable& GlobalHandleTable();
- /// Provides a const reference to the thread wakeup callback handle table.
- const Kernel::HandleTable& ThreadWakeupCallbackHandleTable() const;
+ /// Provides a const reference to the global handle table.
+ const Kernel::HandleTable& GlobalHandleTable() const;
struct Impl;
std::unique_ptr<Impl> impl;
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 86f1421bf..c65f82fb7 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -18,10 +18,11 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/time_manager.h"
namespace Kernel {
-GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {}
+GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {}
GlobalScheduler::~GlobalScheduler() = default;
@@ -35,7 +36,7 @@ void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) {
}
void GlobalScheduler::UnloadThread(std::size_t core) {
- Scheduler& sched = system.Scheduler(core);
+ Scheduler& sched = kernel.Scheduler(core);
sched.UnloadThread();
}
@@ -50,7 +51,7 @@ void GlobalScheduler::SelectThread(std::size_t core) {
sched.is_context_switch_pending = sched.selected_thread != sched.current_thread;
std::atomic_thread_fence(std::memory_order_seq_cst);
};
- Scheduler& sched = system.Scheduler(core);
+ Scheduler& sched = kernel.Scheduler(core);
Thread* current_thread = nullptr;
// Step 1: Get top thread in schedule queue.
current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front();
@@ -356,6 +357,32 @@ void GlobalScheduler::Shutdown() {
thread_list.clear();
}
+void GlobalScheduler::Lock() {
+ Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadID();
+ if (current_thread == current_owner) {
+ ++scope_lock;
+ } else {
+ inner_lock.lock();
+ current_owner = current_thread;
+ ASSERT(current_owner != Core::EmuThreadHandle::InvalidHandle());
+ scope_lock = 1;
+ }
+}
+
+void GlobalScheduler::Unlock() {
+ if (--scope_lock != 0) {
+ ASSERT(scope_lock > 0);
+ return;
+ }
+ for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
+ SelectThread(i);
+ }
+ current_owner = Core::EmuThreadHandle::InvalidHandle();
+ scope_lock = 1;
+ inner_lock.unlock();
+ // TODO(Blinkhawk): Setup the interrupts and change context on current core.
+}
+
Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id)
: system(system), cpu_core(cpu_core), core_id(core_id) {}
@@ -485,4 +512,27 @@ void Scheduler::Shutdown() {
selected_thread = nullptr;
}
+SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} {
+ kernel.GlobalScheduler().Lock();
+}
+
+SchedulerLock::~SchedulerLock() {
+ kernel.GlobalScheduler().Unlock();
+}
+
+SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle,
+ Thread* time_task, s64 nanoseconds)
+ : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{
+ nanoseconds} {
+ event_handle = InvalidHandle;
+}
+
+SchedulerLockAndSleep::~SchedulerLockAndSleep() {
+ if (sleep_cancelled) {
+ return;
+ }
+ auto& time_manager = kernel.TimeManager();
+ time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
+}
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 96db049cb..1c93a838c 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -6,6 +6,7 @@
#include <atomic>
#include <memory>
+#include <mutex>
#include <vector>
#include "common/common_types.h"
@@ -20,11 +21,13 @@ class System;
namespace Kernel {
+class KernelCore;
class Process;
+class SchedulerLock;
class GlobalScheduler final {
public:
- explicit GlobalScheduler(Core::System& system);
+ explicit GlobalScheduler(KernelCore& kernel);
~GlobalScheduler();
/// Adds a new thread to the scheduler
@@ -138,6 +141,14 @@ public:
void Shutdown();
private:
+ friend class SchedulerLock;
+
+ /// Lock the scheduler to the current thread.
+ void Lock();
+
+ /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling
+ /// and reschedules current core if needed.
+ void Unlock();
/**
* Transfers a thread into an specific core. If the destination_core is -1
* it will be unscheduled from its source code and added into its suggested
@@ -158,9 +169,14 @@ private:
// ordered from Core 0 to Core 3.
std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
+ /// Scheduler lock mechanisms.
+ std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock
+ std::atomic<s64> scope_lock{};
+ Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()};
+
/// Lists all thread ids that aren't deleted/etc.
std::vector<std::shared_ptr<Thread>> thread_list;
- Core::System& system;
+ KernelCore& kernel;
};
class Scheduler final {
@@ -227,4 +243,30 @@ private:
bool is_context_switch_pending = false;
};
+class SchedulerLock {
+public:
+ explicit SchedulerLock(KernelCore& kernel);
+ ~SchedulerLock();
+
+protected:
+ KernelCore& kernel;
+};
+
+class SchedulerLockAndSleep : public SchedulerLock {
+public:
+ explicit SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task,
+ s64 nanoseconds);
+ ~SchedulerLockAndSleep();
+
+ void CancelSleep() {
+ sleep_cancelled = true;
+ }
+
+private:
+ Handle& event_handle;
+ Thread* time_task;
+ s64 nanoseconds;
+ bool sleep_cancelled{};
+};
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index ae5f2c8bd..bf850e0b2 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -46,9 +46,9 @@ Thread::~Thread() = default;
void Thread::Stop() {
// Cancel any outstanding wakeup events for this thread
Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
- callback_handle);
- kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
- callback_handle = 0;
+ global_handle);
+ kernel.GlobalHandleTable().Close(global_handle);
+ global_handle = 0;
SetStatus(ThreadStatus::Dead);
Signal();
@@ -73,12 +73,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
// thread-safe version of ScheduleEvent.
const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
Core::System::GetInstance().CoreTiming().ScheduleEvent(
- cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle);
+ cycles, kernel.ThreadWakeupCallbackEventType(), global_handle);
}
void Thread::CancelWakeupTimer() {
Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
- callback_handle);
+ global_handle);
}
void Thread::ResumeFromWait() {
@@ -190,7 +190,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin
thread->condvar_wait_address = 0;
thread->wait_handle = 0;
thread->name = std::move(name);
- thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
+ thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap();
thread->owner_process = &owner_process;
auto& scheduler = kernel.GlobalScheduler();
scheduler.AddThread(thread);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 7a4916318..129e7858a 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -453,6 +453,10 @@ public:
is_sync_cancelled = value;
}
+ Handle GetGlobalHandle() const {
+ return global_handle;
+ }
+
private:
void SetSchedulingStatus(ThreadSchedStatus new_status);
void SetCurrentPriority(u32 new_priority);
@@ -514,7 +518,7 @@ private:
VAddr arb_wait_address{0};
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
- Handle callback_handle = 0;
+ Handle global_handle = 0;
/// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
/// was waiting via WaitSynchronization then the object will be the last object that became
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
new file mode 100644
index 000000000..21b290468
--- /dev/null
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -0,0 +1,44 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/core_timing_util.h"
+#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/time_manager.h"
+
+namespace Kernel {
+
+TimeManager::TimeManager(Core::System& system) : system{system} {
+ time_manager_event_type = Core::Timing::CreateEvent(
+ "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) {
+ Handle proper_handle = static_cast<Handle>(thread_handle);
+ std::shared_ptr<Thread> thread =
+ this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
+ thread->ResumeFromWait();
+ });
+}
+
+void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) {
+ if (nanoseconds > 0) {
+ ASSERT(timetask);
+ event_handle = timetask->GetGlobalHandle();
+ const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
+ system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle);
+ } else {
+ event_handle = InvalidHandle;
+ }
+}
+
+void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
+ if (event_handle == InvalidHandle) {
+ return;
+ }
+ system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle);
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h
new file mode 100644
index 000000000..eaec486d1
--- /dev/null
+++ b/src/core/hle/kernel/time_manager.h
@@ -0,0 +1,43 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+
+#include "core/hle/kernel/object.h"
+
+namespace Core {
+class System;
+} // namespace Core
+
+namespace Core::Timing {
+struct EventType;
+} // namespace Core::Timing
+
+namespace Kernel {
+
+class Thread;
+
+/**
+ * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp
+ * method when the event is triggered.
+ */
+class TimeManager {
+public:
+ explicit TimeManager(Core::System& system);
+
+ /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds'
+ /// returns a non-invalid handle in `event_handle` if correctly scheduled
+ void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds);
+
+ /// Unschedule an existing time event
+ void UnscheduleTimeEvent(Handle event_handle);
+
+private:
+ Core::System& system;
+ std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index cc978713b..d1bf13c89 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -607,7 +607,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system,
{40, nullptr, "GetCradleFwVersion"},
{50, nullptr, "IsVrModeEnabled"},
{51, nullptr, "SetVrModeEnabled"},
- {52, nullptr, "SwitchLcdBacklight"},
+ {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"},
{53, nullptr, "BeginVrModeEx"},
{54, nullptr, "EndVrModeEx"},
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
@@ -636,7 +636,6 @@ void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
-
rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
}
@@ -660,6 +659,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
return;
}
+
rb.Push(RESULT_SUCCESS);
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
}
@@ -672,6 +672,17 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u8>(FocusState::InFocus));
}
+void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
+
+ LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}",
+ is_lcd_backlight_off_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 0b9a4332d..0843de781 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -182,6 +182,7 @@ private:
void GetOperationMode(Kernel::HLERequestContext& ctx);
void GetPerformanceMode(Kernel::HLERequestContext& ctx);
void GetBootMode(Kernel::HLERequestContext& ctx);
+ void SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx);
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 15c09f04c..c1e32b28c 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -287,13 +287,13 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
Input::AnalogDirection::DOWN));
- pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
- pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
pad_state.r_stick_right.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
- ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
+ pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
+ pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
+ ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index d1fc94060..7c0303684 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -94,6 +94,7 @@ void LogSettings() {
LogSetting("Renderer_UseAccurateGpuEmulation", Settings::values.use_accurate_gpu_emulation);
LogSetting("Renderer_UseAsynchronousGpuEmulation",
Settings::values.use_asynchronous_gpu_emulation);
+ LogSetting("Renderer_UseVsync", Settings::values.use_vsync);
LogSetting("Audio_OutputEngine", Settings::values.sink_id);
LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching);
LogSetting("Audio_OutputDevice", Settings::values.audio_device_id);
diff --git a/src/core/settings.h b/src/core/settings.h
index f837d3fbc..15b691342 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -435,6 +435,7 @@ struct Values {
bool use_disk_shader_cache;
bool use_accurate_gpu_emulation;
bool use_asynchronous_gpu_emulation;
+ bool use_vsync;
bool force_30fps_mode;
float bg_red;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 0e72d31cd..0f3685d1c 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -188,6 +188,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
Settings::values.use_accurate_gpu_emulation);
AddField(field_type, "Renderer_UseAsynchronousGpuEmulation",
Settings::values.use_asynchronous_gpu_emulation);
+ AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync);
AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode);
}