Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qbackingstorerhisupport.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 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#include <qpa/qplatformintegration.h>
6#include <private/qguiapplication_p.h>
7
8#if QT_CONFIG(opengl)
9#include <QtGui/qoffscreensurface.h>
10#include <QtGui/private/qopenglcontext_p.h>
11#endif
12
13#if QT_CONFIG(vulkan)
14#include <QtGui/private/qvulkandefaultinstance_p.h>
15#endif
16
18
19Q_DECLARE_LOGGING_CATEGORY(lcQpaBackingStore)
20
22{
23 reset();
24}
25
26void QBackingStoreRhiSupport::SwapchainData::reset()
27{
28 delete swapchain;
29 delete renderPassDescriptor;
30 delete windowWatcher;
31 *this = {};
32}
33
35{
36 for (SwapchainData &d : m_swapchains)
37 d.reset();
38
39 m_swapchains.clear();
40
41 delete m_rhi;
42 m_rhi = nullptr;
43
44 delete m_openGLFallbackSurface;
45 m_openGLFallbackSurface = nullptr;
46}
47
49{
51 return false;
52
53 // note: m_window may be null (special case for fully offscreen rendering)
54
55 QRhi *rhi = nullptr;
56 QOffscreenSurface *surface = nullptr;
57 QRhi::Flags flags;
58
59#if QT_CONFIG(opengl)
60 if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::OpenGL) {
61 surface = QRhiGles2InitParams::newFallbackSurface(m_format);
63 params.fallbackSurface = surface;
64 params.window = m_window;
65 params.format = m_format;
66 params.shareContext = qt_gl_global_share_context();
68 }
69#endif
70
71#ifdef Q_OS_WIN
72 if (!rhi) {
75 params.enableDebugLayer = m_config.isDebugLayerEnabled();
77 if (!rhi && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
78 qCDebug(lcQpaBackingStore, "Failed to create a D3D device with default settings; "
79 "attempting to get a software rasterizer backed device instead");
82 }
83 } else if (m_config.api() == QPlatformBackingStoreRhiConfig::D3D12) {
84 QRhiD3D12InitParams params;
85 params.enableDebugLayer = m_config.isDebugLayerEnabled();
87 }
88 }
89#endif
90
91#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
92 if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::Metal) {
94 // For parity with Qt Quick, fall back to OpenGL when there is no Metal (f.ex. in macOS virtual machines).
97 } else {
98 qCDebug(lcQpaBackingStore, "Metal does not seem to be supported. Falling back to OpenGL.");
100 }
101 }
102#endif
103
104#if QT_CONFIG(vulkan)
105 if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::Vulkan) {
106 if (m_config.isDebugLayerEnabled())
107 QVulkanDefaultInstance::setFlag(QVulkanDefaultInstance::EnableValidation);
109 if (m_window) {
110 if (!m_window->vulkanInstance())
111 m_window->setVulkanInstance(QVulkanDefaultInstance::instance());
112 params.inst = m_window->vulkanInstance();
113 } else {
114 params.inst = QVulkanDefaultInstance::instance();
115 }
116 if (!params.inst) {
117 qWarning("No QVulkanInstance set for the top-level window, this is wrong.");
118 return false;
119 }
120 params.window = m_window;
122 }
123#endif
124
125 if (!rhi) {
126 qWarning("Failed to create QRhi for QBackingStoreRhiSupport");
127 delete surface;
128 return false;
129 }
130
131 m_rhi = rhi;
132 m_openGLFallbackSurface = surface;
133 return true;
134}
135
137{
138 auto it = m_swapchains.constFind(window);
139 if (it != m_swapchains.constEnd())
140 return it.value().swapchain;
141
142 QRhiSwapChain *swapchain = nullptr;
143 QRhiRenderPassDescriptor *rp = nullptr;
144 if (window && m_rhi) {
145 QRhiSwapChain::Flags flags;
146 const QSurfaceFormat format = window->requestedFormat();
147 if (format.swapInterval() == 0)
149 if (format.alphaBufferSize() > 0)
151#if QT_CONFIG(vulkan)
152 if (m_config.api() == QPlatformBackingStoreRhiConfig::Vulkan && !window->vulkanInstance())
153 window->setVulkanInstance(QVulkanDefaultInstance::instance());
154#endif
155 qCDebug(lcQpaBackingStore) << "Creating swapchain for window" << window;
156 swapchain = m_rhi->newSwapChain();
157 swapchain->setWindow(window);
158 swapchain->setFlags(flags);
159 rp = swapchain->newCompatibleRenderPassDescriptor();
160 swapchain->setRenderPassDescriptor(rp);
161 if (!swapchain->createOrResize()) {
162 qWarning("Failed to create swapchain for window flushed with an RHI-enabled backingstore");
163 delete rp;
164 return nullptr;
165 }
166 }
167 if (swapchain) {
168 SwapchainData d;
169 d.swapchain = swapchain;
170 d.renderPassDescriptor = rp;
171 d.windowWatcher = new QBackingStoreRhiSupportWindowWatcher(this);
172 m_swapchains.insert(window, d);
173 window->installEventFilter(d.windowWatcher);
174 }
175 return swapchain;
176}
177
179{
180 if (event->type() == QEvent::PlatformSurface
182 {
184 auto it = m_rhiSupport->m_swapchains.find(window);
185 if (it != m_rhiSupport->m_swapchains.end()) {
186 qCDebug(lcQpaBackingStore) << "SurfaceAboutToBeDestroyed received for tracked window" << window << "cleaning up swapchain";
187 auto data = *it;
188 m_rhiSupport->m_swapchains.erase(it);
189 data.reset(); // deletes 'this'
190 }
191 }
192 return false;
193}
194
196{
198 switch (config.api()) {
202 break;
205 break;
208 break;
211 break;
212 default:
213 break;
214 }
215 return type;
216}
217
219{
220 switch (api) {
222 return QRhi::OpenGLES2;
224 return QRhi::Metal;
226 return QRhi::Vulkan;
228 return QRhi::D3D11;
230 return QRhi::D3D12;
232 return QRhi::Null;
233 default:
234 break;
235 }
236 return QRhi::Null;
237}
238
240{
242 static bool checked = false;
243
244 if (!checked) {
245 checked = true;
246
247 const bool alwaysRhi = qEnvironmentVariableIntValue("QT_WIDGETS_RHI");
248 if (alwaysRhi)
249 config.setEnabled(true);
250
251 // if enabled, choose an api
252 if (config.isEnabled()) {
253#if defined(Q_OS_WIN)
255#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
257#elif QT_CONFIG(opengl)
259#elif QT_CONFIG(vulkan)
261#else
262 qWarning("QT_WIDGETS_RHI is set but no backend is available; ignoring");
263 return false;
264#endif
265
266 // the env.var. will always override
267 if (qEnvironmentVariableIsSet("QT_WIDGETS_RHI_BACKEND")) {
268 const QString backend = qEnvironmentVariable("QT_WIDGETS_RHI_BACKEND");
269#ifdef Q_OS_WIN
270 if (backend == QStringLiteral("d3d11") || backend == QStringLiteral("d3d"))
272 if (backend == QStringLiteral("d3d12"))
274#endif
275#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
276 if (backend == QStringLiteral("metal"))
278#endif
279#if QT_CONFIG(opengl)
280 if (backend == QStringLiteral("opengl") || backend == QStringLiteral("gl"))
282#endif
283#if QT_CONFIG(vulkan)
284 if (backend == QStringLiteral("vulkan"))
286#endif
287 }
288
289 if (qEnvironmentVariableIntValue("QT_WIDGETS_RHI_DEBUG_LAYER"))
290 config.setDebugLayer(true);
291 }
292
293 qCDebug(lcQpaBackingStore) << "Check for forced use of QRhi resulted in enable"
294 << config.isEnabled() << "with api" << QRhi::backendName(apiToRhiBackend(config.api()));
295 }
296
297 if (config.isEnabled()) {
298 if (outConfig)
299 *outConfig = config;
300 if (outType)
301 *outType = surfaceTypeForConfig(config);
302 return true;
303 }
304 return false;
305}
306
bool eventFilter(QObject *obj, QEvent *ev) override
Filters events if this object has been installed as an event filter for the watched object.
static QSurface::SurfaceType surfaceTypeForConfig(const QPlatformBackingStoreRhiConfig &config)
static bool checkForceRhi(QPlatformBackingStoreRhiConfig *outConfig, QSurface::SurfaceType *outType)
QRhiSwapChain * swapChainForWindow(QWindow *window)
static QRhi::Implementation apiToRhiBackend(QPlatformBackingStoreRhiConfig::Api api)
\inmodule QtCore
Definition qcoreevent.h:45
@ PlatformSurface
Definition qcoreevent.h:278
static QPlatformIntegration * platformIntegration()
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1279
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1209
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1258
iterator erase(const_iterator it)
Definition qhash.h:1223
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:949
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
\inmodule QtCore
Definition qobject.h:90
\inmodule QtGui
The QPlatformSurfaceEvent class is used to notify about native platform surface events....
Definition qevent.h:530
SurfaceEventType surfaceEventType() const
Returns the specific type of platform surface event.
Definition qevent.h:540
\inmodule QtGui
\inmodule QtGui
\inmodule QtRhi
\inmodule QtGui
Definition qrhi.h:1119
\inmodule QtGui
Definition qrhi.h:1513
virtual QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor()=0
virtual bool createOrResize()=0
Creates the swapchain if not already done and resizes the swapchain buffers to match the current size...
@ SurfaceHasNonPreMulAlpha
Definition qrhi.h:1517
void setFlags(Flags f)
Sets the flags f.
Definition qrhi.h:1545
void setWindow(QWindow *window)
Sets the window.
Definition qrhi.h:1539
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Associates with the QRhiRenderPassDescriptor desc.
Definition qrhi.h:1557
\inmodule QtGui
\inmodule QtGui
Definition qrhi.h:1767
Implementation
Describes which graphics API-specific backend gets used by a QRhi instance.
Definition qrhi.h:1769
@ Metal
Definition qrhi.h:1774
@ Vulkan
Definition qrhi.h:1771
@ Null
Definition qrhi.h:1770
@ D3D11
Definition qrhi.h:1773
@ D3D12
Definition qrhi.h:1775
@ OpenGLES2
Definition qrhi.h:1772
QRhiSwapChain * newSwapChain()
Definition qrhi.cpp:10256
const char * backendName() const
Definition qrhi.cpp:8321
static bool probe(Implementation impl, QRhiInitParams *params)
Definition qrhi.cpp:8215
static QRhi * create(Implementation impl, QRhiInitParams *params, Flags flags={}, QRhiNativeHandles *importDevice=nullptr)
Definition qrhi.cpp:8129
@ PreferSoftwareRenderer
Definition qrhi.h:1780
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
SurfaceType
The SurfaceType enum describes what type of surface this is.
Definition qsurface.h:30
@ RasterSurface
Definition qsurface.h:31
@ OpenGLSurface
Definition qsurface.h:32
@ MetalSurface
Definition qsurface.h:36
@ VulkanSurface
Definition qsurface.h:35
@ Direct3DSurface
Definition qsurface.h:37
\inmodule QtGui
Definition qwindow.h:63
QSurfaceFormat format() const override
Returns the actual format of this window.
Definition qwindow.cpp:888
QSet< QString >::iterator it
Combined button and popup list for selecting options.
EGLConfig config
#define qWarning
Definition qlogging.h:162
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
QOpenGLContext * qt_gl_global_share_context()
GLenum type
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
void ** params
struct _cl_event * event
GLhandleARB obj
[2]
GLboolean reset
#define QStringLiteral(str)
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
QWindow * qobject_cast< QWindow * >(QObject *o)
Definition qwindow.h:367
aWidget window() -> setWindowTitle("New Window Title")
[2]