[gtk/wip/chergert/glproto: 253/526] add shader loading (and unloading) to driver




commit e9e6686da3a9d1cac28324156f9a56f9d060a905
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jan 13 22:01:12 2021 -0800

    add shader loading (and unloading) to driver

 gsk/next/gskgldriver.c         | 142 ++++++++++++++++++++++++++++++++++++++++-
 gsk/next/gskgldriverprivate.h  |  16 ++++-
 gsk/next/gskglprogramprivate.h |  26 +++++---
 3 files changed, 172 insertions(+), 12 deletions(-)
---
diff --git a/gsk/next/gskgldriver.c b/gsk/next/gskgldriver.c
index 9175ca3346..fc68c253ed 100644
--- a/gsk/next/gskgldriver.c
+++ b/gsk/next/gskgldriver.c
@@ -24,9 +24,10 @@
 #include "config.h"
 
 #include <gdk/gdkglcontextprivate.h>
-#include <gdk/gdktextureprivate.h>
 #include <gdk/gdkgltextureprivate.h>
+#include <gdk/gdktextureprivate.h>
 #include <gsk/gskdebugprivate.h>
+#include <gsk/gskglshaderprivate.h>
 #include <gsk/gskrendererprivate.h>
 
 #include "gskglcommandqueueprivate.h"
@@ -131,6 +132,18 @@ gsk_next_driver_collect_unused_textures (GskNextDriver *self,
   return old_size - g_hash_table_size (self->textures);
 }
 
+static void
+gsk_next_driver_shader_weak_cb (gpointer  data,
+                                GObject  *where_object_was)
+{
+  GskNextDriver *self = data;
+
+  g_assert (GSK_IS_NEXT_DRIVER (self));
+
+  if (self->shader_cache)
+    g_hash_table_remove (self->shader_cache, where_object_was);
+}
+
 static void
 gsk_next_driver_dispose (GObject *object)
 {
@@ -152,6 +165,24 @@ gsk_next_driver_dispose (GObject *object)
 #undef GSK_GL_ADD_UNIFORM
 #undef GSK_GL_DEFINE_PROGRAM
 
+  if (self->shader_cache != NULL)
+    {
+      GHashTableIter iter;
+      gpointer k, v;
+
+      g_hash_table_iter_init (&iter, self->shader_cache);
+      while (g_hash_table_iter_next (&iter, &k, &v))
+        {
+          GskGLShader *shader = k;
+          g_object_weak_unref (G_OBJECT (shader),
+                               gsk_next_driver_shader_weak_cb,
+                               self);
+          g_hash_table_iter_remove (&iter);
+        }
+
+      g_clear_pointer (&self->shader_cache, g_hash_table_unref);
+    }
+
   if (self->command_queue != NULL)
     {
       gsk_gl_command_queue_make_current (self->command_queue);
@@ -172,6 +203,7 @@ gsk_next_driver_dispose (GObject *object)
   g_clear_pointer (&self->key_to_texture_id, g_hash_table_unref);
   g_clear_pointer (&self->texture_id_to_key, g_hash_table_unref);
   g_clear_pointer (&self->render_targets, g_ptr_array_unref);
+  g_clear_pointer (&self->shader_cache, g_hash_table_unref);
 
   G_OBJECT_CLASS (gsk_next_driver_parent_class)->dispose (object);
 }
@@ -194,6 +226,10 @@ gsk_next_driver_init (GskNextDriver *self)
                                                    texture_key_equal,
                                                    g_free,
                                                    NULL);
+  self->shader_cache = g_hash_table_new_full (NULL,
+                                              NULL,
+                                              g_object_unref,
+                                              g_object_unref);
   gsk_gl_texture_pool_init (&self->texture_pool);
   self->render_targets = g_ptr_array_new ();
 }
@@ -648,7 +684,7 @@ gsk_next_driver_acquire_texture (GskNextDriver *self,
 }
 
 /**
- * gsk_gl_driver_release_texture:
+ * gsk_next_driver_release_texture:
  * @self: a #GskNextDriver
  * @texture: a #GskGLTexture
  *
@@ -789,3 +825,105 @@ gsk_next_driver_release_render_target (GskNextDriver     *self,
 
   return texture_id;
 }
+
+/**
+ * gsk_next_driver_lookup_shader:
+ * @self: a #GskNextDriver
+ * @shader: the shader to lookup or load
+ * @error: a location for a #GError, or %NULL
+ *
+ * Attepts to load @shader from the shader cache.
+ *
+ * If it has not been loaded, then it will compile the shader on demand.
+ *
+ * Returns: (transfer none): a #GskGLShader if successful; otherwise
+ *   %NULL and @error is set.
+ */
+GskGLProgram *
+gsk_next_driver_lookup_shader (GskNextDriver  *self,
+                               GskGLShader    *shader,
+                               GError        **error)
+{
+  GskGLProgram *program;
+
+  g_return_val_if_fail (self != NULL, NULL);
+  g_return_val_if_fail (shader != NULL, NULL);
+
+  program = g_hash_table_lookup (self->shader_cache, shader);
+
+  if (program == NULL)
+    {
+      const GskGLUniform *uniforms;
+      GskGLCompiler *compiler;
+      GBytes *suffix;
+      int n_required_textures;
+      int n_uniforms;
+
+      uniforms = gsk_gl_shader_get_uniforms (shader, &n_uniforms);
+      if (n_uniforms > G_N_ELEMENTS (program->args_locations))
+        {
+          g_set_error (error,
+                       GDK_GL_ERROR,
+                       GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+                       "GLShaderNode supports max %d custom uniforms",
+                       (int)G_N_ELEMENTS (program->args_locations));
+          return NULL;
+        }
+
+      n_required_textures = gsk_gl_shader_get_n_textures (shader);
+      if (n_required_textures > G_N_ELEMENTS (program->texture_locations))
+        {
+          g_set_error (error,
+                       GDK_GL_ERROR,
+                       GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+                       "GLShaderNode supports max %d texture sources",
+                       (int)(G_N_ELEMENTS (program->texture_locations)));
+          return NULL;
+        }
+
+      compiler = gsk_gl_compiler_new (self->command_queue, FALSE);
+      suffix = gsk_gl_shader_get_source (shader);
+
+      gsk_gl_compiler_set_preamble_from_resource (compiler,
+                                                  GSK_GL_COMPILER_ALL,
+                                                  "/org/gtk/libgsk/glsl/preamble.glsl");
+      gsk_gl_compiler_set_preamble_from_resource (compiler,
+                                                  GSK_GL_COMPILER_VERTEX,
+                                                  "/org/gtk/libgsk/glsl/preamble.vs.glsl");
+      gsk_gl_compiler_set_preamble_from_resource (compiler,
+                                                  GSK_GL_COMPILER_FRAGMENT,
+                                                  "/org/gtk/libgsk/glsl/preamble.fs.glsl");
+      gsk_gl_compiler_set_suffix (compiler, GSK_GL_COMPILER_FRAGMENT, suffix);
+
+      if ((program = gsk_gl_compiler_compile (compiler, NULL, NULL)))
+        {
+          gsk_gl_program_add_uniform (program, "u_size", UNIFORM_CUSTOM_SIZE);
+          gsk_gl_program_add_uniform (program, "u_texture1", UNIFORM_CUSTOM_TEXTURE1);
+          gsk_gl_program_add_uniform (program, "u_texture2", UNIFORM_CUSTOM_TEXTURE2);
+          gsk_gl_program_add_uniform (program, "u_texture3", UNIFORM_CUSTOM_TEXTURE3);
+          gsk_gl_program_add_uniform (program, "u_texture4", UNIFORM_CUSTOM_TEXTURE4);
+          for (guint i = 0; i < n_uniforms; i++)
+            gsk_gl_program_add_uniform (program, uniforms[i].name, UNIFORM_CUSTOM_LAST+i);
+
+          program->size_location = gsk_gl_program_get_uniform_location (program, UNIFORM_CUSTOM_SIZE);
+          program->texture_locations[0] = gsk_gl_program_get_uniform_location (program, 
UNIFORM_CUSTOM_TEXTURE1);
+          program->texture_locations[1] = gsk_gl_program_get_uniform_location (program, 
UNIFORM_CUSTOM_TEXTURE2);
+          program->texture_locations[2] = gsk_gl_program_get_uniform_location (program, 
UNIFORM_CUSTOM_TEXTURE3);
+          program->texture_locations[3] = gsk_gl_program_get_uniform_location (program, 
UNIFORM_CUSTOM_TEXTURE4);
+          for (guint i = 0; i < n_uniforms; i++)
+            program->args_locations[i] = gsk_gl_program_get_uniform_location (program, 
UNIFORM_CUSTOM_LAST+i);
+          for (guint i = n_uniforms; i < G_N_ELEMENTS (program->args_locations); i++)
+            program->args_locations[i] = -1;
+
+          g_hash_table_insert (self->shader_cache, shader, program);
+
+          g_object_weak_ref (G_OBJECT (shader),
+                             gsk_next_driver_shader_weak_cb,
+                             self);
+        }
+
+      g_object_unref (compiler);
+    }
+
+  return g_steal_pointer (&program);
+}
diff --git a/gsk/next/gskgldriverprivate.h b/gsk/next/gskgldriverprivate.h
index 79980f77cd..6e843e0a93 100644
--- a/gsk/next/gskgldriverprivate.h
+++ b/gsk/next/gskgldriverprivate.h
@@ -38,6 +38,16 @@ enum {
   UNIFORM_SHARED_LAST
 };
 
+enum {
+  UNIFORM_CUSTOM_SIZE = UNIFORM_SHARED_LAST,
+  UNIFORM_CUSTOM_TEXTURE1,
+  UNIFORM_CUSTOM_TEXTURE2,
+  UNIFORM_CUSTOM_TEXTURE3,
+  UNIFORM_CUSTOM_TEXTURE4,
+
+  UNIFORM_CUSTOM_LAST
+};
+
 typedef struct {
   gpointer        pointer;
   float           scale_x;
@@ -82,10 +92,11 @@ struct _GskNextDriver
   GskGLShadowLibrary *shadows;
 
   GHashTable *textures;
-
   GHashTable *key_to_texture_id;
   GHashTable *texture_id_to_key;
 
+  GHashTable *shader_cache;
+
   GArray *autorelease_framebuffers;
   GPtrArray *render_targets;
 
@@ -139,6 +150,9 @@ GskGLTexture  *gsk_next_driver_acquire_texture       (GskNextDriver        *self
                                                       int                   mag_filter);
 void           gsk_next_driver_release_texture       (GskNextDriver        *self,
                                                       GskGLTexture         *texture);
+GskGLProgram  *gsk_next_driver_lookup_shader         (GskNextDriver        *self,
+                                                      GskGLShader          *shader,
+                                                      GError              **error);
 
 G_END_DECLS
 
diff --git a/gsk/next/gskglprogramprivate.h b/gsk/next/gskglprogramprivate.h
index 4cf22e3056..1149002bfc 100644
--- a/gsk/next/gskglprogramprivate.h
+++ b/gsk/next/gskglprogramprivate.h
@@ -33,16 +33,24 @@ G_DECLARE_FINAL_TYPE (GskGLProgram, gsk_gl_program, GSK, GL_PROGRAM, GObject)
 
 struct _GskGLProgram
 {
-  GObject            parent_instance;
-  int                id;
-  char              *name;
-  GArray            *uniform_locations;
+  GObject parent_instance;
+
+  int id;
+  char *name;
+  GArray *uniform_locations;
   GskGLCommandQueue *command_queue;
-  int                projection_location;
-  int                modelview_location;
-  int                viewport_location;
-  int                clip_rect_location;
-  int                alpha_location;
+
+  /* Cached shared locations */
+  int projection_location;
+  int modelview_location;
+  int viewport_location;
+  int clip_rect_location;
+  int alpha_location;
+
+  /* For custom programs */
+  int texture_locations[4];
+  int args_locations[8];
+  int size_location;
 };
 
 GskGLProgram *gsk_gl_program_new         (GskGLCommandQueue       *command_queue,


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