summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-08-31 11:31:20 -0400
committerGravatar GitHub2018-08-31 11:31:20 -0400
commitf08d24e9c0a8dd7920ca5db5a5765b867eb1d714 (patch)
treef2b144f08f5881d4e1174d9eb0184cf6548f20ce /src
parentMerge pull request #1207 from degasus/hotfix (diff)
parentcore: Make the main System class use the PImpl idiom (diff)
downloadyuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.tar.gz
yuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.tar.xz
yuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.zip
Merge pull request #1204 from lioncash/pimpl
core: Make the main System class use the PImpl idiom
Diffstat (limited to 'src')
-rw-r--r--src/core/core.cpp515
-rw-r--r--src/core/core.h138
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp3
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp7
5 files changed, 387 insertions, 279 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 2293669e5..75c259068 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -27,135 +27,299 @@ namespace Core {
27 27
28/*static*/ System System::s_instance; 28/*static*/ System System::s_instance;
29 29
30System::System() = default; 30namespace {
31FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
32 const std::string& path) {
33 // To account for split 00+01+etc files.
34 std::string dir_name;
35 std::string filename;
36 Common::SplitPath(path, &dir_name, &filename, nullptr);
37 if (filename == "00") {
38 const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read);
39 std::vector<FileSys::VirtualFile> concat;
40 for (u8 i = 0; i < 0x10; ++i) {
41 auto next = dir->GetFile(fmt::format("{:02X}", i));
42 if (next != nullptr)
43 concat.push_back(std::move(next));
44 else {
45 next = dir->GetFile(fmt::format("{:02x}", i));
46 if (next != nullptr)
47 concat.push_back(std::move(next));
48 else
49 break;
50 }
51 }
31 52
32System::~System() = default; 53 if (concat.empty())
54 return nullptr;
55
56 return FileSys::ConcatenateFiles(concat, dir->GetName());
57 }
58
59 return vfs->OpenFile(path, FileSys::Mode::Read);
60}
33 61
34/// Runs a CPU core while the system is powered on 62/// Runs a CPU core while the system is powered on
35static void RunCpuCore(std::shared_ptr<Cpu> cpu_state) { 63void RunCpuCore(std::shared_ptr<Cpu> cpu_state) {
36 while (Core::System::GetInstance().IsPoweredOn()) { 64 while (Core::System::GetInstance().IsPoweredOn()) {
37 cpu_state->RunLoop(true); 65 cpu_state->RunLoop(true);
38 } 66 }
39} 67}
68} // Anonymous namespace
40 69
41Cpu& System::CurrentCpuCore() { 70struct System::Impl {
42 // If multicore is enabled, use host thread to figure out the current CPU core 71 Cpu& CurrentCpuCore() {
43 if (Settings::values.use_multi_core) { 72 if (Settings::values.use_multi_core) {
44 const auto& search = thread_to_cpu.find(std::this_thread::get_id()); 73 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
45 ASSERT(search != thread_to_cpu.end()); 74 ASSERT(search != thread_to_cpu.end());
46 ASSERT(search->second); 75 ASSERT(search->second);
47 return *search->second; 76 return *search->second;
77 }
78
79 // Otherwise, use single-threaded mode active_core variable
80 return *cpu_cores[active_core];
48 } 81 }
49 82
50 // Otherwise, use single-threaded mode active_core variable 83 ResultStatus RunLoop(bool tight_loop) {
51 return *cpu_cores[active_core]; 84 status = ResultStatus::Success;
52}
53 85
54System::ResultStatus System::RunLoop(bool tight_loop) { 86 // Update thread_to_cpu in case Core 0 is run from a different host thread
55 status = ResultStatus::Success; 87 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
56 88
57 // Update thread_to_cpu in case Core 0 is run from a different host thread 89 if (GDBStub::IsServerEnabled()) {
58 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; 90 GDBStub::HandlePacket();
59 91
60 if (GDBStub::IsServerEnabled()) { 92 // If the loop is halted and we want to step, use a tiny (1) number of instructions to
61 GDBStub::HandlePacket(); 93 // execute. Otherwise, get out of the loop function.
94 if (GDBStub::GetCpuHaltFlag()) {
95 if (GDBStub::GetCpuStepFlag()) {
96 tight_loop = false;
97 } else {
98 return ResultStatus::Success;
99 }
100 }
101 }
62 102
63 // If the loop is halted and we want to step, use a tiny (1) number of instructions to 103 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
64 // execute. Otherwise, get out of the loop function. 104 cpu_cores[active_core]->RunLoop(tight_loop);
65 if (GDBStub::GetCpuHaltFlag()) { 105 if (Settings::values.use_multi_core) {
66 if (GDBStub::GetCpuStepFlag()) { 106 // Cores 1-3 are run on other threads in this mode
67 tight_loop = false; 107 break;
68 } else {
69 return ResultStatus::Success;
70 } 108 }
71 } 109 }
110
111 if (GDBStub::IsServerEnabled()) {
112 GDBStub::SetCpuStepFlag(false);
113 }
114
115 return status;
72 } 116 }
73 117
74 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { 118 ResultStatus Init(Frontend::EmuWindow& emu_window) {
75 cpu_cores[active_core]->RunLoop(tight_loop); 119 LOG_DEBUG(HW_Memory, "initialized OK");
120
121 CoreTiming::Init();
122 kernel.Initialize();
123
124 // Create a default fs if one doesn't already exist.
125 if (virtual_filesystem == nullptr)
126 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
127
128 current_process = Kernel::Process::Create(kernel, "main");
129
130 cpu_barrier = std::make_shared<CpuBarrier>();
131 cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
132 for (size_t index = 0; index < cpu_cores.size(); ++index) {
133 cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index);
134 }
135
136 telemetry_session = std::make_unique<Core::TelemetrySession>();
137 service_manager = std::make_shared<Service::SM::ServiceManager>();
138
139 Service::Init(service_manager, virtual_filesystem);
140 GDBStub::Init();
141
142 renderer = VideoCore::CreateRenderer(emu_window);
143 if (!renderer->Init()) {
144 return ResultStatus::ErrorVideoCore;
145 }
146
147 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
148
149 // Create threads for CPU cores 1-3, and build thread_to_cpu map
150 // CPU core 0 is run on the main thread
151 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
76 if (Settings::values.use_multi_core) { 152 if (Settings::values.use_multi_core) {
77 // Cores 1-3 are run on other threads in this mode 153 for (size_t index = 0; index < cpu_core_threads.size(); ++index) {
78 break; 154 cpu_core_threads[index] =
155 std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]);
156 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1];
157 }
79 } 158 }
80 }
81 159
82 if (GDBStub::IsServerEnabled()) { 160 LOG_DEBUG(Core, "Initialized OK");
83 GDBStub::SetCpuStepFlag(false); 161
162 // Reset counters and set time origin to current frame
163 GetAndResetPerfStats();
164 perf_stats.BeginSystemFrame();
165
166 return ResultStatus::Success;
84 } 167 }
85 168
86 return status; 169 ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
87} 170 app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
88 171
89System::ResultStatus System::SingleStep() { 172 if (!app_loader) {
90 return RunLoop(false); 173 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
91} 174 return ResultStatus::ErrorGetLoader;
175 }
176 std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
177 app_loader->LoadKernelSystemMode();
92 178
93static FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, 179 if (system_mode.second != Loader::ResultStatus::Success) {
94 const std::string& path) { 180 LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
95 // To account for split 00+01+etc files. 181 static_cast<int>(system_mode.second));
96 std::string dir_name; 182
97 std::string filename; 183 return ResultStatus::ErrorSystemMode;
98 Common::SplitPath(path, &dir_name, &filename, nullptr);
99 if (filename == "00") {
100 const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read);
101 std::vector<FileSys::VirtualFile> concat;
102 for (u8 i = 0; i < 0x10; ++i) {
103 auto next = dir->GetFile(fmt::format("{:02X}", i));
104 if (next != nullptr)
105 concat.push_back(std::move(next));
106 else {
107 next = dir->GetFile(fmt::format("{:02x}", i));
108 if (next != nullptr)
109 concat.push_back(std::move(next));
110 else
111 break;
112 }
113 } 184 }
114 185
115 if (concat.empty()) 186 ResultStatus init_result{Init(emu_window)};
116 return nullptr; 187 if (init_result != ResultStatus::Success) {
188 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
189 static_cast<int>(init_result));
190 Shutdown();
191 return init_result;
192 }
117 193
118 return FileSys::ConcatenateFiles(concat, dir->GetName()); 194 const Loader::ResultStatus load_result{app_loader->Load(current_process)};
195 if (load_result != Loader::ResultStatus::Success) {
196 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
197 Shutdown();
198
199 return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
200 static_cast<u32>(load_result));
201 }
202 status = ResultStatus::Success;
203 return status;
119 } 204 }
120 205
121 return vfs->OpenFile(path, FileSys::Mode::Read); 206 void Shutdown() {
122} 207 // Log last frame performance stats
208 auto perf_results = GetAndResetPerfStats();
209 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed",
210 perf_results.emulation_speed * 100.0);
211 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate",
212 perf_results.game_fps);
213 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
214 perf_results.frametime * 1000.0);
215
216 // Shutdown emulation session
217 renderer.reset();
218 GDBStub::Shutdown();
219 Service::Shutdown();
220 service_manager.reset();
221 telemetry_session.reset();
222 gpu_core.reset();
223
224 // Close all CPU/threading state
225 cpu_barrier->NotifyEnd();
226 if (Settings::values.use_multi_core) {
227 for (auto& thread : cpu_core_threads) {
228 thread->join();
229 thread.reset();
230 }
231 }
232 thread_to_cpu.clear();
233 for (auto& cpu_core : cpu_cores) {
234 cpu_core.reset();
235 }
236 cpu_barrier.reset();
123 237
124System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 238 // Shutdown kernel and core timing
125 app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); 239 kernel.Shutdown();
240 CoreTiming::Shutdown();
241
242 // Close app loader
243 app_loader.reset();
126 244
127 if (!app_loader) { 245 LOG_DEBUG(Core, "Shutdown OK");
128 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
129 return ResultStatus::ErrorGetLoader;
130 } 246 }
131 std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
132 app_loader->LoadKernelSystemMode();
133 247
134 if (system_mode.second != Loader::ResultStatus::Success) { 248 Loader::ResultStatus GetGameName(std::string& out) const {
135 LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", 249 if (app_loader == nullptr)
136 static_cast<int>(system_mode.second)); 250 return Loader::ResultStatus::ErrorNotInitialized;
251 return app_loader->ReadTitle(out);
252 }
137 253
138 return ResultStatus::ErrorSystemMode; 254 void SetStatus(ResultStatus new_status, const char* details = nullptr) {
255 status = new_status;
256 if (details) {
257 status_details = details;
258 }
139 } 259 }
140 260
141 ResultStatus init_result{Init(emu_window)}; 261 PerfStats::Results GetAndResetPerfStats() {
142 if (init_result != ResultStatus::Success) { 262 return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs());
143 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
144 static_cast<int>(init_result));
145 System::Shutdown();
146 return init_result;
147 } 263 }
148 264
149 const Loader::ResultStatus load_result{app_loader->Load(current_process)}; 265 Kernel::KernelCore kernel;
150 if (load_result != Loader::ResultStatus::Success) { 266 /// RealVfsFilesystem instance
151 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); 267 FileSys::VirtualFilesystem virtual_filesystem;
152 System::Shutdown(); 268 /// AppLoader used to load the current executing application
269 std::unique_ptr<Loader::AppLoader> app_loader;
270 std::unique_ptr<VideoCore::RendererBase> renderer;
271 std::unique_ptr<Tegra::GPU> gpu_core;
272 std::shared_ptr<Tegra::DebugContext> debug_context;
273 Kernel::SharedPtr<Kernel::Process> current_process;
274 std::shared_ptr<ExclusiveMonitor> cpu_exclusive_monitor;
275 std::shared_ptr<CpuBarrier> cpu_barrier;
276 std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
277 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
278 size_t active_core{}; ///< Active core, only used in single thread mode
279
280 /// Service manager
281 std::shared_ptr<Service::SM::ServiceManager> service_manager;
282
283 /// Telemetry session for this emulation session
284 std::unique_ptr<Core::TelemetrySession> telemetry_session;
285
286 ResultStatus status = ResultStatus::Success;
287 std::string status_details = "";
288
289 /// Map of guest threads to CPU cores
290 std::map<std::thread::id, std::shared_ptr<Cpu>> thread_to_cpu;
291
292 Core::PerfStats perf_stats;
293 Core::FrameLimiter frame_limiter;
294};
295
296System::System() : impl{std::make_unique<Impl>()} {}
297System::~System() = default;
298
299Cpu& System::CurrentCpuCore() {
300 return impl->CurrentCpuCore();
301}
302
303System::ResultStatus System::RunLoop(bool tight_loop) {
304 return impl->RunLoop(tight_loop);
305}
306
307System::ResultStatus System::SingleStep() {
308 return RunLoop(false);
309}
153 310
154 return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + 311void System::InvalidateCpuInstructionCaches() {
155 static_cast<u32>(load_result)); 312 for (auto& cpu : impl->cpu_cores) {
313 cpu->ArmInterface().ClearInstructionCache();
156 } 314 }
157 status = ResultStatus::Success; 315}
158 return status; 316
317System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
318 return impl->Load(emu_window, filepath);
319}
320
321bool System::IsPoweredOn() const {
322 return impl->cpu_barrier && impl->cpu_barrier->IsAlive();
159} 323}
160 324
161void System::PrepareReschedule() { 325void System::PrepareReschedule() {
@@ -163,131 +327,134 @@ void System::PrepareReschedule() {
163} 327}
164 328
165PerfStats::Results System::GetAndResetPerfStats() { 329PerfStats::Results System::GetAndResetPerfStats() {
166 return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs()); 330 return impl->GetAndResetPerfStats();
167} 331}
168 332
169const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) { 333Core::TelemetrySession& System::TelemetrySession() const {
170 ASSERT(core_index < NUM_CPU_CORES); 334 return *impl->telemetry_session;
171 return cpu_cores[core_index]->Scheduler();
172} 335}
173 336
174Kernel::KernelCore& System::Kernel() { 337ARM_Interface& System::CurrentArmInterface() {
175 return kernel; 338 return CurrentCpuCore().ArmInterface();
176} 339}
177 340
178const Kernel::KernelCore& System::Kernel() const { 341size_t System::CurrentCoreIndex() {
179 return kernel; 342 return CurrentCpuCore().CoreIndex();
343}
344
345Kernel::Scheduler& System::CurrentScheduler() {
346 return *CurrentCpuCore().Scheduler();
347}
348
349const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) {
350 ASSERT(core_index < NUM_CPU_CORES);
351 return impl->cpu_cores[core_index]->Scheduler();
352}
353
354Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() {
355 return impl->current_process;
180} 356}
181 357
182ARM_Interface& System::ArmInterface(size_t core_index) { 358ARM_Interface& System::ArmInterface(size_t core_index) {
183 ASSERT(core_index < NUM_CPU_CORES); 359 ASSERT(core_index < NUM_CPU_CORES);
184 return cpu_cores[core_index]->ArmInterface(); 360 return impl->cpu_cores[core_index]->ArmInterface();
185} 361}
186 362
187Cpu& System::CpuCore(size_t core_index) { 363Cpu& System::CpuCore(size_t core_index) {
188 ASSERT(core_index < NUM_CPU_CORES); 364 ASSERT(core_index < NUM_CPU_CORES);
189 return *cpu_cores[core_index]; 365 return *impl->cpu_cores[core_index];
190} 366}
191 367
192System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { 368ExclusiveMonitor& System::Monitor() {
193 LOG_DEBUG(HW_Memory, "initialized OK"); 369 return *impl->cpu_exclusive_monitor;
370}
194 371
195 CoreTiming::Init(); 372Tegra::GPU& System::GPU() {
196 kernel.Initialize(); 373 return *impl->gpu_core;
374}
197 375
198 // Create a default fs if one doesn't already exist. 376const Tegra::GPU& System::GPU() const {
199 if (virtual_filesystem == nullptr) 377 return *impl->gpu_core;
200 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); 378}
201 379
202 current_process = Kernel::Process::Create(kernel, "main"); 380VideoCore::RendererBase& System::Renderer() {
381 return *impl->renderer;
382}
203 383
204 cpu_barrier = std::make_shared<CpuBarrier>(); 384const VideoCore::RendererBase& System::Renderer() const {
205 cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size()); 385 return *impl->renderer;
206 for (size_t index = 0; index < cpu_cores.size(); ++index) { 386}
207 cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index);
208 }
209 387
210 telemetry_session = std::make_unique<Core::TelemetrySession>(); 388Kernel::KernelCore& System::Kernel() {
211 service_manager = std::make_shared<Service::SM::ServiceManager>(); 389 return impl->kernel;
390}
212 391
213 Service::Init(service_manager, virtual_filesystem); 392const Kernel::KernelCore& System::Kernel() const {
214 GDBStub::Init(); 393 return impl->kernel;
394}
215 395
216 renderer = VideoCore::CreateRenderer(emu_window); 396Core::PerfStats& System::GetPerfStats() {
217 if (!renderer->Init()) { 397 return impl->perf_stats;
218 return ResultStatus::ErrorVideoCore; 398}
219 }
220 399
221 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); 400const Core::PerfStats& System::GetPerfStats() const {
401 return impl->perf_stats;
402}
222 403
223 // Create threads for CPU cores 1-3, and build thread_to_cpu map 404Core::FrameLimiter& System::FrameLimiter() {
224 // CPU core 0 is run on the main thread 405 return impl->frame_limiter;
225 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; 406}
226 if (Settings::values.use_multi_core) {
227 for (size_t index = 0; index < cpu_core_threads.size(); ++index) {
228 cpu_core_threads[index] =
229 std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]);
230 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1];
231 }
232 }
233 407
234 LOG_DEBUG(Core, "Initialized OK"); 408const Core::FrameLimiter& System::FrameLimiter() const {
409 return impl->frame_limiter;
410}
235 411
236 // Reset counters and set time origin to current frame 412Loader::ResultStatus System::GetGameName(std::string& out) const {
237 GetAndResetPerfStats(); 413 return impl->GetGameName(out);
238 perf_stats.BeginSystemFrame(); 414}
239 415
240 return ResultStatus::Success; 416void System::SetStatus(ResultStatus new_status, const char* details) {
417 impl->SetStatus(new_status, details);
241} 418}
242 419
243void System::Shutdown() { 420const std::string& System::GetStatusDetails() const {
244 // Log last frame performance stats 421 return impl->status_details;
245 auto perf_results = GetAndResetPerfStats(); 422}
246 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed",
247 perf_results.emulation_speed * 100.0);
248 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate",
249 perf_results.game_fps);
250 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
251 perf_results.frametime * 1000.0);
252
253 // Shutdown emulation session
254 renderer.reset();
255 GDBStub::Shutdown();
256 Service::Shutdown();
257 service_manager.reset();
258 telemetry_session.reset();
259 gpu_core.reset();
260
261 // Close all CPU/threading state
262 cpu_barrier->NotifyEnd();
263 if (Settings::values.use_multi_core) {
264 for (auto& thread : cpu_core_threads) {
265 thread->join();
266 thread.reset();
267 }
268 }
269 thread_to_cpu.clear();
270 for (auto& cpu_core : cpu_cores) {
271 cpu_core.reset();
272 }
273 cpu_barrier.reset();
274 423
275 // Shutdown kernel and core timing 424Loader::AppLoader& System::GetAppLoader() const {
276 kernel.Shutdown(); 425 return *impl->app_loader;
277 CoreTiming::Shutdown(); 426}
278 427
279 // Close app loader 428void System::SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) {
280 app_loader.reset(); 429 impl->debug_context = std::move(context);
430}
281 431
282 LOG_DEBUG(Core, "Shutdown OK"); 432std::shared_ptr<Tegra::DebugContext> System::GetGPUDebugContext() const {
433 return impl->debug_context;
434}
435
436void System::SetFilesystem(FileSys::VirtualFilesystem vfs) {
437 impl->virtual_filesystem = std::move(vfs);
438}
439
440FileSys::VirtualFilesystem System::GetFilesystem() const {
441 return impl->virtual_filesystem;
442}
443
444System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
445 return impl->Init(emu_window);
446}
447
448void System::Shutdown() {
449 impl->Shutdown();
283} 450}
284 451
285Service::SM::ServiceManager& System::ServiceManager() { 452Service::SM::ServiceManager& System::ServiceManager() {
286 return *service_manager; 453 return *impl->service_manager;
287} 454}
288 455
289const Service::SM::ServiceManager& System::ServiceManager() const { 456const Service::SM::ServiceManager& System::ServiceManager() const {
290 return *service_manager; 457 return *impl->service_manager;
291} 458}
292 459
293} // namespace Core 460} // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index 2c18f7193..984e8f94c 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -94,11 +94,7 @@ public:
94 * This function should only be used by GDB Stub to support breakpoints, memory updates and 94 * This function should only be used by GDB Stub to support breakpoints, memory updates and
95 * step/continue commands. 95 * step/continue commands.
96 */ 96 */
97 void InvalidateCpuInstructionCaches() { 97 void InvalidateCpuInstructionCaches();
98 for (auto& cpu : cpu_cores) {
99 cpu->ArmInterface().ClearInstructionCache();
100 }
101 }
102 98
103 /// Shutdown the emulated system. 99 /// Shutdown the emulated system.
104 void Shutdown(); 100 void Shutdown();
@@ -117,17 +113,13 @@ public:
117 * application). 113 * application).
118 * @returns True if the emulated system is powered on, otherwise false. 114 * @returns True if the emulated system is powered on, otherwise false.
119 */ 115 */
120 bool IsPoweredOn() const { 116 bool IsPoweredOn() const;
121 return cpu_barrier && cpu_barrier->IsAlive();
122 }
123 117
124 /** 118 /**
125 * Returns a reference to the telemetry session for this emulation session. 119 * Returns a reference to the telemetry session for this emulation session.
126 * @returns Reference to the telemetry session. 120 * @returns Reference to the telemetry session.
127 */ 121 */
128 Core::TelemetrySession& TelemetrySession() const { 122 Core::TelemetrySession& TelemetrySession() const;
129 return *telemetry_session;
130 }
131 123
132 /// Prepare the core emulation for a reschedule 124 /// Prepare the core emulation for a reschedule
133 void PrepareReschedule(); 125 void PrepareReschedule();
@@ -136,14 +128,13 @@ public:
136 PerfStats::Results GetAndResetPerfStats(); 128 PerfStats::Results GetAndResetPerfStats();
137 129
138 /// Gets an ARM interface to the CPU core that is currently running 130 /// Gets an ARM interface to the CPU core that is currently running
139 ARM_Interface& CurrentArmInterface() { 131 ARM_Interface& CurrentArmInterface();
140 return CurrentCpuCore().ArmInterface();
141 }
142 132
143 /// Gets the index of the currently running CPU core 133 /// Gets the index of the currently running CPU core
144 size_t CurrentCoreIndex() { 134 size_t CurrentCoreIndex();
145 return CurrentCpuCore().CoreIndex(); 135
146 } 136 /// Gets the scheduler for the CPU core that is currently running
137 Kernel::Scheduler& CurrentScheduler();
147 138
148 /// Gets an ARM interface to the CPU core with the specified index 139 /// Gets an ARM interface to the CPU core with the specified index
149 ARM_Interface& ArmInterface(size_t core_index); 140 ARM_Interface& ArmInterface(size_t core_index);
@@ -151,43 +142,26 @@ public:
151 /// Gets a CPU interface to the CPU core with the specified index 142 /// Gets a CPU interface to the CPU core with the specified index
152 Cpu& CpuCore(size_t core_index); 143 Cpu& CpuCore(size_t core_index);
153 144
145 /// Gets the exclusive monitor
146 ExclusiveMonitor& Monitor();
147
154 /// Gets a mutable reference to the GPU interface 148 /// Gets a mutable reference to the GPU interface
155 Tegra::GPU& GPU() { 149 Tegra::GPU& GPU();
156 return *gpu_core;
157 }
158 150
159 /// Gets an immutable reference to the GPU interface. 151 /// Gets an immutable reference to the GPU interface.
160 const Tegra::GPU& GPU() const { 152 const Tegra::GPU& GPU() const;
161 return *gpu_core;
162 }
163 153
164 /// Gets a mutable reference to the renderer. 154 /// Gets a mutable reference to the renderer.
165 VideoCore::RendererBase& Renderer() { 155 VideoCore::RendererBase& Renderer();
166 return *renderer;
167 }
168 156
169 /// Gets an immutable reference to the renderer. 157 /// Gets an immutable reference to the renderer.
170 const VideoCore::RendererBase& Renderer() const { 158 const VideoCore::RendererBase& Renderer() const;
171 return *renderer;
172 }
173
174 /// Gets the scheduler for the CPU core that is currently running
175 Kernel::Scheduler& CurrentScheduler() {
176 return *CurrentCpuCore().Scheduler();
177 }
178
179 /// Gets the exclusive monitor
180 ExclusiveMonitor& Monitor() {
181 return *cpu_exclusive_monitor;
182 }
183 159
184 /// Gets the scheduler for the CPU core with the specified index 160 /// Gets the scheduler for the CPU core with the specified index
185 const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index); 161 const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index);
186 162
187 /// Gets the current process 163 /// Gets the current process
188 Kernel::SharedPtr<Kernel::Process>& CurrentProcess() { 164 Kernel::SharedPtr<Kernel::Process>& CurrentProcess();
189 return current_process;
190 }
191 165
192 /// Provides a reference to the kernel instance. 166 /// Provides a reference to the kernel instance.
193 Kernel::KernelCore& Kernel(); 167 Kernel::KernelCore& Kernel();
@@ -195,49 +169,37 @@ public:
195 /// Provides a constant reference to the kernel instance. 169 /// Provides a constant reference to the kernel instance.
196 const Kernel::KernelCore& Kernel() const; 170 const Kernel::KernelCore& Kernel() const;
197 171
198 /// Gets the name of the current game 172 /// Provides a reference to the internal PerfStats instance.
199 Loader::ResultStatus GetGameName(std::string& out) const { 173 Core::PerfStats& GetPerfStats();
200 if (app_loader == nullptr)
201 return Loader::ResultStatus::ErrorNotInitialized;
202 return app_loader->ReadTitle(out);
203 }
204 174
205 PerfStats perf_stats; 175 /// Provides a constant reference to the internal PerfStats instance.
206 FrameLimiter frame_limiter; 176 const Core::PerfStats& GetPerfStats() const;
207 177
208 void SetStatus(ResultStatus new_status, const char* details = nullptr) { 178 /// Provides a reference to the frame limiter;
209 status = new_status; 179 Core::FrameLimiter& FrameLimiter();
210 if (details) {
211 status_details = details;
212 }
213 }
214 180
215 const std::string& GetStatusDetails() const { 181 /// Provides a constant referent to the frame limiter
216 return status_details; 182 const Core::FrameLimiter& FrameLimiter() const;
217 }
218 183
219 Loader::AppLoader& GetAppLoader() const { 184 /// Gets the name of the current game
220 return *app_loader; 185 Loader::ResultStatus GetGameName(std::string& out) const;
221 } 186
187 void SetStatus(ResultStatus new_status, const char* details);
188
189 const std::string& GetStatusDetails() const;
190
191 Loader::AppLoader& GetAppLoader() const;
222 192
223 Service::SM::ServiceManager& ServiceManager(); 193 Service::SM::ServiceManager& ServiceManager();
224 const Service::SM::ServiceManager& ServiceManager() const; 194 const Service::SM::ServiceManager& ServiceManager() const;
225 195
226 void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) { 196 void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context);
227 debug_context = std::move(context);
228 }
229 197
230 std::shared_ptr<Tegra::DebugContext> GetGPUDebugContext() const { 198 std::shared_ptr<Tegra::DebugContext> GetGPUDebugContext() const;
231 return debug_context;
232 }
233 199
234 void SetFilesystem(FileSys::VirtualFilesystem vfs) { 200 void SetFilesystem(FileSys::VirtualFilesystem vfs);
235 virtual_filesystem = std::move(vfs);
236 }
237 201
238 FileSys::VirtualFilesystem GetFilesystem() const { 202 FileSys::VirtualFilesystem GetFilesystem() const;
239 return virtual_filesystem;
240 }
241 203
242private: 204private:
243 System(); 205 System();
@@ -253,34 +215,10 @@ private:
253 */ 215 */
254 ResultStatus Init(Frontend::EmuWindow& emu_window); 216 ResultStatus Init(Frontend::EmuWindow& emu_window);
255 217
256 Kernel::KernelCore kernel; 218 struct Impl;
257 /// RealVfsFilesystem instance 219 std::unique_ptr<Impl> impl;
258 FileSys::VirtualFilesystem virtual_filesystem;
259 /// AppLoader used to load the current executing application
260 std::unique_ptr<Loader::AppLoader> app_loader;
261 std::unique_ptr<VideoCore::RendererBase> renderer;
262 std::unique_ptr<Tegra::GPU> gpu_core;
263 std::shared_ptr<Tegra::DebugContext> debug_context;
264 Kernel::SharedPtr<Kernel::Process> current_process;
265 std::shared_ptr<ExclusiveMonitor> cpu_exclusive_monitor;
266 std::shared_ptr<CpuBarrier> cpu_barrier;
267 std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
268 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
269 size_t active_core{}; ///< Active core, only used in single thread mode
270
271 /// Service manager
272 std::shared_ptr<Service::SM::ServiceManager> service_manager;
273
274 /// Telemetry session for this emulation session
275 std::unique_ptr<Core::TelemetrySession> telemetry_session;
276 220
277 static System s_instance; 221 static System s_instance;
278
279 ResultStatus status = ResultStatus::Success;
280 std::string status_details = "";
281
282 /// Map of guest threads to CPU cores
283 std::map<std::thread::id, std::shared_ptr<Cpu>> thread_to_cpu;
284}; 222};
285 223
286inline ARM_Interface& CurrentArmInterface() { 224inline ARM_Interface& CurrentArmInterface() {
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 8bc49935a..0b37098e1 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -7,6 +7,7 @@
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 8#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
9#include "core/hle/service/nvdrv/devices/nvmap.h" 9#include "core/hle/service/nvdrv/devices/nvmap.h"
10#include "core/perf_stats.h"
10#include "video_core/gpu.h" 11#include "video_core/gpu.h"
11#include "video_core/renderer_base.h" 12#include "video_core/renderer_base.h"
12 13
@@ -31,7 +32,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
31 transform, crop_rect}; 32 transform, crop_rect};
32 33
33 auto& instance = Core::System::GetInstance(); 34 auto& instance = Core::System::GetInstance();
34 instance.perf_stats.EndGameFrame(); 35 instance.GetPerfStats().EndGameFrame();
35 instance.Renderer().SwapBuffers(framebuffer); 36 instance.Renderer().SwapBuffers(framebuffer);
36} 37}
37 38
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 3996c24fe..06040da6f 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -17,6 +17,7 @@
17#include "core/hle/service/nvdrv/nvdrv.h" 17#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvflinger/buffer_queue.h" 18#include "core/hle/service/nvflinger/buffer_queue.h"
19#include "core/hle/service/nvflinger/nvflinger.h" 19#include "core/hle/service/nvflinger/nvflinger.h"
20#include "core/perf_stats.h"
20#include "video_core/renderer_base.h" 21#include "video_core/renderer_base.h"
21#include "video_core/video_core.h" 22#include "video_core/video_core.h"
22 23
@@ -137,7 +138,7 @@ void NVFlinger::Compose() {
137 auto& system_instance = Core::System::GetInstance(); 138 auto& system_instance = Core::System::GetInstance();
138 139
139 // There was no queued buffer to draw, render previous frame 140 // There was no queued buffer to draw, render previous frame
140 system_instance.perf_stats.EndGameFrame(); 141 system_instance.GetPerfStats().EndGameFrame();
141 system_instance.Renderer().SwapBuffers({}); 142 system_instance.Renderer().SwapBuffers({});
142 continue; 143 continue;
143 } 144 }
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 73d6419b4..3c4a9f17c 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -14,6 +14,7 @@
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/frontend/emu_window.h" 15#include "core/frontend/emu_window.h"
16#include "core/memory.h" 16#include "core/memory.h"
17#include "core/perf_stats.h"
17#include "core/settings.h" 18#include "core/settings.h"
18#include "core/tracer/recorder.h" 19#include "core/tracer/recorder.h"
19#include "video_core/renderer_opengl/gl_rasterizer.h" 20#include "video_core/renderer_opengl/gl_rasterizer.h"
@@ -115,7 +116,7 @@ RendererOpenGL::~RendererOpenGL() = default;
115void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { 116void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) {
116 ScopeAcquireGLContext acquire_context{render_window}; 117 ScopeAcquireGLContext acquire_context{render_window};
117 118
118 Core::System::GetInstance().perf_stats.EndSystemFrame(); 119 Core::System::GetInstance().GetPerfStats().EndSystemFrame();
119 120
120 // Maintain the rasterizer's state as a priority 121 // Maintain the rasterizer's state as a priority
121 OpenGLState prev_state = OpenGLState::GetCurState(); 122 OpenGLState prev_state = OpenGLState::GetCurState();
@@ -140,8 +141,8 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&
140 141
141 render_window.PollEvents(); 142 render_window.PollEvents();
142 143
143 Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); 144 Core::System::GetInstance().FrameLimiter().DoFrameLimiting(CoreTiming::GetGlobalTimeUs());
144 Core::System::GetInstance().perf_stats.BeginSystemFrame(); 145 Core::System::GetInstance().GetPerfStats().BeginSystemFrame();
145 146
146 // Restore the rasterizer state 147 // Restore the rasterizer state
147 prev_state.Apply(); 148 prev_state.Apply();