[gnome-shell] blur-effect: Implement incremental calculation of gauss coefficient



commit d26bb38be95eedb9919d23123cb7368c3ab28e35
Author: Jonas Dreßler <verdre v0yd nl>
Date:   Mon Feb 10 15:34:03 2020 +0100

    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
    https://github.com/servo/webrender/commit/38ec7db6f165ff7aaad12d91eca7d7a5f51557b5
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/991

 src/shell-blur-effect.c | 94 ++++++++++++++++++++++++++-----------------------
 1 file changed, 50 insertions(+), 44 deletions(-)
---
diff --git a/src/shell-blur-effect.c b/src/shell-blur-effect.c
index dc77714f95..500bad12c5 100644
--- a/src/shell-blur-effect.c
+++ b/src/shell-blur-effect.c
@@ -68,59 +68,65 @@
  *
  * 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 =
-"uniform float blur_radius;                                        \n"
-"uniform float pixel_step;                                         \n"
-"uniform int vertical;                                             \n"
-"                                                                  \n"
-"float gaussian (float sigma, float x) {                           \n"
-"  return exp ( - (x * x) / (2.0 * sigma * sigma));                \n"
-"}                                                                 \n"
-"                                                                  \n";
+"uniform float blur_radius;                                                \n"
+"uniform float pixel_step;                                                 \n"
+"uniform int vertical;                                                     \n";
 
 static const gchar *gaussian_blur_glsl =
-"  float total = 0.0;                                              \n"
-"  int horizontal = 1 - vertical;                                  \n"
-"                                                                  \n"
-"  vec4 ret = vec4 (0);                                            \n"
-"  vec2 uv = vec2 (cogl_tex_coord.st);                             \n"
-"                                                                  \n"
-"  float half_radius = blur_radius / 2.0;                          \n"
-"  int n_steps = int (ceil (half_radius)) + 1;                     \n"
-"                                                                  \n"
-"  for (int i = 0; i < n_steps; i++) {                             \n"
-"    float i0 = min (float (2 * i), blur_radius);                  \n"
-"    float i1 = min (i0 + 1.0, blur_radius);                       \n"
-"                                                                  \n"
-"    float step0 = i0 * pixel_step;                                \n"
-"    float step1 = i1 * pixel_step;                                \n"
-"                                                                  \n"
-"    float weight0 = gaussian (half_radius, i0);                   \n"
-"    float weight1 = gaussian (half_radius, i1);                   \n"
-"    float weight = weight0 + weight1;                             \n"
-"                                                                  \n"
-"    float foffset = (step0 * weight0 + step1 * weight1) / weight; \n"
-"    vec2 offset = vec2(foffset * float(horizontal),               \n"
-"                       foffset * float(vertical));                \n"
-"                                                                  \n"
-"    vec4 c = texture2D(cogl_sampler, uv + offset);                \n"
-"    total += weight;                                              \n"
-"    ret += c * weight;                                            \n"
-"                                                                  \n"
-"    c = texture2D(cogl_sampler, uv - offset);                     \n"
-"    total += weight;                                              \n"
-"    ret += c * weight;                                            \n"
-"  }                                                               \n"
-"                                                                  \n"
-"  cogl_texel = vec4 (ret / total);                                \n";
+"  int horizontal = 1 - vertical;                                          \n"
+"                                                                          \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"
+"                                                                          \n"
+"  vec3 gauss_coefficient;                                                 \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"
+"  float gauss_coefficient_total = gauss_coefficient.x;                    \n"
+"                                                                          \n"
+"  vec4 ret = texture2D (cogl_sampler, uv) * gauss_coefficient.x;          \n"
+"  gauss_coefficient.xy *= gauss_coefficient.yz;                           \n"
+"                                                                          \n"
+"  for (int i = 1; i < n_steps; i += 2) {                                  \n"
+"    float coefficient_subtotal = gauss_coefficient.x;                     \n"
+"    gauss_coefficient.xy *= gauss_coefficient.yz;                         \n"
+"    coefficient_subtotal += gauss_coefficient.x;                          \n"
+"                                                                          \n"
+"    float gauss_ratio = gauss_coefficient.x / coefficient_subtotal;       \n"
+"                                                                          \n"
+"    float foffset = float (i) + gauss_ratio;                              \n"
+"    vec2 offset = vec2 (foffset * pixel_step * float (horizontal),        \n"
+"                        foffset * pixel_step * float (vertical));         \n"
+"                                                                          \n"
+"    ret += texture2D (cogl_sampler, uv + offset) * coefficient_subtotal;  \n"
+"    ret += texture2D (cogl_sampler, uv - offset) * coefficient_subtotal;  \n"
+"                                                                          \n"
+"    gauss_coefficient_total += 2.0 * coefficient_subtotal;                \n"
+"    gauss_coefficient.xy *= gauss_coefficient.yz;                         \n"
+"  }                                                                       \n"
+"                                                                          \n"
+"  cogl_texel = ret / gauss_coefficient_total;                             \n";
 
 static const gchar *brightness_glsl_declarations =
-"uniform float brightness;                                         \n";
+"uniform float brightness;                                                 \n";
 
 static const gchar *brightness_glsl =
-"  cogl_color_out.rgb *= brightness;                               \n";
+"  cogl_color_out.rgb *= brightness;                                       \n";
 
 #define MIN_DOWNSCALE_SIZE 256.f
 #define MAX_BLUR_RADIUS 10.f


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]