[cogl] cogl-1.14.0-21-ge26464f.patch: Sync with 1.14 branch for a crash fix.

Adam Jackson ajax at fedoraproject.org
Wed May 22 17:05:24 UTC 2013


commit 8d64c22d784dd1bc9259f107047b65e7482819f1
Author: Adam Jackson <ajax at redhat.com>
Date:   Wed May 22 13:05:21 2013 -0400

    cogl-1.14.0-21-ge26464f.patch: Sync with 1.14 branch for a crash fix.

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


More information about the scm-commits mailing list