summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bragg <robert@linux.intel.com>2013-05-08 01:42:24 +0100
committerRobert Bragg <robert@linux.intel.com>2014-03-11 15:54:42 +0000
commitcbf449fff7b9b24132957940a4072326cff4a7ff (patch)
tree0695b7e41a95c207fbefbd13a998581e36fe5e9b
parenta041974ef4234231557e5b6bd78ffe612edbb4f7 (diff)
downloadcogl-wip/public-atlas-apis.tar.gz
Adds CoglAtlasSet and CoglAtlas apiswip/public-atlas-apis
This enables applications to more closely manage their own texture atlases via a CoglAtlasSet api. A CoglAtlasSet represents a set of CoglAtlases and a CoglAtlas represents one large texture that is subdivided into smaller "allocations". The intention is to enable functionality like cogl-pango to be implemented outside of Cogl; specifically to allow Rig to handle its own glyph caches for text rendering.
-rw-r--r--cogl-pango/cogl-pango-glyph-cache.c272
-rw-r--r--cogl-pango/cogl-pango-glyph-cache.h2
-rw-r--r--cogl/Makefile.am2
-rw-r--r--cogl/Makefile.sources10
-rw-r--r--cogl/cogl-atlas-private.h88
-rw-r--r--cogl/cogl-atlas-set-private.h58
-rw-r--r--cogl/cogl-atlas-set.c269
-rw-r--r--cogl/cogl-atlas-set.h161
-rw-r--r--cogl/cogl-atlas-texture-private.h20
-rw-r--r--cogl/cogl-atlas-texture.c290
-rw-r--r--cogl/cogl-atlas.c369
-rw-r--r--cogl/cogl-atlas.h117
-rw-r--r--cogl/cogl-context-private.h8
-rw-r--r--cogl/cogl-context.c29
-rw-r--r--cogl/cogl-texture-private.h15
-rw-r--r--cogl/cogl-texture.c22
-rw-r--r--cogl/cogl.h2
-rw-r--r--cogl/winsys/cogl-winsys-egl.c2
-rw-r--r--examples/cogl-crate.c11
19 files changed, 1227 insertions, 520 deletions
diff --git a/cogl-pango/cogl-pango-glyph-cache.c b/cogl-pango/cogl-pango-glyph-cache.c
index 04d1e454..39a3f077 100644
--- a/cogl-pango/cogl-pango-glyph-cache.c
+++ b/cogl-pango/cogl-pango-glyph-cache.c
@@ -26,46 +26,50 @@
* SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <config.h>
#include <glib.h>
#include "cogl-pango-glyph-cache.h"
#include "cogl-pango-private.h"
-#include "cogl/cogl-atlas.h"
+#include "cogl/cogl-atlas-set.h"
#include "cogl/cogl-atlas-texture-private.h"
+#include "cogl/cogl-context-private.h"
typedef struct _CoglPangoGlyphCacheKey CoglPangoGlyphCacheKey;
+typedef struct _AtlasClosureState
+{
+ CoglList list_node;
+ CoglAtlas *atlas;
+ CoglAtlasReorganizeClosure *reorganize_closure;
+ CoglAtlasAllocateClosure *allocate_closure;
+} AtlasClosureState;
+
struct _CoglPangoGlyphCache
{
CoglContext *ctx;
/* Hash table to quickly check whether a particular glyph in a
particular font is already cached */
- GHashTable *hash_table;
+ GHashTable *hash_table;
- /* List of CoglAtlases */
- GSList *atlases;
+ /* Set of CoglAtlases */
+ CoglAtlasSet *atlas_set;
- /* List of callbacks to invoke when an atlas is reorganized */
- GHookList reorganize_callbacks;
+ CoglList atlas_closures;
- /* TRUE if we've ever stored a texture in the global atlas. This is
- used to make sure we only register one callback to listen for
- global atlas reorganizations */
- CoglBool using_global_atlas;
+ /* List of callbacks to invoke when an atlas is reorganized */
+ GHookList reorganize_callbacks;
/* True if some of the glyphs are dirty. This is used as an
optimization in _cogl_pango_glyph_cache_set_dirty_glyphs to avoid
iterating the hash table if we know none of them are dirty */
- CoglBool has_dirty_glyphs;
+ CoglBool has_dirty_glyphs;
/* Whether mipmapping is being used for this cache. This only
affects whether we decide to put the glyph in the global atlas */
- CoglBool use_mipmapping;
+ CoglBool use_mipmapping;
};
struct _CoglPangoGlyphCacheKey
@@ -78,7 +82,10 @@ static void
cogl_pango_glyph_cache_value_free (CoglPangoGlyphCacheValue *value)
{
if (value->texture)
- cogl_object_unref (value->texture);
+ {
+ cogl_object_unref (value->texture);
+ cogl_object_unref (value->atlas);
+ }
g_slice_free (CoglPangoGlyphCacheValue, value);
}
@@ -117,6 +124,91 @@ cogl_pango_glyph_cache_equal_func (const void *a, const void *b)
&& key_a->glyph == key_b->glyph;
}
+static void
+atlas_reorganize_cb (CoglAtlas *atlas, void *user_data)
+{
+ CoglPangoGlyphCache *cache = user_data;
+
+ g_hook_list_invoke (&cache->reorganize_callbacks, FALSE);
+}
+
+static void
+allocate_glyph_cb (CoglAtlas *atlas,
+ CoglTexture *texture,
+ const CoglAtlasAllocation *allocation,
+ void *allocation_data,
+ void *user_data)
+{
+ CoglPangoGlyphCacheValue *value = allocation_data;
+ float tex_width, tex_height;
+
+ if (value->texture)
+ {
+ cogl_object_unref (value->texture);
+ cogl_object_unref (value->atlas);
+ }
+ value->atlas = cogl_object_ref (atlas);
+ value->texture = cogl_object_ref (texture);
+
+ tex_width = cogl_texture_get_width (texture);
+ tex_height = cogl_texture_get_height (texture);
+
+ value->tx1 = allocation->x / tex_width;
+ value->ty1 = allocation->y / tex_height;
+ value->tx2 = (allocation->x + value->draw_width) / tex_width;
+ value->ty2 = (allocation->y + value->draw_height) / tex_height;
+
+ value->tx_pixel = allocation->x;
+ value->ty_pixel = allocation->y;
+
+ /* The glyph has changed position so it will need to be redrawn */
+ value->dirty = TRUE;
+}
+
+static void
+atlas_callback (CoglAtlasSet *set,
+ CoglAtlas *atlas,
+ CoglAtlasSetEvent event,
+ void *user_data)
+{
+ CoglPangoGlyphCache *cache = user_data;
+ AtlasClosureState *state;
+
+ switch (event)
+ {
+ case COGL_ATLAS_SET_EVENT_ADDED:
+ state = g_slice_new (AtlasClosureState);
+ state->atlas = atlas;
+ state->reorganize_closure =
+ cogl_atlas_add_post_reorganize_callback (atlas,
+ atlas_reorganize_cb,
+ cache,
+ NULL); /* destroy */
+ state->allocate_closure =
+ cogl_atlas_add_allocate_callback (atlas,
+ allocate_glyph_cb,
+ cache,
+ NULL); /* destroy */
+
+ _cogl_list_insert (cache->atlas_closures.prev, &state->list_node);
+ break;
+ case COGL_ATLAS_SET_EVENT_REMOVED:
+ break;
+ }
+}
+
+static void
+add_global_atlas_cb (CoglAtlas *atlas,
+ void *user_data)
+{
+ CoglPangoGlyphCache *cache = user_data;
+
+ atlas_callback (_cogl_get_atlas_set (cache->ctx),
+ atlas,
+ COGL_ATLAS_SET_EVENT_ADDED,
+ cache);
+}
+
CoglPangoGlyphCache *
cogl_pango_glyph_cache_new (CoglContext *ctx,
CoglBool use_mipmapping)
@@ -135,32 +227,47 @@ cogl_pango_glyph_cache_new (CoglContext *ctx,
(UDestroyNotify) cogl_pango_glyph_cache_key_free,
(UDestroyNotify) cogl_pango_glyph_cache_value_free);
- cache->atlases = NULL;
+ _cogl_list_init (&cache->atlas_closures);
+
+ cache->atlas_set = cogl_atlas_set_new (ctx);
+
+ cogl_atlas_set_set_components (cache->atlas_set,
+ COGL_TEXTURE_COMPONENTS_A);
+
+ cogl_atlas_set_set_migration_enabled (cache->atlas_set, FALSE);
+ cogl_atlas_set_set_clear_enabled (cache->atlas_set, TRUE);
+
+ /* We want to be notified when new atlases are added to our local
+ * atlas set so they can be monitored for being re-arranged... */
+ cogl_atlas_set_add_atlas_callback (cache->atlas_set,
+ atlas_callback,
+ cache,
+ NULL); /* destroy */
+
+ /* We want to be notified when new atlases are added to the global
+ * atlas set so they can be monitored for being re-arranged... */
+ cogl_atlas_set_add_atlas_callback (_cogl_get_atlas_set (ctx),
+ atlas_callback,
+ cache,
+ NULL); /* destroy */
+ /* The global atlas set may already have atlases that we will
+ * want to monitor... */
+ cogl_atlas_set_foreach (_cogl_get_atlas_set (ctx),
+ add_global_atlas_cb,
+ cache);
+
g_hook_list_init (&cache->reorganize_callbacks, sizeof (GHook));
cache->has_dirty_glyphs = FALSE;
- cache->using_global_atlas = FALSE;
-
cache->use_mipmapping = use_mipmapping;
return cache;
}
-static void
-cogl_pango_glyph_cache_reorganize_cb (void *user_data)
-{
- CoglPangoGlyphCache *cache = user_data;
-
- g_hook_list_invoke (&cache->reorganize_callbacks, FALSE);
-}
-
void
cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache)
{
- g_slist_foreach (cache->atlases, (GFunc) cogl_object_unref, NULL);
- g_slist_free (cache->atlases);
- cache->atlases = NULL;
cache->has_dirty_glyphs = FALSE;
g_hash_table_remove_all (cache->hash_table);
@@ -169,11 +276,16 @@ cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache)
void
cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache)
{
- if (cache->using_global_atlas)
+ AtlasClosureState *state, *tmp;
+
+ _cogl_list_for_each_safe (state, tmp, &cache->atlas_closures, list_node)
{
- _cogl_atlas_texture_remove_reorganize_callback (
- cache->ctx,
- cogl_pango_glyph_cache_reorganize_cb, cache);
+ cogl_atlas_remove_post_reorganize_callback (state->atlas,
+ state->reorganize_closure);
+ cogl_atlas_remove_allocate_callback (state->atlas,
+ state->allocate_closure);
+ _cogl_list_remove (&state->list_node);
+ g_slice_free (AtlasClosureState, state);
}
cogl_pango_glyph_cache_clear (cache);
@@ -185,33 +297,6 @@ cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache)
g_free (cache);
}
-static void
-cogl_pango_glyph_cache_update_position_cb (void *user_data,
- CoglTexture *new_texture,
- const CoglRectangleMapEntry *rect)
-{
- CoglPangoGlyphCacheValue *value = user_data;
- float tex_width, tex_height;
-
- if (value->texture)
- cogl_object_unref (value->texture);
- value->texture = cogl_object_ref (new_texture);
-
- tex_width = cogl_texture_get_width (new_texture);
- tex_height = cogl_texture_get_height (new_texture);
-
- value->tx1 = rect->x / tex_width;
- value->ty1 = rect->y / tex_height;
- value->tx2 = (rect->x + value->draw_width) / tex_width;
- value->ty2 = (rect->y + value->draw_height) / tex_height;
-
- value->tx_pixel = rect->x;
- value->ty_pixel = rect->y;
-
- /* The glyph has changed position so it will need to be redrawn */
- value->dirty = TRUE;
-}
-
static CoglBool
cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
PangoFont *font,
@@ -246,18 +331,6 @@ cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
value->tx_pixel = 0;
value->ty_pixel = 0;
- /* The first time we store a texture in the global atlas we'll
- register for notifications when the global atlas is reorganized
- so we can forward the notification on as a glyph
- reorganization */
- if (!cache->using_global_atlas)
- {
- _cogl_atlas_texture_add_reorganize_callback
- (cache->ctx,
- cogl_pango_glyph_cache_reorganize_cb, cache);
- cache->using_global_atlas = TRUE;
- }
-
return TRUE;
}
@@ -267,44 +340,17 @@ cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache,
PangoGlyph glyph,
CoglPangoGlyphCacheValue *value)
{
- CoglAtlas *atlas = NULL;
- GSList *l;
-
- /* Look for an atlas that can reserve the space */
- for (l = cache->atlases; l; l = l->next)
- if (_cogl_atlas_reserve_space (l->data,
- value->draw_width + 1,
- value->draw_height + 1,
- value))
- {
- atlas = l->data;
- break;
- }
-
- /* If we couldn't find one then start a new atlas */
- if (atlas == NULL)
- {
- atlas = _cogl_atlas_new (COGL_PIXEL_FORMAT_A_8,
- COGL_ATLAS_CLEAR_TEXTURE |
- COGL_ATLAS_DISABLE_MIGRATION,
- cogl_pango_glyph_cache_update_position_cb);
- COGL_NOTE (ATLAS, "Created new atlas for glyphs: %p", atlas);
- /* If we still can't reserve space then something has gone
- seriously wrong so we'll just give up */
- if (!_cogl_atlas_reserve_space (atlas,
- value->draw_width + 1,
- value->draw_height + 1,
- value))
- {
- cogl_object_unref (atlas);
- return FALSE;
- }
-
- _cogl_atlas_add_reorganize_callback
- (atlas, cogl_pango_glyph_cache_reorganize_cb, NULL, cache);
-
- cache->atlases = g_slist_prepend (cache->atlases, atlas);
- }
+ CoglAtlas *atlas;
+
+ /* Add two pixels for the border
+ * FIXME: two pixels isn't enough if mipmapping is in use
+ */
+ atlas = cogl_atlas_set_allocate_space (cache->atlas_set,
+ value->draw_width + 2,
+ value->draw_height + 2,
+ value);
+ if (!atlas)
+ return FALSE;
return TRUE;
}
@@ -345,12 +391,12 @@ cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
value->dirty = FALSE;
else
{
- /* Try adding the glyph to the global atlas... */
+ /* Try adding the glyph to the global atlas set... */
if (!cogl_pango_glyph_cache_add_to_global_atlas (cache,
font,
glyph,
value) &&
- /* If it fails try the local atlas */
+ /* If it fails try the local atlas set */
!cogl_pango_glyph_cache_add_to_local_atlas (cache,
font,
glyph,
diff --git a/cogl-pango/cogl-pango-glyph-cache.h b/cogl-pango/cogl-pango-glyph-cache.h
index b65f2628..b922bc10 100644
--- a/cogl-pango/cogl-pango-glyph-cache.h
+++ b/cogl-pango/cogl-pango-glyph-cache.h
@@ -33,6 +33,7 @@
#include <pango/pango-font.h>
#include "cogl/cogl-texture.h"
+#include "cogl/cogl-atlas.h"
COGL_BEGIN_DECLS
@@ -41,6 +42,7 @@ typedef struct _CoglPangoGlyphCacheValue CoglPangoGlyphCacheValue;
struct _CoglPangoGlyphCacheValue
{
+ CoglAtlas *atlas;
CoglTexture *texture;
float tx1;
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 8973bcef..bd1d9256 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -157,7 +157,7 @@ libcogl2_la_LDFLAGS = \
-no-undefined \
-version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@ \
-export-dynamic \
- -export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_primitive_draw|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|test_|unit_test_).*"
+ -export-symbols-regex "^(cogl|_cogl_list_remove|_cogl_list_insert|_cogl_list_init|_cogl_get_atlas_set|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_primitive_draw|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|test_|unit_test_).*"
libcogl2_la_SOURCES = $(cogl_sources_c)
nodist_libcogl2_la_SOURCES = $(BUILT_SOURCES)
diff --git a/cogl/Makefile.sources b/cogl/Makefile.sources
index dedf4081..fd37391e 100644
--- a/cogl/Makefile.sources
+++ b/cogl/Makefile.sources
@@ -36,7 +36,9 @@ cogl_public_h = \
cogl-renderer.h \
cogl-snippet.h \
cogl-sub-texture.h \
- cogl-atlas-texture.h \
+ cogl-atlas-set.h \
+ cogl-atlas.h \
+ cogl-atlas-texture.h \
cogl-texture-2d-gl.h \
cogl-texture-2d-sliced.h \
cogl-texture-2d.h \
@@ -221,8 +223,10 @@ cogl_sources_c = \
cogl-texture-rectangle.c \
cogl-rectangle-map.h \
cogl-rectangle-map.c \
- cogl-atlas.h \
- cogl-atlas.c \
+ cogl-atlas-set-private.h \
+ cogl-atlas-set.c \
+ cogl-atlas-private.h \
+ cogl-atlas.c \
cogl-atlas-texture-private.h \
cogl-atlas-texture.c \
cogl-meta-texture.c \
diff --git a/cogl/cogl-atlas-private.h b/cogl/cogl-atlas-private.h
new file mode 100644
index 00000000..a47bb8fb
--- /dev/null
+++ b/cogl/cogl-atlas-private.h
@@ -0,0 +1,88 @@
+/*
+ * Cogl
+ *
+ * A Low-Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2010,2011 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _COGL_ATLAS_PRIVATE_H_
+#define _COGL_ATLAS_PRIVATE_H_
+
+#include "cogl-object-private.h"
+#include "cogl-texture.h"
+#include "cogl-list.h"
+#include "cogl-rectangle-map.h"
+#include "cogl-atlas.h"
+
+typedef enum
+{
+ COGL_ATLAS_CLEAR_TEXTURE = (1 << 0),
+ COGL_ATLAS_DISABLE_MIGRATION = (1 << 1)
+} CoglAtlasFlags;
+
+struct _CoglAtlas
+{
+ CoglObject _parent;
+
+ CoglContext *context;
+
+ CoglRectangleMap *map;
+
+ CoglTexture *texture;
+ CoglPixelFormat internal_format;
+ CoglAtlasFlags flags;
+
+ CoglList allocate_closures;
+
+ CoglList pre_reorganize_closures;
+ CoglList post_reorganize_closures;
+};
+
+CoglAtlas *
+_cogl_atlas_new (CoglContext *context,
+ CoglPixelFormat internal_format,
+ CoglAtlasFlags flags);
+
+CoglBool
+_cogl_atlas_allocate_space (CoglAtlas *atlas,
+ int width,
+ int height,
+ void *allocation_data);
+
+void
+_cogl_atlas_remove (CoglAtlas *atlas,
+ int x,
+ int y,
+ int width,
+ int height);
+
+CoglTexture *
+_cogl_atlas_migrate_allocation (CoglAtlas *atlas,
+ int x,
+ int y,
+ int width,
+ int height,
+ CoglPixelFormat internal_format);
+
+#endif /* _COGL_ATLAS_PRIVATE_H_ */
diff --git a/cogl/cogl-atlas-set-private.h b/cogl/cogl-atlas-set-private.h
new file mode 100644
index 00000000..5e3833f7
--- /dev/null
+++ b/cogl/cogl-atlas-set-private.h
@@ -0,0 +1,58 @@
+/*
+ * Cogl
+ *
+ * A Low-Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2013,2014 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ */
+
+#ifndef _COGL_ATLAS_SET_PRIVATE_H_
+#define _COGL_ATLAS_SET_PRIVATE_H_
+
+#include <glib.h>
+
+#include "cogl-atlas.h"
+#include "cogl-atlas-set.h"
+#include "cogl-list.h"
+#include "cogl-object-private.h"
+
+struct _CoglAtlasSet
+{
+ CoglObject _parent;
+
+ CoglContext *context;
+ USList *atlases;
+
+ CoglTextureComponents components;
+ CoglPixelFormat internal_format;
+
+ CoglList atlas_closures;
+
+ unsigned int clear_enabled : 1;
+ unsigned int premultiplied : 1;
+ unsigned int migration_enabled : 1;
+};
+
+#endif /* _COGL_ATLAS_SET_PRIVATE_H_ */
diff --git a/cogl/cogl-atlas-set.c b/cogl/cogl-atlas-set.c
new file mode 100644
index 00000000..b600100d
--- /dev/null
+++ b/cogl/cogl-atlas-set.c
@@ -0,0 +1,269 @@
+/*
+ * 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/>.
+ *
+ *
+ */
+
+#include <config.h>
+
+#include "cogl-atlas-set.h"
+#include "cogl-atlas-set-private.h"
+#include "cogl-atlas-private.h"
+#include "cogl-closure-list-private.h"
+#include "cogl-texture-private.h"
+#include "cogl-error-private.h"
+
+static void
+_cogl_atlas_set_free (CoglAtlasSet *set);
+
+COGL_OBJECT_DEFINE (AtlasSet, atlas_set);
+
+static CoglUserDataKey atlas_private_key;
+
+static void
+dissociate_atlases (CoglAtlasSet *set)
+{
+ USList *l;
+
+ /* NB: The set doesn't maintain a reference on the atlases since we don't
+ * want to keep them alive if they become empty. */
+ for (l = set->atlases; l; l = l->next)
+ cogl_object_set_user_data (l->data, &atlas_private_key, NULL, NULL);
+
+ u_slist_free (set->atlases);
+ set->atlases = NULL;
+}
+
+static void
+_cogl_atlas_set_free (CoglAtlasSet *set)
+{
+ dissociate_atlases (set);
+
+ _cogl_closure_list_disconnect_all (&set->atlas_closures);
+
+ u_slice_free (CoglAtlasSet, set);
+}
+
+static void
+_update_internal_format (CoglAtlasSet *set)
+{
+ set->internal_format = _cogl_texture_derive_format (set->context,
+ COGL_PIXEL_FORMAT_ANY,
+ set->components,
+ set->premultiplied);
+}
+
+CoglAtlasSet *
+cogl_atlas_set_new (CoglContext *context)
+{
+ CoglAtlasSet *set = u_slice_new0 (CoglAtlasSet);
+
+ set->context = context;
+ set->atlases = NULL;
+
+ set->components = COGL_TEXTURE_COMPONENTS_RGBA;
+ set->premultiplied = TRUE;
+ _update_internal_format (set);
+
+ set->clear_enabled = FALSE;
+ set->migration_enabled = TRUE;
+
+ _cogl_list_init (&set->atlas_closures);
+
+ return _cogl_atlas_set_object_new (set);
+}
+
+void
+cogl_atlas_set_set_components (CoglAtlasSet *set,
+ CoglTextureComponents components)
+{
+ u_return_if_fail (set->atlases == NULL);
+
+ set->components = components;
+ _update_internal_format (set);
+}
+
+CoglTextureComponents
+cogl_atlas_set_get_components (CoglAtlasSet *set)
+{
+ return set->components;
+}
+
+void
+cogl_atlas_set_set_premultiplied (CoglAtlasSet *set,
+ CoglBool premultiplied)
+{
+ u_return_if_fail (set->atlases == NULL);
+
+ set->premultiplied = premultiplied;
+ _update_internal_format (set);
+}
+
+CoglBool
+cogl_atlas_set_get_premultiplied (CoglAtlasSet *set)
+{
+ return set->premultiplied;
+}
+
+void
+cogl_atlas_set_set_clear_enabled (CoglAtlasSet *set,
+ CoglBool clear_enabled)
+{
+ _COGL_RETURN_IF_FAIL (set->atlases == NULL);
+
+ set->clear_enabled = clear_enabled;
+}
+
+CoglBool
+cogl_atlas_set_get_clear_enabled (CoglAtlasSet *set,
+ CoglBool clear_enabled)
+{
+ return set->clear_enabled;
+}
+
+void
+cogl_atlas_set_set_migration_enabled (CoglAtlasSet *set,
+ CoglBool migration_enabled)
+{
+ _COGL_RETURN_IF_FAIL (set->atlases == NULL);
+
+ set->migration_enabled = migration_enabled;
+}
+
+CoglBool
+cogl_atlas_set_get_migration_enabled (CoglAtlasSet *set)
+{
+ return set->migration_enabled;
+}
+
+CoglAtlasSetAtlasClosure *
+cogl_atlas_set_add_atlas_callback (CoglAtlasSet *set,
+ CoglAtlasSetAtlasCallback callback,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy)
+{
+ return _cogl_closure_list_add (&set->atlas_closures,
+ callback,
+ user_data,
+ destroy);
+}
+
+void
+cogl_atlas_set_remove_atlas_callback (CoglAtlasSet *set,
+ CoglAtlasSetAtlasClosure *closure)
+{
+ _cogl_closure_disconnect (closure);
+}
+
+static void
+atlas_destroyed_cb (void *user_data, void *instance)
+{
+ CoglAtlasSet *set = user_data;
+ CoglAtlas *atlas = instance;
+
+ set->atlases = u_slist_remove (set->atlases, atlas);
+}
+
+CoglAtlas *
+cogl_atlas_set_allocate_space (CoglAtlasSet *set,
+ int width,
+ int height,
+ void *allocation_data)
+{
+ USList *l;
+ CoglAtlasFlags flags = 0;
+ CoglAtlas *atlas;
+
+ /* Look for an existing atlas that can hold the texture */
+ for (l = set->atlases; l; l = l->next)
+ {
+ if (_cogl_atlas_allocate_space (l->data, width, height, allocation_data))
+ return l->data;
+ }
+
+ if (set->clear_enabled)
+ flags |= COGL_ATLAS_CLEAR_TEXTURE;
+
+ if (!set->migration_enabled)
+ flags |= COGL_ATLAS_DISABLE_MIGRATION;
+
+ atlas = _cogl_atlas_new (set->context,
+ set->internal_format,
+ flags);
+
+ _cogl_closure_list_invoke (&set->atlas_closures,
+ CoglAtlasSetAtlasCallback,
+ set,
+ atlas,
+ COGL_ATLAS_SET_EVENT_ADDED);
+
+ COGL_NOTE (ATLAS, "Created new atlas for textures: %p", atlas);
+ if (!_cogl_atlas_allocate_space (atlas, width, height, allocation_data))
+ {
+ _cogl_closure_list_invoke (&set->atlas_closures,
+ CoglAtlasSetAtlasCallback,
+ set,
+ atlas,
+ COGL_ATLAS_SET_EVENT_REMOVED);
+
+ /* Ok, this means we really can't add it to an atlas */
+ cogl_object_unref (atlas);
+
+ return NULL;
+ }
+
+ set->atlases = u_slist_prepend (set->atlases, atlas);
+
+ /* Set some data on the atlas so we can get notification when it is
+ destroyed in order to remove it from the list. set->atlases
+ effectively holds a weak reference. We don't need a strong
+ reference because the atlas textures take a reference on the
+ atlas so it will stay alive */
+ _cogl_object_set_user_data ((CoglObject *)atlas,
+ &atlas_private_key,
+ set,
+ atlas_destroyed_cb);
+
+ /* XXX: whatever allocates space in an atlas set is responsible for
+ * taking a reference on the corresponding atlas for the allocation
+ * otherwise.
+ *
+ * We want the lifetime of an atlas to be tied to the lifetime of
+ * the allocations within the atlas so we don't keep a reference
+ * ourselves.
+ */
+ u_warn_if_fail (atlas->_parent.ref_count != 1);
+
+ cogl_object_unref (atlas);
+
+ return atlas;
+}
+
+void
+cogl_atlas_set_foreach (CoglAtlasSet *atlas_set,
+ CoglAtlasSetForeachCallback callback,
+ void *user_data)
+{
+ USList *l;
+
+ for (l = atlas_set->atlases; l; l = l->next)
+ callback (l->data, user_data);
+}
diff --git a/cogl/cogl-atlas-set.h b/cogl/cogl-atlas-set.h
new file mode 100644
index 00000000..679bd07e
--- /dev/null
+++ b/cogl/cogl-atlas-set.h
@@ -0,0 +1,161 @@
+/*
+ * Cogl
+ *
+ * A Low-Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2013,2014 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef _COGL_ATLAS_SET_H_
+#define _COGL_ATLAS_SET_H_
+
+#include <cogl/cogl-types.h>
+#include <cogl/cogl-object.h>
+#include <cogl/cogl-atlas.h>
+
+/**
+ * CoglAtlasSet:
+ *
+ * A #CoglAtlasSet represents a set of #CoglAtlas<!-- -->es and a
+ * #CoglAtlas represents one texture that is sub divided into smaller
+ * allocations.
+ *
+ * After creating a #CoglAtlas you can specify a common format for all
+ * #CoglAtlas textures that will belong to that set via
+ * cogl_atlas_set_set_components() and
+ * cogl_atlas_set_set_premultiplied(). These can't be changed once you
+ * start allocating from the set.
+ *
+ * Two notable properties of a #CoglAtlasSet are whether automatic
+ * clearing is enabled and whether migration is enabled.
+ *
+ * Enabling automatic clearing via cogl_atlas_set_clear_enabled()
+ * ensures that each new #CoglAtlas texture that's created is
+ * initialized to contain zeros for all components. Enabling clearing
+ * can be useful for applications that might end up sampling outside
+ * the bounds of individual atlas allocations due to filtering so they
+ * can avoid random values bleeding into samples, resulting in
+ * artefacts.
+ *
+ * When there is not enough room in an atlas texture for a new
+ * allocation, Cogl will try to allocate a larger texture and then
+ * migrate the contents of previous allocations to the new, larger
+ * texture. For images that can easily be re-created and that are
+ * perhaps only used in an add-hoc fashion it may not be worthwhile
+ * the cost of migrating the previous allocations. Migration of
+ * allocations can be disabled via
+ * cogl_atlas_set_set_migration_enabled(). With migrations disabled
+ * then previous allocations will be re-allocated space in any
+ * replacement texture, but no image data will be copied.
+ */
+typedef struct _CoglAtlasSet CoglAtlasSet;
+
+/**
+ * cogl_atlas_set_new:
+ * @context: A #CoglContext pointer
+ *
+ * Return value: A newly allocated #CoglAtlasSet
+ */
+CoglAtlasSet *
+cogl_atlas_set_new (CoglContext *context);
+
+CoglBool
+cogl_is_atlas_set (void *object);
+
+void
+cogl_atlas_set_set_components (CoglAtlasSet *set,
+ CoglTextureComponents components);
+
+CoglTextureComponents
+cogl_atlas_set_get_components (CoglAtlasSet *set);
+
+void
+cogl_atlas_set_set_premultiplied (CoglAtlasSet *set,
+ CoglBool premultiplied);
+
+CoglBool
+cogl_atlas_set_get_premultiplied (CoglAtlasSet *set);
+
+void
+cogl_atlas_set_set_clear_enabled (CoglAtlasSet *set,
+ CoglBool clear_enabled);
+
+CoglBool
+cogl_atlas_set_get_clear_enabled (CoglAtlasSet *set,
+ CoglBool clear_enabled);
+
+void
+cogl_atlas_set_set_migration_enabled (CoglAtlasSet *set,
+ CoglBool migration_enabled);
+
+CoglBool
+cogl_atlas_set_get_migration_enabled (CoglAtlasSet *set);
+
+
+void
+cogl_atlas_set_clear (CoglAtlasSet *set);
+
+typedef enum _CoglAtlasSetEvent
+{
+ COGL_ATLAS_SET_EVENT_ADDED = 1,
+ COGL_ATLAS_SET_EVENT_REMOVED = 2
+} CoglAtlasSetEvent;
+
+typedef struct _CoglClosure CoglAtlasSetAtlasClosure;
+
+typedef void (*CoglAtlasSetAtlasCallback) (CoglAtlasSet *set,
+ CoglAtlas *atlas,
+ CoglAtlasSetEvent event,
+ void *user_data);
+
+CoglAtlasSetAtlasClosure *
+cogl_atlas_set_add_atlas_callback (CoglAtlasSet *set,
+ CoglAtlasSetAtlasCallback callback,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy);
+
+void
+cogl_atlas_set_remove_atlas_callback (CoglAtlasSet *set,
+ CoglAtlasSetAtlasClosure *closure);
+
+CoglAtlas *
+cogl_atlas_set_allocate_space (CoglAtlasSet *set,
+ int width,
+ int height,
+ void *allocation_data);
+
+typedef void (* CoglAtlasSetForeachCallback) (CoglAtlas *atlas,
+ void *user_data);
+
+void
+cogl_atlas_set_foreach (CoglAtlasSet *atlas_set,
+ CoglAtlasSetForeachCallback callback,
+ void *user_data);
+
+#endif /* _COGL_ATLAS_SET_H_ */
diff --git a/cogl/cogl-atlas-texture-private.h b/cogl/cogl-atlas-texture-private.h
index 6e47cc88..64f6b64f 100644
--- a/cogl/cogl-atlas-texture-private.h
+++ b/cogl/cogl-atlas-texture-private.h
@@ -34,7 +34,7 @@
#include "cogl-object-private.h"
#include "cogl-texture-private.h"
#include "cogl-rectangle-map.h"
-#include "cogl-atlas.h"
+#include "cogl-atlas-set-private.h"
#include "cogl-atlas-texture.h"
struct _CoglAtlasTexture
@@ -48,7 +48,7 @@ struct _CoglAtlasTexture
/* The rectangle that was used to add this texture to the
atlas. This includes the 1-pixel border */
- CoglRectangleMapEntry rectangle;
+ CoglAtlasAllocation allocation;
/* The atlas that this texture is in. If the texture is no longer in
an atlas then this will be NULL. A reference is taken on the
@@ -61,17 +61,13 @@ struct _CoglAtlasTexture
CoglTexture *sub_texture;
};
-void
-_cogl_atlas_texture_add_reorganize_callback (CoglContext *ctx,
- UHookFunc callback,
- void *user_data);
-
-void
-_cogl_atlas_texture_remove_reorganize_callback (CoglContext *ctx,
- UHookFunc callback,
- void *user_data);
-
CoglBool
_cogl_is_atlas_texture (void *object);
+void
+_cogl_atlas_texture_atlas_event_handler (CoglAtlasSet *set,
+ CoglAtlas *atlas,
+ CoglAtlasSetEvent event,
+ void *user_data);
+
#endif /* _COGL_ATLAS_TEXTURE_PRIVATE_H_ */
diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c
index 2eaeb3f9..401801fa 100644
--- a/cogl/cogl-atlas-texture.c
+++ b/cogl/cogl-atlas-texture.c
@@ -31,9 +31,7 @@
* Neil Roberts <neil@linux.intel.com>
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <config.h>
#include "cogl-debug.h"
#include "cogl-util.h"
@@ -47,7 +45,8 @@
#include "cogl-rectangle-map.h"
#include "cogl-journal-private.h"
#include "cogl-pipeline-opengl-private.h"
-#include "cogl-atlas.h"
+#include "cogl-atlas-set-private.h"
+#include "cogl-atlas-private.h"
#include "cogl-sub-texture.h"
#include "cogl-error-private.h"
#include "cogl-texture-gl-private.h"
@@ -63,60 +62,58 @@ static const CoglTextureVtable cogl_atlas_texture_vtable;
static CoglSubTexture *
_cogl_atlas_texture_create_sub_texture (CoglTexture *full_texture,
- const CoglRectangleMapEntry *rectangle)
+ const CoglAtlasAllocation *allocation)
{
CoglContext *ctx = full_texture->context;
/* Create a subtexture for the given rectangle not including the
1-pixel border */
return cogl_sub_texture_new (ctx,
full_texture,
- rectangle->x + 1,
- rectangle->y + 1,
- rectangle->width - 2,
- rectangle->height - 2);
+ allocation->x + 1,
+ allocation->y + 1,
+ allocation->width - 2,
+ allocation->height - 2);
}
static void
-_cogl_atlas_texture_update_position_cb (void *user_data,
- CoglTexture *new_texture,
- const CoglRectangleMapEntry *rectangle)
+_cogl_atlas_texture_allocate_cb (CoglAtlas *atlas,
+ CoglTexture *texture,
+ const CoglAtlasAllocation *allocation,
+ void *allocation_data,
+ void *user_data)
{
- CoglAtlasTexture *atlas_tex = user_data;
+ CoglAtlasTexture *atlas_tex = allocation_data;
/* Update the sub texture */
if (atlas_tex->sub_texture)
cogl_object_unref (atlas_tex->sub_texture);
atlas_tex->sub_texture = COGL_TEXTURE (
- _cogl_atlas_texture_create_sub_texture (new_texture, rectangle));
+ _cogl_atlas_texture_create_sub_texture (texture, allocation));
/* Update the position */
- atlas_tex->rectangle = *rectangle;
+ atlas_tex->allocation = *allocation;
+ atlas_tex->atlas = cogl_object_ref (atlas);
}
static void
_cogl_atlas_texture_pre_reorganize_foreach_cb
- (const CoglRectangleMapEntry *entry,
- void *rectangle_data,
+ (CoglAtlas *atlas,
+ const CoglAtlasAllocation *allocation,
+ void *allocation_data,
void *user_data)
{
- CoglAtlasTexture *atlas_tex = rectangle_data;
+ CoglAtlasTexture *atlas_tex = allocation_data;
/* Keep a reference to the texture because we don't want it to be
destroyed during the reorganization */
cogl_object_ref (atlas_tex);
-
- /* Notify cogl-pipeline.c that the texture's underlying GL texture
- * storage is changing so it knows it may need to bind a new texture
- * if the CoglTexture is reused with the same texture unit. */
- _cogl_pipeline_texture_storage_change_notify (COGL_TEXTURE (atlas_tex));
}
static void
-_cogl_atlas_texture_pre_reorganize_cb (void *data)
+_cogl_atlas_texture_pre_reorganize_cb (CoglAtlas *atlas,
+ void *user_data)
{
- CoglAtlas *atlas = data;
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ CoglContext *ctx = user_data;
/* We don't know if any journal entries currently depend on OpenGL
* texture coordinates that would be invalidated by reorganizing
@@ -127,52 +124,50 @@ _cogl_atlas_texture_pre_reorganize_cb (void *data)
*/
_cogl_flush (ctx);
- if (atlas->map)
- _cogl_rectangle_map_foreach (atlas->map,
- _cogl_atlas_texture_pre_reorganize_foreach_cb,
- NULL);
+ cogl_atlas_foreach (atlas,
+ _cogl_atlas_texture_pre_reorganize_foreach_cb,
+ NULL);
}
typedef struct
{
CoglAtlasTexture **textures;
/* Number of textures found so far */
- unsigned int n_textures;
-} CoglAtlasTextureGetRectanglesData;
+ int n_textures;
+} CoglAtlasTextureGetAllocationsData;
static void
-_cogl_atlas_texture_get_rectangles_cb (const CoglRectangleMapEntry *entry,
- void *rectangle_data,
- void *user_data)
+_cogl_atlas_texture_get_allocations_cb (CoglAtlas *atlas,
+ const CoglAtlasAllocation *allocation,
+ void *allocation_data,
+ void *user_data)
{
- CoglAtlasTextureGetRectanglesData *data = user_data;
+ CoglAtlasTextureGetAllocationsData *data = user_data;
- data->textures[data->n_textures++] = rectangle_data;
+ data->textures[data->n_textures++] = allocation_data;
}
static void
-_cogl_atlas_texture_post_reorganize_cb (void *user_data)
+_cogl_atlas_texture_post_reorganize_cb (CoglAtlas *atlas,
+ void *user_data)
{
- CoglAtlas *atlas = user_data;
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ int n_allocations = cogl_atlas_get_n_allocations (atlas);
- if (atlas->map)
+ if (n_allocations)
{
- CoglAtlasTextureGetRectanglesData data;
- unsigned int i;
+ CoglAtlasTextureGetAllocationsData data;
+ int i;
- data.textures = u_new (CoglAtlasTexture *,
- _cogl_rectangle_map_get_n_rectangles (atlas->map));
+ data.textures = u_alloca (sizeof (CoglAtlasTexture *) * n_allocations);
data.n_textures = 0;
/* We need to remove all of the references that we took during
- the preorganize callback. We have to get a separate array of
- the textures because CoglRectangleMap doesn't support
- removing rectangles during iteration */
- _cogl_rectangle_map_foreach (atlas->map,
- _cogl_atlas_texture_get_rectangles_cb,
- &data);
+ * the preorganize callback. We have to get a separate array of
+ * the textures because CoglAtlas doesn't support removing
+ * allocations during iteration */
+ cogl_atlas_foreach (atlas,
+ _cogl_atlas_texture_get_allocations_cb,
+ &data);
for (i = 0; i < data.n_textures; i++)
{
@@ -183,48 +178,7 @@ _cogl_atlas_texture_post_reorganize_cb (void *user_data)
if (data.textures[i]->atlas)
cogl_object_unref (data.textures[i]);
}
-
- u_free (data.textures);
}
-
- /* Notify any listeners that an atlas has changed */
- u_hook_list_invoke (&ctx->atlas_reorganize_callbacks, FALSE);
-}
-
-static void
-_cogl_atlas_texture_atlas_destroyed_cb (void *user_data)
-{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- /* Remove the atlas from the global list */
- ctx->atlases = u_slist_remove (ctx->atlases, user_data);
-}
-
-static CoglAtlas *
-_cogl_atlas_texture_create_atlas (CoglContext *ctx)
-{
- static CoglUserDataKey atlas_private_key;
-
- CoglAtlas *atlas = _cogl_atlas_new (COGL_PIXEL_FORMAT_RGBA_8888,
- 0,
- _cogl_atlas_texture_update_position_cb);
-
- _cogl_atlas_add_reorganize_callback (atlas,
- _cogl_atlas_texture_pre_reorganize_cb,
- _cogl_atlas_texture_post_reorganize_cb,
- atlas);
-
- ctx->atlases = u_slist_prepend (ctx->atlases, atlas);
-
- /* Set some data on the atlas so we can get notification when it is
- destroyed in order to remove it from the list. ctx->atlases
- effectively holds a weak reference. We don't need a strong
- reference because the atlas textures take a reference on the
- atlas so it will stay alive */
- cogl_object_set_user_data (COGL_OBJECT (atlas), &atlas_private_key, atlas,
- _cogl_atlas_texture_atlas_destroyed_cb);
-
- return atlas;
}
static void
@@ -273,7 +227,10 @@ _cogl_atlas_texture_remove_from_atlas (CoglAtlasTexture *atlas_tex)
if (atlas_tex->atlas)
{
_cogl_atlas_remove (atlas_tex->atlas,
- &atlas_tex->rectangle);
+ atlas_tex->allocation.x,
+ atlas_tex->allocation.y,
+ atlas_tex->allocation.width,
+ atlas_tex->allocation.height);
cogl_object_unref (atlas_tex->atlas);
atlas_tex->atlas = NULL;
@@ -382,12 +339,12 @@ _cogl_atlas_texture_migrate_out_of_atlas (CoglAtlasTexture *atlas_tex)
_cogl_flush (ctx);
standalone_tex =
- _cogl_atlas_copy_rectangle (atlas_tex->atlas,
- atlas_tex->rectangle.x + 1,
- atlas_tex->rectangle.y + 1,
- atlas_tex->rectangle.width - 2,
- atlas_tex->rectangle.height - 2,
- atlas_tex->internal_format);
+ _cogl_atlas_migrate_allocation (atlas_tex->atlas,
+ atlas_tex->allocation.x + 1,
+ atlas_tex->allocation.y + 1,
+ atlas_tex->allocation.width - 2,
+ atlas_tex->allocation.height - 2,
+ atlas_tex->internal_format);
/* Note: we simply silently ignore failures to migrate a texture
* out (most likely due to lack of memory) and hope for the
* best.
@@ -459,8 +416,8 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
dst_width,
dst_height,
bmp,
- dst_x + atlas_tex->rectangle.x + 1,
- dst_y + atlas_tex->rectangle.y + 1,
+ dst_x + atlas_tex->allocation.x + 1,
+ dst_y + atlas_tex->allocation.y + 1,
0, /* level 0 */
error))
return FALSE;
@@ -471,20 +428,20 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
src_x, src_y,
1, dst_height,
bmp,
- atlas_tex->rectangle.x,
- dst_y + atlas_tex->rectangle.y + 1,
+ atlas_tex->allocation.x,
+ dst_y + atlas_tex->allocation.y + 1,
0, /* level 0 */
error))
return FALSE;
/* Update the right edge pixels */
- if (dst_x + dst_width == atlas_tex->rectangle.width - 2 &&
+ if (dst_x + dst_width == atlas_tex->allocation.width - 2 &&
!cogl_texture_set_region_from_bitmap (atlas->texture,
src_x + dst_width - 1, src_y,
1, dst_height,
bmp,
- atlas_tex->rectangle.x +
- atlas_tex->rectangle.width - 1,
- dst_y + atlas_tex->rectangle.y + 1,
+ atlas_tex->allocation.x +
+ atlas_tex->allocation.width - 1,
+ dst_y + atlas_tex->allocation.y + 1,
0, /* level 0 */
error))
return FALSE;
@@ -494,20 +451,20 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
src_x, src_y,
dst_width, 1,
bmp,
- dst_x + atlas_tex->rectangle.x + 1,
- atlas_tex->rectangle.y,
+ dst_x + atlas_tex->allocation.x + 1,
+ atlas_tex->allocation.y,
0, /* level 0 */
error))
return FALSE;
/* Update the bottom edge pixels */
- if (dst_y + dst_height == atlas_tex->rectangle.height - 2 &&
+ if (dst_y + dst_height == atlas_tex->allocation.height - 2 &&
!cogl_texture_set_region_from_bitmap (atlas->texture,
src_x, src_y + dst_height - 1,
dst_width, 1,
bmp,
- dst_x + atlas_tex->rectangle.x + 1,
- atlas_tex->rectangle.y +
- atlas_tex->rectangle.height - 1,
+ dst_x + atlas_tex->allocation.x + 1,
+ atlas_tex->allocation.y +
+ atlas_tex->allocation.height - 1,
0, /* level 0 */
error))
return FALSE;
@@ -649,6 +606,38 @@ _cogl_atlas_texture_can_use_format (CoglPixelFormat format)
format == COGL_PIXEL_FORMAT_RGBA_8888);
}
+void
+_cogl_atlas_texture_atlas_event_handler (CoglAtlasSet *set,
+ CoglAtlas *atlas,
+ CoglAtlasSetEvent event,
+ void *user_data)
+{
+ switch (event)
+ {
+ case COGL_ATLAS_SET_EVENT_ADDED:
+ {
+ CoglAtlasReorganizeCallback pre_callback =
+ _cogl_atlas_texture_pre_reorganize_cb;
+ CoglAtlasReorganizeCallback post_callback =
+ _cogl_atlas_texture_post_reorganize_cb;
+
+ cogl_atlas_add_allocate_callback (atlas,
+ _cogl_atlas_texture_allocate_cb,
+ NULL, /* user data */
+ NULL); /* destroy */
+ cogl_atlas_add_pre_reorganize_callback (atlas, pre_callback,
+ set->context,
+ NULL); /* destroy */
+ cogl_atlas_add_post_reorganize_callback (atlas, post_callback,
+ set->context,
+ NULL); /* destroy */
+ break;
+ }
+ case COGL_ATLAS_SET_EVENT_REMOVED:
+ break;
+ }
+}
+
static CoglAtlasTexture *
_cogl_atlas_texture_create_base (CoglContext *ctx,
int width,
@@ -712,7 +701,6 @@ allocate_space (CoglAtlasTexture *atlas_tex,
CoglTexture *tex = COGL_TEXTURE (atlas_tex);
CoglContext *ctx = tex->context;
CoglAtlas *atlas;
- USList *l;
/* If the texture is in a strange format then we won't use it */
if (!_cogl_atlas_texture_can_use_format (internal_format))
@@ -738,43 +726,24 @@ allocate_space (CoglAtlasTexture *atlas_tex,
return FALSE;
}
- /* Look for an existing atlas that can hold the texture */
- for (l = ctx->atlases; l; l = l->next)
- /* Try to make some space in the atlas for the texture */
- if (_cogl_atlas_reserve_space (atlas = l->data,
- /* Add two pixels for the border */
- width + 2, height + 2,
- atlas_tex))
- {
- cogl_object_ref (atlas);
- break;
- }
-
- /* If we couldn't find a suitable atlas then start another */
- if (l == NULL)
+ /* Add two pixels for the border
+ * FIXME: two pixels isn't enough if mipmapping is in use
+ */
+ atlas = cogl_atlas_set_allocate_space (ctx->atlas_set,
+ tex->width + 2,
+ tex->height + 2,
+ atlas_tex);
+ if (!atlas)
{
- atlas = _cogl_atlas_texture_create_atlas (ctx);
- COGL_NOTE (ATLAS, "Created new atlas for textures: %p", atlas);
- if (!_cogl_atlas_reserve_space (atlas,
- /* Add two pixels for the border */
- width + 2, height + 2,
- atlas_tex))
- {
- /* Ok, this means we really can't add it to the atlas */
- cogl_object_unref (atlas);
-
- _cogl_set_error (error,
- COGL_SYSTEM_ERROR,
- COGL_SYSTEM_ERROR_NO_MEMORY,
- "Not enough memory to atlas texture");
- return FALSE;
- }
+ _cogl_set_error (error,
+ COGL_SYSTEM_ERROR,
+ COGL_SYSTEM_ERROR_NO_MEMORY,
+ "Not enough memory to atlas texture");
+ return FALSE;
}
atlas_tex->internal_format = internal_format;
- atlas_tex->atlas = atlas;
-
return TRUE;
}
@@ -974,31 +943,6 @@ cogl_atlas_texture_new_from_file (CoglContext *ctx,
return atlas_tex;
}
-void
-_cogl_atlas_texture_add_reorganize_callback (CoglContext *ctx,
- UHookFunc callback,
- void *user_data)
-{
- UHook *hook = u_hook_alloc (&ctx->atlas_reorganize_callbacks);
- hook->func = callback;
- hook->data = user_data;
- u_hook_prepend (&ctx->atlas_reorganize_callbacks, hook);
-}
-
-void
-_cogl_atlas_texture_remove_reorganize_callback (CoglContext *ctx,
- UHookFunc callback,
- void *user_data)
-{
- UHook *hook = u_hook_find_func_data (&ctx->atlas_reorganize_callbacks,
- FALSE,
- callback,
- user_data);
-
- if (hook)
- u_hook_destroy_link (&ctx->atlas_reorganize_callbacks, hook);
-}
-
static CoglTextureType
_cogl_atlas_texture_get_type (CoglTexture *tex)
{
diff --git a/cogl/cogl-atlas.c b/cogl/cogl-atlas.c
index fd5a3164..94ae7929 100644
--- a/cogl/cogl-atlas.c
+++ b/cogl/cogl-atlas.c
@@ -29,11 +29,9 @@
* Neil Roberts <neil@linux.intel.com>
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <config.h>
-#include "cogl-atlas.h"
+#include "cogl-atlas-private.h"
#include "cogl-rectangle-map.h"
#include "cogl-context-private.h"
#include "cogl-texture-private.h"
@@ -50,26 +48,48 @@
static void _cogl_atlas_free (CoglAtlas *atlas);
-COGL_OBJECT_INTERNAL_DEFINE (Atlas, atlas);
+COGL_OBJECT_DEFINE (Atlas, atlas);
CoglAtlas *
-_cogl_atlas_new (CoglPixelFormat texture_format,
- CoglAtlasFlags flags,
- CoglAtlasUpdatePositionCallback update_position_cb)
+_cogl_atlas_new (CoglContext *context,
+ CoglPixelFormat internal_format,
+ CoglAtlasFlags flags)
{
CoglAtlas *atlas = u_new (CoglAtlas, 1);
- atlas->update_position_cb = update_position_cb;
+ atlas->context = context;
atlas->map = NULL;
atlas->texture = NULL;
atlas->flags = flags;
- atlas->texture_format = texture_format;
- u_hook_list_init (&atlas->pre_reorganize_callbacks, sizeof (UHook));
- u_hook_list_init (&atlas->post_reorganize_callbacks, sizeof (UHook));
+ atlas->internal_format = internal_format;
+
+ _cogl_list_init (&atlas->allocate_closures);
+
+ _cogl_list_init (&atlas->pre_reorganize_closures);
+ _cogl_list_init (&atlas->post_reorganize_closures);
return _cogl_atlas_object_new (atlas);
}
+CoglAtlasAllocateClosure *
+cogl_atlas_add_allocate_callback (CoglAtlas *atlas,
+ CoglAtlasAllocateCallback callback,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy)
+{
+ return _cogl_closure_list_add (&atlas->allocate_closures,
+ callback,
+ user_data,
+ destroy);
+}
+
+void
+cogl_atlas_remove_allocate_callback (CoglAtlas *atlas,
+ CoglAtlasAllocateClosure *closure)
+{
+ _cogl_closure_disconnect (closure);
+}
+
static void
_cogl_atlas_free (CoglAtlas *atlas)
{
@@ -80,8 +100,10 @@ _cogl_atlas_free (CoglAtlas *atlas)
if (atlas->map)
_cogl_rectangle_map_free (atlas->map);
- u_hook_list_clear (&atlas->pre_reorganize_callbacks);
- u_hook_list_clear (&atlas->post_reorganize_callbacks);
+ _cogl_closure_list_disconnect_all (&atlas->allocate_closures);
+
+ _cogl_closure_list_disconnect_all (&atlas->pre_reorganize_closures);
+ _cogl_closure_list_disconnect_all (&atlas->post_reorganize_closures);
u_free (atlas);
}
@@ -89,21 +111,22 @@ _cogl_atlas_free (CoglAtlas *atlas)
typedef struct _CoglAtlasRepositionData
{
/* The current user data for this texture */
- void *user_data;
+ void *allocation_data;
+
/* The old and new positions of the texture */
CoglRectangleMapEntry old_position;
CoglRectangleMapEntry new_position;
} CoglAtlasRepositionData;
static void
-_cogl_atlas_migrate (CoglAtlas *atlas,
- unsigned int n_textures,
+_cogl_atlas_migrate (CoglAtlas *atlas,
+ int n_textures,
CoglAtlasRepositionData *textures,
- CoglTexture *old_texture,
- CoglTexture *new_texture,
- void *skip_user_data)
+ CoglTexture *old_texture,
+ CoglTexture *new_texture,
+ void *skip_allocation_data)
{
- unsigned int i;
+ int i;
CoglBlitData blit_data;
/* If the 'disable migrate' flag is set then we won't actually copy
@@ -111,19 +134,30 @@ _cogl_atlas_migrate (CoglAtlas *atlas,
callback to update the position */
if ((atlas->flags & COGL_ATLAS_DISABLE_MIGRATION))
for (i = 0; i < n_textures; i++)
- /* Update the texture position */
- atlas->update_position_cb (textures[i].user_data,
- new_texture,
- &textures[i].new_position);
+ {
+ CoglAtlasAllocation *allocation =
+ (CoglAtlasAllocation *)&textures[i].new_position;
+
+ /* Update the texture position */
+ _cogl_closure_list_invoke (&atlas->allocate_closures,
+ CoglAtlasAllocateCallback,
+ atlas,
+ new_texture,
+ allocation,
+ textures[i].allocation_data);
+ }
else
{
_cogl_blit_begin (&blit_data, new_texture, old_texture);
for (i = 0; i < n_textures; i++)
{
+ CoglAtlasAllocation *allocation =
+ (CoglAtlasAllocation *)&textures[i].new_position;
+
/* Skip the texture that is being added because it doesn't contain
any data yet */
- if (textures[i].user_data != skip_user_data)
+ if (textures[i].allocation_data != skip_allocation_data)
_cogl_blit (&blit_data,
textures[i].old_position.x,
textures[i].old_position.y,
@@ -133,9 +167,12 @@ _cogl_atlas_migrate (CoglAtlas *atlas,
textures[i].new_position.height);
/* Update the texture position */
- atlas->update_position_cb (textures[i].user_data,
+ _cogl_closure_list_invoke (&atlas->allocate_closures,
+ CoglAtlasAllocateCallback,
+ atlas,
new_texture,
- &textures[i].new_position);
+ allocation,
+ textures[i].allocation_data);
}
_cogl_blit_end (&blit_data);
@@ -146,23 +183,23 @@ typedef struct _CoglAtlasGetRectanglesData
{
CoglAtlasRepositionData *textures;
/* Number of textures found so far */
- unsigned int n_textures;
+ int n_textures;
} CoglAtlasGetRectanglesData;
static void
_cogl_atlas_get_rectangles_cb (const CoglRectangleMapEntry *rectangle,
- void *rect_data,
- void *user_data)
+ void *rect_data,
+ void *user_data)
{
CoglAtlasGetRectanglesData *data = user_data;
data->textures[data->n_textures].old_position = *rectangle;
- data->textures[data->n_textures++].user_data = rect_data;
+ data->textures[data->n_textures++].allocation_data = rect_data;
}
static void
-_cogl_atlas_get_next_size (unsigned int *map_width,
- unsigned int *map_height)
+_cogl_atlas_get_next_size (int *map_width,
+ int *map_height)
{
/* Double the size of the texture by increasing whichever dimension
is smaller */
@@ -173,19 +210,18 @@ _cogl_atlas_get_next_size (unsigned int *map_width,
}
static void
-_cogl_atlas_get_initial_size (CoglPixelFormat format,
- unsigned int *map_width,
- unsigned int *map_height)
+_cogl_atlas_get_initial_size (CoglAtlas *atlas,
+ int *map_width,
+ int *map_height)
{
+ CoglContext *ctx = atlas->context;
unsigned int size;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
ctx->driver_vtable->pixel_format_to_gl (ctx,
- format,
+ atlas->internal_format,
&gl_intformat,
&gl_format,
&gl_type);
@@ -195,7 +231,7 @@ _cogl_atlas_get_initial_size (CoglPixelFormat format,
initial minimum size. If the format is only 1 byte per pixel we
can use 1024x1024, otherwise we'll assume it will take 4 bytes
per pixel and use 512x512. */
- if (_cogl_pixel_format_get_bytes_per_pixel (format) == 1)
+ if (_cogl_pixel_format_get_bytes_per_pixel (atlas->internal_format) == 1)
size = 1024;
else
size = 512;
@@ -216,20 +252,19 @@ _cogl_atlas_get_initial_size (CoglPixelFormat format,
}
static CoglRectangleMap *
-_cogl_atlas_create_map (CoglPixelFormat format,
- unsigned int map_width,
- unsigned int map_height,
- unsigned int n_textures,
+_cogl_atlas_create_map (CoglAtlas *atlas,
+ int map_width,
+ int map_height,
+ int n_textures,
CoglAtlasRepositionData *textures)
{
+ CoglContext *ctx = atlas->context;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
- _COGL_GET_CONTEXT (ctx, NULL);
-
ctx->driver_vtable->pixel_format_to_gl (ctx,
- format,
+ atlas->internal_format,
&gl_intformat,
&gl_format,
&gl_type);
@@ -246,7 +281,7 @@ _cogl_atlas_create_map (CoglPixelFormat format,
CoglRectangleMap *new_atlas = _cogl_rectangle_map_new (map_width,
map_height,
NULL);
- unsigned int i;
+ int i;
COGL_NOTE (ATLAS, "Trying to resize the atlas to %ux%u",
map_width, map_height);
@@ -256,7 +291,7 @@ _cogl_atlas_create_map (CoglPixelFormat format,
if (!_cogl_rectangle_map_add (new_atlas,
textures[i].old_position.width,
textures[i].old_position.height,
- textures[i].user_data,
+ textures[i].allocation_data,
&textures[i].new_position))
break;
@@ -284,30 +319,29 @@ _cogl_atlas_create_texture (CoglAtlas *atlas,
int width,
int height)
{
+ CoglContext *ctx = atlas->context;
CoglTexture2D *tex;
CoglError *ignore_error = NULL;
- _COGL_GET_CONTEXT (ctx, NULL);
-
if ((atlas->flags & COGL_ATLAS_CLEAR_TEXTURE))
{
uint8_t *clear_data;
CoglBitmap *clear_bmp;
- int bpp = _cogl_pixel_format_get_bytes_per_pixel (atlas->texture_format);
+ int bpp = _cogl_pixel_format_get_bytes_per_pixel (atlas->internal_format);
/* Create a buffer of zeroes to initially clear the texture */
clear_data = u_malloc0 (width * height * bpp);
clear_bmp = cogl_bitmap_new_for_data (ctx,
width,
height,
- atlas->texture_format,
+ atlas->internal_format,
width * bpp,
clear_data);
tex = cogl_texture_2d_new_from_bitmap (clear_bmp);
_cogl_texture_set_internal_format (COGL_TEXTURE (tex),
- atlas->texture_format);
+ atlas->internal_format);
if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error))
{
@@ -325,7 +359,7 @@ _cogl_atlas_create_texture (CoglAtlas *atlas,
tex = cogl_texture_2d_new_with_size (ctx, width, height);
_cogl_texture_set_internal_format (COGL_TEXTURE (tex),
- atlas->texture_format);
+ atlas->internal_format);
if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error))
{
@@ -352,36 +386,24 @@ _cogl_atlas_compare_size_cb (const void *a,
return a_size < b_size ? 1 : a_size > b_size ? -1 : 0;
}
-static void
-_cogl_atlas_notify_pre_reorganize (CoglAtlas *atlas)
-{
- u_hook_list_invoke (&atlas->pre_reorganize_callbacks, FALSE);
-}
-
-static void
-_cogl_atlas_notify_post_reorganize (CoglAtlas *atlas)
-{
- u_hook_list_invoke (&atlas->post_reorganize_callbacks, FALSE);
-}
-
CoglBool
-_cogl_atlas_reserve_space (CoglAtlas *atlas,
- unsigned int width,
- unsigned int height,
- void *user_data)
+_cogl_atlas_allocate_space (CoglAtlas *atlas,
+ int width,
+ int height,
+ void *allocation_data)
{
CoglAtlasGetRectanglesData data;
CoglRectangleMap *new_map;
CoglTexture2D *new_tex;
- unsigned int map_width, map_height;
+ int map_width, map_height;
CoglBool ret;
- CoglRectangleMapEntry new_position;
+ CoglAtlasAllocation new_allocation;
/* Check if we can fit the rectangle into the existing map */
if (atlas->map &&
_cogl_rectangle_map_add (atlas->map, width, height,
- user_data,
- &new_position))
+ allocation_data,
+ (CoglRectangleMapEntry *)&new_allocation))
{
COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
atlas,
@@ -393,9 +415,12 @@ _cogl_atlas_reserve_space (CoglAtlas *atlas,
100 / (_cogl_rectangle_map_get_width (atlas->map) *
_cogl_rectangle_map_get_height (atlas->map)));
- atlas->update_position_cb (user_data,
+ _cogl_closure_list_invoke (&atlas->allocate_closures,
+ CoglAtlasAllocateCallback,
+ atlas,
atlas->texture,
- &new_position);
+ &new_allocation,
+ allocation_data);
return TRUE;
}
@@ -404,7 +429,9 @@ _cogl_atlas_reserve_space (CoglAtlas *atlas,
we'll notify any users of the atlas that this is going to happen
so that for example in CoglAtlasTexture it can notify that the
storage has changed and cause a flush */
- _cogl_atlas_notify_pre_reorganize (atlas);
+ _cogl_closure_list_invoke (&atlas->pre_reorganize_closures,
+ CoglAtlasReorganizeCallback,
+ atlas);
/* Get an array of all the textures currently in the atlas. */
data.n_textures = 0;
@@ -412,7 +439,7 @@ _cogl_atlas_reserve_space (CoglAtlas *atlas,
data.textures = u_malloc (sizeof (CoglAtlasRepositionData));
else
{
- unsigned int n_rectangles =
+ int n_rectangles =
_cogl_rectangle_map_get_n_rectangles (atlas->map);
data.textures = u_malloc (sizeof (CoglAtlasRepositionData) *
(n_rectangles + 1));
@@ -427,7 +454,7 @@ _cogl_atlas_reserve_space (CoglAtlas *atlas,
data.textures[data.n_textures].old_position.y = 0;
data.textures[data.n_textures].old_position.width = width;
data.textures[data.n_textures].old_position.height = height;
- data.textures[data.n_textures++].user_data = user_data;
+ data.textures[data.n_textures++].allocation_data = allocation_data;
/* The atlasing algorithm works a lot better if the rectangles are
added in decreasing order of size so we'll first sort the
@@ -452,10 +479,9 @@ _cogl_atlas_reserve_space (CoglAtlas *atlas,
_cogl_atlas_get_next_size (&map_width, &map_height);
}
else
- _cogl_atlas_get_initial_size (atlas->texture_format,
- &map_width, &map_height);
+ _cogl_atlas_get_initial_size (atlas, &map_width, &map_height);
- new_map = _cogl_atlas_create_map (atlas->texture_format,
+ new_map = _cogl_atlas_create_map (atlas,
map_width, map_height,
data.n_textures, data.textures);
@@ -500,16 +526,24 @@ _cogl_atlas_reserve_space (CoglAtlas *atlas,
data.textures,
atlas->texture,
COGL_TEXTURE (new_tex),
- user_data);
+ allocation_data);
_cogl_rectangle_map_free (atlas->map);
cogl_object_unref (atlas->texture);
}
else
- /* We know there's only one texture so we can just directly
- update the rectangle from its new position */
- atlas->update_position_cb (data.textures[0].user_data,
- COGL_TEXTURE (new_tex),
- &data.textures[0].new_position);
+ {
+ CoglAtlasAllocation *allocation =
+ (CoglAtlasAllocation *)&data.textures[0].new_position;
+
+ /* We know there's only one texture so we can just directly
+ update the rectangle from its new position */
+ _cogl_closure_list_invoke (&atlas->allocate_closures,
+ CoglAtlasAllocateCallback,
+ atlas,
+ COGL_TEXTURE (new_tex),
+ allocation,
+ data.textures[0].allocation_data);
+ }
atlas->map = new_map;
atlas->texture = COGL_TEXTURE (new_tex);
@@ -530,21 +564,28 @@ _cogl_atlas_reserve_space (CoglAtlas *atlas,
u_free (data.textures);
- _cogl_atlas_notify_post_reorganize (atlas);
+ _cogl_closure_list_invoke (&atlas->pre_reorganize_closures,
+ CoglAtlasReorganizeCallback,
+ atlas);
return ret;
}
void
_cogl_atlas_remove (CoglAtlas *atlas,
- const CoglRectangleMapEntry *rectangle)
+ int x,
+ int y,
+ int width,
+ int height)
{
- _cogl_rectangle_map_remove (atlas->map, rectangle);
+ CoglRectangleMapEntry rectangle = { x, y, width, height };
+
+ _cogl_rectangle_map_remove (atlas->map, &rectangle);
COGL_NOTE (ATLAS, "%p: Removed rectangle sized %ix%i",
atlas,
- rectangle->width,
- rectangle->height);
+ rectangle.width,
+ rectangle.height);
COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
atlas,
_cogl_rectangle_map_get_width (atlas->map),
@@ -555,6 +596,12 @@ _cogl_atlas_remove (CoglAtlas *atlas,
_cogl_rectangle_map_get_height (atlas->map)));
};
+CoglTexture *
+cogl_atlas_get_texture (CoglAtlas *atlas)
+{
+ return atlas->texture;
+}
+
static CoglTexture *
create_migration_texture (CoglContext *ctx,
int width,
@@ -606,19 +653,18 @@ create_migration_texture (CoglContext *ctx,
}
CoglTexture *
-_cogl_atlas_copy_rectangle (CoglAtlas *atlas,
- int x,
- int y,
- int width,
- int height,
- CoglPixelFormat internal_format)
+_cogl_atlas_migrate_allocation (CoglAtlas *atlas,
+ int x,
+ int y,
+ int width,
+ int height,
+ CoglPixelFormat internal_format)
{
+ CoglContext *ctx = atlas->context;
CoglTexture *tex;
CoglBlitData blit_data;
CoglError *ignore_error = NULL;
- _COGL_GET_CONTEXT (ctx, NULL);
-
/* Create a new texture at the right size */
tex = create_migration_texture (ctx, width, height, internal_format);
if (!cogl_texture_allocate (tex, &ignore_error))
@@ -641,50 +687,91 @@ _cogl_atlas_copy_rectangle (CoglAtlas *atlas,
return tex;
}
+CoglAtlasReorganizeClosure *
+cogl_atlas_add_pre_reorganize_callback (CoglAtlas *atlas,
+ CoglAtlasReorganizeCallback callback,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy)
+{
+ _COGL_RETURN_VAL_IF_FAIL (callback != NULL, NULL);
+
+ return _cogl_closure_list_add (&atlas->pre_reorganize_closures,
+ callback,
+ user_data,
+ destroy);
+}
+
void
-_cogl_atlas_add_reorganize_callback (CoglAtlas *atlas,
- UHookFunc pre_callback,
- UHookFunc post_callback,
- void *user_data)
+cogl_atlas_remove_pre_reorganize_callback (CoglAtlas *atlas,
+ CoglAtlasReorganizeClosure *closure)
{
- if (pre_callback)
- {
- UHook *hook = u_hook_alloc (&atlas->post_reorganize_callbacks);
- hook->func = pre_callback;
- hook->data = user_data;
- u_hook_prepend (&atlas->pre_reorganize_callbacks, hook);
- }
- if (post_callback)
- {
- UHook *hook = u_hook_alloc (&atlas->pre_reorganize_callbacks);
- hook->func = post_callback;
- hook->data = user_data;
- u_hook_prepend (&atlas->post_reorganize_callbacks, hook);
- }
+ _cogl_closure_disconnect (closure);
+}
+
+CoglAtlasReorganizeClosure *
+cogl_atlas_add_post_reorganize_callback (CoglAtlas *atlas,
+ CoglAtlasReorganizeCallback callback,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy)
+{
+ _COGL_RETURN_VAL_IF_FAIL (callback != NULL, NULL);
+
+ return _cogl_closure_list_add (&atlas->post_reorganize_closures,
+ callback,
+ user_data,
+ destroy);
}
void
-_cogl_atlas_remove_reorganize_callback (CoglAtlas *atlas,
- UHookFunc pre_callback,
- UHookFunc post_callback,
- void *user_data)
+cogl_atlas_remove_post_reorganize_callback (CoglAtlas *atlas,
+ CoglAtlasReorganizeClosure *closure)
{
- if (pre_callback)
- {
- UHook *hook = u_hook_find_func_data (&atlas->pre_reorganize_callbacks,
- FALSE,
- pre_callback,
- user_data);
- if (hook)
- u_hook_destroy_link (&atlas->pre_reorganize_callbacks, hook);
- }
- if (post_callback)
+ _cogl_closure_disconnect (closure);
+}
+
+typedef struct _ForeachState
+{
+ CoglAtlas *atlas;
+ CoglAtlasForeachCallback callback;
+ void *user_data;
+} ForeachState;
+
+static void
+foreach_rectangle_cb (const CoglRectangleMapEntry *entry,
+ void *rectangle_data,
+ void *user_data)
+{
+ ForeachState *state = user_data;
+
+ state->callback (state->atlas,
+ (CoglAtlasAllocation *)entry,
+ rectangle_data,
+ state->user_data);
+}
+
+void
+cogl_atlas_foreach (CoglAtlas *atlas,
+ CoglAtlasForeachCallback callback,
+ void *user_data)
+{
+ if (atlas->map)
{
- UHook *hook = u_hook_find_func_data (&atlas->post_reorganize_callbacks,
- FALSE,
- post_callback,
- user_data);
- if (hook)
- u_hook_destroy_link (&atlas->post_reorganize_callbacks, hook);
+ ForeachState state;
+
+ state.atlas = atlas;
+ state.callback = callback;
+ state.user_data = user_data;
+
+ _cogl_rectangle_map_foreach (atlas->map, foreach_rectangle_cb, &state);
}
}
+
+int
+cogl_atlas_get_n_allocations (CoglAtlas *atlas)
+{
+ if (atlas->map)
+ return _cogl_rectangle_map_get_n_rectangles (atlas->map);
+ else
+ return 0;
+}
+
diff --git a/cogl/cogl-atlas.h b/cogl/cogl-atlas.h
index 5bba5e74..05f506be 100644
--- a/cogl/cogl-atlas.h
+++ b/cogl/cogl-atlas.h
@@ -26,80 +26,89 @@
* SOFTWARE.
*/
-#ifndef __COGL_ATLAS_H
-#define __COGL_ATLAS_H
+#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
-#include "cogl-rectangle-map.h"
-#include "cogl-object-private.h"
-#include "cogl-texture.h"
+#ifndef _COGL_ATLAS_H_
+#define _COGL_ATLAS_H_
-typedef void
-(* CoglAtlasUpdatePositionCallback) (void *user_data,
- CoglTexture *new_texture,
- const CoglRectangleMapEntry *rect);
+#include <cogl/cogl-types.h>
+#include <cogl/cogl-object.h>
+#include <cogl/cogl-texture.h>
-typedef enum
+typedef struct _CoglAtlasAllocation
{
- COGL_ATLAS_CLEAR_TEXTURE = (1 << 0),
- COGL_ATLAS_DISABLE_MIGRATION = (1 << 1)
-} CoglAtlasFlags;
+ int x;
+ int y;
+ int width;
+ int height;
+} CoglAtlasAllocation;
typedef struct _CoglAtlas CoglAtlas;
-#define COGL_ATLAS(object) ((CoglAtlas *) object)
+/* XXX: Note that during migration _cogl_atlas_get_texture() may not match the
+ * @texture given here. @texture is more up to date... */
+typedef void
+(* CoglAtlasAllocateCallback) (CoglAtlas *atlas,
+ CoglTexture *texture,
+ const CoglAtlasAllocation *allocation,
+ void *allocation_data,
+ void *user_data);
-struct _CoglAtlas
-{
- CoglObject _parent;
+typedef struct _CoglClosure CoglAtlasAllocateClosure;
- CoglRectangleMap *map;
+CoglAtlasAllocateClosure *
+cogl_atlas_add_allocate_callback (CoglAtlas *atlas,
+ CoglAtlasAllocateCallback callback,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy);
- CoglTexture *texture;
- CoglPixelFormat texture_format;
- CoglAtlasFlags flags;
+void
+cogl_atlas_remove_allocate_callback (CoglAtlas *atlas,
+ CoglAtlasAllocateClosure *closure);
- CoglAtlasUpdatePositionCallback update_position_cb;
+CoglTexture *
+cogl_atlas_get_texture (CoglAtlas *atlas);
- UHookList pre_reorganize_callbacks;
- UHookList post_reorganize_callbacks;
-};
+typedef void (*CoglAtlasForeachCallback) (CoglAtlas *atlas,
+ const CoglAtlasAllocation *allocation,
+ void *allocation_data,
+ void *user_data);
+void
+cogl_atlas_foreach (CoglAtlas *atlas,
+ CoglAtlasForeachCallback callback,
+ void *user_data);
-CoglAtlas *
-_cogl_atlas_new (CoglPixelFormat texture_format,
- CoglAtlasFlags flags,
- CoglAtlasUpdatePositionCallback update_position_cb);
+int
+cogl_atlas_get_n_allocations (CoglAtlas *atlas);
-CoglBool
-_cogl_atlas_reserve_space (CoglAtlas *atlas,
- unsigned int width,
- unsigned int height,
- void *user_data);
+typedef struct _CoglClosure CoglAtlasReorganizeClosure;
-void
-_cogl_atlas_remove (CoglAtlas *atlas,
- const CoglRectangleMapEntry *rectangle);
+typedef void (*CoglAtlasReorganizeCallback) (CoglAtlas *atlas,
+ void *user_data);
-CoglTexture *
-_cogl_atlas_copy_rectangle (CoglAtlas *atlas,
- int x,
- int y,
- int width,
- int height,
- CoglPixelFormat format);
+CoglAtlasReorganizeClosure *
+cogl_atlas_add_pre_reorganize_callback (CoglAtlas *atlas,
+ CoglAtlasReorganizeCallback callback,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy);
void
-_cogl_atlas_add_reorganize_callback (CoglAtlas *atlas,
- UHookFunc pre_callback,
- UHookFunc post_callback,
- void *user_data);
+cogl_atlas_remove_pre_reorganize_callback (CoglAtlas *atlas,
+ CoglAtlasReorganizeClosure *closure);
+
+CoglAtlasReorganizeClosure *
+cogl_atlas_add_post_reorganize_callback (CoglAtlas *atlas,
+ CoglAtlasReorganizeCallback callback,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy);
void
-_cogl_atlas_remove_reorganize_callback (CoglAtlas *atlas,
- UHookFunc pre_callback,
- UHookFunc post_callback,
- void *user_data);
+cogl_atlas_remove_post_reorganize_callback (CoglAtlas *atlas,
+ CoglAtlasReorganizeClosure *closure);
CoglBool
-_cogl_is_atlas (void *object);
+cogl_is_atlas (void *object);
-#endif /* __COGL_ATLAS_H */
+#endif /* _COGL_ATLAS_H_ */
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index b89db269..291c6808 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -45,7 +45,7 @@
#include "cogl-pipeline-private.h"
#include "cogl-buffer-private.h"
#include "cogl-bitmask.h"
-#include "cogl-atlas.h"
+#include "cogl-atlas-set.h"
#include "cogl-driver.h"
#include "cogl-texture-driver.h"
#include "cogl-pipeline-cache.h"
@@ -212,8 +212,7 @@ struct _CoglContext
CoglPipeline *texture_download_pipeline;
CoglPipeline *blit_texture_pipeline;
- USList *atlases;
- UHookList atlas_reorganize_callbacks;
+ CoglAtlasSet *atlas_set;
/* This debugging variable is used to pick a colour for visually
displaying the quad batches. It needs to be global so that it can
@@ -360,4 +359,7 @@ _cogl_context_get_gl_extensions (CoglContext *context);
const char *
_cogl_context_get_gl_version (CoglContext *context);
+CoglAtlasSet *
+_cogl_get_atlas_set (CoglContext *context);
+
#endif /* __COGL_CONTEXT_PRIVATE_H */
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index dca21277..747abd67 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -28,9 +28,7 @@
*
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <config.h>
#include "cogl-object.h"
#include "cogl-private.h"
@@ -47,6 +45,8 @@
#include "cogl-texture-2d-private.h"
#include "cogl-texture-3d-private.h"
#include "cogl-texture-rectangle-private.h"
+#include "cogl-atlas-set.h"
+#include "cogl-atlas-texture-private.h"
#include "cogl-pipeline-private.h"
#include "cogl-pipeline-opengl-private.h"
#include "cogl-framebuffer-private.h"
@@ -432,9 +432,6 @@ cogl_context_new (CoglDisplay *display,
cogl_object_unref (white_pixel_bitmap);
- context->atlases = NULL;
- u_hook_list_init (&context->atlas_reorganize_callbacks, sizeof (UHook));
-
context->buffer_map_fallback_array = u_byte_array_new ();
context->buffer_map_fallback_in_use = FALSE;
@@ -451,6 +448,14 @@ cogl_context_new (CoglDisplay *display,
_cogl_list_init (&context->fences);
+ context->atlas_set = cogl_atlas_set_new (context);
+ cogl_atlas_set_set_components (context->atlas_set, COGL_TEXTURE_COMPONENTS_RGBA);
+ cogl_atlas_set_set_premultiplied (context->atlas_set, FALSE);
+ cogl_atlas_set_add_atlas_callback (context->atlas_set,
+ _cogl_atlas_texture_atlas_event_handler,
+ NULL, /* user data */
+ NULL); /* destroy */
+
return context;
}
@@ -461,6 +466,9 @@ _cogl_context_free (CoglContext *context)
winsys->context_deinit (context);
+ if (context->atlas_set)
+ cogl_object_unref (context->atlas_set);
+
if (context->default_gl_texture_2d_tex)
cogl_object_unref (context->default_gl_texture_2d_tex);
if (context->default_gl_texture_3d_tex)
@@ -499,9 +507,6 @@ _cogl_context_free (CoglContext *context)
if (context->current_clip_stack_valid)
_cogl_clip_stack_unref (context->current_clip_stack);
- u_slist_free (context->atlases);
- u_hook_list_clear (&context->atlas_reorganize_callbacks);
-
_cogl_bitmask_destroy (&context->enabled_builtin_attributes);
_cogl_bitmask_destroy (&context->enable_builtin_attributes_tmp);
_cogl_bitmask_destroy (&context->enabled_texcoord_attributes);
@@ -711,3 +716,9 @@ cogl_get_clock_time (CoglContext *context)
else
return 0;
}
+
+CoglAtlasSet *
+_cogl_get_atlas_set (CoglContext *context)
+{
+ return context->atlas_set;
+}
diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h
index 59567f25..0feaeb01 100644
--- a/cogl/cogl-texture-private.h
+++ b/cogl/cogl-texture-private.h
@@ -279,9 +279,9 @@ void
_cogl_texture_ensure_non_quad_rendering (CoglTexture *texture);
/*
- * This determines a CoglPixelFormat according to texture::components
- * and texture::premultiplied (i.e. the user required components and
- * whether the texture should be considered premultiplied)
+ * This determines a CoglPixelFormat according to @components and
+ * @premultiplied (i.e. the user required components and whether the
+ * texture should be considered premultiplied)
*
* A reference/source format can be given (or COGL_PIXEL_FORMAT_ANY)
* and wherever possible this function tries to simply return the
@@ -291,6 +291,15 @@ _cogl_texture_ensure_non_quad_rendering (CoglTexture *texture);
* how to convert a source image in preparation for uploading.
*/
CoglPixelFormat
+_cogl_texture_derive_format (CoglContext *ctx,
+ CoglPixelFormat src_format,
+ CoglTextureComponents components,
+ CoglBool premultiplied);
+
+/* This is a thin wrapper around _cogl_texture_derive_format
+ * that simply passes texture->context, texture->components and
+ * texture->premultiplied in as arguments */
+CoglPixelFormat
_cogl_texture_determine_internal_format (CoglTexture *texture,
CoglPixelFormat src_format);
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index 8d8af469..c45509bb 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -1340,18 +1340,18 @@ _cogl_texture_set_internal_format (CoglTexture *texture,
}
CoglPixelFormat
-_cogl_texture_determine_internal_format (CoglTexture *texture,
- CoglPixelFormat src_format)
+_cogl_texture_derive_format (CoglContext *ctx,
+ CoglPixelFormat src_format,
+ CoglTextureComponents components,
+ CoglBool premultiplied)
{
- switch (texture->components)
+ switch (components)
{
case COGL_TEXTURE_COMPONENTS_DEPTH:
if (src_format & COGL_DEPTH_BIT)
return src_format;
else
{
- CoglContext *ctx = texture->context;
-
if (_cogl_has_private_feature (ctx,
COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) ||
_cogl_has_private_feature (ctx,
@@ -1382,7 +1382,7 @@ _cogl_texture_determine_internal_format (CoglTexture *texture,
else
format = COGL_PIXEL_FORMAT_RGBA_8888;
- if (texture->premultiplied)
+ if (premultiplied)
{
if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format))
return format |= COGL_PREMULT_BIT;
@@ -1397,6 +1397,16 @@ _cogl_texture_determine_internal_format (CoglTexture *texture,
u_return_val_if_reached (COGL_PIXEL_FORMAT_RGBA_8888_PRE);
}
+CoglPixelFormat
+_cogl_texture_determine_internal_format (CoglTexture *texture,
+ CoglPixelFormat src_format)
+{
+ return _cogl_texture_derive_format (texture->context,
+ src_format,
+ texture->components,
+ texture->premultiplied);
+}
+
void
cogl_texture_set_components (CoglTexture *texture,
CoglTextureComponents components)
diff --git a/cogl/cogl.h b/cogl/cogl.h
index f3f65b2d..b98b3010 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -75,6 +75,8 @@
#include <cogl/cogl-texture-3d.h>
#include <cogl/cogl-texture-2d-sliced.h>
#include <cogl/cogl-sub-texture.h>
+#include <cogl/cogl-atlas-set.h>
+#include <cogl/cogl-atlas.h>
#include <cogl/cogl-atlas-texture.h>
#include <cogl/cogl-meta-texture.h>
#include <cogl/cogl-primitive-texture.h>
diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c
index 8fa7f9a1..7b15755b 100644
--- a/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/winsys/cogl-winsys-egl.c
@@ -811,7 +811,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
COGL_FRAMEBUFFER (onscreen),
COGL_FRAMEBUFFER_STATE_BIND);
- if (n_rectangles && egl_renderer->pf_eglSwapBuffersWithDamage)
+ if (egl_renderer->pf_eglSwapBuffersWithDamage)
{
CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
size_t size = n_rectangles * sizeof (int) * 4;
diff --git a/examples/cogl-crate.c b/examples/cogl-crate.c
index 4eeab9d9..985ac370 100644
--- a/examples/cogl-crate.c
+++ b/examples/cogl-crate.c
@@ -284,8 +284,17 @@ main (int argc, char **argv)
if (data.swap_ready)
{
+ static gboolean swapped = FALSE;
+ int rect[4] = { 0, 0, 320, 240 };
+
paint (&data);
- cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb));
+ if (!swapped)
+ {
+ cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb));
+ swapped = TRUE;
+ }
+ else
+ cogl_onscreen_swap_buffers_with_damage (COGL_ONSCREEN (fb), rect, 1);
}
cogl_poll_renderer_get_info (cogl_context_get_renderer (ctx),