diff options
Diffstat (limited to 'src/widgets/kernel/qwidgetrepaintmanager.cpp')
-rw-r--r-- | src/widgets/kernel/qwidgetrepaintmanager.cpp | 96 |
1 files changed, 54 insertions, 42 deletions
diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp index 69ab7de1af..0dee380a91 100644 --- a/src/widgets/kernel/qwidgetrepaintmanager.cpp +++ b/src/widgets/kernel/qwidgetrepaintmanager.cpp @@ -1,7 +1,6 @@ // 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" #include "qwidgetrepaintmanager_p.h" @@ -49,7 +48,7 @@ public: } bool isLocked() const { - foreach (bool v, m_locked) { + for (const auto &[_, v] : m_locked.asKeyValueRange()) { if (v) return true; } @@ -126,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); @@ -302,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); @@ -340,9 +339,9 @@ void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime update // 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(); @@ -351,12 +350,16 @@ void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime update const qint64 elapsed = wd->lastComposeTime.elapsed(); if (elapsed <= qint64(1000.0f / refresh)) updateTime = UpdateLater; - } + } } 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: { @@ -539,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->texture(), 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) { @@ -565,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); } @@ -706,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)); @@ -799,7 +805,6 @@ void QWidgetRepaintManager::paintAndFlush() QTLWExtra *tlwExtra = tlw->d_func()->topData(); tlwExtra->widgetTextures.clear(); findAllTextureWidgetsRecursively(tlw, tlw); - qt_window_private(tlw->windowHandle())->compositing = false; // will get updated in flush() if (toClean.isEmpty()) { // Nothing to repaint. However renderToTexture widgets are handled @@ -808,7 +813,7 @@ void QWidgetRepaintManager::paintAndFlush() // 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); @@ -850,7 +855,7 @@ 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(); @@ -988,7 +993,7 @@ void QWidgetRepaintManager::flush() 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; @@ -1011,11 +1016,13 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen)) return; + QWindow *window = widget->windowHandle(); + // We should only be flushing to native widgets + Q_ASSERT(window); + // Foreign Windows do not have backing store content and must not be flushed - if (QWindow *widgetWindow = widget->windowHandle()) { - if (widgetWindow->type() == Qt::ForeignWindow) - return; - } + if (window->type() == Qt::ForeignWindow) + return; static bool fpsDebug = qEnvironmentVariableIntValue("QT_DEBUG_FPS"); if (fpsDebug) { @@ -1032,37 +1039,51 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf if (widget != tlw) offset += widget->mapTo(tlw, QPoint()); - if (widget->d_func()->usesRhiFlush) { - QRhi *rhi = store->handle()->rhi(); - qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget - << "with QRhi" << rhi - << "to window" << widget->windowHandle(); + // A widget uses RHI flush if itself, or one of its non-native children + // uses RHI for its drawing. If so, we composite the backing store raster + // data along with textures produced by the RHI widgets. + const bool flushWithRhi = widget->d_func()->usesRhiFlush; + + qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget + << "to" << window << (flushWithRhi ? "using RHI" : ""); + + // A widget uses RHI flush if itself, or one of its non-native children + // uses RHI for its drawing. If so, we composite the backing store raster + // data along with textures produced by the RHI widgets. + if (flushWithRhi) { if (!widgetTextures) widgetTextures = qt_dummy_platformTextureList; - qt_window_private(tlw->windowHandle())->compositing = true; - QWidgetPrivate *widgetWindowPrivate = widget->window()->d_func(); - widgetWindowPrivate->sendComposeStatus(widget->window(), false); + // We only need to let the widget sub-hierarchy that + // we are flushing know that we're compositing. + auto *widgetPrivate = QWidgetPrivate::get(widget); + widgetPrivate->sendComposeStatus(widget, 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); QPlatformBackingStore::FlushResult flushResult; - flushResult = store->handle()->rhiFlush(widget->windowHandle(), + flushResult = store->handle()->rhiFlush(window, widget->devicePixelRatio(), region, offset, widgetTextures, translucentBackground); - widgetWindowPrivate->sendComposeStatus(widget->window(), true); + + widgetPrivate->sendComposeStatus(widget, true); + if (flushResult == QPlatformBackingStore::FlushFailedDueToLostDevice) { - store->handle()->graphicsDeviceReportedLost(); + qSendWindowChangeToTextureChildrenRecursively(widget->window(), + QEvent::WindowAboutToChangeInternal); + store->handle()->graphicsDeviceReportedLost(window); + qSendWindowChangeToTextureChildrenRecursively(widget->window(), + QEvent::WindowChangeInternal); widget->update(); } } else { - qCInfo(lcWidgetPainting) << "Flushing" << region << "of" << widget; - store->flush(region, widget->windowHandle(), offset); + store->flush(region, window, offset); } } @@ -1107,11 +1128,7 @@ void QWidgetRepaintManager::removeStaticWidget(QWidget *widget) bool QWidgetRepaintManager::hasStaticContents() const { -#if defined(Q_OS_WIN) return !staticWidgets.isEmpty(); -#else - return !staticWidgets.isEmpty() && false; -#endif } /*! @@ -1133,7 +1150,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(); @@ -1275,11 +1292,6 @@ void QWidgetPrivate::invalidateBackingStore_resizeHelper(const QPoint &oldPos, c } } -QRhi *QWidgetRepaintManager::rhi() const -{ - return store->handle()->rhi(); -} - QT_END_NAMESPACE #include "qwidgetrepaintmanager.moc" |