9#include <QtQuick/private/qquickitem_p.h>
10#include <QtQuick/private/qquickwindow_p.h>
12#include <QtGui/qwindow.h>
13#include <QtGui/qpa/qplatformintegration.h>
14#include <QtGui/private/qguiapplication_p.h>
17#include <QtGui/private/qvulkandefaultinstance_p.h>
20#include <QOperatingSystemVersion>
23#include <QStandardPaths>
27#include <QOffscreenSurface>
30#include <dxgiformat.h>
37QSGRhiSupport::QSGRhiSupport()
41void QSGRhiSupport::applySettings()
45 m_settingsApplied =
true;
51 QSGRhiSupport::checkEnvQSgInfo();
53 if (m_requested.valid) {
55 switch (m_requested.api) {
56 case QSGRendererInterface::OpenGL:
57 m_rhiBackend = QRhi::OpenGLES2;
59 case QSGRendererInterface::Direct3D11:
60 m_rhiBackend = QRhi::D3D11;
62 case QSGRendererInterface::Direct3D12:
63 m_rhiBackend = QRhi::D3D12;
65 case QSGRendererInterface::Vulkan:
66 m_rhiBackend = QRhi::Vulkan;
68 case QSGRendererInterface::Metal:
69 m_rhiBackend = QRhi::Metal;
71 case QSGRendererInterface::Null:
72 m_rhiBackend = QRhi::Null;
75 Q_ASSERT_X(
false,
"QSGRhiSupport",
"Internal error: unhandled GraphicsApi type");
80 const QByteArray rhiBackend = qgetenv(
"QSG_RHI_BACKEND");
81 if (rhiBackend == QByteArrayLiteral(
"gl")
82 || rhiBackend == QByteArrayLiteral(
"gles2")
83 || rhiBackend == QByteArrayLiteral(
"opengl"))
85 m_rhiBackend = QRhi::OpenGLES2;
86 }
else if (rhiBackend == QByteArrayLiteral(
"d3d11") || rhiBackend == QByteArrayLiteral(
"d3d")) {
87 m_rhiBackend = QRhi::D3D11;
88 }
else if (rhiBackend == QByteArrayLiteral(
"d3d12")) {
89 m_rhiBackend = QRhi::D3D12;
90 }
else if (rhiBackend == QByteArrayLiteral(
"vulkan")) {
91 m_rhiBackend = QRhi::Vulkan;
92 }
else if (rhiBackend == QByteArrayLiteral(
"metal")) {
93 m_rhiBackend = QRhi::Metal;
94 }
else if (rhiBackend == QByteArrayLiteral(
"null")) {
95 m_rhiBackend = QRhi::Null;
97 if (!rhiBackend.isEmpty()) {
98 qWarning(
"Unknown key \"%s\" for QSG_RHI_BACKEND, falling back to default backend.",
99 rhiBackend.constData());
102 m_rhiBackend = QRhi::D3D11;
103#elif QT_CONFIG(metal)
104 m_rhiBackend = QRhi::Metal;
105#elif QT_CONFIG(opengl)
106 m_rhiBackend = QRhi::OpenGLES2;
108 m_rhiBackend = QRhi::Vulkan;
113 adjustToPlatformQuirks();
124void QSGRhiSupport::adjustToPlatformQuirks()
130 if (m_rhiBackend == QRhi::Metal) {
131 QRhiMetalInitParams rhiParams;
132 if (!QRhi::probe(m_rhiBackend, &rhiParams)) {
133 qCDebug(QSG_LOG_INFO,
"Metal does not seem to be supported. Falling back to OpenGL.");
134 m_rhiBackend = QRhi::OpenGLES2;
135 auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
136 if (platformIntegration
137 && !platformIntegration->hasCapability(QPlatformIntegration::OpenGL)) {
138 qCWarning(QSG_LOG_INFO,
"OpenGL not available. Falling back to Null backend.");
139 m_rhiBackend = QRhi::Null;
146void QSGRhiSupport::checkEnvQSgInfo()
149 if (qEnvironmentVariableIsSet(
"QSG_INFO"))
150 const_cast<QLoggingCategory &>(QSG_LOG_INFO()).setEnabled(QtDebugMsg,
true);
153QRhiRenderBuffer::Flags QSGRhiSupport::depthStencilBufferFlags()
155 static const bool noTransientDepthBuffer = qEnvironmentVariableIntValue(
"QSG_NO_TRANSIENT_DEPTH_BUFFER");
156 return noTransientDepthBuffer ? QRhiRenderBuffer::NoTransientBacking : QRhiRenderBuffer::Flags();
162#define GL_BGRA 0x80E1
182#define GL_RG16 0x822C
190#define GL_RGBA8 0x8058
194#define GL_RGBA32F 0x8814
198#define GL_RGBA16F 0x881A
202#define GL_R16F 0x822D
206#define GL_R32F 0x822E
209#ifndef GL_DEPTH_COMPONENT16
210#define GL_DEPTH_COMPONENT16 0x81A5
213#ifndef GL_DEPTH_COMPONENT24
214#define GL_DEPTH_COMPONENT24 0x81A6
217#ifndef GL_DEPTH_COMPONENT32F
218#define GL_DEPTH_COMPONENT32F 0x8CAC
221#ifndef GL_DEPTH24_STENCIL8
222#define GL_DEPTH24_STENCIL8 0x88F0
225#ifndef GL_DEPTH_STENCIL
226#define GL_DEPTH_STENCIL 0x84F9
230#define GL_RGB10_A2 0x8059
234#define GL_SRGB_ALPHA 0x8C42
237#ifndef GL_SRGB8_ALPHA8
238#define GL_SRGB8_ALPHA8 0x8C43
241QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromGL(uint format, QRhiTexture::Flags *flags)
244 auto rhiFormat = QRhiTexture::UnknownFormat;
247 case GL_SRGB8_ALPHA8:
253 rhiFormat = QRhiTexture::RGBA8;
256 rhiFormat = QRhiTexture::BGRA8;
259 rhiFormat = QRhiTexture::R16;
262 rhiFormat = QRhiTexture::RG16;
267 rhiFormat = QRhiTexture::R8;
272 rhiFormat = QRhiTexture::RG8;
275 rhiFormat = QRhiTexture::RED_OR_ALPHA8;
278 rhiFormat = QRhiTexture::RGBA16F;
281 rhiFormat = QRhiTexture::RGBA32F;
284 rhiFormat = QRhiTexture::R16F;
287 rhiFormat = QRhiTexture::R32F;
290 rhiFormat = QRhiTexture::RGB10A2;
292 case GL_DEPTH_COMPONENT:
294 case GL_DEPTH_COMPONENT16:
295 rhiFormat = QRhiTexture::D16;
297 case GL_DEPTH_COMPONENT24:
298 rhiFormat = QRhiTexture::D24;
300 case GL_DEPTH_STENCIL:
302 case GL_DEPTH24_STENCIL8:
303 rhiFormat = QRhiTexture::D24S8;
305 case GL_DEPTH_COMPONENT32F:
306 rhiFormat = QRhiTexture::D32F;
309 qWarning(
"GL format %d is not supported", format);
313 (*flags) |=(QRhiTexture::sRGB);
319QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromVulkan(uint format, QRhiTexture::Flags *flags)
321 auto rhiFormat = QRhiTexture::UnknownFormat;
324 case VK_FORMAT_R8G8B8A8_SRGB:
327 case VK_FORMAT_R8G8B8A8_UNORM:
328 case VK_FORMAT_UNDEFINED:
329 rhiFormat = QRhiTexture::RGBA8;
331 case VK_FORMAT_B8G8R8A8_SRGB:
334 case VK_FORMAT_B8G8R8A8_UNORM:
335 rhiFormat = QRhiTexture::BGRA8;
337 case VK_FORMAT_R8_SRGB:
340 case VK_FORMAT_R8_UNORM:
341 rhiFormat = QRhiTexture::R8;
343 case VK_FORMAT_R8G8_SRGB:
346 case VK_FORMAT_R8G8_UNORM:
347 rhiFormat = QRhiTexture::RG8;
349 case VK_FORMAT_R16_UNORM:
350 rhiFormat = QRhiTexture::R16;
352 case VK_FORMAT_R16G16_UNORM:
353 rhiFormat = QRhiTexture::RG16;
355 case VK_FORMAT_R16G16B16A16_SFLOAT:
356 rhiFormat = QRhiTexture::RGBA16F;
358 case VK_FORMAT_R32G32B32A32_SFLOAT:
359 rhiFormat = QRhiTexture::RGBA32F;
361 case VK_FORMAT_R16_SFLOAT:
362 rhiFormat = QRhiTexture::R16F;
364 case VK_FORMAT_R32_SFLOAT:
365 rhiFormat = QRhiTexture::R32F;
367 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
369 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
370 rhiFormat = QRhiTexture::RGB10A2;
372 case VK_FORMAT_D16_UNORM:
373 rhiFormat = QRhiTexture::D16;
375 case VK_FORMAT_X8_D24_UNORM_PACK32:
376 rhiFormat = QRhiTexture::D24;
378 case VK_FORMAT_D24_UNORM_S8_UINT:
379 rhiFormat = QRhiTexture::D24S8;
381 case VK_FORMAT_D32_SFLOAT:
382 rhiFormat = QRhiTexture::D32F;
384 case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
387 case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
388 rhiFormat = QRhiTexture::BC1;
390 case VK_FORMAT_BC2_SRGB_BLOCK:
393 case VK_FORMAT_BC2_UNORM_BLOCK:
394 rhiFormat = QRhiTexture::BC2;
396 case VK_FORMAT_BC3_SRGB_BLOCK:
399 case VK_FORMAT_BC3_UNORM_BLOCK:
400 rhiFormat = QRhiTexture::BC3;
402 case VK_FORMAT_BC4_UNORM_BLOCK:
403 rhiFormat = QRhiTexture::BC4;
405 case VK_FORMAT_BC5_UNORM_BLOCK:
406 rhiFormat = QRhiTexture::BC5;
408 case VK_FORMAT_BC6H_UFLOAT_BLOCK:
409 rhiFormat = QRhiTexture::BC6H;
411 case VK_FORMAT_BC7_SRGB_BLOCK:
414 case VK_FORMAT_BC7_UNORM_BLOCK:
415 rhiFormat = QRhiTexture::BC7;
417 case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
420 case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
421 rhiFormat = QRhiTexture::ETC2_RGB8;
423 case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
426 case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
427 rhiFormat = QRhiTexture::ETC2_RGB8A1;
429 case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
432 case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
433 rhiFormat = QRhiTexture::ETC2_RGBA8;
435 case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
438 case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
439 rhiFormat = QRhiTexture::ASTC_4x4;
441 case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
444 case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
445 rhiFormat = QRhiTexture::ASTC_5x4;
447 case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
450 case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
451 rhiFormat = QRhiTexture::ASTC_5x5;
453 case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
456 case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
457 rhiFormat = QRhiTexture::ASTC_6x5;
459 case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
462 case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
463 rhiFormat = QRhiTexture::ASTC_6x6;
465 case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
468 case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
469 rhiFormat = QRhiTexture::ASTC_8x5;
471 case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
474 case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
475 rhiFormat = QRhiTexture::ASTC_8x6;
477 case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
480 case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
481 rhiFormat = QRhiTexture::ASTC_8x8;
483 case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
486 case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
487 rhiFormat = QRhiTexture::ASTC_10x5;
489 case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
492 case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
493 rhiFormat = QRhiTexture::ASTC_10x6;
495 case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
498 case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
499 rhiFormat = QRhiTexture::ASTC_10x8;
501 case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
504 case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
505 rhiFormat = QRhiTexture::ASTC_10x10;
507 case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
510 case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
511 rhiFormat = QRhiTexture::ASTC_12x10;
513 case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
516 case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
517 rhiFormat = QRhiTexture::ASTC_12x12;
520 qWarning(
"VkFormat %d is not supported", format);
524 (*flags) |=(QRhiTexture::sRGB);
530QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromDXGI(uint format, QRhiTexture::Flags *flags)
532 auto rhiFormat = QRhiTexture::UnknownFormat;
535 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
538 case DXGI_FORMAT_R8G8B8A8_UNORM:
539 case DXGI_FORMAT_UNKNOWN:
540 rhiFormat = QRhiTexture::RGBA8;
542 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
545 case DXGI_FORMAT_B8G8R8A8_UNORM:
546 rhiFormat = QRhiTexture::BGRA8;
548 case DXGI_FORMAT_R8_UNORM:
549 rhiFormat = QRhiTexture::R8;
551 case DXGI_FORMAT_R8G8_UNORM:
552 rhiFormat = QRhiTexture::RG8;
554 case DXGI_FORMAT_R16_UNORM:
555 rhiFormat = QRhiTexture::R16;
557 case DXGI_FORMAT_R16G16_UNORM:
558 rhiFormat = QRhiTexture::RG16;
560 case DXGI_FORMAT_R16G16B16A16_FLOAT:
561 rhiFormat = QRhiTexture::RGBA16F;
563 case DXGI_FORMAT_R32G32B32A32_FLOAT:
564 rhiFormat = QRhiTexture::RGBA32F;
566 case DXGI_FORMAT_R16_FLOAT:
567 rhiFormat = QRhiTexture::R16F;
569 case DXGI_FORMAT_R32_FLOAT:
570 rhiFormat = QRhiTexture::R32F;
572 case DXGI_FORMAT_R10G10B10A2_UNORM:
573 rhiFormat = QRhiTexture::RGB10A2;
575 case DXGI_FORMAT_R16_TYPELESS:
576 rhiFormat = QRhiTexture::D16;
578 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
579 rhiFormat = QRhiTexture::D24;
581 case DXGI_FORMAT_D24_UNORM_S8_UINT:
582 rhiFormat = QRhiTexture::D24S8;
584 case DXGI_FORMAT_R32_TYPELESS:
585 rhiFormat = QRhiTexture::D32F;
587 case DXGI_FORMAT_BC1_UNORM_SRGB:
590 case DXGI_FORMAT_BC1_UNORM:
591 rhiFormat = QRhiTexture::BC1;
593 case DXGI_FORMAT_BC2_UNORM_SRGB:
596 case DXGI_FORMAT_BC2_UNORM:
597 rhiFormat = QRhiTexture::BC2;
599 case DXGI_FORMAT_BC3_UNORM_SRGB:
602 case DXGI_FORMAT_BC3_UNORM:
603 rhiFormat = QRhiTexture::BC3;
605 case DXGI_FORMAT_BC4_UNORM:
606 rhiFormat = QRhiTexture::BC4;
608 case DXGI_FORMAT_BC5_UNORM:
609 rhiFormat = QRhiTexture::BC5;
611 case DXGI_FORMAT_BC6H_UF16:
612 rhiFormat = QRhiTexture::BC6H;
614 case DXGI_FORMAT_BC7_UNORM_SRGB:
617 case DXGI_FORMAT_BC7_UNORM:
618 rhiFormat = QRhiTexture::BC7;
621 qWarning(
"DXGI_FORMAT %d is not supported", format);
625 (*flags) |=(QRhiTexture::sRGB);
631namespace QSGRhiSupportMac {
632 QRhiTexture::Format toRhiTextureFormatFromMetal(uint format, QRhiTexture::Flags *flags);
634QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromMetal(uint format, QRhiTexture::Flags *flags)
636 return QSGRhiSupportMac::toRhiTextureFormatFromMetal(format, flags);
640void QSGRhiSupport::configure(QSGRendererInterface::GraphicsApi api)
642 if (api == QSGRendererInterface::Unknown) {
644 m_requested.valid =
false;
647 Q_ASSERT(QSGRendererInterface::isApiRhiBased(api));
648 m_requested.valid =
true;
649 m_requested.api = api;
654QSGRhiSupport *QSGRhiSupport::instance_internal()
656 static QSGRhiSupport inst;
660QSGRhiSupport *QSGRhiSupport::instance()
662 QSGRhiSupport *inst = instance_internal();
663 if (!inst->m_settingsApplied)
664 inst->applySettings();
668QString QSGRhiSupport::rhiBackendName()
const
670 return QString::fromUtf8(QRhi::backendName(m_rhiBackend));
673QSGRendererInterface::GraphicsApi QSGRhiSupport::graphicsApi()
const
675 switch (m_rhiBackend) {
677 return QSGRendererInterface::Null;
679 return QSGRendererInterface::Vulkan;
680 case QRhi::OpenGLES2:
681 return QSGRendererInterface::OpenGL;
683 return QSGRendererInterface::Direct3D11;
685 return QSGRendererInterface::Direct3D12;
687 return QSGRendererInterface::Metal;
689 return QSGRendererInterface::Unknown;
693QSurface::SurfaceType QSGRhiSupport::windowSurfaceType()
const
695 switch (m_rhiBackend) {
697 return QSurface::VulkanSurface;
698 case QRhi::OpenGLES2:
699 return QSurface::OpenGLSurface;
702 return QSurface::Direct3DSurface;
704 return QSurface::MetalSurface;
706 return QSurface::OpenGLSurface;
711static const void *qsgrhi_vk_rifResource(QSGRendererInterface::Resource res,
712 const QRhiNativeHandles *nat,
713 const QRhiNativeHandles *cbNat,
714 const QRhiNativeHandles *rpNat)
716 const QRhiVulkanNativeHandles *vknat =
static_cast<
const QRhiVulkanNativeHandles *>(nat);
717 const QRhiVulkanCommandBufferNativeHandles *maybeVkCbNat =
718 static_cast<
const QRhiVulkanCommandBufferNativeHandles *>(cbNat);
719 const QRhiVulkanRenderPassNativeHandles *maybeVkRpNat =
720 static_cast<
const QRhiVulkanRenderPassNativeHandles *>(rpNat);
723 case QSGRendererInterface::DeviceResource:
725 case QSGRendererInterface::CommandQueueResource:
726 return &vknat->gfxQueue;
727 case QSGRendererInterface::CommandListResource:
729 return &maybeVkCbNat->commandBuffer;
732 case QSGRendererInterface::PhysicalDeviceResource:
733 return &vknat->physDev;
734 case QSGRendererInterface::RenderPassResource:
736 return &maybeVkRpNat->renderPass;
739 case QSGRendererInterface::GraphicsQueueFamilyIndexResource:
740 return &vknat->gfxQueueFamilyIdx;
741 case QSGRendererInterface::GraphicsQueueIndexResource:
742 return &vknat->gfxQueueIdx;
750static const void *qsgrhi_gl_rifResource(QSGRendererInterface::Resource res,
const QRhiNativeHandles *nat)
752 const QRhiGles2NativeHandles *glnat =
static_cast<
const QRhiGles2NativeHandles *>(nat);
754 case QSGRendererInterface::OpenGLContextResource:
755 return glnat->context;
763static const void *qsgrhi_d3d11_rifResource(QSGRendererInterface::Resource res,
const QRhiNativeHandles *nat)
765 const QRhiD3D11NativeHandles *d3dnat =
static_cast<
const QRhiD3D11NativeHandles *>(nat);
767 case QSGRendererInterface::DeviceResource:
769 case QSGRendererInterface::DeviceContextResource:
770 return d3dnat->context;
776static const void *qsgrhi_d3d12_rifResource(QSGRendererInterface::Resource res,
const QRhiNativeHandles *nat)
778 const QRhiD3D12NativeHandles *d3dnat =
static_cast<
const QRhiD3D12NativeHandles *>(nat);
780 case QSGRendererInterface::DeviceResource:
782 case QSGRendererInterface::CommandQueueResource:
783 return d3dnat->commandQueue;
791static const void *qsgrhi_mtl_rifResource(QSGRendererInterface::Resource res,
const QRhiNativeHandles *nat,
792 const QRhiNativeHandles *cbNat)
794 const QRhiMetalNativeHandles *mtlnat =
static_cast<
const QRhiMetalNativeHandles *>(nat);
795 const QRhiMetalCommandBufferNativeHandles *maybeMtlCbNat =
796 static_cast<
const QRhiMetalCommandBufferNativeHandles *>(cbNat);
799 case QSGRendererInterface::DeviceResource:
801 case QSGRendererInterface::CommandQueueResource:
802 return mtlnat->cmdQueue;
803 case QSGRendererInterface::CommandListResource:
805 return maybeMtlCbNat->commandBuffer;
808 case QSGRendererInterface::CommandEncoderResource:
810 return maybeMtlCbNat->encoder;
819const void *QSGRhiSupport::rifResource(QSGRendererInterface::Resource res,
820 const QSGDefaultRenderContext *rc,
821 const QQuickWindow *w)
823 QRhi *rhi = rc->rhi();
830 case QSGRendererInterface::RhiResource:
832 case QSGRendererInterface::RhiSwapchainResource:
833 return QQuickWindowPrivate::get(w)->swapchain;
834 case QSGRendererInterface::RhiRedirectCommandBuffer:
835 return QQuickWindowPrivate::get(w)->redirect.commandBuffer;
836 case QSGRendererInterface::RhiRedirectRenderTarget:
837 return QQuickWindowPrivate::get(w)->redirect.rt.rt.renderTarget;
842 const QRhiNativeHandles *nat = rhi->nativeHandles();
846 switch (m_rhiBackend) {
850 QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
851 QRhiRenderPassDescriptor *rp = rc->currentFrameRenderPass();
852 return qsgrhi_vk_rifResource(res, nat,
853 cb ? cb->nativeHandles() :
nullptr,
854 rp ? rp->nativeHandles() :
nullptr);
858 case QRhi::OpenGLES2:
859 return qsgrhi_gl_rifResource(res, nat);
863 return qsgrhi_d3d11_rifResource(res, nat);
865 return qsgrhi_d3d12_rifResource(res, nat);
870 QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
871 return qsgrhi_mtl_rifResource(res, nat, cb ? cb->nativeHandles() :
nullptr);
879int QSGRhiSupport::chooseSampleCount(
int samples, QRhi *rhi)
881 int msaaSampleCount = samples;
882 if (qEnvironmentVariableIsSet(
"QSG_SAMPLES"))
883 msaaSampleCount = qEnvironmentVariableIntValue(
"QSG_SAMPLES");
884 msaaSampleCount = qMax(1, msaaSampleCount);
885 if (msaaSampleCount > 1) {
886 const QList<
int> supportedSampleCounts = rhi->supportedSampleCounts();
887 if (!supportedSampleCounts.contains(msaaSampleCount)) {
888 int reducedSampleCount = 1;
889 for (
int i = supportedSampleCounts.size() - 1; i >= 0; --i) {
890 if (supportedSampleCounts[i] <= msaaSampleCount) {
891 reducedSampleCount = supportedSampleCounts[i];
895 qWarning() <<
"Requested MSAA sample count" << msaaSampleCount
896 <<
"but supported sample counts are" << supportedSampleCounts
897 <<
", using sample count" << reducedSampleCount <<
"instead";
898 msaaSampleCount = reducedSampleCount;
901 return msaaSampleCount;
904int QSGRhiSupport::chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi)
906 return chooseSampleCount(qMax(QSurfaceFormat::defaultFormat().samples(), window->requestedFormat().samples()), rhi);
910QOffscreenSurface *QSGRhiSupport::maybeCreateOffscreenSurface(QWindow *window)
912 QOffscreenSurface *offscreenSurface =
nullptr;
914 if (rhiBackend() == QRhi::OpenGLES2) {
915 const QSurfaceFormat format = window->requestedFormat();
916 offscreenSurface = QRhiGles2InitParams::newFallbackSurface(format);
921 return offscreenSurface;
924void QSGRhiSupport::prepareWindowForRhi(QQuickWindow *window)
927 if (rhiBackend() == QRhi::Vulkan) {
928 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
936 if (!window->vulkanInstance() && !wd->renderControl) {
937 QVulkanInstance *vkinst = QVulkanDefaultInstance::instance();
939 qCDebug(QSG_LOG_INFO) <<
"Got Vulkan instance from QVulkanDefaultInstance, requested api version was" << vkinst->apiVersion();
941 qCDebug(QSG_LOG_INFO) <<
"No Vulkan instance from QVulkanDefaultInstance, expect problems";
942 window->setVulkanInstance(vkinst);
952 QDir::root().mkpath(name);
953 return QFileInfo(name).isWritable();
958 static bool checked =
false;
959 static QString currentCacheDir;
960 static bool cacheWritable =
false;
963 return cacheWritable ? currentCacheDir : QString();
972 const QString cachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
973 const QString subPath = QLatin1String(
"/qtpipelinecache-") + QSysInfo::buildAbi() + QLatin1Char(
'/');
975 if (!cachePath.isEmpty()) {
976 currentCacheDir = cachePath + subPath;
977 cacheWritable = ensureWritableDir(currentCacheDir);
980 return cacheWritable ? currentCacheDir : QString();
985 const QString cacheDir = automaticPipelineCacheDir();
986 if (!cacheDir.isEmpty())
987 return cacheDir + QLatin1String(
"qqpc_") + QString::fromLatin1(rhi->backendName()).toLower();
994 return wflags.testFlag(Qt::ToolTip) || wflags.testFlag(Qt::SplashScreen);
1000 return wflags.testFlag(Qt::Dialog) || wflags.testFlag(Qt::Popup);
1003#if !QT_CONFIG(temporaryfile)
1004static inline QString pipelineCacheLockFileName(
const QString &name)
1006 return name + QLatin1String(
".lck");
1010void QSGRhiSupport::preparePipelineCache(QRhi *rhi, QQuickWindow *window)
1012 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
1015 QString pipelineCacheLoad = wd->graphicsConfig.pipelineCacheLoadFile();
1016 bool isAutomatic =
false;
1017 if (pipelineCacheLoad.isEmpty() && wd->graphicsConfig.isAutomaticPipelineCacheEnabled()) {
1018 if (!isAutomaticPipelineCacheLoadSkippedForWindow(window->flags())) {
1019 pipelineCacheLoad = automaticPipelineCacheFileName(rhi);
1024 if (pipelineCacheLoad.isEmpty())
1027#if !QT_CONFIG(temporaryfile)
1028 QLockFile lock(pipelineCacheLockFileName(pipelineCacheLoad));
1030 qWarning(
"Could not create pipeline cache lock file '%s'",
1031 qPrintable(lock.fileName()));
1036 QFile f(pipelineCacheLoad);
1037 if (!f.open(QIODevice::ReadOnly)) {
1039 qWarning(
"Could not open pipeline cache source file '%s'",
1040 qPrintable(pipelineCacheLoad));
1045 const QByteArray buf = f.readAll();
1046 if (!buf.isEmpty()) {
1047 qCDebug(QSG_LOG_INFO,
"Attempting to seed pipeline cache for QRhi %p from '%s'",
1048 rhi, qPrintable(pipelineCacheLoad));
1049 rhi->setPipelineCacheData(buf);
1053void QSGRhiSupport::finalizePipelineCache(QRhi *rhi,
const QQuickGraphicsConfiguration &config)
1056 qCDebug(QSG_LOG_INFO,
"Total time spent on pipeline creation during the lifetime of the QRhi %p was %lld ms",
1057 rhi, rhi->statistics().totalPipelineCreationTime);
1060 QString pipelineCacheSave = config.pipelineCacheSaveFile();
1061 bool isAutomatic =
false;
1062 if (pipelineCacheSave.isEmpty() && config.isAutomaticPipelineCacheEnabled()) {
1063 pipelineCacheSave = automaticPipelineCacheFileName(rhi);
1067 if (pipelineCacheSave.isEmpty())
1070 const QByteArray buf = rhi->pipelineCacheData();
1074 if (buf.isEmpty()) {
1082 QDir().remove(pipelineCacheSave);
1088#if QT_CONFIG(temporaryfile)
1089 QSaveFile f(pipelineCacheSave);
1091 QLockFile lock(pipelineCacheLockFileName(pipelineCacheSave));
1093 qWarning(
"Could not create pipeline cache lock file '%s'",
1094 qPrintable(lock.fileName()));
1097 QFile f(pipelineCacheSave);
1099 if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
1101 const QString msg = f.errorString();
1102 qWarning(
"Could not open pipeline cache output file '%s': %s",
1103 qPrintable(pipelineCacheSave), qPrintable(msg));
1108 qCDebug(QSG_LOG_INFO,
"Writing pipeline cache contents (%d bytes) for QRhi %p to '%s'",
1109 int(buf.size()), rhi, qPrintable(pipelineCacheSave));
1111 if (f.write(buf) != buf.size()
1112#if QT_CONFIG(temporaryfile)
1118 const QString msg = f.errorString();
1119 qWarning(
"Could not write pipeline cache: %s", qPrintable(msg));
1126QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QSurface *offscreenSurface,
bool forcePreferSwRenderer)
1128 QRhi *rhi =
nullptr;
1129 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
1130 const QQuickGraphicsDevicePrivate *customDevD = QQuickGraphicsDevicePrivate::get(&wd->customDeviceObjects);
1131 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Rhi) {
1132 rhi = customDevD->u.rhi;
1134 preparePipelineCache(rhi, window);
1135 return { rhi,
false };
1139 const bool debugLayer = wd->graphicsConfig.isDebugLayerEnabled();
1140 const bool debugMarkers = wd->graphicsConfig.isDebugMarkersEnabled();
1141 const bool timestamps = wd->graphicsConfig.timestampsEnabled();
1142 const bool preferSoftware = wd->graphicsConfig.prefersSoftwareDevice() || forcePreferSwRenderer;
1143 const bool pipelineCacheSave = !wd->graphicsConfig.pipelineCacheSaveFile().isEmpty()
1144 || (wd->graphicsConfig.isAutomaticPipelineCacheEnabled()
1145 && !isAutomaticPipelineCacheSaveSkippedForWindow(window->flags()));
1147 const QString backendName = rhiBackendName();
1148 qCDebug(QSG_LOG_INFO,
1149 "Creating QRhi with backend %s for window %p (wflags 0x%X)\n"
1150 " Graphics API debug/validation layers: %d\n"
1151 " Debug markers: %d\n"
1153 " Prefer software device: %d%s\n"
1154 " Shader/pipeline cache collection: %d",
1155 qPrintable(backendName), window,
int(window->flags()), debugLayer,
1156 debugMarkers, timestamps, preferSoftware, forcePreferSwRenderer ?
" [FORCED]" :
"", pipelineCacheSave);
1159 flags |= QRhi::SuppressSmokeTestWarnings;
1161 flags |= QRhi::EnableDebugMarkers;
1163 flags |= QRhi::EnableTimestamps;
1165 flags |= QRhi::PreferSoftwareRenderer;
1166 if (pipelineCacheSave)
1167 flags |= QRhi::EnablePipelineCacheDataSave;
1169 QRhiAdapter *rhiAdapter = customDevD->type == QQuickGraphicsDevicePrivate::Type::RhiAdapter ? customDevD->u.rhiAdapter :
nullptr;
1170 const QRhi::Implementation backend = rhiBackend();
1171 if (backend == QRhi::Null) {
1172 QRhiNullInitParams rhiParams;
1173 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1175#if QT_CONFIG(opengl)
1176 if (backend == QRhi::OpenGLES2) {
1177 const QSurfaceFormat format = window->requestedFormat();
1178 QRhiGles2InitParams rhiParams;
1179 rhiParams.format = format;
1180 rhiParams.fallbackSurface = offscreenSurface;
1181 rhiParams.window = window;
1182 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::OpenGLContext) {
1183 QRhiGles2NativeHandles importDev;
1184 importDev.context = customDevD->u.context;
1185 qCDebug(QSG_LOG_INFO,
"Using existing QOpenGLContext %p", importDev.context);
1186 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1188 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1192 Q_UNUSED(offscreenSurface);
1193 if (backend == QRhi::OpenGLES2)
1194 qWarning(
"OpenGL was requested for Qt Quick, but this build of Qt has no OpenGL support.");
1196#if QT_CONFIG(vulkan)
1197 if (backend == QRhi::Vulkan) {
1199 QVulkanDefaultInstance::setFlag(QVulkanDefaultInstance::EnableValidation,
true);
1200 QRhiVulkanInitParams rhiParams;
1201 prepareWindowForRhi(window);
1202 rhiParams.inst = window->vulkanInstance();
1203 if (!rhiParams.inst)
1204 qWarning(
"No QVulkanInstance set for QQuickWindow, this is wrong.");
1205 if (window->handle())
1206 rhiParams.window = window;
1207 rhiParams.deviceExtensions = wd->graphicsConfig.deviceExtensions();
1208 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceObjects) {
1209 QRhiVulkanNativeHandles importDev;
1210 importDev.physDev =
reinterpret_cast<VkPhysicalDevice>(customDevD->u.deviceObjects.physicalDevice);
1211 importDev.dev =
reinterpret_cast<VkDevice>(customDevD->u.deviceObjects.device);
1212 importDev.gfxQueueFamilyIdx = customDevD->u.deviceObjects.queueFamilyIndex;
1213 importDev.gfxQueueIdx = customDevD->u.deviceObjects.queueIndex;
1214 qCDebug(QSG_LOG_INFO,
"Using existing native Vulkan physical device %p device %p graphics queue family index %d",
1215 importDev.physDev, importDev.dev, importDev.gfxQueueFamilyIdx);
1216 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1217 }
else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::PhysicalDevice) {
1218 QRhiVulkanNativeHandles importDev;
1219 importDev.physDev =
reinterpret_cast<VkPhysicalDevice>(customDevD->u.physicalDevice.physicalDevice);
1220 qCDebug(QSG_LOG_INFO,
"Using existing native Vulkan physical device %p", importDev.physDev);
1221 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1223 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1227 if (backend == QRhi::Vulkan)
1228 qWarning(
"Vulkan was requested for Qt Quick, but this build of Qt has no Vulkan support.");
1231 if (backend == QRhi::D3D11) {
1232 QRhiD3D11InitParams rhiParams;
1233 rhiParams.enableDebugLayer = debugLayer;
1234 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndContext) {
1235 QRhiD3D11NativeHandles importDev;
1236 importDev.dev = customDevD->u.deviceAndContext.device;
1237 importDev.context = customDevD->u.deviceAndContext.context;
1238 qCDebug(QSG_LOG_INFO,
"Using existing native D3D11 device %p and context %p",
1239 importDev.dev, importDev.context);
1240 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1241 }
else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Adapter) {
1242 QRhiD3D11NativeHandles importDev;
1243 importDev.adapterLuidLow = customDevD->u.adapter.luidLow;
1244 importDev.adapterLuidHigh = customDevD->u.adapter.luidHigh;
1245 importDev.featureLevel = customDevD->u.adapter.featureLevel;
1246 qCDebug(QSG_LOG_INFO,
"Using D3D11 adapter LUID %u, %d and feature level %d",
1247 importDev.adapterLuidLow, importDev.adapterLuidHigh, importDev.featureLevel);
1248 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1250 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1251 if (!rhi && attemptReinitWithSwRastUponFail() && !flags.testFlag(QRhi::PreferSoftwareRenderer) && !rhiAdapter) {
1252 qCDebug(QSG_LOG_INFO,
"Failed to create a D3D device with default settings; "
1253 "attempting to get a software rasterizer backed device instead");
1254 flags |= QRhi::PreferSoftwareRenderer;
1255 rhi = QRhi::create(backend, &rhiParams, flags);
1258 }
else if (backend == QRhi::D3D12) {
1259 QRhiD3D12InitParams rhiParams;
1260 rhiParams.enableDebugLayer = debugLayer;
1261 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndContext) {
1262 QRhiD3D12NativeHandles importDev;
1263 importDev.dev = customDevD->u.deviceAndContext.device;
1264 qCDebug(QSG_LOG_INFO,
"Using existing native D3D12 device %p", importDev.dev);
1265 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1266 }
else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Adapter) {
1267 QRhiD3D12NativeHandles importDev;
1268 importDev.adapterLuidLow = customDevD->u.adapter.luidLow;
1269 importDev.adapterLuidHigh = customDevD->u.adapter.luidHigh;
1270 importDev.minimumFeatureLevel = customDevD->u.adapter.featureLevel;
1271 qCDebug(QSG_LOG_INFO,
"Using D3D12 adapter LUID %u, %d and minimum feature level %d",
1272 importDev.adapterLuidLow, importDev.adapterLuidHigh, importDev.minimumFeatureLevel);
1273 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1275 QRhiAdapter *rhiAdapter = customDevD->type == QQuickGraphicsDevicePrivate::Type::RhiAdapter ? customDevD->u.rhiAdapter :
nullptr;
1276 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1277 if (!rhi && attemptReinitWithSwRastUponFail() && !flags.testFlag(QRhi::PreferSoftwareRenderer) && !rhiAdapter) {
1278 qCDebug(QSG_LOG_INFO,
"Failed to create a D3D device with default settings; "
1279 "attempting to get a software rasterizer backed device instead");
1280 flags |= QRhi::PreferSoftwareRenderer;
1281 rhi = QRhi::create(backend, &rhiParams, flags);
1287 if (backend == QRhi::Metal) {
1288 QRhiMetalInitParams rhiParams;
1289 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndCommandQueue) {
1290 QRhiMetalNativeHandles importDev;
1291 importDev.dev = (MTLDevice *) customDevD->u.deviceAndCommandQueue.device;
1292 importDev.cmdQueue = (MTLCommandQueue *) customDevD->u.deviceAndCommandQueue.cmdQueue;
1293 qCDebug(QSG_LOG_INFO,
"Using existing native Metal device %p and command queue %p",
1294 importDev.dev, importDev.cmdQueue);
1295 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1297 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1303 qCDebug(QSG_LOG_INFO,
"Created QRhi %p for window %p", rhi, window);
1304 preparePipelineCache(rhi, window);
1306 qWarning(
"Failed to create RHI (backend %d)", backend);
1309 return { rhi,
true };
1312void QSGRhiSupport::destroyRhi(QRhi *rhi,
const QQuickGraphicsConfiguration &config)
1317 if (!rhi->isDeviceLost())
1318 finalizePipelineCache(rhi, config);
1323QImage QSGRhiSupport::grabAndBlockInCurrentFrame(QRhi *rhi, QRhiCommandBuffer *cb, QRhiTexture *src)
1325 Q_ASSERT(rhi->isRecordingFrame());
1327 QRhiReadbackResult result;
1328 QRhiReadbackDescription readbackDesc(src);
1329 QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
1330 resourceUpdates->readBackTexture(readbackDesc, &result);
1332 cb->resourceUpdate(resourceUpdates);
1336 QImage::Format imageFormat;
1337 if (result.format == QRhiTexture::BGRA8) {
1338#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1339 imageFormat = QImage::Format_ARGB32_Premultiplied;
1341 imageFormat = QImage::Format_RGBA8888_Premultiplied;
1345 imageFormat = QImage::Format_RGBA8888_Premultiplied;
1348 const uchar *p =
reinterpret_cast<
const uchar *>(result.data.constData());
1349 const QImage img(p, result.pixelSize.width(), result.pixelSize.height(), imageFormat);
1351 if (rhi->isYUpInFramebuffer())
1352 return img.flipped();
1357QImage QSGRhiSupport::grabOffscreen(QQuickWindow *window)
1364 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
1367 Q_ASSERT(!wd->renderControl);
1369 QScopedPointer<QOffscreenSurface> offscreenSurface(maybeCreateOffscreenSurface(window));
1370 RhiCreateResult rhiResult = createRhi(window, offscreenSurface.data());
1371 if (!rhiResult.rhi) {
1372 qWarning(
"Failed to initialize QRhi for offscreen readback");
1375 std::unique_ptr<QRhi> rhiOwner(rhiResult.rhi);
1376 QRhi *rhi = rhiResult.own ? rhiOwner.get() : rhiOwner.release();
1378 const QSize pixelSize = window->size() * window->devicePixelRatio();
1379 QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, pixelSize, 1,
1380 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
1381 if (!texture->create()) {
1382 qWarning(
"Failed to build texture for offscreen readback");
1385 QScopedPointer<QRhiRenderBuffer> depthStencil(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, 1,
1386 depthStencilBufferFlags()));
1387 if (!depthStencil->create()) {
1388 qWarning(
"Failed to create depth/stencil buffer for offscreen readback");
1391 QRhiTextureRenderTargetDescription rtDesc(texture.data());
1392 rtDesc.setDepthStencilBuffer(depthStencil.data());
1393 QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
1394 QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
1395 rt->setRenderPassDescriptor(rpDesc.data());
1396 if (!rt->create()) {
1397 qWarning(
"Failed to build render target for offscreen readback");
1403 QSGDefaultRenderContext::InitParams params;
1405 params.sampleCount = 1;
1406 params.initialSurfacePixelSize = pixelSize;
1407 params.maybeSurface = window;
1408 wd->context->initialize(¶ms);
1412 auto renderTarget = QQuickRenderTarget::fromRhiRenderTarget(rt.data());
1415 renderTarget.setDevicePixelRatio(window->devicePixelRatio());
1416 window->setRenderTarget(renderTarget);
1418 QRhiCommandBuffer *cb =
nullptr;
1419 if (rhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess) {
1420 qWarning(
"Failed to start recording the frame for offscreen readback");
1424 wd->setCustomCommandBuffer(cb);
1426 wd->syncSceneGraph();
1427 wd->renderSceneGraph();
1428 wd->setCustomCommandBuffer(
nullptr);
1430 QImage image = grabAndBlockInCurrentFrame(rhi, cb, texture.data());
1431 rhi->endOffscreenFrame();
1433 image.setDevicePixelRatio(window->devicePixelRatio());
1434 wd->cleanupNodesOnShutdown();
1435 wd->context->invalidate();
1437 window->setRenderTarget(QQuickRenderTarget());
1444QImage QSGRhiSupport::grabOffscreenForProtectedContent(QQuickWindow *window)
1452 QScopedPointer<QQuickWindow> offscreenWindow;
1453 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
1456 Q_ASSERT(!wd->renderControl);
1460 if (window->requestedFormat().testOption(QSurfaceFormat::ProtectedContent)) {
1461 QSurfaceFormat surfaceFormat = window->requestedFormat();
1462 surfaceFormat.setOption(QSurfaceFormat::ProtectedContent,
false);
1463 offscreenWindow.reset(
new QQuickWindow());
1464 offscreenWindow->setFormat(surfaceFormat);
1467 QScopedPointer<QOffscreenSurface> offscreenSurface(maybeCreateOffscreenSurface(window));
1468 RhiCreateResult rhiResult = createRhi(offscreenWindow.data() ? offscreenWindow.data() : window, offscreenSurface.data());
1469 if (!rhiResult.rhi) {
1470 qWarning(
"Failed to initialize QRhi for offscreen readback");
1473 QScopedPointer<QRhi> rhiOwner(rhiResult.rhi);
1474 QRhi *rhi = rhiResult.own ? rhiOwner.data() : rhiOwner.take();
1476 const QSize pixelSize = window->size() * window->devicePixelRatio();
1477 QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, pixelSize, 1,
1478 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
1479 if (!texture->create()) {
1480 qWarning(
"Failed to build texture for offscreen readback");
1483 QScopedPointer<QRhiRenderBuffer> depthStencil(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, 1,
1484 depthStencilBufferFlags()));
1485 if (!depthStencil->create()) {
1486 qWarning(
"Failed to create depth/stencil buffer for offscreen readback");
1489 QRhiTextureRenderTargetDescription rtDesc(texture.data());
1490 rtDesc.setDepthStencilBuffer(depthStencil.data());
1491 QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
1492 QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
1493 rt->setRenderPassDescriptor(rpDesc.data());
1494 if (!rt->create()) {
1495 qWarning(
"Failed to build render target for offscreen readback");
1500 QRhi *currentRhi = wd->rhi;
1503 QSGDefaultRenderContext::InitParams params;
1505 params.sampleCount = 1;
1506 params.initialSurfacePixelSize = pixelSize;
1507 params.maybeSurface = window;
1508 wd->context->initialize(¶ms);
1511 QQuickRenderTarget currentRenderTarget = window->renderTarget();
1514 window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(rt.data()));
1516 QRhiCommandBuffer *cb =
nullptr;
1517 if (rhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess) {
1518 qWarning(
"Failed to start recording the frame for offscreen readback");
1522 wd->setCustomCommandBuffer(cb);
1524 wd->syncSceneGraph();
1525 wd->renderSceneGraph();
1526 wd->setCustomCommandBuffer(
nullptr);
1528 QImage image = grabAndBlockInCurrentFrame(rhi, cb, texture.data());
1529 rhi->endOffscreenFrame();
1531 image.setDevicePixelRatio(window->devicePixelRatio());
1535 wd->cleanupNodesOnShutdown();
1536 wd->context->invalidate();
1538 window->setRenderTarget(QQuickRenderTarget());
1543 window->setRenderTarget(currentRenderTarget);
1544 wd->rhi = currentRhi;
1545 params.rhi = currentRhi;
1546 wd->context->initialize(¶ms);
1553void QSGRhiSupport::applySwapChainFormat(QRhiSwapChain *scWithWindowSet, QQuickWindow *window)
1555 Q_ASSERT(scWithWindowSet->window() == window);
1557 QRhiSwapChain::Format swapChainFormat = QRhiSwapChain::SDR;
1559 QByteArray hdrRequest = qgetenv(
"QSG_RHI_HDR");
1560 if (hdrRequest.isEmpty())
1561 hdrRequest = window->property(
"_qt_sg_hdr_format").toByteArray();
1563 if (!hdrRequest.isEmpty()) {
1564 hdrRequest = hdrRequest.toLower();
1565 if (hdrRequest == QByteArrayLiteral(
"scrgb") || hdrRequest == QByteArrayLiteral(
"extendedsrgblinear"))
1566 swapChainFormat = QRhiSwapChain::HDRExtendedSrgbLinear;
1567 else if (hdrRequest == QByteArrayLiteral(
"hdr10"))
1568 swapChainFormat = QRhiSwapChain::HDR10;
1569 else if (hdrRequest == QByteArrayLiteral(
"p3"))
1570 swapChainFormat = QRhiSwapChain::HDRExtendedDisplayP3Linear;
1573 const char *fmtStr =
"unknown";
1574 switch (swapChainFormat) {
1575 case QRhiSwapChain::SDR:
1578 case QRhiSwapChain::HDRExtendedSrgbLinear:
1581 case QRhiSwapChain::HDR10:
1584 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
1585 fmtStr =
"Extended Linear Display P3";
1591 if (!scWithWindowSet->isFormatSupported(swapChainFormat)) {
1592 if (swapChainFormat != QRhiSwapChain::SDR) {
1593 qCDebug(QSG_LOG_INFO,
"Requested a %s swapchain but it is reported to be unsupported with the current display(s). "
1594 "In multi-screen configurations make sure the window is located on a HDR-enabled screen. "
1595 "Request ignored, using SDR swapchain.", fmtStr);
1600 scWithWindowSet->setFormat(swapChainFormat);
1602 if (swapChainFormat != QRhiSwapChain::SDR) {
1603 qCDebug(QSG_LOG_INFO,
"Creating %s swapchain", fmtStr);
1604 qCDebug(QSG_LOG_INFO) <<
"HDR output info:" << scWithWindowSet->hdrInfo();
1608QRhiTexture::Format QSGRhiSupport::toRhiTextureFormat(uint nativeFormat, QRhiTexture::Flags *flags)
const
1610 switch (m_rhiBackend) {
1611#if QT_CONFIG(vulkan)
1613 return toRhiTextureFormatFromVulkan(nativeFormat, flags);
1615#if QT_CONFIG(opengl)
1616 case QRhi::OpenGLES2:
1618 return toRhiTextureFormatFromGL(nativeFormat, flags);
1623 return toRhiTextureFormatFromDXGI(nativeFormat, flags);
1627 return toRhiTextureFormatFromMetal(nativeFormat, flags);
1630 return QRhiTexture::UnknownFormat;
1632 Q_UNUSED(nativeFormat)
1636bool QSGRhiSupport::attemptReinitWithSwRastUponFail()
const
1638 const QRhi::Implementation backend = rhiBackend();
1644 if (backend == QRhi::D3D11 || backend == QRhi::D3D12)
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)