summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/manual/qmlperf/CMakeLists.txt3
-rw-r--r--tests/manual/qmlperf/datagenerator.cpp325
-rw-r--r--tests/manual/qmlperf/datagenerator.h44
-rw-r--r--tests/manual/qmlperf/qml/qmlperf/AutoTest.qml219
-rw-r--r--tests/manual/qmlperf/qml/qmlperf/Tests.qml184
-rw-r--r--tests/manual/qmlperf/qml/qmlperf/main.qml559
6 files changed, 1162 insertions, 172 deletions
diff --git a/tests/manual/qmlperf/CMakeLists.txt b/tests/manual/qmlperf/CMakeLists.txt
index 31235e32..b2a90d5f 100644
--- a/tests/manual/qmlperf/CMakeLists.txt
+++ b/tests/manual/qmlperf/CMakeLists.txt
@@ -9,6 +9,7 @@ qt_internal_add_manual_test(qmlperf
datagenerator.cpp datagenerator.h
main.cpp
)
+
target_link_libraries(qmlperf PUBLIC
Qt::Gui
Qt::Qml
@@ -18,6 +19,8 @@ target_link_libraries(qmlperf PUBLIC
set(qmlperf_resource_files
"qml/qmlperf/main.qml"
+ "qml/qmlperf/Tests.qml"
+ "qml/qmlperf/AutoTest.qml"
)
qt_internal_add_resource(qmlperf "qmlperf"
diff --git a/tests/manual/qmlperf/datagenerator.cpp b/tests/manual/qmlperf/datagenerator.cpp
index df00d483..a092e749 100644
--- a/tests/manual/qmlperf/datagenerator.cpp
+++ b/tests/manual/qmlperf/datagenerator.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "datagenerator.h"
@@ -7,62 +7,329 @@
Q_DECLARE_METATYPE(QScatter3DSeries *)
-DataGenerator::DataGenerator(QObject *parent) :
- QObject(parent)
+DataGenerator::DataGenerator(QObject *parent)
+ : QObject(parent)
{
qRegisterMetaType<QScatter3DSeries *>();
-
- m_file = new QFile("results.txt");
- if (!m_file->open(QIODevice::WriteOnly | QIODevice::Text)) {
- delete m_file;
- m_file = 0;
- }
+ qRegisterMetaType<QSurface3DSeries *>();
+ qRegisterMetaType<QBar3DSeries *>();
+ setFilePath(QUrl());
}
DataGenerator::~DataGenerator()
{
m_file->close();
+ m_csv->close();
delete m_file;
+ delete m_csv;
}
-void DataGenerator::generateData(QScatter3DSeries *series, uint count)
+void DataGenerator::generateSurfaceData(QSurface3DSeries *series, uint count)
{
- QScatterDataArray *dataArray = new QScatterDataArray;
- dataArray->resize(count);
- QScatterDataItem *ptrToDataArray = &dataArray->first();
+ if (m_surfaceResetArray) {
+ for (auto row : *m_surfaceResetArray)
+ row->clear();
+ m_surfaceResetArray->clear();
+ }
+ m_surfaceResetArray = new QSurfaceDataArray;
+ m_surfaceResetArray->reserve(count);
for (uint i = 0; i < count; i++) {
- ptrToDataArray->setPosition(QVector3D(QRandomGenerator::global()->generateDouble(),
- QRandomGenerator::global()->generateDouble(),
- QRandomGenerator::global()->generateDouble()));
- ptrToDataArray++;
+ m_surfaceResetArray->append(new QSurfaceDataRow());
+ QSurfaceDataRow *row = m_surfaceResetArray->at(i);
+ row->reserve(count);
+ for (uint j = 0; j < count; j++) {
+ float x = float(j) / float(count);
+ float z = float(i) / float(count);
+ row->append(
+ QSurfaceDataItem(QVector3D(x, QRandomGenerator::global()->generateDouble(), z)));
+ }
}
- series->dataProxy()->resetArray(dataArray);
+ writeLine(QString("Surface Graph: setting %1 points").arg(count * count));
+
+ m_timer.start();
+ series->dataProxy()->resetArray(m_surfaceResetArray);
+ long long nsecs = m_timer.nsecsElapsed();
+
+ writeLine(QString("Took %1 nanoseconds").arg(nsecs));
+
+ populateSurfaceCaches(count);
}
-void DataGenerator::add(QScatter3DSeries *series, uint count)
+void DataGenerator::generateScatterData(QScatter3DSeries *series, uint count)
{
- QScatterDataArray appendArray;
- appendArray.resize(count);
+ if (m_scatterResetArray) {
+ m_scatterResetArray->clear();
+ }
+ m_scatterResetArray = new QScatterDataArray;
+ m_scatterResetArray->reserve(count * count);
+ for (uint i = 0; i < count * count; i++) {
+ m_scatterResetArray->append(
+ QScatterDataItem(QVector3D(QRandomGenerator::global()->generateDouble() * 2 - 1,
+ QRandomGenerator::global()->generateDouble() * 2 - 1,
+ QRandomGenerator::global()->generateDouble() * 2 - 1)));
+ }
+ writeLine(QString("Scatter Graph: setting %1 points").arg(count * count));
+
+ m_timer.start();
+ series->dataProxy()->resetArray(m_scatterResetArray);
+ long long nsecs = m_timer.nsecsElapsed();
+
+ writeLine(QString("Took %1 nanoseconds").arg(nsecs));
+
+ populateScatterCaches(count);
+}
+
+void DataGenerator::generateBarData(QBar3DSeries *series, uint count)
+{
+ if (m_barResetArray) {
+ for (auto row : *m_barResetArray)
+ row->clear();
+ m_barResetArray->clear();
+ }
+
+ m_barResetArray = new QBarDataArray;
+ m_barResetArray->reserve(count);
for (uint i = 0; i < count; i++) {
- appendArray[i].setPosition(QVector3D(QRandomGenerator::global()->generateDouble(),
- QRandomGenerator::global()->generateDouble(),
- QRandomGenerator::global()->generateDouble()));
+ m_barResetArray->append(new QBarDataRow());
+ QBarDataRow *row = m_barResetArray->at(i);
+ row->reserve(count);
+ for (uint j = 0; j < count; j++) {
+ row->append(QBarDataItem(QRandomGenerator::global()->generateDouble()));
+ }
+ }
+
+ writeLine(QString("Bar Graph: setting %1 points").arg(count * count));
+
+ m_timer.start();
+ series->dataProxy()->resetArray(m_barResetArray);
+ long long nsecs = m_timer.nsecsElapsed();
+
+ writeLine(QString("Took %1 nanoseconds").arg(nsecs));
+
+ populateBarChaches(count);
+}
+
+void DataGenerator::updateSurfaceData(QSurface3DSeries *series)
+{
+ if (!series || series->dataProxy()->columnCount() == 0 || series->dataProxy()->rowCount() == 0)
+ return;
+
+ static int index = 0;
+ const QSurfaceDataArray &cache = m_surfaceCaches.at(index);
+ const int rows = cache.count();
+ for (int i = 0; i < rows; i++) {
+ const QSurfaceDataRow &sourceRow = *(cache.at(i));
+ QSurfaceDataRow &row = *(*m_surfaceResetArray)[i];
+ std::copy(sourceRow.cbegin(), sourceRow.cend(), row.begin());
}
- series->dataProxy()->addItems(appendArray);
+ series->dataProxy()->resetArray(m_surfaceResetArray);
+
+ index++;
+ if (index >= m_cacheCount)
+ index = 0;
}
+void DataGenerator::updateScatterData(QScatter3DSeries *series)
+{
+ if (!series || series->dataProxy()->array()->count() == 0)
+ return;
-void DataGenerator::writeLine(int itemCount, float fps)
+ static int index = 0;
+ const QScatterDataArray &cache = m_scatterCaches.at(index);
+
+ const int count = cache.count();
+ for (int i = 0; i < count; i++) {
+ (*m_scatterResetArray)[i].setPosition(cache.at(i).position());
+ }
+
+ series->dataProxy()->resetArray(m_scatterResetArray);
+ index++;
+ if (index >= m_cacheCount)
+ index = 0;
+}
+void DataGenerator::updateBarData(QBar3DSeries *series)
+{
+ static int index = 0;
+ const int rows = series->dataProxy()->rowCount();
+
+ const QBarDataArray &cache = m_barCaches.at(index);
+ for (int i = 0; i < rows; i++) {
+ const QBarDataRow &sourceRow = *(cache.at(i));
+ QBarDataRow &row = *(*m_barResetArray)[i];
+ std::copy(sourceRow.cbegin(), sourceRow.cend(), row.begin());
+ }
+
+ series->dataProxy()->resetArray(m_barResetArray);
+ index++;
+ if (index >= m_cacheCount)
+ index = 0;
+}
+
+void DataGenerator::setFilePath(const QUrl &path)
+{
+ if (m_file) {
+ m_file->close();
+ delete m_file;
+ }
+ if (m_csv) {
+ m_csv->close();
+ delete m_csv;
+ }
+
+ QString pathString = path.toLocalFile();
+ if (!pathString.isEmpty()) {
+ pathString += "/";
+ qDebug() << "Set path to : " << pathString;
+ emit onMessage("Set path to " + pathString);
+ }
+
+ m_file = new QFile(pathString + "results.txt");
+ if (!m_file->open(QIODevice::WriteOnly | QIODevice::Text)) {
+ qDebug() << m_file->errorString();
+ delete m_file;
+ m_file = 0;
+ }
+ m_csv = new QFile(pathString + "measurements.csv");
+ if (!m_csv->open(QIODevice::WriteOnly | QIODevice::Text)) {
+ qDebug() << m_file->errorString();
+ delete m_csv;
+ m_csv = 0;
+ } else {
+ QTextStream out(m_csv);
+ QString headers = QString("Graph type,Number of points,Optimization,MSAA "
+ "Samples,Shadow Quality,Init Time,Average FPS");
+ out << headers << Qt::endl;
+ }
+}
+
+void DataGenerator::writeLine(const QString &line)
{
if (m_file) {
QTextStream out(m_file);
- QString fpsFormatString(QStringLiteral("%1 %2\n"));
- QString fpsString = fpsFormatString.arg(itemCount).arg(fps);
+ qDebug() << line << Qt::endl;
+ out << line << Qt::endl;
+ emit onMessage(line);
+ }
+}
+
+void DataGenerator::writeCSV(const QString &line)
+{
+ if (m_csv) {
+ qDebug() << line << Qt::endl;
+ QTextStream out(m_csv);
+ out << line << Qt::endl;
+ }
+}
- out << fpsString;
+void DataGenerator::populateSurfaceCaches(int sideLength)
+{
+ for (int i = 0; i < m_surfaceCaches.size(); i++) {
+ QSurfaceDataArray &array = m_surfaceCaches[i];
+ array.clear();
+ }
+ m_surfaceCaches.clear();
+
+ // Re-create the cache array
+ m_surfaceCaches.resize(m_cacheCount);
+ for (int i = 0; i < m_cacheCount; i++) {
+ QSurfaceDataArray &array = m_surfaceCaches[i];
+ array.reserve(sideLength);
+ for (int j = 0; j < sideLength; j++) {
+ array.append(new QSurfaceDataRow(sideLength));
+ }
+ }
+
+ //Populate caches
+ for (int i = 0; i < m_cacheCount; i++) {
+ QSurfaceDataArray &cache = m_surfaceCaches[i];
+ float timeStep = float(i) / float(m_cacheCount);
+ for (int j = 0; j < sideLength; j++) {
+ QSurfaceDataRow &row = *(cache[j]);
+ for (int k = 0; k < sideLength; k++) {
+ float x = float(k) / float(sideLength);
+ float z = float(j) / float(sideLength);
+ float y = qSin(2 * M_PI * (x + z + (timeStep))) * 0.5 + 0.5;
+ row[k] = QSurfaceDataItem(QVector3D(x, y, z));
+ }
+ }
+ }
+}
+
+void DataGenerator::populateScatterCaches(int sideLength)
+{
+ for (int i = 0; i < m_scatterCaches.size(); i++) {
+ QScatterDataArray &array = m_scatterCaches[i];
+ array.clear();
+ }
+ m_scatterCaches.clear();
+
+ // Re-create the cache array
+ const int count = sideLength * sideLength;
+ m_scatterCaches.resize(m_cacheCount);
+ for (int i = 0; i < m_cacheCount; i++) {
+ QScatterDataArray &array = m_scatterCaches[i];
+ array.reserve(count);
+ for (int j = 0; j < count; j++) {
+ array.append(QScatterDataItem());
+ }
+ }
+
+ //Populate caches
+ for (int i = 0; i < m_cacheCount; i++) {
+ // time loops from 0 to 4
+ float t = (float(i) * 4) / float(m_cacheCount);
+ QScatterDataArray &cache = m_scatterCaches[i];
+ for (int j = 0; j < sideLength; j++) {
+ for (int k = 0; k < sideLength; k++) {
+ float u = (float(j) / float(sideLength)) * 2 - 1;
+ float v = (float(k) / float(sideLength)) * 2 - 1;
+
+ //create a torus
+ float r1 = 0.7f + 0.1f * qSin(M_PI * (6.0f * u + 0.5f * t));
+ float r2 = 0.15f + 0.05f * qSin(M_PI * (8.0f * u + 4.0f * v + 2.0f * t));
+ float s = r1 + r2 * qCos(M_PI * v);
+
+ float x = s * qSin(M_PI * u);
+ float y = r2 * qSin(M_PI * v);
+ float z = s * qCos(M_PI * u);
+ cache[sideLength * j + k].setPosition(QVector3D(x, y, z));
+ }
+ }
+ }
+}
+
+void DataGenerator::populateBarChaches(int sideLength)
+{
+ for (int i = 0; i < m_barCaches.size(); i++) {
+ QBarDataArray &array = m_barCaches[i];
+ array.clear();
+ }
+ m_barCaches.clear();
+
+ // Re-create the cache array
+ m_barCaches.resize(m_cacheCount);
+ for (int i = 0; i < m_cacheCount; i++) {
+ QBarDataArray &array = m_barCaches[i];
+ array.reserve(sideLength);
+ for (int j = 0; j < sideLength; j++) {
+ array.append(new QBarDataRow(sideLength));
+ }
+ }
+ for (int i = 0; i < m_cacheCount; i++) {
+ QBarDataArray &cache = m_barCaches[i];
+ float timeStep = float(i) / float(m_cacheCount);
+ for (int j = 0; j < sideLength; j++) {
+ QBarDataRow &row = *(cache[j]);
+ for (int k = 0; k < sideLength; k++) {
+ float x = float(j) / float(sideLength);
+ float z = float(k) / float(sideLength);
+ float y = qSin(2 * M_PI * (x + z + (timeStep))) * 0.5 + 0.5;
+ row[k] = QBarDataItem(y);
+ }
+ }
}
}
diff --git a/tests/manual/qmlperf/datagenerator.h b/tests/manual/qmlperf/datagenerator.h
index 99a9dbf7..5e8fe959 100644
--- a/tests/manual/qmlperf/datagenerator.h
+++ b/tests/manual/qmlperf/datagenerator.h
@@ -1,27 +1,53 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef DATAGENERATOR_H
#define DATAGENERATOR_H
-#include <QtDataVisualization/QScatter3DSeries>
#include <QtCore/QFile>
+#include <QtDataVisualization>
-class DataGenerator : public QObject
+class DataGenerator : public QObject
{
Q_OBJECT
public:
DataGenerator(QObject *parent = 0);
- virtual ~DataGenerator();
+ ~DataGenerator() override;
public Q_SLOTS:
- void generateData(QScatter3DSeries *series, uint count);
- void add(QScatter3DSeries *series, uint count);
- void writeLine(int itemCount, float fps);
+ void generateSurfaceData(QSurface3DSeries *series, uint count);
+ void generateScatterData(QScatter3DSeries *series, uint count);
+ void generateBarData(QBar3DSeries *series, uint count);
+
+ void updateScatterData(QScatter3DSeries *series);
+ void updateSurfaceData(QSurface3DSeries *series);
+ void updateBarData(QBar3DSeries *series);
+
+ void setFilePath(const QUrl &path);
+ void writeLine(const QString &line);
+ void writeCSV(const QString &line);
+
+Q_SIGNALS:
+ void onMessage(const QString &message);
+ void onCaptureInit(long long nanoseconds);
private:
- QScatter3DSeries m_series;
- QFile *m_file;
+ QFile *m_file = nullptr;
+ QFile *m_csv = nullptr;
+ QElapsedTimer m_timer;
+ int m_cacheCount = 60;
+
+ QList<QSurfaceDataArray> m_surfaceCaches;
+ QList<QScatterDataArray> m_scatterCaches;
+ QList<QBarDataArray> m_barCaches;
+
+ QSurfaceDataArray *m_surfaceResetArray = nullptr;
+ QScatterDataArray *m_scatterResetArray = nullptr;
+ QBarDataArray *m_barResetArray = nullptr;
+
+ void populateSurfaceCaches(int sideLength);
+ void populateScatterCaches(int sideLength);
+ void populateBarChaches(int sideLength);
};
#endif // DATAGENERATOR_H
diff --git a/tests/manual/qmlperf/qml/qmlperf/AutoTest.qml b/tests/manual/qmlperf/qml/qmlperf/AutoTest.qml
new file mode 100644
index 00000000..d860b99a
--- /dev/null
+++ b/tests/manual/qmlperf/qml/qmlperf/AutoTest.qml
@@ -0,0 +1,219 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import QtDataVisualization
+import "."
+
+Item {
+
+ height: 150
+
+ property list<string> graphTypes: ["Surface", "Scatter", "Bars"]
+ property int currentGraph: 0
+
+ property list<int>dataPoints: [10, 100, 300, 500]
+ property int currentPoints: 0
+
+ property list<string> optimization: ["Default", "Static"]
+ property int currentOptimization: 0
+
+ property list<int> sampleCounts: [0,2,4,8]
+ property int currentSamples: 0
+
+
+ property int shadowQuality
+
+ property bool finished: true
+
+ property int initTime: 0
+
+ function initAutoTest() {
+ //go through each graph iterating over all the variables
+ liveDataCB.checked = true
+ rotateCB.checked = true
+
+ tests.onTestFinished.connect(test)
+ dataGenerator.onCaptureInit.connect(setInitTime)
+
+ finished = false
+
+ currentGraph = 0
+ currentPoints = 0
+ currentOptimization = 0
+ currentSamples= 0
+ shadowQuality = 0
+
+ setParameters()
+ tests.startTest()
+ }
+
+ function test() {
+ //write previous test results
+ var averageFps = tests.averageFps
+ // graph type, num points, optimization, msaa, init time, averagefps
+ var csvLine = graphTypes[currentGraph] + ","
+ + (dataPoints[currentPoints] * dataPoints[currentPoints])+ ","
+ + optimization[currentOptimization] + ","
+ + sampleCounts[currentSamples] + ","
+ + shadowQuality + ","
+ + initTime + ","
+ + averageFps
+
+ dataGenerator.writeCSV(csvLine)
+ increment()
+ setParameters()
+ if (!finished) {
+ tests.startTest()
+ } else {
+ tests.onTestFinished.disconnect(test)
+ dataGenerator.onCaptureInit.disconnect(setInitTime)
+ }
+ }
+
+ function increment() {
+ if (varyShadow.checked) {
+ if (shadowQuality < 6) {
+ shadowQuality++
+ return
+ }
+ shadowQuality = 0
+ }
+
+ if (varySamples.checked) {
+ if (currentSamples < sampleCounts.length -1) {
+ currentSamples ++
+ return
+ }
+ currentSamples = 0
+ }
+
+ if (varyOptimization.checked) {
+ if (currentOptimization < optimization.length -1
+ && tabBar.currentIndex !== 0) {
+ currentOptimization++
+ return
+ }
+ currentOptimization = 0
+ }
+
+ if (varyPoints.checked) {
+ if (currentPoints < dataPoints.length -1) {
+ currentPoints ++
+ return
+ }
+ currentPoints = 0
+ }
+
+ if (varyGraphs.checked) {
+ if (currentGraph < graphTypes.length - 1) {
+ currentGraph++
+ console.log("Switching to " + graphTypes[currentGraph])
+ return
+ }
+ currentGraph = 0
+ }
+
+ dataGenerator.writeLine("Finished all tests!")
+ finished = true
+ }
+
+
+ function setParameters() {
+ if (varyShadow.checked) {
+ surfaceGraph.shadowQuality = shadowQuality
+ scatterGraph.shadowQuality = shadowQuality
+ barGraph.shadowQuality = shadowQuality
+ }
+
+ if (varySamples.checked) {
+ surfaceGraph.msaaSamples = sampleCounts[currentSamples]
+ scatterGraph.msaaSamples = sampleCounts[currentSamples]
+ barGraph.msaaSamples = sampleCounts[currentSamples]
+ }
+
+ if (varyOptimization.checked) {
+ if (optimization[currentOptimization] === "Legacy") {
+ scatterGraph.optimizationHint = AbstractGraph3D.OptimizationHint.Default
+ barGraph.optimizationHint = AbstractGraph3D.OptimizationHint.Default
+ } else {
+ scatterGraph.optimizationHint = AbstractGraph3D.OptimizationHint.Legacy
+ barGraph.optimizationHint = AbstractGraph3D.OptimizationHint.Legacy
+ }
+ }
+
+ if (varyGraphs.checked)
+ tabBar.setCurrentIndex(currentGraph)
+
+ if (varyPoints.checked) {
+ if (tabBar.currentIndex === 0)
+ dataGenerator.generateSurfaceData(surfaceSeries, dataPoints[currentPoints])
+ else if (tabBar.currentIndex === 1)
+ dataGenerator.generateScatterData(scatterSeries, dataPoints[currentPoints])
+ else
+ dataGenerator.generateBarData(barSeries, dataPoints[currentPoints])
+ }
+ }
+
+ function setInitTime(nsecs) {
+ initTime = nsecs
+ }
+
+ Button {
+ id: autoButton
+ text: finished? "Auto Test" : "End test"
+ width: parent.width - 20
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ height: 50
+ onClicked: {
+ if (finished) {
+ dataGenerator.writeLine("Testing configurations...")
+ initAutoTest()
+ } else {
+ finished = true
+ }
+
+ }
+ }
+
+ GridLayout {
+ id: autoTestParams
+ anchors.top: autoButton.bottom
+ anchors.topMargin: 10
+ width: parent.width - 50
+ enabled: finished
+ anchors.horizontalCenter: parent.Center
+ height: 50
+ columns: 2
+ CheckBox {
+ id: varyGraphs
+ text: qsTr("Vary graphs")
+ Layout.alignment: Qt.AlignCenter
+ checked: true
+ }
+ CheckBox {
+ id: varyPoints
+ text: qsTr("Vary points")
+ Layout.alignment: Qt.AlignCenter
+ checked: true
+ }
+ CheckBox {
+ id: varyOptimization
+ text: qsTr("Vary optimization")
+ Layout.alignment: Qt.AlignCenter
+ }
+ CheckBox {
+ id: varySamples
+ text: qsTr("Vary MSAA ")
+ Layout.alignment: Qt.AlignCenter
+ }
+ CheckBox {
+ id: varyShadow
+ text: qsTr("Vary Shadow ")
+ Layout.alignment: Qt.AlignCenter
+ }
+ }
+}
diff --git a/tests/manual/qmlperf/qml/qmlperf/Tests.qml b/tests/manual/qmlperf/qml/qmlperf/Tests.qml
new file mode 100644
index 00000000..dc533641
--- /dev/null
+++ b/tests/manual/qmlperf/qml/qmlperf/Tests.qml
@@ -0,0 +1,184 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import QtDataVisualization
+import "."
+
+Item {
+ id: tests
+
+ property alias currentFps: fpsText.fps
+ property alias dataPoints: dataPointText.dataPoints
+ property alias buttonVisible: testButton.visible
+ property real averageFps: 0
+
+ signal onTestFinished
+
+ property list<real> fpsCounts: []
+ Component.onCompleted: {
+ dataGenerator.onMessage.connect(addLine)
+ }
+
+ function addLine(line) {
+ logModel.append({'logText':line});
+ }
+
+
+ function startTest() {
+ // logModel.clear()
+ fpsCounts = []
+ dataGenerator.writeLine(" ")
+ switch (tabBar.currentIndex) {
+ case 0:
+ dataGenerator.writeLine("Started surface test with configuration:")
+ break
+ case 1:
+ dataGenerator.writeLine("Started scatter test with configuration:")
+ break
+ case 2:
+ dataGenerator.writeLine("Started bars test with configuration:")
+ break
+ default:
+ break
+ }
+
+ if (tabBar.currentIndex === 0) {
+ dataGenerator.writeLine("Shadow Quality: " + surfaceGraph.shadowQuality)
+ dataGenerator.writeLine("MSAA samples: "
+ + surfaceGraph.msaaSamples)
+ } else if (tabBar.currentIndex === 1) {
+ dataGenerator.writeLine("Shadow Quality: " + scatterGraph.shadowQuality)
+ var optimizationString = scatterGraph.optimizationHint? "Static" : "Default"
+ dataGenerator.writeLine("Optimization: " + optimizationString)
+ dataGenerator.writeLine("MSAA samples: "
+ + scatterGraph.msaaSamples)
+ } else {
+ dataGenerator.writeLine("Shadow Quality: " + scatterGraph.shadowQuality)
+ optimizationString = barGraph.optimizationHint? "Static" : "Default"
+ dataGenerator.writeLine("Optimization: " + optimizationString)
+ dataGenerator.writeLine("MSAA samples: "
+ + barGraph.msaaSamples)
+
+ }
+
+ testTimer.start()
+ }
+
+ Button {
+ id: testButton
+ text: "Test current"
+ onClicked: startTest()
+ height: 50
+ width: parent.width - 20
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+
+ ColumnLayout {
+ id: statsPanel
+ anchors.top: testButton.bottom
+ anchors.topMargin: 20
+ width: parent.width
+ Text {
+ id: statsBanner
+ text: "Statistics"
+ font.bold: true
+ font.pixelSize: 16
+ Layout.fillWidth: true
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ Text {
+ id: fpsText
+ property real fps: 0
+ text: qsTr("FPS: %1").arg(fps)
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignHCenter
+
+ }
+
+ Text {
+ id: dataPointText
+ property int dataPoints: 0
+ text : qsTr("Data Points: %1").arg(dataPoints)
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ Text {
+ id: logBanner
+ text: "Log"
+ font.bold: true
+ font.pixelSize: 16
+ Layout.fillWidth: true
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+
+ Rectangle {
+ id: logBackground
+ Layout.fillWidth: true
+ Layout.preferredHeight: 170
+ Layout.margins: 10
+ color: "forestgreen"
+ ListView {
+ id: logView
+ anchors.fill: parent
+ highlightFollowsCurrentItem: true
+ clip: true
+ delegate: Text {
+ text: logText
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ width: logView.width
+ wrapMode: Text.Wrap
+ }
+
+ model: ListModel {
+ id: logModel
+ }
+
+ onCountChanged: {
+ logView.currentIndex = count - 1
+ }
+ }
+ }
+ }
+
+ Timer {
+ id: testTimer
+ interval: 1000
+ repeat: true
+ onTriggered: {
+ var fps = 0
+ if (tabBar.currentIndex === 0)
+ fps = surfaceGraph.currentFps
+ else if (tabBar.currentIndex === 1)
+ fps = scatterGraph.currentFps
+ else
+ fps = barGraph.currentFps
+
+ if (fps != -1) {
+ fpsCounts.push(fps)
+ dataGenerator.writeLine("FPS: " + fps)
+ }
+ else {
+ dataGenerator.writeLine("Invalid fps reading")
+ }
+
+ if (fpsCounts.length >= 5) {
+ var sum = 0
+ fpsCounts.forEach((element) => sum+=element);
+ averageFps = sum / fpsCounts.length
+ dataGenerator.writeLine("Average FPS: " + averageFps)
+ testTimer.stop()
+ onTestFinished()
+ }
+ }
+ }
+}
diff --git a/tests/manual/qmlperf/qml/qmlperf/main.qml b/tests/manual/qmlperf/qml/qmlperf/main.qml
index 4562e538..ce282e87 100644
--- a/tests/manual/qmlperf/qml/qmlperf/main.qml
+++ b/tests/manual/qmlperf/qml/qmlperf/main.qml
@@ -1,176 +1,467 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+import QtCore
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
-import QtDataVisualization 1.2
+import QtQuick3D.Helpers
+import QtQuick.Dialogs
+import QtDataVisualization
import "."
Item {
- id: mainview
+ id: mainView
width: 1280
height: 1024
- property var itemCount: 1000.0
- property var addItems: 500.0
-
- Button {
- id: changeButton
- width: parent.width / 7
- height: 50
+ TabBar {
+ id: tabBar
+ anchors.top: parent.top
+ anchors.right: panels.left
anchors.left: parent.left
- enabled: true
- text: "Change"
- onClicked: {
- console.log("changeButton clicked");
- if (graphView.state == "meshsphere") {
- graphView.state = "meshcube"
- } else if (graphView.state == "meshcube") {
- graphView.state = "meshpyramid"
- } else if (graphView.state == "meshpyramid") {
- graphView.state = "meshpoint"
- } else if (graphView.state == "meshpoint") {
- graphView.state = "meshsphere"
- }
+ contentHeight: 50
+ TabButton {
+ text: qsTr("Surface")
+ }
+ TabButton {
+ text: qsTr("Scatter")
+ }
+ TabButton {
+ text: qsTr("Bars")
}
}
- Text {
- id: fpsText
- text: "Reading"
- width: (parent.width / 7) * 3
- height: 50
- anchors.left: changeButton.right
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
- }
+ Rectangle {
+ id: panels
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ width: parent.width / 5
+ color: "green"
+
+ ColumnLayout {
+ id: buttonPanel
+ anchors.top: parent.top
+ width: parent.width
+ spacing: 10
+ visible: autoTest.finished
- Button {
- id: optimization
- width: parent.width / 7
- height: 50
- anchors.left: fpsText.right
- enabled: true
- text: scatterPlot.optimizationHints === AbstractGraph3D.OptimizationDefault ? "To Static" : "To Default"
- onClicked: {
- console.log("Optimization");
- if (scatterPlot.optimizationHints === AbstractGraph3D.OptimizationDefault) {
- scatterPlot.optimizationHints = AbstractGraph3D.OptimizationStatic;
- optimization.text = "To Default";
- } else {
- scatterPlot.optimizationHints = AbstractGraph3D.OptimizationDefault;
- optimization.text = "To Static";
+ Button {
+ id: shadowToggle
+ property int shadowQuality: 0
+ property string qualityName: "None"
+ text: qsTr("Shadow Quality : %1").arg(qualityName)
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ Layout.margins: 10
+ Layout.alignment: Qt.AlignCenter
+ onClicked: {
+ var nextQuality = (shadowQuality + 1) % 7
+ surfaceGraph.shadowQuality = nextQuality
+ scatterGraph.shadowQuality = nextQuality
+ barGraph.shadowQuality = nextQuality
+ shadowQuality = nextQuality
+ qualityName = barGraph.shadowQuality.toString()
+ console.log("Set shadow quality to " + qualityName)
+ }
+ }
+
+ Button {
+ id: optimizationToggle
+ visible: tabBar.currentIndex > 0
+ property string optimization: "Default"
+ text: qsTr("Optimization: %1").arg(optimization)
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ Layout.margins: 10
+ Layout.alignment: Qt.AlignCenter
+ onClicked: {
+ if (optimization === "Static") {
+ scatterGraph.optimizationHints = AbstractGraph3D.OptimizationDefault
+ barGraph.optimizationHints = AbstractGraph3D.OptimizationDefault
+ optimization= "Default"
+ } else {
+ scatterGraph.optimizationHints = AbstractGraph3D.OptimizationStatic
+ barGraph.optimizationHints = AbstractGraph3D.OptimizationStatic
+ optimization = "Static"
+ }
+ console.log("Set optimization to " + optimization)
+ }
+ }
+
+ Button {
+ id: samplesButton
+ property list<int> samples: [0,2,4,8]
+ property int index: 0
+ text: qsTr("MSAA samples: %1").arg(samples[index])
+
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ Layout.margins: 10
+ Layout.alignment: Qt.AlignCenter
+ onClicked: {
+ index = (index + 1) % 4
+ surfaceGraph.msaaSamples = samples[index]
+ scatterGraph.msaaSamples = samples[index]
+ barGraph.msaaSamples = samples[index]
+ console.log("Set msaa samples to " + samples[index])
+ }
+ }
+
+ Button {
+ id: scatterMesh
+ visible: tabBar.currentIndex === 1
+ property string mesh: "Sphere"
+ text: qsTr("Mesh: %1").arg(mesh)
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ Layout.margins: 10
+ Layout.alignment: Qt.AlignCenter
+ onClicked: {
+ if (mesh === "Sphere") {
+ scatterSeries.mesh = Abstract3DSeries.MeshCube
+ mesh = "Cube"
+ } else if (mesh === "Cube") {
+ scatterSeries.mesh = Abstract3DSeries.MeshPyramid
+ mesh = "Pyramid"
+ } else if (mesh === "Pyramid") {
+ scatterSeries.mesh = Abstract3DSeries.MeshPoint
+ mesh = "Point"
+ } else {
+ scatterSeries.mesh = Abstract3DSeries.MeshSphere
+ mesh = "Sphere"
+ }
+ }
+ }
+
+
+ Button {
+ id: surfaceShadingToggle
+ visible: tabBar.currentIndex <= 2
+ text: qsTr("Flat shading: %1").arg(surfaceSeries.flatShadingEnabled.toString())
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ Layout.margins: 10
+ Layout.alignment: Qt.AlignCenter
+ onClicked: {
+ surfaceSeries.flatShadingEnabled =
+ !surfaceSeries.flatShadingEnabled
+ scatterSeries.meshSmooth = !scatterSeries.meshSmooth
+ }
+ }
+
+ Button {
+ id: gridToggle
+ visible: tabBar.currentIndex === 0
+ property bool gridEnabled
+ text: qsTr("Show grid: %1").arg(gridEnabled.toString())
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ Layout.margins: 10
+ Layout.alignment: Qt.AlignCenter
+ onClicked: {
+ if (surfaceSeries.drawMode & Surface3DSeries.DrawWireframe)
+ surfaceSeries.drawMode &= ~Surface3DSeries.DrawWireframe;
+ else
+ surfaceSeries.drawMode |= Surface3DSeries.DrawWireframe;
+
+ gridEnabled = surfaceSeries.drawMode & Surface3DSeries.DrawWireframe
+ }
+
+ }
+
+ ColumnLayout {
+ id: pointSetContainer
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ Layout.margins: 10
+ Layout.alignment: Qt.AlignCenter
+
+
+ Text {
+ id: spinboxTitle
+ text: "Side length"
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ SpinBox {
+ id: sizeField
+ from: 2
+ to: 500
+ stepSize: 20
+ value: 10
+ editable: true
+ Layout.preferredWidth: parent.width
+ }
+
+ Button {
+ id: pointSetButton
+ text: qsTr("Place points");
+ Layout.preferredWidth: parent.width
+ Layout.bottomMargin: 10
+ onClicked: {
+ switch (tabBar.currentIndex) {
+ case 0:
+ dataGenerator.generateSurfaceData(surfaceSeries, sizeField.value)
+ break;
+ case 1:
+ dataGenerator.generateScatterData(scatterSeries, sizeField.value)
+ break;
+ case 2:
+ dataGenerator.generateBarData(barSeries, sizeField.value)
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ GridLayout {
+ id: checkBoxPanel
+ anchors.top: buttonPanel.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.margins: 10
+ visible: autoTest.finished
+ columns: 2
+
+ CheckBox {
+ id: liveDataCB
+ text: qsTr("Live Data")
+ Layout.fillWidth: true
+ Layout.margins: 10
+ Layout.alignment: Qt.AlignCenter
+ }
+ CheckBox {
+ id: rotateCB
+ text: qsTr("Rotation")
+ Layout.fillWidth: true
+ Layout.margins: 10
+ Layout.alignment: Qt.AlignCenter
+ }
+
+ ColumnLayout {
+ id: freqContainer
+ Layout.columnSpan: 2
+ Text {
+ text: qsTr("Frequency: %1").arg(frequencySlider.value)
+ Layout.fillWidth: true
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+ Slider {
+ id: frequencySlider
+ from: 1
+ to: 60
+ stepSize: 1
+ value: 30
+ snapMode: Slider.SnapAlways
+ Layout.alignment: Qt.AlignCenter
+ }
}
}
- }
- Button {
- id: itemAdd
- width: parent.width / 7
- height: 50
- anchors.left: optimization.right
- enabled: true
- text: "Add"
- onClicked: {
- itemCount = itemCount + addItems;
- dataGenerator.add(scatterSeries, addItems);
+ AutoTest {
+ id: autoTest
+ width: parent.width
+ anchors.top: checkBoxPanel.bottom
+ anchors.left: parent.left
+ anchors.topMargin: 10
+ }
+
+ Tests {
+ id: tests
+ width: parent.width
+ anchors.top: autoTest.bottom
+ anchors.left: parent.left
+ buttonVisible: autoTest.finished
+ }
+
+ Button {
+ id: pathButton
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: "Set logfile path"
+ anchors.margins: 10
+ onClicked: folderDialog.open()
}
}
- Button {
- id: writeLine
- width: parent.width / 7
- height: 50
- anchors.left: itemAdd.right
- enabled: true
- text: "Write"
- onClicked: {
- dataGenerator.writeLine(itemCount, scatterPlot.currentFps.toFixed(1));
+ FolderDialog {
+ id: folderDialog
+ currentFolder: StandardPaths.standardLocations(StandardPaths.DocumentsLocation)[0]
+ onAccepted: dataGenerator.setFilePath(currentFolder)
+ }
+
+ Timer {
+ id: rotationTimer
+ interval: 15
+ running: rotateCB.checked
+ repeat: true
+ onTriggered: {
+ switch (tabBar.currentIndex) {
+ case 0:
+ if (++surfaceGraph.scene.activeCamera.xRotation == 360)
+ surfaceGraph.cameraXRotation = 0;
+ break
+ case 1:
+ if (++scatterGraph.scene.activeCamera.xRotation == 360)
+ scatterGraph.cameraXRotation = 0;
+ break
+ case 2:
+ if (++barGraph.scene.activeCamera.xRotation == 360)
+ barGraph.cameraXRotation = 0;
+ break
+ }
}
}
- Item {
- id: graphView
- width: mainview.width
- height: mainview.height
- anchors.top: changeButton.bottom
- anchors.left: mainview.left
- state: "meshsphere"
-
- Scatter3D {
- id: scatterPlot
- width: graphView.width
- height: graphView.height
- shadowQuality: AbstractGraph3D.ShadowQualityNone
- optimizationHints: AbstractGraph3D.OptimizationDefault
- scene.activeCamera.yRotation: 45.0
- measureFps: true
- onCurrentFpsChanged: {
- fpsText.text = itemCount + " : " + scatterPlot.currentFps.toFixed(1);
+ Timer {
+ id: updateTimer
+ interval: 1000 / frequencySlider.value
+ running: liveDataCB.checked
+ repeat: true
+ onTriggered: {
+ switch (tabBar.currentIndex) {
+ case 0:
+ dataGenerator.updateSurfaceData(surfaceSeries)
+ break
+ case 1:
+ dataGenerator.updateScatterData(scatterSeries)
+ break
+ case 2:
+ dataGenerator.updateBarData(barSeries)
+ break
}
+ }
+ }
+
+
+ StackLayout {
+ anchors.top: tabBar.bottom
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: panels.left
+ currentIndex: tabBar.currentIndex
+
+ Item {
+ id: surfaceTab
+ Surface3D {
+ id: surfaceGraph
+ anchors.fill: parent
+ shadowQuality: AbstractGraph3D.ShadowQualityNone
+ scene.activeCamera.yRotation: 45.0
+ measureFps: true
+
+ axisX.min: 0
+ axisX.max: 1
+ axisY.min: 0
+ axisY.max: 1
+ horizontalAspectRatio: 1.0
+
- theme: Theme3D {
- type: Theme3D.ThemeRetro
- colorStyle: Theme3D.ColorStyleRangeGradient
- baseGradients: customGradient
+ theme : Theme3D {
+ type: Theme3D.ThemeQt
+ colorStyle: Theme3D.ColorStyleRangeGradient
+ baseGradients: surfaceGradient
- ColorGradient {
- id: customGradient
- ColorGradientStop { position: 1.0; color: "red" }
- ColorGradientStop { position: 0.0; color: "blue" }
+ ColorGradient {
+ id: surfaceGradient
+ ColorGradientStop { position: 1.0; color: "red" }
+ ColorGradientStop { position: 0.0; color: "blue" }
+ }
}
- }
- Scatter3DSeries {
- id: scatterSeries
- mesh: Abstract3DSeries.MeshSphere
- }
+ Surface3DSeries {
+ id: surfaceSeries
+ dataProxy.onArrayReset: tests.dataPoints = dataProxy.columnCount * dataProxy.rowCount
+ }
- Component.onCompleted: dataGenerator.generateData(scatterSeries, itemCount);
+ onCurrentFpsChanged: {
+ tests.currentFps = currentFps
+ }
+ }
}
+ Item {
+ id: scatterTab
+ Scatter3D {
+ id: scatterGraph
+ anchors.fill: parent
+ shadowQuality: AbstractGraph3D.ShadowQualityNone
+ scene.activeCamera.yRotation: 45.0
+ aspectRatio: 1.0
+ horizontalAspectRatio: 1.0
+
+ axisY.min: -1
+ axisY.max: 1
+ axisX.min: -1
+ axisX.max: 1
+ axisZ.min: -1
+ axisZ.max: 1
+
+ measureFps: true
+ theme : Theme3D {
+ type: Theme3D.ThemeQt
+ colorStyle: Theme3D.ColorStyleRangeGradient
+ baseGradients: scatterGradient
- states: [
- State {
- name: "meshsphere"
- StateChangeScript {
- name: "doSphere"
- script: {
- console.log("Do the sphere");
- scatterSeries.mesh = Abstract3DSeries.MeshSphere;
+ ColorGradient {
+ id: scatterGradient
+ ColorGradientStop { position: 1.0; color: "yellow" }
+ ColorGradientStop { position: 0.6; color: "red" }
+ ColorGradientStop { position: 0.4; color: "blue" }
+ ColorGradientStop { position: 0.0; color: "green" }
}
}
- },
- State {
- name: "meshcube"
- StateChangeScript {
- name: "doCube"
- script: {
- console.log("Do the cube");
- scatterSeries.mesh = Abstract3DSeries.MeshCube;
- }
+ Scatter3DSeries {
+ id: scatterSeries
+ dataProxy.onArrayReset: tests.dataPoints = dataProxy.itemCount
+ itemSize: 0.1
}
- },
- State {
- name: "meshpyramid"
- StateChangeScript {
- name: "doPyramid"
- script: {
- console.log("Do the pyramid");
- scatterSeries.mesh = Abstract3DSeries.MeshPyramid;
- }
+ onCurrentFpsChanged: {
+ tests.currentFps = currentFps
}
- },
- State {
- name: "meshpoint"
- StateChangeScript {
- name: "doPoint"
- script: {
- console.log("Do the point");
- scatterSeries.mesh = Abstract3DSeries.MeshPoint;
+ }
+ }
+ Item {
+ id: barTab
+ Bars3D {
+ id: barGraph
+ anchors.fill: parent
+ shadowQuality: AbstractGraph3D.ShadowQualityNone
+ scene.activeCamera.yRotation: 45.0
+ measureFps: true
+ valueAxis.min: 0
+ valueAxis.max: 1
+
+ theme : Theme3D {
+ type: Theme3D.ThemeQt
+ colorStyle: Theme3D.ColorStyleRangeGradient
+ baseGradients: barGradient
+
+ ColorGradient{
+ id: barGradient
+ ColorGradientStop { position: 1.0; color: "red" }
+ ColorGradientStop { position: 0.0; color: "blue" }
}
}
+
+ Bar3DSeries {
+ id: barSeries
+ dataProxy.onArrayReset: tests.dataPoints
+ = dataProxy.colCount * dataProxy.rowCount
+
+ }
+
+ onCurrentFpsChanged: {
+ tests.currentFps = currentFps
+ }
}
- ]
+ }
}
}