Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsgrhisupport.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsgrhisupport_p.h"
5#include "qsgcontext_p.h"
7
8#include <QtQuick/private/qquickitem_p.h>
9#include <QtQuick/private/qquickwindow_p.h>
10
11#include <QtGui/qwindow.h>
12
13#if QT_CONFIG(vulkan)
14#include <QtGui/private/qvulkandefaultinstance_p.h>
15#endif
16
17#include <QOperatingSystemVersion>
18#include <QLockFile>
19#include <QSaveFile>
20#include <QStandardPaths>
21#include <QDir>
22#include <QFileInfo>
23#include <QSysInfo>
24#include <QOffscreenSurface>
25
26#ifdef Q_OS_WIN
27#include <dxgiformat.h>
28#endif
29
30#include <memory>
31
33
34QSGRhiSupport::QSGRhiSupport()
35{
36}
37
38void QSGRhiSupport::applySettings()
39{
40 // Multiple calls to this function are perfectly possible!
41 // Just store that it was called at least once.
42 m_settingsApplied = true;
43
44 // This is also done when creating the renderloop but we may be before that
45 // in case we get here due to a setGraphicsApi() -> configure() early
46 // on in main(). Avoid losing info logs since troubleshooting gets
47 // confusing otherwise.
49
50 if (m_requested.valid) {
51 // explicit rhi backend request from C++ (e.g. via QQuickWindow)
52 switch (m_requested.api) {
54 m_rhiBackend = QRhi::OpenGLES2;
55 break;
57 m_rhiBackend = QRhi::D3D11;
58 break;
60 m_rhiBackend = QRhi::D3D12;
61 break;
63 m_rhiBackend = QRhi::Vulkan;
64 break;
66 m_rhiBackend = QRhi::Metal;
67 break;
69 m_rhiBackend = QRhi::Null;
70 break;
71 default:
72 Q_ASSERT_X(false, "QSGRhiSupport", "Internal error: unhandled GraphicsApi type");
73 break;
74 }
75 } else {
76 // check env.vars., fall back to platform-specific defaults when backend is not set
77 const QByteArray rhiBackend = qgetenv("QSG_RHI_BACKEND");
78 if (rhiBackend == QByteArrayLiteral("gl")
79 || rhiBackend == QByteArrayLiteral("gles2")
80 || rhiBackend == QByteArrayLiteral("opengl"))
81 {
82 m_rhiBackend = QRhi::OpenGLES2;
83 } else if (rhiBackend == QByteArrayLiteral("d3d11") || rhiBackend == QByteArrayLiteral("d3d")) {
84 m_rhiBackend = QRhi::D3D11;
85 } else if (rhiBackend == QByteArrayLiteral("d3d12")) {
86 m_rhiBackend = QRhi::D3D12;
87 } else if (rhiBackend == QByteArrayLiteral("vulkan")) {
88 m_rhiBackend = QRhi::Vulkan;
89 } else if (rhiBackend == QByteArrayLiteral("metal")) {
90 m_rhiBackend = QRhi::Metal;
91 } else if (rhiBackend == QByteArrayLiteral("null")) {
92 m_rhiBackend = QRhi::Null;
93 } else {
94 if (!rhiBackend.isEmpty()) {
95 qWarning("Unknown key \"%s\" for QSG_RHI_BACKEND, falling back to default backend.",
96 rhiBackend.constData());
97 }
98#if defined(Q_OS_WIN)
99 m_rhiBackend = QRhi::D3D11;
100#elif QT_CONFIG(metal)
101 m_rhiBackend = QRhi::Metal;
102#elif QT_CONFIG(opengl)
103 m_rhiBackend = QRhi::OpenGLES2;
104#else
105 m_rhiBackend = QRhi::Vulkan;
106#endif
107
108 // Now that we established our initial choice, we may want to opt
109 // for another backend under certain special circumstances.
110 adjustToPlatformQuirks();
111 }
112 }
113
114 // At this point the RHI backend is fixed, it cannot be changed once we
115 // return from this function. This is because things like the QWindow
116 // (QQuickWindow) may depend on the graphics API as well (surfaceType
117 // f.ex.), and all that is based on what we report from here. So further
118 // adjustments are not possible (or, at minimum, not safe and portable).
119}
120
121void QSGRhiSupport::adjustToPlatformQuirks()
122{
123#if QT_CONFIG(metal)
124 // A macOS VM may not have Metal support at all. We have to decide at this
125 // point, it will be too late afterwards, and the only way is to see if
126 // MTLCreateSystemDefaultDevice succeeds.
127 if (m_rhiBackend == QRhi::Metal) {
128 QRhiMetalInitParams rhiParams;
129 if (!QRhi::probe(m_rhiBackend, &rhiParams)) {
130 m_rhiBackend = QRhi::OpenGLES2;
131 qCDebug(QSG_LOG_INFO, "Metal does not seem to be supported. Falling back to OpenGL.");
132 }
133 }
134#endif
135}
136
138{
139 // For compatibility with 5.3 and earlier's QSG_INFO environment variables
140 if (qEnvironmentVariableIsSet("QSG_INFO"))
141 const_cast<QLoggingCategory &>(QSG_LOG_INFO()).setEnabled(QtDebugMsg, true);
142}
143
144
145#if QT_CONFIG(opengl)
146#ifndef GL_BGRA
147#define GL_BGRA 0x80E1
148#endif
149
150#ifndef GL_R8
151#define GL_R8 0x8229
152#endif
153
154#ifndef GL_RG8
155#define GL_RG8 0x822B
156#endif
157
158#ifndef GL_RG
159#define GL_RG 0x8227
160#endif
161
162#ifndef GL_R16
163#define GL_R16 0x822A
164#endif
165
166#ifndef GL_RG16
167#define GL_RG16 0x822C
168#endif
169
170#ifndef GL_RED
171#define GL_RED 0x1903
172#endif
173
174#ifndef GL_RGBA8
175#define GL_RGBA8 0x8058
176#endif
177
178#ifndef GL_RGBA32F
179#define GL_RGBA32F 0x8814
180#endif
181
182#ifndef GL_RGBA16F
183#define GL_RGBA16F 0x881A
184#endif
185
186#ifndef GL_R16F
187#define GL_R16F 0x822D
188#endif
189
190#ifndef GL_R32F
191#define GL_R32F 0x822E
192#endif
193
194#ifndef GL_DEPTH_COMPONENT16
195#define GL_DEPTH_COMPONENT16 0x81A5
196#endif
197
198#ifndef GL_DEPTH_COMPONENT24
199#define GL_DEPTH_COMPONENT24 0x81A6
200#endif
201
202#ifndef GL_DEPTH_COMPONENT32F
203#define GL_DEPTH_COMPONENT32F 0x8CAC
204#endif
205
206#ifndef GL_DEPTH24_STENCIL8
207#define GL_DEPTH24_STENCIL8 0x88F0
208#endif
209
210#ifndef GL_DEPTH_STENCIL
211#define GL_DEPTH_STENCIL 0x84F9
212#endif
213
214#ifndef GL_RGB10_A2
215#define GL_RGB10_A2 0x8059
216#endif
217
218#ifndef GL_SRGB_ALPHA
219#define GL_SRGB_ALPHA 0x8C42
220#endif
221
222#ifndef GL_SRGB8_ALPHA8
223#define GL_SRGB8_ALPHA8 0x8C43
224#endif
225
226QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromGL(uint format, QRhiTexture::Flags *flags)
227{
228 bool sRGB = false;
229 auto rhiFormat = QRhiTexture::UnknownFormat;
230 switch (format) {
231 case GL_SRGB_ALPHA:
232 case GL_SRGB8_ALPHA8:
233 sRGB = true;
235 case GL_RGBA:
236 case GL_RGBA8:
237 case 0:
238 rhiFormat = QRhiTexture::RGBA8;
239 break;
240 case GL_BGRA:
241 rhiFormat = QRhiTexture::BGRA8;
242 break;
243 case GL_R16:
244 rhiFormat = QRhiTexture::R16;
245 break;
246 case GL_RG16:
247 rhiFormat = QRhiTexture::RG16;
248 break;
249 case GL_RED:
251 case GL_R8:
252 rhiFormat = QRhiTexture::R8;
253 break;
254 case GL_RG:
256 case GL_RG8:
257 rhiFormat = QRhiTexture::RG8;
258 break;
259 case GL_ALPHA:
260 rhiFormat = QRhiTexture::RED_OR_ALPHA8;
261 break;
262 case GL_RGBA16F:
263 rhiFormat = QRhiTexture::RGBA16F;
264 break;
265 case GL_RGBA32F:
266 rhiFormat = QRhiTexture::RGBA32F;
267 break;
268 case GL_R16F:
269 rhiFormat = QRhiTexture::R16F;
270 break;
271 case GL_R32F:
272 rhiFormat = QRhiTexture::R32F;
273 break;
274 case GL_RGB10_A2:
275 rhiFormat = QRhiTexture::RGB10A2;
276 break;
277 case GL_DEPTH_COMPONENT:
280 rhiFormat = QRhiTexture::D16;
281 break;
283 rhiFormat = QRhiTexture::D24;
284 break;
285 case GL_DEPTH_STENCIL:
288 rhiFormat = QRhiTexture::D24S8;
289 break;
291 rhiFormat = QRhiTexture::D32F;
292 break;
293 default:
294 qWarning("GL format %d is not supported", format);
295 break;
296 }
297 if (sRGB)
298 (*flags) |=(QRhiTexture::sRGB);
299 return rhiFormat;
300}
301#endif
302
303#if QT_CONFIG(vulkan)
304QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromVulkan(uint format, QRhiTexture::Flags *flags)
305{
306 auto rhiFormat = QRhiTexture::UnknownFormat;
307 bool sRGB = false;
308 switch (format) {
309 case VK_FORMAT_R8G8B8A8_SRGB:
310 sRGB = true;
312 case VK_FORMAT_R8G8B8A8_UNORM:
313 case VK_FORMAT_UNDEFINED:
314 rhiFormat = QRhiTexture::RGBA8;
315 break;
316 case VK_FORMAT_B8G8R8A8_SRGB:
317 sRGB = true;
319 case VK_FORMAT_B8G8R8A8_UNORM:
320 rhiFormat = QRhiTexture::BGRA8;
321 break;
322 case VK_FORMAT_R8_SRGB:
323 sRGB = true;
325 case VK_FORMAT_R8_UNORM:
326 rhiFormat = QRhiTexture::R8;
327 break;
328 case VK_FORMAT_R8G8_SRGB:
329 sRGB = true;
331 case VK_FORMAT_R8G8_UNORM:
332 rhiFormat = QRhiTexture::RG8;
333 break;
334 case VK_FORMAT_R16_UNORM:
335 rhiFormat = QRhiTexture::R16;
336 break;
337 case VK_FORMAT_R16G16_UNORM:
338 rhiFormat = QRhiTexture::RG16;
339 break;
340 case VK_FORMAT_R16G16B16A16_SFLOAT:
341 rhiFormat = QRhiTexture::RGBA16F;
342 break;
343 case VK_FORMAT_R32G32B32A32_SFLOAT:
344 rhiFormat = QRhiTexture::RGBA32F;
345 break;
346 case VK_FORMAT_R16_SFLOAT:
347 rhiFormat = QRhiTexture::R16F;
348 break;
349 case VK_FORMAT_R32_SFLOAT:
350 rhiFormat = QRhiTexture::R32F;
351 break;
352 case VK_FORMAT_A2B10G10R10_UNORM_PACK32: // intentionally
354 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
355 rhiFormat = QRhiTexture::RGB10A2;
356 break;
357 case VK_FORMAT_D16_UNORM:
358 rhiFormat = QRhiTexture::D16;
359 break;
360 case VK_FORMAT_X8_D24_UNORM_PACK32:
361 rhiFormat = QRhiTexture::D24;
362 break;
363 case VK_FORMAT_D24_UNORM_S8_UINT:
364 rhiFormat = QRhiTexture::D24S8;
365 break;
366 case VK_FORMAT_D32_SFLOAT:
367 rhiFormat = QRhiTexture::D32F;
368 break;
369 case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
370 sRGB = true;
372 case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
373 rhiFormat = QRhiTexture::BC1;
374 break;
375 case VK_FORMAT_BC2_SRGB_BLOCK:
376 sRGB = true;
378 case VK_FORMAT_BC2_UNORM_BLOCK:
379 rhiFormat = QRhiTexture::BC2;
380 break;
381 case VK_FORMAT_BC3_SRGB_BLOCK:
382 sRGB = true;
384 case VK_FORMAT_BC3_UNORM_BLOCK:
385 rhiFormat = QRhiTexture::BC3;
386 break;
387 case VK_FORMAT_BC4_UNORM_BLOCK:
388 rhiFormat = QRhiTexture::BC4;
389 break;
390 case VK_FORMAT_BC5_UNORM_BLOCK:
391 rhiFormat = QRhiTexture::BC5;
392 break;
393 case VK_FORMAT_BC6H_UFLOAT_BLOCK:
394 rhiFormat = QRhiTexture::BC6H;
395 break;
396 case VK_FORMAT_BC7_SRGB_BLOCK:
397 sRGB = true;
399 case VK_FORMAT_BC7_UNORM_BLOCK:
400 rhiFormat = QRhiTexture::BC7;
401 break;
402 case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
403 sRGB = true;
405 case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
406 rhiFormat = QRhiTexture::ETC2_RGB8;
407 break;
408 case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
409 sRGB = true;
411 case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
412 rhiFormat = QRhiTexture::ETC2_RGB8A1;
413 break;
414 case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
415 sRGB = true;
417 case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
418 rhiFormat = QRhiTexture::ETC2_RGBA8;
419 break;
420 case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
421 sRGB = true;
423 case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
424 rhiFormat = QRhiTexture::ASTC_4x4;
425 break;
426 case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
427 sRGB = true;
429 case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
430 rhiFormat = QRhiTexture::ASTC_5x4;
431 break;
432 case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
433 sRGB = true;
435 case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
436 rhiFormat = QRhiTexture::ASTC_5x5;
437 break;
438 case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
439 sRGB = true;
441 case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
442 rhiFormat = QRhiTexture::ASTC_6x5;
443 break;
444 case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
445 sRGB = true;
447 case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
448 rhiFormat = QRhiTexture::ASTC_6x6;
449 break;
450 case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
451 sRGB = true;
453 case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
454 rhiFormat = QRhiTexture::ASTC_8x5;
455 break;
456 case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
457 sRGB = true;
459 case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
460 rhiFormat = QRhiTexture::ASTC_8x6;
461 break;
462 case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
463 sRGB = true;
465 case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
466 rhiFormat = QRhiTexture::ASTC_8x8;
467 break;
468 case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
469 sRGB = true;
471 case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
472 rhiFormat = QRhiTexture::ASTC_10x5;
473 break;
474 case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
475 sRGB = true;
477 case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
478 rhiFormat = QRhiTexture::ASTC_10x6;
479 break;
480 case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
481 sRGB = true;
483 case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
484 rhiFormat = QRhiTexture::ASTC_10x8;
485 break;
486 case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
487 sRGB = true;
489 case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
490 rhiFormat = QRhiTexture::ASTC_10x10;
491 break;
492 case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
493 sRGB = true;
495 case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
496 rhiFormat = QRhiTexture::ASTC_12x10;
497 break;
498 case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
499 sRGB = true;
501 case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
502 rhiFormat = QRhiTexture::ASTC_12x12;
503 break;
504 default:
505 qWarning("VkFormat %d is not supported", format);
506 break;
507 }
508 if (sRGB)
509 (*flags) |=(QRhiTexture::sRGB);
510 return rhiFormat;
511}
512#endif
513
514#ifdef Q_OS_WIN
515QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromDXGI(uint format, QRhiTexture::Flags *flags)
516{
517 auto rhiFormat = QRhiTexture::UnknownFormat;
518 bool sRGB = false;
519 switch (format) {
520 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
521 sRGB = true;
523 case DXGI_FORMAT_R8G8B8A8_UNORM:
524 case DXGI_FORMAT_UNKNOWN:
525 rhiFormat = QRhiTexture::RGBA8;
526 break;
527 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
528 sRGB = true;
530 case DXGI_FORMAT_B8G8R8A8_UNORM:
531 rhiFormat = QRhiTexture::BGRA8;
532 break;
533 case DXGI_FORMAT_R8_UNORM:
534 rhiFormat = QRhiTexture::R8;
535 break;
536 case DXGI_FORMAT_R8G8_UNORM:
537 rhiFormat = QRhiTexture::RG8;
538 break;
539 case DXGI_FORMAT_R16_UNORM:
540 rhiFormat = QRhiTexture::R16;
541 break;
542 case DXGI_FORMAT_R16G16_UNORM:
543 rhiFormat = QRhiTexture::RG16;
544 break;
545 case DXGI_FORMAT_R16G16B16A16_FLOAT:
546 rhiFormat = QRhiTexture::RGBA16F;
547 break;
548 case DXGI_FORMAT_R32G32B32A32_FLOAT:
549 rhiFormat = QRhiTexture::RGBA32F;
550 break;
551 case DXGI_FORMAT_R16_FLOAT:
552 rhiFormat = QRhiTexture::R16F;
553 break;
554 case DXGI_FORMAT_R32_FLOAT:
555 rhiFormat = QRhiTexture::R32F;
556 break;
557 case DXGI_FORMAT_R10G10B10A2_UNORM:
558 rhiFormat = QRhiTexture::RGB10A2;
559 break;
560 case DXGI_FORMAT_R16_TYPELESS:
561 rhiFormat = QRhiTexture::D16;
562 break;
563 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
564 rhiFormat = QRhiTexture::D24;
565 break;
566 case DXGI_FORMAT_D24_UNORM_S8_UINT:
567 rhiFormat = QRhiTexture::D24S8;
568 break;
569 case DXGI_FORMAT_R32_TYPELESS:
570 rhiFormat = QRhiTexture::D32F;
571 break;
572 case DXGI_FORMAT_BC1_UNORM_SRGB:
573 sRGB = true;
575 case DXGI_FORMAT_BC1_UNORM:
576 rhiFormat = QRhiTexture::BC1;
577 break;
578 case DXGI_FORMAT_BC2_UNORM_SRGB:
579 sRGB = true;
581 case DXGI_FORMAT_BC2_UNORM:
582 rhiFormat = QRhiTexture::BC2;
583 break;
584 case DXGI_FORMAT_BC3_UNORM_SRGB:
585 sRGB = true;
587 case DXGI_FORMAT_BC3_UNORM:
588 rhiFormat = QRhiTexture::BC3;
589 break;
590 case DXGI_FORMAT_BC4_UNORM:
591 rhiFormat = QRhiTexture::BC4;
592 break;
593 case DXGI_FORMAT_BC5_UNORM:
594 rhiFormat = QRhiTexture::BC5;
595 break;
596 case DXGI_FORMAT_BC6H_UF16:
597 rhiFormat = QRhiTexture::BC6H;
598 break;
599 case DXGI_FORMAT_BC7_UNORM_SRGB:
600 sRGB = true;
602 case DXGI_FORMAT_BC7_UNORM:
603 rhiFormat = QRhiTexture::BC7;
604 break;
605 default:
606 qWarning("DXGI_FORMAT %d is not supported", format);
607 break;
608 }
609 if (sRGB)
610 (*flags) |=(QRhiTexture::sRGB);
611 return rhiFormat;
612}
613#endif
614
615#if QT_CONFIG(metal)
616namespace QSGRhiSupportMac {
618}
619QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromMetal(uint format, QRhiTexture::Flags *flags)
620{
622}
623#endif
624
626{
628 // behave as if nothing was explicitly requested
629 m_requested.valid = false;
630 applySettings();
631 } else {
633 m_requested.valid = true;
634 m_requested.api = api;
635 applySettings();
636 }
637}
638
640{
641 static QSGRhiSupport inst;
642 return &inst;
643}
644
646{
648 if (!inst->m_settingsApplied)
649 inst->applySettings();
650 return inst;
651}
652
657
659{
660 switch (m_rhiBackend) {
661 case QRhi::Null:
663 case QRhi::Vulkan:
665 case QRhi::OpenGLES2:
667 case QRhi::D3D11:
669 case QRhi::D3D12:
671 case QRhi::Metal:
673 default:
675 }
676}
677
679{
680 switch (m_rhiBackend) {
681 case QRhi::Vulkan:
683 case QRhi::OpenGLES2:
685 case QRhi::D3D11:
686 case QRhi::D3D12:
688 case QRhi::Metal:
690 default:
692 }
693}
694
695#if QT_CONFIG(vulkan)
696static const void *qsgrhi_vk_rifResource(QSGRendererInterface::Resource res,
697 const QRhiNativeHandles *nat,
698 const QRhiNativeHandles *cbNat,
699 const QRhiNativeHandles *rpNat)
700{
701 const QRhiVulkanNativeHandles *vknat = static_cast<const QRhiVulkanNativeHandles *>(nat);
702 const QRhiVulkanCommandBufferNativeHandles *maybeVkCbNat =
703 static_cast<const QRhiVulkanCommandBufferNativeHandles *>(cbNat);
704 const QRhiVulkanRenderPassNativeHandles *maybeVkRpNat =
705 static_cast<const QRhiVulkanRenderPassNativeHandles *>(rpNat);
706
707 switch (res) {
709 return &vknat->dev;
711 return &vknat->gfxQueue;
713 if (maybeVkCbNat)
714 return &maybeVkCbNat->commandBuffer;
715 else
716 return nullptr;
718 return &vknat->physDev;
720 if (maybeVkRpNat)
721 return &maybeVkRpNat->renderPass;
722 else
723 return nullptr;
725 return &vknat->gfxQueueFamilyIdx;
727 return &vknat->gfxQueueIdx;
728 default:
729 return nullptr;
730 }
731}
732#endif
733
734#if QT_CONFIG(opengl)
735static const void *qsgrhi_gl_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat)
736{
737 const QRhiGles2NativeHandles *glnat = static_cast<const QRhiGles2NativeHandles *>(nat);
738 switch (res) {
740 return glnat->context;
741 default:
742 return nullptr;
743 }
744}
745#endif
746
747#ifdef Q_OS_WIN
748static const void *qsgrhi_d3d11_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat)
749{
750 const QRhiD3D11NativeHandles *d3dnat = static_cast<const QRhiD3D11NativeHandles *>(nat);
751 switch (res) {
753 return d3dnat->dev;
755 return d3dnat->context;
756 default:
757 return nullptr;
758 }
759}
760
761static const void *qsgrhi_d3d12_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat)
762{
763 const QRhiD3D12NativeHandles *d3dnat = static_cast<const QRhiD3D12NativeHandles *>(nat);
764 switch (res) {
766 return d3dnat->dev;
768 return d3dnat->commandQueue;
769 default:
770 return nullptr;
771 }
772}
773#endif
774
775#if QT_CONFIG(metal)
776static const void *qsgrhi_mtl_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat,
777 const QRhiNativeHandles *cbNat)
778{
779 const QRhiMetalNativeHandles *mtlnat = static_cast<const QRhiMetalNativeHandles *>(nat);
780 const QRhiMetalCommandBufferNativeHandles *maybeMtlCbNat =
781 static_cast<const QRhiMetalCommandBufferNativeHandles *>(cbNat);
782
783 switch (res) {
785 return mtlnat->dev;
787 return mtlnat->cmdQueue;
789 if (maybeMtlCbNat)
790 return maybeMtlCbNat->commandBuffer;
791 else
792 return nullptr;
794 if (maybeMtlCbNat)
795 return maybeMtlCbNat->encoder;
796 else
797 return nullptr;
798 default:
799 return nullptr;
800 }
801}
802#endif
803
805 const QSGDefaultRenderContext *rc,
806 const QQuickWindow *w)
807{
808 QRhi *rhi = rc->rhi();
809 if (!rhi)
810 return nullptr;
811
812 // Accessing the underlying QRhi* objects are essential both for Qt Quick
813 // 3D and advanced solutions, such as VR engine integrations.
814 switch (res) {
816 return rhi;
818 return QQuickWindowPrivate::get(w)->swapchain;
820 return QQuickWindowPrivate::get(w)->redirect.commandBuffer;
822 return QQuickWindowPrivate::get(w)->redirect.rt.rt.renderTarget;
823 default:
824 break;
825 }
826
827 const QRhiNativeHandles *nat = rhi->nativeHandles();
828 if (!nat)
829 return nullptr;
830
831 switch (m_rhiBackend) {
832#if QT_CONFIG(vulkan)
833 case QRhi::Vulkan:
834 {
837 return qsgrhi_vk_rifResource(res, nat,
838 cb ? cb->nativeHandles() : nullptr,
839 rp ? rp->nativeHandles() : nullptr);
840 }
841#endif
842#if QT_CONFIG(opengl)
843 case QRhi::OpenGLES2:
844 return qsgrhi_gl_rifResource(res, nat);
845#endif
846#ifdef Q_OS_WIN
847 case QRhi::D3D11:
848 return qsgrhi_d3d11_rifResource(res, nat);
849 case QRhi::D3D12:
850 return qsgrhi_d3d12_rifResource(res, nat);
851#endif
852#if QT_CONFIG(metal)
853 case QRhi::Metal:
854 {
856 return qsgrhi_mtl_rifResource(res, nat, cb ? cb->nativeHandles() : nullptr);
857 }
858#endif
859 default:
860 return nullptr;
861 }
862}
863
865{
866 int msaaSampleCount = samples;
867 if (qEnvironmentVariableIsSet("QSG_SAMPLES"))
868 msaaSampleCount = qEnvironmentVariableIntValue("QSG_SAMPLES");
869 msaaSampleCount = qMax(1, msaaSampleCount);
870 if (msaaSampleCount > 1) {
871 const QVector<int> supportedSampleCounts = rhi->supportedSampleCounts();
872 if (!supportedSampleCounts.contains(msaaSampleCount)) {
873 int reducedSampleCount = 1;
874 for (int i = supportedSampleCounts.size() - 1; i >= 0; --i) {
875 if (supportedSampleCounts[i] <= msaaSampleCount) {
876 reducedSampleCount = supportedSampleCounts[i];
877 break;
878 }
879 }
880 qWarning() << "Requested MSAA sample count" << msaaSampleCount
881 << "but supported sample counts are" << supportedSampleCounts
882 << ", using sample count" << reducedSampleCount << "instead";
883 msaaSampleCount = reducedSampleCount;
884 }
885 }
886 return msaaSampleCount;
887}
888
893
894// must be called on the main thread
896{
897 QOffscreenSurface *offscreenSurface = nullptr;
898#if QT_CONFIG(opengl)
899 if (rhiBackend() == QRhi::OpenGLES2) {
900 const QSurfaceFormat format = window->requestedFormat();
901 offscreenSurface = QRhiGles2InitParams::newFallbackSurface(format);
902 }
903#else
905#endif
906 return offscreenSurface;
907}
908
910{
911#if QT_CONFIG(vulkan)
912 if (rhiBackend() == QRhi::Vulkan) {
914 // QQuickWindows must get a QVulkanInstance automatically (it is
915 // created when the first window is constructed and is destroyed only
916 // on exit), unless the application decided to set its own. With
917 // QQuickRenderControl, no QVulkanInstance is created, because it must
918 // always be under the application's control then (since the default
919 // instance we could create here would not be configurable by the
920 // application in any way, and that is often not acceptable).
921 if (!window->vulkanInstance() && !wd->renderControl) {
922 QVulkanInstance *vkinst = QVulkanDefaultInstance::instance();
923 if (vkinst)
924 qCDebug(QSG_LOG_INFO) << "Got Vulkan instance from QVulkanDefaultInstance, requested api version was" << vkinst->apiVersion();
925 else
926 qCDebug(QSG_LOG_INFO) << "No Vulkan instance from QVulkanDefaultInstance, expect problems";
927 window->setVulkanInstance(vkinst);
928 }
929 }
930#else
932#endif
933}
934
935static inline bool ensureWritableDir(const QString &name)
936{
937 QDir::root().mkpath(name);
938 return QFileInfo(name).isWritable();
939}
940
942{
943 static bool checked = false;
944 static QString currentCacheDir;
945 static bool cacheWritable = false;
946
947 if (checked)
948 return cacheWritable ? currentCacheDir : QString();
949
950 checked = true;
951
952 // Intentionally not using the global cache path (GenericCacheLocation) -
953 // we do not want forever growing pipeline cache files that contain
954 // everything from all Qt apps ever run (that would affect load times
955 // eventually, resource use, etc.). Stick to being application-specific.
956
958 const QString subPath = QLatin1String("/qtpipelinecache-") + QSysInfo::buildAbi() + QLatin1Char('/');
959
960 if (!cachePath.isEmpty()) {
961 currentCacheDir = cachePath + subPath;
962 cacheWritable = ensureWritableDir(currentCacheDir);
963 }
964
965 return cacheWritable ? currentCacheDir : QString();
966}
967
969{
970 const QString cacheDir = automaticPipelineCacheDir();
971 if (!cacheDir.isEmpty())
972 return cacheDir + QLatin1String("qqpc_") + QString::fromLatin1(rhi->backendName()).toLower();
973
974 return QString();
975}
976
977static inline bool isAutomaticPipelineCacheLoadSkippedForWindow(Qt::WindowFlags wflags)
978{
979 return wflags.testFlag(Qt::ToolTip) || wflags.testFlag(Qt::SplashScreen);
980}
981
982static inline bool isAutomaticPipelineCacheSaveSkippedForWindow(Qt::WindowFlags wflags)
983{
984 // this catches Tool, ToolTip, SplashScreen as well
985 return wflags.testFlag(Qt::Dialog) || wflags.testFlag(Qt::Popup);
986}
987
989{
990 return name + QLatin1String(".lck");
991}
992
993void QSGRhiSupport::preparePipelineCache(QRhi *rhi, QQuickWindow *window)
994{
996
997 // the explicitly set filename always takes priority as per docs
998 QString pipelineCacheLoad = wd->graphicsConfig.pipelineCacheLoadFile();
999 bool isAutomatic = false;
1000 if (pipelineCacheLoad.isEmpty() && wd->graphicsConfig.isAutomaticPipelineCacheEnabled()) {
1002 pipelineCacheLoad = automaticPipelineCacheFileName(rhi);
1003 isAutomatic = true;
1004 }
1005 }
1006
1007 if (pipelineCacheLoad.isEmpty())
1008 return;
1009
1010 QLockFile lock(pipelineCacheLockFileName(pipelineCacheLoad));
1011 if (!lock.lock()) {
1012 qWarning("Could not create pipeline cache lock file '%s'",
1013 qPrintable(lock.fileName()));
1014 return;
1015 }
1016
1017 QFile f(pipelineCacheLoad);
1018 if (!f.open(QIODevice::ReadOnly)) {
1019 if (!isAutomatic) {
1020 qWarning("Could not open pipeline cache source file '%s'",
1021 qPrintable(pipelineCacheLoad));
1022 }
1023 return;
1024 }
1025
1026 const QByteArray buf = f.readAll();
1027 if (!buf.isEmpty()) {
1028 qCDebug(QSG_LOG_INFO, "Attempting to seed pipeline cache for QRhi %p from '%s'",
1029 rhi, qPrintable(pipelineCacheLoad));
1031 }
1032}
1033
1034void QSGRhiSupport::finalizePipelineCache(QRhi *rhi, const QQuickGraphicsConfiguration &config)
1035{
1036 // output the rhi statistics about pipelines, as promised by the documentation
1037 qCDebug(QSG_LOG_INFO, "Total time spent on pipeline creation during the lifetime of the QRhi %p was %lld ms",
1039
1040 // the explicitly set filename always takes priority as per docs
1041 QString pipelineCacheSave = config.pipelineCacheSaveFile();
1042 bool isAutomatic = false;
1043 if (pipelineCacheSave.isEmpty() && config.isAutomaticPipelineCacheEnabled()) {
1044 pipelineCacheSave = automaticPipelineCacheFileName(rhi);
1045 isAutomatic = true;
1046 }
1047
1048 if (pipelineCacheSave.isEmpty())
1049 return;
1050
1051 const QByteArray buf = rhi->pipelineCacheData();
1052
1053 // If empty, do nothing. This is exactly what will happen if the rhi was
1054 // created without QRhi::EnablePipelineCacheDataSave set.
1055 if (buf.isEmpty()) {
1056 if (isAutomatic) {
1057 // Attempt to remove the file. If it does not exist or this fails,
1058 // that's fine. The goal is just to prevent warnings from
1059 // setPipelineCacheData in future runs, e.g. if the Qt or driver
1060 // version does not match _and_ we do not generate any data at run
1061 // time, then not writing the file out also means the warning would
1062 // appear again and again on every run. Prevent that.
1063 QDir().remove(pipelineCacheSave);
1064 }
1065 return;
1066 }
1067
1068 QLockFile lock(pipelineCacheLockFileName(pipelineCacheSave));
1069 if (!lock.lock()) {
1070 qWarning("Could not create pipeline cache lock file '%s'",
1071 qPrintable(lock.fileName()));
1072 return;
1073 }
1074
1075#if QT_CONFIG(temporaryfile)
1076 QSaveFile f(pipelineCacheSave);
1077#else
1078 QFile f(pipelineCacheSave);
1079#endif
1081 if (!isAutomatic) {
1082 const QString msg = f.errorString();
1083 qWarning("Could not open pipeline cache output file '%s': %s",
1084 qPrintable(pipelineCacheSave), qPrintable(msg));
1085 }
1086 return;
1087 }
1088
1089 qCDebug(QSG_LOG_INFO, "Writing pipeline cache contents (%d bytes) for QRhi %p to '%s'",
1090 int(buf.size()), rhi, qPrintable(pipelineCacheSave));
1091
1092 if (f.write(buf) != buf.size()
1093#if QT_CONFIG(temporaryfile)
1094 || !f.commit()
1095#endif
1096 )
1097 {
1098 if (!isAutomatic) {
1099 const QString msg = f.errorString();
1100 qWarning("Could not write pipeline cache: %s", qPrintable(msg));
1101 }
1102 return;
1103 }
1104}
1105
1106// must be called on the render thread
1108{
1109 QRhi *rhi = nullptr;
1112 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Rhi) {
1113 rhi = customDevD->u.rhi;
1114 if (rhi) {
1115 preparePipelineCache(rhi, window);
1116 return { rhi, false };
1117 }
1118 }
1119
1120 const bool debugLayer = wd->graphicsConfig.isDebugLayerEnabled();
1121 const bool debugMarkers = wd->graphicsConfig.isDebugMarkersEnabled();
1122 const bool timestamps = wd->graphicsConfig.timestampsEnabled();
1123 const bool preferSoftware = wd->graphicsConfig.prefersSoftwareDevice() || forcePreferSwRenderer;
1124 const bool pipelineCacheSave = !wd->graphicsConfig.pipelineCacheSaveFile().isEmpty()
1127
1129 qCDebug(QSG_LOG_INFO,
1130 "Creating QRhi with backend %s for window %p (wflags 0x%X)\n"
1131 " Graphics API debug/validation layers: %d\n"
1132 " Debug markers: %d\n"
1133 " Timestamps: %d\n"
1134 " Prefer software device: %d%s\n"
1135 " Shader/pipeline cache collection: %d",
1136 qPrintable(backendName), window, int(window->flags()), debugLayer,
1137 debugMarkers, timestamps, preferSoftware, forcePreferSwRenderer ? " [FORCED]" : "", pipelineCacheSave);
1138
1139 QRhi::Flags flags;
1141 if (debugMarkers)
1143 if (timestamps)
1145 if (preferSoftware)
1147 if (pipelineCacheSave)
1149
1150 const QRhi::Implementation backend = rhiBackend();
1151 if (backend == QRhi::Null) {
1152 QRhiNullInitParams rhiParams;
1153 rhi = QRhi::create(backend, &rhiParams, flags);
1154 }
1155#if QT_CONFIG(opengl)
1156 if (backend == QRhi::OpenGLES2) {
1157 const QSurfaceFormat format = window->requestedFormat();
1158 QRhiGles2InitParams rhiParams;
1159 rhiParams.format = format;
1160 rhiParams.fallbackSurface = offscreenSurface;
1161 rhiParams.window = window;
1162 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::OpenGLContext) {
1163 QRhiGles2NativeHandles importDev;
1164 importDev.context = customDevD->u.context;
1165 qCDebug(QSG_LOG_INFO, "Using existing QOpenGLContext %p", importDev.context);
1166 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1167 } else {
1168 rhi = QRhi::create(backend, &rhiParams, flags);
1169 }
1170 }
1171#else
1172 Q_UNUSED(offscreenSurface);
1173 if (backend == QRhi::OpenGLES2)
1174 qWarning("OpenGL was requested for Qt Quick, but this build of Qt has no OpenGL support.");
1175#endif
1176#if QT_CONFIG(vulkan)
1177 if (backend == QRhi::Vulkan) {
1178 if (debugLayer)
1179 QVulkanDefaultInstance::setFlag(QVulkanDefaultInstance::EnableValidation, true);
1180 QRhiVulkanInitParams rhiParams;
1181 prepareWindowForRhi(window); // sets a vulkanInstance if not yet present
1182 rhiParams.inst = window->vulkanInstance();
1183 if (!rhiParams.inst)
1184 qWarning("No QVulkanInstance set for QQuickWindow, this is wrong.");
1185 if (window->handle()) // only used for vkGetPhysicalDeviceSurfaceSupportKHR and that implies having a valid native window
1186 rhiParams.window = window;
1187 rhiParams.deviceExtensions = wd->graphicsConfig.deviceExtensions();
1188 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceObjects) {
1189 QRhiVulkanNativeHandles importDev;
1190 importDev.physDev = reinterpret_cast<VkPhysicalDevice>(customDevD->u.deviceObjects.physicalDevice);
1191 importDev.dev = reinterpret_cast<VkDevice>(customDevD->u.deviceObjects.device);
1192 importDev.gfxQueueFamilyIdx = customDevD->u.deviceObjects.queueFamilyIndex;
1193 importDev.gfxQueueIdx = customDevD->u.deviceObjects.queueIndex;
1194 qCDebug(QSG_LOG_INFO, "Using existing native Vulkan physical device %p device %p graphics queue family index %d",
1195 importDev.physDev, importDev.dev, importDev.gfxQueueFamilyIdx);
1196 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1197 } else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::PhysicalDevice) {
1198 QRhiVulkanNativeHandles importDev;
1199 importDev.physDev = reinterpret_cast<VkPhysicalDevice>(customDevD->u.physicalDevice.physicalDevice);
1200 qCDebug(QSG_LOG_INFO, "Using existing native Vulkan physical device %p", importDev.physDev);
1201 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1202 } else {
1203 rhi = QRhi::create(backend, &rhiParams, flags);
1204 }
1205 }
1206#else
1207 if (backend == QRhi::Vulkan)
1208 qWarning("Vulkan was requested for Qt Quick, but this build of Qt has no Vulkan support.");
1209#endif
1210#ifdef Q_OS_WIN
1211 if (backend == QRhi::D3D11) {
1212 QRhiD3D11InitParams rhiParams;
1213 rhiParams.enableDebugLayer = debugLayer;
1214 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndContext) {
1215 QRhiD3D11NativeHandles importDev;
1216 importDev.dev = customDevD->u.deviceAndContext.device;
1217 importDev.context = customDevD->u.deviceAndContext.context;
1218 qCDebug(QSG_LOG_INFO, "Using existing native D3D11 device %p and context %p",
1219 importDev.dev, importDev.context);
1220 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1221 } else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Adapter) {
1222 QRhiD3D11NativeHandles importDev;
1223 importDev.adapterLuidLow = customDevD->u.adapter.luidLow;
1224 importDev.adapterLuidHigh = customDevD->u.adapter.luidHigh;
1225 importDev.featureLevel = customDevD->u.adapter.featureLevel;
1226 qCDebug(QSG_LOG_INFO, "Using D3D11 adapter LUID %u, %d and feature level %d",
1227 importDev.adapterLuidLow, importDev.adapterLuidHigh, importDev.featureLevel);
1228 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1229 } else {
1230 rhi = QRhi::create(backend, &rhiParams, flags);
1232 qCDebug(QSG_LOG_INFO, "Failed to create a D3D device with default settings; "
1233 "attempting to get a software rasterizer backed device instead");
1235 rhi = QRhi::create(backend, &rhiParams, flags);
1236 }
1237 }
1238 } else if (backend == QRhi::D3D12) {
1239 QRhiD3D12InitParams rhiParams;
1240 rhiParams.enableDebugLayer = debugLayer;
1241 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndContext) {
1242 QRhiD3D12NativeHandles importDev;
1243 importDev.dev = customDevD->u.deviceAndContext.device;
1244 qCDebug(QSG_LOG_INFO, "Using existing native D3D12 device %p", importDev.dev);
1245 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1246 } else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Adapter) {
1247 QRhiD3D12NativeHandles importDev;
1248 importDev.adapterLuidLow = customDevD->u.adapter.luidLow;
1249 importDev.adapterLuidHigh = customDevD->u.adapter.luidHigh;
1250 importDev.minimumFeatureLevel = customDevD->u.adapter.featureLevel;
1251 qCDebug(QSG_LOG_INFO, "Using D3D12 adapter LUID %u, %d and minimum feature level %d",
1252 importDev.adapterLuidLow, importDev.adapterLuidHigh, importDev.minimumFeatureLevel);
1253 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1254 } else {
1255 rhi = QRhi::create(backend, &rhiParams, flags);
1257 qCDebug(QSG_LOG_INFO, "Failed to create a D3D device with default settings; "
1258 "attempting to get a software rasterizer backed device instead");
1260 rhi = QRhi::create(backend, &rhiParams, flags);
1261 }
1262 }
1263 }
1264#endif
1265#if QT_CONFIG(metal)
1266 if (backend == QRhi::Metal) {
1267 QRhiMetalInitParams rhiParams;
1268 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndCommandQueue) {
1269 QRhiMetalNativeHandles importDev;
1270 importDev.dev = (MTLDevice *) customDevD->u.deviceAndCommandQueue.device;
1271 importDev.cmdQueue = (MTLCommandQueue *) customDevD->u.deviceAndCommandQueue.cmdQueue;
1272 qCDebug(QSG_LOG_INFO, "Using existing native Metal device %p and command queue %p",
1273 importDev.dev, importDev.cmdQueue);
1274 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1275 } else {
1276 rhi = QRhi::create(backend, &rhiParams, flags);
1277 }
1278 }
1279#endif
1280
1281 if (rhi) {
1282 qCDebug(QSG_LOG_INFO, "Created QRhi %p for window %p", rhi, window);
1283 preparePipelineCache(rhi, window);
1284 } else {
1285 qWarning("Failed to create RHI (backend %d)", backend);
1286 }
1287
1288 return { rhi, true };
1289}
1290
1292{
1293 if (!rhi)
1294 return;
1295
1296 if (!rhi->isDeviceLost())
1297 finalizePipelineCache(rhi, config);
1298
1299 delete rhi;
1300}
1301
1303{
1304 Q_ASSERT(rhi->isRecordingFrame());
1305
1307 QRhiReadbackDescription readbackDesc(src); // null src == read from swapchain backbuffer
1308 QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
1309 resourceUpdates->readBackTexture(readbackDesc, &result);
1310
1311 cb->resourceUpdate(resourceUpdates);
1312 rhi->finish(); // make sure the readback has finished, stall the pipeline if needed
1313
1314 // May be RGBA or BGRA. Plus premultiplied alpha.
1315 QImage::Format imageFormat;
1316 if (result.format == QRhiTexture::BGRA8) {
1317#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1319#else
1321 // ### and should swap too
1322#endif
1323 } else {
1325 }
1326
1327 const uchar *p = reinterpret_cast<const uchar *>(result.data.constData());
1328 const QImage img(p, result.pixelSize.width(), result.pixelSize.height(), imageFormat);
1329
1330 if (rhi->isYUpInFramebuffer())
1331 return img.mirrored();
1332
1333 return img.copy();
1334}
1335
1337{
1338 // Set up and then tear down the entire rendering infrastructure. This
1339 // function is called on the gui/main thread - but that's alright because
1340 // there is no onscreen rendering initialized at this point (so no render
1341 // thread for instance).
1342
1344 // It is expected that window is not using QQuickRenderControl, i.e. it is
1345 // a normal QQuickWindow that just happens to be not exposed.
1346 Q_ASSERT(!wd->renderControl);
1347
1348 QScopedPointer<QOffscreenSurface> offscreenSurface(maybeCreateOffscreenSurface(window));
1349 RhiCreateResult rhiResult = createRhi(window, offscreenSurface.data());
1350 if (!rhiResult.rhi) {
1351 qWarning("Failed to initialize QRhi for offscreen readback");
1352 return QImage();
1353 }
1354 std::unique_ptr<QRhi> rhiOwner(rhiResult.rhi);
1355 QRhi *rhi = rhiResult.own ? rhiOwner.get() : rhiOwner.release();
1356
1357 const QSize pixelSize = window->size() * window->devicePixelRatio();
1358 QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, pixelSize, 1,
1360 if (!texture->create()) {
1361 qWarning("Failed to build texture for offscreen readback");
1362 return QImage();
1363 }
1364 QScopedPointer<QRhiRenderBuffer> depthStencil(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, 1));
1365 if (!depthStencil->create()) {
1366 qWarning("Failed to create depth/stencil buffer for offscreen readback");
1367 return QImage();
1368 }
1370 rtDesc.setDepthStencilBuffer(depthStencil.data());
1371 QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
1372 QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
1373 rt->setRenderPassDescriptor(rpDesc.data());
1374 if (!rt->create()) {
1375 qWarning("Failed to build render target for offscreen readback");
1376 return QImage();
1377 }
1378
1379 wd->rhi = rhi;
1380
1382 params.rhi = rhi;
1383 params.sampleCount = 1;
1384 params.initialSurfacePixelSize = pixelSize;
1385 params.maybeSurface = window;
1386 wd->context->initialize(&params);
1387
1388 // There was no rendercontrol which means a custom render target
1389 // should not be set either. Set our own, temporarily.
1390 window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(rt.data()));
1391
1392 QRhiCommandBuffer *cb = nullptr;
1394 qWarning("Failed to start recording the frame for offscreen readback");
1395 return QImage();
1396 }
1397
1399 wd->polishItems();
1400 wd->syncSceneGraph();
1401 wd->renderSceneGraph();
1402 wd->setCustomCommandBuffer(nullptr);
1403
1405 rhi->endOffscreenFrame();
1406
1407 image.setDevicePixelRatio(window->devicePixelRatio());
1409 wd->context->invalidate();
1410
1411 window->setRenderTarget(QQuickRenderTarget());
1412 wd->rhi = nullptr;
1413
1414 return image;
1415}
1416
1417#ifdef Q_OS_WEBOS
1418QImage QSGRhiSupport::grabOffscreenForProtectedContent(QQuickWindow *window)
1419{
1420 // If a context is created for protected content, grabbing GPU
1421 // resources are restricted. For the case, normal context
1422 // and surface are needed to allow CPU access.
1423 // So dummy offscreen window is used here
1424 // This function is called in rendering thread.
1425
1426 QScopedPointer<QQuickWindow> offscreenWindow;
1428 // It is expected that window is not using QQuickRenderControl, i.e. it is
1429 // a normal QQuickWindow that just happens to be not exposed.
1430 Q_ASSERT(!wd->renderControl);
1431
1432 // If context and surface are created for protected content,
1433 // CPU can't read the frame resources. So normal context and surface are needed.
1434 if (window->requestedFormat().testOption(QSurfaceFormat::ProtectedContent)) {
1435 QSurfaceFormat surfaceFormat = window->requestedFormat();
1436 surfaceFormat.setOption(QSurfaceFormat::ProtectedContent, false);
1437 offscreenWindow.reset(new QQuickWindow());
1438 offscreenWindow->setFormat(surfaceFormat);
1439 }
1440
1441 QScopedPointer<QOffscreenSurface> offscreenSurface(maybeCreateOffscreenSurface(window));
1442 RhiCreateResult rhiResult = createRhi(offscreenWindow.data() ? offscreenWindow.data() : window, offscreenSurface.data());
1443 if (!rhiResult.rhi) {
1444 qWarning("Failed to initialize QRhi for offscreen readback");
1445 return QImage();
1446 }
1447 QScopedPointer<QRhi> rhiOwner(rhiResult.rhi);
1448 QRhi *rhi = rhiResult.own ? rhiOwner.data() : rhiOwner.take();
1449
1450 const QSize pixelSize = window->size() * window->devicePixelRatio();
1451 QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, pixelSize, 1,
1453 if (!texture->create()) {
1454 qWarning("Failed to build texture for offscreen readback");
1455 return QImage();
1456 }
1457 QScopedPointer<QRhiRenderBuffer> depthStencil(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, 1));
1458 if (!depthStencil->create()) {
1459 qWarning("Failed to create depth/stencil buffer for offscreen readback");
1460 return QImage();
1461 }
1463 rtDesc.setDepthStencilBuffer(depthStencil.data());
1464 QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
1465 QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
1466 rt->setRenderPassDescriptor(rpDesc.data());
1467 if (!rt->create()) {
1468 qWarning("Failed to build render target for offscreen readback");
1469 return QImage();
1470 }
1471
1472 // Backup the original Rhi
1473 QRhi *currentRhi = wd->rhi;
1474 wd->rhi = rhi;
1475
1477 params.rhi = rhi;
1478 params.sampleCount = 1;
1479 params.initialSurfacePixelSize = pixelSize;
1480 params.maybeSurface = window;
1481 wd->context->initialize(&params);
1482
1483 // Backup the original RenderTarget
1484 QQuickRenderTarget currentRenderTarget = window->renderTarget();
1485 // There was no rendercontrol which means a custom render target
1486 // should not be set either. Set our own, temporarily.
1487 window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(rt.data()));
1488
1489 QRhiCommandBuffer *cb = nullptr;
1491 qWarning("Failed to start recording the frame for offscreen readback");
1492 return QImage();
1493 }
1494
1496 wd->polishItems();
1497 wd->syncSceneGraph();
1498 wd->renderSceneGraph();
1499 wd->setCustomCommandBuffer(nullptr);
1500
1502 rhi->endOffscreenFrame();
1503
1504 image.setDevicePixelRatio(window->devicePixelRatio());
1505
1506 // Called from gui/main thread on no onscreen rendering initialized
1507 if (!currentRhi) {
1509 wd->context->invalidate();
1510
1511 window->setRenderTarget(QQuickRenderTarget());
1512 wd->rhi = nullptr;
1513 } else {
1514 // Called from rendering thread for protected content
1515 // Restore to original Rhi, RenderTarget and Context
1516 window->setRenderTarget(currentRenderTarget);
1517 wd->rhi = currentRhi;
1518 params.rhi = currentRhi;
1519 wd->context->initialize(&params);
1520 }
1521
1522 return image;
1523}
1524#endif
1525
1527{
1528 Q_ASSERT(scWithWindowSet->window() == window);
1529
1530 QRhiSwapChain::Format swapChainFormat = QRhiSwapChain::SDR;
1531
1532 QByteArray hdrRequest = qgetenv("QSG_RHI_HDR");
1533 if (hdrRequest.isEmpty())
1534 hdrRequest = window->property("_qt_sg_hdr_format").toByteArray();
1535
1536 if (!hdrRequest.isEmpty()) {
1537 hdrRequest = hdrRequest.toLower();
1538 if (hdrRequest == QByteArrayLiteral("scrgb") || hdrRequest == QByteArrayLiteral("extendedsrgblinear"))
1539 swapChainFormat = QRhiSwapChain::HDRExtendedSrgbLinear;
1540 else if (hdrRequest == QByteArrayLiteral("hdr10"))
1541 swapChainFormat = QRhiSwapChain::HDR10;
1542 else if (hdrRequest == QByteArrayLiteral("p3"))
1544 }
1545
1546 const char *fmtStr = "unknown";
1547 switch (swapChainFormat) {
1548 case QRhiSwapChain::SDR:
1549 fmtStr = "SDR";
1550 break;
1552 fmtStr = "scRGB";
1553 break;
1555 fmtStr = "HDR10";
1556 break;
1558 fmtStr = "Extended Linear Display P3";
1559 break;
1560 default:
1561 break;
1562 }
1563
1564 if (!scWithWindowSet->isFormatSupported(swapChainFormat)) {
1565 if (swapChainFormat != QRhiSwapChain::SDR) {
1566 qCDebug(QSG_LOG_INFO, "Requested a %s swapchain but it is reported to be unsupported with the current display(s). "
1567 "In multi-screen configurations make sure the window is located on a HDR-enabled screen. "
1568 "Request ignored, using SDR swapchain.", fmtStr);
1569 }
1570 return;
1571 }
1572
1573 scWithWindowSet->setFormat(swapChainFormat);
1574
1575 if (swapChainFormat != QRhiSwapChain::SDR) {
1576 qCDebug(QSG_LOG_INFO, "Creating %s swapchain", fmtStr);
1577 qCDebug(QSG_LOG_INFO) << "HDR output info:" << scWithWindowSet->hdrInfo();
1578 }
1579}
1580
1581QRhiTexture::Format QSGRhiSupport::toRhiTextureFormat(uint nativeFormat, QRhiTexture::Flags *flags) const
1582{
1583 switch (m_rhiBackend) {
1584#if QT_CONFIG(vulkan)
1585 case QRhi::Vulkan:
1586 return toRhiTextureFormatFromVulkan(nativeFormat, flags);
1587#endif
1588#if QT_CONFIG(opengl)
1589 case QRhi::OpenGLES2:
1590 Q_UNUSED(flags);
1591 return toRhiTextureFormatFromGL(nativeFormat, flags);
1592#endif
1593#ifdef Q_OS_WIN
1594 case QRhi::D3D11:
1595 case QRhi::D3D12:
1596 return toRhiTextureFormatFromDXGI(nativeFormat, flags);
1597#endif
1598#if QT_CONFIG(metal)
1599 case QRhi::Metal:
1600 return toRhiTextureFormatFromMetal(nativeFormat, flags);
1601#endif
1602 default:
1604 }
1605 Q_UNUSED(nativeFormat)
1607}
1608
1610{
1611 const QRhi::Implementation backend = rhiBackend();
1612
1613 // On Windows it makes sense to retry using a software adapter whenever
1614 // device creation or swapchain creation fails, as WARP is usually available
1615 // (built in to the OS) and is good quality. This helps a lot in particular
1616 // when running in a VM that cripples proper 3D graphics.
1617 if (backend == QRhi::D3D11 || backend == QRhi::D3D12)
1618 return true;
1619
1620 return false;
1621}
1622
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qdir.h:20
bool remove(const QString &fileName)
Removes the file, fileName.
Definition qdir.cpp:1898
static QDir root()
Returns the root directory.
Definition qdir.h:224
bool isWritable() const
Returns true if the user can write to the file system entry this QFileInfo refers to; otherwise retur...
\inmodule QtCore
Definition qfile.h:93
\inmodule QtGui
Definition qimage.h:37
Format
The following image formats are available in Qt.
Definition qimage.h:41
@ Format_RGBA8888_Premultiplied
Definition qimage.h:60
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
\inmodule QtCore
Definition qlockfile.h:17
\inmodule QtCore
\inmodule QtGui
QQuickGraphicsConfiguration controls lower level graphics settings for the QQuickWindow.
static QQuickGraphicsDevicePrivate * get(QQuickGraphicsDevice *p)
The QQuickRenderTarget class provides an opaque container for native graphics resources specifying a ...
static QQuickRenderTarget fromRhiRenderTarget(QRhiRenderTarget *renderTarget)
QQuickGraphicsConfiguration graphicsConfig
static QQuickWindowPrivate * get(QQuickWindow *c)
QSGRenderContext * context
QQuickRenderControl * renderControl
void setCustomCommandBuffer(QRhiCommandBuffer *cb)
QQuickGraphicsDevice customDeviceObjects
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtGui
Definition qrhi.h:1651
\inmodule QtGui
\variable QRhiD3D11InitParams::enableDebugLayer
\inmodule QtGui
\variable QRhiGles2InitParams::format
\variable QRhiMetalNativeHandles::dev
\inmodule QtRhi
\inmodule QtRhi
\inmodule QtGui
Definition qrhi.h:777
\inmodule QtGui
Definition qrhi.h:1142
virtual const QRhiNativeHandles * nativeHandles()
Definition qrhi.cpp:4952
\inmodule QtGui
Definition qrhi.h:1731
void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
Enqueues a texture-to-host copy operation as described by rb.
Definition qrhi.cpp:9186
\inmodule QtGui
Definition qrhi.h:1549
Format
Describes the swapchain format.
Definition qrhi.h:1561
@ HDRExtendedSrgbLinear
Definition qrhi.h:1563
@ HDRExtendedDisplayP3Linear
Definition qrhi.h:1565
\inmodule QtGui
Definition qrhi.h:895
@ UsedAsTransferSource
Definition qrhi.h:902
@ RenderTarget
Definition qrhi.h:898
Format
Specifies the texture format.
Definition qrhi.h:914
@ ASTC_10x8
Definition qrhi.h:959
@ ASTC_12x12
Definition qrhi.h:962
@ ASTC_8x5
Definition qrhi.h:954
@ ASTC_10x5
Definition qrhi.h:957
@ RGBA32F
Definition qrhi.h:926
@ ETC2_RGBA8
Definition qrhi.h:947
@ ASTC_5x5
Definition qrhi.h:951
@ ASTC_4x4
Definition qrhi.h:949
@ ASTC_6x6
Definition qrhi.h:953
@ ASTC_12x10
Definition qrhi.h:961
@ ETC2_RGB8
Definition qrhi.h:945
@ ASTC_5x4
Definition qrhi.h:950
@ RED_OR_ALPHA8
Definition qrhi.h:923
@ ASTC_6x5
Definition qrhi.h:952
@ ASTC_8x8
Definition qrhi.h:956
@ RGBA16F
Definition qrhi.h:925
@ RGB10A2
Definition qrhi.h:930
@ ASTC_10x6
Definition qrhi.h:958
@ ASTC_10x10
Definition qrhi.h:960
@ UnknownFormat
Definition qrhi.h:915
@ ETC2_RGB8A1
Definition qrhi.h:946
@ ASTC_8x6
Definition qrhi.h:955
\variable QRhiVulkanNativeHandles::physDev
\inmodule QtGui
\variable QRhiVulkanInitParams::inst
\variable QRhiVulkanCommandBufferNativeHandles::commandBuffer
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
FrameOpResult endOffscreenFrame(EndFrameFlags flags={})
Ends, submits, and waits for the offscreen frame.
Definition qrhi.cpp:10912
QRhiStats statistics() const
Gathers and returns statistics about the timings and allocations of graphics resources.
Definition qrhi.cpp:10456
bool isYUpInFramebuffer() const
Definition qrhi.cpp:10030
QList< int > supportedSampleCounts() const
Definition qrhi.cpp:10953
QRhiRenderBuffer * newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount=1, QRhiRenderBuffer::Flags flags={}, QRhiTexture::Format backingFormatHint=QRhiTexture::UnknownFormat)
Definition qrhi.cpp:10535
Implementation
Describes which graphics API-specific backend gets used by a QRhi instance.
Definition qrhi.h:1806
@ Metal
Definition qrhi.h:1811
@ Vulkan
Definition qrhi.h:1808
@ Null
Definition qrhi.h:1807
@ D3D11
Definition qrhi.h:1810
@ D3D12
Definition qrhi.h:1812
@ OpenGLES2
Definition qrhi.h:1809
QRhi::FrameOpResult finish()
Waits for any work on the graphics queue (where applicable) to complete, then executes all deferred o...
Definition qrhi.cpp:10936
FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, BeginFrameFlags flags={})
Starts a new offscreen frame.
Definition qrhi.cpp:10893
QRhiTextureRenderTarget * newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags={})
Definition qrhi.cpp:10682
bool isRecordingFrame() const
Definition qrhi.cpp:10802
const char * backendName() const
Definition qrhi.cpp:8683
static bool probe(Implementation impl, QRhiInitParams *params)
Definition qrhi.cpp:8577
static QRhi * create(Implementation impl, QRhiInitParams *params, Flags flags={}, QRhiNativeHandles *importDevice=nullptr)
Definition qrhi.cpp:8491
QByteArray pipelineCacheData()
Definition qrhi.cpp:10271
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10562
void setPipelineCacheData(const QByteArray &data)
Loads data into the pipeline cache, when applicable.
Definition qrhi.cpp:10325
const QRhiNativeHandles * nativeHandles()
Definition qrhi.cpp:10137
QRhiResourceUpdateBatch * nextResourceUpdateBatch()
Definition qrhi.cpp:9252
@ FrameOpSuccess
Definition qrhi.h:1825
bool isDeviceLost() const
Definition qrhi.cpp:10227
@ EnablePipelineCacheDataSave
Definition qrhi.h:1818
@ SuppressSmokeTestWarnings
Definition qrhi.h:1820
@ EnableDebugMarkers
Definition qrhi.h:1816
@ PreferSoftwareRenderer
Definition qrhi.h:1817
@ EnableTimestamps
Definition qrhi.h:1819
QRhiRenderPassDescriptor * currentFrameRenderPass() const
QRhiCommandBuffer * currentFrameCommandBuffer() const
virtual void initialize(const InitParams *params)
virtual void invalidate()
Resource
\value DeviceResource The resource is a pointer to the graphics device, when applicable.
static bool isApiRhiBased(GraphicsApi api)
GraphicsApi
\value Unknown An unknown graphics API is in use \value Software The Qt Quick 2D Renderer is in use \...
QRhiTexture::Format toRhiTextureFormat(uint nativeFormat, QRhiTexture::Flags *flags) const
QOffscreenSurface * maybeCreateOffscreenSurface(QWindow *window)
void applySwapChainFormat(QRhiSwapChain *scWithWindowSet, QQuickWindow *window)
static QSGRhiSupport * instance_internal()
static void checkEnvQSgInfo()
const void * rifResource(QSGRendererInterface::Resource res, const QSGDefaultRenderContext *rc, const QQuickWindow *w)
static int chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi)
bool attemptReinitWithSwRastUponFail() const
QSGRendererInterface::GraphicsApi graphicsApi() const
QSGRendererInterface::GraphicsApi api
void prepareWindowForRhi(QQuickWindow *window)
RhiCreateResult createRhi(QQuickWindow *window, QSurface *offscreenSurface, bool forcePreferSwRenderer=false)
static int chooseSampleCount(int samples, QRhi *rhi)
static QImage grabAndBlockInCurrentFrame(QRhi *rhi, QRhiCommandBuffer *cb, QRhiTexture *src=nullptr)
void configure(QSGRendererInterface::GraphicsApi api)
QRhi::Implementation rhiBackend() const
QImage grabOffscreen(QQuickWindow *window)
void destroyRhi(QRhi *rhi, const QQuickGraphicsConfiguration &config)
QString rhiBackendName() const
static QSGRhiSupport * instance()
QSurface::SurfaceType windowSurfaceType() const
\inmodule QtCore
Definition qsize.h:25
static QString writableLocation(StandardLocation type)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
static QSurfaceFormat defaultFormat()
Returns the global default surface format.
void setOption(FormatOption option, bool on=true)
\inmodule QtGui
Definition qsurface.h:21
SurfaceType
The SurfaceType enum describes what type of surface this is.
Definition qsurface.h:30
@ OpenGLSurface
Definition qsurface.h:32
@ MetalSurface
Definition qsurface.h:36
@ VulkanSurface
Definition qsurface.h:35
@ Direct3DSurface
Definition qsurface.h:37
static QString buildAbi()
Definition qsysinfo.cpp:657
The QVulkanInstance class represents a native Vulkan instance, enabling Vulkan rendering onto a QSurf...
\inmodule QtGui
Definition qwindow.h:63
QRhiTexture::Format toRhiTextureFormatFromMetal(uint format, QRhiTexture::Flags *flags)
Combined button and popup list for selecting options.
@ ToolTip
Definition qnamespace.h:213
@ Popup
Definition qnamespace.h:211
@ SplashScreen
Definition qnamespace.h:214
@ Dialog
Definition qnamespace.h:208
Definition image.cpp:4
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define Q_FALLTHROUGH()
static const QPainterPath::ElementType * subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end, const qreal *points, bool *closed)
EGLConfig config
static QString backendName
@ QtDebugMsg
Definition qlogging.h:30
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLsizei samples
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum src
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLenum GLuint texture
GLuint name
GLint GLsizei GLsizei GLenum format
void ** params
#define GL_DEPTH_COMPONENT32F
Definition qopenglext.h:994
GLuint res
#define GL_DEPTH24_STENCIL8
#define GL_DEPTH_COMPONENT16
Definition qopenglext.h:328
#define GL_R16
#define GL_RG16
#define GL_R8
GLint void * img
Definition qopenglext.h:233
#define GL_RGBA16F
Definition qopenglext.h:913
#define GL_RG8
#define GL_BGRA
Definition qopenglext.h:97
#define GL_SRGB_ALPHA
Definition qopenglext.h:864
#define GL_R32F
#define GL_SRGB8_ALPHA8
Definition qopenglext.h:865
#define GL_RG
#define GL_R16F
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define GL_DEPTH_STENCIL
#define GL_RGBA32F
Definition qopenglext.h:911
#define GL_DEPTH_COMPONENT24
Definition qopenglext.h:329
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define GL_RGBA8
#define GL_RED
static QString pipelineCacheLockFileName(const QString &name)
static bool isAutomaticPipelineCacheLoadSkippedForWindow(Qt::WindowFlags wflags)
static QString automaticPipelineCacheDir()
static bool ensureWritableDir(const QString &name)
static QString automaticPipelineCacheFileName(QRhi *rhi)
static bool isAutomaticPipelineCacheSaveSkippedForWindow(Qt::WindowFlags wflags)
#define GL_RGBA
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define qPrintable(string)
Definition qstring.h:1531
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QT_CONFIG(feature)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
unsigned int uint
Definition qtypes.h:34
QReadWriteLock lock
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QNetworkRequestFactory api
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
\variable QRhiReadbackResult::completed
Definition qrhi.h:800
\inmodule QtGui
\inmodule QtGui
Definition qrhi.h:1723
qint64 totalPipelineCreationTime
Definition qrhi.h:1783