Jelajahi Sumber

Services/NvFlinger: Do vSync in a sepparate thread on Multicore.

Fernando Sahmkow 6 tahun lalu
induk
melakukan
272a87127a

+ 6 - 2
src/core/core.cpp

@@ -294,8 +294,6 @@ struct System::Impl {
         service_manager.reset();
         service_manager.reset();
         cheat_engine.reset();
         cheat_engine.reset();
         telemetry_session.reset();
         telemetry_session.reset();
-        perf_stats.reset();
-        gpu_core.reset();
         device_memory.reset();
         device_memory.reset();
 
 
         // Close all CPU/threading state
         // Close all CPU/threading state
@@ -307,6 +305,8 @@ struct System::Impl {
 
 
         // Close app loader
         // Close app loader
         app_loader.reset();
         app_loader.reset();
+        gpu_core.reset();
+        perf_stats.reset();
 
 
         // Clear all applets
         // Clear all applets
         applet_manager.ClearAll();
         applet_manager.ClearAll();
@@ -764,4 +764,8 @@ void System::ExitDynarmicProfile() {
     MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]);
     MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]);
 }
 }
 
 
+bool System::IsMulticore() const {
+    return impl->is_multicore;
+}
+
 } // namespace Core
 } // namespace Core

+ 3 - 0
src/core/core.h

@@ -381,6 +381,9 @@ public:
     /// Exit Dynarmic Microprofile
     /// Exit Dynarmic Microprofile
     void ExitDynarmicProfile();
     void ExitDynarmicProfile();
 
 
+    /// Tells if system is running on multicore.
+    bool IsMulticore() const;
+
 private:
 private:
     System();
     System();
 
 

+ 46 - 3
src/core/hle/service/nvflinger/nvflinger.cpp

@@ -9,6 +9,7 @@
 #include "common/logging/log.h"
 #include "common/logging/log.h"
 #include "common/microprofile.h"
 #include "common/microprofile.h"
 #include "common/scope_exit.h"
 #include "common/scope_exit.h"
+#include "common/thread.h"
 #include "core/core.h"
 #include "core/core.h"
 #include "core/core_timing.h"
 #include "core/core_timing.h"
 #include "core/core_timing_util.h"
 #include "core/core_timing_util.h"
@@ -30,6 +31,33 @@ namespace Service::NVFlinger {
 constexpr s64 frame_ticks = static_cast<s64>(1000000000 / 60);
 constexpr s64 frame_ticks = static_cast<s64>(1000000000 / 60);
 constexpr s64 frame_ticks_30fps = static_cast<s64>(1000000000 / 30);
 constexpr s64 frame_ticks_30fps = static_cast<s64>(1000000000 / 30);
 
 
+void NVFlinger::VSyncThread(NVFlinger& nv_flinger) {
+    nv_flinger.SplitVSync();
+}
+
+void NVFlinger::SplitVSync() {
+    system.RegisterHostThread();
+    std::string name = "yuzu:VSyncThread";
+    MicroProfileOnThreadCreate(name.c_str());
+    Common::SetCurrentThreadName(name.c_str());
+    Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
+    s64 delay = 0;
+    while (is_running) {
+        guard->lock();
+        const s64 time_start = system.CoreTiming().GetGlobalTimeNs().count();
+        Compose();
+        const auto ticks = GetNextTicks();
+        const s64 time_end = system.CoreTiming().GetGlobalTimeNs().count();
+        const s64 time_passed = time_end - time_start;
+        const s64 next_time = std::max<s64>(0, ticks - time_passed - delay);
+        guard->unlock();
+        if (next_time > 0) {
+            wait_event->WaitFor(std::chrono::nanoseconds{next_time});
+        }
+        delay = (system.CoreTiming().GetGlobalTimeNs().count() - time_end) - next_time;
+    }
+}
+
 NVFlinger::NVFlinger(Core::System& system) : system(system) {
 NVFlinger::NVFlinger(Core::System& system) : system(system) {
     displays.emplace_back(0, "Default", system);
     displays.emplace_back(0, "Default", system);
     displays.emplace_back(1, "External", system);
     displays.emplace_back(1, "External", system);
@@ -47,12 +75,25 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
             this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - ns_late),
             this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - ns_late),
                                                     composition_event);
                                                     composition_event);
         });
         });
-
-    system.CoreTiming().ScheduleEvent(frame_ticks, composition_event);
+    if (system.IsMulticore()) {
+        is_running = true;
+        wait_event = std::make_unique<Common::Event>();
+        vsync_thread = std::make_unique<std::thread>(VSyncThread, std::ref(*this));
+    } else {
+        system.CoreTiming().ScheduleEvent(frame_ticks, composition_event);
+    }
 }
 }
 
 
 NVFlinger::~NVFlinger() {
 NVFlinger::~NVFlinger() {
-    system.CoreTiming().UnscheduleEvent(composition_event, 0);
+    if (system.IsMulticore()) {
+        is_running = false;
+        wait_event->Set();
+        vsync_thread->join();
+        vsync_thread.reset();
+        wait_event.reset();
+    } else {
+        system.CoreTiming().UnscheduleEvent(composition_event, 0);
+    }
 }
 }
 
 
 void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
 void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
@@ -200,10 +241,12 @@ void NVFlinger::Compose() {
 
 
         auto& gpu = system.GPU();
         auto& gpu = system.GPU();
         const auto& multi_fence = buffer->get().multi_fence;
         const auto& multi_fence = buffer->get().multi_fence;
+        guard->unlock();
         for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) {
         for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) {
             const auto& fence = multi_fence.fences[fence_id];
             const auto& fence = multi_fence.fences[fence_id];
             gpu.WaitFence(fence.id, fence.value);
             gpu.WaitFence(fence.id, fence.value);
         }
         }
+        guard->lock();
 
 
         MicroProfileFlip();
         MicroProfileFlip();
 
 

+ 14 - 0
src/core/hle/service/nvflinger/nvflinger.h

@@ -4,16 +4,22 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <atomic>
 #include <memory>
 #include <memory>
 #include <mutex>
 #include <mutex>
 #include <optional>
 #include <optional>
 #include <string>
 #include <string>
 #include <string_view>
 #include <string_view>
 #include <vector>
 #include <vector>
+#include <thread>
 
 
 #include "common/common_types.h"
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/object.h"
 
 
+namespace Common {
+class Event;
+} // namespace Common
+
 namespace Core::Timing {
 namespace Core::Timing {
 class CoreTiming;
 class CoreTiming;
 struct EventType;
 struct EventType;
@@ -97,6 +103,10 @@ private:
     /// Finds the layer identified by the specified ID in the desired display.
     /// Finds the layer identified by the specified ID in the desired display.
     const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
     const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
 
 
+    static void VSyncThread(NVFlinger& nv_flinger);
+
+    void SplitVSync();
+
     std::shared_ptr<Nvidia::Module> nvdrv;
     std::shared_ptr<Nvidia::Module> nvdrv;
 
 
     std::vector<VI::Display> displays;
     std::vector<VI::Display> displays;
@@ -116,6 +126,10 @@ private:
     std::shared_ptr<std::mutex> guard;
     std::shared_ptr<std::mutex> guard;
 
 
     Core::System& system;
     Core::System& system;
+
+    std::unique_ptr<std::thread> vsync_thread;
+    std::unique_ptr<Common::Event> wait_event;
+    std::atomic<bool> is_running{};
 };
 };
 
 
 } // namespace Service::NVFlinger
 } // namespace Service::NVFlinger