[vlc-commits] [Git][videolan/vlc][master] 3 commits: qml: introduce `visualRect` property in `DualKawaseBlur`
Steve Lhomme (@robUx4)
gitlab at videolan.org
Mon Apr 27 17:02:30 UTC 2026
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
393d5472 by Fatih Uzunoglu at 2026-04-27T16:40:15+00:00
qml: introduce `visualRect` property in `DualKawaseBlur`
This property can be used in these two cases (but not
limited to):
- Using viewport rect to only blur area of interest,
discarding empty* margins, and extend the visual to
make it seem as if viewport rect is never used. If
the margins are truly empty, the result would be
the same since blurring a uniform solid color would
not result in anything different than the color.
- Freely adjusting the visual position, since with
viewport rect, it is always centered in the parent
(root, effect).
* Empty does not necessarily mean transparent, it can
be any uniform color plane as well.
- - - - -
f258ddd4 by Fatih Uzunoglu at 2026-04-27T16:40:15+00:00
qml: limit the blur effect intermediate layer sizes to area of interest in `MainDisplay`
This patch implements the todo mentioned previously in 2630a5cd:
> It is currently a todo to further reduce the VRAM consumption
> by trimming the intermediate layer size within the effect,
> since we do not need to apply blurring in the plain area which
> has only one unique color (the background color).
Now, another todo is to further limit the layer sizes based on the view's
content margins (`Flickable` margins and control paddings and insets).
- - - - -
df2fc34f by Fatih Uzunoglu at 2026-04-27T16:40:15+00:00
qml: no longer anchor the partial effect in `MainDisplay`
We can simply use `sourceVisualRect` at all times. I do
not have a strong opinion on this, but anchoring the
effect is an ugly workaround.
- - - - -
2 changed files:
- modules/gui/qt/maininterface/qml/MainDisplay.qml
- modules/gui/qt/widgets/qml/DualKawaseBlur.qml
Changes:
=====================================
modules/gui/qt/maininterface/qml/MainDisplay.qml
=====================================
@@ -260,7 +260,7 @@ FocusScope {
// since 03b0de26, already provides the effect the whole source texture with a proper sub-rect,
// so the effect here can sample the top edge neighbour pixels, but for the bottom edge we
// need to configure the layer:
- readonly property int bottomExtension: 16
+ readonly property int edgeExtension: 16
// The layer width is smaller than the item width, this is intentional because we do not want
// to include the area that playqueue occupies in the layer since it is empty. Note that we
// still want to do layering here, because even though the layer is smaller than the item
@@ -269,14 +269,14 @@ FocusScope {
// need to use background coloring. It is currently a todo to further reduce video memory
// consumption by covering the effect for only the area of interest, currently the blur
// effect does not support having an extension area for postprocessing.
- layer.sourceRect: Qt.rect(0, 0, stackView.width + 1, height + bottomExtension)
+ layer.sourceRect: Qt.rect(0, 0, Math.min(stackView.width + edgeExtension, stackViewParent.width), height + edgeExtension)
Rectangle {
// Extension of parent rectangle for the bottom extension.
anchors.top: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
- height: stackViewParent.bottomExtension
+ height: stackViewParent.edgeExtension
visible: stackViewParent.layer.enabled && (height > 0)
color: parent.color
}
@@ -284,28 +284,22 @@ FocusScope {
layer.effect: Widgets.PartialEffect {
id: stackViewParentLayerEffect
- // Setting `height` does not seem to work here. Anchoring the effect is not very nice, but it works:
- anchors.fill: stackViewParent // WARNING: layered item is not necessarily the visual parent of its layer effect.
- anchors.bottomMargin: -stackViewParent.bottomExtension
-
blending: stackViewParent.color.a < (1.0 - Number.EPSILON)
// Each pass of the blur effect also suffers from the border neighbour pixel issue mentioned
// above, making all the borders problematic, to a less considerable extent. For that reason,
// we extend both the top and the bottom edges and use viewport to prevent overdraw:
effectRect: Qt.rect(0,
- stackView.height - stackViewParent.bottomExtension,
+ stackView.height - stackViewParent.edgeExtension,
width,
- loaderProgress.height + miniPlayer.height + 2 * stackViewParent.bottomExtension)
+ loaderProgress.height + miniPlayer.height + 2 * stackViewParent.edgeExtension)
- // Bottom extension is not necessary here, but it is provided to prevent stretching glitch at
+ // Edge extension is not necessary here, but it is provided to prevent stretching glitch at
// initialization. Currently this is not a problem because the effect is opaque since the
// background is opaque, and effect visual has higher z than the source visual.
- sourceVisualRect: ((stackView.width < stackViewParent.width) || blending) ?
- Qt.rect(0, 0,
- stackView.width,
- stackView.height + (frostedGlassEffect.blending ? 0 : stackViewParent.bottomExtension)) :
- Qt.rect(0, 0, 0, 0)
+ sourceVisualRect: Qt.rect(0, 0,
+ stackViewParent.layer.sourceRect.width,
+ stackView.height + (frostedGlassEffect.blending ? 0 : stackViewParent.edgeExtension))
effect: frostedGlassEffect
@@ -321,11 +315,18 @@ FocusScope {
backgroundColor: (ready ? "transparent" : stackViewParent.color)
tint: frostedTheme.bg.secondary
- // Prevent overdraw (the extension margin should not be painted):
+ // Prevent overdraw (the extension margin should not be painted).
+ // This also saves video memory compared to solely using visual rect.
viewportRect: Qt.rect(0,
- stackViewParent.bottomExtension,
- width,
- height - (2 * stackViewParent.bottomExtension))
+ stackViewParent.edgeExtension,
+ Math.min(stackView.width + stackViewParent.edgeExtension, stackViewParent.width),
+ height - (2 * stackViewParent.edgeExtension))
+
+ visualRect: (stackView.width < stackViewParent.width) ? Qt.rect(viewportRect.x,
+ viewportRect.y,
+ width,
+ viewportRect.height)
+ : Qt.rect(0, 0, 0, 0)
}
}
=====================================
modules/gui/qt/widgets/qml/DualKawaseBlur.qml
=====================================
@@ -18,6 +18,7 @@
import QtQuick
import QtQuick.Window
+import VLC.MainInterface
import VLC.Util
// This item provides the novel "Dual Kawase" effect [1], which offers a very ideal
@@ -101,6 +102,23 @@ Item {
// Since the discard occurs at layer level, using this saves video memory.
property rect viewportRect
+ // Visual rect allows to extend the visual (us2) in effect's local coordinates.
+ // Unlike viewport rect, visual rect is not relevant to the layers hence will
+ // not allow saving video memory. The reason for this to exist is that when
+ // viewport rect is used to save video memory, the effect may still need to
+ // cover a certain area without stretching the blurred result and to keep
+ // the postprocess coverage available beyond the blurred result but within
+ // the effect area. A particular use case is when blurred content has large
+ // margins that are empty, where in this case visual rect with clamp to edge
+ // wrap mode would make the effect look as if the whole source was blurred,
+ // but with the benefit of saving video memory, provided that the viewport
+ // rect is set to discard the empty margins. Another use case is freely
+ // adjusting the position of the visual when viewport rect is smaller than
+ // the effect size, since with only viewport rect the visual is always
+ // centered in the parent (effect).
+ property rect visualRect
+ property int visualWrapMode: TextureProviderIndirection.ClampToEdge
+
// 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,
@@ -109,6 +127,13 @@ Item {
viewportRect.height / 2)
: Qt.rect(0, 0, 0, 0)
+ // This is only supposed to be used in visual delegate (us2), maybe we move it there?
+ readonly property rect _localVisualRect: ((visualRect.width > 0 && visualRect.height > 0)) ? Qt.rect(visualRect.x / 2,
+ visualRect.y / 2,
+ visualRect.width / 2,
+ visualRect.height / 2)
+ : Qt.rect(0, 0, 0, 0)
+
property alias sourceTextureProviderObserver: ds1.tpObserver // for accessory
sourceTextureProviderObserver.notifyAllChanges: !live
@@ -457,14 +482,39 @@ Item {
UpsamplerShaderEffect {
id: us2
- // {us1/ds1}.size * 2
- anchors.centerIn: parent
- width: (root.viewportRect.width > 0) ? root.viewportRect.width : parent.width
- height: (root.viewportRect.height > 0) ? root.viewportRect.height : parent.height
+ // {us1/ds1}.size * 2, unless visual rect is used
+ anchors.centerIn: useIndirection ? undefined : parent
+
+ x: useIndirection ? root.visualRect.x : 0
+ y: useIndirection ? root.visualRect.y : 0
+
+ width: {
+ if (useIndirection)
+ return root.visualRect.width
+
+ if (root.viewportRect.width > 0)
+ return root.viewportRect.width
+
+ return parent.width
+ }
+
+ height: {
+ if (useIndirection)
+ return root.visualRect.height
+
+ if (root.viewportRect.height > 0)
+ return root.viewportRect.height
+
+ return parent.height
+ }
+
+ readonly property bool useIndirection: (root.visualRect.width > 0 && root.visualRect.height > 0)
visible: tpObserver.isValid && root.available
- source: (root.mode === DualKawaseBlur.Mode.TwoPass) ? ds1layer : us1layer
+ source: useIndirection ? textureProviderIndirection : targetSource
+
+ readonly property Item targetSource: (root.mode === DualKawaseBlur.Mode.TwoPass) ? ds1layer : us1layer
property alias tint: root.tint
property alias tintStrength: root.tintStrength
@@ -474,5 +524,29 @@ Item {
fragmentShader: root.postprocess ? "qrc:///shaders/DualKawaseBlur_upsample_postprocess.frag.qsb"
: "qrc:///shaders/DualKawaseBlur_upsample.frag.qsb"
+
+ property real _eDPR: MainCtx.effectiveDevicePixelRatio(Window.window) || 1.0
+
+ Connections {
+ target: MainCtx
+
+ function onIntfDevicePixelRatioChanged() {
+ us2._eDPR = MainCtx.effectiveDevicePixelRatio(us2.Window.window) || 1.0
+ }
+ }
+
+ TextureProviderIndirection {
+ id: textureProviderIndirection
+
+ source: us2.targetSource
+
+ textureSubRect: Qt.rect(0,
+ 0,
+ root._localVisualRect.width * us2._eDPR,
+ root._localVisualRect.height * us2._eDPR)
+
+ horizontalWrapMode: root.visualWrapMode
+ verticalWrapMode: root.visualWrapMode
+ }
}
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/455c91cf004a2a6367e1a1b931654d4b264c07dd...df2fc34fdc1a047cbd4509b70dff1d9e1ceb2689
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/455c91cf004a2a6367e1a1b931654d4b264c07dd...df2fc34fdc1a047cbd4509b70dff1d9e1ceb2689
You're receiving this email because of your account on code.videolan.org.
More information about the vlc-commits
mailing list