Re-apply change 353dcfd307853da289fdd245410e2e07358624a0 by Friedemann Kleint
[qt-netbsd.git] / src / opengl / qgl_x11egl.cpp
blob9db3a3098ba0940de96411b42fc67d5071741050
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** No Commercial Usage
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
26 ** package.
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.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "qgl.h"
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"
50 QT_BEGIN_NAMESPACE
53 bool QGLFormat::hasOpenGL()
55 return true;
58 bool QGLFormat::hasOpenGLOverlays()
60 return false;
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)
71 Q_D(QGLContext);
73 if (!device())
74 return false;
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())) {
82 delete d->eglContext;
83 d->eglContext = 0;
84 return false;
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)) {
96 delete d->eglContext;
97 d->eglContext = 0;
98 return false;
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;
108 d->eglContext = 0;
109 return false;
112 #if defined(EGL_VERSION_1_1)
113 if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
114 eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
115 #endif
117 return true;
121 void QGLContext::reset()
123 Q_D(QGLContext);
124 if (!d->valid)
125 return;
126 d->cleanup();
127 doneCurrent();
128 if (d->eglContext) {
129 delete d->eglContext;
130 d->eglContext = 0;
132 d->crWin = false;
133 d->sharing = false;
134 d->valid = false;
135 d->transpColor = QColor();
136 d->initDone = false;
137 qgl_share_reg()->removeShare(this);
140 void QGLContext::makeCurrent()
142 Q_D(QGLContext);
143 if(!d->valid || !d->eglContext) {
144 qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
145 return;
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;
153 currentCtx = this;
157 void QGLContext::doneCurrent()
159 Q_D(QGLContext);
160 if (d->eglContext)
161 d->eglContext->doneCurrent();
163 if (qgl_context_storage.hasLocalData())
164 qgl_context_storage.localData()->context = 0;
165 currentCtx = 0;
169 void QGLContext::swapBuffers() const
171 Q_D(const QGLContext);
172 if(!d->valid || !d->eglContext)
173 return;
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
186 Q_UNUSED(c);
187 return 0;
190 void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
192 Q_UNUSED(fnt);
193 Q_UNUSED(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 *)
209 Q_D(QGLWidget);
210 if (!isValid())
211 return;
212 makeCurrent();
213 if (!d->glcx->initialized())
214 glInit();
215 resizeGL(width(), height());
216 //handle overlay
219 const QGLContext* QGLWidget::overlayContext() const
221 return 0;
224 void QGLWidget::makeOverlayCurrent()
226 //handle overlay
229 void QGLWidget::updateOverlayGL()
231 //handle overlay
234 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
236 Q_D(QGLWidget);
237 if (context == 0) {
238 qWarning("QGLWidget::setContext: Cannot set null context");
239 return;
241 if (!context->deviceIsPixmap() && context->device() != this) {
242 qWarning("QGLWidget::setContext: Context must refer to this widget");
243 return;
246 if (d->glcx)
247 d->glcx->doneCurrent();
248 QGLContext* oldcx = d->glcx;
249 d->glcx = context;
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))
267 createFailed = true;
269 if (createFailed) {
270 if (deleteOldContext)
271 delete oldcx;
272 return;
275 if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
276 if (deleteOldContext)
277 delete oldcx;
278 return;
281 bool visible = isVisible();
282 if (visible)
283 hide();
285 XVisualInfo vi;
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;
294 if (vi.visualid) {
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);
304 else {
305 qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!",
306 nativeVisualId, (int)qeglCtx->config());
307 vi.visualid = 0;
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();
319 vi.depth = 32;
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);
333 break;
336 XFree(matchingVisuals);
338 #endif
340 if (vi.visualid == 0) {
341 EGLint depth;
342 qeglCtx->configAttrib(EGL_BUFFER_SIZE, &depth);
343 int err;
344 err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), depth, TrueColor, &vi);
345 if (err == 0) {
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);
350 if (err == 0) {
351 qWarning("Error: Couldn't get any matching X visual!");
352 return;
353 } else
354 qWarning(" - Falling back to X11 suggested depth (%d)", depth);
355 } else
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 :-(
359 if (useArgb)
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());
377 if (parentWidget())
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;
385 if(useArgb) {
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)
394 delete oldcx;
395 oldcx = 0;
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;
404 return;
407 d->eglSurfaceWindowId = w; // Remember the window id we created the surface for
409 if (visible)
410 show();
412 XFlush(X11->display);
413 d->glcx->setWindowCreated(true);
416 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
418 Q_Q(QGLWidget);
420 initContext(context, shareWidget);
422 if(q->isValid() && glcx->format().hasOverlay()) {
423 //no overlay
424 qWarning("QtOpenGL ES doesn't currently support overlays");
428 bool QGLWidgetPrivate::renderCxPm(QPixmap*)
430 return false;
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;
450 if (init_done)
451 return;
452 init_done = true;
453 init_extensions();
456 // Re-creates the EGL surface if the window ID has changed or if force is true
457 void QGLWidgetPrivate::recreateEglSurface(bool force)
459 Q_Q(QGLWidget);
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;
472 QT_END_NAMESPACE