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

Correct shadows for shaped and rounded windows #882

Merged
merged 20 commits into from
Sep 16, 2022
Merged

Correct shadows for shaped and rounded windows #882

merged 20 commits into from
Sep 16, 2022

Conversation

yshui
Copy link
Owner

@yshui yshui commented Aug 26, 2022

Example:

Based on #881 This is only implemented for glx, not xrender.

This is used to create image masks that can be used to mask out
`compose` regions. For example, this can be used to mask out window body
so shadow won't be painted on them.

This could be more efficient than using rectangular regions for masking,
when there are a large number of rectangles; or more flexible, in the
case of window with rounded corners.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Use masks in compose.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
There are some complications, when sampling pixels outside a
xrender picture, xrender doesn't support a behaviour similar to OpenGL's
clamp to border. So we give the masks an extra 1-pixel outer rim, so
we can control what color the outside pixels would be, by using the
"Pad" repeat mode.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
When removing shadow behind a window with rounded corners, keep the
corner part - those parts will be removed using the mask instead.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
gl_common.c is getting too big.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Instead of always using the back texture/fbo. Also use the size of the
source texture, instead of hard coded back buffer size.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Using integral to estimate the sum of the kernel will overestimate a
little bit.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Since image_dst is in X coordinates, after flipping Y, we need to
subtract the height of the drawing area, to make it the bottom right
corner for OpenGL.

However, this breaks blur. Because we assumed the drawing area is the
same size as the texture, which is not the case for blur. So add the
height of the drawing area as another parameter.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
If the backend implements shadow_from_mask then it doesn't need to
implement render_shadow.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Do this for shaped, and rounded windows.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
@codecov
Copy link

codecov bot commented Aug 26, 2022

Codecov Report

Merging #882 (0777f07) into next (e0758eb) will decrease coverage by 0.79%.
The diff coverage is 7.84%.

❗ Current head 0777f07 differs from pull request most recent head 483aa43. Consider uploading reports for the commit 483aa43 to get more accurate results

Impacted file tree graph

@@            Coverage Diff             @@
##             next     #882      +/-   ##
==========================================
- Coverage   39.01%   38.22%   -0.80%     
==========================================
  Files          46       47       +1     
  Lines        9976    10342     +366     
==========================================
+ Hits         3892     3953      +61     
- Misses       6084     6389     +305     
Impacted Files Coverage Δ
src/backend/gl/blur.c 0.00% <0.00%> (ø)
src/backend/gl/gl_common.h 30.23% <ø> (-0.72%) ⬇️
src/backend/gl/glx.c 38.48% <0.00%> (+0.49%) ⬆️
src/backend/xrender/xrender.c 0.00% <0.00%> (ø)
src/common.h 75.00% <ø> (ø)
src/kernel.h 100.00% <ø> (ø)
src/render.c 1.30% <0.00%> (ø)
src/utils.h 48.38% <ø> (ø)
src/win.h 78.12% <ø> (ø)
src/backend/gl/gl_common.c 25.33% <11.73%> (+9.24%) ⬆️
... and 9 more

@nawuko
Copy link

nawuko commented Aug 27, 2022

This will be an awesome feature 👍

Dunno if it is ready for testing, shadow branch (0777f07) dosen't draw any shadows, i get following error:
picom[863747]: [ 27.08.2022 16:09:16.603 gl_create_shader ERROR ] GLX error at line 61: GL_INVALID_OPERATION

Nvidia Closed Source Driver
Driver Version: 515.65.01
CUDA Version: 11.7
Backend: glx
Shape: Yes
XRandR: Yes
Present: Present
Use Overlay: Yes
OpenGL ES profile version string: OpenGL ES 3.2 NVIDIA 515.65.01
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20

Shadows work on branch mask (e4221e0)

@yshui
Copy link
Owner Author

yshui commented Aug 27, 2022

@nawuko can you record a trace?

@yshui
Copy link
Owner Author

yshui commented Aug 27, 2022

@nawuko also, is there more in the log?

@nawuko
Copy link

nawuko commented Aug 29, 2022

@nawuko also, is there more in the log?

Nothing more in the logs, with default logging level, with trace logging i get the following (truncated)

[ 29.08.2022 13:13:13.295 redirect_start DEBUG ] Redirecting the screen.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Found GLX extension GLX_SGI_video_sync.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Found GLX extension GLX_SGI_swap_control.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Missing GLX extension GLX_OML_sync_control.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Missing GLX extension GLX_MESA_swap_control.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Found GLX extension GLX_EXT_swap_control.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Found GLX extension GLX_EXT_texture_from_pixmap.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Found GLX extension GLX_ARB_create_context.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Found GLX extension GLX_EXT_buffer_age.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Found GLX extension GLX_ARB_create_context_robustness.
[ 29.08.2022 13:13:13.297 glx_has_extension INFO ] Missing GLX extension GLX_MESA_query_renderer.
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
uniform mat4 projection; uniform float scale = 1.0; uniform vec2 texorig; layout(location = 0) in vec2 coord; layout(location = 1) in vec2 in_texcoord; out vec2 texcoord; void main() { gl_Position = projection * vec4(coord, 0, scale); texcoord = in_texcoord + texorig; }
===
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
uniform float opacity; uniform float dim; uniform float corner_radius; uniform float border_width; uniform bool invert_color; in vec2 texcoord; uniform sampler2D tex; uniform sampler2D brightness; uniform float max_brightness; float rectangle_sdf(vec2 point, vec2 half_size) { vec2 d = abs(point) - half_size; return length(max(d, 0.0)); } vec4 default_post_processing(vec4 c) { vec4 border_color = texture(tex, vec2(0.0, 0.5)); if (invert_color) { c = vec4(c.aaa - c.rgb, c.a); border_color = vec4(border_color.aaa - border_color.rgb, border_color.a); } c = vec4(c.rgb * (1.0 - dim), c.a) * opacity; border_color = vec4(border_color.rgb * (1.0 - dim), border_color.a) * opacity; vec3 rgb_brightness = texelFetch(brightness, ivec2(0, 0), 0).rgb; float brightness = rgb_brightness.r * 0.21 + rgb_brightness.g * 0.72 + rgb_brightness.b * 0.07; if (brightness > max_brightness) { c.rgb = c.rgb * (max_brightness / brightness); border_color.rgb = border_color.rgb * (max_brightness / brightness); } vec4 rim_color = mix(c, border_color, clamp(border_width, 0.0f, 1.0f)); vec2 outer_size = vec2(textureSize(tex, 0)); vec2 inner_size = outer_size - vec2(corner_radius) * 2.0f; float rect_distance = rectangle_sdf(texcoord - outer_size / 2.0f, inner_size / 2.0f) - corner_radius; if (rect_distance > 0.0f) { c = (1.0f - clamp(rect_distance, 0.0f, 1.0f)) * rim_color; } else { float factor = clamp(rect_distance + border_width, 0.0f, 1.0f); c = (1.0f - factor) * c + factor * border_color; } return c; } vec4 window_shader(); float mask_factor(); void main() { gl_FragColor = window_shader() * mask_factor(); }
===
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
uniform sampler2D mask_tex; uniform vec2 mask_offset; uniform float mask_corner_radius; uniform bool mask_inverted; in vec2 texcoord; float mask_rectangle_sdf(vec2 point, vec2 half_size) { vec2 d = abs(point) - half_size; return length(max(d, 0.0)); } float mask_factor() { vec2 mask_size = textureSize(mask_tex, 0); vec2 maskcoord = texcoord - mask_offset; vec4 mask = texture2D(mask_tex, maskcoord / mask_size); if (mask_corner_radius != 0) { vec2 inner_size = mask_size - vec2(mask_corner_radius) * 2.0f; float dist = mask_rectangle_sdf(maskcoord - mask_size / 2.0f, inner_size / 2.0f) - mask_corner_radius; if (dist > 0.0f) { mask.r *= (1.0f - clamp(dist, 0.0f, 1.0f)); } } if (mask_inverted) { mask.rgb = 1.0 - mask.rgb; } return mask.r; }
===
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
in vec2 texcoord; uniform sampler2D tex; vec4 default_post_processing(vec4 c); vec4 window_shader() { vec4 c = texelFetch(tex, ivec2(texcoord), 0); return default_post_processing(c); }
===
[ 29.08.2022 13:13:13.327 glGetUniformLocationChecked INFO ] Failed to get location of uniform 'time'. This is normal when using custom shaders.
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
layout(location = 0) in vec2 in_coord; uniform mat4 projection; void main() { gl_Position = projection * vec4(in_coord, 0, 1); }
===
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
uniform vec4 color; void main() { gl_FragColor = color; }
===
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
uniform mat4 projection; layout(location = 0) in vec2 coord; out vec2 texcoord; void main() { gl_Position = projection * vec4(coord, 0, 1); texcoord = coord; }
===
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
uniform sampler2D tex; in vec2 texcoord; void main() { gl_FragColor = texelFetch(tex, ivec2(texcoord.xy), 0); }
===
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
uniform mat4 projection; layout(location = 0) in vec2 coord; out vec2 texcoord; void main() { gl_Position = projection * vec4(coord, 0, 1); texcoord = coord; }
===
[ 29.08.2022 13:13:13.327 gl_create_shader TRACE ] ===
#version 330
uniform vec4 color; uniform sampler2D tex; in vec2 texcoord; out vec4 out_color; void main() { vec4 c = texelFetch(tex, ivec2(texcoord), 0); out_color = c.r * color; }
===
[ 29.08.2022 13:13:13.328 gl_create_shader TRACE ] ===
#version 330
uniform mat4 projection; uniform vec2 texsize; layout(location = 0) in vec2 in_coord; layout(location = 1) in vec2 in_texcoord; out vec2 texcoord; void main() { gl_Position = projection * vec4(in_coord, 0, 1); texcoord = in_texcoord / texsize; }
===
-[ 29.08.2022 13:13:13.328 gl_create_shader ERROR ] GLX error at line 61: GL_INVALID_OPERATION
[ 29.08.2022 13:13:13.328 gl_create_shader TRACE ] ===
#version 330
uniform sampler2D tex; in vec2 texcoord; void main() { gl_FragColor = vec4(texture2D(tex, vec2(texcoord.xy), 0).rgb, 1); }
===
[ 29.08.2022 13:13:13.328 gl_has_extension INFO ] Missing GL extension GL_GREMEDY_string_marker.
[ 29.08.2022 13:13:13.328 gl_init DEBUG ] GL_VENDOR = NVIDIA Corporation
[ 29.08.2022 13:13:13.328 gl_init INFO ] GL vendor is NVIDIA, don't use glFinish
[ 29.08.2022 13:13:13.328 gl_create_shader TRACE ] ===
#version 330
uniform mat4 projection; uniform float scale = 1.0; uniform vec2 texorig; layout(location = 0) in vec2 coord; layout(location = 1) in vec2 in_texcoord; out vec2 texcoord; void main() { gl_Position = projection * vec4(coord, 0, scale); texcoord = in_texcoord + texorig; }
===
[ 29.08.2022 13:13:13.328 gl_create_shader TRACE ] ===
#version 330
uniform sampler2D tex_src; uniform float scale = 1.0; uniform vec2 pixel_norm; in vec2 texcoord; out vec4 out_color; void main() { vec2 offset = 4.25 * pixel_norm; vec2 uv = texcoord * pixel_norm * (2.0 / scale); vec4 sum = texture2D(tex_src, uv) * 4.0; sum += texture2D(tex_src, uv - vec2(0.5, 0.5) * offset); sum += texture2D(tex_src, uv + vec2(0.5, 0.5) * offset); sum += texture2D(tex_src, uv + vec2(0.5, -0.5) * offset); sum += texture2D(tex_src, uv - vec2(0.5, -0.5) * offset); out_color = sum / 8.0; }
===
[ 29.08.2022 13:13:13.328 gl_create_shader TRACE ] ===
#version 330
uniform mat4 projection; uniform float scale = 1.0; uniform vec2 texorig; layout(location = 0) in vec2 coord; layout(location = 1) in vec2 in_texcoord; out vec2 texcoord; void main() { gl_Position = projection * vec4(coord, 0, scale); texcoord = in_texcoord + texorig; }
===
[ 29.08.2022 13:13:13.328 gl_create_shader TRACE ] ===
#version 330
uniform sampler2D tex_src; uniform float scale = 1.0; uniform vec2 pixel_norm; uniform float opacity; in vec2 texcoord; out vec4 out_color; float mask_factor(); void main() { vec2 offset = 4.25 * pixel_norm; vec2 uv = texcoord * pixel_norm / (2 * scale); vec4 sum = texture2D(tex_src, uv + vec2(-1.0, 0.0) * offset); sum += texture2D(tex_src, uv + vec2(-0.5, 0.5) * offset) * 2.0; sum += texture2D(tex_src, uv + vec2(0.0, 1.0) * offset); sum += texture2D(tex_src, uv + vec2(0.5, 0.5) * offset) * 2.0; sum += texture2D(tex_src, uv + vec2(1.0, 0.0) * offset); sum += texture2D(tex_src, uv + vec2(0.5, -0.5) * offset) * 2.0; sum += texture2D(tex_src, uv + vec2(0.0, -1.0) * offset); sum += texture2D(tex_src, uv + vec2(-0.5, -0.5) * offset) * 2.0; out_color = sum / 12.0 * opacity * mask_factor(); }
===
[ 29.08.2022 13:13:13.328 gl_create_shader TRACE ] ===
#version 330
uniform sampler2D mask_tex; uniform vec2 mask_offset; uniform float mask_corner_radius; uniform bool mask_inverted; in vec2 texcoord; float mask_rectangle_sdf(vec2 point, vec2 half_size) { vec2 d = abs(point) - half_size; return length(max(d, 0.0)); } float mask_factor() { vec2 mask_size = textureSize(mask_tex, 0); vec2 maskcoord = texcoord - mask_offset; vec4 mask = texture2D(mask_tex, maskcoord / mask_size); if (mask_corner_radius != 0) { vec2 inner_size = mask_size - vec2(mask_corner_radius) * 2.0f; float dist = mask_rectangle_sdf(maskcoord - mask_size / 2.0f, inner_size / 2.0f) - mask_corner_radius; if (dist > 0.0f) { mask.r *= (1.0f - clamp(dist, 0.0f, 1.0f)); } } if (mask_inverted) { mask.rgb = 1.0 - mask.rgb; } return mask.r; }
===

Sadly can't provide an apitrace atm.
I have blur, dbus, opacity disabled, rounding (corner-radius), fading and shadows active.

@doums
Copy link

doums commented Aug 29, 2022

Hello, I observe the same error, no shadow is rendered.

Arch Linux 5.19.4-arch1-1
Xorg
XMonad (No DE)
Nvidia proprietary driver: nvidia and nvidia-utils
Driver Version: 515.65.01
Backend: glx

you can find my config here -> https://github.com/doums/dotfiles/blob/master/.config/picom.conf

error in picom logs

[ 29/08/2022 18:51:58.134 gl_create_shader ERROR ] GLX error at line 61: GL_INVALID_OPERATION

I tried to generate a trace, sadly I got an error with apitrace preventing to start picom.

picom: symbol lookup error: /usr/bin/../lib/apitrace/wrappers/glxtrace.so: undefined symbol: __libc_dlsym, version GLIBC_PRIVATE

Edit: On a different machine, same Linux distribution, similar install, but with xf86-video-intel and mesa instead of nvidia proprietary driver, there is no shadow problem. It's likely a nvidia compatibility problem.

@frebib
Copy link

frebib commented Aug 30, 2022

I can also reproduce this with nvidia proprietary drivers and glx backend. Here's an apitrace
(I also ran into the same libc issue with apitrace as @doums. I recompiled it with this patch applied: apitrace/apitrace@d28a980)
picom.trace.tar.gz
I had to compress it so github would accept upload.

A small snippet from the dumped trace:

203 glCreateShader(type = GL_VERTEX_SHADER) = 1
204 glShaderSource(shader = 1, count = 1, string = &"#version 330
uniform mat4 projection; uniform vec2 texsize; layout(location = 0) in vec2 in_coord; layout(location = 1) in vec2 in_texcoord; out vec2 texcoord; void main() { gl_Position = projection * vec4(in_coord, 0, 1); texcoord = in_texcoord / texsize; }", length = NULL)
205 glCompileShader(shader = 1)
206 glGetShaderiv(shader = 1, pname = GL_COMPILE_STATUS, params = &1)
207 glGetError() = GL_INVALID_OPERATION

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
@yshui
Copy link
Owner Author

yshui commented Aug 31, 2022

@frebib Thanks for the trace! I have fixed the problem, apparently a typo... 😢

@nawuko
Copy link

nawuko commented Aug 31, 2022

Can confirm, its working for me now on nvidia 👍

@doums
Copy link

doums commented Aug 31, 2022

image
I confirm too, thx for this PR.

@frebib
Copy link

frebib commented Aug 31, 2022

Works great for me too. Thanks for the quick fix!
It's so good to finally get this functionality without the performance penalty that other patches with this functionality incur.
Great work 🎉

@frebib
Copy link

frebib commented Aug 31, 2022

Out of curiosity, should this fix the shadow/blur behind windows with strange bounding boxes like the context menus in Firefox? I still see a small ~5-6 pixel border of shadow/blur even with this patch and I'm not sure if that's intentional. I have shadow-ignore-shaped=false and detect-rounded-corners=true although I'm not sure they'd help towards that

@yshui
Copy link
Owner Author

yshui commented Aug 31, 2022

@frebib unfortunately no, firefox's context menu doesn't use the X shape extension, it just has parts of it being completely transparent. that's why there are gaps.

i am considering adding an option to use windows' alpha channels as their bounding shape, which would solve this.

@yshui
Copy link
Owner Author

yshui commented Sep 9, 2022

I wonder how many people has already tested this branch?

@doums
Copy link

doums commented Sep 9, 2022

I wonder how many people has already tested this branch?

At least 3 peoples, me on two different machines, with both Nvidia proprietary and free drivers.

@frebib
Copy link

frebib commented Sep 9, 2022

Second that. I have this running on two computers with one running proprietary nvidia drivers and the other i915 iGPU and it's running great

@yshui
Copy link
Owner Author

yshui commented Sep 16, 2022

OK, let's make the call and merge this without @tryone144's review.

@tryone144 please still do have a look at this when you find some time! i still would like to hear your input.

@yshui yshui merged commit f2970bc into next Sep 16, 2022
@yshui yshui deleted the shadow branch September 16, 2022 14:15
@Monsterovich
Copy link
Contributor

Monsterovich commented Sep 17, 2022

Wth happened to the shadows. They are ugly now.

Now:
Снимок экрана_2022-09-18_01-04-23
Before:
Снимок экрана_2022-09-18_01-05-18

P.S. My config is here: #863 Nothing has changed ever since.

@yshui
Copy link
Owner Author

yshui commented Sep 18, 2022

@Monsterovich I was trying out using dual kawase blur for shadow, I changed it back to gaussian now.

@doums
Copy link

doums commented Sep 19, 2022

I was observing the same as @Monsterovich, but playing a bit with shadow values fixed the issue, but yea shadow was rendered differently.

@Monsterovich
Copy link
Contributor

I was observing the same as @Monsterovich, but playing a bit with shadow values fixed the issue, but yea shadow was rendered differently.

How did you fix it?

@doums
Copy link

doums commented Sep 19, 2022

Using these values

shadow-radius = 11;
shadow-offset-x = -16;
shadow-offset-y = -12;

at least for me it kinda fix what we observe on your first screenshot
but it's definitively not good as before

@yshui
Copy link
Owner Author

yshui commented Sep 19, 2022

@Monsterovich it should be back to what it used to be on latest git.

@Monsterovich
Copy link
Contributor

@Monsterovich it should be back to what it used to be on latest git.

I don't see any new commits in the "next" branch. Have you pushed them yet?

@yshui
Copy link
Owner Author

yshui commented Sep 19, 2022

@Monsterovich oops, I didn't. 😅 Sorry about that!

@Monsterovich
Copy link
Contributor

@yshui Thank you! Could you please take a look at #863? This issue is really annoying.

@Monsterovich
Copy link
Contributor

@yshui There is also a bit of a problem with the new changes. The underside of the shadow is smooth as it was before. But the sides are not smooth. Why is that? Without zooming in it looks like graphical artifacts.

изображение

@Monsterovich
Copy link
Contributor

@yshui Can you suggest a fix for the ugly effect with the shadows? #882 (comment)?

bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this pull request Nov 15, 2022
https://build.opensuse.org/request/show/1035698
by user mia + dimstar_suse
- Update to version 10
  * picom now needs libEGL to build
Notable changes:
  * experimental-backends is now the default. Everything should
    keep working, except the --glx-fshader-win option. The old
    window shader support has been replaced by --window-shader-fd.
    This new shader support has a different interface, so you have
    to adapt your existing shaders.
    gh#yshui/picom#875
  * legacy-backends option has been added so you can go back to the
    old backends, which will eventually be removed.
  * picom.desktop is installed to /etc/xdg/autostart/.
    picom should autostart now.
    gh#yshui/picom#791
  * Shadows and blur now match the shape of the window.
    This includes windows using the XShape extension, and windows
    with rounded corners.
    gh#yshui/picom#882
  *
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants