[Cogl] [PATCH] Test case for atlas textures beeing freed during atlas migration

Neil Roberts neil at linux.intel.com
Mon May 19 04:52:08 PDT 2014


We currently have a problem where Cogl will crash if atlas migration
causes the atlas to be freed. This can happen if the only reference to
the atlas is by a texture that is only referenced by the last flushed
pipeline. That pipeline will lose its reference during migration
because a new pipeline will be flushed to migrate the textures. This
test case replicates that situation.

https://bugzilla.gnome.org/show_bug.cgi?id=719551

Reviewed-by: Neil Roberts <neil at linux.intel.com>
---
 tests/conform/Makefile.am                     |  1 +
 tests/conform/test-atlas-free-while-migrate.c | 96 +++++++++++++++++++++++++++
 tests/conform/test-conform-main.c             |  1 +
 3 files changed, 98 insertions(+)
 create mode 100644 tests/conform/test-atlas-free-while-migrate.c

diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am
index edfe940..a2d71c7 100644
--- a/tests/conform/Makefile.am
+++ b/tests/conform/Makefile.am
@@ -25,6 +25,7 @@ unported_test_sources = \
 
 test_sources = \
 	test-atlas-migration.c \
+	test-atlas-free-while-migrate.c \
 	test-blend-strings.c \
 	test-blend.c \
 	test-depth-test.c \
diff --git a/tests/conform/test-atlas-free-while-migrate.c b/tests/conform/test-atlas-free-while-migrate.c
new file mode 100644
index 0000000..483f7f4
--- /dev/null
+++ b/tests/conform/test-atlas-free-while-migrate.c
@@ -0,0 +1,96 @@
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+/* This test is intended to replicate the following bug:
+ *
+ * https://bugzilla.gnome.org/show_bug.cgi?id=728064
+ *
+ * The problem in that bug is that a texture can be freed while the
+ * atlas is being migrated if the only reference to it was by the last
+ * flushed pipeline. This pipeline will lose a reference when a new
+ * pipeline is used to blit the textures. If that texture was the only
+ * one in an atlas then the atlas will also get freed before Cogl gets
+ * a chance to take a reference on it for the new texture
+ */
+
+static CoglTexture *
+create_texture (int size)
+{
+  CoglAtlasTexture *texture;
+  uint8_t *data;
+
+  data = g_malloc (size * size * 4);
+
+  texture = cogl_atlas_texture_new_from_data (test_ctx,
+                                              size, /* width */
+                                              size, /* height */
+                                              /* format */
+                                              COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+                                              /* rowstride */
+                                              size * 4,
+                                              data,
+                                              NULL);
+
+  g_free (data);
+
+  return texture;
+}
+
+static void
+texture_destroy_cb (void *user_data)
+{
+  CoglBool *texture_destroyed = user_data;
+
+  *texture_destroyed = TRUE;
+}
+
+void
+test_atlas_free_while_migrate (void)
+{
+  CoglTexture *tex;
+  CoglPipeline *pipeline;
+  static CoglUserDataKey texture_key;
+  CoglBool texture_destroyed = FALSE;
+
+  pipeline = cogl_pipeline_new (test_ctx);
+
+  tex = create_texture (500);
+
+  cogl_object_set_user_data (tex,
+                             &texture_key,
+                             &texture_destroyed,
+                             texture_destroy_cb);
+
+  cogl_pipeline_set_layer_texture (pipeline, 0 /* layer */, tex);
+
+  cogl_object_unref (tex);
+
+  cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10);
+
+  cogl_object_unref (pipeline);
+
+  /* The texture shouldn't have been destroyed yet because Cogl will
+   * still be keeping a reference to it as the last texture used.
+   * Technically it is free to destroy the texture here if it wants to
+   * but if it does then this test case is useless so we need to
+   * change it anyway if that code changes */
+  g_assert (!texture_destroyed);
+
+  /* The only reference to the pipeline should now be due to it being
+   * the last flushed pipeline. This will also keep the texture alive
+   * until the middle of the atlas migration. We'll now try to create
+   * a new texture which will cause CoglAtlas to try and move the
+   * existing texture to a larger texture but this will cause the
+   * texture to be unref'd in the process.
+   */
+
+  tex = create_texture (32);
+  cogl_texture_allocate (tex, NULL);
+
+  /* The texture should now have been destroyed in the process of
+   * atlas migration */
+  g_assert (texture_destroyed);
+
+  cogl_object_unref (tex);
+}
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
index c119d79..d1ce4aa 100644
--- a/tests/conform/test-conform-main.c
+++ b/tests/conform/test-conform-main.c
@@ -83,6 +83,7 @@ main (int argc, char **argv)
    * the maximum texture level. */
   ADD_TEST (test_texture_mipmap_get_set, TEST_REQUIREMENT_GL, 0);
   ADD_TEST (test_atlas_migration, 0, 0);
+  ADD_TEST (test_atlas_free_while_migrate, 0, 0);
   ADD_TEST (test_read_texture_formats, 0, 0);
   ADD_TEST (test_write_texture_formats, 0, 0);
   ADD_TEST (test_alpha_textures, 0, 0);
-- 
1.9.0



More information about the Cogl mailing list