[vlc-commits] [Git][videolan/vlc][master] 5 commits: qt: support hollowing in `RoundedRectangleShadow.frag`

Steve Lhomme (@robUx4) gitlab at videolan.org
Mon May 19 13:55:17 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
ed43bb6e by Fatih Uzunoglu at 2025-05-19T13:24:29+00:00
qt: support hollowing in `RoundedRectangleShadow.frag`

Hollowing only makes sense when there is compensation.

- - - - -
b446a5c8 by Fatih Uzunoglu at 2025-05-19T13:24:29+00:00
qml: add property `hollow` to `RoundedRectangleShadow`

- - - - -
42cb339d by Fatih Uzunoglu at 2025-05-19T13:24:29+00:00
qml: use `RoundedRectangleShadow` instead of `RectangularGlow` for the window shadow

- - - - -
6448e518 by Fatih Uzunoglu at 2025-05-19T13:24:29+00:00
qt: get rid of obsolete `RectangularGlow.qml`

CSD window shadow no longer uses `RectangularGlow.qml`,
and there are no other places use it or potentially use
it.

- - - - -
cd2c8fb5 by Fatih Uzunoglu at 2025-05-19T13:24:29+00:00
qt: get rid of `RectangularGlow.frag`

- - - - -


11 changed files:

- modules/gui/qt/Makefile.am
- modules/gui/qt/maininterface/qml/MainInterface.qml
- modules/gui/qt/meson.build
- − modules/gui/qt/shaders/HollowRectangularGlow.frag
- − modules/gui/qt/shaders/RectangularGlow.frag
- modules/gui/qt/shaders/RoundedRectangleShadow.frag
- + modules/gui/qt/shaders/RoundedRectangleShadow_hollow.frag
- modules/gui/qt/shaders/meson.build
- modules/gui/qt/shaders/shaders.qrc
- − modules/gui/qt/widgets/qml/RectangularGlow.qml
- modules/gui/qt/widgets/qml/RoundedRectangleShadow.qml


Changes:

=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -1303,7 +1303,6 @@ libqml_module_widgets_a_QML = \
 	widgets/qml/PartialEffect.qml \
 	widgets/qml/ViewHeader.qml \
 	widgets/qml/ProgressIndicator.qml \
-	widgets/qml/RectangularGlow.qml \
 	widgets/qml/ImageExt.qml \
 	widgets/qml/ScrollBarExt.qml \
 	widgets/qml/FastBlend.qml \
@@ -1356,8 +1355,6 @@ libqt_plugin_la_SHADER := shaders/FadingEdge.frag \
                           shaders/Noise.frag \
                           shaders/RectFilter.frag \
                           shaders/SubTexture.vert \
-                          shaders/HollowRectangularGlow.frag \
-                          shaders/RectangularGlow.frag \
                           shaders/SDFAARoundedTexture.frag \
                           shaders/SDFAARoundedTexture_cropsupport_bordersupport.frag \
                           shaders/DitheredTexture.frag \
@@ -1365,7 +1362,8 @@ libqt_plugin_la_SHADER := shaders/FadingEdge.frag \
                           shaders/FastBlend_additive.frag \
                           shaders/FastBlend_multiply.frag \
                           shaders/FastBlend_screen.frag \
-                          shaders/RoundedRectangleShadow.frag
+                          shaders/RoundedRectangleShadow.frag \
+                          shaders/RoundedRectangleShadow_hollow.frag
 if ENABLE_QT
 
 libqt_plugin_la_LIBADD += libqml_module_dialogs.a \


=====================================
modules/gui/qt/maininterface/qml/MainInterface.qml
=====================================
@@ -319,34 +319,24 @@ Item {
 
     //draw the window drop shadow ourselve when the windowing system doesn't
     //provide them but support extended frame
-    Widgets.RectangularGlow {
+    Widgets.RoundedRectangleShadow {
         id: effect
-        z: -1
+        parent: g_mainInterface
         hollow: Window.window && (Window.window.color.a < 1.0) // the interface may be translucent if the window has backdrop blur
         blending: false // stacked below everything, no need for blending even though it is not opaque
         visible: _extendedFrameVisible && !MainCtx.platformHandlesShadowsWithCSD()
-        anchors.fill: g_mainInterface
-        spread: 0.0
-        color: "black"
         opacity:  0.5
-        cornerRadius: glowRadius
-        states: [
-            State {
-                when: MainCtx.intfMainWindow.active
-                PropertyChanges {
-                    target: effect
-                    glowRadius: MainCtx.windowExtendedMargin * 0.7
-                }
-            },
-            State {
-                when: !MainCtx.intfMainWindow.active
-                PropertyChanges {
-                    target: effect
-                    glowRadius: MainCtx.windowExtendedMargin * 0.5
-                }
-            }
-        ]
-        Behavior on  glowRadius {
+
+        // Blur radius can not be greater than (margin / compensationFactor), as in that case it would need bigger
+        // size than the window to compensate. If you want bigger blur radius, either decrease the compensation
+        // factor which can lead to visible clipping, or increase the window extended margin:
+        property real activeBlurRadius: (MainCtx.windowExtendedMargin / effect.compensationFactor)
+
+        blurRadius: MainCtx.intfMainWindow.active ? activeBlurRadius
+                                                  : (activeBlurRadius / 2.0)
+
+        Behavior on blurRadius {
+            // FIXME: Use UniformAnimator instead
             NumberAnimation {
                 duration: VLCStyle.duration_veryShort
             }


=====================================
modules/gui/qt/meson.build
=====================================
@@ -898,7 +898,6 @@ qml_modules += {
         'widgets/qml/PartialEffect.qml',
         'widgets/qml/ViewHeader.qml',
         'widgets/qml/ProgressIndicator.qml',
-        'widgets/qml/RectangularGlow.qml',
         qml_blureffect_file,
         'widgets/qml/ImageExt.qml',
         'widgets/qml/ScrollBarExt.qml',


=====================================
modules/gui/qt/shaders/HollowRectangularGlow.frag deleted
=====================================
@@ -1,58 +0,0 @@
-#version 440
-/*****************************************************************************
- * Copyright (C) 2024 VLC authors and VideoLAN
- * Copyright (C) 2022 The Qt Company Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * ( at your option ) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-layout(location = 0) in vec2 qt_TexCoord0;
-layout(location = 0) out vec4 fragColor;
-
-layout(std140, binding = 0) uniform buf {
-    // qt_Matrix and qt_Opacity must always be both present
-    // if the built-in vertex shader is used.
-    mat4 qt_Matrix;
-    float qt_Opacity;
-    vec4 color;
-    float relativeSizeX;
-    float relativeSizeY;
-    float spread;
-    float width;
-    float height;
-    float cornerRadius;
-    float inverseSpread;
-};
-
-float linearstep(float e0, float e1, float x)
-{
-    return clamp((x - e0) / (e1 - e0), 0.0, 1.0);
-}
-
-void main()
-{
-    // discard inner rectangle:
-    float radius = ((relativeSizeX * width - cornerRadius * 2.0) / (inverseSpread * inverseSpread)) + cornerRadius;
-    if ((qt_TexCoord0.x >= (radius / width) && qt_TexCoord0.x <= (1.0 - (radius / width))) &&
-        (qt_TexCoord0.y >= (radius / height) && qt_TexCoord0.y <= (1.0 - (radius / height))))
-        discard;
-
-    float alpha =
-        smoothstep(0.0, relativeSizeX, 0.5 - abs(0.5 - qt_TexCoord0.x)) *
-        smoothstep(0.0, relativeSizeY, 0.5 - abs(0.5 - qt_TexCoord0.y));
-
-    float spreadMultiplier = linearstep(spread, 1.0 - spread, alpha);
-    fragColor = color * qt_Opacity * spreadMultiplier * alpha;
-}


=====================================
modules/gui/qt/shaders/RectangularGlow.frag deleted
=====================================
@@ -1,47 +0,0 @@
-#version 440
-/*****************************************************************************
- * Copyright (C) 2022 The Qt Company Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * ( at your option ) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-layout(location = 0) in vec2 qt_TexCoord0;
-layout(location = 0) out vec4 fragColor;
-
-layout(std140, binding = 0) uniform buf {
-    // qt_Matrix and qt_Opacity must always be both present
-    // if the built-in vertex shader is used.
-    mat4 qt_Matrix;
-    float qt_Opacity;
-    vec4 color;
-    float relativeSizeX;
-    float relativeSizeY;
-    float spread;
-};
-
-float linearstep(float e0, float e1, float x)
-{
-    return clamp((x - e0) / (e1 - e0), 0.0, 1.0);
-}
-
-void main()
-{
-    float alpha =
-        smoothstep(0.0, relativeSizeX, 0.5 - abs(0.5 - qt_TexCoord0.x)) *
-        smoothstep(0.0, relativeSizeY, 0.5 - abs(0.5 - qt_TexCoord0.y));
-
-    float spreadMultiplier = linearstep(spread, 1.0 - spread, alpha);
-    fragColor = color * qt_Opacity * spreadMultiplier * spreadMultiplier;
-}


=====================================
modules/gui/qt/shaders/RoundedRectangleShadow.frag
=====================================
@@ -105,6 +105,12 @@ void main()
     vec2 compensatedOffset = vec2(blurRadius, blurRadius) * compensationFactor;
     vec2 denormalCoord = size * qt_TexCoord0;
 
+#ifdef HOLLOW
+    if (denormalCoord.x >= compensatedOffset.x && denormalCoord.x <= (size.x - compensatedOffset.x) &&
+        denormalCoord.y >= compensatedOffset.y && denormalCoord.y <= (size.y - compensatedOffset.y))
+      discard;
+#endif
+
     float shadow = roundedBoxShadow(compensatedOffset,
                                     size - compensatedOffset,
                                     denormalCoord,


=====================================
modules/gui/qt/shaders/RoundedRectangleShadow_hollow.frag
=====================================
@@ -0,0 +1,131 @@
+#version 440
+
+// WARNING: This file must be in sync with RoundedRectangleShadow.frag
+// TODO: Generate this shader at build time.
+#define HOLLOW
+
+// TODO: Dithering is not necessary with light colors. It is pretty much
+//       necessary with dark colors due to premultiplied alpha to prevent
+//       color banding. So, this should ideally be used only when the
+//       background color is dark. When the build system starts supporting
+//       defines to feed qsb, we can have the non-dithering version as well.
+#define DITHERING
+
+/*****************************************************************************
+ * Copyright (C) 2025 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#extension GL_GOOGLE_include_directive : enable
+
+#include "Common.glsl"
+
+// This is provided by the default vertex shader even when there is no texture:
+layout(location = 0) in vec2 qt_TexCoord0;
+
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+  mat4 qt_Matrix;
+  float qt_Opacity;
+
+  float blurRadius;
+  float radius;
+  float compensationFactor;
+
+  vec2 size;
+  vec4 color;
+};
+
+// Evan Wallace's Fast Rounded Rectangle Shadows
+// https://madebyevan.com/shaders/fast-rounded-rectangle-shadows/
+// License: CC0 (http://creativecommons.org/publicdomain/zero/1.0/)
+/// <roundedboxshadow>
+
+// A standard gaussian function, used for weighting samples
+float gaussian(float x, float sigma) {
+  const float pi = 3.141592653589793;
+  return exp(-(x * x) / (2.0 * sigma * sigma)) / (sqrt(2.0 * pi) * sigma);
+}
+
+// This approximates the error function, needed for the gaussian integral
+vec2 erf(vec2 x) {
+  vec2 s = sign(x), a = abs(x);
+  x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
+  x *= x;
+  return s - s / (x * x);
+}
+
+// Return the blurred mask along the x dimension
+float roundedBoxShadowX(float x, float y, float sigma, float corner, vec2 halfSize) {
+  float delta = min(halfSize.y - corner - abs(y), 0.0);
+  float curved = halfSize.x - corner + sqrt(max(0.0, corner * corner - delta * delta));
+  vec2 integral = 0.5 + 0.5 * erf((x + vec2(-curved, curved)) * (sqrt(0.5) / sigma));
+  return integral.y - integral.x;
+}
+
+// Return the mask for the shadow of a box from lower to upper
+float roundedBoxShadow(vec2 lower, vec2 upper, vec2 point, float sigma, float corner) {
+  // Center everything to make the math easier
+  vec2 center = (lower + upper) * 0.5;
+  vec2 halfSize = (upper - lower) * 0.5;
+  point -= center;
+
+  // The signal is only non-zero in a limited range, so don't waste samples
+  float low = point.y - halfSize.y;
+  float high = point.y + halfSize.y;
+  float start = clamp(-3.0 * sigma, low, high);
+  float end = clamp(3.0 * sigma, low, high);
+
+  // Accumulate samples (we can get away with surprisingly few samples)
+  float step = (end - start) / 4.0;
+  float y = start + step * 0.5;
+  float value = 0.0;
+  for (int i = 0; i < 4; i++) {
+    value += roundedBoxShadowX(point.x, point.y - y, sigma, corner, halfSize) * gaussian(y, sigma) * step;
+    y += step;
+  }
+
+  return value;
+}
+
+/// </roundedboxshadow>
+
+void main()
+{
+    vec2 compensatedOffset = vec2(blurRadius, blurRadius) * compensationFactor;
+    vec2 denormalCoord = size * qt_TexCoord0;
+
+#ifdef HOLLOW
+    if (denormalCoord.x >= compensatedOffset.x && denormalCoord.x <= (size.x - compensatedOffset.x) &&
+        denormalCoord.y >= compensatedOffset.y && denormalCoord.y <= (size.y - compensatedOffset.y))
+      discard;
+#endif
+
+    float shadow = roundedBoxShadow(compensatedOffset,
+                                    size - compensatedOffset,
+                                    denormalCoord,
+                                    blurRadius,
+                                    radius / 2.);
+
+    fragColor = color * shadow * qt_Opacity; // premultiplied
+
+#ifdef DITHERING
+    float r = rand(qt_TexCoord0) - 0.5;
+    vec4 noise = vec4(r,r,r,r) * DITHERING_STRENGTH;
+    fragColor += noise * step(DITHERING_CUTOFF, fragColor.a); // additive
+#endif
+}


=====================================
modules/gui/qt/shaders/meson.build
=====================================
@@ -13,8 +13,6 @@ shader_sources = [
     'Noise.frag',
     'RectFilter.frag',
     'SubTexture.vert',
-    'HollowRectangularGlow.frag',
-    'RectangularGlow.frag',
     'SDFAARoundedTexture.frag',
     'SDFAARoundedTexture_cropsupport_bordersupport.frag',
     'DitheredTexture.frag',
@@ -23,6 +21,7 @@ shader_sources = [
     'FastBlend_multiply.frag',
     'FastBlend_screen.frag',
     'RoundedRectangleShadow.frag',
+    'RoundedRectangleShadow_hollow.frag',
 ]
 
 shader_files = files(shader_sources)


=====================================
modules/gui/qt/shaders/shaders.qrc
=====================================
@@ -7,8 +7,6 @@
         <file alias="Noise.frag.qsb">Noise.frag.qsb</file>
         <file alias="RectFilter.frag.qsb">RectFilter.frag.qsb</file>
         <file alias="SubTexture.vert.qsb">SubTexture.vert.qsb</file>
-        <file alias="HollowRectangularGlow.frag.qsb">HollowRectangularGlow.frag.qsb</file>
-        <file alias="RectangularGlow.frag.qsb">RectangularGlow.frag.qsb</file>
         <file alias="SDFAARoundedTexture.frag.qsb">SDFAARoundedTexture.frag.qsb</file>
         <file alias="SDFAARoundedTexture_cropsupport_bordersupport.frag.qsb">SDFAARoundedTexture_cropsupport_bordersupport.frag.qsb</file>
         <file alias="DitheredTexture.frag.qsb">DitheredTexture.frag.qsb</file>
@@ -17,5 +15,6 @@
         <file alias="FastBlend_multiply.frag.qsb">FastBlend_multiply.frag.qsb</file>
         <file alias="FastBlend_screen.frag.qsb">FastBlend_screen.frag.qsb</file>
         <file alias="RoundedRectangleShadow.frag.qsb">RoundedRectangleShadow.frag.qsb</file>
+        <file alias="RoundedRectangleShadow_hollow.frag.qsb">RoundedRectangleShadow_hollow.frag.qsb</file>
     </qresource>
 </RCC>


=====================================
modules/gui/qt/widgets/qml/RectangularGlow.qml deleted
=====================================
@@ -1,64 +0,0 @@
-/*****************************************************************************
- * Copyright (C) 2024 VLC authors and VideoLAN
- * Copyright (C) 2020 The Qt Company Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * ( at your option ) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-import QtQuick
-
-Item {
-    id: rootItem
-
-    property real glowRadius: 0.0
-
-    property real spread: 0.0
-
-    property color color: "white"
-
-    property real cornerRadius: glowRadius
-
-    property alias blending: shaderItem.blending
-
-    property alias cullMode: shaderItem.cullMode
-
-    property bool hollow: false
-
-    ShaderEffect {
-        id: shaderItem
-
-        x: (parent.width - width) / 2.0
-        y: (parent.height - height) / 2.0
-        width: parent.width + rootItem.glowRadius * 2 + cornerRadius * 2
-        height: parent.height + rootItem.glowRadius * 2 + cornerRadius * 2
-
-        function clampedCornerRadius() {
-            var maxCornerRadius = Math.min(rootItem.width, rootItem.height) / 2 + glowRadius;
-            return Math.max(0, Math.min(rootItem.cornerRadius, maxCornerRadius))
-        }
-
-        property color color: rootItem.color
-        property real inverseSpread: 1.0 - rootItem.spread
-        property real relativeSizeX: ((inverseSpread * inverseSpread) * rootItem.glowRadius + cornerRadius * 2.0) / width
-        property real relativeSizeY: relativeSizeX * (width / height)
-        property real spread: rootItem.spread / 2.0
-        property real cornerRadius: clampedCornerRadius()
-
-        fragmentShader: rootItem.hollow ? "qrc:///shaders/HollowRectangularGlow.frag.qsb"
-                                        : "qrc:///shaders/RectangularGlow.frag.qsb"
-
-        cullMode: ShaderEffect.BackFaceCulling
-    }
-}


=====================================
modules/gui/qt/widgets/qml/RoundedRectangleShadow.qml
=====================================
@@ -51,11 +51,15 @@ ShaderEffect {
     // to prevent overlapping shadows (breaks batching) and to decrease the shader coverage:
     property real compensationFactor: 2.0
 
+    // Do not paint in the non-compensated inner area - only makes sense if there is compensation:
+    property bool hollow: false
+
     blending: true
 
     supportsAtlasTextures: true // irrelevant, but nevertheless...
 
     // cullMode: ShaderEffect.BackFaceCulling // problematic with item layers
 
-    fragmentShader: "qrc:///shaders/RoundedRectangleShadow.frag.qsb"
+    fragmentShader: hollow ? "qrc:///shaders/RoundedRectangleShadow_hollow.frag.qsb"
+                           : "qrc:///shaders/RoundedRectangleShadow.frag.qsb"
 }



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/09dc8b44f9b7b3b98ba62be58939185be4e532e6...cd2c8fb5520e688a27a251adafcfa8b5b0eb9f6c

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/09dc8b44f9b7b3b98ba62be58939185be4e532e6...cd2c8fb5520e688a27a251adafcfa8b5b0eb9f6c
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