diff options
Diffstat (limited to 'src/widgets/kernel/qwidgetbackingstore.cpp')
-rw-r--r-- | src/widgets/kernel/qwidgetbackingstore.cpp | 144 |
1 files changed, 95 insertions, 49 deletions
diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 9d024fd359..242872d6b2 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWidgets module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -56,6 +48,7 @@ #include <private/qapplication_p.h> #include <private/qpaintengine_raster_p.h> #include <private/qgraphicseffect_p.h> +#include <QtGui/private/qwindow_p.h> #include <qpa/qplatformbackingstore.h> @@ -74,7 +67,8 @@ extern QRegion qt_dirtyRegion(QWidget *); * \a region is the region to be updated in \a widget coordinates. */ void QWidgetBackingStore::qt_flush(QWidget *widget, const QRegion ®ion, QBackingStore *backingStore, - QWidget *tlw, const QPoint &tlwOffset, QPlatformTextureList *widgetTextures) + QWidget *tlw, const QPoint &tlwOffset, QPlatformTextureList *widgetTextures, + QWidgetBackingStore *widgetBackingStore) { #ifdef QT_NO_OPENGL Q_UNUSED(widgetTextures); @@ -92,33 +86,34 @@ void QWidgetBackingStore::qt_flush(QWidget *widget, const QRegion ®ion, QBack QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false); #endif - //The performance hit by doing this should be negligible. However, be aware that - //using this FPS when you have > 1 windowsurface can give you inaccurate FPS + if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen)) + return; static bool fpsDebug = qgetenv("QT_DEBUG_FPS").toInt(); if (fpsDebug) { - static QTime time = QTime::currentTime(); - static int frames = 0; - - frames++; - - if(time.elapsed() > 5000) { - double fps = double(frames * 1000) /time.restart(); - fprintf(stderr,"FPS: %.1f\n",fps); - frames = 0; + if (!widgetBackingStore->perfFrames++) + widgetBackingStore->perfTime.start(); + if (widgetBackingStore->perfTime.elapsed() > 5000) { + double fps = double(widgetBackingStore->perfFrames * 1000) / widgetBackingStore->perfTime.restart(); + qDebug("FPS: %.1f\n", fps); + widgetBackingStore->perfFrames = 0; } } - if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen)) - return; - QPoint offset = tlwOffset; if (widget != tlw) offset += widget->mapTo(tlw, QPoint()); #ifndef QT_NO_OPENGL - if (widgetTextures) - backingStore->handle()->composeAndFlush(widget->windowHandle(), region, offset, widgetTextures, tlw->d_func()->shareContext()); - else + if (widgetTextures) { + widget->window()->d_func()->sendComposeStatus(widget->window(), false); + // A window may have alpha even when the app did not request + // WA_TranslucentBackground. Therefore the compositor needs to know whether the app intends + // to rely on translucency, in order to decide if it should clear to transparent or opaque. + const bool translucentBackground = widget->testAttribute(Qt::WA_TranslucentBackground); + backingStore->handle()->composeAndFlush(widget->windowHandle(), region, offset, widgetTextures, + widget->d_func()->shareContext(), translucentBackground); + widget->window()->d_func()->sendComposeStatus(widget->window(), true); + } else #endif backingStore->flush(region, widget->windowHandle(), offset); } @@ -270,7 +265,7 @@ void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn) return; const QPoint offset = widget->mapTo(tlw, QPoint()); - qt_flush(widget, rgn, tlwExtra->backingStoreTracker->store, tlw, offset); + qt_flush(widget, rgn, tlwExtra->backingStoreTracker->store, tlw, offset, 0, tlw->d_func()->maybeBackingStore()); } #endif // QT_NO_PAINT_DEBUG @@ -519,6 +514,8 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, const QPoint offset = widget->mapTo(tlw, QPoint()); if (QWidgetPrivate::get(widget)->renderToTexture) { + if (!widget->d_func()->inDirtyList) + addDirtyRenderToTextureWidget(widget); if (!updateRequestSent || updateTime == UpdateNow) sendUpdateRequest(tlw, updateTime); return; @@ -613,6 +610,8 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, } if (QWidgetPrivate::get(widget)->renderToTexture) { + if (!widget->d_func()->inDirtyList) + addDirtyRenderToTextureWidget(widget); if (!updateRequestSent || updateTime == UpdateNow) sendUpdateRequest(tlw, updateTime); return; @@ -710,6 +709,7 @@ void QWidgetBackingStore::removeDirtyWidget(QWidget *w) dirtyWidgetsRemoveAll(w); dirtyOnScreenWidgetsRemoveAll(w); + dirtyRenderToTextureWidgets.removeAll(w); resetWidget(w); QWidgetPrivate *wd = w->d_func(); @@ -744,7 +744,8 @@ QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) widgetTextures(0), fullUpdatePending(0), updateRequestSent(0), - textureListWatcher(0) + textureListWatcher(0), + perfFrames(0) { store = tlw->backingStore(); Q_ASSERT(store); @@ -755,9 +756,11 @@ QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) QWidgetBackingStore::~QWidgetBackingStore() { - for (int c = 0; c < dirtyWidgets.size(); ++c) { + for (int c = 0; c < dirtyWidgets.size(); ++c) resetWidget(dirtyWidgets.at(c)); - } + for (int c = 0; c < dirtyRenderToTextureWidgets.size(); ++c) + resetWidget(dirtyRenderToTextureWidgets.at(c)); + #ifndef QT_NO_OPENGL delete dirtyOnScreenWidgets; #endif @@ -944,7 +947,7 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg // Nothing to repaint. if (!isDirty() && store->size().isValid()) { - qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset, widgetTextures); + qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset, widgetTextures, this); return; } @@ -961,7 +964,8 @@ static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatfo { QWidgetPrivate *wd = QWidgetPrivate::get(widget); if (wd->renderToTexture) - widgetTextures->appendTexture(wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size())); + widgetTextures->appendTexture(wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()), + widget->testAttribute(Qt::WA_AlwaysStackOnTop)); for (int i = 0; i < wd->children.size(); ++i) { QWidget *w = qobject_cast<QWidget *>(wd->children.at(i)); @@ -1121,17 +1125,55 @@ void QWidgetBackingStore::doSync() widgetTextures = new QPlatformTextureList; findTextureWidgetsRecursively(tlw, tlw, widgetTextures); } + qt_window_private(tlw->windowHandle())->compositing = widgetTextures && !widgetTextures->isEmpty(); fullUpdatePending = false; #endif if (toClean.isEmpty()) { - // Nothing to repaint. However, we might have newly exposed areas on the - // screen if this function was called from sync(QWidget *, QRegion)), so - // we have to make sure those are flushed. + // Nothing to repaint. However renderToTexture widgets are handled + // specially, they are not in the regular dirty list, in order to + // prevent triggering unnecessary backingstore painting when only the + // OpenGL content changes. Check if we have such widgets in the special + // dirty list. + for (int i = 0; i < dirtyRenderToTextureWidgets.count(); ++i) { + QWidget *w = dirtyRenderToTextureWidgets.at(i); + w->d_func()->sendPaintEvent(w->rect()); + resetWidget(w); + } + dirtyRenderToTextureWidgets.clear(); + + // We might have newly exposed areas on the screen if this function was + // called from sync(QWidget *, QRegion)), so we have to make sure those + // are flushed. We also need to composite the renderToTexture widgets. flush(); + return; } +#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; + } + } +#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(); + #ifndef QT_NO_GRAPHICSVIEW if (tlw->d_func()->extra->proxyWidget) { updateStaticContentsSize(); @@ -1200,15 +1242,19 @@ void QWidgetBackingStore::flush(QWidget *widget) { if (!dirtyOnScreen.isEmpty()) { QWidget *target = widget ? widget : tlw; - qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset, widgetTextures); + qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset, widgetTextures, this); dirtyOnScreen = QRegion(); +#ifndef QT_NO_OPENGL + if (widgetTextures && widgetTextures->count()) + return; +#endif } if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) { #ifndef QT_NO_OPENGL if (widgetTextures && widgetTextures->count()) { QWidget *target = widget ? widget : tlw; - qt_flush(target, QRegion(), store, tlw, tlwOffset, widgetTextures); + qt_flush(target, QRegion(), store, tlw, tlwOffset, widgetTextures, this); } #endif return; @@ -1218,7 +1264,7 @@ void QWidgetBackingStore::flush(QWidget *widget) QWidget *w = dirtyOnScreenWidgets->at(i); QWidgetPrivate *wd = w->d_func(); Q_ASSERT(wd->needsFlush); - qt_flush(w, *wd->needsFlush, store, tlw, tlwOffset); + qt_flush(w, *wd->needsFlush, store, tlw, tlwOffset, 0, this); *wd->needsFlush = QRegion(); } dirtyOnScreenWidgets->clear(); |