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
21{
22public:
24 ~ThreadLocalRhiHolder() { resetRhi(); }
25
26 QRhi *ensureRhi(QRhi *referenceRhi)
27 {
28 if (m_rhi || m_cpuOnly)
29 return m_rhi.get();
30
31 QRhi::Implementation referenceBackend = referenceRhi ? referenceRhi->backend() : QRhi::Null;
32 const QPlatformIntegration *qpa = QGuiApplicationPrivate::platformIntegration();
33
34 if (qpa && qpa->hasCapability(QPlatformIntegration::RhiBasedRendering)) {
35
36#if QT_CONFIG(metal)
37 if (canUseRhiImpl(QRhi::Metal, referenceBackend)) {
38 QRhiMetalInitParams params;
39 m_rhi.reset(QRhi::create(QRhi::Metal, &params));
40 }
41#endif
42
43#if defined(Q_OS_WIN)
44 if (!m_rhi && canUseRhiImpl(QRhi::D3D11, referenceBackend)) {
45 QRhiD3D11InitParams params;
46 m_rhi.reset(QRhi::create(QRhi::D3D11, &params));
47 }
48#endif
49
50#if QT_CONFIG(opengl)
51 if (!m_rhi && canUseRhiImpl(QRhi::OpenGLES2, referenceBackend)) {
52 if (qpa->hasCapability(QPlatformIntegration::OpenGL)
53 && !QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets)) {
54
55 m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
56 QRhiGles2InitParams params;
57 params.fallbackSurface = m_fallbackSurface.get();
58 if (referenceBackend == QRhi::OpenGLES2)
59 params.shareContext = static_cast<const QRhiGles2NativeHandles *>(
60 referenceRhi->nativeHandles())
61 ->context;
62 m_rhi.reset(QRhi::create(QRhi::OpenGLES2, &params));
63
64# if defined(Q_OS_ANDROID)
65 // reset RHI state on application suspension, as this will be invalid after
66 // resuming
67 if (!m_appStateChangedConnection) {
68 if (!m_eventsReceiver)
69 m_eventsReceiver = std::make_unique<QObject>();
70
71 auto onStateChanged = [this](auto state) {
72 if (state == Qt::ApplicationSuspended)
73 resetRhi();
74 };
75
76 m_appStateChangedConnection =
77 QObject::connect(qApp, &QGuiApplication::applicationStateChanged,
78 m_eventsReceiver.get(), onStateChanged);
79 }
80# endif
81 }
82 }
83#endif
84 }
85
86 if (!m_rhi) {
87 m_cpuOnly = true;
88 qWarning() << Q_FUNC_INFO << ": No RHI backend. Using CPU conversion.";
89 }
90
91 return m_rhi.get();
92 }
93
94 void setPreferredBackend(QRhi::Implementation backend)
95 {
96 m_preferredBackend = backend;
97 resetRhi();
98 }
99
100private:
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 (m_preferredBackend != QRhi::Null)
119 return implementation == m_preferredBackend;
120
121 // Can use (assuming platform and configuration allow)
122 return true;
123 }
124
125private:
126 QRhi::Implementation m_preferredBackend = QRhi::Null;
127 std::unique_ptr<QRhi> m_rhi;
128#if QT_CONFIG(opengl)
130#endif
131 bool m_cpuOnly = false;
132#if defined(Q_OS_ANDROID)
134 // we keep and check QMetaObject::Connection because the sender, qApp,
135 // can be recreated and the connection invalidated.
137#endif
138};
139
140Q_CONSTINIT thread_local std::optional<ThreadLocalRhiHolder> g_threadLocalRhiHolder;
141
143{
144 if (QThread::isMainThread()) {
145 // ensure cleanup in qApp dtor
146 qAddPostRoutine([] {
147 g_threadLocalRhiHolder.reset();
148 });
149 }
150}
151
152} // namespace
153
154QRhi *qEnsureThreadLocalRhi(QRhi *referenceRhi)
155{
156 if (!g_threadLocalRhiHolder)
157 g_threadLocalRhiHolder.emplace();
158
159 return g_threadLocalRhiHolder->ensureRhi(referenceRhi);
160}
161
162void qSetPreferredThreadLocalRhiBackend(QRhi::Implementation backend)
163{
164 g_threadLocalRhiHolder->setPreferredBackend(backend);
165}
166
167QT_END_NAMESPACE
void setPreferredBackend(QRhi::Implementation backend)
Combined button and popup list for selecting options.
QRhi * qEnsureThreadLocalRhi(QRhi *referenceRhi)
void qSetPreferredThreadLocalRhiBackend(QRhi::Implementation backend)