Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qthreadlocalrhi.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 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
5
6#include <QtCore/qcoreapplication.h>
7#include <QtCore/qthreadstorage.h>
8#include <QtGui/private/qguiapplication_p.h>
9#include <QtGui/qoffscreensurface.h>
10#include <QtGui/qpa/qplatformintegration.h>
11
12#if defined(Q_OS_ANDROID)
13# include <QtCore/qmetaobject.h>
14#endif
15
17
18namespace {
19
20static thread_local QRhi::Implementation s_preferredBackend = QRhi::Null;
21
22#if QT_CONFIG(opengl)
23
24bool openGLCapsSupported(const QPlatformIntegration &qpa)
25{
26 return qpa.hasCapability(QPlatformIntegration::OpenGL) &&
27 !QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets) &&
28 (QThread::isMainThread() ||
29 (qpa.hasCapability(QPlatformIntegration::ThreadedOpenGL) &&
30 qpa.hasCapability(QPlatformIntegration::OffscreenSurface)));
31}
32#endif
33
35{
36public:
38
39 QRhi *ensureRhi([[maybe_unused]] QRhi::Implementation backend)
40 {
41 if (m_rhi || m_cpuOnly)
42 return m_rhi.get();
43
44 const QPlatformIntegration *qpa = QGuiApplicationPrivate::platformIntegration();
45
46 if (qpa && qpa->hasCapability(QPlatformIntegration::RhiBasedRendering)) {
47
48#if QT_CONFIG(metal)
49 if (canUseRhiImpl(QRhi::Metal, backend)) {
50 QRhiMetalInitParams params;
51 m_rhi.reset(QRhi::create(QRhi::Metal, &params));
52 }
53#endif
54
55#if defined(Q_OS_WIN)
56 if (!m_rhi && canUseRhiImpl(QRhi::D3D11, backend)) {
57 QRhiD3D11InitParams params;
58 m_rhi.reset(QRhi::create(QRhi::D3D11, &params));
59 }
60#endif
61
62#if QT_CONFIG(opengl)
63 if (!m_rhi && canUseRhiImpl(QRhi::OpenGLES2, backend)) {
64 if (openGLCapsSupported(*qpa)) {
65
66 m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
67 QRhiGles2InitParams params;
68 params.fallbackSurface = m_fallbackSurface.get();
69 m_rhi.reset(QRhi::create(QRhi::OpenGLES2, &params));
70
71# if defined(Q_OS_ANDROID)
72 // reset RHI state on application suspension, as this will be invalid after
73 // resuming
74 if (!m_appStateChangedConnection) {
75 if (!m_eventsReceiver)
76 m_eventsReceiver = std::make_unique<QObject>();
77
78 auto onStateChanged = [this](auto state) {
79 if (state == Qt::ApplicationSuspended)
80 resetRhi();
81 };
82
83 m_appStateChangedConnection =
84 QObject::connect(qApp, &QGuiApplication::applicationStateChanged,
85 m_eventsReceiver.get(), onStateChanged);
86 }
87# endif
88 }
89 }
90#endif
91 }
92
93 if (!m_rhi) {
94 m_cpuOnly = true;
95 qWarning() << Q_FUNC_INFO << ": No RHI backend. Using CPU conversion.";
96 }
97
98 return m_rhi.get();
99 }
100
101 void resetRhi()
102 {
103 m_rhi.reset();
104#if QT_CONFIG(opengl)
105 m_fallbackSurface.reset();
106#endif
107 m_cpuOnly = false;
108 }
109
110 bool canUseRhiImpl(const QRhi::Implementation implementation,
111 const QRhi::Implementation reference)
112 {
113 // First priority goes to reference backend
114 if (reference != QRhi::Null)
115 return implementation == reference;
116
117 // If no reference, but preference exists, compare to that
118 if (s_preferredBackend != QRhi::Null)
119 return implementation == s_preferredBackend;
120
121 // Can use (assuming platform and configuration allow)
122 return true;
123 }
124
125private:
126 std::unique_ptr<QRhi> m_rhi;
127#if QT_CONFIG(opengl)
129#endif
130 bool m_cpuOnly = false;
131#if defined(Q_OS_ANDROID)
133 // we keep and check QMetaObject::Connection because the sender, qApp,
134 // can be recreated and the connection invalidated.
136#endif
137};
138
140
141}
142
143QRhi *qEnsureThreadLocalRhi(QRhi::Implementation backend)
144{
145 return g_threadLocalRhiHolder.localData().ensureRhi(backend);
146}
147
148void qSetPreferredThreadLocalRhiBackend(QRhi::Implementation backend)
149{
150 if (s_preferredBackend != backend) {
151 s_preferredBackend = backend;
152 g_threadLocalRhiHolder.localData().resetRhi();
153 }
154}
155
156QT_END_NAMESPACE
QRhi * ensureRhi(QRhi::Implementation backend)
bool canUseRhiImpl(const QRhi::Implementation implementation, const QRhi::Implementation reference)
Combined button and popup list for selecting options.
static QRhi::Implementation s_preferredBackend
QThreadStorage< ThreadLocalRhiHolder > g_threadLocalRhiHolder
QRhi * qEnsureThreadLocalRhi(QRhi::Implementation backend)
void qSetPreferredThreadLocalRhiBackend(QRhi::Implementation backend)