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
qoffscreenintegration_x11.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 <QByteArray>
7#include <QOpenGLContext>
8
9#include <X11/Xlib.h>
10#include <GL/glx.h>
11
12#include <QtGui/private/qglxconvenience_p.h>
13
14#include <qpa/qplatformsurface.h>
15#include <qsurface.h>
16
17QT_BEGIN_NAMESPACE
18
19class QOffscreenX11Info
20{
21public:
22 QOffscreenX11Info(QOffscreenX11Connection *connection)
23 : m_connection(connection)
24 {
25 }
26
27 Display *display() const {
28 return (Display *)m_connection->display();
29 }
30
31 Window root() const {
32 return DefaultRootWindow(display());
33 }
34
35 int screenNumber() const {
36 return m_connection->screenNumber();
37 }
38
39private:
40 QOffscreenX11Connection *m_connection;
41};
42
44: QOffscreenIntegration(paramList)
45{
46
47}
48
50
51bool QOffscreenX11Integration::hasCapability(QPlatformIntegration::Capability cap) const
52{
53 switch (cap) {
54 case OpenGL: return true;
55 case ThreadedOpenGL: return true;
56 default: return QOffscreenIntegration::hasCapability(cap);
57 }
58}
59
60#if !defined(QT_NO_OPENGL) && QT_CONFIG(xcb_glx_plugin)
61QPlatformOpenGLContext *QOffscreenX11Integration::createPlatformOpenGLContext(QOpenGLContext *context) const
62{
63 auto &connection = nativeInterface()->m_connection;
64
65 if (!connection)
66 connection.reset(new QOffscreenX11Connection);
67
68 if (!connection->display())
69 return nullptr;
70
71 return new QOffscreenX11GLXContext(connection->x11Info(), context);
72}
73#endif // !defined(QT_NO_OPENGL) && QT_CONFIG(xcb_glx_plugin)
74
76{
77 if (!m_nativeInterface)
78 m_nativeInterface.reset(new QOffscreenX11PlatformNativeInterface(const_cast<QOffscreenX11Integration *>(this)));
79 return static_cast<QOffscreenX11PlatformNativeInterface *>(m_nativeInterface.data());
80}
81
87
89
90void *QOffscreenX11PlatformNativeInterface::nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
91{
92 Q_UNUSED(screen);
93 if (resource.toLower() == QByteArrayLiteral("display") ) {
94 if (!m_connection)
95 m_connection.reset(new QOffscreenX11Connection);
96 return m_connection->display();
97 }
98 return nullptr;
99}
100
101#if !defined(QT_NO_OPENGL) && QT_CONFIG(xcb_glx_plugin)
102void *QOffscreenX11PlatformNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) {
103 if (resource.toLower() == QByteArrayLiteral("glxconfig") ) {
104 if (context) {
105 QOffscreenX11GLXContext *glxPlatformContext = static_cast<QOffscreenX11GLXContext *>(context->handle());
106 if (glxPlatformContext)
107 return glxPlatformContext->glxConfig();
108 }
109 }
110 if (resource.toLower() == QByteArrayLiteral("glxcontext") ) {
111 if (context) {
112 QOffscreenX11GLXContext *glxPlatformContext = static_cast<QOffscreenX11GLXContext *>(context->handle());
113 if (glxPlatformContext)
114 return glxPlatformContext->glxContext();
115 }
116 }
117 return nullptr;
118}
119#endif
120
121#if QT_CONFIG(xcb)
122Display *QOffscreenX11PlatformNativeInterface::display() const
123{
124 return m_connection ? reinterpret_cast<Display *>(m_connection->display()) : nullptr;
125}
126#endif
127
129{
130 XInitThreads();
131
132 QByteArray displayName = qgetenv("DISPLAY");
133 Display *display = XOpenDisplay(displayName.constData());
134 m_display = display;
135 m_screenNumber = m_display ? DefaultScreen(m_display) : -1;
136}
137
139{
140 if (m_display)
141 XCloseDisplay((Display *)m_display);
142}
143
144QOffscreenX11Info *QOffscreenX11Connection::x11Info()
145{
146 if (!m_x11Info)
147 m_x11Info.reset(new QOffscreenX11Info(this));
148 return m_x11Info.data();
149}
150
151#if QT_CONFIG(xcb_glx_plugin)
152class QOffscreenX11GLXContextData
153{
154public:
155 QOffscreenX11Info *x11 = nullptr;
156 QSurfaceFormat format;
157 GLXContext context = nullptr;
158 GLXContext shareContext = nullptr;
159 GLXFBConfig config = nullptr;
160 Window window = 0;
161};
162
163static Window createDummyWindow(QOffscreenX11Info *x11, XVisualInfo *visualInfo)
164{
165 Colormap cmap = XCreateColormap(x11->display(), x11->root(), visualInfo->visual, AllocNone);
166 XSetWindowAttributes a;
167 a.background_pixel = WhitePixel(x11->display(), x11->screenNumber());
168 a.border_pixel = BlackPixel(x11->display(), x11->screenNumber());
169 a.colormap = cmap;
170
171
172 Window window = XCreateWindow(x11->display(), x11->root(),
173 0, 0, 100, 100,
174 0, visualInfo->depth, InputOutput, visualInfo->visual,
175 CWBackPixel|CWBorderPixel|CWColormap, &a);
176 XFreeColormap(x11->display(), cmap);
177 return window;
178}
179
180static Window createDummyWindow(QOffscreenX11Info *x11, GLXFBConfig config)
181{
182 XVisualInfo *visualInfo = glXGetVisualFromFBConfig(x11->display(), config);
183 if (Q_UNLIKELY(!visualInfo))
184 qFatal("Could not initialize GLX");
185 Window window = createDummyWindow(x11, visualInfo);
186 XFree(visualInfo);
187 return window;
188}
189
190QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGLContext *context)
191 : d(new QOffscreenX11GLXContextData)
192{
193
194 d->x11 = x11;
195 d->format = context->format();
196
197 if (d->format.renderableType() == QSurfaceFormat::DefaultRenderableType)
198 d->format.setRenderableType(QSurfaceFormat::OpenGL);
199
200 if (d->format.renderableType() != QSurfaceFormat::OpenGL)
201 return;
202
203 d->shareContext = nullptr;
204 if (context->shareHandle())
205 d->shareContext = static_cast<QOffscreenX11GLXContext *>(context->shareHandle())->d->context;
206
207 GLXFBConfig config = qglx_findConfig(x11->display(), x11->screenNumber(), d->format);
208 d->config = config;
209
210 if (config) {
211 d->context = glXCreateNewContext(x11->display(), config, GLX_RGBA_TYPE, d->shareContext, true);
212 if (!d->context && d->shareContext) {
213 d->shareContext = nullptr;
214 // re-try without a shared glx context
215 d->context = glXCreateNewContext(x11->display(), config, GLX_RGBA_TYPE, nullptr, true);
216 }
217
218 // Get the basic surface format details
219 if (d->context)
220 qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config);
221
222 // Create a temporary window so that we can make the new context current
223 d->window = createDummyWindow(x11, config);
224 } else {
225 XVisualInfo *visualInfo = qglx_findVisualInfo(x11->display(), 0, &d->format);
226 if (Q_UNLIKELY(!visualInfo))
227 qFatal("Could not initialize GLX");
228 d->context = glXCreateContext(x11->display(), visualInfo, d->shareContext, true);
229 if (!d->context && d->shareContext) {
230 // re-try without a shared glx context
231 d->shareContext = nullptr;
232 d->context = glXCreateContext(x11->display(), visualInfo, nullptr, true);
233 }
234
235 d->window = createDummyWindow(x11, visualInfo);
236 XFree(visualInfo);
237 }
238}
239
240QOffscreenX11GLXContext::~QOffscreenX11GLXContext()
241{
242 glXDestroyContext(d->x11->display(), d->context);
243 XDestroyWindow(d->x11->display(), d->window);
244}
245
246bool QOffscreenX11GLXContext::makeCurrent(QPlatformSurface *surface)
247{
248 QSize size = surface->surface()->size();
249
250 XResizeWindow(d->x11->display(), d->window, size.width(), size.height());
251 XSync(d->x11->display(), true);
252
253 if (glXMakeCurrent(d->x11->display(), d->window, d->context)) {
254 glViewport(0, 0, size.width(), size.height());
255 return true;
256 }
257
258 return false;
259}
260
261void QOffscreenX11GLXContext::doneCurrent()
262{
263 glXMakeCurrent(d->x11->display(), 0, nullptr);
264}
265
266void QOffscreenX11GLXContext::swapBuffers(QPlatformSurface *)
267{
268}
269
270QFunctionPointer QOffscreenX11GLXContext::getProcAddress(const char *procName)
271{
272 return (QFunctionPointer)glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName));
273}
274
275QSurfaceFormat QOffscreenX11GLXContext::format() const
276{
277 return d->format;
278}
279
280bool QOffscreenX11GLXContext::isSharing() const
281{
282 return d->shareContext;
283}
284
285bool QOffscreenX11GLXContext::isValid() const
286{
287 return d->context && d->window;
288}
289
290GLXContext QOffscreenX11GLXContext::glxContext() const
291{
292 return d->context;
293}
294
295void *QOffscreenX11GLXContext::glxConfig() const
296{
297 return d->config;
298}
299#endif // QT_CONFIG(xcb_glx_plugin)
300QT_END_NAMESPACE
QOffscreenPlatformNativeInterface(QOffscreenIntegration *integration)
bool hasCapability(QPlatformIntegration::Capability cap) const override
QOffscreenX11PlatformNativeInterface * nativeInterface() const override
QOffscreenX11Integration(const QStringList &paramList)
QOffscreenX11PlatformNativeInterface(QOffscreenIntegration *integration)
void * nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override