source: trunk/src/opengl/qgl_x11egl.cpp@ 729

Last change on this file since 729 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 26.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 QtOpenGL 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 "qgl.h"
43#include <private/qt_x11_p.h>
44#include <private/qpixmap_x11_p.h>
45#include <private/qimagepixmapcleanuphooks_p.h>
46#include <private/qgl_p.h>
47#include <private/qpaintengine_opengl_p.h>
48#include "qgl_egl_p.h"
49#include "qcolormap.h"
50#include <QDebug>
51
52
53QT_BEGIN_NAMESPACE
54
55
56bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config,
57 const QX11Info &x11Info, bool useArgbVisual);
58
59/*
60 QGLTemporaryContext implementation
61*/
62
63class QGLTemporaryContextPrivate
64{
65public:
66 bool initialized;
67 Window window;
68 EGLContext context;
69 EGLSurface surface;
70 EGLDisplay display;
71};
72
73QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
74 : d(new QGLTemporaryContextPrivate)
75{
76 d->initialized = false;
77 d->window = 0;
78 d->context = 0;
79 d->surface = 0;
80 int screen = 0;
81
82 d->display = eglGetDisplay(EGLNativeDisplayType(X11->display));
83
84 if (!eglInitialize(d->display, NULL, NULL)) {
85 qWarning("QGLTemporaryContext: Unable to initialize EGL display.");
86 return;
87 }
88
89 EGLConfig config;
90 int numConfigs = 0;
91 EGLint attribs[] = {
92 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
93#ifdef QT_OPENGL_ES_2
94 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
95#endif
96 EGL_NONE
97 };
98
99 eglChooseConfig(d->display, attribs, &config, 1, &numConfigs);
100 if (!numConfigs) {
101 qWarning("QGLTemporaryContext: No EGL configurations available.");
102 return;
103 }
104
105 XVisualInfo visualInfo;
106 XVisualInfo *vi;
107 int numVisuals;
108 EGLint id = 0;
109
110 eglGetConfigAttrib(d->display, config, EGL_NATIVE_VISUAL_ID, &id);
111 if (id == 0) {
112 // EGL_NATIVE_VISUAL_ID is optional and might not be supported
113 // on some implementations - we'll have to do it the hard way
114 QX11Info xinfo;
115 qt_egl_setup_x11_visual(visualInfo, d->display, config, xinfo, false);
116 } else {
117 visualInfo.visualid = id;
118 }
119 vi = XGetVisualInfo(X11->display, VisualIDMask, &visualInfo, &numVisuals);
120 if (!vi || numVisuals < 1) {
121 qWarning("QGLTemporaryContext: Unable to get X11 visual info id.");
122 return;
123 }
124
125 d->window = XCreateWindow(X11->display, RootWindow(X11->display, screen),
126 0, 0, 1, 1, 0,
127 vi->depth, InputOutput, vi->visual,
128 0, 0);
129
130 d->surface = eglCreateWindowSurface(d->display, config, (EGLNativeWindowType) d->window, NULL);
131
132 if (d->surface == EGL_NO_SURFACE) {
133 qWarning("QGLTemporaryContext: Error creating EGL surface.");
134 XFree(vi);
135 XDestroyWindow(X11->display, d->window);
136 return;
137 }
138
139 EGLint contextAttribs[] = {
140#ifdef QT_OPENGL_ES_2
141 EGL_CONTEXT_CLIENT_VERSION, 2,
142#endif
143 EGL_NONE
144 };
145 d->context = eglCreateContext(d->display, config, 0, contextAttribs);
146 if (d->context != EGL_NO_CONTEXT
147 && eglMakeCurrent(d->display, d->surface, d->surface, d->context))
148 {
149 d->initialized = true;
150 } else {
151 qWarning("QGLTemporaryContext: Error creating EGL context.");
152 eglDestroySurface(d->display, d->surface);
153 XDestroyWindow(X11->display, d->window);
154 }
155 XFree(vi);
156}
157
158QGLTemporaryContext::~QGLTemporaryContext()
159{
160 if (d->initialized) {
161 eglMakeCurrent(d->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
162 eglDestroyContext(d->display, d->context);
163 eglDestroySurface(d->display, d->surface);
164 XDestroyWindow(X11->display, d->window);
165 }
166}
167
168bool QGLFormat::hasOpenGLOverlays()
169{
170 return false;
171}
172
173void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
174{
175 if (device->devType() == QInternal::Image)
176 props.setPixelFormat(static_cast<QImage *>(device)->format());
177}
178
179// Chooses the EGL config and creates the EGL context
180bool QGLContext::chooseContext(const QGLContext* shareContext)
181{
182 Q_D(QGLContext);
183
184 if (!device())
185 return false;
186
187 int devType = device()->devType();
188
189 // Get the display and initialize it.
190 if (d->eglContext == 0) {
191 d->eglContext = new QEglContext();
192 d->eglContext->setApi(QEgl::OpenGL);
193 if (!d->eglContext->openDisplay(device())) {
194 delete d->eglContext;
195 d->eglContext = 0;
196 return false;
197 }
198
199 // Construct the configuration we need for this surface.
200 QEglProperties configProps;
201 qt_egl_set_format(configProps, devType, d->glFormat);
202 qt_egl_add_platform_config(configProps, device());
203 configProps.setRenderableType(QEgl::OpenGL);
204
205#if We_have_an_EGL_library_which_bothers_to_check_EGL_BUFFER_SIZE
206 if (device()->depth() == 16 && configProps.value(EGL_ALPHA_SIZE) <= 0) {
207 qDebug("Setting EGL_BUFFER_SIZE to 16");
208 configProps.setValue(EGL_BUFFER_SIZE, 16);
209 configProps.setValue(EGL_ALPHA_SIZE, 0);
210 }
211
212 if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) {
213 delete d->eglContext;
214 d->eglContext = 0;
215 return false;
216 }
217#else
218 QEgl::PixelFormatMatch matchType = QEgl::BestPixelFormat;
219 if ((device()->depth() == 16) && configProps.value(EGL_ALPHA_SIZE) == 0) {
220 configProps.setValue(EGL_RED_SIZE, 5);
221 configProps.setValue(EGL_GREEN_SIZE, 6);
222 configProps.setValue(EGL_BLUE_SIZE, 5);
223 configProps.setValue(EGL_ALPHA_SIZE, 0);
224 matchType = QEgl::ExactPixelFormat;
225 }
226
227 // Search for a matching configuration, reducing the complexity
228 // each time until we get something that matches.
229 if (!d->eglContext->chooseConfig(configProps, matchType)) {
230 delete d->eglContext;
231 d->eglContext = 0;
232 return false;
233 }
234#endif
235
236// qDebug("QGLContext::chooseContext() - using EGL config %d:", d->eglContext->config());
237// qDebug() << QEglProperties(d->eglContext->config()).toString();
238
239 // Create a new context for the configuration.
240 if (!d->eglContext->createContext
241 (shareContext ? shareContext->d_func()->eglContext : 0)) {
242 delete d->eglContext;
243 d->eglContext = 0;
244 return false;
245 }
246 d->sharing = d->eglContext->isSharing();
247 if (d->sharing && shareContext)
248 const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
249
250#if defined(EGL_VERSION_1_1)
251 if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
252 eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
253#endif
254 }
255
256 // Inform the higher layers about the actual format properties.
257 qt_egl_update_format(*(d->eglContext), d->glFormat);
258
259 return true;
260}
261
262void QGLWidget::resizeEvent(QResizeEvent *)
263{
264 Q_D(QGLWidget);
265 if (!isValid())
266 return;
267 makeCurrent();
268 if (!d->glcx->initialized())
269 glInit();
270 resizeGL(width(), height());
271 //handle overlay
272}
273
274const QGLContext* QGLWidget::overlayContext() const
275{
276 return 0;
277}
278
279void QGLWidget::makeOverlayCurrent()
280{
281 //handle overlay
282}
283
284void QGLWidget::updateOverlayGL()
285{
286 //handle overlay
287}
288
289//#define QT_DEBUG_X11_VISUAL_SELECTION 1
290
291bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual)
292{
293 bool foundVisualIsArgb = useArgbVisual;
294
295#ifdef QT_DEBUG_X11_VISUAL_SELECTION
296 qDebug("qt_egl_setup_x11_visual() - useArgbVisual=%d", useArgbVisual);
297#endif
298
299 memset(&vi, 0, sizeof(XVisualInfo));
300
301 EGLint eglConfigColorSize;
302 eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &eglConfigColorSize);
303
304 // Check to see if EGL is suggesting an appropriate visual id:
305 EGLint nativeVisualId;
306 eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId);
307 vi.visualid = nativeVisualId;
308
309 if (vi.visualid) {
310 // EGL has suggested a visual id, so get the rest of the visual info for that id:
311 XVisualInfo *chosenVisualInfo;
312 int matchingCount = 0;
313 chosenVisualInfo = XGetVisualInfo(x11Info.display(), VisualIDMask, &vi, &matchingCount);
314 if (chosenVisualInfo) {
315#if !defined(QT_NO_XRENDER)
316 if (useArgbVisual) {
317 // Check to make sure the visual provided by EGL is ARGB
318 XRenderPictFormat *format;
319 format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual);
320 if (format->type == PictTypeDirect && format->direct.alphaMask) {
321#ifdef QT_DEBUG_X11_VISUAL_SELECTION
322 qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid);
323#endif
324 foundVisualIsArgb = true;
325 vi = *chosenVisualInfo;
326 }
327 else {
328 qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this is not ARGB",
329 nativeVisualId, (int)config);
330 vi.visualid = 0;
331 }
332 } else
333#endif
334 {
335 if (eglConfigColorSize == chosenVisualInfo->depth) {
336#ifdef QT_DEBUG_X11_VISUAL_SELECTION
337 qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
338#endif
339 vi = *chosenVisualInfo;
340 } else
341 qWarning("Warning: EGL suggested using X visual ID %d (%d bpp) for config %d (%d bpp), but the depths do not match!",
342 nativeVisualId, chosenVisualInfo->depth, (int)config, eglConfigColorSize);
343 }
344 XFree(chosenVisualInfo);
345 }
346 else {
347 qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!",
348 nativeVisualId, (int)config);
349 vi.visualid = 0;
350 }
351 }
352
353 // If EGL does not know the visual ID, so try to select an appropriate one ourselves, first
354 // using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo
355
356#if !defined(QT_NO_XRENDER)
357 if (vi.visualid == 0 && useArgbVisual) {
358 // Try to use XRender to find an ARGB visual we can use
359 vi.screen = x11Info.screen();
360 vi.depth = 32; //### We might at some point (soon) get ARGB4444
361 vi.c_class = TrueColor;
362 XVisualInfo *matchingVisuals;
363 int matchingCount = 0;
364 matchingVisuals = XGetVisualInfo(x11Info.display(),
365 VisualScreenMask|VisualDepthMask|VisualClassMask,
366 &vi, &matchingCount);
367
368 for (int i = 0; i < matchingCount; ++i) {
369 XRenderPictFormat *format;
370 format = XRenderFindVisualFormat(x11Info.display(), matchingVisuals[i].visual);
371 if (format->type == PictTypeDirect && format->direct.alphaMask) {
372 vi = matchingVisuals[i];
373 foundVisualIsArgb = true;
374#ifdef QT_DEBUG_X11_VISUAL_SELECTION
375 qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid);
376#endif
377 break;
378 }
379 }
380 XFree(matchingVisuals);
381 }
382#endif
383
384 if (vi.visualid == 0) {
385 EGLint depth;
386 eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth);
387 int err;
388 err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
389 if (err == 0) {
390 qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!",
391 (int)config, depth);
392 depth = x11Info.depth();
393 err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
394 if (err == 0) {
395 qWarning("Error: Couldn't get any matching X visual!");
396 return false;
397 } else
398 qWarning(" - Falling back to X11 suggested depth (%d)", depth);
399 }
400#ifdef QT_DEBUG_X11_VISUAL_SELECTION
401 else
402 qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth);
403#endif
404
405 // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-(
406 if (useArgbVisual)
407 foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444
408 }
409
410#ifdef QT_DEBUG_X11_VISUAL_SELECTION
411 qDebug("Visual Info:");
412 qDebug(" bits_per_rgb=%d", vi.bits_per_rgb);
413 qDebug(" red_mask=0x%x", vi.red_mask);
414 qDebug(" green_mask=0x%x", vi.green_mask);
415 qDebug(" blue_mask=0x%x", vi.blue_mask);
416 qDebug(" colormap_size=%d", vi.colormap_size);
417 qDebug(" c_class=%d", vi.c_class);
418 qDebug(" depth=%d", vi.depth);
419 qDebug(" screen=%d", vi.screen);
420 qDebug(" visualid=%d", vi.visualid);
421#endif
422 return foundVisualIsArgb;
423}
424
425void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
426{
427 Q_D(QGLWidget);
428 if (context == 0) {
429 qWarning("QGLWidget::setContext: Cannot set null context");
430 return;
431 }
432 if (!context->deviceIsPixmap() && context->device() != this) {
433 qWarning("QGLWidget::setContext: Context must refer to this widget");
434 return;
435 }
436
437 if (d->glcx)
438 d->glcx->doneCurrent();
439 QGLContext* oldcx = d->glcx;
440 d->glcx = context;
441
442 if (parentWidget()) {
443 // force creation of delay-created widgets
444 parentWidget()->winId();
445 if (parentWidget()->x11Info().screen() != x11Info().screen())
446 d_func()->xinfo = parentWidget()->d_func()->xinfo;
447 }
448
449 // If the application has set WA_TranslucentBackground and not explicitly set
450 // the alpha buffer size to zero, modify the format so it have an alpha channel
451 QGLFormat& fmt = d->glcx->d_func()->glFormat;
452 const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground) || fmt.alpha();
453 if (tryArgbVisual && fmt.alphaBufferSize() == -1)
454 fmt.setAlphaBufferSize(1);
455
456 bool createFailed = false;
457 if (!d->glcx->isValid()) {
458 // Create the QGLContext here, which in turn chooses the EGL config
459 // and creates the EGL context:
460 if (!d->glcx->create(shareContext ? shareContext : oldcx))
461 createFailed = true;
462 }
463 if (createFailed) {
464 if (deleteOldContext)
465 delete oldcx;
466 return;
467 }
468
469 if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
470 if (deleteOldContext)
471 delete oldcx;
472 return;
473 }
474
475 bool visible = isVisible();
476 if (visible)
477 hide();
478
479 XVisualInfo vi;
480 QEglContext *eglContext = d->glcx->d_func()->eglContext;
481 bool usingArgbVisual = qt_egl_setup_x11_visual(vi, eglContext->display(), eglContext->config(),
482 x11Info(), tryArgbVisual);
483
484 XSetWindowAttributes a;
485
486 Window p = RootWindow(x11Info().display(), x11Info().screen());
487 if (parentWidget())
488 p = parentWidget()->winId();
489
490 QColormap colmap = QColormap::instance(vi.screen);
491 a.background_pixel = colmap.pixel(palette().color(backgroundRole()));
492 a.border_pixel = colmap.pixel(Qt::black);
493
494 unsigned int valueMask = CWBackPixel|CWBorderPixel;
495 if (usingArgbVisual) {
496 a.colormap = XCreateColormap(x11Info().display(), p, vi.visual, AllocNone);
497 valueMask |= CWColormap;
498 }
499
500 Window w = XCreateWindow(x11Info().display(), p, x(), y(), width(), height(),
501 0, vi.depth, InputOutput, vi.visual, valueMask, &a);
502
503 if (deleteOldContext)
504 delete oldcx;
505 oldcx = 0;
506
507 create(w); // Create with the ID of the window we've just created
508
509
510 // Create the EGL surface to draw into.
511 QGLContextPrivate *ctxpriv = d->glcx->d_func();
512 ctxpriv->eglSurface = ctxpriv->eglContext->createSurface(this);
513 if (ctxpriv->eglSurface == EGL_NO_SURFACE) {
514 delete ctxpriv->eglContext;
515 ctxpriv->eglContext = 0;
516 return;
517 }
518
519 d->eglSurfaceWindowId = w; // Remember the window id we created the surface for
520
521 if (visible)
522 show();
523
524 XFlush(X11->display);
525 d->glcx->setWindowCreated(true);
526}
527
528void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
529{
530 Q_Q(QGLWidget);
531
532 initContext(context, shareWidget);
533
534 if(q->isValid() && glcx->format().hasOverlay()) {
535 //no overlay
536 qWarning("QtOpenGL ES doesn't currently support overlays");
537 }
538}
539
540void QGLWidgetPrivate::cleanupColormaps()
541{
542}
543
544const QGLColormap & QGLWidget::colormap() const
545{
546 return d_func()->cmap;
547}
548
549void QGLWidget::setColormap(const QGLColormap &)
550{
551}
552
553// Re-creates the EGL surface if the window ID has changed or if force is true
554void QGLWidgetPrivate::recreateEglSurface(bool force)
555{
556 Q_Q(QGLWidget);
557
558 Window currentId = q->winId();
559
560 if ( force || (currentId != eglSurfaceWindowId) ) {
561 // The window id has changed so we need to re-create the EGL surface
562 QEglContext *ctx = glcx->d_func()->eglContext;
563 EGLSurface surface = glcx->d_func()->eglSurface;
564 if (surface != EGL_NO_SURFACE)
565 ctx->destroySurface(surface); // Will force doneCurrent() if nec.
566 surface = ctx->createSurface(q);
567 if (surface == EGL_NO_SURFACE)
568 qWarning("Error creating EGL window surface: 0x%x", eglGetError());
569 glcx->d_func()->eglSurface = surface;
570
571 eglSurfaceWindowId = currentId;
572 }
573}
574
575// Selects which configs should be used
576EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly)
577{
578 // Cache the configs we select as they wont change:
579 static EGLConfig roPixmapRGBConfig = 0;
580 static EGLConfig roPixmapRGBAConfig = 0;
581 static EGLConfig rwPixmapRGBConfig = 0;
582 static EGLConfig rwPixmapRGBAConfig = 0;
583
584 EGLConfig* targetConfig;
585
586 if (hasAlpha) {
587 if (readOnly)
588 targetConfig = &roPixmapRGBAConfig;
589 else
590 targetConfig = &rwPixmapRGBAConfig;
591 }
592 else {
593 if (readOnly)
594 targetConfig = &roPixmapRGBConfig;
595 else
596 targetConfig = &rwPixmapRGBConfig;
597 }
598
599 if (*targetConfig == 0) {
600 QEglProperties configAttribs;
601 configAttribs.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT);
602 configAttribs.setRenderableType(QEgl::OpenGL);
603 if (hasAlpha)
604 configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
605 else
606 configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
607
608 // If this is going to be a render target, it needs to have a depth, stencil & sample buffer
609 if (!readOnly) {
610 configAttribs.setValue(EGL_DEPTH_SIZE, 1);
611 configAttribs.setValue(EGL_STENCIL_SIZE, 1);
612 configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1);
613 }
614
615 EGLint configCount = 0;
616 do {
617 eglChooseConfig(QEglContext::defaultDisplay(0), configAttribs.properties(), targetConfig, 1, &configCount);
618 if (configCount > 0) {
619 // Got one
620 qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") << (readOnly ? "readonly" : "target" )
621 << "config (" << int(*targetConfig) << ") to create a pixmap surface:";
622
623// QEglProperties configProps(*targetConfig);
624// qDebug() << configProps.toString();
625 break;
626 }
627 qWarning("choosePixmapConfig() - No suitible config found, reducing requirements");
628 } while (configAttribs.reduceConfiguration());
629 }
630
631 if (*targetConfig == 0)
632 qWarning("choosePixmapConfig() - Couldn't find a suitable config");
633
634 return *targetConfig;
635}
636
637bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly)
638{
639 Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
640 QX11PixmapData* pixmapData = static_cast<QX11PixmapData*>(pmd);
641
642 bool hasAlpha = pixmapData->hasAlphaChannel();
643
644 EGLConfig pixmapConfig = qt_chooseEGLConfigForPixmap(hasAlpha, readOnly);
645
646 QEglProperties pixmapAttribs;
647
648 // If the pixmap can't be bound to a texture, it's pretty useless
649 pixmapAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
650 if (hasAlpha)
651 pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
652 else
653 pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
654
655 EGLSurface pixmapSurface;
656 pixmapSurface = eglCreatePixmapSurface(QEglContext::defaultDisplay(0),
657 pixmapConfig,
658 (EGLNativePixmapType) pixmapData->handle(),
659 pixmapAttribs.properties());
660// qDebug("qt_createEGLSurfaceForPixmap() created surface 0x%x for pixmap 0x%x",
661// pixmapSurface, pixmapData->handle());
662 if (pixmapSurface == EGL_NO_SURFACE) {
663 qWarning() << "Failed to create a pixmap surface using config" << (int)pixmapConfig
664 << ":" << QEglContext::errorString(eglGetError());
665 return false;
666 }
667
668 static bool doneOnce = false;
669 if (!doneOnce) {
670 // Make sure QGLTextureCache is instanciated so it can install cleanup hooks
671 // which cleanup the EGL surface.
672 QGLTextureCache::instance();
673 doneOnce = true;
674 }
675
676 Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
677 pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
678 QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData); // Make sure the cleanup hook gets called
679
680 return true;
681}
682
683
684QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key,
685 QGLContext::BindOptions options)
686{
687 Q_Q(QGLContext);
688
689 // The EGL texture_from_pixmap has no facility to invert the y coordinate
690 if (!(options & QGLContext::CanFlipNativePixmapBindOption))
691 return 0;
692
693 Q_ASSERT(pd->classId() == QPixmapData::X11Class);
694
695 static bool checkedForTFP = false;
696 static bool haveTFP = false;
697
698 if (!checkedForTFP) {
699 // Check for texture_from_pixmap egl extension
700 checkedForTFP = true;
701 if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") ||
702 eglContext->hasExtension("EGL_EXT_texture_from_pixmap"))
703 {
704 qDebug("Found texture_from_pixmap EGL extension!");
705 haveTFP = true;
706 }
707 }
708
709 if (!haveTFP)
710 return 0;
711
712 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
713
714 bool hasAlpha = pixmapData->hasAlphaChannel();
715
716 // Check to see if the surface is still valid
717 if (pixmapData->gl_surface &&
718 hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
719 {
720 // Surface is invalid!
721 destroyGlSurfaceForPixmap(pixmapData);
722 }
723
724 if (pixmapData->gl_surface == 0) {
725 bool success = qt_createEGLSurfaceForPixmap(pixmapData, true);
726 if (!success) {
727 haveTFP = false;
728 return 0;
729 }
730 }
731
732 Q_ASSERT(pixmapData->gl_surface);
733
734 GLuint textureId;
735 glGenTextures(1, &textureId);
736 glBindTexture(GL_TEXTURE_2D, textureId);
737
738 // bind the egl pixmap surface to a texture
739 EGLBoolean success;
740 success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
741 if (success == EGL_FALSE) {
742 qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError());
743 eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface);
744 pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
745 haveTFP = false;
746 return 0;
747 }
748
749 QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
750 pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
751
752 // We assume the cost of bound pixmaps is zero
753 QGLTextureCache::instance()->insert(q, key, texture, 0);
754
755 glBindTexture(GL_TEXTURE_2D, textureId);
756 return texture;
757}
758
759void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
760{
761 Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
762 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
763 if (pixmapData->gl_surface) {
764 EGLBoolean success;
765 success = eglDestroySurface(QEglContext::defaultDisplay(0), (EGLSurface)pixmapData->gl_surface);
766 if (success == EGL_FALSE) {
767 qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
768 << QEglContext::errorString(eglGetError());
769 }
770 pixmapData->gl_surface = 0;
771 }
772}
773
774void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
775{
776 Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
777 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
778 if (pixmapData->gl_surface) {
779 EGLBoolean success;
780 success = eglReleaseTexImage(QEglContext::defaultDisplay(0),
781 (EGLSurface)pixmapData->gl_surface,
782 EGL_BACK_BUFFER);
783 if (success == EGL_FALSE) {
784 qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
785 << QEglContext::errorString(eglGetError());
786 }
787 }
788}
789
790QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.