source: trunk/src/gui/egl/qegl_x11.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 18.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
58QT_BEGIN_NAMESPACE
59
60
61EGLNativeDisplayType QEgl::nativeDisplay()
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
71EGLNativeWindowType QEgl::nativeWindow(QWidget* widget)
72{
73 return (EGLNativeWindowType)(widget->winId());
74}
75
76EGLNativePixmapType QEgl::nativePixmap(QPixmap* pixmap)
77{
78 return (EGLNativePixmapType)(pixmap->handle());
79}
80
81static 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".
93void QEglProperties::setVisualFormat(const QX11Info *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
118extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
119
120// Set pixel format and other properties based on a paint device.
121void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev)
122{
123 if (!dev)
124 return;
125 if (dev->devType() == QInternal::Image)
126 setPixelFormat(static_cast<QImage *>(dev)->format());
127 else
128 setVisualFormat(qt_x11Info(dev));
129}
130
131//#define QT_DEBUG_X11_VISUAL_SELECTION 1
132
133VisualID 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.nokia.com/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 //!defined(QT_NO_XRENDER)
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
325void qt_set_winid_on_widget(QWidget* w, Qt::HANDLE id)
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
333EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEglProperties *unusedProperties)
334{
335 Q_UNUSED(unusedProperties);
336
337 int devType = device->devType();
338
339 if (devType == QInternal::Pbuffer) {
340 // TODO
341 return EGL_NO_SURFACE;
342 }
343
344 QX11PixmapData *x11PixmapData = 0;
345 if (devType == QInternal::Pixmap) {
346 QPixmapData *pmd = static_cast<QPixmap*>(device)->data_ptr().data();
347 if (pmd->classId() == QPixmapData::X11Class)
348 x11PixmapData = static_cast<QX11PixmapData*>(pmd);
349 else {
350 // TODO: Replace the pixmap's data with a new QX11PixmapData
351 qWarning("WARNING: Creating an EGL surface on a QPixmap is only supported for QX11PixmapData");
352 return EGL_NO_SURFACE;
353 }
354 } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) {
355 qWarning("WARNING: Creating an EGLSurface for device type %d isn't supported", devType);
356 return EGL_NO_SURFACE;
357 }
358
359 VisualID visualId = QEgl::getCompatibleVisualId(config);
360 EGLint alphaSize;
361 eglGetConfigAttrib(QEgl::display(), config, EGL_ALPHA_SIZE, &alphaSize);
362
363 if (devType == QInternal::Widget) {
364 QWidget *widget = static_cast<QWidget*>(device);
365
366 VisualID currentVisualId = 0;
367 if (widget->testAttribute(Qt::WA_WState_Created))
368 currentVisualId = XVisualIDFromVisual((Visual*)widget->x11Info().visual());
369
370 if (currentVisualId != visualId) {
371 // The window is either not created or has the wrong visual. Either way, we need
372 // to create a window with the correct visual and call create() on the widget:
373
374 bool visible = widget->isVisible();
375 if (visible)
376 widget->hide();
377
378 XVisualInfo visualInfo;
379 visualInfo.visualid = visualId;
380 {
381 XVisualInfo *visualInfoPtr;
382 int matchingCount = 0;
383 visualInfoPtr = XGetVisualInfo(widget->x11Info().display(), VisualIDMask,
384 &visualInfo, &matchingCount);
385 Q_ASSERT(visualInfoPtr); // visualId really should be valid!
386 visualInfo = *visualInfoPtr;
387 XFree(visualInfoPtr);
388 }
389
390 Window parentWindow = RootWindow(widget->x11Info().display(), widget->x11Info().screen());
391 if (widget->parentWidget())
392 parentWindow = widget->parentWidget()->winId();
393
394 XSetWindowAttributes windowAttribs;
395 QColormap colmap = QColormap::instance(widget->x11Info().screen());
396 windowAttribs.background_pixel = colmap.pixel(widget->palette().color(widget->backgroundRole()));
397 windowAttribs.border_pixel = colmap.pixel(Qt::black);
398
399 unsigned int valueMask = CWBackPixel|CWBorderPixel;
400 if (alphaSize > 0) {
401 windowAttribs.colormap = XCreateColormap(widget->x11Info().display(), parentWindow,
402 visualInfo.visual, AllocNone);
403 valueMask |= CWColormap;
404 }
405
406 Window window = XCreateWindow(widget->x11Info().display(), parentWindow,
407 widget->x(), widget->y(), widget->width(), widget->height(),
408 0, visualInfo.depth, InputOutput, visualInfo.visual,
409 valueMask, &windowAttribs);
410
411 // This is a nasty hack to get round the fact that we can't be a friend of QWidget:
412 qt_set_winid_on_widget(widget, window);
413
414 if (visible)
415 widget->show();
416 }
417
418 // At this point, the widget's window should be created and have the correct visual. Now we
419 // just need to create the EGL surface for it:
420 EGLSurface surf = eglCreateWindowSurface(QEgl::display(), config, (EGLNativeWindowType)widget->winId(), 0);
421 if (surf == EGL_NO_SURFACE)
422 qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError());
423 return surf;
424 }
425
426 if (x11PixmapData) {
427 // X11 Pixmaps are only created with a depth, so that's all we need to check
428 EGLint configDepth;
429 eglGetConfigAttrib(QEgl::display(), config, EGL_BUFFER_SIZE , &configDepth);
430 if (x11PixmapData->depth() != configDepth) {
431 // The bit depths are wrong which means the EGLConfig isn't compatable with
432 // this pixmap. So we need to replace the pixmap's existing data with a new
433 // one which is created with the correct depth:
434
435#ifndef QT_NO_XRENDER
436 if (configDepth == 32) {
437 qWarning("Warning: EGLConfig's depth (32) != pixmap's depth (%d), converting to ARGB32",
438 x11PixmapData->depth());
439 x11PixmapData->convertToARGB32(true);
440 } else
441#endif
442 {
443 qWarning("Warning: EGLConfig's depth (%d) != pixmap's depth (%d)",
444 configDepth, x11PixmapData->depth());
445 }
446 }
447
448 QEglProperties surfaceAttribs;
449
450 // If the pixmap can't be bound to a texture, it's pretty useless
451 surfaceAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
452 if (alphaSize > 0)
453 surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
454 else
455 surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
456
457 EGLSurface surf = eglCreatePixmapSurface(QEgl::display(), config,
458 (EGLNativePixmapType) x11PixmapData->handle(),
459 surfaceAttribs.properties());
460 x11PixmapData->gl_surface = (void*)surf;
461 QImagePixmapCleanupHooks::enableCleanupHooks(x11PixmapData);
462 return surf;
463 }
464
465 return EGL_NO_SURFACE;
466}
467
468QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.