mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Remove built-in (non-Microprofile) profiler
This commit is contained in:
		
							parent
							
								
									92c8bd4b1f
								
							
						
					
					
						commit
						3b4e400333
					
				
					 9 changed files with 2 additions and 382 deletions
				
			
		|  | @ -69,7 +69,6 @@ set(HEADERS | ||||||
| set(UIS | set(UIS | ||||||
|             debugger/callstack.ui |             debugger/callstack.ui | ||||||
|             debugger/disassembler.ui |             debugger/disassembler.ui | ||||||
|             debugger/profiler.ui |  | ||||||
|             debugger/registers.ui |             debugger/registers.ui | ||||||
|             configure.ui |             configure.ui | ||||||
|             configure_audio.ui |             configure_audio.ui | ||||||
|  |  | ||||||
|  | @ -2,6 +2,8 @@ | ||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
|  | #include <QAction> | ||||||
|  | #include <QLayout> | ||||||
| #include <QMouseEvent> | #include <QMouseEvent> | ||||||
| #include <QPainter> | #include <QPainter> | ||||||
| #include <QString> | #include <QString> | ||||||
|  | @ -9,121 +11,12 @@ | ||||||
| #include "citra_qt/util/util.h" | #include "citra_qt/util/util.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/microprofile.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
 | // 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).
 | // non-Qt frontends don't need it (and don't implement the UI drawing hooks either).
 | ||||||
| #if MICROPROFILE_ENABLED | #if MICROPROFILE_ENABLED | ||||||
| #define MICROPROFILEUI_IMPL 1 | #define MICROPROFILEUI_IMPL 1 | ||||||
| #include "common/microprofileui.h" | #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 { | class MicroProfileWidget : public QWidget { | ||||||
| public: | public: | ||||||
|  |  | ||||||
|  | @ -8,46 +8,6 @@ | ||||||
| #include <QDockWidget> | #include <QDockWidget> | ||||||
| #include <QTimer> | #include <QTimer> | ||||||
| #include "common/microprofile.h" | #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 { | class MicroProfileDialog : public QWidget { | ||||||
|     Q_OBJECT |     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> |  | ||||||
|  | @ -113,11 +113,6 @@ void GMainWindow::InitializeDebugWidgets() { | ||||||
| 
 | 
 | ||||||
|     QMenu* debug_menu = ui.menu_View_Debugging; |     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 | #if MICROPROFILE_ENABLED | ||||||
|     microProfileDialog = new MicroProfileDialog(this); |     microProfileDialog = new MicroProfileDialog(this); | ||||||
|     microProfileDialog->hide(); |     microProfileDialog->hide(); | ||||||
|  |  | ||||||
|  | @ -12,7 +12,6 @@ set(SRCS | ||||||
|             memory_util.cpp |             memory_util.cpp | ||||||
|             microprofile.cpp |             microprofile.cpp | ||||||
|             misc.cpp |             misc.cpp | ||||||
|             profiler.cpp |  | ||||||
|             scm_rev.cpp |             scm_rev.cpp | ||||||
|             string_util.cpp |             string_util.cpp | ||||||
|             symbols.cpp |             symbols.cpp | ||||||
|  | @ -45,7 +44,6 @@ set(HEADERS | ||||||
|             microprofile.h |             microprofile.h | ||||||
|             microprofileui.h |             microprofileui.h | ||||||
|             platform.h |             platform.h | ||||||
|             profiler_reporting.h |  | ||||||
|             quaternion.h |             quaternion.h | ||||||
|             scm_rev.h |             scm_rev.h | ||||||
|             scope_exit.h |             scope_exit.h | ||||||
|  |  | ||||||
|  | @ -1,101 +0,0 @@ | ||||||
| // Copyright 2015 Citra Emulator Project
 |  | ||||||
| // Licensed under GPLv2 or any later version
 |  | ||||||
| // Refer to the license.txt file included.
 |  | ||||||
| 
 |  | ||||||
| #include <algorithm> |  | ||||||
| #include <cstddef> |  | ||||||
| #include <vector> |  | ||||||
| #include "common/assert.h" |  | ||||||
| #include "common/profiler_reporting.h" |  | ||||||
| #include "common/synchronized_wrapper.h" |  | ||||||
| 
 |  | ||||||
| namespace Common { |  | ||||||
| namespace Profiling { |  | ||||||
| 
 |  | ||||||
| ProfilingManager::ProfilingManager() |  | ||||||
|     : last_frame_end(Clock::now()), this_frame_start(Clock::now()) {} |  | ||||||
| 
 |  | ||||||
| void ProfilingManager::BeginFrame() { |  | ||||||
|     this_frame_start = Clock::now(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ProfilingManager::FinishFrame() { |  | ||||||
|     Clock::time_point now = Clock::now(); |  | ||||||
| 
 |  | ||||||
|     results.interframe_time = now - last_frame_end; |  | ||||||
|     results.frame_time = now - this_frame_start; |  | ||||||
| 
 |  | ||||||
|     last_frame_end = now; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| TimingResultsAggregator::TimingResultsAggregator(size_t window_size) |  | ||||||
|     : max_window_size(window_size), window_size(0) { |  | ||||||
|     interframe_times.resize(window_size, Duration::zero()); |  | ||||||
|     frame_times.resize(window_size, Duration::zero()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void TimingResultsAggregator::Clear() { |  | ||||||
|     window_size = cursor = 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void TimingResultsAggregator::AddFrame(const ProfilingFrameResult& frame_result) { |  | ||||||
|     interframe_times[cursor] = frame_result.interframe_time; |  | ||||||
|     frame_times[cursor] = frame_result.frame_time; |  | ||||||
| 
 |  | ||||||
|     ++cursor; |  | ||||||
|     if (cursor == max_window_size) |  | ||||||
|         cursor = 0; |  | ||||||
|     if (window_size < max_window_size) |  | ||||||
|         ++window_size; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static AggregatedDuration AggregateField(const std::vector<Duration>& v, size_t len) { |  | ||||||
|     AggregatedDuration result; |  | ||||||
|     result.avg = Duration::zero(); |  | ||||||
|     result.min = result.max = (len == 0 ? Duration::zero() : v[0]); |  | ||||||
| 
 |  | ||||||
|     for (size_t i = 0; i < len; ++i) { |  | ||||||
|         Duration value = v[i]; |  | ||||||
|         result.avg += value; |  | ||||||
|         result.min = std::min(result.min, value); |  | ||||||
|         result.max = std::max(result.max, value); |  | ||||||
|     } |  | ||||||
|     if (len != 0) |  | ||||||
|         result.avg /= len; |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static float tof(Common::Profiling::Duration dur) { |  | ||||||
|     using FloatMs = std::chrono::duration<float, std::chrono::milliseconds::period>; |  | ||||||
|     return std::chrono::duration_cast<FloatMs>(dur).count(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| AggregatedFrameResult TimingResultsAggregator::GetAggregatedResults() const { |  | ||||||
|     AggregatedFrameResult result; |  | ||||||
| 
 |  | ||||||
|     result.interframe_time = AggregateField(interframe_times, window_size); |  | ||||||
|     result.frame_time = AggregateField(frame_times, window_size); |  | ||||||
| 
 |  | ||||||
|     if (result.interframe_time.avg != Duration::zero()) { |  | ||||||
|         result.fps = 1000.0f / tof(result.interframe_time.avg); |  | ||||||
|     } else { |  | ||||||
|         result.fps = 0.0f; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ProfilingManager& GetProfilingManager() { |  | ||||||
|     // Takes advantage of "magic" static initialization for race-free initialization.
 |  | ||||||
|     static ProfilingManager manager; |  | ||||||
|     return manager; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SynchronizedRef<TimingResultsAggregator> GetTimingResultsAggregator() { |  | ||||||
|     static SynchronizedWrapper<TimingResultsAggregator> aggregator(30); |  | ||||||
|     return SynchronizedRef<TimingResultsAggregator>(aggregator); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| } // namespace Profiling
 |  | ||||||
| } // namespace Common
 |  | ||||||
|  | @ -1,83 +0,0 @@ | ||||||
| // Copyright 2015 Citra Emulator Project
 |  | ||||||
| // Licensed under GPLv2 or any later version
 |  | ||||||
| // Refer to the license.txt file included.
 |  | ||||||
| 
 |  | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <chrono> |  | ||||||
| #include <cstddef> |  | ||||||
| #include <vector> |  | ||||||
| #include "common/synchronized_wrapper.h" |  | ||||||
| 
 |  | ||||||
| namespace Common { |  | ||||||
| namespace Profiling { |  | ||||||
| 
 |  | ||||||
| using Clock = std::chrono::high_resolution_clock; |  | ||||||
| using Duration = Clock::duration; |  | ||||||
| 
 |  | ||||||
| struct ProfilingFrameResult { |  | ||||||
|     /// Time since the last delivered frame
 |  | ||||||
|     Duration interframe_time; |  | ||||||
| 
 |  | ||||||
|     /// Time spent processing a frame, excluding VSync
 |  | ||||||
|     Duration frame_time; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| class ProfilingManager final { |  | ||||||
| public: |  | ||||||
|     ProfilingManager(); |  | ||||||
| 
 |  | ||||||
|     /// This should be called after swapping screen buffers.
 |  | ||||||
|     void BeginFrame(); |  | ||||||
|     /// This should be called before swapping screen buffers.
 |  | ||||||
|     void FinishFrame(); |  | ||||||
| 
 |  | ||||||
|     /// Get the timing results from the previous frame. This is updated when you call FinishFrame().
 |  | ||||||
|     const ProfilingFrameResult& GetPreviousFrameResults() const { |  | ||||||
|         return results; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     Clock::time_point last_frame_end; |  | ||||||
|     Clock::time_point this_frame_start; |  | ||||||
| 
 |  | ||||||
|     ProfilingFrameResult results; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct AggregatedDuration { |  | ||||||
|     Duration avg, min, max; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct AggregatedFrameResult { |  | ||||||
|     /// Time since the last delivered frame
 |  | ||||||
|     AggregatedDuration interframe_time; |  | ||||||
| 
 |  | ||||||
|     /// Time spent processing a frame, excluding VSync
 |  | ||||||
|     AggregatedDuration frame_time; |  | ||||||
| 
 |  | ||||||
|     float fps; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| class TimingResultsAggregator final { |  | ||||||
| public: |  | ||||||
|     TimingResultsAggregator(size_t window_size); |  | ||||||
| 
 |  | ||||||
|     void Clear(); |  | ||||||
| 
 |  | ||||||
|     void AddFrame(const ProfilingFrameResult& frame_result); |  | ||||||
| 
 |  | ||||||
|     AggregatedFrameResult GetAggregatedResults() const; |  | ||||||
| 
 |  | ||||||
|     size_t max_window_size; |  | ||||||
|     size_t window_size; |  | ||||||
|     size_t cursor; |  | ||||||
| 
 |  | ||||||
|     std::vector<Duration> interframe_times; |  | ||||||
|     std::vector<Duration> frame_times; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ProfilingManager& GetProfilingManager(); |  | ||||||
| SynchronizedRef<TimingResultsAggregator> GetTimingResultsAggregator(); |  | ||||||
| 
 |  | ||||||
| } // namespace Profiling
 |  | ||||||
| } // namespace Common
 |  | ||||||
|  | @ -10,7 +10,6 @@ | ||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "common/bit_field.h" | #include "common/bit_field.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/profiler_reporting.h" |  | ||||||
| #include "common/synchronized_wrapper.h" | #include "common/synchronized_wrapper.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/frontend/emu_window.h" | #include "core/frontend/emu_window.h" | ||||||
|  | @ -146,12 +145,6 @@ void RendererOpenGL::SwapBuffers() { | ||||||
| 
 | 
 | ||||||
|     DrawScreens(); |     DrawScreens(); | ||||||
| 
 | 
 | ||||||
|     auto& profiler = Common::Profiling::GetProfilingManager(); |  | ||||||
|     profiler.FinishFrame(); |  | ||||||
|     { |  | ||||||
|         auto aggregator = Common::Profiling::GetTimingResultsAggregator(); |  | ||||||
|         aggregator->AddFrame(profiler.GetPreviousFrameResults()); |  | ||||||
|     } |  | ||||||
|     { |     { | ||||||
|         auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); |         auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); | ||||||
|         perf_stats->EndSystemFrame(); |         perf_stats->EndSystemFrame(); | ||||||
|  | @ -163,7 +156,6 @@ void RendererOpenGL::SwapBuffers() { | ||||||
| 
 | 
 | ||||||
|     prev_state.Apply(); |     prev_state.Apply(); | ||||||
| 
 | 
 | ||||||
|     profiler.BeginFrame(); |  | ||||||
|     { |     { | ||||||
|         auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); |         auto perf_stats = Core::System::GetInstance().perf_stats.Lock(); | ||||||
|         perf_stats->BeginSystemFrame(); |         perf_stats->BeginSystemFrame(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue