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