1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt Gui module
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qrhiprofiler_p_p.h"
38#include "qrhi_p_p.h"
39#include <QtCore/qiodevice.h>
40
41QT_BEGIN_NAMESPACE
42
43/*!
44 \class QRhiProfiler
45 \internal
46 \inmodule QtGui
47
48 \brief Collects resource and timing information from an active QRhi.
49
50 A QRhiProfiler is present for each QRhi. Query it via QRhi::profiler(). The
51 profiler is active only when the QRhi was created with
52 QRhi::EnableProfiling. No data is collected otherwise.
53
54 \note GPU timings are only available when QRhi indicates that
55 QRhi::Timestamps is supported.
56
57 Besides collecting data from the QRhi implementations, some additional
58 values are calculated. For example, for textures and similar resources the
59 profiler gives an estimate of the complete amount of memory the resource
60 needs.
61
62 \section2 Output Format
63
64 The output is comma-separated text. Each line has a number of
65 comma-separated entries and each line ends with a comma.
66
67 For example:
68
69 \badcode
70 1,0,140446057946208,Triangle vbuf,type,0,usage,1,logical_size,84,effective_size,84,backing_gpu_buf_count,1,backing_cpu_buf_count,0,
71 1,0,140446057947376,Triangle ubuf,type,2,usage,4,logical_size,68,effective_size,256,backing_gpu_buf_count,2,backing_cpu_buf_count,0,
72 1,1,140446057950416,,type,0,usage,1,logical_size,112,effective_size,112,backing_gpu_buf_count,1,backing_cpu_buf_count,0,
73 1,1,140446057950544,,type,0,usage,2,logical_size,12,effective_size,12,backing_gpu_buf_count,1,backing_cpu_buf_count,0,
74 1,1,140446057947440,,type,2,usage,4,logical_size,68,effective_size,256,backing_gpu_buf_count,2,backing_cpu_buf_count,0,
75 1,1,140446057984784,Cube vbuf (textured),type,0,usage,1,logical_size,720,effective_size,720,backing_gpu_buf_count,1,backing_cpu_buf_count,0,
76 1,1,140446057982528,Cube ubuf (textured),type,2,usage,4,logical_size,68,effective_size,256,backing_gpu_buf_count,2,backing_cpu_buf_count,0,
77 7,8,140446058913648,Qt texture,width,256,height,256,format,1,owns_native_resource,1,mip_count,9,layer_count,1,effective_sample_count,1,approx_byte_size,349524,
78 1,8,140446058795856,Cube vbuf (textured with offscreen),type,0,usage,1,logical_size,720,effective_size,720,backing_gpu_buf_count,1,backing_cpu_buf_count,0,
79 1,8,140446058947920,Cube ubuf (textured with offscreen),type,2,usage,4,logical_size,68,effective_size,256,backing_gpu_buf_count,2,backing_cpu_buf_count,0,
80 7,8,140446058794928,Texture for offscreen content,width,512,height,512,format,1,owns_native_resource,1,mip_count,1,layer_count,1,effective_sample_count,1,approx_byte_size,1048576,
81 1,8,140446058963904,Triangle vbuf,type,0,usage,1,logical_size,84,effective_size,84,backing_gpu_buf_count,1,backing_cpu_buf_count,0,
82 1,8,140446058964560,Triangle ubuf,type,2,usage,4,logical_size,68,effective_size,256,backing_gpu_buf_count,2,backing_cpu_buf_count,0,
83 5,9,140446057945392,,type,0,width,1280,height,720,effective_sample_count,1,transient_backing,0,winsys_backing,0,approx_byte_size,3686400,
84 11,9,140446057944592,,width,1280,height,720,buffer_count,2,msaa_buffer_count,0,effective_sample_count,1,approx_total_byte_size,7372800,
85 9,9,140446058913648,Qt texture,slot,0,size,262144,
86 10,9,140446058913648,Qt texture,slot,0,
87 17,2019,140446057944592,,frames_since_resize,121,min_ms_frame_delta,9,max_ms_frame_delta,33,Favg_ms_frame_delta,16.1167,
88 18,2019,140446057944592,,frames_since_resize,121,min_ms_frame_build,0,max_ms_frame_build,1,Favg_ms_frame_build,0.00833333,
89 17,4019,140446057944592,,frames_since_resize,241,min_ms_frame_delta,15,max_ms_frame_delta,17,Favg_ms_frame_delta,16.0583,
90 18,4019,140446057944592,,frames_since_resize,241,min_ms_frame_build,0,max_ms_frame_build,0,Favg_ms_frame_build,0,
91 12,5070,140446057944592,,
92 2,5079,140446057947376,Triangle ubuf,
93 2,5079,140446057946208,Triangle vbuf,
94 2,5079,140446057947440,,
95 2,5079,140446057950544,,
96 2,5079,140446057950416,,
97 8,5079,140446058913648,Qt texture,
98 2,5079,140446057982528,Cube ubuf (textured),
99 2,5079,140446057984784,Cube vbuf (textured),
100 2,5079,140446058964560,Triangle ubuf,
101 2,5079,140446058963904,Triangle vbuf,
102 8,5079,140446058794928,Texture for offscreen content,
103 2,5079,140446058947920,Cube ubuf (textured with offscreen),
104 2,5079,140446058795856,Cube vbuf (textured with offscreen),
105 6,5079,140446057945392,,
106 \endcode
107
108 Each line starts with \c op, \c timestamp, \c res, \c name where op is a
109 value from StreamOp, timestamp is a recording timestamp in milliseconds
110 (qint64), res is a number (quint64) referring to the QRhiResource the entry
111 refers to, or 0 if not applicable. \c name is the value of
112 QRhiResource::name() and may be empty as well. The \c name will never
113 contain a comma.
114
115 This is followed by any number of \c{key, value} pairs where \c key is an
116 unspecified string and \c value is a number. If \c key starts with \c F, it
117 indicates the value is a float. Otherwise assume that the value is a
118 qint64.
119 */
120
121/*!
122 \enum QRhiProfiler::StreamOp
123 Describes an entry in the profiler's output stream.
124
125 \value NewBuffer A buffer is created
126 \value ReleaseBuffer A buffer is destroyed
127 \value NewBufferStagingArea A staging buffer for buffer upload is created
128 \value ReleaseBufferStagingArea A staging buffer for buffer upload is destroyed
129 \value NewRenderBuffer A renderbuffer is created
130 \value ReleaseRenderBuffer A renderbuffer is destroyed
131 \value NewTexture A texture is created
132 \value ReleaseTexture A texture is destroyed
133 \value NewTextureStagingArea A staging buffer for texture upload is created
134 \value ReleaseTextureStagingArea A staging buffer for texture upload is destroyed
135 \value ResizeSwapChain A swapchain is created or resized
136 \value ReleaseSwapChain A swapchain is destroyed
137 \value NewReadbackBuffer A staging buffer for readback is created
138 \value ReleaseReadbackBuffer A staging buffer for readback is destroyed
139 \value GpuMemAllocStats GPU memory allocator statistics
140 \value GpuFrameTime GPU frame times
141 \value FrameToFrameTime CPU frame-to-frame times
142 \value FrameBuildTime CPU beginFrame-endFrame times
143 */
144
145/*!
146 \class QRhiProfiler::CpuTime
147 \internal
148 \inmodule QtGui
149 \brief Contains CPU-side frame timings.
150
151 Once sufficient number of frames have been rendered, the minimum, maximum,
152 and average values (in milliseconds) from various measurements are made
153 available in this struct queriable from QRhiProfiler::frameToFrameTimes()
154 and QRhiProfiler::frameBuildTimes().
155
156 \sa QRhiProfiler::setFrameTimingWriteInterval()
157 */
158
159/*!
160 \class QRhiProfiler::GpuTime
161 \internal
162 \inmodule QtGui
163 \brief Contains GPU-side frame timings.
164
165 Once sufficient number of frames have been rendered, the minimum, maximum,
166 and average values (in milliseconds) calculated from GPU command buffer
167 timestamps are made available in this struct queriable from
168 QRhiProfiler::gpuFrameTimes().
169
170 \sa QRhiProfiler::setFrameTimingWriteInterval()
171 */
172
173/*!
174 \internal
175 */
176QRhiProfiler::QRhiProfiler()
177 : d(new QRhiProfilerPrivate)
178{
179 d->ts.start();
180}
181
182/*!
183 Destructor.
184 */
185QRhiProfiler::~QRhiProfiler()
186{
187 // Flush because there is a high chance we have writes that were made since
188 // the event loop last ran. (esp. relevant for network devices like QTcpSocket)
189 if (d->outputDevice)
190 d->outputDevice->waitForBytesWritten(1000);
191
192 delete d;
193}
194
195/*!
196 Sets the output \a device.
197
198 \note No output will be generated when QRhi::EnableProfiling was not set.
199 */
200void QRhiProfiler::setDevice(QIODevice *device)
201{
202 d->outputDevice = device;
203}
204
205/*!
206 Requests writing a GpuMemAllocStats entry into the output, when applicable.
207 Backends that do not support this will ignore the request. This is an
208 explicit request since getting the allocator status and statistics may be
209 an expensive operation.
210 */
211void QRhiProfiler::addVMemAllocatorStats()
212{
213 if (d->rhiDWhenEnabled)
214 d->rhiDWhenEnabled->sendVMemStatsToProfiler();
215}
216
217/*!
218 \return the currently set frame timing writeout interval.
219 */
220int QRhiProfiler::frameTimingWriteInterval() const
221{
222 return d->frameTimingWriteInterval;
223}
224
225/*!
226 Sets the number of frames that need to be rendered before the collected CPU
227 and GPU timings are processed (min, max, average are calculated) to \a
228 frameCount.
229
230 The default value is 120.
231 */
232void QRhiProfiler::setFrameTimingWriteInterval(int frameCount)
233{
234 if (frameCount > 0)
235 d->frameTimingWriteInterval = frameCount;
236}
237
238/*!
239 \return min, max, and avg in milliseconds for the time that elapsed between two
240 QRhi::endFrame() calls.
241
242 \note The values are all 0 until at least frameTimingWriteInterval() frames
243 have been rendered.
244 */
245QRhiProfiler::CpuTime QRhiProfiler::frameToFrameTimes(QRhiSwapChain *sc) const
246{
247 auto it = d->swapchains.constFind(sc);
248 if (it != d->swapchains.constEnd())
249 return it->frameToFrameTime;
250
251 return QRhiProfiler::CpuTime();
252}
253
254/*!
255 \return min, max, and avg in milliseconds for the time that elapsed between
256 a QRhi::beginFrame() and QRhi::endFrame().
257
258 \note The values are all 0 until at least frameTimingWriteInterval() frames
259 have been rendered.
260 */
261QRhiProfiler::CpuTime QRhiProfiler::frameBuildTimes(QRhiSwapChain *sc) const
262{
263 auto it = d->swapchains.constFind(sc);
264 if (it != d->swapchains.constEnd())
265 return it->beginToEndFrameTime;
266
267 return QRhiProfiler::CpuTime();
268}
269
270/*!
271 \return min, max, and avg in milliseconds for the GPU time that is spent on
272 one frame.
273
274 \note The values are all 0 until at least frameTimingWriteInterval() frames
275 have been rendered.
276
277 The GPU times should only be compared between runs on the same GPU of the
278 same system with the same backend. Comparing times for different graphics
279 cards or for different backends can give misleading results. The numbers are
280 not meant to be comparable that way.
281
282 \note Some backends have no support for this, and even for those that have,
283 it is not guaranteed that the driver will support it at run time. Support
284 can be checked via QRhi::Timestamps.
285 */
286QRhiProfiler::GpuTime QRhiProfiler::gpuFrameTimes(QRhiSwapChain *sc) const
287{
288 auto it = d->swapchains.constFind(sc);
289 if (it != d->swapchains.constEnd())
290 return it->gpuFrameTime;
291
292 return QRhiProfiler::GpuTime();
293}
294
295void QRhiProfilerPrivate::startEntry(QRhiProfiler::StreamOp op, qint64 timestamp, QRhiResource *res)
296{
297 buf.clear();
298 buf.append(QByteArray::number(op));
299 buf.append(',');
300 buf.append(QByteArray::number(timestamp));
301 buf.append(',');
302 buf.append(QByteArray::number(quint64(quintptr(res))));
303 buf.append(',');
304 if (res)
305 buf.append(res->name());
306 buf.append(',');
307}
308
309void QRhiProfilerPrivate::writeInt(const char *key, qint64 v)
310{
311 Q_ASSERT(key[0] != 'F');
312 buf.append(key);
313 buf.append(',');
314 buf.append(QByteArray::number(v));
315 buf.append(',');
316}
317
318void QRhiProfilerPrivate::writeFloat(const char *key, float f)
319{
320 Q_ASSERT(key[0] == 'F');
321 buf.append(key);
322 buf.append(',');
323 buf.append(QByteArray::number(double(f)));
324 buf.append(',');
325}
326
327void QRhiProfilerPrivate::endEntry()
328{
329 buf.append('\n');
330 outputDevice->write(buf);
331}
332
333void QRhiProfilerPrivate::newBuffer(QRhiBuffer *buf, quint32 realSize, int backingGpuBufCount, int backingCpuBufCount)
334{
335 if (!outputDevice)
336 return;
337
338 startEntry(QRhiProfiler::NewBuffer, ts.elapsed(), buf);
339 writeInt("type", buf->type());
340 writeInt("usage", buf->usage());
341 writeInt("logical_size", buf->size());
342 writeInt("effective_size", realSize);
343 writeInt("backing_gpu_buf_count", backingGpuBufCount);
344 writeInt("backing_cpu_buf_count", backingCpuBufCount);
345 endEntry();
346}
347
348void QRhiProfilerPrivate::releaseBuffer(QRhiBuffer *buf)
349{
350 if (!outputDevice)
351 return;
352
353 startEntry(QRhiProfiler::ReleaseBuffer, ts.elapsed(), buf);
354 endEntry();
355}
356
357void QRhiProfilerPrivate::newBufferStagingArea(QRhiBuffer *buf, int slot, quint32 size)
358{
359 if (!outputDevice)
360 return;
361
362 startEntry(QRhiProfiler::NewBufferStagingArea, ts.elapsed(), buf);
363 writeInt("slot", slot);
364 writeInt("size", size);
365 endEntry();
366}
367
368void QRhiProfilerPrivate::releaseBufferStagingArea(QRhiBuffer *buf, int slot)
369{
370 if (!outputDevice)
371 return;
372
373 startEntry(QRhiProfiler::ReleaseBufferStagingArea, ts.elapsed(), buf);
374 writeInt("slot", slot);
375 endEntry();
376}
377
378void QRhiProfilerPrivate::newRenderBuffer(QRhiRenderBuffer *rb, bool transientBacking, bool winSysBacking, int sampleCount)
379{
380 if (!outputDevice)
381 return;
382
383 const QRhiRenderBuffer::Type type = rb->type();
384 const QSize sz = rb->pixelSize();
385 // just make up something, ds is likely D24S8 while color is RGBA8 or similar
386 const QRhiTexture::Format assumedFormat = type == QRhiRenderBuffer::DepthStencil ? QRhiTexture::D32F : QRhiTexture::RGBA8;
387 quint32 byteSize = rhiDWhenEnabled->approxByteSizeForTexture(assumedFormat, sz, 1, 1);
388 if (sampleCount > 1)
389 byteSize *= uint(sampleCount);
390
391 startEntry(QRhiProfiler::NewRenderBuffer, ts.elapsed(), rb);
392 writeInt("type", type);
393 writeInt("width", sz.width());
394 writeInt("height", sz.height());
395 writeInt("effective_sample_count", sampleCount);
396 writeInt("transient_backing", transientBacking);
397 writeInt("winsys_backing", winSysBacking);
398 writeInt("approx_byte_size", byteSize);
399 endEntry();
400}
401
402void QRhiProfilerPrivate::releaseRenderBuffer(QRhiRenderBuffer *rb)
403{
404 if (!outputDevice)
405 return;
406
407 startEntry(QRhiProfiler::ReleaseRenderBuffer, ts.elapsed(), rb);
408 endEntry();
409}
410
411void QRhiProfilerPrivate::newTexture(QRhiTexture *tex, bool owns, int mipCount, int layerCount, int sampleCount)
412{
413 if (!outputDevice)
414 return;
415
416 const QRhiTexture::Format format = tex->format();
417 const QSize sz = tex->pixelSize();
418 quint32 byteSize = rhiDWhenEnabled->approxByteSizeForTexture(format, sz, mipCount, layerCount);
419 if (sampleCount > 1)
420 byteSize *= uint(sampleCount);
421
422 startEntry(QRhiProfiler::NewTexture, ts.elapsed(), tex);
423 writeInt("width", sz.width());
424 writeInt("height", sz.height());
425 writeInt("format", format);
426 writeInt("owns_native_resource", owns);
427 writeInt("mip_count", mipCount);
428 writeInt("layer_count", layerCount);
429 writeInt("effective_sample_count", sampleCount);
430 writeInt("approx_byte_size", byteSize);
431 endEntry();
432}
433
434void QRhiProfilerPrivate::releaseTexture(QRhiTexture *tex)
435{
436 if (!outputDevice)
437 return;
438
439 startEntry(QRhiProfiler::ReleaseTexture, ts.elapsed(), tex);
440 endEntry();
441}
442
443void QRhiProfilerPrivate::newTextureStagingArea(QRhiTexture *tex, int slot, quint32 size)
444{
445 if (!outputDevice)
446 return;
447
448 startEntry(QRhiProfiler::NewTextureStagingArea, ts.elapsed(), tex);
449 writeInt("slot", slot);
450 writeInt("size", size);
451 endEntry();
452}
453
454void QRhiProfilerPrivate::releaseTextureStagingArea(QRhiTexture *tex, int slot)
455{
456 if (!outputDevice)
457 return;
458
459 startEntry(QRhiProfiler::ReleaseTextureStagingArea, ts.elapsed(), tex);
460 writeInt("slot", slot);
461 endEntry();
462}
463
464void QRhiProfilerPrivate::resizeSwapChain(QRhiSwapChain *sc, int bufferCount, int msaaBufferCount, int sampleCount)
465{
466 if (!outputDevice)
467 return;
468
469 const QSize sz = sc->currentPixelSize();
470 quint32 byteSize = rhiDWhenEnabled->approxByteSizeForTexture(QRhiTexture::BGRA8, sz, 1, 1);
471 byteSize = byteSize * uint(bufferCount) + byteSize * uint(msaaBufferCount) * uint(sampleCount);
472
473 startEntry(QRhiProfiler::ResizeSwapChain, ts.elapsed(), sc);
474 writeInt("width", sz.width());
475 writeInt("height", sz.height());
476 writeInt("buffer_count", bufferCount);
477 writeInt("msaa_buffer_count", msaaBufferCount);
478 writeInt("effective_sample_count", sampleCount);
479 writeInt("approx_total_byte_size", byteSize);
480 endEntry();
481}
482
483void QRhiProfilerPrivate::releaseSwapChain(QRhiSwapChain *sc)
484{
485 if (!outputDevice)
486 return;
487
488 startEntry(QRhiProfiler::ReleaseSwapChain, ts.elapsed(), sc);
489 endEntry();
490}
491
492template<typename T>
493void calcTiming(QList<T> *vec, T *minDelta, T *maxDelta, float *avgDelta)
494{
495 if (vec->isEmpty())
496 return;
497
498 *minDelta = *maxDelta = 0;
499 float totalDelta = 0;
500 for (T delta : qAsConst(*vec)) {
501 totalDelta += float(delta);
502 if (*minDelta == 0 || delta < *minDelta)
503 *minDelta = delta;
504 if (*maxDelta == 0 || delta > *maxDelta)
505 *maxDelta = delta;
506 }
507 *avgDelta = totalDelta / vec->count();
508
509 vec->clear();
510}
511
512void QRhiProfilerPrivate::beginSwapChainFrame(QRhiSwapChain *sc)
513{
514 Sc &scd(swapchains[sc]);
515 scd.beginToEndTimer.start();
516}
517
518void QRhiProfilerPrivate::endSwapChainFrame(QRhiSwapChain *sc, int frameCount)
519{
520 Sc &scd(swapchains[sc]);
521 if (!scd.frameToFrameRunning) {
522 scd.frameToFrameTimer.start();
523 scd.frameToFrameRunning = true;
524 return;
525 }
526
527 scd.frameToFrameSamples.append(scd.frameToFrameTimer.restart());
528 if (scd.frameToFrameSamples.count() >= frameTimingWriteInterval) {
529 calcTiming(&scd.frameToFrameSamples,
530 &scd.frameToFrameTime.minTime, &scd.frameToFrameTime.maxTime, &scd.frameToFrameTime.avgTime);
531 if (outputDevice) {
532 startEntry(QRhiProfiler::FrameToFrameTime, ts.elapsed(), sc);
533 writeInt("frames_since_resize", frameCount);
534 writeInt("min_ms_frame_delta", scd.frameToFrameTime.minTime);
535 writeInt("max_ms_frame_delta", scd.frameToFrameTime.maxTime);
536 writeFloat("Favg_ms_frame_delta", scd.frameToFrameTime.avgTime);
537 endEntry();
538 }
539 }
540
541 scd.beginToEndSamples.append(scd.beginToEndTimer.elapsed());
542 if (scd.beginToEndSamples.count() >= frameTimingWriteInterval) {
543 calcTiming(&scd.beginToEndSamples,
544 &scd.beginToEndFrameTime.minTime, &scd.beginToEndFrameTime.maxTime, &scd.beginToEndFrameTime.avgTime);
545 if (outputDevice) {
546 startEntry(QRhiProfiler::FrameBuildTime, ts.elapsed(), sc);
547 writeInt("frames_since_resize", frameCount);
548 writeInt("min_ms_frame_build", scd.beginToEndFrameTime.minTime);
549 writeInt("max_ms_frame_build", scd.beginToEndFrameTime.maxTime);
550 writeFloat("Favg_ms_frame_build", scd.beginToEndFrameTime.avgTime);
551 endEntry();
552 }
553 }
554}
555
556void QRhiProfilerPrivate::swapChainFrameGpuTime(QRhiSwapChain *sc, float gpuTime)
557{
558 Sc &scd(swapchains[sc]);
559 scd.gpuFrameSamples.append(gpuTime);
560 if (scd.gpuFrameSamples.count() >= frameTimingWriteInterval) {
561 calcTiming(&scd.gpuFrameSamples,
562 &scd.gpuFrameTime.minTime, &scd.gpuFrameTime.maxTime, &scd.gpuFrameTime.avgTime);
563 if (outputDevice) {
564 startEntry(QRhiProfiler::GpuFrameTime, ts.elapsed(), sc);
565 writeFloat("Fmin_ms_gpu_frame_time", scd.gpuFrameTime.minTime);
566 writeFloat("Fmax_ms_gpu_frame_time", scd.gpuFrameTime.maxTime);
567 writeFloat("Favg_ms_gpu_frame_time", scd.gpuFrameTime.avgTime);
568 endEntry();
569 }
570 }
571}
572
573void QRhiProfilerPrivate::newReadbackBuffer(qint64 id, QRhiResource *src, quint32 size)
574{
575 if (!outputDevice)
576 return;
577
578 startEntry(QRhiProfiler::NewReadbackBuffer, ts.elapsed(), src);
579 writeInt("id", id);
580 writeInt("size", size);
581 endEntry();
582}
583
584void QRhiProfilerPrivate::releaseReadbackBuffer(qint64 id)
585{
586 if (!outputDevice)
587 return;
588
589 startEntry(QRhiProfiler::ReleaseReadbackBuffer, ts.elapsed(), nullptr);
590 writeInt("id", id);
591 endEntry();
592}
593
594void QRhiProfilerPrivate::vmemStat(uint realAllocCount, uint subAllocCount, quint32 totalSize, quint32 unusedSize)
595{
596 if (!outputDevice)
597 return;
598
599 startEntry(QRhiProfiler::GpuMemAllocStats, ts.elapsed(), nullptr);
600 writeInt("real_alloc_count", realAllocCount);
601 writeInt("sub_alloc_count", subAllocCount);
602 writeInt("total_size", totalSize);
603 writeInt("unused_size", unusedSize);
604 endEntry();
605}
606
607QT_END_NAMESPACE
608