[vlc-commits] [Git][videolan/vlc][master] 7 commits: qt: do not tint alpha channel in `DualKawaseBlur.frag`
Steve Lhomme (@robUx4)
gitlab at videolan.org
Thu Dec 18 12:01:29 UTC 2025
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
7a211a7d by Fatih Uzunoglu at 2025-12-18T11:38:17+00:00
qt: do not tint alpha channel in `DualKawaseBlur.frag`
Tinting should not be applied to the alpha channel of
the source.
- - - - -
b010ebf1 by Fatih Uzunoglu at 2025-12-18T11:38:17+00:00
qt: introduce background coloring in `DualKawaseBlur.frag`
- - - - -
aad71ed0 by Fatih Uzunoglu at 2025-12-18T11:38:17+00:00
qt: expose background coloring in `DualKawaseBlur.qml`
- - - - -
b1e2a426 by Fatih Uzunoglu at 2025-12-18T11:38:17+00:00
qml: use bg coloring if source is translucent in blur effect of `ArtistTopBanner`
- - - - -
b8d2c949 by Fatih Uzunoglu at 2025-12-18T11:38:17+00:00
qml: provide `available` in `DualKawaseBlur`
- - - - -
f79b4c08 by Fatih Uzunoglu at 2025-12-18T11:38:17+00:00
qml: use background coloring in blur effect of `Player`
- - - - -
918c2d38 by Fatih Uzunoglu at 2025-12-18T11:38:17+00:00
qml: get rid of unnecessary `Item` in `ArtistTopBanner`
- - - - -
7 changed files:
- modules/gui/qt/medialibrary/qml/ArtistTopBanner.qml
- modules/gui/qt/player/qml/Player.qml
- modules/gui/qt/shaders/DualKawaseBlur.frag
- modules/gui/qt/shaders/DualKawaseBlur_downsample.frag
- modules/gui/qt/shaders/DualKawaseBlur_upsample.frag
- modules/gui/qt/shaders/DualKawaseBlur_upsample_postprocess.frag
- modules/gui/qt/widgets/qml/DualKawaseBlur.qml
Changes:
=====================================
modules/gui/qt/medialibrary/qml/ArtistTopBanner.qml
=====================================
@@ -74,63 +74,61 @@ FocusScope {
opacity: blurEffect.visible ? 1.0 : 0.5
}
- Item {
- anchors.fill: background
-
- visible: (GraphicsInfo.shaderType === GraphicsInfo.RhiShader) && (root.artist.id) // do not display the effect during initialization
+ Widgets.DualKawaseBlur {
+ id: blurEffect
- // This blur effect does not create an implicit layer that is updated
- // each time the size changes. The source texture is static, so the blur
- // is applied only once and we adjust the viewport through the parent item
- // with clipping.
- Widgets.DualKawaseBlur {
- id: blurEffect
+ anchors.verticalCenter: background.verticalCenter
+ anchors.left: background.left
+ anchors.right: background.right
- anchors.verticalCenter: parent.verticalCenter
- anchors.left: parent.left
- anchors.right: parent.right
+ visible: (available) && (root.artist.id) // do not display the effect during initialization
- // NOTE: No need to disable `live`, as this uses two pass mode so there is no video memory saving benefit.
+ // NOTE: No need to disable `live`, as this uses two pass mode so there is no video memory saving benefit.
- readonly property bool sourceNeedsTiling: (background.fillMode === Image.Tile)
+ readonly property bool sourceNeedsTiling: (background.fillMode === Image.Tile)
- readonly property real aspectRatio: (background.implicitHeight / background.implicitWidth)
+ readonly property real aspectRatio: (background.implicitHeight / background.implicitWidth)
- height: sourceNeedsTiling ? background.height : (aspectRatio * width)
+ height: sourceNeedsTiling ? background.height : (aspectRatio * width)
- source: textureProviderItem
+ source: textureProviderItem
- // Instead of clipping in the parent, denote the viewport here so we both
- // do not need to clip the excess, and also save significant video memory:
- viewportRect: !blurEffect.sourceNeedsLayering ? Qt.rect((width - parent.width) / 2, (height - parent.height) / 2, parent.width, parent.height)
- : Qt.rect(0, 0, 0, 0)
+ // Instead of clipping in the parent, denote the viewport here so we both
+ // do not need to clip the excess, and also save significant video memory:
+ viewportRect: !blurEffect.sourceNeedsLayering ? Qt.rect((width - background.width) / 2,
+ (height - background.height) / 2,
+ background.width,
+ background.height)
+ : Qt.rect(0, 0, 0, 0)
- Widgets.TextureProviderItem {
- id: textureProviderItem
+ backgroundColor: theme.bg.primary
+ postprocess: sourceTextureProviderObserver.hasAlphaChannel
- // Like in `Player.qml`, this is used because when the source is
- // mipmapped, sometimes it can not be sampled. This is considered
- // a Qt bug, but `QSGTextureView` has a workaround for that. So,
- // we can have an indirection here through `TextureProviderItem`.
- // This is totally acceptable as there is virtually no overhead.
+ Widgets.TextureProviderItem {
+ id: textureProviderItem
- source: background
+ // Like in `Player.qml`, this is used because when the source is
+ // mipmapped, sometimes it can not be sampled. This is considered
+ // a Qt bug, but `QSGTextureView` has a workaround for that. So,
+ // we can have an indirection here through `TextureProviderItem`.
+ // This is totally acceptable as there is virtually no overhead.
- detachAtlasTextures: blurEffect.sourceNeedsTiling
+ source: background
- horizontalWrapMode: blurEffect.sourceNeedsTiling ? Widgets.TextureProviderItem.Repeat : Widgets.TextureProviderItem.ClampToEdge
- verticalWrapMode: blurEffect.sourceNeedsTiling ? Widgets.TextureProviderItem.Repeat : Widgets.TextureProviderItem.ClampToEdge
+ detachAtlasTextures: blurEffect.sourceNeedsTiling
- textureSubRect: blurEffect.sourceNeedsTiling ? Qt.rect(blurEffect.width / 8,
- blurEffect.height / 8,
- blurEffect.width * 1.25,
- blurEffect.height * 1.25) : undefined
- }
+ horizontalWrapMode: blurEffect.sourceNeedsTiling ? Widgets.TextureProviderItem.Repeat : Widgets.TextureProviderItem.ClampToEdge
+ verticalWrapMode: blurEffect.sourceNeedsTiling ? Widgets.TextureProviderItem.Repeat : Widgets.TextureProviderItem.ClampToEdge
- // Strong blurring is not wanted here:
- mode: Widgets.DualKawaseBlur.Mode.TwoPass
- radius: 1
+ textureSubRect: blurEffect.sourceNeedsTiling ? Qt.rect(blurEffect.width / 8,
+ blurEffect.height / 8,
+ blurEffect.width * 1.25,
+ blurEffect.height * 1.25) : undefined
}
+
+ // Strong blurring is not wanted here:
+ mode: Widgets.DualKawaseBlur.Mode.TwoPass
+ radius: 1
}
Rectangle {
=====================================
modules/gui/qt/player/qml/Player.qml
=====================================
@@ -277,7 +277,9 @@ FocusScope {
// background image
Rectangle {
focus: false
- color: bgtheme.bg.primary
+ // NOTE: Rectangle has an optimization that it does not use a scene graph node if the color is transparent.
+ color: blurredBackground.available ? "transparent" // background coloring in blur effect is used otherwise
+ : bgtheme.bg.primary
anchors.fill: parent
readonly property ColorContext colorContext: ColorContext {
@@ -304,6 +306,7 @@ FocusScope {
postprocess: true
tint: bgtheme.palette.isDark ? "black" : "white"
tintStrength: 0.5
+ backgroundColor: bgtheme.bg.primary
// The window naturally clips the content, but having this saves some
// video memory, depending on the excess content in the last layer:
=====================================
modules/gui/qt/shaders/DualKawaseBlur.frag
=====================================
@@ -35,6 +35,7 @@ layout(std140, binding = 0) uniform qt_buf {
#ifdef POSTPROCESS
vec4 tint;
+ vec4 backgroundColor;
float tintStrength;
float exclusionStrength;
float noiseStrength;
@@ -123,14 +124,18 @@ void main()
result = exclude(result, exclColor);
// Tint:
- result = mix(result, fromPremult(tint), tintStrength);
+ result.rgb = mix(result.rgb, fromPremult(tint).rgb, tintStrength);
+
+ result = toPremult(result);
+
+ // Background color:
+ // Source over blending, premultiplied (S + D * (1 - S.a)):
+ result = result + backgroundColor * (1.0 - result.a);
// Noise:
float r = rand(qt_TexCoord0) - 0.5;
- vec4 noise = vec4(r,r,r,1.0) * noiseStrength;
+ vec4 noise = vec4(r,r,r,r) * noiseStrength;
result += noise;
-
- result = toPremult(result);
#endif
fragColor = result * qt_Opacity; // premultiplied alpha
=====================================
modules/gui/qt/shaders/DualKawaseBlur_downsample.frag
=====================================
@@ -39,6 +39,7 @@ layout(std140, binding = 0) uniform qt_buf {
#ifdef POSTPROCESS
vec4 tint;
+ vec4 backgroundColor;
float tintStrength;
float exclusionStrength;
float noiseStrength;
@@ -127,14 +128,18 @@ void main()
result = exclude(result, exclColor);
// Tint:
- result = mix(result, fromPremult(tint), tintStrength);
+ result.rgb = mix(result.rgb, fromPremult(tint).rgb, tintStrength);
+
+ result = toPremult(result);
+
+ // Background color:
+ // Source over blending, premultiplied (S + D * (1 - S.a)):
+ result = result + backgroundColor * (1.0 - result.a);
// Noise:
float r = rand(qt_TexCoord0) - 0.5;
- vec4 noise = vec4(r,r,r,1.0) * noiseStrength;
+ vec4 noise = vec4(r,r,r,r) * noiseStrength;
result += noise;
-
- result = toPremult(result);
#endif
fragColor = result * qt_Opacity; // premultiplied alpha
=====================================
modules/gui/qt/shaders/DualKawaseBlur_upsample.frag
=====================================
@@ -39,6 +39,7 @@ layout(std140, binding = 0) uniform qt_buf {
#ifdef POSTPROCESS
vec4 tint;
+ vec4 backgroundColor;
float tintStrength;
float exclusionStrength;
float noiseStrength;
@@ -127,14 +128,18 @@ void main()
result = exclude(result, exclColor);
// Tint:
- result = mix(result, fromPremult(tint), tintStrength);
+ result.rgb = mix(result.rgb, fromPremult(tint).rgb, tintStrength);
+
+ result = toPremult(result);
+
+ // Background color:
+ // Source over blending, premultiplied (S + D * (1 - S.a)):
+ result = result + backgroundColor * (1.0 - result.a);
// Noise:
float r = rand(qt_TexCoord0) - 0.5;
- vec4 noise = vec4(r,r,r,1.0) * noiseStrength;
+ vec4 noise = vec4(r,r,r,r) * noiseStrength;
result += noise;
-
- result = toPremult(result);
#endif
fragColor = result * qt_Opacity; // premultiplied alpha
=====================================
modules/gui/qt/shaders/DualKawaseBlur_upsample_postprocess.frag
=====================================
@@ -40,6 +40,7 @@ layout(std140, binding = 0) uniform qt_buf {
#ifdef POSTPROCESS
vec4 tint;
+ vec4 backgroundColor;
float tintStrength;
float exclusionStrength;
float noiseStrength;
@@ -128,14 +129,18 @@ void main()
result = exclude(result, exclColor);
// Tint:
- result = mix(result, fromPremult(tint), tintStrength);
+ result.rgb = mix(result.rgb, fromPremult(tint).rgb, tintStrength);
+
+ result = toPremult(result);
+
+ // Background color:
+ // Source over blending, premultiplied (S + D * (1 - S.a)):
+ result = result + backgroundColor * (1.0 - result.a);
// Noise:
float r = rand(qt_TexCoord0) - 0.5;
- vec4 noise = vec4(r,r,r,1.0) * noiseStrength;
+ vec4 noise = vec4(r,r,r,r) * noiseStrength;
result += noise;
-
- result = toPremult(result);
#endif
fragColor = result * qt_Opacity; // premultiplied alpha
=====================================
modules/gui/qt/widgets/qml/DualKawaseBlur.qml
=====================================
@@ -34,6 +34,8 @@ 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
+ readonly property bool available: (GraphicsInfo.shaderType === GraphicsInfo.RhiShader)
+
enum Mode {
FourPass, // 2 downsample + 2 upsamples (3 layers/buffers)
TwoPass // 1 downsample + 1 upsample (1 layer/buffer)
@@ -49,6 +51,7 @@ Item {
property real tintStrength: 0.0
property real noiseStrength: 0.0
property real exclusionStrength: 0.0
+ property color backgroundColor: "transparent"
/// </postprocess>
// NOTE: This property is also an optimization hint. When it is false, the
@@ -64,12 +67,19 @@ Item {
// The effective radius is always going to be a half-integer.
property int radius: 1
+ // NOTE: This property concerns the blending in the scene graph, not the internal
+ // blending used with regard to background coloring. In that case blending
+ // is always done.
// 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: (!sourceTextureIsValid || sourceTextureProviderObserver.hasAlphaChannel ||
- (postprocess && (tintStrength > 0.0 && tint.a < 1.0)))
+ property bool blending: (postprocess &&
+ backgroundColor.a > (1.0 - Number.EPSILON)) ? false // the result is opaque, no need for sg blending
+ : _sourceIsTranslucent
+
+ // WARNING: If texture is not valid/ready, Qt generates a transparent texture to use as source.
+ readonly property bool _sourceIsTranslucent: (!sourceTextureIsValid || sourceTextureProviderObserver.hasAlphaChannel)
// source must be a texture provider item. Some items such as `Image` and
// `ShaderEffectSource` are inherently texture provider. Other items needs
@@ -122,7 +132,7 @@ Item {
if (live)
return // no-op
- if (root.GraphicsInfo.shaderType !== GraphicsInfo.RhiShader)
+ if (!root.available)
return // not applicable
if (!root.sourceTextureIsValid) {
@@ -432,6 +442,7 @@ Item {
property alias tintStrength: root.tintStrength
property alias noiseStrength: root.noiseStrength
property alias exclusionStrength: root.exclusionStrength
+ property alias backgroundColor: root.backgroundColor
fragmentShader: root.postprocess ? "qrc:///shaders/DualKawaseBlur_upsample_postprocess.frag.qsb"
: "qrc:///shaders/DualKawaseBlur_upsample.frag.qsb"
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/3cd86f0c90ee367a307b4d19802675c82ea5020b...918c2d380ad4fc63a9af223e57be6d33ba6fd835
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/3cd86f0c90ee367a307b4d19802675c82ea5020b...918c2d380ad4fc63a9af223e57be6d33ba6fd835
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