Changeset 846 for trunk/src/opengl/qgl_x11egl.cpp
- Timestamp:
- May 5, 2011, 5:36:53 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/vendor/nokia/qt/4.7.2 (added) merged: 845 /branches/vendor/nokia/qt/current merged: 844 /branches/vendor/nokia/qt/4.6.3 removed
- Property svn:mergeinfo changed
-
trunk/src/opengl/qgl_x11egl.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 43 43 #include <private/qt_x11_p.h> 44 44 #include <private/qpixmap_x11_p.h> 45 #include <private/qimagepixmapcleanuphooks_p.h>46 45 #include <private/qgl_p.h> 47 46 #include <private/qpaintengine_opengl_p.h> … … 49 48 #include "qcolormap.h" 50 49 #include <QDebug> 50 #include <QPixmap> 51 51 52 52 53 53 QT_BEGIN_NAMESPACE 54 54 55 56 bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config,57 const QX11Info &x11Info, bool useArgbVisual);58 55 59 56 /* … … 80 77 int screen = 0; 81 78 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 } 79 d->display = QEgl::display(); 88 80 89 81 EGLConfig config; … … 106 98 XVisualInfo *vi; 107 99 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 } 100 101 visualInfo.visualid = QEgl::getCompatibleVisualId(config); 119 102 vi = XGetVisualInfo(X11->display, VisualIDMask, &visualInfo, &numVisuals); 120 103 if (!vi || numVisuals < 1) { … … 171 154 } 172 155 173 void 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 156 // Chooses the EGL config and creates the EGL context 180 157 bool QGLContext::chooseContext(const QGLContext* shareContext) … … 187 164 int devType = device()->devType(); 188 165 189 // Get the display and initialize it. 166 QX11PixmapData *x11PixmapData = 0; 167 if (devType == QInternal::Pixmap) { 168 QPixmapData *pmd = static_cast<QPixmap*>(device())->data_ptr().data(); 169 if (pmd->classId() == QPixmapData::X11Class) 170 x11PixmapData = static_cast<QX11PixmapData*>(pmd); 171 else { 172 // TODO: Replace the pixmap's data with a new QX11PixmapData 173 qWarning("WARNING: Creating a QGLContext on a QPixmap is only supported for X11 pixmap backend"); 174 return false; 175 } 176 } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) { 177 qWarning("WARNING: Creating a QGLContext not supported on device type %d", devType); 178 return false; 179 } 180 181 // Only create the eglContext if we don't already have one: 190 182 if (d->eglContext == 0) { 191 183 d->eglContext = new QEglContext(); 184 d->ownsEglContext = true; 192 185 d->eglContext->setApi(QEgl::OpenGL); 186 187 // If the device is a widget with WA_TranslucentBackground set, make sure the glFormat 188 // has the alpha channel option set: 189 if (devType == QInternal::Widget) { 190 QWidget* widget = static_cast<QWidget*>(device()); 191 if (widget->testAttribute(Qt::WA_TranslucentBackground)) 192 d->glFormat.setAlpha(true); 193 } 193 194 194 195 // Construct the configuration we need for this surface. 195 196 QEglProperties configProps; 196 qt_egl_set_format(configProps, devType, d->glFormat); 197 qt_egl_add_platform_config(configProps, device()); 197 configProps.setDeviceType(devType); 198 198 configProps.setRenderableType(QEgl::OpenGL); 199 200 #if We_have_an_EGL_library_which_bothers_to_check_EGL_BUFFER_SIZE 201 if (device()->depth() == 16 && configProps.value(EGL_ALPHA_SIZE) <= 0) { 202 qDebug("Setting EGL_BUFFER_SIZE to 16"); 203 configProps.setValue(EGL_BUFFER_SIZE, 16); 204 configProps.setValue(EGL_ALPHA_SIZE, 0); 205 } 199 qt_eglproperties_set_glformat(configProps, d->glFormat); 200 201 // Set buffer preserved for regular QWidgets, QGLWidgets are ok with either preserved or destroyed: 202 if ((devType == QInternal::Widget) && qobject_cast<QGLWidget*>(static_cast<QWidget*>(device())) == 0) 203 configProps.setValue(EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); 206 204 207 205 if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) { … … 210 208 return false; 211 209 } 212 #else 213 QEgl::PixelFormatMatch matchType = QEgl::BestPixelFormat; 214 if ((device()->depth() == 16) && configProps.value(EGL_ALPHA_SIZE) == 0) { 215 configProps.setValue(EGL_RED_SIZE, 5); 216 configProps.setValue(EGL_GREEN_SIZE, 6); 217 configProps.setValue(EGL_BLUE_SIZE, 5); 218 configProps.setValue(EGL_ALPHA_SIZE, 0); 219 matchType = QEgl::ExactPixelFormat; 220 } 221 222 // Search for a matching configuration, reducing the complexity 223 // each time until we get something that matches. 224 if (!d->eglContext->chooseConfig(configProps, matchType)) { 210 211 // Create a new context for the configuration. 212 QEglContext* eglSharedContext = shareContext ? shareContext->d_func()->eglContext : 0; 213 if (!d->eglContext->createContext(eglSharedContext)) { 225 214 delete d->eglContext; 226 215 d->eglContext = 0; 227 216 return false; 228 217 } 229 #endif230 231 // qDebug("QGLContext::chooseContext() - using EGL config %d:", d->eglContext->config());232 // qDebug() << QEglProperties(d->eglContext->config()).toString();233 234 // Create a new context for the configuration.235 if (!d->eglContext->createContext236 (shareContext ? shareContext->d_func()->eglContext : 0)) {237 delete d->eglContext;238 d->eglContext = 0;239 return false;240 }241 218 d->sharing = d->eglContext->isSharing(); 242 219 if (d->sharing && shareContext) 243 220 const_cast<QGLContext *>(shareContext)->d_func()->sharing = true; 244 245 #if defined(EGL_VERSION_1_1) 246 if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget) 247 eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval()); 248 #endif 249 } 250 251 // Inform the higher layers about the actual format properties. 252 qt_egl_update_format(*(d->eglContext), d->glFormat); 221 } 222 223 // Inform the higher layers about the actual format properties 224 qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config()); 225 226 // Do don't create the EGLSurface for everything. 227 // QWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface 228 // QGLWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface 229 // QPixmap - yes, create the EGLSurface but store it in QX11PixmapData::gl_surface 230 // QGLPixelBuffer - no, it creates the surface itself and stores it in QGLPixelBufferPrivate::pbuf 231 232 if (devType == QInternal::Widget) { 233 if (d->eglSurface != EGL_NO_SURFACE) 234 eglDestroySurface(d->eglContext->display(), d->eglSurface); 235 d->eglSurface = QEgl::createSurface(device(), d->eglContext->config()); 236 XFlush(X11->display); 237 setWindowCreated(true); 238 } 239 240 if (x11PixmapData) { 241 // TODO: Actually check to see if the existing surface can be re-used 242 if (x11PixmapData->gl_surface) 243 eglDestroySurface(d->eglContext->display(), (EGLSurface)x11PixmapData->gl_surface); 244 245 x11PixmapData->gl_surface = (void*)QEgl::createSurface(device(), d->eglContext->config()); 246 } 253 247 254 248 return true; … … 282 276 } 283 277 284 //#define QT_DEBUG_X11_VISUAL_SELECTION 1285 286 bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual)287 {288 bool foundVisualIsArgb = useArgbVisual;289 290 #ifdef QT_DEBUG_X11_VISUAL_SELECTION291 qDebug("qt_egl_setup_x11_visual() - useArgbVisual=%d", useArgbVisual);292 #endif293 294 memset(&vi, 0, sizeof(XVisualInfo));295 296 EGLint eglConfigColorSize;297 eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &eglConfigColorSize);298 299 // Check to see if EGL is suggesting an appropriate visual id:300 EGLint nativeVisualId;301 eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId);302 vi.visualid = nativeVisualId;303 304 if (vi.visualid) {305 // EGL has suggested a visual id, so get the rest of the visual info for that id:306 XVisualInfo *chosenVisualInfo;307 int matchingCount = 0;308 chosenVisualInfo = XGetVisualInfo(x11Info.display(), VisualIDMask, &vi, &matchingCount);309 if (chosenVisualInfo) {310 #if !defined(QT_NO_XRENDER)311 if (useArgbVisual) {312 // Check to make sure the visual provided by EGL is ARGB313 XRenderPictFormat *format;314 format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual);315 if (format->type == PictTypeDirect && format->direct.alphaMask) {316 #ifdef QT_DEBUG_X11_VISUAL_SELECTION317 qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid);318 #endif319 foundVisualIsArgb = true;320 vi = *chosenVisualInfo;321 }322 else {323 qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this is not ARGB",324 nativeVisualId, (int)config);325 vi.visualid = 0;326 }327 } else328 #endif329 {330 if (eglConfigColorSize == chosenVisualInfo->depth) {331 #ifdef QT_DEBUG_X11_VISUAL_SELECTION332 qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);333 #endif334 vi = *chosenVisualInfo;335 } else336 qWarning("Warning: EGL suggested using X visual ID %d (%d bpp) for config %d (%d bpp), but the depths do not match!",337 nativeVisualId, chosenVisualInfo->depth, (int)config, eglConfigColorSize);338 }339 XFree(chosenVisualInfo);340 }341 else {342 qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!",343 nativeVisualId, (int)config);344 vi.visualid = 0;345 }346 }347 348 // If EGL does not know the visual ID, so try to select an appropriate one ourselves, first349 // using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo350 351 #if !defined(QT_NO_XRENDER)352 if (vi.visualid == 0 && useArgbVisual) {353 // Try to use XRender to find an ARGB visual we can use354 vi.screen = x11Info.screen();355 vi.depth = 32; //### We might at some point (soon) get ARGB4444356 vi.c_class = TrueColor;357 XVisualInfo *matchingVisuals;358 int matchingCount = 0;359 matchingVisuals = XGetVisualInfo(x11Info.display(),360 VisualScreenMask|VisualDepthMask|VisualClassMask,361 &vi, &matchingCount);362 363 for (int i = 0; i < matchingCount; ++i) {364 XRenderPictFormat *format;365 format = XRenderFindVisualFormat(x11Info.display(), matchingVisuals[i].visual);366 if (format->type == PictTypeDirect && format->direct.alphaMask) {367 vi = matchingVisuals[i];368 foundVisualIsArgb = true;369 #ifdef QT_DEBUG_X11_VISUAL_SELECTION370 qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid);371 #endif372 break;373 }374 }375 XFree(matchingVisuals);376 }377 #endif378 379 if (vi.visualid == 0) {380 EGLint depth;381 eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth);382 int err;383 err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);384 if (err == 0) {385 qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!",386 (int)config, depth);387 depth = x11Info.depth();388 err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);389 if (err == 0) {390 qWarning("Error: Couldn't get any matching X visual!");391 return false;392 } else393 qWarning(" - Falling back to X11 suggested depth (%d)", depth);394 }395 #ifdef QT_DEBUG_X11_VISUAL_SELECTION396 else397 qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth);398 #endif399 400 // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-(401 if (useArgbVisual)402 foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444403 }404 405 #ifdef QT_DEBUG_X11_VISUAL_SELECTION406 qDebug("Visual Info:");407 qDebug(" bits_per_rgb=%d", vi.bits_per_rgb);408 qDebug(" red_mask=0x%x", vi.red_mask);409 qDebug(" green_mask=0x%x", vi.green_mask);410 qDebug(" blue_mask=0x%x", vi.blue_mask);411 qDebug(" colormap_size=%d", vi.colormap_size);412 qDebug(" c_class=%d", vi.c_class);413 qDebug(" depth=%d", vi.depth);414 qDebug(" screen=%d", vi.screen);415 qDebug(" visualid=%d", vi.visualid);416 #endif417 return foundVisualIsArgb;418 }419 420 278 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext) 421 279 { … … 434 292 QGLContext* oldcx = d->glcx; 435 293 d->glcx = context; 436 437 if (parentWidget()) {438 // force creation of delay-created widgets439 parentWidget()->winId();440 if (parentWidget()->x11Info().screen() != x11Info().screen())441 d_func()->xinfo = parentWidget()->d_func()->xinfo;442 }443 444 // If the application has set WA_TranslucentBackground and not explicitly set445 // the alpha buffer size to zero, modify the format so it have an alpha channel446 QGLFormat& fmt = d->glcx->d_func()->glFormat;447 const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground) || fmt.alpha();448 if (tryArgbVisual && fmt.alphaBufferSize() == -1)449 fmt.setAlphaBufferSize(1);450 294 451 295 bool createFailed = false; … … 462 306 } 463 307 464 if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) { 465 if (deleteOldContext) 466 delete oldcx; 467 return; 468 } 469 470 bool visible = isVisible(); 471 if (visible) 472 hide(); 473 474 XVisualInfo vi; 475 QEglContext *eglContext = d->glcx->d_func()->eglContext; 476 bool usingArgbVisual = qt_egl_setup_x11_visual(vi, eglContext->display(), eglContext->config(), 477 x11Info(), tryArgbVisual); 478 479 XSetWindowAttributes a; 480 481 Window p = RootWindow(x11Info().display(), x11Info().screen()); 482 if (parentWidget()) 483 p = parentWidget()->winId(); 484 485 QColormap colmap = QColormap::instance(vi.screen); 486 a.background_pixel = colmap.pixel(palette().color(backgroundRole())); 487 a.border_pixel = colmap.pixel(Qt::black); 488 489 unsigned int valueMask = CWBackPixel|CWBorderPixel; 490 if (usingArgbVisual) { 491 a.colormap = XCreateColormap(x11Info().display(), p, vi.visual, AllocNone); 492 valueMask |= CWColormap; 493 } 494 495 Window w = XCreateWindow(x11Info().display(), p, x(), y(), width(), height(), 496 0, vi.depth, InputOutput, vi.visual, valueMask, &a); 497 498 if (deleteOldContext) 499 delete oldcx; 500 oldcx = 0; 501 502 create(w); // Create with the ID of the window we've just created 503 504 505 // Create the EGL surface to draw into. 506 QGLContextPrivate *ctxpriv = d->glcx->d_func(); 507 ctxpriv->eglSurface = ctxpriv->eglContext->createSurface(this); 508 if (ctxpriv->eglSurface == EGL_NO_SURFACE) { 509 delete ctxpriv->eglContext; 510 ctxpriv->eglContext = 0; 511 return; 512 } 513 514 d->eglSurfaceWindowId = w; // Remember the window id we created the surface for 515 516 if (visible) 517 show(); 518 519 XFlush(X11->display); 520 d->glcx->setWindowCreated(true); 308 309 d->eglSurfaceWindowId = winId(); // Remember the window id we created the surface for 521 310 } 522 311 … … 527 316 initContext(context, shareWidget); 528 317 529 if (q->isValid() && glcx->format().hasOverlay()) {318 if (q->isValid() && glcx->format().hasOverlay()) { 530 319 //no overlay 531 320 qWarning("QtOpenGL ES doesn't currently support overlays"); … … 546 335 } 547 336 548 // Re-creates the EGL surface if the window ID has changed or if force is true549 void QGLWidgetPrivate::recreateEglSurface( bool force)337 // Re-creates the EGL surface if the window ID has changed or if there isn't a surface 338 void QGLWidgetPrivate::recreateEglSurface() 550 339 { 551 340 Q_Q(QGLWidget); … … 553 342 Window currentId = q->winId(); 554 343 555 if ( force || (currentId != eglSurfaceWindowId) ) { 556 // The window id has changed so we need to re-create the EGL surface 557 QEglContext *ctx = glcx->d_func()->eglContext; 558 EGLSurface surface = glcx->d_func()->eglSurface; 559 if (surface != EGL_NO_SURFACE) 560 ctx->destroySurface(surface); // Will force doneCurrent() if nec. 561 surface = ctx->createSurface(q); 562 if (surface == EGL_NO_SURFACE) 563 qWarning("Error creating EGL window surface: 0x%x", eglGetError()); 564 glcx->d_func()->eglSurface = surface; 565 344 // If the window ID has changed since the surface was created, we need to delete the 345 // old surface before re-creating a new one. Note: This should not be the case as the 346 // surface should be deleted before the old window id. 347 if (glcx->d_func()->eglSurface != EGL_NO_SURFACE && (currentId != eglSurfaceWindowId)) { 348 qWarning("EGL surface for deleted window %x was not destroyed", uint(eglSurfaceWindowId)); 349 glcx->d_func()->destroyEglSurfaceForDevice(); 350 } 351 352 if (glcx->d_func()->eglSurface == EGL_NO_SURFACE) { 353 glcx->d_func()->eglSurface = glcx->d_func()->eglContext->createSurface(q); 566 354 eglSurfaceWindowId = currentId; 567 355 } 568 356 } 569 357 570 // Selects which configs should be used 571 EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly) 572 { 573 // Cache the configs we select as they wont change: 574 static EGLConfig roPixmapRGBConfig = 0; 575 static EGLConfig roPixmapRGBAConfig = 0; 576 static EGLConfig rwPixmapRGBConfig = 0; 577 static EGLConfig rwPixmapRGBAConfig = 0; 578 579 EGLConfig* targetConfig; 580 581 if (hasAlpha) { 582 if (readOnly) 583 targetConfig = &roPixmapRGBAConfig; 584 else 585 targetConfig = &rwPixmapRGBAConfig; 586 } 587 else { 588 if (readOnly) 589 targetConfig = &roPixmapRGBConfig; 590 else 591 targetConfig = &rwPixmapRGBConfig; 592 } 593 594 if (*targetConfig == 0) { 595 QEglProperties configAttribs; 596 configAttribs.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT); 597 configAttribs.setRenderableType(QEgl::OpenGL); 598 if (hasAlpha) 599 configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); 600 else 601 configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); 602 603 // If this is going to be a render target, it needs to have a depth, stencil & sample buffer 604 if (!readOnly) { 605 configAttribs.setValue(EGL_DEPTH_SIZE, 1); 606 configAttribs.setValue(EGL_STENCIL_SIZE, 1); 607 configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1); 608 } 609 610 EGLint configCount = 0; 611 do { 612 eglChooseConfig(QEglContext::display(), configAttribs.properties(), targetConfig, 1, &configCount); 613 if (configCount > 0) { 614 // Got one 615 qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") << (readOnly ? "readonly" : "target" ) 616 << "config (" << int(*targetConfig) << ") to create a pixmap surface:"; 617 618 // QEglProperties configProps(*targetConfig); 619 // qDebug() << configProps.toString(); 620 break; 621 } 622 qWarning("choosePixmapConfig() - No suitible config found, reducing requirements"); 623 } while (configAttribs.reduceConfiguration()); 624 } 625 626 if (*targetConfig == 0) 627 qWarning("choosePixmapConfig() - Couldn't find a suitable config"); 628 629 return *targetConfig; 630 } 631 632 bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly) 633 { 634 Q_ASSERT(pmd->classId() == QPixmapData::X11Class); 635 QX11PixmapData* pixmapData = static_cast<QX11PixmapData*>(pmd); 636 637 bool hasAlpha = pixmapData->hasAlphaChannel(); 638 639 EGLConfig pixmapConfig = qt_chooseEGLConfigForPixmap(hasAlpha, readOnly); 640 641 QEglProperties pixmapAttribs; 642 643 // If the pixmap can't be bound to a texture, it's pretty useless 644 pixmapAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D); 645 if (hasAlpha) 646 pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA); 647 else 648 pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB); 649 650 EGLSurface pixmapSurface; 651 pixmapSurface = eglCreatePixmapSurface(QEglContext::display(), 652 pixmapConfig, 653 (EGLNativePixmapType) pixmapData->handle(), 654 pixmapAttribs.properties()); 655 // qDebug("qt_createEGLSurfaceForPixmap() created surface 0x%x for pixmap 0x%x", 656 // pixmapSurface, pixmapData->handle()); 657 if (pixmapSurface == EGL_NO_SURFACE) { 658 qWarning() << "Failed to create a pixmap surface using config" << (int)pixmapConfig 659 << ":" << QEglContext::errorString(eglGetError()); 660 return false; 661 } 662 663 static bool doneOnce = false; 664 if (!doneOnce) { 665 // Make sure QGLTextureCache is instanciated so it can install cleanup hooks 666 // which cleanup the EGL surface. 667 QGLTextureCache::instance(); 668 doneOnce = true; 669 } 670 671 Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure! 672 pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface; 673 QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData); // Make sure the cleanup hook gets called 674 675 return true; 676 } 677 678 679 QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key, 358 359 QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key, 680 360 QGLContext::BindOptions options) 681 361 { … … 686 366 return 0; 687 367 688 Q_ASSERT(pd->classId() == QPixmapData::X11Class);689 368 690 369 static bool checkedForTFP = false; 691 370 static bool haveTFP = false; 371 static bool checkedForEglImageTFP = false; 372 static bool haveEglImageTFP = false; 373 374 375 if (!checkedForEglImageTFP) { 376 checkedForEglImageTFP = true; 377 378 // We need to be able to create an EGLImage from a native pixmap, which was split 379 // into a separate EGL extension, EGL_KHR_image_pixmap. It is possible to have 380 // eglCreateImageKHR & eglDestroyImageKHR without support for pixmaps, so we must 381 // check we have the EGLImage from pixmap functionality. 382 if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) { 383 384 // Being able to create an EGLImage from a native pixmap is also pretty useless 385 // without the ability to bind that EGLImage as a texture, which is provided by 386 // the GL_OES_EGL_image extension, which we try to resolve here: 387 haveEglImageTFP = qt_resolve_eglimage_gl_extensions(q); 388 389 if (haveEglImageTFP) 390 qDebug("Found EGL_KHR_image_pixmap & GL_OES_EGL_image extensions (preferred method)!"); 391 } 392 } 692 393 693 394 if (!checkedForTFP) { 694 395 // Check for texture_from_pixmap egl extension 695 396 checkedForTFP = true; 696 if ( eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") ||697 eglContext->hasExtension("EGL_EXT_texture_from_pixmap"))397 if (QEgl::hasExtension("EGL_NOKIA_texture_from_pixmap") || 398 QEgl::hasExtension("EGL_EXT_texture_from_pixmap")) 698 399 { 699 400 qDebug("Found texture_from_pixmap EGL extension!"); … … 702 403 } 703 404 704 if (!haveTFP )405 if (!haveTFP && !haveEglImageTFP) 705 406 return 0; 706 407 707 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd); 708 408 409 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data()); 410 Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class); 709 411 bool hasAlpha = pixmapData->hasAlphaChannel(); 710 711 // Check to see if the surface is still valid 712 if (pixmapData->gl_surface && 713 hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) 714 { 715 // Surface is invalid! 716 destroyGlSurfaceForPixmap(pixmapData); 717 } 718 719 if (pixmapData->gl_surface == 0) { 720 bool success = qt_createEGLSurfaceForPixmap(pixmapData, true); 721 if (!success) { 722 haveTFP = false; 723 return 0; 724 } 725 } 726 727 Q_ASSERT(pixmapData->gl_surface); 728 412 bool pixmapHasValidSurface = false; 413 bool textureIsBound = false; 729 414 GLuint textureId; 730 415 glGenTextures(1, &textureId); 731 416 glBindTexture(GL_TEXTURE_2D, textureId); 732 417 733 // bind the egl pixmap surface to a texture 734 EGLBoolean success; 735 success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); 736 if (success == EGL_FALSE) { 737 qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError()); 738 eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface); 739 pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE; 740 haveTFP = false; 741 return 0; 742 } 743 744 QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options); 745 pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture; 746 747 // We assume the cost of bound pixmaps is zero 748 QGLTextureCache::instance()->insert(q, key, texture, 0); 749 750 glBindTexture(GL_TEXTURE_2D, textureId); 418 if (haveTFP && pixmapData->gl_surface && 419 hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) 420 { 421 pixmapHasValidSurface = true; 422 } 423 424 // If we already have a valid EGL surface for the pixmap, we should use it 425 if (pixmapHasValidSurface) { 426 EGLBoolean success; 427 success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); 428 if (success == EGL_FALSE) { 429 qWarning() << "eglBindTexImage() failed:" << QEgl::errorString(); 430 eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); 431 pixmapData->gl_surface = (void*)EGL_NO_SURFACE; 432 } else 433 textureIsBound = true; 434 } 435 436 // If the pixmap doesn't already have a valid surface, try binding it via EGLImage 437 // first, as going through EGLImage should be faster and better supported: 438 if (!textureIsBound && haveEglImageTFP) { 439 EGLImageKHR eglImage; 440 441 EGLint attribs[] = { 442 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, 443 EGL_NONE 444 }; 445 eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, 446 (EGLClientBuffer)QEgl::nativePixmap(pixmap), attribs); 447 448 QGLContext* ctx = q; 449 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage); 450 451 GLint err = glGetError(); 452 if (err == GL_NO_ERROR) 453 textureIsBound = true; 454 455 // Once the egl image is bound, the texture becomes a new sibling image and we can safely 456 // destroy the EGLImage we created for the pixmap: 457 if (eglImage != EGL_NO_IMAGE_KHR) 458 QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); 459 } 460 461 if (!textureIsBound && haveTFP) { 462 // Check to see if the surface is still valid 463 if (pixmapData->gl_surface && 464 hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) 465 { 466 // Surface is invalid! 467 destroyGlSurfaceForPixmap(pixmapData); 468 } 469 470 if (pixmapData->gl_surface == 0) { 471 EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap, 472 QEgl::OpenGL, 473 hasAlpha ? QEgl::Translucent : QEgl::NoOptions); 474 475 pixmapData->gl_surface = (void*)QEgl::createSurface(pixmap, config); 476 if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE) 477 return false; 478 } 479 480 EGLBoolean success; 481 success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); 482 if (success == EGL_FALSE) { 483 qWarning() << "eglBindTexImage() failed:" << QEgl::errorString(); 484 eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); 485 pixmapData->gl_surface = (void*)EGL_NO_SURFACE; 486 haveTFP = false; // If TFP isn't working, disable it's use 487 } else 488 textureIsBound = true; 489 } 490 491 QGLTexture *texture = 0; 492 493 if (textureIsBound) { 494 texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options); 495 pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture; 496 497 // We assume the cost of bound pixmaps is zero 498 QGLTextureCache::instance()->insert(q, key, texture, 0); 499 500 glBindTexture(GL_TEXTURE_2D, textureId); 501 } else 502 glDeleteTextures(1, &textureId); 503 751 504 return texture; 752 505 } 506 753 507 754 508 void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd) … … 758 512 if (pixmapData->gl_surface) { 759 513 EGLBoolean success; 760 success = eglDestroySurface(QEgl Context::display(), (EGLSurface)pixmapData->gl_surface);514 success = eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); 761 515 if (success == EGL_FALSE) { 762 516 qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: " 763 << QEgl Context::errorString(eglGetError());517 << QEgl::errorString(); 764 518 } 765 519 pixmapData->gl_surface = 0; … … 773 527 if (pixmapData->gl_surface) { 774 528 EGLBoolean success; 775 success = eglReleaseTexImage(QEgl Context::display(),529 success = eglReleaseTexImage(QEgl::display(), 776 530 (EGLSurface)pixmapData->gl_surface, 777 531 EGL_BACK_BUFFER); 778 532 if (success == EGL_FALSE) { 779 533 qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: " 780 << QEgl Context::errorString(eglGetError());534 << QEgl::errorString(); 781 535 } 782 536 }
Note:
See TracChangeset
for help on using the changeset viewer.