mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 22:50:21 +00:00
Add performance stats overlay in status bar
Show FPS, frame time, visible/total objects, and visible/total triangles in the status bar. Toggled via Settings > Show Performance Stats, persisted in app settings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr const char* kGeometryLibraryKey = "geometry/library";
|
constexpr const char* kGeometryLibraryKey = "geometry/library";
|
||||||
constexpr const char* kGeometryLibraryDefault = "hybrid-cgal-simple-opencascade";
|
constexpr const char* kGeometryLibraryDefault = "hybrid-cgal-simple-opencascade";
|
||||||
|
constexpr const char* kShowStatsKey = "viewport/show_stats";
|
||||||
}
|
}
|
||||||
|
|
||||||
AppSettings& AppSettings::instance() {
|
AppSettings& AppSettings::instance() {
|
||||||
@@ -46,12 +47,25 @@ void AppSettings::setGeometryLibrary(const QString& value) {
|
|||||||
emit geometryLibraryChanged(value);
|
emit geometryLibraryChanged(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AppSettings::showStats() const {
|
||||||
|
return show_stats_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppSettings::setShowStats(bool value) {
|
||||||
|
if (show_stats_ == value) return;
|
||||||
|
show_stats_ = value;
|
||||||
|
persist();
|
||||||
|
emit showStatsChanged(value);
|
||||||
|
}
|
||||||
|
|
||||||
void AppSettings::load() {
|
void AppSettings::load() {
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
geometry_library_ = settings.value(kGeometryLibraryKey, kGeometryLibraryDefault).toString();
|
geometry_library_ = settings.value(kGeometryLibraryKey, kGeometryLibraryDefault).toString();
|
||||||
|
show_stats_ = settings.value(kShowStatsKey, false).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppSettings::persist() {
|
void AppSettings::persist() {
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue(kGeometryLibraryKey, geometry_library_);
|
settings.setValue(kGeometryLibraryKey, geometry_library_);
|
||||||
|
settings.setValue(kShowStatsKey, show_stats_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,12 @@ public:
|
|||||||
QString geometryLibrary() const;
|
QString geometryLibrary() const;
|
||||||
void setGeometryLibrary(const QString& value);
|
void setGeometryLibrary(const QString& value);
|
||||||
|
|
||||||
|
bool showStats() const;
|
||||||
|
void setShowStats(bool value);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void geometryLibraryChanged(const QString& value);
|
void geometryLibraryChanged(const QString& value);
|
||||||
|
void showStatsChanged(bool value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AppSettings();
|
AppSettings();
|
||||||
@@ -43,6 +47,7 @@ private:
|
|||||||
void persist();
|
void persist();
|
||||||
|
|
||||||
QString geometry_library_;
|
QString geometry_library_;
|
||||||
|
bool show_stats_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // APPSETTINGS_H
|
#endif // APPSETTINGS_H
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
#include "AppSettings.h"
|
||||||
#include "SettingsWindow.h"
|
#include "SettingsWindow.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -43,6 +44,23 @@ MainWindow::MainWindow(QWidget* parent)
|
|||||||
QMessageBox::warning(this, "Error", msg);
|
QMessageBox::warning(this, "Error", msg);
|
||||||
}, Qt::QueuedConnection);
|
}, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
connect(viewport_, &ViewportWindow::frameStatsUpdated, this, [this](const ViewportWindow::FrameStats& s) {
|
||||||
|
if (!stats_label_->isVisible()) return;
|
||||||
|
stats_label_->setText(
|
||||||
|
QString("%1 fps | %2 ms | %3/%4 obj | %5/%6 tri")
|
||||||
|
.arg(s.fps, 0, 'f', 1)
|
||||||
|
.arg(s.frame_time_ms, 0, 'f', 1)
|
||||||
|
.arg(s.visible_objects)
|
||||||
|
.arg(s.total_objects)
|
||||||
|
.arg(s.visible_triangles)
|
||||||
|
.arg(s.total_triangles));
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(&AppSettings::instance(), &AppSettings::showStatsChanged, this, [this](bool show) {
|
||||||
|
stats_label_->setVisible(show);
|
||||||
|
if (!show) stats_label_->clear();
|
||||||
|
});
|
||||||
|
|
||||||
connect(&element_poll_timer_, &QTimer::timeout, this, &MainWindow::pollNewElements);
|
connect(&element_poll_timer_, &QTimer::timeout, this, &MainWindow::pollNewElements);
|
||||||
element_poll_timer_.setInterval(100);
|
element_poll_timer_.setInterval(100);
|
||||||
|
|
||||||
@@ -91,7 +109,10 @@ void MainWindow::setupUi() {
|
|||||||
progress_bar_->setMaximumWidth(200);
|
progress_bar_->setMaximumWidth(200);
|
||||||
progress_bar_->setVisible(false);
|
progress_bar_->setVisible(false);
|
||||||
status_label_ = new QLabel("Ready");
|
status_label_ = new QLabel("Ready");
|
||||||
|
stats_label_ = new QLabel();
|
||||||
|
stats_label_->setVisible(AppSettings::instance().showStats());
|
||||||
statusBar()->addWidget(status_label_, 1);
|
statusBar()->addWidget(status_label_, 1);
|
||||||
|
statusBar()->addPermanentWidget(stats_label_);
|
||||||
statusBar()->addPermanentWidget(progress_bar_);
|
statusBar()->addPermanentWidget(progress_bar_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ private:
|
|||||||
QTableWidget* property_table_ = nullptr;
|
QTableWidget* property_table_ = nullptr;
|
||||||
QProgressBar* progress_bar_ = nullptr;
|
QProgressBar* progress_bar_ = nullptr;
|
||||||
QLabel* status_label_ = nullptr;
|
QLabel* status_label_ = nullptr;
|
||||||
|
QLabel* stats_label_ = nullptr;
|
||||||
QTimer element_poll_timer_;
|
QTimer element_poll_timer_;
|
||||||
QElapsedTimer load_timer_;
|
QElapsedTimer load_timer_;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "SettingsWindow.h"
|
#include "SettingsWindow.h"
|
||||||
#include "AppSettings.h"
|
#include "AppSettings.h"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
@@ -40,6 +41,9 @@ void SettingsWindow::setupUi() {
|
|||||||
geometry_library_edit_->setMinimumWidth(280);
|
geometry_library_edit_->setMinimumWidth(280);
|
||||||
form->addRow("Geometry Library", geometry_library_edit_);
|
form->addRow("Geometry Library", geometry_library_edit_);
|
||||||
|
|
||||||
|
show_stats_check_ = new QCheckBox(this);
|
||||||
|
form->addRow("Show Performance Stats", show_stats_check_);
|
||||||
|
|
||||||
auto* button_box = new QDialogButtonBox(
|
auto* button_box = new QDialogButtonBox(
|
||||||
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||||
|
|
||||||
@@ -60,9 +64,11 @@ void SettingsWindow::showEvent(QShowEvent* event) {
|
|||||||
|
|
||||||
void SettingsWindow::syncFromSettings() {
|
void SettingsWindow::syncFromSettings() {
|
||||||
geometry_library_edit_->setText(AppSettings::instance().geometryLibrary());
|
geometry_library_edit_->setText(AppSettings::instance().geometryLibrary());
|
||||||
|
show_stats_check_->setChecked(AppSettings::instance().showStats());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsWindow::onAccepted() {
|
void SettingsWindow::onAccepted() {
|
||||||
AppSettings::instance().setGeometryLibrary(geometry_library_edit_->text());
|
AppSettings::instance().setGeometryLibrary(geometry_library_edit_->text());
|
||||||
|
AppSettings::instance().setShowStats(show_stats_check_->isChecked());
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
|
||||||
|
class QCheckBox;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QShowEvent;
|
class QShowEvent;
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ private:
|
|||||||
void syncFromSettings();
|
void syncFromSettings();
|
||||||
|
|
||||||
QLineEdit* geometry_library_edit_ = nullptr;
|
QLineEdit* geometry_library_edit_ = nullptr;
|
||||||
|
QCheckBox* show_stats_check_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -532,6 +532,7 @@ void ViewportWindow::updateCamera() {
|
|||||||
void ViewportWindow::buildVisibleList(const QMatrix4x4& vp) {
|
void ViewportWindow::buildVisibleList(const QMatrix4x4& vp) {
|
||||||
visible_counts_.clear();
|
visible_counts_.clear();
|
||||||
visible_offsets_.clear();
|
visible_offsets_.clear();
|
||||||
|
visible_triangles_ = 0;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(upload_mutex_);
|
std::lock_guard<std::mutex> lock(upload_mutex_);
|
||||||
if (object_draw_info_.empty()) return;
|
if (object_draw_info_.empty()) return;
|
||||||
@@ -582,6 +583,7 @@ void ViewportWindow::buildVisibleList(const QMatrix4x4& vp) {
|
|||||||
visible_counts_.push_back(static_cast<GLsizei>(obj.index_count));
|
visible_counts_.push_back(static_cast<GLsizei>(obj.index_count));
|
||||||
visible_offsets_.push_back(reinterpret_cast<const void*>(
|
visible_offsets_.push_back(reinterpret_cast<const void*>(
|
||||||
static_cast<uintptr_t>(obj.index_offset)));
|
static_cast<uintptr_t>(obj.index_offset)));
|
||||||
|
visible_triangles_ += obj.index_count / 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -617,6 +619,25 @@ void ViewportWindow::render() {
|
|||||||
renderAxisGizmo();
|
renderAxisGizmo();
|
||||||
|
|
||||||
context_->swapBuffers(this);
|
context_->swapBuffers(this);
|
||||||
|
|
||||||
|
// Compute FPS (updated once per second to avoid flicker).
|
||||||
|
float dt = frame_clock_.restart() / 1000.0f;
|
||||||
|
accumulated_time_ += dt;
|
||||||
|
frame_count_++;
|
||||||
|
if (accumulated_time_ >= 1.0f) {
|
||||||
|
last_fps_ = static_cast<float>(frame_count_) / accumulated_time_;
|
||||||
|
frame_count_ = 0;
|
||||||
|
accumulated_time_ = 0.0f;
|
||||||
|
|
||||||
|
FrameStats stats;
|
||||||
|
stats.fps = last_fps_;
|
||||||
|
stats.frame_time_ms = 1000.0f / last_fps_;
|
||||||
|
stats.total_objects = static_cast<uint32_t>(object_draw_info_.size());
|
||||||
|
stats.visible_objects = static_cast<uint32_t>(visible_counts_.size());
|
||||||
|
stats.total_triangles = total_triangles_;
|
||||||
|
stats.visible_triangles = visible_triangles_;
|
||||||
|
emit frameStatsUpdated(stats);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewportWindow::renderAxisGizmo() {
|
void ViewportWindow::renderAxisGizmo() {
|
||||||
|
|||||||
@@ -65,9 +65,19 @@ public:
|
|||||||
void setSelectedObjectId(uint32_t id);
|
void setSelectedObjectId(uint32_t id);
|
||||||
uint32_t pickObjectAt(int x, int y);
|
uint32_t pickObjectAt(int x, int y);
|
||||||
|
|
||||||
|
struct FrameStats {
|
||||||
|
float fps;
|
||||||
|
float frame_time_ms;
|
||||||
|
uint32_t total_objects;
|
||||||
|
uint32_t visible_objects;
|
||||||
|
uint32_t total_triangles;
|
||||||
|
uint32_t visible_triangles;
|
||||||
|
};
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void objectPicked(uint32_t object_id);
|
void objectPicked(uint32_t object_id);
|
||||||
void initialized();
|
void initialized();
|
||||||
|
void frameStatsUpdated(const ViewportWindow::FrameStats& stats);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void exposeEvent(QExposeEvent* event) override;
|
void exposeEvent(QExposeEvent* event) override;
|
||||||
@@ -152,6 +162,10 @@ private:
|
|||||||
|
|
||||||
// Stats
|
// Stats
|
||||||
uint32_t total_triangles_ = 0;
|
uint32_t total_triangles_ = 0;
|
||||||
|
uint32_t visible_triangles_ = 0;
|
||||||
|
int frame_count_ = 0;
|
||||||
|
float accumulated_time_ = 0.0f;
|
||||||
|
float last_fps_ = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VIEWPORTWINDOW_H
|
#endif // VIEWPORTWINDOW_H
|
||||||
|
|||||||
Reference in New Issue
Block a user