[vlc-commits] [Git][videolan/vlc][master] 6 commits: qt: add property `hasAlphaChannel` to `TextureProviderObserver`

Steve Lhomme (@robUx4) gitlab at videolan.org
Thu Sep 18 11:58:41 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
6385eae0 by Fatih Uzunoglu at 2025-09-18T11:28:46+00:00
qt: add property `hasAlphaChannel` to `TextureProviderObserver`

As the name suggests, this makes it possible to introspect
whether the source texture has an alpha channel or not.

This is mostly relevant for non-layer textures, as it seems
that layers always have an alpha channel.

- - - - -
a320efa4 by Fatih Uzunoglu at 2025-09-18T11:28:46+00:00
qt: add property `hasMipmaps` to `TextureProviderObserver`

As the name suggests, this makes it possible to introspect
whether the source texture has mipmaps or not.

- - - - -
f2455278 by Fatih Uzunoglu at 2025-09-18T11:28:46+00:00
qt: add property `isAtlasTexture` to `TextureProviderObserver`

As the name suggests, this makes it possible to introspect
whether the source texture is the atlas (sub) texture.

- - - - -
aa2b1ec6 by Fatih Uzunoglu at 2025-09-18T11:28:46+00:00
qt: add property `isValid` to `TextureProviderObserver`

This is to see if the source texture provider actually
provides a texture, and especially useful if it is
important to know when the texture would be available.

One particular use case for this is with static effects,
such that it makes it possible to apply the effect once
the source provider starts providing the texture.

`Image` as texture provider has `Image.Ready` status,
but it seems that it is not really the best reflection
for whether the texture is ready or not. My understanding
is that it is rather for when the image is loaded, and
not necessarily the texture.

- - - - -
a3db0754 by Fatih Uzunoglu at 2025-09-18T11:28:46+00:00
qt: reset native texture size when texture is gone in `TextureProviderObserver`

This was missing unlike the scene graph texture size, but would be asymptomatic
in most if not all use cases without this fix.

- - - - -
5fe7e512 by Fatih Uzunoglu at 2025-09-18T11:28:46+00:00
qml: do not enable blending if source has no alpha channel in `DualKawaseBlur`

This is useful if the source is a texture generated from a JPEG image, for
example, where there can't be an alpha channel.

PNG images would probably have an alpha channel, whether or not the image
actually uses transparency, so this may not mean much in that case but it is
still good to have.

This should be safe because we are not supporting having transparent border
(like `FastBlur`), so blending should solely depend on the source texture.

- - - - -


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
=====================================
@@ -70,9 +70,9 @@ void TextureProviderObserver::setSource(const QQuickItem *source)
                 m_provider = m_source->textureProvider(); // This can only be called in the rendering thread.
                 assert(m_provider);
 
-                connect(m_provider, &QSGTextureProvider::textureChanged, this, &TextureProviderObserver::updateTextureSize, Qt::DirectConnection);
+                connect(m_provider, &QSGTextureProvider::textureChanged, this, &TextureProviderObserver::updateProperties, Qt::DirectConnection);
 
-                updateTextureSize();
+                updateProperties();
             }, static_cast<Qt::ConnectionType>(Qt::SingleShotConnection | Qt::DirectConnection));
         };
 
@@ -101,7 +101,39 @@ QSize TextureProviderObserver::nativeTextureSize() const
     return m_nativeTextureSize.load(std::memory_order_acquire);
 }
 
-void TextureProviderObserver::updateTextureSize()
+bool TextureProviderObserver::hasAlphaChannel() const
+{
+    // This is likely called in the QML/GUI thread.
+    // QML/GUI thread can freely block the rendering thread to the extent the time is reasonable and a
+    // fraction of `1/FPS`, because it is already throttled by v-sync (so it would just throttle less).
+    return m_hasAlphaChannel.load(std::memory_order_acquire);
+}
+
+bool TextureProviderObserver::hasMipmaps() const
+{
+    // This is likely called in the QML/GUI thread.
+    // QML/GUI thread can freely block the rendering thread to the extent the time is reasonable and a
+    // fraction of `1/FPS`, because it is already throttled by v-sync (so it would just throttle less).
+    return m_hasMipmaps.load(std::memory_order_acquire);
+}
+
+bool TextureProviderObserver::isAtlasTexture() const
+{
+    // This is likely called in the QML/GUI thread.
+    // QML/GUI thread can freely block the rendering thread to the extent the time is reasonable and a
+    // fraction of `1/FPS`, because it is already throttled by v-sync (so it would just throttle less).
+    return m_isAtlasTexture.load(std::memory_order_acquire);
+}
+
+bool TextureProviderObserver::isValid() const
+{
+    // This is likely called in the QML/GUI thread.
+    // QML/GUI thread can freely block the rendering thread to the extent the time is reasonable and a
+    // fraction of `1/FPS`, because it is already throttled by v-sync (so it would just throttle less).
+    return m_isValid.load(std::memory_order_acquire);
+}
+
+void TextureProviderObserver::updateProperties()
 {
     // This is likely called in the rendering thread.
     // Rendering thread should avoid blocking the QML/GUI thread. In this case, unlike the high precision
@@ -114,33 +146,78 @@ void TextureProviderObserver::updateTextureSize()
     {
         if (const auto texture = m_provider->texture())
         {
-            const auto textureSize = texture->textureSize();
-            m_textureSize.store(textureSize, memoryOrder);
-
             {
-                // Native texture size
+                // SG and native texture size
+
+                // SG texture size:
+                const auto textureSize = texture->textureSize();
+                m_textureSize.store(textureSize, memoryOrder);
 
-                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);
-                };
+                {
+                    // 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);
+                    };
 
 #ifdef RHI_HEADER_AVAILABLE
-                const QRhiTexture* const rhiTexture = texture->rhiTexture();
-                if (Q_LIKELY(rhiTexture))
-                    m_nativeTextureSize.store(rhiTexture->pixelSize(), memoryOrder);
-                else
-                    legacyUpdateNativeTextureSize();
+                    const QRhiTexture* const rhiTexture = texture->rhiTexture();
+                    if (Q_LIKELY(rhiTexture))
+                        m_nativeTextureSize.store(rhiTexture->pixelSize(), memoryOrder);
+                    else
+                        legacyUpdateNativeTextureSize();
 #else
-                legacyUpdateNativeTextureSize();
+                    legacyUpdateNativeTextureSize();
 #endif
+                }
             }
 
+            {
+                // Alpha channel
+                const bool hasAlphaChannel = texture->hasAlphaChannel();
+
+                if (m_hasAlphaChannel.exchange(hasAlphaChannel, memoryOrder) != hasAlphaChannel)
+                    emit hasAlphaChannelChanged(hasAlphaChannel);
+            }
+
+            {
+                // Mipmaps
+                const bool hasMipmaps = texture->hasMipmaps();
+
+                if (m_hasMipmaps.exchange(hasMipmaps, memoryOrder) != hasMipmaps)
+                    emit hasMipmapsChanged(hasMipmaps);
+            }
+
+            {
+                // Atlas texture
+                const bool isAtlasTexture = texture->isAtlasTexture();
+
+                if (m_isAtlasTexture.exchange(isAtlasTexture, memoryOrder) != isAtlasTexture)
+                    emit isAtlasTextureChanged(isAtlasTexture);
+            }
+
+            if (!m_isValid.exchange(true, memoryOrder))
+                emit isValidChanged(true);
+
             return;
         }
     }
 
     m_textureSize.store({}, memoryOrder);
+    m_nativeTextureSize.store({}, memoryOrder);
+
+    if (m_hasAlphaChannel.exchange(false, memoryOrder))
+        emit hasAlphaChannelChanged(false);
+
+    if (m_hasMipmaps.exchange(false, memoryOrder))
+        emit hasMipmapsChanged(false);
+
+    if (m_isAtlasTexture.exchange(false, memoryOrder))
+        emit isAtlasTextureChanged(false);
+
+    if (m_isValid.exchange(false, memoryOrder))
+        emit isValidChanged(false);
 }


=====================================
modules/gui/qt/util/textureproviderobserver.hpp
=====================================
@@ -55,18 +55,34 @@ class TextureProviderObserver : public QObject
     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)
 
+    // 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
+    //       connection (default), it may be queued in the receiver thread:
+    Q_PROPERTY(bool hasAlphaChannel READ hasAlphaChannel NOTIFY hasAlphaChannelChanged FINAL)
+    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
+
 public:
     explicit TextureProviderObserver(QObject *parent = nullptr);
 
     void setSource(const QQuickItem* source);
     QSize textureSize() const;
     QSize nativeTextureSize() const;
+    bool hasAlphaChannel() const;
+    bool hasMipmaps() const;
+    bool isAtlasTexture() const;
+    bool isValid() const;
 
 signals:
     void sourceChanged();
+    void hasAlphaChannelChanged(bool);
+    void hasMipmapsChanged(bool);
+    void isAtlasTextureChanged(bool);
+    void isValidChanged(bool);
 
 private slots:
-    void updateTextureSize();
+    void updateProperties();
 
 private:
     QPointer<const QQuickItem> m_source;
@@ -83,6 +99,11 @@ private:
 
     std::atomic<QSize> m_textureSize {{}}; // invalid by default
     std::atomic<QSize> m_nativeTextureSize {{}}; // invalid by default
+
+    std::atomic<bool> m_hasAlphaChannel = false;
+    std::atomic<bool> m_hasMipmaps = false;
+    std::atomic<bool> m_isAtlasTexture = false;
+    std::atomic<bool> m_isValid = false;
 };
 
 #endif // TEXTUREPROVIDEROBSERVER_HPP


=====================================
modules/gui/qt/widgets/qml/DualKawaseBlur.qml
=====================================
@@ -52,7 +52,11 @@ Item {
     // The effective radius is always going to be a half-integer.
     property int radius: 1
 
-    property bool blending: true
+    // NOTE: It seems that if SG accumulated opacity is lower than 1.0, blending is
+    //       used even if it is set false here. For that reason, it should not be
+    //       necessary to check for opacity (well, accumulated opacity can not be
+    //       checked directly in QML anyway).
+    property bool blending: (!ds1SourceObserver.isValid || ds1SourceObserver.hasAlphaChannel)
 
     // source must be a texture provider item. Some items such as `Image` and
     // `ShaderEffectSource` are inherently texture provider. Other items needs



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c7200f46b42d187f8e4b2ae40fcdf700b3d4746f...5fe7e5120299df7354a053115b07dfda44f2b1ea

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c7200f46b42d187f8e4b2ae40fcdf700b3d4746f...5fe7e5120299df7354a053115b07dfda44f2b1ea
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