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
qoffscreensurface.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 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// Qt-Security score:significant reason:default
4
6
8#include "qscreen.h"
11#include "qwindow.h"
13
14#include <private/qwindow_p.h>
15
17
18using namespace Qt::StringLiterals;
19
20/*!
21 \class QOffscreenSurface
22 \inmodule QtGui
23 \since 5.1
24 \brief The QOffscreenSurface class represents an offscreen surface in the underlying platform.
25
26 QOffscreenSurface is intended to be used with QOpenGLContext to allow rendering with OpenGL in
27 an arbitrary thread without the need to create a QWindow.
28
29 Even though the surface is typically renderable, the surface's pixels are not accessible.
30 QOffscreenSurface should only be used to create OpenGL resources such as textures
31 or framebuffer objects.
32
33 An application will typically use QOffscreenSurface to perform some time-consuming tasks in a
34 separate thread in order to avoid stalling the main rendering thread. Resources created in the
35 QOffscreenSurface's context can be shared with the main OpenGL context. Some common use cases
36 are asynchronous texture uploads or rendering into a QOpenGLFramebufferObject.
37
38 How the offscreen surface is implemented depends on the underlying platform, but it will
39 typically use a pixel buffer (pbuffer). If the platform doesn't implement or support
40 offscreen surfaces, QOffscreenSurface will use an invisible QWindow internally.
41
42 \note Due to the fact that QOffscreenSurface is backed by a QWindow on some platforms,
43 cross-platform applications must ensure that create() is only called on the main (GUI)
44 thread. The QOffscreenSurface is then safe to be used with
45 \l{QOpenGLContext::makeCurrent()}{makeCurrent()} on other threads, but the
46 initialization and destruction must always happen on the main (GUI) thread.
47
48 \note In order to create an offscreen surface that is guaranteed to be compatible with
49 a given context and window, make sure to set the format to the context's or the
50 window's actual format, that is, the QSurfaceFormat returned from
51 QOpenGLContext::format() or QWindow::format() \e{after the context or window has been
52 created}. Passing the format returned from QWindow::requestedFormat() to setFormat()
53 may result in an incompatible offscreen surface since the underlying windowing system
54 interface may offer a different set of configurations for window and pbuffer surfaces.
55
56 \note Some platforms may utilize a surfaceless context extension (for example
57 EGL_KHR_surfaceless_context) when available. In this case there will be no underlying
58 native surface. For the use cases of QOffscreenSurface (rendering to FBOs, texture
59 upload) this is not a problem.
60*/
61
62/*!
63 \since 5.10
64
65 Creates an offscreen surface for the \a targetScreen with the given \a parent.
66
67 The underlying platform surface is not created until create() is called.
68
69 \sa setScreen(), create()
70*/
71QOffscreenSurface::QOffscreenSurface(QScreen *targetScreen, QObject *parent)
72 : QObject(*new QOffscreenSurfacePrivate(), parent)
73 , QSurface(Offscreen)
74{
75 Q_D(QOffscreenSurface);
76 d->screen = targetScreen;
77 if (!d->screen)
78 d->screen = QGuiApplication::primaryScreen();
79
80 //if your applications aborts here, then chances are your creating a QOffscreenSurface before
81 //the screen list is populated.
82 Q_ASSERT(d->screen);
83
84 connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*)));
85}
86
87/*!
88 Destroys the offscreen surface.
89*/
90QOffscreenSurface::~QOffscreenSurface()
91{
92 destroy();
93}
94
95/*!
96 Returns the surface type of the offscreen surface.
97
98 The surface type of an offscreen surface is always QSurface::OpenGLSurface.
99*/
100QOffscreenSurface::SurfaceType QOffscreenSurface::surfaceType() const
101{
102 Q_D(const QOffscreenSurface);
103 return d->surfaceType;
104}
105
106/*!
107 Allocates the platform resources associated with the offscreen surface.
108
109 It is at this point that the surface format set using setFormat() gets resolved
110 into an actual native surface.
111
112 Call destroy() to free the platform resources if necessary.
113
114 \note Some platforms require this function to be called on the main (GUI) thread.
115
116 \sa destroy()
117*/
118void QOffscreenSurface::create()
119{
120 Q_D(QOffscreenSurface);
121 if (!d->platformOffscreenSurface && !d->offscreenWindow) {
122 d->platformOffscreenSurface = QGuiApplicationPrivate::platformIntegration()->createPlatformOffscreenSurface(this);
123 // No platform offscreen surface, fallback to an invisible window
124 if (!d->platformOffscreenSurface) {
125 if (!QThread::isMainThread())
126 qWarning("Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures.");
127 d->offscreenWindow = new QWindow(d->screen);
128 // Make the window frameless to prevent Windows from enlarging it, should it
129 // violate the minimum title bar width on the platform.
130 d->offscreenWindow->setFlags(d->offscreenWindow->flags()
131 | Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
132 d->offscreenWindow->setObjectName("QOffscreenSurface"_L1);
133 // Remove this window from the global list since we do not want it to be destroyed when closing the app.
134 // The QOffscreenSurface has to be usable even after exiting the event loop.
135 QGuiApplicationPrivate::window_list.removeOne(d->offscreenWindow);
136 d->offscreenWindow->setSurfaceType(QWindow::OpenGLSurface);
137 d->offscreenWindow->setFormat(d->requestedFormat);
138 // Prevent QPlatformWindow::initialGeometry() and platforms from setting a default geometry.
139 qt_window_private(d->offscreenWindow)->setAutomaticPositionAndResizeEnabled(false);
140 d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height());
141 d->offscreenWindow->create();
142 }
143
144 QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated);
145 QGuiApplication::sendEvent(this, &e);
146 }
147}
148
149/*!
150 Releases the native platform resources associated with this offscreen surface.
151
152 \sa create()
153*/
154void QOffscreenSurface::destroy()
155{
156 Q_D(QOffscreenSurface);
157
158 QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
159 QGuiApplication::sendEvent(this, &e);
160
161 delete d->platformOffscreenSurface;
162 d->platformOffscreenSurface = nullptr;
163 if (d->offscreenWindow) {
164 d->offscreenWindow->destroy();
165 delete d->offscreenWindow;
166 d->offscreenWindow = nullptr;
167 }
168}
169
170/*!
171 Returns \c true if this offscreen surface is valid; otherwise returns \c false.
172
173 The offscreen surface is valid if the platform resources have been successfully allocated.
174
175 \sa create()
176*/
177bool QOffscreenSurface::isValid() const
178{
179 Q_D(const QOffscreenSurface);
180 return (d->platformOffscreenSurface && d->platformOffscreenSurface->isValid())
181 || (d->offscreenWindow && d->offscreenWindow->handle());
182}
183
184/*!
185 Sets the offscreen surface \a format.
186
187 The surface format will be resolved in the create() function. Calling
188 this function after create() will not re-resolve the surface format of the native surface.
189
190 \sa create(), destroy()
191*/
192void QOffscreenSurface::setFormat(const QSurfaceFormat &format)
193{
194 Q_D(QOffscreenSurface);
195 d->requestedFormat = format;
196}
197
198/*!
199 Returns the requested surfaceformat of this offscreen surface.
200
201 If the requested format was not supported by the platform implementation,
202 the requestedFormat will differ from the actual offscreen surface format.
203
204 This is the value set with setFormat().
205
206 \sa setFormat(), format()
207 */
208QSurfaceFormat QOffscreenSurface::requestedFormat() const
209{
210 Q_D(const QOffscreenSurface);
211 return d->requestedFormat;
212}
213
214/*!
215 Returns the actual format of this offscreen surface.
216
217 After the offscreen surface has been created, this function will return the actual
218 surface format of the surface. It might differ from the requested format if the requested
219 format could not be fulfilled by the platform.
220
221 \sa create(), requestedFormat()
222*/
223QSurfaceFormat QOffscreenSurface::format() const
224{
225 Q_D(const QOffscreenSurface);
226 if (d->platformOffscreenSurface)
227 return d->platformOffscreenSurface->format();
228 if (d->offscreenWindow)
229 return d->offscreenWindow->format();
230 return d->requestedFormat;
231}
232
233/*!
234 Returns the size of the offscreen surface.
235*/
236QSize QOffscreenSurface::size() const
237{
238 Q_D(const QOffscreenSurface);
239 return d->size;
240}
241
242/*!
243 Returns the screen to which the offscreen surface is connected.
244
245 \sa setScreen()
246*/
247QScreen *QOffscreenSurface::screen() const
248{
249 Q_D(const QOffscreenSurface);
250 return d->screen;
251}
252
253/*!
254 Sets the screen to which the offscreen surface is connected.
255
256 If the offscreen surface has been created, it will be recreated on the \a newScreen.
257
258 \sa screen()
259*/
260void QOffscreenSurface::setScreen(QScreen *newScreen)
261{
262 Q_D(QOffscreenSurface);
263 if (!newScreen)
264 newScreen = QCoreApplication::instance() ? QGuiApplication::primaryScreen() : nullptr;
265 if (newScreen != d->screen) {
266 const bool wasCreated = d->platformOffscreenSurface != nullptr || d->offscreenWindow != nullptr;
267 if (wasCreated)
268 destroy();
269 if (d->screen)
270 disconnect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*)));
271 d->screen = newScreen;
272 if (newScreen) {
273 connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*)));
274 if (wasCreated)
275 create();
276 }
277 emit screenChanged(newScreen);
278 }
279}
280
281/*!
282 Called when the offscreen surface's screen is destroyed.
283
284 \internal
285*/
286void QOffscreenSurface::screenDestroyed(QObject *object)
287{
288 Q_D(QOffscreenSurface);
289 if (object == static_cast<QObject *>(d->screen))
290 setScreen(nullptr);
291}
292
293/*!
294 \fn QOffscreenSurface::screenChanged(QScreen *screen)
295
296 This signal is emitted when an offscreen surface's \a screen changes, either
297 by being set explicitly with setScreen(), or automatically when
298 the window's screen is removed.
299*/
300
301/*!
302 Returns the platform offscreen surface corresponding to the offscreen surface.
303
304 \internal
305*/
306QPlatformOffscreenSurface *QOffscreenSurface::handle() const
307{
308 Q_D(const QOffscreenSurface);
309 return d->platformOffscreenSurface;
310}
311
312/*!
313 \fn template <typename QNativeInterface> QNativeInterface *QOffscreenSurface::nativeInterface() const
314
315 Returns a native interface of the given type for the surface.
316
317 This function provides access to platform specific functionality
318 of QOffScreenSurface, as defined in the QNativeInterface namespace:
319
320 \annotatedlist native-interfaces-qoffscreensurface
321
322 If the requested interface is not available a \nullptr is returned.
323*/
324
325/*!
326 Returns the platform surface corresponding to the offscreen surface.
327
328 \internal
329*/
330QPlatformSurface *QOffscreenSurface::surfaceHandle() const
331{
332 Q_D(const QOffscreenSurface);
333 if (d->offscreenWindow)
334 return d->offscreenWindow->handle();
335
336 return d->platformOffscreenSurface;
337}
338
339using namespace QNativeInterface;
340
341void *QOffscreenSurface::resolveInterface(const char *name, int revision) const
342{
343 Q_UNUSED(name); Q_UNUSED(revision);
344
345 Q_D(const QOffscreenSurface);
346 Q_UNUSED(d);
347
348#if defined(Q_OS_ANDROID)
349 QT_NATIVE_INTERFACE_RETURN_IF(QAndroidOffscreenSurface, d->platformOffscreenSurface);
350#endif
351
352 return nullptr;
353}
354
355QT_END_NAMESPACE
356
357#include "moc_qoffscreensurface.cpp"
Combined button and popup list for selecting options.