1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
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.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at http://www.qtsoftware.com/contact.
40 ****************************************************************************/
43 #include <private/qt_x11_p.h>
44 #include <private/qgl_p.h>
45 #include <private/qpaintengine_opengl_p.h>
46 #include "qgl_egl_p.h"
47 #include "qcolormap.h"
53 bool QGLFormat::hasOpenGL()
58 bool QGLFormat::hasOpenGLOverlays()
63 void qt_egl_add_platform_config(QEglProperties
& props
, QPaintDevice
*device
)
65 if (device
->devType() == QInternal::Image
)
66 props
.setPixelFormat(static_cast<QImage
*>(device
)->format());
69 bool QGLContext::chooseContext(const QGLContext
* shareContext
)
76 int devType
= device()->devType();
78 // Get the display and initialize it.
79 d
->eglContext
= new QEglContext();
80 d
->eglContext
->setApi(QEgl::OpenGL
);
81 if (!d
->eglContext
->openDisplay(device())) {
87 // Construct the configuration we need for this surface.
88 QEglProperties configProps
;
89 qt_egl_set_format(configProps
, devType
, d
->glFormat
);
90 qt_egl_add_platform_config(configProps
, device());
91 configProps
.setRenderableType(QEgl::OpenGL
);
93 // Search for a matching configuration, reducing the complexity
94 // each time until we get something that matches.
95 if (!d
->eglContext
->chooseConfig(configProps
, QEgl::BestPixelFormat
)) {
101 // Inform the higher layers about the actual format properties.
102 qt_egl_update_format(*(d
->eglContext
), d
->glFormat
);
104 // Create a new context for the configuration.
105 if (!d
->eglContext
->createContext
106 (shareContext
? shareContext
->d_func()->eglContext
: 0)) {
107 delete d
->eglContext
;
112 #if defined(EGL_VERSION_1_1)
113 if (d
->glFormat
.swapInterval() != -1 && devType
== QInternal::Widget
)
114 eglSwapInterval(d
->eglContext
->display(), d
->glFormat
.swapInterval());
121 void QGLContext::reset()
129 delete d
->eglContext
;
135 d
->transpColor
= QColor();
137 qgl_share_reg()->removeShare(this);
140 void QGLContext::makeCurrent()
143 if(!d
->valid
|| !d
->eglContext
) {
144 qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
148 if (d
->eglContext
->makeCurrent()) {
149 if (!qgl_context_storage
.hasLocalData() && QThread::currentThread())
150 qgl_context_storage
.setLocalData(new QGLThreadContext
);
151 if (qgl_context_storage
.hasLocalData())
152 qgl_context_storage
.localData()->context
= this;
157 void QGLContext::doneCurrent()
161 d
->eglContext
->doneCurrent();
163 if (qgl_context_storage
.hasLocalData())
164 qgl_context_storage
.localData()->context
= 0;
169 void QGLContext::swapBuffers() const
171 Q_D(const QGLContext
);
172 if(!d
->valid
|| !d
->eglContext
)
175 d
->eglContext
->swapBuffers();
178 QColor
QGLContext::overlayTransparentColor() const
180 return QColor(0, 0, 0); // Invalid color
183 uint
QGLContext::colorIndex(const QColor
&c
) const
185 //### color index doesn't work on egl
190 void QGLContext::generateFontDisplayLists(const QFont
& fnt
, int listBase
)
196 void *QGLContext::getProcAddress(const QString
&proc
) const
198 return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc
.toLatin1().data()));
201 void QGLWidget::setMouseTracking(bool enable
)
203 QWidget::setMouseTracking(enable
);
207 void QGLWidget::resizeEvent(QResizeEvent
*)
213 if (!d
->glcx
->initialized())
215 resizeGL(width(), height());
219 const QGLContext
* QGLWidget::overlayContext() const
224 void QGLWidget::makeOverlayCurrent()
229 void QGLWidget::updateOverlayGL()
234 void QGLWidget::setContext(QGLContext
*context
, const QGLContext
* shareContext
, bool deleteOldContext
)
238 qWarning("QGLWidget::setContext: Cannot set null context");
241 if (!context
->deviceIsPixmap() && context
->device() != this) {
242 qWarning("QGLWidget::setContext: Context must refer to this widget");
247 d
->glcx
->doneCurrent();
248 QGLContext
* oldcx
= d
->glcx
;
251 if (parentWidget()) {
252 // force creation of delay-created widgets
253 parentWidget()->winId();
254 if (parentWidget()->x11Info().screen() != x11Info().screen())
255 d_func()->xinfo
= parentWidget()->d_func()->xinfo
;
258 // If the application has set WA_TranslucentBackground and not explicitly set
259 // the alpha buffer size to zero, modify the format so it have an alpha channel
260 QGLFormat
& fmt
= d
->glcx
->d_func()->glFormat
;
261 if (testAttribute(Qt::WA_TranslucentBackground
) && fmt
.alphaBufferSize() == -1)
262 fmt
.setAlphaBufferSize(1);
264 bool createFailed
= false;
265 if (!d
->glcx
->isValid()) {
266 if (!d
->glcx
->create(shareContext
? shareContext
: oldcx
))
270 if (deleteOldContext
)
275 if (d
->glcx
->windowCreated() || d
->glcx
->deviceIsPixmap()) {
276 if (deleteOldContext
)
281 bool visible
= isVisible();
286 memset(&vi
, 0, sizeof(XVisualInfo
));
288 // Check to see if EGL is suggesting an appropriate visual id:
289 EGLint nativeVisualId
;
290 QEglContext
* qeglCtx
= d
->glcx
->d_func()->eglContext
;
291 qeglCtx
->configAttrib(EGL_NATIVE_VISUAL_ID
, &nativeVisualId
);
292 vi
.visualid
= nativeVisualId
;
295 // EGL has suggested a visual id, so get the rest of the visual info for that id:
296 XVisualInfo
*chosenVisualInfo
;
297 int matchingCount
= 0;
298 chosenVisualInfo
= XGetVisualInfo(x11Info().display(), VisualIDMask
, &vi
, &matchingCount
);
299 if (chosenVisualInfo
) {
300 qDebug("Using X Visual ID (%d) provided by EGL", (int)vi
.visualid
);
301 vi
= *chosenVisualInfo
;
302 XFree(chosenVisualInfo
);
305 qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!",
306 nativeVisualId
, (int)qeglCtx
->config());
311 // If EGL does not know the visual ID, so try to select an appropriate one ourselves, first
312 // using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo
314 bool useArgb
= context
->format().alpha() && !context
->deviceIsPixmap();
315 #if !defined(QT_NO_XRENDER)
316 if (vi
.visualid
== 0 && useArgb
) {
317 // Try to use XRender to find an ARGB visual we can use
318 vi
.screen
= x11Info().screen();
320 vi
.c_class
= TrueColor
;
321 XVisualInfo
*matchingVisuals
;
322 int matchingCount
= 0;
323 matchingVisuals
= XGetVisualInfo(x11Info().display(),
324 VisualScreenMask
|VisualDepthMask
|VisualClassMask
,
325 &vi
, &matchingCount
);
327 for (int i
= 0; i
< matchingCount
; ++i
) {
328 XRenderPictFormat
*format
;
329 format
= XRenderFindVisualFormat(x11Info().display(), matchingVisuals
[i
].visual
);
330 if (format
->type
== PictTypeDirect
&& format
->direct
.alphaMask
) {
331 vi
= matchingVisuals
[i
];
332 qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi
.visualid
);
336 XFree(matchingVisuals
);
340 if (vi
.visualid
== 0) {
342 qeglCtx
->configAttrib(EGL_BUFFER_SIZE
, &depth
);
344 err
= XMatchVisualInfo(x11Info().display(), x11Info().screen(), depth
, TrueColor
, &vi
);
346 qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!",
347 (int)qeglCtx
->config(), depth
);
348 depth
= x11Info().depth();
349 err
= XMatchVisualInfo(x11Info().display(), x11Info().screen(), depth
, TrueColor
, &vi
);
351 qWarning("Error: Couldn't get any matching X visual!");
354 qWarning(" - Falling back to X11 suggested depth (%d)", depth
);
356 qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi
.visualid
, depth
);
358 // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-(
360 useArgb
= vi
.depth
== 32;
363 // qDebug("Visual Info:");
364 // qDebug(" bits_per_rgb=%d", vi.bits_per_rgb);
365 // qDebug(" red_mask=0x%x", vi.red_mask);
366 // qDebug(" green_mask=0x%x", vi.green_mask);
367 // qDebug(" blue_mask=0x%x", vi.blue_mask);
368 // qDebug(" colormap_size=%d", vi.colormap_size);
369 // qDebug(" c_class=%d", vi.c_class);
370 // qDebug(" depth=%d", vi.depth);
371 // qDebug(" screen=%d", vi.screen);
372 // qDebug(" visualid=%d", vi.visualid);
374 XSetWindowAttributes a
;
376 Window p
= RootWindow(x11Info().display(), x11Info().screen());
378 p
= parentWidget()->winId();
380 QColormap colmap
= QColormap::instance(vi
.screen
);
381 a
.background_pixel
= colmap
.pixel(palette().color(backgroundRole()));
382 a
.border_pixel
= colmap
.pixel(Qt::black
);
384 unsigned int valueMask
= CWBackPixel
|CWBorderPixel
;
386 a
.colormap
= XCreateColormap(x11Info().display(), p
, vi
.visual
, AllocNone
);
387 valueMask
|= CWColormap
;
390 Window w
= XCreateWindow(x11Info().display(), p
, x(), y(), width(), height(),
391 0, vi
.depth
, InputOutput
, vi
.visual
, valueMask
, &a
);
393 if (deleteOldContext
)
397 create(w
); // Create with the ID of the window we've just created
400 // Create the EGL surface to draw into.
401 if (!d
->glcx
->d_func()->eglContext
->createSurface(this)) {
402 delete d
->glcx
->d_func()->eglContext
;
403 d
->glcx
->d_func()->eglContext
= 0;
407 d
->eglSurfaceWindowId
= w
; // Remember the window id we created the surface for
412 XFlush(X11
->display
);
413 d
->glcx
->setWindowCreated(true);
416 void QGLWidgetPrivate::init(QGLContext
*context
, const QGLWidget
* shareWidget
)
420 initContext(context
, shareWidget
);
422 if(q
->isValid() && glcx
->format().hasOverlay()) {
424 qWarning("QtOpenGL ES doesn't currently support overlays");
428 bool QGLWidgetPrivate::renderCxPm(QPixmap
*)
433 void QGLWidgetPrivate::cleanupColormaps()
437 const QGLColormap
& QGLWidget::colormap() const
439 return d_func()->cmap
;
442 void QGLWidget::setColormap(const QGLColormap
&)
446 void QGLExtensions::init()
448 static bool init_done
= false;
456 // Re-creates the EGL surface if the window ID has changed or if force is true
457 void QGLWidgetPrivate::recreateEglSurface(bool force
)
461 Window currentId
= q
->winId();
463 if ( force
|| (currentId
!= eglSurfaceWindowId
) ) {
464 // The window id has changed so we need to re-create the EGL surface
465 if (!glcx
->d_func()->eglContext
->recreateSurface(q
))
466 qWarning("Error creating EGL window surface: 0x%x", eglGetError());
468 eglSurfaceWindowId
= currentId
;