mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	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