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(QRhi *referenceRhi)
40 {
41 if (m_rhi || m_cpuOnly)
42 return m_rhi.get();
43
44 [[maybe_unused]] QRhi::Implementation referenceBackend =
45 referenceRhi ? referenceRhi->backend() : QRhi::Null;
46 const QPlatformIntegration *qpa = QGuiApplicationPrivate::platformIntegration();
47
48 if (qpa && qpa->hasCapability(QPlatformIntegration::RhiBasedRendering)) {
49
50#if QT_CONFIG(metal)
51 if (canUseRhiImpl(QRhi::Metal, referenceBackend)) {
52 QRhiMetalInitParams params;
53 m_rhi.reset(QRhi::create(QRhi::Metal, &params));
54 }
55#endif
56
57#if defined(Q_OS_WIN)
58 if (!m_rhi && canUseRhiImpl(QRhi::D3D11, referenceBackend)) {
59 QRhiD3D11InitParams params;
60 m_rhi.reset(QRhi::create(QRhi::D3D11, &params));
61 }
62#endif
63
64#if QT_CONFIG(opengl)
65 if (!m_rhi && canUseRhiImpl(QRhi::OpenGLES2, referenceBackend)) {
66 if (openGLCapsSupported(*qpa)) {
67
68 m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
69 QRhiGles2InitParams params;
70 params.fallbackSurface = m_fallbackSurface.get();
71 if (referenceBackend == QRhi::OpenGLES2)
72 params.shareContext = static_cast<const QRhiGles2NativeHandles *>(
73 referenceRhi->nativeHandles())
74 ->context;
75 m_rhi.reset(QRhi::create(QRhi::OpenGLES2, &params));
76
77# if defined(Q_OS_ANDROID)
78 // reset RHI state on application suspension, as this will be invalid after
79 // resuming
80 if (!m_appStateChangedConnection) {
81 if (!m_eventsReceiver)
82 m_eventsReceiver = std::make_unique<QObject>();
83
84 auto onStateChanged = [this](auto state) {
85 if (state == Qt::ApplicationSuspended)
86 resetRhi();
87 };
88
89 m_appStateChangedConnection =
90 QObject::connect(qApp, &QGuiApplication::applicationStateChanged,
91 m_eventsReceiver.get(), onStateChanged);
92 }
93# endif
94 }
95 }
96#endif
97 }
98
99 if (!m_rhi) {
100 m_cpuOnly = true;
101 qWarning() << Q_FUNC_INFO << ": No RHI backend. Using CPU conversion.";
102 }
103
104 return m_rhi.get();
105 }
106
107 void resetRhi()
108 {
109 m_rhi.reset();
110#if QT_CONFIG(opengl)
111 m_fallbackSurface.reset();
112#endif
113 m_cpuOnly = false;
114 }
115
116 bool canUseRhiImpl(const QRhi::Implementation implementation,
117 const QRhi::Implementation reference)
118 {
119 // First priority goes to reference backend
120 if (reference != QRhi::Null)
121 return implementation == reference;
122
123 // If no reference, but preference exists, compare to that
124 if (s_preferredBackend != QRhi::Null)
125 return implementation == s_preferredBackend;
126
127 // Can use (assuming platform and configuration allow)
128 return true;
129 }
130
131private:
132 std::unique_ptr<QRhi> m_rhi;
133#if QT_CONFIG(opengl)
135#endif
136 bool m_cpuOnly = false;
137#if defined(Q_OS_ANDROID)
139 // we keep and check QMetaObject::Connection because the sender, qApp,
140 // can be recreated and the connection invalidated.
142#endif
143};
144
146
147}
148
149QRhi *qEnsureThreadLocalRhi(QRhi *referenceRhi)
150{
151 return g_threadLocalRhiHolder.localData().ensureRhi(referenceRhi);
152}
153
154void qSetPreferredThreadLocalRhiBackend(QRhi::Implementation backend)
155{
156 s_preferredBackend = backend;
157 g_threadLocalRhiHolder.localData().resetRhi();
158}
159
160QT_END_NAMESPACE
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 *referenceRhi)
void qSetPreferredThreadLocalRhiBackend(QRhi::Implementation backend)