From 6c2da36c22e25e626a9812419332ad379e854133 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 12 Dec 2014 12:59:43 +0100 Subject: Prevent continuous painting with viewport QOpenGLWidget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the source widget to the texture list (may be null for custom compositor implementations that add textures not belonging to actual widgets). This allows us to do proper checks with the dirtyRenderToTextureWidgets list. As a result paint events are only sent to a QOpenGLWidget if (1) there was an update() for it or (2) it was actually marked dirty. (2) was previously behaving differently: the widget got a paint event when anything in the window has changed. This is fine for naive animating OpenGL code but less ideal for QGraphicsView. Bool properties like stacksOnTop are now stored in a flags value to prevent future explosion of texture list fields and parameters. Task-number: QTBUG-43178 Change-Id: I48cbcf93df72ac682c9b5d64982a8b648fe21ef3 Reviewed-by: Jørgen Lind Reviewed-by: Paul Olav Tvete --- src/gui/painting/qplatformbackingstore.cpp | 22 ++++++++++----- src/gui/painting/qplatformbackingstore.h | 11 ++++++-- .../eglconvenience/qeglcompositor.cpp | 4 +-- .../eglconvenience/qeglplatformbackingstore.cpp | 6 ++--- src/widgets/kernel/qwidgetbackingstore.cpp | 31 +++++++++------------- 5 files changed, 42 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index e87f796888..76269f6e65 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -82,9 +82,10 @@ public: struct QBackingstoreTextureInfo { + QWidget *widget; // may be null GLuint textureId; QRect rect; - bool stacksOnTop; + QPlatformTextureList::Flags flags; }; Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_MOVABLE_TYPE); @@ -122,10 +123,16 @@ GLuint QPlatformTextureList::textureId(int index) const return d->textures.at(index).textureId; } -bool QPlatformTextureList::stacksOnTop(int index) const +QWidget *QPlatformTextureList::widget(int index) { Q_D(const QPlatformTextureList); - return d->textures.at(index).stacksOnTop; + return d->textures.at(index).widget; +} + +QPlatformTextureList::Flags QPlatformTextureList::flags(int index) const +{ + Q_D(const QPlatformTextureList); + return d->textures.at(index).flags; } QRect QPlatformTextureList::geometry(int index) const @@ -149,13 +156,14 @@ bool QPlatformTextureList::isLocked() const return d->locked; } -void QPlatformTextureList::appendTexture(GLuint textureId, const QRect &geometry, bool stacksOnTop) +void QPlatformTextureList::appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags) { Q_D(QPlatformTextureList); QBackingstoreTextureInfo bi; + bi.widget = widget; bi.textureId = textureId; bi.rect = geometry; - bi.stacksOnTop = stacksOnTop; + bi.flags = flags; d->textures.append(bi); } @@ -245,7 +253,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets. for (int i = 0; i < textures->count(); ++i) { - if (!textures->stacksOnTop(i)) { + if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { QRect targetRect = deviceRect(textures->geometry(i), window); QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); @@ -272,7 +280,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. for (int i = 0; i < textures->count(); ++i) { - if (textures->stacksOnTop(i)) { + if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { QRect targetRect = deviceRect(textures->geometry(i), window); QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index 52c263f05d..c69612ca44 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -69,6 +69,11 @@ class Q_GUI_EXPORT QPlatformTextureList : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QPlatformTextureList) public: + enum Flag { + StacksOnTop = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + explicit QPlatformTextureList(QObject *parent = 0); ~QPlatformTextureList(); @@ -76,16 +81,18 @@ public: bool isEmpty() const { return count() == 0; } GLuint textureId(int index) const; QRect geometry(int index) const; - bool stacksOnTop(int index) const; + QWidget *widget(int index); + Flags flags(int index) const; void lock(bool on); bool isLocked() const; - void appendTexture(GLuint textureId, const QRect &geometry, bool stacksOnTop = false); + void appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags = 0); void clear(); Q_SIGNALS: void locked(bool); }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformTextureList::Flags) #endif class Q_GUI_EXPORT QPlatformBackingStore diff --git a/src/platformsupport/eglconvenience/qeglcompositor.cpp b/src/platformsupport/eglconvenience/qeglcompositor.cpp index 5866edc48d..a46e5698de 100644 --- a/src/platformsupport/eglconvenience/qeglcompositor.cpp +++ b/src/platformsupport/eglconvenience/qeglcompositor.cpp @@ -151,7 +151,7 @@ void QEGLCompositor::render(QEGLPlatformWindow *window) const bool translucent = window->window()->requestedFormat().alphaBufferSize() > 0; blend.set(translucent); m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); - } else if (!textures->stacksOnTop(i)) { + } else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { // Texture from an FBO belonging to a QOpenGLWidget blend.set(false); m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft); @@ -159,7 +159,7 @@ void QEGLCompositor::render(QEGLPlatformWindow *window) } for (int i = 0; i < textures->count(); ++i) { - if (textures->stacksOnTop(i)) { + if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); blend.set(true); m_blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); diff --git a/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp b/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp index 43c18573f2..d7d95ea97d 100644 --- a/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp @@ -152,7 +152,7 @@ void QEGLPlatformBackingStore::flush(QWindow *window, const QRegion ®ion, con screen->compositingContext()->makeCurrent(dstWin->window()); updateTexture(); m_textures->clear(); - m_textures->appendTexture(m_bsTexture, window->geometry()); + m_textures->appendTexture(Q_NULLPTR, m_bsTexture, window->geometry()); composite(screen->compositingContext(), dstWin); } @@ -176,10 +176,10 @@ void QEGLPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &r m_textures->clear(); for (int i = 0; i < textures->count(); ++i) - m_textures->appendTexture(textures->textureId(i), textures->geometry(i), textures->stacksOnTop(i)); + m_textures->appendTexture(textures->widget(i), textures->textureId(i), textures->geometry(i), textures->flags(i)); updateTexture(); - m_textures->appendTexture(m_bsTexture, window->geometry()); + m_textures->appendTexture(Q_NULLPTR, m_bsTexture, window->geometry()); textures->lock(true); m_lockedWidgetTextures = textures; diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 9f014aa4fe..cd01869af2 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -963,9 +963,12 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures) { QWidgetPrivate *wd = QWidgetPrivate::get(widget); - if (wd->renderToTexture) - widgetTextures->appendTexture(wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()), - widget->testAttribute(Qt::WA_AlwaysStackOnTop)); + if (wd->renderToTexture) { + QPlatformTextureList::Flags flags = 0; + if (widget->testAttribute(Qt::WA_AlwaysStackOnTop)) + flags |= QPlatformTextureList::StacksOnTop; + widgetTextures->appendTexture(widget, wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()), flags); + } for (int i = 0; i < wd->children.size(); ++i) { QWidget *w = qobject_cast(wd->children.at(i)); @@ -1156,28 +1159,20 @@ void QWidgetBackingStore::doSync() } #ifndef QT_NO_OPENGL - // There is something other dirty than the renderToTexture widgets. - // Now it is time to include the renderToTexture ones among the others. if (widgetTextures && widgetTextures->count()) { for (int i = 0; i < widgetTextures->count(); ++i) { - const QRect rect = widgetTextures->geometry(i); // mapped to the tlw already - dirty += rect; - toClean += rect; + QWidget *w = widgetTextures->widget(i); + if (dirtyRenderToTextureWidgets.contains(w)) { + const QRect rect = widgetTextures->geometry(i); // mapped to the tlw already + dirty += rect; + toClean += rect; + } } } -#endif - - // The dirtyRenderToTextureWidgets list is useless here, so just reset. As - // unintuitive as it is, we need to send paint events to renderToTexture - // widgets always when something (any widget) needs to be updated, even if - // the renderToTexture widget itself is clean, i.e. there was no update() - // call for it. This is because changing any widget will cause a flush and - // so a potentially blocking buffer swap for the window, and skipping paints - // for the renderToTexture widgets would make it impossible to have smoothly - // animated content in them. for (int i = 0; i < dirtyRenderToTextureWidgets.count(); ++i) resetWidget(dirtyRenderToTextureWidgets.at(i)); dirtyRenderToTextureWidgets.clear(); +#endif #ifndef QT_NO_GRAPHICSVIEW if (tlw->d_func()->extra->proxyWidget) { -- cgit v1.2.3