[gtk+/wip/ebassi/gsk-renderer: 61/79] gsk: Consolidate program creation and storage



commit 3b85e0ed416a733f7c43856e75b8a940a517cf78
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Mon Jul 4 13:46:22 2016 +0100

    gsk: Consolidate program creation and storage
    
    We should use ShaderBuilder to create and store programs for the GL
    renderer. This allows us to simplify the creation of programs (by moving
    the compilation phase into the ShaderBuilder::create_program() method),
    and move towards the ability to create multiple programs and just keep a
    reference to the program id.

 gsk/gskglrenderer.c           |   87 +++++++---------------
 gsk/gskshaderbuilder.c        |  164 ++++++++++++++++++++++++++++++-----------
 gsk/gskshaderbuilderprivate.h |   16 ++--
 3 files changed, 155 insertions(+), 112 deletions(-)
---
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index 3f2a213..91589bc 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -87,7 +87,9 @@ struct _GskGLRenderer
   GQuark uniforms[N_UNIFORMS];
   GQuark attributes[N_ATTRIBUTES];
 
-  GskShaderBuilder *blend_program;
+  GskShaderBuilder *shader_builder;
+
+  int blend_program_id;
 
   guint vao_id;
 
@@ -295,9 +297,6 @@ static gboolean
 gsk_gl_renderer_create_programs (GskGLRenderer *self)
 {
   GskShaderBuilder *builder;
-  const char *vertex_preamble;
-  const char *fragment_preamble;
-  int vertex_id = -1, fragment_id = -1;
   GError *error = NULL;
   gboolean res = FALSE;
 
@@ -317,26 +316,23 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self)
   if (gdk_gl_context_get_use_es (self->context))
     {
       gsk_shader_builder_set_version (builder, SHADER_VERSION_GLES);
+      gsk_shader_builder_set_vertex_preamble (builder, "es2_common.vs.glsl");
+      gsk_shader_builder_set_fragment_preamble (builder, "es2_common.fs.glsl");
       gsk_shader_builder_add_define (builder, "GSK_GLES", "1");
-
-      vertex_preamble = "gles_common.vs.glsl";
-      fragment_preamble = "gles_common.fs.glsl";
     }
   else if (gdk_gl_context_is_legacy (self->context))
     {
       gsk_shader_builder_set_version (builder, SHADER_VERSION_GL_LEGACY);
+      gsk_shader_builder_set_vertex_preamble (builder, "gl_common.vs.glsl");
+      gsk_shader_builder_set_fragment_preamble (builder, "gl_common.fs.glsl");
       gsk_shader_builder_add_define (builder, "GSK_LEGACY", "1");
-
-      vertex_preamble = "gl_common.vs.glsl";
-      fragment_preamble = "gl_common.fs.glsl";
     }
   else
     {
       gsk_shader_builder_set_version (builder, SHADER_VERSION_GL3);
+      gsk_shader_builder_set_vertex_preamble (builder, "gl3_common.vs.glsl");
+      gsk_shader_builder_set_fragment_preamble (builder, "gl3_common.fs.glsl");
       gsk_shader_builder_add_define (builder, "GSK_GL3", "1");
-
-      vertex_preamble = "gl3_common.vs.glsl";
-      fragment_preamble = "gl3_common.fs.glsl";
     }
 
 #ifdef G_ENABLE_DEBUG
@@ -344,62 +340,28 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self)
     gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
 #endif
 
-  vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
-                                                 vertex_preamble,
-                                                 "blend.vs.glsl",
-                                                 &error);
-  if (error != NULL)
-    {
-      g_critical ("Unable to compile vertex shader: %s", error->message);
-      g_error_free (error);
-      goto out;
-    }
-
-  fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
-                                                   fragment_preamble,
-                                                   "blend.fs.glsl",
-                                                   &error);
-  if (error != NULL)
-    {
-      g_critical ("Unable to compile fragment shader: %s", error->message);
-      g_error_free (error);
-      goto out;
-    }
-
-  gsk_shader_builder_create_program (builder, vertex_id, fragment_id, &error);
+  self->blend_program_id =
+    gsk_shader_builder_create_program (builder, "blend.vs.glsl", "blend.fs.glsl", &error);
   if (error != NULL)
     {
       g_critical ("Unable to create program: %s", error->message);
       g_error_free (error);
+      g_object_unref (builder);
       goto out;
     }
 
-  self->blend_program = g_object_ref (builder);
+  self->shader_builder = builder;
 
   res = TRUE;
 
 out:
-  g_object_unref (builder);
-
-  if (vertex_id > 0)
-    glDeleteShader (vertex_id);
-  if (fragment_id > 0)
-    glDeleteShader (fragment_id);
-
   return res;
 }
 
 static void
 gsk_gl_renderer_destroy_programs (GskGLRenderer *self)
 {
-  if (self->blend_program != NULL)
-    {
-      int program_id = gsk_shader_builder_get_program (self->blend_program);
-
-      glDeleteProgram (program_id);
-
-      g_clear_object (&self->blend_program);
-    }
+  g_clear_object (&self->shader_builder);
 }
 
 static gboolean
@@ -440,10 +402,11 @@ gsk_gl_renderer_realize (GskRenderer *renderer)
   gdk_gl_context_make_current (self->context);
 
   GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
-  gsk_gl_renderer_create_buffers (self);
   if (!gsk_gl_renderer_create_programs (self))
     return FALSE;
 
+  gsk_gl_renderer_create_buffers (self);
+
   return TRUE;
 }
 
@@ -722,6 +685,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
   graphene_rect_t bounds;
   GskRenderNode *child;
   RenderItem item;
+  int program_id;
 
   if (gsk_render_node_is_hidden (node))
     {
@@ -767,23 +731,24 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
   item.render_data.vao_id = self->vao_id;
   item.render_data.buffer_id = 0;
 
-  item.render_data.program_id = gsk_shader_builder_get_program (self->blend_program);
+  program_id = self->blend_program_id;
+  item.render_data.program_id = program_id;
 
   item.render_data.map_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[MAP]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MAP]);
   item.render_data.parentMap_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[PARENT_MAP]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[PARENT_MAP]);
   item.render_data.mvp_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[MVP]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MVP]);
   item.render_data.alpha_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[ALPHA]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[ALPHA]);
   item.render_data.blendMode_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[BLEND_MODE]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[BLEND_MODE]);
 
   item.render_data.position_location =
-    gsk_shader_builder_get_attribute_location (self->blend_program, self->attributes[POSITION]);
+    gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[POSITION]);
   item.render_data.uv_location =
-    gsk_shader_builder_get_attribute_location (self->blend_program, self->attributes[UV]);
+    gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[UV]);
 
   if (parent != NULL)
     item.parent_data = &(parent->render_data);
diff --git a/gsk/gskshaderbuilder.c b/gsk/gskshaderbuilder.c
index b17c41a..8e37294 100644
--- a/gsk/gskshaderbuilder.c
+++ b/gsk/gskshaderbuilder.c
@@ -7,27 +7,59 @@
 #include <gdk/gdk.h>
 #include <epoxy/gl.h>
 
+typedef struct {
+  int program_id;
+
+  GHashTable *uniform_locations;
+  GHashTable *attribute_locations;
+} ShaderProgram;
+
 struct _GskShaderBuilder
 {
   GObject parent_instance;
 
   char *resource_base_path;
+  char *vertex_preamble;
+  char *fragment_preamble;
 
   int version;
 
-  int program_id;
-
   GPtrArray *defines;
   GPtrArray *uniforms;
   GPtrArray *attributes;
 
-  GHashTable *uniform_locations;
-  GHashTable *attribute_locations;
+  GHashTable *programs;
 };
 
 G_DEFINE_TYPE (GskShaderBuilder, gsk_shader_builder, G_TYPE_OBJECT)
 
 static void
+shader_program_free (gpointer data)
+{
+  ShaderProgram *p = data;
+
+  g_clear_pointer (&p->uniform_locations, g_hash_table_unref);
+  g_clear_pointer (&p->attribute_locations, g_hash_table_unref);
+
+  glDeleteProgram (p->program_id);
+
+  g_slice_free (ShaderProgram, data);
+}
+
+static ShaderProgram *
+shader_program_new (int program_id)
+{
+  ShaderProgram *p = g_slice_new (ShaderProgram);
+
+  p->program_id = program_id;
+
+  p->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+  p->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  return p;
+}
+
+static void
 gsk_shader_builder_finalize (GObject *gobject)
 {
   GskShaderBuilder *self = GSK_SHADER_BUILDER (gobject);
@@ -38,8 +70,7 @@ gsk_shader_builder_finalize (GObject *gobject)
   g_clear_pointer (&self->uniforms, g_ptr_array_unref);
   g_clear_pointer (&self->attributes, g_ptr_array_unref);
 
-  g_clear_pointer (&self->uniform_locations, g_hash_table_unref);
-  g_clear_pointer (&self->attribute_locations, g_hash_table_unref);
+  g_clear_pointer (&self->programs, g_hash_table_unref);
 
   G_OBJECT_CLASS (gsk_shader_builder_parent_class)->finalize (gobject);
 }
@@ -57,8 +88,9 @@ gsk_shader_builder_init (GskShaderBuilder *self)
   self->uniforms = g_ptr_array_new_with_free_func (g_free);
   self->attributes = g_ptr_array_new_with_free_func (g_free);
 
-  self->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
-  self->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+  self->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+                                          NULL,
+                                          shader_program_free);
 }
 
 GskShaderBuilder *
@@ -78,6 +110,26 @@ gsk_shader_builder_set_resource_base_path (GskShaderBuilder *builder,
 }
 
 void
+gsk_shader_builder_set_vertex_preamble (GskShaderBuilder *builder,
+                                        const char       *vertex_preamble)
+{
+  g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
+
+  g_free (builder->vertex_preamble);
+  builder->vertex_preamble = g_strdup (vertex_preamble);
+}
+
+void
+gsk_shader_builder_set_fragment_preamble (GskShaderBuilder *builder,
+                                          const char       *fragment_preamble)
+{
+  g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
+
+  g_free (builder->fragment_preamble);
+  builder->fragment_preamble = g_strdup (fragment_preamble);
+}
+
+void
 gsk_shader_builder_set_version (GskShaderBuilder *builder,
                                 int               version)
 {
@@ -150,7 +202,7 @@ lookup_shader_code (GString *code,
   return TRUE;
 }
 
-int
+static int
 gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
                                    int               shader_type,
                                    const char       *shader_preamble,
@@ -163,9 +215,6 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
   int status;
   int i;
 
-  g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
-  g_return_val_if_fail (shader_source != NULL, -1);
-
   code = g_string_new (NULL);
 
   if (builder->version > 0)
@@ -249,16 +298,16 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
 
 static void
 gsk_shader_builder_cache_uniforms (GskShaderBuilder *builder,
-                                   int               program_id)
+                                   ShaderProgram    *program)
 {
   int i;
 
   for (i = 0; i < builder->uniforms->len; i++)
     {
       const char *uniform = g_ptr_array_index (builder->uniforms, i);
-      int loc = glGetUniformLocation (program_id, uniform);
+      int loc = glGetUniformLocation (program->program_id, uniform);
 
-      g_hash_table_insert (builder->uniform_locations,
+      g_hash_table_insert (program->uniform_locations,
                            GINT_TO_POINTER (g_quark_from_string (uniform)),
                            GINT_TO_POINTER (loc));
     }
@@ -266,16 +315,16 @@ gsk_shader_builder_cache_uniforms (GskShaderBuilder *builder,
 
 static void
 gsk_shader_builder_cache_attributes (GskShaderBuilder *builder,
-                                     int               program_id)
+                                     ShaderProgram    *program)
 {
   int i;
 
   for (i = 0; i < builder->attributes->len; i++)
     {
       const char *attribute = g_ptr_array_index (builder->attributes, i);
-      int loc = glGetAttribLocation (program_id, attribute);
+      int loc = glGetAttribLocation (program->program_id, attribute);
 
-      g_hash_table_insert (builder->attribute_locations,
+      g_hash_table_insert (program->attribute_locations,
                            GINT_TO_POINTER (g_quark_from_string (attribute)),
                            GINT_TO_POINTER (loc));
     }
@@ -283,16 +332,35 @@ gsk_shader_builder_cache_attributes (GskShaderBuilder *builder,
 
 int
 gsk_shader_builder_create_program (GskShaderBuilder *builder,
-                                   int               vertex_id,
-                                   int               fragment_id,
+                                   const char       *vertex_shader,
+                                   const char       *fragment_shader,
                                    GError          **error)
 {
+  ShaderProgram *program;
+  int vertex_id, fragment_id;
   int program_id;
   int status;
 
   g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
-  g_return_val_if_fail (vertex_id > 0, -1);
-  g_return_val_if_fail (fragment_id > 0, -1);
+  g_return_val_if_fail (vertex_shader != NULL, -1);
+  g_return_val_if_fail (fragment_shader != NULL, -1);
+
+  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,
+                                                   error);
+  if (fragment_id < 0)
+    {
+      glDeleteShader (vertex_id);
+      return -1;
+    }
 
   program_id = glCreateProgram ();
   glAttachShader (program_id, vertex_id);
@@ -320,10 +388,11 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
       goto out;
     }
 
-  gsk_shader_builder_cache_uniforms (builder, program_id);
-  gsk_shader_builder_cache_attributes (builder, program_id);
+  program = shader_program_new (program_id);
+  gsk_shader_builder_cache_uniforms (builder, program);
+  gsk_shader_builder_cache_attributes (builder, program);
 
-  builder->program_id = program_id;
+  g_hash_table_insert (builder->programs, GINT_TO_POINTER (program_id), program);
 
 #ifdef G_ENABLE_DEBUG
   if (GSK_DEBUG_CHECK (OPENGL))
@@ -331,7 +400,7 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
       GHashTableIter iter;
       gpointer name_p, location_p;
 
-      g_hash_table_iter_init (&iter, builder->uniform_locations);
+      g_hash_table_iter_init (&iter, program->uniform_locations);
       while (g_hash_table_iter_next (&iter, &name_p, &location_p))
         {
           g_print ("Uniform '%s' - location: %d\n",
@@ -339,7 +408,7 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
                    GPOINTER_TO_INT (location_p));
         }
 
-      g_hash_table_iter_init (&iter, builder->attribute_locations);
+      g_hash_table_iter_init (&iter, program->attribute_locations);
       while (g_hash_table_iter_next (&iter, &name_p, &location_p))
         {
           g_print ("Attribute '%s' - location: %d\n",
@@ -350,27 +419,40 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
 #endif
 
 out:
-  glDetachShader (program_id, vertex_id);
-  glDetachShader (program_id, fragment_id);
+  if (vertex_id > 0)
+    {
+      glDetachShader (program_id, vertex_id);
+      glDeleteShader (vertex_id);
+    }
+
+  if (fragment_id > 0)
+    {
+      glDetachShader (program_id, fragment_id);
+      glDeleteShader (fragment_id);
+    }
 
   return program_id;
 }
 
 int
 gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
+                                         int               program_id,
                                          GQuark            uniform_quark)
 {
+  ShaderProgram *p = NULL;
   gpointer loc_p = NULL;
 
   g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
+  g_return_val_if_fail (program_id >= 0, -1);
 
-  if (builder->program_id < 0)
+  if (builder->uniforms->len == 0)
     return -1;
 
-  if (builder->uniforms->len == 0)
+  p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
+  if (p == NULL)
     return -1;
 
-  if (g_hash_table_lookup_extended (builder->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, 
&loc_p))
+  if (g_hash_table_lookup_extended (p->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, &loc_p))
     return GPOINTER_TO_INT (loc_p);
 
   return -1;
@@ -378,28 +460,24 @@ gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
 
 int
 gsk_shader_builder_get_attribute_location (GskShaderBuilder *builder,
+                                           int               program_id,
                                            GQuark            attribute_quark)
 {
+  ShaderProgram *p = NULL;
   gpointer loc_p = NULL;
 
   g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
+  g_return_val_if_fail (program_id >= 0, -1);
 
-  if (builder->program_id < 0)
+  if (builder->attributes->len == 0)
     return -1;
 
-  if (builder->attributes->len == 0)
+  p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
+  if (p == NULL)
     return -1;
 
-  if (g_hash_table_lookup_extended (builder->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, 
&loc_p))
+  if (g_hash_table_lookup_extended (p->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, &loc_p))
     return GPOINTER_TO_INT (loc_p);
 
   return -1;
 }
-
-int
-gsk_shader_builder_get_program (GskShaderBuilder *builder)
-{
-  g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
-
-  return builder->program_id;
-}
diff --git a/gsk/gskshaderbuilderprivate.h b/gsk/gskshaderbuilderprivate.h
index ce069ed..144b2b0 100644
--- a/gsk/gskshaderbuilderprivate.h
+++ b/gsk/gskshaderbuilderprivate.h
@@ -16,6 +16,10 @@ void                    gsk_shader_builder_set_version                  (GskShad
                                                                          int               version);
 void                    gsk_shader_builder_set_resource_base_path       (GskShaderBuilder *builder,
                                                                          const char       *base_path);
+void                    gsk_shader_builder_set_vertex_preamble          (GskShaderBuilder *builder,
+                                                                         const char       *shader_preamble);
+void                    gsk_shader_builder_set_fragment_preamble        (GskShaderBuilder *builder,
+                                                                         const char       *shader_preamble);
 
 GQuark                  gsk_shader_builder_add_uniform                  (GskShaderBuilder *builder,
                                                                          const char       *uniform_name);
@@ -25,20 +29,16 @@ void                    gsk_shader_builder_add_define                   (GskShad
                                                                          const char       *define_name,
                                                                          const char       *define_value);
 
-int                     gsk_shader_builder_compile_shader               (GskShaderBuilder *builder,
-                                                                         int               shader_type,
-                                                                         const char       *shader_preamble,
-                                                                         const char       *shader_source,
-                                                                         GError          **error);
 int                     gsk_shader_builder_create_program               (GskShaderBuilder *builder,
-                                                                         int               vertex_id,
-                                                                         int               fragment_id,
+                                                                         const char       *vertex_shader,
+                                                                         const char       *fragment_shader,
                                                                          GError          **error);
 
-int                     gsk_shader_builder_get_program                  (GskShaderBuilder *builder);
 int                     gsk_shader_builder_get_uniform_location         (GskShaderBuilder *builder,
+                                                                         int               program_id,
                                                                          GQuark            uniform_quark);
 int                     gsk_shader_builder_get_attribute_location       (GskShaderBuilder *builder,
+                                                                         int               program_id,
                                                                          GQuark            attribute_quark);
 
 G_END_DECLS


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