diff options
| author | 2018-08-31 11:31:20 -0400 | |
|---|---|---|
| committer | 2018-08-31 11:31:20 -0400 | |
| commit | f08d24e9c0a8dd7920ca5db5a5765b867eb1d714 (patch) | |
| tree | f2b144f08f5881d4e1174d9eb0184cf6548f20ce /src | |
| 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.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.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 { | |||
| 27 | 27 | ||
| 28 | /*static*/ System System::s_instance; | 28 | /*static*/ System System::s_instance; |
| 29 | 29 | ||
| 30 | System::System() = default; | 30 | namespace { |
| 31 | FileSys::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 | ||
| 32 | System::~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 |
| 35 | static void RunCpuCore(std::shared_ptr<Cpu> cpu_state) { | 63 | void 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 | ||
| 41 | Cpu& System::CurrentCpuCore() { | 70 | struct 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 | ||
| 54 | System::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 | ||
| 89 | System::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 | ||
| 93 | static 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 | ||
| 124 | System::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 | |||
| 296 | System::System() : impl{std::make_unique<Impl>()} {} | ||
| 297 | System::~System() = default; | ||
| 298 | |||
| 299 | Cpu& System::CurrentCpuCore() { | ||
| 300 | return impl->CurrentCpuCore(); | ||
| 301 | } | ||
| 302 | |||
| 303 | System::ResultStatus System::RunLoop(bool tight_loop) { | ||
| 304 | return impl->RunLoop(tight_loop); | ||
| 305 | } | ||
| 306 | |||
| 307 | System::ResultStatus System::SingleStep() { | ||
| 308 | return RunLoop(false); | ||
| 309 | } | ||
| 153 | 310 | ||
| 154 | return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + | 311 | void 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 | |
| 317 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | ||
| 318 | return impl->Load(emu_window, filepath); | ||
| 319 | } | ||
| 320 | |||
| 321 | bool System::IsPoweredOn() const { | ||
| 322 | return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); | ||
| 159 | } | 323 | } |
| 160 | 324 | ||
| 161 | void System::PrepareReschedule() { | 325 | void System::PrepareReschedule() { |
| @@ -163,131 +327,134 @@ void System::PrepareReschedule() { | |||
| 163 | } | 327 | } |
| 164 | 328 | ||
| 165 | PerfStats::Results System::GetAndResetPerfStats() { | 329 | PerfStats::Results System::GetAndResetPerfStats() { |
| 166 | return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs()); | 330 | return impl->GetAndResetPerfStats(); |
| 167 | } | 331 | } |
| 168 | 332 | ||
| 169 | const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) { | 333 | Core::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 | ||
| 174 | Kernel::KernelCore& System::Kernel() { | 337 | ARM_Interface& System::CurrentArmInterface() { |
| 175 | return kernel; | 338 | return CurrentCpuCore().ArmInterface(); |
| 176 | } | 339 | } |
| 177 | 340 | ||
| 178 | const Kernel::KernelCore& System::Kernel() const { | 341 | size_t System::CurrentCoreIndex() { |
| 179 | return kernel; | 342 | return CurrentCpuCore().CoreIndex(); |
| 343 | } | ||
| 344 | |||
| 345 | Kernel::Scheduler& System::CurrentScheduler() { | ||
| 346 | return *CurrentCpuCore().Scheduler(); | ||
| 347 | } | ||
| 348 | |||
| 349 | const 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 | |||
| 354 | Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() { | ||
| 355 | return impl->current_process; | ||
| 180 | } | 356 | } |
| 181 | 357 | ||
| 182 | ARM_Interface& System::ArmInterface(size_t core_index) { | 358 | ARM_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 | ||
| 187 | Cpu& System::CpuCore(size_t core_index) { | 363 | Cpu& 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 | ||
| 192 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | 368 | ExclusiveMonitor& System::Monitor() { |
| 193 | LOG_DEBUG(HW_Memory, "initialized OK"); | 369 | return *impl->cpu_exclusive_monitor; |
| 370 | } | ||
| 194 | 371 | ||
| 195 | CoreTiming::Init(); | 372 | Tegra::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. | 376 | const 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"); | 380 | VideoCore::RendererBase& System::Renderer() { |
| 381 | return *impl->renderer; | ||
| 382 | } | ||
| 203 | 383 | ||
| 204 | cpu_barrier = std::make_shared<CpuBarrier>(); | 384 | const 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>(); | 388 | Kernel::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); | 392 | const Kernel::KernelCore& System::Kernel() const { |
| 214 | GDBStub::Init(); | 393 | return impl->kernel; |
| 394 | } | ||
| 215 | 395 | ||
| 216 | renderer = VideoCore::CreateRenderer(emu_window); | 396 | Core::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()); | 400 | const 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 | 404 | Core::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"); | 408 | const Core::FrameLimiter& System::FrameLimiter() const { |
| 409 | return impl->frame_limiter; | ||
| 410 | } | ||
| 235 | 411 | ||
| 236 | // Reset counters and set time origin to current frame | 412 | Loader::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; | 416 | void System::SetStatus(ResultStatus new_status, const char* details) { |
| 417 | impl->SetStatus(new_status, details); | ||
| 241 | } | 418 | } |
| 242 | 419 | ||
| 243 | void System::Shutdown() { | 420 | const 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 | 424 | Loader::AppLoader& System::GetAppLoader() const { |
| 276 | kernel.Shutdown(); | 425 | return *impl->app_loader; |
| 277 | CoreTiming::Shutdown(); | 426 | } |
| 278 | 427 | ||
| 279 | // Close app loader | 428 | void 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"); | 432 | std::shared_ptr<Tegra::DebugContext> System::GetGPUDebugContext() const { |
| 433 | return impl->debug_context; | ||
| 434 | } | ||
| 435 | |||
| 436 | void System::SetFilesystem(FileSys::VirtualFilesystem vfs) { | ||
| 437 | impl->virtual_filesystem = std::move(vfs); | ||
| 438 | } | ||
| 439 | |||
| 440 | FileSys::VirtualFilesystem System::GetFilesystem() const { | ||
| 441 | return impl->virtual_filesystem; | ||
| 442 | } | ||
| 443 | |||
| 444 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | ||
| 445 | return impl->Init(emu_window); | ||
| 446 | } | ||
| 447 | |||
| 448 | void System::Shutdown() { | ||
| 449 | impl->Shutdown(); | ||
| 283 | } | 450 | } |
| 284 | 451 | ||
| 285 | Service::SM::ServiceManager& System::ServiceManager() { | 452 | Service::SM::ServiceManager& System::ServiceManager() { |
| 286 | return *service_manager; | 453 | return *impl->service_manager; |
| 287 | } | 454 | } |
| 288 | 455 | ||
| 289 | const Service::SM::ServiceManager& System::ServiceManager() const { | 456 | const 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 | ||
| 242 | private: | 204 | private: |
| 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 | ||
| 286 | inline ARM_Interface& CurrentArmInterface() { | 224 | 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 @@ | |||
| 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; | |||
| 115 | void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { | 116 | void 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(); |