blur-effect: Implement incremental calculation of gauss coefficient

Use the shader for linear sampling and incremental calculation of the
gaussian kernel values as it was implemented by Patrick Walton in
webrender.

The sigma value for the blur (the standard deviation) is calculated by
taking the blur radius and dividing it by 3, this value is used by most
implementations of gaussian blurs since it covers a high percentage of
the gaussian shape.

The linear sampling optimization is implemented by skipping every second
texel (i += 2) in the for-loop that's sampling adjacent texels.

https://github.com/servo/webrender/blob/master/webrender/res/cs_blur.glsl
38ec7db6f1

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/991
This commit is contained in:
Jonas Dreßler 2020-02-10 15:34:03 +01:00 committed by Georges Basile Stavracas Neto
parent b75e61d5c8
commit d26bb38be9

View File

@ -68,53 +68,59 @@
* *
* http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ * http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/
* *
* ## Incremental gauss-factor calculation
*
* The kernel values for the gaussian kernel are computed incrementally instead
* of running the expensive calculations multiple times inside the blur shader.
* The implementation is based on the algorithm presented by K. Turkowski in
* GPU Gems 3, chapter 40:
*
* https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch40.html
*
*/ */
static const gchar *gaussian_blur_glsl_declarations = static const gchar *gaussian_blur_glsl_declarations =
"uniform float blur_radius; \n" "uniform float blur_radius; \n"
"uniform float pixel_step; \n" "uniform float pixel_step; \n"
"uniform int vertical; \n" "uniform int vertical; \n";
" \n"
"float gaussian (float sigma, float x) { \n"
" return exp ( - (x * x) / (2.0 * sigma * sigma)); \n"
"} \n"
" \n";
static const gchar *gaussian_blur_glsl = static const gchar *gaussian_blur_glsl =
" float total = 0.0; \n"
" int horizontal = 1 - vertical; \n" " int horizontal = 1 - vertical; \n"
" \n" " \n"
" vec4 ret = vec4 (0); \n" " int n_steps = int (ceil (blur_radius)); \n"
" float sigma = float (n_steps) / 3.0; \n"
" \n"
" vec2 uv = vec2 (cogl_tex_coord.st); \n" " vec2 uv = vec2 (cogl_tex_coord.st); \n"
" \n" " \n"
" float half_radius = blur_radius / 2.0; \n" " vec3 gauss_coefficient; \n"
" int n_steps = int (ceil (half_radius)) + 1; \n" " gauss_coefficient.x = 1.0 / (sqrt (2.0 * 3.14159265) * sigma); \n"
" gauss_coefficient.y = exp (-0.5 / (sigma * sigma)); \n"
" gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y; \n"
" \n" " \n"
" for (int i = 0; i < n_steps; i++) { \n" " float gauss_coefficient_total = gauss_coefficient.x; \n"
" float i0 = min (float (2 * i), blur_radius); \n"
" float i1 = min (i0 + 1.0, blur_radius); \n"
" \n" " \n"
" float step0 = i0 * pixel_step; \n" " vec4 ret = texture2D (cogl_sampler, uv) * gauss_coefficient.x; \n"
" float step1 = i1 * pixel_step; \n" " gauss_coefficient.xy *= gauss_coefficient.yz; \n"
" \n" " \n"
" float weight0 = gaussian (half_radius, i0); \n" " for (int i = 1; i < n_steps; i += 2) { \n"
" float weight1 = gaussian (half_radius, i1); \n" " float coefficient_subtotal = gauss_coefficient.x; \n"
" float weight = weight0 + weight1; \n" " gauss_coefficient.xy *= gauss_coefficient.yz; \n"
" coefficient_subtotal += gauss_coefficient.x; \n"
" \n" " \n"
" float foffset = (step0 * weight0 + step1 * weight1) / weight; \n" " float gauss_ratio = gauss_coefficient.x / coefficient_subtotal; \n"
" vec2 offset = vec2(foffset * float(horizontal), \n"
" foffset * float(vertical)); \n"
" \n" " \n"
" vec4 c = texture2D(cogl_sampler, uv + offset); \n" " float foffset = float (i) + gauss_ratio; \n"
" total += weight; \n" " vec2 offset = vec2 (foffset * pixel_step * float (horizontal), \n"
" ret += c * weight; \n" " foffset * pixel_step * float (vertical)); \n"
" \n" " \n"
" c = texture2D(cogl_sampler, uv - offset); \n" " ret += texture2D (cogl_sampler, uv + offset) * coefficient_subtotal; \n"
" total += weight; \n" " ret += texture2D (cogl_sampler, uv - offset) * coefficient_subtotal; \n"
" ret += c * weight; \n" " \n"
" gauss_coefficient_total += 2.0 * coefficient_subtotal; \n"
" gauss_coefficient.xy *= gauss_coefficient.yz; \n"
" } \n" " } \n"
" \n" " \n"
" cogl_texel = vec4 (ret / total); \n"; " cogl_texel = ret / gauss_coefficient_total; \n";
static const gchar *brightness_glsl_declarations = static const gchar *brightness_glsl_declarations =
"uniform float brightness; \n"; "uniform float brightness; \n";