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

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