Use aligned allocators for GtkSnapshot
authorРуслан Ижбулатов <lrn1986@gmail.com>
Sat, 9 Jun 2018 14:06:55 +0000 (14:06 +0000)
committerРуслан Ижбулатов <lrn1986@gmail.com>
Sun, 10 Jun 2018 20:35:54 +0000 (20:35 +0000)
Any data that is later fed to graphene must be
allocated with proper alignment, if graphene
uses SSE2 or GCC vector instructions.

This adds custom array code (a streamlined copy
of GArray with all unnecessary bells and whistles removed),
which is then used for the state_stack instead of GArray.

There's also a runtime check for the size of GtkSnapshotState
itself being a multiple of 16. If that is not so, any array
elements past the 0th element will lose alignment.
There are probably struct attributes that can
make GtkSnapshotState always have size that is a multiple
of 16, but we'll burn that bridge if we cross it.

gsk/gskalloc.c
gtk/gtksnapshot.c
gtk/gtksnapshotprivate.h

index cf1c03163cef5a15c8800b93fd6f53332e657613..76d46f5c628e6665b42671b530b8aeb7bb902a17 100644 (file)
@@ -24,7 +24,7 @@
 # define aligned_free(x) free (x)
 #endif
 
-/**
+/*
  * gsk_aligned_alloc:
  * @size: the size of the memory to allocate
  * @number: the multiples of @size to allocate
@@ -91,7 +91,7 @@ gsk_aligned_alloc (gsize size,
   return res;
 }
 
-/**
+/*
  * gsk_aligned_alloc0:
  * @size: the size of the memory to allocate
  * @number: the multiples of @size to allocate
@@ -117,7 +117,7 @@ gsk_aligned_alloc0 (gsize size,
   return mem;
 }
 
-/**
+/*
  * gsk_aligned_free:
  * @mem: the memory to deallocate
  *
index 907b089f7a8dd1766a108b4412a1f737dfe20084..9d7044679197a52dadfb29982f1072b9da240c9e 100644 (file)
 
 #include "gsk/gskrendernodeprivate.h"
 
+#include "gsk/gskallocprivate.h"
+
 #include "gtk/gskpango.h"
 
 
+static void gtk_snapshot_state_clear (GtkSnapshotState *state);
+
+/* Returns the smallest power of 2 greater than n, or n if
+ * such power does not fit in a guint
+ */
+static guint
+g_nearest_pow (gint num)
+{
+  guint n = 1;
+
+  while (n < num && n > 0)
+    n <<= 1;
+
+  return n ? n : num;
+}
+
+typedef struct _GtkRealSnapshotStateArray  GtkRealSnapshotStateArray;
+
+struct _GtkRealSnapshotStateArray
+{
+  GtkSnapshotState *data;
+  guint   len;
+  guint   alloc;
+  gint    ref_count;
+};
+
+static GtkSnapshotStateArray*
+gtk_snapshot_state_array_new (void)
+{
+  GtkRealSnapshotStateArray *array;
+
+  g_return_val_if_fail (sizeof (GtkSnapshotState) % 16 == 0, NULL);
+
+  array = g_slice_new (GtkRealSnapshotStateArray);
+
+  array->data      = NULL;
+  array->len       = 0;
+  array->alloc     = 0;
+  array->ref_count = 1;
+
+  return (GtkSnapshotStateArray *) array;
+}
+
+static GtkSnapshotState *
+gtk_snapshot_state_array_free (GtkSnapshotStateArray *farray)
+{
+  GtkRealSnapshotStateArray *array = (GtkRealSnapshotStateArray*) farray;
+  guint i;
+
+  g_return_val_if_fail (array, NULL);
+
+  for (i = 0; i < array->len; i++)
+    gtk_snapshot_state_clear (&array->data[i]);
+
+  gsk_aligned_free (array->data);
+
+  g_slice_free1 (sizeof (GtkRealSnapshotStateArray), array);
+
+  return NULL;
+}
+
+#define MIN_ARRAY_SIZE 16
+
+static void
+gtk_snapshot_state_array_maybe_expand (GtkRealSnapshotStateArray *array,
+                                       gint                       len)
+{
+  guint want_alloc = sizeof (GtkSnapshotState) * (array->len + len);
+  GtkSnapshotState *new_data;
+
+  if (want_alloc <= array->alloc)
+    return;
+
+  want_alloc = g_nearest_pow (want_alloc);
+  want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE);
+  new_data = gsk_aligned_alloc0 (want_alloc, 1, 16);
+  memcpy (new_data, array->data, sizeof (GtkSnapshotState) * array->len);
+  gsk_aligned_free (array->data);
+  array->data = new_data;
+  array->alloc = want_alloc;
+}
+
+static GtkSnapshotStateArray*
+gtk_snapshot_state_array_remove_index (GtkSnapshotStateArray *farray,
+                                       guint                  index_)
+{
+  GtkRealSnapshotStateArray *array = (GtkRealSnapshotStateArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+  g_return_val_if_fail (index_ < array->len, NULL);
+
+  gtk_snapshot_state_clear (&array->data[index_]);
+
+  memmove (&array->data[index_],
+           &array->data[index_ + 1],
+           (array->len - index_ - 1) * sizeof (GtkSnapshotState));
+
+  array->len -= 1;
+
+  return farray;
+}
+
+#define gtk_snapshot_state_array_append_val(a,v)       gtk_snapshot_state_array_append_vals (a, &(v), 1)
+
+static GtkSnapshotStateArray*
+gtk_snapshot_state_array_append_vals (GtkSnapshotStateArray *farray,
+                                      gconstpointer          data,
+                                      guint                  len)
+{
+  GtkRealSnapshotStateArray *array = (GtkRealSnapshotStateArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+
+  if (len == 0)
+    return farray;
+
+  gtk_snapshot_state_array_maybe_expand (array, len);
+
+  memcpy (&array->data[array->len], data,
+          sizeof (GtkSnapshotState) * len);
+
+  array->len += len;
+
+  return farray;
+}
+
+
 /**
  * SECTION:gtksnapshot
  * @Short_description: Auxiliary object for snapshots
@@ -120,9 +249,9 @@ gtk_snapshot_push_state (GtkSnapshot            *snapshot,
   state.start_node_index = snapshot->nodes->len;
   state.n_nodes = 0;
 
-  g_array_append_val (snapshot->state_stack, state);
+  gtk_snapshot_state_array_append_val (snapshot->state_stack, state);
 
-  return &g_array_index (snapshot->state_stack, GtkSnapshotState, snapshot->state_stack->len - 1);
+  return &snapshot->state_stack->data[snapshot->state_stack->len - 1];
 }
 
 static GtkSnapshotState *
@@ -130,7 +259,7 @@ gtk_snapshot_get_current_state (const GtkSnapshot *snapshot)
 {
   g_assert (snapshot->state_stack->len > 0);
 
-  return &g_array_index (snapshot->state_stack, GtkSnapshotState, snapshot->state_stack->len - 1);
+  return &snapshot->state_stack->data[snapshot->state_stack->len - 1];
 }
 
 static GtkSnapshotState *
@@ -138,7 +267,7 @@ gtk_snapshot_get_previous_state (const GtkSnapshot *snapshot)
 {
   g_assert (snapshot->state_stack->len > 1);
 
-  return &g_array_index (snapshot->state_stack, GtkSnapshotState, snapshot->state_stack->len - 2);
+  return &snapshot->state_stack->data[snapshot->state_stack->len - 2];
 }
 
 static void
@@ -160,8 +289,7 @@ gtk_snapshot_new (void)
 
   snapshot = g_object_new (GTK_TYPE_SNAPSHOT, NULL);
 
-  snapshot->state_stack = g_array_new (FALSE, TRUE, sizeof (GtkSnapshotState));
-  g_array_set_clear_func (snapshot->state_stack, (GDestroyNotify)gtk_snapshot_state_clear);
+  snapshot->state_stack = gtk_snapshot_state_array_new ();
   snapshot->nodes = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_render_node_unref);
 
   gtk_snapshot_push_state (snapshot,
@@ -925,7 +1053,7 @@ gtk_snapshot_pop_internal (GtkSnapshot *snapshot)
                             snapshot->nodes->len - state->n_nodes,
                             state->n_nodes);
 
-  g_array_remove_index (snapshot->state_stack, state_index);
+  gtk_snapshot_state_array_remove_index (snapshot->state_stack, state_index);
 
   return node;
 }
@@ -955,7 +1083,7 @@ gtk_snapshot_to_node (GtkSnapshot *snapshot)
   
   result = gtk_snapshot_pop_internal (snapshot);
 
-  g_array_free (snapshot->state_stack, TRUE);
+  gtk_snapshot_state_array_free (snapshot->state_stack);
   snapshot->state_stack = NULL;
 
   g_ptr_array_free (snapshot->nodes, TRUE);
index b54fb4b7028e37008021716a9561845b89271875..5ecda2d5014e901358ae1249d4abf9f35e00f77e 100644 (file)
 G_BEGIN_DECLS
 
 typedef struct _GtkSnapshotState GtkSnapshotState;
+typedef struct _GtkSnapshotStateArray GtkSnapshotStateArray;
+
+/* This is a stripped-down copy of GArray tailored specifically
+ * for GtkSnapshotState and guaranteed to be aligned to 16 byte
+ * bounaries.
+ */
+struct _GtkSnapshotStateArray
+{
+  GtkSnapshotState *data;
+  guint len;
+};
 
 typedef GskRenderNode * (* GtkSnapshotCollectFunc) (GtkSnapshot      *snapshot,
                                                     GtkSnapshotState *state,
@@ -88,7 +99,7 @@ struct _GtkSnapshotState {
 struct _GdkSnapshot {
   GObject                parent_instance; /* it's really GdkSnapshot, but don't tell anyone! */
 
-  GArray                *state_stack;
+  GtkSnapshotStateArray *state_stack;
   GPtrArray             *nodes;
 };