diff options
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 21 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 1 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 2 | ||||
-rw-r--r-- | src/opengl/qgl.h | 1 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 2 | ||||
-rw-r--r-- | src/opengl/qgl_x11egl.cpp | 24 | ||||
-rw-r--r-- | src/opengl/qglpaintdevice.cpp | 16 | ||||
-rw-r--r-- | src/opengl/qglpaintdevice_p.h | 1 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_x11gl_egl.cpp | 247 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_x11gl_p.h | 8 | ||||
-rw-r--r-- | src/opengl/qwindowsurface_gl.cpp | 1 | ||||
-rw-r--r-- | src/opengl/qwindowsurface_x11gl.cpp | 130 | ||||
-rw-r--r-- | src/opengl/qwindowsurface_x11gl_p.h | 1 |
13 files changed, 264 insertions, 191 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 955a129..8460430 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1807,27 +1807,6 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); d->stencilClean = true; - switch (pdev->devType()) { - case QInternal::Pixmap: - d->deviceHasAlpha = static_cast<QPixmap *>(pdev)->hasAlphaChannel(); - break; - case QInternal::FramebufferObject: - { - GLenum f = static_cast<QGLFramebufferObject *>(pdev)->format().internalTextureFormat(); -#ifndef QT_OPENGL_ES - d->deviceHasAlpha = (f != GL_RGB && f != GL_RGB5 && f != GL_RGB8); -#else - d->deviceHasAlpha = (f == GL_RGBA); -#endif - } - break; - default: - // widget, pbuffer - d->deviceHasAlpha = d->ctx->d_func()->reqFormat.alpha(); - break; - } - - // Calling begin paint should make the correct context current. So, any // code which calls into GL or otherwise needs a current context *must* // go after beginPaint: diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 2ac2ca4..30f6634 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -290,7 +290,6 @@ public: bool needsSync; bool multisamplingAlwaysEnabled; - bool deviceHasAlpha; GLfloat depthRange[2]; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 394bcbc..72ed6be 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -3984,7 +3984,7 @@ bool QGLWidget::event(QEvent *e) if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) { // The window may have been re-created during re-parent or state change - if so, the EGL // surface will need to be re-created. - d->recreateEglSurface(false); + d->recreateEglSurface(); } #endif #elif defined(Q_WS_WIN) diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index b1e2ede..92a064f 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -432,6 +432,7 @@ private: friend class QGLFBOGLPaintDevice; friend class QGLPaintDevice; friend class QX11GLPixmapData; + friend class QX11GLSharedContexts; private: Q_DISABLE_COPY(QGLContext) }; diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index ee580a6..f19e394 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -195,7 +195,7 @@ public: #elif defined(Q_WS_X11) QGLOverlayWidget *olw; #ifndef QT_NO_EGL - void recreateEglSurface(bool force); + void recreateEglSurface(); WId eglSurfaceWindowId; #endif #elif defined(Q_WS_MAC) diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index d67a3ea..c0b1515 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -335,24 +335,24 @@ void QGLWidget::setColormap(const QGLColormap &) { } -// Re-creates the EGL surface if the window ID has changed or if force is true -void QGLWidgetPrivate::recreateEglSurface(bool force) +// Re-creates the EGL surface if the window ID has changed or if there isn't a surface +void QGLWidgetPrivate::recreateEglSurface() { Q_Q(QGLWidget); Window currentId = q->winId(); - if ( force || (currentId != eglSurfaceWindowId) ) { - // The window id has changed so we need to re-create the EGL surface - QEglContext *ctx = glcx->d_func()->eglContext; - EGLSurface surface = glcx->d_func()->eglSurface; - if (surface != EGL_NO_SURFACE) - ctx->destroySurface(surface); // Will force doneCurrent() if nec. - surface = ctx->createSurface(q); - if (surface == EGL_NO_SURFACE) - qWarning("Error creating EGL window surface: 0x%x", eglGetError()); - glcx->d_func()->eglSurface = surface; + // If the window ID has changed since the surface was created, we need to delete the + // old surface before re-creating a new one. Note: This should not be the case as the + // surface should be deleted before the old window id. + if (glcx->d_func()->eglSurface != EGL_NO_SURFACE && (currentId != eglSurfaceWindowId)) { + qWarning("EGL surface for deleted window %x was not destroyed", eglSurfaceWindowId); + glcx->d_func()->destroyEglSurfaceForDevice(); + } + if (glcx->d_func()->eglSurface == EGL_NO_SURFACE) { + qDebug("Re-creating the surface"); + glcx->d_func()->eglSurface = glcx->d_func()->eglContext->createSurface(q); eglSurfaceWindowId = currentId; } } diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp index 2d82222..e874e85 100644 --- a/src/opengl/qglpaintdevice.cpp +++ b/src/opengl/qglpaintdevice.cpp @@ -63,6 +63,22 @@ QGLPaintDevice::~QGLPaintDevice() { } +int QGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + switch(metric) { + case PdmWidth: + return size().width(); + case PdmHeight: + return size().height(); + case PdmDepth: { + const QGLFormat f = format(); + return f.redBufferSize() + f.greenBufferSize() + f.blueBufferSize() + f.alphaBufferSize(); + } + default: + qWarning("QGLPaintDevice::metric() - metric %d not known", metric); + return 0; + } +} void QGLPaintDevice::beginPaint() { diff --git a/src/opengl/qglpaintdevice_p.h b/src/opengl/qglpaintdevice_p.h index 3d669da..04f9c3c 100644 --- a/src/opengl/qglpaintdevice_p.h +++ b/src/opengl/qglpaintdevice_p.h @@ -81,6 +81,7 @@ public: static QGLPaintDevice* getDevice(QPaintDevice*); protected: + int metric(QPaintDevice::PaintDeviceMetric metric) const; GLuint m_previousFBO; GLuint m_thisFBO; }; diff --git a/src/opengl/qpixmapdata_x11gl_egl.cpp b/src/opengl/qpixmapdata_x11gl_egl.cpp index 4d726b6..58d34fc 100644 --- a/src/opengl/qpixmapdata_x11gl_egl.cpp +++ b/src/opengl/qpixmapdata_x11gl_egl.cpp @@ -62,123 +62,170 @@ QT_BEGIN_NAMESPACE -// On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need -// different contexts: - -Q_GLOBAL_STATIC(QEglContext, qt_x11gl_rgbContext); -Q_GLOBAL_STATIC(QEglContext, qt_x11gl_argbContext); -Q_GLOBAL_STATIC_WITH_ARGS(QGLContext, qt_x11gl_fake_shared_context, (QX11GLPixmapData::glFormat())); +class QX11GLSharedContexts +{ +public: + 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(); -QEglContext* QX11GLPixmapData::rgbContext = 0; -QEglContext* QX11GLPixmapData::argbContext = 0; + 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 seperate 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. + } + } -bool QX11GLPixmapData::hasX11GLPixmaps() -{ - static bool checkedForX11Pixmaps = false; - static bool haveX11Pixmaps = false; + if (!argbContext->isValid()) + break; - if (checkedForX11Pixmaps) - return haveX11Pixmaps; + // 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); + } - checkedForX11Pixmaps = true; + if (!valid) { + qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString(); + break; + } - EGLint rgbConfigId; - EGLint argbConfigId; + // The pixmap surface destruction hooks are installed by QGLTextureCache, so we + // must make sure this is instanciated: + QGLTextureCache::instance(); + } while(0); - do { - if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty()) - break; - EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable); - EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, - QEgl::Renderable | QEgl::Translucent); + if (!valid) + cleanup(); + else + qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); - eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId); - eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId); + } - if (!rgbContext) { - rgbContext = qt_x11gl_rgbContext(); - rgbContext->setConfig(rgbConfig); - rgbContext->createContext(); + void cleanup() { + if (sharedQGLContext) { + delete sharedQGLContext; + sharedQGLContext = 0; } + if (argbContext && argbContext != rgbContext) + delete argbContext; + argbContext = 0; - if (!rgbContext->isValid()) - break; - - // If the configs are the same, use the same egl contexts: - if (rgbConfig == argbConfig) - argbContext = rgbContext; - - if (!argbContext) { - argbContext = qt_x11gl_argbContext(); - 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 (rgbContext) { + delete rgbContext; + rgbContext = 0; } - if (!argbContext->isValid()) - break; - - { - QX11PixmapData *argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); - argbPixmapData->resize(100, 100); - argbPixmapData->fill(Qt::transparent); // Force ARGB - QPixmap argbPixmap(argbPixmapData); - EGLSurface argbPixmapSurface = QEgl::createSurface(&argbPixmap, argbConfig); - haveX11Pixmaps = argbContext->makeCurrent(argbPixmapSurface); - argbContext->doneCurrent(); - eglDestroySurface(QEgl::display(), argbPixmapSurface); + // Deleting the QPixmap will fire the pixmap destruction cleanup hooks which in turn + // will destroy the egl surface: + if (sharePixmap) { + delete sharePixmap; + sharePixmap = 0; } + } - if (!haveX11Pixmaps) { - qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString(); - break; - } + bool isValid() { return valid;} - // If the ARGB & RGB configs are different, check RGB too: - if (argbConfig != rgbConfig) { - QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); - rgbPixmapData->resize(100, 100); - rgbPixmapData->fill(Qt::red); + // On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need + // different contexts: + QEglContext *rgbContext; + QEglContext *argbContext; - QPixmap rgbPixmap(rgbPixmapData); - EGLSurface rgbPixmapSurface = QEgl::createSurface(&rgbPixmap, rgbConfig); - haveX11Pixmaps = rgbContext->makeCurrent(rgbPixmapSurface); - rgbContext->doneCurrent(); - eglDestroySurface(QEgl::display(), rgbPixmapSurface); + // The share context wraps the rgbContext and is used as the master of the context share + // group. As all other contexts will have the same egl context (or a shared one if rgb != argb) + // all QGLContexts will actually be sharing and can be in the same context group. + QGLContext *sharedQGLContext; +private: + QPixmap *sharePixmap; + bool valid; +}; - if (!haveX11Pixmaps) { - qWarning() << "Unable to make pixmap config current:" << QEgl::errorString(); - break; - } - } +static void qt_cleanup_x11gl_share_contexts(); - // The pixmap surface destruction hooks are installed by QGLTextureCache, so we - // must make sure this is instanciated: - QGLTextureCache::instance(); - } while (0); +Q_GLOBAL_STATIC_WITH_INITIALIZER(QX11GLSharedContexts, qt_x11gl_share_contexts, + { + qAddPostRoutine(qt_cleanup_x11gl_share_contexts); + }) - if (!haveX11Pixmaps) { - if (argbContext && (argbContext != rgbContext)) { - delete argbContext; - argbContext = 0; - } - if (rgbContext) { - delete rgbContext; - rgbContext = 0; - } - } +static void qt_cleanup_x11gl_share_contexts() +{ + qt_x11gl_share_contexts()->cleanup(); +} - if (haveX11Pixmaps) - qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); - else - qDebug("QX11GLPixmapData is *NOT* being used"); + +QX11GLSharedContexts* QX11GLPixmapData::sharedContexts() +{ + return qt_x11gl_share_contexts(); +} + +bool QX11GLPixmapData::hasX11GLPixmaps() +{ + static bool checkedForX11Pixmaps = false; + static bool haveX11Pixmaps = false; + + if (checkedForX11Pixmaps) + return haveX11Pixmaps; + + checkedForX11Pixmaps = true; + + if (!qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty() && sharedContexts()->isValid()) + haveX11Pixmaps = true; return haveX11Pixmaps; } @@ -264,14 +311,14 @@ QPaintEngine* QX11GLPixmapData::paintEngine() const if (!ctx) { ctx = new QGLContext(glFormat()); Q_ASSERT(ctx->d_func()->eglContext == 0); - ctx->d_func()->eglContext = hasAlphaChannel() ? argbContext : rgbContext; + ctx->d_func()->eglContext = hasAlphaChannel() ? sharedContexts()->argbContext : sharedContexts()->rgbContext; // While we use a seperate QGLContext for each pixmap, the underlying QEglContext is // the same. So we must use a "fake" QGLContext and fool the texture cache into thinking // each pixmap's QGLContext is sharing with this central one. The only place this is // going to fail is where we the underlying EGL RGB and ARGB contexts aren't sharing. ctx->d_func()->sharing = true; - QGLContextGroup::addShare(ctx, qt_x11gl_fake_shared_context()); + QGLContextGroup::addShare(ctx, sharedContexts()->sharedQGLContext); // Update the glFormat for the QGLContext: qt_glformat_from_eglconfig(ctx->d_func()->glFormat, ctx->d_func()->eglContext->config()); @@ -336,12 +383,6 @@ void QX11GLPixmapData::beginPaint() QGLPaintDevice::beginPaint(); } -void QX11GLPixmapData::endPaint() -{ - glFinish(); - QGLPaintDevice::endPaint(); -} - QGLContext* QX11GLPixmapData::context() const { return ctx; diff --git a/src/opengl/qpixmapdata_x11gl_p.h b/src/opengl/qpixmapdata_x11gl_p.h index 8681336..2d1336b 100644 --- a/src/opengl/qpixmapdata_x11gl_p.h +++ b/src/opengl/qpixmapdata_x11gl_p.h @@ -65,6 +65,8 @@ QT_BEGIN_NAMESPACE +class QX11GLSharedContexts; + class QX11GLPixmapData : public QX11PixmapData, public QGLPaintDevice { public: @@ -79,17 +81,13 @@ public: // Re-implemented from QGLPaintDevice QPaintEngine* paintEngine() const; // Also re-implements QX11PixmapData::paintEngine void beginPaint(); - void endPaint(); QGLContext* context() const; QSize size() const; static bool hasX11GLPixmaps(); static QGLFormat glFormat(); + static QX11GLSharedContexts* sharedContexts(); -#ifndef QT_NO_EGL - static QEglContext* rgbContext; - static QEglContext* argbContext; -#endif private: mutable QGLContext* ctx; }; diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index ca88de3..b693245 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -97,6 +97,7 @@ extern Q_GUI_EXPORT bool qt_win_owndc_required; QGLGraphicsSystem::QGLGraphicsSystem() : QGraphicsSystem() { + QGLWindowSurface::surfaceFormat.setSampleBuffers(true); #if defined(Q_WS_X11) && !defined(QT_OPENGL_ES) // only override the system defaults if the user hasn't already // picked a visual diff --git a/src/opengl/qwindowsurface_x11gl.cpp b/src/opengl/qwindowsurface_x11gl.cpp index 7befe03..3de6cae 100644 --- a/src/opengl/qwindowsurface_x11gl.cpp +++ b/src/opengl/qwindowsurface_x11gl.cpp @@ -72,63 +72,66 @@ extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11 void QX11GLWindowSurface::flush(QWidget *widget, const QRegion &widgetRegion, const QPoint &offset) { -// qDebug("QX11GLWindowSurface::flush()"); - QTime startTime = QTime::currentTime(); + // We don't need to know the widget which initiated the flush. Instead we just use the offset + // to translate the widgetRegion: + Q_UNUSED(widget); + if (m_backBuffer.isNull()) { - qDebug("QHarmattanWindowSurface::flush() - backBuffer is null, not flushing anything"); + qDebug("QX11GLWindowSurface::flush() - backBuffer is null, not flushing anything"); return; } - QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft(); - QRegion windowRegion(widgetRegion); - QRect boundingRect = widgetRegion.boundingRect(); - if (!widgetOffset.isNull()) - windowRegion.translate(-widgetOffset); - QRect windowBoundingRect = windowRegion.boundingRect(); + Q_ASSERT(window()->size() != m_backBuffer.size()); - int rectCount; - XRectangle *rects = (XRectangle *)qt_getClipRects(windowRegion, rectCount); - if (rectCount <= 0) - return; -// qDebug() << "XSetClipRectangles"; -// for (int i = 0; i < num; ++i) -// qDebug() << ' ' << i << rects[i].x << rects[i].x << rects[i].y << rects[i].width << rects[i].height; + // Wait for all GL rendering to the back buffer pixmap to complete before trying to + // copy it to the window. We do this by making sure the pixmap's context is current + // and then call eglWaitClient. The EGL 1.4 spec says eglWaitClient doesn't have to + // block, just that "All rendering calls...are guaranteed to be executed before native + // rendering calls". This makes it potentially less expensive than glFinish. + QGLContext* ctx = static_cast<QX11GLPixmapData*>(m_backBuffer.data_ptr().data())->context(); + if (QGLContext::currentContext() != ctx && ctx && ctx->isValid()) + ctx->makeCurrent(); + eglWaitClient(); if (m_windowGC == 0) { - m_windowGC = XCreateGC(X11->display, m_window->handle(), 0, 0); - XSetGraphicsExposures(X11->display, m_windowGC, False); + XGCValues attribs; + attribs.graphics_exposures = False; + m_windowGC = XCreateGC(X11->display, m_window->handle(), GCGraphicsExposures, &attribs); } + int rectCount; + XRectangle *rects = (XRectangle *)qt_getClipRects(widgetRegion, rectCount); + if (rectCount <= 0) + return; + XSetClipRectangles(X11->display, m_windowGC, 0, 0, rects, rectCount, YXBanded); + + QRect dirtyRect = widgetRegion.boundingRect().translated(-offset); XCopyArea(X11->display, m_backBuffer.handle(), m_window->handle(), m_windowGC, - boundingRect.x() + offset.x(), boundingRect.y() + offset.y(), - boundingRect.width(), boundingRect.height(), - windowBoundingRect.x(), windowBoundingRect.y()); - - QX11GLPixmapData* pmd = static_cast<QX11GLPixmapData*>(m_backBuffer.data_ptr().data()); - Q_ASSERT(pmd->context()); - pmd->context()->makeCurrent(); - XSync(X11->display, False); + dirtyRect.x(), dirtyRect.y(), dirtyRect.width(), dirtyRect.height(), + dirtyRect.x(), dirtyRect.y()); + + // Make sure the blit of the update from the back buffer to the window completes + // before allowing rendering to start again to the back buffer. Otherwise the GPU + // might start rendering to the back buffer again while the blit takes place. eglWaitNative(EGL_CORE_NATIVE_ENGINE); } void QX11GLWindowSurface::setGeometry(const QRect &rect) { if (rect.width() > m_backBuffer.size().width() || rect.height() > m_backBuffer.size().height()) { - QSize newSize = rect.size(); -// QSize newSize(1024,512); - qDebug() << "QX11GLWindowSurface::setGeometry() - creating a pixmap of size" << newSize; QX11GLPixmapData *pd = new QX11GLPixmapData; + QSize newSize = rect.size(); pd->resize(newSize.width(), newSize.height()); m_backBuffer = QPixmap(pd); if (window()->testAttribute(Qt::WA_TranslucentBackground)) m_backBuffer.fill(Qt::transparent); + if (m_pixmapGC) { + XFreeGC(X11->display, m_pixmapGC); + m_pixmapGC = 0; + } } -// if (gc) -// XFreeGC(X11->display, gc); -// gc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0); -// XSetGraphicsExposures(X11->display, gc, False); QWindowSurface::setGeometry(rect); } @@ -139,10 +142,10 @@ bool QX11GLWindowSurface::scroll(const QRegion &area, int dx, int dy) Q_ASSERT(m_backBuffer.data_ptr()->classId() == QPixmapData::X11Class); - QX11GLPixmapData* pmd = static_cast<QX11GLPixmapData*>(m_backBuffer.data_ptr().data()); - Q_ASSERT(pmd->context()); - pmd->context()->makeCurrent(); - glFinish(); + // Make sure all GL rendering is complete before starting the scroll operation: + QGLContext* ctx = static_cast<QX11GLPixmapData*>(m_backBuffer.data_ptr().data())->context(); + if (QGLContext::currentContext() != ctx && ctx && ctx->isValid()) + ctx->makeCurrent(); eglWaitClient(); if (!m_pixmapGC) @@ -154,24 +157,57 @@ bool QX11GLWindowSurface::scroll(const QRegion &area, int dx, int dy) rect.x()+dx, rect.y()+dy); } - XSync(X11->display, False); + // Make sure the scroll operation is complete before allowing GL rendering to resume eglWaitNative(EGL_CORE_NATIVE_ENGINE); return true; } -/* -void QX11GLWindowSurface::beginPaint(const QRegion ®ion) -{ -} -void QX11GLWindowSurface::endPaint(const QRegion ®ion) +QPixmap QX11GLWindowSurface::grabWidget(const QWidget *widget, const QRect& rect) const { -} + if (!widget || m_backBuffer.isNull()) + return QPixmap(); -QImage *QX11GLWindowSurface::buffer(const QWidget *widget) -{ + 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; } -*/ QT_END_NAMESPACE diff --git a/src/opengl/qwindowsurface_x11gl_p.h b/src/opengl/qwindowsurface_x11gl_p.h index 3a952e8..4d493d0 100644 --- a/src/opengl/qwindowsurface_x11gl_p.h +++ b/src/opengl/qwindowsurface_x11gl_p.h @@ -68,6 +68,7 @@ public: void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); void setGeometry(const QRect &rect); bool scroll(const QRegion &area, int dx, int dy); + QPixmap grabWidget(const QWidget *widget, const QRect& rectangle = QRect()) const; private: GC m_windowGC; |