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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtquick3d/src/quick3d/qquick3drenderstats.cpp