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);
156#define GL_BGRA 0x80E1
176#define GL_RG16 0x822C
184#define GL_RGBA8 0x8058
188#define GL_RGBA32F 0x8814
192#define GL_RGBA16F 0x881A
196#define GL_R16F 0x822D
200#define GL_R32F 0x822E
203#ifndef GL_DEPTH_COMPONENT16
204#define GL_DEPTH_COMPONENT16 0x81A5
207#ifndef GL_DEPTH_COMPONENT24
208#define GL_DEPTH_COMPONENT24 0x81A6
211#ifndef GL_DEPTH_COMPONENT32F
212#define GL_DEPTH_COMPONENT32F 0x8CAC
215#ifndef GL_DEPTH24_STENCIL8
216#define GL_DEPTH24_STENCIL8 0x88F0
219#ifndef GL_DEPTH_STENCIL
220#define GL_DEPTH_STENCIL 0x84F9
224#define GL_RGB10_A2 0x8059
228#define GL_SRGB_ALPHA 0x8C42
231#ifndef GL_SRGB8_ALPHA8
232#define GL_SRGB8_ALPHA8 0x8C43
235QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromGL(uint format, QRhiTexture::Flags *flags)
238 auto rhiFormat = QRhiTexture::UnknownFormat;
241 case GL_SRGB8_ALPHA8:
247 rhiFormat = QRhiTexture::RGBA8;
250 rhiFormat = QRhiTexture::BGRA8;
253 rhiFormat = QRhiTexture::R16;
256 rhiFormat = QRhiTexture::RG16;
261 rhiFormat = QRhiTexture::R8;
266 rhiFormat = QRhiTexture::RG8;
269 rhiFormat = QRhiTexture::RED_OR_ALPHA8;
272 rhiFormat = QRhiTexture::RGBA16F;
275 rhiFormat = QRhiTexture::RGBA32F;
278 rhiFormat = QRhiTexture::R16F;
281 rhiFormat = QRhiTexture::R32F;
284 rhiFormat = QRhiTexture::RGB10A2;
286 case GL_DEPTH_COMPONENT:
288 case GL_DEPTH_COMPONENT16:
289 rhiFormat = QRhiTexture::D16;
291 case GL_DEPTH_COMPONENT24:
292 rhiFormat = QRhiTexture::D24;
294 case GL_DEPTH_STENCIL:
296 case GL_DEPTH24_STENCIL8:
297 rhiFormat = QRhiTexture::D24S8;
299 case GL_DEPTH_COMPONENT32F:
300 rhiFormat = QRhiTexture::D32F;
303 qWarning(
"GL format %d is not supported", format);
307 (*flags) |=(QRhiTexture::sRGB);
313QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromVulkan(uint format, QRhiTexture::Flags *flags)
315 auto rhiFormat = QRhiTexture::UnknownFormat;
318 case VK_FORMAT_R8G8B8A8_SRGB:
321 case VK_FORMAT_R8G8B8A8_UNORM:
322 case VK_FORMAT_UNDEFINED:
323 rhiFormat = QRhiTexture::RGBA8;
325 case VK_FORMAT_B8G8R8A8_SRGB:
328 case VK_FORMAT_B8G8R8A8_UNORM:
329 rhiFormat = QRhiTexture::BGRA8;
331 case VK_FORMAT_R8_SRGB:
334 case VK_FORMAT_R8_UNORM:
335 rhiFormat = QRhiTexture::R8;
337 case VK_FORMAT_R8G8_SRGB:
340 case VK_FORMAT_R8G8_UNORM:
341 rhiFormat = QRhiTexture::RG8;
343 case VK_FORMAT_R16_UNORM:
344 rhiFormat = QRhiTexture::R16;
346 case VK_FORMAT_R16G16_UNORM:
347 rhiFormat = QRhiTexture::RG16;
349 case VK_FORMAT_R16G16B16A16_SFLOAT:
350 rhiFormat = QRhiTexture::RGBA16F;
352 case VK_FORMAT_R32G32B32A32_SFLOAT:
353 rhiFormat = QRhiTexture::RGBA32F;
355 case VK_FORMAT_R16_SFLOAT:
356 rhiFormat = QRhiTexture::R16F;
358 case VK_FORMAT_R32_SFLOAT:
359 rhiFormat = QRhiTexture::R32F;
361 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
363 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
364 rhiFormat = QRhiTexture::RGB10A2;
366 case VK_FORMAT_D16_UNORM:
367 rhiFormat = QRhiTexture::D16;
369 case VK_FORMAT_X8_D24_UNORM_PACK32:
370 rhiFormat = QRhiTexture::D24;
372 case VK_FORMAT_D24_UNORM_S8_UINT:
373 rhiFormat = QRhiTexture::D24S8;
375 case VK_FORMAT_D32_SFLOAT:
376 rhiFormat = QRhiTexture::D32F;
378 case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
381 case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
382 rhiFormat = QRhiTexture::BC1;
384 case VK_FORMAT_BC2_SRGB_BLOCK:
387 case VK_FORMAT_BC2_UNORM_BLOCK:
388 rhiFormat = QRhiTexture::BC2;
390 case VK_FORMAT_BC3_SRGB_BLOCK:
393 case VK_FORMAT_BC3_UNORM_BLOCK:
394 rhiFormat = QRhiTexture::BC3;
396 case VK_FORMAT_BC4_UNORM_BLOCK:
397 rhiFormat = QRhiTexture::BC4;
399 case VK_FORMAT_BC5_UNORM_BLOCK:
400 rhiFormat = QRhiTexture::BC5;
402 case VK_FORMAT_BC6H_UFLOAT_BLOCK:
403 rhiFormat = QRhiTexture::BC6H;
405 case VK_FORMAT_BC7_SRGB_BLOCK:
408 case VK_FORMAT_BC7_UNORM_BLOCK:
409 rhiFormat = QRhiTexture::BC7;
411 case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
414 case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
415 rhiFormat = QRhiTexture::ETC2_RGB8;
417 case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
420 case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
421 rhiFormat = QRhiTexture::ETC2_RGB8A1;
423 case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
426 case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
427 rhiFormat = QRhiTexture::ETC2_RGBA8;
429 case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
432 case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
433 rhiFormat = QRhiTexture::ASTC_4x4;
435 case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
438 case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
439 rhiFormat = QRhiTexture::ASTC_5x4;
441 case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
444 case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
445 rhiFormat = QRhiTexture::ASTC_5x5;
447 case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
450 case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
451 rhiFormat = QRhiTexture::ASTC_6x5;
453 case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
456 case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
457 rhiFormat = QRhiTexture::ASTC_6x6;
459 case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
462 case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
463 rhiFormat = QRhiTexture::ASTC_8x5;
465 case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
468 case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
469 rhiFormat = QRhiTexture::ASTC_8x6;
471 case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
474 case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
475 rhiFormat = QRhiTexture::ASTC_8x8;
477 case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
480 case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
481 rhiFormat = QRhiTexture::ASTC_10x5;
483 case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
486 case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
487 rhiFormat = QRhiTexture::ASTC_10x6;
489 case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
492 case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
493 rhiFormat = QRhiTexture::ASTC_10x8;
495 case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
498 case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
499 rhiFormat = QRhiTexture::ASTC_10x10;
501 case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
504 case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
505 rhiFormat = QRhiTexture::ASTC_12x10;
507 case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
510 case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
511 rhiFormat = QRhiTexture::ASTC_12x12;
514 qWarning(
"VkFormat %d is not supported", format);
518 (*flags) |=(QRhiTexture::sRGB);
524QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromDXGI(uint format, QRhiTexture::Flags *flags)
526 auto rhiFormat = QRhiTexture::UnknownFormat;
529 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
532 case DXGI_FORMAT_R8G8B8A8_UNORM:
533 case DXGI_FORMAT_UNKNOWN:
534 rhiFormat = QRhiTexture::RGBA8;
536 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
539 case DXGI_FORMAT_B8G8R8A8_UNORM:
540 rhiFormat = QRhiTexture::BGRA8;
542 case DXGI_FORMAT_R8_UNORM:
543 rhiFormat = QRhiTexture::R8;
545 case DXGI_FORMAT_R8G8_UNORM:
546 rhiFormat = QRhiTexture::RG8;
548 case DXGI_FORMAT_R16_UNORM:
549 rhiFormat = QRhiTexture::R16;
551 case DXGI_FORMAT_R16G16_UNORM:
552 rhiFormat = QRhiTexture::RG16;
554 case DXGI_FORMAT_R16G16B16A16_FLOAT:
555 rhiFormat = QRhiTexture::RGBA16F;
557 case DXGI_FORMAT_R32G32B32A32_FLOAT:
558 rhiFormat = QRhiTexture::RGBA32F;
560 case DXGI_FORMAT_R16_FLOAT:
561 rhiFormat = QRhiTexture::R16F;
563 case DXGI_FORMAT_R32_FLOAT:
564 rhiFormat = QRhiTexture::R32F;
566 case DXGI_FORMAT_R10G10B10A2_UNORM:
567 rhiFormat = QRhiTexture::RGB10A2;
569 case DXGI_FORMAT_R16_TYPELESS:
570 rhiFormat = QRhiTexture::D16;
572 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
573 rhiFormat = QRhiTexture::D24;
575 case DXGI_FORMAT_D24_UNORM_S8_UINT:
576 rhiFormat = QRhiTexture::D24S8;
578 case DXGI_FORMAT_R32_TYPELESS:
579 rhiFormat = QRhiTexture::D32F;
581 case DXGI_FORMAT_BC1_UNORM_SRGB:
584 case DXGI_FORMAT_BC1_UNORM:
585 rhiFormat = QRhiTexture::BC1;
587 case DXGI_FORMAT_BC2_UNORM_SRGB:
590 case DXGI_FORMAT_BC2_UNORM:
591 rhiFormat = QRhiTexture::BC2;
593 case DXGI_FORMAT_BC3_UNORM_SRGB:
596 case DXGI_FORMAT_BC3_UNORM:
597 rhiFormat = QRhiTexture::BC3;
599 case DXGI_FORMAT_BC4_UNORM:
600 rhiFormat = QRhiTexture::BC4;
602 case DXGI_FORMAT_BC5_UNORM:
603 rhiFormat = QRhiTexture::BC5;
605 case DXGI_FORMAT_BC6H_UF16:
606 rhiFormat = QRhiTexture::BC6H;
608 case DXGI_FORMAT_BC7_UNORM_SRGB:
611 case DXGI_FORMAT_BC7_UNORM:
612 rhiFormat = QRhiTexture::BC7;
615 qWarning(
"DXGI_FORMAT %d is not supported", format);
619 (*flags) |=(QRhiTexture::sRGB);
625namespace QSGRhiSupportMac {
626 QRhiTexture::Format toRhiTextureFormatFromMetal(uint format, QRhiTexture::Flags *flags);
628QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromMetal(uint format, QRhiTexture::Flags *flags)
630 return QSGRhiSupportMac::toRhiTextureFormatFromMetal(format, flags);
634void QSGRhiSupport::configure(QSGRendererInterface::GraphicsApi api)
636 if (api == QSGRendererInterface::Unknown) {
638 m_requested.valid =
false;
641 Q_ASSERT(QSGRendererInterface::isApiRhiBased(api));
642 m_requested.valid =
true;
643 m_requested.api = api;
648QSGRhiSupport *QSGRhiSupport::instance_internal()
650 static QSGRhiSupport inst;
654QSGRhiSupport *QSGRhiSupport::instance()
656 QSGRhiSupport *inst = instance_internal();
657 if (!inst->m_settingsApplied)
658 inst->applySettings();
662QString QSGRhiSupport::rhiBackendName()
const
664 return QString::fromUtf8(QRhi::backendName(m_rhiBackend));
667QSGRendererInterface::GraphicsApi QSGRhiSupport::graphicsApi()
const
669 switch (m_rhiBackend) {
671 return QSGRendererInterface::Null;
673 return QSGRendererInterface::Vulkan;
674 case QRhi::OpenGLES2:
675 return QSGRendererInterface::OpenGL;
677 return QSGRendererInterface::Direct3D11;
679 return QSGRendererInterface::Direct3D12;
681 return QSGRendererInterface::Metal;
683 return QSGRendererInterface::Unknown;
687QSurface::SurfaceType QSGRhiSupport::windowSurfaceType()
const
689 switch (m_rhiBackend) {
691 return QSurface::VulkanSurface;
692 case QRhi::OpenGLES2:
693 return QSurface::OpenGLSurface;
696 return QSurface::Direct3DSurface;
698 return QSurface::MetalSurface;
700 return QSurface::OpenGLSurface;
705static const void *qsgrhi_vk_rifResource(QSGRendererInterface::Resource res,
706 const QRhiNativeHandles *nat,
707 const QRhiNativeHandles *cbNat,
708 const QRhiNativeHandles *rpNat)
710 const QRhiVulkanNativeHandles *vknat =
static_cast<
const QRhiVulkanNativeHandles *>(nat);
711 const QRhiVulkanCommandBufferNativeHandles *maybeVkCbNat =
712 static_cast<
const QRhiVulkanCommandBufferNativeHandles *>(cbNat);
713 const QRhiVulkanRenderPassNativeHandles *maybeVkRpNat =
714 static_cast<
const QRhiVulkanRenderPassNativeHandles *>(rpNat);
717 case QSGRendererInterface::DeviceResource:
719 case QSGRendererInterface::CommandQueueResource:
720 return &vknat->gfxQueue;
721 case QSGRendererInterface::CommandListResource:
723 return &maybeVkCbNat->commandBuffer;
726 case QSGRendererInterface::PhysicalDeviceResource:
727 return &vknat->physDev;
728 case QSGRendererInterface::RenderPassResource:
730 return &maybeVkRpNat->renderPass;
733 case QSGRendererInterface::GraphicsQueueFamilyIndexResource:
734 return &vknat->gfxQueueFamilyIdx;
735 case QSGRendererInterface::GraphicsQueueIndexResource:
736 return &vknat->gfxQueueIdx;
744static const void *qsgrhi_gl_rifResource(QSGRendererInterface::Resource res,
const QRhiNativeHandles *nat)
746 const QRhiGles2NativeHandles *glnat =
static_cast<
const QRhiGles2NativeHandles *>(nat);
748 case QSGRendererInterface::OpenGLContextResource:
749 return glnat->context;
757static const void *qsgrhi_d3d11_rifResource(QSGRendererInterface::Resource res,
const QRhiNativeHandles *nat)
759 const QRhiD3D11NativeHandles *d3dnat =
static_cast<
const QRhiD3D11NativeHandles *>(nat);
761 case QSGRendererInterface::DeviceResource:
763 case QSGRendererInterface::DeviceContextResource:
764 return d3dnat->context;
770static const void *qsgrhi_d3d12_rifResource(QSGRendererInterface::Resource res,
const QRhiNativeHandles *nat)
772 const QRhiD3D12NativeHandles *d3dnat =
static_cast<
const QRhiD3D12NativeHandles *>(nat);
774 case QSGRendererInterface::DeviceResource:
776 case QSGRendererInterface::CommandQueueResource:
777 return d3dnat->commandQueue;
785static const void *qsgrhi_mtl_rifResource(QSGRendererInterface::Resource res,
const QRhiNativeHandles *nat,
786 const QRhiNativeHandles *cbNat)
788 const QRhiMetalNativeHandles *mtlnat =
static_cast<
const QRhiMetalNativeHandles *>(nat);
789 const QRhiMetalCommandBufferNativeHandles *maybeMtlCbNat =
790 static_cast<
const QRhiMetalCommandBufferNativeHandles *>(cbNat);
793 case QSGRendererInterface::DeviceResource:
795 case QSGRendererInterface::CommandQueueResource:
796 return mtlnat->cmdQueue;
797 case QSGRendererInterface::CommandListResource:
799 return maybeMtlCbNat->commandBuffer;
802 case QSGRendererInterface::CommandEncoderResource:
804 return maybeMtlCbNat->encoder;
813const void *QSGRhiSupport::rifResource(QSGRendererInterface::Resource res,
814 const QSGDefaultRenderContext *rc,
815 const QQuickWindow *w)
817 QRhi *rhi = rc->rhi();
824 case QSGRendererInterface::RhiResource:
826 case QSGRendererInterface::RhiSwapchainResource:
827 return QQuickWindowPrivate::get(w)->swapchain;
828 case QSGRendererInterface::RhiRedirectCommandBuffer:
829 return QQuickWindowPrivate::get(w)->redirect.commandBuffer;
830 case QSGRendererInterface::RhiRedirectRenderTarget:
831 return QQuickWindowPrivate::get(w)->redirect.rt.rt.renderTarget;
836 const QRhiNativeHandles *nat = rhi->nativeHandles();
840 switch (m_rhiBackend) {
844 QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
845 QRhiRenderPassDescriptor *rp = rc->currentFrameRenderPass();
846 return qsgrhi_vk_rifResource(res, nat,
847 cb ? cb->nativeHandles() :
nullptr,
848 rp ? rp->nativeHandles() :
nullptr);
852 case QRhi::OpenGLES2:
853 return qsgrhi_gl_rifResource(res, nat);
857 return qsgrhi_d3d11_rifResource(res, nat);
859 return qsgrhi_d3d12_rifResource(res, nat);
864 QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
865 return qsgrhi_mtl_rifResource(res, nat, cb ? cb->nativeHandles() :
nullptr);
873int QSGRhiSupport::chooseSampleCount(
int samples, QRhi *rhi)
875 int msaaSampleCount = samples;
876 if (qEnvironmentVariableIsSet(
"QSG_SAMPLES"))
877 msaaSampleCount = qEnvironmentVariableIntValue(
"QSG_SAMPLES");
878 msaaSampleCount = qMax(1, msaaSampleCount);
879 if (msaaSampleCount > 1) {
880 const QList<
int> supportedSampleCounts = rhi->supportedSampleCounts();
881 if (!supportedSampleCounts.contains(msaaSampleCount)) {
882 int reducedSampleCount = 1;
883 for (
int i = supportedSampleCounts.size() - 1; i >= 0; --i) {
884 if (supportedSampleCounts[i] <= msaaSampleCount) {
885 reducedSampleCount = supportedSampleCounts[i];
889 qWarning() <<
"Requested MSAA sample count" << msaaSampleCount
890 <<
"but supported sample counts are" << supportedSampleCounts
891 <<
", using sample count" << reducedSampleCount <<
"instead";
892 msaaSampleCount = reducedSampleCount;
895 return msaaSampleCount;
898int QSGRhiSupport::chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi)
900 return chooseSampleCount(qMax(QSurfaceFormat::defaultFormat().samples(), window->requestedFormat().samples()), rhi);
904QOffscreenSurface *QSGRhiSupport::maybeCreateOffscreenSurface(QWindow *window)
906 QOffscreenSurface *offscreenSurface =
nullptr;
908 if (rhiBackend() == QRhi::OpenGLES2) {
909 const QSurfaceFormat format = window->requestedFormat();
910 offscreenSurface = QRhiGles2InitParams::newFallbackSurface(format);
915 return offscreenSurface;
918void QSGRhiSupport::prepareWindowForRhi(QQuickWindow *window)
921 if (rhiBackend() == QRhi::Vulkan) {
922 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
930 if (!window->vulkanInstance() && !wd->renderControl) {
931 QVulkanInstance *vkinst = QVulkanDefaultInstance::instance();
933 qCDebug(QSG_LOG_INFO) <<
"Got Vulkan instance from QVulkanDefaultInstance, requested api version was" << vkinst->apiVersion();
935 qCDebug(QSG_LOG_INFO) <<
"No Vulkan instance from QVulkanDefaultInstance, expect problems";
936 window->setVulkanInstance(vkinst);
946 QDir::root().mkpath(name);
947 return QFileInfo(name).isWritable();
952 static bool checked =
false;
953 static QString currentCacheDir;
954 static bool cacheWritable =
false;
957 return cacheWritable ? currentCacheDir : QString();
966 const QString cachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
967 const QString subPath = QLatin1String(
"/qtpipelinecache-") + QSysInfo::buildAbi() + QLatin1Char(
'/');
969 if (!cachePath.isEmpty()) {
970 currentCacheDir = cachePath + subPath;
971 cacheWritable = ensureWritableDir(currentCacheDir);
974 return cacheWritable ? currentCacheDir : QString();
979 const QString cacheDir = automaticPipelineCacheDir();
980 if (!cacheDir.isEmpty())
981 return cacheDir + QLatin1String(
"qqpc_") + QString::fromLatin1(rhi->backendName()).toLower();
988 return wflags.testFlag(Qt::ToolTip) || wflags.testFlag(Qt::SplashScreen);
994 return wflags.testFlag(Qt::Dialog) || wflags.testFlag(Qt::Popup);
997#if !QT_CONFIG(temporaryfile)
998static inline QString pipelineCacheLockFileName(
const QString &name)
1000 return name + QLatin1String(
".lck");
1004void QSGRhiSupport::preparePipelineCache(QRhi *rhi, QQuickWindow *window)
1006 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
1009 QString pipelineCacheLoad = wd->graphicsConfig.pipelineCacheLoadFile();
1010 bool isAutomatic =
false;
1011 if (pipelineCacheLoad.isEmpty() && wd->graphicsConfig.isAutomaticPipelineCacheEnabled()) {
1012 if (!isAutomaticPipelineCacheLoadSkippedForWindow(window->flags())) {
1013 pipelineCacheLoad = automaticPipelineCacheFileName(rhi);
1018 if (pipelineCacheLoad.isEmpty())
1021#if !QT_CONFIG(temporaryfile)
1022 QLockFile lock(pipelineCacheLockFileName(pipelineCacheLoad));
1024 qWarning(
"Could not create pipeline cache lock file '%s'",
1025 qPrintable(lock.fileName()));
1030 QFile f(pipelineCacheLoad);
1031 if (!f.open(QIODevice::ReadOnly)) {
1033 qWarning(
"Could not open pipeline cache source file '%s'",
1034 qPrintable(pipelineCacheLoad));
1039 const QByteArray buf = f.readAll();
1040 if (!buf.isEmpty()) {
1041 qCDebug(QSG_LOG_INFO,
"Attempting to seed pipeline cache for QRhi %p from '%s'",
1042 rhi, qPrintable(pipelineCacheLoad));
1043 rhi->setPipelineCacheData(buf);
1047void QSGRhiSupport::finalizePipelineCache(QRhi *rhi,
const QQuickGraphicsConfiguration &config)
1050 qCDebug(QSG_LOG_INFO,
"Total time spent on pipeline creation during the lifetime of the QRhi %p was %lld ms",
1051 rhi, rhi->statistics().totalPipelineCreationTime);
1054 QString pipelineCacheSave = config.pipelineCacheSaveFile();
1055 bool isAutomatic =
false;
1056 if (pipelineCacheSave.isEmpty() && config.isAutomaticPipelineCacheEnabled()) {
1057 pipelineCacheSave = automaticPipelineCacheFileName(rhi);
1061 if (pipelineCacheSave.isEmpty())
1064 const QByteArray buf = rhi->pipelineCacheData();
1068 if (buf.isEmpty()) {
1076 QDir().remove(pipelineCacheSave);
1082#if QT_CONFIG(temporaryfile)
1083 QSaveFile f(pipelineCacheSave);
1085 QLockFile lock(pipelineCacheLockFileName(pipelineCacheSave));
1087 qWarning(
"Could not create pipeline cache lock file '%s'",
1088 qPrintable(lock.fileName()));
1091 QFile f(pipelineCacheSave);
1093 if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
1095 const QString msg = f.errorString();
1096 qWarning(
"Could not open pipeline cache output file '%s': %s",
1097 qPrintable(pipelineCacheSave), qPrintable(msg));
1102 qCDebug(QSG_LOG_INFO,
"Writing pipeline cache contents (%d bytes) for QRhi %p to '%s'",
1103 int(buf.size()), rhi, qPrintable(pipelineCacheSave));
1105 if (f.write(buf) != buf.size()
1106#if QT_CONFIG(temporaryfile)
1112 const QString msg = f.errorString();
1113 qWarning(
"Could not write pipeline cache: %s", qPrintable(msg));
1120QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QSurface *offscreenSurface,
bool forcePreferSwRenderer)
1122 QRhi *rhi =
nullptr;
1123 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
1124 const QQuickGraphicsDevicePrivate *customDevD = QQuickGraphicsDevicePrivate::get(&wd->customDeviceObjects);
1125 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Rhi) {
1126 rhi = customDevD->u.rhi;
1128 preparePipelineCache(rhi, window);
1129 return { rhi,
false };
1133 const bool debugLayer = wd->graphicsConfig.isDebugLayerEnabled();
1134 const bool debugMarkers = wd->graphicsConfig.isDebugMarkersEnabled();
1135 const bool timestamps = wd->graphicsConfig.timestampsEnabled();
1136 const bool preferSoftware = wd->graphicsConfig.prefersSoftwareDevice() || forcePreferSwRenderer;
1137 const bool pipelineCacheSave = !wd->graphicsConfig.pipelineCacheSaveFile().isEmpty()
1138 || (wd->graphicsConfig.isAutomaticPipelineCacheEnabled()
1139 && !isAutomaticPipelineCacheSaveSkippedForWindow(window->flags()));
1141 const QString backendName = rhiBackendName();
1142 qCDebug(QSG_LOG_INFO,
1143 "Creating QRhi with backend %s for window %p (wflags 0x%X)\n"
1144 " Graphics API debug/validation layers: %d\n"
1145 " Debug markers: %d\n"
1147 " Prefer software device: %d%s\n"
1148 " Shader/pipeline cache collection: %d",
1149 qPrintable(backendName), window,
int(window->flags()), debugLayer,
1150 debugMarkers, timestamps, preferSoftware, forcePreferSwRenderer ?
" [FORCED]" :
"", pipelineCacheSave);
1153 flags |= QRhi::SuppressSmokeTestWarnings;
1155 flags |= QRhi::EnableDebugMarkers;
1157 flags |= QRhi::EnableTimestamps;
1159 flags |= QRhi::PreferSoftwareRenderer;
1160 if (pipelineCacheSave)
1161 flags |= QRhi::EnablePipelineCacheDataSave;
1163 QRhiAdapter *rhiAdapter = customDevD->type == QQuickGraphicsDevicePrivate::Type::RhiAdapter ? customDevD->u.rhiAdapter :
nullptr;
1164 const QRhi::Implementation backend = rhiBackend();
1165 if (backend == QRhi::Null) {
1166 QRhiNullInitParams rhiParams;
1167 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1169#if QT_CONFIG(opengl)
1170 if (backend == QRhi::OpenGLES2) {
1171 const QSurfaceFormat format = window->requestedFormat();
1172 QRhiGles2InitParams rhiParams;
1173 rhiParams.format = format;
1174 rhiParams.fallbackSurface = offscreenSurface;
1175 rhiParams.window = window;
1176 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::OpenGLContext) {
1177 QRhiGles2NativeHandles importDev;
1178 importDev.context = customDevD->u.context;
1179 qCDebug(QSG_LOG_INFO,
"Using existing QOpenGLContext %p", importDev.context);
1180 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1182 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1186 Q_UNUSED(offscreenSurface);
1187 if (backend == QRhi::OpenGLES2)
1188 qWarning(
"OpenGL was requested for Qt Quick, but this build of Qt has no OpenGL support.");
1190#if QT_CONFIG(vulkan)
1191 if (backend == QRhi::Vulkan) {
1193 QVulkanDefaultInstance::setFlag(QVulkanDefaultInstance::EnableValidation,
true);
1194 QRhiVulkanInitParams rhiParams;
1195 prepareWindowForRhi(window);
1196 rhiParams.inst = window->vulkanInstance();
1197 if (!rhiParams.inst)
1198 qWarning(
"No QVulkanInstance set for QQuickWindow, this is wrong.");
1199 if (window->handle())
1200 rhiParams.window = window;
1201 rhiParams.deviceExtensions = wd->graphicsConfig.deviceExtensions();
1202 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceObjects) {
1203 QRhiVulkanNativeHandles importDev;
1204 importDev.physDev =
reinterpret_cast<VkPhysicalDevice>(customDevD->u.deviceObjects.physicalDevice);
1205 importDev.dev =
reinterpret_cast<VkDevice>(customDevD->u.deviceObjects.device);
1206 importDev.gfxQueueFamilyIdx = customDevD->u.deviceObjects.queueFamilyIndex;
1207 importDev.gfxQueueIdx = customDevD->u.deviceObjects.queueIndex;
1208 qCDebug(QSG_LOG_INFO,
"Using existing native Vulkan physical device %p device %p graphics queue family index %d",
1209 importDev.physDev, importDev.dev, importDev.gfxQueueFamilyIdx);
1210 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1211 }
else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::PhysicalDevice) {
1212 QRhiVulkanNativeHandles importDev;
1213 importDev.physDev =
reinterpret_cast<VkPhysicalDevice>(customDevD->u.physicalDevice.physicalDevice);
1214 qCDebug(QSG_LOG_INFO,
"Using existing native Vulkan physical device %p", importDev.physDev);
1215 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1217 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1221 if (backend == QRhi::Vulkan)
1222 qWarning(
"Vulkan was requested for Qt Quick, but this build of Qt has no Vulkan support.");
1225 if (backend == QRhi::D3D11) {
1226 QRhiD3D11InitParams rhiParams;
1227 rhiParams.enableDebugLayer = debugLayer;
1228 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndContext) {
1229 QRhiD3D11NativeHandles importDev;
1230 importDev.dev = customDevD->u.deviceAndContext.device;
1231 importDev.context = customDevD->u.deviceAndContext.context;
1232 qCDebug(QSG_LOG_INFO,
"Using existing native D3D11 device %p and context %p",
1233 importDev.dev, importDev.context);
1234 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1235 }
else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Adapter) {
1236 QRhiD3D11NativeHandles importDev;
1237 importDev.adapterLuidLow = customDevD->u.adapter.luidLow;
1238 importDev.adapterLuidHigh = customDevD->u.adapter.luidHigh;
1239 importDev.featureLevel = customDevD->u.adapter.featureLevel;
1240 qCDebug(QSG_LOG_INFO,
"Using D3D11 adapter LUID %u, %d and feature level %d",
1241 importDev.adapterLuidLow, importDev.adapterLuidHigh, importDev.featureLevel);
1242 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1244 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1245 if (!rhi && attemptReinitWithSwRastUponFail() && !flags.testFlag(QRhi::PreferSoftwareRenderer) && !rhiAdapter) {
1246 qCDebug(QSG_LOG_INFO,
"Failed to create a D3D device with default settings; "
1247 "attempting to get a software rasterizer backed device instead");
1248 flags |= QRhi::PreferSoftwareRenderer;
1249 rhi = QRhi::create(backend, &rhiParams, flags);
1252 }
else if (backend == QRhi::D3D12) {
1253 QRhiD3D12InitParams rhiParams;
1254 rhiParams.enableDebugLayer = debugLayer;
1255 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndContext) {
1256 QRhiD3D12NativeHandles importDev;
1257 importDev.dev = customDevD->u.deviceAndContext.device;
1258 qCDebug(QSG_LOG_INFO,
"Using existing native D3D12 device %p", importDev.dev);
1259 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1260 }
else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Adapter) {
1261 QRhiD3D12NativeHandles importDev;
1262 importDev.adapterLuidLow = customDevD->u.adapter.luidLow;
1263 importDev.adapterLuidHigh = customDevD->u.adapter.luidHigh;
1264 importDev.minimumFeatureLevel = customDevD->u.adapter.featureLevel;
1265 qCDebug(QSG_LOG_INFO,
"Using D3D12 adapter LUID %u, %d and minimum feature level %d",
1266 importDev.adapterLuidLow, importDev.adapterLuidHigh, importDev.minimumFeatureLevel);
1267 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1269 QRhiAdapter *rhiAdapter = customDevD->type == QQuickGraphicsDevicePrivate::Type::RhiAdapter ? customDevD->u.rhiAdapter :
nullptr;
1270 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1271 if (!rhi && attemptReinitWithSwRastUponFail() && !flags.testFlag(QRhi::PreferSoftwareRenderer) && !rhiAdapter) {
1272 qCDebug(QSG_LOG_INFO,
"Failed to create a D3D device with default settings; "
1273 "attempting to get a software rasterizer backed device instead");
1274 flags |= QRhi::PreferSoftwareRenderer;
1275 rhi = QRhi::create(backend, &rhiParams, flags);
1281 if (backend == QRhi::Metal) {
1282 QRhiMetalInitParams rhiParams;
1283 if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndCommandQueue) {
1284 QRhiMetalNativeHandles importDev;
1285 importDev.dev = (MTLDevice *) customDevD->u.deviceAndCommandQueue.device;
1286 importDev.cmdQueue = (MTLCommandQueue *) customDevD->u.deviceAndCommandQueue.cmdQueue;
1287 qCDebug(QSG_LOG_INFO,
"Using existing native Metal device %p and command queue %p",
1288 importDev.dev, importDev.cmdQueue);
1289 rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
1291 rhi = QRhi::create(backend, &rhiParams, flags,
nullptr, rhiAdapter);
1297 qCDebug(QSG_LOG_INFO,
"Created QRhi %p for window %p", rhi, window);
1298 preparePipelineCache(rhi, window);
1300 qWarning(
"Failed to create RHI (backend %d)", backend);
1303 return { rhi,
true };
1306void QSGRhiSupport::destroyRhi(QRhi *rhi,
const QQuickGraphicsConfiguration &config)
1311 if (!rhi->isDeviceLost())
1312 finalizePipelineCache(rhi, config);
1317QImage QSGRhiSupport::grabAndBlockInCurrentFrame(QRhi *rhi, QRhiCommandBuffer *cb, QRhiTexture *src)
1319 Q_ASSERT(rhi->isRecordingFrame());
1321 QRhiReadbackResult result;
1322 QRhiReadbackDescription readbackDesc(src);
1323 QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
1324 resourceUpdates->readBackTexture(readbackDesc, &result);
1326 cb->resourceUpdate(resourceUpdates);
1330 QImage::Format imageFormat;
1331 if (result.format == QRhiTexture::BGRA8) {
1332#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1333 imageFormat = QImage::Format_ARGB32_Premultiplied;
1335 imageFormat = QImage::Format_RGBA8888_Premultiplied;
1339 imageFormat = QImage::Format_RGBA8888_Premultiplied;
1342 const uchar *p =
reinterpret_cast<
const uchar *>(result.data.constData());
1343 const QImage img(p, result.pixelSize.width(), result.pixelSize.height(), imageFormat);
1345 if (rhi->isYUpInFramebuffer())
1346 return img.flipped();
1351QImage QSGRhiSupport::grabOffscreen(QQuickWindow *window)
1358 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
1361 Q_ASSERT(!wd->renderControl);
1363 QScopedPointer<QOffscreenSurface> offscreenSurface(maybeCreateOffscreenSurface(window));
1364 RhiCreateResult rhiResult = createRhi(window, offscreenSurface.data());
1365 if (!rhiResult.rhi) {
1366 qWarning(
"Failed to initialize QRhi for offscreen readback");
1369 std::unique_ptr<QRhi> rhiOwner(rhiResult.rhi);
1370 QRhi *rhi = rhiResult.own ? rhiOwner.get() : rhiOwner.release();
1372 const QSize pixelSize = window->size() * window->devicePixelRatio();
1373 QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, pixelSize, 1,
1374 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
1375 if (!texture->create()) {
1376 qWarning(
"Failed to build texture for offscreen readback");
1379 QScopedPointer<QRhiRenderBuffer> depthStencil(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, 1));
1380 if (!depthStencil->create()) {
1381 qWarning(
"Failed to create depth/stencil buffer for offscreen readback");
1384 QRhiTextureRenderTargetDescription rtDesc(texture.data());
1385 rtDesc.setDepthStencilBuffer(depthStencil.data());
1386 QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
1387 QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
1388 rt->setRenderPassDescriptor(rpDesc.data());
1389 if (!rt->create()) {
1390 qWarning(
"Failed to build render target for offscreen readback");
1396 QSGDefaultRenderContext::InitParams params;
1398 params.sampleCount = 1;
1399 params.initialSurfacePixelSize = pixelSize;
1400 params.maybeSurface = window;
1401 wd->context->initialize(¶ms);
1405 auto renderTarget = QQuickRenderTarget::fromRhiRenderTarget(rt.data());
1408 renderTarget.setDevicePixelRatio(window->devicePixelRatio());
1409 window->setRenderTarget(renderTarget);
1411 QRhiCommandBuffer *cb =
nullptr;
1412 if (rhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess) {
1413 qWarning(
"Failed to start recording the frame for offscreen readback");
1417 wd->setCustomCommandBuffer(cb);
1419 wd->syncSceneGraph();
1420 wd->renderSceneGraph();
1421 wd->setCustomCommandBuffer(
nullptr);
1423 QImage image = grabAndBlockInCurrentFrame(rhi, cb, texture.data());
1424 rhi->endOffscreenFrame();
1426 image.setDevicePixelRatio(window->devicePixelRatio());
1427 wd->cleanupNodesOnShutdown();
1428 wd->context->invalidate();
1430 window->setRenderTarget(QQuickRenderTarget());
1437QImage QSGRhiSupport::grabOffscreenForProtectedContent(QQuickWindow *window)
1445 QScopedPointer<QQuickWindow> offscreenWindow;
1446 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
1449 Q_ASSERT(!wd->renderControl);
1453 if (window->requestedFormat().testOption(QSurfaceFormat::ProtectedContent)) {
1454 QSurfaceFormat surfaceFormat = window->requestedFormat();
1455 surfaceFormat.setOption(QSurfaceFormat::ProtectedContent,
false);
1456 offscreenWindow.reset(
new QQuickWindow());
1457 offscreenWindow->setFormat(surfaceFormat);
1460 QScopedPointer<QOffscreenSurface> offscreenSurface(maybeCreateOffscreenSurface(window));
1461 RhiCreateResult rhiResult = createRhi(offscreenWindow.data() ? offscreenWindow.data() : window, offscreenSurface.data());
1462 if (!rhiResult.rhi) {
1463 qWarning(
"Failed to initialize QRhi for offscreen readback");
1466 QScopedPointer<QRhi> rhiOwner(rhiResult.rhi);
1467 QRhi *rhi = rhiResult.own ? rhiOwner.data() : rhiOwner.take();
1469 const QSize pixelSize = window->size() * window->devicePixelRatio();
1470 QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, pixelSize, 1,
1471 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
1472 if (!texture->create()) {
1473 qWarning(
"Failed to build texture for offscreen readback");
1476 QScopedPointer<QRhiRenderBuffer> depthStencil(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, 1));
1477 if (!depthStencil->create()) {
1478 qWarning(
"Failed to create depth/stencil buffer for offscreen readback");
1481 QRhiTextureRenderTargetDescription rtDesc(texture.data());
1482 rtDesc.setDepthStencilBuffer(depthStencil.data());
1483 QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
1484 QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
1485 rt->setRenderPassDescriptor(rpDesc.data());
1486 if (!rt->create()) {
1487 qWarning(
"Failed to build render target for offscreen readback");
1492 QRhi *currentRhi = wd->rhi;
1495 QSGDefaultRenderContext::InitParams params;
1497 params.sampleCount = 1;
1498 params.initialSurfacePixelSize = pixelSize;
1499 params.maybeSurface = window;
1500 wd->context->initialize(¶ms);
1503 QQuickRenderTarget currentRenderTarget = window->renderTarget();
1506 window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(rt.data()));
1508 QRhiCommandBuffer *cb =
nullptr;
1509 if (rhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess) {
1510 qWarning(
"Failed to start recording the frame for offscreen readback");
1514 wd->setCustomCommandBuffer(cb);
1516 wd->syncSceneGraph();
1517 wd->renderSceneGraph();
1518 wd->setCustomCommandBuffer(
nullptr);
1520 QImage image = grabAndBlockInCurrentFrame(rhi, cb, texture.data());
1521 rhi->endOffscreenFrame();
1523 image.setDevicePixelRatio(window->devicePixelRatio());
1527 wd->cleanupNodesOnShutdown();
1528 wd->context->invalidate();
1530 window->setRenderTarget(QQuickRenderTarget());
1535 window->setRenderTarget(currentRenderTarget);
1536 wd->rhi = currentRhi;
1537 params.rhi = currentRhi;
1538 wd->context->initialize(¶ms);
1545void QSGRhiSupport::applySwapChainFormat(QRhiSwapChain *scWithWindowSet, QQuickWindow *window)
1547 Q_ASSERT(scWithWindowSet->window() == window);
1549 QRhiSwapChain::Format swapChainFormat = QRhiSwapChain::SDR;
1551 QByteArray hdrRequest = qgetenv(
"QSG_RHI_HDR");
1552 if (hdrRequest.isEmpty())
1553 hdrRequest = window->property(
"_qt_sg_hdr_format").toByteArray();
1555 if (!hdrRequest.isEmpty()) {
1556 hdrRequest = hdrRequest.toLower();
1557 if (hdrRequest == QByteArrayLiteral(
"scrgb") || hdrRequest == QByteArrayLiteral(
"extendedsrgblinear"))
1558 swapChainFormat = QRhiSwapChain::HDRExtendedSrgbLinear;
1559 else if (hdrRequest == QByteArrayLiteral(
"hdr10"))
1560 swapChainFormat = QRhiSwapChain::HDR10;
1561 else if (hdrRequest == QByteArrayLiteral(
"p3"))
1562 swapChainFormat = QRhiSwapChain::HDRExtendedDisplayP3Linear;
1565 const char *fmtStr =
"unknown";
1566 switch (swapChainFormat) {
1567 case QRhiSwapChain::SDR:
1570 case QRhiSwapChain::HDRExtendedSrgbLinear:
1573 case QRhiSwapChain::HDR10:
1576 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
1577 fmtStr =
"Extended Linear Display P3";
1583 if (!scWithWindowSet->isFormatSupported(swapChainFormat)) {
1584 if (swapChainFormat != QRhiSwapChain::SDR) {
1585 qCDebug(QSG_LOG_INFO,
"Requested a %s swapchain but it is reported to be unsupported with the current display(s). "
1586 "In multi-screen configurations make sure the window is located on a HDR-enabled screen. "
1587 "Request ignored, using SDR swapchain.", fmtStr);
1592 scWithWindowSet->setFormat(swapChainFormat);
1594 if (swapChainFormat != QRhiSwapChain::SDR) {
1595 qCDebug(QSG_LOG_INFO,
"Creating %s swapchain", fmtStr);
1596 qCDebug(QSG_LOG_INFO) <<
"HDR output info:" << scWithWindowSet->hdrInfo();
1600QRhiTexture::Format QSGRhiSupport::toRhiTextureFormat(uint nativeFormat, QRhiTexture::Flags *flags)
const
1602 switch (m_rhiBackend) {
1603#if QT_CONFIG(vulkan)
1605 return toRhiTextureFormatFromVulkan(nativeFormat, flags);
1607#if QT_CONFIG(opengl)
1608 case QRhi::OpenGLES2:
1610 return toRhiTextureFormatFromGL(nativeFormat, flags);
1615 return toRhiTextureFormatFromDXGI(nativeFormat, flags);
1619 return toRhiTextureFormatFromMetal(nativeFormat, flags);
1622 return QRhiTexture::UnknownFormat;
1624 Q_UNUSED(nativeFormat)
1628bool QSGRhiSupport::attemptReinitWithSwRastUponFail()
const
1630 const QRhi::Implementation backend = rhiBackend();
1636 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)