Merge pull request #2587 from yuriks/status-bar
Replace built-in Profiler with indicators in status bar
This commit is contained in:
commit
b250ce21b9
28 changed files with 321 additions and 449 deletions
|
@ -69,7 +69,6 @@ set(HEADERS
|
|||
set(UIS
|
||||
debugger/callstack.ui
|
||||
debugger/disassembler.ui
|
||||
debugger/profiler.ui
|
||||
debugger/registers.ui
|
||||
configure.ui
|
||||
configure_audio.ui
|
||||
|
|
|
@ -146,6 +146,7 @@ void Config::ReadValues() {
|
|||
|
||||
UISettings::values.single_window_mode = qt_config->value("singleWindowMode", true).toBool();
|
||||
UISettings::values.display_titlebar = qt_config->value("displayTitleBars", true).toBool();
|
||||
UISettings::values.show_status_bar = qt_config->value("showStatusBar", true).toBool();
|
||||
UISettings::values.confirm_before_closing = qt_config->value("confirmClose", true).toBool();
|
||||
UISettings::values.first_start = qt_config->value("firstStart", true).toBool();
|
||||
|
||||
|
@ -252,6 +253,7 @@ void Config::SaveValues() {
|
|||
|
||||
qt_config->setValue("singleWindowMode", UISettings::values.single_window_mode);
|
||||
qt_config->setValue("displayTitleBars", UISettings::values.display_titlebar);
|
||||
qt_config->setValue("showStatusBar", UISettings::values.show_status_bar);
|
||||
qt_config->setValue("confirmClose", UISettings::values.confirm_before_closing);
|
||||
qt_config->setValue("firstStart", UISettings::values.first_start);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "citra_qt/configure_system.h"
|
||||
#include "citra_qt/ui_settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/cfg/cfg.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "ui_configure_system.h"
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QAction>
|
||||
#include <QLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QString>
|
||||
|
@ -9,121 +11,12 @@
|
|||
#include "citra_qt/util/util.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/profiler_reporting.h"
|
||||
|
||||
// Include the implementation of the UI in this file. This isn't in microprofile.cpp because the
|
||||
// non-Qt frontends don't need it (and don't implement the UI drawing hooks either).
|
||||
#if MICROPROFILE_ENABLED
|
||||
#define MICROPROFILEUI_IMPL 1
|
||||
#include "common/microprofileui.h"
|
||||
#endif
|
||||
|
||||
using namespace Common::Profiling;
|
||||
|
||||
static QVariant GetDataForColumn(int col, const AggregatedDuration& duration) {
|
||||
static auto duration_to_float = [](Duration dur) -> float {
|
||||
using FloatMs = std::chrono::duration<float, std::chrono::milliseconds::period>;
|
||||
return std::chrono::duration_cast<FloatMs>(dur).count();
|
||||
};
|
||||
|
||||
switch (col) {
|
||||
case 1:
|
||||
return duration_to_float(duration.avg);
|
||||
case 2:
|
||||
return duration_to_float(duration.min);
|
||||
case 3:
|
||||
return duration_to_float(duration.max);
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
ProfilerModel::ProfilerModel(QObject* parent) : QAbstractItemModel(parent) {
|
||||
updateProfilingInfo();
|
||||
}
|
||||
|
||||
QVariant ProfilerModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return tr("Category");
|
||||
case 1:
|
||||
return tr("Avg");
|
||||
case 2:
|
||||
return tr("Min");
|
||||
case 3:
|
||||
return tr("Max");
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QModelIndex ProfilerModel::index(int row, int column, const QModelIndex& parent) const {
|
||||
return createIndex(row, column);
|
||||
}
|
||||
|
||||
QModelIndex ProfilerModel::parent(const QModelIndex& child) const {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int ProfilerModel::columnCount(const QModelIndex& parent) const {
|
||||
return 4;
|
||||
}
|
||||
|
||||
int ProfilerModel::rowCount(const QModelIndex& parent) const {
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
QVariant ProfilerModel::data(const QModelIndex& index, int role) const {
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (index.row() == 0) {
|
||||
if (index.column() == 0) {
|
||||
return tr("Frame");
|
||||
} else {
|
||||
return GetDataForColumn(index.column(), results.frame_time);
|
||||
}
|
||||
} else if (index.row() == 1) {
|
||||
if (index.column() == 0) {
|
||||
return tr("Frame (with swapping)");
|
||||
} else {
|
||||
return GetDataForColumn(index.column(), results.interframe_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void ProfilerModel::updateProfilingInfo() {
|
||||
results = GetTimingResultsAggregator()->GetAggregatedResults();
|
||||
emit dataChanged(createIndex(0, 1), createIndex(rowCount() - 1, 3));
|
||||
}
|
||||
|
||||
ProfilerWidget::ProfilerWidget(QWidget* parent) : QDockWidget(parent) {
|
||||
ui.setupUi(this);
|
||||
|
||||
model = new ProfilerModel(this);
|
||||
ui.treeView->setModel(model);
|
||||
|
||||
connect(this, SIGNAL(visibilityChanged(bool)), SLOT(setProfilingInfoUpdateEnabled(bool)));
|
||||
connect(&update_timer, SIGNAL(timeout()), model, SLOT(updateProfilingInfo()));
|
||||
}
|
||||
|
||||
void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable) {
|
||||
if (enable) {
|
||||
update_timer.start(100);
|
||||
model->updateProfilingInfo();
|
||||
} else {
|
||||
update_timer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPROFILE_ENABLED
|
||||
|
||||
class MicroProfileWidget : public QWidget {
|
||||
public:
|
||||
|
|
|
@ -8,46 +8,6 @@
|
|||
#include <QDockWidget>
|
||||
#include <QTimer>
|
||||
#include "common/microprofile.h"
|
||||
#include "common/profiler_reporting.h"
|
||||
#include "ui_profiler.h"
|
||||
|
||||
class ProfilerModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProfilerModel(QObject* parent);
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex& parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex& child) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
public slots:
|
||||
void updateProfilingInfo();
|
||||
|
||||
private:
|
||||
Common::Profiling::AggregatedFrameResult results;
|
||||
};
|
||||
|
||||
class ProfilerWidget : public QDockWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProfilerWidget(QWidget* parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void setProfilingInfoUpdateEnabled(bool enable);
|
||||
|
||||
private:
|
||||
Ui::Profiler ui;
|
||||
ProfilerModel* model;
|
||||
|
||||
QTimer update_timer;
|
||||
};
|
||||
|
||||
class MicroProfileDialog : public QWidget {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Profiler</class>
|
||||
<widget class="QDockWidget" name="Profiler">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Profiler</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTreeView" name="treeView">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -45,6 +45,7 @@ GameList::GameList(QWidget* parent) : QWidget{parent} {
|
|||
// with signals/slots. In this case, QList falls under the umbrells of custom types.
|
||||
qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
|
||||
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(tree_view);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
|
|
@ -95,6 +95,26 @@ void GMainWindow::InitializeWidgets() {
|
|||
|
||||
game_list = new GameList();
|
||||
ui.horizontalLayout->addWidget(game_list);
|
||||
|
||||
// Create status bar
|
||||
emu_speed_label = new QLabel();
|
||||
emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% "
|
||||
"indicate emulation is running faster or slower than a 3DS."));
|
||||
game_fps_label = new QLabel();
|
||||
game_fps_label->setToolTip(tr("How many frames per second the game is currently displaying. "
|
||||
"This will vary from game to game and scene to scene."));
|
||||
emu_frametime_label = new QLabel();
|
||||
emu_frametime_label->setToolTip(
|
||||
tr("Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For "
|
||||
"full-speed emulation this should be at most 16.67 ms."));
|
||||
|
||||
for (auto& label : {emu_speed_label, game_fps_label, emu_frametime_label}) {
|
||||
label->setVisible(false);
|
||||
label->setFrameStyle(QFrame::NoFrame);
|
||||
label->setContentsMargins(4, 0, 4, 0);
|
||||
statusBar()->addPermanentWidget(label);
|
||||
}
|
||||
statusBar()->setVisible(true);
|
||||
}
|
||||
|
||||
void GMainWindow::InitializeDebugWidgets() {
|
||||
|
@ -103,11 +123,6 @@ void GMainWindow::InitializeDebugWidgets() {
|
|||
|
||||
QMenu* debug_menu = ui.menu_View_Debugging;
|
||||
|
||||
profilerWidget = new ProfilerWidget(this);
|
||||
addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
|
||||
profilerWidget->hide();
|
||||
debug_menu->addAction(profilerWidget->toggleViewAction());
|
||||
|
||||
#if MICROPROFILE_ENABLED
|
||||
microProfileDialog = new MicroProfileDialog(this);
|
||||
microProfileDialog->hide();
|
||||
|
@ -230,6 +245,9 @@ void GMainWindow::RestoreUIState() {
|
|||
|
||||
ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar);
|
||||
OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
|
||||
|
||||
ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar);
|
||||
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
|
||||
}
|
||||
|
||||
void GMainWindow::ConnectWidgetEvents() {
|
||||
|
@ -240,6 +258,8 @@ void GMainWindow::ConnectWidgetEvents() {
|
|||
connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window,
|
||||
SLOT(OnEmulationStarting(EmuThread*)));
|
||||
connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping()));
|
||||
|
||||
connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
|
||||
}
|
||||
|
||||
void GMainWindow::ConnectMenuEvents() {
|
||||
|
@ -262,6 +282,7 @@ void GMainWindow::ConnectMenuEvents() {
|
|||
&GMainWindow::ToggleWindowMode);
|
||||
connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this,
|
||||
&GMainWindow::OnDisplayTitleBars);
|
||||
connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
|
||||
}
|
||||
|
||||
void GMainWindow::OnDisplayTitleBars(bool show) {
|
||||
|
@ -387,6 +408,8 @@ void GMainWindow::BootGame(const QString& filename) {
|
|||
if (ui.action_Single_Window_Mode->isChecked()) {
|
||||
game_list->hide();
|
||||
}
|
||||
status_bar_update_timer.start(2000);
|
||||
|
||||
render_window->show();
|
||||
render_window->setFocus();
|
||||
|
||||
|
@ -421,6 +444,12 @@ void GMainWindow::ShutdownGame() {
|
|||
render_window->hide();
|
||||
game_list->show();
|
||||
|
||||
// Disable status bar updates
|
||||
status_bar_update_timer.stop();
|
||||
emu_speed_label->setVisible(false);
|
||||
game_fps_label->setVisible(false);
|
||||
emu_frametime_label->setVisible(false);
|
||||
|
||||
emulation_running = false;
|
||||
}
|
||||
|
||||
|
@ -600,6 +629,23 @@ void GMainWindow::OnCreateGraphicsSurfaceViewer() {
|
|||
graphicsSurfaceViewerWidget->show();
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateStatusBar() {
|
||||
if (emu_thread == nullptr) {
|
||||
status_bar_update_timer.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
auto results = Core::System::GetInstance().GetAndResetPerfStats();
|
||||
|
||||
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
|
||||
game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
|
||||
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
|
||||
|
||||
emu_speed_label->setVisible(true);
|
||||
game_fps_label->setVisible(true);
|
||||
emu_frametime_label->setVisible(true);
|
||||
}
|
||||
|
||||
bool GMainWindow::ConfirmClose() {
|
||||
if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
|
||||
return true;
|
||||
|
@ -625,6 +671,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
|
|||
#endif
|
||||
UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked();
|
||||
UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked();
|
||||
UISettings::values.show_status_bar = ui.action_Show_Status_Bar->isChecked();
|
||||
UISettings::values.first_start = false;
|
||||
|
||||
game_list->SaveInterfaceLayout();
|
||||
|
|
|
@ -127,17 +127,26 @@ private slots:
|
|||
void OnCreateGraphicsSurfaceViewer();
|
||||
|
||||
private:
|
||||
void UpdateStatusBar();
|
||||
|
||||
Ui::MainWindow ui;
|
||||
|
||||
GRenderWindow* render_window;
|
||||
GameList* game_list;
|
||||
|
||||
// Status bar elements
|
||||
QLabel* emu_speed_label = nullptr;
|
||||
QLabel* game_fps_label = nullptr;
|
||||
QLabel* emu_frametime_label = nullptr;
|
||||
QTimer status_bar_update_timer;
|
||||
|
||||
std::unique_ptr<Config> config;
|
||||
|
||||
// Whether emulation is currently running in Citra.
|
||||
bool emulation_running = false;
|
||||
std::unique_ptr<EmuThread> emu_thread;
|
||||
|
||||
// Debugger panes
|
||||
ProfilerWidget* profilerWidget;
|
||||
MicroProfileDialog* microProfileDialog;
|
||||
DisassemblerWidget* disasmWidget;
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
</widget>
|
||||
<addaction name="action_Single_Window_Mode"/>
|
||||
<addaction name="action_Display_Dock_Widget_Headers"/>
|
||||
<addaction name="action_Show_Status_Bar"/>
|
||||
<addaction name="menu_View_Debugging"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Help">
|
||||
|
@ -101,7 +102,6 @@
|
|||
<addaction name="menu_View"/>
|
||||
<addaction name="menu_Help"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="action_Load_File">
|
||||
<property name="text">
|
||||
<string>Load File...</string>
|
||||
|
@ -167,6 +167,14 @@
|
|||
<string>Display Dock Widget Headers</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Show_Status_Bar">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Status Bar</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Select_Game_List_Root">
|
||||
<property name="text">
|
||||
<string>Select Game Directory...</string>
|
||||
|
|
|
@ -27,6 +27,7 @@ struct Values {
|
|||
|
||||
bool single_window_mode;
|
||||
bool display_titlebar;
|
||||
bool show_status_bar;
|
||||
|
||||
bool confirm_before_closing;
|
||||
bool first_start;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue