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
qxcbglxintegration.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// Qt-Security score:significant reason:default
4
6
7#if QT_CONFIG(xcb_glx)
8#include <xcb/glx.h>
9#endif
10
12#include "qxcbglxwindow.h"
13#include "qxcbscreen.h"
15
16#include <QtCore/QVersionNumber>
17#include <QtGui/QOpenGLContext>
18#include <QtGui/private/qopenglcontext_p.h>
19
21
22#define register /* C++17 deprecated register */
23#include <X11/Xlibint.h>
24#undef register
25
26QT_BEGIN_NAMESPACE
27
28#if QT_CONFIG(xcb_glx)
29 #define QT_XCB_GLX_REQUIRED_MAJOR 1
30 #define QT_XCB_GLX_REQUIRED_MINOR 3
31
32 #if XCB_GLX_MAJOR_VERSION == 1 && XCB_GLX_MINOR_VERSION < 4
33 #define XCB_GLX_BUFFER_SWAP_COMPLETE 1
34 typedef struct xcb_glx_buffer_swap_complete_event_t {
35 uint8_t response_type;
36 uint8_t pad0;
37 uint16_t sequence;
38 uint16_t event_type;
39 uint8_t pad1[2];
40 xcb_glx_drawable_t drawable;
41 uint32_t ust_hi;
42 uint32_t ust_lo;
43 uint32_t msc_hi;
44 uint32_t msc_lo;
45 uint32_t sbc;
46 } xcb_glx_buffer_swap_complete_event_t;
47 #endif
48 typedef struct {
49 int type;
50 unsigned long serial; /* # of last request processed by server */
51 Bool send_event; /* true if this came from a SendEvent request */
52 Display *display; /* Display the event was read from */
53 Drawable drawable; /* drawable on which event was requested in event mask */
54 int event_type;
55 int64_t ust;
56 int64_t msc;
57 int64_t sbc;
58 } QGLXBufferSwapComplete;
59#endif
60
61QXcbGlxIntegration::QXcbGlxIntegration()
62 : m_connection(nullptr)
63 , m_glx_first_event(0)
64{
65 qCDebug(lcQpaGl) << "Xcb GLX gl-integration created";
66}
67
71
72bool QXcbGlxIntegration::initialize(QXcbConnection *connection)
73{
74 m_connection = connection;
75#if QT_CONFIG(xcb_glx)
76
77 const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection->xcb_connection(), &xcb_glx_id);
78 if (!reply || !reply->present)
79 return false;
80
81 m_glx_first_event = reply->first_event;
82
83 auto xglx_query = Q_XCB_REPLY(xcb_glx_query_version, m_connection->xcb_connection(),
84 XCB_GLX_MAJOR_VERSION,
85 XCB_GLX_MINOR_VERSION);
86 if ((!xglx_query)
87 || (QVersionNumber(xglx_query->major_version, xglx_query->minor_version)
88 < QVersionNumber(QT_XCB_GLX_REQUIRED_MAJOR, QT_XCB_GLX_REQUIRED_MINOR))) {
89 qCWarning(lcQpaGl) << "QXcbConnection: Failed to initialize GLX";
90 return false;
91 }
92#endif
93
94 m_native_interface_handler.reset(new QXcbGlxNativeInterfaceHandler(connection->nativeInterface()));
95
96 qCDebug(lcQpaGl) << "Xcb GLX gl-integration successfully initialized";
97 return true;
98}
99
100bool QXcbGlxIntegration::handleXcbEvent(xcb_generic_event_t *event, uint responseType)
101{
102 bool handled = false;
103 // Check if a custom XEvent constructor was registered in xlib for this event type, and call it discarding the constructed XEvent if any.
104 // XESetWireToEvent might be used by libraries to intercept messages from the X server e.g. the OpenGL lib waiting for DRI2 events.
105 Display *xdisplay = static_cast<Display *>(m_connection->xlib_display());
106 XLockDisplay(xdisplay);
107 bool locked = true;
108 Bool (*proc)(Display*, XEvent*, xEvent*) = XESetWireToEvent(xdisplay, responseType, nullptr);
109 if (proc) {
110 XESetWireToEvent(xdisplay, responseType, proc);
111 XEvent dummy;
112 event->sequence = LastKnownRequestProcessed(xdisplay);
113 if (proc(xdisplay, &dummy, (xEvent*)event)) {
114#if QT_CONFIG(xcb_glx)
115 // DRI2 clients don't receive GLXBufferSwapComplete events on the wire.
116 // Instead the GLX event is synthesized from the DRI2BufferSwapComplete event
117 // by DRI2WireToEvent(). For an application to be able to see the event
118 // we have to convert it to an xcb_glx_buffer_swap_complete_event_t and
119 // pass it to the native event filter.
120 const uint swap_complete = m_glx_first_event + XCB_GLX_BUFFER_SWAP_COMPLETE;
121 QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
122 if (dispatcher && uint(dummy.type) == swap_complete && responseType != swap_complete) {
123 QGLXBufferSwapComplete *xev = reinterpret_cast<QGLXBufferSwapComplete *>(&dummy);
124 xcb_glx_buffer_swap_complete_event_t ev;
125 memset(&ev, 0, sizeof(xcb_glx_buffer_swap_complete_event_t));
126 ev.response_type = xev->type;
127 ev.sequence = xev->serial;
128 ev.event_type = xev->event_type;
129 ev.drawable = xev->drawable;
130 ev.ust_hi = xev->ust >> 32;
131 ev.ust_lo = xev->ust & 0xffffffff;
132 ev.msc_hi = xev->msc >> 32;
133 ev.msc_lo = xev->msc & 0xffffffff;
134 ev.sbc = xev->sbc & 0xffffffff;
135 // Unlock the display before calling the native event filter
136 XUnlockDisplay(xdisplay);
137 locked = false;
138 auto eventType = m_connection->nativeInterface()->nativeEventType();
139 qintptr result = 0;
140 handled = dispatcher->filterNativeEvent(eventType, &ev, &result);
141 }
142#endif
143 }
144 }
145 if (locked)
146 XUnlockDisplay(xdisplay);
147 return handled;
148}
149
150QXcbWindow *QXcbGlxIntegration::createWindow(QWindow *window) const
151{
152 return new QXcbGlxWindow(window);
153}
154
156{
157 QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle());
158 return new QGLXContext(static_cast<Display *>(m_connection->xlib_display()),
159 screen, screen->surfaceFormatFor(context->format()), context->shareHandle());
160}
161
162QOpenGLContext *QXcbGlxIntegration::createOpenGLContext(GLXContext glxContext, void *visualInfo, QOpenGLContext *shareContext) const
163{
164 if (!glxContext)
165 return nullptr;
166
167 QPlatformOpenGLContext *shareHandle = shareContext ? shareContext->handle() : nullptr;
168
169 auto *context = new QOpenGLContext;
170 auto *contextPrivate = QOpenGLContextPrivate::get(context);
171 auto *display = static_cast<Display *>(m_connection->xlib_display());
172 contextPrivate->adopt(new QGLXContext(display, glxContext, visualInfo, shareHandle));
173 return context;
174}
175
177{
178 static bool vendorChecked = false;
179 static bool glxPbufferUsable = true;
180 if (!vendorChecked) {
181 vendorChecked = true;
182 Display *display = glXGetCurrentDisplay();
183 if (!display)
184 display = static_cast<Display *>(m_connection->xlib_display());
185
186 const char *glxvendor = glXGetClientString(display, GLX_VENDOR);
187 if (glxvendor) {
188 if (!strcmp(glxvendor, "ATI") || !strcmp(glxvendor, "Chromium"))
189 glxPbufferUsable = false;
190 }
191 }
192 if (glxPbufferUsable)
193 return new QGLXPbuffer(surface);
194 else
195 return nullptr; // trigger fallback to hidden QWindow
196
197}
198
200{
201 return QGLXContext::supportsThreading();
202}
203
205{
206 static bool vendorChecked = false;
207 static bool isSwitchableWidgetCompositionAvailable = true;
208 if (!vendorChecked) {
209 vendorChecked = true;
210 Display *display = glXGetCurrentDisplay();
211 if (!display)
212 display = static_cast<Display *>(m_connection->xlib_display());
213
214 const char *glxvendor = glXGetClientString(display, GLX_VENDOR);
215 if (glxvendor) {
216 if (!strcmp(glxvendor, "Parallels Inc"))
217 isSwitchableWidgetCompositionAvailable = false;
218 }
219 }
220
221 return isSwitchableWidgetCompositionAvailable;
222}
223
224
225QT_END_NAMESPACE
QXcbWindow * createWindow(QWindow *window) const override
bool supportsThreadedOpenGL() const override
QPlatformOffscreenSurface * createPlatformOffscreenSurface(QOffscreenSurface *surface) const override
bool handleXcbEvent(xcb_generic_event_t *event, uint responseType) override
bool supportsSwitchableWidgetComposition() const override
QPlatformOpenGLContext * createPlatformOpenGLContext(QOpenGLContext *context) const override
bool initialize(QXcbConnection *connection) override