mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	Merge pull request #1204 from lioncash/pimpl
core: Make the main System class use the PImpl idiom
This commit is contained in:
		
						commit
						f08d24e9c0
					
				| @ -27,71 +27,9 @@ namespace Core { | |||||||
| 
 | 
 | ||||||
| /*static*/ System System::s_instance; | /*static*/ System System::s_instance; | ||||||
| 
 | 
 | ||||||
| System::System() = default; | namespace { | ||||||
| 
 | FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | ||||||
| System::~System() = default; |                                          const std::string& path) { | ||||||
| 
 |  | ||||||
| /// Runs a CPU core while the system is powered on
 |  | ||||||
| static void RunCpuCore(std::shared_ptr<Cpu> cpu_state) { |  | ||||||
|     while (Core::System::GetInstance().IsPoweredOn()) { |  | ||||||
|         cpu_state->RunLoop(true); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Otherwise, use single-threaded mode active_core variable
 |  | ||||||
|     return *cpu_cores[active_core]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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]; |  | ||||||
| 
 |  | ||||||
|     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; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| System::ResultStatus System::SingleStep() { |  | ||||||
|     return RunLoop(false); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, |  | ||||||
|                                                 const std::string& path) { |  | ||||||
|     // To account for split 00+01+etc files.
 |     // To account for split 00+01+etc files.
 | ||||||
|     std::string dir_name; |     std::string dir_name; | ||||||
|     std::string filename; |     std::string filename; | ||||||
| @ -121,41 +59,267 @@ static FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem | |||||||
|     return vfs->OpenFile(path, FileSys::Mode::Read); |     return vfs->OpenFile(path, FileSys::Mode::Read); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Runs a CPU core while the system is powered on
 | ||||||
|  | void RunCpuCore(std::shared_ptr<Cpu> cpu_state) { | ||||||
|  |     while (Core::System::GetInstance().IsPoweredOn()) { | ||||||
|  |         cpu_state->RunLoop(true); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | } // Anonymous namespace
 | ||||||
|  | 
 | ||||||
|  | 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]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ResultStatus 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]; | ||||||
|  | 
 | ||||||
|  |         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; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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) { | ||||||
|  |             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]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LOG_DEBUG(Core, "Initialized OK"); | ||||||
|  | 
 | ||||||
|  |         // Reset counters and set time origin to current frame
 | ||||||
|  |         GetAndResetPerfStats(); | ||||||
|  |         perf_stats.BeginSystemFrame(); | ||||||
|  | 
 | ||||||
|  |         return ResultStatus::Success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | ||||||
|  |         app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); | ||||||
|  | 
 | ||||||
|  |         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(); | ||||||
|  | 
 | ||||||
|  |         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; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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(); | ||||||
|  | 
 | ||||||
|  |         // Shutdown kernel and core timing
 | ||||||
|  |         kernel.Shutdown(); | ||||||
|  |         CoreTiming::Shutdown(); | ||||||
|  | 
 | ||||||
|  |         // Close app loader
 | ||||||
|  |         app_loader.reset(); | ||||||
|  | 
 | ||||||
|  |         LOG_DEBUG(Core, "Shutdown OK"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Loader::ResultStatus GetGameName(std::string& out) const { | ||||||
|  |         if (app_loader == nullptr) | ||||||
|  |             return Loader::ResultStatus::ErrorNotInitialized; | ||||||
|  |         return app_loader->ReadTitle(out); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void SetStatus(ResultStatus new_status, const char* details = nullptr) { | ||||||
|  |         status = new_status; | ||||||
|  |         if (details) { | ||||||
|  |             status_details = details; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     PerfStats::Results GetAndResetPerfStats() { | ||||||
|  |         return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void System::InvalidateCpuInstructionCaches() { | ||||||
|  |     for (auto& cpu : impl->cpu_cores) { | ||||||
|  |         cpu->ArmInterface().ClearInstructionCache(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | ||||||
|     app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); |     return impl->Load(emu_window, filepath); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     if (!app_loader) { | bool System::IsPoweredOn() const { | ||||||
|         LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); |     return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); | ||||||
|         return ResultStatus::ErrorGetLoader; |  | ||||||
|     } |  | ||||||
|     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)); |  | ||||||
| 
 |  | ||||||
|         return ResultStatus::ErrorSystemMode; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     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; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     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(); |  | ||||||
| 
 |  | ||||||
|         return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + |  | ||||||
|                                          static_cast<u32>(load_result)); |  | ||||||
|     } |  | ||||||
|     status = ResultStatus::Success; |  | ||||||
|     return status; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void System::PrepareReschedule() { | void System::PrepareReschedule() { | ||||||
| @ -163,131 +327,134 @@ void System::PrepareReschedule() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| PerfStats::Results System::GetAndResetPerfStats() { | PerfStats::Results System::GetAndResetPerfStats() { | ||||||
|     return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs()); |     return impl->GetAndResetPerfStats(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Core::TelemetrySession& System::TelemetrySession() const { | ||||||
|  |     return *impl->telemetry_session; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ARM_Interface& System::CurrentArmInterface() { | ||||||
|  |     return CurrentCpuCore().ArmInterface(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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) { | const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) { | ||||||
|     ASSERT(core_index < NUM_CPU_CORES); |     ASSERT(core_index < NUM_CPU_CORES); | ||||||
|     return cpu_cores[core_index]->Scheduler(); |     return impl->cpu_cores[core_index]->Scheduler(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Kernel::KernelCore& System::Kernel() { | Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() { | ||||||
|     return kernel; |     return impl->current_process; | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const Kernel::KernelCore& System::Kernel() const { |  | ||||||
|     return kernel; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ARM_Interface& System::ArmInterface(size_t core_index) { | ARM_Interface& System::ArmInterface(size_t core_index) { | ||||||
|     ASSERT(core_index < NUM_CPU_CORES); |     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) { | Cpu& System::CpuCore(size_t core_index) { | ||||||
|     ASSERT(core_index < NUM_CPU_CORES); |     ASSERT(core_index < NUM_CPU_CORES); | ||||||
|     return *cpu_cores[core_index]; |     return *impl->cpu_cores[core_index]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ExclusiveMonitor& System::Monitor() { | ||||||
|  |     return *impl->cpu_exclusive_monitor; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Tegra::GPU& System::GPU() { | ||||||
|  |     return *impl->gpu_core; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const Tegra::GPU& System::GPU() const { | ||||||
|  |     return *impl->gpu_core; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | VideoCore::RendererBase& System::Renderer() { | ||||||
|  |     return *impl->renderer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const VideoCore::RendererBase& System::Renderer() const { | ||||||
|  |     return *impl->renderer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Kernel::KernelCore& System::Kernel() { | ||||||
|  |     return impl->kernel; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const Kernel::KernelCore& System::Kernel() const { | ||||||
|  |     return impl->kernel; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Core::PerfStats& System::GetPerfStats() { | ||||||
|  |     return impl->perf_stats; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const Core::PerfStats& System::GetPerfStats() const { | ||||||
|  |     return impl->perf_stats; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Core::FrameLimiter& System::FrameLimiter() { | ||||||
|  |     return impl->frame_limiter; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const Core::FrameLimiter& System::FrameLimiter() const { | ||||||
|  |     return impl->frame_limiter; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Loader::ResultStatus System::GetGameName(std::string& out) const { | ||||||
|  |     return impl->GetGameName(out); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void System::SetStatus(ResultStatus new_status, const char* details) { | ||||||
|  |     impl->SetStatus(new_status, details); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const std::string& System::GetStatusDetails() const { | ||||||
|  |     return impl->status_details; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Loader::AppLoader& System::GetAppLoader() const { | ||||||
|  |     return *impl->app_loader; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void System::SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) { | ||||||
|  |     impl->debug_context = std::move(context); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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) { | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | ||||||
|     LOG_DEBUG(HW_Memory, "initialized OK"); |     return impl->Init(emu_window); | ||||||
| 
 |  | ||||||
|     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) { |  | ||||||
|         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]; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     LOG_DEBUG(Core, "Initialized OK"); |  | ||||||
| 
 |  | ||||||
|     // Reset counters and set time origin to current frame
 |  | ||||||
|     GetAndResetPerfStats(); |  | ||||||
|     perf_stats.BeginSystemFrame(); |  | ||||||
| 
 |  | ||||||
|     return ResultStatus::Success; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void System::Shutdown() { | void System::Shutdown() { | ||||||
|     // Log last frame performance stats
 |     impl->Shutdown(); | ||||||
|     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(); |  | ||||||
| 
 |  | ||||||
|     // Shutdown kernel and core timing
 |  | ||||||
|     kernel.Shutdown(); |  | ||||||
|     CoreTiming::Shutdown(); |  | ||||||
| 
 |  | ||||||
|     // Close app loader
 |  | ||||||
|     app_loader.reset(); |  | ||||||
| 
 |  | ||||||
|     LOG_DEBUG(Core, "Shutdown OK"); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Service::SM::ServiceManager& System::ServiceManager() { | Service::SM::ServiceManager& System::ServiceManager() { | ||||||
|     return *service_manager; |     return *impl->service_manager; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const Service::SM::ServiceManager& System::ServiceManager() const { | const Service::SM::ServiceManager& System::ServiceManager() const { | ||||||
|     return *service_manager; |     return *impl->service_manager; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace Core
 | } // namespace Core
 | ||||||
|  | |||||||
							
								
								
									
										138
									
								
								src/core/core.h
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								src/core/core.h
									
									
									
									
									
								
							| @ -94,11 +94,7 @@ public: | |||||||
|      * This function should only be used by GDB Stub to support breakpoints, memory updates and |      * This function should only be used by GDB Stub to support breakpoints, memory updates and | ||||||
|      * step/continue commands. |      * step/continue commands. | ||||||
|      */ |      */ | ||||||
|     void InvalidateCpuInstructionCaches() { |     void InvalidateCpuInstructionCaches(); | ||||||
|         for (auto& cpu : cpu_cores) { |  | ||||||
|             cpu->ArmInterface().ClearInstructionCache(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /// Shutdown the emulated system.
 |     /// Shutdown the emulated system.
 | ||||||
|     void Shutdown(); |     void Shutdown(); | ||||||
| @ -117,17 +113,13 @@ public: | |||||||
|      * application). |      * application). | ||||||
|      * @returns True if the emulated system is powered on, otherwise false. |      * @returns True if the emulated system is powered on, otherwise false. | ||||||
|      */ |      */ | ||||||
|     bool IsPoweredOn() const { |     bool IsPoweredOn() const; | ||||||
|         return cpu_barrier && cpu_barrier->IsAlive(); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Returns a reference to the telemetry session for this emulation session. |      * Returns a reference to the telemetry session for this emulation session. | ||||||
|      * @returns Reference to the telemetry session. |      * @returns Reference to the telemetry session. | ||||||
|      */ |      */ | ||||||
|     Core::TelemetrySession& TelemetrySession() const { |     Core::TelemetrySession& TelemetrySession() const; | ||||||
|         return *telemetry_session; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /// Prepare the core emulation for a reschedule
 |     /// Prepare the core emulation for a reschedule
 | ||||||
|     void PrepareReschedule(); |     void PrepareReschedule(); | ||||||
| @ -136,14 +128,13 @@ public: | |||||||
|     PerfStats::Results GetAndResetPerfStats(); |     PerfStats::Results GetAndResetPerfStats(); | ||||||
| 
 | 
 | ||||||
|     /// Gets an ARM interface to the CPU core that is currently running
 |     /// Gets an ARM interface to the CPU core that is currently running
 | ||||||
|     ARM_Interface& CurrentArmInterface() { |     ARM_Interface& CurrentArmInterface(); | ||||||
|         return CurrentCpuCore().ArmInterface(); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /// Gets the index of the currently running CPU core
 |     /// Gets the index of the currently running CPU core
 | ||||||
|     size_t CurrentCoreIndex() { |     size_t CurrentCoreIndex(); | ||||||
|         return CurrentCpuCore().CoreIndex(); | 
 | ||||||
|     } |     /// 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
 |     /// Gets an ARM interface to the CPU core with the specified index
 | ||||||
|     ARM_Interface& ArmInterface(size_t core_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
 |     /// Gets a CPU interface to the CPU core with the specified index
 | ||||||
|     Cpu& CpuCore(size_t core_index); |     Cpu& CpuCore(size_t core_index); | ||||||
| 
 | 
 | ||||||
|  |     /// Gets the exclusive monitor
 | ||||||
|  |     ExclusiveMonitor& Monitor(); | ||||||
|  | 
 | ||||||
|     /// Gets a mutable reference to the GPU interface
 |     /// Gets a mutable reference to the GPU interface
 | ||||||
|     Tegra::GPU& GPU() { |     Tegra::GPU& GPU(); | ||||||
|         return *gpu_core; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /// Gets an immutable reference to the GPU interface.
 |     /// Gets an immutable reference to the GPU interface.
 | ||||||
|     const Tegra::GPU& GPU() const { |     const Tegra::GPU& GPU() const; | ||||||
|         return *gpu_core; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /// Gets a mutable reference to the renderer.
 |     /// Gets a mutable reference to the renderer.
 | ||||||
|     VideoCore::RendererBase& Renderer() { |     VideoCore::RendererBase& Renderer(); | ||||||
|         return *renderer; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /// Gets an immutable reference to the renderer.
 |     /// Gets an immutable reference to the renderer.
 | ||||||
|     const VideoCore::RendererBase& Renderer() const { |     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; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /// Gets the scheduler for the CPU core with the specified index
 |     /// Gets the scheduler for the CPU core with the specified index
 | ||||||
|     const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index); |     const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index); | ||||||
| 
 | 
 | ||||||
|     /// Gets the current process
 |     /// Gets the current process
 | ||||||
|     Kernel::SharedPtr<Kernel::Process>& CurrentProcess() { |     Kernel::SharedPtr<Kernel::Process>& CurrentProcess(); | ||||||
|         return current_process; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /// Provides a reference to the kernel instance.
 |     /// Provides a reference to the kernel instance.
 | ||||||
|     Kernel::KernelCore& Kernel(); |     Kernel::KernelCore& Kernel(); | ||||||
| @ -195,49 +169,37 @@ public: | |||||||
|     /// Provides a constant reference to the kernel instance.
 |     /// Provides a constant reference to the kernel instance.
 | ||||||
|     const Kernel::KernelCore& Kernel() const; |     const Kernel::KernelCore& Kernel() const; | ||||||
| 
 | 
 | ||||||
|  |     /// Provides a reference to the internal PerfStats instance.
 | ||||||
|  |     Core::PerfStats& GetPerfStats(); | ||||||
|  | 
 | ||||||
|  |     /// Provides a constant reference to the internal PerfStats instance.
 | ||||||
|  |     const Core::PerfStats& GetPerfStats() const; | ||||||
|  | 
 | ||||||
|  |     /// Provides a reference to the frame limiter;
 | ||||||
|  |     Core::FrameLimiter& FrameLimiter(); | ||||||
|  | 
 | ||||||
|  |     /// Provides a constant referent to the frame limiter
 | ||||||
|  |     const Core::FrameLimiter& FrameLimiter() const; | ||||||
|  | 
 | ||||||
|     /// Gets the name of the current game
 |     /// Gets the name of the current game
 | ||||||
|     Loader::ResultStatus GetGameName(std::string& out) const { |     Loader::ResultStatus GetGameName(std::string& out) const; | ||||||
|         if (app_loader == nullptr) |  | ||||||
|             return Loader::ResultStatus::ErrorNotInitialized; |  | ||||||
|         return app_loader->ReadTitle(out); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     PerfStats perf_stats; |     void SetStatus(ResultStatus new_status, const char* details); | ||||||
|     FrameLimiter frame_limiter; |  | ||||||
| 
 | 
 | ||||||
|     void SetStatus(ResultStatus new_status, const char* details = nullptr) { |     const std::string& GetStatusDetails() const; | ||||||
|         status = new_status; |  | ||||||
|         if (details) { |  | ||||||
|             status_details = details; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     const std::string& GetStatusDetails() const { |     Loader::AppLoader& GetAppLoader() const; | ||||||
|         return status_details; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Loader::AppLoader& GetAppLoader() const { |  | ||||||
|         return *app_loader; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     Service::SM::ServiceManager& ServiceManager(); |     Service::SM::ServiceManager& ServiceManager(); | ||||||
|     const Service::SM::ServiceManager& ServiceManager() const; |     const Service::SM::ServiceManager& ServiceManager() const; | ||||||
| 
 | 
 | ||||||
|     void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) { |     void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context); | ||||||
|         debug_context = std::move(context); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<Tegra::DebugContext> GetGPUDebugContext() const { |     std::shared_ptr<Tegra::DebugContext> GetGPUDebugContext() const; | ||||||
|         return debug_context; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     void SetFilesystem(FileSys::VirtualFilesystem vfs) { |     void SetFilesystem(FileSys::VirtualFilesystem vfs); | ||||||
|         virtual_filesystem = std::move(vfs); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     FileSys::VirtualFilesystem GetFilesystem() const { |     FileSys::VirtualFilesystem GetFilesystem() const; | ||||||
|         return virtual_filesystem; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     System(); |     System(); | ||||||
| @ -253,34 +215,10 @@ private: | |||||||
|      */ |      */ | ||||||
|     ResultStatus Init(Frontend::EmuWindow& emu_window); |     ResultStatus Init(Frontend::EmuWindow& emu_window); | ||||||
| 
 | 
 | ||||||
|     Kernel::KernelCore kernel; |     struct Impl; | ||||||
|     /// RealVfsFilesystem instance
 |     std::unique_ptr<Impl> impl; | ||||||
|     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; |  | ||||||
| 
 | 
 | ||||||
|     static System s_instance; |     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() { | inline ARM_Interface& CurrentArmInterface() { | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ | |||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | ||||||
| #include "core/hle/service/nvdrv/devices/nvmap.h" | #include "core/hle/service/nvdrv/devices/nvmap.h" | ||||||
|  | #include "core/perf_stats.h" | ||||||
| #include "video_core/gpu.h" | #include "video_core/gpu.h" | ||||||
| #include "video_core/renderer_base.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}; |         transform, crop_rect}; | ||||||
| 
 | 
 | ||||||
|     auto& instance = Core::System::GetInstance(); |     auto& instance = Core::System::GetInstance(); | ||||||
|     instance.perf_stats.EndGameFrame(); |     instance.GetPerfStats().EndGameFrame(); | ||||||
|     instance.Renderer().SwapBuffers(framebuffer); |     instance.Renderer().SwapBuffers(framebuffer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ | |||||||
| #include "core/hle/service/nvdrv/nvdrv.h" | #include "core/hle/service/nvdrv/nvdrv.h" | ||||||
| #include "core/hle/service/nvflinger/buffer_queue.h" | #include "core/hle/service/nvflinger/buffer_queue.h" | ||||||
| #include "core/hle/service/nvflinger/nvflinger.h" | #include "core/hle/service/nvflinger/nvflinger.h" | ||||||
|  | #include "core/perf_stats.h" | ||||||
| #include "video_core/renderer_base.h" | #include "video_core/renderer_base.h" | ||||||
| #include "video_core/video_core.h" | #include "video_core/video_core.h" | ||||||
| 
 | 
 | ||||||
| @ -137,7 +138,7 @@ void NVFlinger::Compose() { | |||||||
|             auto& system_instance = Core::System::GetInstance(); |             auto& system_instance = Core::System::GetInstance(); | ||||||
| 
 | 
 | ||||||
|             // There was no queued buffer to draw, render previous frame
 |             // There was no queued buffer to draw, render previous frame
 | ||||||
|             system_instance.perf_stats.EndGameFrame(); |             system_instance.GetPerfStats().EndGameFrame(); | ||||||
|             system_instance.Renderer().SwapBuffers({}); |             system_instance.Renderer().SwapBuffers({}); | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ | |||||||
| #include "core/core_timing.h" | #include "core/core_timing.h" | ||||||
| #include "core/frontend/emu_window.h" | #include "core/frontend/emu_window.h" | ||||||
| #include "core/memory.h" | #include "core/memory.h" | ||||||
|  | #include "core/perf_stats.h" | ||||||
| #include "core/settings.h" | #include "core/settings.h" | ||||||
| #include "core/tracer/recorder.h" | #include "core/tracer/recorder.h" | ||||||
| #include "video_core/renderer_opengl/gl_rasterizer.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) { | void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { | ||||||
|     ScopeAcquireGLContext acquire_context{render_window}; |     ScopeAcquireGLContext acquire_context{render_window}; | ||||||
| 
 | 
 | ||||||
|     Core::System::GetInstance().perf_stats.EndSystemFrame(); |     Core::System::GetInstance().GetPerfStats().EndSystemFrame(); | ||||||
| 
 | 
 | ||||||
|     // Maintain the rasterizer's state as a priority
 |     // Maintain the rasterizer's state as a priority
 | ||||||
|     OpenGLState prev_state = OpenGLState::GetCurState(); |     OpenGLState prev_state = OpenGLState::GetCurState(); | ||||||
| @ -140,8 +141,8 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig& | |||||||
| 
 | 
 | ||||||
|     render_window.PollEvents(); |     render_window.PollEvents(); | ||||||
| 
 | 
 | ||||||
|     Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); |     Core::System::GetInstance().FrameLimiter().DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); | ||||||
|     Core::System::GetInstance().perf_stats.BeginSystemFrame(); |     Core::System::GetInstance().GetPerfStats().BeginSystemFrame(); | ||||||
| 
 | 
 | ||||||
|     // Restore the rasterizer state
 |     // Restore the rasterizer state
 | ||||||
|     prev_state.Apply(); |     prev_state.Apply(); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei