[gtk/wip/chergert/glproto: 462/493] implement basic batch reordering by framebuffer




commit 3840fb88d8d7125a5d25fd9839b97b39d278ffdf
Author: Christian Hergert <chergert redhat com>
Date:   Mon Feb 15 17:19:25 2021 -0800

    implement basic batch reordering by framebuffer
    
    Still a lot we can do here, just some basics.

 gsk/next/gskglcommandqueue.c        | 285 ++++++++++++++++++------------------
 gsk/next/gskglcommandqueueprivate.h |  25 ++--
 gsk/next/gskgldriver.c              |   7 +-
 gsk/next/gskglprogram.c             |  70 +--------
 gsk/next/gskglprogramprivate.h      |  14 +-
 gsk/next/gskgluniformstate.c        |  24 ++-
 gsk/next/gskgluniformstateprivate.h | 158 +++++++-------------
 7 files changed, 235 insertions(+), 348 deletions(-)
---
diff --git a/gsk/next/gskglcommandqueue.c b/gsk/next/gskglcommandqueue.c
index 6fdda74aff..2db79e2b13 100644
--- a/gsk/next/gskglcommandqueue.c
+++ b/gsk/next/gskglcommandqueue.c
@@ -36,6 +36,8 @@
 #include "gskglcommandqueueprivate.h"
 #include "gskgluniformstateprivate.h"
 
+#include "inlinearray.h"
+
 G_DEFINE_TYPE (GskGLCommandQueue, gsk_gl_command_queue, G_TYPE_OBJECT)
 
 static inline void
@@ -166,13 +168,13 @@ gsk_gl_command_queue_print_batch (GskGLCommandQueue       *self,
 
       for (guint i = 0; i < batch->draw.bind_count; i++)
         {
-          const GskGLCommandBind *bind = &g_array_index (self->batch_binds, GskGLCommandBind, 
batch->draw.bind_offset + i);
+          const GskGLCommandBind *bind = &self->batch_binds.elements[batch->draw.bind_offset + i];
           g_print ("      Bind[%d]: %u\n", bind->texture, bind->id);
         }
 
       for (guint i = 0; i < batch->draw.uniform_count; i++)
         {
-          const GskGLCommandUniform *uniform = &g_array_index (self->batch_uniforms, GskGLCommandUniform, 
batch->draw.uniform_offset + i);
+          const GskGLCommandUniform *uniform = &self->batch_uniforms.elements[batch->draw.uniform_offset + 
i];
           g_printerr ("  Uniform[%02d]: ", uniform->location);
           print_uniform (uniform->info.format,
                          uniform->info.array_count,
@@ -227,6 +229,56 @@ gsk_gl_command_queue_capture_png (GskGLCommandQueue *self,
   g_free (data);
 }
 
+static inline guint
+snapshot_attachments (const GskGLAttachmentState *state,
+                      GskGLCommandBindArray      *array)
+{
+  GskGLCommandBind *bind = gsk_gl_command_bind_array_append_n (array, G_N_ELEMENTS (state->textures));
+  guint count = 0;
+
+  for (guint i = 0; i < G_N_ELEMENTS (state->textures); i++)
+    {
+      if (state->textures[i].id)
+        {
+          bind[count].id = state->textures[i].id;
+          bind[count].texture = state->textures[i].texture;
+          count++;
+        }
+    }
+
+  if (count != G_N_ELEMENTS (state->textures))
+    array->len -= G_N_ELEMENTS (state->textures) - count;
+
+  return count;
+}
+
+static inline guint
+snapshot_uniforms (GskGLUniformState        *state,
+                   GskGLUniformProgram      *program,
+                   GskGLCommandUniformArray *array)
+{
+  GskGLCommandUniform *uniform = gsk_gl_command_uniform_array_append_n (array, program->n_sparse);
+  guint count = 0;
+
+  for (guint i = 0; i < program->n_sparse; i++)
+    {
+      guint location = program->sparse[i];
+      const GskGLUniformInfo *info = &program->uniforms[location].info;
+
+      if (!info->initial)
+        {
+          uniform[count].location = location;
+          uniform[count].info = *info;
+          count++;
+        }
+    }
+
+  if (count != program->n_sparse)
+    array->len -= program->n_sparse - count;
+
+  return count;
+}
+
 static void
 gsk_gl_command_queue_dispose (GObject *object)
 {
@@ -237,12 +289,12 @@ gsk_gl_command_queue_dispose (GObject *object)
   g_clear_object (&self->profiler);
   g_clear_object (&self->gl_profiler);
   g_clear_object (&self->context);
-  g_clear_pointer (&self->batches, g_free);
   g_clear_pointer (&self->attachments, gsk_gl_attachment_state_unref);
   g_clear_pointer (&self->uniforms, gsk_gl_uniform_state_unref);
-  g_clear_pointer (&self->batch_draws, g_array_unref);
-  g_clear_pointer (&self->batch_binds, g_array_unref);
-  g_clear_pointer (&self->batch_uniforms, g_array_unref);
+
+  gsk_gl_command_batch_array_clear (&self->batches);
+  gsk_gl_command_bind_array_clear (&self->batch_binds);
+  gsk_gl_command_uniform_array_clear (&self->batch_uniforms);
 
   gsk_gl_buffer_destroy (&self->vertices);
 
@@ -262,11 +314,10 @@ gsk_gl_command_queue_init (GskGLCommandQueue *self)
 {
   self->max_texture_size = -1;
 
-  self->batches_len = 128;
-  self->batches = g_new0 (GskGLCommandBatch, self->batches_len);
-  self->batch_draws = g_array_new (FALSE, FALSE, sizeof (GskGLCommandDraw));
-  self->batch_binds = g_array_new (FALSE, FALSE, sizeof (GskGLCommandBind));
-  self->batch_uniforms = g_array_new (FALSE, FALSE, sizeof (GskGLCommandUniform));
+  gsk_gl_command_batch_array_init (&self->batches, 128);
+  gsk_gl_command_bind_array_init (&self->batch_binds, 1024);
+  gsk_gl_command_uniform_array_init (&self->batch_uniforms, 2048);
+
   self->debug_groups = g_string_chunk_new (4096);
 
   gsk_gl_buffer_init (&self->vertices, GL_ARRAY_BUFFER, sizeof (GskGLDrawVertex));
@@ -304,13 +355,7 @@ begin_next_batch (GskGLCommandQueue *self)
 
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
 
-  if G_UNLIKELY (self->n_batches == self->batches_len)
-    {
-      self->batches_len *= 2;
-      self->batches = g_realloc_n (self->batches, self->batches_len, sizeof (GskGLCommandBatch));
-    }
-
-  batch = &self->batches[self->n_batches++];
+  batch = gsk_gl_command_batch_array_append (&self->batches);
   batch->any.next_batch_index = -1;
   batch->any.prev_batch_index = self->tail_batch_index;
 
@@ -323,16 +368,16 @@ enqueue_batch (GskGLCommandQueue *self)
   guint index;
 
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
-  g_assert (self->n_batches > 0);
+  g_assert (self->batches.len > 0);
 
-  index = self->n_batches - 1;
+  index = self->batches.len - 1;
 
   if (self->head_batch_index == -1)
     self->head_batch_index = index;
 
   if (self->tail_batch_index != -1)
     {
-      GskGLCommandBatch *prev = &self->batches[self->tail_batch_index];
+      GskGLCommandBatch *prev = &self->batches.elements[self->tail_batch_index];
 
       prev->any.next_batch_index = index;
     }
@@ -344,9 +389,9 @@ static void
 discard_batch (GskGLCommandQueue *self)
 {
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
-  g_assert (self->n_batches > 0);
+  g_assert (self->batches.len > 0);
 
-  self->n_batches--;
+  self->batches.len--;
 }
 
 void
@@ -360,7 +405,10 @@ gsk_gl_command_queue_begin_draw (GskGLCommandQueue     *self,
   g_assert (self->in_draw == FALSE);
   g_assert (viewport != NULL);
 
-  if (self->n_batches == G_MAXINT16)
+  /* Our internal links use 16-bits, so that is our max number
+   * of batches we can have in one frame.
+   */
+  if (self->batches.len == G_MAXINT16)
     return;
 
   self->program_info = program;
@@ -373,9 +421,9 @@ gsk_gl_command_queue_begin_draw (GskGLCommandQueue     *self,
   batch->any.viewport.height = viewport->size.height;
   batch->draw.framebuffer = 0;
   batch->draw.uniform_count = 0;
-  batch->draw.uniform_offset = self->batch_uniforms->len;
+  batch->draw.uniform_offset = self->batch_uniforms.len;
   batch->draw.bind_count = 0;
-  batch->draw.bind_offset = self->batch_binds->len;
+  batch->draw.bind_offset = self->batch_binds.len;
   batch->draw.vbo_count = 0;
   batch->draw.vbo_offset = gsk_gl_buffer_get_offset (&self->vertices);
 
@@ -384,41 +432,20 @@ gsk_gl_command_queue_begin_draw (GskGLCommandQueue     *self,
   self->in_draw = TRUE;
 }
 
-static inline void
-gsk_gl_command_queue_uniform_snapshot_cb (const GskGLUniformInfo *info,
-                                          guint                   location,
-                                          gpointer                user_data)
-{
-  GArray *uniforms = user_data;
-
-  g_assert (info != NULL);
-  g_assert (info->format > 0);
-  g_assert (location < GL_MAX_UNIFORM_LOCATIONS);
-
-  /* To avoid calling g_array_set_size() a bunch in this callback,
-   * we've already "set_size()" before the callback was called and
-   * so we can instead be certain the size is large enough and use
-   * ++ on length directly.
-   */
-  g_array_index (uniforms, GskGLCommandUniform, uniforms->len).location = location;
-  g_array_index (uniforms, GskGLCommandUniform, uniforms->len).info = *info;
-  uniforms->len++;
-}
-
 void
 gsk_gl_command_queue_end_draw (GskGLCommandQueue *self)
 {
   GskGLCommandBatch *last_batch;
   GskGLCommandBatch *batch;
-  guint n_changed;
 
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
-  g_assert (self->n_batches > 0);
+  g_assert (self->batches.len > 0);
 
-  if (self->n_batches == G_MAXINT16)
+  /* Max batches is 16-bit */
+  if (self->batches.len == G_MAXINT16)
     return;
 
-  batch = &self->batches[self->n_batches - 1];
+  batch = gsk_gl_command_batch_array_tail (&self->batches);
 
   g_assert (self->in_draw == TRUE);
   g_assert (batch->any.kind == GSK_GL_COMMAND_KIND_DRAW);
@@ -435,67 +462,32 @@ gsk_gl_command_queue_end_draw (GskGLCommandQueue *self)
   self->attachments->fbo.changed = FALSE;
   self->fbo_max = MAX (self->fbo_max, self->attachments->fbo.id);
 
-  /* To avoid many g_array_set_size() calls, we first resize the
-   * array to be large enough for all our changes. Then we just ++
-   * from the callback.
+  /* Save our full uniform state for this draw so we can possibly
+   * reorder the draw later.
    */
-  n_changed = self->program_info->n_changed;
+  batch->draw.uniform_offset = self->batch_uniforms.len;
+  batch->draw.uniform_count = snapshot_uniforms (self->uniforms, self->program_info, &self->batch_uniforms);
 
-  if (n_changed)
+  /* Track the bind attachments that changed */
+  if (self->program_info->has_attachments)
     {
-      g_array_set_size (self->batch_uniforms, self->batch_uniforms->len + n_changed);
-      self->batch_uniforms->len -= n_changed;
-
-      /* Store information about uniforms that changed */
-      batch->draw.uniform_offset = self->batch_uniforms->len;
-      gsk_gl_uniform_state_snapshot (self->uniforms,
-                                     self->program_info,
-                                     gsk_gl_command_queue_uniform_snapshot_cb,
-                                     self->batch_uniforms);
-      batch->draw.uniform_count = n_changed;
+      batch->draw.bind_offset = self->batch_binds.len;
+      batch->draw.bind_count = snapshot_attachments (self->attachments, &self->batch_binds);
     }
   else
     {
-      batch->draw.uniform_offset = 0;
-      batch->draw.uniform_count = 0;
-    }
-
-  /* Track the bind attachments that changed */
-  if (self->attachments->n_changed > 0)
-    {
-      GskGLCommandBind *bind;
-
-      batch->draw.bind_offset = self->batch_binds->len;
-      batch->draw.bind_count = self->attachments->n_changed;
-
-      g_array_set_size (self->batch_binds, self->batch_binds->len + batch->draw.bind_count);
-      bind = &g_array_index (self->batch_binds, GskGLCommandBind, self->batch_binds->len - 
batch->draw.bind_count);
-
-      for (guint i = 0;
-           (self->attachments->n_changed > 0 &&
-            i < G_N_ELEMENTS (self->attachments->textures));
-           i++)
-        {
-          GskGLBindTexture *texture = &self->attachments->textures[i];
-
-          if (texture->changed)
-            {
-              texture->changed = FALSE;
-              bind->texture = texture->texture;
-              bind->id = texture->id;
-              bind++;
-              self->attachments->n_changed--;
-            }
-        }
+      batch->draw.bind_offset = 0;
+      batch->draw.bind_count = 0;
     }
 
-  if (self->n_batches > 1)
-    last_batch = &self->batches[self->n_batches - 2];
+  if (self->batches.len > 1)
+    last_batch = &self->batches.elements[self->batches.len - 2];
   else
     last_batch = NULL;
 
   /* Do simple chaining of draw to last batch. */
   /* TODO: Use merging capabilities for out-or-order batching */
+#if 0
   if (batch->draw.uniform_count == 0 &&
       batch->draw.bind_count == 0 &&
       last_batch != NULL &&
@@ -513,6 +505,9 @@ gsk_gl_command_queue_end_draw (GskGLCommandQueue *self)
     {
       enqueue_batch (self);
     }
+#else
+      enqueue_batch (self);
+#endif
 
   self->in_draw = FALSE;
   self->program_info = NULL;
@@ -540,12 +535,12 @@ gsk_gl_command_queue_split_draw (GskGLCommandQueue *self)
   graphene_rect_t viewport;
 
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
-  g_assert (self->n_batches > 0);
+  g_assert (self->batches.len > 0);
   g_assert (self->in_draw == TRUE);
 
   program = self->program_info;
 
-  batch = &self->batches[self->n_batches - 1];
+  batch = gsk_gl_command_batch_array_tail (&self->batches);
 
   g_assert (batch->any.kind == GSK_GL_COMMAND_KIND_DRAW);
 
@@ -568,7 +563,7 @@ gsk_gl_command_queue_clear (GskGLCommandQueue     *self,
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
   g_assert (self->in_draw == FALSE);
 
-  if (self->n_batches == G_MAXINT16)
+  if (self->batches.len == G_MAXINT16)
     return;
 
   if (clear_bits == 0)
@@ -600,7 +595,7 @@ gsk_gl_command_queue_push_debug_group (GskGLCommandQueue *self,
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
   g_assert (self->in_draw == FALSE);
 
-  if (self->n_batches == G_MAXINT16)
+  if (self->batches.len == G_MAXINT16)
     return;
 
   batch = begin_next_batch (self);
@@ -622,7 +617,7 @@ gsk_gl_command_queue_pop_debug_group (GskGLCommandQueue *self)
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
   g_assert (self->in_draw == FALSE);
 
-  if (self->n_batches == G_MAXINT16)
+  if (self->batches.len == G_MAXINT16)
     return;
 
   batch = begin_next_batch (self);
@@ -744,10 +739,10 @@ apply_uniform (gconstpointer    dataptr,
     break;
 
     case GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT:
-      if (info.send_corners)
+      //if (info.send_corners)
         glUniform4fv (location, 3, dataptr);
-      else
-        glUniform4fv (location, 1, dataptr);
+      //else
+        //glUniform4fv (location, 1, dataptr);
     break;
 
     default:
@@ -818,12 +813,12 @@ gsk_gl_command_queue_unlink (GskGLCommandQueue *self,
   if (batch->any.prev_batch_index == -1)
     self->head_batch_index = batch->any.next_batch_index;
   else
-    self->batches[batch->any.prev_batch_index].any.next_batch_index = batch->any.next_batch_index;
+    self->batches.elements[batch->any.prev_batch_index].any.next_batch_index = batch->any.next_batch_index;
 
   if (batch->any.next_batch_index == -1)
     self->tail_batch_index = batch->any.prev_batch_index;
   else
-    self->batches[batch->any.next_batch_index].any.prev_batch_index = batch->any.prev_batch_index;
+    self->batches.elements[batch->any.next_batch_index].any.prev_batch_index = batch->any.prev_batch_index;
 
   batch->any.prev_batch_index = -1;
   batch->any.next_batch_index = -1;
@@ -834,19 +829,22 @@ gsk_gl_command_queue_insert_before (GskGLCommandQueue *self,
                                     GskGLCommandBatch *batch,
                                     GskGLCommandBatch *sibling)
 {
-  int sibling_index = sibling - self->batches;
-  int index = batch - self->batches;
+  int sibling_index;
+  int index;
+
+  g_assert (batch >= self->batches.elements);
+  g_assert (batch < &self->batches.elements[self->batches.len]);
+  g_assert (sibling >= self->batches.elements);
+  g_assert (sibling < &self->batches.elements[self->batches.len]);
 
-  g_assert (batch >= self->batches);
-  g_assert (batch < &self->batches[self->n_batches]);
-  g_assert (sibling >= self->batches);
-  g_assert (sibling < &self->batches[self->n_batches]);
+  index = gsk_gl_command_batch_array_index_of (&self->batches, batch);
+  sibling_index = gsk_gl_command_batch_array_index_of (&self->batches, sibling);
 
   batch->any.next_batch_index = sibling_index;
   batch->any.prev_batch_index = sibling->any.prev_batch_index;
 
   if (batch->any.prev_batch_index > -1)
-    self->batches[batch->any.prev_batch_index].any.next_batch_index = index;
+    self->batches.elements[batch->any.prev_batch_index].any.next_batch_index = index;
 
   sibling->any.prev_batch_index = index;
 
@@ -883,12 +881,12 @@ gsk_gl_command_queue_sort_batches (GskGLCommandQueue *self)
 
   while (index >= 0)
     {
-      GskGLCommandBatch *batch = &self->batches[index];
+      GskGLCommandBatch *batch = &self->batches.elements[index];
       int cur_index = index;
       int fbo = -1;
 
       g_assert (index > -1);
-      g_assert (index < self->n_batches);
+      g_assert (index < self->batches.len);
 
       switch (batch->any.kind)
         {
@@ -911,7 +909,7 @@ gsk_gl_command_queue_sort_batches (GskGLCommandQueue *self)
       index = batch->any.prev_batch_index;
 
       g_assert (index >= -1);
-      g_assert (index < (int)self->n_batches);
+      g_assert (index < (int)self->batches.len);
       g_assert (fbo >= -1);
 
       if (fbo == -1)
@@ -919,12 +917,12 @@ gsk_gl_command_queue_sort_batches (GskGLCommandQueue *self)
 
       g_assert (fbo <= self->fbo_max);
       g_assert (seen[fbo] >= -1);
-      g_assert (seen[fbo] < (int)self->n_batches);
+      g_assert (seen[fbo] < (int)self->batches.len);
 
       if (seen[fbo] != -1 && seen[fbo] != batch->any.next_batch_index)
         {
           int mru_index = seen[fbo];
-          GskGLCommandBatch *mru = &self->batches[mru_index];
+          GskGLCommandBatch *mru = &self->batches.elements[mru_index];
 
           g_assert (mru_index > -1);
 
@@ -968,6 +966,7 @@ gsk_gl_command_queue_execute (GskGLCommandQueue    *self,
   gboolean has_scissor = scissor != NULL;
   gboolean scissor_state = -1;
   graphene_rect_t scissor_test;
+  int textures[8];
   int framebuffer = -1;
   GLuint vao_id;
   int next_batch_index;
@@ -983,10 +982,13 @@ gsk_gl_command_queue_execute (GskGLCommandQueue    *self,
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
   g_assert (self->in_draw == FALSE);
 
-  if (self->n_batches == 0)
+  if (self->batches.len == 0)
     return;
 
-#if 0
+  for (guint i = 0; i < G_N_ELEMENTS (textures); i++)
+    textures[i] = -1;
+
+#if 1
   /* TODO: For batch sorting to work, we need to snapshot the whole uniform
    * state with each batch so that we can re-apply all uniforms since what
    * we captured may not reflect the current state.
@@ -1046,10 +1048,10 @@ gsk_gl_command_queue_execute (GskGLCommandQueue    *self,
 
   while (next_batch_index >= 0)
     {
-      const GskGLCommandBatch *batch = &self->batches[next_batch_index];
+      const GskGLCommandBatch *batch = &self->batches.elements[next_batch_index];
 
       g_assert (next_batch_index >= 0);
-      g_assert (next_batch_index < self->n_batches);
+      g_assert (next_batch_index < self->batches.len);
       g_assert (batch->any.next_batch_index != next_batch_index);
 
       count++;
@@ -1074,13 +1076,13 @@ gsk_gl_command_queue_execute (GskGLCommandQueue    *self,
 
         case GSK_GL_COMMAND_KIND_PUSH_DEBUG_GROUP:
 #ifdef G_ENABLE_DEBUG
-          gdk_gl_context_push_debug_group (self->context, batch->debug_group.debug_group);
+          //gdk_gl_context_push_debug_group (self->context, batch->debug_group.debug_group);
 #endif
         break;
 
         case GSK_GL_COMMAND_KIND_POP_DEBUG_GROUP:
 #ifdef G_ENABLE_DEBUG
-          gdk_gl_context_pop_debug_group (self->context);
+          //gdk_gl_context_pop_debug_group (self->context);
 #endif
         break;
 
@@ -1104,31 +1106,37 @@ gsk_gl_command_queue_execute (GskGLCommandQueue    *self,
 
           if G_UNLIKELY (batch->draw.bind_count > 0)
             {
-              const GskGLCommandBind *bind = &g_array_index (self->batch_binds, GskGLCommandBind, 
batch->draw.bind_offset);
+              const GskGLCommandBind *bind = &self->batch_binds.elements[batch->draw.bind_offset];
 
               for (guint i = 0; i < batch->draw.bind_count; i++)
                 {
-                  if (active != bind->texture)
+                  if (textures[bind->texture] != bind->id)
                     {
-                      active = bind->texture;
-                      glActiveTexture (GL_TEXTURE0 + bind->texture);
+                      if (active != bind->texture)
+                        {
+                          active = bind->texture;
+                          glActiveTexture (GL_TEXTURE0 + bind->texture);
+                        }
+
+                      glBindTexture (GL_TEXTURE_2D, bind->id);
+                      textures[bind->texture] = bind->id;
                     }
 
-                  glBindTexture (GL_TEXTURE_2D, bind->id);
                   bind++;
                 }
+
+              n_binds += batch->draw.bind_count;
             }
 
           if (batch->draw.uniform_count > 0)
             {
-              const GskGLCommandUniform *u = &g_array_index (self->batch_uniforms, GskGLCommandUniform, 
batch->draw.uniform_offset);
+              const GskGLCommandUniform *u = &self->batch_uniforms.elements[batch->draw.uniform_offset];
 
               for (guint i = 0; i < batch->draw.uniform_count; i++, u++)
                 apply_uniform (gsk_gl_uniform_state_get_uniform_data (self->uniforms, u->info.offset),
                                u->info, u->location);
 
               n_uniforms += batch->draw.uniform_count;
-              n_binds += batch->draw.bind_count;
             }
 
           glDrawArrays (GL_TRIANGLES, batch->draw.vbo_offset, batch->draw.vbo_count);
@@ -1187,7 +1195,7 @@ void
 gsk_gl_command_queue_begin_frame (GskGLCommandQueue *self)
 {
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
-  g_assert (self->n_batches == 0);
+  g_assert (self->batches.len == 0);
 
   gsk_gl_command_queue_make_current (self);
 
@@ -1235,10 +1243,9 @@ gsk_gl_command_queue_end_frame (GskGLCommandQueue *self)
 
   g_string_chunk_clear (self->debug_groups);
 
-  self->n_batches = 0;
-  self->batch_draws->len = 0;
-  self->batch_uniforms->len = 0;
-  self->batch_binds->len = 0;
+  self->batches.len = 0;
+  self->batch_binds.len = 0;
+  self->batch_uniforms.len = 0;
   self->n_uploads = 0;
   self->tail_batch_index = -1;
   self->in_frame = FALSE;
diff --git a/gsk/next/gskglcommandqueueprivate.h b/gsk/next/gskglcommandqueueprivate.h
index 98d2f03e56..6402d878f6 100644
--- a/gsk/next/gskglcommandqueueprivate.h
+++ b/gsk/next/gskglcommandqueueprivate.h
@@ -28,6 +28,8 @@
 #include "gskglattachmentstateprivate.h"
 #include "gskgluniformstateprivate.h"
 
+#include "inlinearray.h"
+
 #include "../gl/gskglprofilerprivate.h"
 
 G_BEGIN_DECLS
@@ -180,6 +182,10 @@ typedef union _GskGLCommandBatch
 
 G_STATIC_ASSERT (sizeof (GskGLCommandBatch) == 32);
 
+DEFINE_INLINE_ARRAY (GskGLCommandBatch, gsk_gl_command_batch_array)
+DEFINE_INLINE_ARRAY (GskGLCommandBind, gsk_gl_command_bind_array)
+DEFINE_INLINE_ARRAY (GskGLCommandUniform, gsk_gl_command_uniform_array)
+
 struct _GskGLCommandQueue
 {
   GObject parent_instance;
@@ -192,9 +198,7 @@ struct _GskGLCommandQueue
    * together. The idea here is that we reduce the need for pointers so that
    * using g_realloc()'d arrays is fine.
    */
-  GskGLCommandBatch *batches;
-  gsize batches_len;
-  gsize n_batches;
+  GskGLCommandBatchArray batches;
 
   /* Contains array of vertices and some wrapper code to help upload them
    * to the GL driver. We can also tweak this to use double buffered arrays
@@ -224,24 +228,17 @@ struct _GskGLCommandQueue
   GskProfiler *profiler;
   GskGLProfiler *gl_profiler;
 
-  /* Array of GskGLCommandDraw which allows us to have a static size field
-   * in GskGLCommandBatch to coalesce draws. Multiple GskGLCommandDraw may
-   * be processed together (and out-of-order) to reduce the number of state
-   * changes when submitting commands.
-   */
-  GArray *batch_draws;
-
   /* Array of GskGLCommandBind which denote what textures need to be attached
    * to which slot. GskGLCommandDraw.bind_offset and bind_count reference this
    * array to determine what to attach.
    */
-  GArray *batch_binds;
+  GskGLCommandBindArray batch_binds;
 
   /* Array of GskGLCommandUniform denoting which uniforms must be updated
    * before the glDrawArrays() may be called. These are referenced from the
    * GskGLCommandDraw.uniform_offset and uniform_count fields.
    */
-  GArray *batch_uniforms;
+  GskGLCommandUniformArray batch_uniforms;
 
   /* String storage for debug groups */
   GStringChunk *debug_groups;
@@ -333,13 +330,13 @@ void               gsk_gl_command_queue_split_draw           (GskGLCommandQueue
 static inline GskGLCommandBatch *
 gsk_gl_command_queue_get_batch (GskGLCommandQueue *self)
 {
-  return &self->batches[self->n_batches - 1];
+  return gsk_gl_command_batch_array_tail (&self->batches);
 }
 
 static inline GskGLDrawVertex *
 gsk_gl_command_queue_add_vertices (GskGLCommandQueue *self)
 {
-  self->batches[self->n_batches - 1].draw.vbo_count += GSK_GL_N_VERTICES;
+  gsk_gl_command_queue_get_batch (self)->draw.vbo_count += GSK_GL_N_VERTICES;
   return gsk_gl_buffer_advance (&self->vertices, GSK_GL_N_VERTICES);
 }
 
diff --git a/gsk/next/gskgldriver.c b/gsk/next/gskgldriver.c
index 5f089d2cb9..626e84f457 100644
--- a/gsk/next/gskgldriver.c
+++ b/gsk/next/gskgldriver.c
@@ -364,6 +364,7 @@ gsk_next_driver_load_programs (GskNextDriver  *self,
   G_STMT_START {                                                                                \
     GskGLProgram *program;                                                                      \
     gboolean have_alpha;                                                                        \
+    gboolean have_source;                                                                       \
                                                                                                 \
     gsk_gl_compiler_set_source_from_resource (compiler, GSK_GL_COMPILER_ALL, resource);         \
                                                                                                 \
@@ -371,7 +372,7 @@ gsk_next_driver_load_programs (GskNextDriver  *self,
       goto failure;                                                                             \
                                                                                                 \
     have_alpha = gsk_gl_program_add_uniform (program, "u_alpha", UNIFORM_SHARED_ALPHA);         \
-    gsk_gl_program_add_uniform (program, "u_source", UNIFORM_SHARED_SOURCE);                    \
+    have_source = gsk_gl_program_add_uniform (program, "u_source", UNIFORM_SHARED_SOURCE);      \
     gsk_gl_program_add_uniform (program, "u_clip_rect", UNIFORM_SHARED_CLIP_RECT);              \
     gsk_gl_program_add_uniform (program, "u_viewport", UNIFORM_SHARED_VIEWPORT);                \
     gsk_gl_program_add_uniform (program, "u_projection", UNIFORM_SHARED_PROJECTION);            \
@@ -379,7 +380,7 @@ gsk_next_driver_load_programs (GskNextDriver  *self,
                                                                                                 \
     uniforms                                                                                    \
                                                                                                 \
-    gsk_gl_program_uniforms_added (program);                                                    \
+    gsk_gl_program_uniforms_added (program, have_source);                                       \
                                                                                                 \
     if (have_alpha)                                                                             \
       gsk_gl_program_set_uniform1f (program, UNIFORM_SHARED_ALPHA, 0, 1.0f);                    \
@@ -1129,7 +1130,7 @@ gsk_next_driver_lookup_shader (GskNextDriver  *self,
           for (guint i = n_uniforms; i < G_N_ELEMENTS (program->args_locations); i++)
             program->args_locations[i] = -1;
 
-          gsk_gl_program_uniforms_added (program);
+          gsk_gl_program_uniforms_added (program, TRUE);
 
           if (have_alpha)
             gsk_gl_program_set_uniform1f (program, UNIFORM_SHARED_ALPHA, 0, 1.0f);
diff --git a/gsk/next/gskglprogram.c b/gsk/next/gskglprogram.c
index eb7c7af128..679a704f7a 100644
--- a/gsk/next/gskglprogram.c
+++ b/gsk/next/gskglprogram.c
@@ -151,74 +151,10 @@ gsk_gl_program_delete (GskGLProgram *self)
   self->id = -1;
 }
 
-void
-gsk_gl_program_begin_draw (GskGLProgram            *self,
-                           const graphene_rect_t   *viewport,
-                           const graphene_matrix_t *projection,
-                           const graphene_matrix_t *modelview,
-                           const GskRoundedRect    *clip,
-                           float                    alpha)
-{
-  g_assert (GSK_IS_GL_PROGRAM (self));
-  g_assert (viewport != NULL);
-  g_assert (projection != NULL);
-  g_assert (modelview != NULL);
-  g_assert (clip != NULL);
-
-  gsk_gl_command_queue_begin_draw (self->driver->command_queue, self->program_info, viewport);
-
-  if (self->uniform_locations[UNIFORM_SHARED_VIEWPORT] > -1)
-    gsk_gl_uniform_state_set4fv (self->uniforms,
-                                 self->program_info,
-                                 self->uniform_locations[UNIFORM_SHARED_VIEWPORT],
-                                 0,
-                                 1,
-                                 (const float *)viewport);
-
-  if (self->uniform_locations[UNIFORM_SHARED_MODELVIEW] > -1)
-    gsk_gl_uniform_state_set_matrix (self->uniforms,
-                                     self->program_info,
-                                     self->uniform_locations[UNIFORM_SHARED_MODELVIEW],
-                                     0,
-                                     modelview);
-
-  if (self->uniform_locations[UNIFORM_SHARED_PROJECTION] > -1)
-    gsk_gl_uniform_state_set_matrix (self->uniforms,
-                                     self->program_info,
-                                     self->uniform_locations[UNIFORM_SHARED_PROJECTION],
-                                     0,
-                                     projection);
-
-  if (self->uniform_locations[UNIFORM_SHARED_CLIP_RECT] > -1)
-    {
-      if (clip != NULL)
-        gsk_gl_uniform_state_set_rounded_rect (self->uniforms,
-                                               self->program_info,
-                                               self->uniform_locations[UNIFORM_SHARED_CLIP_RECT],
-                                               0,
-                                               clip);
-      else
-        gsk_gl_uniform_state_set_rounded_rect (self->uniforms,
-                                               self->program_info,
-                                               self->uniform_locations[UNIFORM_SHARED_CLIP_RECT],
-                                               0,
-                                               &GSK_ROUNDED_RECT_INIT (0,
-                                                                       0,
-                                                                       viewport->size.width,
-                                                                       viewport->size.height));
-    }
-
-  if (self->uniform_locations[UNIFORM_SHARED_ALPHA] > -1)
-    gsk_gl_uniform_state_set1f (self->uniforms,
-                                self->program_info,
-                                self->uniform_locations[UNIFORM_SHARED_ALPHA],
-                                0,
-                                alpha);
-}
-
 /**
  * gsk_gl_program_uniforms_added:
  * @self: a #GskGLProgram
+ * @has_attachments: if any uniform is for a bind/texture attachment
  *
  * This function should be called after all of the uniforms ahve
  * been added with gsk_gl_program_add_uniform().
@@ -228,11 +164,13 @@ gsk_gl_program_begin_draw (GskGLProgram            *self,
  * runtime for comparison data.
  */
 void
-gsk_gl_program_uniforms_added (GskGLProgram *self)
+gsk_gl_program_uniforms_added (GskGLProgram *self,
+                               gboolean      has_attachments)
 {
   g_return_if_fail (GSK_IS_GL_PROGRAM (self));
   g_return_if_fail (self->uniforms == NULL);
 
   self->uniforms = self->driver->command_queue->uniforms;
   self->program_info = gsk_gl_uniform_state_get_program (self->uniforms, self->id, self->n_uniforms);
+  self->program_info->has_attachments = has_attachments;
 }
diff --git a/gsk/next/gskglprogramprivate.h b/gsk/next/gskglprogramprivate.h
index f5e04395f6..beadf48758 100644
--- a/gsk/next/gskglprogramprivate.h
+++ b/gsk/next/gskglprogramprivate.h
@@ -55,10 +55,7 @@ struct _GskGLProgram
   int args_locations[8];
   int size_location;
 
-  /* Used to avoid comparing shared state */
-  guint last_shared_state;
-
-  /* Static array for uniform locations (only support up to 32) */
+  /* Static array for key->location transforms */
   int uniform_locations[32];
 };
 
@@ -68,14 +65,9 @@ GskGLProgram *gsk_gl_program_new            (GskNextDriver           *driver,
 gboolean      gsk_gl_program_add_uniform    (GskGLProgram            *self,
                                              const char              *name,
                                              guint                    key);
-void          gsk_gl_program_uniforms_added (GskGLProgram            *self);
+void          gsk_gl_program_uniforms_added (GskGLProgram            *self,
+                                             gboolean                 has_attachments);
 void          gsk_gl_program_delete         (GskGLProgram            *self);
-void          gsk_gl_program_begin_draw     (GskGLProgram            *self,
-                                             const graphene_rect_t   *viewport,
-                                             const graphene_matrix_t *projection,
-                                             const graphene_matrix_t *modelview,
-                                             const GskRoundedRect    *clip,
-                                             float                    alpha);
 
 #define gsk_gl_program_get_uniform_location(s,k) ((s)->uniform_locations[(k)])
 
diff --git a/gsk/next/gskgluniformstate.c b/gsk/next/gskgluniformstate.c
index 6e85853375..8bda3acf48 100644
--- a/gsk/next/gskgluniformstate.c
+++ b/gsk/next/gskgluniformstate.c
@@ -152,13 +152,14 @@ setup_info:
                                 uniform_sizes[format] * MAX (1, array_count),
                                 &offset);
 
-  info->info.changed = FALSE;
   info->info.format = format;
   info->info.offset = offset;
   info->info.array_count = array_count;
   info->info.initial = TRUE;
   info->stamp = 0;
 
+  program->sparse[program->n_sparse++] = location;
+
   *infoptr = info;
 
   return state->values_buf + offset;
@@ -182,13 +183,13 @@ gsk_gl_uniform_state_end_frame (GskGLUniformState *state)
   g_hash_table_iter_init (&iter, state->programs);
   while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&program))
     {
-      for (guint j = 0; j < program->n_uniforms; j++)
+      for (guint j = 0; j < program->n_sparse; j++)
         {
-          GskGLUniformInfoElement *info = &program->uniforms[j];
+          guint location = program->sparse[j];
+          GskGLUniformInfoElement *info = &program->uniforms[location];
           guint size;
 
-          if (info->info.format == 0)
-            continue;
+          g_assert (info->info.format > 0);
 
           /* Calculate how much size is needed for the uniform, including arrays */
           size = uniform_sizes[info->info.format] * MAX (1, info->info.array_count);
@@ -197,15 +198,12 @@ gsk_gl_uniform_state_end_frame (GskGLUniformState *state)
           allocator += gsk_gl_uniform_state_align (allocator, size);
 
           info->info.offset = allocator;
-          info->info.changed = FALSE;
           info->info.initial = TRUE;
-          info->info.send_corners = FALSE;
+          info->stamp = 0;
 
           /* Now advance for this items data */
           allocator += size;
         }
-
-      program->n_changed = 0;
     }
 
   state->values_pos = allocator;
@@ -238,14 +236,14 @@ gsk_gl_uniform_state_get_program (GskGLUniformState *state,
   if (ret == NULL)
     {
       gsize uniform_size = n_uniforms * sizeof (GskGLUniformInfoElement);
-      gsize changed_size = n_uniforms * sizeof (guint);
-      gsize size = sizeof (GskGLUniformProgram) + uniform_size + changed_size;
+      gsize sparse_size = n_uniforms * sizeof (guint);
+      gsize size = sizeof (GskGLUniformProgram) + uniform_size + sparse_size;
 
       ret = g_malloc0 (size);
       ret->program_id = program;
       ret->n_uniforms = n_uniforms;
-      ret->n_changed = 0;
-      ret->changed = (guint *)&ret->uniforms[n_uniforms];
+      ret->n_sparse = 0;
+      ret->sparse = (guint *)&ret->uniforms[n_uniforms];
 
       for (guint i = 0; i < n_uniforms; i++)
         ret->uniforms[i].info.initial = TRUE;
diff --git a/gsk/next/gskgluniformstateprivate.h b/gsk/next/gskgluniformstateprivate.h
index bc5ad197d4..b29f969b7b 100644
--- a/gsk/next/gskgluniformstateprivate.h
+++ b/gsk/next/gskgluniformstateprivate.h
@@ -39,13 +39,10 @@ typedef struct { guint v0; } Uniform1ui;
 
 typedef struct _GskGLUniformInfo
 {
-  guint changed : 1;
   guint format : 5;
   guint array_count : 6;
   guint initial : 1;
-  guint send_corners : 1;
-  guint unused : 2;
-  guint offset : 16;
+  guint offset : 20;
 } GskGLUniformInfo;
 
 G_STATIC_ASSERT (sizeof (GskGLUniformInfo) == 4);
@@ -61,14 +58,14 @@ G_STATIC_ASSERT (sizeof (GskGLUniformInfoElement) == 8);
 typedef struct _GskGLUniformProgram
 {
   guint program_id;
-  guint n_uniforms;
+  guint n_uniforms : 12;
+  guint has_attachments : 1;
 
-  /* To avoid walking unchanged locations in @uniform_info (or sparse
-   * elements used to map location->info), we use this to determine the
-   * specific uniforms that changed this frame.
+  /* To avoid walking our 1:1 array of location->uniform slots, we have
+   * a sparse index that allows us to skip the empty zones.
    */
-  guint *changed;
-  guint n_changed;
+  guint *sparse;
+  guint n_sparse;
 
   /* Uniforms are provided inline at the end of structure to avoid
    * an extra dereference.
@@ -133,10 +130,6 @@ GskGLUniformProgram *gsk_gl_uniform_state_get_program (GskGLUniformState
                                                        guint                      program,
                                                        guint                      n_uniforms);
 void                 gsk_gl_uniform_state_end_frame   (GskGLUniformState         *state);
-void                 gsk_gl_uniform_state_snapshot    (GskGLUniformState         *self,
-                                                       guint                      program_id,
-                                                       GskGLUniformStateCallback  callback,
-                                                       gpointer                   user_data);
 gsize                gsk_gl_uniform_format_size       (GskGLUniformFormat         format);
 gpointer             gsk_gl_uniform_state_init_value  (GskGLUniformState         *state,
                                                        GskGLUniformProgram       *program,
@@ -150,23 +143,17 @@ gpointer             gsk_gl_uniform_state_init_value  (GskGLUniformState
 
 #define gsk_gl_uniform_state_snapshot(state, program_info, callback, user_data) \
   G_STMT_START {                                                                \
-    if (program_info->n_changed)                                                \
+    for (guint z = 0; z < program_info->n_sparse; z++)                          \
       {                                                                         \
-        for (guint z = 0; z < program_info->n_changed; z++)                     \
-          {                                                                     \
-            guint location = program_info->changed[z];                          \
-            GskGLUniformInfo *info = &program_info->uniforms[location].info;    \
+        guint location = program_info->sparse[z];                               \
+        GskGLUniformInfoElement *info = &program_info->uniforms[location];      \
                                                                                 \
-            g_assert (info->changed);                                           \
+        g_assert (location < GL_MAX_UNIFORM_LOCATIONS);                         \
+        g_assert (location < program_info->n_uniforms);                         \
                                                                                 \
-            callback (info, location, user_data);                               \
-                                                                                \
-            info->changed = FALSE;                                              \
-            info->send_corners = FALSE;                                         \
-          }                                                                     \
+        if (info->info.format > 0)                       \
+          callback (&info->info, location, user_data);                          \
       }                                                                         \
-                                                                                \
-    program_info->n_changed = 0;                                                \
   } G_STMT_END
 
 static inline gpointer
@@ -251,20 +238,12 @@ gsk_gl_uniform_state_realloc (GskGLUniformState *state,
   } G_STMT_END
 
 static inline void
-gsk_gl_uniform_program_changed (GskGLUniformProgram     *program,
-                                GskGLUniformInfoElement *info,
-                                guint                    location,
-                                guint                    stamp)
+gsk_gl_uniform_info_changed (GskGLUniformInfoElement *info,
+                             guint                    location,
+                             guint                    stamp)
 {
   info->stamp = stamp;
-
-  if (info->info.changed == FALSE)
-    {
-      info->info.changed = TRUE;
-      info->info.initial = FALSE;
-
-      program->changed[program->n_changed++] = location;
-    }
+  info->info.initial = FALSE;
 }
 
 static inline void
@@ -282,11 +261,11 @@ gsk_gl_uniform_state_set1f (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_1F, 1, location, stamp, 
&info)))
     {
-      if (info->info.initial || u->v0 != value0)
+      if (stamp || info->info.initial || u->v0 != value0)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1f , 1);
           u->v0 = value0;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -307,12 +286,12 @@ gsk_gl_uniform_state_set2f (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_2F, 1, location, stamp, 
&info)))
     {
-      if (info->info.initial || u->v0 != value0 || u->v1 != value1)
+      if (stamp || info->info.initial || u->v0 != value0 || u->v1 != value1)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform2f, 1);
           u->v0 = value0;
           u->v1 = value1;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -334,13 +313,13 @@ gsk_gl_uniform_state_set3f (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_3F, 1, location, stamp, 
&info)))
     {
-      if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2)
+      if (stamp || info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform3f, 1);
           u->v0 = value0;
           u->v1 = value1;
           u->v2 = value2;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -363,14 +342,14 @@ gsk_gl_uniform_state_set4f (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_4F, 1, location, stamp, 
&info)))
     {
-      if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2 || u->v3 != value3)
+      if (stamp || info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2 || u->v3 != 
value3)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform4f, 1);
           u->v0 = value0;
           u->v1 = value1;
           u->v2 = value2;
           u->v3 = value3;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -390,11 +369,11 @@ gsk_gl_uniform_state_set1ui (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_1UI, 1, location, stamp, 
&info)))
     {
-      if (info->info.initial || u->v0 != value0)
+      if (stamp || info->info.initial || u->v0 != value0)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1ui, 1);
           u->v0 = value0;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -414,11 +393,11 @@ gsk_gl_uniform_state_set1i (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_1I, 1, location, stamp, 
&info)))
     {
-      if (info->info.initial || u->v0 != value0)
+      if (stamp || info->info.initial || u->v0 != value0)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1i, 1);
           u->v0 = value0;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -439,12 +418,12 @@ gsk_gl_uniform_state_set2i (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_2I, 1, location, stamp, 
&info)))
     {
-      if (info->info.initial || u->v0 != value0 || u->v1 != value1)
+      if (stamp || info->info.initial || u->v0 != value0 || u->v1 != value1)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform2i, 1);
           u->v0 = value0;
           u->v1 = value1;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -466,13 +445,13 @@ gsk_gl_uniform_state_set3i (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_3I, 1, location, stamp, 
&info)))
     {
-      if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2)
+      if (stamp || info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform3i, 1);
           u->v0 = value0;
           u->v1 = value1;
           u->v2 = value2;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -495,14 +474,14 @@ gsk_gl_uniform_state_set4i (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_4I, 1, location, stamp, 
&info)))
     {
-      if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2 || u->v3 != value3)
+      if (stamp || info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2 || u->v3 != 
value3)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform4i, 1);
           u->v0 = value0;
           u->v1 = value1;
           u->v2 = value2;
           u->v3 = value3;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -515,13 +494,6 @@ rounded_rect_equal (const GskRoundedRect *r1,
    * should allow us to compare without any gaps using memcmp().
    */
   G_STATIC_ASSERT (sizeof *r1 == (sizeof (float) * 12));
-
-  if (r1 == r2)
-    return TRUE;
-
-  if (r1 == NULL)
-    return FALSE;
-
   return memcmp (r1, r2, sizeof *r1) == 0;
 }
 
@@ -541,21 +513,11 @@ gsk_gl_uniform_state_set_rounded_rect (GskGLUniformState    *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT, 1, location, 
stamp, &info)))
     {
-      if (info->info.initial || !rounded_rect_equal (rounded_rect, u))
+      if (stamp || info->info.initial || !rounded_rect_equal (rounded_rect, u))
         {
-          g_assert (!info->info.send_corners || info->info.changed);
-
-          if (!info->info.send_corners)
-            {
-              if (info->info.initial ||
-                  memcmp (u->corner, rounded_rect->corner, sizeof u->corner) != 0)
-                info->info.send_corners = TRUE;
-            }
-
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, GskRoundedRect, 1);
-
           memcpy (u, rounded_rect, sizeof *rounded_rect);
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -576,12 +538,12 @@ gsk_gl_uniform_state_set_matrix (GskGLUniformState       *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_MATRIX, 1, location, stamp, 
&info)))
     {
-      if (!info->info.initial && memcmp (u, matrix, sizeof *u) == 0)
-        return;
-
-      GSK_GL_UNIFORM_STATE_REPLACE (info, u, graphene_matrix_t, 1);
-      memcpy (u, matrix, sizeof *matrix);
-      gsk_gl_uniform_program_changed (program, info, location, stamp);
+      if (stamp || info->info.initial || memcmp (u, matrix, sizeof *u) != 0)
+        {
+          GSK_GL_UNIFORM_STATE_REPLACE (info, u, graphene_matrix_t, 1);
+          memcpy (u, matrix, sizeof *matrix);
+          gsk_gl_uniform_info_changed (info, location, stamp);
+        }
     }
 }
 
@@ -616,11 +578,11 @@ gsk_gl_uniform_state_set_texture (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_TEXTURE, 1, location, 
stamp, &info)))
     {
-      if (info->info.initial || *u != texture_slot)
+      if (stamp || info->info.initial || *u != texture_slot)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, guint, 1);
           *u = texture_slot;
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -655,11 +617,11 @@ gsk_gl_uniform_state_set_color (GskGLUniformState   *state,
       if (color == NULL)
         color = &transparent;
 
-      if (info->info.initial || memcmp (color, u, sizeof *color) != 0)
+      if (stamp || info->info.initial || memcmp (color, u, sizeof *color) != 0)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, GdkRGBA, 1);
           memcpy (u, color, sizeof *color);
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -681,13 +643,11 @@ gsk_gl_uniform_state_set1fv (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_1FV, count, location, 
stamp, &info)))
     {
-      gboolean changed = info->info.initial || memcmp (u, value, sizeof *u * count) != 0;
-
-      if (changed)
+      if (stamp || info->info.initial || memcmp (u, value, sizeof *u * count) != 0)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1f, count);
           memcpy (u, value, sizeof (Uniform1f) * count);
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -709,13 +669,11 @@ gsk_gl_uniform_state_set2fv (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_2FV, count, location, 
stamp, &info)))
     {
-      gboolean changed = info->info.initial || memcmp (u, value, sizeof *u * count) != 0;
-
-      if (changed)
+      if (stamp || info->info.initial || memcmp (u, value, sizeof *u * count) != 0)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform2f, count);
           memcpy (u, value, sizeof (Uniform2f) * count);
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -737,13 +695,11 @@ gsk_gl_uniform_state_set3fv (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_3FV, count, location, 
stamp, &info)))
     {
-      gboolean changed = info->info.initial || memcmp (u, value, sizeof *u * count) != 0;
-
-      if (changed)
+      if (stamp || info->info.initial || memcmp (u, value, sizeof *u * count) != 0)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform3f, count);
           memcpy (u, value, sizeof (Uniform3f) * count);
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }
@@ -765,13 +721,11 @@ gsk_gl_uniform_state_set4fv (GskGLUniformState   *state,
 
   if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_4FV, count, location, 
stamp, &info)))
     {
-      gboolean changed = info->info.initial || memcmp (u, value, sizeof *u * count) != 0;
-
-      if (changed)
+      if (stamp || info->info.initial || memcmp (u, value, sizeof *u * count) != 0)
         {
           GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform4f, count);
           memcpy (u, value, sizeof (Uniform4f) * count);
-          gsk_gl_uniform_program_changed (program, info, location, stamp);
+          gsk_gl_uniform_info_changed (info, location, stamp);
         }
     }
 }


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