[vlc-commits] [Git][videolan/vlc][master] 4 commits: qt: workaround for `QTBUG-97589` in `MatrixChangeObserverNode`

Steve Lhomme (@robUx4) gitlab at videolan.org
Mon Mar 17 11:42:11 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
01cf648c by Fatih Uzunoglu at 2025-03-17T11:28:47+00:00
qt: workaround for `QTBUG-97589` in `MatrixChangeObserverNode`

- - - - -
b6b39290 by Fatih Uzunoglu at 2025-03-17T11:28:47+00:00
qt: do not assert valid size in `CommitSize()` in `compositor_wayland_module.c`

So that we don't need to require adjusting the size before the scale.

- - - - -
1f49d541 by Fatih Uzunoglu at 2025-03-17T11:28:47+00:00
qt: update video surface on after rendering rather than update polish when applicable

Currently the new approach is only enabled for `CompositorWayland` and
`CompositorDirectComposition`.

- - - - -
bfd578ad by Fatih Uzunoglu at 2025-03-17T11:28:47+00:00
qt: get rid of WindowResizer

- Now that size change can be requested from the UI at most
  once per UI frame rendered, WindowResizer has become less
  relevant.
- !1978 (vout: Use a fair display lock and interrupt wait)
  already reduced the waiting time considerably.

Since the UI uses VSync (except CompositorX11), it should
be fine to have blocking stuff that only take couple of
milliseconds to execute.

- - - - -


10 changed files:

- modules/gui/qt/maininterface/compositor.cpp
- modules/gui/qt/maininterface/compositor.hpp
- modules/gui/qt/maininterface/compositor_dcomp.hpp
- modules/gui/qt/maininterface/compositor_wayland.hpp
- modules/gui/qt/maininterface/compositor_wayland_module.c
- modules/gui/qt/maininterface/videosurface.cpp
- modules/gui/qt/maininterface/videosurface.hpp
- modules/gui/qt/player/qml/PIPPlayer.qml
- modules/gui/qt/widgets/native/viewblockingrectangle.cpp
- modules/gui/qt/widgets/native/viewblockingrectangle.hpp


Changes:

=====================================
modules/gui/qt/maininterface/compositor.cpp
=====================================
@@ -202,12 +202,13 @@ void CompositorVideo::commonSetupVoutWindow(vlc_window_t* p_wnd, VoutDestroyCb d
     // These need to be connected here, since the compositor might not be ready when
     // these signals are emitted. VOut window might not be set, or worse, compositor's
     // internal preparations might not be completed yet:
+    constexpr auto connType = static_cast<Qt::ConnectionType>(Qt::UniqueConnection | Qt::DirectConnection);
     connect(m_videoSurfaceProvider.get(), &VideoSurfaceProvider::surfacePositionChanged,
-            this, &CompositorVideo::onSurfacePositionChanged, Qt::UniqueConnection);
+            this, &CompositorVideo::onSurfacePositionChanged, connType);
     connect(m_videoSurfaceProvider.get(), &VideoSurfaceProvider::surfaceSizeChanged,
-            this, &CompositorVideo::onSurfaceSizeChanged, Qt::UniqueConnection);
+            this, &CompositorVideo::onSurfaceSizeChanged, connType);
     connect(m_videoSurfaceProvider.get(), &VideoSurfaceProvider::surfaceScaleChanged,
-            this, &CompositorVideo::onSurfaceScaleChanged, Qt::UniqueConnection);
+            this, &CompositorVideo::onSurfaceScaleChanged, connType);
 }
 
 void CompositorVideo::windowDestroy()
@@ -268,7 +269,7 @@ bool CompositorVideo::commonGUICreateImpl(QWindow* window, CompositorVideo::Flag
     assert(m_mainCtx);
     assert(window);
 
-    m_videoSurfaceProvider = std::make_unique<VideoSurfaceProvider>();
+    m_videoSurfaceProvider = std::make_unique<VideoSurfaceProvider>(canDoThreadedSurfaceUpdates());
     m_mainCtx->setVideoSurfaceProvider(m_videoSurfaceProvider.get());
     const bool backendIsOpenVg = QQuickWindow::sceneGraphBackend() == QLatin1String("openvg");
     if (!backendIsOpenVg && (flags & CompositorVideo::CAN_SHOW_PIP) && var_InheritBool(m_intf, "qt-pip-mode"))


=====================================
modules/gui/qt/maininterface/compositor.hpp
=====================================
@@ -137,6 +137,9 @@ public:
     virtual void windowUnsetFullscreen();
     virtual void windowSetFullscreen(const char *id);
 
+    // The following method should return true if surface updates can be threaded:
+    virtual bool canDoThreadedSurfaceUpdates() const { return false; };
+
 protected:
     void commonSetupVoutWindow(vlc_window_t* p_wnd, VoutDestroyCb destroyCb);
     void commonWindowEnable();


=====================================
modules/gui/qt/maininterface/compositor_dcomp.hpp
=====================================
@@ -69,6 +69,8 @@ public:
 
     bool eventFilter(QObject *watched, QEvent *event) override;
 
+    bool canDoThreadedSurfaceUpdates() const override { return true; };
+
 private slots:
     void onSurfacePositionChanged(const QPointF& position) override;
     void onSurfaceSizeChanged(const QSizeF& size) override;


=====================================
modules/gui/qt/maininterface/compositor_wayland.hpp
=====================================
@@ -78,6 +78,8 @@ public:
     int windowEnable(const vlc_window_cfg_t *) override;
     void windowDisable() override;
 
+    bool canDoThreadedSurfaceUpdates() const override { return true; };
+
 protected slots:
     void onSurfacePositionChanged(const QPointF&) override;
     void onSurfaceSizeChanged(const QSizeF&) override;


=====================================
modules/gui/qt/maininterface/compositor_wayland_module.c
=====================================
@@ -103,19 +103,19 @@ static void SetSize(struct qtwayland_t* obj, size_t width, size_t height)
     sys->height = height;
 }
 
-static void CommitSize(struct qtwayland_t* obj)
+static bool CommitSize(struct qtwayland_t* obj)
 {
 #ifdef QT_HAS_WAYLAND_FRACTIONAL_SCALING
     assert(obj);
     const qtwayland_priv_t* const sys = (qtwayland_priv_t*)obj->p_sys;
     assert(sys);
     if (!sys->video_surface)
-        return;
+        return false;
     if (sys->viewport)
     {
         // Non-positive size (except (-1, -1) pair) causes protocol error:
-        assert((sys->width > 0 && sys->height > 0) ||
-               (sys->height == -1 && sys->width == -1));
+        if (unlikely(!((sys->width > 0 && sys->height > 0) || (sys->height == -1 && sys->width == -1))))
+            return false;
 
         // width and height here represent the final size, after scaling
         // is taken into account. The fractional scaling protocol is not
@@ -124,8 +124,11 @@ static void CommitSize(struct qtwayland_t* obj)
         // to determine the device pixel ratio.
         wp_viewport_set_destination(sys->viewport, sys->width, sys->height);
         wl_surface_commit(sys->video_surface);
+        return true;
     }
 #endif
+
+    return false;
 }
 
 static void SetScale(struct qtwayland_t* obj, double scale)


=====================================
modules/gui/qt/maininterface/videosurface.cpp
=====================================
@@ -16,7 +16,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 #include "videosurface.hpp"
-#include "maininterface/mainctx.hpp"
+
 #include <QSGRectangleNode>
 #include <QThreadPool>
 #include <vlc_window.h>
@@ -26,75 +26,16 @@
 #  include <QtGui/qpa/qplatformwindow.h>
 #endif
 
-WindowResizer::WindowResizer(vlc_window_t* window):
-    m_requestedWidth(0),
-    m_requestedHeight(0),
-    m_currentWidth(0),
-    m_currentHeight(0),
-    m_running(false),
-    m_voutWindow(window)
-{
-    vlc_mutex_init(&m_lock);
-    vlc_cond_init(&m_cond);
-    setAutoDelete(false);
-}
-
-WindowResizer::~WindowResizer()
-{
-}
-
-void WindowResizer::run()
-{
-    vlc_mutex_lock(&m_lock);
-    while (m_requestedWidth != m_currentWidth ||
-           m_requestedHeight != m_currentHeight)
-    {
-        unsigned width = m_requestedWidth;
-        unsigned height = m_requestedHeight;
-        vlc_mutex_unlock(&m_lock);
-
-        vlc_window_ReportSize(m_voutWindow, width, height);
-
-        vlc_mutex_lock(&m_lock);
-        m_currentWidth = width;
-        m_currentHeight = height;
-    }
-    m_running = false;
-    vlc_cond_signal(&m_cond);
-    vlc_mutex_unlock(&m_lock);
-}
-
-void WindowResizer::reportSize(float width, float height)
-{
-    if (width < 0 || height < 0)
-        return;
-
-    vlc_mutex_locker locker(&m_lock);
-    m_requestedWidth = static_cast<unsigned>(width);
-    m_requestedHeight = static_cast<unsigned>(height);
-    if (m_running == false)
-    {
-        m_running = true;
-        QThreadPool::globalInstance()->start(this);
-    }
-}
-
-/* Must called under m_voutlock before deletion */
-void WindowResizer::waitForCompletion()
-{
-    vlc_mutex_locker locker(&m_lock);
-    while (m_running)
-        vlc_cond_wait(&m_cond, &m_lock);
-}
+#include "maininterface/mainctx.hpp"
 
-VideoSurfaceProvider::VideoSurfaceProvider(QObject* parent)
+VideoSurfaceProvider::VideoSurfaceProvider(bool threadedSurfaceUpdates, QObject* parent)
     : QObject(parent)
+    , m_threadedSurfaceUpdates(threadedSurfaceUpdates)
 {
 }
 
 bool VideoSurfaceProvider::isEnabled()
 {
-    QMutexLocker lock(&m_voutlock);
     return m_voutWindow != nullptr;
 }
 
@@ -106,27 +47,14 @@ bool VideoSurfaceProvider::hasVideoEmbed() const
 void VideoSurfaceProvider::enable(vlc_window_t* voutWindow)
 {
     assert(voutWindow);
-    {
-        QMutexLocker lock(&m_voutlock);
-        m_voutWindow = voutWindow;
-        m_resizer = new (std::nothrow) WindowResizer(voutWindow);
-    }
+    m_voutWindow = voutWindow;
     emit videoEnabledChanged(true);
 }
 
 void VideoSurfaceProvider::disable()
 {
     setVideoEmbed(false);
-    {
-        QMutexLocker lock(&m_voutlock);
-        if (m_resizer != nullptr)
-        {
-            m_resizer->waitForCompletion();
-            delete m_resizer;
-            m_resizer = nullptr;
-        }
-        m_voutWindow = nullptr;
-    }
+    m_voutWindow = nullptr;
     emit videoEnabledChanged(false);
 }
 
@@ -138,44 +66,36 @@ void VideoSurfaceProvider::setVideoEmbed(bool embed)
 
 void VideoSurfaceProvider::onWindowClosed()
 {
-    QMutexLocker lock(&m_voutlock);
-    if (m_resizer != nullptr)
-        m_resizer->waitForCompletion();
     if (m_voutWindow)
         vlc_window_ReportClose(m_voutWindow);
 }
 
 void VideoSurfaceProvider::onMousePressed(int vlcButton)
 {
-    QMutexLocker lock(&m_voutlock);
     if (m_voutWindow)
         vlc_window_ReportMousePressed(m_voutWindow, vlcButton);
 }
 
 void VideoSurfaceProvider::onMouseReleased(int vlcButton)
 {
-    QMutexLocker lock(&m_voutlock);
     if (m_voutWindow)
         vlc_window_ReportMouseReleased(m_voutWindow, vlcButton);
 }
 
 void VideoSurfaceProvider::onMouseDoubleClick(int vlcButton)
 {
-    QMutexLocker lock(&m_voutlock);
     if (m_voutWindow)
         vlc_window_ReportMouseDoubleClick(m_voutWindow, vlcButton);
 }
 
 void VideoSurfaceProvider::onMouseMoved(float x, float y)
 {
-    QMutexLocker lock(&m_voutlock);
     if (m_voutWindow)
         vlc_window_ReportMouseMoved(m_voutWindow, x, y);
 }
 
 void VideoSurfaceProvider::onMouseWheeled(int vlcButton)
 {
-    QMutexLocker lock(&m_voutlock);
     if (m_voutWindow)
         vlc_window_ReportKeyPress(m_voutWindow, vlcButton);
 }
@@ -184,19 +104,14 @@ void VideoSurfaceProvider::onKeyPressed(int key, Qt::KeyboardModifiers modifiers
 {
     QKeyEvent event(QEvent::KeyPress, key, modifiers);
     int vlckey = qtEventToVLCKey(&event);
-    QMutexLocker lock(&m_voutlock);
     if (m_voutWindow)
         vlc_window_ReportKeyPress(m_voutWindow, vlckey);
-
 }
 
 void VideoSurfaceProvider::onSurfaceSizeChanged(QSizeF size)
 {
     emit surfaceSizeChanged(size);
-    QMutexLocker lock(&m_voutlock);
-    if (m_resizer)
-        m_resizer->reportSize(std::ceil(size.width()), std::ceil(size.height()));
-    else if (m_voutWindow)
+    if (m_voutWindow)
         vlc_window_ReportSize(m_voutWindow, std::ceil(size.width()), std::ceil(size.height()));
 }
 
@@ -207,17 +122,6 @@ VideoSurface::VideoSurface(QQuickItem* parent)
     setAcceptHoverEvents(true);
     setAcceptedMouseButtons(Qt::AllButtons);
     setFlag(ItemAcceptsInputMethod, true);
-
-    {
-        connect(this, &QQuickItem::widthChanged, this, &VideoSurface::updateSurfaceSize);
-        connect(this, &QQuickItem::heightChanged, this, &VideoSurface::updateSurfaceSize);
-
-        connect(this, &QQuickItem::xChanged, this, &VideoSurface::updateSurfacePosition);
-        connect(this, &QQuickItem::yChanged, this, &VideoSurface::updateSurfacePosition);
-
-        // This is for the case when the item's parent-relative position stays the same, but ancestors change position:
-        connect(this, &ViewBlockingRectangle::scenePositionHasChanged, this, &VideoSurface::updateSurfacePosition, Qt::QueuedConnection);
-    }
 }
 
 int VideoSurface::qtMouseButton2VLC( Qt::MouseButton qtButton )
@@ -321,30 +225,50 @@ void VideoSurface::setCursorShape(Qt::CursorShape shape)
     setCursor(shape);
 }
 
-void VideoSurface::updatePolish()
+void VideoSurface::synchronize()
 {
-    QQuickItem::updatePolish();
+    // This may be called from the rendering thread, not necessarily
+    // during synchronization (GUI thread is not blocked). Try to
+    // be very careful.
 
-    assert(window());
+    QSizeF size;
+    QPointF position;
 
-    if (m_sizeDirty && !size().isEmpty())
+    if (QThread::currentThread() == thread())
     {
-        emit surfaceSizeChanged(size() * window()->effectiveDevicePixelRatio());
-        m_sizeDirty = false;
+        // Item's thread (GUI thread):
+        size = this->size();
+        position = this->mapToScene(QPointF(0,0));
+    }
+    else
+    {
+        // Render thread:
+        size = renderSize();
+        position = renderPosition();
     }
 
-    if (m_positionDirty)
+    if (m_oldRenderSize != size || m_dprDirty)
     {
-        QPointF scenePosition = this->mapToScene(QPointF(0,0));
+        if (!size.isEmpty())
+        {
+            emit surfaceSizeChanged(size * m_dpr);
+            m_oldRenderSize = size;
+        }
+    }
 
-        emit surfacePositionChanged(scenePosition * window()->effectiveDevicePixelRatio());
-        m_positionDirty = false;
+    if (m_oldRenderPosition != position || m_dprDirty)
+    {
+        if (position.x() >= 0.0 && position.y() >= 0.0)
+        {
+            emit surfacePositionChanged(position * m_dpr); // render position is relative to scene/viewport
+            m_oldRenderPosition = position;
+        }
     }
 
-    if (m_scaleDirty)
+    if (m_dprDirty)
     {
-        emit surfaceScaleChanged(window()->effectiveDevicePixelRatio());
-        m_scaleDirty = false;
+        emit surfaceScaleChanged(m_dpr);
+        m_dprDirty = false;
     }
 }
 
@@ -352,37 +276,14 @@ void VideoSurface::itemChange(ItemChange change, const ItemChangeData &value)
 {
     if (change == ItemDevicePixelRatioHasChanged || change == ItemSceneChange)
     {
-        updateSurfaceScale();
+        m_dprChanged = true;
+        // Request update, so that `updatePaintNode()` gets called which updates the DPR for `::synchronize()`:
+        update();
     }
 
     QQuickItem::itemChange(change, value);
 }
 
-void VideoSurface::updateSurfacePosition()
-{
-    m_positionDirty = true;
-    polish();
-}
-
-void VideoSurface::updateSurfaceSize()
-{
-    m_sizeDirty = true;
-    polish();
-}
-
-void VideoSurface::updateSurfaceScale()
-{
-    m_scaleDirty = true;
-    polish();
-}
-
-void VideoSurface::updateSurface()
-{
-    updateSurfacePosition();
-    updateSurfaceSize();
-    updateSurfaceScale();
-}
-
 void VideoSurface::setVideoSurfaceProvider(VideoSurfaceProvider *newVideoSurfaceProvider)
 {
     if (m_provider == newVideoSurfaceProvider)
@@ -404,15 +305,13 @@ void VideoSurface::setVideoSurfaceProvider(VideoSurfaceProvider *newVideoSurface
         connect(this, &VideoSurface::mouseDblClicked, m_provider, &VideoSurfaceProvider::onMouseDoubleClick);
         connect(this, &VideoSurface::mouseReleased, m_provider, &VideoSurfaceProvider::onMouseReleased);
         connect(this, &VideoSurface::keyPressed, m_provider, &VideoSurfaceProvider::onKeyPressed);
-        connect(this, &VideoSurface::surfaceSizeChanged, m_provider, &VideoSurfaceProvider::onSurfaceSizeChanged);
-        connect(this, &VideoSurface::surfacePositionChanged, m_provider, &VideoSurfaceProvider::surfacePositionChanged);
-        connect(this, &VideoSurface::surfaceScaleChanged, m_provider, &VideoSurfaceProvider::surfaceScaleChanged);
+        connect(this, &VideoSurface::surfaceSizeChanged, m_provider, &VideoSurfaceProvider::onSurfaceSizeChanged, Qt::DirectConnection);
+        connect(this, &VideoSurface::surfacePositionChanged, m_provider, &VideoSurfaceProvider::surfacePositionChanged, Qt::DirectConnection);
+        connect(this, &VideoSurface::surfaceScaleChanged, m_provider, &VideoSurfaceProvider::surfaceScaleChanged, Qt::DirectConnection);
 
         connect(&m_wheelEventConverter, &WheelToVLCConverter::vlcWheelKey, m_provider, &VideoSurfaceProvider::onMouseWheeled);
-        connect(m_provider, &VideoSurfaceProvider::videoEnabledChanged, this, &VideoSurface::updateSurface);
 
         setFlag(ItemHasContents, true);
-        updateSurface(); // Polish is queued anyway, updatePolish() should be called when the initial size is set.
     }
     else
     {
@@ -421,3 +320,48 @@ void VideoSurface::setVideoSurfaceProvider(VideoSurfaceProvider *newVideoSurface
 
     emit videoSurfaceProviderChanged();
 }
+
+QSGNode *VideoSurface::updatePaintNode(QSGNode *node, UpdatePaintNodeData *data)
+{
+    // This is called from the render thread, but during synchronization.
+    // So the GUI thread is blocked here. This makes it safer to access the window
+    // to get the effective DPR, rather than doing it outside the synchronization
+    // stage.
+
+    const auto w = window();
+    assert (w);
+
+    if (Q_UNLIKELY(!m_provider))
+        return node;
+
+    if (w != m_oldWindow)
+    {
+        if (m_oldWindow)
+            disconnect(m_oldWindow, &QQuickWindow::afterRendering, this, &VideoSurface::synchronize);
+
+        m_oldWindow = w;
+
+        if (w)
+        {
+            // This is constant:
+            if (m_provider->supportsThreadedSurfaceUpdates())
+            {
+                // Synchronize just before swapping the frame for better synchronization:
+                connect(w, &QQuickWindow::afterRendering, this, &VideoSurface::synchronize, Qt::DirectConnection);
+            }
+            else
+            {
+                connect(w, &QQuickWindow::afterAnimating, this, &VideoSurface::synchronize);
+            }
+        }
+    }
+
+    if (m_dprChanged)
+    {
+        m_dpr = w->effectiveDevicePixelRatio();
+        m_dprDirty = true;
+        m_dprChanged = false;
+    }
+
+    return ViewBlockingRectangle::updatePaintNode(node, data);
+}


=====================================
modules/gui/qt/maininterface/videosurface.hpp
=====================================
@@ -35,33 +35,11 @@ Q_MOC_INCLUDE( "maininterface/mainctx.hpp")
 
 class MainCtx;
 
-class WindowResizer :
-    public QRunnable
-{
-public:
-    WindowResizer(vlc_window_t* window);
-    virtual ~WindowResizer();
-
-    void run() override;
-    void reportSize(float width, float height);
-    void waitForCompletion();
-
-private:
-    vlc_mutex_t m_lock;
-    vlc_cond_t m_cond;
-    unsigned m_requestedWidth;
-    unsigned m_requestedHeight;
-    unsigned m_currentWidth;
-    unsigned m_currentHeight;
-    bool m_running;
-    vlc_window_t* m_voutWindow;
-};
-
 class VideoSurfaceProvider : public QObject
 {
     Q_OBJECT
 public:
-    VideoSurfaceProvider(QObject* parent = nullptr);
+    VideoSurfaceProvider(bool threadedSurfaceUpdates = false, QObject* parent = nullptr);
     virtual ~VideoSurfaceProvider() {}
 
     void enable(vlc_window_t* voutWindow);
@@ -71,6 +49,8 @@ public:
     void setVideoEmbed(bool embed);
     bool hasVideoEmbed() const;
 
+    bool supportsThreadedSurfaceUpdates() const { return m_threadedSurfaceUpdates; };
+
 signals:
     void ctxChanged(MainCtx*);
     bool videoEnabledChanged(bool);
@@ -90,10 +70,9 @@ public slots:
     void onSurfaceSizeChanged(QSizeF size);
 
 protected:
-    QMutex m_voutlock;
     vlc_window_t* m_voutWindow = nullptr;
-    WindowResizer * m_resizer = nullptr;
     bool m_videoEmbed = false;
+    bool m_threadedSurfaceUpdates = false;
 };
 
 
@@ -110,6 +89,8 @@ public:
     void setVideoSurfaceProvider(VideoSurfaceProvider *newVideoSurfaceProvider);
 
 protected:
+    QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
+
     int qtMouseButton2VLC( Qt::MouseButton qtButton );
 
     void mousePressEvent(QMouseEvent *event) override;
@@ -125,10 +106,7 @@ protected:
     Qt::CursorShape getCursorShape() const;
     void setCursorShape(Qt::CursorShape);
 
-    void updatePolish() override;
-
     void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) override;
-
 signals:
     void surfaceSizeChanged(QSizeF);
     void surfacePositionChanged(QPointF);
@@ -143,10 +121,7 @@ signals:
     void videoSurfaceProviderChanged();
 
 protected slots:
-    void updateSurfacePosition();
-    void updateSurfaceSize();
-    void updateSurfaceScale();
-    void updateSurface();
+    void synchronize();
 
 private:
     QPointF m_oldHoverPos;
@@ -155,9 +130,22 @@ private:
 
     QPointer<VideoSurfaceProvider> m_provider;
 
-    bool m_sizeDirty = false;
-    bool m_positionDirty = false;
-    bool m_scaleDirty = false;
+    QPointer<QQuickWindow> m_oldWindow;
+
+    // This is updated and read from different threads, but during synchronization stage so explicit synchronization
+    // such as atomic boolean or locking is not necessary:
+    bool m_dprChanged = false; // itemChange() <-> updatePaintNode() (different threads, but GUI thread is blocked)
+
+    // These are updated and read from either the item/GUI thread or the render thread:
+    QSizeF m_oldRenderSize;
+    QPointF m_oldRenderPosition {-1., -1.};
+
+    // m_dpr and m_dprDirty are updated in render thread when the GUI thread is blocked (updatePaintNode()).
+    // m_dprDirty may be updated in GUI thread when threaded updates is not possible. Since m_dprDirty can
+    // not be updated both in render thread and GUI thread concurrently (as GUI thread is blocked during
+    // updatePaintNode() call), data synchronization should not be necessary:
+    qreal m_dpr = 1.0;
+    bool m_dprDirty = false;
 };
 
 #endif // VIDEOSURFACE_HPP


=====================================
modules/gui/qt/player/qml/PIPPlayer.qml
=====================================
@@ -30,10 +30,6 @@ T.Control {
     width: Math.round(VLCStyle.dp(320, VLCStyle.scale))
     height: Math.round(VLCStyle.dp(180, VLCStyle.scale))
 
-    //VideoSurface x,y won't update
-    onXChanged: videoSurface.updateSurfacePosition()
-    onYChanged: videoSurface.updateSurfacePosition()
-
     objectName: "pip window"
 
     property real dragXMin: 0


=====================================
modules/gui/qt/widgets/native/viewblockingrectangle.cpp
=====================================
@@ -122,12 +122,19 @@ QSGNode *ViewBlockingRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNod
 
     if (!oldNode)
     {
-        const auto observerNode = new MatrixChangeObserverNode([p = QPointer(this)]() {
+        const auto observerNode = new MatrixChangeObserverNode([p = QPointer(this)](const QMatrix4x4& matrix) {
             if (Q_LIKELY(p))
+            {
+                p->m_renderPosition = {matrix.row(0)[3], // Viewport/scene X
+                                       matrix.row(1)[3]}; // Viewport/scene y
                 emit p->scenePositionHasChanged();
+            }
         });
         observerNode->setFlag(QSGNode::OwnedByParent);
 
+        // Initial position:
+        m_renderPosition = mapToScene(QPointF(0,0));
+
         if (softwareMode)
         {
             softwareRenderNode = new SoftwareRenderNode;
@@ -157,6 +164,8 @@ QSGNode *ViewBlockingRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNod
 
     const auto rect = boundingRect();
 
+    m_renderSize = rect.size();
+
     if (softwareMode)
     {
         softwareRenderNode->setRect(rect);
@@ -185,3 +194,13 @@ QSGNode *ViewBlockingRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNod
         return rectangleNode;
     }
 }
+
+QSizeF ViewBlockingRectangle::renderSize() const
+{
+    return m_renderSize;
+}
+
+QPointF ViewBlockingRectangle::renderPosition() const
+{
+    return m_renderPosition;
+}


=====================================
modules/gui/qt/widgets/native/viewblockingrectangle.hpp
=====================================
@@ -29,27 +29,35 @@
 class MatrixChangeObserverNode : public QSGRenderNode
 {
 public:
-    explicit MatrixChangeObserverNode(const std::function<void()>& callback)
+    explicit MatrixChangeObserverNode(const std::function<void(const QMatrix4x4&)>& callback)
         : m_callback(callback) { }
 
-    void render(const RenderState *) override
+    // Use prepare(), because matrix() returns dangling pointer when render() is called from Qt 6.2 to 6.5 (QTBUG-97589):
+    void prepare() override
     {
+        QSGRenderNode::prepare(); // The documentation says that the default implementation is empty, but still call it just in case.
+
         assert(matrix());
         const QMatrix4x4 m = *matrix(); // matrix() is the combined matrix here
         if (m_lastCombinedMatrix != m)
         {
-            m_callback();
+            m_callback(m);
             m_lastCombinedMatrix = m;
         }
     }
 
+    void render(const RenderState *) override
+    {
+        // We do not render anything in this node.
+    }
+
     RenderingFlags flags() const override
     {
         // Enable all optimizations, as we are not actually rendering anything in this node:
         return static_cast<RenderingFlags>(BoundedRectRendering | DepthAwareRendering | OpaqueRendering | NoExternalRendering);
     }
 private:
-    std::function<void()> m_callback;
+    std::function<void(const QMatrix4x4& newMatrix)> m_callback;
     QMatrix4x4 m_lastCombinedMatrix;
 };
 
@@ -65,10 +73,20 @@ public:
 protected:
     QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
 
+    // For now these are protected, but can be made public if necessary:
+    // These methods should only be called from the rendering thread.
+    QSizeF renderSize() const;
+    QPointF renderPosition() const;
+
 private:
     QColor m_color;
     bool m_windowChanged = false;
 
+    // Although these members belong to the class instance's thread, they
+    // are updated in the rendering thread:
+    QSizeF m_renderSize;
+    QPointF m_renderPosition {-1., -1.};
+
 signals:
     // NOTE: `scenePositionHasChanged()` signal is emitted from the render thread,
     //       and NOT during synchronization (meaning, GUI thread is not blocked):



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/fa612b4075ca572e874e70dd579bcc479c6d9f55...bfd578ad7d546f3e0574eff13f1d0c7464358347

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/fa612b4075ca572e874e70dd579bcc479c6d9f55...bfd578ad7d546f3e0574eff13f1d0c7464358347
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list