Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
a40b40ce by Fatih Uzunoglu at 2026-02-08T11:15:55+00:00
qt: add property `normalizedTextureSubRect` to `TextureProviderObserver`

- - - - -
2ed3cbd3 by Fatih Uzunoglu at 2026-02-08T11:15:55+00:00
qml: consider sub-rect changes on scheduling update in `DualKawaseBlur`

`onNextTextureChange` was meant for effective change, not necessarily
if the texture actually changes. This means that if both the previous
and the next textures the same but differ in sub-rect (such as, being
different parts of the atlas), an update should be scheduled.

The parameter is renamed to `onNextEffectiveTextureChange` to reflect
the changed behavior.

This was not considered before, because the use case in `Player.qml`
requests the texture to be mipmapped, which means that the texture
would not be placed in the atlas and normal rect would remain
(0.0, 0.0, 1.0, 1.0) while the actual texture changes. The problem
is that there is no guarantee that the texture is going to be mip-
mapped, even if explicitly requested.

This fixes background blur effect not updated on track change in
the player page.

- - - - -
416fe28d by Fatih Uzunoglu at 2026-02-08T11:15:55+00:00
qt: introduce `notifyAllChanges` property in `TextureProviderObserver`

When `true` (by default `false`), all properties are notified on change.

This property may be set to `true` when the source is a static texture.
It is strongly discouraged to set it `true` for rapidly changing cases,
such as when the source is a layer, since if the connections are queued,
they can easily backlog when the texture changes rapidly (such as with
resize).

- - - - -
33a52701 by Fatih Uzunoglu at 2026-02-08T11:15:55+00:00
qml: use `notifyAllChanges` of source texture provider in `DualKawaseBlur`

We can make use of `notifyAllChanges` if `live` is `false`, and get rid of
the additional `Connections`.

- - - - -
49622710 by Fatih Uzunoglu at 2026-02-08T11:15:55+00:00
qt: do not notify comparison key change by default in `TextureProviderObserver`

Although it is not as rapid as size change (layer resize case), comparison key
may still change often. Now that we have a property to enable notify all
changes, we can make comparison key changes not notified by default.

- - - - -


3 changed files:

- modules/gui/qt/util/textureproviderobserver.cpp
- modules/gui/qt/util/textureproviderobserver.hpp
- modules/gui/qt/widgets/qml/DualKawaseBlur.qml


Changes:

=====================================
modules/gui/qt/util/textureproviderobserver.cpp
=====================================
@@ -157,6 +157,11 @@ qint64 TextureProviderObserver::comparisonKey() const
     return m_comparisonKey.load(std::memory_order_acquire);
 }
 
+QRectF TextureProviderObserver::normalizedTextureSubRect() const
+{
+    return m_normalizedTextureSubRect.load(std::memory_order_acquire);
+}
+
 void TextureProviderObserver::updateProperties()
 {
     // This is likely called in the rendering thread.
@@ -168,6 +173,8 @@ void TextureProviderObserver::updateProperties()
 
     if (m_provider)
     {
+        const bool notifyAllChanges = m_notifyAllChanges.load(memoryOrder);
+
         if (const auto texture = m_provider->texture())
         {
             {
@@ -175,30 +182,75 @@ void TextureProviderObserver::updateProperties()
 
                 // SG texture size:
                 const auto textureSize = texture->textureSize();
-                m_textureSize.store(textureSize, memoryOrder);
+                if (notifyAllChanges)
+                {
+                    if (m_textureSize.exchange(textureSize, memoryOrder) != 
textureSize)
+                        emit textureSizeChanged(textureSize);
+                }
+                else
+                {
+                    m_textureSize.store(textureSize, memoryOrder);
+                }
 
                 {
                     // Native texture size
 
                     const auto legacyUpdateNativeTextureSize = [&]() {
                         const auto ntsr = texture->normalizedTextureSubRect();
-                        
m_nativeTextureSize.store({static_cast<int>(textureSize.width() / ntsr.width()),
-                                                   
static_cast<int>(textureSize.height() / ntsr.height())},
-                                                  memoryOrder);
+                        const QSize size = 
{static_cast<int>(textureSize.width() / ntsr.width()),
+                                            
static_cast<int>(textureSize.height() / ntsr.height())};
+
+                        if (notifyAllChanges)
+                        {
+                            if (m_nativeTextureSize.exchange(size, 
memoryOrder) != size)
+                                emit nativeTextureSizeChanged(size);
+                        }
+                        else
+                        {
+                            m_nativeTextureSize.store(size, memoryOrder);
+                        }
                     };
 
 #ifdef RHI_HEADER_AVAILABLE
                     const QRhiTexture* const rhiTexture = 
texture->rhiTexture();
                     if (Q_LIKELY(rhiTexture))
-                        m_nativeTextureSize.store(rhiTexture->pixelSize(), 
memoryOrder);
+                    {
+                        const QSize size = rhiTexture->pixelSize();
+                        if (notifyAllChanges)
+                        {
+                            if (m_nativeTextureSize.exchange(size, 
memoryOrder) != size)
+                                emit nativeTextureSizeChanged(size);
+                        }
+                        else
+                        {
+                            m_nativeTextureSize.store(size, memoryOrder);
+                        }
+                    }
                     else
+                    {
                         legacyUpdateNativeTextureSize();
+                    }
 #else
                     legacyUpdateNativeTextureSize();
 #endif
                 }
             }
 
+            {
+                // Normal rect
+                const QRectF& normalizedTextureSubRect = 
texture->normalizedTextureSubRect();
+
+                if (notifyAllChanges)
+                {
+                    if 
(m_normalizedTextureSubRect.exchange(normalizedTextureSubRect, memoryOrder) != 
normalizedTextureSubRect)
+                        emit 
normalizedTextureSubRectChanged(normalizedTextureSubRect);
+                }
+                else
+                {
+                    m_normalizedTextureSubRect.store(normalizedTextureSubRect, 
memoryOrder);
+                }
+            }
+
             {
                 // Alpha channel
                 const bool hasAlphaChannel = texture->hasAlphaChannel();
@@ -230,8 +282,16 @@ void TextureProviderObserver::updateProperties()
                 // Comparison key
                 const qint64 comparisonKey = texture->comparisonKey();
 
-                if (m_comparisonKey.exchange(comparisonKey, memoryOrder) != 
comparisonKey)
-                    emit comparisonKeyChanged(comparisonKey);
+                if (notifyAllChanges)
+                {
+                    if (m_comparisonKey.exchange(comparisonKey, memoryOrder) 
!= comparisonKey) {
+                        emit comparisonKeyChanged(comparisonKey);
+                    }
+                }
+                else
+                {
+                    m_comparisonKey.store(comparisonKey, memoryOrder);
+                }
             }
 
             return;
@@ -243,8 +303,14 @@ void TextureProviderObserver::updateProperties()
 
 void TextureProviderObserver::resetProperties(std::memory_order memoryOrder)
 {
-    m_textureSize.store({}, memoryOrder);
-    m_nativeTextureSize.store({}, memoryOrder);
+    if (m_textureSize.exchange({}, memoryOrder) != QSize())
+        emit textureSizeChanged({});
+
+    if (m_nativeTextureSize.exchange({}, memoryOrder) != QSize())
+        emit nativeTextureSizeChanged({});
+
+    if (m_normalizedTextureSubRect.exchange({}, memoryOrder) != QRectF())
+        emit normalizedTextureSubRectChanged({});
 
     if (m_hasAlphaChannel.exchange(false, memoryOrder))
         emit hasAlphaChannelChanged(false);


=====================================
modules/gui/qt/util/textureproviderobserver.hpp
=====================================
@@ -47,13 +47,16 @@ class TextureProviderObserver : public QObject
     //          to not conflict with the updates, if the properties must 
reflect the immediately up-to-date
     //          texture and the properties change each frame, as otherwise it 
might end up in a
     //          "forever chase"), so by the time the sampling is done the 
properties should be consistent.
-    // NOTE: These properties do not provide notify signal, dynamic textures 
such as layer may
+    // NOTE: By default these properties are not notified, as dynamic textures 
such as layer may
     //       change rapidly (even though throttled by v-sync in the rendering 
thread), and if
     //       such signal is connected to a receiver that lives in the GUI 
thread, the queued
     //       invocations can easily backlog. Similar to the high precision 
timer, we moved
     //       away from event based approach in favor of sampling based 
approach here.
-    Q_PROPERTY(QSize textureSize READ textureSize FINAL) // Scene graph 
texture size
-    Q_PROPERTY(QSize nativeTextureSize READ nativeTextureSize FINAL) // Native 
texture size (e.g. for atlas textures, the atlas size)
+    Q_PROPERTY(bool notifyAllChanges MEMBER m_notifyAllChanges NOTIFY 
notifyAllChangesChanged FINAL)
+    Q_PROPERTY(QSize textureSize READ textureSize NOTIFY textureSizeChanged 
FINAL) // Scene graph texture size
+    Q_PROPERTY(QSize nativeTextureSize READ nativeTextureSize NOTIFY 
nativeTextureSizeChanged FINAL) // Native texture size (e.g. for atlas 
textures, the atlas size)
+    Q_PROPERTY(QRectF normalizedTextureSubRect READ normalizedTextureSubRect 
NOTIFY normalizedTextureSubRectChanged FINAL)
+    Q_PROPERTY(qint64 comparisonKey READ comparisonKey NOTIFY 
comparisonKeyChanged FINAL)
 
     // NOTE: Since it is not expected that these properties change rapidly, 
they have notify signals.
     //       These signals may be emitted in the rendering thread, thus if the 
connection is auto
@@ -62,7 +65,6 @@ class TextureProviderObserver : public QObject
     Q_PROPERTY(bool hasMipmaps READ hasMipmaps NOTIFY hasMipmapsChanged FINAL)
     Q_PROPERTY(bool isAtlasTexture READ isAtlasTexture NOTIFY 
isAtlasTextureChanged FINAL)
     Q_PROPERTY(bool isValid READ isValid NOTIFY isValidChanged FINAL) // 
whether a texture is provided or not
-    Q_PROPERTY(qint64 comparisonKey READ comparisonKey NOTIFY 
comparisonKeyChanged FINAL)
 
 public:
     explicit TextureProviderObserver(QObject *parent = nullptr);
@@ -75,13 +77,18 @@ public:
     QSize textureSize() const;
     QSize nativeTextureSize() const;
     qint64 comparisonKey() const;
+    QRectF normalizedTextureSubRect() const;
     bool hasAlphaChannel() const;
     bool hasMipmaps() const;
     bool isAtlasTexture() const;
     bool isValid() const;
 
 signals:
+    void notifyAllChangesChanged();
     void sourceChanged();
+    void textureSizeChanged(const QSize&);
+    void nativeTextureSizeChanged(const QSize&);
+    void normalizedTextureSubRectChanged(const QRectF&);
     void hasAlphaChannelChanged(bool);
     void hasMipmapsChanged(bool);
     void isAtlasTextureChanged(bool);
@@ -105,9 +112,11 @@ private:
     // where the SG synchronization would not be blocking the (GUI) thread 
where this
     // observer lives.
 
+    std::atomic<bool> m_notifyAllChanges = false;
     std::atomic<QSize> m_textureSize {{}}; // invalid by default
     std::atomic<QSize> m_nativeTextureSize {{}}; // invalid by default
     std::atomic<qint64> m_comparisonKey {-1};
+    std::atomic<QRectF> m_normalizedTextureSubRect {{}}; // invalid by default
 
     std::atomic<bool> m_hasAlphaChannel = false;
     std::atomic<bool> m_hasMipmaps = false;


=====================================
modules/gui/qt/widgets/qml/DualKawaseBlur.qml
=====================================
@@ -108,6 +108,7 @@ Item {
                                                                                
                      : Qt.rect(0, 0, 0, 0)
 
     property alias sourceTextureProviderObserver: ds1.tpObserver // for 
accessory
+    sourceTextureProviderObserver.notifyAllChanges: !live
 
     readonly property bool sourceTextureIsValid: 
sourceTextureProviderObserver.isValid
 
@@ -124,14 +125,15 @@ Item {
 
     property bool _queuedScheduledUpdate: false
 
-    // WARNING: The QML property type is not `int` because the target property 
type is `qint64`.
-    readonly property var _comparisonKey: 
sourceTextureProviderObserver.comparisonKey
-    property var _oldComparisonKey
+    readonly property var _comparisonVar: ({key: 
sourceTextureProviderObserver.comparisonKey,
+                                            subRect: 
sourceTextureProviderObserver.normalizedTextureSubRect})
+    property var _oldComparisonVar
+
+    on_ComparisonVarChanged: {
+        if (_comparisonVar.key >= 0) {
+            if (_oldComparisonVar !== undefined && _oldComparisonVar !== 
_comparisonVar) {
+                _oldComparisonVar = undefined
 
-    on_ComparisonKeyChanged: {
-        if (_comparisonKey >= 0) {
-            if (_oldComparisonKey !== undefined && _oldComparisonKey !== 
_comparisonKey) {
-                _oldComparisonKey = undefined
                 // If source texture is not valid, update will be requeued in 
`scheduleUpdate()`.
                 // That being said, a non-valid source texture should have 
(-1) as comparison key,
                 // which we already checked here.
@@ -140,7 +142,10 @@ Item {
         }
     }
 
-    function scheduleUpdate(onNextTextureChange /* : bool */ = false) {
+    // When `onNextEffectiveTextureChange` is set, the update is scheduled 
automatically when the effective
+    // texture changes, which is when the texture itself changes or the 
texture remains the same but
+    // the sub-rect changes (such as, the new texture is a different part of 
the same atlas texture).
+    function scheduleUpdate(onNextEffectiveTextureChange /* : bool */ = false) 
{
         if (live)
             return // no-op
 
@@ -152,8 +157,8 @@ Item {
             return
         }
 
-        if (onNextTextureChange) {
-            root._oldComparisonKey = root._comparisonKey
+        if (onNextEffectiveTextureChange) {
+            root._oldComparisonVar = root._comparisonVar
             return
         }
 



View it on GitLab: 
https://code.videolan.org/videolan/vlc/-/compare/b82cad5c5dae0e3736a23838474db68cdd130d56...4962271021860d1a7d0b9c6b00b4070af788537c

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


VideoLAN code repository instance
_______________________________________________
vlc-commits mailing list
[email protected]
https://mailman.videolan.org/listinfo/vlc-commits

Reply via email to