[gtk/ngl-vertex-attributes: 4/8] gsk: Give ngl its own shader sources




commit 3252f1e301d27a63fbdd7e662d9742af9119ed8d
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Mar 11 21:31:31 2021 -0500

    gsk: Give ngl its own shader sources
    
    We may want to change the interface between the
    shaders and the renderer for ngl, and therefore,
    sharing the shaders between gl and ngl will not
    be practical, going forward.

 gsk/gen-gsk-gresources-xml.py                  |  15 +-
 gsk/meson.build                                |  23 ++
 gsk/ngl/gskngldriver.c                         |   6 +-
 gsk/ngl/gsknglprograms.defs                    |  30 +--
 gsk/ngl/resources/blend.glsl                   | 310 +++++++++++++++++++++++++
 gsk/ngl/resources/blit.glsl                    |  13 ++
 gsk/ngl/resources/blur.glsl                    |  55 +++++
 gsk/ngl/resources/border.glsl                  |  40 ++++
 gsk/ngl/resources/color.glsl                   |  18 ++
 gsk/ngl/resources/color_matrix.glsl            |  25 ++
 gsk/ngl/resources/coloring.glsl                |  22 ++
 gsk/ngl/resources/conic_gradient.glsl          |  73 ++++++
 gsk/ngl/resources/cross_fade.glsl              |  20 ++
 gsk/ngl/resources/custom.glsl                  |  21 ++
 gsk/ngl/resources/inset_shadow.glsl            |  41 ++++
 gsk/ngl/resources/linear_gradient.glsl         |  95 ++++++++
 gsk/ngl/resources/outset_shadow.glsl           |  33 +++
 gsk/ngl/resources/preamble.fs.glsl             | 139 +++++++++++
 gsk/ngl/resources/preamble.glsl                |  57 +++++
 gsk/ngl/resources/preamble.vs.glsl             |  69 ++++++
 gsk/ngl/resources/radial_gradient.glsl         |  74 ++++++
 gsk/ngl/resources/repeat.glsl                  |  41 ++++
 gsk/ngl/resources/unblurred_outset_shadow.glsl |  42 ++++
 23 files changed, 1241 insertions(+), 21 deletions(-)
---
diff --git a/gsk/gen-gsk-gresources-xml.py b/gsk/gen-gsk-gresources-xml.py
index 5db5044b09..16a2c4042a 100644
--- a/gsk/gen-gsk-gresources-xml.py
+++ b/gsk/gen-gsk-gresources-xml.py
@@ -20,13 +20,17 @@ def replace_if_changed(new, old):
   else:
     os.remove(new)
 
-source_shaders = []
+gl_source_shaders = []
+ngl_source_shaders = []
 vulkan_compiled_shaders = []
 vulkan_shaders = []
 
 for f in sys.argv[2:]:
   if f.endswith('.glsl'):
-    source_shaders.append(f)
+    if f.startswith('ngl'):
+      ngl_source_shaders.append(f);
+    else:
+      gl_source_shaders.append(f)
   elif f.endswith('.spv'):
     vulkan_compiled_shaders.append(f)
   elif f.endswith('.frag') or f.endswith('.vert'):
@@ -40,11 +44,16 @@ xml = '''<?xml version='1.0' encoding='UTF-8'?>
 
 '''
 
-for f in source_shaders:
+for f in gl_source_shaders:
   xml += '    <file alias=\'glsl/{0}\'>resources/glsl/{0}</file>\n'.format(os.path.basename(f))
 
 xml += '\n'
 
+for f in ngl_source_shaders:
+  xml += '    <file alias=\'ngl/{0}\'>ngl/resources/{0}</file>\n'.format(os.path.basename(f))
+
+xml += '\n'
+
 for f in vulkan_compiled_shaders:
   xml += '    <file alias=\'vulkan/{0}\'>resources/vulkan/{0}</file>\n'.format(os.path.basename(f))
 
diff --git a/gsk/meson.build b/gsk/meson.build
index dd1ac34ff9..8f9a6281c0 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -20,6 +20,28 @@ gsk_private_gl_shaders = [
   'resources/glsl/custom.glsl',
 ]
 
+gsk_private_ngl_shaders = [
+  'ngl/resources/preamble.glsl',
+  'ngl/resources/preamble.fs.glsl',
+  'ngl/resources/preamble.vs.glsl',
+  'ngl/resources/border.glsl',
+  'ngl/resources/blit.glsl',
+  'ngl/resources/coloring.glsl',
+  'ngl/resources/color.glsl',
+  'ngl/resources/linear_gradient.glsl',
+  'ngl/resources/radial_gradient.glsl',
+  'ngl/resources/conic_gradient.glsl',
+  'ngl/resources/color_matrix.glsl',
+  'ngl/resources/blur.glsl',
+  'ngl/resources/inset_shadow.glsl',
+  'ngl/resources/outset_shadow.glsl',
+  'ngl/resources/unblurred_outset_shadow.glsl',
+  'ngl/resources/cross_fade.glsl',
+  'ngl/resources/blend.glsl',
+  'ngl/resources/repeat.glsl',
+  'ngl/resources/custom.glsl',
+]
+
 gsk_public_sources = files([
   'gskdiff.c',
   'gskcairorenderer.c',
@@ -150,6 +172,7 @@ gsk_resources_xml = configure_file(output: 'gsk.resources.xml',
     find_program('gen-gsk-gresources-xml.py'),
     '@OUTPUT@',
     gsk_private_gl_shaders,
+    gsk_private_ngl_shaders,
     gsk_private_vulkan_compiled_shaders,
     gsk_private_vulkan_shaders
   ],
diff --git a/gsk/ngl/gskngldriver.c b/gsk/ngl/gskngldriver.c
index 692e6a9d5d..1b00b135ed 100644
--- a/gsk/ngl/gskngldriver.c
+++ b/gsk/ngl/gskngldriver.c
@@ -336,13 +336,13 @@ gsk_ngl_driver_load_programs (GskNglDriver  *self,
   /* Setup preambles that are shared by all shaders */
   gsk_ngl_compiler_set_preamble_from_resource (compiler,
                                                GSK_NGL_COMPILER_ALL,
-                                               "/org/gtk/libgsk/glsl/preamble.glsl");
+                                               "/org/gtk/libgsk/ngl/preamble.glsl");
   gsk_ngl_compiler_set_preamble_from_resource (compiler,
                                                GSK_NGL_COMPILER_VERTEX,
-                                               "/org/gtk/libgsk/glsl/preamble.vs.glsl");
+                                               "/org/gtk/libgsk/ngl/preamble.vs.glsl");
   gsk_ngl_compiler_set_preamble_from_resource (compiler,
                                                GSK_NGL_COMPILER_FRAGMENT,
-                                               "/org/gtk/libgsk/glsl/preamble.fs.glsl");
+                                               "/org/gtk/libgsk/ngl/preamble.fs.glsl");
 
   /* Setup attributes that are provided via VBO */
   gsk_ngl_compiler_bind_attribute (compiler, "aPosition", 0);
diff --git a/gsk/ngl/gsknglprograms.defs b/gsk/ngl/gsknglprograms.defs
index b0b797f0e9..85c9366ad6 100644
--- a/gsk/ngl/gsknglprograms.defs
+++ b/gsk/ngl/gsknglprograms.defs
@@ -1,69 +1,69 @@
 GSK_NGL_DEFINE_PROGRAM (blend,
-                        "/org/gtk/libgsk/glsl/blend.glsl",
+                        "/org/gtk/libgsk/ngl/blend.glsl",
                         GSK_NGL_ADD_UNIFORM (1, BLEND_SOURCE2, u_source2)
                         GSK_NGL_ADD_UNIFORM (2, BLEND_MODE, u_mode))
 
 GSK_NGL_DEFINE_PROGRAM (blit,
-                        "/org/gtk/libgsk/glsl/blit.glsl",
+                        "/org/gtk/libgsk/ngl/blit.glsl",
                         GSK_NGL_NO_UNIFORMS)
 
 GSK_NGL_DEFINE_PROGRAM (blur,
-                        "/org/gtk/libgsk/glsl/blur.glsl",
+                        "/org/gtk/libgsk/ngl/blur.glsl",
                         GSK_NGL_ADD_UNIFORM (1, BLUR_RADIUS, u_blur_radius)
                         GSK_NGL_ADD_UNIFORM (2, BLUR_SIZE, u_blur_size)
                         GSK_NGL_ADD_UNIFORM (3, BLUR_DIR, u_blur_dir))
 
 GSK_NGL_DEFINE_PROGRAM (border,
-                        "/org/gtk/libgsk/glsl/border.glsl",
+                        "/org/gtk/libgsk/ngl/border.glsl",
                         GSK_NGL_ADD_UNIFORM (1, BORDER_COLOR, u_color)
                         GSK_NGL_ADD_UNIFORM (2, BORDER_WIDTHS, u_widths)
                         GSK_NGL_ADD_UNIFORM (3, BORDER_OUTLINE_RECT, u_outline_rect))
 
 GSK_NGL_DEFINE_PROGRAM (color,
-                        "/org/gtk/libgsk/glsl/color.glsl",
+                        "/org/gtk/libgsk/ngl/color.glsl",
                         GSK_NGL_ADD_UNIFORM (1, COLOR_COLOR, u_color))
 
 GSK_NGL_DEFINE_PROGRAM (coloring,
-                        "/org/gtk/libgsk/glsl/coloring.glsl",
+                        "/org/gtk/libgsk/ngl/coloring.glsl",
                         GSK_NGL_ADD_UNIFORM (1, COLORING_COLOR, u_color))
 
 GSK_NGL_DEFINE_PROGRAM (color_matrix,
-                        "/org/gtk/libgsk/glsl/color_matrix.glsl",
+                        "/org/gtk/libgsk/ngl/color_matrix.glsl",
                         GSK_NGL_ADD_UNIFORM (1, COLOR_MATRIX_COLOR_MATRIX, u_color_matrix)
                         GSK_NGL_ADD_UNIFORM (2, COLOR_MATRIX_COLOR_OFFSET, u_color_offset))
 
 GSK_NGL_DEFINE_PROGRAM (conic_gradient,
-                        "/org/gtk/libgsk/glsl/conic_gradient.glsl",
+                        "/org/gtk/libgsk/ngl/conic_gradient.glsl",
                         GSK_NGL_ADD_UNIFORM (1, CONIC_GRADIENT_COLOR_STOPS, u_color_stops)
                         GSK_NGL_ADD_UNIFORM (2, CONIC_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops)
                         GSK_NGL_ADD_UNIFORM (3, CONIC_GRADIENT_GEOMETRY, u_geometry))
 
 GSK_NGL_DEFINE_PROGRAM (cross_fade,
-                        "/org/gtk/libgsk/glsl/cross_fade.glsl",
+                        "/org/gtk/libgsk/ngl/cross_fade.glsl",
                         GSK_NGL_ADD_UNIFORM (1, CROSS_FADE_PROGRESS, u_progress)
                         GSK_NGL_ADD_UNIFORM (2, CROSS_FADE_SOURCE2, u_source2))
 
 GSK_NGL_DEFINE_PROGRAM (inset_shadow,
-                        "/org/gtk/libgsk/glsl/inset_shadow.glsl",
+                        "/org/gtk/libgsk/ngl/inset_shadow.glsl",
                         GSK_NGL_ADD_UNIFORM (1, INSET_SHADOW_COLOR, u_color)
                         GSK_NGL_ADD_UNIFORM (2, INSET_SHADOW_SPREAD, u_spread)
                         GSK_NGL_ADD_UNIFORM (3, INSET_SHADOW_OFFSET, u_offset)
                         GSK_NGL_ADD_UNIFORM (4, INSET_SHADOW_OUTLINE_RECT, u_outline_rect))
 
 GSK_NGL_DEFINE_PROGRAM (linear_gradient,
-                        "/org/gtk/libgsk/glsl/linear_gradient.glsl",
+                        "/org/gtk/libgsk/ngl/linear_gradient.glsl",
                         GSK_NGL_ADD_UNIFORM (1, LINEAR_GRADIENT_COLOR_STOPS, u_color_stops)
                         GSK_NGL_ADD_UNIFORM (2, LINEAR_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops)
                         GSK_NGL_ADD_UNIFORM (3, LINEAR_GRADIENT_POINTS, u_points)
                         GSK_NGL_ADD_UNIFORM (4, LINEAR_GRADIENT_REPEAT, u_repeat))
 
 GSK_NGL_DEFINE_PROGRAM (outset_shadow,
-                        "/org/gtk/libgsk/glsl/outset_shadow.glsl",
+                        "/org/gtk/libgsk/ngl/outset_shadow.glsl",
                         GSK_NGL_ADD_UNIFORM (1, OUTSET_SHADOW_COLOR, u_color)
                         GSK_NGL_ADD_UNIFORM (2, OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
 
 GSK_NGL_DEFINE_PROGRAM (radial_gradient,
-                        "/org/gtk/libgsk/glsl/radial_gradient.glsl",
+                        "/org/gtk/libgsk/ngl/radial_gradient.glsl",
                         GSK_NGL_ADD_UNIFORM (1, RADIAL_GRADIENT_COLOR_STOPS, u_color_stops)
                         GSK_NGL_ADD_UNIFORM (2, RADIAL_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops)
                         GSK_NGL_ADD_UNIFORM (3, RADIAL_GRADIENT_REPEAT, u_repeat)
@@ -71,12 +71,12 @@ GSK_NGL_DEFINE_PROGRAM (radial_gradient,
                         GSK_NGL_ADD_UNIFORM (5, RADIAL_GRADIENT_GEOMETRY, u_geometry))
 
 GSK_NGL_DEFINE_PROGRAM (repeat,
-                        "/org/gtk/libgsk/glsl/repeat.glsl",
+                        "/org/gtk/libgsk/ngl/repeat.glsl",
                         GSK_NGL_ADD_UNIFORM (1, REPEAT_CHILD_BOUNDS, u_child_bounds)
                         GSK_NGL_ADD_UNIFORM (2, REPEAT_TEXTURE_RECT, u_texture_rect))
 
 GSK_NGL_DEFINE_PROGRAM (unblurred_outset_shadow,
-                        "/org/gtk/libgsk/glsl/unblurred_outset_shadow.glsl",
+                        "/org/gtk/libgsk/ngl/unblurred_outset_shadow.glsl",
                         GSK_NGL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_COLOR, u_color)
                         GSK_NGL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread)
                         GSK_NGL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset)
diff --git a/gsk/ngl/resources/blend.glsl b/gsk/ngl/resources/blend.glsl
new file mode 100644
index 0000000000..22323402ac
--- /dev/null
+++ b/gsk/ngl/resources/blend.glsl
@@ -0,0 +1,310 @@
+// VERTEX_SHADER:
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+uniform int u_mode;
+uniform sampler2D u_source2;
+
+float
+combine (float source, float backdrop)
+{
+  return source + backdrop * (1.0 - source);
+}
+
+vec4
+composite (vec4 Cs, vec4 Cb, vec3 B)
+{
+  float ao = Cs.a + Cb.a * (1.0 - Cs.a);
+  vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - Cs.a)*Cb.a*Cb.rgb) / ao;
+  return vec4(Co, ao);
+}
+
+vec4
+normal (vec4 Cs, vec4 Cb)
+{
+  return composite (Cs, Cb, Cs.rgb);
+}
+
+vec4
+multiply (vec4 Cs, vec4 Cb)
+{
+  return composite (Cs, Cb, Cs.rgb * Cb.rgb);
+}
+
+vec4
+difference (vec4 Cs, vec4 Cb)
+{
+  return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb));
+}
+
+vec4
+screen (vec4 Cs, vec4 Cb)
+{
+  return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb);
+}
+
+float
+hard_light (float source, float backdrop)
+{
+  if (source <= 0.5)
+    return 2.0 * backdrop * source;
+  else
+    return 2.0 * (backdrop + source - backdrop * source) - 1.0;
+}
+
+vec4
+hard_light (vec4 Cs, vec4 Cb)
+{
+  vec3 B = vec3 (hard_light (Cs.r, Cb.r),
+                 hard_light (Cs.g, Cb.g),
+                 hard_light (Cs.b, Cb.b));
+  return composite (Cs, Cb, B);
+}
+
+float
+soft_light (float source, float backdrop)
+{
+  float db;
+
+  if (backdrop <= 0.25)
+    db = ((16.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop;
+  else
+    db = sqrt (backdrop);
+
+  if (source <= 0.5)
+    return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop);
+  else
+    return backdrop + (2.0 * source - 1.0) * (db - backdrop);
+}
+
+vec4
+soft_light (vec4 Cs, vec4 Cb)
+{
+  vec3 B = vec3 (soft_light (Cs.r, Cb.r),
+                 soft_light (Cs.g, Cb.g),
+                 soft_light (Cs.b, Cb.b));
+  return composite (Cs, Cb, B);
+}
+
+vec4
+overlay (vec4 Cs, vec4 Cb)
+{
+  vec3 B = vec3 (hard_light (Cb.r, Cs.r),
+                 hard_light (Cb.g, Cs.g),
+                 hard_light (Cb.b, Cs.b));
+  return composite (Cs, Cb, B);
+}
+
+vec4
+darken (vec4 Cs, vec4 Cb)
+{
+  vec3 B = min (Cs.rgb, Cb.rgb);
+  return composite (Cs, Cb, B);
+}
+
+vec4
+lighten (vec4 Cs, vec4 Cb)
+{
+  vec3 B = max (Cs.rgb, Cb.rgb);
+  return composite (Cs, Cb, B);
+}
+
+float
+color_dodge (float source, float backdrop)
+{
+  return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0);
+}
+
+vec4
+color_dodge (vec4 Cs, vec4 Cb)
+{
+  vec3 B = vec3 (color_dodge (Cs.r, Cb.r),
+                 color_dodge (Cs.g, Cb.g),
+                 color_dodge (Cs.b, Cb.b));
+  return composite (Cs, Cb, B);
+}
+
+
+float
+color_burn (float source, float backdrop)
+{
+  return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0);
+}
+
+vec4
+color_burn (vec4 Cs, vec4 Cb)
+{
+  vec3 B = vec3 (color_burn (Cs.r, Cb.r),
+                 color_burn (Cs.g, Cb.g),
+                 color_burn (Cs.b, Cb.b));
+  return composite (Cs, Cb, B);
+}
+
+vec4
+exclusion (vec4 Cs, vec4 Cb)
+{
+  vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb;
+  return composite (Cs, Cb, B);
+}
+
+float
+lum (vec3 c)
+{
+  return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
+}
+
+vec3
+clip_color (vec3 c)
+{
+  float l = lum (c);
+  float n = min (c.r, min (c.g, c.b));
+  float x = max (c.r, max (c.g, c.b));
+  if (n < 0.0) c = l + (((c - l) * l) / (l - n));
+  if (x > 1.0) c = l + (((c - l) * (1.0 - l)) / (x - l));
+  return c;
+}
+
+vec3
+set_lum (vec3 c, float l)
+{
+  float d = l - lum (c);
+  return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
+}
+
+float
+sat (vec3 c)
+{
+  return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
+}
+
+vec3
+set_sat (vec3 c, float s)
+{
+  float cmin = min (c.r, min (c.g, c.b));
+  float cmax = max (c.r, max (c.g, c.b));
+  vec3 res;
+
+  if (cmax == cmin)
+    res = vec3 (0, 0, 0);
+  else
+    {
+      if (c.r == cmax)
+        {
+          if (c.g == cmin)
+            {
+              res.b = ((c.b - cmin) * s) / (cmax - cmin);
+              res.g = 0.0;
+            }
+          else
+            {
+              res.g = ((c.g - cmin) * s) / (cmax - cmin);
+              res.b = 0.0;
+            }
+          res.r = s;
+        }
+      else if (c.g == cmax)
+        {
+          if (c.r == cmin)
+            {
+              res.b = ((c.b - cmin) * s) / (cmax - cmin);
+              res.r = 0.0;
+            }
+          else
+            {
+              res.r = ((c.r - cmin) * s) / (cmax - cmin);
+              res.b = 0.0;
+            }
+          res.g = s;
+        }
+      else
+        {
+          if (c.r == cmin)
+            {
+              res.g = ((c.g - cmin) * s) / (cmax - cmin);
+              res.r = 0.0;
+            }
+          else
+            {
+              res.r = ((c.r - cmin) * s) / (cmax - cmin);
+              res.g = 0.0;
+            }
+          res.b = s;
+        }
+    }
+  return res;
+}
+
+vec4
+color (vec4 Cs, vec4 Cb)
+{
+  vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
+  return composite (Cs, Cb, B);
+}
+
+vec4
+hue (vec4 Cs, vec4 Cb)
+{
+  vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb));
+  return composite (Cs, Cb, B);
+}
+
+vec4
+saturation (vec4 Cs, vec4 Cb)
+{
+  vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb));
+  return composite (Cs, Cb, B);
+}
+
+vec4
+luminosity (vec4 Cs, vec4 Cb)
+{
+  vec3 B = set_lum (Cb.rgb, lum (Cs.rgb));
+  return composite (Cs, Cb, B);
+}
+
+void main() {
+  vec4 bottom_color = GskTexture(u_source, vUv);
+  vec4 top_color = GskTexture(u_source2, vUv);
+
+  vec4 result;
+  if (u_mode == 0)
+    result = normal(top_color, bottom_color);
+  else if (u_mode == 1)
+    result = multiply(top_color, bottom_color);
+  else if (u_mode == 2)
+    result = screen(top_color, bottom_color);
+  else if (u_mode == 3)
+    result = overlay(top_color, bottom_color);
+  else if (u_mode == 4)
+    result = darken(top_color, bottom_color);
+  else if (u_mode == 5)
+    result = lighten(top_color, bottom_color);
+  else if (u_mode == 6)
+    result = color_dodge(top_color, bottom_color);
+  else if (u_mode == 7)
+    result = color_burn(top_color, bottom_color);
+  else if (u_mode == 8)
+    result = hard_light(top_color, bottom_color);
+  else if (u_mode == 9)
+    result = soft_light(top_color, bottom_color);
+  else if (u_mode == 10)
+    result = difference(top_color, bottom_color);
+  else if (u_mode == 11)
+    result = exclusion(top_color, bottom_color);
+  else if (u_mode == 12)
+    result = color(top_color, bottom_color);
+  else if (u_mode == 13)
+    result = hue(top_color, bottom_color);
+  else if (u_mode == 14)
+    result = saturation(top_color, bottom_color);
+  else if (u_mode == 15)
+    result = luminosity(top_color, bottom_color);
+  else
+    discard;
+
+  gskSetOutputColor(result * u_alpha);
+}
diff --git a/gsk/ngl/resources/blit.glsl b/gsk/ngl/resources/blit.glsl
new file mode 100644
index 0000000000..f01cd238ec
--- /dev/null
+++ b/gsk/ngl/resources/blit.glsl
@@ -0,0 +1,13 @@
+// VERTEX_SHADER:
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+void main() {
+  vec4 diffuse = GskTexture(u_source, vUv);
+
+  gskSetOutputColor(diffuse * u_alpha);
+}
diff --git a/gsk/ngl/resources/blur.glsl b/gsk/ngl/resources/blur.glsl
new file mode 100644
index 0000000000..f782ab48cc
--- /dev/null
+++ b/gsk/ngl/resources/blur.glsl
@@ -0,0 +1,55 @@
+// VERTEX_SHADER:
+uniform float u_blur_radius;
+uniform vec2 u_blur_size;
+uniform vec2 u_blur_dir;
+
+_OUT_ vec2 pixel_step;
+_OUT_ float pixels_per_side;
+_OUT_ vec3 initial_gaussian;
+
+const float PI = 3.14159265;
+const float RADIUS_MULTIPLIER = 2.0;
+
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+
+  pixel_step = (vec2(1.0) / u_blur_size) * u_blur_dir;
+  pixels_per_side = floor(u_blur_radius * RADIUS_MULTIPLIER / 2.0);
+
+  float sigma = u_blur_radius / 2.0; // *shrug*
+  initial_gaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma);
+  initial_gaussian.y = exp(-0.5 / (sigma * sigma));
+  initial_gaussian.z = initial_gaussian.y * initial_gaussian.y;
+}
+
+// FRAGMENT_SHADER:
+_IN_ vec2 pixel_step;
+_IN_ float pixels_per_side;
+_IN_ vec3 initial_gaussian;
+
+// blur_radius 0 is NOT supported and MUST be caught before.
+
+// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
+void main() {
+  vec3 incrementalGaussian = initial_gaussian;
+
+  float coefficientSum = 0.0;
+  vec4 sum = GskTexture(u_source, vUv) * incrementalGaussian.x;
+  coefficientSum += incrementalGaussian.x;
+  incrementalGaussian.xy *= incrementalGaussian.yz;
+
+  vec2 p = pixel_step;
+  for (int i = 1; i <= int(pixels_per_side); i++) {
+    sum += GskTexture(u_source, vUv - p) * incrementalGaussian.x;
+    sum += GskTexture(u_source, vUv + p) * incrementalGaussian.x;
+
+    coefficientSum += 2.0 * incrementalGaussian.x;
+    incrementalGaussian.xy *= incrementalGaussian.yz;
+
+    p += pixel_step;
+  }
+
+  gskSetOutputColor(sum / coefficientSum);
+}
diff --git a/gsk/ngl/resources/border.glsl b/gsk/ngl/resources/border.glsl
new file mode 100644
index 0000000000..677a0df7cd
--- /dev/null
+++ b/gsk/ngl/resources/border.glsl
@@ -0,0 +1,40 @@
+// VERTEX_SHADER:
+uniform vec4 u_color;
+uniform vec4 u_widths;
+uniform vec4[3] u_outline_rect;
+
+_OUT_ vec4 final_color;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  final_color = gsk_premultiply(u_color) * u_alpha;
+
+  GskRoundedRect outside = gsk_create_rect(u_outline_rect);
+  GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths);
+
+  gsk_rounded_rect_transform(outside, u_modelview);
+  gsk_rounded_rect_transform(inside, u_modelview);
+
+  gsk_rounded_rect_encode(outside, transformed_outside_outline);
+  gsk_rounded_rect_encode(inside, transformed_inside_outline);
+}
+
+// FRAGMENT_SHADER:
+uniform vec4[3] u_outline_rect;
+
+_IN_ vec4 final_color;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+  vec2 frag = gsk_get_frag_coord();
+
+  float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
+                      gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
+                      0.0, 1.0);
+
+  gskSetOutputColor(final_color * alpha);
+}
diff --git a/gsk/ngl/resources/color.glsl b/gsk/ngl/resources/color.glsl
new file mode 100644
index 0000000000..636456ce0d
--- /dev/null
+++ b/gsk/ngl/resources/color.glsl
@@ -0,0 +1,18 @@
+// VERTEX_SHADER:
+uniform vec4 u_color;
+
+_OUT_ vec4 final_color;
+
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  final_color = gsk_premultiply(u_color) * u_alpha;
+}
+
+// FRAGMENT_SHADER:
+_IN_ vec4 final_color;
+
+void main() {
+  gskSetOutputColor(final_color);
+}
+
diff --git a/gsk/ngl/resources/color_matrix.glsl b/gsk/ngl/resources/color_matrix.glsl
new file mode 100644
index 0000000000..79cb36434e
--- /dev/null
+++ b/gsk/ngl/resources/color_matrix.glsl
@@ -0,0 +1,25 @@
+// VERTEX_SHADER:
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+uniform mat4 u_color_matrix;
+uniform vec4 u_color_offset;
+
+void main() {
+  vec4 color = GskTexture(u_source, vUv);
+
+  // Un-premultilpy
+  if (color.a != 0.0)
+    color.rgb /= color.a;
+
+  color = u_color_matrix * color + u_color_offset;
+  color = clamp(color, 0.0, 1.0);
+
+  color.rgb *= color.a;
+
+  gskSetOutputColor(color * u_alpha);
+}
diff --git a/gsk/ngl/resources/coloring.glsl b/gsk/ngl/resources/coloring.glsl
new file mode 100644
index 0000000000..a675493030
--- /dev/null
+++ b/gsk/ngl/resources/coloring.glsl
@@ -0,0 +1,22 @@
+// VERTEX_SHADER:
+uniform vec4 u_color;
+
+_OUT_ vec4 final_color;
+
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+
+  final_color = gsk_premultiply(u_color) * u_alpha;
+}
+
+// FRAGMENT_SHADER:
+
+_IN_ vec4 final_color;
+
+void main() {
+  vec4 diffuse = GskTexture(u_source, vUv);
+
+  gskSetOutputColor(final_color * diffuse.a);
+}
diff --git a/gsk/ngl/resources/conic_gradient.glsl b/gsk/ngl/resources/conic_gradient.glsl
new file mode 100644
index 0000000000..630a42c5e6
--- /dev/null
+++ b/gsk/ngl/resources/conic_gradient.glsl
@@ -0,0 +1,73 @@
+// VERTEX_SHADER
+uniform vec4 u_geometry;
+
+_NOPERSPECTIVE_ _OUT_ vec2 coord;
+
+void main() {
+  gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
+
+  vec2 mv0 = u_modelview[0].xy;
+  vec2 mv1 = u_modelview[1].xy;
+  vec2 offset = aPosition - u_geometry.xy;
+
+  coord = vec2(dot(mv0, offset),
+               dot(mv1, offset));
+}
+
+// FRAGMENT_SHADER:
+#ifdef GSK_LEGACY
+uniform int u_num_color_stops;
+#else
+uniform highp int u_num_color_stops; // Why? Because it works like this.
+#endif
+
+uniform vec4 u_geometry;
+uniform float u_color_stops[6 * 5];
+
+_NOPERSPECTIVE_ _IN_ vec2 coord;
+
+float get_offset(int index) {
+  return u_color_stops[5 * index];
+}
+
+vec4 get_color(int index) {
+  int base = 5 * index + 1;
+
+  return vec4(u_color_stops[base],
+              u_color_stops[base + 1],
+              u_color_stops[base + 2],
+              u_color_stops[base + 3]);
+}
+
+void main() {
+  // direction of point in range [-PI, PI]
+  vec2 pos = floor(coord);
+  float angle = atan(pos.y, pos.x);
+
+  // fract() does the modulo here, so now we have progress
+  // into the current conic
+  float offset = fract(angle * u_geometry.z + u_geometry.w);
+
+  if (offset < get_offset(0)) {
+    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+    return;
+  }
+
+  int n = u_num_color_stops - 1;
+  for (int i = 0; i < n; i++) {
+    float curr_offset = get_offset(i);
+    float next_offset = get_offset(i + 1);
+
+    if (offset >= curr_offset && offset < next_offset) {
+      float f = (offset - curr_offset) / (next_offset - curr_offset);
+      vec4 curr_color = gsk_premultiply(get_color(i));
+      vec4 next_color = gsk_premultiply(get_color(i + 1));
+      vec4 color = mix(curr_color, next_color, f);
+
+      gskSetOutputColor(color * u_alpha);
+      return;
+    }
+  }
+
+  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
+}
diff --git a/gsk/ngl/resources/cross_fade.glsl b/gsk/ngl/resources/cross_fade.glsl
new file mode 100644
index 0000000000..f824430f9d
--- /dev/null
+++ b/gsk/ngl/resources/cross_fade.glsl
@@ -0,0 +1,20 @@
+// VERTEX_SHADER:
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+uniform float u_progress;
+uniform sampler2D u_source2;
+
+void main() {
+  vec4 source1 = GskTexture(u_source, vUv);  // start child
+  vec4 source2 = GskTexture(u_source2, vUv); // end child
+
+  float p_start = (1.0 - u_progress) * u_alpha;
+  float p_end = u_progress * u_alpha;
+  vec4 color = (p_start * source1) + (p_end * source2);
+  gskSetOutputColor(color);
+}
diff --git a/gsk/ngl/resources/custom.glsl b/gsk/ngl/resources/custom.glsl
new file mode 100644
index 0000000000..d2aed97fc8
--- /dev/null
+++ b/gsk/ngl/resources/custom.glsl
@@ -0,0 +1,21 @@
+// VERTEX_SHADER:
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+  vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// The shader supplies:
+void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv);
+
+uniform vec2 u_size;
+uniform sampler2D u_source2;
+uniform sampler2D u_source3;
+uniform sampler2D u_source4;
+
+void main() {
+  vec4 fragColor;
+  vec2 fragCoord = vec2(vUv.x * u_size.x, (1.0-vUv.y) * u_size.y);
+  mainImage(fragColor, fragCoord, u_size, vUv);
+  gskSetOutputColor(fragColor);
+}
diff --git a/gsk/ngl/resources/inset_shadow.glsl b/gsk/ngl/resources/inset_shadow.glsl
new file mode 100644
index 0000000000..9a21cdef09
--- /dev/null
+++ b/gsk/ngl/resources/inset_shadow.glsl
@@ -0,0 +1,41 @@
+// VERTEX_SHADER:
+uniform vec4 u_color;
+uniform float u_spread;
+uniform vec2 u_offset;
+uniform vec4[3] u_outline_rect;
+
+_OUT_ vec4 final_color;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  final_color = gsk_premultiply(u_color) * u_alpha;
+
+  GskRoundedRect outside = gsk_create_rect(u_outline_rect);
+  GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread));
+
+  gsk_rounded_rect_offset(inside, u_offset);
+
+  gsk_rounded_rect_transform(outside, u_modelview);
+  gsk_rounded_rect_transform(inside, u_modelview);
+
+  gsk_rounded_rect_encode(outside, transformed_outside_outline);
+  gsk_rounded_rect_encode(inside, transformed_inside_outline);
+}
+
+// FRAGMENT_SHADER:
+_IN_ vec4 final_color;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+  vec2 frag = gsk_get_frag_coord();
+
+  float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
+                      gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
+                      0.0, 1.0);
+
+  gskSetOutputColor(final_color * alpha);
+}
diff --git a/gsk/ngl/resources/linear_gradient.glsl b/gsk/ngl/resources/linear_gradient.glsl
new file mode 100644
index 0000000000..cc90392c06
--- /dev/null
+++ b/gsk/ngl/resources/linear_gradient.glsl
@@ -0,0 +1,95 @@
+// VERTEX_SHADER
+uniform vec4 u_points;
+
+_NOPERSPECTIVE_ _OUT_ vec4 info;
+
+void main() {
+  gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
+
+  vec2 mv0 = u_modelview[0].xy;
+  vec2 mv1 = u_modelview[1].xy;
+  vec2 offset = aPosition - u_points.xy;
+  vec2 coord = vec2(dot(mv0, offset),
+                    dot(mv1, offset));
+
+  // Original equation:
+  // VS | maxDist = length(end - start);
+  // VS | gradient = end - start;
+  // VS | gradientLength = length(gradient);
+  // FS | pos = frag_coord - start
+  // FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient
+  // FS | offset = length(proj) / maxDist
+
+  // Simplified formula derivation:
+  // 1. Notice that maxDist = gradientLength:
+  // offset = length(proj) / gradientLength
+  // 2. Let gnorm = gradient / gradientLength, then:
+  // proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * 
gradientLength) =
+  //      = dot(gnorm, pos) * gnorm
+  // 3. Since gnorm is unit length then:
+  // length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos)
+  // 4. We can avoid the FS division by passing a scaled pos from the VS:
+  // offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength)
+  // 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL
+  vec2 gradient = vec2(dot(mv0, u_points.zw),
+                       dot(mv1, u_points.zw));
+  float rcp_gradient_length = inversesqrt(dot(gradient, gradient));
+
+  info = rcp_gradient_length * vec4(coord, gradient);
+}
+
+// FRAGMENT_SHADER:
+#ifdef GSK_LEGACY
+uniform int u_num_color_stops;
+#else
+uniform highp int u_num_color_stops; // Why? Because it works like this.
+#endif
+
+uniform float u_color_stops[6 * 5];
+uniform bool u_repeat;
+
+_NOPERSPECTIVE_ _IN_ vec4 info;
+
+float get_offset(int index) {
+  return u_color_stops[5 * index];
+}
+
+vec4 get_color(int index) {
+  int base = 5 * index + 1;
+
+  return vec4(u_color_stops[base],
+              u_color_stops[base + 1],
+              u_color_stops[base + 2],
+              u_color_stops[base + 3]);
+}
+
+void main() {
+  float offset = dot(info.xy, info.zw);
+
+  if (u_repeat) {
+    offset = fract(offset);
+  }
+
+  if (offset < get_offset(0)) {
+    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+    return;
+  }
+
+  int n = u_num_color_stops - 1;
+  for (int i = 0; i < n; i++) {
+    float curr_offset = get_offset(i);
+    float next_offset = get_offset(i + 1);
+
+    if (offset >= curr_offset && offset < next_offset) {
+      float f = (offset - curr_offset) / (next_offset - curr_offset);
+      vec4 curr_color = gsk_premultiply(get_color(i));
+      vec4 next_color = gsk_premultiply(get_color(i + 1));
+      vec4 color = mix(curr_color, next_color, f);
+
+      gskSetOutputColor(color * u_alpha);
+      return;
+    }
+  }
+
+  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
+}
diff --git a/gsk/ngl/resources/outset_shadow.glsl b/gsk/ngl/resources/outset_shadow.glsl
new file mode 100644
index 0000000000..373c650179
--- /dev/null
+++ b/gsk/ngl/resources/outset_shadow.glsl
@@ -0,0 +1,33 @@
+// VERTEX_SHADER:
+uniform vec4 u_color;
+uniform vec4[3] u_outline_rect;
+
+_OUT_ vec4 final_color;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline;
+
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+
+  final_color = gsk_premultiply(u_color) * u_alpha;
+
+  GskRoundedRect outline = gsk_create_rect(u_outline_rect);
+  gsk_rounded_rect_transform(outline, u_modelview);
+  gsk_rounded_rect_encode(outline, transformed_outline);
+}
+
+// FRAGMENT_SHADER:
+_IN_ vec4 final_color;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline;
+
+void main() {
+  vec2 frag = gsk_get_frag_coord();
+
+  float alpha = GskTexture(u_source, vUv).a;
+  alpha *= (1.0 -  clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outline), frag), 0.0, 1.0));
+
+  vec4 color = final_color * alpha;
+
+  gskSetOutputColor(color);
+}
diff --git a/gsk/ngl/resources/preamble.fs.glsl b/gsk/ngl/resources/preamble.fs.glsl
new file mode 100644
index 0000000000..3a2fe49240
--- /dev/null
+++ b/gsk/ngl/resources/preamble.fs.glsl
@@ -0,0 +1,139 @@
+uniform sampler2D u_source;
+uniform mat4 u_projection;
+uniform mat4 u_modelview;
+uniform float u_alpha;// = 1.0;
+uniform vec4 u_viewport;
+uniform vec4[3] u_clip_rect;
+
+#if defined(GSK_LEGACY)
+_OUT_ vec4 outputColor;
+#elif !defined(GSK_GLES)
+_OUT_ vec4 outputColor;
+#endif
+
+_IN_ vec2 vUv;
+
+
+
+GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r)
+{
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+  return GskRoundedRect(r[0], r[1], r[2]);
+#else
+  return r;
+#endif
+}
+
+float
+gsk_ellipsis_dist (vec2 p, vec2 radius)
+{
+  if (radius == vec2(0, 0))
+    return 0.0;
+
+  vec2 p0 = p / radius;
+  vec2 p1 = 2.0 * p0 / radius;
+
+  return (dot(p0, p0) - 1.0) / length (p1);
+}
+
+float
+gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
+{
+  float d = gsk_ellipsis_dist (point - center, radius);
+  return clamp (0.5 - d, 0.0, 1.0);
+}
+
+float
+gsk_rounded_rect_coverage (GskRoundedRect r, vec2 p)
+{
+  if (p.x < r.bounds.x || p.y < r.bounds.y ||
+      p.x >= r.bounds.z || p.y >= r.bounds.w)
+    return 0.0;
+
+  vec2 ref_tl = r.corner_points1.xy;
+  vec2 ref_tr = r.corner_points1.zw;
+  vec2 ref_br = r.corner_points2.xy;
+  vec2 ref_bl = r.corner_points2.zw;
+
+  if (p.x >= ref_tl.x && p.x >= ref_bl.x &&
+      p.x <= ref_tr.x && p.x <= ref_br.x)
+    return 1.0;
+
+  if (p.y >= ref_tl.y && p.y >= ref_tr.y &&
+      p.y <= ref_bl.y && p.y <= ref_br.y)
+    return 1.0;
+
+  vec2 rad_tl = r.corner_points1.xy - r.bounds.xy;
+  vec2 rad_tr = r.corner_points1.zw - r.bounds.zy;
+  vec2 rad_br = r.corner_points2.xy - r.bounds.zw;
+  vec2 rad_bl = r.corner_points2.zw - r.bounds.xw;
+
+  float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl);
+  float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr);
+  float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br);
+  float d_bl = gsk_ellipsis_coverage(p, ref_bl, rad_bl);
+
+  vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
+
+  bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y,
+                       p.x > ref_tr.x && p.y < ref_tr.y,
+                       p.x > ref_br.x && p.y > ref_br.y,
+                       p.x < ref_bl.x && p.y > ref_bl.y);
+
+  return 1.0 - dot(vec4(is_out), corner_coverages);
+}
+
+float
+gsk_rect_coverage (vec4 r, vec2 p)
+{
+  if (p.x < r.x || p.y < r.y ||
+      p.x >= r.z || p.y >= r.w)
+    return 0.0;
+
+  return 1.0;
+}
+
+vec4 GskTexture(sampler2D sampler, vec2 texCoords) {
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+  return texture2D(sampler, texCoords);
+#else
+  return texture(sampler, texCoords);
+#endif
+}
+
+#ifdef GSK_GL3
+layout(origin_upper_left) in vec4 gl_FragCoord;
+#endif
+
+vec2 gsk_get_frag_coord() {
+  vec2 fc = gl_FragCoord.xy;
+
+#ifdef GSK_GL3
+  fc += u_viewport.xy;
+#else
+  fc.x += u_viewport.x;
+  fc.y = (u_viewport.y + u_viewport.w) - fc.y;
+#endif
+
+  return fc;
+}
+
+void gskSetOutputColor(vec4 color) {
+  vec4 result;
+
+#if defined(NO_CLIP)
+  result = color;
+#elif defined(RECT_CLIP)
+  result = color * gsk_rect_coverage(gsk_get_bounds(u_clip_rect),
+                                     gsk_get_frag_coord());
+#else
+  result = color * gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect),
+                                             gsk_get_frag_coord());
+#endif
+
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+  gl_FragColor = result;
+#else
+  outputColor = result;
+#endif
+}
diff --git a/gsk/ngl/resources/preamble.glsl b/gsk/ngl/resources/preamble.glsl
new file mode 100644
index 0000000000..8bc007ba67
--- /dev/null
+++ b/gsk/ngl/resources/preamble.glsl
@@ -0,0 +1,57 @@
+#ifndef GSK_LEGACY
+precision highp float;
+#endif
+
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+#define _OUT_ varying
+#define _IN_ varying
+#define _NOPERSPECTIVE_
+#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3]
+#else
+#define _OUT_ out
+#define _IN_ in
+#define _NOPERSPECTIVE_ noperspective
+#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect
+#endif
+
+
+struct GskRoundedRect
+{
+  vec4 bounds; // Top left and bottom right
+  // Look, arrays can't be in structs if you want to return the struct
+  // from a function in gles or whatever. Just kill me.
+  vec4 corner_points1; // xy = top left, zw = top right
+  vec4 corner_points2; // xy = bottom right, zw = bottom left
+};
+
+// Transform from a C GskRoundedRect to what we need.
+GskRoundedRect
+gsk_create_rect(vec4[3] data)
+{
+  vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw);
+
+  vec4 corner_points1 = vec4(bounds.xy + data[1].xy,
+                             bounds.zy + vec2(data[1].zw * vec2(-1, 1)));
+  vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)),
+                             bounds.xw + vec2(data[2].zw * vec2(1, -1)));
+
+  return GskRoundedRect(bounds, corner_points1, corner_points2);
+}
+
+vec4
+gsk_get_bounds(vec4[3] data)
+{
+  return vec4(data[0].xy, data[0].xy + data[0].zw);
+}
+
+vec4 gsk_premultiply(vec4 c) {
+  return vec4(c.rgb * c.a, c.a);
+}
+
+vec4 gsk_scaled_premultiply(vec4 c, float s) {
+  // Fast version of gsk_premultiply(c) * s
+  // 4 muls instead of 7
+  float a = s * c.a;
+
+  return vec4(c.rgb * a, a);
+}
diff --git a/gsk/ngl/resources/preamble.vs.glsl b/gsk/ngl/resources/preamble.vs.glsl
new file mode 100644
index 0000000000..89ee6f74e0
--- /dev/null
+++ b/gsk/ngl/resources/preamble.vs.glsl
@@ -0,0 +1,69 @@
+uniform mat4 u_projection;
+uniform mat4 u_modelview;
+uniform float u_alpha;
+
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+attribute vec2 aPosition;
+attribute vec2 aUv;
+_OUT_ vec2 vUv;
+#else
+_IN_ vec2 aPosition;
+_IN_ vec2 aUv;
+_OUT_ vec2 vUv;
+#endif
+
+// amount is: top, right, bottom, left
+GskRoundedRect
+gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount)
+{
+  vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz;
+  vec4 new_corner_points1 = r.corner_points1;
+  vec4 new_corner_points2 = r.corner_points2;
+
+  if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy;
+  if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy;
+  if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw;
+  if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw;
+
+  return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2);
+}
+
+void
+gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset)
+{
+  r.bounds.xy += offset;
+  r.bounds.zw += offset;
+  r.corner_points1.xy += offset;
+  r.corner_points1.zw += offset;
+  r.corner_points2.xy += offset;
+  r.corner_points2.zw += offset;
+}
+
+void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat)
+{
+  r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy;
+  r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy;
+
+  r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy;
+  r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy;
+
+  r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy;
+  r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy;
+}
+
+#if defined(GSK_LEGACY)
+// Can't have out or inout array parameters...
+#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = 
r.corner_points2;
+#else
+void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r)
+{
+#if defined(GSK_GLES)
+  out_r[0] = r.bounds;
+  out_r[1] = r.corner_points1;
+  out_r[2] = r.corner_points2;
+#else
+  out_r = r;
+#endif
+}
+
+#endif
diff --git a/gsk/ngl/resources/radial_gradient.glsl b/gsk/ngl/resources/radial_gradient.glsl
new file mode 100644
index 0000000000..0ab3fdf07a
--- /dev/null
+++ b/gsk/ngl/resources/radial_gradient.glsl
@@ -0,0 +1,74 @@
+// VERTEX_SHADER
+uniform vec4 u_geometry;
+
+_NOPERSPECTIVE_ _OUT_ vec2 coord;
+
+void main() {
+  gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
+
+  vec2 mv0 = u_modelview[0].xy;
+  vec2 mv1 = u_modelview[1].xy;
+  vec2 offset = aPosition - u_geometry.xy;
+  vec2 dir = vec2(dot(mv0, offset),
+                  dot(mv1, offset));
+
+  coord = dir * u_geometry.zw;
+}
+
+// FRAGMENT_SHADER:
+#ifdef GSK_LEGACY
+uniform int u_num_color_stops;
+#else
+uniform highp int u_num_color_stops;
+#endif
+
+uniform bool u_repeat;
+uniform vec2 u_range;
+uniform float u_color_stops[6 * 5];
+
+_NOPERSPECTIVE_ _IN_ vec2 coord;
+
+float get_offset(int index) {
+  return u_color_stops[5 * index];
+}
+
+vec4 get_color(int index) {
+  int base = 5 * index + 1;
+
+  return vec4(u_color_stops[base],
+              u_color_stops[base + 1],
+              u_color_stops[base + 2],
+              u_color_stops[base + 3]);
+}
+
+void main() {
+  // Reverse scale
+  float offset = length(coord) * u_range.x + u_range.y;
+
+  if (u_repeat) {
+    offset = fract(offset);
+  }
+
+  if (offset < get_offset(0)) {
+    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+    return;
+  }
+
+  int n = u_num_color_stops - 1;
+  for (int i = 0; i < n; i++) {
+    float curr_offset = get_offset(i);
+    float next_offset = get_offset(i + 1);
+
+    if (offset >= curr_offset && offset < next_offset) {
+      float f = (offset - curr_offset) / (next_offset - curr_offset);
+      vec4 curr_color = gsk_premultiply(get_color(i));
+      vec4 next_color = gsk_premultiply(get_color(i + 1));
+      vec4 color = mix(curr_color, next_color, f);
+
+      gskSetOutputColor(color * u_alpha);
+      return;
+    }
+  }
+
+  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
+}
diff --git a/gsk/ngl/resources/repeat.glsl b/gsk/ngl/resources/repeat.glsl
new file mode 100644
index 0000000000..a9ebcc5e10
--- /dev/null
+++ b/gsk/ngl/resources/repeat.glsl
@@ -0,0 +1,41 @@
+// VERTEX_SHADER:
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+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(u_child_bounds.x + mapped_x * u_child_bounds.z, 1.0);
+  float wrapped_y = wrap(u_child_bounds.y + 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 = GskTexture(u_source, tp);
+
+  gskSetOutputColor(diffuse * u_alpha);
+}
diff --git a/gsk/ngl/resources/unblurred_outset_shadow.glsl b/gsk/ngl/resources/unblurred_outset_shadow.glsl
new file mode 100644
index 0000000000..f110370412
--- /dev/null
+++ b/gsk/ngl/resources/unblurred_outset_shadow.glsl
@@ -0,0 +1,42 @@
+// VERTEX_SHADER:
+uniform vec4 u_color;
+uniform float u_spread;
+uniform vec2 u_offset;
+uniform vec4[3] u_outline_rect;
+
+_OUT_ vec4 final_color;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  final_color = gsk_premultiply(u_color) * u_alpha;
+
+  GskRoundedRect inside = gsk_create_rect(u_outline_rect);
+  GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread));
+
+  gsk_rounded_rect_offset(outside, u_offset);
+
+  gsk_rounded_rect_transform(outside, u_modelview);
+  gsk_rounded_rect_transform(inside, u_modelview);
+
+  gsk_rounded_rect_encode(outside, transformed_outside_outline);
+  gsk_rounded_rect_encode(inside, transformed_inside_outline);
+}
+
+// FRAGMENT_SHADER:
+_IN_ vec4 final_color;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+  vec2 frag = gsk_get_frag_coord();
+
+  float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
+                      gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
+                      0.0, 1.0);
+
+  gskSetOutputColor(final_color * alpha);
+}
+


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