[vlc-commits] [Git][videolan/vlc][master] 7 commits: qml: use common component for `ShaderEffect` in `DualKawaseBlur`
Steve Lhomme (@robUx4)
gitlab at videolan.org
Fri Nov 14 06:43:48 UTC 2025
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
6af130a0 by Fatih Uzunoglu at 2025-11-14T06:19:59+00:00
qml: use common component for `ShaderEffect` in `DualKawaseBlur`
This is only for maintenance, no behavioral change is intended.
- - - - -
bf7f7074 by Fatih Uzunoglu at 2025-11-14T06:19:59+00:00
qml: do not bother updating texture size if not necessary in `DualKawaseBlur`
The intermediate layers are not used in two pass configuration, so it is not
necessary to update the source texture size for them.
- - - - -
a8c6dd62 by Fatih Uzunoglu at 2025-11-14T06:19:59+00:00
qml: do not constantly update texture sizes if non-live in `DualKawaseBlur`
If the effect is not live, we can update the source texture sizes of the
layers once. There is no need to constantly update the texture sizes in
non-live case, because the textures do not change.
- - - - -
3a13b49a by Fatih Uzunoglu at 2025-11-14T06:19:59+00:00
qml: rename "configuration" to "mode" in `DualKawaseBlur`
The reason for that change is "configuration" is too long.
- - - - -
dcb834f7 by Fatih Uzunoglu at 2025-11-14T06:19:59+00:00
qml: define the postprocess properties in root in `DualKawaseBlur`
This is mainly to reveal the defaults in root, so that the reader
does not need to check `us2` to see the default values.
- - - - -
d6ebe030 by Fatih Uzunoglu at 2025-11-14T06:19:59+00:00
qml: calculate local viewport rect once in `DualKawaseBlur`
- - - - -
28a5cc2b by Fatih Uzunoglu at 2025-11-14T06:19:59+00:00
qml: use common component for `ShaderEffectSource` in `DualKawaseBlur`
This is only for maintenance, no behavioral change is intended.
- - - - -
2 changed files:
- modules/gui/qt/medialibrary/qml/ArtistTopBanner.qml
- modules/gui/qt/widgets/qml/DualKawaseBlur.qml
Changes:
=====================================
modules/gui/qt/medialibrary/qml/ArtistTopBanner.qml
=====================================
@@ -128,7 +128,7 @@ FocusScope {
}
// Strong blurring is not wanted here:
- configuration: Widgets.DualKawaseBlur.Configuration.TwoPass
+ mode: Widgets.DualKawaseBlur.Mode.TwoPass
radius: 1
}
}
=====================================
modules/gui/qt/widgets/qml/DualKawaseBlur.qml
=====================================
@@ -34,23 +34,23 @@ Item {
implicitWidth: source ? Math.min(source.paintedWidth ?? Number.MAX_VALUE, source.width) : 0
implicitHeight: source ? Math.min(source.paintedHeight ?? Number.MAX_VALUE, source.height) : 0
- enum Configuration {
+ enum Mode {
FourPass, // 2 downsample + 2 upsamples (3 layers/buffers)
TwoPass // 1 downsample + 1 upsample (1 layer/buffer)
}
+ property int mode: DualKawaseBlur.Mode.FourPass
+
/// <postprocess>
// The following property must be set in order to make other properties respected:
property bool postprocess: false
- property alias tint: us2.tint
- property alias tintStrength: us2.tintStrength
- property alias noiseStrength: us2.noiseStrength
- property alias exclusionStrength: us2.exclusionStrength
+ property color tint: "transparent"
+ property real tintStrength: 0.0
+ property real noiseStrength: 0.0
+ property real exclusionStrength: 0.0
/// </postprocess>
- property int configuration: DualKawaseBlur.Configuration.FourPass
-
// NOTE: This property is also an optimization hint. When it is false, the
// intermediate buffers for the blur passes may be released (only
// the two intermediate layers in four pass mode, we must have one
@@ -89,7 +89,15 @@ Item {
// Since the discard occurs at layer level, using this saves video memory.
property rect viewportRect
- property alias sourceTextureProviderObserver: ds1SourceObserver // for accessory
+ // Local viewport rect is viewport rect divided by two, because it is used as the source
+ // rect of last layer, which is 2x upsampled by the painter delegate (us2):
+ readonly property rect _localViewportRect: ((viewportRect.width > 0 && viewportRect.height > 0)) ? Qt.rect(viewportRect.x / 2,
+ viewportRect.y / 2,
+ viewportRect.width / 2,
+ viewportRect.height / 2)
+ : Qt.rect(0, 0, 0, 0)
+
+ property alias sourceTextureProviderObserver: ds1.tpObserver // for accessory
readonly property bool sourceTextureIsValid: sourceTextureProviderObserver.isValid
@@ -148,10 +156,12 @@ Item {
}
}
- // TODO: Get rid of this in favor of GLSL 1.30's `textureSize()`
+ // TODO: We could use `textureSize()` and get rid of this, but we
+ // can not because we are targeting GLSL 1.20/ESSL 1.0, even
+ // though the shader is written in GLSL 4.40.
Connections {
target: root.Window.window
- enabled: root.visible
+ enabled: root.visible && root.live
function onAfterAnimating() {
// Sampling point for getting the native texture sizes:
@@ -163,10 +173,12 @@ Item {
// implicitly (due to source texture provider's signal
// `textureChanged()`).
- ds1.sourceTextureSize = ds1SourceObserver.nativeTextureSize
- ds2.sourceTextureSize = ds2SourceObserver.nativeTextureSize
- us1.sourceTextureSize = us1SourceObserver.nativeTextureSize
- us2.sourceTextureSize = us2SourceObserver.nativeTextureSize
+ ds1.sourceTextureSize = ds1.tpObserver.nativeTextureSize
+ if (root.mode === DualKawaseBlur.Mode.FourPass) {
+ ds2.sourceTextureSize = ds2.tpObserver.nativeTextureSize
+ us1.sourceTextureSize = us1.tpObserver.nativeTextureSize
+ }
+ us2.sourceTextureSize = us2.tpObserver.nativeTextureSize
// It is not clear if `ShaderEffect` updates the uniform
// buffer after `afterAnimating()` signal but before the
@@ -184,80 +196,99 @@ Item {
// No need to check for if such slot exists for each,
// this is basically Qt version check in disguise.
ds1.ensurePolished()
- ds2.ensurePolished()
- us1.ensurePolished()
+ if (root.mode === DualKawaseBlur.Mode.FourPass) {
+ ds2.ensurePolished()
+ us1.ensurePolished()
+ }
us2.ensurePolished()
}
}
}
- ShaderEffect {
- id: ds1
-
- // When downsampled, we can decrease the size here so that the layer occupies less VRAM:
- width: parent.width / 2
- height: parent.height / 2
-
- readonly property Item source: root.source
-
- // TODO: Instead of normalizing here, we could use GLSL 1.30's `textureSize()`
- // and normalize in the vertex shader, but we can not because we are
- // targeting GLSL 1.20/ESSL 1.0, even though the shader is written in
- // GLSL 4.40.
- readonly property rect normalRect: (root.sourceRect.width > 0.0 && root.sourceRect.height > 0.0) ? Qt.rect(root.sourceRect.x / sourceTextureSize.width,
- root.sourceRect.y / sourceTextureSize.height,
- root.sourceRect.width / sourceTextureSize.width,
- root.sourceRect.height / sourceTextureSize.height)
- : Qt.rect(0.0, 0.0, 0.0, 0.0)
+ component DefaultShaderEffect : ShaderEffect {
+ id: shaderEffect
+ required property Item source
readonly property int radius: root.radius
- // TODO: We could use `textureSize()` and get rid of this, but we
- // can not because we are targeting GLSL 1.20/ESSL 1.0, even
- // though the shader is written in GLSL 4.40.
- TextureProviderObserver {
- id: ds1SourceObserver
- source: ds1.source
- }
-
property size sourceTextureSize
+ property rect normalRect // may not be necessary, but still needed to prevent warning
+
+ property alias tpObserver: textureProviderObserver
// cullMode: ShaderEffect.BackFaceCulling // QTBUG-136611 (Layering breaks culling with OpenGL)
- fragmentShader: "qrc:///shaders/DualKawaseBlur_downsample.frag.qsb"
// Maybe we should have vertex shader unconditionally, and calculate the half pixel there instead of fragment shader?
vertexShader: (normalRect.width > 0.0 && normalRect.height > 0.0) ? "qrc:///shaders/SubTexture.vert.qsb"
: ""
- visible: false
-
supportsAtlasTextures: true
blending: root.blending
+
+ visible: false
+
+ TextureProviderObserver {
+ id: textureProviderObserver
+ source: shaderEffect.source
+ }
}
- ShaderEffectSource {
- id: ds1layer
+ component DownsamplerShaderEffect : DefaultShaderEffect {
+ fragmentShader: source ? "qrc:///shaders/DualKawaseBlur_downsample.frag.qsb"
+ : "" // to prevent warning if source becomes null
+ }
+
+ component UpsamplerShaderEffect : DefaultShaderEffect {
+ fragmentShader: source ? "qrc:///shaders/DualKawaseBlur_upsample.frag.qsb"
+ : "" // to prevent warning if source becomes null
+ }
+
+ component DefaultShaderEffectSource : ShaderEffectSource {
+ // This is necessary to release resources even if `sourceItem` becomes null (non-live case):
+ parent: sourceItem ? root : null
- sourceItem: ds1
visible: false
+ live: root.live
smooth: true
+ }
- live: root.live
+ DownsamplerShaderEffect {
+ id: ds1
+
+ // When downsampled, we can decrease the size here so that the layer occupies less VRAM:
+ width: parent.width / 2
+ height: parent.height / 2
- // Divided by two, because viewport rect is local to the final upsampler (us2), which is the painter delegate here (regardless of the mode):
- // Viewport rect is only relevant for the last layer, so in here (ds1layer) it is only for the two-pass mode:
- sourceRect: ((root.configuration === DualKawaseBlur.Configuration.TwoPass) &&
- (root.viewportRect.width > 0 && root.viewportRect.height > 0)) ? Qt.rect(root.viewportRect.x / 2,
- root.viewportRect.y / 2,
- root.viewportRect.width / 2,
- root.viewportRect.height / 2)
- : Qt.rect(0, 0, 0, 0)
+ source: root.source
+
+ // TODO: Instead of normalizing here, we could use GLSL 1.30's `textureSize()`
+ // and normalize in the vertex shader, but we can not because we are
+ // targeting GLSL 1.20/ESSL 1.0, even though the shader is written in
+ // GLSL 4.40.
+ normalRect: (root.sourceRect.width > 0.0 && root.sourceRect.height > 0.0) ? Qt.rect(root.sourceRect.x / sourceTextureSize.width,
+ root.sourceRect.y / sourceTextureSize.height,
+ root.sourceRect.width / sourceTextureSize.width,
+ root.sourceRect.height / sourceTextureSize.height)
+ : Qt.rect(0.0, 0.0, 0.0, 0.0)
+ }
+
+ DefaultShaderEffectSource {
+ id: ds1layer
+
+ sourceItem: ds1
+
+ // Last layer for two pass mode, so use the viewport rect:
+ sourceRect: (root.mode === DualKawaseBlur.Mode.TwoPass) ? root._localViewportRect : Qt.rect(0, 0, 0, 0)
function scheduleChainedUpdate() {
if (!ds1layer) // context is lost, Qt bug (reproduced with 6.2)
return
+ ds1.sourceTextureSize = ds1.tpObserver.nativeTextureSize
+ if (ds1.ensurePolished)
+ ds1.ensurePolished()
+
// Common for both four and two pass mode:
ds1layer.parent = root
ds1layer.scheduleUpdate()
@@ -266,7 +297,7 @@ Item {
root._window.afterAnimating.disconnect(ds1layer, ds1layer.scheduleChainedUpdate)
// In four pass mode, we can release the two intermediate layers:
- if (root.configuration === DualKawaseBlur.Configuration.FourPass) {
+ if (root.mode === DualKawaseBlur.Mode.FourPass) {
// Scheduling update must be done sequentially for each layer in
// a chain. It seems that each layer needs one frame for it to be
// used as a source in another layer, so we can not schedule
@@ -279,7 +310,7 @@ Item {
}
}
- ShaderEffect {
+ DownsamplerShaderEffect {
id: ds2
// When downsampled, we can decrease the size here so that the layer occupies less VRAM:
@@ -287,45 +318,18 @@ Item {
height: ds1.height / 2
// Qt uses reference counting, otherwise ds1layer may not be released, even if it has no parent (see `QQuickItemPrivate::derefWindow()`):
- readonly property Item source: ((root.configuration === DualKawaseBlur.Configuration.TwoPass) || !ds1layer.parent) ? null : ds1layer
- property rect normalRect // not necessary here, added because of the warning
- readonly property int radius: root.radius
-
- // TODO: We could use `textureSize()` and get rid of this, but we
- // can not because we are targeting GLSL 1.20/ESSL 1.0, even
- // though the shader is written in GLSL 4.40.
- TextureProviderObserver {
- id: ds2SourceObserver
- source: ds2.source
- }
-
- property size sourceTextureSize
-
- // cullMode: ShaderEffect.BackFaceCulling // QTBUG-136611 (Layering breaks culling with OpenGL)
-
- visible: false
-
- fragmentShader: source ? "qrc:///shaders/DualKawaseBlur_downsample.frag.qsb" : "" // to prevent warning if source becomes null
-
- supportsAtlasTextures: true
-
- blending: root.blending
+ source: ((root.mode === DualKawaseBlur.Mode.TwoPass) || !ds1layer.parent) ? null : ds1layer
}
- ShaderEffectSource {
+ DefaultShaderEffectSource {
id: ds2layer
- // So that if configuration is two pass (this is not used), the buffer is released:
- // This is mainly relevant for switching configuration case, as initially if this was
+ // So that if the mode is two pass (this is not used), the buffer is released:
+ // This is mainly relevant for switching the mode case, as initially if this was
// never visible and was never used as texture provider, it should have never allocated
// resources to begin with.
- sourceItem: (root.configuration === DualKawaseBlur.Configuration.FourPass) ? ds2 : null
- parent: (!inhibitParent && sourceItem) ? root : null // this seems necessary to release resources even if sourceItem becomes null (non-live case)
-
- visible: false
- smooth: true
-
- live: root.live
+ sourceItem: (root.mode === DualKawaseBlur.Mode.FourPass) ? ds2 : null
+ parent: (!inhibitParent && sourceItem) ? root : null // necessary to release resources even if `sourceItem` becomes null (non-live case)
property bool inhibitParent: false
@@ -333,6 +337,10 @@ Item {
if (!ds2layer) // context is lost, Qt bug (reproduced with 6.2)
return
+ ds2.sourceTextureSize = ds2.tpObserver.nativeTextureSize
+ if (ds2.ensurePolished)
+ ds2.ensurePolished()
+
ds2layer.inhibitParent = false
ds2layer.scheduleUpdate()
@@ -343,66 +351,37 @@ Item {
}
}
- ShaderEffect {
+ UpsamplerShaderEffect {
id: us1
width: ds2.width * 2
height: ds2.height * 2
// Qt uses reference counting, otherwise ds2layer may not be released, even if it has no parent (see `QQuickItemPrivate::derefWindow()`):
- readonly property Item source: ((root.configuration === DualKawaseBlur.Configuration.TwoPass) || !ds2layer.parent) ? null : ds2layer
- property rect normalRect // not necessary here, added because of the warning
- readonly property int radius: root.radius
-
- // TODO: We could use `textureSize()` and get rid of this, but we
- // can not because we are targeting GLSL 1.20/ESSL 1.0, even
- // though the shader is written in GLSL 4.40.
- TextureProviderObserver {
- id: us1SourceObserver
- source: us1.source
- }
-
- property size sourceTextureSize
-
- // cullMode: ShaderEffect.BackFaceCulling // QTBUG-136611 (Layering breaks culling with OpenGL)
-
- visible: false
-
- fragmentShader: source ? "qrc:///shaders/DualKawaseBlur_upsample.frag.qsb" : "" // to prevent warning if source becomes null
-
- supportsAtlasTextures: true
-
- blending: root.blending
+ source: ((root.mode === DualKawaseBlur.Mode.TwoPass) || !ds2layer.parent) ? null : ds2layer
}
- ShaderEffectSource {
+ DefaultShaderEffectSource {
id: us1layer
- // So that if configuration is two pass (this is not used), the buffer is released:
- // This is mainly relevant for switching configuration case, as initially if this was
+ // So that if the mode is two pass (this is not used), the buffer is released:
+ // This is mainly relevant for switching the mode case, as initially if this was
// never visible and was never used as texture provider, it should have never allocated
// resources to begin with.
- sourceItem: (root.configuration === DualKawaseBlur.Configuration.FourPass) ? us1 : null
- parent: sourceItem ? root : null // this seems necessary to release resources even if sourceItem becomes null (non-live case)
+ sourceItem: (root.mode === DualKawaseBlur.Mode.FourPass) ? us1 : null
- visible: false
- smooth: true
-
- live: root.live
-
- // Divided by two, because viewport rect is local to the final upsampler (us2), which is the painter delegate here (regardless of the mode):
- // No need to check for the mode, because this is not used in two pass mode (calculations are negligible).
- // TODO: Investigate if we can propagate the viewport rect back to the intermediate layers in four-pass mode to save more video memory.
- sourceRect: (root.viewportRect.width > 0 && root.viewportRect.height > 0) ? Qt.rect(root.viewportRect.x / 2,
- root.viewportRect.y / 2,
- root.viewportRect.width / 2,
- root.viewportRect.height / 2)
- : Qt.rect(0, 0, 0, 0)
+ // Last layer for four pass mode, so use the viewport rect:
+ // No need to check for the mode because this layer is not used in two pass mode anyway.
+ sourceRect: root._localViewportRect
function scheduleChainedUpdate() {
if (!us1layer) // context is lost, Qt bug (reproduced with 6.2)
return
+ us1.sourceTextureSize = us1.tpObserver.nativeTextureSize
+ if (us1.ensurePolished)
+ us1.ensurePolished()
+
us1layer.scheduleUpdate()
if (root._window) {
@@ -415,6 +394,8 @@ Item {
if (!ds1layer || !ds2layer) // context is lost, Qt bug (reproduced with 6.2)
return
+ us2.sourceTextureSize = us2.tpObserver.nativeTextureSize
+
// Last layer is updated, now it is time to release the intermediate buffers:
console.debug(root, ": releasing intermediate layers, expect the video memory consumption to drop.")
@@ -435,7 +416,7 @@ Item {
}
}
- ShaderEffect {
+ UpsamplerShaderEffect {
id: us2
// {us1/ds1}.size * 2
@@ -443,34 +424,16 @@ Item {
width: (root.viewportRect.width > 0) ? root.viewportRect.width : parent.width
height: (root.viewportRect.height > 0) ? root.viewportRect.height : parent.height
- visible: us2SourceObserver.isValid
-
- readonly property Item source: (root.configuration === DualKawaseBlur.Configuration.TwoPass) ? ds1layer : us1layer
- property rect normalRect // not necessary here, added because of the warning
- readonly property int radius: root.radius
-
- // TODO: We could use `textureSize()` and get rid of this, but we
- // can not because we are targeting GLSL 1.20/ESSL 1.0, even
- // though the shader is written in GLSL 4.40.
- TextureProviderObserver {
- id: us2SourceObserver
- source: us2.source
- }
-
- property size sourceTextureSize
+ visible: tpObserver.isValid
- // cullMode: ShaderEffect.BackFaceCulling // QTBUG-136611 (Layering breaks culling with OpenGL)
+ source: (root.mode === DualKawaseBlur.Mode.TwoPass) ? ds1layer : us1layer
- property color tint: "transparent"
- property real tintStrength: 0.0
- property real noiseStrength: 0.0
- property real exclusionStrength: 0.0
+ property alias tint: root.tint
+ property alias tintStrength: root.tintStrength
+ property alias noiseStrength: root.noiseStrength
+ property alias exclusionStrength: root.exclusionStrength
fragmentShader: root.postprocess ? "qrc:///shaders/DualKawaseBlur_upsample_postprocess.frag.qsb"
: "qrc:///shaders/DualKawaseBlur_upsample.frag.qsb"
-
- supportsAtlasTextures: true
-
- blending: root.blending
}
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/1dd7f9d121a7a4647168907599a5f4383539b122...28a5cc2b31de26dfbb911c762f1d48c25aa0a696
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/1dd7f9d121a7a4647168907599a5f4383539b122...28a5cc2b31de26dfbb911c762f1d48c25aa0a696
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