[gtk/ngl-vertex-attributes: 2/2] ngl: Set color and alpha as vertex attributes




commit 440ba94017f753d35d7ab5aa0d5ce483bc9de5d9
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Mar 11 19:46:15 2021 -0500

    ngl: Set color and alpha as vertex attributes
    
    Instead of using uniforms for these, pass them
    as vertex attributes. This will let us batch more
    draw calls, since we don't have to change uniforms
    so often.

 gsk/ngl/gsknglcommandqueue.c                   |  12 +
 gsk/ngl/gskngldriver.c                         |  15 +-
 gsk/ngl/gskngldriverprivate.h                  |   9 +-
 gsk/ngl/gsknglprograms.defs                    |   8 +-
 gsk/ngl/gsknglrenderjob.c                      | 373 +++++++++++--------------
 gsk/ngl/gskngltypesprivate.h                   |   2 +
 gsk/resources/ngl/blend.glsl                   |   7 +-
 gsk/resources/ngl/blit.glsl                    |   7 +-
 gsk/resources/ngl/border.glsl                  |   3 +-
 gsk/resources/ngl/color.glsl                   |   4 +-
 gsk/resources/ngl/color_matrix.glsl            |   7 +-
 gsk/resources/ngl/coloring.glsl                |   4 +-
 gsk/resources/ngl/conic_gradient.glsl          |  12 +-
 gsk/resources/ngl/cross_fade.glsl              |   9 +-
 gsk/resources/ngl/inset_shadow.glsl            |   3 +-
 gsk/resources/ngl/linear_gradient.glsl         |  10 +-
 gsk/resources/ngl/outset_shadow.glsl           |   3 +-
 gsk/resources/ngl/preamble.fs.glsl             |   2 +-
 gsk/resources/ngl/preamble.vs.glsl             |   5 +-
 gsk/resources/ngl/radial_gradient.glsl         |   9 +-
 gsk/resources/ngl/repeat.glsl                  |   6 +-
 gsk/resources/ngl/unblurred_outset_shadow.glsl |   3 +-
 22 files changed, 247 insertions(+), 266 deletions(-)
---
diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c
index 9426c199b1..5d8ed2e0f8 100644
--- a/gsk/ngl/gsknglcommandqueue.c
+++ b/gsk/ngl/gsknglcommandqueue.c
@@ -1096,6 +1096,18 @@ gsk_ngl_command_queue_execute (GskNglCommandQueue   *self,
                          sizeof (GskNglDrawVertex),
                          (void *) G_STRUCT_OFFSET (GskNglDrawVertex, uv));
 
+  /* 2 = color location */
+  glEnableVertexAttribArray (2);
+  glVertexAttribPointer (2, 4, GL_FLOAT, GL_FALSE,
+                         sizeof (GskNglDrawVertex),
+                         (void *) G_STRUCT_OFFSET (GskNglDrawVertex, color));
+
+  /* 3 = alpha location */
+  glEnableVertexAttribArray (3);
+  glVertexAttribPointer (3, 1, GL_FLOAT, GL_FALSE,
+                         sizeof (GskNglDrawVertex),
+                         (void *) G_STRUCT_OFFSET (GskNglDrawVertex, alpha));
+
   /* Setup initial scissor clip */
   if (scissor != NULL)
     {
diff --git a/gsk/ngl/gskngldriver.c b/gsk/ngl/gskngldriver.c
index 692e6a9d5d..9513020fa9 100644
--- a/gsk/ngl/gskngldriver.c
+++ b/gsk/ngl/gskngldriver.c
@@ -347,6 +347,8 @@ gsk_ngl_driver_load_programs (GskNglDriver  *self,
   /* Setup attributes that are provided via VBO */
   gsk_ngl_compiler_bind_attribute (compiler, "aPosition", 0);
   gsk_ngl_compiler_bind_attribute (compiler, "aUv", 1);
+  gsk_ngl_compiler_bind_attribute (compiler, "aColor", 2);
+  gsk_ngl_compiler_bind_attribute (compiler, "aAlpha", 3);
 
   /* Use XMacros to register all of our programs and their uniforms */
 #define GSK_NGL_NO_UNIFORMS
@@ -360,13 +362,11 @@ gsk_ngl_driver_load_programs (GskNglDriver  *self,
 #define GSK_NGL_COMPILE_PROGRAM(name, uniforms, clip)                                            \
   G_STMT_START {                                                                                 \
     GskNglProgram *program;                                                                      \
-    gboolean have_alpha;                                                                         \
     gboolean have_source;                                                                        \
                                                                                                  \
     if (!(program = gsk_ngl_compiler_compile (compiler, #name, clip, error)))                    \
       goto failure;                                                                              \
                                                                                                  \
-    have_alpha = gsk_ngl_program_add_uniform (program, "u_alpha", UNIFORM_SHARED_ALPHA);         \
     have_source = gsk_ngl_program_add_uniform (program, "u_source", UNIFORM_SHARED_SOURCE);      \
     gsk_ngl_program_add_uniform (program, "u_clip_rect", UNIFORM_SHARED_CLIP_RECT);              \
     gsk_ngl_program_add_uniform (program, "u_viewport", UNIFORM_SHARED_VIEWPORT);                \
@@ -377,9 +377,6 @@ gsk_ngl_driver_load_programs (GskNglDriver  *self,
                                                                                                  \
     gsk_ngl_program_uniforms_added (program, have_source);                                       \
                                                                                                  \
-    if (have_alpha)                                                                              \
-      gsk_ngl_program_set_uniform1f (program, UNIFORM_SHARED_ALPHA, 0, 1.0f);                    \
-                                                                                                 \
     *(GskNglProgram **)(((guint8 *)self) + G_STRUCT_OFFSET (GskNglDriver, name)) =               \
          g_steal_pointer (&program);                                                             \
   } G_STMT_END;
@@ -1045,17 +1042,16 @@ gsk_ngl_driver_lookup_shader (GskNglDriver  *self,
       /* Setup attributes that are provided via VBO */
       gsk_ngl_compiler_bind_attribute (compiler, "aPosition", 0);
       gsk_ngl_compiler_bind_attribute (compiler, "aUv", 1);
+      gsk_ngl_compiler_bind_attribute (compiler, "aColor", 2);
+      gsk_ngl_compiler_bind_attribute (compiler, "aAlpha", 3);
 
       if ((program = gsk_ngl_compiler_compile (compiler, NULL, "", error)))
         {
-          gboolean have_alpha;
-
           gsk_ngl_program_add_uniform (program, "u_source", UNIFORM_SHARED_SOURCE);
           gsk_ngl_program_add_uniform (program, "u_clip_rect", UNIFORM_SHARED_CLIP_RECT);
           gsk_ngl_program_add_uniform (program, "u_viewport", UNIFORM_SHARED_VIEWPORT);
           gsk_ngl_program_add_uniform (program, "u_projection", UNIFORM_SHARED_PROJECTION);
           gsk_ngl_program_add_uniform (program, "u_modelview", UNIFORM_SHARED_MODELVIEW);
-          have_alpha = gsk_ngl_program_add_uniform (program, "u_alpha", UNIFORM_SHARED_ALPHA);
 
           gsk_ngl_program_add_uniform (program, "u_size", UNIFORM_CUSTOM_SIZE);
           gsk_ngl_program_add_uniform (program, "u_texture1", UNIFORM_CUSTOM_TEXTURE1);
@@ -1077,9 +1073,6 @@ gsk_ngl_driver_lookup_shader (GskNglDriver  *self,
 
           gsk_ngl_program_uniforms_added (program, TRUE);
 
-          if (have_alpha)
-            gsk_ngl_program_set_uniform1f (program, UNIFORM_SHARED_ALPHA, 0, 1.0f);
-
           g_hash_table_insert (self->shader_cache, shader, program);
           g_object_weak_ref (G_OBJECT (shader),
                              gsk_ngl_driver_shader_weak_cb,
diff --git a/gsk/ngl/gskngldriverprivate.h b/gsk/ngl/gskngldriverprivate.h
index 28199ec016..87c567d205 100644
--- a/gsk/ngl/gskngldriverprivate.h
+++ b/gsk/ngl/gskngldriverprivate.h
@@ -29,7 +29,6 @@
 G_BEGIN_DECLS
 
 enum {
-  UNIFORM_SHARED_ALPHA,
   UNIFORM_SHARED_SOURCE,
   UNIFORM_SHARED_CLIP_RECT,
   UNIFORM_SHARED_VIEWPORT,
@@ -58,13 +57,17 @@ typedef struct {
   graphene_rect_t parent_rect; /* Valid when pointer_is_child */
 } GskTextureKey;
 
-#define GSL_GK_NO_UNIFORMS UNIFORM_INVALID_##__COUNTER__
+#define GSK_NGL_NO_UNIFORMS CONCAT_EXPANDED(UNIFORM_INVALID_,__COUNTER__)
+#define CONCAT_EXPANDED(a,b) CONCAT_EXPANDED2(a,b)
+#define CONCAT_EXPANDED2(a,b) a##b
 #define GSK_NGL_ADD_UNIFORM(pos, KEY, name) UNIFORM_##KEY = UNIFORM_SHARED_LAST + pos,
 #define GSK_NGL_DEFINE_PROGRAM(name, resource, uniforms) enum { uniforms };
 # include "gsknglprograms.defs"
 #undef GSK_NGL_DEFINE_PROGRAM
 #undef GSK_NGL_ADD_UNIFORM
-#undef GSL_GK_NO_UNIFORMS
+#undef GSK_NGL_NO_UNIFORMS
+#undef CONCAT_EXPANDED
+#undef CONCAT_EXPANDED2
 
 #define GSK_TYPE_NGL_DRIVER (gsk_ngl_driver_get_type())
 
diff --git a/gsk/ngl/gsknglprograms.defs b/gsk/ngl/gsknglprograms.defs
index 85c9366ad6..e20cca2fa9 100644
--- a/gsk/ngl/gsknglprograms.defs
+++ b/gsk/ngl/gsknglprograms.defs
@@ -15,17 +15,16 @@ GSK_NGL_DEFINE_PROGRAM (blur,
 
 GSK_NGL_DEFINE_PROGRAM (border,
                         "/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/ngl/color.glsl",
-                        GSK_NGL_ADD_UNIFORM (1, COLOR_COLOR, u_color))
+                        GSK_NGL_NO_UNIFORMS)
 
 GSK_NGL_DEFINE_PROGRAM (coloring,
                         "/org/gtk/libgsk/ngl/coloring.glsl",
-                        GSK_NGL_ADD_UNIFORM (1, COLORING_COLOR, u_color))
+                        GSK_NGL_NO_UNIFORMS)
 
 GSK_NGL_DEFINE_PROGRAM (color_matrix,
                         "/org/gtk/libgsk/ngl/color_matrix.glsl",
@@ -45,7 +44,6 @@ GSK_NGL_DEFINE_PROGRAM (cross_fade,
 
 GSK_NGL_DEFINE_PROGRAM (inset_shadow,
                         "/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))
@@ -59,7 +57,6 @@ GSK_NGL_DEFINE_PROGRAM (linear_gradient,
 
 GSK_NGL_DEFINE_PROGRAM (outset_shadow,
                         "/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,
@@ -77,7 +74,6 @@ GSK_NGL_DEFINE_PROGRAM (repeat,
 
 GSK_NGL_DEFINE_PROGRAM (unblurred_outset_shadow,
                         "/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)
                         GSK_NGL_ADD_UNIFORM (4, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c
index 93ca180133..a02319262f 100644
--- a/gsk/ngl/gsknglrenderjob.c
+++ b/gsk/ngl/gsknglrenderjob.c
@@ -142,6 +142,9 @@ struct _GskNglRenderJob
   /* Our current alpha state as we process nodes */
   float alpha;
 
+  /* Our current color state as we process nodes */
+  GdkRGBA color;
+
   /* Offset (delta x,y) as we process nodes. Occasionally this is merged into
    * a transform that is referenced from child transform nodes.
    */
@@ -388,13 +391,19 @@ gsk_ngl_render_job_set_alpha (GskNglRenderJob *job,
     {
       float ret = job->alpha;
       job->alpha = alpha;
-      job->driver->stamps[UNIFORM_SHARED_ALPHA]++;
       return ret;
     }
 
   return alpha;
 }
 
+static inline void
+gsk_ngl_render_job_set_color (GskNglRenderJob *job,
+                              const GdkRGBA   *color)
+{
+  job->color = *color;
+}
+
 static void
 extract_matrix_metadata (GskNglRenderModelview *modelview)
 {
@@ -874,49 +883,97 @@ gsk_ngl_render_job_update_clip (GskNglRenderJob     *job,
   return TRUE;
 }
 
-/* load_vertex_data_with_region */
-static inline void
-gsk_ngl_render_job_load_vertices_from_offscreen (GskNglRenderJob             *job,
-                                                 const graphene_rect_t       *bounds,
-                                                 const GskNglRenderOffscreen *offscreen)
+/* fill_vertex_data */
+static void
+gsk_ngl_render_job_draw_coords (GskNglRenderJob *job,
+                                float            min_x,
+                                float            min_y,
+                                float            max_x,
+                                float            max_y,
+                                float            min_u,
+                                float            min_v,
+                                float            max_u,
+                                float            max_v)
 {
   GskNglDrawVertex *vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
-  float min_x = job->offset_x + bounds->origin.x;
-  float min_y = job->offset_y + bounds->origin.y;
-  float max_x = min_x + bounds->size.width;
-  float max_y = min_y + bounds->size.height;
-  float y1 = offscreen->was_offscreen ? offscreen->area.y2 : offscreen->area.y;
-  float y2 = offscreen->was_offscreen ? offscreen->area.y : offscreen->area.y2;
 
   vertices[0].position[0] = min_x;
   vertices[0].position[1] = min_y;
-  vertices[0].uv[0] = offscreen->area.x;
-  vertices[0].uv[1] = y1;
+  vertices[0].uv[0] = min_u;
+  vertices[0].uv[1] = min_v;
+  vertices[0].color[0] = job->color.red;
+  vertices[0].color[1] = job->color.green;
+  vertices[0].color[2] = job->color.blue;
+  vertices[0].color[3] = job->color.alpha;
+  vertices[0].alpha = job->alpha;
 
   vertices[1].position[0] = min_x;
   vertices[1].position[1] = max_y;
-  vertices[1].uv[0] = offscreen->area.x;
-  vertices[1].uv[1] = y2;
+  vertices[1].uv[0] = min_u;
+  vertices[1].uv[1] = max_v;
+  vertices[1].color[0] = job->color.red;
+  vertices[1].color[1] = job->color.green;
+  vertices[1].color[2] = job->color.blue;
+  vertices[1].color[3] = job->color.alpha;
+  vertices[1].alpha = job->alpha;
 
   vertices[2].position[0] = max_x;
   vertices[2].position[1] = min_y;
-  vertices[2].uv[0] = offscreen->area.x2;
-  vertices[2].uv[1] = y1;
+  vertices[2].uv[0] = max_u;
+  vertices[2].uv[1] = min_v;
+  vertices[2].color[0] = job->color.red;
+  vertices[2].color[1] = job->color.green;
+  vertices[2].color[2] = job->color.blue;
+  vertices[2].color[3] = job->color.alpha;
+  vertices[2].alpha = job->alpha;
 
   vertices[3].position[0] = max_x;
   vertices[3].position[1] = max_y;
-  vertices[3].uv[0] = offscreen->area.x2;
-  vertices[3].uv[1] = y2;
+  vertices[3].uv[0] = max_u;
+  vertices[3].uv[1] = max_v;
+  vertices[3].color[0] = job->color.red;
+  vertices[3].color[1] = job->color.green;
+  vertices[3].color[2] = job->color.blue;
+  vertices[3].color[3] = job->color.alpha;
+  vertices[3].alpha = job->alpha;
 
   vertices[4].position[0] = min_x;
   vertices[4].position[1] = max_y;
-  vertices[4].uv[0] = offscreen->area.x;
-  vertices[4].uv[1] = y2;
+  vertices[4].uv[0] = min_u;
+  vertices[4].uv[1] = max_v;
+  vertices[4].color[0] = job->color.red;
+  vertices[4].color[1] = job->color.green;
+  vertices[4].color[2] = job->color.blue;
+  vertices[4].color[3] = job->color.alpha;
+  vertices[4].alpha = job->alpha;
 
   vertices[5].position[0] = max_x;
   vertices[5].position[1] = min_y;
-  vertices[5].uv[0] = offscreen->area.x2;
-  vertices[5].uv[1] = y1;
+  vertices[5].uv[0] = max_u;
+  vertices[5].uv[1] = min_v;
+  vertices[5].color[0] = job->color.red;
+  vertices[5].color[1] = job->color.green;
+  vertices[5].color[2] = job->color.blue;
+  vertices[5].color[3] = job->color.alpha;
+  vertices[5].alpha = job->alpha;
+}
+
+/* load_vertex_data_with_region */
+static inline void
+gsk_ngl_render_job_load_vertices_from_offscreen (GskNglRenderJob             *job,
+                                                 const graphene_rect_t       *bounds,
+                                                 const GskNglRenderOffscreen *offscreen)
+{
+  float min_x = job->offset_x + bounds->origin.x;
+  float min_y = job->offset_y + bounds->origin.y;
+  float max_x = min_x + bounds->size.width;
+  float max_y = min_y + bounds->size.height;
+  float y1 = offscreen->was_offscreen ? offscreen->area.y2 : offscreen->area.y;
+  float y2 = offscreen->was_offscreen ? offscreen->area.y : offscreen->area.y2;
+
+  gsk_ngl_render_job_draw_coords (job,
+                                  min_x, min_y, max_x, max_y,
+                                  offscreen->area.x, y1, offscreen->area.x2, y2);
 }
 
 /* load_float_vertex_data */
@@ -927,41 +984,12 @@ gsk_ngl_render_job_draw (GskNglRenderJob *job,
                          float            width,
                          float            height)
 {
-  GskNglDrawVertex *vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
   float min_x = job->offset_x + x;
   float min_y = job->offset_y + y;
   float max_x = min_x + width;
   float max_y = min_y + height;
 
-  vertices[0].position[0] = min_x;
-  vertices[0].position[1] = min_y;
-  vertices[0].uv[0] = 0;
-  vertices[0].uv[1] = 0;
-
-  vertices[1].position[0] = min_x;
-  vertices[1].position[1] = max_y;
-  vertices[1].uv[0] = 0;
-  vertices[1].uv[1] = 1;
-
-  vertices[2].position[0] = max_x;
-  vertices[2].position[1] = min_y;
-  vertices[2].uv[0] = 1;
-  vertices[2].uv[1] = 0;
-
-  vertices[3].position[0] = max_x;
-  vertices[3].position[1] = max_y;
-  vertices[3].uv[0] = 1;
-  vertices[3].uv[1] = 1;
-
-  vertices[4].position[0] = min_x;
-  vertices[4].position[1] = max_y;
-  vertices[4].uv[0] = 0;
-  vertices[4].uv[1] = 1;
-
-  vertices[5].position[0] = max_x;
-  vertices[5].position[1] = min_y;
-  vertices[5].uv[0] = 1;
-  vertices[5].uv[1] = 0;
+  gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y, 0, 0, 1, 1);
 }
 
 /* load_vertex_data */
@@ -976,47 +1004,6 @@ gsk_ngl_render_job_draw_rect (GskNglRenderJob       *job,
                            bounds->size.height);
 }
 
-/* fill_vertex_data */
-static void
-gsk_ngl_render_job_draw_coords (GskNglRenderJob *job,
-                                float            min_x,
-                                float            min_y,
-                                float            max_x,
-                                float            max_y)
-{
-  GskNglDrawVertex *vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
-
-  vertices[0].position[0] = min_x;
-  vertices[0].position[1] = min_y;
-  vertices[0].uv[0] = 0;
-  vertices[0].uv[1] = 1;
-
-  vertices[1].position[0] = min_x;
-  vertices[1].position[1] = max_y;
-  vertices[1].uv[0] = 0;
-  vertices[1].uv[1] = 0;
-
-  vertices[2].position[0] = max_x;
-  vertices[2].position[1] = min_y;
-  vertices[2].uv[0] = 1;
-  vertices[2].uv[1] = 1;
-
-  vertices[3].position[0] = max_x;
-  vertices[3].position[1] = max_y;
-  vertices[3].uv[0] = 1;
-  vertices[3].uv[1] = 0;
-
-  vertices[4].position[0] = min_x;
-  vertices[4].position[1] = max_y;
-  vertices[4].uv[0] = 0;
-  vertices[4].uv[1] = 0;
-
-  vertices[5].position[0] = max_x;
-  vertices[5].position[1] = min_y;
-  vertices[5].uv[0] = 1;
-  vertices[5].uv[1] = 1;
-}
-
 /* load_offscreen_vertex_data */
 static inline void
 gsk_ngl_render_job_draw_offscreen_rect (GskNglRenderJob       *job,
@@ -1027,7 +1014,7 @@ gsk_ngl_render_job_draw_offscreen_rect (GskNglRenderJob       *job,
   float max_x = min_x + bounds->size.width;
   float max_y = min_y + bounds->size.height;
 
-  gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y);
+  gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y, 0, 1, 1, 0);
 }
 
 static inline void
@@ -1069,13 +1056,6 @@ gsk_ngl_render_job_begin_draw (GskNglRenderJob *job,
                                             program->uniform_locations[UNIFORM_SHARED_CLIP_RECT],
                                             job->driver->stamps[UNIFORM_SHARED_CLIP_RECT],
                                             &job->current_clip->rect);
-
-  if (program->uniform_locations[UNIFORM_SHARED_ALPHA] > -1)
-    gsk_ngl_uniform_state_set1f (program->uniforms,
-                                 program->program_info,
-                                 program->uniform_locations[UNIFORM_SHARED_ALPHA],
-                                 job->driver->stamps[UNIFORM_SHARED_ALPHA],
-                                 job->alpha);
 }
 
 #define CHOOSE_PROGRAM(job,name) \
@@ -1283,7 +1263,7 @@ blur_offscreen (GskNglRenderJob       *job,
   gsk_ngl_program_set_uniform2f (job->current_program,
                                  UNIFORM_BLUR_DIR, 0,
                                  1, 0);
-  gsk_ngl_render_job_draw_coords (job, 0, 0, texture_to_blur_width, texture_to_blur_height);
+  gsk_ngl_render_job_draw_coords (job, 0, 0, texture_to_blur_width, texture_to_blur_height, 0, 1, 1, 0);
   gsk_ngl_render_job_end_draw (job);
 
   /* Bind second pass framebuffer and clear it */
@@ -1307,7 +1287,7 @@ blur_offscreen (GskNglRenderJob       *job,
   gsk_ngl_program_set_uniform2f (job->current_program,
                                  UNIFORM_BLUR_DIR, 0,
                                  0, 1);
-  gsk_ngl_render_job_draw_coords (job, 0, 0, texture_to_blur_width, texture_to_blur_height);
+  gsk_ngl_render_job_draw_coords (job, 0, 0, texture_to_blur_width, texture_to_blur_height, 0, 1, 1, 0);
   gsk_ngl_render_job_end_draw (job);
 
   gsk_ngl_render_job_pop_modelview (job);
@@ -1381,9 +1361,7 @@ gsk_ngl_render_job_visit_color_node (GskNglRenderJob     *job,
                                      const GskRenderNode *node)
 {
   gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color));
-  gsk_ngl_program_set_uniform_color (job->current_program,
-                                     UNIFORM_COLOR_COLOR, 0,
-                                     gsk_color_node_get_color (node));
+  gsk_ngl_render_job_set_color (job, gsk_color_node_get_color (node));
   gsk_ngl_render_job_draw_rect (job, &node->bounds);
   gsk_ngl_render_job_end_draw (job);
 }
@@ -1694,9 +1672,7 @@ gsk_ngl_render_job_visit_rect_border_node (GskNglRenderJob     *job,
 
   gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color));
 
-  gsk_ngl_program_set_uniform_color (job->current_program,
-                                     UNIFORM_COLOR_COLOR, 0,
-                                     &colors[0]);
+  gsk_ngl_render_job_set_color (job, &colors[0]);
 
   gsk_ngl_render_job_draw_rect (job,
       &GRAPHENE_RECT_INIT (origin->x,
@@ -1737,12 +1713,10 @@ gsk_ngl_render_job_visit_uniform_border_node (GskNglRenderJob     *job,
   gsk_ngl_render_job_transform_rounded_rect (job, rounded_outline, &outline);
 
   gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow));
+  gsk_ngl_render_job_set_color (job, &colors[0]);
   gsk_ngl_program_set_uniform_rounded_rect (job->current_program,
                                             UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0,
                                             &outline);
-  gsk_ngl_program_set_uniform_color (job->current_program,
-                                     UNIFORM_INSET_SHADOW_COLOR, 0,
-                                     &colors[0]);
   gsk_ngl_program_set_uniform1f (job->current_program,
                                  UNIFORM_INSET_SHADOW_SPREAD, 0,
                                  widths[0]);
@@ -1758,12 +1732,13 @@ gsk_ngl_render_job_visit_border_node (GskNglRenderJob     *job,
                                       const GskRenderNode *node)
 {
   const GskRoundedRect *rounded_outline = gsk_border_node_get_outline (node);
-  const GdkRGBA *colors = gsk_border_node_get_colors (node);
+  const GdkRGBA *c = gsk_border_node_get_colors (node);
   const float *widths = gsk_border_node_get_widths (node);
   struct {
     float w;
     float h;
   } sizes[4];
+  float a = job->alpha;
 
   /* Top left */
   if (widths[3] > 0)
@@ -1818,52 +1793,48 @@ gsk_ngl_render_job_visit_border_node (GskNglRenderJob     *job,
     const GskNglDrawVertex side_data[4][6] = {
       /* Top */
       {
-        { { min_x,              min_y              }, { 0, 1 }, }, /* Upper left */
-        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
-        { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
+        { { min_x,              min_y              }, { 0, 1 }, { c[0].red, c[0].green, c[0].blue, 
c[0].alpha }, a }, /* Upper left */
+        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, 
c[0].alpha }, a }, /* Lower left */
+        { { max_x,              min_y              }, { 1, 1 }, { c[0].red, c[0].green, c[0].blue, 
c[0].alpha }, a }, /* Upper right */
 
-        { { max_x - sizes[1].w, min_y + sizes[1].h }, { 1, 0 }, }, /* Lower right */
-        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
-        { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
+        { { max_x - sizes[1].w, min_y + sizes[1].h }, { 1, 0 }, { c[0].red, c[0].green, c[0].blue, 
c[0].alpha }, a }, /* Lower right */
+        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, 
c[0].alpha }, a }, /* Lower left */
+        { { max_x,              min_y              }, { 1, 1 }, { c[0].red, c[0].green, c[0].blue, 
c[0].alpha }, a }, /* Upper right */
       },
       /* Right */
       {
-        { { max_x - sizes[1].w, min_y + sizes[1].h }, { 0, 1 }, }, /* Upper left */
-        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
-        { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
+        { { max_x - sizes[1].w, min_y + sizes[1].h }, { 0, 1 }, { c[1].red, c[1].green, c[1].blue, 
c[1].alpha }, a }, /* Upper left */
+        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, { c[1].red, c[1].green, c[1].blue, 
c[1].alpha }, a }, /* Lower left */
+        { { max_x,              min_y              }, { 1, 1 }, { c[1].red, c[1].green, c[1].blue, 
c[1].alpha }, a }, /* Upper right */
 
-        { { max_x,              max_y              }, { 1, 0 }, }, /* Lower right */
-        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
-        { { max_x,              min_y              }, { 1, 1 }, }, /* Upper right */
+        { { max_x,              max_y              }, { 1, 0 }, { c[1].red, c[1].green, c[1].blue, 
c[1].alpha }, a }, /* Lower right */
+        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, { c[1].red, c[1].green, c[1].blue, 
c[1].alpha }, a }, /* Lower left */
+        { { max_x,              min_y              }, { 1, 1 }, { c[1].red, c[1].green, c[1].blue, 
c[1].alpha }, a }, /* Upper right */
       },
       /* Bottom */
       {
-        { { min_x + sizes[3].w, max_y - sizes[3].h }, { 0, 1 }, }, /* Upper left */
-        { { min_x,              max_y              }, { 0, 0 }, }, /* Lower left */
-        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
+        { { min_x + sizes[3].w, max_y - sizes[3].h }, { 0, 1 }, { c[2].red, c[2].green, c[2].blue, 
c[2].alpha }, a }, /* Upper left */
+        { { min_x,              max_y              }, { 0, 0 }, { c[2].red, c[2].green, c[2].blue, 
c[2].alpha }, a }, /* Lower left */
+        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, { c[2].red, c[2].green, c[2].blue, 
c[2].alpha }, a }, /* Upper right */
 
-        { { max_x,              max_y              }, { 1, 0 }, }, /* Lower right */
-        { { min_x            ,  max_y              }, { 0, 0 }, }, /* Lower left */
-        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
+        { { max_x,              max_y              }, { 1, 0 }, { c[2].red, c[2].green, c[2].blue, 
c[2].alpha }, a }, /* Lower right */
+        { { min_x            ,  max_y              }, { 0, 0 }, { c[2].red, c[2].green, c[2].blue, 
c[2].alpha }, a }, /* Lower left */
+        { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, { c[2].red, c[2].green, c[2].blue, 
c[2].alpha }, a }, /* Upper right */
       },
       /* Left */
       {
-        { { min_x,              min_y              }, { 0, 1 }, }, /* Upper left */
-        { { min_x,              max_y              }, { 0, 0 }, }, /* Lower left */
-        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
+        { { min_x,              min_y              }, { 0, 1 }, { c[3].red, c[3].green, c[3].blue, 
c[3].alpha }, a }, /* Upper left */
+        { { min_x,              max_y              }, { 0, 0 }, { c[3].red, c[3].green, c[3].blue, 
c[3].alpha }, a }, /* Lower left */
+        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, { c[3].red, c[3].green, c[3].blue, 
c[3].alpha }, a }, /* Upper right */
 
-        { { min_x + sizes[3].w, max_y - sizes[3].h }, { 1, 0 }, }, /* Lower right */
-        { { min_x,              max_y              }, { 0, 0 }, }, /* Lower left */
-        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
+        { { min_x + sizes[3].w, max_y - sizes[3].h }, { 1, 0 }, { c[3].red, c[3].green, c[3].blue, 
c[3].alpha }, a }, /* Lower right */
+        { { min_x,              max_y              }, { 0, 0 }, { c[3].red, c[3].green, c[3].blue, 
c[3].alpha }, a }, /* Lower left */
+        { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, { c[3].red, c[3].green, c[3].blue, 
c[3].alpha }, a }, /* Upper right */
       }
     };
-    int indices[4] = { 0, 1, 2, 3 };
     GskRoundedRect outline;
     GskNglProgram *program;
 
-    /* We sort them by color */
-    sort_border_sides (colors, indices);
-
     /* Prepare outline */
     gsk_ngl_render_job_transform_rounded_rect (job, rounded_outline, &outline);
 
@@ -1881,16 +1852,12 @@ gsk_ngl_render_job_visit_border_node (GskNglRenderJob     *job,
       {
         GskNglDrawVertex *vertices;
 
-        if (widths[indices[i]] <= 0)
+        if (widths[i] <= 0)
           continue;
 
         gsk_ngl_render_job_begin_draw (job, program);
-        gsk_ngl_program_set_uniform4fv (job->current_program,
-                                        UNIFORM_BORDER_COLOR, 0,
-                                        1,
-                                        (const float *)&colors[indices[i]]);
         vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
-        memcpy (vertices, side_data[indices[i]], sizeof (GskNglDrawVertex) * GSK_NGL_N_VERTICES);
+        memcpy (vertices, side_data[i], sizeof (GskNglDrawVertex) * GSK_NGL_N_VERTICES);
         gsk_ngl_render_job_end_draw (job);
       }
   }
@@ -2019,12 +1986,10 @@ gsk_ngl_render_job_visit_unblurred_inset_shadow_node (GskNglRenderJob     *job,
   gsk_ngl_render_job_transform_rounded_rect (job, outline, &transformed_outline);
 
   gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow));
+  gsk_ngl_render_job_set_color (job, gsk_inset_shadow_node_get_color (node));
   gsk_ngl_program_set_uniform_rounded_rect (job->current_program,
                                             UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0,
                                             &transformed_outline);
-  gsk_ngl_program_set_uniform_color (job->current_program,
-                                     UNIFORM_INSET_SHADOW_COLOR, 0,
-                                     gsk_inset_shadow_node_get_color (node));
   gsk_ngl_program_set_uniform1f (job->current_program,
                                  UNIFORM_INSET_SHADOW_SPREAD, 0,
                                  gsk_inset_shadow_node_get_spread (node));
@@ -2122,12 +2087,10 @@ gsk_ngl_render_job_visit_blurred_inset_shadow_node (GskNglRenderJob     *job,
 
       /* Actual inset shadow outline drawing */
       gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow));
+      gsk_ngl_render_job_set_color (job, gsk_inset_shadow_node_get_color (node));
       gsk_ngl_program_set_uniform_rounded_rect (job->current_program,
                                                 UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0,
                                                 &transformed_outline);
-      gsk_ngl_program_set_uniform_color (job->current_program,
-                                         UNIFORM_INSET_SHADOW_COLOR, 0,
-                                         gsk_inset_shadow_node_get_color (node));
       gsk_ngl_program_set_uniform1f (job->current_program,
                                      UNIFORM_INSET_SHADOW_SPREAD, 0,
                                      spread * MAX (scale_x, scale_y));
@@ -2231,12 +2194,10 @@ gsk_ngl_render_job_visit_unblurred_outset_shadow_node (GskNglRenderJob     *job,
   gsk_ngl_render_job_transform_rounded_rect (job, outline, &transformed_outline);
 
   gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, unblurred_outset_shadow));
+  gsk_ngl_render_job_set_color (job, gsk_outset_shadow_node_get_color (node));
   gsk_ngl_program_set_uniform_rounded_rect (job->current_program,
                                             UNIFORM_UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, 0,
                                             &transformed_outline);
-  gsk_ngl_program_set_uniform_color (job->current_program,
-                                     UNIFORM_UNBLURRED_OUTSET_SHADOW_COLOR, 0,
-                                     gsk_outset_shadow_node_get_color (node));
   gsk_ngl_program_set_uniform1f (job->current_program,
                                  UNIFORM_UNBLURRED_OUTSET_SHADOW_SPREAD, 0,
                                  spread);
@@ -2387,9 +2348,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob     *job,
 
       /* Draw the outline using color program */
       gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color));
-      gsk_ngl_program_set_uniform_color (job->current_program,
-                                         UNIFORM_COLOR_COLOR, 0,
-                                         &white);
+      gsk_ngl_render_job_set_color (job, &white);
       gsk_ngl_render_job_draw (job, 0, 0, texture_width, texture_height);
       gsk_ngl_render_job_end_draw (job);
 
@@ -2433,9 +2392,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob     *job,
       init_full_texture_region (&offscreen);
 
       gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, outset_shadow));
-      gsk_ngl_program_set_uniform_color (job->current_program,
-                                         UNIFORM_OUTSET_SHADOW_COLOR, 0,
-                                         color);
+      gsk_ngl_render_job_set_color (job, color);
       gsk_ngl_program_set_uniform_texture (job->current_program,
                                            UNIFORM_SHARED_SOURCE, 0,
                                            GL_TEXTURE_2D,
@@ -2456,9 +2413,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob     *job,
     }
 
   gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, outset_shadow));
-  gsk_ngl_program_set_uniform_color (job->current_program,
-                                     UNIFORM_OUTSET_SHADOW_COLOR, 0,
-                                     color);
+  gsk_ngl_render_job_set_color (job, color);
   gsk_ngl_program_set_uniform_texture (job->current_program,
                                        UNIFORM_SHARED_SOURCE, 0,
                                        GL_TEXTURE_2D,
@@ -2753,14 +2708,9 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob     *job,
 
   /* If the font has color glyphs, we don't need to recolor anything */
   if (!force_color && gsk_text_node_has_color_glyphs (node))
-    {
-      program = CHOOSE_PROGRAM (job, blit);
-    }
+    program = CHOOSE_PROGRAM (job, blit);
   else
-    {
-      program = CHOOSE_PROGRAM (job, coloring);
-      gsk_ngl_program_set_uniform_color (program, UNIFORM_COLORING_COLOR, 0, color);
-    }
+    program = CHOOSE_PROGRAM (job, coloring);
 
   lookup.font = (PangoFont *)font;
   lookup.scale = (guint) (text_scale * 1024);
@@ -2835,31 +2785,61 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob     *job,
       vertices[base+0].position[1] = glyph_y;
       vertices[base+0].uv[0] = tx;
       vertices[base+0].uv[1] = ty;
+      vertices[base+0].color[0] = color->red;
+      vertices[base+0].color[1] = color->green;
+      vertices[base+0].color[2] = color->blue;
+      vertices[base+0].color[3] = color->alpha;
+      vertices[base+0].alpha = job->alpha;
 
       vertices[base+1].position[0] = glyph_x;
       vertices[base+1].position[1] = glyph_y2;
       vertices[base+1].uv[0] = tx;
       vertices[base+1].uv[1] = ty2;
+      vertices[base+1].color[0] = color->red;
+      vertices[base+1].color[1] = color->green;
+      vertices[base+1].color[2] = color->blue;
+      vertices[base+1].color[3] = color->alpha;
+      vertices[base+1].alpha = job->alpha;
 
       vertices[base+2].position[0] = glyph_x2;
       vertices[base+2].position[1] = glyph_y;
       vertices[base+2].uv[0] = tx2;
       vertices[base+2].uv[1] = ty;
+      vertices[base+2].color[0] = color->red;
+      vertices[base+2].color[1] = color->green;
+      vertices[base+2].color[2] = color->blue;
+      vertices[base+2].color[3] = color->alpha;
+      vertices[base+2].alpha = job->alpha;
 
       vertices[base+3].position[0] = glyph_x2;
       vertices[base+3].position[1] = glyph_y2;
       vertices[base+3].uv[0] = tx2;
       vertices[base+3].uv[1] = ty2;
+      vertices[base+3].color[0] = color->red;
+      vertices[base+3].color[1] = color->green;
+      vertices[base+3].color[2] = color->blue;
+      vertices[base+3].color[3] = color->alpha;
+      vertices[base+3].alpha = job->alpha;
 
       vertices[base+4].position[0] = glyph_x;
       vertices[base+4].position[1] = glyph_y2;
       vertices[base+4].uv[0] = tx;
       vertices[base+4].uv[1] = ty2;
+      vertices[base+4].color[0] = color->red;
+      vertices[base+4].color[1] = color->green;
+      vertices[base+4].color[2] = color->blue;
+      vertices[base+4].color[3] = color->alpha;
+      vertices[base+4].alpha = job->alpha;
 
       vertices[base+5].position[0] = glyph_x2;
       vertices[base+5].position[1] = glyph_y;
       vertices[base+5].uv[0] = tx2;
       vertices[base+5].uv[1] = ty;
+      vertices[base+5].color[0] = color->red;
+      vertices[base+5].color[1] = color->green;
+      vertices[base+5].color[2] = color->blue;
+      vertices[base+5].color[3] = color->alpha;
+      vertices[base+5].alpha = job->alpha;
 
       batch->draw.vbo_count += GSK_NGL_N_VERTICES;
       used++;
@@ -2952,14 +2932,12 @@ gsk_ngl_render_job_visit_shadow_node (GskNglRenderJob     *job,
 
       gsk_ngl_render_job_offset (job, dx, dy);
       gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, coloring));
+      gsk_ngl_render_job_set_color (job, &shadow->color);
       gsk_ngl_program_set_uniform_texture (job->current_program,
                                            UNIFORM_SHARED_SOURCE, 0,
                                            GL_TEXTURE_2D,
                                            GL_TEXTURE0,
                                            offscreen.texture_id);
-      gsk_ngl_program_set_uniform_color (job->current_program,
-                                         UNIFORM_COLORING_COLOR, 0,
-                                         &shadow->color);
       gsk_ngl_render_job_load_vertices_from_offscreen (job, &bounds, &offscreen);
       gsk_ngl_render_job_end_draw (job);
       gsk_ngl_render_job_offset (job, -dx, -dy);
@@ -3014,7 +2992,7 @@ gsk_ngl_render_job_visit_blur_node (GskNglRenderJob     *job,
                                        GL_TEXTURE_2D,
                                        GL_TEXTURE0,
                                        offscreen.texture_id);
-  gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y);
+  gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y, 0, 1, 1, 0);
   gsk_ngl_render_job_end_draw (job);
 }
 
@@ -3123,9 +3101,7 @@ gsk_ngl_render_job_visit_gl_shader_node_fallback (GskNglRenderJob     *job,
   static const GdkRGBA pink = { 255 / 255., 105 / 255., 180 / 255., 1.0 };
 
   gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color));
-  gsk_ngl_program_set_uniform_color (job->current_program,
-                                     UNIFORM_COLOR_COLOR, 0,
-                                     &pink);
+  gsk_ngl_render_job_set_color (job, &pink);
   gsk_ngl_render_job_draw_rect (job, &node->bounds);
   gsk_ngl_render_job_end_draw (job);
 }
@@ -3317,7 +3293,6 @@ gsk_ngl_render_job_visit_texture_node (GskNglRenderJob     *job,
 
       for (guint i = 0; i < n_slices; i ++)
         {
-          GskNglDrawVertex *vertices;
           const GskNglTextureSlice *slice = &slices[i];
           float x1, x2, y1, y2;
 
@@ -3333,37 +3308,8 @@ gsk_ngl_render_job_visit_texture_node (GskNglRenderJob     *job,
                                                GL_TEXTURE_2D,
                                                GL_TEXTURE0,
                                                slice->texture_id);
-          vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
-
-          vertices[0].position[0] = x1;
-          vertices[0].position[1] = y1;
-          vertices[0].uv[0] = 0;
-          vertices[0].uv[1] = 0;
-
-          vertices[1].position[0] = x1;
-          vertices[1].position[1] = y2;
-          vertices[1].uv[0] = 0;
-          vertices[1].uv[1] = 1;
-
-          vertices[2].position[0] = x2;
-          vertices[2].position[1] = y1;
-          vertices[2].uv[0] = 1;
-          vertices[2].uv[1] = 0;
-
-          vertices[3].position[0] = x2;
-          vertices[3].position[1] = y2;
-          vertices[3].uv[0] = 1;
-          vertices[3].uv[1] = 1;
-
-          vertices[4].position[0] = x1;
-          vertices[4].position[1] = y2;
-          vertices[4].uv[0] = 0;
-          vertices[4].uv[1] = 1;
-
-          vertices[5].position[0] = x2;
-          vertices[5].position[1] = y1;
-          vertices[5].uv[0] = 1;
-          vertices[5].uv[1] = 0;
+
+          gsk_ngl_render_job_draw_coords (job, x1, y1, x2, y2, 0, 0, 1, 1);
         }
 
       gsk_ngl_render_job_end_draw (job);
@@ -3900,6 +3846,7 @@ gsk_ngl_render_job_new (GskNglDriver          *driver,
   job->viewport = *viewport;
 
   gsk_ngl_render_job_set_alpha (job, 1.0);
+  gsk_ngl_render_job_set_color (job, &(GdkRGBA){ 0.f, 0.f, 0.f, 0.f });
   gsk_ngl_render_job_set_projection_from_rect (job, viewport, NULL);
   gsk_ngl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale_factor, scale_factor));
 
diff --git a/gsk/ngl/gskngltypesprivate.h b/gsk/ngl/gskngltypesprivate.h
index aba6f2f4c9..39cdbb03c5 100644
--- a/gsk/ngl/gskngltypesprivate.h
+++ b/gsk/ngl/gskngltypesprivate.h
@@ -55,6 +55,8 @@ struct _GskNglDrawVertex
 {
   float position[2];
   float uv[2];
+  float color[4];
+  float alpha;
 };
 
 G_END_DECLS
diff --git a/gsk/resources/ngl/blend.glsl b/gsk/resources/ngl/blend.glsl
index 22323402ac..f09fd848d9 100644
--- a/gsk/resources/ngl/blend.glsl
+++ b/gsk/resources/ngl/blend.glsl
@@ -1,14 +1,19 @@
 // VERTEX_SHADER:
+_OUT_ float alpha;
+
 void main() {
   gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
 
   vUv = vec2(aUv.x, aUv.y);
+  alpha = aAlpha;
 }
 
 // FRAGMENT_SHADER:
 uniform int u_mode;
 uniform sampler2D u_source2;
 
+_IN_ float alpha;
+
 float
 combine (float source, float backdrop)
 {
@@ -306,5 +311,5 @@ void main() {
   else
     discard;
 
-  gskSetOutputColor(result * u_alpha);
+  gskSetOutputColor(result * alpha);
 }
diff --git a/gsk/resources/ngl/blit.glsl b/gsk/resources/ngl/blit.glsl
index f01cd238ec..69c4fb1f8f 100644
--- a/gsk/resources/ngl/blit.glsl
+++ b/gsk/resources/ngl/blit.glsl
@@ -1,13 +1,18 @@
 // VERTEX_SHADER:
+_OUT_ float alpha;
+
 void main() {
   gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
 
   vUv = vec2(aUv.x, aUv.y);
+  alpha = aAlpha;
 }
 
 // FRAGMENT_SHADER:
+_IN_ float alpha;
+
 void main() {
   vec4 diffuse = GskTexture(u_source, vUv);
 
-  gskSetOutputColor(diffuse * u_alpha);
+  gskSetOutputColor(diffuse * alpha);
 }
diff --git a/gsk/resources/ngl/border.glsl b/gsk/resources/ngl/border.glsl
index 677a0df7cd..8f1d09496f 100644
--- a/gsk/resources/ngl/border.glsl
+++ b/gsk/resources/ngl/border.glsl
@@ -1,5 +1,4 @@
 // VERTEX_SHADER:
-uniform vec4 u_color;
 uniform vec4 u_widths;
 uniform vec4[3] u_outline_rect;
 
@@ -10,7 +9,7 @@ _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;
+  final_color = gsk_premultiply(aColor) * aAlpha;
 
   GskRoundedRect outside = gsk_create_rect(u_outline_rect);
   GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths);
diff --git a/gsk/resources/ngl/color.glsl b/gsk/resources/ngl/color.glsl
index 636456ce0d..c2c81acef6 100644
--- a/gsk/resources/ngl/color.glsl
+++ b/gsk/resources/ngl/color.glsl
@@ -1,12 +1,10 @@
 // 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;
+  final_color = gsk_premultiply(aColor) * aAlpha;
 }
 
 // FRAGMENT_SHADER:
diff --git a/gsk/resources/ngl/color_matrix.glsl b/gsk/resources/ngl/color_matrix.glsl
index 79cb36434e..0fa93297e4 100644
--- a/gsk/resources/ngl/color_matrix.glsl
+++ b/gsk/resources/ngl/color_matrix.glsl
@@ -1,14 +1,19 @@
 // VERTEX_SHADER:
+_OUT_ float alpha;
+
 void main() {
   gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
 
   vUv = vec2(aUv.x, aUv.y);
+  alpha = aAlpha;
 }
 
 // FRAGMENT_SHADER:
 uniform mat4 u_color_matrix;
 uniform vec4 u_color_offset;
 
+_IN_ float alpha;
+
 void main() {
   vec4 color = GskTexture(u_source, vUv);
 
@@ -21,5 +26,5 @@ void main() {
 
   color.rgb *= color.a;
 
-  gskSetOutputColor(color * u_alpha);
+  gskSetOutputColor(color * alpha);
 }
diff --git a/gsk/resources/ngl/coloring.glsl b/gsk/resources/ngl/coloring.glsl
index a675493030..ed000f3cec 100644
--- a/gsk/resources/ngl/coloring.glsl
+++ b/gsk/resources/ngl/coloring.glsl
@@ -1,6 +1,4 @@
 // VERTEX_SHADER:
-uniform vec4 u_color;
-
 _OUT_ vec4 final_color;
 
 void main() {
@@ -8,7 +6,7 @@ void main() {
 
   vUv = vec2(aUv.x, aUv.y);
 
-  final_color = gsk_premultiply(u_color) * u_alpha;
+  final_color = gsk_premultiply(aColor) * aAlpha;
 }
 
 // FRAGMENT_SHADER:
diff --git a/gsk/resources/ngl/conic_gradient.glsl b/gsk/resources/ngl/conic_gradient.glsl
index 630a42c5e6..ae1b2a9c18 100644
--- a/gsk/resources/ngl/conic_gradient.glsl
+++ b/gsk/resources/ngl/conic_gradient.glsl
@@ -2,6 +2,7 @@
 uniform vec4 u_geometry;
 
 _NOPERSPECTIVE_ _OUT_ vec2 coord;
+_OUT_ float alpha;
 
 void main() {
   gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
@@ -10,8 +11,8 @@ void main() {
   vec2 mv1 = u_modelview[1].xy;
   vec2 offset = aPosition - u_geometry.xy;
 
-  coord = vec2(dot(mv0, offset),
-               dot(mv1, offset));
+  coord = vec2(dot(mv0, offset), dot(mv1, offset));
+  alpha = aAlpha;
 }
 
 // FRAGMENT_SHADER:
@@ -25,6 +26,7 @@ uniform vec4 u_geometry;
 uniform float u_color_stops[6 * 5];
 
 _NOPERSPECTIVE_ _IN_ vec2 coord;
+_IN_ float alpha;
 
 float get_offset(int index) {
   return u_color_stops[5 * index];
@@ -49,7 +51,7 @@ void main() {
   float offset = fract(angle * u_geometry.z + u_geometry.w);
 
   if (offset < get_offset(0)) {
-    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), alpha));
     return;
   }
 
@@ -64,10 +66,10 @@ void main() {
       vec4 next_color = gsk_premultiply(get_color(i + 1));
       vec4 color = mix(curr_color, next_color, f);
 
-      gskSetOutputColor(color * u_alpha);
+      gskSetOutputColor(color * alpha);
       return;
     }
   }
 
-  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
+  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), alpha));
 }
diff --git a/gsk/resources/ngl/cross_fade.glsl b/gsk/resources/ngl/cross_fade.glsl
index f824430f9d..6a4544d0e0 100644
--- a/gsk/resources/ngl/cross_fade.glsl
+++ b/gsk/resources/ngl/cross_fade.glsl
@@ -1,20 +1,25 @@
 // VERTEX_SHADER:
+_OUT_ float alpha;
+
 void main() {
   gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
 
   vUv = vec2(aUv.x, aUv.y);
+  alpha = aAlpha;
 }
 
 // FRAGMENT_SHADER:
 uniform float u_progress;
 uniform sampler2D u_source2;
 
+_IN_ float alpha;
+
 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;
+  float p_start = (1.0 - u_progress) * alpha;
+  float p_end = u_progress * alpha;
   vec4 color = (p_start * source1) + (p_end * source2);
   gskSetOutputColor(color);
 }
diff --git a/gsk/resources/ngl/inset_shadow.glsl b/gsk/resources/ngl/inset_shadow.glsl
index 9a21cdef09..18e9fce9c7 100644
--- a/gsk/resources/ngl/inset_shadow.glsl
+++ b/gsk/resources/ngl/inset_shadow.glsl
@@ -1,5 +1,4 @@
 // VERTEX_SHADER:
-uniform vec4 u_color;
 uniform float u_spread;
 uniform vec2 u_offset;
 uniform vec4[3] u_outline_rect;
@@ -11,7 +10,7 @@ _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;
+  final_color = gsk_premultiply(aColor) * aAlpha;
 
   GskRoundedRect outside = gsk_create_rect(u_outline_rect);
   GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread));
diff --git a/gsk/resources/ngl/linear_gradient.glsl b/gsk/resources/ngl/linear_gradient.glsl
index cc90392c06..bebd18dfee 100644
--- a/gsk/resources/ngl/linear_gradient.glsl
+++ b/gsk/resources/ngl/linear_gradient.glsl
@@ -2,6 +2,7 @@
 uniform vec4 u_points;
 
 _NOPERSPECTIVE_ _OUT_ vec4 info;
+_OUT_ float alpha;
 
 void main() {
   gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
@@ -36,6 +37,8 @@ void main() {
   float rcp_gradient_length = inversesqrt(dot(gradient, gradient));
 
   info = rcp_gradient_length * vec4(coord, gradient);
+
+  alpha = aAlpha;
 }
 
 // FRAGMENT_SHADER:
@@ -49,6 +52,7 @@ uniform float u_color_stops[6 * 5];
 uniform bool u_repeat;
 
 _NOPERSPECTIVE_ _IN_ vec4 info;
+_IN_ float alpha;
 
 float get_offset(int index) {
   return u_color_stops[5 * index];
@@ -71,7 +75,7 @@ void main() {
   }
 
   if (offset < get_offset(0)) {
-    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), alpha));
     return;
   }
 
@@ -86,10 +90,10 @@ void main() {
       vec4 next_color = gsk_premultiply(get_color(i + 1));
       vec4 color = mix(curr_color, next_color, f);
 
-      gskSetOutputColor(color * u_alpha);
+      gskSetOutputColor(color * alpha);
       return;
     }
   }
 
-  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
+  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), alpha));
 }
diff --git a/gsk/resources/ngl/outset_shadow.glsl b/gsk/resources/ngl/outset_shadow.glsl
index 373c650179..bdb62a446f 100644
--- a/gsk/resources/ngl/outset_shadow.glsl
+++ b/gsk/resources/ngl/outset_shadow.glsl
@@ -1,5 +1,4 @@
 // VERTEX_SHADER:
-uniform vec4 u_color;
 uniform vec4[3] u_outline_rect;
 
 _OUT_ vec4 final_color;
@@ -10,7 +9,7 @@ void main() {
 
   vUv = vec2(aUv.x, aUv.y);
 
-  final_color = gsk_premultiply(u_color) * u_alpha;
+  final_color = gsk_premultiply(aColor) * aAlpha;
 
   GskRoundedRect outline = gsk_create_rect(u_outline_rect);
   gsk_rounded_rect_transform(outline, u_modelview);
diff --git a/gsk/resources/ngl/preamble.fs.glsl b/gsk/resources/ngl/preamble.fs.glsl
index 3a2fe49240..b22fb815ed 100644
--- a/gsk/resources/ngl/preamble.fs.glsl
+++ b/gsk/resources/ngl/preamble.fs.glsl
@@ -1,7 +1,6 @@
 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;
 
@@ -12,6 +11,7 @@ _OUT_ vec4 outputColor;
 #endif
 
 _IN_ vec2 vUv;
+_IN_ float vAlpha;
 
 
 
diff --git a/gsk/resources/ngl/preamble.vs.glsl b/gsk/resources/ngl/preamble.vs.glsl
index 89ee6f74e0..5b5d17f249 100644
--- a/gsk/resources/ngl/preamble.vs.glsl
+++ b/gsk/resources/ngl/preamble.vs.glsl
@@ -1,14 +1,17 @@
 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;
+attribute vec4 aColor;
+attribute float aAlpha;
 _OUT_ vec2 vUv;
 #else
 _IN_ vec2 aPosition;
 _IN_ vec2 aUv;
+_IN_ vec4 aColor;
+_IN_ float aAlpha;
 _OUT_ vec2 vUv;
 #endif
 
diff --git a/gsk/resources/ngl/radial_gradient.glsl b/gsk/resources/ngl/radial_gradient.glsl
index 0ab3fdf07a..4d4a73b01e 100644
--- a/gsk/resources/ngl/radial_gradient.glsl
+++ b/gsk/resources/ngl/radial_gradient.glsl
@@ -2,6 +2,7 @@
 uniform vec4 u_geometry;
 
 _NOPERSPECTIVE_ _OUT_ vec2 coord;
+_OUT_ float alpha;
 
 void main() {
   gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
@@ -13,6 +14,7 @@ void main() {
                   dot(mv1, offset));
 
   coord = dir * u_geometry.zw;
+  alpha = aAlpha;
 }
 
 // FRAGMENT_SHADER:
@@ -27,6 +29,7 @@ uniform vec2 u_range;
 uniform float u_color_stops[6 * 5];
 
 _NOPERSPECTIVE_ _IN_ vec2 coord;
+_IN_ float alpha;
 
 float get_offset(int index) {
   return u_color_stops[5 * index];
@@ -50,7 +53,7 @@ void main() {
   }
 
   if (offset < get_offset(0)) {
-    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), alpha));
     return;
   }
 
@@ -65,10 +68,10 @@ void main() {
       vec4 next_color = gsk_premultiply(get_color(i + 1));
       vec4 color = mix(curr_color, next_color, f);
 
-      gskSetOutputColor(color * u_alpha);
+      gskSetOutputColor(color * alpha);
       return;
     }
   }
 
-  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
+  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), alpha));
 }
diff --git a/gsk/resources/ngl/repeat.glsl b/gsk/resources/ngl/repeat.glsl
index a9ebcc5e10..b226e03a80 100644
--- a/gsk/resources/ngl/repeat.glsl
+++ b/gsk/resources/ngl/repeat.glsl
@@ -1,14 +1,18 @@
 // VERTEX_SHADER:
+_OUT_ float alpha;
+
 void main() {
   gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
 
   vUv = vec2(aUv.x, aUv.y);
+  alpha = aAlpha;
 }
 
 // FRAGMENT_SHADER:
 uniform vec4 u_child_bounds;
 uniform vec4 u_texture_rect;
 
+_IN_ float alpha;
 
 float wrap(float f, float wrap_for) {
   return mod(f, wrap_for);
@@ -37,5 +41,5 @@ void main() {
 
   vec4 diffuse = GskTexture(u_source, tp);
 
-  gskSetOutputColor(diffuse * u_alpha);
+  gskSetOutputColor(diffuse * alpha);
 }
diff --git a/gsk/resources/ngl/unblurred_outset_shadow.glsl b/gsk/resources/ngl/unblurred_outset_shadow.glsl
index f110370412..a59a9381a6 100644
--- a/gsk/resources/ngl/unblurred_outset_shadow.glsl
+++ b/gsk/resources/ngl/unblurred_outset_shadow.glsl
@@ -1,5 +1,4 @@
 // VERTEX_SHADER:
-uniform vec4 u_color;
 uniform float u_spread;
 uniform vec2 u_offset;
 uniform vec4[3] u_outline_rect;
@@ -11,7 +10,7 @@ _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;
+  final_color = gsk_premultiply(aColor) * aAlpha;
 
   GskRoundedRect inside = gsk_create_rect(u_outline_rect);
   GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread));


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