diff options
author | Tom Cooksey <thomas.cooksey@nokia.com> | 2010-04-21 15:59:40 (GMT) |
---|---|---|
committer | Tom Cooksey <thomas.cooksey@nokia.com> | 2010-04-22 14:38:08 (GMT) |
commit | 0c77187652b976c3b9a17e95311bda3e3d8a6fbe (patch) | |
tree | b6df8fd0c7b0c16d3f504a41a0264f85389958b7 /src | |
parent | 1a00c7dec743c05b0f64bcacc03b3d2c90ac881d (diff) | |
download | Qt-0c77187652b976c3b9a17e95311bda3e3d8a6fbe.zip Qt-0c77187652b976c3b9a17e95311bda3e3d8a6fbe.tar.gz Qt-0c77187652b976c3b9a17e95311bda3e3d8a6fbe.tar.bz2 |
QX11GL: Cleanup the window surface & remove some synchronisation
Previously we were calling all manor of synchronisation calls to
make sure there were no issues. These have been sanitised to just
use eglWaitClient and eglWaitNative and only in places which need
it. There is still a bug where small updates will sometimes result
in small horizontal streaks. However, this has been confirmed to be
a cache flush bug in the X server 2D driver. The driver bug is
tracked in Meamo bugzilla as bug 164941. Hopefully it will be fixed
soon.
Reviewed-By: TrustMe
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/painting/qwindowsurface_p.h | 8 | ||||
-rw-r--r-- | src/opengl/qwindowsurface_x11gl.cpp | 92 |
2 files changed, 47 insertions, 53 deletions
diff --git a/src/gui/painting/qwindowsurface_p.h b/src/gui/painting/qwindowsurface_p.h index e6ee5f6..6171ae8 100644 --- a/src/gui/painting/qwindowsurface_p.h +++ b/src/gui/painting/qwindowsurface_p.h @@ -73,8 +73,12 @@ public: QWidget *window() const; virtual QPaintDevice *paintDevice() = 0; - virtual void flush(QWidget *widget, const QRegion ®ion, - const QPoint &offset) = 0; + + // 'widget' can be a child widget, in which case 'region' is in child widget coordinates and + // offset is the (child) widget's offset in relation to the window surface. On QWS, 'offset' + // can be larger than just the offset from the top-level widget as there may also be window + // decorations which are painted into the window surface. + virtual void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) = 0; virtual void setGeometry(const QRect &rect); QRect geometry() const; diff --git a/src/opengl/qwindowsurface_x11gl.cpp b/src/opengl/qwindowsurface_x11gl.cpp index 7befe03..e5a1760 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,11 @@ 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) -{ -} - -QImage *QX11GLWindowSurface::buffer(const QWidget *widget) -{ -} -*/ QT_END_NAMESPACE |