Warning: That file was not part of the compilation database. It may have many parsing errors.

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 QtOpenGL 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 "qgl.h"
43#include <private/qt_x11_p.h>
44#include <private/qpixmap_x11_p.h>
45#include <private/qgl_p.h>
46#include <private/qpaintengine_opengl_p.h>
47#include "qgl_egl_p.h"
48#include "qcolormap.h"
49#include <QDebug>
50#include <QPixmap>
51
52
53QT_BEGIN_NAMESPACE
54
55
56/*
57 QGLTemporaryContext implementation
58*/
59
60class QGLTemporaryContextPrivate
61{
62public:
63 bool initialized;
64 Window window;
65 EGLContext context;
66 EGLSurface surface;
67 EGLDisplay display;
68};
69
70QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
71 : d(new QGLTemporaryContextPrivate)
72{
73 d->initialized = false;
74 d->window = 0;
75 d->context = 0;
76 d->surface = 0;
77 int screen = 0;
78
79 d->display = QEgl::display();
80
81 EGLConfig config;
82 int numConfigs = 0;
83 EGLint attribs[] = {
84 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
85#ifdef QT_OPENGL_ES_2
86 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
87#endif
88 EGL_NONE
89 };
90
91 eglChooseConfig(d->display, attribs, &config, 1, &numConfigs);
92 if (!numConfigs) {
93 qWarning("QGLTemporaryContext: No EGL configurations available.");
94 return;
95 }
96
97 XVisualInfo visualInfo;
98 XVisualInfo *vi;
99 int numVisuals;
100
101 visualInfo.visualid = QEgl::getCompatibleVisualId(config);
102 vi = XGetVisualInfo(X11->display, VisualIDMask, &visualInfo, &numVisuals);
103 if (!vi || numVisuals < 1) {
104 qWarning("QGLTemporaryContext: Unable to get X11 visual info id.");
105 return;
106 }
107
108 XSetWindowAttributes attr;
109 unsigned long mask;
110 attr.background_pixel = 0;
111 attr.border_pixel = 0;
112 attr.colormap = XCreateColormap(X11->display, DefaultRootWindow(X11->display), vi->visual, AllocNone);
113 attr.event_mask = StructureNotifyMask | ExposureMask;
114 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
115
116 d->window = XCreateWindow(X11->display, RootWindow(X11->display, screen),
117 0, 0, 1, 1, 0,
118 vi->depth, InputOutput, vi->visual,
119 mask, &attr);
120
121 d->surface = eglCreateWindowSurface(d->display, config, (EGLNativeWindowType) d->window, NULL);
122
123 if (d->surface == EGL_NO_SURFACE) {
124 qWarning("QGLTemporaryContext: Error creating EGL surface.");
125 XFree(vi);
126 XDestroyWindow(X11->display, d->window);
127 return;
128 }
129
130 EGLint contextAttribs[] = {
131#ifdef QT_OPENGL_ES_2
132 EGL_CONTEXT_CLIENT_VERSION, 2,
133#endif
134 EGL_NONE
135 };
136 d->context = eglCreateContext(d->display, config, 0, contextAttribs);
137 if (d->context != EGL_NO_CONTEXT
138 && eglMakeCurrent(d->display, d->surface, d->surface, d->context))
139 {
140 d->initialized = true;
141 } else {
142 qWarning("QGLTemporaryContext: Error creating EGL context.");
143 eglDestroySurface(d->display, d->surface);
144 XDestroyWindow(X11->display, d->window);
145 }
146 XFree(vi);
147}
148
149QGLTemporaryContext::~QGLTemporaryContext()
150{
151 if (d->initialized) {
152 eglMakeCurrent(d->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
153 eglDestroyContext(d->display, d->context);
154 eglDestroySurface(d->display, d->surface);
155 XDestroyWindow(X11->display, d->window);
156 }
157}
158
159bool QGLFormat::hasOpenGLOverlays()
160{
161 return false;
162}
163
164// Chooses the EGL config and creates the EGL context
165bool QGLContext::chooseContext(const QGLContext* shareContext)
166{
167 Q_D(QGLContext);
168
169 if (!device())
170 return false;
171
172 int devType = device()->devType();
173
174 QX11PixmapData *x11PixmapData = 0;
175 if (devType == QInternal::Pixmap) {
176 QPixmapData *pmd = static_cast<QPixmap*>(device())->data_ptr().data();
177 if (pmd->classId() == QPixmapData::X11Class)
178 x11PixmapData = static_cast<QX11PixmapData*>(pmd);
179 else {
180 // TODO: Replace the pixmap's data with a new QX11PixmapData
181 qWarning("WARNING: Creating a QGLContext on a QPixmap is only supported for X11 pixmap backend");
182 return false;
183 }
184 } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) {
185 qWarning("WARNING: Creating a QGLContext not supported on device type %d", devType);
186 return false;
187 }
188
189 // Only create the eglContext if we don't already have one:
190 if (d->eglContext == 0) {
191 d->eglContext = new QEglContext();
192 d->ownsEglContext = true;
193 d->eglContext->setApi(QEgl::OpenGL);
194
195 // If the device is a widget with WA_TranslucentBackground set, make sure the glFormat
196 // has the alpha channel option set:
197 if (devType == QInternal::Widget) {
198 QWidget* widget = static_cast<QWidget*>(device());
199 if (widget->testAttribute(Qt::WA_TranslucentBackground))
200 d->glFormat.setAlpha(true);
201 }
202
203 // Construct the configuration we need for this surface.
204 QEglProperties configProps;
205 configProps.setDeviceType(devType);
206 configProps.setRenderableType(QEgl::OpenGL);
207 qt_eglproperties_set_glformat(configProps, d->glFormat);
208
209 // Set buffer preserved for regular QWidgets, QGLWidgets are ok with either preserved or destroyed:
210 if ((devType == QInternal::Widget) && qobject_cast<QGLWidget*>(static_cast<QWidget*>(device())) == 0)
211 configProps.setValue(EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
212
213 if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) {
214 delete d->eglContext;
215 d->eglContext = 0;
216 return false;
217 }
218
219 // Create a new context for the configuration.
220 QEglContext* eglSharedContext = shareContext ? shareContext->d_func()->eglContext : 0;
221 if (!d->eglContext->createContext(eglSharedContext)) {
222 delete d->eglContext;
223 d->eglContext = 0;
224 return false;
225 }
226 d->sharing = d->eglContext->isSharing();
227 if (d->sharing && shareContext)
228 const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
229 }
230
231 // Inform the higher layers about the actual format properties
232 qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config());
233
234 // Do don't create the EGLSurface for everything.
235 // QWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface
236 // QGLWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface
237 // QPixmap - yes, create the EGLSurface but store it in QX11PixmapData::gl_surface
238 // QGLPixelBuffer - no, it creates the surface itself and stores it in QGLPixelBufferPrivate::pbuf
239
240 if (devType == QInternal::Widget) {
241 if (d->eglSurface != EGL_NO_SURFACE)
242 eglDestroySurface(d->eglContext->display(), d->eglSurface);
243 // extraWindowSurfaceCreationProps default to NULL unless were specifically set before
244 d->eglSurface = QEgl::createSurface(device(), d->eglContext->config(), d->extraWindowSurfaceCreationProps);
245 XFlush(X11->display);
246 setWindowCreated(true);
247 }
248
249 if (x11PixmapData) {
250 // TODO: Actually check to see if the existing surface can be re-used
251 if (x11PixmapData->gl_surface)
252 eglDestroySurface(d->eglContext->display(), (EGLSurface)x11PixmapData->gl_surface);
253
254 x11PixmapData->gl_surface = (void*)QEgl::createSurface(device(), d->eglContext->config());
255 }
256
257 return true;
258}
259
260void *QGLContext::chooseVisual()
261{
262 qFatal("QGLContext::chooseVisual - this method must not be called as Qt is built with EGL support");
263 return 0;
264}
265
266void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
267{
268 Q_UNUSED(f);
269 Q_UNUSED(bufDepth);
270 qFatal("QGLContext::tryVisual - this method must not be called as Qt is built with EGL support");
271 return 0;
272}
273
274void QGLWidget::resizeEvent(QResizeEvent *)
275{
276 Q_D(QGLWidget);
277 if (!isValid())
278 return;
279 makeCurrent();
280 if (!d->glcx->initialized())
281 glInit();
282 resizeGL(width(), height());
283 //handle overlay
284}
285
286const QGLContext* QGLWidget::overlayContext() const
287{
288 return 0;
289}
290
291void QGLWidget::makeOverlayCurrent()
292{
293 //handle overlay
294}
295
296void QGLWidget::updateOverlayGL()
297{
298 //handle overlay
299}
300
301void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
302{
303 Q_D(QGLWidget);
304 if (context == 0) {
305 qWarning("QGLWidget::setContext: Cannot set null context");
306 return;
307 }
308 if (!context->deviceIsPixmap() && context->device() != this) {
309 qWarning("QGLWidget::setContext: Context must refer to this widget");
310 return;
311 }
312
313 if (d->glcx)
314 d->glcx->doneCurrent();
315 QGLContext* oldcx = d->glcx;
316 d->glcx = context;
317
318 bool createFailed = false;
319 if (!d->glcx->isValid()) {
320 // Create the QGLContext here, which in turn chooses the EGL config
321 // and creates the EGL context:
322 if (!d->glcx->create(shareContext ? shareContext : oldcx))
323 createFailed = true;
324 }
325 if (createFailed) {
326 if (deleteOldContext)
327 delete oldcx;
328 return;
329 }
330
331
332 d->eglSurfaceWindowId = winId(); // Remember the window id we created the surface for
333}
334
335void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
336{
337 Q_Q(QGLWidget);
338
339 initContext(context, shareWidget);
340
341 if (q->isValid() && glcx->format().hasOverlay()) {
342 //no overlay
343 qWarning("QtOpenGL ES doesn't currently support overlays");
344 }
345}
346
347void QGLWidgetPrivate::cleanupColormaps()
348{
349}
350
351const QGLColormap & QGLWidget::colormap() const
352{
353 return d_func()->cmap;
354}
355
356void QGLWidget::setColormap(const QGLColormap &)
357{
358}
359
360// Re-creates the EGL surface if the window ID has changed or if there isn't a surface
361void QGLWidgetPrivate::recreateEglSurface()
362{
363 Q_Q(QGLWidget);
364
365 Window currentId = q->winId();
366
367 // If the window ID has changed since the surface was created, we need to delete the
368 // old surface before re-creating a new one. Note: This should not be the case as the
369 // surface should be deleted before the old window id.
370 if (glcx->d_func()->eglSurface != EGL_NO_SURFACE && (currentId != eglSurfaceWindowId)) {
371 qWarning("EGL surface for deleted window %lx was not destroyed", uint(eglSurfaceWindowId));
372 glcx->d_func()->destroyEglSurfaceForDevice();
373 }
374
375 if (glcx->d_func()->eglSurface == EGL_NO_SURFACE) {
376 glcx->d_func()->eglSurface = glcx->d_func()->eglContext->createSurface(q);
377 eglSurfaceWindowId = currentId;
378 }
379}
380
381
382QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key,
383 QGLContext::BindOptions options)
384{
385 Q_Q(QGLContext);
386
387 // The EGL texture_from_pixmap has no facility to invert the y coordinate
388 if (!(options & QGLContext::CanFlipNativePixmapBindOption))
389 return 0;
390
391
392 static bool checkedForTFP = false;
393 static bool haveTFP = false;
394 static bool checkedForEglImageTFP = false;
395 static bool haveEglImageTFP = false;
396
397
398 if (!checkedForEglImageTFP) {
399 checkedForEglImageTFP = true;
400
401 // We need to be able to create an EGLImage from a native pixmap, which was split
402 // into a separate EGL extension, EGL_KHR_image_pixmap. It is possible to have
403 // eglCreateImageKHR & eglDestroyImageKHR without support for pixmaps, so we must
404 // check we have the EGLImage from pixmap functionality.
405 if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) {
406
407 // Being able to create an EGLImage from a native pixmap is also pretty useless
408 // without the ability to bind that EGLImage as a texture, which is provided by
409 // the GL_OES_EGL_image extension, which we try to resolve here:
410 haveEglImageTFP = qt_resolve_eglimage_gl_extensions(q);
411
412 if (haveEglImageTFP)
413 qDebug("Found EGL_KHR_image_pixmap & GL_OES_EGL_image extensions (preferred method)!");
414 }
415 }
416
417 if (!checkedForTFP) {
418 // Check for texture_from_pixmap egl extension
419 checkedForTFP = true;
420 if (QEgl::hasExtension("EGL_NOKIA_texture_from_pixmap") ||
421 QEgl::hasExtension("EGL_EXT_texture_from_pixmap"))
422 {
423 qDebug("Found texture_from_pixmap EGL extension!");
424 haveTFP = true;
425 }
426 }
427
428 if (!haveTFP && !haveEglImageTFP)
429 return 0;
430
431
432 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data());
433 Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
434 bool hasAlpha = pixmapData->hasAlphaChannel();
435 bool pixmapHasValidSurface = false;
436 bool textureIsBound = false;
437 GLuint textureId;
438 glGenTextures(1, &textureId);
439 glBindTexture(GL_TEXTURE_2D, textureId);
440
441 if (haveTFP && pixmapData->gl_surface &&
442 hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
443 {
444 pixmapHasValidSurface = true;
445 }
446
447 // If we already have a valid EGL surface for the pixmap, we should use it
448 if (pixmapHasValidSurface) {
449 EGLBoolean success;
450 success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
451 if (success == EGL_FALSE) {
452 qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
453 eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
454 pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
455 } else
456 textureIsBound = true;
457 }
458
459 // If the pixmap doesn't already have a valid surface, try binding it via EGLImage
460 // first, as going through EGLImage should be faster and better supported:
461 if (!textureIsBound && haveEglImageTFP) {
462 EGLImageKHR eglImage;
463
464 EGLint attribs[] = {
465 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
466 EGL_NONE
467 };
468 eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
469 (EGLClientBuffer)QEgl::nativePixmap(pixmap), attribs);
470
471 QGLContext* ctx = q;
472 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);
473
474 GLint err = glGetError();
475 if (err == GL_NO_ERROR)
476 textureIsBound = true;
477
478 // Once the egl image is bound, the texture becomes a new sibling image and we can safely
479 // destroy the EGLImage we created for the pixmap:
480 if (eglImage != EGL_NO_IMAGE_KHR)
481 QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
482 }
483
484 if (!textureIsBound && haveTFP) {
485 // Check to see if the surface is still valid
486 if (pixmapData->gl_surface &&
487 hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
488 {
489 // Surface is invalid!
490 destroyGlSurfaceForPixmap(pixmapData);
491 }
492
493 if (pixmapData->gl_surface == 0) {
494 EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
495 QEgl::OpenGL,
496 hasAlpha ? QEgl::Translucent : QEgl::NoOptions);
497
498 pixmapData->gl_surface = (void*)QEgl::createSurface(pixmap, config);
499 if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE)
500 return false;
501 }
502
503 EGLBoolean success;
504 success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
505 if (success == EGL_FALSE) {
506 qWarning() << "eglBindTexImage() failed:" << QEgl::errorString();
507 eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
508 pixmapData->gl_surface = (void*)EGL_NO_SURFACE;
509 haveTFP = false; // If TFP isn't working, disable it's use
510 } else
511 textureIsBound = true;
512 }
513
514 QGLTexture *texture = 0;
515
516 if (textureIsBound) {
517 texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
518 pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
519
520 // We assume the cost of bound pixmaps is zero
521 QGLTextureCache::instance()->insert(q, key, texture, 0);
522
523 glBindTexture(GL_TEXTURE_2D, textureId);
524 } else
525 glDeleteTextures(1, &textureId);
526
527 return texture;
528}
529
530
531void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
532{
533 Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
534 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
535 if (pixmapData->gl_surface) {
536 EGLBoolean success;
537 success = eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
538 if (success == EGL_FALSE) {
539 qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
540 << QEgl::errorString();
541 }
542 pixmapData->gl_surface = 0;
543 }
544}
545
546void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
547{
548 Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
549 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
550 if (pixmapData->gl_surface) {
551 EGLBoolean success;
552 success = eglReleaseTexImage(QEgl::display(),
553 (EGLSurface)pixmapData->gl_surface,
554 EGL_BACK_BUFFER);
555 if (success == EGL_FALSE) {
556 qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
557 << QEgl::errorString();
558 }
559 }
560}
561
562QT_END_NAMESPACE
563

Warning: That file was not part of the compilation database. It may have many parsing errors.