diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index f6c1bb222..43500a9c4 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -356,6 +356,8 @@ cogl_sources_c = \
$(srcdir)/gl-prototypes/cogl-in-gles2-core-functions.h \
$(srcdir)/gl-prototypes/cogl-fixed-functions.h \
$(srcdir)/gl-prototypes/cogl-glsl-functions.h \
+ $(srcdir)/cogl-memory-stack-private.h \
+ $(srcdir)/cogl-memory-stack.c \
$(NULL)
if USE_GLIB
diff --git a/cogl/cogl-memory-stack-private.h b/cogl/cogl-memory-stack-private.h
new file mode 100644
index 000000000..858807ab5
--- /dev/null
+++ b/cogl/cogl-memory-stack-private.h
@@ -0,0 +1,51 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ *
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#include
+
+#ifndef __COGL_MEMORY_STACK__
+#define __COGL_MEMORY_STACK__
+
+G_BEGIN_DECLS
+
+typedef struct _CoglMemoryStack CoglMemoryStack;
+
+CoglMemoryStack *
+_cogl_memory_stack_new (size_t initial_size_bytes);
+
+void *
+_cogl_memory_stack_alloc (CoglMemoryStack *stack, size_t bytes);
+
+void
+_cogl_memory_stack_rewind (CoglMemoryStack *stack);
+
+void
+_cogl_memory_stack_free (CoglMemoryStack *stack);
+
+G_END_DECLS
+
+#endif /* __COGL_MEMORY_STACK__ */
diff --git a/cogl/cogl-memory-stack.c b/cogl/cogl-memory-stack.c
new file mode 100644
index 000000000..5a939ec86
--- /dev/null
+++ b/cogl/cogl-memory-stack.c
@@ -0,0 +1,188 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ *
+ *
+ * CoglMemoryStack provides a really simple, but lightning fast
+ * memory stack allocation strategy:
+ *
+ * - The underlying pool of memory is grow-only.
+ * - The pool is considered to be a stack which may be comprised
+ * of multiple smaller stacks. Allocation is done as follows:
+ * - If there's enough memory in the current sub-stack then the
+ * stack-pointer will be returned as the allocation and the
+ * stack-pointer will be incremented by the allocation size.
+ * - If there isn't enough memory in the current sub-stack
+ * then a new sub-stack is allocated twice as big as the current
+ * sub-stack or twice as big as the requested allocation size if
+ * that's bigger and the stack-pointer is set to the start of the
+ * new sub-stack.
+ * - Allocations can't be freed in a random-order, you can only
+ * rewind the entire stack back to the start. There is no
+ * the concept of stack frames to allow partial rewinds.
+ *
+ * For example; we plan to use this in our tesselator which has to
+ * allocate lots of small vertex, edge and face structures because
+ * when tesselation has been finished we just want to free the whole
+ * lot in one go.
+ *
+ *
+ * Authors:
+ * Robert Bragg
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-memory-stack-private.h"
+#include "cogl-queue.h"
+
+#include
+
+#include
+
+typedef struct _CoglMemorySubStack CoglMemorySubStack;
+
+COGL_TAILQ_HEAD (CoglMemorySubStackList, CoglMemorySubStack);
+
+struct _CoglMemorySubStack
+{
+ COGL_TAILQ_ENTRY (CoglMemorySubStack) list_node;
+ size_t bytes;
+ uint8_t *data;
+};
+
+typedef struct _CoglMemoryStack
+{
+ CoglMemorySubStackList sub_stacks;
+
+ CoglMemorySubStack *sub_stack;
+ size_t sub_stack_offset;
+} CoglMemoryStack;
+
+static CoglMemorySubStack *
+_cogl_memory_sub_stack_alloc (size_t bytes)
+{
+ CoglMemorySubStack *sub_stack = g_slice_new (CoglMemorySubStack);
+ sub_stack->bytes = bytes;
+ sub_stack->data = g_malloc (bytes);
+ return sub_stack;
+}
+
+static void
+_cogl_memory_stack_add_sub_stack (CoglMemoryStack *stack,
+ size_t sub_stack_bytes)
+{
+ CoglMemorySubStack *sub_stack =
+ _cogl_memory_sub_stack_alloc (sub_stack_bytes);
+ COGL_TAILQ_INSERT_TAIL (&stack->sub_stacks, sub_stack, list_node);
+ stack->sub_stack = sub_stack;
+ stack->sub_stack_offset = 0;
+}
+
+CoglMemoryStack *
+_cogl_memory_stack_new (size_t initial_size_bytes)
+{
+ CoglMemoryStack *stack = g_slice_new0 (CoglMemoryStack);
+
+ COGL_TAILQ_INIT (&stack->sub_stacks);
+
+ _cogl_memory_stack_add_sub_stack (stack, initial_size_bytes);
+
+ return stack;
+}
+
+void *
+_cogl_memory_stack_alloc (CoglMemoryStack *stack, size_t bytes)
+{
+ CoglMemorySubStack *sub_stack;
+ void *ret;
+
+ sub_stack = stack->sub_stack;
+ if (G_LIKELY (sub_stack->bytes - stack->sub_stack_offset >= bytes))
+ {
+ ret = sub_stack->data + stack->sub_stack_offset;
+ stack->sub_stack_offset += bytes;
+ return ret;
+ }
+
+ /* If the stack has been rewound and then a large initial allocation
+ * is made then we may need to skip over one or more of the
+ * sub-stacks that are too small for the requested allocation
+ * size... */
+ for (sub_stack = sub_stack->list_node.tqe_next;
+ sub_stack;
+ sub_stack = sub_stack->list_node.tqe_next)
+ {
+ if (sub_stack->bytes >= bytes)
+ {
+ ret = sub_stack->data;
+ stack->sub_stack = sub_stack;
+ stack->sub_stack_offset = bytes;
+ return ret;
+ }
+ }
+
+ /* Finally if we couldn't find a free sub-stack with enough space
+ * for the requested allocation we allocate another sub-stack that's
+ * twice as big as the last sub-stack or twice as big as the
+ * requested allocation if that's bigger.
+ */
+
+ sub_stack = COGL_TAILQ_LAST (&stack->sub_stacks, CoglMemorySubStackList);
+
+ _cogl_memory_stack_add_sub_stack (stack, MAX (sub_stack->bytes, bytes) * 2);
+
+ sub_stack = COGL_TAILQ_LAST (&stack->sub_stacks, CoglMemorySubStackList);
+
+ stack->sub_stack_offset += bytes;
+
+ return sub_stack->data;
+}
+
+void
+_cogl_memory_stack_rewind (CoglMemoryStack *stack)
+{
+ stack->sub_stack = COGL_TAILQ_FIRST (&stack->sub_stacks);
+ stack->sub_stack_offset = 0;
+}
+
+static void
+_cogl_memory_sub_stack_free (CoglMemorySubStack *sub_stack)
+{
+ g_free (sub_stack->data);
+ g_slice_free (CoglMemorySubStack, sub_stack);
+}
+
+void
+_cogl_memory_stack_free (CoglMemoryStack *stack)
+{
+ CoglMemorySubStack *sub_stack;
+
+ for (sub_stack = stack->sub_stacks.tqh_first;
+ sub_stack;
+ sub_stack = sub_stack->list_node.tqe_next)
+ {
+ _cogl_memory_sub_stack_free (sub_stack);
+ }
+
+ g_slice_free (CoglMemoryStack, stack);
+}