Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3drenderstats.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
7#include <QtQuick3DRuntimeRender/private/qssgrendermesh_p.h>
8#include <QtQuick/qquickwindow.h>
9#include <QtQuick/qquickitem.h>
10
11QT_BEGIN_NAMESPACE
12
13/*!
14 \qmltype RenderStats
15 \inqmlmodule QtQuick3D
16 \brief Provides information of the scene rendering.
17
18 The RenderStats type provides information about scene rendering statistics. This
19 cannot be created directly, but can be retrieved from a \l View3D.
20
21 Use the \l DebugView item to display the data on-screen.
22*/
23
24QQuick3DRenderStats::QQuick3DRenderStats(QObject *parent)
25 : QObject(parent)
26{
27 m_frameTimer.start();
28}
29
30/*!
31 \qmlproperty int QtQuick3D::RenderStats::fps
32 \readonly
33
34 This property holds the number of frames rendered during the last second.
35*/
36int QQuick3DRenderStats::fps() const
37{
38 return m_fps;
39}
40
41/*!
42 \qmlproperty real QtQuick3D::RenderStats::frameTime
43 \readonly
44
45 This property holds the amount of time elapsed since the last frame, in
46 milliseconds.
47*/
48float QQuick3DRenderStats::frameTime() const
49{
50 return m_results.frameTime;
51}
52
53/*!
54 \qmlproperty real QtQuick3D::RenderStats::renderTime
55 \readonly
56
57 This property holds the amount of time spent on generating a new frame,
58 including both the preparation phase and the recording of draw calls. The
59 value is in milliseconds.
60*/
61float QQuick3DRenderStats::renderTime() const
62{
63 return m_results.renderTime;
64}
65
66/*!
67 \qmlproperty real QtQuick3D::RenderStats::renderPrepareTime
68 \readonly
69
70 This property holds the amount of time spent in the preparation phase of
71 rendering, in milliseconds. This is a subset of the total render time
72 reported in renderTime.
73*/
74float QQuick3DRenderStats::renderPrepareTime() const
75{
76 return m_results.renderPrepareTime;
77}
78
79/*!
80 \qmlproperty real QtQuick3D::RenderStats::syncTime
81 \readonly
82
83 This property holds the amount of time spent inside the sync function, in
84 milliseconds. The property values of the objects are updated during the
85 sync.
86*/
87float QQuick3DRenderStats::syncTime() const
88{
89 return m_results.syncTime;
90}
91
92/*!
93 \qmlproperty real QtQuick3D::RenderStats::maxFrameTime
94 \readonly
95
96 This property holds the maximum time spent rendering a single frame during
97 the last second.
98*/
99float QQuick3DRenderStats::maxFrameTime() const
100{
101 return m_maxFrameTime;
102}
103
104float QQuick3DRenderStats::timestamp() const
105{
106 return m_frameTimer.nsecsElapsed() / 1000000.0f;
107}
108
109void QQuick3DRenderStats::startSync()
110{
111 m_syncStartTime = timestamp();
112}
113
114void QQuick3DRenderStats::endSync(bool dump)
115{
116 m_results.syncTime = timestamp() - m_syncStartTime;
117
118 if (dump)
119 qDebug("Sync took: %f ms", m_results.syncTime);
120}
121
122void QQuick3DRenderStats::startRender()
123{
124 m_renderStartTime = timestamp();
125}
126
127void QQuick3DRenderStats::startRenderPrepare()
128{
129 m_renderPrepareStartTime = timestamp();
130}
131
132void QQuick3DRenderStats::endRenderPrepare()
133{
134 m_results.renderPrepareTime = timestamp() - m_renderPrepareStartTime;
135}
136
137void QQuick3DRenderStats::endRender(bool dump)
138{
139 // Threading-wise this and onFrameSwapped are not perfect. These are called
140 // on the render thread (if there is one) outside of the sync step, so
141 // writing the data in m_results, which then may be read by the properties
142 // on the main thread concurrently, is not ideal. But at least the data the
143 // results are generated from (the m_* timings and all the stuff from
144 // QSSGRhiContextStats) belong to the render thread, so that's good.
145
146 m_renderingThisFrame = true;
147 const float endTime = timestamp();
148 m_results.renderTime = endTime - m_renderStartTime;
149
150 if (dump)
151 qDebug("Render took: %f ms (of which prep: %f ms)", m_results.renderTime, m_results.renderPrepareTime);
152}
153
154void QQuick3DRenderStats::onFrameSwapped()
155{
156 // NOTE: This is called on the render thread
157 // This is the real start and end of a frame
158
159 if (m_renderingThisFrame) {
160 ++m_frameCount;
161 m_results.frameTime = timestamp();
162 m_internalMaxFrameTime = qMax(m_results.frameTime, m_internalMaxFrameTime);
163
164 m_secTimer += m_results.frameTime;
165 m_notifyTimer += m_results.frameTime;
166
167 m_results.renderTime = m_results.frameTime - m_renderStartTime;
168
169 processRhiContextStats();
170
171 if (m_window) {
172 QRhiSwapChain *sc = m_window->swapChain();
173 if (sc) {
174 QRhiCommandBuffer *cb = sc->currentFrameCommandBuffer();
175 if (cb) {
176 const float msecs = float(cb->lastCompletedGpuTime() * 1000.0);
177 if (!qFuzzyIsNull(msecs))
178 m_results.lastCompletedGpuTime = msecs;
179 }
180 }
181 }
182
183 const float notifyInterval = 200.0f;
184 if (m_notifyTimer >= notifyInterval) {
185 m_notifyTimer -= notifyInterval;
186
187 if (m_results.frameTime != m_notifiedResults.frameTime) {
188 m_notifiedResults.frameTime = m_results.frameTime;
189 emit frameTimeChanged();
190 }
191
192 if (m_results.syncTime != m_notifiedResults.syncTime) {
193 m_notifiedResults.syncTime = m_results.syncTime;
194 emit syncTimeChanged();
195 }
196
197 if (m_results.renderTime != m_notifiedResults.renderTime) {
198 m_notifiedResults.renderTime = m_results.renderTime;
199 m_notifiedResults.renderPrepareTime = m_results.renderPrepareTime;
200 emit renderTimeChanged();
201 }
202
203 if (m_results.lastCompletedGpuTime != m_notifiedResults.lastCompletedGpuTime) {
204 m_notifiedResults.lastCompletedGpuTime = m_results.lastCompletedGpuTime;
205 emit lastCompletedGpuTimeChanged();
206 }
207
208 notifyRhiContextStats();
209 }
210
211 const float fpsInterval = 1000.0f;
212 if (m_secTimer >= fpsInterval) {
213 m_secTimer -= fpsInterval;
214
215 m_fps = m_frameCount;
216 m_frameCount = 0;
217 emit fpsChanged();
218
219 m_maxFrameTime = m_internalMaxFrameTime;
220 m_internalMaxFrameTime = 0;
221 emit maxFrameTimeChanged();
222 }
223
224 m_renderingThisFrame = false; // reset for next frame
225 }
226
227 // Always reset the frame timer
228 m_frameTimer.start();
229}
230
231void QQuick3DRenderStats::setRhiContext(QSSGRhiContext *ctx, QSSGRenderLayer *layer)
232{
233 // called from synchronize(), so on the render thread with gui blocked
234
235 m_layer = layer;
236 m_contextStats = &QSSGRhiContextStats::get(*ctx);
237
238 // setExtendedDataCollectionEnabled will likely get called at some point
239 // before this (so too early), sync the flag here as well now that we know
240 // all we need to know.
241 if (m_extendedDataCollectionEnabled)
242 m_contextStats->dynamicDataSources.insert(layer);
243
244 if (m_contextStats && m_contextStats->rhiCtx->rhi()) {
245 const QString backendName = QString::fromUtf8(m_contextStats->rhiCtx->rhi()->backendName());
246 if (m_graphicsApiName != backendName) {
247 m_graphicsApiName = backendName;
248 emit graphicsApiNameChanged();
249 }
250 }
251}
252
253void QQuick3DRenderStats::setWindow(QQuickWindow *window)
254{
255 if (m_window == window)
256 return;
257
258 if (m_window)
259 disconnect(m_frameSwappedConnection);
260
261 m_window = window;
262
263 if (m_window) {
264 m_frameSwappedConnection = connect(m_window, &QQuickWindow::afterFrameEnd,
265 this, &QQuick3DRenderStats::onFrameSwapped,
266 Qt::DirectConnection);
267 }
268}
269
270/*!
271 \qmlproperty bool QtQuick3D::RenderStats::extendedDataCollectionEnabled
272
273 This property controls if render pass and draw call statistics are
274 processed and made available. This may incur a small performance cost and
275 is therefore optional.
276
277 Properties such as drawCallCount, drawVertexCount, or renderPassCount are
278 updated only when this property is set to true.
279
280 The default value is false.
281
282 \note Changing the visibility of a \l DebugView associated with the \l
283 View3D automatically toggles the value based on the DebugView's
284 \l{QQuickItem::visible}{visible} property.
285
286 \since 6.5
287 */
288bool QQuick3DRenderStats::extendedDataCollectionEnabled() const
289{
290 return m_extendedDataCollectionEnabled;
291}
292
293void QQuick3DRenderStats::setExtendedDataCollectionEnabled(bool enable)
294{
295 if (enable != m_extendedDataCollectionEnabled) {
296 m_extendedDataCollectionEnabled = enable;
297 emit extendedDataCollectionEnabledChanged();
298 }
299 if (m_contextStats) {
300 // This is what allows recognizing that there is at least one DebugView
301 // that is visible and wants all the data, and also helps in not
302 // performing all the processing if the set is empty (because then we
303 // know that no DebugView wants to display the data)
304 if (m_extendedDataCollectionEnabled)
305 m_contextStats->dynamicDataSources.insert(m_layer);
306 else
307 m_contextStats->dynamicDataSources.remove(m_layer);
308 }
309}
310
311static const char *textureFormatStr(QRhiTexture::Format format)
312{
313 switch (format) {
314 case QRhiTexture::RGBA8:
315 return "RGBA8";
316 case QRhiTexture::BGRA8:
317 return "BGRA8";
318 case QRhiTexture::R8:
319 return "R8";
320 case QRhiTexture::RG8:
321 return "RG8";
322 case QRhiTexture::R16:
323 return "R16";
324 case QRhiTexture::RG16:
325 return "RG16";
326 case QRhiTexture::RED_OR_ALPHA8:
327 return "R8/A8";
328 case QRhiTexture::RGBA16F:
329 return "RGBA16F";
330 case QRhiTexture::RGBA32F:
331 return "RGBA32F";
332 case QRhiTexture::R16F:
333 return "R16F";
334 case QRhiTexture::R32F:
335 return "R32F";
336 case QRhiTexture::RGB10A2:
337 return "RGB10A2";
338 case QRhiTexture::D16:
339 return "D16";
340 case QRhiTexture::D24:
341 return "D24";
342 case QRhiTexture::D24S8:
343 return "D24S8";
344 case QRhiTexture::D32F:
345 return "D32F";
346 case QRhiTexture::BC1:
347 return "BC1";
348 case QRhiTexture::BC2:
349 return "BC2";
350 case QRhiTexture::BC3:
351 return "BC3";
352 case QRhiTexture::BC4:
353 return "BC4";
354 case QRhiTexture::BC5:
355 return "BC5";
356 case QRhiTexture::BC6H:
357 return "BC6H";
358 case QRhiTexture::BC7:
359 return "BC7";
360 case QRhiTexture::ETC2_RGB8:
361 return "ETC2_RGB8";
362 case QRhiTexture::ETC2_RGB8A1:
363 return "ETC2_RGB8A1";
364 case QRhiTexture::ETC2_RGBA8:
365 return "ETC2_RGBA8";
366 case QRhiTexture::ASTC_4x4:
367 return "ASTC_4x4";
368 case QRhiTexture::ASTC_5x4:
369 return "ASTC_5x4";
370 case QRhiTexture::ASTC_5x5:
371 return "ASTC_5x5";
372 case QRhiTexture::ASTC_6x5:
373 return "ASTC_6x5";
374 case QRhiTexture::ASTC_6x6:
375 return "ASTC_6x6";
376 case QRhiTexture::ASTC_8x5:
377 return "ASTC_8x5";
378 case QRhiTexture::ASTC_8x6:
379 return "ASTC_8x6";
380 case QRhiTexture::ASTC_8x8:
381 return "ASTC_8x8";
382 case QRhiTexture::ASTC_10x5:
383 return "ASTC_10x5";
384 case QRhiTexture::ASTC_10x6:
385 return "ASTC_10x6";
386 case QRhiTexture::ASTC_10x8:
387 return "ASTC_10x8";
388 case QRhiTexture::ASTC_10x10:
389 return "ASTC_10x10";
390 case QRhiTexture::ASTC_12x10:
391 return "ASTC_12x10";
392 case QRhiTexture::ASTC_12x12:
393 return "ASTC_12x12";
394 default:
395 break;
396 }
397 return "<unknown>";
398}
399
400static inline void printRenderPassDetails(QString *dst, const QSSGRhiContextStats::RenderPassInfo &rp)
401{
402 *dst += QString::asprintf("| %s | %dx%d | %llu | %llu |\n",
403 rp.rtName.constData(),
404 rp.pixelSize.width(),
405 rp.pixelSize.height(),
406 QSSGRhiContextStats::totalVertexCountForPass(rp),
407 QSSGRhiContextStats::totalDrawCallCountForPass(rp));
408}
409
410static inline QByteArray nameForRenderMesh(const QSSGRenderMesh *mesh)
411{
412 if (!mesh->subsets.isEmpty()) {
413 auto buf = mesh->subsets[0].rhi.vertexBuffer;
414 if (buf)
415 return buf->buffer()->name();
416 }
417 return {};
418}
419
420void QQuick3DRenderStats::processRhiContextStats()
421{
422 if (!m_contextStats || !m_extendedDataCollectionEnabled)
423 return;
424
425 // the render pass list is per renderer, i.e. per View3D
426 const QSSGRhiContextStats::PerLayerInfo data = m_contextStats->perLayerInfo[m_layer];
427
428 const QSSGRhiContext *rhiCtx = m_contextStats->rhiCtx;
429 const QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
430
431 // textures and meshes include all assets registered to the per-QQuickWindow QSSGRhiContext
432 const QSSGRhiContextStats::GlobalInfo globalData = m_contextStats->globalInfo;
433 const auto textures = rhiCtxD->m_textures;
434 const auto meshes = rhiCtxD->m_meshes;
435 const auto pipelines = rhiCtxD->m_pipelines;
436
437 m_results.drawCallCount = 0;
438 m_results.drawVertexCount = 0;
439 for (const auto &pass : data.renderPasses) {
440 m_results.drawCallCount += QSSGRhiContextStats::totalDrawCallCountForPass(pass);
441 m_results.drawVertexCount += QSSGRhiContextStats::totalVertexCountForPass(pass);
442 }
443 m_results.drawCallCount += QSSGRhiContextStats::totalDrawCallCountForPass(data.externalRenderPass);
444 m_results.drawVertexCount += QSSGRhiContextStats::totalVertexCountForPass(data.externalRenderPass);
445
446 m_results.imageDataSize = globalData.imageDataSize;
447 m_results.meshDataSize = globalData.meshDataSize;
448
449 m_results.renderPassCount = data.renderPasses.size()
450 + (data.externalRenderPass.pixelSize.isEmpty() ? 0 : 1);
451
452 QString renderPassDetails = QLatin1String(R"(
453| Name | Size | Vertices | Draw calls |
454| ---- | ---- | -------- | ---------- |
455)");
456
457 if (!data.externalRenderPass.pixelSize.isEmpty())
458 printRenderPassDetails(&renderPassDetails, data.externalRenderPass);
459 for (const auto &pass : data.renderPasses) {
460 if (!pass.pixelSize.isEmpty())
461 printRenderPassDetails(&renderPassDetails, pass);
462 }
463 renderPassDetails += QString::asprintf("\nGenerated from QSSGRenderLayer %p", m_layer);
464 m_results.renderPassDetails = renderPassDetails;
465
466 if (m_results.activeTextures != textures) {
467 m_results.activeTextures = textures;
468 QString texDetails = QLatin1String(R"(
469| Name | Size | Format | Mip | Flags |
470| ---- | ---- | ------ | --- | ----- |
471)");
472 QList<QRhiTexture *> textureList = textures.values();
473 std::sort(textureList.begin(), textureList.end(), [](QRhiTexture *a, QRhiTexture *b) {
474 return a->name() < b->name();
475 });
476 for (QRhiTexture *tex : textureList) {
477 int mipCount = 1;
478 const QRhiTexture::Flags flags = tex->flags();
479 if (flags.testFlag(QRhiTexture::MipMapped))
480 mipCount = m_contextStats->rhiCtx->rhi()->mipLevelsForSize(tex->pixelSize());
481 QByteArray flagMsg;
482 if (flags.testFlag(QRhiTexture::CubeMap))
483 flagMsg += QByteArrayLiteral("[cube]");
484 texDetails += QString::asprintf("| %s | %dx%d | %s | %d | %s |\n",
485 tex->name().constData(),
486 tex->pixelSize().width(),
487 tex->pixelSize().height(),
488 textureFormatStr(tex->format()),
489 mipCount,
490 flagMsg.constData());
491 }
492 texDetails += QString::asprintf("\nAsset textures registered with QSSGRhiContext %p", m_contextStats->rhiCtx);
493 m_results.textureDetails = texDetails;
494 }
495
496 if (m_results.activeMeshes != meshes) {
497 m_results.activeMeshes = meshes;
498 QString meshDetails = QLatin1String(R"(
499| Name | Submeshes | Vertices | V.buf size | I.buf size |
500| ---- | --------- | -------- | ---------- | ---------- |
501)");
502 QList<QSSGRenderMesh *> meshList = meshes.values();
503 std::sort(meshList.begin(), meshList.end(), [](QSSGRenderMesh *a, QSSGRenderMesh *b) {
504 return nameForRenderMesh(a) < nameForRenderMesh(b);
505 });
506 for (QSSGRenderMesh *mesh : meshList) {
507 const QByteArray name = nameForRenderMesh(mesh);
508 const int subsetCount = int(mesh->subsets.size());
509 quint64 vertexCount = 0;
510 quint32 vbufSize = 0;
511 quint32 ibufSize = 0;
512 if (subsetCount > 0) {
513 for (const QSSGRenderSubset &subset : std::as_const(mesh->subsets))
514 vertexCount += subset.count;
515 // submeshes ref into the same vertex and index buffer
516 const QSSGRhiBuffer *vbuf = mesh->subsets[0].rhi.vertexBuffer.get();
517 if (vbuf)
518 vbufSize = vbuf->buffer()->size();
519 const QSSGRhiBuffer *ibuf = mesh->subsets[0].rhi.indexBuffer.get();
520 if (ibuf)
521 ibufSize = ibuf->buffer()->size();
522 }
523 meshDetails += QString::asprintf("| %s | %d | %llu | %u | %u |\n",
524 name.constData(),
525 subsetCount,
526 vertexCount,
527 vbufSize,
528 ibufSize);
529
530 }
531 meshDetails += QString::asprintf("\nAsset meshes registered with QSSGRhiContext %p", m_contextStats->rhiCtx);
532 m_results.meshDetails = meshDetails;
533 }
534
535 m_results.pipelineCount = pipelines.count();
536
537 m_results.materialGenerationTime = m_contextStats->globalInfo.materialGenerationTime;
538 m_results.effectGenerationTime = m_contextStats->globalInfo.effectGenerationTime;
539
540 m_results.rhiStats = m_contextStats->rhiCtx->rhi()->statistics();
541}
542
543void QQuick3DRenderStats::notifyRhiContextStats()
544{
545 if (!m_contextStats || !m_extendedDataCollectionEnabled)
546 return;
547
548 if (m_results.drawCallCount != m_notifiedResults.drawCallCount) {
549 m_notifiedResults.drawCallCount = m_results.drawCallCount;
550 emit drawCallCountChanged();
551 }
552
553 if (m_results.drawVertexCount != m_notifiedResults.drawVertexCount) {
554 m_notifiedResults.drawVertexCount = m_results.drawVertexCount;
555 emit drawVertexCountChanged();
556 }
557
558 if (m_results.imageDataSize != m_notifiedResults.imageDataSize) {
559 m_notifiedResults.imageDataSize = m_results.imageDataSize;
560 emit imageDataSizeChanged();
561 }
562
563 if (m_results.meshDataSize != m_notifiedResults.meshDataSize) {
564 m_notifiedResults.meshDataSize = m_results.meshDataSize;
565 emit meshDataSizeChanged();
566 }
567
568 if (m_results.renderPassCount != m_notifiedResults.renderPassCount) {
569 m_notifiedResults.renderPassCount = m_results.renderPassCount;
570 emit renderPassCountChanged();
571 }
572
573 if (m_results.renderPassDetails != m_notifiedResults.renderPassDetails) {
574 m_notifiedResults.renderPassDetails = m_results.renderPassDetails;
575 emit renderPassDetailsChanged();
576 }
577
578 if (m_results.textureDetails != m_notifiedResults.textureDetails) {
579 m_notifiedResults.textureDetails = m_results.textureDetails;
580 emit textureDetailsChanged();
581 }
582
583 if (m_results.meshDetails != m_notifiedResults.meshDetails) {
584 m_notifiedResults.meshDetails = m_results.meshDetails;
585 emit meshDetailsChanged();
586 }
587
588 if (m_results.pipelineCount != m_notifiedResults.pipelineCount) {
589 m_notifiedResults.pipelineCount = m_results.pipelineCount;
590 emit pipelineCountChanged();
591 }
592
593 if (m_results.materialGenerationTime != m_notifiedResults.materialGenerationTime) {
594 m_notifiedResults.materialGenerationTime = m_results.materialGenerationTime;
595 emit materialGenerationTimeChanged();
596 }
597
598 if (m_results.effectGenerationTime != m_notifiedResults.effectGenerationTime) {
599 m_notifiedResults.effectGenerationTime = m_results.effectGenerationTime;
600 emit effectGenerationTimeChanged();
601 }
602
603 if (m_results.rhiStats.totalPipelineCreationTime != m_notifiedResults.rhiStats.totalPipelineCreationTime) {
604 m_notifiedResults.rhiStats.totalPipelineCreationTime = m_results.rhiStats.totalPipelineCreationTime;
605 emit pipelineCreationTimeChanged();
606 }
607
608 if (m_results.rhiStats.allocCount != m_notifiedResults.rhiStats.allocCount) {
609 m_notifiedResults.rhiStats.allocCount = m_results.rhiStats.allocCount;
610 emit vmemAllocCountChanged();
611 }
612
613 if (m_results.rhiStats.usedBytes != m_notifiedResults.rhiStats.usedBytes) {
614 m_notifiedResults.rhiStats.usedBytes = m_results.rhiStats.usedBytes;
615 emit vmemUsedBytesChanged();
616 }
617}
618
619/*!
620 \qmlproperty quint64 QtQuick3D::RenderStats::drawCallCount
621 \readonly
623 This property holds the total number of draw calls (including non-indexed,
624 indexed, instanced, and instanced indexed draw calls) that were registered
625 during the last render of the \l View3D.
626
627 The value is updated only when extendedDataCollectionEnabled is enabled.
628
629 \since 6.5
630*/
631quint64 QQuick3DRenderStats::drawCallCount() const
632{
633 return m_results.drawCallCount;
634}
635
636/*!
637 \qmlproperty quint64 QtQuick3D::RenderStats::drawVertexCount
638 \readonly
639
640 This property holds the total number of vertices in draw calls that were
641 registered during the last render of the \l View3D.
642
643 The value includes the number of vertex and index count from draw calls
644 that were registered during the last render of the \l View3D. While the
645 number is not guaranteed to be totally accurate, it is expected to give a
646 good indication of the complexity of the scene rendering.
647
648 The value is updated only when extendedDataCollectionEnabled is enabled.
649
650 \since 6.5
651*/
652quint64 QQuick3DRenderStats::drawVertexCount() const
653{
654 return m_results.drawVertexCount;
655}
656
657/*!
658 \qmlproperty quint64 QtQuick3D::RenderStats::imageDataSize
659 \readonly
660
661 This property holds the approximate size in bytes of the image data for
662 texture maps currently registered with the View3D's window. The value is
663 per-window, meaning if there are multiple View3D objects within the same
664 QQuickWindow, those will likely report the same value.
666 The value is updated only when extendedDataCollectionEnabled is enabled.
667
668 \note The value is reported on a per-QQuickWindow basis. If there are
669 multiple View3D instances within the same window, the DebugView shows the
670 same value for all those View3Ds.
671
672 \since 6.5
673*/
674quint64 QQuick3DRenderStats::imageDataSize() const
675{
676 return m_results.imageDataSize;
677}
678
679/*!
680 \qmlproperty quint64 QtQuick3D::RenderStats::meshDataSize
681 \readonly
682
683 This property holds the approximate size in bytes of the mesh data
684 currently registered with the View3D's window. The value is per-window,
685 meaning if there are multiple View3D objects within the same QQuickWindow,
686 those will likely report the same value.
688 The value is updated only when extendedDataCollectionEnabled is enabled.
689
690 \note The value is reported on a per-QQuickWindow basis. If there are
691 multiple View3D instances within the same window, the DebugView shows the
692 same value for all those View3Ds.
693
694 \since 6.5
695*/
696quint64 QQuick3DRenderStats::meshDataSize() const
697{
698 return m_results.meshDataSize;
699}
700
701/*!
702 \qmlproperty int QtQuick3D::RenderStats::renderPassCount
703 \readonly
704
705 This property holds the total number of render passes that were registered
706 during the last render of the \l View3D.
707
708 Many features, such as realtime shadow mapping, postprocessing effects, the
709 depth and screen textures, and certain antialiasing methods involve
710 multiple additional render passes. While the number is not guaranteed to
711 include absolutely all render passes, it is expected to give a good
712 indication of the complexity of the scene rendering.
713
714 The value is updated only when extendedDataCollectionEnabled is enabled.
715
716 \since 6.5
717*/
718int QQuick3DRenderStats::renderPassCount() const
719{
720 return m_results.renderPassCount;
721}
722
723/*!
724 \qmlproperty string QtQuick3D::RenderStats::renderPassDetails
725 \readonly
726 \internal
727 \since 6.5
728*/
729QString QQuick3DRenderStats::renderPassDetails() const
730{
731 return m_results.renderPassDetails;
732}
733
734/*!
735 \qmlproperty string QtQuick3D::RenderStats::textureDetails
736 \readonly
737 \internal
738 \since 6.5
739*/
740QString QQuick3DRenderStats::textureDetails() const
741{
742 return m_results.textureDetails;
743}
744
745/*!
746 \qmlproperty string QtQuick3D::RenderStats::meshDetails
747 \readonly
748 \internal
749 \since 6.5
750*/
751QString QQuick3DRenderStats::meshDetails() const
752{
753 return m_results.meshDetails;
754}
755
756/*!
757 \qmlproperty int QtQuick3D::RenderStats::pipelineCount
758 \readonly
759
760 This property holds the total number of cached graphics pipelines for the
761 window the \l View3D belongs to.
763 The value is updated only when extendedDataCollectionEnabled is enabled.
764
765 \note The value is reported on a per-QQuickWindow basis. If there are
766 multiple View3D instances within the same window, the DebugView shows the
767 same value for all those View3Ds.
768
769 \since 6.5
770*/
771int QQuick3DRenderStats::pipelineCount() const
772{
773 return m_results.pipelineCount;
774}
775
776/*!
777 \qmlproperty qint64 QtQuick3D::RenderStats::materialGenerationTime
778 \readonly
779
780 This property holds the total number of milliseconds spent on generating
781 and processing shader code for \l DefaultMaterial, \l PrincipledMaterial,
782 and \l CustomMaterial in the window the \l View3D belongs to.
784 The value is updated only when extendedDataCollectionEnabled is enabled.
785
786 \note The value is reported on a per-QQuickWindow basis. If there are
787 multiple View3D instances within the same window, the DebugView shows the
788 same value for all those View3Ds.
789
790 \since 6.5
791*/
792qint64 QQuick3DRenderStats::materialGenerationTime() const
793{
794 return m_results.materialGenerationTime;
795}
796
797/*!
798 \qmlproperty qint64 QtQuick3D::RenderStats::effectGenerationTime
799 \readonly
800
801 This property holds the total number of milliseconds spent on generating
802 and processing shader code for post-processing effects in the window the \l
803 View3D belongs to.
805 The value is updated only when extendedDataCollectionEnabled is enabled.
806
807 \note The value is reported on a per-QQuickWindow basis. If there are
808 multiple View3D instances within the same window, the DebugView shows the
809 same value for all those View3Ds.
810
811 \since 6.5
812*/
813qint64 QQuick3DRenderStats::effectGenerationTime() const
814{
815 return m_results.effectGenerationTime;
816}
817
818/*!
819 \qmlproperty qint64 QtQuick3D::RenderStats::pipelineCreationTime
820 \readonly
821
822 This property holds the total number of milliseconds spent on creating
823 graphics pipelines on the rendering hardware interface level. This can
824 include, among other things: compilation times for compiling HLSL to an
825 intermediate format, compiling MSL, compiling GLSL code with
826 glCompileShader or linking using program binaries, and generating Vulkan
827 pipelines with all that entails (e.g. SPIR-V -> ISA compilation). The value
828 reflects all Qt Quick and Qt Quick 3D rendering in the window the \l View3D
829 belongs to.
830
831 \note The value includes operations that are under Qt's control. Depending
832 on the underlying graphics API, some pipeline (shader, graphics state)
833 related operations may happen asynchronously, and may be affected by
834 caching on various levels in the graphics stack. Releasing cached resource
835 by calling QQuickWindow::releaseResources() or clicking the corresponding
836 DebugView button may also have varying results, depending on the underlying
837 details (rhi backend, graphics API); it may or may not affect this counter
838 due to a varying number of factors.
839
840 This timing is provided as a general, high level indication. Combined with
841 \l materialGenerationTime, application developers can use these values to
842 confirm that the time spent on material and graphics pipeline processing is
843 reasonably low during the normal use of the application, once all caches
844 (both persistent and in-memory) are warm. Avoid drawing conclusions from
845 the first run of the application. (since that may not benefit from
846 persistent, disk-based caches yet)
848 The value is updated only when extendedDataCollectionEnabled is enabled.
849
850 \note The value is reported on a per-QQuickWindow basis. If there are
851 multiple View3D instances within the same window, the DebugView shows the
852 same value for all those View3Ds.
853
854 \since 6.5
855*/
856qint64 QQuick3DRenderStats::pipelineCreationTime() const
857{
858 return m_results.rhiStats.totalPipelineCreationTime;
859}
860
861/*!
862 \qmlproperty quint32 QtQuick3D::RenderStats::vmemAllocCount
863 \readonly
864
865 When applicable, the number of allocations made by the graphics memory
866 allocator library. This includes allocations from all Qt Quick and Qt Quick
867 3D rendering in the QQuickWindow to which the \l View3D belongs. The value
868 is zero with graphics APIs such as OpenGL, Direct3D, and Metal because
869 memory allocation is not under Qt's control then.
871 The value is updated only when extendedDataCollectionEnabled is enabled.
872
873 \note The value is reported on a per-QQuickWindow basis. If there are
874 multiple View3D instances within the same window, the DebugView shows the
875 same value for all those View3Ds.
876
877 \since 6.5
878*/
879quint32 QQuick3DRenderStats::vmemAllocCount() const
880{
881 return m_results.rhiStats.allocCount;
882}
883
884/*!
885 \qmlproperty quint64 QtQuick3D::RenderStats::vmemUsedBytes
886 \readonly
887
888 When applicable, the number of bytes used by allocations made by the
889 graphics memory allocator library. This includes allocations from all Qt
890 Quick and Qt Quick 3D rendering in the QQuickWindow to which the \l View3D
891 belongs. The value is zero with graphics APIs such as OpenGL, Direct3D, and
892 Metal because memory allocation is not under Qt's control then.
894 The value is updated only when extendedDataCollectionEnabled is enabled.
895
896 \note The value is reported on a per-QQuickWindow basis. If there are
897 multiple View3D instances within the same window, the DebugView shows the
898 same value for all those View3Ds.
899
900 \since 6.5
901*/
902quint64 QQuick3DRenderStats::vmemUsedBytes() const
903{
904 return m_results.rhiStats.usedBytes;
905}
906
907/*!
908 \qmlproperty string QtQuick3D::RenderStats::graphicsAPIName
909 \readonly
910
911 This property holds the name of the current graphics API (RHI) backend
912 currently in use.
913
914 \since 6.5
915*/
916QString QQuick3DRenderStats::graphicsApiName() const
917{
918 return m_graphicsApiName;
919}
920
921/*!
922 \qmlproperty real QtQuick3D::RenderStats::lastCompletedGpuTime
923 \readonly
924
925 When GPU timing collection is
926 \l{QQuickGraphicsConfiguration::setTimestamps()}{enabled in Qt Quick}, and
927 the relevant features are supported by the underlying graphics API, this
928 property contains the last retrieved elapsed GPU time in milliseconds.
929
930 \note The value is retrieved asynchronously, and usually refers to a frame
931 older than the previous one, meaning that the value is not necessarily in
932 sync with the other, CPU-side timings.
933
934 \note The result is based on the rendering of the entire contents of the
935 QQuickWindow the View3D belongs to. It includes all the contents of Qt
936 Quick scene, including all 2D elements and all View3D items within that
937 window.
938
939 \since 6.6
940
941 \sa QQuickGraphicsConfiguration::setTimestamps()
943float QQuick3DRenderStats::lastCompletedGpuTime() const
944{
945 return m_results.lastCompletedGpuTime;
946}
947
948/*!
949 \internal
950 */
951void QQuick3DRenderStats::releaseCachedResources()
952{
953 if (m_window)
954 m_window->releaseResources();
955 else
956 qWarning("QQuick3DRenderStats: No window, cannot request releasing cached resources");
957}
958
959QT_END_NAMESPACE
static QByteArray nameForRenderMesh(const QSSGRenderMesh *mesh)
static void printRenderPassDetails(QString *dst, const QSSGRhiContextStats::RenderPassInfo &rp)
static const char * textureFormatStr(QRhiTexture::Format format)