Blame SOURCES/cogl-1.14.0-21-ge26464f.patch

21ac67
Only things missing here from upstream are translations and .gitignore changes
21ac67
21ac67
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
21ac67
index 33214ab..80d3b09 100644
21ac67
--- a/cogl/Makefile.am
21ac67
+++ b/cogl/Makefile.am
21ac67
@@ -349,6 +349,8 @@ cogl_sources_c = \
21ac67
 	$(srcdir)/cogl-pipeline-snippet.c		\
21ac67
 	$(srcdir)/cogl-pipeline-cache.h			\
21ac67
 	$(srcdir)/cogl-pipeline-cache.c			\
21ac67
+	$(srcdir)/cogl-pipeline-hash-table.h		\
21ac67
+	$(srcdir)/cogl-pipeline-hash-table.c		\
21ac67
 	$(srcdir)/cogl-material-compat.c		\
21ac67
 	$(srcdir)/cogl-program.c			\
21ac67
 	$(srcdir)/cogl-program-private.h		\
21ac67
@@ -552,7 +554,7 @@ include $(top_srcdir)/build/autotools/Makefile.am.enums
21ac67
 
21ac67
 lib_LTLIBRARIES += libcogl.la
21ac67
 
21ac67
-libcogl_la_LIBADD = -lm $(COGL_DEP_LIBS) $(COGL_EXTRA_LDFLAGS)
21ac67
+libcogl_la_LIBADD = $(LIBM) $(COGL_DEP_LIBS) $(COGL_EXTRA_LDFLAGS)
21ac67
 if !USE_GLIB
21ac67
 libcogl_la_LIBADD += $(top_builddir)/deps/glib/libglib.la
21ac67
 libcogl_la_LIBADD += $(top_builddir)/deps/gmodule/libgmodule.la
21ac67
diff --git a/cogl/cogl-bitmap-pixbuf.c b/cogl/cogl-bitmap-pixbuf.c
21ac67
index a02b253..ad34234 100644
21ac67
--- a/cogl/cogl-bitmap-pixbuf.c
21ac67
+++ b/cogl/cogl-bitmap-pixbuf.c
21ac67
@@ -125,11 +125,24 @@ _cogl_bitmap_from_file (CoglContext *ctx,
21ac67
   /* allocate buffer big enough to hold pixel data */
21ac67
   bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
21ac67
                                              width, height,
21ac67
-                                             COGL_PIXEL_FORMAT_ARGB_8888);
21ac67
+                                             COGL_PIXEL_FORMAT_ARGB_8888,
21ac67
+                                             error);
21ac67
+  if (bmp == NULL)
21ac67
+    {
21ac67
+      CFRelease (image);
21ac67
+      return NULL;
21ac67
+    }
21ac67
   rowstride = cogl_bitmap_get_rowstride (bmp);
21ac67
   out_data = _cogl_bitmap_map (bmp,
21ac67
                                COGL_BUFFER_ACCESS_WRITE,
21ac67
-                               COGL_BUFFER_MAP_HINT_DISCARD);
21ac67
+                               COGL_BUFFER_MAP_HINT_DISCARD,
21ac67
+                               error);
21ac67
+  if (out_data == NULL)
21ac67
+    {
21ac67
+      cogl_object_unref (bmp);
21ac67
+      CFRelease (image);
21ac67
+      return NULL;
21ac67
+    }
21ac67
 
21ac67
   /* render to buffer */
21ac67
   color_space = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
21ac67
diff --git a/cogl/cogl-matrix.h b/cogl/cogl-matrix.h
21ac67
index 90f3ea9..a136ea0 100644
21ac67
--- a/cogl/cogl-matrix.h
21ac67
+++ b/cogl/cogl-matrix.h
21ac67
@@ -27,6 +27,8 @@
21ac67
 #ifndef __COGL_MATRIX_H
21ac67
 #define __COGL_MATRIX_H
21ac67
 
21ac67
+#include <cogl/cogl-defines.h>
21ac67
+
21ac67
 #ifdef COGL_HAS_GTYPE_SUPPORT
21ac67
 #include <glib-object.h>
21ac67
 #endif /* COGL_HAS_GTYPE_SUPPORT */
21ac67
diff --git a/cogl/cogl-pipeline-cache.c b/cogl/cogl-pipeline-cache.c
21ac67
index fab3614..df4c433 100644
21ac67
--- a/cogl/cogl-pipeline-cache.c
21ac67
+++ b/cogl/cogl-pipeline-cache.c
21ac67
@@ -3,7 +3,7 @@
21ac67
  *
21ac67
  * An object oriented GL/GLES Abstraction/Utility Layer
21ac67
  *
21ac67
- * Copyright (C) 2011 Intel Corporation.
21ac67
+ * Copyright (C) 2011, 2013 Intel Corporation.
21ac67
  *
21ac67
  * This library is free software; you can redistribute it and/or
21ac67
  * modify it under the terms of the GNU Lesser General Public
21ac67
@@ -32,133 +32,47 @@
21ac67
 #include "cogl-context-private.h"
21ac67
 #include "cogl-pipeline-private.h"
21ac67
 #include "cogl-pipeline-cache.h"
21ac67
+#include "cogl-pipeline-hash-table.h"
21ac67
 
21ac67
 struct _CoglPipelineCache
21ac67
 {
21ac67
-  GHashTable *fragment_hash;
21ac67
-  GHashTable *vertex_hash;
21ac67
-  GHashTable *combined_hash;
21ac67
+  CoglPipelineHashTable fragment_hash;
21ac67
+  CoglPipelineHashTable vertex_hash;
21ac67
+  CoglPipelineHashTable combined_hash;
21ac67
 };
21ac67
 
21ac67
-static unsigned int
21ac67
-pipeline_fragment_hash (const void *data)
21ac67
-{
21ac67
-  unsigned int fragment_state;
21ac67
-  unsigned int layer_fragment_state;
21ac67
-
21ac67
-  _COGL_GET_CONTEXT (ctx, 0);
21ac67
-
21ac67
-  fragment_state =
21ac67
-    _cogl_pipeline_get_state_for_fragment_codegen (ctx);
21ac67
-  layer_fragment_state =
21ac67
-    _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx);
21ac67
-
21ac67
-  return _cogl_pipeline_hash ((CoglPipeline *)data,
21ac67
-                              fragment_state, layer_fragment_state,
21ac67
-                              0);
21ac67
-}
21ac67
-
21ac67
-static CoglBool
21ac67
-pipeline_fragment_equal (const void *a, const void *b)
21ac67
+CoglPipelineCache *
21ac67
+_cogl_pipeline_cache_new (void)
21ac67
 {
21ac67
+  CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
21ac67
+  unsigned long vertex_state;
21ac67
+  unsigned long layer_vertex_state;
21ac67
   unsigned int fragment_state;
21ac67
   unsigned int layer_fragment_state;
21ac67
 
21ac67
   _COGL_GET_CONTEXT (ctx, 0);
21ac67
 
21ac67
+  vertex_state =
21ac67
+    COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
+  layer_vertex_state =
21ac67
+    COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
   fragment_state =
21ac67
     _cogl_pipeline_get_state_for_fragment_codegen (ctx);
21ac67
   layer_fragment_state =
21ac67
     _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx);
21ac67
 
21ac67
-  return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b,
21ac67
-                               fragment_state, layer_fragment_state,
21ac67
-                               0);
21ac67
-}
21ac67
-
21ac67
-static unsigned int
21ac67
-pipeline_vertex_hash (const void *data)
21ac67
-{
21ac67
-  unsigned long vertex_state =
21ac67
-    COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
-  unsigned long layer_vertex_state =
21ac67
-    COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
-
21ac67
-  return _cogl_pipeline_hash ((CoglPipeline *)data,
21ac67
-                              vertex_state, layer_vertex_state,
21ac67
-                              0);
21ac67
-}
21ac67
-
21ac67
-static CoglBool
21ac67
-pipeline_vertex_equal (const void *a, const void *b)
21ac67
-{
21ac67
-  unsigned long vertex_state =
21ac67
-    COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
-  unsigned long layer_vertex_state =
21ac67
-    COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
-
21ac67
-  return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b,
21ac67
-                               vertex_state, layer_vertex_state,
21ac67
-                               0);
21ac67
-}
21ac67
-
21ac67
-static unsigned int
21ac67
-pipeline_combined_hash (const void *data)
21ac67
-{
21ac67
-  unsigned int combined_state;
21ac67
-  unsigned int layer_combined_state;
21ac67
-
21ac67
-  _COGL_GET_CONTEXT (ctx, 0);
21ac67
-
21ac67
-  combined_state =
21ac67
-    _cogl_pipeline_get_state_for_fragment_codegen (ctx) |
21ac67
-    COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
-  layer_combined_state =
21ac67
-    _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) |
21ac67
-    COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
-
21ac67
-  return _cogl_pipeline_hash ((CoglPipeline *)data,
21ac67
-                              combined_state, layer_combined_state,
21ac67
-                              0);
21ac67
-}
21ac67
-
21ac67
-static CoglBool
21ac67
-pipeline_combined_equal (const void *a, const void *b)
21ac67
-{
21ac67
-  unsigned int combined_state;
21ac67
-  unsigned int layer_combined_state;
21ac67
-
21ac67
-  _COGL_GET_CONTEXT (ctx, 0);
21ac67
-
21ac67
-  combined_state =
21ac67
-    _cogl_pipeline_get_state_for_fragment_codegen (ctx) |
21ac67
-    COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
-  layer_combined_state =
21ac67
-    _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) |
21ac67
-    COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
21ac67
-
21ac67
-  return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b,
21ac67
-                               combined_state, layer_combined_state,
21ac67
-                               0);
21ac67
-}
21ac67
-
21ac67
-CoglPipelineCache *
21ac67
-_cogl_pipeline_cache_new (void)
21ac67
-{
21ac67
-  CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
21ac67
-
21ac67
-  cache->fragment_hash = g_hash_table_new_full (pipeline_fragment_hash,
21ac67
-                                                pipeline_fragment_equal,
21ac67
-                                                cogl_object_unref,
21ac67
-                                                cogl_object_unref);
21ac67
-  cache->vertex_hash = g_hash_table_new_full (pipeline_vertex_hash,
21ac67
-                                              pipeline_vertex_equal,
21ac67
-                                              cogl_object_unref,
21ac67
-                                              cogl_object_unref);
21ac67
-  cache->combined_hash = g_hash_table_new_full (pipeline_combined_hash,
21ac67
-                                                pipeline_combined_equal,
21ac67
-                                                cogl_object_unref,
21ac67
-                                                cogl_object_unref);
21ac67
+  _cogl_pipeline_hash_table_init (&cache->vertex_hash,
21ac67
+                                  vertex_state,
21ac67
+                                  layer_vertex_state,
21ac67
+                                  "vertex shaders");
21ac67
+  _cogl_pipeline_hash_table_init (&cache->fragment_hash,
21ac67
+                                  fragment_state,
21ac67
+                                  layer_fragment_state,
21ac67
+                                  "fragment shaders");
21ac67
+  _cogl_pipeline_hash_table_init (&cache->combined_hash,
21ac67
+                                  vertex_state | fragment_state,
21ac67
+                                  layer_vertex_state | layer_fragment_state,
21ac67
+                                  "programs");
21ac67
 
21ac67
   return cache;
21ac67
 }
21ac67
@@ -166,9 +80,9 @@ _cogl_pipeline_cache_new (void)
21ac67
 void
21ac67
 _cogl_pipeline_cache_free (CoglPipelineCache *cache)
21ac67
 {
21ac67
-  g_hash_table_destroy (cache->fragment_hash);
21ac67
-  g_hash_table_destroy (cache->vertex_hash);
21ac67
-  g_hash_table_destroy (cache->combined_hash);
21ac67
+  _cogl_pipeline_hash_table_destroy (&cache->fragment_hash);
21ac67
+  _cogl_pipeline_hash_table_destroy (&cache->vertex_hash);
21ac67
+  _cogl_pipeline_hash_table_destroy (&cache->combined_hash);
21ac67
   g_free (cache);
21ac67
 }
21ac67
 
21ac67
@@ -176,107 +90,22 @@ CoglPipeline *
21ac67
 _cogl_pipeline_cache_get_fragment_template (CoglPipelineCache *cache,
21ac67
                                             CoglPipeline *key_pipeline)
21ac67
 {
21ac67
-  CoglPipeline *template =
21ac67
-    g_hash_table_lookup (cache->fragment_hash, key_pipeline);
21ac67
-
21ac67
-  if (template == NULL)
21ac67
-    {
21ac67
-      /* XXX: I wish there was a way to insert into a GHashTable with
21ac67
-       * a pre-calculated hash value since there is a cost to
21ac67
-       * calculating the hash of a CoglPipeline and in this case we
21ac67
-       * know we have already called _cogl_pipeline_hash during the
21ac67
-       * lookup so we could pass the value through to here to avoid
21ac67
-       * hashing it again.
21ac67
-       */
21ac67
-
21ac67
-      /* XXX: Any keys referenced by the hash table need to remain
21ac67
-       * valid all the while that there are corresponding values,
21ac67
-       * so for now we simply make a copy of the current authority
21ac67
-       * pipeline.
21ac67
-       *
21ac67
-       * FIXME: A problem with this is that our key into the cache may
21ac67
-       * hold references to some arbitrary user textures which will
21ac67
-       * now be kept alive indefinitly which is a shame. A better
21ac67
-       * solution will be to derive a special "key pipeline" from the
21ac67
-       * authority which derives from the base Cogl pipeline (to avoid
21ac67
-       * affecting the lifetime of any other pipelines) and only takes
21ac67
-       * a copy of the state that relates to the fragment shader and
21ac67
-       * references small dummy textures instead of potentially large
21ac67
-       * user textures. */
21ac67
-      template = cogl_pipeline_copy (key_pipeline);
21ac67
-
21ac67
-      g_hash_table_insert (cache->fragment_hash,
21ac67
-                           template,
21ac67
-                           cogl_object_ref (template));
21ac67
-
21ac67
-      if (G_UNLIKELY (g_hash_table_size (cache->fragment_hash) > 50))
21ac67
-        {
21ac67
-          static CoglBool seen = FALSE;
21ac67
-          if (!seen)
21ac67
-            g_warning ("Over 50 separate fragment shaders have been "
21ac67
-                       "generated which is very unusual, so something "
21ac67
-                       "is probably wrong!\n");
21ac67
-          seen = TRUE;
21ac67
-        }
21ac67
-    }
21ac67
-
21ac67
-  return template;
21ac67
+  return _cogl_pipeline_hash_table_get (&cache->fragment_hash,
21ac67
+                                        key_pipeline);
21ac67
 }
21ac67
 
21ac67
 CoglPipeline *
21ac67
 _cogl_pipeline_cache_get_vertex_template (CoglPipelineCache *cache,
21ac67
                                           CoglPipeline *key_pipeline)
21ac67
 {
21ac67
-  CoglPipeline *template =
21ac67
-    g_hash_table_lookup (cache->vertex_hash, key_pipeline);
21ac67
-
21ac67
-  if (template == NULL)
21ac67
-    {
21ac67
-      template = cogl_pipeline_copy (key_pipeline);
21ac67
-
21ac67
-      g_hash_table_insert (cache->vertex_hash,
21ac67
-                           template,
21ac67
-                           cogl_object_ref (template));
21ac67
-
21ac67
-      if (G_UNLIKELY (g_hash_table_size (cache->vertex_hash) > 50))
21ac67
-        {
21ac67
-          static CoglBool seen = FALSE;
21ac67
-          if (!seen)
21ac67
-            g_warning ("Over 50 separate vertex shaders have been "
21ac67
-                       "generated which is very unusual, so something "
21ac67
-                       "is probably wrong!\n");
21ac67
-          seen = TRUE;
21ac67
-        }
21ac67
-    }
21ac67
-
21ac67
-  return template;
21ac67
+  return _cogl_pipeline_hash_table_get (&cache->vertex_hash,
21ac67
+                                        key_pipeline);
21ac67
 }
21ac67
 
21ac67
 CoglPipeline *
21ac67
 _cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache,
21ac67
                                             CoglPipeline *key_pipeline)
21ac67
 {
21ac67
-  CoglPipeline *template =
21ac67
-    g_hash_table_lookup (cache->combined_hash, key_pipeline);
21ac67
-
21ac67
-  if (template == NULL)
21ac67
-    {
21ac67
-      template = cogl_pipeline_copy (key_pipeline);
21ac67
-
21ac67
-      g_hash_table_insert (cache->combined_hash,
21ac67
-                           template,
21ac67
-                           cogl_object_ref (template));
21ac67
-
21ac67
-      if (G_UNLIKELY (g_hash_table_size (cache->combined_hash) > 50))
21ac67
-        {
21ac67
-          static CoglBool seen = FALSE;
21ac67
-          if (!seen)
21ac67
-            g_warning ("Over 50 separate programs have been "
21ac67
-                       "generated which is very unusual, so something "
21ac67
-                       "is probably wrong!\n");
21ac67
-          seen = TRUE;
21ac67
-        }
21ac67
-    }
21ac67
-
21ac67
-  return template;
21ac67
+  return _cogl_pipeline_hash_table_get (&cache->combined_hash,
21ac67
+                                        key_pipeline);
21ac67
 }
21ac67
diff --git a/cogl/cogl-pipeline-hash-table.c b/cogl/cogl-pipeline-hash-table.c
21ac67
new file mode 100644
21ac67
index 0000000..8921efc
21ac67
--- /dev/null
21ac67
+++ b/cogl/cogl-pipeline-hash-table.c
21ac67
@@ -0,0 +1,153 @@
21ac67
+/*
21ac67
+ * Cogl
21ac67
+ *
21ac67
+ * An object oriented GL/GLES Abstraction/Utility Layer
21ac67
+ *
21ac67
+ * Copyright (C) 2013 Intel Corporation.
21ac67
+ *
21ac67
+ * This library is free software; you can redistribute it and/or
21ac67
+ * modify it under the terms of the GNU Lesser General Public
21ac67
+ * License as published by the Free Software Foundation; either
21ac67
+ * version 2 of the License, or (at your option) any later version.
21ac67
+ *
21ac67
+ * This library is distributed in the hope that it will be useful,
21ac67
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
21ac67
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21ac67
+ * Lesser General Public License for more details.
21ac67
+ *
21ac67
+ * You should have received a copy of the GNU Lesser General Public
21ac67
+ * License along with this library. If not, see
21ac67
+ * <http://www.gnu.org/licenses/>.
21ac67
+ *
21ac67
+ *
21ac67
+ * Authors:
21ac67
+ *   Neil Roberts <neil@linux.intel.com>
21ac67
+ *   Robert Bragg <robert@linux.intel.com>
21ac67
+ */
21ac67
+
21ac67
+#ifdef HAVE_CONFIG_H
21ac67
+#include "config.h"
21ac67
+#endif
21ac67
+
21ac67
+#include "cogl-context-private.h"
21ac67
+#include "cogl-pipeline-private.h"
21ac67
+#include "cogl-pipeline-hash-table.h"
21ac67
+
21ac67
+typedef struct
21ac67
+{
21ac67
+  /* The template pipeline */
21ac67
+  CoglPipeline *pipeline;
21ac67
+
21ac67
+  /* Calculating the hash is a little bit expensive for pipelines so
21ac67
+   * we don't want to do it repeatedly for entries that are already in
21ac67
+   * the hash table. Instead we cache the value here and calculate it
21ac67
+   * outside of the GHashTable. */
21ac67
+  unsigned int hash_value;
21ac67
+
21ac67
+  /* GHashTable annoyingly doesn't let us pass a user data pointer to
21ac67
+   * the hash and equal functions so to work around it we have to
21ac67
+   * store the pointer in every hash table entry. We will use this
21ac67
+   * entry as both the key and the value */
21ac67
+  CoglPipelineHashTable *hash;
21ac67
+} CoglPipelineHashTableEntry;
21ac67
+
21ac67
+static void
21ac67
+value_destroy_cb (void *value)
21ac67
+{
21ac67
+  CoglPipelineHashTableEntry *entry = value;
21ac67
+
21ac67
+  cogl_object_unref (entry->pipeline);
21ac67
+
21ac67
+  g_slice_free (CoglPipelineHashTableEntry, entry);
21ac67
+}
21ac67
+
21ac67
+static unsigned int
21ac67
+entry_hash (const void *data)
21ac67
+{
21ac67
+  const CoglPipelineHashTableEntry *entry = data;
21ac67
+
21ac67
+  return entry->hash_value;
21ac67
+}
21ac67
+
21ac67
+static CoglBool
21ac67
+entry_equal (const void *a,
21ac67
+             const void *b)
21ac67
+{
21ac67
+  const CoglPipelineHashTableEntry *entry_a = a;
21ac67
+  const CoglPipelineHashTableEntry *entry_b = b;
21ac67
+  const CoglPipelineHashTable *hash = entry_a->hash;
21ac67
+
21ac67
+  return _cogl_pipeline_equal (entry_a->pipeline,
21ac67
+                               entry_b->pipeline,
21ac67
+                               hash->main_state,
21ac67
+                               hash->layer_state,
21ac67
+                               0);
21ac67
+}
21ac67
+
21ac67
+void
21ac67
+_cogl_pipeline_hash_table_init (CoglPipelineHashTable *hash,
21ac67
+                                unsigned int main_state,
21ac67
+                                unsigned int layer_state,
21ac67
+                                const char *debug_string)
21ac67
+{
21ac67
+  hash->n_unique_pipelines = 0;
21ac67
+  hash->debug_string = debug_string;
21ac67
+  hash->main_state = main_state;
21ac67
+  hash->layer_state = layer_state;
21ac67
+  hash->table = g_hash_table_new_full (entry_hash,
21ac67
+                                       entry_equal,
21ac67
+                                       NULL, /* key destroy */
21ac67
+                                       value_destroy_cb);
21ac67
+}
21ac67
+
21ac67
+void
21ac67
+_cogl_pipeline_hash_table_destroy (CoglPipelineHashTable *hash)
21ac67
+{
21ac67
+  g_hash_table_destroy (hash->table);
21ac67
+}
21ac67
+
21ac67
+CoglPipeline *
21ac67
+_cogl_pipeline_hash_table_get (CoglPipelineHashTable *hash,
21ac67
+                               CoglPipeline *key_pipeline)
21ac67
+{
21ac67
+  CoglPipelineHashTableEntry dummy_entry;
21ac67
+  CoglPipelineHashTableEntry *entry;
21ac67
+  unsigned int copy_state;
21ac67
+
21ac67
+  dummy_entry.pipeline = key_pipeline;
21ac67
+  dummy_entry.hash = hash;
21ac67
+  dummy_entry.hash_value = _cogl_pipeline_hash (key_pipeline,
21ac67
+                                                hash->main_state,
21ac67
+                                                hash->layer_state,
21ac67
+                                                0);
21ac67
+  entry = g_hash_table_lookup (hash->table, &dummy_entry);
21ac67
+
21ac67
+  if (entry)
21ac67
+    return entry->pipeline;
21ac67
+
21ac67
+  if (hash->n_unique_pipelines == 50)
21ac67
+    g_warning ("Over 50 separate %s have been generated which is very "
21ac67
+               "unusual, so something is probably wrong!\n",
21ac67
+               hash->debug_string);
21ac67
+
21ac67
+  entry = g_slice_new (CoglPipelineHashTableEntry);
21ac67
+  entry->hash = hash;
21ac67
+  entry->hash_value = dummy_entry.hash_value;
21ac67
+
21ac67
+  copy_state = hash->main_state;
21ac67
+  if (hash->layer_state)
21ac67
+    copy_state |= COGL_PIPELINE_STATE_LAYERS;
21ac67
+
21ac67
+  /* Create a new pipeline that is a child of the root pipeline
21ac67
+   * instead of a normal copy so that the template pipeline won't hold
21ac67
+   * a reference to the original pipeline */
21ac67
+  entry->pipeline = _cogl_pipeline_deep_copy (key_pipeline,
21ac67
+                                              copy_state,
21ac67
+                                              hash->layer_state);
21ac67
+
21ac67
+  g_hash_table_insert (hash->table, entry, entry);
21ac67
+
21ac67
+  hash->n_unique_pipelines++;
21ac67
+
21ac67
+  return entry->pipeline;
21ac67
+}
21ac67
diff --git a/cogl/cogl-pipeline-hash-table.h b/cogl/cogl-pipeline-hash-table.h
21ac67
new file mode 100644
21ac67
index 0000000..1b0a0d9
21ac67
--- /dev/null
21ac67
+++ b/cogl/cogl-pipeline-hash-table.h
21ac67
@@ -0,0 +1,69 @@
21ac67
+/*
21ac67
+ * Cogl
21ac67
+ *
21ac67
+ * An object oriented GL/GLES Abstraction/Utility Layer
21ac67
+ *
21ac67
+ * Copyright (C) 2013 Intel Corporation.
21ac67
+ *
21ac67
+ * This library is free software; you can redistribute it and/or
21ac67
+ * modify it under the terms of the GNU Lesser General Public
21ac67
+ * License as published by the Free Software Foundation; either
21ac67
+ * version 2 of the License, or (at your option) any later version.
21ac67
+ *
21ac67
+ * This library is distributed in the hope that it will be useful,
21ac67
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
21ac67
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21ac67
+ * Lesser General Public License for more details.
21ac67
+ *
21ac67
+ * You should have received a copy of the GNU Lesser General Public
21ac67
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21ac67
+ *
21ac67
+ *
21ac67
+ */
21ac67
+
21ac67
+#ifndef __COGL_PIPELINE_HASH_H__
21ac67
+#define __COGL_PIPELINE_HASH_H__
21ac67
+
21ac67
+#include "cogl-pipeline.h"
21ac67
+
21ac67
+typedef struct
21ac67
+{
21ac67
+  /* Total number of pipelines that were ever added to the hash. This
21ac67
+   * is not decremented when a pipeline is removed. It is only used to
21ac67
+   * generate a warning if an unusually high number of pipelines are
21ac67
+   * generated */
21ac67
+  int n_unique_pipelines;
21ac67
+
21ac67
+  /* String that will be used to describe the usage of this hash table
21ac67
+   * in the debug warning when too many pipelines are generated. This
21ac67
+   * must be a static string because it won't be copied or freed */
21ac67
+  const char *debug_string;
21ac67
+
21ac67
+  unsigned int main_state;
21ac67
+  unsigned int layer_state;
21ac67
+
21ac67
+  GHashTable *table;
21ac67
+} CoglPipelineHashTable;
21ac67
+
21ac67
+void
21ac67
+_cogl_pipeline_hash_table_init (CoglPipelineHashTable *hash,
21ac67
+                                unsigned int main_state,
21ac67
+                                unsigned int layer_state,
21ac67
+                                const char *debug_string);
21ac67
+
21ac67
+void
21ac67
+_cogl_pipeline_hash_table_destroy (CoglPipelineHashTable *hash);
21ac67
+
21ac67
+/*
21ac67
+ * Gets a pipeline from the hash that has the same state as
21ac67
+ * @key_pipeline according to the limited state bits passed to
21ac67
+ * _cogl_pipeline_hash_table_init(). If there is no matching pipelines
21ac67
+ * already then a copy of key_pipeline is stored in the hash so that
21ac67
+ * it will be used next time the function is called with a similar
21ac67
+ * pipeline. In that case the copy itself will be returned
21ac67
+ */
21ac67
+CoglPipeline *
21ac67
+_cogl_pipeline_hash_table_get (CoglPipelineHashTable *hash,
21ac67
+                               CoglPipeline *key_pipeline);
21ac67
+
21ac67
+#endif /* __COGL_PIPELINE_HASH_H__ */
21ac67
diff --git a/cogl/cogl-pipeline-layer-private.h b/cogl/cogl-pipeline-layer-private.h
21ac67
index 125b967..7577559 100644
21ac67
--- a/cogl/cogl-pipeline-layer-private.h
21ac67
+++ b/cogl/cogl-pipeline-layer-private.h
21ac67
@@ -358,6 +358,11 @@ _cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer);
21ac67
 CoglPipelineWrapMode
21ac67
 _cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer);
21ac67
 
21ac67
+void
21ac67
+_cogl_pipeline_layer_copy_differences (CoglPipelineLayer *dest,
21ac67
+                                       CoglPipelineLayer *src,
21ac67
+                                       unsigned long differences);
21ac67
+
21ac67
 unsigned long
21ac67
 _cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
21ac67
                                           CoglPipelineLayer *layer1);
21ac67
diff --git a/cogl/cogl-pipeline-layer.c b/cogl/cogl-pipeline-layer.c
21ac67
index d9590c8..9bc26ef 100644
21ac67
--- a/cogl/cogl-pipeline-layer.c
21ac67
+++ b/cogl/cogl-pipeline-layer.c
21ac67
@@ -42,6 +42,8 @@
21ac67
 #include "cogl-context-private.h"
21ac67
 #include "cogl-texture-private.h"
21ac67
 
21ac67
+#include <string.h>
21ac67
+
21ac67
 static void
21ac67
 _cogl_pipeline_layer_free (CoglPipelineLayer *layer);
21ac67
 
21ac67
@@ -146,6 +148,107 @@ _cogl_get_n_args_for_combine_func (CoglPipelineCombineFunc func)
21ac67
   return 0;
21ac67
 }
21ac67
 
21ac67
+void
21ac67
+_cogl_pipeline_layer_copy_differences (CoglPipelineLayer *dest,
21ac67
+                                       CoglPipelineLayer *src,
21ac67
+                                       unsigned long differences)
21ac67
+{
21ac67
+  CoglPipelineLayerBigState *big_dest, *big_src;
21ac67
+
21ac67
+  if ((differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE) &&
21ac67
+      !dest->has_big_state)
21ac67
+    {
21ac67
+      dest->big_state = g_slice_new (CoglPipelineLayerBigState);
21ac67
+      dest->has_big_state = TRUE;
21ac67
+    }
21ac67
+
21ac67
+  big_dest = dest->big_state;
21ac67
+  big_src = src->big_state;
21ac67
+
21ac67
+  dest->differences |= differences;
21ac67
+
21ac67
+  while (differences)
21ac67
+    {
21ac67
+      int index = _cogl_util_ffs (differences) - 1;
21ac67
+
21ac67
+      differences &= ~(1 << index);
21ac67
+
21ac67
+      /* This convoluted switch statement is just here so that we'll
21ac67
+       * get a warning if a new state is added without handling it
21ac67
+       * here */
21ac67
+      switch (index)
21ac67
+        {
21ac67
+        case COGL_PIPELINE_LAYER_STATE_COUNT:
21ac67
+        case COGL_PIPELINE_LAYER_STATE_UNIT_INDEX:
21ac67
+          g_warn_if_reached ();
21ac67
+          break;
21ac67
+
21ac67
+        case COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE_INDEX:
21ac67
+          dest->texture_type = src->texture_type;
21ac67
+          break;
21ac67
+
21ac67
+        case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX:
21ac67
+          dest->texture = src->texture;
21ac67
+          if (dest->texture)
21ac67
+            cogl_object_ref (dest->texture);
21ac67
+          break;
21ac67
+
21ac67
+        case COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX:
21ac67
+          dest->sampler_cache_entry = src->sampler_cache_entry;
21ac67
+          break;
21ac67
+
21ac67
+        case COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX:
21ac67
+          {
21ac67
+            CoglPipelineCombineFunc func;
21ac67
+            int n_args, i;
21ac67
+
21ac67
+            func = big_src->texture_combine_rgb_func;
21ac67
+            big_dest->texture_combine_rgb_func = func;
21ac67
+            n_args = _cogl_get_n_args_for_combine_func (func);
21ac67
+            for (i = 0; i < n_args; i++)
21ac67
+              {
21ac67
+                big_dest->texture_combine_rgb_src[i] =
21ac67
+                  big_src->texture_combine_rgb_src[i];
21ac67
+                big_dest->texture_combine_rgb_op[i] =
21ac67
+                  big_src->texture_combine_rgb_op[i];
21ac67
+              }
21ac67
+
21ac67
+            func = big_src->texture_combine_alpha_func;
21ac67
+            big_dest->texture_combine_alpha_func = func;
21ac67
+            n_args = _cogl_get_n_args_for_combine_func (func);
21ac67
+            for (i = 0; i < n_args; i++)
21ac67
+              {
21ac67
+                big_dest->texture_combine_alpha_src[i] =
21ac67
+                  big_src->texture_combine_alpha_src[i];
21ac67
+                big_dest->texture_combine_alpha_op[i] =
21ac67
+                  big_src->texture_combine_alpha_op[i];
21ac67
+              }
21ac67
+          }
21ac67
+          break;
21ac67
+
21ac67
+        case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX:
21ac67
+          memcpy (big_dest->texture_combine_constant,
21ac67
+                  big_src->texture_combine_constant,
21ac67
+                  sizeof (big_dest->texture_combine_constant));
21ac67
+          break;
21ac67
+
21ac67
+        case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX:
21ac67
+          big_dest->point_sprite_coords = big_src->point_sprite_coords;
21ac67
+          break;
21ac67
+
21ac67
+        case COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX:
21ac67
+          _cogl_pipeline_snippet_list_copy (&big_dest->vertex_snippets,
21ac67
+                                            &big_src->vertex_snippets);
21ac67
+          break;
21ac67
+
21ac67
+        case COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX:
21ac67
+          _cogl_pipeline_snippet_list_copy (&big_dest->fragment_snippets,
21ac67
+                                            &big_src->fragment_snippets);
21ac67
+          break;
21ac67
+        }
21ac67
+    }
21ac67
+}
21ac67
+
21ac67
 static void
21ac67
 _cogl_pipeline_layer_init_multi_property_sparse_state (
21ac67
                                                   CoglPipelineLayer *layer,
21ac67
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
21ac67
index 56700b5..acb5653 100644
21ac67
--- a/cogl/cogl-pipeline-private.h
21ac67
+++ b/cogl/cogl-pipeline-private.h
21ac67
@@ -845,6 +845,17 @@ _cogl_pipeline_hash (CoglPipeline *pipeline,
21ac67
                      unsigned long layer_differences,
21ac67
                      CoglPipelineEvalFlags flags);
21ac67
 
21ac67
+/* Makes a copy of the given pipeline that is a child of the root
21ac67
+ * pipeline rather than a child of the source pipeline. That way the
21ac67
+ * new pipeline won't hold a reference to the source pipeline. The
21ac67
+ * differences specified in @differences and @layer_differences are
21ac67
+ * copied across and all other state is left with the default
21ac67
+ * values. */
21ac67
+CoglPipeline *
21ac67
+_cogl_pipeline_deep_copy (CoglPipeline *pipeline,
21ac67
+                          unsigned long differences,
21ac67
+                          unsigned long layer_differences);
21ac67
+
21ac67
 CoglPipeline *
21ac67
 _cogl_pipeline_journal_ref (CoglPipeline *pipeline);
21ac67
 
21ac67
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
21ac67
index c029f45..a91ad25 100644
21ac67
--- a/cogl/cogl-pipeline.c
21ac67
+++ b/cogl/cogl-pipeline.c
21ac67
@@ -2771,6 +2771,97 @@ _cogl_pipeline_hash (CoglPipeline *pipeline,
21ac67
 
21ac67
 typedef struct
21ac67
 {
21ac67
+  CoglContext *context;
21ac67
+  CoglPipeline *src_pipeline;
21ac67
+  CoglPipeline *dst_pipeline;
21ac67
+  unsigned int layer_differences;
21ac67
+} DeepCopyData;
21ac67
+
21ac67
+static CoglBool
21ac67
+deep_copy_layer_cb (CoglPipelineLayer *src_layer,
21ac67
+                    void *user_data)
21ac67
+{
21ac67
+  DeepCopyData *data = user_data;
21ac67
+  CoglPipelineLayer *dst_layer;
21ac67
+  unsigned int differences = data->layer_differences;
21ac67
+
21ac67
+  dst_layer = _cogl_pipeline_get_layer (data->dst_pipeline, src_layer->index);
21ac67
+
21ac67
+  while (src_layer != data->context->default_layer_n &&
21ac67
+         src_layer != data->context->default_layer_0 &&
21ac67
+         differences)
21ac67
+    {
21ac67
+      unsigned long to_copy = differences & src_layer->differences;
21ac67
+
21ac67
+      if (to_copy)
21ac67
+        {
21ac67
+          _cogl_pipeline_layer_copy_differences (dst_layer, src_layer, to_copy);
21ac67
+          differences ^= to_copy;
21ac67
+        }
21ac67
+
21ac67
+      src_layer = COGL_PIPELINE_LAYER (COGL_NODE (src_layer)->parent);
21ac67
+    }
21ac67
+
21ac67
+  return TRUE;
21ac67
+}
21ac67
+
21ac67
+CoglPipeline *
21ac67
+_cogl_pipeline_deep_copy (CoglPipeline *pipeline,
21ac67
+                          unsigned long differences,
21ac67
+                          unsigned long layer_differences)
21ac67
+{
21ac67
+  CoglPipeline *new, *authority;
21ac67
+  CoglBool copy_layer_state;
21ac67
+
21ac67
+  _COGL_GET_CONTEXT (ctx, NULL);
21ac67
+
21ac67
+  if ((differences & COGL_PIPELINE_STATE_LAYERS))
21ac67
+    {
21ac67
+      copy_layer_state = TRUE;
21ac67
+      differences &= ~COGL_PIPELINE_STATE_LAYERS;
21ac67
+    }
21ac67
+  else
21ac67
+    copy_layer_state = FALSE;
21ac67
+
21ac67
+  new = cogl_pipeline_new (ctx);
21ac67
+
21ac67
+  for (authority = pipeline;
21ac67
+       authority != ctx->default_pipeline && differences;
21ac67
+       authority = COGL_PIPELINE (COGL_NODE (authority)->parent))
21ac67
+    {
21ac67
+      unsigned long to_copy = differences & authority->differences;
21ac67
+
21ac67
+      if (to_copy)
21ac67
+        {
21ac67
+          _cogl_pipeline_copy_differences (new, authority, to_copy);
21ac67
+          differences ^= to_copy;
21ac67
+        }
21ac67
+    }
21ac67
+
21ac67
+  if (copy_layer_state)
21ac67
+    {
21ac67
+      DeepCopyData data;
21ac67
+
21ac67
+      /* The unit index doesn't need to be copied because it should
21ac67
+       * end up with the same values anyway because the new pipeline
21ac67
+       * will have the same indices as the source pipeline */
21ac67
+      layer_differences &= ~COGL_PIPELINE_LAYER_STATE_UNIT;
21ac67
+
21ac67
+      data.context = ctx;
21ac67
+      data.src_pipeline = pipeline;
21ac67
+      data.dst_pipeline = new;
21ac67
+      data.layer_differences = layer_differences;
21ac67
+
21ac67
+      _cogl_pipeline_foreach_layer_internal (pipeline,
21ac67
+                                             deep_copy_layer_cb,
21ac67
+                                             &data);
21ac67
+    }
21ac67
+
21ac67
+  return new;
21ac67
+}
21ac67
+
21ac67
+typedef struct
21ac67
+{
21ac67
   int i;
21ac67
   CoglPipelineLayer **layers;
21ac67
 } AddLayersToArrayState;
21ac67
diff --git a/cogl/cogl-xlib-renderer.c b/cogl/cogl-xlib-renderer.c
21ac67
index 18c0fe6..eb1f51a 100644
21ac67
--- a/cogl/cogl-xlib-renderer.c
21ac67
+++ b/cogl/cogl-xlib-renderer.c
21ac67
@@ -238,7 +238,7 @@ update_outputs (CoglRenderer *renderer,
21ac67
 
21ac67
   _cogl_xlib_renderer_trap_errors (renderer, &state);
21ac67
 
21ac67
-  for (i = 0; i < resources->ncrtc && !error; i++)
21ac67
+  for (i = 0; resources && i < resources->ncrtc && !error; i++)
21ac67
     {
21ac67
       XRRCrtcInfo *crtc_info = NULL;
21ac67
       XRROutputInfo *output_info = NULL;
21ac67
diff --git a/cogl/cogl-xlib.h b/cogl/cogl-xlib.h
21ac67
index 7a6bc7e..5dab8ae 100644
21ac67
--- a/cogl/cogl-xlib.h
21ac67
+++ b/cogl/cogl-xlib.h
21ac67
@@ -79,6 +79,8 @@ cogl_xlib_set_display (Display *display);
21ac67
 CoglFilterReturn
21ac67
 cogl_xlib_handle_event (XEvent *xevent);
21ac67
 
21ac67
+COGL_END_DECLS
21ac67
+
21ac67
 #undef __COGL_XLIB_H_INSIDE__
21ac67
 
21ac67
 #endif /* __COGL_XLIB_H__ */
21ac67
diff --git a/configure.ac b/configure.ac
21ac67
index 43bf407..4ba85b8 100644
21ac67
--- a/configure.ac
21ac67
+++ b/configure.ac
21ac67
@@ -25,7 +25,7 @@ m4_define([cogl_version],
21ac67
 dnl Since the core Cogl library has to also maintain support for the
21ac67
 dnl Cogl 1.x API for Clutter then we track the 1.x version separately.
21ac67
 m4_define([cogl_1_minor_version], [14])
21ac67
-m4_define([cogl_1_micro_version], [0])
21ac67
+m4_define([cogl_1_micro_version], [1])
21ac67
 m4_define([cogl_1_version], [1.cogl_1_minor_version.cogl_1_micro_version])
21ac67
 
21ac67
 dnl ================================================================
21ac67
@@ -70,7 +70,7 @@ dnl ================================================================
21ac67
 # libtool version info we don't automatically derive this from the
21ac67
 # pretty version number because we want to test the results of
21ac67
 # updating the version number in advance of a release.
21ac67
-m4_define([cogl_release_status], [release])
21ac67
+m4_define([cogl_release_status], [git])
21ac67
 
21ac67
 AC_INIT(cogl, [cogl_1_version])
21ac67
 AC_CONFIG_SRCDIR(cogl/cogl.h)
21ac67
@@ -178,6 +178,12 @@ dnl internal glib configure (as-glibconfig.m4)
21ac67
 m4_ifdef([LT_OUTPUT], [LT_OUTPUT])
21ac67
 
21ac67
 dnl ================================================================
21ac67
+dnl Find an appropriate libm, for sin() etc.
21ac67
+dnl ================================================================
21ac67
+LT_LIB_M
21ac67
+AC_SUBST(LIBM)
21ac67
+
21ac67
+dnl ================================================================
21ac67
 dnl See what platform we are building for
21ac67
 dnl ================================================================
21ac67
 AC_CANONICAL_HOST
21ac67
@@ -474,6 +480,7 @@ AS_IF(
21ac67
     EXPERIMENTAL_OPTIONS="$EXPERIMENTAL_OPTIONS Quartz Core Graphics,"
21ac67
     AC_DEFINE([USE_QUARTZ], 1,
21ac67
 	      [Use Core Graphics (Quartz) for loading image data])
21ac67
+    COGL_EXTRA_LDFLAGS="$COGL_EXTRA_LDFLAGS -framework ApplicationServices"
21ac67
     COGL_IMAGE_BACKEND="quartz"
21ac67
   ],
21ac67
   [
21ac67
@@ -1173,6 +1180,12 @@ AC_CHECK_FUNCS([ffs])
21ac67
 dnl 'memmem' is a GNU extension but we have a simple fallback
21ac67
 AC_CHECK_FUNCS([memmem])
21ac67
 
21ac67
+dnl This is used in the cogl-gles2-gears example but it is a GNU extension
21ac67
+save_libs="$LIBS"
21ac67
+LIBS="$LIBS $LIBM"
21ac67
+AC_CHECK_FUNCS([sincos])
21ac67
+LIBS="$save_libs"
21ac67
+
21ac67
 dnl ================================================================
21ac67
 dnl Platform values
21ac67
 dnl ================================================================
21ac67
diff --git a/examples/Makefile.am b/examples/Makefile.am
21ac67
index 86801c6..ae3e5f7 100644
21ac67
--- a/examples/Makefile.am
21ac67
+++ b/examples/Makefile.am
21ac67
@@ -20,7 +20,8 @@ endif
21ac67
 
21ac67
 common_ldadd = \
21ac67
 	$(COGL_DEP_LIBS) \
21ac67
-	$(top_builddir)/cogl/libcogl.la
21ac67
+	$(top_builddir)/cogl/libcogl.la \
21ac67
+	$(LIBM)
21ac67
 
21ac67
 if !USE_GLIB
21ac67
 common_ldadd += $(top_builddir)/deps/glib/libglib.la
21ac67
diff --git a/examples/android/hello/jni/main.c b/examples/android/hello/jni/main.c
21ac67
index 2c5bd9b..c9a8401 100644
21ac67
--- a/examples/android/hello/jni/main.c
21ac67
+++ b/examples/android/hello/jni/main.c
21ac67
@@ -42,7 +42,7 @@ static int test_init (TestData* data)
21ac67
   CoglOnscreen *onscreen;
21ac67
   CoglError *error = NULL;
21ac67
   CoglVertexP2C4 triangle_vertices[] = {
21ac67
-        {0, 0.7, 0xff, 0x00, 0x00, 0x80},
21ac67
+        {0, 0.7, 0xff, 0x00, 0x00, 0xff},
21ac67
         {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
21ac67
         {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
21ac67
   };
21ac67
diff --git a/examples/cogl-gles2-context.c b/examples/cogl-gles2-context.c
21ac67
index 1cf375f..de66c21 100644
21ac67
--- a/examples/cogl-gles2-context.c
21ac67
+++ b/examples/cogl-gles2-context.c
21ac67
@@ -70,7 +70,7 @@ main (int argc, char **argv)
21ac67
     CoglOnscreen *onscreen;
21ac67
     CoglError *error = NULL;
21ac67
     CoglVertexP2C4 triangle_vertices[] = {
21ac67
-        {0, 0.7, 0xff, 0x00, 0x00, 0x80},
21ac67
+        {0, 0.7, 0xff, 0x00, 0x00, 0xff},
21ac67
         {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
21ac67
         {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
21ac67
     };
21ac67
diff --git a/examples/cogl-gles2-gears.c b/examples/cogl-gles2-gears.c
21ac67
index d7dd271..c7185b6 100644
21ac67
--- a/examples/cogl-gles2-gears.c
21ac67
+++ b/examples/cogl-gles2-gears.c
21ac67
@@ -35,6 +35,10 @@
21ac67
  * Jul 13, 2010
21ac67
  */
21ac67
 
21ac67
+#ifdef HAVE_CONFIG_H
21ac67
+#include "config.h"
21ac67
+#endif
21ac67
+
21ac67
 #define GL_GLEXT_PROTOTYPES
21ac67
 
21ac67
 #include <math.h>
21ac67
@@ -110,6 +114,15 @@ static GLfloat ProjectionMatrix[16];
21ac67
 /** The direction of the directional light for the scene */
21ac67
 static const GLfloat LightSourcePosition[4] = { 5.0, 5.0, 10.0, 1.0};
21ac67
 
21ac67
+#ifndef HAVE_SINCOS
21ac67
+static void
21ac67
+sincos (double x, double *sinx, double *cosx)
21ac67
+{
21ac67
+  *sinx = sin (x);
21ac67
+  *cosx = cos (x);
21ac67
+}
21ac67
+#endif /* HAVE_SINCOS */
21ac67
+
21ac67
 /**
21ac67
  * Fills a gear vertex.
21ac67
  *
21ac67
diff --git a/examples/cogl-hello.c b/examples/cogl-hello.c
21ac67
index 5bda9bf..3ba1e31 100644
21ac67
--- a/examples/cogl-hello.c
21ac67
+++ b/examples/cogl-hello.c
21ac67
@@ -39,7 +39,7 @@ main (int argc, char **argv)
21ac67
     CoglOnscreen *onscreen;
21ac67
     CoglError *error = NULL;
21ac67
     CoglVertexP2C4 triangle_vertices[] = {
21ac67
-        {0, 0.7, 0xff, 0x00, 0x00, 0x80},
21ac67
+        {0, 0.7, 0xff, 0x00, 0x00, 0xff},
21ac67
         {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
21ac67
         {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
21ac67
     };
21ac67
diff --git a/examples/cogl-msaa.c b/examples/cogl-msaa.c
21ac67
index 73f9c4e..4a388bc 100644
21ac67
--- a/examples/cogl-msaa.c
21ac67
+++ b/examples/cogl-msaa.c
21ac67
@@ -12,7 +12,7 @@ main (int argc, char **argv)
21ac67
     CoglFramebuffer *fb;
21ac67
     CoglError *error = NULL;
21ac67
     CoglVertexP2C4 triangle_vertices[] = {
21ac67
-        {0, 0.7, 0xff, 0x00, 0x00, 0x80},
21ac67
+        {0, 0.7, 0xff, 0x00, 0x00, 0xff},
21ac67
         {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
21ac67
         {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
21ac67
     };
21ac67
diff --git a/examples/cogl-sdl-hello.c b/examples/cogl-sdl-hello.c
21ac67
index 961137a..acb9125 100644
21ac67
--- a/examples/cogl-sdl-hello.c
21ac67
+++ b/examples/cogl-sdl-hello.c
21ac67
@@ -80,7 +80,7 @@ main (int argc, char **argv)
21ac67
   CoglOnscreen *onscreen;
21ac67
   CoglError *error = NULL;
21ac67
   CoglVertexP2C4 triangle_vertices[] = {
21ac67
-    {0, 0.7, 0xff, 0x00, 0x00, 0x80},
21ac67
+    {0, 0.7, 0xff, 0x00, 0x00, 0xff},
21ac67
     {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
21ac67
     {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
21ac67
   };
21ac67
diff --git a/examples/cogl-sdl2-hello.c b/examples/cogl-sdl2-hello.c
21ac67
index 405cb92..12e6ced 100644
21ac67
--- a/examples/cogl-sdl2-hello.c
21ac67
+++ b/examples/cogl-sdl2-hello.c
21ac67
@@ -89,7 +89,7 @@ main (int argc, char **argv)
21ac67
   CoglOnscreen *onscreen;
21ac67
   CoglError *error = NULL;
21ac67
   CoglVertexP2C4 triangle_vertices[] = {
21ac67
-    {0, 0.7, 0xff, 0x00, 0x00, 0x80},
21ac67
+    {0, 0.7, 0xff, 0x00, 0x00, 0xff},
21ac67
     {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
21ac67
     {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
21ac67
   };
21ac67
diff --git a/examples/cogl-x11-foreign.c b/examples/cogl-x11-foreign.c
21ac67
index ca9e3ed..a60397c 100644
21ac67
--- a/examples/cogl-x11-foreign.c
21ac67
+++ b/examples/cogl-x11-foreign.c
21ac67
@@ -61,7 +61,7 @@ main (int argc, char **argv)
21ac67
   unsigned long mask;
21ac67
   Window xwin;
21ac67
   CoglVertexP2C4 triangle_vertices[] = {
21ac67
-      {0, 0.7, 0xff, 0x00, 0x00, 0x80},
21ac67
+      {0, 0.7, 0xff, 0x00, 0x00, 0xff},
21ac67
       {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
21ac67
       {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
21ac67
   };
21ac67
diff --git a/examples/cogland.c b/examples/cogland.c
21ac67
index c18850a..7a02719 100644
21ac67
--- a/examples/cogland.c
21ac67
+++ b/examples/cogland.c
21ac67
@@ -93,7 +93,6 @@ struct _CoglandCompositor
21ac67
   struct wl_display *wayland_display;
21ac67
   struct wl_event_loop *wayland_loop;
21ac67
 
21ac67
-  CoglDisplay *cogl_display;
21ac67
   CoglContext *cogl_context;
21ac67
 
21ac67
   int virtual_width;
21ac67
@@ -336,15 +335,16 @@ cogland_queue_redraw (CoglandCompositor *compositor)
21ac67
 }
21ac67
 
21ac67
 static void
21ac67
-shm_buffer_damaged (CoglandSurface *surface,
21ac67
-                    int32_t x,
21ac67
-                    int32_t y,
21ac67
-                    int32_t width,
21ac67
-                    int32_t height)
21ac67
+surface_damaged (CoglandSurface *surface,
21ac67
+                 int32_t x,
21ac67
+                 int32_t y,
21ac67
+                 int32_t width,
21ac67
+                 int32_t height)
21ac67
 {
21ac67
   struct wl_buffer *wayland_buffer = surface->buffer;
21ac67
 
21ac67
-  if (surface->texture)
21ac67
+  if (surface->texture &&
21ac67
+      wl_buffer_is_shm (surface->buffer))
21ac67
     {
21ac67
       CoglPixelFormat format;
21ac67
       int stride = wl_shm_buffer_get_stride (wayland_buffer);
21ac67
@@ -381,6 +381,8 @@ shm_buffer_damaged (CoglandSurface *surface,
21ac67
                                stride,
21ac67
                                data);
21ac67
     }
21ac67
+
21ac67
+  cogland_queue_redraw (surface->compositor);
21ac67
 }
21ac67
 
21ac67
 static void
21ac67
@@ -546,16 +548,18 @@ cogland_surface_commit (struct wl_client *client,
21ac67
 
21ac67
           wl_signal_add (&surface->buffer->resource.destroy_signal,
21ac67
                          &surface->buffer_destroy_listener);
21ac67
-          wl_list_remove (&surface->pending.buffer_destroy_listener.link);
21ac67
         }
21ac67
     }
21ac67
-  surface->pending.buffer = NULL;
21ac67
+  if (surface->pending.buffer)
21ac67
+    {
21ac67
+      wl_list_remove (&surface->pending.buffer_destroy_listener.link);
21ac67
+      surface->pending.buffer = NULL;
21ac67
+    }
21ac67
   surface->pending.sx = 0;
21ac67
   surface->pending.sy = 0;
21ac67
 
21ac67
   /* wl_surface.damage */
21ac67
   if (surface->buffer &&
21ac67
-      wl_buffer_is_shm (surface->buffer) &&
21ac67
       surface->texture &&
21ac67
       !region_is_empty (&surface->pending.damage))
21ac67
     {
21ac67
@@ -571,11 +575,11 @@ cogland_surface_commit (struct wl_client *client,
21ac67
       if (region->y1 < 0)
21ac67
         region->y1 = 0;
21ac67
 
21ac67
-      shm_buffer_damaged (surface,
21ac67
-                          region->x1,
21ac67
-                          region->y1,
21ac67
-                          region->x2 - region->x1,
21ac67
-                          region->y2 - region->y1);
21ac67
+      surface_damaged (surface,
21ac67
+                       region->x1,
21ac67
+                       region->y1,
21ac67
+                       region->x2 - region->x1,
21ac67
+                       region->y2 - region->y1);
21ac67
     }
21ac67
   region_init (&surface->pending.damage);
21ac67
 
21ac67
@@ -583,8 +587,6 @@ cogland_surface_commit (struct wl_client *client,
21ac67
   wl_list_insert_list (&compositor->frame_callbacks,
21ac67
                        &surface->pending.frame_callback_list);
21ac67
   wl_list_init (&surface->pending.frame_callback_list);
21ac67
-
21ac67
-  cogland_queue_redraw (compositor);
21ac67
 }
21ac67
 
21ac67
 static void
21ac67
@@ -614,6 +616,9 @@ cogland_surface_free (CoglandSurface *surface)
21ac67
   compositor->surfaces = g_list_remove (compositor->surfaces, surface);
21ac67
   cogland_surface_detach_buffer_and_notify (surface);
21ac67
 
21ac67
+  if (surface->pending.buffer)
21ac67
+    wl_list_remove (&surface->pending.buffer_destroy_listener.link);
21ac67
+
21ac67
   wl_list_for_each_safe (cb, next,
21ac67
                          &surface->pending.frame_callback_list, link)
21ac67
     wl_resource_destroy (&cb->resource);
21ac67
@@ -970,7 +975,7 @@ get_shell_surface (struct wl_client *client,
21ac67
                    struct wl_resource *surface_resource)
21ac67
 {
21ac67
   CoglandSurface *surface = surface_resource->data;
21ac67
-  CoglandShellSurface *shell_surface = g_new0 (CoglandShellSurface, 1);
21ac67
+  CoglandShellSurface *shell_surface;
21ac67
 
21ac67
   if (surface->has_shell_surface)
21ac67
     {
21ac67
@@ -980,6 +985,7 @@ get_shell_surface (struct wl_client *client,
21ac67
       return;
21ac67
     }
21ac67
 
21ac67
+  shell_surface = g_new0 (CoglandShellSurface, 1);
21ac67
   shell_surface->resource.destroy = destroy_shell_surface;
21ac67
   shell_surface->resource.object.id = id;
21ac67
   shell_surface->resource.object.interface = &wl_shell_surface_interface;
21ac67
@@ -1012,6 +1018,36 @@ bind_shell (struct wl_client *client,
21ac67
                         &cogland_shell_interface, id, data);
21ac67
 }
21ac67
 
21ac67
+static CoglContext *
21ac67
+create_cogl_context (CoglandCompositor *compositor,
21ac67
+                     CoglBool use_egl_constraint,
21ac67
+                     CoglError **error)
21ac67
+{
21ac67
+  CoglRenderer *renderer = renderer = cogl_renderer_new ();
21ac67
+  CoglDisplay *display;
21ac67
+  CoglContext *context;
21ac67
+
21ac67
+  if (use_egl_constraint)
21ac67
+    cogl_renderer_add_constraint (renderer, COGL_RENDERER_CONSTRAINT_USES_EGL);
21ac67
+
21ac67
+  if (!cogl_renderer_connect (renderer, error))
21ac67
+    {
21ac67
+      cogl_object_unref (renderer);
21ac67
+      return NULL;
21ac67
+    }
21ac67
+
21ac67
+  display = cogl_display_new (renderer, NULL);
21ac67
+  cogl_wayland_display_set_compositor_display (display,
21ac67
+                                               compositor->wayland_display);
21ac67
+
21ac67
+  context = cogl_context_new (display, error);
21ac67
+
21ac67
+  cogl_object_unref (renderer);
21ac67
+  cogl_object_unref (display);
21ac67
+
21ac67
+  return context;
21ac67
+}
21ac67
+
21ac67
 int
21ac67
 main (int argc, char **argv)
21ac67
 {
21ac67
@@ -1020,7 +1056,7 @@ main (int argc, char **argv)
21ac67
   CoglError *error = NULL;
21ac67
   GError *gerror = NULL;
21ac67
   CoglVertexP2C4 triangle_vertices[] = {
21ac67
-      {0, 0.7, 0xff, 0x00, 0x00, 0x80},
21ac67
+      {0, 0.7, 0xff, 0x00, 0x00, 0xff},
21ac67
       {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
21ac67
       {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
21ac67
   };
21ac67
@@ -1055,13 +1091,30 @@ main (int argc, char **argv)
21ac67
     wayland_event_source_new (compositor.wayland_display);
21ac67
   g_source_attach (compositor.wayland_event_source, NULL);
21ac67
 
21ac67
-  compositor.cogl_display = cogl_display_new (NULL, NULL);
21ac67
-  cogl_wayland_display_set_compositor_display (compositor.cogl_display,
21ac67
-                                               compositor.wayland_display);
21ac67
-
21ac67
-  compositor.cogl_context = cogl_context_new (compositor.cogl_display, &error);
21ac67
-  if (!compositor.cogl_context)
21ac67
-    g_error ("Failed to create a Cogl context: %s\n", error->message);
21ac67
+  /* We want Cogl to use an EGL renderer because otherwise it won't
21ac67
+   * set up the wl_drm object and only SHM buffers will work. */
21ac67
+  compositor.cogl_context =
21ac67
+    create_cogl_context (&compositor,
21ac67
+                         TRUE /* use EGL constraint */,
21ac67
+                         &error);
21ac67
+  if (compositor.cogl_context == NULL)
21ac67
+    {
21ac67
+      /* If we couldn't get an EGL context then try any type of
21ac67
+       * context */
21ac67
+      cogl_error_free (error);
21ac67
+      error = NULL;
21ac67
+
21ac67
+      compositor.cogl_context =
21ac67
+        create_cogl_context (&compositor,
21ac67
+                             FALSE, /* don't set EGL constraint */
21ac67
+                             &error);
21ac67
+
21ac67
+      if (compositor.cogl_context)
21ac67
+        g_warning ("Failed to create context with EGL constraint, "
21ac67
+                   "falling back");
21ac67
+      else
21ac67
+        g_error ("Failed to create a Cogl context: %s\n", error->message);
21ac67
+    }
21ac67
 
21ac67
   compositor.virtual_width = 800;
21ac67
   compositor.virtual_height = 600;
21ac67
diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am
21ac67
index 69a460d..9782755 100644
21ac67
--- a/tests/conform/Makefile.am
21ac67
+++ b/tests/conform/Makefile.am
21ac67
@@ -65,6 +65,7 @@ test_sources = \
21ac67
 	test-framebuffer-get-bits.c \
21ac67
 	test-primitive-and-journal.c \
21ac67
 	test-copy-replace-texture.c \
21ac67
+	test-pipeline-cache-unrefs-texture.c \
21ac67
 	$(NULL)
21ac67
 
21ac67
 test_conformance_SOURCES = $(common_sources) $(test_sources)
21ac67
@@ -131,7 +132,10 @@ AM_CPPFLAGS += \
21ac67
 	-DCOGL_COMPILATION
21ac67
 
21ac67
 test_conformance_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS)
21ac67
-test_conformance_LDADD = $(COGL_DEP_LIBS) $(top_builddir)/cogl/libcogl.la
21ac67
+test_conformance_LDADD = \
21ac67
+	$(COGL_DEP_LIBS) \
21ac67
+	$(top_builddir)/cogl/libcogl.la \
21ac67
+	$(LIBM)
21ac67
 if !USE_GLIB
21ac67
 test_conformance_LDADD += $(top_builddir)/deps/glib/libglib.la
21ac67
 endif
21ac67
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
21ac67
index 0b55db6..1d1447e 100644
21ac67
--- a/tests/conform/test-conform-main.c
21ac67
+++ b/tests/conform/test-conform-main.c
21ac67
@@ -120,6 +120,8 @@ main (int argc, char **argv)
21ac67
 
21ac67
   ADD_TEST (test_copy_replace_texture, 0, 0);
21ac67
 
21ac67
+  ADD_TEST (test_pipeline_cache_unrefs_texture, 0, 0);
21ac67
+
21ac67
   UNPORTED_TEST (test_viewport);
21ac67
 
21ac67
   ADD_TEST (test_gles2_context, TEST_REQUIREMENT_GLES2_CONTEXT, 0);
21ac67
diff --git a/tests/conform/test-pipeline-cache-unrefs-texture.c b/tests/conform/test-pipeline-cache-unrefs-texture.c
21ac67
new file mode 100644
21ac67
index 0000000..ccd02e7
21ac67
--- /dev/null
21ac67
+++ b/tests/conform/test-pipeline-cache-unrefs-texture.c
21ac67
@@ -0,0 +1,92 @@
21ac67
+#include <cogl/cogl.h>
21ac67
+
21ac67
+#include "test-utils.h"
21ac67
+
21ac67
+/* Keep track of the number of textures that we've created and are
21ac67
+ * still alive */
21ac67
+static int destroyed_texture_count = 0;
21ac67
+
21ac67
+#define N_TEXTURES 3
21ac67
+
21ac67
+static void
21ac67
+free_texture_cb (void *user_data)
21ac67
+{
21ac67
+  destroyed_texture_count++;
21ac67
+}
21ac67
+
21ac67
+static CoglTexture *
21ac67
+create_texture (void)
21ac67
+{
21ac67
+  static const guint8 data[] =
21ac67
+    { 0xff, 0xff, 0xff, 0xff };
21ac67
+  static CoglUserDataKey texture_data_key;
21ac67
+  CoglTexture2D *tex_2d;
21ac67
+
21ac67
+  tex_2d = cogl_texture_2d_new_from_data (test_ctx,
21ac67
+                                          1, 1, /* width / height */
21ac67
+                                          COGL_PIXEL_FORMAT_RGBA_8888_PRE,
21ac67
+                                          COGL_PIXEL_FORMAT_ANY,
21ac67
+                                          4, /* rowstride */
21ac67
+                                          data,
21ac67
+                                          NULL);
21ac67
+
21ac67
+  /* Set some user data on the texture so we can track when it has
21ac67
+   * been destroyed */
21ac67
+  cogl_object_set_user_data (COGL_OBJECT (tex_2d),
21ac67
+                             &texture_data_key,
21ac67
+                             GINT_TO_POINTER (1),
21ac67
+                             free_texture_cb);
21ac67
+
21ac67
+  return COGL_TEXTURE (tex_2d);
21ac67
+}
21ac67
+
21ac67
+void
21ac67
+test_pipeline_cache_unrefs_texture (void)
21ac67
+{
21ac67
+  CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
21ac67
+  CoglPipeline *simple_pipeline;
21ac67
+  int i;
21ac67
+
21ac67
+  /* Create a pipeline with three texture layers. That way we can be
21ac67
+   * pretty sure the pipeline will cause a unique shader to be
21ac67
+   * generated in the cache */
21ac67
+  for (i = 0; i < N_TEXTURES; i++)
21ac67
+    {
21ac67
+      CoglTexture *tex = create_texture ();
21ac67
+      cogl_pipeline_set_layer_texture (pipeline, i, tex);
21ac67
+      cogl_object_unref (tex);
21ac67
+    }
21ac67
+
21ac67
+  /* Draw something with the pipeline to ensure it gets into the
21ac67
+   * pipeline cache */
21ac67
+  cogl_framebuffer_draw_rectangle (test_fb,
21ac67
+                                   pipeline,
21ac67
+                                   0, 0, 10, 10);
21ac67
+  cogl_framebuffer_finish (test_fb);
21ac67
+
21ac67
+  /* Draw something else so that it is no longer the current flushed
21ac67
+   * pipeline, and the units have a different texture bound */
21ac67
+  simple_pipeline = cogl_pipeline_new (test_ctx);
21ac67
+  for (i = 0; i < N_TEXTURES; i++)
21ac67
+    {
21ac67
+      CoglColor combine_constant;
21ac67
+      cogl_color_init_from_4ub (&combine_constant, i, 0, 0, 255);
21ac67
+      cogl_pipeline_set_layer_combine_constant (simple_pipeline,
21ac67
+                                                i,
21ac67
+                                                &combine_constant);
21ac67
+    }
21ac67
+  cogl_framebuffer_draw_rectangle (test_fb, simple_pipeline, 0, 0, 10, 10);
21ac67
+  cogl_framebuffer_finish (test_fb);
21ac67
+  cogl_object_unref (simple_pipeline);
21ac67
+
21ac67
+  g_assert_cmpint (destroyed_texture_count, ==, 0);
21ac67
+
21ac67
+  /* Destroy the pipeline. This should immediately cause the textures
21ac67
+   * to be freed */
21ac67
+  cogl_object_unref (pipeline);
21ac67
+
21ac67
+  g_assert_cmpint (destroyed_texture_count, ==, N_TEXTURES);
21ac67
+
21ac67
+  if (cogl_test_verbose ())
21ac67
+    g_print ("OK\n");
21ac67
+}
21ac67
diff --git a/tests/micro-perf/Makefile.am b/tests/micro-perf/Makefile.am
21ac67
index c221dd6..5c5f69d 100644
21ac67
--- a/tests/micro-perf/Makefile.am
21ac67
+++ b/tests/micro-perf/Makefile.am
21ac67
@@ -19,5 +19,10 @@ endif
21ac67
 
21ac67
 AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS)
21ac67
 
21ac67
+common_ldadd = \
21ac67
+	$(COGL_DEP_LIBS) \
21ac67
+	$(top_builddir)/cogl/libcogl.la \
21ac67
+	$(LIBM)
21ac67
+
21ac67
 test_journal_SOURCES = test-journal.c
21ac67
-test_journal_LDADD = $(COGL_DEP_LIBS) $(top_builddir)/cogl/libcogl.la
21ac67
+test_journal_LDADD = $(common_ldadd)