1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsgrhisupport_p.h"
41#include "qsgcontext_p.h"
42#if QT_CONFIG(opengl)
43# include "qsgdefaultrendercontext_p.h"
44#endif
45#include <QtGui/qwindow.h>
46
47#if QT_CONFIG(vulkan)
48#include <QtGui/qvulkaninstance.h>
49#endif
50
51QT_BEGIN_NAMESPACE
52
53#if QT_CONFIG(vulkan)
54QVulkanInstance *s_vulkanInstance = nullptr;
55#endif
56
57QVulkanInstance *QSGRhiSupport::vulkanInstance()
58{
59#if QT_CONFIG(vulkan)
60 QSGRhiSupport *inst = QSGRhiSupport::instance();
61 if (!inst->isRhiEnabled() || inst->rhiBackend() != QRhi::Vulkan)
62 return nullptr;
63
64 if (!s_vulkanInstance) {
65 s_vulkanInstance = new QVulkanInstance;
66 if (inst->isDebugLayerRequested()) {
67#ifndef Q_OS_ANDROID
68 s_vulkanInstance->setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation");
69#else
70 s_vulkanInstance->setLayers(QByteArrayList()
71 << "VK_LAYER_GOOGLE_threading"
72 << "VK_LAYER_LUNARG_parameter_validation"
73 << "VK_LAYER_LUNARG_object_tracker"
74 << "VK_LAYER_LUNARG_core_validation"
75 << "VK_LAYER_LUNARG_image"
76 << "VK_LAYER_LUNARG_swapchain"
77 << "VK_LAYER_GOOGLE_unique_objects");
78#endif
79 }
80 s_vulkanInstance->setExtensions(QByteArrayList()
81 << "VK_KHR_get_physical_device_properties2");
82 if (!s_vulkanInstance->create()) {
83 qWarning(msg: "Failed to create Vulkan instance");
84 delete s_vulkanInstance;
85 s_vulkanInstance = nullptr;
86 }
87 }
88 return s_vulkanInstance;
89#else
90 return nullptr;
91#endif
92}
93
94void QSGRhiSupport::cleanup()
95{
96#if QT_CONFIG(vulkan)
97 delete s_vulkanInstance;
98 s_vulkanInstance = nullptr;
99#endif
100}
101
102QSGRhiSupport::QSGRhiSupport()
103 : m_set(false),
104 m_enableRhi(false),
105 m_debugLayer(false),
106 m_profile(false),
107 m_shaderEffectDebug(false),
108 m_preferSoftwareRenderer(false)
109{
110}
111
112void QSGRhiSupport::applySettings()
113{
114 m_set = true;
115
116 // This is also done when creating the renderloop but we may be before that
117 // in case we get here due to a setScenegraphBackend() -> configure() early
118 // on in main(). Avoid losing info logs since troubleshooting gets
119 // confusing otherwise.
120 QSGRhiSupport::checkEnvQSgInfo();
121
122 if (m_requested.valid) {
123 // explicit rhi backend request from C++ (e.g. via QQuickWindow)
124 m_enableRhi = m_requested.rhi;
125 switch (m_requested.api) {
126 case QSGRendererInterface::OpenGLRhi:
127 m_rhiBackend = QRhi::OpenGLES2;
128 break;
129 case QSGRendererInterface::Direct3D11Rhi:
130 m_rhiBackend = QRhi::D3D11;
131 break;
132 case QSGRendererInterface::VulkanRhi:
133 m_rhiBackend = QRhi::Vulkan;
134 break;
135 case QSGRendererInterface::MetalRhi:
136 m_rhiBackend = QRhi::Metal;
137 break;
138 case QSGRendererInterface::NullRhi:
139 m_rhiBackend = QRhi::Null;
140 break;
141 default:
142 Q_ASSERT_X(false, "QSGRhiSupport", "Internal error: unhandled GraphicsApi type");
143 break;
144 }
145 } else {
146 // check env.vars., fall back to platform-specific defaults when backend is not set
147 m_enableRhi = uint(qEnvironmentVariableIntValue(varName: "QSG_RHI"));
148 const QByteArray rhiBackend = qgetenv(varName: "QSG_RHI_BACKEND");
149 if (rhiBackend == QByteArrayLiteral("gl")
150 || rhiBackend == QByteArrayLiteral("gles2")
151 || rhiBackend == QByteArrayLiteral("opengl"))
152 {
153 m_rhiBackend = QRhi::OpenGLES2;
154 } else if (rhiBackend == QByteArrayLiteral("d3d11") || rhiBackend == QByteArrayLiteral("d3d")) {
155 m_rhiBackend = QRhi::D3D11;
156 } else if (rhiBackend == QByteArrayLiteral("vulkan")) {
157 m_rhiBackend = QRhi::Vulkan;
158 } else if (rhiBackend == QByteArrayLiteral("metal")) {
159 m_rhiBackend = QRhi::Metal;
160 } else if (rhiBackend == QByteArrayLiteral("null")) {
161 m_rhiBackend = QRhi::Null;
162 } else {
163 if (!rhiBackend.isEmpty()) {
164 qWarning(msg: "Unknown key \"%s\" for QSG_RHI_BACKEND, falling back to default backend.",
165 rhiBackend.constData());
166 }
167#if defined(Q_OS_WIN)
168 m_rhiBackend = QRhi::D3D11;
169#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
170 m_rhiBackend = QRhi::Metal;
171#else
172 m_rhiBackend = QRhi::OpenGLES2;
173#endif
174 // Vulkan has to be requested explicitly
175 }
176 }
177
178 if (!m_enableRhi)
179 return;
180
181 // validation layers (Vulkan) or debug layer (D3D)
182 m_debugLayer = uint(qEnvironmentVariableIntValue(varName: "QSG_RHI_DEBUG_LAYER"));
183
184 // EnableProfiling + DebugMarkers
185 m_profile = uint(qEnvironmentVariableIntValue(varName: "QSG_RHI_PROFILE"));
186
187 m_shaderEffectDebug = uint(qEnvironmentVariableIntValue(varName: "QSG_RHI_SHADEREFFECT_DEBUG"));
188
189 m_preferSoftwareRenderer = uint(qEnvironmentVariableIntValue(varName: "QSG_RHI_PREFER_SOFTWARE_RENDERER"));
190
191 m_killDeviceFrameCount = qEnvironmentVariableIntValue(varName: "QSG_RHI_SIMULATE_DEVICE_LOSS");
192 if (m_killDeviceFrameCount > 0 && m_rhiBackend == QRhi::D3D11)
193 qDebug(msg: "Graphics device will be reset every %d frames", m_killDeviceFrameCount);
194
195 const QString backendName = rhiBackendName();
196 qCDebug(QSG_LOG_INFO,
197 "Using QRhi with backend %s\n graphics API debug/validation layers: %d\n QRhi profiling and debug markers: %d",
198 qPrintable(backendName), m_debugLayer, m_profile);
199 if (m_preferSoftwareRenderer)
200 qCDebug(QSG_LOG_INFO, "Prioritizing software renderers");
201}
202
203QSGRhiSupport *QSGRhiSupport::staticInst()
204{
205 static QSGRhiSupport inst;
206 return &inst;
207}
208
209void QSGRhiSupport::checkEnvQSgInfo()
210{
211 // For compatibility with 5.3 and earlier's QSG_INFO environment variables
212 if (qEnvironmentVariableIsSet(varName: "QSG_INFO"))
213 const_cast<QLoggingCategory &>(QSG_LOG_INFO()).setEnabled(type: QtDebugMsg, enable: true);
214}
215
216void QSGRhiSupport::configure(QSGRendererInterface::GraphicsApi api)
217{
218 Q_ASSERT(QSGRendererInterface::isApiRhiBased(api));
219 QSGRhiSupport *inst = staticInst();
220 if (inst->m_set) {
221 qWarning(msg: "QRhi is already configured, request ignored");
222 return;
223 }
224 inst->m_requested.valid = true;
225 inst->m_requested.api = api;
226 inst->m_requested.rhi = true;
227 inst->applySettings();
228}
229
230QSGRhiSupport *QSGRhiSupport::instance()
231{
232 QSGRhiSupport *inst = staticInst();
233 if (!inst->m_set)
234 inst->applySettings();
235 return inst;
236}
237
238QString QSGRhiSupport::rhiBackendName() const
239{
240 if (m_enableRhi) {
241 switch (m_rhiBackend) {
242 case QRhi::Null:
243 return QLatin1String("Null");
244 case QRhi::Vulkan:
245 return QLatin1String("Vulkan");
246 case QRhi::OpenGLES2:
247 return QLatin1String("OpenGL");
248 case QRhi::D3D11:
249 return QLatin1String("D3D11");
250 case QRhi::Metal:
251 return QLatin1String("Metal");
252 default:
253 return QLatin1String("Unknown");
254 }
255 }
256 return QLatin1String("Unknown (RHI not enabled)");
257}
258
259QSGRendererInterface::GraphicsApi QSGRhiSupport::graphicsApi() const
260{
261 if (!m_enableRhi)
262 return QSGRendererInterface::OpenGL;
263
264 switch (m_rhiBackend) {
265 case QRhi::Null:
266 return QSGRendererInterface::NullRhi;
267 case QRhi::Vulkan:
268 return QSGRendererInterface::VulkanRhi;
269 case QRhi::OpenGLES2:
270 return QSGRendererInterface::OpenGLRhi;
271 case QRhi::D3D11:
272 return QSGRendererInterface::Direct3D11Rhi;
273 case QRhi::Metal:
274 return QSGRendererInterface::MetalRhi;
275 default:
276 return QSGRendererInterface::Unknown;
277 }
278}
279
280QSurface::SurfaceType QSGRhiSupport::windowSurfaceType() const
281{
282 if (!m_enableRhi)
283 return QSurface::OpenGLSurface;
284
285 switch (m_rhiBackend) {
286 case QRhi::Vulkan:
287 return QSurface::VulkanSurface;
288 case QRhi::OpenGLES2:
289 return QSurface::OpenGLSurface;
290 case QRhi::D3D11:
291 return QSurface::OpenGLSurface; // yup, OpenGLSurface
292 case QRhi::Metal:
293 return QSurface::MetalSurface;
294 default:
295 return QSurface::OpenGLSurface;
296 }
297}
298
299#if QT_CONFIG(vulkan)
300static const void *qsgrhi_vk_rifResource(QSGRendererInterface::Resource res,
301 const QRhiNativeHandles *nat,
302 const QRhiNativeHandles *cbNat,
303 const QRhiNativeHandles *rpNat)
304{
305 const QRhiVulkanNativeHandles *vknat = static_cast<const QRhiVulkanNativeHandles *>(nat);
306 const QRhiVulkanCommandBufferNativeHandles *maybeVkCbNat =
307 static_cast<const QRhiVulkanCommandBufferNativeHandles *>(cbNat);
308 const QRhiVulkanRenderPassNativeHandles *maybeVkRpNat =
309 static_cast<const QRhiVulkanRenderPassNativeHandles *>(rpNat);
310
311 switch (res) {
312 case QSGRendererInterface::DeviceResource:
313 return &vknat->dev;
314 case QSGRendererInterface::CommandQueueResource:
315 return &vknat->gfxQueue;
316 case QSGRendererInterface::CommandListResource:
317 if (maybeVkCbNat)
318 return &maybeVkCbNat->commandBuffer;
319 else
320 return nullptr;
321 case QSGRendererInterface::PhysicalDeviceResource:
322 return &vknat->physDev;
323 case QSGRendererInterface::RenderPassResource:
324 if (maybeVkRpNat)
325 return &maybeVkRpNat->renderPass;
326 else
327 return nullptr;
328 default:
329 return nullptr;
330 }
331}
332#endif
333
334#if QT_CONFIG(opengl)
335static const void *qsgrhi_gl_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat)
336{
337 const QRhiGles2NativeHandles *glnat = static_cast<const QRhiGles2NativeHandles *>(nat);
338 switch (res) {
339 case QSGRendererInterface::OpenGLContextResource:
340 return glnat->context;
341 default:
342 return nullptr;
343 }
344}
345#endif
346
347#ifdef Q_OS_WIN
348static const void *qsgrhi_d3d11_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat)
349{
350 const QRhiD3D11NativeHandles *d3dnat = static_cast<const QRhiD3D11NativeHandles *>(nat);
351 switch (res) {
352 case QSGRendererInterface::DeviceResource:
353 return d3dnat->dev;
354 case QSGRendererInterface::DeviceContextResource:
355 return d3dnat->context;
356 default:
357 return nullptr;
358 }
359}
360#endif
361
362#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
363static const void *qsgrhi_mtl_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat,
364 const QRhiNativeHandles *cbNat)
365{
366 const QRhiMetalNativeHandles *mtlnat = static_cast<const QRhiMetalNativeHandles *>(nat);
367 const QRhiMetalCommandBufferNativeHandles *maybeMtlCbNat =
368 static_cast<const QRhiMetalCommandBufferNativeHandles *>(cbNat);
369
370 switch (res) {
371 case QSGRendererInterface::DeviceResource:
372 return mtlnat->dev;
373 case QSGRendererInterface::CommandQueueResource:
374 return mtlnat->cmdQueue;
375 case QSGRendererInterface::CommandListResource:
376 if (maybeMtlCbNat)
377 return maybeMtlCbNat->commandBuffer;
378 else
379 return nullptr;
380 case QSGRendererInterface::CommandEncoderResource:
381 if (maybeMtlCbNat)
382 return maybeMtlCbNat->encoder;
383 else
384 return nullptr;
385 default:
386 return nullptr;
387 }
388}
389#endif
390
391const void *QSGRhiSupport::rifResource(QSGRendererInterface::Resource res,
392 const QSGDefaultRenderContext *rc)
393{
394// ### This condition is a temporary workaround to allow compilation
395// with -no-opengl, but Vulkan or Metal enabled, to succeed. Full
396// support for RHI-capable -no-opengl builds will be available in
397// Qt 6 once the direct OpenGL code path gets removed.
398#if QT_CONFIG(opengl)
399
400 QRhi *rhi = rc->rhi();
401 if (res == QSGRendererInterface::RhiResource || !rhi)
402 return rhi;
403
404 const QRhiNativeHandles *nat = rhi->nativeHandles();
405 if (!nat)
406 return nullptr;
407
408 switch (m_rhiBackend) {
409#if QT_CONFIG(vulkan)
410 case QRhi::Vulkan:
411 {
412 QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
413 QRhiRenderPassDescriptor *rp = rc->currentFrameRenderPass();
414 return qsgrhi_vk_rifResource(res, nat,
415 cbNat: cb ? cb->nativeHandles() : nullptr,
416 rpNat: rp ? rp->nativeHandles() : nullptr);
417 }
418#endif
419#if QT_CONFIG(opengl)
420 case QRhi::OpenGLES2:
421 return qsgrhi_gl_rifResource(res, nat);
422#endif
423#ifdef Q_OS_WIN
424 case QRhi::D3D11:
425 return qsgrhi_d3d11_rifResource(res, nat);
426#endif
427#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
428 case QRhi::Metal:
429 {
430 QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
431 return qsgrhi_mtl_rifResource(res, nat, cb ? cb->nativeHandles() : nullptr);
432 }
433#endif
434 default:
435 return nullptr;
436 }
437
438#else
439 Q_UNUSED(res);
440 Q_UNUSED(rc);
441 return nullptr;
442#endif
443}
444
445int QSGRhiSupport::chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi)
446{
447 int msaaSampleCount = qMax(a: QSurfaceFormat::defaultFormat().samples(), b: window->requestedFormat().samples());
448 if (qEnvironmentVariableIsSet(varName: "QSG_SAMPLES"))
449 msaaSampleCount = qEnvironmentVariableIntValue(varName: "QSG_SAMPLES");
450 msaaSampleCount = qMax(a: 1, b: msaaSampleCount);
451 if (msaaSampleCount > 1) {
452 const QVector<int> supportedSampleCounts = rhi->supportedSampleCounts();
453 if (!supportedSampleCounts.contains(t: msaaSampleCount)) {
454 int reducedSampleCount = 1;
455 for (int i = supportedSampleCounts.count() - 1; i >= 0; --i) {
456 if (supportedSampleCounts[i] <= msaaSampleCount) {
457 reducedSampleCount = supportedSampleCounts[i];
458 break;
459 }
460 }
461 qWarning() << "Requested MSAA sample count" << msaaSampleCount
462 << "but supported sample counts are" << supportedSampleCounts
463 << ", using sample count" << reducedSampleCount << "instead";
464 msaaSampleCount = reducedSampleCount;
465 }
466 }
467 return msaaSampleCount;
468}
469
470// must be called on the main thread
471QOffscreenSurface *QSGRhiSupport::maybeCreateOffscreenSurface(QWindow *window)
472{
473 QOffscreenSurface *offscreenSurface = nullptr;
474#if QT_CONFIG(opengl)
475 if (rhiBackend() == QRhi::OpenGLES2) {
476 const QSurfaceFormat format = window->requestedFormat();
477 offscreenSurface = QRhiGles2InitParams::newFallbackSurface(format);
478 }
479#else
480 Q_UNUSED(window);
481#endif
482 return offscreenSurface;
483}
484
485// must be called on the render thread
486QRhi *QSGRhiSupport::createRhi(QWindow *window, QOffscreenSurface *offscreenSurface)
487{
488#if !QT_CONFIG(opengl) && !QT_CONFIG(vulkan)
489 Q_UNUSED(window);
490#endif
491
492 QRhi *rhi = nullptr;
493
494 QRhi::Flags flags;
495 if (isProfilingRequested())
496 flags |= QRhi::EnableProfiling | QRhi::EnableDebugMarkers;
497 if (isSoftwareRendererRequested())
498 flags |= QRhi::PreferSoftwareRenderer;
499
500 QRhi::Implementation backend = rhiBackend();
501 if (backend == QRhi::Null) {
502 QRhiNullInitParams rhiParams;
503 rhi = QRhi::create(impl: backend, params: &rhiParams, flags);
504 }
505#if QT_CONFIG(opengl)
506 if (backend == QRhi::OpenGLES2) {
507 const QSurfaceFormat format = window->requestedFormat();
508 QRhiGles2InitParams rhiParams;
509 rhiParams.format = format;
510 rhiParams.fallbackSurface = offscreenSurface;
511 rhiParams.window = window;
512 rhi = QRhi::create(impl: backend, params: &rhiParams, flags);
513 }
514#else
515 Q_UNUSED(offscreenSurface);
516#endif
517#if QT_CONFIG(vulkan)
518 if (backend == QRhi::Vulkan) {
519 QRhiVulkanInitParams rhiParams;
520 rhiParams.inst = window->vulkanInstance();
521 if (!rhiParams.inst)
522 qWarning(msg: "No QVulkanInstance set for QQuickWindow, this is wrong.");
523 rhiParams.window = window;
524 rhi = QRhi::create(impl: backend, params: &rhiParams, flags);
525 }
526#endif
527#ifdef Q_OS_WIN
528 if (backend == QRhi::D3D11) {
529 QRhiD3D11InitParams rhiParams;
530 rhiParams.enableDebugLayer = isDebugLayerRequested();
531 if (m_killDeviceFrameCount > 0) {
532 rhiParams.framesUntilKillingDeviceViaTdr = m_killDeviceFrameCount;
533 rhiParams.repeatDeviceKill = true;
534 }
535 rhi = QRhi::create(backend, &rhiParams, flags);
536 }
537#endif
538#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
539 if (backend == QRhi::Metal) {
540 QRhiMetalInitParams rhiParams;
541 rhi = QRhi::create(backend, &rhiParams, flags);
542 }
543#endif
544
545 if (!rhi)
546 qWarning(msg: "Failed to create RHI (backend %d)", backend);
547
548 return rhi;
549}
550
551QImage QSGRhiSupport::grabAndBlockInCurrentFrame(QRhi *rhi, QRhiSwapChain *swapchain)
552{
553 Q_ASSERT(rhi->isRecordingFrame());
554
555 QRhiReadbackResult result;
556 QRhiReadbackDescription readbackDesc; // read from swapchain backbuffer
557 QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
558 resourceUpdates->readBackTexture(rb: readbackDesc, result: &result);
559
560 swapchain->currentFrameCommandBuffer()->resourceUpdate(resourceUpdates);
561 rhi->finish(); // make sure the readback has finished, stall the pipeline if needed
562
563 // May be RGBA or BGRA. Plus premultiplied alpha.
564 QImage::Format imageFormat;
565 if (result.format == QRhiTexture::BGRA8) {
566#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
567 imageFormat = QImage::Format_ARGB32_Premultiplied;
568#else
569 imageFormat = QImage::Format_RGBA8888_Premultiplied;
570 // ### and should swap too
571#endif
572 } else {
573 imageFormat = QImage::Format_RGBA8888_Premultiplied;
574 }
575
576 const uchar *p = reinterpret_cast<const uchar *>(result.data.constData());
577 const QImage img(p, result.pixelSize.width(), result.pixelSize.height(), imageFormat);
578
579 if (rhi->isYUpInFramebuffer())
580 return img.mirrored();
581
582 return img.copy();
583}
584
585QSGRhiProfileConnection *QSGRhiProfileConnection::instance()
586{
587 static QSGRhiProfileConnection inst;
588 return &inst;
589}
590
591void QSGRhiProfileConnection::initialize(QRhi *rhi)
592{
593#ifdef RHI_REMOTE_PROFILER
594 const QString profHost = qEnvironmentVariable(varName: "QSG_RHI_PROFILE_HOST");
595 if (!profHost.isEmpty()) {
596 int profPort = qEnvironmentVariableIntValue(varName: "QSG_RHI_PROFILE_PORT");
597 if (!profPort)
598 profPort = 30667;
599 qCDebug(QSG_LOG_INFO, "Sending RHI profiling output to %s:%d", qPrintable(profHost), profPort);
600 m_profConn.reset(other: new QTcpSocket);
601 QObject::connect(sender: m_profConn.data(), signal: &QAbstractSocket::errorOccurred, context: m_profConn.data(),
602 slot: [this](QAbstractSocket::SocketError socketError) { qWarning(msg: " RHI profiler error: %d (%s)",
603 socketError, qPrintable(m_profConn->errorString())); });
604 m_profConn->connectToHost(hostName: profHost, port: profPort);
605 m_profConn->waitForConnected(); // blocking wait because we want to send stuff already from the init below
606 rhi->profiler()->setDevice(m_profConn.data());
607 m_lastMemStatWrite.start();
608 }
609#else
610 Q_UNUSED(rhi);
611#endif
612}
613
614void QSGRhiProfileConnection::cleanup()
615{
616#ifdef RHI_REMOTE_PROFILER
617 m_profConn.reset();
618#endif
619}
620
621void QSGRhiProfileConnection::send(QRhi *rhi)
622{
623#ifdef RHI_REMOTE_PROFILER
624 if (m_profConn) {
625 // do this every 5 sec at most
626 if (m_lastMemStatWrite.elapsed() >= 5000) {
627 rhi->profiler()->addVMemAllocatorStats();
628 m_lastMemStatWrite.restart();
629 }
630 }
631#else
632 Q_UNUSED(rhi);
633#endif
634}
635
636QT_END_NAMESPACE
637

source code of qtdeclarative/src/quick/scenegraph/qsgrhisupport.cpp