-
-
Notifications
You must be signed in to change notification settings - Fork 588
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
Better blur texture sampling (in experimental backends) #428
Conversation
Create texture with GL_LINEAR filtering and GL_CLAMP_TO_EDGE wrapping. Change `texelFetch()`-call in fragement shader to `texture2D()` to be taken into account. This requires supplying the size of a pixel in normalized texture coordinates via an additional uniform. Fixes darkening at the screen edges with larger blur radii caused by sampling coordinates being out of texture bounds. This is undefined behaviour unless the context has set the flag *GL_ARB_robust_buffer_access_behaviour*, in which case "zero"-pixels are returned (i.e. black). Current behaviour seems to depend on the driver.
Make use of hardware linear interpolation in a GPU to sample 2 pixels with a single texture access inside the blur shaders by sampling between both pixels based on their relative weight. This is significantly easier for a single dimension as 2D bilinear filtering would raise additional constraints on the kernels (not single zero-entries, no zero-diagonals, ...) which require additional checks with limited improvements. Therfore, only use interpolation along the larger dimension should be a sufficient improvement. Using this will effectively half the number of texture accesses and additions needed for a kernel. E.g. a 1D-pass of the gaussian blur with radius 15 will only need 16 samples instead of 31.
Create pictures used for bluring with REPEAT attribute set to PAD (same logic as GL_CLAMP_TO_EDGE in OpenGL). Fixes darkening at the screen edges with larger blur radii caused by sampling out of texture bounds. Related: 4b0ff37
Codecov Report
@@ Coverage Diff @@
## next #428 +/- ##
==========================================
+ Coverage 36.99% 37.09% +0.09%
==========================================
Files 45 45
Lines 8572 8614 +42
==========================================
+ Hits 3171 3195 +24
- Misses 5401 5419 +18
|
int nele = width * height; | ||
// '%.7g' is at most 14 characters, inserted 3 times | ||
size_t body_len = (strlen(shader_add) + 42) * (uint)nele; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since one of the for loops will only run for ceil(width/2)
or ceil(height/2)
iterations, body_len
will be too large. Being some bytes to large shouldn't be a problem. Being at least one to short however is bad.
If the buffer should be tighter, this may be computed depending on which loop will run with less iterations.
@tryone144 Thanks for the PR. Great work as always! Sorry I couldn't get back to you sooner, I will merge this now. BTW, do you mind becoming a collaborator on picom? |
Forgive my ignorance, but could someone give me the rundown of what exactly this includes? I've been using @tryone144 's branch for dual-kawase blur on experimental backends for a while, does any of this correlate to this new merge? Just anxiously awaiting until picom becomes all that everyone wants it to be! |
@vide0hanz This PR fix the problem where you would see dark edges around the screen when blur is enabled; as well as improve the performance of blur by using a clever trick to speed up the blur kernel. This doesn't contribute directly to merging dual-kawase. But yes, I would like to merge that ASAP too. |
@vide0hanz These changes aren't directly related to the new updated blur code. But merging them first allows for a bit cleaner changes to the existing kernel-blur / feature-parity with the new dual-kawase code. As yshui already summarized, this PR just fixes some visual "glitches" and improves performance of the box/gaussian blur. |
Overview
Use correct wrap/repeat setting for blur textures to prevent darkening around the screen borders. This occurs due to sampling outside of the texture, especially noticeable with larger blur radii.
The required changes to the fragment shader allowed for further improvements by utilizing the linear interpolation hardware in a GPU in the glx backend.
Old behavior:
New behavior:
Changes
REPEAT
modePAD
when creating blur pictures in the xrender backend to pad theimage with edge pixels.
WRAP
modeCLAMP_TO_EDGE
when creating blur textures in the glx backend to clamp sampling to the edge pixels. Required changes to the fragment shader:texture2D()
instead oftexelFetch()
, as the latter does not respectWRAP
settings.texture2D()
we can use the hardware accelerated linear interpolation on texture sampling to effectively sample two pixels with onetexture2D()
call. By precomputing the required offsets when creating the blur-shader we can reduce the number of texture accesses by half. This technique has been described in detail in this blog article.This PR only fixes it for the new experimental backends. The legacy xrender backend has the same darkening problem while the glx backend seems to sample random junk. If wanted these may be fixed in a second PR.