Qt 4.8
qegl_x11.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <QtCore/qdebug.h>
43 
44 #include <QtGui/private/qt_x11_p.h>
45 #include <QtGui/qx11info_x11.h>
46 #include <QtGui/private/qpixmapdata_p.h>
47 #include <QtGui/private/qpixmap_x11_p.h>
48 #include <QtGui/private/qimagepixmapcleanuphooks_p.h>
49 
50 #include <QtGui/qpaintdevice.h>
51 #include <QtGui/qpixmap.h>
52 #include <QtGui/qwidget.h>
53 #include <QtGui/qcolormap.h>
54 
55 #include "QtGui/private/qegl_p.h"
56 #include "QtGui/private/qeglcontext_p.h"
57 
59 
60 
62 {
63  Display *xdpy = QX11Info::display();
64  if (!xdpy) {
65  qWarning("QEglContext::getDisplay(): X11 display is not open");
66  return EGLNativeDisplayType(EGL_DEFAULT_DISPLAY);
67  }
68  return EGLNativeDisplayType(xdpy);
69 }
70 
72 {
73  return (EGLNativeWindowType)(widget->winId());
74 }
75 
77 {
78  return (EGLNativePixmapType)(pixmap->handle());
79 }
80 
81 static int countBits(unsigned long mask)
82 {
83  int count = 0;
84  while (mask != 0) {
85  if (mask & 1)
86  ++count;
87  mask >>= 1;
88  }
89  return count;
90 }
91 
92 // Set the pixel format parameters from the visual in "xinfo".
94 {
95  if (!xinfo)
96  return;
97  Visual *visual = (Visual*)xinfo->visual();
98  if (!visual)
99  return;
100  if (visual->c_class != TrueColor && visual->c_class != DirectColor)
101  return;
102  setValue(EGL_RED_SIZE, countBits(visual->red_mask));
103  setValue(EGL_GREEN_SIZE, countBits(visual->green_mask));
104  setValue(EGL_BLUE_SIZE, countBits(visual->blue_mask));
105 
106  EGLint alphaBits = 0;
107 #if !defined(QT_NO_XRENDER)
108  XRenderPictFormat *format;
109  format = XRenderFindVisualFormat(xinfo->display(), visual);
110  if (format && (format->type == PictTypeDirect) && format->direct.alphaMask) {
111  alphaBits = countBits(format->direct.alphaMask);
112  qDebug("QEglProperties::setVisualFormat() - visual's alphaMask is %d", alphaBits);
113  }
114 #endif
115  setValue(EGL_ALPHA_SIZE, alphaBits);
116 }
117 
118 extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
119 
120 // Set pixel format and other properties based on a paint device.
122 {
123  if (!dev)
124  return;
125  if (dev->devType() == QInternal::Image)
126  setPixelFormat(static_cast<QImage *>(dev)->format());
127  else
129 }
130 
131 //#define QT_DEBUG_X11_VISUAL_SELECTION 1
132 
133 VisualID QEgl::getCompatibleVisualId(EGLConfig config)
134 {
135  VisualID visualId = 0;
136  EGLint eglValue = 0;
137 
138  EGLint configRedSize = 0;
139  eglGetConfigAttrib(display(), config, EGL_RED_SIZE, &configRedSize);
140 
141  EGLint configGreenSize = 0;
142  eglGetConfigAttrib(display(), config, EGL_GREEN_SIZE, &configGreenSize);
143 
144  EGLint configBlueSize = 0;
145  eglGetConfigAttrib(display(), config, EGL_BLUE_SIZE, &configBlueSize);
146 
147  EGLint configAlphaSize = 0;
148  eglGetConfigAttrib(display(), config, EGL_ALPHA_SIZE, &configAlphaSize);
149 
150  eglGetConfigAttrib(display(), config, EGL_CONFIG_ID, &eglValue);
151  int configId = eglValue;
152 
153  // See if EGL provided a valid VisualID:
154  eglGetConfigAttrib(display(), config, EGL_NATIVE_VISUAL_ID, &eglValue);
155  visualId = (VisualID)eglValue;
156  if (visualId) {
157  // EGL has suggested a visual id, so get the rest of the visual info for that id:
158  XVisualInfo visualInfoTemplate;
159  memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
160  visualInfoTemplate.visualid = visualId;
161 
162  XVisualInfo *chosenVisualInfo;
163  int matchingCount = 0;
164  chosenVisualInfo = XGetVisualInfo(X11->display, VisualIDMask, &visualInfoTemplate, &matchingCount);
165  if (chosenVisualInfo) {
166  // Skip size checks if implementation supports non-matching visual
167  // and config (http://bugreports.qt-project.org/browse/QTBUG-9444).
168  if (QEgl::hasExtension("EGL_NV_post_convert_rounding")) {
169  XFree(chosenVisualInfo);
170  return visualId;
171  }
172 
173  int visualRedSize = countBits(chosenVisualInfo->red_mask);
174  int visualGreenSize = countBits(chosenVisualInfo->green_mask);
175  int visualBlueSize = countBits(chosenVisualInfo->blue_mask);
176  int visualAlphaSize = -1; // Need XRender to tell us the alpha channel size
177 
178 #if !defined(QT_NO_XRENDER)
179  if (X11->use_xrender) {
180  // If we have XRender, actually check the visual supplied by EGL is ARGB
181  XRenderPictFormat *format;
182  format = XRenderFindVisualFormat(X11->display, chosenVisualInfo->visual);
183  if (format && (format->type == PictTypeDirect))
184  visualAlphaSize = countBits(format->direct.alphaMask);
185  }
186 #endif
187 
188  bool visualMatchesConfig = false;
189  if ( visualRedSize == configRedSize &&
190  visualGreenSize == configGreenSize &&
191  visualBlueSize == configBlueSize )
192  {
193  // We need XRender to check the alpha channel size of the visual. If we don't have
194  // the alpha size, we don't check it against the EGL config's alpha size.
195  if (visualAlphaSize >= 0)
196  visualMatchesConfig = visualAlphaSize == configAlphaSize;
197  else
198  visualMatchesConfig = true;
199  }
200 
201  if (!visualMatchesConfig) {
202  if (visualAlphaSize >= 0) {
203  qWarning("Warning: EGL suggested using X Visual ID %d (ARGB%d%d%d%d) for EGL config %d (ARGB%d%d%d%d), but this is incompatable",
204  (int)visualId, visualAlphaSize, visualRedSize, visualGreenSize, visualBlueSize,
205  configId, configAlphaSize, configRedSize, configGreenSize, configBlueSize);
206  } else {
207  qWarning("Warning: EGL suggested using X Visual ID %d (RGB%d%d%d) for EGL config %d (RGB%d%d%d), but this is incompatable",
208  (int)visualId, visualRedSize, visualGreenSize, visualBlueSize,
209  configId, configRedSize, configGreenSize, configBlueSize);
210  }
211  visualId = 0;
212  }
213  } else {
214  qWarning("Warning: EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID",
215  (int)visualId, configId);
216  visualId = 0;
217  }
218  XFree(chosenVisualInfo);
219  }
220 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
221  else
222  qDebug("EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId);
223 #endif
224 
225  if (visualId) {
226 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
227  if (configAlphaSize > 0)
228  qDebug("Using ARGB Visual ID %d provided by EGL for config %d", (int)visualId, configId);
229  else
230  qDebug("Using Opaque Visual ID %d provided by EGL for config %d", (int)visualId, configId);
231 #endif
232  return visualId;
233  }
234 
235 
236  // If EGL didn't give us a valid visual ID, try XRender
237 #if !defined(QT_NO_XRENDER)
238  if (!visualId && X11->use_xrender) {
239  XVisualInfo visualInfoTemplate;
240  memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
241 
242  visualInfoTemplate.c_class = TrueColor;
243 
244  XVisualInfo *matchingVisuals;
245  int matchingCount = 0;
246  matchingVisuals = XGetVisualInfo(X11->display,
247  VisualClassMask,
248  &visualInfoTemplate,
249  &matchingCount);
250 
251  for (int i = 0; i < matchingCount; ++i) {
252  XRenderPictFormat *format;
253  format = XRenderFindVisualFormat(X11->display, matchingVisuals[i].visual);
254 
255  // Check the format for the visual matches the EGL config
256  if ( (countBits(format->direct.redMask) == configRedSize) &&
257  (countBits(format->direct.greenMask) == configGreenSize) &&
258  (countBits(format->direct.blueMask) == configBlueSize) &&
259  (countBits(format->direct.alphaMask) == configAlphaSize) )
260  {
261  visualId = matchingVisuals[i].visualid;
262  break;
263  }
264  }
265  if (matchingVisuals)
266  XFree(matchingVisuals);
267 
268  }
269  if (visualId) {
270 # ifdef QT_DEBUG_X11_VISUAL_SELECTION
271  if (configAlphaSize > 0)
272  qDebug("Using ARGB Visual ID %d provided by XRender for EGL config %d", (int)visualId, configId);
273  else
274  qDebug("Using Opaque Visual ID %d provided by XRender for EGL config %d", (int)visualId, configId);
275 # endif // QT_DEBUG_X11_VISUAL_SELECTION
276  return visualId;
277  }
278 # ifdef QT_DEBUG_X11_VISUAL_SELECTION
279  else
280  qDebug("Failed to find an XVisual which matches EGL config %d using XRender", configId);
281 # endif // QT_DEBUG_X11_VISUAL_SELECTION
282 
283 #endif
284 
285 
286  // Finally, if XRender also failed to find a visual (or isn't present), try to
287  // use XGetVisualInfo and only use the bit depths to match on:
288  if (!visualId) {
289  XVisualInfo visualInfoTemplate;
290  memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
291  XVisualInfo *matchingVisuals;
292  int matchingCount = 0;
293 
294  visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize;
295  matchingVisuals = XGetVisualInfo(X11->display,
296  VisualDepthMask,
297  &visualInfoTemplate,
298  &matchingCount);
299  if (!matchingVisuals) {
300  // Try again without taking the alpha channel into account:
301  visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize;
302  matchingVisuals = XGetVisualInfo(X11->display,
303  VisualDepthMask,
304  &visualInfoTemplate,
305  &matchingCount);
306  }
307 
308  if (matchingVisuals) {
309  visualId = matchingVisuals[0].visualid;
310  XFree(matchingVisuals);
311  }
312  }
313 
314  if (visualId) {
315 #ifdef QT_DEBUG_X11_VISUAL_SELECTION
316  qDebug("Using Visual ID %d provided by XGetVisualInfo for EGL config %d", (int)visualId, configId);
317 #endif
318  return visualId;
319  }
320 
321  qWarning("Unable to find an X11 visual which matches EGL config %d", configId);
322  return (VisualID)0;
323 }
324 
326 {
327  w->create(id);
328 }
329 
330 
331 // NOTE: The X11 version of createSurface will re-create the native drawable if it's visual doesn't
332 // match the one for the passed in EGLConfig
333 EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEglProperties *properties)
334 {
335  int devType = device->devType();
336 
337  if (devType == QInternal::Pbuffer) {
338  // TODO
339  return EGL_NO_SURFACE;
340  }
341 
342  QX11PixmapData *x11PixmapData = 0;
343  if (devType == QInternal::Pixmap) {
344  QPixmapData *pmd = static_cast<QPixmap*>(device)->data_ptr().data();
345  if (pmd->classId() == QPixmapData::X11Class)
346  x11PixmapData = static_cast<QX11PixmapData*>(pmd);
347  else {
348  // TODO: Replace the pixmap's data with a new QX11PixmapData
349  qWarning("WARNING: Creating an EGL surface on a QPixmap is only supported for QX11PixmapData");
350  return EGL_NO_SURFACE;
351  }
352  } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) {
353  qWarning("WARNING: Creating an EGLSurface for device type %d isn't supported", devType);
354  return EGL_NO_SURFACE;
355  }
356 
357  VisualID visualId = QEgl::getCompatibleVisualId(config);
358  EGLint alphaSize;
359  eglGetConfigAttrib(QEgl::display(), config, EGL_ALPHA_SIZE, &alphaSize);
360 
361  if (devType == QInternal::Widget) {
362  QWidget *widget = static_cast<QWidget*>(device);
363 
364  VisualID currentVisualId = 0;
366  currentVisualId = XVisualIDFromVisual((Visual*)widget->x11Info().visual());
367 
368  if (currentVisualId != visualId) {
369  // The window is either not created or has the wrong visual. Either way, we need
370  // to create a window with the correct visual and call create() on the widget:
371 
372  bool visible = widget->isVisible();
373  if (visible)
374  widget->hide();
375 
376  XVisualInfo visualInfo;
377  visualInfo.visualid = visualId;
378  {
379  XVisualInfo *visualInfoPtr;
380  int matchingCount = 0;
381  visualInfoPtr = XGetVisualInfo(widget->x11Info().display(), VisualIDMask,
382  &visualInfo, &matchingCount);
383  Q_ASSERT(visualInfoPtr); // visualId really should be valid!
384  visualInfo = *visualInfoPtr;
385  XFree(visualInfoPtr);
386  }
387 
388  Window parentWindow = RootWindow(widget->x11Info().display(), widget->x11Info().screen());
389  if (widget->parentWidget())
390  parentWindow = widget->parentWidget()->winId();
391 
392  XSetWindowAttributes windowAttribs;
393  QColormap colmap = QColormap::instance(widget->x11Info().screen());
394  windowAttribs.background_pixel = colmap.pixel(widget->palette().color(widget->backgroundRole()));
395  windowAttribs.border_pixel = colmap.pixel(Qt::black);
396 
397  unsigned int valueMask = CWBackPixel|CWBorderPixel;
398  if (alphaSize > 0) {
399  windowAttribs.colormap = XCreateColormap(widget->x11Info().display(), parentWindow,
400  visualInfo.visual, AllocNone);
401  valueMask |= CWColormap;
402  }
403 
404  Window window = XCreateWindow(widget->x11Info().display(), parentWindow,
405  widget->x(), widget->y(), widget->width(), widget->height(),
406  0, visualInfo.depth, InputOutput, visualInfo.visual,
407  valueMask, &windowAttribs);
408 
409  // This is a nasty hack to get round the fact that we can't be a friend of QWidget:
410  qt_set_winid_on_widget(widget, window);
411 
412  if (visible)
413  widget->show();
414  }
415 
416  // At this point, the widget's window should be created and have the correct visual. Now we
417  // just need to create the EGL surface for it:
418  const int *props;
419  if (properties)
420  props = properties->properties();
421  else
422  props = 0;
423  EGLSurface surf = eglCreateWindowSurface(QEgl::display(), config, (EGLNativeWindowType)widget->winId(), props);
424  if (surf == EGL_NO_SURFACE)
425  qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError());
426  return surf;
427  }
428 
429  if (x11PixmapData) {
430  // X11 Pixmaps are only created with a depth, so that's all we need to check
431  EGLint configDepth;
432  eglGetConfigAttrib(QEgl::display(), config, EGL_BUFFER_SIZE , &configDepth);
433  if (x11PixmapData->depth() != configDepth) {
434  // The bit depths are wrong which means the EGLConfig isn't compatable with
435  // this pixmap. So we need to replace the pixmap's existing data with a new
436  // one which is created with the correct depth:
437 
438 #ifndef QT_NO_XRENDER
439  if (configDepth == 32) {
440  qWarning("Warning: EGLConfig's depth (32) != pixmap's depth (%d), converting to ARGB32",
441  x11PixmapData->depth());
442  x11PixmapData->convertToARGB32(true);
443  } else
444 #endif
445  {
446  qWarning("Warning: EGLConfig's depth (%d) != pixmap's depth (%d)",
447  configDepth, x11PixmapData->depth());
448  }
449  }
450 
451  QEglProperties surfaceAttribs;
452 
453  // If the pixmap can't be bound to a texture, it's pretty useless
454  surfaceAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
455  if (alphaSize > 0)
456  surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
457  else
458  surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
459 
460  EGLSurface surf = eglCreatePixmapSurface(QEgl::display(), config,
461  (EGLNativePixmapType) x11PixmapData->handle(),
462  surfaceAttribs.properties());
463  x11PixmapData->gl_surface = (void*)surf;
465  return surf;
466  }
467 
468  return EGL_NO_SURFACE;
469 }
470 
QPalette palette
the widget&#39;s palette
Definition: qwidget.h:180
QWidget * parentWidget() const
Returns the parent of this widget, or 0 if it does not have any parent widget.
Definition: qwidget.h:1035
static QColormap instance(int screen=-1)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QPointer< QWidget > widget
int width
the width of the widget excluding any window frame
Definition: qwidget.h:166
NativePixmapType EGLNativePixmapType
Definition: qegl_p.h:117
bool isVisible() const
Definition: qwidget.h:1005
const EGLint * properties() const
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
const QX11Info & x11Info() const
Returns information about the configuration of the X display used to display the widget.
QPalette::ColorRole backgroundRole() const
Returns the background role of the widget.
Definition: qwidget.cpp:4677
Qt::HANDLE handle() const
Returns the pixmap&#39;s handle to the device context.
Definition: qpixmap.cpp:1299
static void enableCleanupHooks(const QImage &image)
void qt_set_winid_on_widget(QWidget *w, Qt::HANDLE id)
Definition: qegl_x11.cpp:325
void setValue(int name, int value)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
#define X11
Definition: qt_x11_p.h:724
int x
the x coordinate of the widget relative to its parent including any window frame
Definition: qwidget.h:161
const QColor & color(ColorGroup cg, ColorRole cr) const
Returns the color in the specified color group, used for the given color role.
Definition: qpalette.h:107
NativeWindowType EGLNativeWindowType
Definition: qegl_p.h:116
Q_GUI_EXPORT EGLNativePixmapType nativePixmap(QPixmap *)
Definition: qegl_qpa.cpp:65
virtual int devType() const
Definition: qpaintdevice.h:167
static int countBits(unsigned long mask)
Definition: qegl_x11.cpp:81
Q_CORE_EXPORT void qDebug(const char *,...)
void setVisualFormat(const QX11Info *xinfo)
Definition: qegl_x11.cpp:93
NSWindow * window
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
Q_GUI_EXPORT EGLDisplay display()
Definition: qegl.cpp:589
const QX11Info * qt_x11Info(const QPaintDevice *pd)
Qt::HANDLE handle() const
Definition: qpixmap_x11_p.h:95
int height
the height of the widget excluding any window frame
Definition: qwidget.h:167
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition: qwidget.h:1041
Q_CORE_EXPORT void qWarning(const char *,...)
void convertToARGB32(bool preserveContents=true)
void create(WId=0, bool initializeWindow=true, bool destroyOldWindow=true)
Creates a new widget window if window is 0, otherwise sets the widget&#39;s window to window...
Definition: qwidget.cpp:1454
ClassId classId() const
void * HANDLE
Definition: qnamespace.h:1671
void * visual() const
Returns the current visual.
void show()
Shows the widget and its child widgets.
uint pixel(const QColor &color) const
Q_GUI_EXPORT bool hasExtension(const char *extensionName)
Definition: qegl.cpp:791
void hide()
Hides the widget.
Definition: qwidget.h:501
struct _XDisplay Display
Definition: qwindowdefs.h:115
The QX11Info class provides information about the X display configuration.
Definition: qx11info_x11.h:63
int depth() const
QVarLengthArray< EGLint > props
Q_GUI_EXPORT EGLSurface createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *surfaceAttribs=0)
Definition: qegl_x11.cpp:333
Q_GUI_EXPORT EGLNativeDisplayType nativeDisplay()
Definition: qegl_qpa.cpp:55
void * data_ptr(const QTransform &t)
Definition: qpainter_p.h:81
int y
the y coordinate of the widget relative to its parent and including any window frame ...
Definition: qwidget.h:162
void setPaintDeviceFormat(QPaintDevice *dev)
Definition: qegl_qpa.cpp:93
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
Q_GUI_EXPORT VisualID getCompatibleVisualId(EGLConfig config)
Definition: qegl_x11.cpp:133
void setPixelFormat(QImage::Format pixelFormat)
NativeDisplayType EGLNativeDisplayType
Definition: qegl_p.h:118
WId winId() const
Returns the window system identifier of the widget.
Definition: qwidget.cpp:2557
Q_GUI_EXPORT EGLNativeWindowType nativeWindow(QWidget *)
Definition: qegl_qpa.cpp:60
static Display * display()
Returns the default display for the application.
int screen() const
Returns the number of the screen currently in use.