void QX11WindowSurface::setGeometry(const QRect &rect) { QWindowSurface::setGeometry(rect); const QSize size = rect.size(); if (d_ptr->device.size() == size || size.width() <= 0 || size.height() <= 0) return; #ifndef QT_NO_XRENDER if (d_ptr->translucentBackground) { QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType); data->xinfo = d_ptr->widget->x11Info(); data->resize(size.width(), size.height()); d_ptr->device = QPixmap(data); } else #endif { QPixmap::x11SetDefaultScreen(d_ptr->widget->x11Info().screen()); QX11PixmapData *oldData = static_cast<QX11PixmapData *>(d_ptr->device.pixmapData()); if (oldData && !(oldData->flags & QX11PixmapData::Uninitialized) && hasStaticContents()) { // Copy the content of the old pixmap into the new one. QX11PixmapData *newData = new QX11PixmapData(QPixmapData::PixmapType); newData->resize(size.width(), size.height()); Q_ASSERT(oldData->d == newData->d); QRegion staticRegion(staticContents()); // Make sure we're inside the boundaries of the old pixmap. staticRegion &= QRect(0, 0, oldData->w, oldData->h); const QRect boundingRect(staticRegion.boundingRect()); const int dx = boundingRect.x(); const int dy = boundingRect.y(); int num; XRectangle *rects = (XRectangle *)qt_getClipRects(staticRegion, num); GC tmpGc = XCreateGC(X11->display, oldData->hd, 0, 0); XSetClipRectangles(X11->display, tmpGc, 0, 0, rects, num, YXBanded); XCopyArea(X11->display, oldData->hd, newData->hd, tmpGc, dx, dy, qMin(boundingRect.width(), size.width()), qMin(boundingRect.height(), size.height()), dx, dy); XFreeGC(X11->display, tmpGc); newData->flags &= ~QX11PixmapData::Uninitialized; d_ptr->device = QPixmap(newData); } else { d_ptr->device = QPixmap(size); } } if (gc) { XFreeGC(X11->display, gc); gc = 0; } if (!d_ptr->device.isNull()) { gc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0); XSetGraphicsExposures(X11->display, gc, False); } }
QPixmap QX11GLWindowSurface::grabWidget(const QWidget *widget, const QRect& rect) const { if (!widget || m_backBuffer.isNull()) return QPixmap(); QRect srcRect; // make sure the rect is inside the widget & clip to widget's rect if (!rect.isEmpty()) srcRect = rect & widget->rect(); else srcRect = widget->rect(); if (srcRect.isEmpty()) return QPixmap(); // If it's a child widget we have to translate the coordinates if (widget != window()) srcRect.translate(widget->mapTo(window(), QPoint(0, 0))); QPixmap::x11SetDefaultScreen(widget->x11Info().screen()); QX11PixmapData *pmd = new QX11PixmapData(QPixmapData::PixmapType); pmd->resize(srcRect.width(), srcRect.height()); QPixmap px(pmd); GC tmpGc = XCreateGC(X11->display, m_backBuffer.handle(), 0, 0); // Make sure all GL rendering is complete before copying the window QGLContext* ctx = static_cast<QX11GLPixmapData*>(m_backBuffer.pixmapData())->context(); if (QGLContext::currentContext() != ctx && ctx && ctx->isValid()) ctx->makeCurrent(); eglWaitClient(); // Copy srcRect from the backing store to the new pixmap XSetGraphicsExposures(X11->display, tmpGc, False); XCopyArea(X11->display, m_backBuffer.handle(), px.handle(), tmpGc, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), 0, 0); XFreeGC(X11->display, tmpGc); // Wait until the copy has finised before allowing more rendering into the back buffer eglWaitNative(EGL_CORE_NATIVE_ENGINE); return px; }
QX11GLSharedContexts() : rgbContext(0) , argbContext(0) , sharedQGLContext(0) , sharePixmap(0) { EGLint rgbConfigId; EGLint argbConfigId; do { EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable); EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable | QEgl::Translucent); eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId); eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId); rgbContext = new QEglContext; rgbContext->setConfig(rgbConfig); rgbContext->createContext(); if (!rgbContext->isValid()) break; // If the RGB & ARGB configs are the same, use the same egl context for both: if (rgbConfig == argbConfig) argbContext = rgbContext; // Otherwise, create a separate context to be used for ARGB pixmaps: if (!argbContext) { argbContext = new QEglContext; argbContext->setConfig(argbConfig); bool success = argbContext->createContext(rgbContext); if (!success) { qWarning("QX11GLPixmapData - RGB & ARGB contexts aren't shared"); success = argbContext->createContext(); if (!success) argbContext = rgbContext; // Might work, worth a shot at least. } } if (!argbContext->isValid()) break; // Create the pixmap which will be used to create the egl surface for the share QGLContext QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); rgbPixmapData->resize(8, 8); rgbPixmapData->fill(Qt::red); sharePixmap = new QPixmap(rgbPixmapData); EGLSurface sharePixmapSurface = QEgl::createSurface(sharePixmap, rgbConfig); rgbPixmapData->gl_surface = (void*)sharePixmapSurface; // Create the actual QGLContext which will be used for sharing sharedQGLContext = new QGLContext(QX11GLPixmapData::glFormat()); sharedQGLContext->d_func()->eglContext = rgbContext; sharedQGLContext->d_func()->eglSurface = sharePixmapSurface; sharedQGLContext->d_func()->valid = true; qt_glformat_from_eglconfig(sharedQGLContext->d_func()->glFormat, rgbConfig); valid = rgbContext->makeCurrent(sharePixmapSurface); // If the ARGB & RGB configs are different, check ARGB works too: if (argbConfig != rgbConfig) { QX11PixmapData *argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); argbPixmapData->resize(8, 8); argbPixmapData->fill(Qt::transparent); // Force ARGB QPixmap argbPixmap(argbPixmapData); // destroys pixmap data when goes out of scope EGLSurface argbPixmapSurface = QEgl::createSurface(&argbPixmap, argbConfig); valid = argbContext->makeCurrent(argbPixmapSurface); argbContext->doneCurrent(); eglDestroySurface(QEgl::display(), argbPixmapSurface); argbPixmapData->gl_surface = 0; } if (!valid) { qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString(); break; } // The pixmap surface destruction hooks are installed by QGLTextureCache, so we // must make sure this is instanciated: QGLTextureCache::instance(); } while(0); if (!valid) cleanup(); else qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); }
bool QX11GLPixmapData::hasX11GLPixmaps() { static bool checkedForX11Pixmaps = false; static bool haveX11Pixmaps = false; if (checkedForX11Pixmaps) return haveX11Pixmaps; checkedForX11Pixmaps = true; QX11PixmapData *argbPixmapData = 0; QX11PixmapData *rgbPixmapData = 0; do { if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty()) break; // Check we actually have EGL configs which support pixmaps EGLConfig argbConfig = qt_chooseEGLConfigForPixmap(true, false); EGLConfig rgbConfig = qt_chooseEGLConfigForPixmap(false, false); if (argbConfig == 0 || rgbConfig == 0) break; // Create the shared contexts: eglBindAPI(EGL_OPENGL_ES_API); EGLint contextAttribs[] = { #if defined(QT_OPENGL_ES_2) EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; qPixmapARGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0), argbConfig, 0, contextAttribs); if (argbConfig == rgbConfig) { // If the configs are the same, we can re-use the same context. qPixmapRGBSharedEglContext = qPixmapARGBSharedEglContext; } else { qPixmapRGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0), rgbConfig, 0, contextAttribs); } argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); argbPixmapData->resize(100, 100); argbPixmapData->fill(Qt::transparent); // Force ARGB if (!qt_createEGLSurfaceForPixmap(argbPixmapData, false)) break; haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0), (EGLSurface)argbPixmapData->gl_surface, (EGLSurface)argbPixmapData->gl_surface, qPixmapARGBSharedEglContext); if (!haveX11Pixmaps) { EGLint err = eglGetError(); qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); break; } // If the ARGB & RGB configs are the same, we don't need to check RGB too if (haveX11Pixmaps && (argbConfig != rgbConfig)) { rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); rgbPixmapData->resize(100, 100); rgbPixmapData->fill(Qt::red); // Try to actually create an EGL pixmap surface if (!qt_createEGLSurfaceForPixmap(rgbPixmapData, false)) break; haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0), (EGLSurface)rgbPixmapData->gl_surface, (EGLSurface)rgbPixmapData->gl_surface, qPixmapRGBSharedEglContext); if (!haveX11Pixmaps) { EGLint err = eglGetError(); qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); break; } } } while (0); if (qPixmapARGBSharedEglContext || qPixmapRGBSharedEglContext) { eglMakeCurrent(QEglContext::defaultDisplay(0), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } if (argbPixmapData) { if (argbPixmapData->gl_surface) QGLContextPrivate::destroyGlSurfaceForPixmap(argbPixmapData); delete argbPixmapData; argbPixmapData = 0; } if (rgbPixmapData) { if (rgbPixmapData->gl_surface) QGLContextPrivate::destroyGlSurfaceForPixmap(rgbPixmapData); delete rgbPixmapData; rgbPixmapData = 0; } if (!haveX11Pixmaps) { // Clean up the context(s) if we can't use X11GL pixmaps if (qPixmapARGBSharedEglContext != EGL_NO_CONTEXT) eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapARGBSharedEglContext); if (qPixmapRGBSharedEglContext != qPixmapARGBSharedEglContext && qPixmapRGBSharedEglContext != EGL_NO_CONTEXT) { eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapRGBSharedEglContext); } qPixmapRGBSharedEglContext = EGL_NO_CONTEXT; qPixmapARGBSharedEglContext = EGL_NO_CONTEXT; } if (haveX11Pixmaps) qDebug("QX11GLPixmapData is supported"); else qDebug("QX11GLPixmapData is *NOT* being used"); return haveX11Pixmaps; }