diff options
Diffstat (limited to 'src/widgets/kernel/qwidgetrepaintmanager.cpp')
-rw-r--r-- | src/widgets/kernel/qwidgetrepaintmanager.cpp | 344 |
1 files changed, 126 insertions, 218 deletions
diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp index 977a746c5a..607a767a20 100644 --- a/src/widgets/kernel/qwidgetrepaintmanager.cpp +++ b/src/widgets/kernel/qwidgetrepaintmanager.cpp @@ -1,42 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qplatformdefs.h" @@ -65,12 +28,11 @@ QT_BEGIN_NAMESPACE -#ifndef QT_NO_OPENGL Q_GLOBAL_STATIC(QPlatformTextureList, qt_dummy_platformTextureList) // Watches one or more QPlatformTextureLists for changes in the lock state and // triggers a backingstore sync when all the registered lists turn into -// unlocked state. This is essential when a custom composeAndFlush() +// unlocked state. This is essential when a custom rhiFlush() // implementation in a platform plugin is not synchronous and keeps // holding on to the textures for some time even after returning from there. class QPlatformTextureListWatcher : public QObject @@ -86,7 +48,7 @@ public: } bool isLocked() const { - foreach (bool v, m_locked) { + for (const auto &[_, v] : m_locked.asKeyValueRange()) { if (v) return true; } @@ -105,7 +67,6 @@ private: QHash<QPlatformTextureList *, bool> m_locked; QWidgetRepaintManager *m_repaintManager; }; -#endif // --------------------------------------------------------------------------- @@ -164,7 +125,7 @@ void QWidgetPrivate::invalidateBackingStore(const T &r) return; QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); - if (!tlwExtra || !tlwExtra->backingStore) + if (!tlwExtra || !tlwExtra->backingStore || !tlwExtra->repaintManager) return; T clipped(r); @@ -340,7 +301,7 @@ void QWidgetRepaintManager::removeDirtyWidget(QWidget *w) needsFlushWidgets.removeAll(w); QWidgetPrivate *wd = w->d_func(); - const int n = wd->children.count(); + const int n = wd->children.size(); for (int i = 0; i < n; ++i) { if (QWidget *child = qobject_cast<QWidget*>(wd->children.at(i))) removeDirtyWidget(child); @@ -374,14 +335,13 @@ void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime update qCInfo(lcWidgetPainting) << "Sending update request to" << widget << "with" << updateTime; -#ifndef QT_NO_OPENGL // Having every repaint() leading to a sync/flush is bad as it causes // compositing and waiting for vsync each and every time. Change to // UpdateLater, except for approx. once per frame to prevent starvation in // case the control does not get back to the event loop. - QWidget *w = widget->window(); - if (updateTime == UpdateNow && w && w->windowHandle() && QWindowPrivate::get(w->windowHandle())->compositing) { + if (updateTime == UpdateNow && QWidgetPrivate::get(widget)->textureChildSeen) { int refresh = 60; + QWidget *w = widget->window(); QScreen *ws = w->windowHandle()->screen(); if (ws) refresh = ws->refreshRate(); @@ -390,13 +350,16 @@ void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime update const qint64 elapsed = wd->lastComposeTime.elapsed(); if (elapsed <= qint64(1000.0f / refresh)) updateTime = UpdateLater; - } + } } -#endif switch (updateTime) { case UpdateLater: - updateRequestSent = true; + // Prevent redundant update request events, unless it's a + // paint on screen widget, as these don't go through the + // normal backingstore sync machinery. + if (!widget->d_func()->shouldPaintOnScreen()) + updateRequestSent = true; QCoreApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); break; case UpdateNow: { @@ -414,25 +377,6 @@ static bool hasPlatformWindow(QWidget *widget) return widget && widget->windowHandle() && widget->windowHandle()->handle(); } -static QList<QRect> getSortedRectsToScroll(const QRegion ®ion, int dx, int dy) -{ - QList<QRect> rects; - std::copy(region.begin(), region.end(), std::back_inserter(rects)); - if (rects.count() > 1) { - std::sort(rects.begin(), rects.end(), [=](const QRect &r1, const QRect &r2) { - if (r1.y() == r2.y()) { - if (dx > 0) - return r1.x() > r2.x(); - return r1.x() < r2.x(); - } - if (dy > 0) - return r1.y() > r2.y(); - return r1.y() < r2.y(); - }); - } - return rects; -} - //parent's coordinates; move whole rect; update parent and widget //assume the screen blt has already been done, so we don't need to refresh that part void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) @@ -442,14 +386,13 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) return; QWidget *tlw = q->window(); - QTLWExtra* x = tlw->d_func()->topData(); static const bool accelEnv = qEnvironmentVariableIntValue("QT_NO_FAST_MOVE") == 0; - QWidget *pw = q->parentWidget(); - QPoint toplevelOffset = pw->mapTo(tlw, QPoint()); - QWidgetPrivate *pd = pw->d_func(); - QRect clipR(pd->clipRect()); + QWidget *parentWidget = q->parentWidget(); + QPoint toplevelOffset = parentWidget->mapTo(tlw, QPoint()); + QWidgetPrivate *parentPrivate = parentWidget->d_func(); + const QRect clipR(parentPrivate->clipRect()); const QRect newRect(rect.translated(dx, dy)); QRect destRect = rect.intersected(clipR); if (destRect.isValid()) @@ -458,60 +401,40 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) const QRect parentRect(rect & clipR); const bool nativeWithTextureChild = textureChildSeen && hasPlatformWindow(q); - const bool accelerateMove = accelEnv && isOpaque && !nativeWithTextureChild + bool accelerateMove = accelEnv && isOpaque && !nativeWithTextureChild && sourceRect.isValid() #if QT_CONFIG(graphicsview) // No accelerate move for proxy widgets. && !tlw->d_func()->extra->proxyWidget #endif - ; + && !isOverlapped(sourceRect) && !isOverlapped(destRect); if (!accelerateMove) { - QRegion parentR(effectiveRectFor(parentRect)); + QRegion parentRegion(effectiveRectFor(parentRect)); if (!extra || !extra->hasMask) { - parentR -= newRect; + parentRegion -= newRect; } else { // invalidateBackingStore() excludes anything outside the mask - parentR += newRect & clipR; + parentRegion += newRect & clipR; } - pd->invalidateBackingStore(parentR); + parentPrivate->invalidateBackingStore(parentRegion); invalidateBackingStore((newRect & clipR).translated(-data.crect.topLeft())); } else { - - QWidgetRepaintManager *repaintManager = x->repaintManager.get(); + QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(tlw)->maybeRepaintManager(); + Q_ASSERT(repaintManager); QRegion childExpose(newRect & clipR); - QRegion overlappedExpose; - - if (sourceRect.isValid()) { - overlappedExpose = (overlappedRegion(sourceRect) | overlappedRegion(destRect)) & clipR; - - const qreal factor = QHighDpiScaling::factor(q->windowHandle()); - if (overlappedExpose.isEmpty() || qFloor(factor) == factor) { - const QList<QRect> rectsToScroll = - getSortedRectsToScroll(QRegion(sourceRect) - overlappedExpose, dx, dy); - for (QRect r : rectsToScroll) { - if (repaintManager->bltRect(r, dx, dy, pw)) { - childExpose -= r.translated(dx, dy); - } - } - } - childExpose -= overlappedExpose; - } + if (repaintManager->bltRect(sourceRect, dx, dy, parentWidget)) + childExpose -= destRect; - if (!pw->updatesEnabled()) + if (!parentWidget->updatesEnabled()) return; const bool childUpdatesEnabled = q->updatesEnabled(); - if (childUpdatesEnabled) { - if (!overlappedExpose.isEmpty()) { - overlappedExpose.translate(-data.crect.topLeft()); - invalidateBackingStore(overlappedExpose); - } - if (!childExpose.isEmpty()) { - childExpose.translate(-data.crect.topLeft()); - repaintManager->markDirty(childExpose, q); - isMoved = true; - } + + if (childUpdatesEnabled && !childExpose.isEmpty()) { + childExpose.translate(-data.crect.topLeft()); + repaintManager->markDirty(childExpose, q); + isMoved = true; } QRegion parentExpose(parentRect); @@ -520,14 +443,14 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft()); if (!parentExpose.isEmpty()) { - repaintManager->markDirty(parentExpose, pw); - pd->isMoved = true; + repaintManager->markDirty(parentExpose, parentWidget); + parentPrivate->isMoved = true; } if (childUpdatesEnabled) { QRegion needsFlush(sourceRect); needsFlush += destRect; - repaintManager->markNeedsFlush(pw, needsFlush, toplevelOffset); + repaintManager->markNeedsFlush(parentWidget, needsFlush, toplevelOffset); } } } @@ -537,20 +460,20 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) { Q_Q(QWidget); QWidget *tlw = q->window(); - QTLWExtra* x = tlw->d_func()->topData(); - QWidgetRepaintManager *repaintManager = x->repaintManager.get(); + QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(tlw)->maybeRepaintManager(); if (!repaintManager) return; static const bool accelEnv = qEnvironmentVariableIntValue("QT_NO_FAST_SCROLL") == 0; - const QRect clipR = clipRect(); - const QRect scrollRect = rect & clipR; - const bool accelerateScroll = accelEnv && isOpaque && !q_func()->testAttribute(Qt::WA_WState_InPaintEvent); + const QRect scrollRect = rect & clipRect(); + bool overlapped = false; + bool accelerateScroll = accelEnv && isOpaque && !q_func()->testAttribute(Qt::WA_WState_InPaintEvent) + && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft()))); if (!accelerateScroll) { - if (!overlappedRegion(scrollRect.translated(data.crect.topLeft()), true).isEmpty()) { + if (overlapped) { QRegion region(scrollRect); subtractOpaqueSiblings(region); invalidateBackingStore(region); @@ -562,23 +485,12 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) const QRect destRect = scrollRect.translated(dx, dy) & scrollRect; const QRect sourceRect = destRect.translated(-dx, -dy); - const QRegion overlappedExpose = (overlappedRegion(scrollRect.translated(data.crect.topLeft()))) - .translated(-data.crect.topLeft()) & clipR; QRegion childExpose(scrollRect); - - const qreal factor = QHighDpiScaling::factor(q->windowHandle()); - if (overlappedExpose.isEmpty() || qFloor(factor) == factor) { - const QList<QRect> rectsToScroll = - getSortedRectsToScroll(QRegion(sourceRect) - overlappedExpose, dx, dy); - for (const QRect &r : rectsToScroll) { - if (repaintManager->bltRect(r, dx, dy, q)) { - childExpose -= r.translated(dx, dy); - } - } + if (sourceRect.isValid()) { + if (repaintManager->bltRect(sourceRect, dx, dy, q)) + childExpose -= destRect; } - childExpose -= overlappedExpose; - if (inDirtyList) { if (rect == q->rect()) { dirty.translate(dx, dy); @@ -595,8 +507,6 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) if (!q->updatesEnabled()) return; - if (!overlappedExpose.isEmpty()) - invalidateBackingStore(overlappedExpose); if (!childExpose.isEmpty()) { repaintManager->markDirty(childExpose, q); isScrolled = true; @@ -624,7 +534,6 @@ bool QWidgetRepaintManager::bltRect(const QRect &rect, int dx, int dy, QWidget * // --------------------------------------------------------------------------- -#ifndef QT_NO_OPENGL static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures, QList<QWidget *> *nativeChildren) @@ -633,7 +542,8 @@ static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, if (wd->renderToTexture) { QPlatformTextureList::Flags flags = wd->textureListFlags(); const QRect rect(widget->mapTo(tlw, QPoint()), widget->size()); - widgetTextures->appendTexture(widget, wd->textureId(), rect, wd->clipRect(), flags); + QWidgetPrivate::TextureData data = wd->texture(); + widgetTextures->appendTexture(widget, data.textureLeft, data.textureRight, rect, wd->clipRect(), flags); } for (int i = 0; i < wd->children.size(); ++i) { @@ -659,7 +569,7 @@ static void findAllTextureWidgetsRecursively(QWidget *tlw, QWidget *widget) if (!tl->isEmpty()) QWidgetPrivate::get(tlw)->topData()->widgetTextures.push_back(std::move(tl)); // Native child widgets, if there was any, get their own separate QPlatformTextureList. - for (QWidget *ncw : qAsConst(nativeChildren)) { + for (QWidget *ncw : std::as_const(nativeChildren)) { if (QWidgetPrivate::get(ncw)->textureChildSeen) findAllTextureWidgetsRecursively(tlw, ncw); } @@ -677,33 +587,12 @@ static QPlatformTextureList *widgetTexturesFor(QWidget *tlw, QWidget *widget) } } - if (QWidgetPrivate::get(widget)->textureChildSeen) { - // No render-to-texture widgets in the (sub-)tree due to hidden or native - // children. Returning null results in using the normal backingstore flush path - // without OpenGL-based compositing. This is very desirable normally. However, - // some platforms cannot handle switching between the non-GL and GL paths for - // their windows so it has to be opt-in. - static bool switchableWidgetComposition = - QGuiApplicationPrivate::instance()->platformIntegration() - ->hasCapability(QPlatformIntegration::SwitchableWidgetComposition); - if (!switchableWidgetComposition) - return qt_dummy_platformTextureList(); - } - - return nullptr; -} + if (QWidgetPrivate::get(widget)->textureChildSeen) + return qt_dummy_platformTextureList(); -#else - -static QPlatformTextureList *widgetTexturesFor(QWidget *tlw, QWidget *widget) -{ - Q_UNUSED(tlw); - Q_UNUSED(widget); return nullptr; } -#endif // QT_NO_OPENGL - // --------------------------------------------------------------------------- /*! @@ -778,7 +667,6 @@ bool QWidgetPrivate::shouldDiscardSyncRequest() const bool QWidgetRepaintManager::syncAllowed() { -#ifndef QT_NO_OPENGL QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); if (textureListWatcher && !textureListWatcher->isLocked()) { textureListWatcher->deleteLater(); @@ -797,7 +685,6 @@ bool QWidgetRepaintManager::syncAllowed() if (skipSync) // cannot compose due to widget textures being in use return false; } -#endif return true; } @@ -823,7 +710,9 @@ void QWidgetRepaintManager::paintAndFlush() const QRect tlwRect = tlw->data->crect; if (!updatesDisabled && store->size() != tlwRect.size()) { - if (hasStaticContents() && !store->size().isEmpty() ) { + QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration(); + if (hasStaticContents() && !store->size().isEmpty() + && integration->hasCapability(QPlatformIntegration::BackingStoreStaticContents)) { // Repaint existing dirty area and newly visible area. const QRect clipRect(QPoint(0, 0), store->size()); const QRegion staticRegion(staticContents(nullptr, clipRect)); @@ -910,24 +799,21 @@ void QWidgetRepaintManager::paintAndFlush() } dirtyWidgets.clear(); -#ifndef QT_NO_OPENGL // Find all render-to-texture child widgets (including self). // The search is cut at native widget boundaries, meaning that each native child widget // has its own list for the subtree below it. QTLWExtra *tlwExtra = tlw->d_func()->topData(); tlwExtra->widgetTextures.clear(); findAllTextureWidgetsRecursively(tlw, tlw); - qt_window_private(tlw->windowHandle())->compositing = false; // will get updated in flush() -#endif if (toClean.isEmpty()) { // 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 + // texture content changes. Check if we have such widgets in the special // dirty list. QVarLengthArray<QWidget *, 16> paintPending; - const int numPaintPending = dirtyRenderToTextureWidgets.count(); + const int numPaintPending = dirtyRenderToTextureWidgets.size(); paintPending.reserve(numPaintPending); for (int i = 0; i < numPaintPending; ++i) { QWidget *w = dirtyRenderToTextureWidgets.at(i); @@ -956,7 +842,6 @@ void QWidgetRepaintManager::paintAndFlush() return; } -#ifndef QT_NO_OPENGL for (const auto &tl : tlwExtra->widgetTextures) { for (int i = 0; i < tl->count(); ++i) { QWidget *w = static_cast<QWidget *>(tl->source(i)); @@ -970,10 +855,9 @@ void QWidgetRepaintManager::paintAndFlush() } } } - for (int i = 0; i < dirtyRenderToTextureWidgets.count(); ++i) + for (int i = 0; i < dirtyRenderToTextureWidgets.size(); ++i) resetWidget(dirtyRenderToTextureWidgets.at(i)); dirtyRenderToTextureWidgets.clear(); -#endif #if QT_CONFIG(graphicsview) if (tlw->d_func()->extra->proxyWidget) { @@ -1018,7 +902,8 @@ void QWidgetRepaintManager::paintAndFlush() // Paint the rest with composition. if (repaintAllWidgets || !dirtyCopy.isEmpty()) { - QWidgetPrivate::DrawWidgetFlags flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive; + QWidgetPrivate::DrawWidgetFlags flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive + | QWidgetPrivate::UseEffectRegionBounds; tlw->d_func()->drawWidget(store->paintDevice(), dirtyCopy, QPoint(), flags, nullptr, this); } @@ -1099,18 +984,16 @@ void QWidgetRepaintManager::flush() // Render-to-texture widgets are not in topLevelNeedsFlush so flush if we have not done it above. if (!flushed && !hasNeedsFlushWidgets) { -#ifndef QT_NO_OPENGL if (!tlw->d_func()->topData()->widgetTextures.empty()) { if (QPlatformTextureList *widgetTextures = widgetTexturesFor(tlw, tlw)) flush(tlw, QRegion(), widgetTextures); } -#endif } if (!hasNeedsFlushWidgets) return; - for (QWidget *w : qExchange(needsFlushWidgets, {})) { + for (QWidget *w : std::exchange(needsFlushWidgets, {})) { QWidgetPrivate *wd = w->d_func(); Q_ASSERT(wd->needsFlush); QPlatformTextureList *widgetTexturesForNative = wd->textureChildSeen ? widgetTexturesFor(tlw, w) : nullptr; @@ -1126,12 +1009,7 @@ void QWidgetRepaintManager::flush() */ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatformTextureList *widgetTextures) { -#ifdef QT_NO_OPENGL - Q_UNUSED(widgetTextures); - Q_ASSERT(!region.isEmpty()); -#else Q_ASSERT(!region.isEmpty() || widgetTextures); -#endif Q_ASSERT(widget); Q_ASSERT(tlw); @@ -1144,8 +1022,6 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf return; } - qCInfo(lcWidgetPainting) << "Flushing" << region << "of" << widget; - static bool fpsDebug = qEnvironmentVariableIntValue("QT_DEBUG_FPS"); if (fpsDebug) { if (!perfFrames++) @@ -1161,40 +1037,70 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf if (widget != tlw) offset += widget->mapTo(tlw, QPoint()); - QRegion effectiveRegion = region; -#ifndef QT_NO_OPENGL - const bool compositionWasActive = widget->d_func()->renderToTextureComposeActive; - if (!widgetTextures) { - widget->d_func()->renderToTextureComposeActive = false; - // Detect the case of falling back to the normal flush path when no - // render-to-texture widgets are visible anymore. We will force one - // last flush to go through the OpenGL-based composition to prevent - // artifacts. The next flush after this one will use the normal path. - if (compositionWasActive) + // Use a condition that tries to keep both QTBUG-108344 and QTBUG-113557 + // happy, i.e. support both (A) "native rhi-based child in a rhi-based + // toplevel" and (B) "native raster child in a rhi-based toplevel". + // + // If the tlw and the backingstore are RHI-based, then there are two cases + // to consider: + // + // (1) widget is not a native child, i.e. the QWindow for widget and tlw are + // the same, + // + // (2) widget is a native child which we now attempt to flush with tlw's + // backingstore to widget's native window. This is the interesting one. + // + // Using the condition tlw->usesRhiFlush on its own is insufficient since + // it fails to capture the case of a raster-based native child widget + // within tlw. (which must hit the non-rhi flush path) + // + // Extending the condition with tlw->windowHandle() == widget->windowHandle() + // would be logical but wrong, when it comes to (A) since flushing a + // RHI-based native child with a given 3D API using a RHI-based + // tlw/backingstore with the same 3D API needs to be supported still. (this + // happens when e.g. someone calls winId() on a QOpenGLWidget) + // + // Different 3D APIs do not need to be supported since we do not allow to + // do things like having a QQuickWidget with Vulkan and a QOpenGLWidget in + // the same toplevel, regardless of the widgets being native children or + // not. Hence comparing the surfaceType() instead. This satisfies both (A) + // and (B) given that an RHI-based toplevel cannot be RasterSurface. + // + if (tlw->d_func()->usesRhiFlush && tlw->windowHandle()->surfaceType() == widget->windowHandle()->surfaceType()) { + QRhi *rhi = store->handle()->rhi(); + qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget + << "with QRhi" << rhi + << "to window" << widget->windowHandle(); + if (!widgetTextures) widgetTextures = qt_dummy_platformTextureList; - } else { - widget->d_func()->renderToTextureComposeActive = true; - } - // When changing the composition status, make sure the dirty region covers - // the entire widget. Just having e.g. the shown/hidden render-to-texture - // widget's area marked as dirty is incorrect when changing flush paths. - if (compositionWasActive != widget->d_func()->renderToTextureComposeActive) - effectiveRegion = widget->rect(); - - // re-test since we may have been forced to this path via the dummy texture list above - if (widgetTextures) { - qt_window_private(tlw->windowHandle())->compositing = true; - widget->window()->d_func()->sendComposeStatus(widget->window(), false); + + QWidgetPrivate *widgetWindowPrivate = widget->window()->d_func(); + widgetWindowPrivate->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); - store->handle()->composeAndFlush(widget->windowHandle(), effectiveRegion, offset, - widgetTextures, translucentBackground); - widget->window()->d_func()->sendComposeStatus(widget->window(), true); - } else -#endif - store->flush(effectiveRegion, widget->windowHandle(), offset); + + QPlatformBackingStore::FlushResult flushResult; + flushResult = store->handle()->rhiFlush(widget->windowHandle(), + widget->devicePixelRatio(), + region, + offset, + widgetTextures, + translucentBackground); + widgetWindowPrivate->sendComposeStatus(widget->window(), true); + if (flushResult == QPlatformBackingStore::FlushFailedDueToLostDevice) { + qSendWindowChangeToTextureChildrenRecursively(widget->window(), + QEvent::WindowAboutToChangeInternal); + store->handle()->graphicsDeviceReportedLost(); + qSendWindowChangeToTextureChildrenRecursively(widget->window(), + QEvent::WindowChangeInternal); + widget->update(); + } + } else { + qCInfo(lcWidgetPainting) << "Flushing" << region << "of" << widget; + store->flush(region, widget->windowHandle(), offset); + } } // --------------------------------------------------------------------------- @@ -1238,11 +1144,7 @@ void QWidgetRepaintManager::removeStaticWidget(QWidget *widget) bool QWidgetRepaintManager::hasStaticContents() const { -#if defined(Q_OS_WIN) return !staticWidgets.isEmpty(); -#else - return !staticWidgets.isEmpty() && false; -#endif } /*! @@ -1264,7 +1166,7 @@ QRegion QWidgetRepaintManager::staticContents(QWidget *parent, const QRect &with return region; const bool clipToRect = !withinClipRect.isEmpty(); - const int count = staticWidgets.count(); + const int count = staticWidgets.size(); for (int i = 0; i < count; ++i) { QWidget *w = staticWidgets.at(i); QWidgetPrivate *wd = w->d_func(); @@ -1406,6 +1308,12 @@ void QWidgetPrivate::invalidateBackingStore_resizeHelper(const QPoint &oldPos, c } } +QRhi *QWidgetRepaintManager::rhi() const +{ + return store->handle()->rhi(); +} + QT_END_NAMESPACE #include "qwidgetrepaintmanager.moc" +#include "moc_qwidgetrepaintmanager_p.cpp" |