[cogl/wip/for-cairo-cogl: 1/8] pipeline: Split more code out from cogl-pipeline.c



commit d4459e2d421ca348a149117805e793f0b7975c99
Author: Robert Bragg <robert linux intel com>
Date:   Fri Sep 9 00:40:06 2011 +0100

    pipeline: Split more code out from cogl-pipeline.c
    
    This splits out the core CoglPipelineLayer support code from
    cogl-pipeline.c into cogl-pipeline-layer.c; it splits out the debugging
    code for dumping a pipeline to a .dot file into cogl-pipeline-debug.c
    and it splits the CoglPipelineNode support which is shared between
    CoglPipeline and CoglPipelineLayer into cogl-node.c.
    
    Note: cogl-pipeline-layer.c only contains the layer code directly
    relating to CoglPipelineLayer objects; it does not contain any
    _cogl_pipeline API relating to how CoglPipeline tracks and manipulates
    layers.

 cogl/Makefile.am                         |    6 +
 cogl/cogl-internal.h                     |    8 +
 cogl/cogl-node-private.h                 |   85 +++
 cogl/cogl-node.c                         |  103 +++
 cogl/cogl-pipeline-debug.c               |  284 ++++++++
 cogl/cogl-pipeline-fragend-arbfp.c       |    3 +-
 cogl/cogl-pipeline-fragend-glsl.c        |    3 +-
 cogl/cogl-pipeline-layer-private.h       |  380 ++++++++++
 cogl/cogl-pipeline-layer-state-private.h |   11 +
 cogl/cogl-pipeline-layer.c               |  798 ++++++++++++++++++++
 cogl/cogl-pipeline-private.h             |  411 +----------
 cogl/cogl-pipeline.c                     | 1161 +-----------------------------
 cogl/cogl-pipeline.h                     |    5 +-
 cogl/cogl-texture.h                      |    1 +
 configure.ac                             |    2 +
 15 files changed, 1752 insertions(+), 1509 deletions(-)
---
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index c0c048b..54485c3 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -244,12 +244,18 @@ cogl_sources_c = \
 	$(srcdir)/cogl-matrix-stack.h			\
 	$(srcdir)/cogl-depth-state.c			\
 	$(srcdir)/cogl-depth-state-private.h		\
+	$(srcdir)/cogl-node.c				\
+	$(srcdir)/cogl-node-private.h			\
 	$(srcdir)/cogl-pipeline.c			\
 	$(srcdir)/cogl-pipeline-private.h		\
+	$(srcdir)/cogl-pipeline-layer.c			\
+	$(srcdir)/cogl-pipeline-layer-private.h		\
 	$(srcdir)/cogl-pipeline-state.c			\
 	$(srcdir)/cogl-pipeline-layer-state-private.h	\
 	$(srcdir)/cogl-pipeline-layer-state.c		\
 	$(srcdir)/cogl-pipeline-state-private.h		\
+	$(srcdir)/cogl-pipeline-debug.c			\
+	$(srcdir)/cogl-pipeline-debug-private.h		\
 	$(srcdir)/cogl-pipeline-opengl.c		\
 	$(srcdir)/cogl-pipeline-opengl-private.h	\
 	$(srcdir)/cogl-pipeline-fragend-glsl.c		\
diff --git a/cogl/cogl-internal.h b/cogl/cogl-internal.h
index bedb74b..eee0e08 100644
--- a/cogl/cogl-internal.h
+++ b/cogl/cogl-internal.h
@@ -131,6 +131,14 @@ typedef enum
   COGL_PRIVATE_FEATURE_MESA_PACK_INVERT = 1L<<1
 } CoglPrivateFeatureFlags;
 
+/* Sometimes when evaluating pipelines, either during comparisons or
+ * if calculating a hash value we need to tweak the evaluation
+ * semantics */
+typedef enum _CoglPipelineEvalFlags
+{
+  COGL_PIPELINE_EVAL_FLAG_NONE = 0
+} CoglPipelineEvalFlags;
+
 gboolean
 _cogl_check_extension (const char *name, const char *ext);
 
diff --git a/cogl/cogl-node-private.h b/cogl/cogl-node-private.h
new file mode 100644
index 0000000..71f1806
--- /dev/null
+++ b/cogl/cogl-node-private.h
@@ -0,0 +1,85 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2008,2009,2010 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert linux intel com>
+ */
+
+#ifndef __COGL_NODE_PRIVATE_H
+#define __COGL_NODE_PRIVATE_H
+
+#include "cogl-object-private.h"
+#include "cogl-queue.h"
+
+typedef struct _CoglNode CoglNode;
+
+COGL_LIST_HEAD (CoglNodeList, CoglNode);
+
+/* Pipelines and layers represent their state in a tree structure where
+ * some of the state relating to a given pipeline or layer may actually
+ * be owned by one if is ancestors in the tree. We have a common data
+ * type to track the tree heirachy so we can share code... */
+struct _CoglNode
+{
+  /* the parent in terms of class hierarchy, so anything inheriting
+   * from CoglNode also inherits from CoglObject. */
+  CoglObject _parent;
+
+  /* The parent pipeline/layer */
+  CoglNode *parent;
+
+  /* The list entry here contains pointers to the node's siblings */
+  COGL_LIST_ENTRY (CoglNode) list_node;
+
+  /* List of children */
+  CoglNodeList children;
+
+  /* TRUE if the node took a strong reference on its parent. Weak
+   * pipelines for instance don't take a reference on their parent. */
+  gboolean has_parent_reference;
+};
+
+#define COGL_NODE(X) ((CoglNode *)(X))
+
+void
+_cogl_pipeline_node_init (CoglNode *node);
+
+typedef void (*CoglNodeUnparentVFunc) (CoglNode *node);
+
+void
+_cogl_pipeline_node_set_parent_real (CoglNode *node,
+                                     CoglNode *parent,
+                                     CoglNodeUnparentVFunc unparent,
+                                     gboolean take_strong_reference);
+
+void
+_cogl_pipeline_node_unparent_real (CoglNode *node);
+
+typedef gboolean (*CoglNodeChildCallback) (CoglNode *child, void *user_data);
+
+void
+_cogl_pipeline_node_foreach_child (CoglNode *node,
+                                   CoglNodeChildCallback callback,
+                                   void *user_data);
+
+#endif /* __COGL_NODE_PRIVATE_H */
diff --git a/cogl/cogl-node.c b/cogl/cogl-node.c
new file mode 100644
index 0000000..46112f3
--- /dev/null
+++ b/cogl/cogl-node.c
@@ -0,0 +1,103 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2008,2009,2010 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-node-private.h"
+
+void
+_cogl_pipeline_node_init (CoglNode *node)
+{
+  node->parent = NULL;
+  COGL_LIST_INIT (&node->children);
+}
+
+void
+_cogl_pipeline_node_set_parent_real (CoglNode *node,
+                                     CoglNode *parent,
+                                     CoglNodeUnparentVFunc unparent,
+                                     gboolean take_strong_reference)
+{
+  /* NB: the old parent may indirectly be keeping the new parent alive
+   * so we have to ref the new parent before unrefing the old.
+   *
+   * Note: we take a reference here regardless of
+   * take_strong_reference because weak children may need special
+   * handling when the parent disposes itself which relies on a
+   * consistent link to all weak nodes. Once the node is linked to its
+   * parent then we remove the reference at the end if
+   * take_strong_reference == FALSE. */
+  cogl_object_ref (parent);
+
+  if (node->parent)
+    unparent (node);
+
+  COGL_LIST_INSERT_HEAD (&parent->children, node, list_node);
+
+  node->parent = parent;
+  node->has_parent_reference = take_strong_reference;
+
+  /* Now that there is a consistent parent->child link we can remove
+   * the parent reference if no reference was requested. If it turns
+   * out that the new parent was only being kept alive by the old
+   * parent then it will be disposed of here. */
+  if (!take_strong_reference)
+    cogl_object_unref (parent);
+}
+
+void
+_cogl_pipeline_node_unparent_real (CoglNode *node)
+{
+  CoglNode *parent = node->parent;
+
+  if (parent == NULL)
+    return;
+
+  g_return_if_fail (!COGL_LIST_EMPTY (&parent->children));
+
+  COGL_LIST_REMOVE (node, list_node);
+
+  if (node->has_parent_reference)
+    cogl_object_unref (parent);
+
+  node->parent = NULL;
+}
+
+void
+_cogl_pipeline_node_foreach_child (CoglNode *node,
+                                   CoglNodeChildCallback callback,
+                                   void *user_data)
+{
+  CoglNode *child, *next;
+
+  COGL_LIST_FOREACH_SAFE (child, &node->children, list_node, next)
+    callback (child, user_data);
+}
+
+
diff --git a/cogl/cogl-pipeline-debug.c b/cogl/cogl-pipeline-debug.c
new file mode 100644
index 0000000..0dd7c6f
--- /dev/null
+++ b/cogl/cogl-pipeline-debug.c
@@ -0,0 +1,284 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2008,2009,2010,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
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-context-private.h"
+#include "cogl-pipeline-private.h"
+#include "cogl-pipeline-layer-private.h"
+#include "cogl-node-private.h"
+
+#include <glib.h>
+
+typedef struct
+{
+  int parent_id;
+  int *node_id_ptr;
+  GString *graph;
+  int indent;
+} PrintDebugState;
+
+static gboolean
+dump_layer_cb (CoglNode *node, void *user_data)
+{
+  CoglPipelineLayer *layer = COGL_PIPELINE_LAYER (node);
+  PrintDebugState *state = user_data;
+  int layer_id = *state->node_id_ptr;
+  PrintDebugState state_out;
+  GString *changes_label;
+  gboolean changes = FALSE;
+
+  if (state->parent_id >= 0)
+    g_string_append_printf (state->graph, "%*slayer%p -> layer%p;\n",
+                            state->indent, "",
+                            layer->_parent.parent,
+                            layer);
+
+  g_string_append_printf (state->graph,
+                          "%*slayer%p [label=\"layer=0x%p\\n"
+                          "ref count=%d\" "
+                          "color=\"blue\"];\n",
+                          state->indent, "",
+                          layer,
+                          layer,
+                          COGL_OBJECT (layer)->ref_count);
+
+  changes_label = g_string_new ("");
+  g_string_append_printf (changes_label,
+                          "%*slayer%p -> layer_state%d [weight=100];\n"
+                          "%*slayer_state%d [shape=box label=\"",
+                          state->indent, "",
+                          layer,
+                          layer_id,
+                          state->indent, "",
+                          layer_id);
+
+  if (layer->differences & COGL_PIPELINE_LAYER_STATE_UNIT)
+    {
+      changes = TRUE;
+      g_string_append_printf (changes_label,
+                              "\\lunit=%u\\n",
+                              layer->unit_index);
+    }
+
+  if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
+    {
+      changes = TRUE;
+      g_string_append_printf (changes_label,
+                              "\\ltexture=%p\\n",
+                              layer->texture);
+    }
+
+  if (changes)
+    {
+      g_string_append_printf (changes_label, "\"];\n");
+      g_string_append (state->graph, changes_label->str);
+      g_string_free (changes_label, TRUE);
+    }
+
+  state_out.parent_id = layer_id;
+
+  state_out.node_id_ptr = state->node_id_ptr;
+  (*state_out.node_id_ptr)++;
+
+  state_out.graph = state->graph;
+  state_out.indent = state->indent + 2;
+
+  _cogl_pipeline_node_foreach_child (COGL_NODE (layer),
+                                     dump_layer_cb,
+                                     &state_out);
+
+  return TRUE;
+}
+
+static gboolean
+dump_layer_ref_cb (CoglPipelineLayer *layer, void *data)
+{
+  PrintDebugState *state = data;
+  int pipeline_id = *state->node_id_ptr;
+
+  g_string_append_printf (state->graph,
+                          "%*spipeline_state%d -> layer%p;\n",
+                          state->indent, "",
+                          pipeline_id,
+                          layer);
+
+  return TRUE;
+}
+
+static gboolean
+dump_pipeline_cb (CoglNode *node, void *user_data)
+{
+  CoglPipeline *pipeline = COGL_PIPELINE (node);
+  PrintDebugState *state = user_data;
+  int pipeline_id = *state->node_id_ptr;
+  PrintDebugState state_out;
+  GString *changes_label;
+  gboolean changes = FALSE;
+  gboolean layers = FALSE;
+
+  if (state->parent_id >= 0)
+    g_string_append_printf (state->graph, "%*spipeline%d -> pipeline%d;\n",
+                            state->indent, "",
+                            state->parent_id,
+                            pipeline_id);
+
+  g_string_append_printf (state->graph,
+                          "%*spipeline%d [label=\"pipeline=0x%p\\n"
+                          "ref count=%d\\n"
+                          "breadcrumb=\\\"%s\\\"\" color=\"red\"];\n",
+                          state->indent, "",
+                          pipeline_id,
+                          pipeline,
+                          COGL_OBJECT (pipeline)->ref_count,
+                          pipeline->has_static_breadcrumb ?
+                          pipeline->static_breadcrumb : "NULL");
+
+  changes_label = g_string_new ("");
+  g_string_append_printf (changes_label,
+                          "%*spipeline%d -> pipeline_state%d [weight=100];\n"
+                          "%*spipeline_state%d [shape=box label=\"",
+                          state->indent, "",
+                          pipeline_id,
+                          pipeline_id,
+                          state->indent, "",
+                          pipeline_id);
+
+
+  if (pipeline->differences & COGL_PIPELINE_STATE_COLOR)
+    {
+      changes = TRUE;
+      g_string_append_printf (changes_label,
+                              "\\lcolor=0x%02X%02X%02X%02X\\n",
+                              cogl_color_get_red_byte (&pipeline->color),
+                              cogl_color_get_green_byte (&pipeline->color),
+                              cogl_color_get_blue_byte (&pipeline->color),
+                              cogl_color_get_alpha_byte (&pipeline->color));
+    }
+
+  if (pipeline->differences & COGL_PIPELINE_STATE_BLEND)
+    {
+      const char *blend_enable_name;
+
+      changes = TRUE;
+
+      switch (pipeline->blend_enable)
+        {
+        case COGL_PIPELINE_BLEND_ENABLE_AUTOMATIC:
+          blend_enable_name = "AUTO";
+          break;
+        case COGL_PIPELINE_BLEND_ENABLE_ENABLED:
+          blend_enable_name = "ENABLED";
+          break;
+        case COGL_PIPELINE_BLEND_ENABLE_DISABLED:
+          blend_enable_name = "DISABLED";
+          break;
+        default:
+          blend_enable_name = "UNKNOWN";
+        }
+      g_string_append_printf (changes_label,
+                              "\\lblend=%s\\n",
+                              blend_enable_name);
+    }
+
+  if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
+    {
+      changes = TRUE;
+      layers = TRUE;
+      g_string_append_printf (changes_label, "\\ln_layers=%d\\n",
+                              pipeline->n_layers);
+    }
+
+  if (changes)
+    {
+      g_string_append_printf (changes_label, "\"];\n");
+      g_string_append (state->graph, changes_label->str);
+      g_string_free (changes_label, TRUE);
+    }
+
+  if (layers)
+    {
+      g_list_foreach (pipeline->layer_differences,
+                      (GFunc)dump_layer_ref_cb,
+                      state);
+    }
+
+  state_out.parent_id = pipeline_id;
+
+  state_out.node_id_ptr = state->node_id_ptr;
+  (*state_out.node_id_ptr)++;
+
+  state_out.graph = state->graph;
+  state_out.indent = state->indent + 2;
+
+  _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
+                                     dump_pipeline_cb,
+                                     &state_out);
+
+  return TRUE;
+}
+
+void
+_cogl_debug_dump_pipelines_dot_file (const char *filename)
+{
+  GString *graph;
+  PrintDebugState layer_state;
+  PrintDebugState pipeline_state;
+  int layer_id = 0;
+  int pipeline_id = 0;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  if (!ctx->default_pipeline)
+    return;
+
+  graph = g_string_new ("");
+  g_string_append_printf (graph, "digraph {\n");
+
+  layer_state.graph = graph;
+  layer_state.parent_id = -1;
+  layer_state.node_id_ptr = &layer_id;
+  layer_state.indent = 0;
+  dump_layer_cb (ctx->default_layer_0, &layer_state);
+
+  pipeline_state.graph = graph;
+  pipeline_state.parent_id = -1;
+  pipeline_state.node_id_ptr = &pipeline_id;
+  pipeline_state.indent = 0;
+  dump_pipeline_cb (ctx->default_pipeline, &pipeline_state);
+
+  g_string_append_printf (graph, "}\n");
+
+  if (filename)
+    g_file_set_contents (filename, graph->str, -1, NULL);
+  else
+    g_print ("%s", graph->str);
+
+  g_string_free (graph, TRUE);
+}
diff --git a/cogl/cogl-pipeline-fragend-arbfp.c b/cogl/cogl-pipeline-fragend-arbfp.c
index 8c25b36..e121e68 100644
--- a/cogl/cogl-pipeline-fragend-arbfp.c
+++ b/cogl/cogl-pipeline-fragend-arbfp.c
@@ -31,6 +31,7 @@
 
 #include "cogl-debug.h"
 #include "cogl-pipeline-private.h"
+#include "cogl-pipeline-layer-private.h"
 
 #ifdef COGL_PIPELINE_FRAGEND_ARBFP
 
@@ -709,7 +710,7 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
   if (!shader_state->source)
     return TRUE;
 
-  if (!_cogl_pipeline_need_texture_combine_separate (combine_authority))
+  if (!_cogl_pipeline_layer_needs_combine_separate (combine_authority))
     {
       append_masked_combine (pipeline,
                              layer,
diff --git a/cogl/cogl-pipeline-fragend-glsl.c b/cogl/cogl-pipeline-fragend-glsl.c
index a7a21e3..a41e4ba 100644
--- a/cogl/cogl-pipeline-fragend-glsl.c
+++ b/cogl/cogl-pipeline-fragend-glsl.c
@@ -33,6 +33,7 @@
 #include <string.h>
 
 #include "cogl-pipeline-private.h"
+#include "cogl-pipeline-layer-private.h"
 #include "cogl-shader-private.h"
 #include "cogl-blend-string.h"
 
@@ -730,7 +731,7 @@ ensure_layer_generated (CoglPipeline *pipeline,
                           "  vec4 layer%i;\n",
                           layer_index);
 
-  if (!_cogl_pipeline_need_texture_combine_separate (combine_authority) ||
+  if (!_cogl_pipeline_layer_needs_combine_separate (combine_authority) ||
       /* GL_DOT3_RGBA Is a bit weird as a GL_COMBINE_RGB function
        * since if you use it, it overrides your ALPHA function...
        */
diff --git a/cogl/cogl-pipeline-layer-private.h b/cogl/cogl-pipeline-layer-private.h
new file mode 100644
index 0000000..5df32c4
--- /dev/null
+++ b/cogl/cogl-pipeline-layer-private.h
@@ -0,0 +1,380 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2008,2009,2010,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
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert linux intel com>
+ */
+
+#ifndef __COGL_PIPELINE_LAYER_PRIVATE_H
+#define __COGL_PIPELINE_LAYER_PRIVATE_H
+
+#include "cogl-pipeline.h"
+#include "cogl-node-private.h"
+#include "cogl-texture.h"
+#include "cogl-matrix.h"
+#include "cogl-pipeline-layer-state.h"
+#include "cogl-internal.h"
+
+#include <glib.h>
+
+/* This isn't defined in the GLES headers */
+#ifndef GL_CLAMP_TO_BORDER
+#define GL_CLAMP_TO_BORDER 0x812d
+#endif
+
+typedef struct _CoglPipelineLayer     CoglPipelineLayer;
+#define COGL_PIPELINE_LAYER(OBJECT) ((CoglPipelineLayer *)OBJECT)
+
+/* GL_ALWAYS is just used here as a value that is known not to clash
+ * with any valid GL wrap modes.
+ *
+ * XXX: keep the values in sync with the CoglPipelineWrapMode enum
+ * so no conversion is actually needed.
+ */
+typedef enum _CoglPipelineWrapModeInternal
+{
+  COGL_PIPELINE_WRAP_MODE_INTERNAL_REPEAT = GL_REPEAT,
+  COGL_PIPELINE_WRAP_MODE_INTERNAL_CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE,
+  COGL_PIPELINE_WRAP_MODE_INTERNAL_CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER,
+  COGL_PIPELINE_WRAP_MODE_INTERNAL_AUTOMATIC = GL_ALWAYS
+} CoglPipelineWrapModeInternal;
+
+/* XXX: should I rename these as
+ * COGL_PIPELINE_LAYER_STATE_INDEX_XYZ... ?
+ */
+typedef enum
+{
+  /* sparse state */
+  COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
+  COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX,
+  COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
+  COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
+  COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
+  COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
+  COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
+  COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
+  COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
+
+  /* note: layers don't currently have any non-sparse state */
+
+  COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT,
+  COGL_PIPELINE_LAYER_STATE_COUNT = COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT
+} CoglPipelineLayerStateIndex;
+
+/* XXX: If you add or remove state groups here you may need to update
+ * some of the state masks following this enum too!
+ *
+ * FIXME: perhaps it would be better to rename this enum to
+ * CoglPipelineLayerStateGroup to better convey the fact that a single
+ * enum here can map to multiple properties.
+ */
+typedef enum
+{
+  COGL_PIPELINE_LAYER_STATE_UNIT =
+    1L<<COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
+  COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET =
+    1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX,
+  COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA =
+    1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
+  COGL_PIPELINE_LAYER_STATE_FILTERS =
+    1L<<COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
+  COGL_PIPELINE_LAYER_STATE_WRAP_MODES =
+    1L<<COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
+
+  COGL_PIPELINE_LAYER_STATE_COMBINE =
+    1L<<COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
+  COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT =
+    1L<<COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
+  COGL_PIPELINE_LAYER_STATE_USER_MATRIX =
+    1L<<COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
+
+  COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS =
+    1L<<COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
+
+  /* COGL_PIPELINE_LAYER_STATE_TEXTURE_INTERN   = 1L<<8, */
+
+} CoglPipelineLayerState;
+
+/*
+ * Various special masks that tag state-groups in different ways...
+ */
+
+#define COGL_PIPELINE_LAYER_STATE_ALL \
+  ((1L<<COGL_PIPELINE_LAYER_STATE_COUNT) - 1)
+
+#define COGL_PIPELINE_LAYER_STATE_ALL_SPARSE \
+  COGL_PIPELINE_LAYER_STATE_ALL
+
+#define COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE \
+  (COGL_PIPELINE_LAYER_STATE_COMBINE | \
+   COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT | \
+   COGL_PIPELINE_LAYER_STATE_USER_MATRIX | \
+   COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS)
+
+#define COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY \
+  (COGL_PIPELINE_LAYER_STATE_FILTERS | \
+   COGL_PIPELINE_LAYER_STATE_WRAP_MODES | \
+   COGL_PIPELINE_LAYER_STATE_COMBINE)
+
+#define COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN 0
+
+typedef enum
+{
+  /* These are the same values as GL */
+  COGL_PIPELINE_COMBINE_FUNC_ADD         = 0x0104,
+  COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED  = 0x8574,
+  COGL_PIPELINE_COMBINE_FUNC_SUBTRACT    = 0x84E7,
+  COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE = 0x8575,
+  COGL_PIPELINE_COMBINE_FUNC_REPLACE     = 0x1E01,
+  COGL_PIPELINE_COMBINE_FUNC_MODULATE    = 0x2100,
+  COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB    = 0x86AE,
+  COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA   = 0x86AF
+} CoglPipelineCombineFunc;
+
+typedef enum
+{
+  /* These are the same values as GL */
+  COGL_PIPELINE_COMBINE_SOURCE_TEXTURE       = 0x1702,
+  COGL_PIPELINE_COMBINE_SOURCE_CONSTANT      = 0x8576,
+  COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR = 0x8577,
+  COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS      = 0x8578,
+  COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0      = 0x84C0
+} CoglPipelineCombineSource;
+
+typedef enum
+{
+  /* These are the same values as GL */
+  COGL_PIPELINE_COMBINE_OP_SRC_COLOR           = 0x0300,
+  COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR = 0x0301,
+  COGL_PIPELINE_COMBINE_OP_SRC_ALPHA           = 0x0302,
+  COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA = 0x0303
+} CoglPipelineCombineOp;
+
+typedef struct
+{
+  /* The texture combine state determines how the color of individual
+   * texture fragments are calculated. */
+  CoglPipelineCombineFunc texture_combine_rgb_func;
+  CoglPipelineCombineSource texture_combine_rgb_src[3];
+  CoglPipelineCombineOp texture_combine_rgb_op[3];
+
+  CoglPipelineCombineFunc texture_combine_alpha_func;
+  CoglPipelineCombineSource texture_combine_alpha_src[3];
+  CoglPipelineCombineOp texture_combine_alpha_op[3];
+
+  float texture_combine_constant[4];
+
+  /* The texture matrix dscribes how to transform texture coordinates */
+  CoglMatrix matrix;
+
+  gboolean point_sprite_coords;
+
+} CoglPipelineLayerBigState;
+
+struct _CoglPipelineLayer
+{
+  /* XXX: Please think twice about adding members that *have* be
+   * initialized during a _cogl_pipeline_layer_copy. We are aiming
+   * to have copies be as cheap as possible and copies may be
+   * done by the primitives APIs which means they may happen
+   * in performance critical code paths.
+   *
+   * XXX: If you are extending the state we track please consider if
+   * the state is expected to vary frequently across many pipelines or
+   * if the state can be shared among many derived pipelines instead.
+   * This will determine if the state should be added directly to this
+   * structure which will increase the memory overhead for *all*
+   * layers or if instead it can go under ->big_state.
+   */
+
+  /* Layers represent their state in a tree structure where some of
+   * the state relating to a given pipeline or layer may actually be
+   * owned by one if is ancestors in the tree. We have a common data
+   * type to track the tree heirachy so we can share code... */
+  CoglNode _parent;
+
+  /* Some layers have a pipeline owner, which is to say that the layer
+   * is referenced in that pipelines->layer_differences list.  A layer
+   * doesn't always have an owner and may simply be an ancestor for
+   * other layers that keeps track of some shared state. */
+  CoglPipeline      *owner;
+
+  /* The lowest index is blended first then others on top */
+  int	             index;
+
+  /* A mask of which state groups are different in this layer
+   * in comparison to its parent. */
+  unsigned long             differences;
+
+  /* Common differences
+   *
+   * As a basic way to reduce memory usage we divide the layer
+   * state into two groups; the minimal state modified in 90% of
+   * all layers and the rest, so that the second group can
+   * be allocated dynamically when required.
+   */
+
+  /* Each layer is directly associated with a single texture unit */
+  int                        unit_index;
+
+  /* The texture for this layer, or NULL for an empty
+   * layer */
+  CoglTexture               *texture;
+  GLenum                     target;
+
+  CoglPipelineFilter         mag_filter;
+  CoglPipelineFilter         min_filter;
+
+  CoglPipelineWrapModeInternal wrap_mode_s;
+  CoglPipelineWrapModeInternal wrap_mode_t;
+  CoglPipelineWrapModeInternal wrap_mode_p;
+
+  /* Infrequent differences aren't currently tracked in
+   * a separate, dynamically allocated structure as they are
+   * for pipelines... */
+  CoglPipelineLayerBigState *big_state;
+
+  /* bitfields */
+
+  /* Determines if layer->big_state is valid */
+  unsigned int          has_big_state:1;
+
+};
+
+typedef gboolean
+(*CoglPipelineLayerStateComparitor) (CoglPipelineLayer *authority0,
+                                     CoglPipelineLayer *authority1);
+
+
+
+void
+_cogl_pipeline_init_default_layers (void);
+
+static inline CoglPipelineLayer *
+_cogl_pipeline_layer_get_parent (CoglPipelineLayer *layer)
+{
+  CoglNode *parent_node = COGL_NODE (layer)->parent;
+  return COGL_PIPELINE_LAYER (parent_node);
+}
+
+CoglPipelineLayer *
+_cogl_pipeline_layer_copy (CoglPipelineLayer *layer);
+
+void
+_cogl_pipeline_layer_resolve_authorities (CoglPipelineLayer *layer,
+                                          unsigned long differences,
+                                          CoglPipelineLayer **authorities);
+
+gboolean
+_cogl_pipeline_layer_equal (CoglPipelineLayer *layer0,
+                            CoglPipelineLayer *layer1,
+                            unsigned long differences_mask,
+                            CoglPipelineEvalFlags flags);
+
+CoglPipelineLayer *
+_cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
+                                        CoglPipelineLayer *layer,
+                                        CoglPipelineLayerState change);
+
+void
+_cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer);
+
+gboolean
+_cogl_pipeline_layer_has_alpha (CoglPipelineLayer *layer);
+
+gboolean
+_cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
+                                      int layer_index);
+
+/*
+ * Calls the pre_paint method on the layer texture if there is
+ * one. This will determine whether mipmaps are needed based on the
+ * filter settings.
+ */
+void
+_cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layerr);
+
+void
+_cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer,
+                                     CoglPipelineWrapModeInternal *wrap_mode_s,
+                                     CoglPipelineWrapModeInternal *wrap_mode_t,
+                                     CoglPipelineWrapModeInternal *wrap_mode_r);
+
+void
+_cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer,
+                                  CoglPipelineFilter *min_filter,
+                                  CoglPipelineFilter *mag_filter);
+
+void
+_cogl_pipeline_get_layer_filters (CoglPipeline *pipeline,
+                                  int layer_index,
+                                  CoglPipelineFilter *min_filter,
+                                  CoglPipelineFilter *mag_filter);
+
+typedef enum {
+  COGL_PIPELINE_LAYER_TYPE_TEXTURE
+} CoglPipelineLayerType;
+
+CoglPipelineLayerType
+_cogl_pipeline_layer_get_type (CoglPipelineLayer *layer);
+
+CoglTexture *
+_cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer);
+
+CoglTexture *
+_cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer);
+
+CoglPipelineFilter
+_cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer);
+
+CoglPipelineFilter
+_cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer);
+
+CoglPipelineWrapMode
+_cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer);
+
+CoglPipelineWrapMode
+_cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer);
+
+CoglPipelineWrapMode
+_cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer);
+
+unsigned long
+_cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
+                                          CoglPipelineLayer *layer1);
+
+CoglPipelineLayer *
+_cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer,
+                                    unsigned long difference);
+
+CoglTexture *
+_cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer);
+
+int
+_cogl_pipeline_layer_get_unit_index (CoglPipelineLayer *layer);
+
+gboolean
+_cogl_pipeline_layer_needs_combine_separate
+                                       (CoglPipelineLayer *combine_authority);
+
+#endif /* __COGL_PIPELINE_LAYER_PRIVATE_H */
diff --git a/cogl/cogl-pipeline-layer-state-private.h b/cogl/cogl-pipeline-layer-state-private.h
index 5c0aa64..b840fc9 100644
--- a/cogl/cogl-pipeline-layer-state-private.h
+++ b/cogl/cogl-pipeline-layer-state-private.h
@@ -28,11 +28,22 @@
 #ifndef __COGL_PIPELINE_LAYER_STATE_PRIVATE_H
 #define __COGL_PIPELINE_LAYER_STATE_PRIVATE_H
 
+#include "cogl-pipeline-layer-state.h"
+#include "cogl-pipeline-private.h"
+
 CoglPipelineLayer *
 _cogl_pipeline_set_layer_unit (CoglPipeline *required_owner,
                                CoglPipelineLayer *layer,
                                int unit_index);
 
+CoglPipelineFilter
+_cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline,
+                                     int layer_index);
+
+CoglPipelineFilter
+_cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline,
+                                     int layer_index);
+
 gboolean
 _cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0,
                                            CoglPipelineLayer *authority1,
diff --git a/cogl/cogl-pipeline-layer.c b/cogl/cogl-pipeline-layer.c
new file mode 100644
index 0000000..963412a
--- /dev/null
+++ b/cogl/cogl-pipeline-layer.c
@@ -0,0 +1,798 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2008,2009,2010 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-pipeline.h"
+#include "cogl-pipeline-layer-private.h"
+#include "cogl-pipeline-layer-state-private.h"
+#include "cogl-pipeline-layer-state.h"
+#include "cogl-node-private.h"
+#include "cogl-pipeline-opengl-private.h"
+#include "cogl-context-private.h"
+
+static void
+_cogl_pipeline_layer_free (CoglPipelineLayer *layer);
+
+/* This type was made deprecated before the cogl_is_pipeline_layer
+   function was ever exposed in the public headers so there's no need
+   to make the cogl_is_pipeline_layer function public. We use INTERNAL
+   so that the cogl_is_* function won't get defined */
+COGL_OBJECT_INTERNAL_DEFINE (PipelineLayer, pipeline_layer);
+
+
+CoglPipelineLayer *
+_cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer,
+                                    unsigned long difference)
+{
+  CoglPipelineLayer *authority = layer;
+  while (!(authority->differences & difference))
+    authority = _cogl_pipeline_layer_get_parent (authority);
+  return authority;
+}
+
+int
+_cogl_pipeline_layer_get_unit_index (CoglPipelineLayer *layer)
+{
+  CoglPipelineLayer *authority =
+    _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_UNIT);
+  return authority->unit_index;
+}
+
+gboolean
+_cogl_pipeline_layer_has_alpha (CoglPipelineLayer *layer)
+{
+  CoglPipelineLayer *combine_authority =
+    _cogl_pipeline_layer_get_authority (layer,
+                                        COGL_PIPELINE_LAYER_STATE_COMBINE);
+  CoglPipelineLayerBigState *big_state = combine_authority->big_state;
+  CoglPipelineLayer *tex_authority;
+
+  /* has_alpha maintains the alpha status for the GL_PREVIOUS layer */
+
+  /* For anything but the default texture combine we currently just
+   * assume it may result in an alpha value < 1
+   *
+   * FIXME: we could do better than this. */
+  if (big_state->texture_combine_alpha_func !=
+      COGL_PIPELINE_COMBINE_FUNC_MODULATE ||
+      big_state->texture_combine_alpha_src[0] !=
+      COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS ||
+      big_state->texture_combine_alpha_op[0] !=
+      COGL_PIPELINE_COMBINE_OP_SRC_ALPHA ||
+      big_state->texture_combine_alpha_src[1] !=
+      COGL_PIPELINE_COMBINE_SOURCE_TEXTURE ||
+      big_state->texture_combine_alpha_op[1] !=
+      COGL_PIPELINE_COMBINE_OP_SRC_ALPHA)
+    {
+      return TRUE;
+    }
+
+  /* NB: A layer may have a combine mode set on it but not yet
+   * have an associated texture which would mean we'd fallback
+   * to the default texture which doesn't have an alpha component
+   */
+  tex_authority =
+    _cogl_pipeline_layer_get_authority (layer,
+                                        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
+  if (tex_authority->texture &&
+      cogl_texture_get_format (tex_authority->texture) & COGL_A_BIT)
+    {
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+unsigned int
+_cogl_get_n_args_for_combine_func (CoglPipelineCombineFunc func)
+{
+  switch (func)
+    {
+    case COGL_PIPELINE_COMBINE_FUNC_REPLACE:
+      return 1;
+    case COGL_PIPELINE_COMBINE_FUNC_MODULATE:
+    case COGL_PIPELINE_COMBINE_FUNC_ADD:
+    case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED:
+    case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT:
+    case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB:
+    case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA:
+      return 2;
+    case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE:
+      return 3;
+    }
+  return 0;
+}
+
+static void
+_cogl_pipeline_layer_init_multi_property_sparse_state (
+                                                  CoglPipelineLayer *layer,
+                                                  CoglPipelineLayerState change)
+{
+  CoglPipelineLayer *authority;
+
+  /* Nothing to initialize in these cases since they are all comprised
+   * of one member which we expect to immediately be overwritten. */
+  if (!(change & COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY))
+    return;
+
+  authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+  switch (change)
+    {
+    /* XXX: avoid using a default: label so we get a warning if we
+     * don't explicitly handle a newly defined state-group here. */
+    case COGL_PIPELINE_LAYER_STATE_UNIT:
+    case COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET:
+    case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA:
+    case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS:
+    case COGL_PIPELINE_LAYER_STATE_USER_MATRIX:
+    case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT:
+      g_return_if_reached ();
+
+    /* XXX: technically we could probably even consider these as
+     * single property state-groups from the pov that currently the
+     * corresponding property setters always update all of the values
+     * at the same time. */
+    case COGL_PIPELINE_LAYER_STATE_FILTERS:
+      layer->min_filter = authority->min_filter;
+      layer->mag_filter = authority->mag_filter;
+      break;
+    case COGL_PIPELINE_LAYER_STATE_WRAP_MODES:
+      layer->wrap_mode_s = authority->wrap_mode_s;
+      layer->wrap_mode_t = authority->wrap_mode_t;
+      layer->wrap_mode_p = authority->wrap_mode_p;
+      break;
+    case COGL_PIPELINE_LAYER_STATE_COMBINE:
+      {
+        int n_args;
+        int i;
+        CoglPipelineLayerBigState *src_big_state = authority->big_state;
+        CoglPipelineLayerBigState *dest_big_state = layer->big_state;
+        GLint func = src_big_state->texture_combine_rgb_func;
+
+        dest_big_state->texture_combine_rgb_func = func;
+        n_args = _cogl_get_n_args_for_combine_func (func);
+        for (i = 0; i < n_args; i++)
+          {
+            dest_big_state->texture_combine_rgb_src[i] =
+              src_big_state->texture_combine_rgb_src[i];
+            dest_big_state->texture_combine_rgb_op[i] =
+              src_big_state->texture_combine_rgb_op[i];
+          }
+
+        func = src_big_state->texture_combine_alpha_func;
+        dest_big_state->texture_combine_alpha_func = func;
+        n_args = _cogl_get_n_args_for_combine_func (func);
+        for (i = 0; i < n_args; i++)
+          {
+            dest_big_state->texture_combine_alpha_src[i] =
+              src_big_state->texture_combine_alpha_src[i];
+            dest_big_state->texture_combine_alpha_op[i] =
+              src_big_state->texture_combine_alpha_op[i];
+          }
+        break;
+      }
+    }
+}
+
+/* NB: If a layer has descendants we can't modify the layer
+ * NB: If the layer is owned and the owner has descendants we can't
+ *     modify the layer.
+ *
+ * This function will allocate a new derived layer if you are trying
+ * to change the state of a layer with dependants (as described above)
+ * so you must always check the return value.
+ *
+ * If a new layer is returned it will be owned by required_owner.
+ * (NB: a layer is always modified with respect to a pipeline - the
+ *  "required_owner")
+ *
+ * required_owner can only by NULL for new, currently unowned layers
+ * with no dependants.
+ */
+CoglPipelineLayer *
+_cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
+                                        CoglPipelineLayer *layer,
+                                        CoglPipelineLayerState change)
+{
+  CoglTextureUnit *unit;
+
+  /* Identify the case where the layer is new with no owner or
+   * dependants and so we don't need to do anything. */
+  if (COGL_LIST_EMPTY (&COGL_NODE (layer)->children) &&
+      layer->owner == NULL)
+    goto init_layer_state;
+
+  /* We only allow a NULL required_owner for new layers */
+  g_return_val_if_fail (required_owner != NULL, layer);
+
+  /* Chain up:
+   * A modification of a layer is indirectly also a modification of
+   * its owner so first make sure to flush the journal of any
+   * references to the current owner state and if necessary perform
+   * a copy-on-write for the required_owner if it has dependants.
+   */
+  _cogl_pipeline_pre_change_notify (required_owner,
+                                    COGL_PIPELINE_STATE_LAYERS,
+                                    NULL,
+                                    TRUE);
+
+  /* Unlike pipelines; layers are simply considered immutable once
+   * they have dependants - either direct children, or another
+   * pipeline as an owner.
+   */
+  if (!COGL_LIST_EMPTY (&COGL_NODE (layer)->children) ||
+      layer->owner != required_owner)
+    {
+      CoglPipelineLayer *new = _cogl_pipeline_layer_copy (layer);
+      if (layer->owner == required_owner)
+        _cogl_pipeline_remove_layer_difference (required_owner, layer, FALSE);
+      _cogl_pipeline_add_layer_difference (required_owner, new, FALSE);
+      cogl_object_unref (new);
+      layer = new;
+      goto init_layer_state;
+    }
+
+  /* Note: At this point we know there is only one pipeline dependant on
+   * this layer (required_owner), and there are no other layers
+   * dependant on this layer so it's ok to modify it. */
+
+  _cogl_pipeline_fragend_layer_change_notify (required_owner, layer, change);
+  _cogl_pipeline_vertend_layer_change_notify (required_owner, layer, change);
+  _cogl_pipeline_progend_layer_change_notify (required_owner, layer, change);
+
+  /* If the layer being changed is the same as the last layer we
+   * flushed to the corresponding texture unit then we keep a track of
+   * the changes so we can try to minimize redundant OpenGL calls if
+   * the same layer is flushed again.
+   */
+  unit = _cogl_get_texture_unit (_cogl_pipeline_layer_get_unit_index (layer));
+  if (unit->layer == layer)
+    unit->layer_changes_since_flush |= change;
+
+init_layer_state:
+
+  if (required_owner)
+    required_owner->age++;
+
+  if (change & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE &&
+      !layer->has_big_state)
+    {
+      layer->big_state = g_slice_new (CoglPipelineLayerBigState);
+      layer->has_big_state = TRUE;
+    }
+
+  /* Note: conceptually we have just been notified that a single
+   * property value is about to change, but since some state-groups
+   * contain multiple properties and 'layer' is about to take over
+   * being the authority for the property's corresponding state-group
+   * we need to maintain the integrity of the other property values
+   * too.
+   *
+   * To ensure this we handle multi-property state-groups by copying
+   * all the values from the old-authority to the new...
+   *
+   * We don't have to worry about non-sparse property groups since
+   * we never take over being an authority for such properties so
+   * they automatically maintain integrity.
+   */
+  if (change & COGL_PIPELINE_LAYER_STATE_ALL_SPARSE &&
+      !(layer->differences & change))
+    {
+      _cogl_pipeline_layer_init_multi_property_sparse_state (layer, change);
+      layer->differences |= change;
+    }
+
+  return layer;
+}
+
+static void
+_cogl_pipeline_layer_unparent (CoglNode *layer)
+{
+  /* Chain up */
+  _cogl_pipeline_node_unparent_real (layer);
+}
+
+static void
+_cogl_pipeline_layer_set_parent (CoglPipelineLayer *layer,
+                                 CoglPipelineLayer *parent)
+{
+  /* Chain up */
+  _cogl_pipeline_node_set_parent_real (COGL_NODE (layer),
+                                       COGL_NODE (parent),
+                                       _cogl_pipeline_layer_unparent,
+                                       TRUE);
+}
+
+CoglPipelineLayer *
+_cogl_pipeline_layer_copy (CoglPipelineLayer *src)
+{
+  CoglPipelineLayer *layer = g_slice_new (CoglPipelineLayer);
+
+  _cogl_pipeline_node_init (COGL_NODE (layer));
+
+  layer->owner = NULL;
+  layer->index = src->index;
+  layer->differences = 0;
+  layer->has_big_state = FALSE;
+
+  _cogl_pipeline_layer_set_parent (layer, src);
+
+  return _cogl_pipeline_layer_object_new (layer);
+}
+
+/* XXX: This is duplicated logic; the same as for
+ * _cogl_pipeline_prune_redundant_ancestry it would be nice to find a
+ * way to consolidate these functions! */
+void
+_cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer)
+{
+  CoglPipelineLayer *new_parent = _cogl_pipeline_layer_get_parent (layer);
+
+  /* walk up past ancestors that are now redundant and potentially
+   * reparent the layer. */
+  while (_cogl_pipeline_layer_get_parent (new_parent) &&
+         (new_parent->differences | layer->differences) ==
+         layer->differences)
+    new_parent = _cogl_pipeline_layer_get_parent (new_parent);
+
+  _cogl_pipeline_layer_set_parent (layer, new_parent);
+}
+
+/* Determine the mask of differences between two layers.
+ *
+ * XXX: If layers and pipelines could both be cast to a common Tree
+ * type of some kind then we could have a unified
+ * compare_differences() function.
+ */
+unsigned long
+_cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
+                                          CoglPipelineLayer *layer1)
+{
+  CoglPipelineLayer *node0;
+  CoglPipelineLayer *node1;
+  int len0;
+  int len1;
+  int len0_index;
+  int len1_index;
+  int count;
+  int i;
+  CoglPipelineLayer *common_ancestor = NULL;
+  unsigned long layers_difference = 0;
+
+  _COGL_GET_CONTEXT (ctx, 0);
+
+  /* Algorithm:
+   *
+   * 1) Walk the ancestors of each layer to the root node, adding a
+   *    pointer to each ancester node to two GArrays:
+   *    ctx->pipeline0_nodes, and ctx->pipeline1_nodes.
+   *
+   * 2) Compare the arrays to find the nodes where they stop to
+   *    differ.
+   *
+   * 3) For each array now iterate from index 0 to the first node of
+   *    difference ORing that nodes ->difference mask into the final
+   *    pipeline_differences mask.
+   */
+
+  g_array_set_size (ctx->pipeline0_nodes, 0);
+  g_array_set_size (ctx->pipeline1_nodes, 0);
+  for (node0 = layer0; node0; node0 = _cogl_pipeline_layer_get_parent (node0))
+    g_array_append_vals (ctx->pipeline0_nodes, &node0, 1);
+  for (node1 = layer1; node1; node1 = _cogl_pipeline_layer_get_parent (node1))
+    g_array_append_vals (ctx->pipeline1_nodes, &node1, 1);
+
+  len0 = ctx->pipeline0_nodes->len;
+  len1 = ctx->pipeline1_nodes->len;
+  /* There's no point looking at the last entries since we know both
+   * layers must have the same default layer as their root node. */
+  len0_index = len0 - 2;
+  len1_index = len1 - 2;
+  count = MIN (len0, len1) - 1;
+  for (i = 0; i < count; i++)
+    {
+      node0 = g_array_index (ctx->pipeline0_nodes,
+                             CoglPipelineLayer *, len0_index--);
+      node1 = g_array_index (ctx->pipeline1_nodes,
+                             CoglPipelineLayer *, len1_index--);
+      if (node0 != node1)
+        {
+          common_ancestor = _cogl_pipeline_layer_get_parent (node0);
+          break;
+        }
+    }
+
+  /* If we didn't already find the first the common_ancestor ancestor
+   * that's because one pipeline is a direct descendant of the other
+   * and in this case the first common ancestor is the last node we
+   * looked at. */
+  if (!common_ancestor)
+    common_ancestor = node0;
+
+  count = len0 - 1;
+  for (i = 0; i < count; i++)
+    {
+      node0 = g_array_index (ctx->pipeline0_nodes, CoglPipelineLayer *, i);
+      if (node0 == common_ancestor)
+        break;
+      layers_difference |= node0->differences;
+    }
+
+  count = len1 - 1;
+  for (i = 0; i < count; i++)
+    {
+      node1 = g_array_index (ctx->pipeline1_nodes, CoglPipelineLayer *, i);
+      if (node1 == common_ancestor)
+        break;
+      layers_difference |= node1->differences;
+    }
+
+  return layers_difference;
+}
+
+static gboolean
+layer_state_equal (CoglPipelineLayerStateIndex state_index,
+                   CoglPipelineLayer **authorities0,
+                   CoglPipelineLayer **authorities1,
+                   CoglPipelineLayerStateComparitor comparitor)
+{
+  return comparitor (authorities0[state_index], authorities1[state_index]);
+}
+
+void
+_cogl_pipeline_layer_resolve_authorities (CoglPipelineLayer *layer,
+                                          unsigned long differences,
+                                          CoglPipelineLayer **authorities)
+{
+  unsigned long remaining = differences;
+  CoglPipelineLayer *authority = layer;
+
+  do
+    {
+      unsigned long found = authority->differences & remaining;
+      int i;
+
+      if (found == 0)
+        continue;
+
+      for (i = 0; TRUE; i++)
+        {
+          unsigned long state = (1L<<i);
+
+          if (state & found)
+            authorities[i] = authority;
+          else if (state > found)
+            break;
+        }
+
+      remaining &= ~found;
+      if (remaining == 0)
+        return;
+    }
+  while ((authority = _cogl_pipeline_layer_get_parent (authority)));
+
+  g_assert (remaining == 0);
+}
+
+gboolean
+_cogl_pipeline_layer_equal (CoglPipelineLayer *layer0,
+                            CoglPipelineLayer *layer1,
+                            unsigned long differences_mask,
+                            CoglPipelineEvalFlags flags)
+{
+  unsigned long layers_difference;
+  CoglPipelineLayer *authorities0[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
+  CoglPipelineLayer *authorities1[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
+
+  if (layer0 == layer1)
+    return TRUE;
+
+  layers_difference =
+    _cogl_pipeline_layer_compare_differences (layer0, layer1);
+
+  /* Only compare the sparse state groups requested by the caller... */
+  layers_difference &= differences_mask;
+
+  _cogl_pipeline_layer_resolve_authorities (layer0,
+                                            layers_difference,
+                                            authorities0);
+  _cogl_pipeline_layer_resolve_authorities (layer1,
+                                            layers_difference,
+                                            authorities1);
+
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET)
+    {
+      CoglPipelineLayerStateIndex state_index =
+        COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX;
+      if (!_cogl_pipeline_layer_texture_target_equal (authorities0[state_index],
+                                                      authorities1[state_index],
+                                                      flags))
+        return FALSE;
+    }
+
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
+    {
+      CoglPipelineLayerStateIndex state_index =
+        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX;
+      if (!_cogl_pipeline_layer_texture_data_equal (authorities0[state_index],
+                                                    authorities1[state_index],
+                                                    flags))
+        return FALSE;
+    }
+
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE &&
+      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
+                          authorities0, authorities1,
+                          _cogl_pipeline_layer_combine_state_equal))
+    return FALSE;
+
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT &&
+      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
+                          authorities0, authorities1,
+                          _cogl_pipeline_layer_combine_constant_equal))
+    return FALSE;
+
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_FILTERS &&
+      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
+                          authorities0, authorities1,
+                          _cogl_pipeline_layer_filters_equal))
+    return FALSE;
+
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_WRAP_MODES &&
+      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
+                          authorities0, authorities1,
+                          _cogl_pipeline_layer_wrap_modes_equal))
+    return FALSE;
+
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX &&
+      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
+                          authorities0, authorities1,
+                          _cogl_pipeline_layer_user_matrix_equal))
+    return FALSE;
+
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS &&
+      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
+                          authorities0, authorities1,
+                          _cogl_pipeline_layer_point_sprite_coords_equal))
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+_cogl_pipeline_layer_free (CoglPipelineLayer *layer)
+{
+  _cogl_pipeline_layer_unparent (COGL_NODE (layer));
+
+  if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA &&
+      layer->texture != NULL)
+    cogl_object_unref (layer->texture);
+
+  if (layer->differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE)
+    g_slice_free (CoglPipelineLayerBigState, layer->big_state);
+
+  g_slice_free (CoglPipelineLayer, layer);
+}
+
+void
+_cogl_pipeline_init_default_layers (void)
+{
+  CoglPipelineLayer *layer = g_slice_new0 (CoglPipelineLayer);
+  CoglPipelineLayerBigState *big_state =
+    g_slice_new0 (CoglPipelineLayerBigState);
+  CoglPipelineLayer *new;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  _cogl_pipeline_node_init (COGL_NODE (layer));
+
+  layer->index = 0;
+
+  layer->differences = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE;
+
+  layer->unit_index = 0;
+
+  layer->texture = NULL;
+  layer->target = 0;
+
+  layer->mag_filter = COGL_PIPELINE_FILTER_LINEAR;
+  layer->min_filter = COGL_PIPELINE_FILTER_LINEAR;
+
+  layer->wrap_mode_s = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
+  layer->wrap_mode_t = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
+  layer->wrap_mode_p = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
+
+  layer->big_state = big_state;
+  layer->has_big_state = TRUE;
+
+  /* Choose the same default combine mode as OpenGL:
+   * RGBA = MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */
+  big_state->texture_combine_rgb_func =
+    COGL_PIPELINE_COMBINE_FUNC_MODULATE;
+  big_state->texture_combine_rgb_src[0] =
+    COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
+  big_state->texture_combine_rgb_src[1] =
+    COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
+  big_state->texture_combine_rgb_op[0] =
+    COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
+  big_state->texture_combine_rgb_op[1] =
+    COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
+  big_state->texture_combine_alpha_func =
+    COGL_PIPELINE_COMBINE_FUNC_MODULATE;
+  big_state->texture_combine_alpha_src[0] =
+    COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
+  big_state->texture_combine_alpha_src[1] =
+    COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
+  big_state->texture_combine_alpha_op[0] =
+    COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
+  big_state->texture_combine_alpha_op[1] =
+    COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
+
+  big_state->point_sprite_coords = FALSE;
+
+  cogl_matrix_init_identity (&big_state->matrix);
+
+  ctx->default_layer_0 = _cogl_pipeline_layer_object_new (layer);
+
+  /* TODO: we should make default_layer_n comprise of two
+   * descendants of default_layer_0:
+   * - the first descendant should change the texture combine
+   *   to what we expect is most commonly used for multitexturing
+   * - the second should revert the above change.
+   *
+   * why? the documentation for how a new layer is initialized
+   * doesn't say that layers > 0 have different defaults so unless
+   * we change the documentation we can't use different defaults,
+   * but if the user does what we expect and changes the
+   * texture combine then we can revert the authority to the
+   * first descendant which means we can maximize the number
+   * of layers with a common ancestor.
+   *
+   * The main problem will be that we'll need to disable the
+   * optimizations for flattening the ancestry when we make
+   * the second descendant which reverts the state.
+   */
+  ctx->default_layer_n = _cogl_pipeline_layer_copy (layer);
+  new = _cogl_pipeline_set_layer_unit (NULL, ctx->default_layer_n, 1);
+  g_assert (new == ctx->default_layer_n);
+  /* Since we passed a newly allocated layer we don't expect that
+   * _set_layer_unit() will have to allocate *another* layer. */
+
+  /* Finally we create a dummy dependant for ->default_layer_n which
+   * effectively ensures that ->default_layer_n and ->default_layer_0
+   * remain immutable.
+   */
+  ctx->dummy_layer_dependant =
+    _cogl_pipeline_layer_copy (ctx->default_layer_n);
+}
+
+void
+_cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layer)
+{
+  CoglPipelineLayer *texture_authority;
+
+  texture_authority =
+    _cogl_pipeline_layer_get_authority (layer,
+                                        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
+
+  if (texture_authority->texture != NULL)
+    {
+      CoglTexturePrePaintFlags flags = 0;
+      CoglPipelineFilter min_filter;
+      CoglPipelineFilter mag_filter;
+
+      _cogl_pipeline_layer_get_filters (layer, &min_filter, &mag_filter);
+
+      if (min_filter == COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST
+          || min_filter == COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST
+          || min_filter == COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR
+          || min_filter == COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR)
+        flags |= COGL_TEXTURE_NEEDS_MIPMAP;
+
+      _cogl_texture_pre_paint (texture_authority->texture, flags);
+    }
+}
+
+/* Determines if we need to handle the RGB and A texture combining
+ * separately or is the same function used for both channel masks and
+ * with the same arguments...
+ */
+gboolean
+_cogl_pipeline_layer_needs_combine_separate
+                                       (CoglPipelineLayer *combine_authority)
+{
+  CoglPipelineLayerBigState *big_state = combine_authority->big_state;
+  int n_args;
+  int i;
+
+  if (big_state->texture_combine_rgb_func !=
+      big_state->texture_combine_alpha_func)
+    return TRUE;
+
+  n_args = _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func);
+
+  for (i = 0; i < n_args; i++)
+    {
+      if (big_state->texture_combine_rgb_src[i] !=
+          big_state->texture_combine_alpha_src[i])
+        return TRUE;
+
+      /*
+       * We can allow some variation of the source operands without
+       * needing a separation...
+       *
+       * "A = REPLACE (CONSTANT[A])" + either of the following...
+       * "RGB = REPLACE (CONSTANT[RGB])"
+       * "RGB = REPLACE (CONSTANT[A])"
+       *
+       * can be combined as:
+       * "RGBA = REPLACE (CONSTANT)" or
+       * "RGBA = REPLACE (CONSTANT[A])" or
+       *
+       * And "A = REPLACE (1-CONSTANT[A])" + either of the following...
+       * "RGB = REPLACE (1-CONSTANT)" or
+       * "RGB = REPLACE (1-CONSTANT[A])"
+       *
+       * can be combined as:
+       * "RGBA = REPLACE (1-CONSTANT)" or
+       * "RGBA = REPLACE (1-CONSTANT[A])"
+       */
+      switch (big_state->texture_combine_alpha_op[i])
+        {
+        case GL_SRC_ALPHA:
+          switch (big_state->texture_combine_rgb_op[i])
+            {
+            case GL_SRC_COLOR:
+            case GL_SRC_ALPHA:
+              break;
+            default:
+              return FALSE;
+            }
+          break;
+        case GL_ONE_MINUS_SRC_ALPHA:
+          switch (big_state->texture_combine_rgb_op[i])
+            {
+            case GL_ONE_MINUS_SRC_COLOR:
+            case GL_ONE_MINUS_SRC_ALPHA:
+              break;
+            default:
+              return FALSE;
+            }
+          break;
+        default:
+          return FALSE;	/* impossible */
+        }
+    }
+
+   return FALSE;
+}
+
+
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
index 931642a..b8965c2 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl-pipeline-private.h
@@ -3,7 +3,7 @@
  *
  * An object oriented GL/GLES Abstraction/Utility Layer
  *
- * Copyright (C) 2008,2009,2010 Intel Corporation.
+ * Copyright (C) 2008,2009,2010,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
@@ -28,19 +28,17 @@
 #ifndef __COGL_PIPELINE_PRIVATE_H
 #define __COGL_PIPELINE_PRIVATE_H
 
-#include "cogl.h"
-
+#include "cogl-node-private.h"
+#include "cogl-pipeline-layer-private.h"
 #include "cogl-pipeline.h"
 #include "cogl-matrix.h"
 #include "cogl-object-private.h"
 #include "cogl-profile.h"
 #include "cogl-queue.h"
+#include "cogl-internal.h"
 
 #include <glib.h>
 
-typedef struct _CoglPipelineLayer     CoglPipelineLayer;
-#define COGL_PIPELINE_LAYER(OBJECT) ((CoglPipelineLayer *)OBJECT)
-
 #ifdef HAVE_COGL_GL
 
 #define COGL_PIPELINE_FRAGEND_ARBFP 0
@@ -150,268 +148,6 @@ typedef struct _CoglPipelineLayer     CoglPipelineLayer;
 #endif
 
 /* XXX: should I rename these as
- * COGL_PIPELINE_LAYER_STATE_INDEX_XYZ... ?
- */
-typedef enum
-{
-  /* sparse state */
-  COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
-  COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX,
-  COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
-  COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
-  COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
-  COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
-  COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
-  COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
-  COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
-
-  /* note: layers don't currently have any non-sparse state */
-
-  COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT,
-  COGL_PIPELINE_LAYER_STATE_COUNT = COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT
-} CoglPipelineLayerStateIndex;
-
-/* XXX: If you add or remove state groups here you may need to update
- * some of the state masks following this enum too!
- *
- * FIXME: perhaps it would be better to rename this enum to
- * CoglPipelineLayerStateGroup to better convey the fact that a single
- * enum here can map to multiple properties.
- */
-typedef enum
-{
-  COGL_PIPELINE_LAYER_STATE_UNIT =
-    1L<<COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
-  COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET =
-    1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX,
-  COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA =
-    1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
-  COGL_PIPELINE_LAYER_STATE_FILTERS =
-    1L<<COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
-  COGL_PIPELINE_LAYER_STATE_WRAP_MODES =
-    1L<<COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
-
-  COGL_PIPELINE_LAYER_STATE_COMBINE =
-    1L<<COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
-  COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT =
-    1L<<COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
-  COGL_PIPELINE_LAYER_STATE_USER_MATRIX =
-    1L<<COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
-
-  COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS =
-    1L<<COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
-
-  /* COGL_PIPELINE_LAYER_STATE_TEXTURE_INTERN   = 1L<<8, */
-
-} CoglPipelineLayerState;
-
-/*
- * Various special masks that tag state-groups in different ways...
- */
-
-#define COGL_PIPELINE_LAYER_STATE_ALL \
-  ((1L<<COGL_PIPELINE_LAYER_STATE_COUNT) - 1)
-
-#define COGL_PIPELINE_LAYER_STATE_ALL_SPARSE \
-  COGL_PIPELINE_LAYER_STATE_ALL
-
-#define COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE \
-  (COGL_PIPELINE_LAYER_STATE_COMBINE | \
-   COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT | \
-   COGL_PIPELINE_LAYER_STATE_USER_MATRIX | \
-   COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS)
-
-#define COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY \
-  (COGL_PIPELINE_LAYER_STATE_FILTERS | \
-   COGL_PIPELINE_LAYER_STATE_WRAP_MODES | \
-   COGL_PIPELINE_LAYER_STATE_COMBINE)
-
-#define COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN 0
-
-
-typedef enum
-{
-  /* These are the same values as GL */
-  COGL_PIPELINE_COMBINE_FUNC_ADD         = 0x0104,
-  COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED  = 0x8574,
-  COGL_PIPELINE_COMBINE_FUNC_SUBTRACT    = 0x84E7,
-  COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE = 0x8575,
-  COGL_PIPELINE_COMBINE_FUNC_REPLACE     = 0x1E01,
-  COGL_PIPELINE_COMBINE_FUNC_MODULATE    = 0x2100,
-  COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB    = 0x86AE,
-  COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA   = 0x86AF
-} CoglPipelineCombineFunc;
-
-typedef enum
-{
-  /* These are the same values as GL */
-  COGL_PIPELINE_COMBINE_SOURCE_TEXTURE       = 0x1702,
-  COGL_PIPELINE_COMBINE_SOURCE_CONSTANT      = 0x8576,
-  COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR = 0x8577,
-  COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS      = 0x8578,
-  COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0      = 0x84C0
-} CoglPipelineCombineSource;
-
-typedef enum
-{
-  /* These are the same values as GL */
-  COGL_PIPELINE_COMBINE_OP_SRC_COLOR           = 0x0300,
-  COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR = 0x0301,
-  COGL_PIPELINE_COMBINE_OP_SRC_ALPHA           = 0x0302,
-  COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA = 0x0303
-} CoglPipelineCombineOp;
-
-typedef struct
-{
-  /* The texture combine state determines how the color of individual
-   * texture fragments are calculated. */
-  CoglPipelineCombineFunc texture_combine_rgb_func;
-  CoglPipelineCombineSource texture_combine_rgb_src[3];
-  CoglPipelineCombineOp texture_combine_rgb_op[3];
-
-  CoglPipelineCombineFunc texture_combine_alpha_func;
-  CoglPipelineCombineSource texture_combine_alpha_src[3];
-  CoglPipelineCombineOp texture_combine_alpha_op[3];
-
-  float texture_combine_constant[4];
-
-  /* The texture matrix dscribes how to transform texture coordinates */
-  CoglMatrix matrix;
-
-  gboolean point_sprite_coords;
-
-} CoglPipelineLayerBigState;
-
-typedef struct _CoglPipelineNode CoglPipelineNode;
-
-COGL_LIST_HEAD (CoglPipelineNodeList, CoglPipelineNode);
-
-/* Materials and layers represent their state in a tree structure where
- * some of the state relating to a given pipeline or layer may actually
- * be owned by one if is ancestors in the tree. We have a common data
- * type to track the tree heirachy so we can share code... */
-struct _CoglPipelineNode
-{
-  /* the parent in terms of class hierarchy, so anything inheriting
-   * from CoglPipelineNode also inherits from CoglObject. */
-  CoglObject _parent;
-
-  /* The parent pipeline/layer */
-  CoglPipelineNode *parent;
-
-  /* The list entry here contains pointers to the node's siblings */
-  COGL_LIST_ENTRY (CoglPipelineNode) list_node;
-
-  /* List of children */
-  CoglPipelineNodeList children;
-
-  /* TRUE if the node took a strong reference on its parent. Weak
-   * pipelines for instance don't take a reference on their parent. */
-  gboolean has_parent_reference;
-};
-
-#define COGL_PIPELINE_NODE(X) ((CoglPipelineNode *)(X))
-
-typedef void (*CoglPipelineNodeUnparentVFunc) (CoglPipelineNode *node);
-
-typedef gboolean (*CoglPipelineNodeChildCallback) (CoglPipelineNode *child,
-                                                   void *user_data);
-
-void
-_cogl_pipeline_node_foreach_child (CoglPipelineNode *node,
-                                   CoglPipelineNodeChildCallback callback,
-                                   void *user_data);
-
-/* This isn't defined in the GLES headers */
-#ifndef GL_CLAMP_TO_BORDER
-#define GL_CLAMP_TO_BORDER 0x812d
-#endif
-
-/* GL_ALWAYS is just used here as a value that is known not to clash
- * with any valid GL wrap modes.
- *
- * XXX: keep the values in sync with the CoglPipelineWrapMode enum
- * so no conversion is actually needed.
- */
-typedef enum _CoglPipelineWrapModeInternal
-{
-  COGL_PIPELINE_WRAP_MODE_INTERNAL_REPEAT = GL_REPEAT,
-  COGL_PIPELINE_WRAP_MODE_INTERNAL_CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE,
-  COGL_PIPELINE_WRAP_MODE_INTERNAL_CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER,
-  COGL_PIPELINE_WRAP_MODE_INTERNAL_AUTOMATIC = GL_ALWAYS
-} CoglPipelineWrapModeInternal;
-
-struct _CoglPipelineLayer
-{
-  /* XXX: Please think twice about adding members that *have* be
-   * initialized during a _cogl_pipeline_layer_copy. We are aiming
-   * to have copies be as cheap as possible and copies may be
-   * done by the primitives APIs which means they may happen
-   * in performance critical code paths.
-   *
-   * XXX: If you are extending the state we track please consider if
-   * the state is expected to vary frequently across many pipelines or
-   * if the state can be shared among many derived pipelines instead.
-   * This will determine if the state should be added directly to this
-   * structure which will increase the memory overhead for *all*
-   * layers or if instead it can go under ->big_state.
-   */
-
-  /* Layers represent their state in a tree structure where some of
-   * the state relating to a given pipeline or layer may actually be
-   * owned by one if is ancestors in the tree. We have a common data
-   * type to track the tree heirachy so we can share code... */
-  CoglPipelineNode _parent;
-
-  /* Some layers have a pipeline owner, which is to say that the layer
-   * is referenced in that pipelines->layer_differences list.  A layer
-   * doesn't always have an owner and may simply be an ancestor for
-   * other layers that keeps track of some shared state. */
-  CoglPipeline      *owner;
-
-  /* The lowest index is blended first then others on top */
-  int	             index;
-
-  /* A mask of which state groups are different in this layer
-   * in comparison to its parent. */
-  unsigned long             differences;
-
-  /* Common differences
-   *
-   * As a basic way to reduce memory usage we divide the layer
-   * state into two groups; the minimal state modified in 90% of
-   * all layers and the rest, so that the second group can
-   * be allocated dynamically when required.
-   */
-
-  /* Each layer is directly associated with a single texture unit */
-  int                        unit_index;
-
-  /* The texture for this layer, or NULL for an empty
-   * layer */
-  CoglTexture               *texture;
-  GLenum                     target;
-
-  CoglPipelineFilter         mag_filter;
-  CoglPipelineFilter         min_filter;
-
-  CoglPipelineWrapModeInternal wrap_mode_s;
-  CoglPipelineWrapModeInternal wrap_mode_t;
-  CoglPipelineWrapModeInternal wrap_mode_p;
-
-  /* Infrequent differences aren't currently tracked in
-   * a separate, dynamically allocated structure as they are
-   * for pipelines... */
-  CoglPipelineLayerBigState *big_state;
-
-  /* bitfields */
-
-  /* Determines if layer->big_state is valid */
-  unsigned int          has_big_state:1;
-
-};
-
-/* XXX: should I rename these as
  * COGL_PIPELINE_STATE_INDEX_XYZ... ?
  */
 typedef enum
@@ -636,14 +372,6 @@ typedef struct
   CoglPipelineLayer *layer;
 } CoglPipelineLayerCacheEntry;
 
-/* Sometimes when evaluating pipelines, either during comparisons or
- * if calculating a hash value we need to tweak the evaluation
- * semantics */
-typedef enum _CoglPipelineEvalFlags
-{
-  COGL_PIPELINE_EVAL_FLAG_NONE = 0
-} CoglPipelineEvalFlags;
-
 typedef struct _CoglPipelineHashState
 {
   unsigned long layer_differences;
@@ -682,7 +410,7 @@ struct _CoglPipeline
    * the state relating to a given pipeline or layer may actually be
    * owned by one if is ancestors in the tree. We have a common data
    * type to track the tree heirachy so we can share code... */
-  CoglPipelineNode _parent;
+  CoglNode _parent;
 
   /* We need to track if a pipeline is referenced in the journal
    * because we can't allow modification to these pipelines without
@@ -863,13 +591,10 @@ _cogl_pipeline_progends[];
 void
 _cogl_pipeline_init_default_pipeline (void);
 
-void
-_cogl_pipeline_init_default_layers (void);
-
 static inline CoglPipeline *
 _cogl_pipeline_get_parent (CoglPipeline *pipeline)
 {
-  CoglPipelineNode *parent_node = COGL_PIPELINE_NODE (pipeline)->parent;
+  CoglNode *parent_node = COGL_NODE (pipeline)->parent;
   return COGL_PIPELINE (parent_node);
 }
 
@@ -886,11 +611,6 @@ _cogl_pipeline_get_authority (CoglPipeline *pipeline,
 typedef gboolean (*CoglPipelineStateComparitor) (CoglPipeline *authority0,
                                                  CoglPipeline *authority1);
 
-typedef gboolean
-(*CoglPipelineLayerStateComparitor) (CoglPipelineLayer *authority0,
-                                     CoglPipelineLayer *authority1);
-
-
 void
 _cogl_pipeline_update_authority (CoglPipeline *pipeline,
                                  CoglPipeline *authority,
@@ -916,21 +636,6 @@ _cogl_pipeline_get_layer (CoglPipeline *pipeline,
 gboolean
 _cogl_is_pipeline_layer (void *object);
 
-static inline CoglPipelineLayer *
-_cogl_pipeline_layer_get_parent (CoglPipelineLayer *layer)
-{
-  CoglPipelineNode *parent_node = COGL_PIPELINE_NODE (layer)->parent;
-  return COGL_PIPELINE_LAYER (parent_node);
-}
-
-CoglPipelineLayer *
-_cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
-                                        CoglPipelineLayer *layer,
-                                        CoglPipelineLayerState change);
-
-void
-_cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer);
-
 void
 _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority,
                                              CoglPipelineLayer *layer);
@@ -949,18 +654,6 @@ _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority,
 gboolean
 _cogl_pipeline_get_real_blend_enabled (CoglPipeline *pipeline);
 
-gboolean
-_cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
-                                      int layer_index);
-
-/*
- * Calls the pre_paint method on the layer texture if there is
- * one. This will determine whether mipmaps are needed based on the
- * filter settings.
- */
-void
-_cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layerr);
-
 /*
  * Calls the pre_paint method on the layer texture if there is
  * one. This will determine whether mipmaps are needed based on the
@@ -1181,14 +874,6 @@ _cogl_pipeline_journal_ref (CoglPipeline *pipeline);
 void
 _cogl_pipeline_journal_unref (CoglPipeline *pipeline);
 
-CoglPipelineFilter
-_cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline,
-                                     int layer_index);
-
-CoglPipelineFilter
-_cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline,
-                                     int layer_index);
-
 const CoglMatrix *
 _cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline,
                                  int layer_index);
@@ -1224,6 +909,16 @@ CoglPipeline *
 _cogl_pipeline_get_authority (CoglPipeline *pipeline,
                               unsigned long difference);
 
+void
+_cogl_pipeline_add_layer_difference (CoglPipeline *pipeline,
+                                     CoglPipelineLayer *layer,
+                                     gboolean inc_n_layers);
+
+void
+_cogl_pipeline_remove_layer_difference (CoglPipeline *pipeline,
+                                        CoglPipelineLayer *layer,
+                                        gboolean dec_n_layers);
+
 CoglPipeline *
 _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline,
                                        CoglPipelineState pipeline_state,
@@ -1249,62 +944,6 @@ _cogl_pipeline_prune_to_n_layers (CoglPipeline *pipeline, int n);
 const GList *
 _cogl_pipeline_get_layers (CoglPipeline *pipeline);
 
-void
-_cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer,
-                                     CoglPipelineWrapModeInternal *wrap_mode_s,
-                                     CoglPipelineWrapModeInternal *wrap_mode_t,
-                                     CoglPipelineWrapModeInternal *wrap_mode_r);
-
-void
-_cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer,
-                                  CoglPipelineFilter *min_filter,
-                                  CoglPipelineFilter *mag_filter);
-
-void
-_cogl_pipeline_get_layer_filters (CoglPipeline *pipeline,
-                                  int layer_index,
-                                  CoglPipelineFilter *min_filter,
-                                  CoglPipelineFilter *mag_filter);
-
-typedef enum {
-  COGL_PIPELINE_LAYER_TYPE_TEXTURE
-} CoglPipelineLayerType;
-
-CoglPipelineLayerType
-_cogl_pipeline_layer_get_type (CoglPipelineLayer *layer);
-
-CoglTexture *
-_cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer);
-
-CoglTexture *
-_cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer);
-
-CoglPipelineFilter
-_cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer);
-
-CoglPipelineFilter
-_cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer);
-
-CoglPipelineWrapMode
-_cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer);
-
-CoglPipelineWrapMode
-_cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer);
-
-CoglPipelineWrapMode
-_cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer);
-
-unsigned long
-_cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
-                                          CoglPipelineLayer *layer1);
-
-CoglPipelineLayer *
-_cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer,
-                                    unsigned long difference);
-
-CoglTexture *
-_cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer);
-
 typedef gboolean (*CoglPipelineInternalLayerCallback) (CoglPipelineLayer *layer,
                                                        void *user_data);
 
@@ -1313,9 +952,6 @@ _cogl_pipeline_foreach_layer_internal (CoglPipeline *pipeline,
                                        CoglPipelineInternalLayerCallback callback,
                                        void *user_data);
 
-int
-_cogl_pipeline_layer_get_unit_index (CoglPipelineLayer *layer);
-
 gboolean
 _cogl_pipeline_need_texture_combine_separate
                                     (CoglPipelineLayer *combine_authority);
@@ -1326,11 +962,26 @@ _cogl_pipeline_init_state_hash_functions (void);
 void
 _cogl_pipeline_init_layer_state_hash_functions (void);
 
+void
+_cogl_pipeline_fragend_layer_change_notify (CoglPipeline *owner,
+                                            CoglPipelineLayer *layer,
+                                            CoglPipelineLayerState change);
+
 CoglPipelineLayerState
 _cogl_pipeline_get_layer_state_for_fragment_codegen (CoglContext *context);
 
 CoglPipelineState
 _cogl_pipeline_get_state_for_fragment_codegen (CoglContext *context);
 
+void
+_cogl_pipeline_vertend_layer_change_notify (CoglPipeline *owner,
+                                            CoglPipelineLayer *layer,
+                                            CoglPipelineLayerState change);
+
+void
+_cogl_pipeline_progend_layer_change_notify (CoglPipeline *owner,
+                                            CoglPipelineLayer *layer,
+                                            CoglPipelineLayerState change);
+
 #endif /* __COGL_PIPELINE_PRIVATE_H */
 
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 88e1bd7..0466740 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -51,13 +51,7 @@
 #include <glib/gprintf.h>
 #include <string.h>
 
-static CoglPipelineLayer *_cogl_pipeline_layer_copy (CoglPipelineLayer *layer);
-
 static void _cogl_pipeline_free (CoglPipeline *tex);
-static void _cogl_pipeline_layer_free (CoglPipelineLayer *layer);
-static void _cogl_pipeline_add_layer_difference (CoglPipeline *pipeline,
-                                                 CoglPipelineLayer *layer,
-                                                 gboolean inc_n_layers);
 static void recursively_free_layer_caches (CoglPipeline *pipeline);
 static gboolean _cogl_pipeline_is_weak (CoglPipeline *pipeline);
 
@@ -89,11 +83,6 @@ _cogl_pipeline_progends[MAX (COGL_PIPELINE_N_PROGENDS, 1)];
 #endif
 
 COGL_OBJECT_DEFINE (Pipeline, pipeline);
-/* This type was made deprecated before the cogl_is_pipeline_layer
-   function was ever exposed in the public headers so there's no need
-   to make the cogl_is_pipeline_layer function public. We use INTERNAL
-   so that the cogl_is_* function won't get defined */
-COGL_OBJECT_INTERNAL_DEFINE (PipelineLayer, pipeline_layer);
 
 GQuark
 _cogl_pipeline_error_quark (void)
@@ -101,75 +90,6 @@ _cogl_pipeline_error_quark (void)
   return g_quark_from_static_string ("cogl-pipeline-error-quark");
 }
 
-static void
-_cogl_pipeline_node_init (CoglPipelineNode *node)
-{
-  node->parent = NULL;
-  COGL_LIST_INIT (&node->children);
-}
-
-static void
-_cogl_pipeline_node_set_parent_real (CoglPipelineNode *node,
-                                     CoglPipelineNode *parent,
-                                     CoglPipelineNodeUnparentVFunc unparent,
-                                     gboolean take_strong_reference)
-{
-  /* NB: the old parent may indirectly be keeping the new parent alive
-   * so we have to ref the new parent before unrefing the old.
-   *
-   * Note: we take a reference here regardless of
-   * take_strong_reference because weak children may need special
-   * handling when the parent disposes itself which relies on a
-   * consistent link to all weak nodes. Once the node is linked to its
-   * parent then we remove the reference at the end if
-   * take_strong_reference == FALSE. */
-  cogl_object_ref (parent);
-
-  if (node->parent)
-    unparent (node);
-
-  COGL_LIST_INSERT_HEAD (&parent->children, node, list_node);
-
-  node->parent = parent;
-  node->has_parent_reference = take_strong_reference;
-
-  /* Now that there is a consistent parent->child link we can remove
-   * the parent reference if no reference was requested. If it turns
-   * out that the new parent was only being kept alive by the old
-   * parent then it will be disposed of here. */
-  if (!take_strong_reference)
-    cogl_object_unref (parent);
-}
-
-static void
-_cogl_pipeline_node_unparent_real (CoglPipelineNode *node)
-{
-  CoglPipelineNode *parent = node->parent;
-
-  if (parent == NULL)
-    return;
-
-  g_return_if_fail (!COGL_LIST_EMPTY (&parent->children));
-
-  COGL_LIST_REMOVE (node, list_node);
-
-  if (node->has_parent_reference)
-    cogl_object_unref (parent);
-
-  node->parent = NULL;
-}
-
-void
-_cogl_pipeline_node_foreach_child (CoglPipelineNode *node,
-                                   CoglPipelineNodeChildCallback callback,
-                                   void *user_data)
-{
-  CoglPipelineNode *child, *next;
-
-  COGL_LIST_FOREACH_SAFE (child, &node->children, list_node, next)
-    callback (child, user_data);
-}
-
 /*
  * This initializes the first pipeline owned by the Cogl context. All
  * subsequently instantiated pipelines created via the cogl_pipeline_new()
@@ -221,7 +141,7 @@ _cogl_pipeline_init_default_pipeline (void)
     &_cogl_pipeline_fixed_vertend;
 #endif
 
-  _cogl_pipeline_node_init (COGL_PIPELINE_NODE (pipeline));
+  _cogl_pipeline_node_init (COGL_NODE (pipeline));
 
   pipeline->is_weak = FALSE;
   pipeline->journal_ref_count = 0;
@@ -305,14 +225,14 @@ _cogl_pipeline_init_default_pipeline (void)
 }
 
 static void
-_cogl_pipeline_unparent (CoglPipelineNode *pipeline)
+_cogl_pipeline_unparent (CoglNode *pipeline)
 {
   /* Chain up */
   _cogl_pipeline_node_unparent_real (pipeline);
 }
 
 static gboolean
-recursively_free_layer_caches_cb (CoglPipelineNode *node,
+recursively_free_layer_caches_cb (CoglNode *node,
                                   void *user_data)
 {
   recursively_free_layer_caches (COGL_PIPELINE (node));
@@ -338,7 +258,7 @@ recursively_free_layer_caches (CoglPipeline *pipeline)
                    pipeline->layers_cache);
   pipeline->layers_cache_dirty = TRUE;
 
-  _cogl_pipeline_node_foreach_child (COGL_PIPELINE_NODE (pipeline),
+  _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
                                      recursively_free_layer_caches_cb,
                                      NULL);
 }
@@ -349,8 +269,8 @@ _cogl_pipeline_set_parent (CoglPipeline *pipeline,
                            gboolean take_strong_reference)
 {
   /* Chain up */
-  _cogl_pipeline_node_set_parent_real (COGL_PIPELINE_NODE (pipeline),
-                                       COGL_PIPELINE_NODE (parent),
+  _cogl_pipeline_node_set_parent_real (COGL_NODE (pipeline),
+                                       COGL_NODE (parent),
                                        _cogl_pipeline_unparent,
                                        take_strong_reference);
 
@@ -375,7 +295,7 @@ _cogl_pipeline_set_parent (CoglPipeline *pipeline,
 static void
 _cogl_pipeline_promote_weak_ancestors (CoglPipeline *strong)
 {
-  CoglPipelineNode *n;
+  CoglNode *n;
 
   g_return_if_fail (!strong->is_weak);
 
@@ -383,10 +303,10 @@ _cogl_pipeline_promote_weak_ancestors (CoglPipeline *strong)
      taking a reference on strong's grandparent. We don't need to take
      a reference on strong's direct parent */
 
-  if (COGL_PIPELINE_NODE (strong)->parent == NULL)
+  if (COGL_NODE (strong)->parent == NULL)
     return;
 
-  for (n = COGL_PIPELINE_NODE (strong)->parent;
+  for (n = COGL_NODE (strong)->parent;
        /* We can assume that all weak pipelines have a parent */
        COGL_PIPELINE (n)->is_weak;
        n = n->parent)
@@ -397,17 +317,17 @@ _cogl_pipeline_promote_weak_ancestors (CoglPipeline *strong)
 static void
 _cogl_pipeline_revert_weak_ancestors (CoglPipeline *strong)
 {
-  CoglPipelineNode *n;
+  CoglNode *n;
 
   g_return_if_fail (!strong->is_weak);
 
   /* This reverts the effect of calling
      _cogl_pipeline_promote_weak_ancestors */
 
-  if (COGL_PIPELINE_NODE (strong)->parent == NULL)
+  if (COGL_NODE (strong)->parent == NULL)
     return;
 
-  for (n = COGL_PIPELINE_NODE (strong)->parent;
+  for (n = COGL_NODE (strong)->parent;
        /* We can assume that all weak pipelines have a parent */
        COGL_PIPELINE (n)->is_weak;
        n = n->parent)
@@ -422,7 +342,7 @@ _cogl_pipeline_copy (CoglPipeline *src, gboolean is_weak)
 {
   CoglPipeline *pipeline = g_slice_new (CoglPipeline);
 
-  _cogl_pipeline_node_init (COGL_PIPELINE_NODE (pipeline));
+  _cogl_pipeline_node_init (COGL_NODE (pipeline));
 
   pipeline->is_weak = is_weak;
 
@@ -501,19 +421,19 @@ cogl_pipeline_new (void)
 }
 
 static gboolean
-destroy_weak_children_cb (CoglPipelineNode *node,
+destroy_weak_children_cb (CoglNode *node,
                           void *user_data)
 {
   CoglPipeline *pipeline = COGL_PIPELINE (node);
 
   if (_cogl_pipeline_is_weak (pipeline))
     {
-      _cogl_pipeline_node_foreach_child (COGL_PIPELINE_NODE (pipeline),
+      _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
                                          destroy_weak_children_cb,
                                          NULL);
 
       pipeline->destroy_callback (pipeline, pipeline->destroy_data);
-      _cogl_pipeline_unparent (COGL_PIPELINE_NODE (pipeline));
+      _cogl_pipeline_unparent (COGL_NODE (pipeline));
     }
 
   return TRUE;
@@ -526,13 +446,13 @@ _cogl_pipeline_free (CoglPipeline *pipeline)
     _cogl_pipeline_revert_weak_ancestors (pipeline);
 
   /* Weak pipelines don't take a reference on their parent */
-  _cogl_pipeline_node_foreach_child (COGL_PIPELINE_NODE (pipeline),
+  _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
                                      destroy_weak_children_cb,
                                      NULL);
 
-  g_assert (COGL_LIST_EMPTY (&COGL_PIPELINE_NODE (pipeline)->children));
+  g_assert (COGL_LIST_EMPTY (&COGL_NODE (pipeline)->children));
 
-  _cogl_pipeline_unparent (COGL_PIPELINE_NODE (pipeline));
+  _cogl_pipeline_unparent (COGL_NODE (pipeline));
 
   if (pipeline->differences & COGL_PIPELINE_STATE_USER_SHADER &&
       pipeline->big_state->user_program)
@@ -561,24 +481,6 @@ _cogl_pipeline_get_real_blend_enabled (CoglPipeline *pipeline)
   return pipeline->real_blend_enable;
 }
 
-CoglPipelineLayer *
-_cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer,
-                                    unsigned long difference)
-{
-  CoglPipelineLayer *authority = layer;
-  while (!(authority->differences & difference))
-    authority = _cogl_pipeline_layer_get_parent (authority);
-  return authority;
-}
-
-int
-_cogl_pipeline_layer_get_unit_index (CoglPipelineLayer *layer)
-{
-  CoglPipelineLayer *authority =
-    _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_UNIT);
-  return authority->unit_index;
-}
-
 static void
 _cogl_pipeline_update_layers_cache (CoglPipeline *pipeline)
 {
@@ -730,53 +632,18 @@ cogl_pipeline_foreach_layer (CoglPipeline *pipeline,
 static gboolean
 layer_has_alpha_cb (CoglPipelineLayer *layer, void *data)
 {
-  CoglPipelineLayer *combine_authority =
-    _cogl_pipeline_layer_get_authority (layer,
-                                        COGL_PIPELINE_LAYER_STATE_COMBINE);
-  CoglPipelineLayerBigState *big_state = combine_authority->big_state;
-  CoglPipelineLayer *tex_authority;
   gboolean *has_alpha = data;
+  *has_alpha = _cogl_pipeline_layer_has_alpha (layer);
 
-  /* has_alpha maintains the alpha status for the GL_PREVIOUS layer */
-
-  /* For anything but the default texture combine we currently just
-   * assume it may result in an alpha value < 1
+  /* return FALSE to stop iterating layers if we find any layer
+   * has alpha ...
    *
-   * FIXME: we could do better than this. */
-  if (big_state->texture_combine_alpha_func !=
-      COGL_PIPELINE_COMBINE_FUNC_MODULATE ||
-      big_state->texture_combine_alpha_src[0] !=
-      COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS ||
-      big_state->texture_combine_alpha_op[0] !=
-      COGL_PIPELINE_COMBINE_OP_SRC_ALPHA ||
-      big_state->texture_combine_alpha_src[1] !=
-      COGL_PIPELINE_COMBINE_SOURCE_TEXTURE ||
-      big_state->texture_combine_alpha_op[1] !=
-      COGL_PIPELINE_COMBINE_OP_SRC_ALPHA)
-    {
-      *has_alpha = TRUE;
-      /* return FALSE to stop iterating layers... */
-      return FALSE;
-    }
-
-  /* NB: A layer may have a combine mode set on it but not yet
-   * have an associated texture which would mean we'd fallback
-   * to the default texture which doesn't have an alpha component
+   * FIXME: actually we should never be bailing out because it's
+   * always possible that a later layer could discard any previous
+   * alpha!
    */
-  tex_authority =
-    _cogl_pipeline_layer_get_authority (layer,
-                                        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
-  if (tex_authority->texture &&
-      cogl_texture_get_format (tex_authority->texture) & COGL_A_BIT)
-    {
-      *has_alpha = TRUE;
-      /* return FALSE to stop iterating layers... */
-      return FALSE;
-    }
 
-  *has_alpha = FALSE;
-  /* return FALSE to continue iterating layers... */
-  return TRUE;
+  return !(*has_alpha);
 }
 
 static gboolean
@@ -1146,7 +1013,7 @@ _cogl_pipeline_init_multi_property_sparse_state (CoglPipeline *pipeline,
 }
 
 static gboolean
-check_if_strong_cb (CoglPipelineNode *node, void *user_data)
+check_if_strong_cb (CoglNode *node, void *user_data)
 {
   CoglPipeline *pipeline = COGL_PIPELINE (node);
   gboolean *has_strong_child = user_data;
@@ -1164,7 +1031,7 @@ static gboolean
 has_strong_children (CoglPipeline *pipeline)
 {
   gboolean has_strong_child = FALSE;
-  _cogl_pipeline_node_foreach_child (COGL_PIPELINE_NODE (pipeline),
+  _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
                                      check_if_strong_cb,
                                      &has_strong_child);
   return has_strong_child;
@@ -1180,7 +1047,7 @@ _cogl_pipeline_is_weak (CoglPipeline *pipeline)
 }
 
 static gboolean
-reparent_children_cb (CoglPipelineNode *node,
+reparent_children_cb (CoglNode *node,
                       void *user_data)
 {
   CoglPipeline *pipeline = COGL_PIPELINE (node);
@@ -1311,14 +1178,14 @@ _cogl_pipeline_pre_change_notify (CoglPipeline     *pipeline,
   /* The simplest descendants to handle are weak pipelines; we simply
    * destroy them if we are modifying a pipeline they depend on. This
    * means weak pipelines never cause us to do a copy-on-write. */
-  _cogl_pipeline_node_foreach_child (COGL_PIPELINE_NODE (pipeline),
+  _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
                                      destroy_weak_children_cb,
                                      NULL);
 
   /* If there are still children remaining though we'll need to
    * perform a copy-on-write and reparent the dependants as children
    * of the copy. */
-  if (!COGL_LIST_EMPTY (&COGL_PIPELINE_NODE (pipeline)->children))
+  if (!COGL_LIST_EMPTY (&COGL_NODE (pipeline)->children))
     {
       CoglPipeline *new_authority;
 
@@ -1352,7 +1219,7 @@ _cogl_pipeline_pre_change_notify (CoglPipeline     *pipeline,
 
       /* Reparent the dependants of pipeline to be children of
        * new_authority instead... */
-      _cogl_pipeline_node_foreach_child (COGL_PIPELINE_NODE (pipeline),
+      _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
                                          reparent_children_cb,
                                          new_authority);
 
@@ -1411,7 +1278,7 @@ _cogl_pipeline_pre_change_notify (CoglPipeline     *pipeline,
 }
 
 
-static void
+void
 _cogl_pipeline_add_layer_difference (CoglPipeline *pipeline,
                                      CoglPipelineLayer *layer,
                                      gboolean inc_n_layers)
@@ -1445,7 +1312,7 @@ _cogl_pipeline_add_layer_difference (CoglPipeline *pipeline,
     pipeline->n_layers++;
 }
 
-static void
+void
 _cogl_pipeline_remove_layer_difference (CoglPipeline *pipeline,
                                         CoglPipelineLayer *layer,
                                         gboolean dec_n_layers)
@@ -1587,7 +1454,7 @@ _cogl_pipeline_prune_to_n_layers (CoglPipeline *pipeline, int n)
   pipeline->differences |= COGL_PIPELINE_STATE_LAYERS;
 }
 
-static void
+void
 _cogl_pipeline_fragend_layer_change_notify (CoglPipeline *owner,
                                             CoglPipelineLayer *layer,
                                             CoglPipelineLayerState change)
@@ -1607,7 +1474,7 @@ _cogl_pipeline_fragend_layer_change_notify (CoglPipeline *owner,
     }
 }
 
-static void
+void
 _cogl_pipeline_vertend_layer_change_notify (CoglPipeline *owner,
                                             CoglPipelineLayer *layer,
                                             CoglPipelineLayerState change)
@@ -1622,7 +1489,7 @@ _cogl_pipeline_vertend_layer_change_notify (CoglPipeline *owner,
     }
 }
 
-static void
+void
 _cogl_pipeline_progend_layer_change_notify (CoglPipeline *owner,
                                             CoglPipelineLayer *layer,
                                             CoglPipelineLayerState change)
@@ -1638,239 +1505,6 @@ _cogl_pipeline_progend_layer_change_notify (CoglPipeline *owner,
                                                            change);
 }
 
-unsigned int
-_cogl_get_n_args_for_combine_func (CoglPipelineCombineFunc func)
-{
-  switch (func)
-    {
-    case COGL_PIPELINE_COMBINE_FUNC_REPLACE:
-      return 1;
-    case COGL_PIPELINE_COMBINE_FUNC_MODULATE:
-    case COGL_PIPELINE_COMBINE_FUNC_ADD:
-    case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED:
-    case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT:
-    case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB:
-    case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA:
-      return 2;
-    case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE:
-      return 3;
-    }
-  return 0;
-}
-
-static void
-_cogl_pipeline_layer_init_multi_property_sparse_state (
-                                                  CoglPipelineLayer *layer,
-                                                  CoglPipelineLayerState change)
-{
-  CoglPipelineLayer *authority;
-
-  /* Nothing to initialize in these cases since they are all comprised
-   * of one member which we expect to immediately be overwritten. */
-  if (!(change & COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY))
-    return;
-
-  authority = _cogl_pipeline_layer_get_authority (layer, change);
-
-  switch (change)
-    {
-    /* XXX: avoid using a default: label so we get a warning if we
-     * don't explicitly handle a newly defined state-group here. */
-    case COGL_PIPELINE_LAYER_STATE_UNIT:
-    case COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET:
-    case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA:
-    case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS:
-    case COGL_PIPELINE_LAYER_STATE_USER_MATRIX:
-    case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT:
-      g_return_if_reached ();
-
-    /* XXX: technically we could probably even consider these as
-     * single property state-groups from the pov that currently the
-     * corresponding property setters always update all of the values
-     * at the same time. */
-    case COGL_PIPELINE_LAYER_STATE_FILTERS:
-      layer->min_filter = authority->min_filter;
-      layer->mag_filter = authority->mag_filter;
-      break;
-    case COGL_PIPELINE_LAYER_STATE_WRAP_MODES:
-      layer->wrap_mode_s = authority->wrap_mode_s;
-      layer->wrap_mode_t = authority->wrap_mode_t;
-      layer->wrap_mode_p = authority->wrap_mode_p;
-      break;
-    case COGL_PIPELINE_LAYER_STATE_COMBINE:
-      {
-        int n_args;
-        int i;
-        CoglPipelineLayerBigState *src_big_state = authority->big_state;
-        CoglPipelineLayerBigState *dest_big_state = layer->big_state;
-        GLint func = src_big_state->texture_combine_rgb_func;
-
-        dest_big_state->texture_combine_rgb_func = func;
-        n_args = _cogl_get_n_args_for_combine_func (func);
-        for (i = 0; i < n_args; i++)
-          {
-            dest_big_state->texture_combine_rgb_src[i] =
-              src_big_state->texture_combine_rgb_src[i];
-            dest_big_state->texture_combine_rgb_op[i] =
-              src_big_state->texture_combine_rgb_op[i];
-          }
-
-        func = src_big_state->texture_combine_alpha_func;
-        dest_big_state->texture_combine_alpha_func = func;
-        n_args = _cogl_get_n_args_for_combine_func (func);
-        for (i = 0; i < n_args; i++)
-          {
-            dest_big_state->texture_combine_alpha_src[i] =
-              src_big_state->texture_combine_alpha_src[i];
-            dest_big_state->texture_combine_alpha_op[i] =
-              src_big_state->texture_combine_alpha_op[i];
-          }
-        break;
-      }
-    }
-}
-
-/* NB: This function will allocate a new derived layer if you are
- * trying to change the state of a layer with dependants so you must
- * always check the return value.
- *
- * If a new layer is returned it will be owned by required_owner.
- *
- * required_owner can only by NULL for new, currently unowned layers
- * with no dependants.
- */
-CoglPipelineLayer *
-_cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
-                                        CoglPipelineLayer *layer,
-                                        CoglPipelineLayerState change)
-{
-  CoglTextureUnit *unit;
-
-  /* Identify the case where the layer is new with no owner or
-   * dependants and so we don't need to do anything. */
-  if (COGL_LIST_EMPTY (&COGL_PIPELINE_NODE (layer)->children) &&
-      layer->owner == NULL)
-    goto init_layer_state;
-
-  /* We only allow a NULL required_owner for new layers */
-  g_return_val_if_fail (required_owner != NULL, layer);
-
-  /* Chain up:
-   * A modification of a layer is indirectly also a modification of
-   * its owner so first make sure to flush the journal of any
-   * references to the current owner state and if necessary perform
-   * a copy-on-write for the required_owner if it has dependants.
-   */
-  _cogl_pipeline_pre_change_notify (required_owner,
-                                    COGL_PIPELINE_STATE_LAYERS,
-                                    NULL,
-                                    TRUE);
-
-  /* Unlike pipelines; layers are simply considered immutable once
-   * they have dependants - either direct children, or another
-   * pipeline as an owner.
-   */
-  if (!COGL_LIST_EMPTY (&COGL_PIPELINE_NODE (layer)->children) ||
-      layer->owner != required_owner)
-    {
-      CoglPipelineLayer *new = _cogl_pipeline_layer_copy (layer);
-      if (layer->owner == required_owner)
-        _cogl_pipeline_remove_layer_difference (required_owner, layer, FALSE);
-      _cogl_pipeline_add_layer_difference (required_owner, new, FALSE);
-      cogl_object_unref (new);
-      layer = new;
-      goto init_layer_state;
-    }
-
-  /* Note: At this point we know there is only one pipeline dependant on
-   * this layer (required_owner), and there are no other layers
-   * dependant on this layer so it's ok to modify it. */
-
-  _cogl_pipeline_fragend_layer_change_notify (required_owner, layer, change);
-  _cogl_pipeline_vertend_layer_change_notify (required_owner, layer, change);
-  _cogl_pipeline_progend_layer_change_notify (required_owner, layer, change);
-
-  /* If the layer being changed is the same as the last layer we
-   * flushed to the corresponding texture unit then we keep a track of
-   * the changes so we can try to minimize redundant OpenGL calls if
-   * the same layer is flushed again.
-   */
-  unit = _cogl_get_texture_unit (_cogl_pipeline_layer_get_unit_index (layer));
-  if (unit->layer == layer)
-    unit->layer_changes_since_flush |= change;
-
-init_layer_state:
-
-  if (required_owner)
-    required_owner->age++;
-
-  if (change & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE &&
-      !layer->has_big_state)
-    {
-      layer->big_state = g_slice_new (CoglPipelineLayerBigState);
-      layer->has_big_state = TRUE;
-    }
-
-  /* Note: conceptually we have just been notified that a single
-   * property value is about to change, but since some state-groups
-   * contain multiple properties and 'layer' is about to take over
-   * being the authority for the property's corresponding state-group
-   * we need to maintain the integrity of the other property values
-   * too.
-   *
-   * To ensure this we handle multi-property state-groups by copying
-   * all the values from the old-authority to the new...
-   *
-   * We don't have to worry about non-sparse property groups since
-   * we never take over being an authority for such properties so
-   * they automatically maintain integrity.
-   */
-  if (change & COGL_PIPELINE_LAYER_STATE_ALL_SPARSE &&
-      !(layer->differences & change))
-    {
-      _cogl_pipeline_layer_init_multi_property_sparse_state (layer, change);
-      layer->differences |= change;
-    }
-
-  return layer;
-}
-
-static void
-_cogl_pipeline_layer_unparent (CoglPipelineNode *layer)
-{
-  /* Chain up */
-  _cogl_pipeline_node_unparent_real (layer);
-}
-
-static void
-_cogl_pipeline_layer_set_parent (CoglPipelineLayer *layer,
-                                 CoglPipelineLayer *parent)
-{
-  /* Chain up */
-  _cogl_pipeline_node_set_parent_real (COGL_PIPELINE_NODE (layer),
-                                       COGL_PIPELINE_NODE (parent),
-                                       _cogl_pipeline_layer_unparent,
-                                       TRUE);
-}
-
-/* XXX: This is duplicated logic; the same as for
- * _cogl_pipeline_prune_redundant_ancestry it would be nice to find a
- * way to consolidate these functions! */
-void
-_cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer)
-{
-  CoglPipelineLayer *new_parent = _cogl_pipeline_layer_get_parent (layer);
-
-  /* walk up past ancestors that are now redundant and potentially
-   * reparent the layer. */
-  while (_cogl_pipeline_layer_get_parent (new_parent) &&
-         (new_parent->differences | layer->differences) ==
-         layer->differences)
-    new_parent = _cogl_pipeline_layer_get_parent (new_parent);
-
-  _cogl_pipeline_layer_set_parent (layer, new_parent);
-}
-
 typedef struct
 {
   /* The layer we are trying to find */
@@ -2249,227 +1883,6 @@ _cogl_pipeline_apply_overrides (CoglPipeline *pipeline,
     }
 }
 
-/* Determine the mask of differences between two layers.
- *
- * XXX: If layers and pipelines could both be cast to a common Tree
- * type of some kind then we could have a unified
- * compare_differences() function.
- */
-unsigned long
-_cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
-                                          CoglPipelineLayer *layer1)
-{
-  CoglPipelineLayer *node0;
-  CoglPipelineLayer *node1;
-  int len0;
-  int len1;
-  int len0_index;
-  int len1_index;
-  int count;
-  int i;
-  CoglPipelineLayer *common_ancestor = NULL;
-  unsigned long layers_difference = 0;
-
-  _COGL_GET_CONTEXT (ctx, 0);
-
-  /* Algorithm:
-   *
-   * 1) Walk the ancestors of each layer to the root node, adding a
-   *    pointer to each ancester node to two GArrays:
-   *    ctx->pipeline0_nodes, and ctx->pipeline1_nodes.
-   *
-   * 2) Compare the arrays to find the nodes where they stop to
-   *    differ.
-   *
-   * 3) For each array now iterate from index 0 to the first node of
-   *    difference ORing that nodes ->difference mask into the final
-   *    pipeline_differences mask.
-   */
-
-  g_array_set_size (ctx->pipeline0_nodes, 0);
-  g_array_set_size (ctx->pipeline1_nodes, 0);
-  for (node0 = layer0; node0; node0 = _cogl_pipeline_layer_get_parent (node0))
-    g_array_append_vals (ctx->pipeline0_nodes, &node0, 1);
-  for (node1 = layer1; node1; node1 = _cogl_pipeline_layer_get_parent (node1))
-    g_array_append_vals (ctx->pipeline1_nodes, &node1, 1);
-
-  len0 = ctx->pipeline0_nodes->len;
-  len1 = ctx->pipeline1_nodes->len;
-  /* There's no point looking at the last entries since we know both
-   * layers must have the same default layer as their root node. */
-  len0_index = len0 - 2;
-  len1_index = len1 - 2;
-  count = MIN (len0, len1) - 1;
-  for (i = 0; i < count; i++)
-    {
-      node0 = g_array_index (ctx->pipeline0_nodes,
-                             CoglPipelineLayer *, len0_index--);
-      node1 = g_array_index (ctx->pipeline1_nodes,
-                             CoglPipelineLayer *, len1_index--);
-      if (node0 != node1)
-        {
-          common_ancestor = _cogl_pipeline_layer_get_parent (node0);
-          break;
-        }
-    }
-
-  /* If we didn't already find the first the common_ancestor ancestor
-   * that's because one pipeline is a direct descendant of the other
-   * and in this case the first common ancestor is the last node we
-   * looked at. */
-  if (!common_ancestor)
-    common_ancestor = node0;
-
-  count = len0 - 1;
-  for (i = 0; i < count; i++)
-    {
-      node0 = g_array_index (ctx->pipeline0_nodes, CoglPipelineLayer *, i);
-      if (node0 == common_ancestor)
-        break;
-      layers_difference |= node0->differences;
-    }
-
-  count = len1 - 1;
-  for (i = 0; i < count; i++)
-    {
-      node1 = g_array_index (ctx->pipeline1_nodes, CoglPipelineLayer *, i);
-      if (node1 == common_ancestor)
-        break;
-      layers_difference |= node1->differences;
-    }
-
-  return layers_difference;
-}
-
-static gboolean
-layer_state_equal (CoglPipelineLayerStateIndex state_index,
-                   CoglPipelineLayer **authorities0,
-                   CoglPipelineLayer **authorities1,
-                   CoglPipelineLayerStateComparitor comparitor)
-{
-  return comparitor (authorities0[state_index], authorities1[state_index]);
-}
-
-static void
-_cogl_pipeline_layer_resolve_authorities (CoglPipelineLayer *layer,
-                                          unsigned long differences,
-                                          CoglPipelineLayer **authorities)
-{
-  unsigned long remaining = differences;
-  CoglPipelineLayer *authority = layer;
-
-  do
-    {
-      unsigned long found = authority->differences & remaining;
-      int i;
-
-      if (found == 0)
-        continue;
-
-      for (i = 0; TRUE; i++)
-        {
-          unsigned long state = (1L<<i);
-
-          if (state & found)
-            authorities[i] = authority;
-          else if (state > found)
-            break;
-        }
-
-      remaining &= ~found;
-      if (remaining == 0)
-        return;
-    }
-  while ((authority = _cogl_pipeline_layer_get_parent (authority)));
-
-  g_assert (remaining == 0);
-}
-
-static gboolean
-_cogl_pipeline_layer_equal (CoglPipelineLayer *layer0,
-                            CoglPipelineLayer *layer1,
-                            unsigned long differences_mask,
-                            CoglPipelineEvalFlags flags)
-{
-  unsigned long layers_difference;
-  CoglPipelineLayer *authorities0[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
-  CoglPipelineLayer *authorities1[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
-
-  if (layer0 == layer1)
-    return TRUE;
-
-  layers_difference =
-    _cogl_pipeline_layer_compare_differences (layer0, layer1);
-
-  /* Only compare the sparse state groups requested by the caller... */
-  layers_difference &= differences_mask;
-
-  _cogl_pipeline_layer_resolve_authorities (layer0,
-                                            layers_difference,
-                                            authorities0);
-  _cogl_pipeline_layer_resolve_authorities (layer1,
-                                            layers_difference,
-                                            authorities1);
-
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET)
-    {
-      CoglPipelineLayerStateIndex state_index =
-        COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX;
-      if (!_cogl_pipeline_layer_texture_target_equal (authorities0[state_index],
-                                                      authorities1[state_index],
-                                                      flags))
-        return FALSE;
-    }
-
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
-    {
-      CoglPipelineLayerStateIndex state_index =
-        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX;
-      if (!_cogl_pipeline_layer_texture_data_equal (authorities0[state_index],
-                                                    authorities1[state_index],
-                                                    flags))
-        return FALSE;
-    }
-
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE &&
-      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
-                          authorities0, authorities1,
-                          _cogl_pipeline_layer_combine_state_equal))
-    return FALSE;
-
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT &&
-      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
-                          authorities0, authorities1,
-                          _cogl_pipeline_layer_combine_constant_equal))
-    return FALSE;
-
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_FILTERS &&
-      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
-                          authorities0, authorities1,
-                          _cogl_pipeline_layer_filters_equal))
-    return FALSE;
-
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_WRAP_MODES &&
-      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
-                          authorities0, authorities1,
-                          _cogl_pipeline_layer_wrap_modes_equal))
-    return FALSE;
-
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX &&
-      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
-                          authorities0, authorities1,
-                          _cogl_pipeline_layer_user_matrix_equal))
-    return FALSE;
-
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS &&
-      !layer_state_equal (COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
-                          authorities0, authorities1,
-                          _cogl_pipeline_layer_point_sprite_coords_equal))
-    return FALSE;
-
-  return TRUE;
-}
-
 static gboolean
 _cogl_pipeline_layers_equal (CoglPipeline *authority0,
                              CoglPipeline *authority1,
@@ -2899,158 +2312,6 @@ _cogl_pipeline_get_age (CoglPipeline *pipeline)
   return pipeline->age;
 }
 
-static CoglPipelineLayer *
-_cogl_pipeline_layer_copy (CoglPipelineLayer *src)
-{
-  CoglPipelineLayer *layer = g_slice_new (CoglPipelineLayer);
-
-  _cogl_pipeline_node_init (COGL_PIPELINE_NODE (layer));
-
-  layer->owner = NULL;
-  layer->index = src->index;
-  layer->differences = 0;
-  layer->has_big_state = FALSE;
-
-  _cogl_pipeline_layer_set_parent (layer, src);
-
-  return _cogl_pipeline_layer_object_new (layer);
-}
-
-static void
-_cogl_pipeline_layer_free (CoglPipelineLayer *layer)
-{
-  _cogl_pipeline_layer_unparent (COGL_PIPELINE_NODE (layer));
-
-  if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA &&
-      layer->texture != NULL)
-    cogl_object_unref (layer->texture);
-
-  if (layer->differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE)
-    g_slice_free (CoglPipelineLayerBigState, layer->big_state);
-
-  g_slice_free (CoglPipelineLayer, layer);
-}
-
-  /* If a layer has descendants we can't modify it freely
-   *
-   * If the layer is owned and the owner has descendants we can't
-   * modify it freely.
-   *
-   * In both cases when we can't freely modify a layer we can either:
-   * - create a new layer; splice it in to replace the layer so it can
-   *   be directly modified.
-   *   XXX: disadvantage is that we have to invalidate the layers_cache
-   *   for the owner and its descendants.
-   * - create a new derived layer and modify that.
-   */
-
-  /* XXX: how is the caller expected to deal with ref-counting?
-   *
-   * If the layer can't be freely modified and we return a new layer
-   * then that will effectively make the caller own a new reference
-   * which doesn't happen if we simply modify the given layer.
-   *
-   * We could make it consistent by taking a reference on the layer if
-   * we don't create a new one. At least this way the caller could
-   * deal with it consistently, though the semantics are a bit
-   * strange.
-   *
-   * Alternatively we could leave it to the caller to check
-   * ...?
-   */
-
-void
-_cogl_pipeline_init_default_layers (void)
-{
-  CoglPipelineLayer *layer = g_slice_new0 (CoglPipelineLayer);
-  CoglPipelineLayerBigState *big_state =
-    g_slice_new0 (CoglPipelineLayerBigState);
-  CoglPipelineLayer *new;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  _cogl_pipeline_node_init (COGL_PIPELINE_NODE (layer));
-
-  layer->index = 0;
-
-  layer->differences = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE;
-
-  layer->unit_index = 0;
-
-  layer->texture = NULL;
-  layer->target = 0;
-
-  layer->mag_filter = COGL_PIPELINE_FILTER_LINEAR;
-  layer->min_filter = COGL_PIPELINE_FILTER_LINEAR;
-
-  layer->wrap_mode_s = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
-  layer->wrap_mode_t = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
-  layer->wrap_mode_p = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
-
-  layer->big_state = big_state;
-  layer->has_big_state = TRUE;
-
-  /* Choose the same default combine mode as OpenGL:
-   * RGBA = MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */
-  big_state->texture_combine_rgb_func =
-    COGL_PIPELINE_COMBINE_FUNC_MODULATE;
-  big_state->texture_combine_rgb_src[0] =
-    COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
-  big_state->texture_combine_rgb_src[1] =
-    COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
-  big_state->texture_combine_rgb_op[0] =
-    COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
-  big_state->texture_combine_rgb_op[1] =
-    COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
-  big_state->texture_combine_alpha_func =
-    COGL_PIPELINE_COMBINE_FUNC_MODULATE;
-  big_state->texture_combine_alpha_src[0] =
-    COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
-  big_state->texture_combine_alpha_src[1] =
-    COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
-  big_state->texture_combine_alpha_op[0] =
-    COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
-  big_state->texture_combine_alpha_op[1] =
-    COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
-
-  big_state->point_sprite_coords = FALSE;
-
-  cogl_matrix_init_identity (&big_state->matrix);
-
-  ctx->default_layer_0 = _cogl_pipeline_layer_object_new (layer);
-
-  /* TODO: we should make default_layer_n comprise of two
-   * descendants of default_layer_0:
-   * - the first descendant should change the texture combine
-   *   to what we expect is most commonly used for multitexturing
-   * - the second should revert the above change.
-   *
-   * why? the documentation for how a new layer is initialized
-   * doesn't say that layers > 0 have different defaults so unless
-   * we change the documentation we can't use different defaults,
-   * but if the user does what we expect and changes the
-   * texture combine then we can revert the authority to the
-   * first descendant which means we can maximize the number
-   * of layers with a common ancestor.
-   *
-   * The main problem will be that we'll need to disable the
-   * optimizations for flattening the ancestry when we make
-   * the second descendant which reverts the state.
-   */
-  ctx->default_layer_n = _cogl_pipeline_layer_copy (layer);
-  new = _cogl_pipeline_set_layer_unit (NULL, ctx->default_layer_n, 1);
-  g_assert (new == ctx->default_layer_n);
-  /* Since we passed a newly allocated layer we don't expect that
-   * _set_layer_unit() will have to allocate *another* layer. */
-
-  /* Finally we create a dummy dependant for ->default_layer_n which
-   * effectively ensures that ->default_layer_n and ->default_layer_0
-   * remain immutable.
-   */
-  ctx->dummy_layer_dependant =
-    _cogl_pipeline_layer_copy (ctx->default_layer_n);
-}
-
 void
 cogl_pipeline_remove_layer (CoglPipeline *pipeline, int layer_index)
 {
@@ -3153,33 +2414,6 @@ cogl_pipeline_get_n_layers (CoglPipeline *pipeline)
 }
 
 void
-_cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layer)
-{
-  CoglPipelineLayer *texture_authority;
-
-  texture_authority =
-    _cogl_pipeline_layer_get_authority (layer,
-                                        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
-
-  if (texture_authority->texture != NULL)
-    {
-      CoglTexturePrePaintFlags flags = 0;
-      CoglPipelineFilter min_filter;
-      CoglPipelineFilter mag_filter;
-
-      _cogl_pipeline_layer_get_filters (layer, &min_filter, &mag_filter);
-
-      if (min_filter == COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST
-          || min_filter == COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST
-          || min_filter == COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR
-          || min_filter == COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR)
-        flags |= COGL_TEXTURE_NEEDS_MIPMAP;
-
-      _cogl_texture_pre_paint (texture_authority->texture, flags);
-    }
-}
-
-void
 _cogl_pipeline_pre_paint_for_layer (CoglPipeline *pipeline,
                                     int layer_id)
 {
@@ -3444,253 +2678,6 @@ _cogl_pipeline_hash (CoglPipeline *pipeline,
 
 typedef struct
 {
-  int parent_id;
-  int *node_id_ptr;
-  GString *graph;
-  int indent;
-} PrintDebugState;
-
-static gboolean
-dump_layer_cb (CoglPipelineNode *node, void *user_data)
-{
-  CoglPipelineLayer *layer = COGL_PIPELINE_LAYER (node);
-  PrintDebugState *state = user_data;
-  int layer_id = *state->node_id_ptr;
-  PrintDebugState state_out;
-  GString *changes_label;
-  gboolean changes = FALSE;
-
-  if (state->parent_id >= 0)
-    g_string_append_printf (state->graph, "%*slayer%p -> layer%p;\n",
-                            state->indent, "",
-                            layer->_parent.parent,
-                            layer);
-
-  g_string_append_printf (state->graph,
-                          "%*slayer%p [label=\"layer=0x%p\\n"
-                          "ref count=%d\" "
-                          "color=\"blue\"];\n",
-                          state->indent, "",
-                          layer,
-                          layer,
-                          COGL_OBJECT (layer)->ref_count);
-
-  changes_label = g_string_new ("");
-  g_string_append_printf (changes_label,
-                          "%*slayer%p -> layer_state%d [weight=100];\n"
-                          "%*slayer_state%d [shape=box label=\"",
-                          state->indent, "",
-                          layer,
-                          layer_id,
-                          state->indent, "",
-                          layer_id);
-
-  if (layer->differences & COGL_PIPELINE_LAYER_STATE_UNIT)
-    {
-      changes = TRUE;
-      g_string_append_printf (changes_label,
-                              "\\lunit=%u\\n",
-                              layer->unit_index);
-    }
-
-  if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
-    {
-      changes = TRUE;
-      g_string_append_printf (changes_label,
-                              "\\ltexture=%p\\n",
-                              layer->texture);
-    }
-
-  if (changes)
-    {
-      g_string_append_printf (changes_label, "\"];\n");
-      g_string_append (state->graph, changes_label->str);
-      g_string_free (changes_label, TRUE);
-    }
-
-  state_out.parent_id = layer_id;
-
-  state_out.node_id_ptr = state->node_id_ptr;
-  (*state_out.node_id_ptr)++;
-
-  state_out.graph = state->graph;
-  state_out.indent = state->indent + 2;
-
-  _cogl_pipeline_node_foreach_child (COGL_PIPELINE_NODE (layer),
-                                     dump_layer_cb,
-                                     &state_out);
-
-  return TRUE;
-}
-
-static gboolean
-dump_layer_ref_cb (CoglPipelineLayer *layer, void *data)
-{
-  PrintDebugState *state = data;
-  int pipeline_id = *state->node_id_ptr;
-
-  g_string_append_printf (state->graph,
-                          "%*spipeline_state%d -> layer%p;\n",
-                          state->indent, "",
-                          pipeline_id,
-                          layer);
-
-  return TRUE;
-}
-
-static gboolean
-dump_pipeline_cb (CoglPipelineNode *node, void *user_data)
-{
-  CoglPipeline *pipeline = COGL_PIPELINE (node);
-  PrintDebugState *state = user_data;
-  int pipeline_id = *state->node_id_ptr;
-  PrintDebugState state_out;
-  GString *changes_label;
-  gboolean changes = FALSE;
-  gboolean layers = FALSE;
-
-  if (state->parent_id >= 0)
-    g_string_append_printf (state->graph, "%*spipeline%d -> pipeline%d;\n",
-                            state->indent, "",
-                            state->parent_id,
-                            pipeline_id);
-
-  g_string_append_printf (state->graph,
-                          "%*spipeline%d [label=\"pipeline=0x%p\\n"
-                          "ref count=%d\\n"
-                          "breadcrumb=\\\"%s\\\"\" color=\"red\"];\n",
-                          state->indent, "",
-                          pipeline_id,
-                          pipeline,
-                          COGL_OBJECT (pipeline)->ref_count,
-                          pipeline->has_static_breadcrumb ?
-                          pipeline->static_breadcrumb : "NULL");
-
-  changes_label = g_string_new ("");
-  g_string_append_printf (changes_label,
-                          "%*spipeline%d -> pipeline_state%d [weight=100];\n"
-                          "%*spipeline_state%d [shape=box label=\"",
-                          state->indent, "",
-                          pipeline_id,
-                          pipeline_id,
-                          state->indent, "",
-                          pipeline_id);
-
-
-  if (pipeline->differences & COGL_PIPELINE_STATE_COLOR)
-    {
-      changes = TRUE;
-      g_string_append_printf (changes_label,
-                              "\\lcolor=0x%02X%02X%02X%02X\\n",
-                              cogl_color_get_red_byte (&pipeline->color),
-                              cogl_color_get_green_byte (&pipeline->color),
-                              cogl_color_get_blue_byte (&pipeline->color),
-                              cogl_color_get_alpha_byte (&pipeline->color));
-    }
-
-  if (pipeline->differences & COGL_PIPELINE_STATE_BLEND)
-    {
-      const char *blend_enable_name;
-
-      changes = TRUE;
-
-      switch (pipeline->blend_enable)
-        {
-        case COGL_PIPELINE_BLEND_ENABLE_AUTOMATIC:
-          blend_enable_name = "AUTO";
-          break;
-        case COGL_PIPELINE_BLEND_ENABLE_ENABLED:
-          blend_enable_name = "ENABLED";
-          break;
-        case COGL_PIPELINE_BLEND_ENABLE_DISABLED:
-          blend_enable_name = "DISABLED";
-          break;
-        default:
-          blend_enable_name = "UNKNOWN";
-        }
-      g_string_append_printf (changes_label,
-                              "\\lblend=%s\\n",
-                              blend_enable_name);
-    }
-
-  if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
-    {
-      changes = TRUE;
-      layers = TRUE;
-      g_string_append_printf (changes_label, "\\ln_layers=%d\\n",
-                              pipeline->n_layers);
-    }
-
-  if (changes)
-    {
-      g_string_append_printf (changes_label, "\"];\n");
-      g_string_append (state->graph, changes_label->str);
-      g_string_free (changes_label, TRUE);
-    }
-
-  if (layers)
-    {
-      g_list_foreach (pipeline->layer_differences,
-                      (GFunc)dump_layer_ref_cb,
-                      state);
-    }
-
-  state_out.parent_id = pipeline_id;
-
-  state_out.node_id_ptr = state->node_id_ptr;
-  (*state_out.node_id_ptr)++;
-
-  state_out.graph = state->graph;
-  state_out.indent = state->indent + 2;
-
-  _cogl_pipeline_node_foreach_child (COGL_PIPELINE_NODE (pipeline),
-                                     dump_pipeline_cb,
-                                     &state_out);
-
-  return TRUE;
-}
-
-void
-_cogl_debug_dump_pipelines_dot_file (const char *filename)
-{
-  GString *graph;
-  PrintDebugState layer_state;
-  PrintDebugState pipeline_state;
-  int layer_id = 0;
-  int pipeline_id = 0;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  if (!ctx->default_pipeline)
-    return;
-
-  graph = g_string_new ("");
-  g_string_append_printf (graph, "digraph {\n");
-
-  layer_state.graph = graph;
-  layer_state.parent_id = -1;
-  layer_state.node_id_ptr = &layer_id;
-  layer_state.indent = 0;
-  dump_layer_cb (ctx->default_layer_0, &layer_state);
-
-  pipeline_state.graph = graph;
-  pipeline_state.parent_id = -1;
-  pipeline_state.node_id_ptr = &pipeline_id;
-  pipeline_state.indent = 0;
-  dump_pipeline_cb (ctx->default_pipeline, &pipeline_state);
-
-  g_string_append_printf (graph, "}\n");
-
-  if (filename)
-    g_file_set_contents (filename, graph->str, -1, NULL);
-  else
-    g_print ("%s", graph->str);
-
-  g_string_free (graph, TRUE);
-}
-
-typedef struct
-{
   int i;
   CoglPipelineLayer **layers;
 } AddLayersToArrayState;
@@ -3704,80 +2691,6 @@ add_layer_to_array_cb (CoglPipelineLayer *layer,
   return TRUE;
 }
 
-/* Determines if we need to handle the RGB and A texture combining
- * separately or is the same function used for both channel masks and
- * with the same arguments...
- */
-gboolean
-_cogl_pipeline_need_texture_combine_separate
-                                       (CoglPipelineLayer *combine_authority)
-{
-  CoglPipelineLayerBigState *big_state = combine_authority->big_state;
-  int n_args;
-  int i;
-
-  if (big_state->texture_combine_rgb_func !=
-      big_state->texture_combine_alpha_func)
-    return TRUE;
-
-  n_args = _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func);
-
-  for (i = 0; i < n_args; i++)
-    {
-      if (big_state->texture_combine_rgb_src[i] !=
-          big_state->texture_combine_alpha_src[i])
-        return TRUE;
-
-      /*
-       * We can allow some variation of the source operands without
-       * needing a separation...
-       *
-       * "A = REPLACE (CONSTANT[A])" + either of the following...
-       * "RGB = REPLACE (CONSTANT[RGB])"
-       * "RGB = REPLACE (CONSTANT[A])"
-       *
-       * can be combined as:
-       * "RGBA = REPLACE (CONSTANT)" or
-       * "RGBA = REPLACE (CONSTANT[A])" or
-       *
-       * And "A = REPLACE (1-CONSTANT[A])" + either of the following...
-       * "RGB = REPLACE (1-CONSTANT)" or
-       * "RGB = REPLACE (1-CONSTANT[A])"
-       *
-       * can be combined as:
-       * "RGBA = REPLACE (1-CONSTANT)" or
-       * "RGBA = REPLACE (1-CONSTANT[A])"
-       */
-      switch (big_state->texture_combine_alpha_op[i])
-        {
-        case GL_SRC_ALPHA:
-          switch (big_state->texture_combine_rgb_op[i])
-            {
-            case GL_SRC_COLOR:
-            case GL_SRC_ALPHA:
-              break;
-            default:
-              return FALSE;
-            }
-          break;
-        case GL_ONE_MINUS_SRC_ALPHA:
-          switch (big_state->texture_combine_rgb_op[i])
-            {
-            case GL_ONE_MINUS_SRC_COLOR:
-            case GL_ONE_MINUS_SRC_ALPHA:
-              break;
-            default:
-              return FALSE;
-            }
-          break;
-        default:
-          return FALSE;	/* impossible */
-        }
-    }
-
-   return FALSE;
-}
-
 /* This tries to find the oldest ancestor whose pipeline and layer
    state matches the given flags. This is mostly used to detect code
    gen authorities so that we can reduce the numer of programs
diff --git a/cogl/cogl-pipeline.h b/cogl/cogl-pipeline.h
index 38cef52..d93c6f8 100644
--- a/cogl/cogl-pipeline.h
+++ b/cogl/cogl-pipeline.h
@@ -28,10 +28,10 @@
 #ifndef __COGL_PIPELINE_H__
 #define __COGL_PIPELINE_H__
 
-G_BEGIN_DECLS
-
 #include <cogl/cogl-types.h>
 
+G_BEGIN_DECLS
+
 #ifdef COGL_ENABLE_EXPERIMENTAL_API
 
 /**
@@ -47,7 +47,6 @@ G_BEGIN_DECLS
  * performs fragment processing including depth testing and texture
  * mapping. Finally it blends the result with the framebuffer.
  */
-
 typedef struct _CoglPipeline	      CoglPipeline;
 
 #define COGL_PIPELINE(OBJECT) ((CoglPipeline *)OBJECT)
diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h
index 12a6b74..295e279 100644
--- a/cogl/cogl-texture.h
+++ b/cogl/cogl-texture.h
@@ -33,6 +33,7 @@
 #if defined (COGL_ENABLE_EXPERIMENTAL_API)
 #include <cogl/cogl-pixel-buffer.h>
 #endif
+#include <cogl/cogl-bitmap.h>
 
 G_BEGIN_DECLS
 
diff --git a/configure.ac b/configure.ac
index 0eab6f3..04becb0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -939,6 +939,8 @@ AC_SUBST(COGL_GL_HEADER_INCLUDES)
 
 AC_DEFINE([COGL_ENABLE_EXPERIMENTAL_2_0_API], [1],
           [Can use Cogl 2.0 API internally])
+AC_DEFINE([COGL_ENABLE_EXPERIMENTAL_API], [1],
+          [Can use experimental API internally])
 
 AC_SUBST(COGL_DEP_CFLAGS)
 AC_SUBST(COGL_DEP_LIBS)



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