summaryrefslogtreecommitdiff
path: root/extra/cogl
diff options
context:
space:
mode:
authorroot <root@rshg054.dnsready.net>2013-09-17 05:09:31 -0700
committerroot <root@rshg054.dnsready.net>2013-09-17 05:09:31 -0700
commit7080cab465360c1e2571433323481aed6741ecbe (patch)
treeac430543eac4e1d1fa7f3512afdad29b5220863b /extra/cogl
parenta1ec78e8d16098adb2e9e1cf4e364625e74c3bc4 (diff)
Tue Sep 17 05:07:41 PDT 2013
Diffstat (limited to 'extra/cogl')
-rw-r--r--extra/cogl/PKGBUILD18
-rw-r--r--extra/cogl/git-fixes.patch1948
2 files changed, 1962 insertions, 4 deletions
diff --git a/extra/cogl/PKGBUILD b/extra/cogl/PKGBUILD
index 9b34a0460..72aa066c1 100644
--- a/extra/cogl/PKGBUILD
+++ b/extra/cogl/PKGBUILD
@@ -1,9 +1,9 @@
-# $Id: PKGBUILD 190118 2013-07-15 21:53:44Z tomegun $
+# $Id: PKGBUILD 194508 2013-09-17 02:50:40Z heftig $
# Maintainer: Ionut Biru <ibiru@archlinux.org>
pkgname=cogl
pkgver=1.14.0
-pkgrel=4
+pkgrel=5
pkgdesc="An object oriented GL/GLES Abstraction/Utility Layer"
arch=('i686' 'x86_64')
url="http://www.clutter-project.org/"
@@ -11,11 +11,21 @@ license=('GPL2')
depends=('libdrm' 'libxext' 'libxdamage' 'libxcomposite' 'gdk-pixbuf2' 'pango')
makedepends=('mesa' 'gobject-introspection')
options=(!libtool !emptydirs)
-source=(http://download.gnome.org/sources/$pkgname/${pkgver%.*}/$pkgname-$pkgver.tar.xz)
-sha256sums=('276e8c9f5ff0fcd57c1eaf74cc245f41ad469a95a18ac831fac2d5960baa5ae8')
+source=(http://download.gnome.org/sources/$pkgname/${pkgver%.*}/$pkgname-$pkgver.tar.xz
+ git-fixes.patch)
+sha256sums=('276e8c9f5ff0fcd57c1eaf74cc245f41ad469a95a18ac831fac2d5960baa5ae8'
+ '5f9279122cabf5cce23c1e19cedd9e67231f63a4d35329924b256fc1adc1aab2')
+
+prepare() {
+ cd "$pkgname-$pkgver"
+ # Update to ba5e5410babf705f53b591579c104181dd752bec
+ # Removed version parts from configure.ac and .gitignore parts, removed conflicting it.po and eu.po commits
+ patch -Np1 -i ../git-fixes.patch
+}
build() {
cd "$pkgname-$pkgver"
+ autoreconf -fi
./configure --prefix=/usr \
--enable-wayland-egl-platform --enable-gles{1,2}
diff --git a/extra/cogl/git-fixes.patch b/extra/cogl/git-fixes.patch
new file mode 100644
index 000000000..2d16a1262
--- /dev/null
+++ b/extra/cogl/git-fixes.patch
@@ -0,0 +1,1948 @@
+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-atlas-texture.c b/cogl/cogl-atlas-texture.c
+index 7f62efc..30dd319 100644
+--- a/cogl/cogl-atlas-texture.c
++++ b/cogl/cogl-atlas-texture.c
+@@ -276,7 +276,8 @@ _cogl_atlas_texture_free (CoglAtlasTexture *atlas_tex)
+ {
+ _cogl_atlas_texture_remove_from_atlas (atlas_tex);
+
+- cogl_object_unref (atlas_tex->sub_texture);
++ if (atlas_tex->sub_texture)
++ cogl_object_unref (atlas_tex->sub_texture);
+
+ /* Chain up */
+ _cogl_texture_free (COGL_TEXTURE (atlas_tex));
+diff --git a/cogl/cogl-auto-texture.c b/cogl/cogl-auto-texture.c
+index 6de2e32..9a5819d 100644
+--- a/cogl/cogl-auto-texture.c
++++ b/cogl/cogl-auto-texture.c
+@@ -179,14 +179,6 @@ _cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
+ &internal_error)))
+ return COGL_TEXTURE (atlas_tex);
+
+- if (cogl_error_matches (internal_error,
+- COGL_SYSTEM_ERROR,
+- COGL_SYSTEM_ERROR_NO_MEMORY))
+- {
+- _cogl_propagate_error (error, internal_error);
+- return NULL;
+- }
+-
+ cogl_error_free (internal_error);
+ internal_error = NULL;
+
+@@ -200,14 +192,6 @@ _cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
+ internal_format,
+ &internal_error));
+
+- if (cogl_error_matches (internal_error,
+- COGL_SYSTEM_ERROR,
+- COGL_SYSTEM_ERROR_NO_MEMORY))
+- {
+- _cogl_propagate_error (error, internal_error);
+- return NULL;
+- }
+-
+ if (!tex)
+ {
+ cogl_error_free (internal_error);
+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-context.c b/cogl/cogl-context.c
+index 175e69d..359e112 100644
+--- a/cogl/cogl-context.c
++++ b/cogl/cogl-context.c
+@@ -133,7 +133,7 @@ cogl_context_new (CoglDisplay *display,
+ CoglError **error)
+ {
+ CoglContext *context;
+- GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
++ uint8_t default_texture_data[] = { 0xff, 0xff, 0xff, 0xff };
+ CoglBitmap *default_texture_bitmap;
+ const CoglWinsysVtable *winsys;
+ int i;
+diff --git a/cogl/cogl-error.c b/cogl/cogl-error.c
+index 753e4c8..f72415b 100644
+--- a/cogl/cogl-error.c
++++ b/cogl/cogl-error.c
+@@ -105,7 +105,10 @@ _cogl_propagate_error (CoglError **dest,
+ _COGL_RETURN_IF_FAIL (src != NULL);
+
+ if (dest == NULL)
+- cogl_error_free (src);
++ {
++ g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "%s", src->message);
++ cogl_error_free (src);
++ }
+ else if (*dest)
+ g_warning (ERROR_OVERWRITTEN_WARNING, src->message);
+ else
+diff --git a/cogl/cogl-error.h b/cogl/cogl-error.h
+index 1b6a951..ef6ee7e 100644
+--- a/cogl/cogl-error.h
++++ b/cogl/cogl-error.h
+@@ -30,6 +30,8 @@
+
+ #include "cogl-types.h"
+
++COGL_BEGIN_DECLS
++
+ /**
+ * SECTION:cogl-error
+ * @short_description: A way for Cogl to throw exceptions
+@@ -173,4 +175,6 @@ cogl_error_matches (CoglError *error,
+ #define COGL_GLIB_ERROR(COGL_ERROR) ((CoglError *)COGL_ERROR)
+ #endif
+
++COGL_END_DECLS
++
+ #endif /* __COGL_ERROR_H__ */
+diff --git a/cogl/cogl-fixed.c b/cogl/cogl-fixed.c
+index e347605..4d92155 100644
+--- a/cogl/cogl-fixed.c
++++ b/cogl/cogl-fixed.c
+@@ -30,6 +30,10 @@
+ #include <glib-object.h>
+ #include <gobject/gvaluecollector.h>
+
++#ifdef HAVE_FLOAT_WORD_ORDER
++#include <endian.h>
++#endif
++
+ #include "cogl-fixed.h"
+
+ /* pre-computed sin table for 1st quadrant
+@@ -306,6 +310,7 @@ static const double _magic = 68719476736.0 * 1.5;
+ *
+ * FIXME - this should go inside the configure.ac
+ */
++#ifdef HAVE_FLOAT_WORD_ORDER
+ #if (__FLOAT_WORD_ORDER == 1234)
+ #define _COGL_MAN 0
+ #elif (__FLOAT_WORD_ORDER == 4321)
+@@ -313,6 +318,9 @@ static const double _magic = 68719476736.0 * 1.5;
+ #else
+ #define COGL_NO_FAST_CONVERSIONS
+ #endif
++#else /* HAVE_FLOAT_WORD_ORDER */
++#define COGL_NO_FAST_CONVERSIONS
++#endif /* HAVE_FLOAT_WORD_ORDER */
+
+ /*
+ * cogl_double_to_fixed :
+@@ -629,7 +637,7 @@ cogl_fixed_sqrt (CoglFixed x)
+ /*
+ * Find the highest bit set
+ */
+-#if defined (__arm__) && !defined(__ARM_ARCH_4T__)
++#if defined (__arm__) && !defined(__ARM_ARCH_4T__) && !defined(__thumb__)
+ /* This actually requires at least arm v5, but gcc does not seem
+ * to set the architecture defines correctly, and it is I think
+ * very unlikely that anyone will want to use clutter on anything
+@@ -807,7 +815,7 @@ CoglFixed
+ cogl_fixed_mul (CoglFixed a,
+ CoglFixed b)
+ {
+-#ifdef __arm__
++#if defined(__arm__) && !defined(__thumb__)
+ /* This provides about 12% speedeup on the gcc -O2 optimised
+ * C version
+ *
+@@ -819,7 +827,7 @@ cogl_fixed_mul (CoglFixed a,
+ __asm__ ("smull %0, %1, %2, %3 \n"
+ "mov %0, %0, lsr %4 \n"
+ "add %1, %0, %1, lsl %5 \n"
+- : "=r"(res_hi), "=r"(res_low) \
++ : "=&r"(res_hi), "=&r"(res_low) \
+ : "r"(a), "r"(b), "i"(COGL_FIXED_Q), "i"(32 - COGL_FIXED_Q));
+
+ return (CoglFixed) res_low;
+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@linux.intel.com>
++ * Robert Bragg <robert@linux.intel.com>
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include "cogl-context-private.h"
++#include "cogl-pipeline-private.h"
++#include "cogl-pipeline-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/cogl/driver/gl/cogl-attribute-gl.c b/cogl/driver/gl/cogl-attribute-gl.c
+index ba7e627..bd9c351 100644
+--- a/cogl/driver/gl/cogl-attribute-gl.c
++++ b/cogl/driver/gl/cogl-attribute-gl.c
+@@ -251,17 +251,25 @@ setup_legacy_buffered_attribute (CoglContext *ctx,
+ case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
+ {
+ int layer_number = attribute->name_state->layer_number;
++ const CoglPipelineGetLayerFlags flags =
++ COGL_PIPELINE_GET_LAYER_NO_CREATE;
+ CoglPipelineLayer *layer =
+- _cogl_pipeline_get_layer (pipeline, layer_number);
+- int unit = _cogl_pipeline_layer_get_unit_index (layer);
++ _cogl_pipeline_get_layer_with_flags (pipeline, layer_number, flags);
+
+- _cogl_bitmask_set (&ctx->enable_texcoord_attributes_tmp, unit, TRUE);
++ if (layer)
++ {
++ int unit = _cogl_pipeline_layer_get_unit_index (layer);
+
+- GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit));
+- GE (ctx, glTexCoordPointer (attribute->d.buffered.n_components,
+- attribute->d.buffered.type,
+- attribute->d.buffered.stride,
+- base + attribute->d.buffered.offset));
++ _cogl_bitmask_set (&ctx->enable_texcoord_attributes_tmp,
++ unit,
++ TRUE);
++
++ GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit));
++ GE (ctx, glTexCoordPointer (attribute->d.buffered.n_components,
++ attribute->d.buffered.type,
++ attribute->d.buffered.stride,
++ base + attribute->d.buffered.offset));
++ }
+ break;
+ }
+ case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
+@@ -316,13 +324,24 @@ setup_legacy_const_attribute (CoglContext *ctx,
+ case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
+ {
+ int layer_number = attribute->name_state->layer_number;
++ const CoglPipelineGetLayerFlags flags =
++ COGL_PIPELINE_GET_LAYER_NO_CREATE;
+ CoglPipelineLayer *layer =
+- _cogl_pipeline_get_layer (pipeline, layer_number);
+- int unit = _cogl_pipeline_layer_get_unit_index (layer);
++ _cogl_pipeline_get_layer_with_flags (pipeline,
++ layer_number,
++ flags);
+
+- GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit));
++ if (layer)
++ {
++ int unit = _cogl_pipeline_layer_get_unit_index (layer);
++
++ GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit));
+
+- GE (ctx, glMultiTexCoord4f (vector[0], vector[1], vector[2], vector[3]));
++ GE (ctx, glMultiTexCoord4f (vector[0],
++ vector[1],
++ vector[2],
++ vector[3]));
++ }
+ break;
+ }
+ case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
+diff --git a/cogl/winsys/cogl-winsys-egl-wayland.c b/cogl/winsys/cogl-winsys-egl-wayland.c
+index feeb529..156ecb9 100644
+--- a/cogl/winsys/cogl-winsys-egl-wayland.c
++++ b/cogl/winsys/cogl-winsys-egl-wayland.c
+@@ -370,12 +370,22 @@ _cogl_winsys_egl_onscreen_deinit (CoglOnscreen *onscreen)
+ wayland_onscreen->wayland_egl_native_window = NULL;
+ }
+
++ /* NB: The wayland protocol docs explicitly state that
++ * "wl_shell_surface_destroy() must be called before destroying the
++ * wl_surface object." ... */
++ if (wayland_onscreen->wayland_shell_surface)
++ {
++ wl_shell_surface_destroy (wayland_onscreen->wayland_shell_surface);
++ wayland_onscreen->wayland_shell_surface = NULL;
++ }
++
+ if (wayland_onscreen->wayland_surface)
+ {
+ wl_surface_destroy (wayland_onscreen->wayland_surface);
+ wayland_onscreen->wayland_surface = NULL;
+ }
+
++
+ g_slice_free (CoglOnscreenWayland, wayland_onscreen);
+ }
+
+diff --git a/configure.ac b/configure.ac
+index 43bf407..3d57980 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -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"
+ ],
+ [
+@@ -950,7 +957,7 @@ AS_IF([test "x$enable_kms_egl_platform" = "xyes"],
+ GBM_VERSION=`$PKG_CONFIG --modversion gbm`
+ GBM_MAJOR=`echo $GBM_VERSION | cut -d'.' -f1`
+ GBM_MINOR=`echo $GBM_VERSION | cut -d'.' -f2`
+- GBM_MICRO=`echo $GBM_VERSION | cut -d'.' -f3`
++ GBM_MICRO=`echo $GBM_VERSION | cut -d'.' -f3 | sed 's/-.*//'`
+
+ AC_DEFINE_UNQUOTED([COGL_GBM_MAJOR], [$GBM_MAJOR], [The major version for libgbm])
+ AC_DEFINE_UNQUOTED([COGL_GBM_MINOR], [$GBM_MINOR], [The minor version for libgbm])
+@@ -1160,7 +1167,10 @@ dnl ================================================================
+ AC_PATH_X
+ AC_HEADER_STDC
+ AC_CHECK_HEADERS(fcntl.h limits.h unistd.h)
+-
++AC_CHECK_HEADER([endian.h],
++ [AC_CHECK_DECL([__FLOAT_WORD_ORDER],
++ AC_DEFINE([HAVE_FLOAT_WORD_ORDER], [1],
++ [Has the __FLOAT_WORD_ORDER macro]))])
+
+ dnl ================================================================
+ dnl Checks for library functions.
+@@ -1173,6 +1183,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..238f34c 100644
+--- a/examples/cogland.c
++++ b/examples/cogland.c
+@@ -8,6 +8,10 @@
+
+ #include <wayland-server.h>
+
++#ifdef COGL_HAS_XLIB_SUPPORT
++#include <cogl/cogl-xlib.h>
++#endif
++
+ typedef struct _CoglandCompositor CoglandCompositor;
+
+ typedef struct
+@@ -25,7 +29,7 @@ typedef struct
+ {
+ CoglandCompositor *compositor;
+
+- struct wl_surface wayland_surface;
++ struct wl_resource resource;
+ int x;
+ int y;
+ struct wl_buffer *buffer;
+@@ -38,6 +42,7 @@ typedef struct
+ struct
+ {
+ /* wl_surface.attach */
++ CoglBool newly_attached;
+ struct wl_buffer *buffer;
+ struct wl_listener buffer_destroy_listener;
+ int32_t sx;
+@@ -93,7 +98,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 +340,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 +386,8 @@ shm_buffer_damaged (CoglandSurface *surface,
+ stride,
+ data);
+ }
++
++ cogland_queue_redraw (surface->compositor);
+ }
+
+ static void
+@@ -453,6 +460,7 @@ cogland_surface_attach (struct wl_client *wayland_client,
+ surface->pending.sx = sx;
+ surface->pending.sy = sy;
+ surface->pending.buffer = buffer;
++ surface->pending.newly_attached = TRUE;
+
+ if (buffer)
+ wl_signal_add (&buffer->resource.destroy_signal,
+@@ -522,7 +530,8 @@ cogland_surface_commit (struct wl_client *client,
+ CoglandCompositor *compositor = surface->compositor;
+
+ /* wl_surface.attach */
+- if (surface->buffer != surface->pending.buffer)
++ if (surface->pending.newly_attached &&
++ surface->buffer != surface->pending.buffer)
+ {
+ CoglError *error = NULL;
+
+@@ -546,16 +555,19 @@ 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;
++ surface->pending.newly_attached = FALSE;
+
+ /* wl_surface.damage */
+ if (surface->buffer &&
+- wl_buffer_is_shm (surface->buffer) &&
+ surface->texture &&
+ !region_is_empty (&surface->pending.damage))
+ {
+@@ -571,11 +583,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 +595,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 +624,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);
+@@ -647,13 +660,13 @@ cogland_compositor_create_surface (struct wl_client *wayland_client,
+
+ surface->compositor = compositor;
+
+- surface->wayland_surface.resource.destroy =
++ surface->resource.destroy =
+ cogland_surface_resource_destroy_cb;
+- surface->wayland_surface.resource.object.id = id;
+- surface->wayland_surface.resource.object.interface = &wl_surface_interface;
+- surface->wayland_surface.resource.object.implementation =
++ surface->resource.object.id = id;
++ surface->resource.object.interface = &wl_surface_interface;
++ surface->resource.object.implementation =
+ (void (**)(void)) &cogland_surface_interface;
+- surface->wayland_surface.resource.data = surface;
++ surface->resource.data = surface;
+
+ surface->buffer_destroy_listener.notify =
+ surface_handle_buffer_destroy;
+@@ -663,7 +676,7 @@ cogland_compositor_create_surface (struct wl_client *wayland_client,
+ wl_list_init (&surface->pending.frame_callback_list);
+ region_init (&surface->pending.damage);
+
+- wl_client_add_resource (wayland_client, &surface->wayland_surface.resource);
++ wl_client_add_resource (wayland_client, &surface->resource);
+
+ compositor->surfaces = g_list_prepend (compositor->surfaces,
+ surface);
+@@ -970,7 +983,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 +993,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;
+@@ -989,7 +1003,7 @@ get_shell_surface (struct wl_client *client,
+
+ shell_surface->surface = surface;
+ shell_surface->surface_destroy_listener.notify = shell_handle_surface_destroy;
+- wl_signal_add (&surface->wayland_surface.resource.destroy_signal,
++ wl_signal_add (&surface->resource.destroy_signal,
+ &shell_surface->surface_destroy_listener);
+
+ surface->has_shell_surface = TRUE;
+@@ -1012,6 +1026,109 @@ 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;
++}
++
++#ifdef COGL_HAS_XLIB_SUPPORT
++
++static CoglFilterReturn
++x_event_cb (XEvent *event,
++ void *data)
++{
++ CoglandCompositor *compositor = data;
++
++ if (event->type == Expose)
++ cogland_queue_redraw (compositor);
++
++ return COGL_FILTER_CONTINUE;
++}
++
++#endif /* COGL_HAS_XLIB_SUPPORT */
++
++static gboolean
++timeout_cb (void *data)
++{
++ cogland_queue_redraw (data);
++
++ return TRUE;
++}
++
++static void
++init_redraws (CoglandCompositor *compositor)
++{
++#ifdef COGL_HAS_XLIB_SUPPORT
++ CoglDisplay *display = cogl_context_get_display (compositor->cogl_context);
++ CoglRenderer *renderer = cogl_display_get_renderer (display);
++ CoglWinsysID winsys = cogl_renderer_get_winsys_id (renderer);
++
++ /* If Cogl is using X then we can listen for Expose events to know
++ * when to repaint the window. Otherwise we don't have any code to
++ * know when the contents of the window is dirty so we'll just
++ * redraw constantly */
++ switch (winsys)
++ {
++ case COGL_WINSYS_ID_GLX:
++ case COGL_WINSYS_ID_EGL_XLIB:
++ {
++ Display *display = cogl_xlib_renderer_get_display (renderer);
++ GList *l;
++
++ for (l = compositor->outputs; l; l = l->next)
++ {
++ CoglandOutput *output = l->data;
++ XWindowAttributes win_attribs;
++ Window win;
++
++ win = cogl_x11_onscreen_get_window_xid (output->onscreen);
++ if (XGetWindowAttributes (display, win, &win_attribs))
++ {
++ XSelectInput (display,
++ win,
++ win_attribs.your_event_mask | ExposureMask);
++ cogl_xlib_renderer_add_filter (renderer,
++ x_event_cb,
++ compositor);
++
++ }
++ }
++ }
++ return;
++
++ default:
++ break;
++ }
++#endif /* COGL_HAS_XLIB_SUPPORT */
++
++ g_timeout_add (16, timeout_cb, compositor);
++}
++
+ int
+ main (int argc, char **argv)
+ {
+@@ -1020,7 +1137,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 +1172,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;
+@@ -1101,7 +1235,7 @@ main (int argc, char **argv)
+
+ g_source_attach (cogl_source, NULL);
+
+- cogland_queue_redraw (&compositor);
++ init_redraws (&compositor);
+
+ g_main_loop_run (loop);
+
+diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am
+index 69a460d..d4062f2 100644
+--- a/tests/conform/Makefile.am
++++ b/tests/conform/Makefile.am
+@@ -65,6 +65,8 @@ test_sources = \
+ test-framebuffer-get-bits.c \
+ test-primitive-and-journal.c \
+ test-copy-replace-texture.c \
++ test-pipeline-cache-unrefs-texture.c \
++ test-texture-no-allocate.c \
+ $(NULL)
+
+ test_conformance_SOURCES = $(common_sources) $(test_sources)
+@@ -131,7 +133,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..c5a5d4c 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);
+@@ -130,6 +132,8 @@ main (int argc, char **argv)
+
+ ADD_TEST (test_euler_quaternion, 0, 0);
+
++ ADD_TEST (test_texture_no_allocate, 0, 0);
++
+ g_printerr ("Unknown test name \"%s\"\n", argv[1]);
+
+ return 1;
+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/conform/test-texture-no-allocate.c b/tests/conform/test-texture-no-allocate.c
+new file mode 100644
+index 0000000..fccb742
+--- /dev/null
++++ b/tests/conform/test-texture-no-allocate.c
+@@ -0,0 +1,80 @@
++#include <cogl/cogl.h>
++
++#include "test-utils.h"
++
++/* Tests that the various texture types can be freed without being
++ * allocated */
++
++/* Texture size that is probably to big to fit within the texture
++ * limits */
++#define BIG_TEX_WIDTH 16384
++#define BIG_TEX_HEIGHT 128
++
++void
++test_texture_no_allocate (void)
++{
++ uint8_t *tex_data;
++ CoglTexture *texture;
++ CoglTexture2D *texture_2d;
++
++ tex_data = g_malloc (BIG_TEX_WIDTH * BIG_TEX_HEIGHT * 4);
++
++ /* NB: if we make the atlas and sliced texture APIs public then this
++ * could changed to explicitly use that instead of the magic texture
++ * API */
++
++ /* Try to create an atlas texture that is too big so it will
++ * internally be freed without allocating */
++ texture = cogl_texture_new_from_data (BIG_TEX_WIDTH,
++ BIG_TEX_HEIGHT,
++ COGL_TEXTURE_NONE, /* flags */
++ /* format */
++ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
++ /* internal format */
++ COGL_PIXEL_FORMAT_ANY,
++ /* rowstride */
++ BIG_TEX_WIDTH * 4,
++ tex_data);
++
++ g_free (tex_data);
++
++ /* It's ok if this causes an error, we just don't want it to
++ * crash */
++
++ if (texture)
++ cogl_object_unref (texture);
++
++ /* Try to create a sliced texture without allocating it */
++ texture = cogl_texture_new_with_size (BIG_TEX_WIDTH,
++ BIG_TEX_HEIGHT,
++ COGL_TEXTURE_NO_ATLAS,
++ COGL_PIXEL_FORMAT_RGBA_8888_PRE);
++ cogl_object_unref (texture);
++
++ /* 2D texture */
++ texture_2d = cogl_texture_2d_new_with_size (test_ctx,
++ 64, 64,
++ COGL_PIXEL_FORMAT_RGBA_8888_PRE);
++ cogl_object_unref (texture_2d);
++
++ /* 3D texture */
++ if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_3D))
++ {
++ CoglTexture3D *texture_3d =
++ cogl_texture_3d_new_with_size (test_ctx,
++ 64, 64, 64,
++ COGL_PIXEL_FORMAT_RGBA_8888_PRE);
++ cogl_object_unref (texture_3d);
++ }
++
++ /* Rectangle texture */
++ if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE))
++ {
++ CoglTextureRectangle *texture_rect =
++ cogl_texture_rectangle_new_with_size (test_ctx,
++ 64, 64,
++ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
++ NULL /* error */);
++ cogl_object_unref (texture_rect);
++ }
++}
+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)