Services/NvFlinger: Do vSync in a sepparate thread on Multicore.
This commit is contained in:
parent
39ddce1ab5
commit
272a87127a
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
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);
|
system.CoreTiming().ScheduleEvent(frame_ticks, composition_event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NVFlinger::~NVFlinger() {
|
NVFlinger::~NVFlinger() {
|
||||||
|
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);
|
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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Reference in New Issue