[cogl/wip/for-cairo-cogl: 9/12] primitive: micro optimize primitive allocations



commit 0d6542d7d15f1ba3438ba2db35756895c8f78880
Author: Robert Bragg <robert linux intel com>
Date:   Tue Sep 20 01:24:16 2011 +0100

    primitive: micro optimize primitive allocations
    
    We've started seeing cases where we want to allocate lots of one-shot
    primitives per-frame and the cost of allocating primitives becomes
    important in this case since it can start being noticeable in profiles.
    
    The main cost for allocating primitives was the GArray allocation
    and appending the attributes to the array. This updates the code to
    simply over allocate the primitive storage so we can embed the list
    of attributes directly in that allocation.
    
    If the user later sets new attributes and there isn't enough embedded
    space then a separate slice allocation for the new attributes is made
    but still this should be far less costly than using a GArray as before.
    Most of the time we would expect when setting new attributes there will
    still be the same number of attributes, so the embedded space can simple
    be reused.

 cogl/cogl-primitive-private.h |    7 ++-
 cogl/cogl-primitive.c         |  103 ++++++++++++++++++++++-------------------
 2 files changed, 61 insertions(+), 49 deletions(-)
---
diff --git a/cogl/cogl-primitive-private.h b/cogl/cogl-primitive-private.h
index c50181f..3deb1e7 100644
--- a/cogl/cogl-primitive-private.h
+++ b/cogl/cogl-primitive-private.h
@@ -39,9 +39,14 @@ struct _CoglPrimitive
   int first_vertex;
   int n_vertices;
   CoglIndices *indices;
-  GArray *attributes;
 
   int immutable_ref;
+
+  CoglAttribute **attributes;
+  int n_attributes;
+
+  int n_embedded_attributes;
+  CoglAttribute *embedded_attribute;
 };
 
 CoglPrimitive *
diff --git a/cogl/cogl-primitive.c b/cogl/cogl-primitive.c
index dace7c6..5e05fc7 100644
--- a/cogl/cogl-primitive.c
+++ b/cogl/cogl-primitive.c
@@ -35,6 +35,7 @@
 #include "cogl-attribute-private.h"
 
 #include <stdarg.h>
+#include <string.h>
 
 static void _cogl_primitive_free (CoglPrimitive *primitive);
 
@@ -46,17 +47,20 @@ cogl_primitive_new_with_attributes (CoglVerticesMode mode,
                                     CoglAttribute **attributes,
                                     int n_attributes)
 {
-  CoglPrimitive *primitive = g_slice_new (CoglPrimitive);
+  CoglPrimitive *primitive;
   int i;
 
+  primitive = g_slice_alloc (sizeof (CoglPrimitive) +
+                             sizeof (CoglAttribute *) * (n_attributes - 1));
   primitive->mode = mode;
   primitive->first_vertex = 0;
   primitive->n_vertices = n_vertices;
   primitive->indices = NULL;
-  primitive->attributes =
-    g_array_new (TRUE, FALSE, sizeof (CoglAttribute *));
   primitive->immutable_ref = 0;
 
+  primitive->n_attributes = n_attributes;
+  primitive->n_embedded_attributes = n_attributes;
+  primitive->attributes = &primitive->embedded_attribute;
   for (i = 0; i < n_attributes; i++)
     {
       CoglAttribute *attribute = attributes[i];
@@ -64,7 +68,7 @@ cogl_primitive_new_with_attributes (CoglVerticesMode mode,
 
       g_return_val_if_fail (cogl_is_attribute (attribute), NULL);
 
-      g_array_append_val (primitive->attributes, attribute);
+      primitive->attributes[i] = attribute;
     }
 
   return _cogl_primitive_object_new (primitive);
@@ -354,27 +358,15 @@ cogl_primitive_new_p3t2c4 (CoglVerticesMode mode,
 }
 
 static void
-free_attributes_list (CoglPrimitive *primitive)
-{
-  int i;
-
-  for (i = 0; i < primitive->attributes->len; i++)
-    {
-      CoglAttribute *attribute =
-        g_array_index (primitive->attributes, CoglAttribute *, i);
-      cogl_object_unref (attribute);
-    }
-  g_array_set_size (primitive->attributes, 0);
-}
-
-static void
 _cogl_primitive_free (CoglPrimitive *primitive)
 {
-  free_attributes_list (primitive);
+  if (primitive->attributes != &primitive->embedded_attribute)
+    g_slice_free1 (sizeof (CoglAttribute *) * primitive->n_attributes,
+                   primitive->attributes);
 
-  g_array_free (primitive->attributes, TRUE);
-
-  g_slice_free (CoglPrimitive, primitive);
+  g_slice_free1 (sizeof (CoglPrimitive) +
+                 sizeof (CoglAttribute *) *
+                 (primitive->n_embedded_attributes - 1), primitive);
 }
 
 static void
@@ -383,7 +375,7 @@ warn_about_midscene_changes (void)
   static gboolean seen = FALSE;
   if (!seen)
     {
-      g_warning ("Mid-scene modification of buffers has "
+      g_warning ("Mid-scene modification of primitives has "
                  "undefined results\n");
       seen = TRUE;
     }
@@ -404,15 +396,42 @@ cogl_primitive_set_attributes (CoglPrimitive *primitive,
       return;
     }
 
-  free_attributes_list (primitive);
-
-  g_array_set_size (primitive->attributes, 0);
+  /* NB: we don't unref the previous attributes before refing the new
+   * in case we would end up releasing the last reference for an
+   * attribute thats actually in the new list too. */
   for (i = 0; i < n_attributes; i++)
     {
-      cogl_object_ref (attributes[i]);
       g_return_if_fail (cogl_is_attribute (attributes[i]));
-      g_array_append_val (primitive->attributes, attributes[i]);
+      cogl_object_ref (attributes[i]);
+    }
+
+  for (i = 0; i < primitive->n_attributes; i++)
+    cogl_object_unref (primitive->attributes[i]);
+
+  /* First try to use the embedded storage assocated with the
+   * primitive, else fallback to slice allocating separate storage for
+   * the attribute pointers... */
+
+  if (n_attributes <= primitive->n_embedded_attributes)
+    {
+      if (primitive->attributes != &primitive->embedded_attribute)
+        g_slice_free1 (sizeof (CoglAttribute *) * primitive->n_attributes,
+                       primitive->attributes);
+      primitive->attributes = &primitive->embedded_attribute;
     }
+  else if (n_attributes > primitive->n_attributes)
+    {
+      if (primitive->attributes != &primitive->embedded_attribute)
+        g_slice_free1 (sizeof (CoglAttribute *) * primitive->n_attributes,
+                       primitive->attributes);
+      primitive->attributes =
+        g_slice_alloc (sizeof (CoglAttribute *) * n_attributes);
+    }
+
+  memcpy (primitive->attributes, attributes,
+          sizeof (CoglAttribute *) * n_attributes);
+
+  primitive->n_attributes = n_attributes;
 }
 
 int
@@ -506,12 +525,8 @@ _cogl_primitive_immutable_ref (CoglPrimitive *primitive)
 
   primitive->immutable_ref++;
 
-  for (i = 0; i < primitive->attributes->len; i++)
-    {
-      CoglAttribute *attribute =
-        g_array_index (primitive->attributes, CoglAttribute *, i);
-      _cogl_attribute_immutable_ref (attribute);
-    }
+  for (i = 0; i < primitive->n_attributes; i++)
+    _cogl_attribute_immutable_ref (primitive->attributes[i]);
 
   return primitive;
 }
@@ -526,33 +541,25 @@ _cogl_primitive_immutable_unref (CoglPrimitive *primitive)
 
   primitive->immutable_ref--;
 
-  for (i = 0; i < primitive->attributes->len; i++)
-    {
-      CoglAttribute *attribute =
-        g_array_index (primitive->attributes, CoglAttribute *, i);
-      _cogl_attribute_immutable_unref (attribute);
-    }
+  for (i = 0; i < primitive->n_attributes; i++)
+    _cogl_attribute_immutable_unref (primitive->attributes[i]);
 }
 
 /* XXX: cogl_draw_primitive() ? */
 void
 cogl_primitive_draw (CoglPrimitive *primitive)
 {
-  CoglAttribute **attributes =
-    (CoglAttribute **)primitive->attributes->data;
-
   if (primitive->indices)
     cogl_draw_indexed_attributes (primitive->mode,
                                   primitive->first_vertex,
                                   primitive->n_vertices,
                                   primitive->indices,
-                                  attributes,
-                                  primitive->attributes->len);
+                                  primitive->attributes,
+                                  primitive->n_attributes);
   else
     cogl_draw_attributes (primitive->mode,
                           primitive->first_vertex,
                           primitive->n_vertices,
-                          attributes,
-                          primitive->attributes->len);
+                          primitive->attributes,
+                          primitive->n_attributes);
 }
-



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