5#include <QtQuick3DRuntimeRender/private/qssgrendermesh_p.h>
6#include <QtQuick/qquickwindow.h>
7#include <QtQuick/qquickitem.h>
48 return m_results.frameTime;
61 return m_results.renderTime;
74 return m_results.renderPrepareTime;
87 return m_results.syncTime;
99 return m_maxFrameTime;
102float QQuick3DRenderStats::timestamp()
const
109 m_syncStartTime = timestamp();
114 m_results.syncTime = timestamp() - m_syncStartTime;
117 qDebug(
"Sync took: %f ms", m_results.syncTime);
122 m_renderStartTime = timestamp();
127 m_renderPrepareStartTime = timestamp();
132 m_results.renderPrepareTime = timestamp() - m_renderPrepareStartTime;
144 m_renderingThisFrame =
true;
145 const float endTime = timestamp();
146 m_results.renderTime = endTime - m_renderStartTime;
149 qDebug(
"Render took: %f ms (of which prep: %f ms)", m_results.renderTime, m_results.renderPrepareTime);
152void QQuick3DRenderStats::onFrameSwapped()
157 if (m_renderingThisFrame) {
159 m_results.frameTime = timestamp();
160 m_internalMaxFrameTime =
qMax(m_results.frameTime, m_internalMaxFrameTime);
162 m_secTimer += m_results.frameTime;
163 m_notifyTimer += m_results.frameTime;
165 m_results.renderTime = m_results.frameTime - m_renderStartTime;
167 processRhiContextStats();
174 const float msecs = float(
cb->lastCompletedGpuTime() * 1000.0);
176 m_results.lastCompletedGpuTime = msecs;
181 const float notifyInterval = 200.0f;
182 if (m_notifyTimer >= notifyInterval) {
183 m_notifyTimer -= notifyInterval;
185 if (m_results.frameTime != m_notifiedResults.frameTime) {
186 m_notifiedResults.frameTime = m_results.frameTime;
190 if (m_results.syncTime != m_notifiedResults.syncTime) {
191 m_notifiedResults.syncTime = m_results.syncTime;
195 if (m_results.renderTime != m_notifiedResults.renderTime) {
196 m_notifiedResults.renderTime = m_results.renderTime;
197 m_notifiedResults.renderPrepareTime = m_results.renderPrepareTime;
201 if (m_results.lastCompletedGpuTime != m_notifiedResults.lastCompletedGpuTime) {
202 m_notifiedResults.lastCompletedGpuTime = m_results.lastCompletedGpuTime;
206 notifyRhiContextStats();
209 const float fpsInterval = 1000.0f;
210 if (m_secTimer >= fpsInterval) {
211 m_secTimer -= fpsInterval;
213 m_fps = m_frameCount;
217 m_maxFrameTime = m_internalMaxFrameTime;
218 m_internalMaxFrameTime = 0;
222 m_renderingThisFrame =
false;
234 m_contextStats = &
ctx->stats();
239 if (m_extendedDataCollectionEnabled)
242 if (m_contextStats && m_contextStats->
context.
rhi()) {
262 m_frameSwappedConnection =
connect(m_window, &QQuickWindow::afterFrameEnd,
263 this, &QQuick3DRenderStats::onFrameSwapped,
288 return m_extendedDataCollectionEnabled;
293 if (
enable != m_extendedDataCollectionEnabled) {
294 m_extendedDataCollectionEnabled =
enable;
297 if (m_contextStats) {
302 if (m_extendedDataCollectionEnabled)
361 return "ETC2_RGB8A1";
410 if (!mesh->
subsets.isEmpty()) {
413 return buf->buffer()->name();
418void QQuick3DRenderStats::processRhiContextStats()
420 if (!m_contextStats || !m_extendedDataCollectionEnabled)
432 m_results.drawCallCount = 0;
433 m_results.drawVertexCount = 0;
434 for (
const auto &pass :
data.renderPasses) {
444 m_results.renderPassCount =
data.renderPasses.size()
445 + (
data.externalRenderPass.pixelSize.isEmpty() ? 0 : 1);
448| Name | Size | Vertices | Draw calls |
449| ---- | ---- | -------- | ---------- |
452 if (!
data.externalRenderPass.pixelSize.isEmpty())
454 for (
const auto &pass :
data.renderPasses) {
455 if (!pass.pixelSize.isEmpty())
461 if (m_results.activeTextures !=
textures) {
462 m_results.activeTextures =
textures;
464| Name | Size | Format | Mip | Flags |
465| ---- | ---- | ------ | --- | ----- |
469 return a->name() < b->name();
473 const QRhiTexture::Flags
flags = tex->flags();
480 tex->name().constData(),
481 tex->pixelSize().width(),
482 tex->pixelSize().height(),
488 m_results.textureDetails = texDetails;
491 if (m_results.activeMeshes != meshes) {
492 m_results.activeMeshes = meshes;
494| Name | Submeshes | Vertices | V.buf size | I.buf size |
495| ---- | --------- | -------- | ---------- | ---------- |
499 return nameForRenderMesh(a) < nameForRenderMesh(b);
503 const int subsetCount = int(mesh->subsets.size());
507 if (subsetCount > 0) {
509 vertexCount += subset.
count;
511 const QSSGRhiBuffer *vbuf = mesh->subsets[0].rhi.vertexBuffer.get();
514 const QSSGRhiBuffer *ibuf = mesh->subsets[0].rhi.indexBuffer.get();
530 m_results.pipelineCount =
pipelines.count();
538void QQuick3DRenderStats::notifyRhiContextStats()
540 if (!m_contextStats || !m_extendedDataCollectionEnabled)
543 if (m_results.drawCallCount != m_notifiedResults.drawCallCount) {
544 m_notifiedResults.drawCallCount = m_results.drawCallCount;
548 if (m_results.drawVertexCount != m_notifiedResults.drawVertexCount) {
549 m_notifiedResults.drawVertexCount = m_results.drawVertexCount;
553 if (m_results.imageDataSize != m_notifiedResults.imageDataSize) {
554 m_notifiedResults.imageDataSize = m_results.imageDataSize;
558 if (m_results.meshDataSize != m_notifiedResults.meshDataSize) {
559 m_notifiedResults.meshDataSize = m_results.meshDataSize;
563 if (m_results.renderPassCount != m_notifiedResults.renderPassCount) {
564 m_notifiedResults.renderPassCount = m_results.renderPassCount;
568 if (m_results.renderPassDetails != m_notifiedResults.renderPassDetails) {
569 m_notifiedResults.renderPassDetails = m_results.renderPassDetails;
573 if (m_results.textureDetails != m_notifiedResults.textureDetails) {
574 m_notifiedResults.textureDetails = m_results.textureDetails;
578 if (m_results.meshDetails != m_notifiedResults.meshDetails) {
579 m_notifiedResults.meshDetails = m_results.meshDetails;
583 if (m_results.pipelineCount != m_notifiedResults.pipelineCount) {
584 m_notifiedResults.pipelineCount = m_results.pipelineCount;
588 if (m_results.materialGenerationTime != m_notifiedResults.materialGenerationTime) {
589 m_notifiedResults.materialGenerationTime = m_results.materialGenerationTime;
593 if (m_results.effectGenerationTime != m_notifiedResults.effectGenerationTime) {
594 m_notifiedResults.effectGenerationTime = m_results.effectGenerationTime;
598 if (m_results.rhiStats.totalPipelineCreationTime != m_notifiedResults.rhiStats.totalPipelineCreationTime) {
599 m_notifiedResults.rhiStats.totalPipelineCreationTime = m_results.rhiStats.totalPipelineCreationTime;
603 if (m_results.rhiStats.allocCount != m_notifiedResults.rhiStats.allocCount) {
604 m_notifiedResults.rhiStats.allocCount = m_results.rhiStats.allocCount;
608 if (m_results.rhiStats.usedBytes != m_notifiedResults.rhiStats.usedBytes) {
609 m_notifiedResults.rhiStats.usedBytes = m_results.rhiStats.usedBytes;
628 return m_results.drawCallCount;
649 return m_results.drawVertexCount;
671 return m_results.imageDataSize;
693 return m_results.meshDataSize;
715 return m_results.renderPassCount;
726 return m_results.renderPassDetails;
737 return m_results.textureDetails;
748 return m_results.meshDetails;
768 return m_results.pipelineCount;
789 return m_results.materialGenerationTime;
810 return m_results.effectGenerationTime;
853 return m_results.rhiStats.totalPipelineCreationTime;
876 return m_results.rhiStats.allocCount;
899 return m_results.rhiStats.usedBytes;
913 return m_graphicsApiName;
940 return m_results.lastCompletedGpuTime;
951 qWarning(
"QQuick3DRenderStats: No window, cannot request releasing cached resources");
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
qint64 restart() noexcept
Restarts the timer and returns the number of milliseconds elapsed since the previous start.
void start() noexcept
Starts this timer.
qint64 nsecsElapsed() const noexcept
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void setWindow(QQuickWindow *window)
void graphicsApiNameChanged()
QQuick3DRenderStats(QObject *parent=nullptr)
\qmltype RenderStats \inqmlmodule QtQuick3D
void meshDataSizeChanged()
void lastCompletedGpuTimeChanged()
void setExtendedDataCollectionEnabled(bool enable)
void pipelineCreationTimeChanged()
qint64 materialGenerationTime
void maxFrameTimeChanged()
void endSync(bool dump=false)
void setRhiContext(QSSGRhiContext *ctx, QSSGRenderLayer *layer)
void pipelineCountChanged()
void drawCallCountChanged()
void meshDetailsChanged()
bool extendedDataCollectionEnabled
void materialGenerationTimeChanged()
void startRenderPrepare()
void vmemUsedBytesChanged()
void textureDetailsChanged()
void vmemAllocCountChanged()
void drawVertexCountChanged()
Q_INVOKABLE void releaseCachedResources()
float lastCompletedGpuTime
QString renderPassDetails
void imageDataSizeChanged()
qint64 pipelineCreationTime
void effectGenerationTimeChanged()
void extendedDataCollectionEnabledChanged()
qint64 effectGenerationTime
void endRender(bool dump=false)
void renderPassDetailsChanged()
void renderPassCountChanged()
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
void releaseResources()
This function tries to release redundant resources currently held by the QML scene.
virtual QRhiCommandBuffer * currentFrameCommandBuffer()=0
Format
Specifies the texture format.
QRhiStats statistics() const
Gathers and returns statistics about the timings and allocations of graphics resources.
static int mipLevelsForSize(const QSize &size)
const char * backendName() const
QRhiBuffer * buffer() const
static quint64 totalVertexCountForPass(const QSSGRhiContextStats::RenderPassInfo &pass)
QHash< QSSGRenderLayer *, PerLayerInfo > perLayerInfo
static quint64 totalDrawCallCountForPass(const QSSGRhiContextStats::RenderPassInfo &pass)
QSet< QSSGRenderLayer * > dynamicDataSources
QSet< QSSGRenderMesh * > registeredMeshes() const
QSet< QRhiTexture * > registeredTextures() const
QHash< QSSGGraphicsPipelineStateKey, QRhiGraphicsPipeline * > pipelines() const
QList< T > values() const
bool remove(const T &value)
iterator insert(const T &value)
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Combined button and popup list for selecting options.
#define QByteArrayLiteral(str)
bool qFuzzyIsNull(qfloat16 f) noexcept
constexpr const T & qMax(const T &a, const T &b)
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint const GLuint GLuint const GLuint * textures
GLenum GLenum GLsizei count
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
static QByteArray nameForRenderMesh(const QSSGRenderMesh *mesh)
static void printRenderPassDetails(QString *dst, const QSSGRhiContextStats::RenderPassInfo &rp)
static const char * textureFormatStr(QRhiTexture::Format format)
static QString dump(const QByteArray &)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
QLatin1StringView QLatin1String
unsigned long long quint64
myObject disconnect()
[26]
QVector< QSSGRenderSubset > subsets
qint64 materialGenerationTime
qint64 effectGenerationTime
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent