Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blur/rounded-corners: rewrite #68

Merged
merged 27 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ac8382c
blur: improve rounded corners implementation
taj-ny May 9, 2024
37e4446
blur/rounded-corners: use uv to get pixel position instead of gl_Frag…
taj-ny May 10, 2024
0f9644c
blur/rounded-corners: fix corners sometimes not being rounded
taj-ny May 10, 2024
b7b4cd5
blur/rounded-corners: don't use rounded corners shader when painting …
taj-ny May 10, 2024
7debe91
blur: fix drawing images behind windows
taj-ny May 10, 2024
87fbddb
blur/rounded-corners: multiply radius by display scale
taj-ny May 10, 2024
836981e
blur/rounded-corners: set active texture to 0 after painting
taj-ny May 10, 2024
0e65dee
blur/rounded-corners: allow corners to occupy more than half of the r…
taj-ny May 18, 2024
bcb72da
blur/rounded-corners: remove corners from opaque region when using fa…
taj-ny May 18, 2024
51e1e0c
index on develop: bcb72da blur/rounded-corners: remove corners from o…
taj-ny May 18, 2024
3732dec
WIP on develop: bcb72da blur/rounded-corners: remove corners from opa…
taj-ny May 18, 2024
2ca3888
blur/rounded-corners: do some stuff
taj-ny Jun 2, 2024
8c8ad5a
blur/rounded-corners: fix various issues when using scaling
taj-ny Jun 15, 2024
82924af
Merge remote-tracking branch 'origin/main' into better-rounded-corners
taj-ny Jun 15, 2024
bcbf1ff
blur/rounded-corners: don't round floating panels
taj-ny Jun 15, 2024
6170c10
blur/rounded-corners: fix corners not being rounded when the window i…
taj-ny Jun 16, 2024
c23daee
kcm: use QSpinBox for corner radius instead of QDoubleSpinBox
taj-ny Jun 16, 2024
bb070a4
blur/rounded-corners: fix noise texture behavior when antialiasing is…
taj-ny Jun 16, 2024
e57bf4a
Revert "blur/rounded-corners: fix noise texture behavior when antiali…
taj-ny Jun 16, 2024
4351b0a
Merge branch 'develop' into better-rounded-corners
taj-ny Jun 16, 2024
c79c6ad
blur/rounded-corners: add back condition to check whether window is m…
taj-ny Jun 16, 2024
fc3e9cd
readme: update
taj-ny Jun 16, 2024
1e6a5bd
readme: update screenshot
taj-ny Jun 16, 2024
5e5953b
blur/rounded-corners: add comment describing how anti-aliasing is imp…
taj-ny Jun 16, 2024
2aec5a1
blur/rounded-corners: allow setting separate radius for menus and docks
taj-ny Jun 17, 2024
f3c073d
fix comments
taj-ny Jun 17, 2024
6b856b1
Merge branch 'develop' into better-rounded-corners
taj-ny Jun 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
# kwin-effects-forceblur [![AUR Version](https://img.shields.io/aur/version/kwin-effects-forceblur)](https://aur.archlinux.org/packages/kwin-effects-forceblur)
A fork of the KWin Blur effect for KDE Plasma 6 with the ability to blur any window on Wayland and X11.
Kwin-effects-forceblur (name subject to change) is a fork of the KWin Blur effect for KDE Plasma 6 with several improvements and bug fixes.

Latest features are available on the ``develop`` branch.

![image](https://github.com/taj-ny/kwin-effects-forceblur/assets/79316397/9d2f337e-badd-4d95-ba55-96c80202e196)
<sup>Window opacity has been set to 85% for System Settings and Dolphin, Firefox uses a transparent theme | [NixOS configuration](https://github.com/taj-ny/nix-config)</sup>
![image](https://github.com/taj-ny/kwin-effects-forceblur/assets/79316397/1078cf12-e6da-43c7-80b4-d90a8b0f3404)
<sup>Window opacity has been set to 85% for System Settings, Dolphin and VSCodium, Firefox uses a transparent theme | [NixOS configuration](https://github.com/taj-ny/nix-config)</sup>

# Features
- Wayland support
- Force blur
- Rounded corners with optional anti-aliasing
- Draw image behind windows instead of blurring (can be used with a blurred image of the wallpaper in order to achieve a very similar effect to blur but with **much** lower GPU usage)
- Rounded corners
- Fix for [artifacts](https://github.com/taj-ny/kwin-effects-forceblur/pull/38) when using a transparent color scheme

### Bug fixes
Fixes for blur-related Plasma bugs that haven't been patched yet.

- Blur may sometimes disappear during animations
- [Transparent color schemes don't work properly with the Breeze application style](https://github.com/taj-ny/kwin-effects-forceblur/pull/38)

# Installation
<details>
Expand Down
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

478 changes: 372 additions & 106 deletions src/blur.cpp

Large diffs are not rendered by default.

59 changes: 48 additions & 11 deletions src/blur.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,27 @@ public Q_SLOTS:

private:
void initBlurStrengthValues();
QRegion blurRegion(EffectWindow *w, bool noRoundedCorners = false) const;
QRegion blurRegion(EffectWindow *w) const;
QRegion decorationBlurRegion(const EffectWindow *w) const;
QRegion transformedBlurRegion(QRegion blurRegion, const WindowPaintData &data) const;
bool decorationSupportsBlurBehind(const EffectWindow *w) const;
bool shouldBlur(const EffectWindow *w, int mask, const WindowPaintData &data);
bool shouldForceBlur(const EffectWindow *w) const;
void updateBlurRegion(EffectWindow *w);
void updateCornerRegions();
void blur(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, const QRegion &region, WindowPaintData &data);
GLTexture *ensureNoiseTexture();
bool hasFakeBlur(EffectWindow *w) const;

/*
* @returns An array containing rounded corner masks for the given screen scale and radii. If no masks exist, they
* will be generated.
*/
std::array<QRegion, 4> roundedCorners(int topCornerRadius, int bottomCornerRadius, qreal scale);

/*
* Generates rounded corner masks for the left and right corner of the given radius.
* @param top Whether the corners belong to the top part of the window.
*/
void generateRoundedCornerMasks(int radius, QRegion &left, QRegion &right, bool top) const;

private:
struct
Expand Down Expand Up @@ -123,10 +134,33 @@ public Q_SLOTS:
int mvpMatrixLocation;
int textureSizeLocation;
int texStartPosLocation;
int regionSizeLocation;

std::unique_ptr<GLTexture> texture;
} m_texturePass;

struct
{
std::unique_ptr<GLShader> shader;

int roundTopLeftCornerLocation;
int roundTopRightCornerLocation;
int roundBottomLeftCornerLocation;
int roundBottomRightCornerLocation;

int topCornerRadiusLocation;
int bottomCornerRadiusLocation;

int antialiasingLocation;

int regionSizeLocation;

int beforeBlurTextureLocation;
int afterBlurTextureLocation;

int mvpMatrixLocation;
} m_roundedCorners;

bool m_valid = false;
long net_wm_blur_region = 0;
QRegion m_paintedArea; // keeps track of all painted areas (from bottom to top)
Expand All @@ -142,9 +176,6 @@ public Q_SLOTS:
bool m_blurNonMatching;
bool m_blurDecorations;
bool m_transparentBlur;
int m_topCornerRadius;
int m_bottomCornerRadius;
bool m_roundCornersOfMaximizedWindows;
bool m_blurMenus;
bool m_blurDocks;
bool m_paintAsTranslucent;
Expand All @@ -153,11 +184,17 @@ public Q_SLOTS:

bool m_hasValidFakeBlurTexture;

// Regions to subtract from the blurred region
QRegion m_topLeftCorner;
QRegion m_topRightCorner;
QRegion m_bottomLeftCorner;
QRegion m_bottomRightCorner;
int m_windowTopCornerRadius;
int m_windowBottomCornerRadius;
int m_menuCornerRadius;
int m_dockCornerRadius;
float m_roundedCornersAntialiasing;
bool m_roundCornersOfMaximizedWindows;
int m_cornerRadiusOffset;

// Corner masks where the key is the screen scale and the value is an array of the masks
// (top left, top right, bottom left, bottom right). Used for rounding the blur region.
std::map<const std::tuple<int, int, qreal>, std::array<QRegion, 4>> m_corners;

struct OffsetStruct
{
Expand Down
9 changes: 9 additions & 0 deletions src/blur.kcfg
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ class3</default>
<entry name="BottomCornerRadius" type="Int">
<default>0</default>
</entry>
<entry name="MenuCornerRadius" type="Int">
<default>0</default>
</entry>
<entry name="DockCornerRadius" type="Int">
<default>0</default>
</entry>
<entry name="RoundedCornersAntialiasing" type="Double">
<default>1.0</default>
</entry>
<entry name="RoundCornersOfMaximizedWindows" type="Bool">
<default>false</default>
</entry>
Expand Down
2 changes: 2 additions & 0 deletions src/blur.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<file>shaders/downsample_core.frag</file>
<file>shaders/noise.frag</file>
<file>shaders/noise_core.frag</file>
<file>shaders/roundedcorners.frag</file>
<file>shaders/roundedcorners_core.frag</file>
<file>shaders/texture.frag</file>
<file>shaders/texture_core.frag</file>
<file>shaders/upsample.frag</file>
Expand Down
58 changes: 56 additions & 2 deletions src/kcm/blur_config.ui
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@
<item>
<widget class="QLabel">
<property name="text">
<string>Top corner radius</string>
<string>Window top corner radius</string>
</property>
</widget>
</item>
Expand All @@ -339,7 +339,7 @@
<item>
<widget class="QLabel">
<property name="text">
<string>Bottom corner radius</string>
<string>Window bottom corner radius</string>
</property>
</widget>
</item>
Expand All @@ -352,6 +352,60 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel">
<property name="text">
<string>Menu corner radius</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="kcfg_MenuCornerRadius">
<property name="minimum">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel">
<property name="text">
<string>Dock corner radius</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="kcfg_DockCornerRadius">
<property name="minimum">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel">
<property name="text">
<string>Anti-aliasing</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="kcfg_RoundedCornersAntialiasing">
<property name="minimum">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="kcfg_RoundCornersOfMaximizedWindows">
<property name="text">
Expand Down
53 changes: 53 additions & 0 deletions src/shaders/roundedcorners.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Modified version of https://www.shadertoy.com/view/ldfSDj

uniform bool roundTopLeftCorner;
uniform bool roundTopRightCorner;
uniform bool roundBottomLeftCorner;
uniform bool roundBottomRightCorner;

uniform int topCornerRadius;
uniform int bottomCornerRadius;

uniform float antialiasing;

uniform vec2 regionSize;

uniform sampler2D beforeBlurTexture;
uniform sampler2D afterBlurTexture;

varying vec2 uv;

float udRoundBox(vec2 p, vec2 b, vec2 fragCoord)
{
float radius = 0.0;
if ((fragCoord.y <= topCornerRadius)
&& ((roundTopLeftCorner && fragCoord.x <= topCornerRadius)
|| (roundTopRightCorner && fragCoord.x >= regionSize.x - topCornerRadius))) {
radius = topCornerRadius;
p.y -= radius;
} else if ((fragCoord.y >= regionSize.y - bottomCornerRadius)
&& ((roundBottomLeftCorner && fragCoord.x <= bottomCornerRadius)
|| (roundBottomRightCorner && fragCoord.x >= regionSize.x - bottomCornerRadius))) {
radius = bottomCornerRadius;
p.y += radius;
}

return length(max(abs(p) - (b + vec2(0.0, radius)) + radius, 0.0)) - radius;
}

void main(void)
{
vec2 halfRegionSize = regionSize * 0.5;
vec2 fragCoord = uv * regionSize;
float box = udRoundBox(fragCoord - halfRegionSize, halfRegionSize, fragCoord);

// If antialiasing is 0, the shader will be used to generate corner masks.
vec3 foreground = vec3(1.0, 1.0, 1.0);
vec3 background = vec3(0.0, 0.0, 0.0);
if (antialiasing > 0.0) {
foreground = texture2D(afterBlurTexture, uv).rgb;
background = texture2D(beforeBlurTexture, uv).rgb;
}

gl_FragColor = vec4(mix(foreground, background, smoothstep(0.0, antialiasing, box)), 1.0);
}
57 changes: 57 additions & 0 deletions src/shaders/roundedcorners_core.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#version 140

// Modified version of https://www.shadertoy.com/view/ldfSDj

uniform bool roundTopLeftCorner;
uniform bool roundTopRightCorner;
uniform bool roundBottomLeftCorner;
uniform bool roundBottomRightCorner;

uniform int topCornerRadius;
uniform int bottomCornerRadius;

uniform float antialiasing;

uniform vec2 regionSize;

uniform sampler2D beforeBlurTexture;
uniform sampler2D afterBlurTexture;

in vec2 uv;

out vec4 fragColor;

float udRoundBox(vec2 p, vec2 b, vec2 fragCoord)
{
float radius = 0.0;
if ((fragCoord.y <= topCornerRadius)
&& ((roundTopLeftCorner && fragCoord.x <= topCornerRadius)
|| (roundTopRightCorner && fragCoord.x >= regionSize.x - topCornerRadius))) {
radius = topCornerRadius;
p.y -= radius;
} else if ((fragCoord.y >= regionSize.y - bottomCornerRadius)
&& ((roundBottomLeftCorner && fragCoord.x <= bottomCornerRadius)
|| (roundBottomRightCorner && fragCoord.x >= regionSize.x - bottomCornerRadius))) {
radius = bottomCornerRadius;
p.y += radius;
}

return length(max(abs(p) - (b + vec2(0.0, radius)) + radius, 0.0)) - radius;
}

void main(void)
{
vec2 halfRegionSize = regionSize * 0.5;
vec2 fragCoord = uv * regionSize;
float box = udRoundBox(fragCoord - halfRegionSize, halfRegionSize, fragCoord);

// If antialiasing is 0, the shader will be used to generate corner masks.
vec3 foreground = vec3(1.0, 1.0, 1.0);
vec3 background = vec3(0.0, 0.0, 0.0);
if (antialiasing > 0.0) {
foreground = texture(afterBlurTexture, uv).rgb;
background = texture(beforeBlurTexture, uv).rgb;
}

fragColor = vec4(mix(foreground, background, smoothstep(0.0, antialiasing, box)), 1.0);
}
4 changes: 2 additions & 2 deletions src/shaders/texture.frag
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
uniform sampler2D texUnit;
uniform vec2 textureSize;
uniform vec2 texStartPos;
uniform vec2 regionSize;

varying vec2 uv;

void main(void)
{
vec2 tex = vec2((texStartPos.xy + gl_FragCoord.xy) / textureSize);

vec2 tex = (texStartPos.xy + vec2(uv.x, 1.0 - uv.y) * regionSize) / textureSize;
gl_FragColor = vec4(texture2D(texUnit, tex).rgb, 0);
}
4 changes: 2 additions & 2 deletions src/shaders/texture_core.frag
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
uniform sampler2D texUnit;
uniform vec2 textureSize;
uniform vec2 texStartPos;
uniform vec2 regionSize;

in vec2 uv;

out vec4 fragColor;

void main(void)
{
vec2 tex = vec2((texStartPos.xy + gl_FragCoord.xy) / textureSize);

vec2 tex = (texStartPos.xy + vec2(uv.x, 1.0 - uv.y) * regionSize) / textureSize;
fragColor = vec4(texture(texUnit, tex).rgb, 0);
}
Loading