diff options
author | bunnei <bunneidev@gmail.com> | 2018-08-31 17:31:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-31 17:31:20 +0200 |
commit | f08d24e9c0a8dd7920ca5db5a5765b867eb1d714 (patch) | |
tree | f2b144f08f5881d4e1174d9eb0184cf6548f20ce | |
parent | Merge pull request #1207 from degasus/hotfix (diff) | |
parent | core: Make the main System class use the PImpl idiom (diff) | |
download | yuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.tar yuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.tar.gz yuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.tar.bz2 yuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.tar.lz yuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.tar.xz yuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.tar.zst yuzu-f08d24e9c0a8dd7920ca5db5a5765b867eb1d714.zip |
-rw-r--r-- | src/core/core.cpp | 515 | ||||
-rw-r--r-- | src/core/core.h | 138 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 3 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 7 |
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 { /*static*/ System System::s_instance; -System::System() = default; +namespace { +FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, + const std::string& path) { + // To account for split 00+01+etc files. + std::string dir_name; + std::string filename; + Common::SplitPath(path, &dir_name, &filename, nullptr); + if (filename == "00") { + const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read); + std::vector<FileSys::VirtualFile> concat; + for (u8 i = 0; i < 0x10; ++i) { + auto next = dir->GetFile(fmt::format("{:02X}", i)); + if (next != nullptr) + concat.push_back(std::move(next)); + else { + next = dir->GetFile(fmt::format("{:02x}", i)); + if (next != nullptr) + concat.push_back(std::move(next)); + else + break; + } + } -System::~System() = default; + if (concat.empty()) + return nullptr; + + return FileSys::ConcatenateFiles(concat, dir->GetName()); + } + + return vfs->OpenFile(path, FileSys::Mode::Read); +} /// Runs a CPU core while the system is powered on -static void RunCpuCore(std::shared_ptr<Cpu> cpu_state) { +void RunCpuCore(std::shared_ptr<Cpu> cpu_state) { while (Core::System::GetInstance().IsPoweredOn()) { cpu_state->RunLoop(true); } } +} // Anonymous namespace -Cpu& System::CurrentCpuCore() { - // If multicore is enabled, use host thread to figure out the current CPU core - if (Settings::values.use_multi_core) { - const auto& search = thread_to_cpu.find(std::this_thread::get_id()); - ASSERT(search != thread_to_cpu.end()); - ASSERT(search->second); - return *search->second; +struct System::Impl { + Cpu& CurrentCpuCore() { + if (Settings::values.use_multi_core) { + const auto& search = thread_to_cpu.find(std::this_thread::get_id()); + ASSERT(search != thread_to_cpu.end()); + ASSERT(search->second); + return *search->second; + } + + // Otherwise, use single-threaded mode active_core variable + return *cpu_cores[active_core]; } - // Otherwise, use single-threaded mode active_core variable - return *cpu_cores[active_core]; -} + ResultStatus RunLoop(bool tight_loop) { + status = ResultStatus::Success; -System::ResultStatus System::RunLoop(bool tight_loop) { - status = ResultStatus::Success; + // Update thread_to_cpu in case Core 0 is run from a different host thread + thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; - // Update thread_to_cpu in case Core 0 is run from a different host thread - thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; + if (GDBStub::IsServerEnabled()) { + GDBStub::HandlePacket(); - if (GDBStub::IsServerEnabled()) { - GDBStub::HandlePacket(); + // If the loop is halted and we want to step, use a tiny (1) number of instructions to + // execute. Otherwise, get out of the loop function. + if (GDBStub::GetCpuHaltFlag()) { + if (GDBStub::GetCpuStepFlag()) { + tight_loop = false; + } else { + return ResultStatus::Success; + } + } + } - // If the loop is halted and we want to step, use a tiny (1) number of instructions to - // execute. Otherwise, get out of the loop function. - if (GDBStub::GetCpuHaltFlag()) { - if (GDBStub::GetCpuStepFlag()) { - tight_loop = false; - } else { - return ResultStatus::Success; + for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { + cpu_cores[active_core]->RunLoop(tight_loop); + if (Settings::values.use_multi_core) { + // Cores 1-3 are run on other threads in this mode + break; } } + + if (GDBStub::IsServerEnabled()) { + GDBStub::SetCpuStepFlag(false); + } + + return status; } - for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { - cpu_cores[active_core]->RunLoop(tight_loop); + ResultStatus Init(Frontend::EmuWindow& emu_window) { + LOG_DEBUG(HW_Memory, "initialized OK"); + + CoreTiming::Init(); + kernel.Initialize(); + + // Create a default fs if one doesn't already exist. + if (virtual_filesystem == nullptr) + virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); + + current_process = Kernel::Process::Create(kernel, "main"); + + cpu_barrier = std::make_shared<CpuBarrier>(); + cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size()); + for (size_t index = 0; index < cpu_cores.size(); ++index) { + cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index); + } + + telemetry_session = std::make_unique<Core::TelemetrySession>(); + service_manager = std::make_shared<Service::SM::ServiceManager>(); + + Service::Init(service_manager, virtual_filesystem); + GDBStub::Init(); + + renderer = VideoCore::CreateRenderer(emu_window); + if (!renderer->Init()) { + return ResultStatus::ErrorVideoCore; + } + + gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); + + // Create threads for CPU cores 1-3, and build thread_to_cpu map + // CPU core 0 is run on the main thread + thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; if (Settings::values.use_multi_core) { - // Cores 1-3 are run on other threads in this mode - break; + for (size_t index = 0; index < cpu_core_threads.size(); ++index) { + cpu_core_threads[index] = + std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]); + thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1]; + } } - } - if (GDBStub::IsServerEnabled()) { - GDBStub::SetCpuStepFlag(false); + LOG_DEBUG(Core, "Initialized OK"); + + // Reset counters and set time origin to current frame + GetAndResetPerfStats(); + perf_stats.BeginSystemFrame(); + + return ResultStatus::Success; } - return status; -} + ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { + app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); -System::ResultStatus System::SingleStep() { - return RunLoop(false); -} + if (!app_loader) { + LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); + return ResultStatus::ErrorGetLoader; + } + std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode = + app_loader->LoadKernelSystemMode(); -static FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, - const std::string& path) { - // To account for split 00+01+etc files. - std::string dir_name; - std::string filename; - Common::SplitPath(path, &dir_name, &filename, nullptr); - if (filename == "00") { - const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read); - std::vector<FileSys::VirtualFile> concat; - for (u8 i = 0; i < 0x10; ++i) { - auto next = dir->GetFile(fmt::format("{:02X}", i)); - if (next != nullptr) - concat.push_back(std::move(next)); - else { - next = dir->GetFile(fmt::format("{:02x}", i)); - if (next != nullptr) - concat.push_back(std::move(next)); - else - break; - } + if (system_mode.second != Loader::ResultStatus::Success) { + LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", + static_cast<int>(system_mode.second)); + + return ResultStatus::ErrorSystemMode; } - if (concat.empty()) - return nullptr; + ResultStatus init_result{Init(emu_window)}; + if (init_result != ResultStatus::Success) { + LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", + static_cast<int>(init_result)); + Shutdown(); + return init_result; + } - return FileSys::ConcatenateFiles(concat, dir->GetName()); + const Loader::ResultStatus load_result{app_loader->Load(current_process)}; + if (load_result != Loader::ResultStatus::Success) { + LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); + Shutdown(); + + return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + + static_cast<u32>(load_result)); + } + status = ResultStatus::Success; + return status; } - return vfs->OpenFile(path, FileSys::Mode::Read); -} + void Shutdown() { + // Log last frame performance stats + auto perf_results = GetAndResetPerfStats(); + Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed", + perf_results.emulation_speed * 100.0); + Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate", + perf_results.game_fps); + Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", + perf_results.frametime * 1000.0); + + // Shutdown emulation session + renderer.reset(); + GDBStub::Shutdown(); + Service::Shutdown(); + service_manager.reset(); + telemetry_session.reset(); + gpu_core.reset(); + + // Close all CPU/threading state + cpu_barrier->NotifyEnd(); + if (Settings::values.use_multi_core) { + for (auto& thread : cpu_core_threads) { + thread->join(); + thread.reset(); + } + } + thread_to_cpu.clear(); + for (auto& cpu_core : cpu_cores) { + cpu_core.reset(); + } + cpu_barrier.reset(); -System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { - app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); + // Shutdown kernel and core timing + kernel.Shutdown(); + CoreTiming::Shutdown(); + + // Close app loader + app_loader.reset(); - if (!app_loader) { - LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); - return ResultStatus::ErrorGetLoader; + LOG_DEBUG(Core, "Shutdown OK"); } - std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode = - app_loader->LoadKernelSystemMode(); - if (system_mode.second != Loader::ResultStatus::Success) { - LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", - static_cast<int>(system_mode.second)); + Loader::ResultStatus GetGameName(std::string& out) const { + if (app_loader == nullptr) + return Loader::ResultStatus::ErrorNotInitialized; + return app_loader->ReadTitle(out); + } - return ResultStatus::ErrorSystemMode; + void SetStatus(ResultStatus new_status, const char* details = nullptr) { + status = new_status; + if (details) { + status_details = details; + } } - ResultStatus init_result{Init(emu_window)}; - if (init_result != ResultStatus::Success) { - LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", - static_cast<int>(init_result)); - System::Shutdown(); - return init_result; + PerfStats::Results GetAndResetPerfStats() { + return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs()); } - const Loader::ResultStatus load_result{app_loader->Load(current_process)}; - if (load_result != Loader::ResultStatus::Success) { - LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); - System::Shutdown(); + Kernel::KernelCore kernel; + /// RealVfsFilesystem instance + FileSys::VirtualFilesystem virtual_filesystem; + /// AppLoader used to load the current executing application + std::unique_ptr<Loader::AppLoader> app_loader; + std::unique_ptr<VideoCore::RendererBase> renderer; + std::unique_ptr<Tegra::GPU> gpu_core; + std::shared_ptr<Tegra::DebugContext> debug_context; + Kernel::SharedPtr<Kernel::Process> current_process; + std::shared_ptr<ExclusiveMonitor> cpu_exclusive_monitor; + std::shared_ptr<CpuBarrier> cpu_barrier; + std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores; + std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads; + size_t active_core{}; ///< Active core, only used in single thread mode + + /// Service manager + std::shared_ptr<Service::SM::ServiceManager> service_manager; + + /// Telemetry session for this emulation session + std::unique_ptr<Core::TelemetrySession> telemetry_session; + + ResultStatus status = ResultStatus::Success; + std::string status_details = ""; + + /// Map of guest threads to CPU cores + std::map<std::thread::id, std::shared_ptr<Cpu>> thread_to_cpu; + + Core::PerfStats perf_stats; + Core::FrameLimiter frame_limiter; +}; + +System::System() : impl{std::make_unique<Impl>()} {} +System::~System() = default; + +Cpu& System::CurrentCpuCore() { + return impl->CurrentCpuCore(); +} + +System::ResultStatus System::RunLoop(bool tight_loop) { + return impl->RunLoop(tight_loop); +} + +System::ResultStatus System::SingleStep() { + return RunLoop(false); +} - return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + - static_cast<u32>(load_result)); +void System::InvalidateCpuInstructionCaches() { + for (auto& cpu : impl->cpu_cores) { + cpu->ArmInterface().ClearInstructionCache(); } - status = ResultStatus::Success; - return status; +} + +System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { + return impl->Load(emu_window, filepath); +} + +bool System::IsPoweredOn() const { + return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); } void System::PrepareReschedule() { @@ -163,131 +327,134 @@ void System::PrepareReschedule() { } PerfStats::Results System::GetAndResetPerfStats() { - return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs()); + return impl->GetAndResetPerfStats(); } -const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) { - ASSERT(core_index < NUM_CPU_CORES); - return cpu_cores[core_index]->Scheduler(); +Core::TelemetrySession& System::TelemetrySession() const { + return *impl->telemetry_session; } -Kernel::KernelCore& System::Kernel() { - return kernel; +ARM_Interface& System::CurrentArmInterface() { + return CurrentCpuCore().ArmInterface(); } -const Kernel::KernelCore& System::Kernel() const { - return kernel; +size_t System::CurrentCoreIndex() { + return CurrentCpuCore().CoreIndex(); +} + +Kernel::Scheduler& System::CurrentScheduler() { + return *CurrentCpuCore().Scheduler(); +} + +const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) { + ASSERT(core_index < NUM_CPU_CORES); + return impl->cpu_cores[core_index]->Scheduler(); +} + +Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() { + return impl->current_process; } ARM_Interface& System::ArmInterface(size_t core_index) { ASSERT(core_index < NUM_CPU_CORES); - return cpu_cores[core_index]->ArmInterface(); + return impl->cpu_cores[core_index]->ArmInterface(); } Cpu& System::CpuCore(size_t core_index) { ASSERT(core_index < NUM_CPU_CORES); - return *cpu_cores[core_index]; + return *impl->cpu_cores[core_index]; } -System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { - LOG_DEBUG(HW_Memory, "initialized OK"); +ExclusiveMonitor& System::Monitor() { + return *impl->cpu_exclusive_monitor; +} - CoreTiming::Init(); - kernel.Initialize(); +Tegra::GPU& System::GPU() { + return *impl->gpu_core; +} - // Create a default fs if one doesn't already exist. - if (virtual_filesystem == nullptr) - virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); +const Tegra::GPU& System::GPU() const { + return *impl->gpu_core; +} - current_process = Kernel::Process::Create(kernel, "main"); +VideoCore::RendererBase& System::Renderer() { + return *impl->renderer; +} - cpu_barrier = std::make_shared<CpuBarrier>(); - cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size()); - for (size_t index = 0; index < cpu_cores.size(); ++index) { - cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index); - } +const VideoCore::RendererBase& System::Renderer() const { + return *impl->renderer; +} - telemetry_session = std::make_unique<Core::TelemetrySession>(); - service_manager = std::make_shared<Service::SM::ServiceManager>(); +Kernel::KernelCore& System::Kernel() { + return impl->kernel; +} - Service::Init(service_manager, virtual_filesystem); - GDBStub::Init(); +const Kernel::KernelCore& System::Kernel() const { + return impl->kernel; +} - renderer = VideoCore::CreateRenderer(emu_window); - if (!renderer->Init()) { - return ResultStatus::ErrorVideoCore; - } +Core::PerfStats& System::GetPerfStats() { + return impl->perf_stats; +} - gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); +const Core::PerfStats& System::GetPerfStats() const { + return impl->perf_stats; +} - // Create threads for CPU cores 1-3, and build thread_to_cpu map - // CPU core 0 is run on the main thread - thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; - if (Settings::values.use_multi_core) { - for (size_t index = 0; index < cpu_core_threads.size(); ++index) { - cpu_core_threads[index] = - std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]); - thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1]; - } - } +Core::FrameLimiter& System::FrameLimiter() { + return impl->frame_limiter; +} - LOG_DEBUG(Core, "Initialized OK"); +const Core::FrameLimiter& System::FrameLimiter() const { + return impl->frame_limiter; +} - // Reset counters and set time origin to current frame - GetAndResetPerfStats(); - perf_stats.BeginSystemFrame(); +Loader::ResultStatus System::GetGameName(std::string& out) const { + return impl->GetGameName(out); +} - return ResultStatus::Success; +void System::SetStatus(ResultStatus new_status, const char* details) { + impl->SetStatus(new_status, details); } -void System::Shutdown() { - // Log last frame performance stats - auto perf_results = GetAndResetPerfStats(); - Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed", - perf_results.emulation_speed * 100.0); - Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate", - perf_results.game_fps); - Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", - perf_results.frametime * 1000.0); - - // Shutdown emulation session - renderer.reset(); - GDBStub::Shutdown(); - Service::Shutdown(); - service_manager.reset(); - telemetry_session.reset(); - gpu_core.reset(); - - // Close all CPU/threading state - cpu_barrier->NotifyEnd(); - if (Settings::values.use_multi_core) { - for (auto& thread : cpu_core_threads) { - thread->join(); - thread.reset(); - } - } - thread_to_cpu.clear(); - for (auto& cpu_core : cpu_cores) { - cpu_core.reset(); - } - cpu_barrier.reset(); +const std::string& System::GetStatusDetails() const { + return impl->status_details; +} - // Shutdown kernel and core timing - kernel.Shutdown(); - CoreTiming::Shutdown(); +Loader::AppLoader& System::GetAppLoader() const { + return *impl->app_loader; +} - // Close app loader - app_loader.reset(); +void System::SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) { + impl->debug_context = std::move(context); +} - LOG_DEBUG(Core, "Shutdown OK"); +std::shared_ptr<Tegra::DebugContext> System::GetGPUDebugContext() const { + return impl->debug_context; +} + +void System::SetFilesystem(FileSys::VirtualFilesystem vfs) { + impl->virtual_filesystem = std::move(vfs); +} + +FileSys::VirtualFilesystem System::GetFilesystem() const { + return impl->virtual_filesystem; +} + +System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { + return impl->Init(emu_window); +} + +void System::Shutdown() { + impl->Shutdown(); } Service::SM::ServiceManager& System::ServiceManager() { - return *service_manager; + return *impl->service_manager; } const Service::SM::ServiceManager& System::ServiceManager() const { - return *service_manager; + return *impl->service_manager; } } // 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: * This function should only be used by GDB Stub to support breakpoints, memory updates and * step/continue commands. */ - void InvalidateCpuInstructionCaches() { - for (auto& cpu : cpu_cores) { - cpu->ArmInterface().ClearInstructionCache(); - } - } + void InvalidateCpuInstructionCaches(); /// Shutdown the emulated system. void Shutdown(); @@ -117,17 +113,13 @@ public: * application). * @returns True if the emulated system is powered on, otherwise false. */ - bool IsPoweredOn() const { - return cpu_barrier && cpu_barrier->IsAlive(); - } + bool IsPoweredOn() const; /** * Returns a reference to the telemetry session for this emulation session. * @returns Reference to the telemetry session. */ - Core::TelemetrySession& TelemetrySession() const { - return *telemetry_session; - } + Core::TelemetrySession& TelemetrySession() const; /// Prepare the core emulation for a reschedule void PrepareReschedule(); @@ -136,14 +128,13 @@ public: PerfStats::Results GetAndResetPerfStats(); /// Gets an ARM interface to the CPU core that is currently running - ARM_Interface& CurrentArmInterface() { - return CurrentCpuCore().ArmInterface(); - } + ARM_Interface& CurrentArmInterface(); /// Gets the index of the currently running CPU core - size_t CurrentCoreIndex() { - return CurrentCpuCore().CoreIndex(); - } + size_t CurrentCoreIndex(); + + /// Gets the scheduler for the CPU core that is currently running + Kernel::Scheduler& CurrentScheduler(); /// Gets an ARM interface to the CPU core with the specified index ARM_Interface& ArmInterface(size_t core_index); @@ -151,43 +142,26 @@ public: /// Gets a CPU interface to the CPU core with the specified index Cpu& CpuCore(size_t core_index); + /// Gets the exclusive monitor + ExclusiveMonitor& Monitor(); + /// Gets a mutable reference to the GPU interface - Tegra::GPU& GPU() { - return *gpu_core; - } + Tegra::GPU& GPU(); /// Gets an immutable reference to the GPU interface. - const Tegra::GPU& GPU() const { - return *gpu_core; - } + const Tegra::GPU& GPU() const; /// Gets a mutable reference to the renderer. - VideoCore::RendererBase& Renderer() { - return *renderer; - } + VideoCore::RendererBase& Renderer(); /// Gets an immutable reference to the renderer. - const VideoCore::RendererBase& Renderer() const { - return *renderer; - } - - /// Gets the scheduler for the CPU core that is currently running - Kernel::Scheduler& CurrentScheduler() { - return *CurrentCpuCore().Scheduler(); - } - - /// Gets the exclusive monitor - ExclusiveMonitor& Monitor() { - return *cpu_exclusive_monitor; - } + const VideoCore::RendererBase& Renderer() const; /// Gets the scheduler for the CPU core with the specified index const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index); /// Gets the current process - Kernel::SharedPtr<Kernel::Process>& CurrentProcess() { - return current_process; - } + Kernel::SharedPtr<Kernel::Process>& CurrentProcess(); /// Provides a reference to the kernel instance. Kernel::KernelCore& Kernel(); @@ -195,49 +169,37 @@ public: /// Provides a constant reference to the kernel instance. const Kernel::KernelCore& Kernel() const; - /// Gets the name of the current game - Loader::ResultStatus GetGameName(std::string& out) const { - if (app_loader == nullptr) - return Loader::ResultStatus::ErrorNotInitialized; - return app_loader->ReadTitle(out); - } + /// Provides a reference to the internal PerfStats instance. + Core::PerfStats& GetPerfStats(); - PerfStats perf_stats; - FrameLimiter frame_limiter; + /// Provides a constant reference to the internal PerfStats instance. + const Core::PerfStats& GetPerfStats() const; - void SetStatus(ResultStatus new_status, const char* details = nullptr) { - status = new_status; - if (details) { - status_details = details; - } - } + /// Provides a reference to the frame limiter; + Core::FrameLimiter& FrameLimiter(); - const std::string& GetStatusDetails() const { - return status_details; - } + /// Provides a constant referent to the frame limiter + const Core::FrameLimiter& FrameLimiter() const; - Loader::AppLoader& GetAppLoader() const { - return *app_loader; - } + /// Gets the name of the current game + Loader::ResultStatus GetGameName(std::string& out) const; + + void SetStatus(ResultStatus new_status, const char* details); + + const std::string& GetStatusDetails() const; + + Loader::AppLoader& GetAppLoader() const; Service::SM::ServiceManager& ServiceManager(); const Service::SM::ServiceManager& ServiceManager() const; - void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) { - debug_context = std::move(context); - } + void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context); - std::shared_ptr<Tegra::DebugContext> GetGPUDebugContext() const { - return debug_context; - } + std::shared_ptr<Tegra::DebugContext> GetGPUDebugContext() const; - void SetFilesystem(FileSys::VirtualFilesystem vfs) { - virtual_filesystem = std::move(vfs); - } + void SetFilesystem(FileSys::VirtualFilesystem vfs); - FileSys::VirtualFilesystem GetFilesystem() const { - return virtual_filesystem; - } + FileSys::VirtualFilesystem GetFilesystem() const; private: System(); @@ -253,34 +215,10 @@ private: */ ResultStatus Init(Frontend::EmuWindow& emu_window); - Kernel::KernelCore kernel; - /// RealVfsFilesystem instance - FileSys::VirtualFilesystem virtual_filesystem; - /// AppLoader used to load the current executing application - std::unique_ptr<Loader::AppLoader> app_loader; - std::unique_ptr<VideoCore::RendererBase> renderer; - std::unique_ptr<Tegra::GPU> gpu_core; - std::shared_ptr<Tegra::DebugContext> debug_context; - Kernel::SharedPtr<Kernel::Process> current_process; - std::shared_ptr<ExclusiveMonitor> cpu_exclusive_monitor; - std::shared_ptr<CpuBarrier> cpu_barrier; - std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores; - std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads; - size_t active_core{}; ///< Active core, only used in single thread mode - - /// Service manager - std::shared_ptr<Service::SM::ServiceManager> service_manager; - - /// Telemetry session for this emulation session - std::unique_ptr<Core::TelemetrySession> telemetry_session; + struct Impl; + std::unique_ptr<Impl> impl; static System s_instance; - - ResultStatus status = ResultStatus::Success; - std::string status_details = ""; - - /// Map of guest threads to CPU cores - std::map<std::thread::id, std::shared_ptr<Cpu>> thread_to_cpu; }; inline 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 @@ #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" #include "core/hle/service/nvdrv/devices/nvmap.h" +#include "core/perf_stats.h" #include "video_core/gpu.h" #include "video_core/renderer_base.h" @@ -31,7 +32,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 transform, crop_rect}; auto& instance = Core::System::GetInstance(); - instance.perf_stats.EndGameFrame(); + instance.GetPerfStats().EndGameFrame(); instance.Renderer().SwapBuffers(framebuffer); } 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 @@ #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" #include "core/hle/service/nvflinger/nvflinger.h" +#include "core/perf_stats.h" #include "video_core/renderer_base.h" #include "video_core/video_core.h" @@ -137,7 +138,7 @@ void NVFlinger::Compose() { auto& system_instance = Core::System::GetInstance(); // There was no queued buffer to draw, render previous frame - system_instance.perf_stats.EndGameFrame(); + system_instance.GetPerfStats().EndGameFrame(); system_instance.Renderer().SwapBuffers({}); continue; } 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 @@ #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/memory.h" +#include "core/perf_stats.h" #include "core/settings.h" #include "core/tracer/recorder.h" #include "video_core/renderer_opengl/gl_rasterizer.h" @@ -115,7 +116,7 @@ RendererOpenGL::~RendererOpenGL() = default; void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { ScopeAcquireGLContext acquire_context{render_window}; - Core::System::GetInstance().perf_stats.EndSystemFrame(); + Core::System::GetInstance().GetPerfStats().EndSystemFrame(); // Maintain the rasterizer's state as a priority OpenGLState prev_state = OpenGLState::GetCurState(); @@ -140,8 +141,8 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig& render_window.PollEvents(); - Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); - Core::System::GetInstance().perf_stats.BeginSystemFrame(); + Core::System::GetInstance().FrameLimiter().DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); + Core::System::GetInstance().GetPerfStats().BeginSystemFrame(); // Restore the rasterizer state prev_state.Apply(); |