diff options
| -rw-r--r-- | src/core/core.cpp | 8 | ||||
| -rw-r--r-- | src/core/core.h | 3 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 49 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.h | 14 |
4 files changed, 69 insertions, 5 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 50656697f..8256ec0fc 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -294,8 +294,6 @@ struct System::Impl { | |||
| 294 | service_manager.reset(); | 294 | service_manager.reset(); |
| 295 | cheat_engine.reset(); | 295 | cheat_engine.reset(); |
| 296 | telemetry_session.reset(); | 296 | telemetry_session.reset(); |
| 297 | perf_stats.reset(); | ||
| 298 | gpu_core.reset(); | ||
| 299 | device_memory.reset(); | 297 | device_memory.reset(); |
| 300 | 298 | ||
| 301 | // Close all CPU/threading state | 299 | // Close all CPU/threading state |
| @@ -307,6 +305,8 @@ struct System::Impl { | |||
| 307 | 305 | ||
| 308 | // Close app loader | 306 | // Close app loader |
| 309 | app_loader.reset(); | 307 | app_loader.reset(); |
| 308 | gpu_core.reset(); | ||
| 309 | perf_stats.reset(); | ||
| 310 | 310 | ||
| 311 | // Clear all applets | 311 | // Clear all applets |
| 312 | applet_manager.ClearAll(); | 312 | applet_manager.ClearAll(); |
| @@ -764,4 +764,8 @@ void System::ExitDynarmicProfile() { | |||
| 764 | MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]); | 764 | MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]); |
| 765 | } | 765 | } |
| 766 | 766 | ||
| 767 | bool System::IsMulticore() const { | ||
| 768 | return impl->is_multicore; | ||
| 769 | } | ||
| 770 | |||
| 767 | } // namespace Core | 771 | } // namespace Core |
diff --git a/src/core/core.h b/src/core/core.h index d2d1fcc5b..133ecb8e1 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -381,6 +381,9 @@ public: | |||
| 381 | /// Exit Dynarmic Microprofile | 381 | /// Exit Dynarmic Microprofile |
| 382 | void ExitDynarmicProfile(); | 382 | void ExitDynarmicProfile(); |
| 383 | 383 | ||
| 384 | /// Tells if system is running on multicore. | ||
| 385 | bool IsMulticore() const; | ||
| 386 | |||
| 384 | private: | 387 | private: |
| 385 | System(); | 388 | System(); |
| 386 | 389 | ||
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index b97f71350..2f44d3779 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/microprofile.h" | 10 | #include "common/microprofile.h" |
| 11 | #include "common/scope_exit.h" | 11 | #include "common/scope_exit.h" |
| 12 | #include "common/thread.h" | ||
| 12 | #include "core/core.h" | 13 | #include "core/core.h" |
| 13 | #include "core/core_timing.h" | 14 | #include "core/core_timing.h" |
| 14 | #include "core/core_timing_util.h" | 15 | #include "core/core_timing_util.h" |
| @@ -30,6 +31,33 @@ namespace Service::NVFlinger { | |||
| 30 | constexpr s64 frame_ticks = static_cast<s64>(1000000000 / 60); | 31 | constexpr s64 frame_ticks = static_cast<s64>(1000000000 / 60); |
| 31 | constexpr s64 frame_ticks_30fps = static_cast<s64>(1000000000 / 30); | 32 | constexpr s64 frame_ticks_30fps = static_cast<s64>(1000000000 / 30); |
| 32 | 33 | ||
| 34 | void NVFlinger::VSyncThread(NVFlinger& nv_flinger) { | ||
| 35 | nv_flinger.SplitVSync(); | ||
| 36 | } | ||
| 37 | |||
| 38 | void NVFlinger::SplitVSync() { | ||
| 39 | system.RegisterHostThread(); | ||
| 40 | std::string name = "yuzu:VSyncThread"; | ||
| 41 | MicroProfileOnThreadCreate(name.c_str()); | ||
| 42 | Common::SetCurrentThreadName(name.c_str()); | ||
| 43 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); | ||
| 44 | s64 delay = 0; | ||
| 45 | while (is_running) { | ||
| 46 | guard->lock(); | ||
| 47 | const s64 time_start = system.CoreTiming().GetGlobalTimeNs().count(); | ||
| 48 | Compose(); | ||
| 49 | const auto ticks = GetNextTicks(); | ||
| 50 | const s64 time_end = system.CoreTiming().GetGlobalTimeNs().count(); | ||
| 51 | const s64 time_passed = time_end - time_start; | ||
| 52 | const s64 next_time = std::max<s64>(0, ticks - time_passed - delay); | ||
| 53 | guard->unlock(); | ||
| 54 | if (next_time > 0) { | ||
| 55 | wait_event->WaitFor(std::chrono::nanoseconds{next_time}); | ||
| 56 | } | ||
| 57 | delay = (system.CoreTiming().GetGlobalTimeNs().count() - time_end) - next_time; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 33 | NVFlinger::NVFlinger(Core::System& system) : system(system) { | 61 | NVFlinger::NVFlinger(Core::System& system) : system(system) { |
| 34 | displays.emplace_back(0, "Default", system); | 62 | displays.emplace_back(0, "Default", system); |
| 35 | displays.emplace_back(1, "External", system); | 63 | displays.emplace_back(1, "External", system); |
| @@ -47,12 +75,25 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { | |||
| 47 | this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - ns_late), | 75 | this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - ns_late), |
| 48 | composition_event); | 76 | composition_event); |
| 49 | }); | 77 | }); |
| 50 | 78 | if (system.IsMulticore()) { | |
| 51 | system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); | 79 | is_running = true; |
| 80 | wait_event = std::make_unique<Common::Event>(); | ||
| 81 | vsync_thread = std::make_unique<std::thread>(VSyncThread, std::ref(*this)); | ||
| 82 | } else { | ||
| 83 | system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); | ||
| 84 | } | ||
| 52 | } | 85 | } |
| 53 | 86 | ||
| 54 | NVFlinger::~NVFlinger() { | 87 | NVFlinger::~NVFlinger() { |
| 55 | system.CoreTiming().UnscheduleEvent(composition_event, 0); | 88 | if (system.IsMulticore()) { |
| 89 | is_running = false; | ||
| 90 | wait_event->Set(); | ||
| 91 | vsync_thread->join(); | ||
| 92 | vsync_thread.reset(); | ||
| 93 | wait_event.reset(); | ||
| 94 | } else { | ||
| 95 | system.CoreTiming().UnscheduleEvent(composition_event, 0); | ||
| 96 | } | ||
| 56 | } | 97 | } |
| 57 | 98 | ||
| 58 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | 99 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { |
| @@ -200,10 +241,12 @@ void NVFlinger::Compose() { | |||
| 200 | 241 | ||
| 201 | auto& gpu = system.GPU(); | 242 | auto& gpu = system.GPU(); |
| 202 | const auto& multi_fence = buffer->get().multi_fence; | 243 | const auto& multi_fence = buffer->get().multi_fence; |
| 244 | guard->unlock(); | ||
| 203 | for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { | 245 | for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { |
| 204 | const auto& fence = multi_fence.fences[fence_id]; | 246 | const auto& fence = multi_fence.fences[fence_id]; |
| 205 | gpu.WaitFence(fence.id, fence.value); | 247 | gpu.WaitFence(fence.id, fence.value); |
| 206 | } | 248 | } |
| 249 | guard->lock(); | ||
| 207 | 250 | ||
| 208 | MicroProfileFlip(); | 251 | MicroProfileFlip(); |
| 209 | 252 | ||
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 02c081494..4bc3d7ab2 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -4,16 +4,22 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <atomic> | ||
| 7 | #include <memory> | 8 | #include <memory> |
| 8 | #include <mutex> | 9 | #include <mutex> |
| 9 | #include <optional> | 10 | #include <optional> |
| 10 | #include <string> | 11 | #include <string> |
| 11 | #include <string_view> | 12 | #include <string_view> |
| 12 | #include <vector> | 13 | #include <vector> |
| 14 | #include <thread> | ||
| 13 | 15 | ||
| 14 | #include "common/common_types.h" | 16 | #include "common/common_types.h" |
| 15 | #include "core/hle/kernel/object.h" | 17 | #include "core/hle/kernel/object.h" |
| 16 | 18 | ||
| 19 | namespace Common { | ||
| 20 | class Event; | ||
| 21 | } // namespace Common | ||
| 22 | |||
| 17 | namespace Core::Timing { | 23 | namespace Core::Timing { |
| 18 | class CoreTiming; | 24 | class CoreTiming; |
| 19 | struct EventType; | 25 | struct EventType; |
| @@ -97,6 +103,10 @@ private: | |||
| 97 | /// Finds the layer identified by the specified ID in the desired display. | 103 | /// Finds the layer identified by the specified ID in the desired display. |
| 98 | const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; | 104 | const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; |
| 99 | 105 | ||
| 106 | static void VSyncThread(NVFlinger& nv_flinger); | ||
| 107 | |||
| 108 | void SplitVSync(); | ||
| 109 | |||
| 100 | std::shared_ptr<Nvidia::Module> nvdrv; | 110 | std::shared_ptr<Nvidia::Module> nvdrv; |
| 101 | 111 | ||
| 102 | std::vector<VI::Display> displays; | 112 | std::vector<VI::Display> displays; |
| @@ -116,6 +126,10 @@ private: | |||
| 116 | std::shared_ptr<std::mutex> guard; | 126 | std::shared_ptr<std::mutex> guard; |
| 117 | 127 | ||
| 118 | Core::System& system; | 128 | Core::System& system; |
| 129 | |||
| 130 | std::unique_ptr<std::thread> vsync_thread; | ||
| 131 | std::unique_ptr<Common::Event> wait_event; | ||
| 132 | std::atomic<bool> is_running{}; | ||
| 119 | }; | 133 | }; |
| 120 | 134 | ||
| 121 | } // namespace Service::NVFlinger | 135 | } // namespace Service::NVFlinger |