[gtk/wip/baedert/for-master: 3/4] gl renderer: Blur shader improvements



commit dc340bcb233962e63922d907236897e65b47de01
Author: Timm Bäder <mail baedert org>
Date:   Thu Nov 21 17:21:09 2019 +0100

    gl renderer: Blur shader improvements
    
    Use a two-pass shader

 gsk/gl/gskglrenderer.c          | 93 +++++++++++++++++++++++++++++++++++++----
 gsk/gl/gskglrenderopsprivate.h  |  2 +-
 gsk/resources/glsl/blur.fs.glsl | 61 +++++++++++++--------------
 3 files changed, 114 insertions(+), 42 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index bcf179b010..adf92919fa 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -1277,11 +1277,21 @@ render_blur_node (GskGLRenderer   *self,
                   RenderOpBuilder *builder,
                   GskQuadVertex   *vertex_data)
 {
+  const float scale = ops_get_scale (builder);
   const float blur_radius = gsk_blur_node_get_radius (node);
+  const float texture_width = ceilf (node->bounds.size.width * scale);
+  const float texture_height = ceilf (node->bounds.size.height * scale);
   GskRenderNode *child = gsk_blur_node_get_child (node);
   TextureRegion region;
   gboolean is_offscreen;
   OpBlur *op;
+  int prev_render_target;
+  int pass1_texture_id, pass1_render_target;
+  int pass2_texture_id, pass2_render_target;
+  graphene_matrix_t prev_projection;
+  graphene_rect_t prev_viewport;
+  graphene_matrix_t item_proj;
+  GskRoundedRect r = GSK_ROUNDED_RECT_INIT (0, 0, texture_width, texture_height);
 
   if (blur_radius <= 0)
     {
@@ -1293,25 +1303,92 @@ render_blur_node (GskGLRenderer   *self,
    * so the resulting offscreen texture is bigger by the gaussian blur factor
    * (see gsk_blur_node_new), but we didn't have to do that if the blur
    * shader could handle that situation. */
-
   add_offscreen_ops (self, builder,
                      &node->bounds,
                      child,
                      &region, &is_offscreen,
                      RESET_CLIP | FORCE_OFFSCREEN | RESET_OPACITY);
 
+  g_assert (is_offscreen);
+
+  gsk_gl_driver_create_render_target (self->gl_driver,
+                                      texture_width, texture_height,
+                                      &pass1_texture_id, &pass1_render_target);
+
+  gsk_gl_driver_create_render_target (self->gl_driver,
+                                      texture_width, texture_height,
+                                      &pass2_texture_id, &pass2_render_target);
+
+
+
+  graphene_matrix_init_ortho (&item_proj,
+                              0, texture_width, 0, texture_height,
+                              ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
+  graphene_matrix_scale (&item_proj, 1, -1, 1);
+
+  prev_projection = ops_set_projection (builder, &item_proj);
+  ops_set_modelview (builder, NULL);
+  prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
+  ops_push_clip (builder, &r);
+
+  prev_render_target = ops_set_render_target (builder, pass1_render_target);
+  ops_begin (builder, OP_CLEAR);
   ops_set_program (builder, &self->blur_program);
 
   op = ops_begin (builder, OP_CHANGE_BLUR);
-  graphene_size_init_from_size (&op->size, &node->bounds.size);
+  op->size.width = texture_width;
+  op->size.height = texture_height;
+  op->size.width = node->bounds.size.width;
+  op->size.height = node->bounds.size.height;
   op->radius = blur_radius;
-
+  op->dir[0] = 1;
+  op->dir[1] = 0;
   ops_set_texture (builder, region.texture_id);
 
-  if (is_offscreen)
-    flip_vertex_data_y (vertex_data);
+  ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+    { { 0,                            }, { 0, 1 }, },
+    { { 0,             texture_height }, { 0, 0 }, },
+    { { texture_width,                }, { 1, 1 }, },
 
-  ops_draw (builder, vertex_data);
+    { { texture_width, texture_height }, { 1, 0 }, },
+    { { 0,             texture_height }, { 0, 0 }, },
+    { { texture_width,                }, { 1, 1 }, },
+  });
+
+  op = ops_begin (builder, OP_CHANGE_BLUR);
+  op->size.width = texture_width;
+  op->size.height = texture_height;
+  op->size.width = texture_width;
+  op->size.height = texture_height;
+  op->size.width = node->bounds.size.width;
+  op->size.height = node->bounds.size.height;
+  op->radius = blur_radius;
+  op->dir[0] = 0;
+  op->dir[1] = 1;
+  ops_set_texture (builder, pass1_texture_id);
+  ops_set_render_target (builder, pass2_render_target);
+  ops_begin (builder, OP_CLEAR);
+  ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { /* render pass 2 */
+    { { 0,                            }, { 0, 1 }, },
+    { { 0,             texture_height }, { 0, 0 }, },
+    { { texture_width,                }, { 1, 1 }, },
+
+    { { texture_width, texture_height }, { 1, 0 }, },
+    { { 0,             texture_height }, { 0, 0 }, },
+    { { texture_width,                }, { 1, 1 }, },
+  });
+
+  ops_set_render_target (builder, prev_render_target);
+  ops_set_viewport (builder, &prev_viewport);
+  ops_set_projection (builder, &prev_projection);
+  ops_pop_modelview (builder);
+  ops_pop_clip (builder);
+
+  /* Draw the result */
+  flip_vertex_data_y (vertex_data);
+  ops_set_program (builder, &self->blit_program);
+  ops_set_texture (builder, pass2_texture_id);
+  ops_draw (builder, vertex_data); /* Render result to screen */
 }
 
 static inline void
@@ -2282,7 +2359,7 @@ apply_blur_op (const Program *program,
   OP_PRINT (" -> Blur");
   glUniform1f (program->blur.blur_radius_location, op->radius);
   glUniform2f (program->blur.blur_size_location, op->size.width, op->size.height);
-  /*glUniform2f (program->blur.dir_location, op->dir[0], op->dir[1]);*/
+  glUniform2f (program->blur.blur_dir_location, op->dir[0], op->dir[1]);
 }
 
 static inline void
@@ -2449,7 +2526,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
   /* blur */
   INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_radius);
   INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_size);
-  /*INIT_PROGRAM_UNIFORM_LOCATION (blur, dir);*/
+  INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_dir);
 
   /* inset shadow */
   INIT_PROGRAM_UNIFORM_LOCATION (inset_shadow, color);
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index e555653617..93f504f287 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -73,7 +73,7 @@ struct _Program
     struct {
       int blur_radius_location;
       int blur_size_location;
-      int dir_location;
+      int blur_dir_location;
     } blur;
     struct {
       int color_location;
diff --git a/gsk/resources/glsl/blur.fs.glsl b/gsk/resources/glsl/blur.fs.glsl
index abad1c1f30..14dd40f3f7 100644
--- a/gsk/resources/glsl/blur.fs.glsl
+++ b/gsk/resources/glsl/blur.fs.glsl
@@ -1,39 +1,34 @@
-uniform float u_blur_radius;// = 40.0;
-uniform vec2 u_blur_size;// = vec2(393, 393);
+uniform float u_blur_radius;
+uniform vec2 u_blur_size;
+uniform vec2 u_blur_dir;
 
-float Gaussian (float sigma, float x) {
-  return exp ( - (x * x) / (2.0 * sigma * sigma));
-}
-
-vec4 blur_pixel (in vec2 uv) {
-  float total = 0.0;
-  vec4 ret = vec4 (0);
-  float pixel_size_x = (1.0 / u_blur_size.x);
-  float pixel_size_y = (1.0 / u_blur_size.y);
-
-  // XXX The magic value here is GAUSSIAN_SCALE_FACTOR from gskcairoblur.c
-  float radius = u_blur_radius  * 2.30348;
-
-  int half_radius = max(int(radius / 2.0), 1);
-
-  for (int y = -half_radius; y < half_radius; y ++) {
-    float fy = Gaussian (radius / 2.0, float(y));
-    float offset_y = float(y) * pixel_size_y;
+const float PI = 3.141;
 
-    for (int x = -half_radius; x < half_radius; x ++) {
-      float fx = Gaussian (radius / 2.0, float(x));
-      float offset_x = float(x) * pixel_size_x;
-
-      vec4 c = Texture(u_source, uv + vec2(offset_x, offset_y));
-      total += fx * fy;
-      ret += c * fx * fy;
-    }
+// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
+void main() {
+  float sigma = u_blur_radius / 2.0;
+  vec3 incrementalGaussian;
+  incrementalGaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma);
+  incrementalGaussian.y = exp(-0.5 / (sigma * sigma));
+  incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y;
+
+  vec2 blur = vec2(1.0) / u_blur_size;
+  float coefficientSum = 0;
+
+  vec4 sum = Texture(u_source, vUv) * incrementalGaussian.x;
+  coefficientSum += incrementalGaussian.x;
+  incrementalGaussian.xy *= incrementalGaussian.yz;
+
+  int pixels_per_side = int(floor(u_blur_radius / 2.0));
+  for (int i = 1; i <= pixels_per_side; i++) {
+    sum += Texture(u_source, vUv.xy - i * blur * u_blur_dir) * incrementalGaussian.x;
+    sum += Texture(u_source, vUv.xy + i * blur * u_blur_dir) * incrementalGaussian.x;
+
+    coefficientSum += 2 * incrementalGaussian.x;
+    incrementalGaussian.xy *= incrementalGaussian.yz;
   }
 
-  return ret / total;
-}
+  sum /= coefficientSum;
 
-void main() {
-  vec4 color = blur_pixel(vUv);
-  setOutputColor(color);
+  setOutputColor(sum);
 }


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