From 416fe28d1a6e0d1af438ee32031d9a321242d633 Mon Sep 17 00:00:00 2001 From: Fatih Uzunoglu Date: Tue, 27 Jan 2026 22:40:19 +0200 Subject: [PATCH] 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). --- .../gui/qt/util/textureproviderobserver.cpp | 63 ++++++++++++++++--- .../gui/qt/util/textureproviderobserver.hpp | 14 +++-- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/modules/gui/qt/util/textureproviderobserver.cpp b/modules/gui/qt/util/textureproviderobserver.cpp index e3da5b9c59..0bb174c02b 100644 --- a/modules/gui/qt/util/textureproviderobserver.cpp +++ b/modules/gui/qt/util/textureproviderobserver.cpp @@ -173,6 +173,8 @@ void TextureProviderObserver::updateProperties() if (m_provider) { + const bool notifyAllChanges = m_notifyAllChanges.load(memoryOrder); + if (const auto texture = m_provider->texture()) { { @@ -180,24 +182,54 @@ 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(textureSize.width() / ntsr.width()), - static_cast(textureSize.height() / ntsr.height())}, - memoryOrder); + const QSize size = {static_cast(textureSize.width() / ntsr.width()), + static_cast(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 @@ -208,7 +240,15 @@ void TextureProviderObserver::updateProperties() // Normal rect const QRectF& normalizedTextureSubRect = texture->normalizedTextureSubRect(); - m_normalizedTextureSubRect.store(normalizedTextureSubRect, memoryOrder); + if (notifyAllChanges) + { + if (m_normalizedTextureSubRect.exchange(normalizedTextureSubRect, memoryOrder) != normalizedTextureSubRect) + emit normalizedTextureSubRectChanged(normalizedTextureSubRect); + } + else + { + m_normalizedTextureSubRect.store(normalizedTextureSubRect, memoryOrder); + } } { @@ -255,9 +295,14 @@ void TextureProviderObserver::updateProperties() void TextureProviderObserver::resetProperties(std::memory_order memoryOrder) { - m_textureSize.store({}, memoryOrder); - m_nativeTextureSize.store({}, memoryOrder); - m_normalizedTextureSubRect.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); diff --git a/modules/gui/qt/util/textureproviderobserver.hpp b/modules/gui/qt/util/textureproviderobserver.hpp index e6d12c4723..b6b338f586 100644 --- a/modules/gui/qt/util/textureproviderobserver.hpp +++ b/modules/gui/qt/util/textureproviderobserver.hpp @@ -47,14 +47,15 @@ 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(QRectF normalizedTextureSubRect READ normalizedTextureSubRect FINAL) + 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) // 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 @@ -83,7 +84,11 @@ public: 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); @@ -107,6 +112,7 @@ private: // where the SG synchronization would not be blocking the (GUI) thread where this // observer lives. + std::atomic m_notifyAllChanges = false; std::atomic m_textureSize {{}}; // invalid by default std::atomic m_nativeTextureSize {{}}; // invalid by default std::atomic m_comparisonKey {-1};