[gtk+/wip/ebassi/gsk-renderer: 44/126] gsk: Rework how GLSL shaders are built



commit d417b1c73e67ebf9979168a2c30492ed9d97986c
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Sun Jul 3 21:12:22 2016 +0100

    gsk: Rework how GLSL shaders are built
    
    The GL renderer should build the GLSL shaders using GskShaderBuilder.
    This allows us to separate the common parts into separate files, and
    assemble them as necessary, instead of shipping one big shader per type
    of GL API (GL3, GL legacy, and GLES).

 gsk/gskglrenderer.c                   |  214 +++++++++++++++++----------------
 gsk/resources/glsl/blend.fs.glsl      |   22 ++++
 gsk/resources/glsl/blend.vs.glsl      |    6 +
 gsk/resources/glsl/es2_common.fs.glsl |   16 +++
 gsk/resources/glsl/es2_common.vs.glsl |    7 +
 gsk/resources/glsl/gl3-base.fs.glsl   |   34 -----
 gsk/resources/glsl/gl3-base.vs.glsl   |   16 ---
 gsk/resources/glsl/gl3_common.fs.glsl |   19 +++
 gsk/resources/glsl/gl3_common.vs.glsl |    7 +
 gsk/resources/glsl/gl_common.fs.glsl  |   14 ++
 gsk/resources/glsl/gl_common.vs.glsl  |    7 +
 gsk/resources/glsl/gles-base.fs.glsl  |   11 --
 gsk/resources/glsl/gles-base.vs.glsl  |   12 --
 13 files changed, 208 insertions(+), 177 deletions(-)
---
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index d9d6540..fd8ee8d 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -7,6 +7,7 @@
 #include "gskrendererprivate.h"
 #include "gskrendernodeprivate.h"
 #include "gskrendernodeiter.h"
+#include "gskshaderbuilderprivate.h"
 
 #include "gskprivate.h"
 
@@ -275,131 +276,135 @@ gsk_gl_renderer_destroy_buffers (GskGLRenderer *self)
   self->has_buffers = FALSE;
 }
 
-static guint
-create_shader (int         type,
-               const char *code)
+static gboolean
+gsk_gl_renderer_create_programs (GskGLRenderer *self)
 {
-  guint shader;
-  int status;
-
-  shader = glCreateShader (type);
-  glShaderSource (shader, 1, &code, NULL);
-  glCompileShader (shader);
-
-  glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
-  if (status == GL_FALSE)
-    {
-      int log_len;
-      char *buffer;
+  GskShaderBuilder *builder;
+  const char *vertex_preamble;
+  const char *fragment_preamble;
+  int vertex_id = -1, fragment_id = -1;
+  int program_id = -1;
+  GError *error = NULL;
+  gboolean res = FALSE;
+  enum {
+    MVP,
+    MAP,
+    PARENT_MAP,
+    ALPHA,
+    BLEND_MODE,
+    N_UNIFORMS
+  };
+  enum {
+    POSITION,
+    UV,
+    N_ATTRIBUTES
+  };
+  GQuark uniforms[N_UNIFORMS];
+  GQuark attributes[N_ATTRIBUTES];
+  
+  builder = gsk_shader_builder_new ();
 
-      glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &log_len);
+  gsk_shader_builder_set_resource_base_path (builder, "/org/gtk/libgsk/glsl");
 
-      buffer = g_malloc0 (log_len + 1);
-      glGetShaderInfoLog (shader, log_len, NULL, buffer);
+  uniforms[MVP] = gsk_shader_builder_add_uniform (builder, "mvp");
+  uniforms[MAP] = gsk_shader_builder_add_uniform (builder, "map");
+  uniforms[PARENT_MAP] = gsk_shader_builder_add_uniform (builder, "parentMap");
+  uniforms[ALPHA] = gsk_shader_builder_add_uniform (builder, "alpha");
+  uniforms[BLEND_MODE] = gsk_shader_builder_add_uniform (builder, "blendMode");
+  
+  attributes[POSITION] = gsk_shader_builder_add_attribute (builder, "position");
+  attributes[UV] = gsk_shader_builder_add_attribute (builder, "uv");
 
-      g_critical ("Compile failure in %s shader:\n%s",
-                  type == GL_VERTEX_SHADER ? "vertex" : "fragment",
-                  buffer);
-      g_free (buffer);
+#define SHADER_VERSION_GLES             110
+#define SHADER_VERSION_GL_LEGACY        120
+#define SHADER_VERSION_GL3              150
 
-      glDeleteShader (shader);
+  if (gdk_gl_context_get_use_es (self->context))
+    {
+      gsk_shader_builder_set_version (builder, SHADER_VERSION_GLES);
+      gsk_shader_builder_add_define (builder, "GSK_GLES", "1");
 
-      return 0;
+      vertex_preamble = "gles_common.vs.glsl";
+      fragment_preamble = "gles_common.fs.glsl";
     }
-
-  return shader;
-}
-
-static void
-gsk_gl_renderer_create_program (GskGLRenderer *self)
-{
-  guint vertex_shader = 0, fragment_shader = 0;
-  const char *fs_path, *vs_path;
-  GBytes *source;
-  int status;
-
-  if (gdk_gl_context_get_use_es (self->context))
+  else if (gdk_gl_context_is_legacy (self->context))
     {
-      vs_path = "/org/gtk/libgsk/glsl/gles-base.vs.glsl";
-      fs_path = "/org/gtk/libgsk/glsl/gles-base.fs.glsl";
+      gsk_shader_builder_set_version (builder, SHADER_VERSION_GL_LEGACY);
+      gsk_shader_builder_add_define (builder, "GSK_LEGACY", "1");
+
+      vertex_preamble = "gl_common.vs.glsl";
+      fragment_preamble = "gl_common.fs.glsl";
     }
   else
     {
-      vs_path = "/org/gtk/libgsk/glsl/gl3-base.vs.glsl";
-      fs_path = "/org/gtk/libgsk/glsl/gl3-base.fs.glsl";
-    }
-
-  GSK_NOTE (OPENGL, g_print ("Compiling vertex shader\n"));
-  source = g_resources_lookup_data (vs_path, 0, NULL);
-  vertex_shader = create_shader (GL_VERTEX_SHADER, g_bytes_get_data (source, NULL));
-  g_bytes_unref (source);
-  if (vertex_shader == 0)
-    goto out;
+      gsk_shader_builder_set_version (builder, SHADER_VERSION_GL3);
+      gsk_shader_builder_add_define (builder, "GSK_GL3", "1");
 
-  GSK_NOTE (OPENGL, g_print ("Compiling fragment shader\n"));
-  source = g_resources_lookup_data (fs_path, 0, NULL);
-  fragment_shader = create_shader (GL_FRAGMENT_SHADER, g_bytes_get_data (source, NULL));
-  g_bytes_unref (source);
-  if (fragment_shader == 0)
-    goto out;
+      vertex_preamble = "gl3_common.vs.glsl";
+      fragment_preamble = "gl3_common.fs.glsl";
+    }
 
-  self->program_id = glCreateProgram ();
-  glAttachShader (self->program_id, vertex_shader);
-  glAttachShader (self->program_id, fragment_shader);
-  glLinkProgram (self->program_id);
+#ifdef G_ENABLE_DEBUG
+  if (GSK_RENDER_MODE_CHECK (SHADERS))
+    gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
+#endif
 
-  glGetProgramiv (self->program_id, GL_LINK_STATUS, &status);
-  if (status == GL_FALSE)
+  vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
+                                                 vertex_preamble,
+                                                 "blend.vs.glsl",
+                                                 &error);
+  if (error != NULL)
     {
-      char *buffer = NULL;
-      int log_len = 0;
-
-      glGetProgramiv (self->program_id, GL_INFO_LOG_LENGTH, &log_len);
-
-      buffer = g_malloc0 (log_len + 1);
-      glGetProgramInfoLog (self->program_id, log_len, NULL, buffer);
-
-      g_critical ("Linking failure in shader:\n%s", buffer);
-      g_free (buffer);
+      g_critical ("Unable to compile vertex shader: %s", error->message);
+      g_error_free (error);
+      goto out;
+    }
 
-      glDeleteProgram (self->program_id);
-      self->program_id = 0;
+  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;
+    }
 
+  program_id = gsk_shader_builder_create_program (builder,
+                                                  vertex_id, fragment_id,
+                                                  &error);
+  if (error != NULL)
+    {
+      g_critical ("Unable to create program: %s", error->message);
+      g_error_free (error);
       goto out;
     }
 
-  /* Find the location of each uniform and attribute we use in our
-   * shaders
-   */
-  self->mvp_location = glGetUniformLocation (self->program_id, "mvp");
-  self->map_location = glGetUniformLocation (self->program_id, "map");
-  self->parentMap_location = glGetUniformLocation (self->program_id, "parentMap");
-  self->alpha_location = glGetUniformLocation (self->program_id, "alpha");
-  self->position_location = glGetAttribLocation (self->program_id, "position");
-  self->uv_location = glGetAttribLocation (self->program_id, "uv");
-  self->blendMode_location = glGetAttribLocation (self->program_id, "blendMode");
-
-  GSK_NOTE (OPENGL, g_print ("Program [%d] { mvp:%u, map:%u, alpha:%u, position:%u, uv:%u }\n",
-                             self->program_id,
-                             self->mvp_location,
-                             self->map_location,
-                             self->alpha_location,
-                             self->position_location,
-                             self->uv_location));
-
-  /* We can detach and destroy the shaders from the linked program */
-  glDetachShader (self->program_id, vertex_shader);
-  glDetachShader (self->program_id, fragment_shader);
+  self->program_id = program_id;
+  self->mvp_location = gsk_shader_builder_get_uniform_location (builder, uniforms[MVP]);
+  self->map_location = gsk_shader_builder_get_uniform_location (builder, uniforms[MAP]);
+  self->parentMap_location = gsk_shader_builder_get_uniform_location (builder, uniforms[PARENT_MAP]);
+  self->alpha_location = gsk_shader_builder_get_uniform_location (builder, uniforms[ALPHA]);
+  self->blendMode_location = gsk_shader_builder_get_uniform_location (builder, uniforms[BLEND_MODE]);
+  self->position_location = gsk_shader_builder_get_attribute_location (builder, attributes[POSITION]);
+  self->uv_location = gsk_shader_builder_get_attribute_location (builder, attributes[UV]);
+
+  res = TRUE;
 
 out:
-  if (vertex_shader != 0)
-    glDeleteShader (vertex_shader);
-  if (fragment_shader != 0)
-    glDeleteShader (fragment_shader);
+  if (vertex_id > 0)
+    glDeleteShader (vertex_id);
+  if (fragment_id > 0)
+    glDeleteShader (fragment_id);
+
+  g_object_unref (builder);
+
+  return res;
 }
 
 static void
-gsk_gl_renderer_destroy_program (GskGLRenderer *self)
+gsk_gl_renderer_destroy_programs (GskGLRenderer *self)
 {
   if (self->program_id != 0)
     {
@@ -447,7 +452,8 @@ gsk_gl_renderer_realize (GskRenderer *renderer)
 
   GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
   gsk_gl_renderer_create_buffers (self);
-  gsk_gl_renderer_create_program (self);
+  if (!gsk_gl_renderer_create_programs (self))
+    return FALSE;
 
   return TRUE;
 }
@@ -466,7 +472,7 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer)
   g_clear_pointer (&self->transparent_render_items, g_array_unref);
 
   gsk_gl_renderer_destroy_buffers (self);
-  gsk_gl_renderer_destroy_program (self);
+  gsk_gl_renderer_destroy_programs (self);
 
   if (self->context == gdk_gl_context_get_current ())
     gdk_gl_context_clear_current ();
diff --git a/gsk/resources/glsl/blend.fs.glsl b/gsk/resources/glsl/blend.fs.glsl
new file mode 100644
index 0000000..5d2f873
--- /dev/null
+++ b/gsk/resources/glsl/blend.fs.glsl
@@ -0,0 +1,22 @@
+vec3 BlendMultiply(vec3 Csrc, vec3 Cdst) {
+  return Csrc * Cdst;
+}
+
+void main() {
+  vec4 src = Texture(map, vUv);
+  vec4 mask = Texture(parentMap, vUv);
+  vec3 res;
+
+  if (blendMode == 0) {
+    res = src.xyz;
+  }
+  else if (blendMode == 1) {
+    res = BlendMultiply(src.xyz, mask.xyz);
+  }
+  else {
+    // Use red for debugging missing blend modes
+    res = vec3(1.0, 0.0, 0.0);
+  }
+
+  setOutputColor(vec4(res, src.a * alpha));
+}
diff --git a/gsk/resources/glsl/blend.vs.glsl b/gsk/resources/glsl/blend.vs.glsl
new file mode 100644
index 0000000..7ec0594
--- /dev/null
+++ b/gsk/resources/glsl/blend.vs.glsl
@@ -0,0 +1,6 @@
+void main() {
+  gl_Position = mvp * vec4(position, 0.0, 1.0);
+
+  // Flip the sampling
+  vUv = vec2(uv.x, 1 - uv.y);
+}
diff --git a/gsk/resources/glsl/es2_common.fs.glsl b/gsk/resources/glsl/es2_common.fs.glsl
new file mode 100644
index 0000000..c09f75e
--- /dev/null
+++ b/gsk/resources/glsl/es2_common.fs.glsl
@@ -0,0 +1,16 @@
+precision mediump float;
+
+uniform mat4 mvp;
+uniform sampler2D map;
+uniform sampler2D parentMap;
+uniform float alpha;
+
+varying vec2 vUv;
+
+vec4 Texture(sampler2D sampler, vec2 texCoords) {
+  return texture2D(sampler, texCoords);
+}
+
+void setOutputColor(vec4 color) {
+  gl_FragColor = color;
+}
diff --git a/gsk/resources/glsl/es2_common.vs.glsl b/gsk/resources/glsl/es2_common.vs.glsl
new file mode 100644
index 0000000..e52c153
--- /dev/null
+++ b/gsk/resources/glsl/es2_common.vs.glsl
@@ -0,0 +1,7 @@
+uniform mat4 mvp;
+uniform float alpha;
+
+attribute vec2 position;
+attribute vec2 uv;
+
+varying vec2 vUv;
diff --git a/gsk/resources/glsl/gl3_common.fs.glsl b/gsk/resources/glsl/gl3_common.fs.glsl
new file mode 100644
index 0000000..48134a3
--- /dev/null
+++ b/gsk/resources/glsl/gl3_common.fs.glsl
@@ -0,0 +1,19 @@
+precision highp float;
+
+uniform sampler2D map;
+uniform sampler2D parentMap;
+uniform mat4 mvp;
+uniform float alpha;
+uniform int blendMode;
+
+in vec2 vUv;
+
+out vec4 outputColor;
+
+vec4 Texture(sampler2D sampler, vec2 texCoords) {
+  return texture(sampler, texCoords);
+}
+
+void setOutputColor(vec4 color) {
+  outputColor = color;
+}
diff --git a/gsk/resources/glsl/gl3_common.vs.glsl b/gsk/resources/glsl/gl3_common.vs.glsl
new file mode 100644
index 0000000..96289e6
--- /dev/null
+++ b/gsk/resources/glsl/gl3_common.vs.glsl
@@ -0,0 +1,7 @@
+uniform mat4 mvp;
+uniform float alpha;
+
+in vec2 position;
+in vec2 uv;
+
+out vec2 vUv;
diff --git a/gsk/resources/glsl/gl_common.fs.glsl b/gsk/resources/glsl/gl_common.fs.glsl
new file mode 100644
index 0000000..e9cfa44
--- /dev/null
+++ b/gsk/resources/glsl/gl_common.fs.glsl
@@ -0,0 +1,14 @@
+uniform mat4 mvp;
+uniform sampler2D map;
+uniform sampler2D parentMap;
+uniform float alpha;
+
+varying vec2 vUv;
+
+vec4 Texture(sampler2D sampler, vec2 texCoords) {
+  return texture2D(sampler, texCoords);
+}
+
+void setOutputColor(vec4 color) {
+  gl_FragColor = color;
+}
diff --git a/gsk/resources/glsl/gl_common.vs.glsl b/gsk/resources/glsl/gl_common.vs.glsl
new file mode 100644
index 0000000..e52c153
--- /dev/null
+++ b/gsk/resources/glsl/gl_common.vs.glsl
@@ -0,0 +1,7 @@
+uniform mat4 mvp;
+uniform float alpha;
+
+attribute vec2 position;
+attribute vec2 uv;
+
+varying vec2 vUv;


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