[gtk: 1/2] GskGLRenderer: Share programs between different renderers in same display



commit 7b0b3d95475940dfd46111aae1aeeb97702d9fe8
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Feb 11 16:56:24 2020 +0100

    GskGLRenderer: Share programs between different renderers in same display
    
    This is similar to how we share texture atlases. Some added complexity
    in that the program state also needed to be shared, so it had to move to
    the shared Programs object.
    
    With this change realization of additional GskRenderers when opening
    popups went from ~60msec to ~35 msec on average.

 gsk/gl/gskglrenderer.c         | 176 ++++++++++++++++++++++++++---------------
 gsk/gl/gskglrenderops.c        |  18 +----
 gsk/gl/gskglrenderopsprivate.h |  25 +++++-
 3 files changed, 140 insertions(+), 79 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 44d8115dbb..d682660e79 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -48,9 +48,9 @@
 
 #define INIT_PROGRAM_UNIFORM_LOCATION(program_name, uniform_basename) \
               G_STMT_START{\
-                self->program_name ## _program.program_name.uniform_basename ## _location = \
-                              glGetUniformLocation(self->program_name ## _program.id, "u_" 
#uniform_basename);\
-                g_assert_cmpint (self->program_name ## _program.program_name.uniform_basename ## _location, 
, -1); \
+                programs->program_name ## _program.program_name.uniform_basename ## _location = \
+                              glGetUniformLocation(programs->program_name ## _program.id, "u_" 
#uniform_basename);\
+                g_assert_cmpint (programs->program_name ## _program.program_name.uniform_basename ## 
_location, >, -1); \
               }G_STMT_END
 
 #define INIT_COMMON_UNIFORM_LOCATION(program_ptr, uniform_basename) \
@@ -439,24 +439,7 @@ struct _GskGLRenderer
   GskGLDriver *gl_driver;
   GskGLProfiler *gl_profiler;
 
-  union {
-    Program programs[GL_N_PROGRAMS];
-    struct {
-      Program blend_program;
-      Program blit_program;
-      Program blur_program;
-      Program border_program;
-      Program color_matrix_program;
-      Program color_program;
-      Program coloring_program;
-      Program cross_fade_program;
-      Program inset_shadow_program;
-      Program linear_gradient_program;
-      Program outset_shadow_program;
-      Program repeat_program;
-      Program unblurred_outset_shadow_program;
-    };
-  };
+  GskGLRendererPrograms *programs;
 
   RenderOpBuilder op_builder;
 
@@ -512,7 +495,7 @@ add_rect_outline_ops (GskGLRenderer         *self,
                       RenderOpBuilder       *builder,
                       const graphene_rect_t *rect)
 {
-  ops_set_program (builder, &self->color_program);
+  ops_set_program (builder, &self->programs->color_program);
   ops_set_color (builder, &BLACK);
 
   add_rect_ops (builder,
@@ -571,7 +554,7 @@ render_fallback_node (GskGLRenderer   *self,
 
   if (cached_id != 0)
     {
-      ops_set_program (builder, &self->blit_program);
+      ops_set_program (builder, &self->programs->blit_program);
       ops_set_texture (builder, cached_id);
       load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
       return;
@@ -647,7 +630,7 @@ render_fallback_node (GskGLRenderer   *self,
 
   gsk_gl_driver_set_texture_for_pointer (self->gl_driver, node, texture_id);
 
-  ops_set_program (builder, &self->blit_program);
+  ops_set_program (builder, &self->programs->blit_program);
   ops_set_texture (builder, texture_id);
   load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
 }
@@ -673,11 +656,11 @@ render_text_node (GskGLRenderer   *self,
   /* If the font has color glyphs, we don't need to recolor anything */
   if (!force_color && gsk_text_node_has_color_glyphs (node))
     {
-      ops_set_program (builder, &self->blit_program);
+      ops_set_program (builder, &self->programs->blit_program);
     }
   else
     {
-      ops_set_program (builder, &self->coloring_program);
+      ops_set_program (builder, &self->programs->coloring_program);
       ops_set_color (builder, color);
     }
 
@@ -762,7 +745,7 @@ render_border_node (GskGLRenderer   *self,
     {
       OpShadow *op;
 
-      ops_set_program (builder, &self->inset_shadow_program);
+      ops_set_program (builder, &self->programs->inset_shadow_program);
       op = ops_begin (builder, OP_CHANGE_INSET_SHADOW);
       op->color = &colors[0];
       op->outline = transform_rect (self, builder, rounded_outline);
@@ -875,7 +858,7 @@ render_border_node (GskGLRenderer   *self,
     /* Prepare outline */
     outline = transform_rect (self, builder, rounded_outline);
 
-    ops_set_program (builder, &self->border_program);
+    ops_set_program (builder, &self->programs->border_program);
     ops_set_border_width (builder, widths);
     ops_set_border (builder, &outline);
 
@@ -895,7 +878,7 @@ render_color_node (GskGLRenderer   *self,
                    GskRenderNode   *node,
                    RenderOpBuilder *builder)
 {
-  ops_set_program (builder, &self->color_program);
+  ops_set_program (builder, &self->programs->color_program);
   ops_set_color (builder, gsk_color_node_peek_color (node));
   load_vertex_data (ops_draw (builder, NULL), node, builder);
 }
@@ -958,7 +941,7 @@ render_texture_node (GskGLRenderer       *self,
 
       gsk_gl_driver_slice_texture (self->gl_driver, texture, &slices, &n_slices);
 
-      ops_set_program (builder, &self->blit_program);
+      ops_set_program (builder, &self->programs->blit_program);
       for (i = 0; i < n_slices; i ++)
         {
           const TextureSlice *slice = &slices[i];
@@ -987,7 +970,7 @@ render_texture_node (GskGLRenderer       *self,
 
       upload_texture (self, texture, &r);
 
-      ops_set_program (builder, &self->blit_program);
+      ops_set_program (builder, &self->programs->blit_program);
       ops_set_texture (builder, r.texture_id);
 
       load_vertex_data_with_region (ops_draw (builder, NULL),
@@ -1061,7 +1044,7 @@ render_transform_node (GskGLRenderer   *self,
              */
             ops_push_modelview (builder, node_transform);
             ops_set_texture (builder, region.texture_id);
-            ops_set_program (builder, &self->blit_program);
+            ops_set_program (builder, &self->programs->blit_program);
 
             load_vertex_data_with_region (ops_draw (builder, NULL),
                                           child, builder,
@@ -1098,7 +1081,7 @@ render_opacity_node (GskGLRenderer   *self,
       prev_opacity = ops_set_opacity (builder,
                                       builder->current_opacity * opacity);
 
-      ops_set_program (builder, &self->blit_program);
+      ops_set_program (builder, &self->programs->blit_program);
       ops_set_texture (builder, region.texture_id);
 
       load_vertex_data_with_region (ops_draw (builder, NULL),
@@ -1128,7 +1111,7 @@ render_linear_gradient_node (GskGLRenderer   *self,
   const graphene_point_t *end = gsk_linear_gradient_node_peek_end (node);
   OpLinearGradient *op;
 
-  ops_set_program (builder, &self->linear_gradient_program);
+  ops_set_program (builder, &self->programs->linear_gradient_program);
   op = ops_begin (builder, OP_CHANGE_LINEAR_GRADIENT);
   op->color_stops = stops;
   op->n_color_stops = n_color_stops;
@@ -1245,7 +1228,7 @@ render_rounded_clip_node (GskGLRenderer       *self,
 
       ops_pop_clip (builder);
 
-      ops_set_program (builder, &self->blit_program);
+      ops_set_program (builder, &self->programs->blit_program);
       ops_set_texture (builder, region.texture_id);
 
       load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
@@ -1272,7 +1255,7 @@ render_color_matrix_node (GskGLRenderer       *self,
                           RESET_CLIP | RESET_OPACITY))
     g_assert_not_reached ();
 
-  ops_set_program (builder, &self->color_matrix_program);
+  ops_set_program (builder, &self->programs->color_matrix_program);
   ops_set_color_matrix (builder,
                         gsk_color_matrix_node_peek_color_matrix (node),
                         gsk_color_matrix_node_peek_color_offset (node));
@@ -1323,7 +1306,7 @@ blur_texture (GskGLRenderer       *self,
 
   prev_render_target = ops_set_render_target (builder, pass1_render_target);
   ops_begin (builder, OP_CLEAR);
-  ops_set_program (builder, &self->blur_program);
+  ops_set_program (builder, &self->programs->blur_program);
 
   op = ops_begin (builder, OP_CHANGE_BLUR);
   op->size.width = texture_to_blur_width;
@@ -1462,7 +1445,7 @@ render_blur_node (GskGLRenderer   *self,
   g_assert (blurred_region.texture_id != 0);
 
   /* Draw the result */
-  ops_set_program (builder, &self->blit_program);
+  ops_set_program (builder, &self->programs->blit_program);
   ops_set_texture (builder, blurred_region.texture_id);
   load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); /* Render result to screen */
 
@@ -1483,7 +1466,7 @@ render_unblurred_inset_shadow_node (GskGLRenderer   *self,
 
   g_assert (blur_radius == 0);
 
-  ops_set_program (builder, &self->inset_shadow_program);
+  ops_set_program (builder, &self->programs->inset_shadow_program);
   op = ops_begin (builder, OP_CHANGE_INSET_SHADOW);
   op->color = gsk_inset_shadow_node_peek_color (node);
   op->outline = transform_rect (self, builder, gsk_inset_shadow_node_peek_outline (node));
@@ -1570,7 +1553,7 @@ render_inset_shadow_node (GskGLRenderer   *self,
       ops_begin (builder, OP_CLEAR);
 
       /* Actual inset shadow outline drawing */
-      ops_set_program (builder, &self->inset_shadow_program);
+      ops_set_program (builder, &self->programs->inset_shadow_program);
       op = ops_begin (builder, OP_CHANGE_INSET_SHADOW);
       op->color = gsk_inset_shadow_node_peek_color (node);
       op->outline = transform_rect (self, builder, &outline_to_blur);
@@ -1621,7 +1604,7 @@ render_inset_shadow_node (GskGLRenderer   *self,
         ops_push_clip (builder, &node_clip);
       }
 
-    ops_set_program (builder, &self->blit_program);
+    ops_set_program (builder, &self->programs->blit_program);
     ops_set_texture (builder, blurred_texture_id);
 
     load_vertex_data_with_region (ops_draw (builder, NULL),
@@ -1646,7 +1629,7 @@ render_unblurred_outset_shadow_node (GskGLRenderer   *self,
   const float dy = gsk_outset_shadow_node_get_dy (node);
   OpShadow *op;
 
-  ops_set_program (builder, &self->unblurred_outset_shadow_program);
+  ops_set_program (builder, &self->programs->unblurred_outset_shadow_program);
   op = ops_begin (builder, OP_CHANGE_UNBLURRED_OUTSET_SHADOW);
   op->color = gsk_outset_shadow_node_peek_color (node);
   op->outline = transform_rect (self, builder, outline);
@@ -1739,7 +1722,7 @@ render_outset_shadow_node (GskGLRenderer   *self,
       prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
 
       /* Draw outline */
-      ops_set_program (builder, &self->color_program);
+      ops_set_program (builder, &self->programs->color_program);
       ops_push_clip (builder, &scaled_outline);
       ops_set_color (builder, &COLOR_WHITE);
       ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
@@ -1776,7 +1759,7 @@ render_outset_shadow_node (GskGLRenderer   *self,
       blurred_texture_id = cached_tid;
     }
 
-  ops_set_program (builder, &self->outset_shadow_program);
+  ops_set_program (builder, &self->programs->outset_shadow_program);
   ops_set_color (builder, color);
   ops_set_texture (builder, blurred_texture_id);
 
@@ -2097,7 +2080,7 @@ render_shadow_node (GskGLRenderer   *self,
           max_y = min_y + shadow_child->bounds.size.height;
         }
 
-      ops_set_program (builder, &self->coloring_program);
+      ops_set_program (builder, &self->programs->coloring_program);
       ops_set_color (builder, &shadow->color);
       ops_set_texture (builder, region.texture_id);
       if (is_offscreen)
@@ -2174,7 +2157,7 @@ render_cross_fade_node (GskGLRenderer   *self,
       return;
     }
 
-  ops_set_program (builder, &self->cross_fade_program);
+  ops_set_program (builder, &self->programs->cross_fade_program);
 
   op = ops_begin (builder, OP_CHANGE_CROSS_FADE);
   op->progress = progress;
@@ -2223,7 +2206,7 @@ render_blend_node (GskGLRenderer   *self,
       return;
     }
 
-  ops_set_program (builder, &self->blend_program);
+  ops_set_program (builder, &self->programs->blend_program);
   ops_set_texture (builder, bottom_region.texture_id);
 
   op = ops_begin (builder, OP_CHANGE_BLEND);
@@ -2272,7 +2255,7 @@ render_repeat_node (GskGLRenderer   *self,
                           RESET_CLIP | RESET_OPACITY))
     g_assert_not_reached ();
 
-  ops_set_program (builder, &self->repeat_program);
+  ops_set_program (builder, &self->programs->repeat_program);
   ops_set_texture (builder, region.texture_id);
 
   op = ops_begin (builder, OP_CHANGE_REPEAT);
@@ -2551,11 +2534,53 @@ gsk_gl_renderer_dispose (GObject *gobject)
   G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject);
 }
 
-static gboolean
+static GskGLRendererPrograms *
+gsk_gl_renderer_programs_new (void)
+{
+  GskGLRendererPrograms *programs;
+  int i;
+
+  programs = g_new0 (GskGLRendererPrograms, 1);
+  programs->ref_count = 1;
+  for (i = 0; i < GL_N_PROGRAMS; i ++)
+    {
+      programs->state[i].opacity = 1.0f;
+    }
+
+  return programs;
+}
+
+static GskGLRendererPrograms *
+gsk_gl_renderer_programs_ref (GskGLRendererPrograms *programs)
+{
+  programs->ref_count++;
+  return programs;
+}
+
+/* Must be called with the context current */
+static void
+gsk_gl_renderer_programs_unref (GskGLRendererPrograms *programs)
+{
+  int i;
+  programs->ref_count--;
+  if (programs->ref_count == 0)
+    {
+      for (i = 0; i < GL_N_PROGRAMS; i ++)
+        {
+          if (programs->programs[i].id != 0)
+            glDeleteProgram (programs->programs[i].id);
+          gsk_transform_unref (programs->state[i].modelview);
+        }
+      g_free (programs);
+    }
+}
+
+static GskGLRendererPrograms *
 gsk_gl_renderer_create_programs (GskGLRenderer  *self,
                                  GError        **error)
 {
   GskGLShaderBuilder shader_builder;
+  GskGLRendererPrograms *programs = NULL;
   int i;
   static const struct {
     const char *resource_path;
@@ -2575,7 +2600,6 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
     { "/org/gtk/libgsk/glsl/repeat.glsl",                    "repeat" },
     { "/org/gtk/libgsk/glsl/unblurred_outset_shadow.glsl",   "unblurred_outset shadow" },
   };
-  gboolean success = TRUE;
 
   gsk_gl_shader_builder_init (&shader_builder,
                               "/org/gtk/libgsk/glsl/preamble.glsl",
@@ -2614,9 +2638,11 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
       shader_builder.gl3 = TRUE;
     }
 
+  programs = gsk_gl_renderer_programs_new ();
+
   for (i = 0; i < GL_N_PROGRAMS; i ++)
     {
-      Program *prog = &self->programs[i];
+      Program *prog = &programs->programs[i];
 
       prog->index = i;
       prog->id = gsk_gl_shader_builder_create_program (&shader_builder,
@@ -2624,7 +2650,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
                                                        error);
       if (prog->id < 0)
         {
-          success = FALSE;
+          g_clear_pointer (&programs, gsk_gl_renderer_programs_unref);
           goto out;
         }
 
@@ -2695,16 +2721,42 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
    * work in gles. */
   for (i = 0; i < GL_N_PROGRAMS; i++)
     {
-      glUseProgram(self->programs[i].id);
-      glUniform1f (self->programs[i].alpha_location, 1.0);
+      glUseProgram(programs->programs[i].id);
+      glUniform1f (programs->programs[i].alpha_location, 1.0);
     }
 
 out:
   gsk_gl_shader_builder_finish (&shader_builder);
 
-  return success;
+  return programs;
+}
+
+static GskGLRendererPrograms *
+get_programs_for_display (GskGLRenderer  *self,
+                          GdkDisplay     *display,
+                          GError        **error)
+{
+  GskGLRendererPrograms *programs;
+
+  if (g_getenv ("GSK_NO_SHARED_PROGRAMS"))
+    return gsk_gl_renderer_create_programs (self, error);
+
+  programs = (GskGLRendererPrograms *)g_object_get_data (G_OBJECT (display), "gsk-gl-programs");
+  if (programs == NULL)
+    {
+      programs = gsk_gl_renderer_create_programs (self, error);
+      if (programs)
+        g_object_set_data_full (G_OBJECT (display), "gsk-gl-programs",
+                                programs,
+                                (GDestroyNotify) gsk_gl_renderer_programs_unref);
+    }
+
+  if (programs)
+    return gsk_gl_renderer_programs_ref (programs);
+  return NULL;
 }
 
+
 static GskGLTextureAtlases *
 get_texture_atlases_for_display (GdkDisplay *display)
 {
@@ -2795,8 +2847,10 @@ gsk_gl_renderer_realize (GskRenderer  *renderer,
   self->gl_driver = gsk_gl_driver_new (self->gl_context);
 
   GSK_RENDERER_NOTE (renderer, OPENGL, g_message ("Creating buffers and programs"));
-  if (!gsk_gl_renderer_create_programs (self, error))
+  self->programs = get_programs_for_display (self, gdk_surface_get_display (surface), error);
+  if (self->programs == NULL)
     return FALSE;
+  self->op_builder.programs = self->programs;
 
   self->atlases = get_texture_atlases_for_display (gdk_surface_get_display (surface));
   self->glyph_cache = get_glyph_cache_for_display (gdk_surface_get_display (surface), self->atlases);
@@ -2813,7 +2867,6 @@ static void
 gsk_gl_renderer_unrealize (GskRenderer *renderer)
 {
   GskGLRenderer *self = GSK_GL_RENDERER (renderer);
-  guint i;
 
   if (self->gl_context == NULL)
     return;
@@ -2824,10 +2877,9 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer)
    * as they will be dropped when we finalize the GskGLDriver
    */
   ops_reset (&self->op_builder);
+  self->op_builder.programs = NULL;
 
-  for (i = 0; i < GL_N_PROGRAMS; i ++)
-    glDeleteProgram (self->programs[i].id);
-
+  g_clear_pointer (&self->programs, gsk_gl_renderer_programs_unref);
   g_clear_pointer (&self->glyph_cache, gsk_gl_glyph_cache_unref);
   g_clear_pointer (&self->icon_cache, gsk_gl_icon_cache_unref);
   g_clear_pointer (&self->atlases, gsk_gl_texture_atlases_unref);
@@ -3277,12 +3329,12 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self)
           break;
 
         case OP_CHANGE_CROSS_FADE:
-          g_assert (program == &self->cross_fade_program);
+          g_assert (program == &self->programs->cross_fade_program);
           apply_cross_fade_op (program, ptr);
           break;
 
         case OP_CHANGE_BLEND:
-          g_assert (program == &self->blend_program);
+          g_assert (program == &self->programs->blend_program);
           apply_blend_op (program, ptr);
           break;
 
diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c
index 175d57ce83..2effc087eb 100644
--- a/gsk/gl/gskglrenderops.c
+++ b/gsk/gl/gskglrenderops.c
@@ -54,7 +54,7 @@ get_current_program_state (RenderOpBuilder *builder)
   if (!builder->current_program)
     return NULL;
 
-  return &builder->program_state[builder->current_program->index];
+  return &builder->programs->state[builder->current_program->index];
 }
 
 void
@@ -194,31 +194,17 @@ ops_transform_bounds_modelview (const RenderOpBuilder *builder,
 void
 ops_init (RenderOpBuilder *builder)
 {
-  int i;
-
   memset (builder, 0, sizeof (*builder));
 
   builder->current_opacity = 1.0f;
 
   op_buffer_init (&builder->render_ops);
   builder->vertices = g_array_new (FALSE, TRUE, sizeof (GskQuadVertex));
-
-  for (i = 0; i < GL_N_PROGRAMS; i ++)
-    {
-      builder->program_state[i].opacity = 1.0f;
-    }
 }
 
 void
 ops_free (RenderOpBuilder *builder)
 {
-  int i;
-
-  for (i = 0; i < GL_N_PROGRAMS; i ++)
-    {
-      gsk_transform_unref (builder->program_state[i].modelview);
-    }
-
   g_array_unref (builder->vertices);
   op_buffer_destroy (&builder->render_ops);
 }
@@ -238,7 +224,7 @@ ops_set_program (RenderOpBuilder *builder,
 
   builder->current_program = program;
 
-  program_state = &builder->program_state[program->index];
+  program_state = &builder->programs->state[program->index];
 
   if (memcmp (&builder->current_projection, &program_state->projection, sizeof (graphene_matrix_t)) != 0)
     {
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index dd3f609ab8..feaf741f6e 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -125,9 +125,32 @@ typedef struct
   };
 } ProgramState;
 
+typedef struct {
+  int ref_count;
+  union {
+    Program programs[GL_N_PROGRAMS];
+    struct {
+      Program blend_program;
+      Program blit_program;
+      Program blur_program;
+      Program border_program;
+      Program color_matrix_program;
+      Program color_program;
+      Program coloring_program;
+      Program cross_fade_program;
+      Program inset_shadow_program;
+      Program linear_gradient_program;
+      Program outset_shadow_program;
+      Program repeat_program;
+      Program unblurred_outset_shadow_program;
+    };
+  };
+  ProgramState state[GL_N_PROGRAMS];
+} GskGLRendererPrograms;
+
 typedef struct
 {
-  ProgramState program_state[GL_N_PROGRAMS];
+  GskGLRendererPrograms *programs;
   const Program *current_program;
   int current_render_target;
   int current_texture;


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