mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-31 15:53:17 +00:00
Frame graph + Precise 60 fps timing (#998)
* video info: add frame graph Toggle advanced info with CTRL+F10. Also fixed imgui using gamepad for nav in wrong situations * 60fps! Implemented a timer that accumulates the time spent sleeping and sleeps for the remaining time. Also measure entire PresentThread time instead of just the time spent in Flip. * sceKernelGettimeofday: replace chrono by win32 api. Better performance bb uses this function too much. Consuming almost 30% of cpu time
This commit is contained in:
parent
a016792371
commit
5a8e8f5936
8 changed files with 183 additions and 26 deletions
|
@ -147,13 +147,20 @@ int PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
|
|||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto duration = now.time_since_epoch();
|
||||
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
|
||||
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(duration - seconds);
|
||||
FILETIME filetime;
|
||||
GetSystemTimeAsFileTime(&filetime);
|
||||
|
||||
tp->tv_sec = seconds.count();
|
||||
tp->tv_usec = microsecs.count();
|
||||
constexpr u64 UNIX_TIME_START = 0x295E9648864000;
|
||||
constexpr u64 TICKS_PER_SECOND = 1000000;
|
||||
|
||||
u64 ticks = filetime.dwHighDateTime;
|
||||
ticks <<= 32;
|
||||
ticks |= filetime.dwLowDateTime;
|
||||
ticks /= 10;
|
||||
ticks -= UNIX_TIME_START;
|
||||
|
||||
tp->tv_sec = ticks / TICKS_PER_SECOND;
|
||||
tp->tv_usec = ticks % TICKS_PER_SECOND;
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <imgui.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
|
@ -160,9 +161,7 @@ int VideoOutDriver::UnregisterBuffers(VideoOutPort* port, s32 attributeIndex) {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
std::chrono::microseconds VideoOutDriver::Flip(const Request& req) {
|
||||
const auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
void VideoOutDriver::Flip(const Request& req) {
|
||||
// Whatever the game is rendering show splash if it is active
|
||||
if (!renderer->ShowSplash(req.frame)) {
|
||||
// Present the frame.
|
||||
|
@ -198,9 +197,6 @@ std::chrono::microseconds VideoOutDriver::Flip(const Request& req) {
|
|||
port->buffer_labels[req.index] = 0;
|
||||
port->SignalVoLabel();
|
||||
}
|
||||
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
}
|
||||
|
||||
void VideoOutDriver::DrawBlankFrame() {
|
||||
|
@ -267,6 +263,8 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
|||
Common::SetCurrentThreadName("PresentThread");
|
||||
Common::SetCurrentThreadRealtime(vblank_period);
|
||||
|
||||
Common::AccurateTimer timer{vblank_period};
|
||||
|
||||
const auto receive_request = [this] -> Request {
|
||||
std::scoped_lock lk{mutex};
|
||||
if (!requests.empty()) {
|
||||
|
@ -279,20 +277,18 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
|||
|
||||
auto delay = std::chrono::microseconds{0};
|
||||
while (!token.stop_requested()) {
|
||||
// Sleep for most of the vblank duration.
|
||||
std::this_thread::sleep_for(vblank_period - delay);
|
||||
timer.Start();
|
||||
|
||||
// Check if it's time to take a request.
|
||||
auto& vblank_status = main_port.vblank_status;
|
||||
if (vblank_status.count % (main_port.flip_rate + 1) == 0) {
|
||||
const auto request = receive_request();
|
||||
if (!request) {
|
||||
delay = std::chrono::microseconds{0};
|
||||
if (!main_port.is_open) {
|
||||
DrawBlankFrame();
|
||||
}
|
||||
} else {
|
||||
delay = Flip(request);
|
||||
Flip(request);
|
||||
FRAME_END;
|
||||
}
|
||||
}
|
||||
|
@ -313,6 +309,8 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
|||
Kernel::SceKernelEvent::Filter::VideoOut, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
timer.End();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
std::chrono::microseconds Flip(const Request& req);
|
||||
void Flip(const Request& req);
|
||||
void DrawBlankFrame(); // Used when there is no flip request to keep ImGui up to date
|
||||
void SubmitFlipInternal(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
|
||||
void PresentThread(std::stop_token token);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue