diff options
Diffstat (limited to 'src/widgets/kernel/qwidgetrepaintmanager.cpp')
-rw-r--r-- | src/widgets/kernel/qwidgetrepaintmanager.cpp | 104 |
1 files changed, 41 insertions, 63 deletions
diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp index 3cc043ca42..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; } @@ -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: { @@ -707,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)); @@ -800,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 @@ -1012,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) { @@ -1033,70 +1039,51 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf if (widget != tlw) offset += widget->mapTo(tlw, QPoint()); - // 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(); + // 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) { qSendWindowChangeToTextureChildrenRecursively(widget->window(), QEvent::WindowAboutToChangeInternal); - store->handle()->graphicsDeviceReportedLost(); + 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); } } @@ -1141,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 } /*! @@ -1309,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" |