summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp12
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h8
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp6
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h8
-rw-r--r--src/core/core.cpp21
-rw-r--r--src/core/core.h10
-rw-r--r--src/core/core_cpu.cpp15
-rw-r--r--src/core/core_cpu.h8
-rw-r--r--src/core/core_timing.cpp195
-rw-r--r--src/core/core_timing.h211
-rw-r--r--src/core/cpu_core_manager.cpp3
-rw-r--r--src/core/crypto/key_manager.cpp3
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp6
-rw-r--r--src/core/hle/kernel/address_arbiter.h6
-rw-r--r--src/core/hle/kernel/kernel.cpp12
-rw-r--r--src/core/hle/kernel/kernel.h9
-rw-r--r--src/core/hle/kernel/scheduler.cpp2
-rw-r--r--src/core/hle/kernel/svc.cpp10
-rw-r--r--src/core/hle/kernel/thread.cpp19
-rw-r--r--src/core/hle/service/audio/audout_u.cpp10
-rw-r--r--src/core/hle/service/audio/audren_u.cpp9
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h7
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h2
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h2
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h2
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/npad.h2
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h2
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp7
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h2
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h2
-rw-r--r--src/core/hle/service/hid/hid.cpp18
-rw-r--r--src/core/hle/service/hid/irs.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp110
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h58
-rw-r--r--src/core/hle/service/service.cpp5
-rw-r--r--src/core/hle/service/service.h15
-rw-r--r--src/core/hle/service/time/time.cpp7
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp71
-rw-r--r--src/core/hle/service/vi/display/vi_display.h98
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp13
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h52
-rw-r--r--src/core/hle/service/vi/vi.cpp26
52 files changed, 725 insertions, 405 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f61bcd40d..988356c65 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -400,6 +400,10 @@ add_library(core STATIC
hle/service/time/time.h
hle/service/usb/usb.cpp
hle/service/usb/usb.h
+ hle/service/vi/display/vi_display.cpp
+ hle/service/vi/display/vi_display.h
+ hle/service/vi/layer/vi_layer.cpp
+ hle/service/vi/layer/vi_layer.h
hle/service/vi/vi.cpp
hle/service/vi/vi.h
hle/service/vi/vi_m.cpp
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index f28951f8a..9b7ca4030 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -112,14 +112,14 @@ public:
// Always execute at least one tick.
amortized_ticks = std::max<u64>(amortized_ticks, 1);
- Timing::AddTicks(amortized_ticks);
+ parent.core_timing.AddTicks(amortized_ticks);
num_interpreted_instructions = 0;
}
u64 GetTicksRemaining() override {
- return std::max(Timing::GetDowncount(), 0);
+ return std::max(parent.core_timing.GetDowncount(), 0);
}
u64 GetCNTPCT() override {
- return Timing::GetTicks();
+ return parent.core_timing.GetTicks();
}
ARM_Dynarmic& parent;
@@ -172,8 +172,10 @@ void ARM_Dynarmic::Step() {
cb->InterpreterFallback(jit->GetPC(), 1);
}
-ARM_Dynarmic::ARM_Dynarmic(ExclusiveMonitor& exclusive_monitor, std::size_t core_index)
- : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index},
+ARM_Dynarmic::ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
+ std::size_t core_index)
+ : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{core_timing},
+ core_index{core_index}, core_timing{core_timing},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {
ThreadContext ctx{};
inner_unicorn.SaveContext(ctx);
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 512bf8ce9..6cc458296 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -16,6 +16,10 @@ namespace Memory {
struct PageTable;
}
+namespace Core::Timing {
+class CoreTiming;
+}
+
namespace Core {
class ARM_Dynarmic_Callbacks;
@@ -23,7 +27,8 @@ class DynarmicExclusiveMonitor;
class ARM_Dynarmic final : public ARM_Interface {
public:
- ARM_Dynarmic(ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
+ ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
+ std::size_t core_index);
~ARM_Dynarmic();
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
@@ -62,6 +67,7 @@ private:
ARM_Unicorn inner_unicorn;
std::size_t core_index;
+ Timing::CoreTiming& core_timing;
DynarmicExclusiveMonitor& exclusive_monitor;
Memory::PageTable* current_page_table = nullptr;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index c36c15c02..a542a098b 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -72,7 +72,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
return {};
}
-ARM_Unicorn::ARM_Unicorn() {
+ARM_Unicorn::ARM_Unicorn(Timing::CoreTiming& core_timing) : core_timing{core_timing} {
CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
auto fpv = 3 << 20;
@@ -177,7 +177,7 @@ void ARM_Unicorn::Run() {
if (GDBStub::IsServerEnabled()) {
ExecuteInstructions(std::max(4000000, 0));
} else {
- ExecuteInstructions(std::max(Timing::GetDowncount(), 0));
+ ExecuteInstructions(std::max(core_timing.GetDowncount(), 0));
}
}
@@ -190,7 +190,7 @@ MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
- Timing::AddTicks(num_instructions);
+ core_timing.AddTicks(num_instructions);
if (GDBStub::IsServerEnabled()) {
if (last_bkpt_hit) {
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index 75761950b..dbd6955ea 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -9,12 +9,17 @@
#include "core/arm/arm_interface.h"
#include "core/gdbstub/gdbstub.h"
+namespace Core::Timing {
+class CoreTiming;
+}
+
namespace Core {
class ARM_Unicorn final : public ARM_Interface {
public:
- ARM_Unicorn();
+ explicit ARM_Unicorn(Timing::CoreTiming& core_timing);
~ARM_Unicorn();
+
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
Kernel::VMAPermission perms) override;
void UnmapMemory(VAddr address, std::size_t size) override;
@@ -43,6 +48,7 @@ public:
private:
uc_engine* uc{};
+ Timing::CoreTiming& core_timing;
GDBStub::BreakpointAddress last_bkpt{};
bool last_bkpt_hit;
};
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 4d9d21ee4..ab7181a05 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -94,8 +94,8 @@ struct System::Impl {
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(HW_Memory, "initialized OK");
- Timing::Init();
- kernel.Initialize();
+ core_timing.Initialize();
+ kernel.Initialize(core_timing);
const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch());
@@ -120,7 +120,7 @@ struct System::Impl {
telemetry_session = std::make_unique<Core::TelemetrySession>();
service_manager = std::make_shared<Service::SM::ServiceManager>();
- Service::Init(service_manager, *virtual_filesystem);
+ Service::Init(service_manager, system, *virtual_filesystem);
GDBStub::Init();
renderer = VideoCore::CreateRenderer(emu_window, system);
@@ -128,7 +128,7 @@ struct System::Impl {
return ResultStatus::ErrorVideoCore;
}
- gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
+ gpu_core = std::make_unique<Tegra::GPU>(system, renderer->Rasterizer());
cpu_core_manager.Initialize(system);
is_powered_on = true;
@@ -205,7 +205,7 @@ struct System::Impl {
// Shutdown kernel and core timing
kernel.Shutdown();
- Timing::Shutdown();
+ core_timing.Shutdown();
// Close app loader
app_loader.reset();
@@ -232,9 +232,10 @@ struct System::Impl {
}
PerfStatsResults GetAndResetPerfStats() {
- return perf_stats.GetAndResetStats(Timing::GetGlobalTimeUs());
+ return perf_stats.GetAndResetStats(core_timing.GetGlobalTimeUs());
}
+ Timing::CoreTiming core_timing;
Kernel::KernelCore kernel;
/// RealVfsFilesystem instance
FileSys::VirtualFilesystem virtual_filesystem;
@@ -396,6 +397,14 @@ const Kernel::KernelCore& System::Kernel() const {
return impl->kernel;
}
+Timing::CoreTiming& System::CoreTiming() {
+ return impl->core_timing;
+}
+
+const Timing::CoreTiming& System::CoreTiming() const {
+ return impl->core_timing;
+}
+
Core::PerfStats& System::GetPerfStats() {
return impl->perf_stats;
}
diff --git a/src/core/core.h b/src/core/core.h
index 511a5ad3a..d720013f7 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -47,6 +47,10 @@ namespace VideoCore {
class RendererBase;
} // namespace VideoCore
+namespace Core::Timing {
+class CoreTiming;
+}
+
namespace Core {
class ARM_Interface;
@@ -205,6 +209,12 @@ public:
/// Provides a constant pointer to the current process.
const Kernel::Process* CurrentProcess() const;
+ /// Provides a reference to the core timing instance.
+ Timing::CoreTiming& CoreTiming();
+
+ /// Provides a constant reference to the core timing instance.
+ const Timing::CoreTiming& CoreTiming() const;
+
/// Provides a reference to the kernel instance.
Kernel::KernelCore& Kernel();
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 452366250..54aa21a3a 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -49,17 +49,18 @@ bool CpuBarrier::Rendezvous() {
return false;
}
-Cpu::Cpu(ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, std::size_t core_index)
- : cpu_barrier{cpu_barrier}, core_index{core_index} {
+Cpu::Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
+ CpuBarrier& cpu_barrier, std::size_t core_index)
+ : cpu_barrier{cpu_barrier}, core_timing{core_timing}, core_index{core_index} {
if (Settings::values.use_cpu_jit) {
#ifdef ARCHITECTURE_x86_64
- arm_interface = std::make_unique<ARM_Dynarmic>(exclusive_monitor, core_index);
+ arm_interface = std::make_unique<ARM_Dynarmic>(core_timing, exclusive_monitor, core_index);
#else
arm_interface = std::make_unique<ARM_Unicorn>();
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
} else {
- arm_interface = std::make_unique<ARM_Unicorn>();
+ arm_interface = std::make_unique<ARM_Unicorn>(core_timing);
}
scheduler = std::make_unique<Kernel::Scheduler>(*arm_interface);
@@ -93,14 +94,14 @@ void Cpu::RunLoop(bool tight_loop) {
if (IsMainCore()) {
// TODO(Subv): Only let CoreTiming idle if all 4 cores are idling.
- Timing::Idle();
- Timing::Advance();
+ core_timing.Idle();
+ core_timing.Advance();
}
PrepareReschedule();
} else {
if (IsMainCore()) {
- Timing::Advance();
+ core_timing.Advance();
}
if (tight_loop) {
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index 1d2bdc6cd..e2204c6b0 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -15,6 +15,10 @@ namespace Kernel {
class Scheduler;
}
+namespace Core::Timing {
+class CoreTiming;
+}
+
namespace Core {
class ARM_Interface;
@@ -41,7 +45,8 @@ private:
class Cpu {
public:
- Cpu(ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, std::size_t core_index);
+ Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
+ CpuBarrier& cpu_barrier, std::size_t core_index);
~Cpu();
void RunLoop(bool tight_loop = true);
@@ -82,6 +87,7 @@ private:
std::unique_ptr<ARM_Interface> arm_interface;
CpuBarrier& cpu_barrier;
std::unique_ptr<Kernel::Scheduler> scheduler;
+ Timing::CoreTiming& core_timing;
std::atomic<bool> reschedule_pending = false;
std::size_t core_index;
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 2b7ca9766..a0dd5db24 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -8,149 +8,98 @@
#include <mutex>
#include <string>
#include <tuple>
-#include <unordered_map>
-#include <vector>
+
#include "common/assert.h"
#include "common/thread.h"
-#include "common/threadsafe_queue.h"
#include "core/core_timing_util.h"
namespace Core::Timing {
-static s64 global_timer;
-static int slice_length;
-static int downcount;
-
-struct EventType {
- TimedCallback callback;
- const std::string* name;
-};
+constexpr int MAX_SLICE_LENGTH = 20000;
-struct Event {
+struct CoreTiming::Event {
s64 time;
u64 fifo_order;
u64 userdata;
const EventType* type;
-};
-
-// Sort by time, unless the times are the same, in which case sort by the order added to the queue
-static bool operator>(const Event& left, const Event& right) {
- return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
-}
-
-static bool operator<(const Event& left, const Event& right) {
- return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
-}
-
-// unordered_map stores each element separately as a linked list node so pointers to elements
-// remain stable regardless of rehashes/resizing.
-static std::unordered_map<std::string, EventType> event_types;
-// The queue is a min-heap using std::make_heap/push_heap/pop_heap.
-// We don't use std::priority_queue because we need to be able to serialize, unserialize and
-// erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't accomodated
-// by the standard adaptor class.
-static std::vector<Event> event_queue;
-static u64 event_fifo_id;
-// the queue for storing the events from other threads threadsafe until they will be added
-// to the event_queue by the emu thread
-static Common::MPSCQueue<Event, false> ts_queue;
-
-// the queue for unscheduling the events from other threads threadsafe
-static Common::MPSCQueue<std::pair<const EventType*, u64>, false> unschedule_queue;
-
-constexpr int MAX_SLICE_LENGTH = 20000;
-
-static s64 idled_cycles;
-
-// Are we in a function that has been called from Advance()
-// If events are sheduled from a function that gets called from Advance(),
-// don't change slice_length and downcount.
-static bool is_global_timer_sane;
-
-static EventType* ev_lost = nullptr;
-
-static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) {}
-
-EventType* RegisterEvent(const std::string& name, TimedCallback callback) {
- // check for existing type with same name.
- // we want event type names to remain unique so that we can use them for serialization.
- ASSERT_MSG(event_types.find(name) == event_types.end(),
- "CoreTiming Event \"{}\" is already registered. Events should only be registered "
- "during Init to avoid breaking save states.",
- name.c_str());
+ // Sort by time, unless the times are the same, in which case sort by
+ // the order added to the queue
+ friend bool operator>(const Event& left, const Event& right) {
+ return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
+ }
- auto info = event_types.emplace(name, EventType{callback, nullptr});
- EventType* event_type = &info.first->second;
- event_type->name = &info.first->first;
- return event_type;
-}
+ friend bool operator<(const Event& left, const Event& right) {
+ return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
+ }
+};
-void UnregisterAllEvents() {
- ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
- event_types.clear();
-}
+CoreTiming::CoreTiming() = default;
+CoreTiming::~CoreTiming() = default;
-void Init() {
+void CoreTiming::Initialize() {
downcount = MAX_SLICE_LENGTH;
slice_length = MAX_SLICE_LENGTH;
global_timer = 0;
idled_cycles = 0;
- // The time between CoreTiming being intialized and the first call to Advance() is considered
+ // The time between CoreTiming being initialized and the first call to Advance() is considered
// the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before
// executing the first cycle of each slice to prepare the slice length and downcount for
// that slice.
is_global_timer_sane = true;
event_fifo_id = 0;
- ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback);
+
+ const auto empty_timed_callback = [](u64, s64) {};
+ ev_lost = RegisterEvent("_lost_event", empty_timed_callback);
}
-void Shutdown() {
+void CoreTiming::Shutdown() {
MoveEvents();
ClearPendingEvents();
UnregisterAllEvents();
}
-// This should only be called from the CPU thread. If you are calling
-// it from any other thread, you are doing something evil
-u64 GetTicks() {
- u64 ticks = static_cast<u64>(global_timer);
- if (!is_global_timer_sane) {
- ticks += slice_length - downcount;
- }
- return ticks;
-}
-
-void AddTicks(u64 ticks) {
- downcount -= static_cast<int>(ticks);
-}
+EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) {
+ // check for existing type with same name.
+ // we want event type names to remain unique so that we can use them for serialization.
+ ASSERT_MSG(event_types.find(name) == event_types.end(),
+ "CoreTiming Event \"{}\" is already registered. Events should only be registered "
+ "during Init to avoid breaking save states.",
+ name.c_str());
-u64 GetIdleTicks() {
- return static_cast<u64>(idled_cycles);
+ auto info = event_types.emplace(name, EventType{callback, nullptr});
+ EventType* event_type = &info.first->second;
+ event_type->name = &info.first->first;
+ return event_type;
}
-void ClearPendingEvents() {
- event_queue.clear();
+void CoreTiming::UnregisterAllEvents() {
+ ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
+ event_types.clear();
}
-void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
+void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
ASSERT(event_type != nullptr);
- s64 timeout = GetTicks() + cycles_into_future;
+ const s64 timeout = GetTicks() + cycles_into_future;
+
// If this event needs to be scheduled before the next advance(), force one early
- if (!is_global_timer_sane)
+ if (!is_global_timer_sane) {
ForceExceptionCheck(cycles_into_future);
+ }
+
event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
-void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
+void CoreTiming::ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type,
+ u64 userdata) {
ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type});
}
-void UnscheduleEvent(const EventType* event_type, u64 userdata) {
- auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
+void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {
+ const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
return e.type == event_type && e.userdata == userdata;
});
@@ -161,13 +110,33 @@ void UnscheduleEvent(const EventType* event_type, u64 userdata) {
}
}
-void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) {
+void CoreTiming::UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) {
unschedule_queue.Push(std::make_pair(event_type, userdata));
}
-void RemoveEvent(const EventType* event_type) {
- auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
- [&](const Event& e) { return e.type == event_type; });
+u64 CoreTiming::GetTicks() const {
+ u64 ticks = static_cast<u64>(global_timer);
+ if (!is_global_timer_sane) {
+ ticks += slice_length - downcount;
+ }
+ return ticks;
+}
+
+u64 CoreTiming::GetIdleTicks() const {
+ return static_cast<u64>(idled_cycles);
+}
+
+void CoreTiming::AddTicks(u64 ticks) {
+ downcount -= static_cast<int>(ticks);
+}
+
+void CoreTiming::ClearPendingEvents() {
+ event_queue.clear();
+}
+
+void CoreTiming::RemoveEvent(const EventType* event_type) {
+ const auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
+ [&](const Event& e) { return e.type == event_type; });
// Removing random items breaks the invariant so we have to re-establish it.
if (itr != event_queue.end()) {
@@ -176,22 +145,24 @@ void RemoveEvent(const EventType* event_type) {
}
}
-void RemoveNormalAndThreadsafeEvent(const EventType* event_type) {
+void CoreTiming::RemoveNormalAndThreadsafeEvent(const EventType* event_type) {
MoveEvents();
RemoveEvent(event_type);
}
-void ForceExceptionCheck(s64 cycles) {
+void CoreTiming::ForceExceptionCheck(s64 cycles) {
cycles = std::max<s64>(0, cycles);
- if (downcount > cycles) {
- // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int
- // here. Account for cycles already executed by adjusting the g.slice_length
- slice_length -= downcount - static_cast<int>(cycles);
- downcount = static_cast<int>(cycles);
+ if (downcount <= cycles) {
+ return;
}
+
+ // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int
+ // here. Account for cycles already executed by adjusting the g.slice_length
+ slice_length -= downcount - static_cast<int>(cycles);
+ downcount = static_cast<int>(cycles);
}
-void MoveEvents() {
+void CoreTiming::MoveEvents() {
for (Event ev; ts_queue.Pop(ev);) {
ev.fifo_order = event_fifo_id++;
event_queue.emplace_back(std::move(ev));
@@ -199,13 +170,13 @@ void MoveEvents() {
}
}
-void Advance() {
+void CoreTiming::Advance() {
MoveEvents();
for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) {
UnscheduleEvent(ev.first, ev.second);
}
- int cycles_executed = slice_length - downcount;
+ const int cycles_executed = slice_length - downcount;
global_timer += cycles_executed;
slice_length = MAX_SLICE_LENGTH;
@@ -229,16 +200,16 @@ void Advance() {
downcount = slice_length;
}
-void Idle() {
+void CoreTiming::Idle() {
idled_cycles += downcount;
downcount = 0;
}
-std::chrono::microseconds GetGlobalTimeUs() {
+std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE};
}
-int GetDowncount() {
+int CoreTiming::GetDowncount() const {
return downcount;
}
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 093989d4c..59163bae1 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -4,92 +4,153 @@
#pragma once
-/**
- * This is a system to schedule events into the emulated machine's future. Time is measured
- * in main CPU clock cycles.
- *
- * To schedule an event, you first have to register its type. This is where you pass in the
- * callback. You then schedule events using the type id you get back.
- *
- * The int cyclesLate that the callbacks get is how many cycles late it was.
- * So to schedule a new event on a regular basis:
- * inside callback:
- * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
- */
-
#include <chrono>
#include <functional>
#include <string>
+#include <unordered_map>
+#include <vector>
#include "common/common_types.h"
+#include "common/threadsafe_queue.h"
namespace Core::Timing {
-struct EventType;
-
+/// A callback that may be scheduled for a particular core timing event.
using TimedCallback = std::function<void(u64 userdata, int cycles_late)>;
-/**
- * CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
- * required to end slice -1 and start slice 0 before the first cycle of code is executed.
- */
-void Init();
-void Shutdown();
-
-/**
- * This should only be called from the emu thread, if you are calling it any other thread, you are
- * doing something evil
- */
-u64 GetTicks();
-u64 GetIdleTicks();
-void AddTicks(u64 ticks);
-
-/**
- * Returns the event_type identifier. if name is not unique, it will assert.
- */
-EventType* RegisterEvent(const std::string& name, TimedCallback callback);
-void UnregisterAllEvents();
-
-/**
- * After the first Advance, the slice lengths and the downcount will be reduced whenever an event
- * is scheduled earlier than the current values.
- * Scheduling from a callback will not update the downcount until the Advance() completes.
- */
-void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
+/// Contains the characteristics of a particular event.
+struct EventType {
+ /// The event's callback function.
+ TimedCallback callback;
+ /// A pointer to the name of the event.
+ const std::string* name;
+};
/**
- * This is to be called when outside of hle threads, such as the graphics thread, wants to
- * schedule things to be executed on the main thread.
- * Not that this doesn't change slice_length and thus events scheduled by this might be called
- * with a delay of up to MAX_SLICE_LENGTH
- */
-void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata);
-
-void UnscheduleEvent(const EventType* event_type, u64 userdata);
-void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata);
-
-/// We only permit one event of each type in the queue at a time.
-void RemoveEvent(const EventType* event_type);
-void RemoveNormalAndThreadsafeEvent(const EventType* event_type);
-
-/** Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
- * the previous timing slice and begins the next one, you must Advance from the previous
- * slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
- * Advance() is required to initialize the slice length before the first cycle of emulated
- * instructions is executed.
+ * This is a system to schedule events into the emulated machine's future. Time is measured
+ * in main CPU clock cycles.
+ *
+ * To schedule an event, you first have to register its type. This is where you pass in the
+ * callback. You then schedule events using the type id you get back.
+ *
+ * The int cyclesLate that the callbacks get is how many cycles late it was.
+ * So to schedule a new event on a regular basis:
+ * inside callback:
+ * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
*/
-void Advance();
-void MoveEvents();
-
-/// Pretend that the main CPU has executed enough cycles to reach the next event.
-void Idle();
-
-/// Clear all pending events. This should ONLY be done on exit.
-void ClearPendingEvents();
-
-void ForceExceptionCheck(s64 cycles);
-
-std::chrono::microseconds GetGlobalTimeUs();
-
-int GetDowncount();
+class CoreTiming {
+public:
+ CoreTiming();
+ ~CoreTiming();
+
+ CoreTiming(const CoreTiming&) = delete;
+ CoreTiming(CoreTiming&&) = delete;
+
+ CoreTiming& operator=(const CoreTiming&) = delete;
+ CoreTiming& operator=(CoreTiming&&) = delete;
+
+ /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
+ /// required to end slice - 1 and start slice 0 before the first cycle of code is executed.
+ void Initialize();
+
+ /// Tears down all timing related functionality.
+ void Shutdown();
+
+ /// Registers a core timing event with the given name and callback.
+ ///
+ /// @param name The name of the core timing event to register.
+ /// @param callback The callback to execute for the event.
+ ///
+ /// @returns An EventType instance representing the registered event.
+ ///
+ /// @pre The name of the event being registered must be unique among all
+ /// registered events.
+ ///
+ EventType* RegisterEvent(const std::string& name, TimedCallback callback);
+
+ /// Unregisters all registered events thus far.
+ void UnregisterAllEvents();
+
+ /// After the first Advance, the slice lengths and the downcount will be reduced whenever an
+ /// event is scheduled earlier than the current values.
+ ///
+ /// Scheduling from a callback will not update the downcount until the Advance() completes.
+ void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
+
+ /// This is to be called when outside of hle threads, such as the graphics thread, wants to
+ /// schedule things to be executed on the main thread.
+ ///
+ /// @note This doesn't change slice_length and thus events scheduled by this might be
+ /// called with a delay of up to MAX_SLICE_LENGTH
+ void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type,
+ u64 userdata = 0);
+
+ void UnscheduleEvent(const EventType* event_type, u64 userdata);
+ void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata);
+
+ /// We only permit one event of each type in the queue at a time.
+ void RemoveEvent(const EventType* event_type);
+ void RemoveNormalAndThreadsafeEvent(const EventType* event_type);
+
+ void ForceExceptionCheck(s64 cycles);
+
+ /// This should only be called from the emu thread, if you are calling it any other thread,
+ /// you are doing something evil
+ u64 GetTicks() const;
+
+ u64 GetIdleTicks() const;
+
+ void AddTicks(u64 ticks);
+
+ /// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
+ /// the previous timing slice and begins the next one, you must Advance from the previous
+ /// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
+ /// Advance() is required to initialize the slice length before the first cycle of emulated
+ /// instructions is executed.
+ void Advance();
+
+ /// Pretend that the main CPU has executed enough cycles to reach the next event.
+ void Idle();
+
+ std::chrono::microseconds GetGlobalTimeUs() const;
+
+ int GetDowncount() const;
+
+private:
+ struct Event;
+
+ /// Clear all pending events. This should ONLY be done on exit.
+ void ClearPendingEvents();
+ void MoveEvents();
+
+ s64 global_timer = 0;
+ s64 idled_cycles = 0;
+ int slice_length = 0;
+ int downcount = 0;
+
+ // Are we in a function that has been called from Advance()
+ // If events are scheduled from a function that gets called from Advance(),
+ // don't change slice_length and downcount.
+ bool is_global_timer_sane = false;
+
+ // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
+ // We don't use std::priority_queue because we need to be able to serialize, unserialize and
+ // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't
+ // accomodated by the standard adaptor class.
+ std::vector<Event> event_queue;
+ u64 event_fifo_id = 0;
+
+ // Stores each element separately as a linked list node so pointers to elements
+ // remain stable regardless of rehashes/resizing.
+ std::unordered_map<std::string, EventType> event_types;
+
+ // The queue for storing the events from other threads threadsafe until they will be added
+ // to the event_queue by the emu thread
+ Common::MPSCQueue<Event> ts_queue;
+
+ // The queue for unscheduling the events from other threads threadsafe
+ Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue;
+
+ EventType* ev_lost = nullptr;
+};
} // namespace Core::Timing
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
index 769a6fefa..2ddb3610d 100644
--- a/src/core/cpu_core_manager.cpp
+++ b/src/core/cpu_core_manager.cpp
@@ -27,7 +27,8 @@ void CpuCoreManager::Initialize(System& system) {
exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
for (std::size_t index = 0; index < cores.size(); ++index) {
- cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index);
+ cores[index] =
+ std::make_unique<Cpu>(system.CoreTiming(), *exclusive_monitor, *barrier, index);
}
// Create threads for CPU cores 1-3, and build thread_to_cpu map
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index ca12fb4ab..dfac9a4b3 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -398,7 +398,8 @@ static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_
}
void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
- std::ifstream file(filename);
+ std::ifstream file;
+ OpenFStream(file, filename, std::ios_base::in);
if (!file.is_open())
return;
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 57157beb4..a250d088d 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -17,8 +17,7 @@
#include "core/hle/result.h"
#include "core/memory.h"
-namespace Kernel {
-namespace AddressArbiter {
+namespace Kernel::AddressArbiter {
// Performs actual address waiting logic.
static ResultCode WaitForAddress(VAddr address, s64 timeout) {
@@ -176,5 +175,4 @@ ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
return WaitForAddress(address, timeout);
}
-} // namespace AddressArbiter
-} // namespace Kernel
+} // namespace Kernel::AddressArbiter
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index e3657b8e9..b58f21bec 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -8,9 +8,8 @@
union ResultCode;
-namespace Kernel {
+namespace Kernel::AddressArbiter {
-namespace AddressArbiter {
enum class ArbitrationType {
WaitIfLessThan = 0,
DecrementAndWaitIfLessThan = 1,
@@ -29,6 +28,5 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu
ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement);
ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout);
-} // namespace AddressArbiter
-} // namespace Kernel
+} // namespace Kernel::AddressArbiter
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 3721ae8fe..dd749eed4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -86,11 +86,11 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
}
struct KernelCore::Impl {
- void Initialize(KernelCore& kernel) {
+ void Initialize(KernelCore& kernel, Core::Timing::CoreTiming& core_timing) {
Shutdown();
InitializeSystemResourceLimit(kernel);
- InitializeThreads();
+ InitializeThreads(core_timing);
}
void Shutdown() {
@@ -122,9 +122,9 @@ struct KernelCore::Impl {
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
}
- void InitializeThreads() {
+ void InitializeThreads(Core::Timing::CoreTiming& core_timing) {
thread_wakeup_event_type =
- Core::Timing::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
+ core_timing.RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
}
std::atomic<u32> next_object_id{0};
@@ -152,8 +152,8 @@ KernelCore::~KernelCore() {
Shutdown();
}
-void KernelCore::Initialize() {
- impl->Initialize(*this);
+void KernelCore::Initialize(Core::Timing::CoreTiming& core_timing) {
+ impl->Initialize(*this, core_timing);
}
void KernelCore::Shutdown() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 7406f107e..154bced42 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -12,8 +12,9 @@ template <typename T>
class ResultVal;
namespace Core::Timing {
+class CoreTiming;
struct EventType;
-}
+} // namespace Core::Timing
namespace Kernel {
@@ -39,7 +40,11 @@ public:
KernelCore& operator=(KernelCore&&) = delete;
/// Resets the kernel to a clean slate for use.
- void Initialize();
+ ///
+ /// @param core_timing CoreTiming instance used to create any necessary
+ /// kernel-specific callback events.
+ ///
+ void Initialize(Core::Timing::CoreTiming& core_timing);
/// Clears all resources in use by the kernel instance.
void Shutdown();
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 9e2517e1b..44f30d070 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -111,7 +111,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
const u64 prev_switch_ticks = last_context_switch_time;
- const u64 most_recent_switch_ticks = Core::Timing::GetTicks();
+ const u64 most_recent_switch_ticks = Core::System::GetInstance().CoreTiming().GetTicks();
const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
if (thread != nullptr) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 5f040f79f..c5d399bab 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -918,6 +918,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
}
const auto& system = Core::System::GetInstance();
+ const auto& core_timing = system.CoreTiming();
const auto& scheduler = system.CurrentScheduler();
const auto* const current_thread = scheduler.GetCurrentThread();
const bool same_thread = current_thread == thread;
@@ -927,9 +928,9 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
- out_ticks = thread_ticks + (Core::Timing::GetTicks() - prev_ctx_ticks);
+ out_ticks = thread_ticks + (core_timing.GetTicks() - prev_ctx_ticks);
} else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
- out_ticks = Core::Timing::GetTicks() - prev_ctx_ticks;
+ out_ticks = core_timing.GetTicks() - prev_ctx_ticks;
}
*result = out_ticks;
@@ -1546,10 +1547,11 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
static u64 GetSystemTick() {
LOG_TRACE(Kernel_SVC, "called");
- const u64 result{Core::Timing::GetTicks()};
+ auto& core_timing = Core::System::GetInstance().CoreTiming();
+ const u64 result{core_timing.GetTicks()};
// Advance time to defeat dumb games that busy-wait for the frame to end.
- Core::Timing::AddTicks(400);
+ core_timing.AddTicks(400);
return result;
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 7881c2b90..6661e2130 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -43,7 +43,8 @@ Thread::~Thread() = default;
void Thread::Stop() {
// Cancel any outstanding wakeup events for this thread
- Core::Timing::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle);
+ Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
+ callback_handle);
kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
callback_handle = 0;
@@ -85,13 +86,14 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
// This function might be called from any thread so we have to be cautious and use the
// thread-safe version of ScheduleEvent.
- Core::Timing::ScheduleEventThreadsafe(Core::Timing::nsToCycles(nanoseconds),
- kernel.ThreadWakeupCallbackEventType(), callback_handle);
+ Core::System::GetInstance().CoreTiming().ScheduleEventThreadsafe(
+ Core::Timing::nsToCycles(nanoseconds), kernel.ThreadWakeupCallbackEventType(),
+ callback_handle);
}
void Thread::CancelWakeupTimer() {
- Core::Timing::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(),
- callback_handle);
+ Core::System::GetInstance().CoreTiming().UnscheduleEventThreadsafe(
+ kernel.ThreadWakeupCallbackEventType(), callback_handle);
}
static std::optional<s32> GetNextProcessorId(u64 mask) {
@@ -190,6 +192,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
return ResultCode(-1);
}
+ auto& system = Core::System::GetInstance();
SharedPtr<Thread> thread(new Thread(kernel));
thread->thread_id = kernel.CreateNewThreadID();
@@ -198,7 +201,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
thread->stack_top = stack_top;
thread->tpidr_el0 = 0;
thread->nominal_priority = thread->current_priority = priority;
- thread->last_running_ticks = Core::Timing::GetTicks();
+ thread->last_running_ticks = system.CoreTiming().GetTicks();
thread->processor_id = processor_id;
thread->ideal_core = processor_id;
thread->affinity_mask = 1ULL << processor_id;
@@ -209,7 +212,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
thread->name = std::move(name);
thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
thread->owner_process = &owner_process;
- thread->scheduler = &Core::System::GetInstance().Scheduler(processor_id);
+ thread->scheduler = &system.Scheduler(processor_id);
thread->scheduler->AddThread(thread, priority);
thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
@@ -258,7 +261,7 @@ void Thread::SetStatus(ThreadStatus new_status) {
}
if (status == ThreadStatus::Running) {
- last_running_ticks = Core::Timing::GetTicks();
+ last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks();
}
status = new_status;
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index dc6a6b188..6831c0735 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -68,12 +68,12 @@ public:
RegisterHandlers(functions);
// This is the event handle used to check if the audio buffer was released
- auto& kernel = Core::System::GetInstance().Kernel();
- buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
- "IAudioOutBufferReleased");
+ auto& system = Core::System::GetInstance();
+ buffer_event = Kernel::WritableEvent::CreateEventPair(
+ system.Kernel(), Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
- stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
- std::move(unique_name),
+ stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
+ audio_params.channel_count, std::move(unique_name),
[=]() { buffer_event.writable->Signal(); });
}
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 76cc48254..7e0cc64a8 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -42,10 +42,11 @@ public:
// clang-format on
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
- system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
- "IAudioRenderer:SystemEvent");
- renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable);
+ auto& system = Core::System::GetInstance();
+ system_event = Kernel::WritableEvent::CreateEventPair(
+ system.Kernel(), Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
+ renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), audren_params,
+ system_event.writable);
}
private:
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index f0e092b1b..5e5097a03 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -7,6 +7,10 @@
#include "common/common_types.h"
#include "common/swap.h"
+namespace Core::Timing {
+class CoreTiming;
+}
+
namespace Service::HID {
class ControllerBase {
public:
@@ -20,7 +24,8 @@ public:
virtual void OnRelease() = 0;
// When the controller is requesting an update for the shared memory
- virtual void OnUpdate(u8* data, std::size_t size) = 0;
+ virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) = 0;
// Called when input devices should be loaded
virtual void OnLoadInputDevices() = 0;
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index b264c9503..c5c2e032a 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -21,8 +21,9 @@ void Controller_DebugPad::OnInit() {}
void Controller_DebugPad::OnRelease() {}
-void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) {
- shared_memory.header.timestamp = Core::Timing::GetTicks();
+void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {
+ shared_memory.header.timestamp = core_timing.GetTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 68b734248..929035034 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -26,7 +26,7 @@ public:
void OnRelease() override;
// When the controller is requesting an update for the shared memory
- void OnUpdate(u8* data, std::size_t size) override;
+ void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index 6d21f1a7d..a179252e3 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -17,8 +17,9 @@ void Controller_Gesture::OnInit() {}
void Controller_Gesture::OnRelease() {}
-void Controller_Gesture::OnUpdate(u8* data, std::size_t size) {
- shared_memory.header.timestamp = Core::Timing::GetTicks();
+void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {
+ shared_memory.header.timestamp = core_timing.GetTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 1056ffbcd..f305fe90f 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -22,7 +22,7 @@ public:
void OnRelease() override;
// When the controller is requesting an update for the shared memory
- void OnUpdate(u8* data, size_t size) override;
+ void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index 798f30436..92d7bfb52 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -19,8 +19,9 @@ void Controller_Keyboard::OnInit() {}
void Controller_Keyboard::OnRelease() {}
-void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) {
- shared_memory.header.timestamp = Core::Timing::GetTicks();
+void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {
+ shared_memory.header.timestamp = core_timing.GetTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index f52775456..73cd2c7bb 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -25,7 +25,7 @@ public:
void OnRelease() override;
// When the controller is requesting an update for the shared memory
- void OnUpdate(u8* data, std::size_t size) override;
+ void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 4985037be..11ab096d9 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -17,8 +17,9 @@ Controller_Mouse::~Controller_Mouse() = default;
void Controller_Mouse::OnInit() {}
void Controller_Mouse::OnRelease() {}
-void Controller_Mouse::OnUpdate(u8* data, std::size_t size) {
- shared_memory.header.timestamp = Core::Timing::GetTicks();
+void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {
+ shared_memory.header.timestamp = core_timing.GetTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 70b654d07..9d46eecbe 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -24,7 +24,7 @@ public:
void OnRelease() override;
// When the controller is requesting an update for the shared memory
- void OnUpdate(u8* data, std::size_t size) override;
+ void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ffdd1c593..e7fc7a619 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -288,7 +288,8 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
}
-void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
+void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t data_len) {
if (!IsControllerActivated())
return;
for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
@@ -308,7 +309,7 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
const auto& last_entry =
main_controller->npad[main_controller->common.last_entry_index];
- main_controller->common.timestamp = Core::Timing::GetTicks();
+ main_controller->common.timestamp = core_timing.GetTicks();
main_controller->common.last_entry_index =
(main_controller->common.last_entry_index + 1) % 17;
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 106cf58c8..18c7a94e6 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -30,7 +30,7 @@ public:
void OnRelease() override;
// When the controller is requesting an update for the shared memory
- void OnUpdate(u8* data, std::size_t size) override;
+ void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index cca4dca1d..946948f5e 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -16,13 +16,14 @@ void Controller_Stubbed::OnInit() {}
void Controller_Stubbed::OnRelease() {}
-void Controller_Stubbed::OnUpdate(u8* data, std::size_t size) {
+void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {
if (!smart_update) {
return;
}
CommonHeader header{};
- header.timestamp = Core::Timing::GetTicks();
+ header.timestamp = core_timing.GetTicks();
header.total_entry_count = 17;
header.entry_count = 0;
header.last_entry_index = 0;
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 4a21c643e..24469f03e 100644
--- a/src/core/hle/service/hid/controllers/stubbed.h
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -20,7 +20,7 @@ public:
void OnRelease() override;
// When the controller is requesting an update for the shared memory
- void OnUpdate(u8* data, std::size_t size) override;
+ void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index a7c8acc72..1a8445a43 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -20,8 +20,9 @@ void Controller_Touchscreen::OnInit() {}
void Controller_Touchscreen::OnRelease() {}
-void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
- shared_memory.header.timestamp = Core::Timing::GetTicks();
+void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {
+ shared_memory.header.timestamp = core_timing.GetTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) {
@@ -48,7 +49,7 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
- const u64 tick = Core::Timing::GetTicks();
+ const u64 tick = core_timing.GetTicks();
touch_entry.delta_time = tick - last_touch;
last_touch = tick;
touch_entry.finger = Settings::values.touchscreen.finger;
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 94cd0eba9..012b6e0dd 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -24,7 +24,7 @@ public:
void OnRelease() override;
// When the controller is requesting an update for the shared memory
- void OnUpdate(u8* data, std::size_t size) override;
+ void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
index eff03d14e..1a9da9576 100644
--- a/src/core/hle/service/hid/controllers/xpad.cpp
+++ b/src/core/hle/service/hid/controllers/xpad.cpp
@@ -17,9 +17,10 @@ void Controller_XPad::OnInit() {}
void Controller_XPad::OnRelease() {}
-void Controller_XPad::OnUpdate(u8* data, std::size_t size) {
+void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {
for (auto& xpad_entry : shared_memory.shared_memory_entries) {
- xpad_entry.header.timestamp = Core::Timing::GetTicks();
+ xpad_entry.header.timestamp = core_timing.GetTicks();
xpad_entry.header.total_entry_count = 17;
if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
index ff836989f..2864e6617 100644
--- a/src/core/hle/service/hid/controllers/xpad.h
+++ b/src/core/hle/service/hid/controllers/xpad.h
@@ -22,7 +22,7 @@ public:
void OnRelease() override;
// When the controller is requesting an update for the shared memory
- void OnUpdate(u8* data, std::size_t size) override;
+ void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 79c320d04..8a6de83a2 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -73,13 +73,15 @@ IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
// Register update callbacks
- pad_update_event = Core::Timing::RegisterEvent(
- "HID::UpdatePadCallback",
- [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); });
+ auto& core_timing = Core::System::GetInstance().CoreTiming();
+ pad_update_event =
+ core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, int cycles_late) {
+ UpdateControllers(userdata, cycles_late);
+ });
// TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
- Core::Timing::ScheduleEvent(pad_update_ticks, pad_update_event);
+ core_timing.ScheduleEvent(pad_update_ticks, pad_update_event);
ReloadInputDevices();
}
@@ -93,7 +95,7 @@ void IAppletResource::DeactivateController(HidController controller) {
}
IAppletResource ::~IAppletResource() {
- Core::Timing::UnscheduleEvent(pad_update_event, 0);
+ Core::System::GetInstance().CoreTiming().UnscheduleEvent(pad_update_event, 0);
}
void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
@@ -105,15 +107,17 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
}
void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) {
+ auto& core_timing = Core::System::GetInstance().CoreTiming();
+
const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
for (const auto& controller : controllers) {
if (should_reload) {
controller->OnLoadInputDevices();
}
- controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
+ controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
}
- Core::Timing::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
+ core_timing.ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
}
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index b427d4068..2c4625c99 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(RESULT_SUCCESS);
- rb.PushRaw<u64>(Core::Timing::GetTicks());
+ rb.PushRaw<u64>(Core::System::GetInstance().CoreTiming().GetTicks());
rb.PushRaw<u32>(0);
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 88d80ba06..45812d238 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -5,6 +5,7 @@
#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
@@ -184,7 +185,7 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& o
IoctlGetGpuTime params{};
std::memcpy(&params, input.data(), input.size());
- params.gpu_time = Core::Timing::cyclesToNs(Core::Timing::GetTicks());
+ params.gpu_time = Core::Timing::cyclesToNs(Core::System::GetInstance().CoreTiming().GetTicks());
std::memcpy(output.data(), &params, output.size());
return 0;
}
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index ce1b59860..56f31e2ac 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -14,11 +14,12 @@
#include "core/core_timing_util.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/readable_event.h"
-#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
#include "core/hle/service/nvflinger/nvflinger.h"
+#include "core/hle/service/vi/display/vi_display.h"
+#include "core/hle/service/vi/layer/vi_layer.h"
#include "core/perf_stats.h"
#include "video_core/renderer_base.h"
@@ -27,19 +28,25 @@ namespace Service::NVFlinger {
constexpr std::size_t SCREEN_REFRESH_RATE = 60;
constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
-NVFlinger::NVFlinger() {
+NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} {
+ displays.emplace_back(0, "Default");
+ displays.emplace_back(1, "External");
+ displays.emplace_back(2, "Edid");
+ displays.emplace_back(3, "Internal");
+ displays.emplace_back(4, "Null");
+
// Schedule the screen composition events
composition_event =
- Core::Timing::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) {
+ core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) {
Compose();
- Core::Timing::ScheduleEvent(frame_ticks - cycles_late, composition_event);
+ this->core_timing.ScheduleEvent(frame_ticks - cycles_late, composition_event);
});
- Core::Timing::ScheduleEvent(frame_ticks, composition_event);
+ core_timing.ScheduleEvent(frame_ticks, composition_event);
}
NVFlinger::~NVFlinger() {
- Core::Timing::UnscheduleEvent(composition_event, 0);
+ core_timing.UnscheduleEvent(composition_event, 0);
}
void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
@@ -52,13 +59,14 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
// TODO(Subv): Currently we only support the Default display.
ASSERT(name == "Default");
- const auto itr = std::find_if(displays.begin(), displays.end(),
- [&](const Display& display) { return display.name == name; });
+ const auto itr =
+ std::find_if(displays.begin(), displays.end(),
+ [&](const VI::Display& display) { return display.GetName() == name; });
if (itr == displays.end()) {
return {};
}
- return itr->id;
+ return itr->GetID();
}
std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
@@ -68,13 +76,10 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
return {};
}
- ASSERT_MSG(display->layers.empty(), "Only one layer is supported per display at the moment");
-
const u64 layer_id = next_layer_id++;
const u32 buffer_queue_id = next_buffer_queue_id++;
- auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id);
- display->layers.emplace_back(layer_id, buffer_queue);
- buffer_queues.emplace_back(std::move(buffer_queue));
+ buffer_queues.emplace_back(buffer_queue_id, layer_id);
+ display->CreateLayer(layer_id, buffer_queues.back());
return layer_id;
}
@@ -85,7 +90,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co
return {};
}
- return layer->buffer_queue->GetId();
+ return layer->GetBufferQueue().GetId();
}
Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const {
@@ -95,20 +100,29 @@ Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_i
return nullptr;
}
- return display->vsync_event.readable;
+ return display->GetVSyncEvent();
+}
+
+BufferQueue& NVFlinger::FindBufferQueue(u32 id) {
+ const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
+ [id](const auto& queue) { return queue.GetId() == id; });
+
+ ASSERT(itr != buffer_queues.end());
+ return *itr;
}
-std::shared_ptr<BufferQueue> NVFlinger::FindBufferQueue(u32 id) const {
+const BufferQueue& NVFlinger::FindBufferQueue(u32 id) const {
const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
- [&](const auto& queue) { return queue->GetId() == id; });
+ [id](const auto& queue) { return queue.GetId() == id; });
ASSERT(itr != buffer_queues.end());
return *itr;
}
-Display* NVFlinger::FindDisplay(u64 display_id) {
- const auto itr = std::find_if(displays.begin(), displays.end(),
- [&](const Display& display) { return display.id == display_id; });
+VI::Display* NVFlinger::FindDisplay(u64 display_id) {
+ const auto itr =
+ std::find_if(displays.begin(), displays.end(),
+ [&](const VI::Display& display) { return display.GetID() == display_id; });
if (itr == displays.end()) {
return nullptr;
@@ -117,9 +131,10 @@ Display* NVFlinger::FindDisplay(u64 display_id) {
return &*itr;
}
-const Display* NVFlinger::FindDisplay(u64 display_id) const {
- const auto itr = std::find_if(displays.begin(), displays.end(),
- [&](const Display& display) { return display.id == display_id; });
+const VI::Display* NVFlinger::FindDisplay(u64 display_id) const {
+ const auto itr =
+ std::find_if(displays.begin(), displays.end(),
+ [&](const VI::Display& display) { return display.GetID() == display_id; });
if (itr == displays.end()) {
return nullptr;
@@ -128,57 +143,41 @@ const Display* NVFlinger::FindDisplay(u64 display_id) const {
return &*itr;
}
-Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
+VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
auto* const display = FindDisplay(display_id);
if (display == nullptr) {
return nullptr;
}
- const auto itr = std::find_if(display->layers.begin(), display->layers.end(),
- [&](const Layer& layer) { return layer.id == layer_id; });
-
- if (itr == display->layers.end()) {
- return nullptr;
- }
-
- return &*itr;
+ return display->FindLayer(layer_id);
}
-const Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
+const VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
const auto* const display = FindDisplay(display_id);
if (display == nullptr) {
return nullptr;
}
- const auto itr = std::find_if(display->layers.begin(), display->layers.end(),
- [&](const Layer& layer) { return layer.id == layer_id; });
-
- if (itr == display->layers.end()) {
- return nullptr;
- }
-
- return &*itr;
+ return display->FindLayer(layer_id);
}
void NVFlinger::Compose() {
for (auto& display : displays) {
// Trigger vsync for this display at the end of drawing
- SCOPE_EXIT({ display.vsync_event.writable->Signal(); });
+ SCOPE_EXIT({ display.SignalVSyncEvent(); });
// Don't do anything for displays without layers.
- if (display.layers.empty())
+ if (!display.HasLayers())
continue;
// TODO(Subv): Support more than 1 layer.
- ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported");
-
- Layer& layer = display.layers[0];
- auto& buffer_queue = layer.buffer_queue;
+ VI::Layer& layer = display.GetLayer(0);
+ auto& buffer_queue = layer.GetBufferQueue();
// Search for a queued buffer and acquire it
- auto buffer = buffer_queue->AcquireBuffer();
+ auto buffer = buffer_queue.AcquireBuffer();
MicroProfileFlip();
@@ -203,19 +202,8 @@ void NVFlinger::Compose() {
igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride,
buffer->get().transform, buffer->get().crop_rect);
- buffer_queue->ReleaseBuffer(buffer->get().slot);
+ buffer_queue.ReleaseBuffer(buffer->get().slot);
}
}
-Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {}
-Layer::~Layer() = default;
-
-Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
- auto& kernel = Core::System::GetInstance().Kernel();
- vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
- fmt::format("Display VSync Event {}", id));
-}
-
-Display::~Display() = default;
-
} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 6d8bcbd30..c0a83fffb 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -4,7 +4,6 @@
#pragma once
-#include <array>
#include <memory>
#include <optional>
#include <string>
@@ -15,8 +14,9 @@
#include "core/hle/kernel/object.h"
namespace Core::Timing {
+class CoreTiming;
struct EventType;
-}
+} // namespace Core::Timing
namespace Kernel {
class ReadableEvent;
@@ -25,34 +25,20 @@ class WritableEvent;
namespace Service::Nvidia {
class Module;
-}
+} // namespace Service::Nvidia
+
+namespace Service::VI {
+class Display;
+class Layer;
+} // namespace Service::VI
namespace Service::NVFlinger {
class BufferQueue;
-struct Layer {
- Layer(u64 id, std::shared_ptr<BufferQueue> queue);
- ~Layer();
-
- u64 id;
- std::shared_ptr<BufferQueue> buffer_queue;
-};
-
-struct Display {
- Display(u64 id, std::string name);
- ~Display();
-
- u64 id;
- std::string name;
-
- std::vector<Layer> layers;
- Kernel::EventPair vsync_event;
-};
-
class NVFlinger final {
public:
- NVFlinger();
+ explicit NVFlinger(Core::Timing::CoreTiming& core_timing);
~NVFlinger();
/// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -79,7 +65,10 @@ public:
Kernel::SharedPtr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
/// Obtains a buffer queue identified by the ID.
- std::shared_ptr<BufferQueue> FindBufferQueue(u32 id) const;
+ BufferQueue& FindBufferQueue(u32 id);
+
+ /// Obtains a buffer queue identified by the ID.
+ const BufferQueue& FindBufferQueue(u32 id) const;
/// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
/// finished.
@@ -87,27 +76,21 @@ public:
private:
/// Finds the display identified by the specified ID.
- Display* FindDisplay(u64 display_id);
+ VI::Display* FindDisplay(u64 display_id);
/// Finds the display identified by the specified ID.
- const Display* FindDisplay(u64 display_id) const;
+ const VI::Display* FindDisplay(u64 display_id) const;
/// Finds the layer identified by the specified ID in the desired display.
- Layer* FindLayer(u64 display_id, u64 layer_id);
+ VI::Layer* FindLayer(u64 display_id, u64 layer_id);
/// Finds the layer identified by the specified ID in the desired display.
- const Layer* FindLayer(u64 display_id, u64 layer_id) const;
+ const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
std::shared_ptr<Nvidia::Module> nvdrv;
- std::array<Display, 5> displays{{
- {0, "Default"},
- {1, "External"},
- {2, "Edid"},
- {3, "Internal"},
- {4, "Null"},
- }};
- std::vector<std::shared_ptr<BufferQueue>> buffer_queues;
+ std::vector<VI::Display> displays;
+ std::vector<BufferQueue> buffer_queues;
/// Id to use for the next layer that is created, this counter is shared among all displays.
u64 next_layer_id = 1;
@@ -117,6 +100,9 @@ private:
/// Event that handles screen composition.
Core::Timing::EventType* composition_event;
+
+ /// Core timing instance for registering/unregistering the composition event.
+ Core::Timing::CoreTiming& core_timing;
};
} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index d25b80ab0..117f87a45 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -194,10 +194,11 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
// Module interface
/// Initialize ServiceManager
-void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs) {
+void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
+ FileSys::VfsFilesystem& vfs) {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
// here and pass it into the respective InstallInterfaces functions.
- auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
+ auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
SM::ServiceManager::InstallInterfaces(sm);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 029533628..830790269 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -14,6 +14,14 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
+namespace Core {
+class System;
+}
+
+namespace FileSys {
+class VfsFilesystem;
+}
+
namespace Kernel {
class ClientPort;
class ServerPort;
@@ -21,10 +29,6 @@ class ServerSession;
class HLERequestContext;
} // namespace Kernel
-namespace FileSys {
-class VfsFilesystem;
-}
-
namespace Service {
namespace SM {
@@ -178,7 +182,8 @@ private:
};
/// Initialize ServiceManager
-void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs);
+void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
+ FileSys::VfsFilesystem& vfs);
/// Shutdown ServiceManager
void Shutdown();
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index efebd1b24..aa115935d 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -5,6 +5,7 @@
#include <chrono>
#include <ctime>
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/hle/ipc_helpers.h"
@@ -106,8 +107,9 @@ private:
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
+ const auto& core_timing = Core::System::GetInstance().CoreTiming();
const SteadyClockTimePoint steady_clock_time_point{
- Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000};
+ Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000};
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(steady_clock_time_point);
@@ -281,8 +283,9 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
return;
}
+ const auto& core_timing = Core::System::GetInstance().CoreTiming();
const SteadyClockTimePoint steady_clock_time_point{
- Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000, {}};
+ Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000, {}};
CalendarTime calendar_time{};
calendar_time.year = tm->tm_year + 1900;
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
new file mode 100644
index 000000000..01d80311b
--- /dev/null
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -0,0 +1,71 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <utility>
+
+#include <fmt/format.h>
+
+#include "common/assert.h"
+#include "core/core.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/service/vi/display/vi_display.h"
+#include "core/hle/service/vi/layer/vi_layer.h"
+
+namespace Service::VI {
+
+Display::Display(u64 id, std::string name) : id{id}, name{std::move(name)} {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ fmt::format("Display VSync Event {}", id));
+}
+
+Display::~Display() = default;
+
+Layer& Display::GetLayer(std::size_t index) {
+ return layers.at(index);
+}
+
+const Layer& Display::GetLayer(std::size_t index) const {
+ return layers.at(index);
+}
+
+Kernel::SharedPtr<Kernel::ReadableEvent> Display::GetVSyncEvent() const {
+ return vsync_event.readable;
+}
+
+void Display::SignalVSyncEvent() {
+ vsync_event.writable->Signal();
+}
+
+void Display::CreateLayer(u64 id, NVFlinger::BufferQueue& buffer_queue) {
+ // TODO(Subv): Support more than 1 layer.
+ ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
+
+ layers.emplace_back(id, buffer_queue);
+}
+
+Layer* Display::FindLayer(u64 id) {
+ const auto itr = std::find_if(layers.begin(), layers.end(),
+ [id](const VI::Layer& layer) { return layer.GetID() == id; });
+
+ if (itr == layers.end()) {
+ return nullptr;
+ }
+
+ return &*itr;
+}
+
+const Layer* Display::FindLayer(u64 id) const {
+ const auto itr = std::find_if(layers.begin(), layers.end(),
+ [id](const VI::Layer& layer) { return layer.GetID() == id; });
+
+ if (itr == layers.end()) {
+ return nullptr;
+ }
+
+ return &*itr;
+}
+
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
new file mode 100644
index 000000000..2acd46ff8
--- /dev/null
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -0,0 +1,98 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "common/common_types.h"
+#include "core/hle/kernel/writable_event.h"
+
+namespace Service::NVFlinger {
+class BufferQueue;
+}
+
+namespace Service::VI {
+
+class Layer;
+
+/// Represents a single display type
+class Display {
+public:
+ /// Constructs a display with a given unique ID and name.
+ ///
+ /// @param id The unique ID for this display.
+ /// @param name The name for this display.
+ ///
+ Display(u64 id, std::string name);
+ ~Display();
+
+ Display(const Display&) = delete;
+ Display& operator=(const Display&) = delete;
+
+ Display(Display&&) = default;
+ Display& operator=(Display&&) = default;
+
+ /// Gets the unique ID assigned to this display.
+ u64 GetID() const {
+ return id;
+ }
+
+ /// Gets the name of this display
+ const std::string& GetName() const {
+ return name;
+ }
+
+ /// Whether or not this display has any layers added to it.
+ bool HasLayers() const {
+ return !layers.empty();
+ }
+
+ /// Gets a layer for this display based off an index.
+ Layer& GetLayer(std::size_t index);
+
+ /// Gets a layer for this display based off an index.
+ const Layer& GetLayer(std::size_t index) const;
+
+ /// Gets the readable vsync event.
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetVSyncEvent() const;
+
+ /// Signals the internal vsync event.
+ void SignalVSyncEvent();
+
+ /// Creates and adds a layer to this display with the given ID.
+ ///
+ /// @param id The ID to assign to the created layer.
+ /// @param buffer_queue The buffer queue for the layer instance to use.
+ ///
+ void CreateLayer(u64 id, NVFlinger::BufferQueue& buffer_queue);
+
+ /// Attempts to find a layer with the given ID.
+ ///
+ /// @param id The layer ID.
+ ///
+ /// @returns If found, the Layer instance with the given ID.
+ /// If not found, then nullptr is returned.
+ ///
+ Layer* FindLayer(u64 id);
+
+ /// Attempts to find a layer with the given ID.
+ ///
+ /// @param id The layer ID.
+ ///
+ /// @returns If found, the Layer instance with the given ID.
+ /// If not found, then nullptr is returned.
+ ///
+ const Layer* FindLayer(u64 id) const;
+
+private:
+ u64 id;
+ std::string name;
+
+ std::vector<Layer> layers;
+ Kernel::EventPair vsync_event;
+};
+
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
new file mode 100644
index 000000000..954225c26
--- /dev/null
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -0,0 +1,13 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/vi/layer/vi_layer.h"
+
+namespace Service::VI {
+
+Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : id{id}, buffer_queue{queue} {}
+
+Layer::~Layer() = default;
+
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
new file mode 100644
index 000000000..c6bfd01f6
--- /dev/null
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -0,0 +1,52 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Service::NVFlinger {
+class BufferQueue;
+}
+
+namespace Service::VI {
+
+/// Represents a single display layer.
+class Layer {
+public:
+ /// Constructs a layer with a given ID and buffer queue.
+ ///
+ /// @param id The ID to assign to this layer.
+ /// @param queue The buffer queue for this layer to use.
+ ///
+ Layer(u64 id, NVFlinger::BufferQueue& queue);
+ ~Layer();
+
+ Layer(const Layer&) = delete;
+ Layer& operator=(const Layer&) = delete;
+
+ Layer(Layer&&) = default;
+ Layer& operator=(Layer&&) = delete;
+
+ /// Gets the ID for this layer.
+ u64 GetID() const {
+ return id;
+ }
+
+ /// Gets a reference to the buffer queue this layer is using.
+ NVFlinger::BufferQueue& GetBufferQueue() {
+ return buffer_queue;
+ }
+
+ /// Gets a const reference to the buffer queue this layer is using.
+ const NVFlinger::BufferQueue& GetBufferQueue() const {
+ return buffer_queue;
+ }
+
+private:
+ u64 id;
+ NVFlinger::BufferQueue& buffer_queue;
+};
+
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index a317a2885..7369a09ec 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -525,7 +525,7 @@ private:
LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
static_cast<u32>(transaction), flags);
- auto buffer_queue = nv_flinger->FindBufferQueue(id);
+ auto& buffer_queue = nv_flinger->FindBufferQueue(id);
if (transaction == TransactionId::Connect) {
IGBPConnectRequestParcel request{ctx.ReadBuffer()};
@@ -538,7 +538,7 @@ private:
} else if (transaction == TransactionId::SetPreallocatedBuffer) {
IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
- buffer_queue->SetPreallocatedBuffer(request.data.slot, request.buffer);
+ buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer);
IGBPSetPreallocatedBufferResponseParcel response{};
ctx.WriteBuffer(response.Serialize());
@@ -546,7 +546,7 @@ private:
IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
const u32 width{request.data.width};
const u32 height{request.data.height};
- std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+ std::optional<u32> slot = buffer_queue.DequeueBuffer(width, height);
if (slot) {
// Buffer is available
@@ -559,8 +559,8 @@ private:
[=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
Kernel::ThreadWakeupReason reason) {
// Repeat TransactParcel DequeueBuffer when a buffer is available
- auto buffer_queue = nv_flinger->FindBufferQueue(id);
- std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+ auto& buffer_queue = nv_flinger->FindBufferQueue(id);
+ std::optional<u32> slot = buffer_queue.DequeueBuffer(width, height);
ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer.");
IGBPDequeueBufferResponseParcel response{*slot};
@@ -568,28 +568,28 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
},
- buffer_queue->GetWritableBufferWaitEvent());
+ buffer_queue.GetWritableBufferWaitEvent());
}
} else if (transaction == TransactionId::RequestBuffer) {
IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
- auto& buffer = buffer_queue->RequestBuffer(request.slot);
+ auto& buffer = buffer_queue.RequestBuffer(request.slot);
IGBPRequestBufferResponseParcel response{buffer};
ctx.WriteBuffer(response.Serialize());
} else if (transaction == TransactionId::QueueBuffer) {
IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()};
- buffer_queue->QueueBuffer(request.data.slot, request.data.transform,
- request.data.GetCropRect());
+ buffer_queue.QueueBuffer(request.data.slot, request.data.transform,
+ request.data.GetCropRect());
IGBPQueueBufferResponseParcel response{1280, 720};
ctx.WriteBuffer(response.Serialize());
} else if (transaction == TransactionId::Query) {
IGBPQueryRequestParcel request{ctx.ReadBuffer()};
- u32 value =
- buffer_queue->Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
+ const u32 value =
+ buffer_queue.Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
IGBPQueryResponseParcel response{value};
ctx.WriteBuffer(response.Serialize());
@@ -629,12 +629,12 @@ private:
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
- const auto buffer_queue = nv_flinger->FindBufferQueue(id);
+ const auto& buffer_queue = nv_flinger->FindBufferQueue(id);
// TODO(Subv): Find out what this actually is.
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent());
+ rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent());
}
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;