mirror of https://github.com/PCSX2/pcsx2.git
Qt: Add performance metrics to status bar
This commit is contained in:
parent
90457e32b6
commit
d01ee3163d
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
|
@ -28,6 +30,7 @@
|
|||
#include "pcsx2/Frontend/InputManager.h"
|
||||
#include "pcsx2/Frontend/ImGuiManager.h"
|
||||
#include "pcsx2/GS.h"
|
||||
#include "pcsx2/GS/GS.h"
|
||||
#include "pcsx2/GSDumpReplayer.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
|
@ -104,6 +107,7 @@ void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
|
|||
}
|
||||
|
||||
pxAssertRel(!VMManager::HasValidVM(), "VM is shut down");
|
||||
loadOurSettings();
|
||||
|
||||
emit onVMStarting();
|
||||
|
||||
|
@ -247,6 +251,11 @@ void EmuThread::run()
|
|||
|
||||
void EmuThread::destroyVM()
|
||||
{
|
||||
m_last_speed = 0.0f;
|
||||
m_last_game_fps = 0.0f;
|
||||
m_last_video_fps = 0.0f;
|
||||
m_last_internal_width = 0;
|
||||
m_last_internal_height = 0;
|
||||
VMManager::Shutdown();
|
||||
}
|
||||
|
||||
|
@ -372,6 +381,11 @@ void EmuThread::reloadGameSettings()
|
|||
}
|
||||
}
|
||||
|
||||
void EmuThread::loadOurSettings()
|
||||
{
|
||||
m_verbose_status = QtHost::GetBaseBoolSettingValue("UI", "VerboseStatusBar", false);
|
||||
}
|
||||
|
||||
void EmuThread::checkForSettingChanges()
|
||||
{
|
||||
if (VMManager::HasValidVM())
|
||||
|
@ -384,6 +398,13 @@ void EmuThread::checkForSettingChanges()
|
|||
GetMTGS().WaitGS();
|
||||
}
|
||||
}
|
||||
|
||||
const bool last_verbose_status = m_verbose_status;
|
||||
|
||||
loadOurSettings();
|
||||
|
||||
if (m_verbose_status != last_verbose_status)
|
||||
updatePerformanceMetrics(true);
|
||||
}
|
||||
|
||||
void EmuThread::toggleSoftwareRendering()
|
||||
|
@ -722,6 +743,85 @@ void Host::OnGameChanged(const std::string& disc_path, const std::string& game_s
|
|||
QString::fromStdString(game_name), game_crc);
|
||||
}
|
||||
|
||||
void EmuThread::updatePerformanceMetrics(bool force)
|
||||
{
|
||||
QString fps_stat, gs_stat;
|
||||
bool changed = force;
|
||||
|
||||
if (m_verbose_status && VMManager::HasValidVM())
|
||||
{
|
||||
std::string gs_stat_str;
|
||||
GSgetTitleStats(gs_stat_str);
|
||||
changed = true;
|
||||
|
||||
if (THREAD_VU1)
|
||||
{
|
||||
gs_stat =
|
||||
QStringLiteral("%1 | EE: %2% | VU: %3% | GS: %4%")
|
||||
.arg(gs_stat_str.c_str())
|
||||
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
|
||||
.arg(PerformanceMetrics::GetVUThreadUsage(), 0, 'f', 0)
|
||||
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
gs_stat = QStringLiteral("%1 | EE: %2% | GS: %3%")
|
||||
.arg(gs_stat_str.c_str())
|
||||
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
|
||||
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
|
||||
}
|
||||
}
|
||||
|
||||
const float speed = std::round(PerformanceMetrics::GetSpeed());
|
||||
const float gfps = std::round(PerformanceMetrics::GetInternalFPS());
|
||||
const float vfps = std::round(PerformanceMetrics::GetFPS());
|
||||
int iwidth, iheight;
|
||||
GSgetInternalResolution(&iwidth, &iheight);
|
||||
|
||||
if (iwidth != m_last_internal_width || iheight != m_last_internal_height ||
|
||||
speed != m_last_speed || gfps != m_last_game_fps || vfps != m_last_video_fps ||
|
||||
changed)
|
||||
{
|
||||
m_last_internal_width = iwidth;
|
||||
m_last_internal_height = iheight;
|
||||
m_last_speed = speed;
|
||||
m_last_game_fps = gfps;
|
||||
m_last_video_fps = vfps;
|
||||
changed = true;
|
||||
|
||||
if (iwidth == 0 && iheight == 0)
|
||||
{
|
||||
// if we don't have width/height yet, we're not going to have fps either.
|
||||
// and we'll probably be <100% due to compiling. so just leave it blank for now.
|
||||
}
|
||||
else if (PerformanceMetrics::IsInternalFPSValid())
|
||||
{
|
||||
fps_stat = QStringLiteral("%1x%2 | G: %3 | V: %4 | %5%")
|
||||
.arg(iwidth)
|
||||
.arg(iheight)
|
||||
.arg(gfps, 0, 'f', 0)
|
||||
.arg(vfps, 0, 'f', 0)
|
||||
.arg(speed, 0, 'f', 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
fps_stat = QStringLiteral("%1x%2 | V: %3 | %4%")
|
||||
.arg(iwidth)
|
||||
.arg(iheight)
|
||||
.arg(vfps, 0, 'f', 0)
|
||||
.arg(speed, 0, 'f', 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
emit onPerformanceMetricsUpdated(fps_stat, gs_stat);
|
||||
}
|
||||
|
||||
void Host::OnPerformanceMetricsUpdated()
|
||||
{
|
||||
g_emu_thread->updatePerformanceMetrics(false);
|
||||
}
|
||||
|
||||
void Host::OnSaveStateLoading(const std::string_view& filename)
|
||||
{
|
||||
emit g_emu_thread->onSaveStateLoading(QtUtils::StringViewToQString(filename));
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
|
||||
void startBackgroundControllerPollTimer();
|
||||
void stopBackgroundControllerPollTimer();
|
||||
void updatePerformanceMetrics(bool force);
|
||||
|
||||
public Q_SLOTS:
|
||||
void startVM(std::shared_ptr<VMBootParameters> boot_params);
|
||||
|
@ -100,6 +101,9 @@ Q_SIGNALS:
|
|||
/// Provided by the host; called when the running executable changes.
|
||||
void onGameChanged(const QString& path, const QString& serial, const QString& name, quint32 crc);
|
||||
|
||||
/// Called when performance metrics are changed, approx. once a second.
|
||||
void onPerformanceMetricsUpdated(const QString& fps_stats, const QString& gs_stats);
|
||||
|
||||
void onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices);
|
||||
void onInputDeviceConnected(const QString& identifier, const QString& device_name);
|
||||
void onInputDeviceDisconnected(const QString& identifier);
|
||||
|
@ -129,6 +133,7 @@ private:
|
|||
|
||||
void createBackgroundControllerPollTimer();
|
||||
void destroyBackgroundControllerPollTimer();
|
||||
void loadOurSettings();
|
||||
|
||||
private Q_SLOTS:
|
||||
void stopInThread();
|
||||
|
@ -148,8 +153,15 @@ private:
|
|||
|
||||
std::atomic_bool m_shutdown_flag{false};
|
||||
|
||||
bool m_verbose_status = false;
|
||||
bool m_is_rendering_to_main = false;
|
||||
bool m_is_fullscreen = false;
|
||||
|
||||
float m_last_speed = 0.0f;
|
||||
float m_last_game_fps = 0.0f;
|
||||
float m_last_video_fps = 0.0f;
|
||||
int m_last_internal_width = 0;
|
||||
int m_last_internal_height = 0;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "pcsx2/Frontend/GameList.h"
|
||||
#include "pcsx2/GSDumpReplayer.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/PerformanceMetrics.h"
|
||||
|
||||
#include "AboutDialog.h"
|
||||
#include "DisplayWidget.h"
|
||||
|
@ -113,6 +114,16 @@ void MainWindow::setupAdditionalUi()
|
|||
m_status_progress_widget->setFixedSize(140, 16);
|
||||
m_status_progress_widget->hide();
|
||||
|
||||
m_status_gs_widget = new QLabel(m_ui.statusBar);
|
||||
m_status_gs_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
m_status_gs_widget->setFixedHeight(16);
|
||||
m_status_gs_widget->hide();
|
||||
|
||||
m_status_fps_widget = new QLabel(m_ui.statusBar);
|
||||
m_status_fps_widget->setAlignment(Qt::AlignRight);
|
||||
m_status_fps_widget->setFixedHeight(16);
|
||||
m_status_fps_widget->hide();
|
||||
|
||||
for (u32 scale = 0; scale <= 10; scale++)
|
||||
{
|
||||
QAction* action = m_ui.menuWindowSize->addAction((scale == 0) ? tr("Internal Resolution") : tr("%1x Scale").arg(scale));
|
||||
|
@ -180,6 +191,8 @@ void MainWindow::connectSignals()
|
|||
});
|
||||
connect(m_ui.actionGridViewRefreshCovers, &QAction::triggered, m_game_list_widget, &GameListWidget::refreshGridCovers);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionViewStatusBarVerbose, "UI", "VerboseStatusBar", false);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableSystemConsole, "Logging", "EnableSystemConsole", false);
|
||||
connect(m_ui.actionEnableSystemConsole, &QAction::triggered, this, &MainWindow::onLoggingOptionChanged);
|
||||
#ifndef PCSX2_DEVBUILD
|
||||
|
@ -216,6 +229,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
|||
connect(thread, &EmuThread::onVMResumed, this, &MainWindow::onVMResumed);
|
||||
connect(thread, &EmuThread::onVMStopped, this, &MainWindow::onVMStopped);
|
||||
connect(thread, &EmuThread::onGameChanged, this, &MainWindow::onGameChanged);
|
||||
connect(thread, &EmuThread::onPerformanceMetricsUpdated, this, &MainWindow::onPerformanceMetricsUpdated);
|
||||
|
||||
connect(m_ui.actionReset, &QAction::triggered, thread, &EmuThread::resetVM);
|
||||
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
|
||||
|
@ -565,6 +579,27 @@ void MainWindow::updateEmulationActions(bool starting, bool running)
|
|||
m_game_list_widget->setDisabled(starting && !running);
|
||||
}
|
||||
|
||||
void MainWindow::updateStatusBarWidgetVisibility()
|
||||
{
|
||||
auto Update = [this](QWidget* widget, bool visible, int stretch)
|
||||
{
|
||||
if (widget->isVisible())
|
||||
{
|
||||
m_ui.statusBar->removeWidget(widget);
|
||||
widget->hide();
|
||||
}
|
||||
|
||||
if (visible)
|
||||
{
|
||||
m_ui.statusBar->addPermanentWidget(widget, stretch);
|
||||
widget->show();
|
||||
}
|
||||
};
|
||||
|
||||
Update(m_status_gs_widget, m_vm_valid && !m_vm_paused, 1);
|
||||
Update(m_status_fps_widget, m_vm_valid, 0);
|
||||
}
|
||||
|
||||
void MainWindow::updateWindowTitle()
|
||||
{
|
||||
QString title;
|
||||
|
@ -994,6 +1029,7 @@ void MainWindow::onVMStarted()
|
|||
m_vm_valid = true;
|
||||
updateEmulationActions(true, true);
|
||||
updateWindowTitle();
|
||||
updateStatusBarWidgetVisibility();
|
||||
}
|
||||
|
||||
void MainWindow::onVMPaused()
|
||||
|
@ -1006,6 +1042,8 @@ void MainWindow::onVMPaused()
|
|||
|
||||
m_vm_paused = true;
|
||||
updateWindowTitle();
|
||||
updateStatusBarWidgetVisibility();
|
||||
m_status_fps_widget->setText(tr("Paused"));
|
||||
}
|
||||
|
||||
void MainWindow::onVMResumed()
|
||||
|
@ -1018,14 +1056,18 @@ void MainWindow::onVMResumed()
|
|||
|
||||
m_vm_paused = false;
|
||||
updateWindowTitle();
|
||||
updateStatusBarWidgetVisibility();
|
||||
m_status_fps_widget->setText(m_last_fps_status);
|
||||
}
|
||||
|
||||
void MainWindow::onVMStopped()
|
||||
{
|
||||
m_vm_valid = false;
|
||||
m_vm_paused = false;
|
||||
m_last_fps_status = QString();
|
||||
updateEmulationActions(false, false);
|
||||
updateWindowTitle();
|
||||
updateStatusBarWidgetVisibility();
|
||||
switchToGameListView();
|
||||
}
|
||||
|
||||
|
@ -1039,6 +1081,13 @@ void MainWindow::onGameChanged(const QString& path, const QString& serial, const
|
|||
updateSaveStateMenus(path, serial, crc);
|
||||
}
|
||||
|
||||
void MainWindow::onPerformanceMetricsUpdated(const QString& fps_stat, const QString& gs_stat)
|
||||
{
|
||||
m_last_fps_status = fps_stat;
|
||||
m_status_fps_widget->setText(m_last_fps_status);
|
||||
m_status_gs_widget->setText(gs_stat);
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (!requestShutdown(true, true, true))
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <optional>
|
||||
|
||||
|
@ -103,6 +104,7 @@ private Q_SLOTS:
|
|||
void onVMStopped();
|
||||
|
||||
void onGameChanged(const QString& path, const QString& serial, const QString& name, quint32 crc);
|
||||
void onPerformanceMetricsUpdated(const QString& fps_stat, const QString& gs_stat);
|
||||
|
||||
void recreate();
|
||||
|
||||
|
@ -124,6 +126,7 @@ private:
|
|||
void restoreStateFromConfig();
|
||||
|
||||
void updateEmulationActions(bool starting, bool running);
|
||||
void updateStatusBarWidgetVisibility();
|
||||
void updateWindowTitle();
|
||||
void setProgressBar(int current, int total);
|
||||
void clearProgressBar();
|
||||
|
@ -166,6 +169,8 @@ private:
|
|||
ControllerSettingsDialog* m_controller_settings_dialog = nullptr;
|
||||
|
||||
QProgressBar* m_status_progress_widget = nullptr;
|
||||
QLabel* m_status_gs_widget = nullptr;
|
||||
QLabel* m_status_fps_widget = nullptr;
|
||||
|
||||
QString m_current_disc_path;
|
||||
QString m_current_game_serial;
|
||||
|
@ -175,6 +180,8 @@ private:
|
|||
bool m_vm_paused = false;
|
||||
bool m_save_states_invalidated = false;
|
||||
bool m_was_focused_on_container_switch = false;
|
||||
|
||||
QString m_last_fps_status;
|
||||
};
|
||||
|
||||
extern MainWindow* g_main_window;
|
||||
|
|
|
@ -168,6 +168,7 @@
|
|||
<addaction name="actionViewToolbar"/>
|
||||
<addaction name="actionViewLockToolbar"/>
|
||||
<addaction name="actionViewStatusBar"/>
|
||||
<addaction name="actionViewStatusBarVerbose"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionViewGameList"/>
|
||||
<addaction name="actionViewGameGrid"/>
|
||||
|
@ -597,6 +598,17 @@
|
|||
<string>&Status Bar</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionViewStatusBarVerbose">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Verbose Status</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionViewGameList">
|
||||
<property name="icon">
|
||||
<iconset theme="list-check">
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "common/Console.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "pcsx2/Config.h"
|
||||
#include "pcsx2/Counters.h"
|
||||
#include "pcsx2/Host.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/GS.h"
|
||||
|
@ -715,14 +716,20 @@ void GSgetStats(std::string& info)
|
|||
|
||||
void GSgetTitleStats(std::string& info)
|
||||
{
|
||||
const char* api_name = HostDisplay::RenderAPIToString(s_render_api);
|
||||
const char* hw_sw_name = (GSConfig.Renderer == GSRendererType::Null) ? " Null" : (GSConfig.UseHardwareRenderer() ? " HW" : " SW");
|
||||
const char* deinterlace_mode = theApp.m_gs_interlace[static_cast<int>(GSConfig.InterlaceMode)].name.c_str();
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
int iwidth, iheight;
|
||||
GSgetInternalResolution(&iwidth, &iheight);
|
||||
|
||||
const char* api_name = HostDisplay::RenderAPIToString(s_render_api);
|
||||
const char* hw_sw_name = (GSConfig.Renderer == GSRendererType::Null) ? " Null" : (GSConfig.UseHardwareRenderer() ? " HW" : " SW");
|
||||
const char* interlace_mode = theApp.m_gs_interlace[static_cast<int>(GSConfig.InterlaceMode)].name.c_str();
|
||||
|
||||
info = format("%s%s | %s | %dx%d", api_name, hw_sw_name, interlace_mode, iwidth, iheight);
|
||||
info = StringUtil::StdStringFromFormat("%s%s | %s | %dx%d", api_name, hw_sw_name, deinterlace_mode, iwidth, iheight);
|
||||
#else
|
||||
const char* interlace_mode = ReportInterlaceMode();
|
||||
const char* video_mode = ReportVideoMode();
|
||||
info = StringUtil::StdStringFromFormat("%s%s | %s | %s | %s", api_name, hw_sw_name, video_mode, interlace_mode, deinterlace_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
#include "GS.h"
|
||||
#include "MTVU.h"
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
#include "VMManager.h"
|
||||
#endif
|
||||
|
||||
static const float UPDATE_INTERVAL = 0.5f;
|
||||
|
||||
static float s_vertical_frequency = 0.0f;
|
||||
|
@ -130,6 +134,7 @@ void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit)
|
|||
if (time < UPDATE_INTERVAL)
|
||||
return;
|
||||
|
||||
s_last_update_time.ResetTo(now_ticks);
|
||||
s_worst_frame_time = s_worst_frame_time_accumulator;
|
||||
s_worst_frame_time_accumulator = 0.0f;
|
||||
s_average_frame_time = s_average_frame_time_accumulator / static_cast<float>(s_frames_since_last_update);
|
||||
|
@ -191,9 +196,12 @@ void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit)
|
|||
s_last_vu_time = vu_time;
|
||||
s_last_ticks = ticks;
|
||||
|
||||
s_last_update_time.ResetTo(now_ticks);
|
||||
s_frames_since_last_update = 0;
|
||||
s_presents_since_last_update = 0;
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
Host::OnPerformanceMetricsUpdated();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PerformanceMetrics::OnGPUPresent(float gpu_time)
|
||||
|
|
|
@ -177,6 +177,9 @@ namespace Host
|
|||
/// Called when the VM is resumed after being paused.
|
||||
void OnVMResumed();
|
||||
|
||||
/// Called when performance metrics are updated, approximately once a second.
|
||||
void OnPerformanceMetricsUpdated();
|
||||
|
||||
/// Called when a save state is loading, before the file is processed.
|
||||
void OnSaveStateLoading(const std::string_view& filename);
|
||||
|
||||
|
|
Loading…
Reference in New Issue