[gtk/wip/baedert/for-master: 11/15] gl renderer: Implement a subset of repeat nodes



commit 34423821b3198868b95b375757af9fc667c336b7
Author: Timm Bäder <mail baedert org>
Date:   Sat Aug 10 14:45:45 2019 +0200

    gl renderer: Implement a subset of repeat nodes

 gsk/gl/gskglrenderer.c            | 126 +++++++++++++++++++++++++++++++++-----
 gsk/gl/gskglrenderopsprivate.h    |  13 +++-
 gsk/gl/gskshaderbuilder.c         |  12 +++-
 gsk/gl/gskshaderbuilderprivate.h  |   1 +
 gsk/meson.build                   |   1 +
 gsk/resources/glsl/repeat.fs.glsl |  34 ++++++++++
 6 files changed, 170 insertions(+), 17 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index cced23aa9b..02573153fe 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -340,6 +340,7 @@ struct _GskGLRenderer
       Program border_program;
       Program cross_fade_program;
       Program blend_program;
+      Program repeat_program;
     };
   };
 
@@ -2082,6 +2083,81 @@ render_blend_node (GskGLRenderer   *self,
   ops_draw (builder, vertex_data);
 }
 
+static inline void
+render_repeat_node (GskGLRenderer   *self,
+                    GskRenderNode   *node,
+                    RenderOpBuilder *builder)
+{
+  const float min_x = builder->dx + node->bounds.origin.x;
+  const float min_y = builder->dy + node->bounds.origin.y;
+  const float max_x = min_x + node->bounds.size.width;
+  const float max_y = min_y + node->bounds.size.height;
+  GskRenderNode *child = gsk_repeat_node_get_child (node);
+  const graphene_rect_t *child_bounds = gsk_repeat_node_peek_child_bounds (node);
+  TextureRegion region;
+  gboolean is_offscreen;
+  RenderOp op;
+
+  if (child_bounds != NULL &&
+      !graphene_rect_equal (child_bounds, &child->bounds))
+    {
+      /* TODO: Implement these repeat nodes. */
+      render_fallback_node (self, node, builder);
+      return;
+    }
+
+  /* Draw the entire child on a texture */
+  add_offscreen_ops (self, builder,
+                     &child->bounds,
+                     child,
+                     &region, &is_offscreen,
+                     RESET_CLIP | RESET_OPACITY);
+
+  ops_set_program (builder, &self->repeat_program);
+  ops_set_texture (builder, region.texture_id);
+  op.op = OP_CHANGE_REPEAT;
+  op.repeat.child_bounds[0] = 0; /* Both currently unused */
+  op.repeat.child_bounds[1] = 0;
+  op.repeat.child_bounds[2] = node->bounds.size.width / child_bounds->size.width;
+  op.repeat.child_bounds[3] = node->bounds.size.height / child_bounds->size.height;
+
+  op.repeat.texture_rect[0] = region.x;
+  op.repeat.texture_rect[1] = region.y;
+  op.repeat.texture_rect[2] = region.x2;
+  op.repeat.texture_rect[3] = region.y2;
+
+  ops_add (builder, &op);
+
+  if (is_offscreen)
+    {
+      const GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = {
+        { { min_x, min_y }, { region.x,  region.y2 }, },
+        { { min_x, max_y }, { region.x,  region.y  }, },
+        { { max_x, min_y }, { region.x2, region.y2 }, },
+
+        { { max_x, max_y }, { region.x2, region.y  }, },
+        { { min_x, max_y }, { region.x,  region.y  }, },
+        { { max_x, min_y }, { region.x2, region.y2 }, },
+      };
+
+      ops_draw (builder, offscreen_vertex_data);
+    }
+  else
+    {
+      const GskQuadVertex onscreen_vertex_data[GL_N_VERTICES] = {
+        { { min_x, min_y }, { region.x,  region.y  }, },
+        { { min_x, max_y }, { region.x,  region.y2 }, },
+        { { max_x, min_y }, { region.x2, region.y  }, },
+
+        { { max_x, max_y }, { region.x2, region.y2 }, },
+        { { min_x, max_y }, { region.x,  region.y2 }, },
+        { { max_x, min_y }, { region.x2, region.y  }, },
+      };
+
+      ops_draw (builder, onscreen_vertex_data);
+    }
+}
+
 static inline void
 apply_viewport_op (const Program  *program,
                    const RenderOp *op)
@@ -2368,6 +2444,14 @@ apply_blend_op (const Program  *program,
   glUniform1i (program->blend.mode_location, op->blend.mode);
 }
 
+static inline void
+apply_repeat_op (const Program  *program,
+                 const RenderOp *op)
+{
+  glUniform4fv (program->repeat.child_bounds_location, 1, op->repeat.child_bounds);
+  glUniform4fv (program->repeat.texture_rect_location, 1, op->repeat.texture_rect);
+}
+
 static void
 gsk_gl_renderer_dispose (GObject *gobject)
 {
@@ -2389,19 +2473,21 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
   static const struct {
     const char *name;
     const char *fs;
+    const char *vs;
   } program_definitions[] = {
-    { "blit",            "blit.fs.glsl" },
-    { "color",           "color.fs.glsl" },
-    { "coloring",        "coloring.fs.glsl" },
-    { "color matrix",    "color_matrix.fs.glsl" },
-    { "linear gradient", "linear_gradient.fs.glsl" },
-    { "blur",            "blur.fs.glsl" },
-    { "inset shadow",    "inset_shadow.fs.glsl" },
-    { "outset shadow",   "outset_shadow.fs.glsl" },
+    { "blit",                      "blit.fs.glsl" },
+    { "color",                     "color.fs.glsl" },
+    { "coloring",                  "coloring.fs.glsl" },
+    { "color matrix",              "color_matrix.fs.glsl" },
+    { "linear gradient",           "linear_gradient.fs.glsl" },
+    { "blur",                      "blur.fs.glsl" },
+    { "inset shadow",              "inset_shadow.fs.glsl" },
+    { "outset shadow",             "outset_shadow.fs.glsl" },
     { "unblurred outset shadow",   "unblurred_outset_shadow.fs.glsl" },
-    { "border",          "border.fs.glsl" },
-    { "cross fade",      "cross_fade.fs.glsl" },
-    { "blend",           "blend.fs.glsl" },
+    { "border",                    "border.fs.glsl" },
+    { "cross fade",                "cross_fade.fs.glsl" },
+    { "blend",                     "blend.fs.glsl" },
+    { "repeat",                    "repeat.fs.glsl" },
   };
 
   builder = gsk_shader_builder_new ();
@@ -2454,6 +2540,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
       prog->index = i;
       prog->id = gsk_shader_builder_create_program (builder,
                                                     program_definitions[i].fs,
+                                                    program_definitions[i].vs,
                                                     &shader_error);
 
       if (shader_error != NULL)
@@ -2461,8 +2548,8 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
           g_propagate_prefixed_error (error, shader_error,
                                       "Unable to create '%s' program (from %s and %s):\n",
                                       program_definitions[i].name,
-                                      "blit.vs.glsl",
-                                      program_definitions[i].fs);
+                                      program_definitions[i].fs,
+                                      program_definitions[i].vs);
 
           g_object_unref (builder);
           return FALSE;
@@ -2536,6 +2623,10 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
   INIT_PROGRAM_UNIFORM_LOCATION (blend, source2);
   INIT_PROGRAM_UNIFORM_LOCATION (blend, mode);
 
+  /* repeat */
+  INIT_PROGRAM_UNIFORM_LOCATION (repeat, child_bounds);
+  INIT_PROGRAM_UNIFORM_LOCATION (repeat, texture_rect);
+
   g_object_unref (builder);
   return TRUE;
 }
@@ -2863,8 +2954,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
       render_blend_node (self, node, builder);
     break;
 
-    case GSK_REPEATING_LINEAR_GRADIENT_NODE:
     case GSK_REPEAT_NODE:
+      render_repeat_node (self, node, builder);
+    break;
+
+    case GSK_REPEATING_LINEAR_GRADIENT_NODE:
     case GSK_CAIRO_NODE:
     default:
       {
@@ -3151,6 +3245,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
           apply_unblurred_outset_shadow_op (program, op);
           break;
 
+        case OP_CHANGE_REPEAT:
+          apply_repeat_op (program, op);
+          break;
+
         case OP_DRAW:
           OP_PRINT (" -> draw %ld, size %ld and program %d\n",
                     op->draw.vao_offset, op->draw.vao_size, program->index);
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index ff8fe642be..60e9317f7c 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -11,7 +11,7 @@
 #include "gskrendernodeprivate.h"
 
 #define GL_N_VERTICES 6
-#define GL_N_PROGRAMS 12
+#define GL_N_PROGRAMS 13
 
 
 
@@ -60,6 +60,7 @@ enum {
   OP_PUSH_DEBUG_GROUP       =  24,
   OP_POP_DEBUG_GROUP        =  25,
   OP_CHANGE_BLEND           =  26,
+  OP_CHANGE_REPEAT          =  27,
 };
 
 typedef struct
@@ -139,6 +140,10 @@ typedef struct
       int source2_location;
       int mode_location;
     } blend;
+    struct {
+      int child_bounds_location;
+      int texture_rect_location;
+    } repeat;
   };
 
 } Program;
@@ -149,7 +154,7 @@ typedef struct
 
   union {
     float opacity;
-    graphene_matrix_t modelview; /* TODO: Make both matrix members just "matrix" */
+    graphene_matrix_t modelview;
     graphene_matrix_t projection;
     const Program *program;
     int texture_id;
@@ -221,6 +226,10 @@ typedef struct
       int source2;
       int mode;
     } blend;
+    struct {
+      float child_bounds[4];
+      float texture_rect[4];
+    } repeat;
     struct {
       char *filename;
       int width;
diff --git a/gsk/gl/gskshaderbuilder.c b/gsk/gl/gskshaderbuilder.c
index dc00371889..c057fcb3dc 100644
--- a/gsk/gl/gskshaderbuilder.c
+++ b/gsk/gl/gskshaderbuilder.c
@@ -257,6 +257,7 @@ gsk_shader_builder_set_common_vertex_shader (GskShaderBuilder  *self,
 int
 gsk_shader_builder_create_program (GskShaderBuilder *builder,
                                    const char       *fragment_shader,
+                                   const char       *vertex_shader,
                                    GError          **error)
 {
   int vertex_id;
@@ -268,7 +269,16 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
   g_return_val_if_fail (fragment_shader != NULL, -1);
   g_return_val_if_fail (builder->common_vertex_shader_id != 0, -1);
 
-  vertex_id = builder->common_vertex_shader_id;
+  if (vertex_shader == NULL)
+    vertex_id = builder->common_vertex_shader_id;
+  else
+    vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
+                                                   builder->vertex_preamble,
+                                                   vertex_shader,
+                                                   error);
+  if (vertex_id < 0)
+      return -1;
+
   fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
                                                    builder->fragment_preamble,
                                                    fragment_shader,
diff --git a/gsk/gl/gskshaderbuilderprivate.h b/gsk/gl/gskshaderbuilderprivate.h
index 025d7a2028..b91af84ea6 100644
--- a/gsk/gl/gskshaderbuilderprivate.h
+++ b/gsk/gl/gskshaderbuilderprivate.h
@@ -31,6 +31,7 @@ void                    gsk_shader_builder_set_common_vertex_shader     (GskShad
 
 int                     gsk_shader_builder_create_program               (GskShaderBuilder *builder,
                                                                          const char       *fragment_shader,
+                                                                         const char       *vertex_shader,
                                                                          GError          **error);
 
 G_END_DECLS
diff --git a/gsk/meson.build b/gsk/meson.build
index dd8a4c967b..6819ac5426 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -12,6 +12,7 @@ gsk_private_gl_shaders = [
   'resources/glsl/border.fs.glsl',
   'resources/glsl/cross_fade.fs.glsl',
   'resources/glsl/blend.fs.glsl',
+  'resources/glsl/repeat.fs.glsl',
   'resources/glsl/es2_common.fs.glsl',
   'resources/glsl/es2_common.vs.glsl',
   'resources/glsl/gl3_common.fs.glsl',
diff --git a/gsk/resources/glsl/repeat.fs.glsl b/gsk/resources/glsl/repeat.fs.glsl
new file mode 100644
index 0000000000..a58047335e
--- /dev/null
+++ b/gsk/resources/glsl/repeat.fs.glsl
@@ -0,0 +1,34 @@
+
+uniform vec4 u_child_bounds;
+uniform vec4 u_texture_rect;
+
+
+float wrap(float f, float wrap_for) {
+  return mod(f, wrap_for);
+}
+
+/* We get the texture coordinates via vUv,
+ * but that might be on a texture atlas, so we need to do the
+ * wrapping ourselves.
+ */
+void main() {
+
+  /* We map the texture coordinate to [1;0], then wrap it and scale the result again */
+
+  float tw = u_texture_rect.z - u_texture_rect.x;
+  float th = u_texture_rect.w - u_texture_rect.y;
+
+  float mapped_x = (vUv.x - u_texture_rect.x) / tw;
+  float mapped_y = (vUv.y - u_texture_rect.y) / th;
+
+  float wrapped_x = wrap(mapped_x * u_child_bounds.z, 1.0);
+  float wrapped_y = wrap(mapped_y * u_child_bounds.w, 1.0);
+
+  vec2 tp;
+  tp.x = u_texture_rect.x + (wrapped_x * tw);
+  tp.y = u_texture_rect.y + (wrapped_y * th);
+
+  vec4 diffuse = Texture(u_source, tp);
+
+  setOutputColor(diffuse * u_alpha);
+}


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