Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
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 // These must be the same env.vars Qt Quick uses (as documented), in order
60 // to ensure symmetry in the behavior between a QQuickWindow and a
61 // (QRhi-based) widget top-level window.
62 if (qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER"))
64 if (qEnvironmentVariableIntValue("QSG_RHI_PROFILE"))
66
67 if (m_config.api() == QPlatformBackingStoreRhiConfig::Null) {
70 }
71
72#if QT_CONFIG(opengl)
73 if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::OpenGL) {
74 surface = QRhiGles2InitParams::newFallbackSurface(m_format);
76 params.fallbackSurface = surface;
77 params.window = m_window;
78 params.format = m_format;
79 params.shareContext = qt_gl_global_share_context();
81 }
82#endif
83
84#ifdef Q_OS_WIN
85 if (!rhi) {
88 params.enableDebugLayer = m_config.isDebugLayerEnabled();
90 if (!rhi && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
91 qCDebug(lcQpaBackingStore, "Failed to create a D3D11 device with default settings; "
92 "attempting to get a software rasterizer backed device instead");
95 }
96 } else if (m_config.api() == QPlatformBackingStoreRhiConfig::D3D12) {
97 QRhiD3D12InitParams params;
98 params.enableDebugLayer = m_config.isDebugLayerEnabled();
100 if (!rhi && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
101 qCDebug(lcQpaBackingStore, "Failed to create a D3D12 device with default settings; "
102 "attempting to get a software rasterizer backed device instead");
105 }
106 }
107 }
108#endif
109
110#if QT_CONFIG(metal)
111 if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::Metal) {
113 // For parity with Qt Quick, fall back to OpenGL when there is no Metal (f.ex. in macOS virtual machines).
116 } else {
117 qCDebug(lcQpaBackingStore, "Metal does not seem to be supported. Falling back to OpenGL.");
119 }
120 }
121#endif
122
123#if QT_CONFIG(vulkan)
124 if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::Vulkan) {
125 if (m_config.isDebugLayerEnabled())
126 QVulkanDefaultInstance::setFlag(QVulkanDefaultInstance::EnableValidation);
128 if (m_window) {
129 if (!m_window->vulkanInstance())
130 m_window->setVulkanInstance(QVulkanDefaultInstance::instance());
131 params.inst = m_window->vulkanInstance();
132 } else {
133 params.inst = QVulkanDefaultInstance::instance();
134 }
135 if (!params.inst) {
136 qWarning("No QVulkanInstance set for the top-level window, this is wrong.");
137 return false;
138 }
139 params.window = m_window;
141 }
142#endif
143
144 if (!rhi) {
145 qWarning("Failed to create QRhi for QBackingStoreRhiSupport");
146 delete surface;
147 return false;
148 }
149
150 m_rhi = rhi;
151 m_openGLFallbackSurface = surface;
152 return true;
153}
154
156{
157 auto it = m_swapchains.constFind(window);
158 if (it != m_swapchains.constEnd())
159 return it.value().swapchain;
160
161 QRhiSwapChain *swapchain = nullptr;
162 QRhiRenderPassDescriptor *rp = nullptr;
163 if (window && m_rhi) {
164 QRhiSwapChain::Flags flags;
165 const QSurfaceFormat format = window->requestedFormat();
166 if (format.swapInterval() == 0)
168 if (format.alphaBufferSize() > 0)
170#if QT_CONFIG(vulkan)
171 if (m_config.api() == QPlatformBackingStoreRhiConfig::Vulkan && !window->vulkanInstance())
172 window->setVulkanInstance(QVulkanDefaultInstance::instance());
173#endif
174 qCDebug(lcQpaBackingStore) << "Creating swapchain for window" << window;
175 swapchain = m_rhi->newSwapChain();
176 swapchain->setWindow(window);
177 swapchain->setFlags(flags);
178 rp = swapchain->newCompatibleRenderPassDescriptor();
179 swapchain->setRenderPassDescriptor(rp);
180 if (!swapchain->createOrResize()) {
181 qWarning("Failed to create swapchain for window flushed with an RHI-enabled backingstore");
182 delete rp;
183 return nullptr;
184 }
185 }
186 if (swapchain) {
187 SwapchainData d;
188 d.swapchain = swapchain;
190 d.windowWatcher = new QBackingStoreRhiSupportWindowWatcher(this);
191 m_swapchains.insert(window, d);
192 window->installEventFilter(d.windowWatcher);
193 }
194 return swapchain;
195}
196
198{
200 || (event->type() == QEvent::PlatformSurface
202 {
204 auto it = m_rhiSupport->m_swapchains.find(window);
205 if (it != m_rhiSupport->m_swapchains.end()) {
206 qCDebug(lcQpaBackingStore) << event << "received for" << window << "- cleaning up swapchain";
207 auto data = *it;
208 m_rhiSupport->m_swapchains.erase(it);
209 data.reset(); // deletes 'this'
210 }
211 }
212 return false;
213}
214
237
258
260{
262 static bool checked = false;
263
264 if (!checked) {
265 checked = true;
266
267 const bool alwaysRhi = qEnvironmentVariableIntValue("QT_WIDGETS_RHI");
268 if (alwaysRhi)
269 config.setEnabled(true);
270
271 // if enabled, choose an api
272 if (config.isEnabled()) {
273#if defined(Q_OS_WIN)
275#elif QT_CONFIG(metal)
277#elif QT_CONFIG(opengl)
279#elif QT_CONFIG(vulkan)
281#else
282 qWarning("QT_WIDGETS_RHI is set but no backend is available; ignoring");
283 return false;
284#endif
285
286 // the env.var. will always override
287 if (qEnvironmentVariableIsSet("QT_WIDGETS_RHI_BACKEND")) {
288 const QString backend = qEnvironmentVariable("QT_WIDGETS_RHI_BACKEND");
289#ifdef Q_OS_WIN
290 if (backend == QStringLiteral("d3d11") || backend == QStringLiteral("d3d"))
292 if (backend == QStringLiteral("d3d12"))
294#endif
295#if QT_CONFIG(metal)
296 if (backend == QStringLiteral("metal"))
298#endif
299#if QT_CONFIG(opengl)
300 if (backend == QStringLiteral("opengl") || backend == QStringLiteral("gl"))
302#endif
303#if QT_CONFIG(vulkan)
304 if (backend == QStringLiteral("vulkan"))
306#endif
307 }
308
309 if (qEnvironmentVariableIntValue("QT_WIDGETS_RHI_DEBUG_LAYER"))
310 config.setDebugLayer(true);
311 }
312
313 qCDebug(lcQpaBackingStore) << "Check for forced use of QRhi resulted in enable"
314 << config.isEnabled() << "with api" << QRhi::backendName(apiToRhiBackend(config.api()));
315 }
316
317 if (config.isEnabled()) {
318 if (outConfig)
319 *outConfig = config;
320 if (outType)
321 *outType = surfaceTypeForConfig(config);
322 return true;
323 }
324 return false;
325}
326
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
@ WindowAboutToChangeInternal
Definition qcoreevent.h:285
@ PlatformSurface
Definition qcoreevent.h:278
static QPlatformIntegration * platformIntegration()
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1299
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:1219
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:951
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
\inmodule QtCore
Definition qobject.h:103
\inmodule QtGui
The QPlatformSurfaceEvent class is used to notify about native platform surface events....
Definition qevent.h:531
SurfaceEventType surfaceEventType() const
Returns the specific type of platform surface event.
Definition qevent.h:541
\inmodule QtGui
\inmodule QtGui
\inmodule QtRhi
\inmodule QtGui
Definition qrhi.h:1142
\inmodule QtGui
Definition qrhi.h:1549
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:1553
void setFlags(Flags f)
Sets the flags f.
Definition qrhi.h:1582
QRhiRenderPassDescriptor * renderPassDescriptor() const
Definition qrhi.h:1593
void setWindow(QWindow *window)
Sets the window.
Definition qrhi.h:1576
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Associates with the QRhiRenderPassDescriptor desc.
Definition qrhi.h:1594
\inmodule QtGui
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
Implementation
Describes which graphics API-specific backend gets used by a QRhi instance.
Definition qrhi.h:1806
@ Metal
Definition qrhi.h:1811
@ Vulkan
Definition qrhi.h:1808
@ Null
Definition qrhi.h:1807
@ D3D11
Definition qrhi.h:1810
@ D3D12
Definition qrhi.h:1812
@ OpenGLES2
Definition qrhi.h:1809
QRhiSwapChain * newSwapChain()
Definition qrhi.cpp:10693
const char * backendName() const
Definition qrhi.cpp:8683
static bool probe(Implementation impl, QRhiInitParams *params)
Definition qrhi.cpp:8577
static QRhi * create(Implementation impl, QRhiInitParams *params, Flags flags={}, QRhiNativeHandles *importDevice=nullptr)
Definition qrhi.cpp:8491
@ EnableDebugMarkers
Definition qrhi.h:1816
@ PreferSoftwareRenderer
Definition qrhi.h:1817
@ EnableTimestamps
Definition qrhi.h:1819
iterator end()
Definition qset.h:140
iterator erase(const_iterator i)
Definition qset.h:145
iterator find(const T &value)
Definition qset.h:159
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
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:946
QSet< QString >::iterator it
Combined button and popup list for selecting options.
EGLConfig config
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
QOpenGLContext * qt_gl_global_share_context()
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLbitfield flags
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]
QNetworkRequestFactory api
[0]
\inmodule QtGui