summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bragg <robert@linux.intel.com>2012-11-22 23:01:08 +0000
committerRobert Bragg <robert@linux.intel.com>2013-01-22 17:48:17 +0000
commit73e8a6d7ce25d6bb994a78935cc589edf02b5130 (patch)
treeb3f47f034b978a9c5ea9927dec1d12cb8d6d9595
parent5a814e386aa4aac5c7e9436cb3d11c0d7ce5c677 (diff)
downloadcogl-73e8a6d7ce25d6bb994a78935cc589edf02b5130.tar.gz
Allow lazy texture storage allocation
Consistent with how we lazily allocate framebuffers this patch allows us to instantiate textures but still specify constraints and requirements before allocating storage so that we can be sure to allocate the most appropriate/efficient storage. This adds a cogl_texture_allocate() function that is analogous to cogl_framebuffer_allocate() which can optionally be called to explicitly allocate storage and catch any errors. If this function isn't used explicitly then Cogl will implicitly ensure textures are allocated before the storage is needed. It is generally recommended to rely on lazy storage allocation or at least perform explicit allocation as late as possible so Cogl can be fully informed about the best way to allocate storage. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit 1fa7c0f10a8a03043e3c75cb079a49625df098b7) Note: This reverts the cogl_texture_rectangle_new_with_size API change that dropped the CoglError argument and keeps the semantics of allocating the texture immediately. This is because Mutter currently uses this API so we will probably look at updating this later once we have a corresponding Mutter patch prepared. The other API changes were kept since they only affected experimental api.
-rw-r--r--cogl-pango/cogl-pango-glyph-cache.c9
-rw-r--r--cogl/cogl-atlas-texture-private.h3
-rw-r--r--cogl/cogl-atlas-texture.c90
-rw-r--r--cogl/cogl-atlas.c22
-rw-r--r--cogl/cogl-auto-texture.c24
-rw-r--r--cogl/cogl-blit.c34
-rw-r--r--cogl/cogl-driver.h13
-rw-r--r--cogl/cogl-framebuffer-private.h2
-rw-r--r--cogl/cogl-framebuffer.c67
-rw-r--r--cogl/cogl-sub-texture.c10
-rw-r--r--cogl/cogl-texture-2d-private.h2
-rw-r--r--cogl/cogl-texture-2d-sliced-private.h1
-rw-r--r--cogl/cogl-texture-2d-sliced.c303
-rw-r--r--cogl/cogl-texture-2d-sliced.h44
-rw-r--r--cogl/cogl-texture-2d.c38
-rw-r--r--cogl/cogl-texture-2d.h15
-rw-r--r--cogl/cogl-texture-3d-private.h2
-rw-r--r--cogl/cogl-texture-3d.c76
-rw-r--r--cogl/cogl-texture-3d.h26
-rw-r--r--cogl/cogl-texture-private.h8
-rw-r--r--cogl/cogl-texture-rectangle-private.h2
-rw-r--r--cogl/cogl-texture-rectangle.c87
-rw-r--r--cogl/cogl-texture.c50
-rw-r--r--cogl/cogl-texture.h31
-rw-r--r--cogl/driver/gl/cogl-framebuffer-gl.c15
-rw-r--r--cogl/driver/gl/cogl-texture-2d-gl-private.h9
-rw-r--r--cogl/driver/gl/cogl-texture-2d-gl.c70
-rw-r--r--cogl/driver/gl/gl/cogl-driver-gl.c2
-rw-r--r--cogl/driver/gl/gles/cogl-driver-gles.c2
-rw-r--r--cogl/driver/nop/cogl-driver-nop.c2
-rw-r--r--cogl/driver/nop/cogl-texture-2d-nop-private.h9
-rw-r--r--cogl/driver/nop/cogl-texture-2d-nop.c22
-rw-r--r--cogl/winsys/cogl-texture-pixmap-x11.c10
-rw-r--r--cogl/winsys/cogl-winsys-glx.c10
-rw-r--r--tests/conform/test-gles2-context.c6
-rw-r--r--tests/conform/test-offscreen.c6
-rw-r--r--tests/conform/test-utils.c6
37 files changed, 711 insertions, 417 deletions
diff --git a/cogl-pango/cogl-pango-glyph-cache.c b/cogl-pango/cogl-pango-glyph-cache.c
index 14c8295a..59cb5f43 100644
--- a/cogl-pango/cogl-pango-glyph-cache.c
+++ b/cogl-pango/cogl-pango-glyph-cache.c
@@ -214,6 +214,7 @@ cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
CoglPangoGlyphCacheValue *value)
{
CoglAtlasTexture *texture;
+ CoglError *ignore_error = NULL;
if (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SHARED_ATLAS))
return FALSE;
@@ -227,10 +228,14 @@ cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
value->draw_width,
value->draw_height,
COGL_TEXTURE_NONE,
- COGL_PIXEL_FORMAT_RGBA_8888_PRE);
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ &ignore_error);
if (texture == NULL)
- return FALSE;
+ {
+ cogl_error_free (ignore_error);
+ return FALSE;
+ }
value->texture = COGL_TEXTURE (texture);
value->tx1 = 0;
diff --git a/cogl/cogl-atlas-texture-private.h b/cogl/cogl-atlas-texture-private.h
index 52fdf069..670eea45 100644
--- a/cogl/cogl-atlas-texture-private.h
+++ b/cogl/cogl-atlas-texture-private.h
@@ -68,7 +68,8 @@ _cogl_atlas_texture_new_with_size (CoglContext *ctx,
int width,
int height,
CoglTextureFlags flags,
- CoglPixelFormat internal_format);
+ CoglPixelFormat internal_format,
+ CoglError **error);
void
_cogl_atlas_texture_add_reorganize_callback (CoglContext *ctx,
diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c
index c37908ad..7f62efce 100644
--- a/cogl/cogl-atlas-texture.c
+++ b/cogl/cogl-atlas-texture.c
@@ -651,32 +651,60 @@ _cogl_atlas_texture_new_with_size (CoglContext *ctx,
int width,
int height,
CoglTextureFlags flags,
- CoglPixelFormat internal_format)
+ CoglPixelFormat internal_format,
+ CoglError **error)
{
CoglAtlasTexture *atlas_tex;
- CoglAtlas *atlas;
- GSList *l;
/* Don't put textures in the atlas if the user has explicitly
requested to disable it */
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_ATLAS)))
- return NULL;
+ {
+ _cogl_set_error (error,
+ COGL_SYSTEM_ERROR,
+ COGL_SYSTEM_ERROR_UNSUPPORTED,
+ "Atlasing disabled");
+ return NULL;
+ }
/* We can't put the texture in the atlas if there are any special
flags. This precludes textures with COGL_TEXTURE_NO_ATLAS and
COGL_TEXTURE_NO_SLICING from being atlased */
if (flags)
- return NULL;
+ {
+ /* XXX: This is a bit of an odd error; if we make this api
+ * public then this should probably be dealt with at a higher
+ * level, in cogl-auto-texture.c:cogl_texture_new_with_size().
+ */
+ _cogl_set_error (error,
+ COGL_SYSTEM_ERROR,
+ COGL_SYSTEM_ERROR_UNSUPPORTED,
+ "Usage constraints preclude atlasing texture");
+ return NULL;
+ }
/* We can't atlas zero-sized textures because it breaks the atlas
data structure */
if (width < 1 || height < 1)
- return NULL;
+ {
+ _cogl_set_error (error,
+ COGL_TEXTURE_ERROR,
+ COGL_TEXTURE_ERROR_SIZE,
+ "1x1 atlas textures not supported");
+ return NULL;
+ }
/* If we can't use FBOs then it will be too slow to migrate textures
and we shouldn't use the atlas */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
- return NULL;
+ {
+ _cogl_set_error (error,
+ COGL_SYSTEM_ERROR,
+ COGL_SYSTEM_ERROR_UNSUPPORTED,
+ "Atlasing disabled because migrations "
+ "would be too slow");
+ return NULL;
+ }
COGL_NOTE (ATLAS, "Adding texture of size %ix%i", width, height);
@@ -685,7 +713,10 @@ _cogl_atlas_texture_new_with_size (CoglContext *ctx,
{
COGL_NOTE (ATLAS, "Texture can not be added because the "
"format is unsupported");
-
+ _cogl_set_error (error,
+ COGL_TEXTURE_ERROR,
+ COGL_TEXTURE_ERROR_FORMAT,
+ "Texture format unsuitable for atlasing");
return NULL;
}
@@ -703,12 +734,27 @@ _cogl_atlas_texture_new_with_size (CoglContext *ctx,
atlas_tex->sub_texture = NULL;
+ atlas_tex->format = internal_format;
+ atlas_tex->atlas = NULL;
+
+ return _cogl_atlas_texture_object_new (atlas_tex);
+}
+
+static CoglBool
+_cogl_atlas_texture_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglContext *ctx = tex->context;
+ CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
+ CoglAtlas *atlas;
+ GSList *l;
+
/* 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,
+ tex->width + 2, tex->height + 2,
atlas_tex))
{
cogl_object_ref (atlas);
@@ -722,20 +768,23 @@ _cogl_atlas_texture_new_with_size (CoglContext *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,
+ tex->width + 2, tex->height + 2,
atlas_tex))
{
/* Ok, this means we really can't add it to the atlas */
cogl_object_unref (atlas);
- g_free (atlas_tex);
- return NULL;
+
+ _cogl_set_error (error,
+ COGL_SYSTEM_ERROR,
+ COGL_SYSTEM_ERROR_NO_MEMORY,
+ "Not enough memory to atlas texture");
+ return FALSE;
}
}
- atlas_tex->format = internal_format;
atlas_tex->atlas = atlas;
- return _cogl_atlas_texture_object_new (atlas_tex);
+ return TRUE;
}
CoglAtlasTexture *
@@ -762,14 +811,14 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
atlas_tex = _cogl_atlas_texture_new_with_size (ctx,
bmp_width, bmp_height,
- flags, internal_format);
+ flags, internal_format,
+ error);
+ if (!atlas_tex)
+ return NULL;
- if (atlas_tex == NULL)
+ if (!cogl_texture_allocate (COGL_TEXTURE (atlas_tex), error))
{
- _cogl_set_error (error,
- COGL_SYSTEM_ERROR,
- COGL_SYSTEM_ERROR_UNSUPPORTED,
- "Texture type not compatible with atlas");
+ cogl_object_unref (atlas_tex);
return NULL;
}
@@ -839,6 +888,7 @@ static const CoglTextureVtable
cogl_atlas_texture_vtable =
{
FALSE, /* not primitive */
+ _cogl_atlas_texture_allocate,
_cogl_atlas_texture_set_region,
NULL, /* get_data */
_cogl_atlas_texture_foreach_sub_texture_in_region,
diff --git a/cogl/cogl-atlas.c b/cogl/cogl-atlas.c
index 62b11f85..d6c0e74f 100644
--- a/cogl/cogl-atlas.c
+++ b/cogl/cogl-atlas.c
@@ -301,6 +301,9 @@ _cogl_atlas_create_texture (CoglAtlas *atlas,
tex = cogl_texture_2d_new_from_bitmap (clear_bmp,
atlas->texture_format,
&ignore_error);
+ if (!tex)
+ cogl_error_free (ignore_error);
+
cogl_object_unref (clear_bmp);
g_free (clear_data);
@@ -309,13 +312,15 @@ _cogl_atlas_create_texture (CoglAtlas *atlas,
{
tex = cogl_texture_2d_new_with_size (ctx,
width, height,
- atlas->texture_format,
- &ignore_error);
+ atlas->texture_format);
+ if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error))
+ {
+ cogl_error_free (ignore_error);
+ cogl_object_unref (tex);
+ tex = NULL;
+ }
}
- if (!tex)
- cogl_error_free (ignore_error);
-
return tex;
}
@@ -547,11 +552,18 @@ _cogl_atlas_copy_rectangle (CoglAtlas *atlas,
{
CoglTexture *tex;
CoglBlitData blit_data;
+ CoglError *ignore_error = NULL;
_COGL_GET_CONTEXT (ctx, NULL);
/* Create a new texture at the right size */
tex = cogl_texture_new_with_size (width, height, flags, format);
+ if (!cogl_texture_allocate (tex, &ignore_error))
+ {
+ cogl_error_free (ignore_error);
+ cogl_object_unref (tex);
+ return NULL;
+ }
/* Blit the data out of the atlas to the new texture. If FBOs
aren't available this will end up having to copy the entire
diff --git a/cogl/cogl-auto-texture.c b/cogl/cogl-auto-texture.c
index bcbb1d0c..ff7673b9 100644
--- a/cogl/cogl-auto-texture.c
+++ b/cogl/cogl-auto-texture.c
@@ -47,12 +47,13 @@
#include "cogl-texture-2d-gl.h"
CoglTexture *
-cogl_texture_new_with_size (unsigned int width,
- unsigned int height,
+cogl_texture_new_with_size (unsigned int width,
+ unsigned int height,
CoglTextureFlags flags,
- CoglPixelFormat internal_format)
+ CoglPixelFormat internal_format)
{
CoglTexture *tex;
+ CoglError *skip_error = NULL;
_COGL_GET_CONTEXT (ctx, NULL);
@@ -63,8 +64,18 @@ cogl_texture_new_with_size (unsigned int width,
/* First try creating a fast-path non-sliced texture */
tex = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx,
width, height,
- internal_format,
- NULL));
+ internal_format));
+
+ /* TODO: instead of allocating storage here it would be better
+ * if we had some api that let us just check that the size is
+ * supported by the hardware so storage could be allocated
+ * lazily when uploading data. */
+ if (!cogl_texture_allocate (tex, &skip_error))
+ {
+ cogl_error_free (skip_error);
+ cogl_object_unref (tex);
+ tex = NULL;
+ }
}
else
tex = NULL;
@@ -83,8 +94,7 @@ cogl_texture_new_with_size (unsigned int width,
width,
height,
max_waste,
- internal_format,
- NULL));
+ internal_format));
}
return tex;
diff --git a/cogl/cogl-blit.c b/cogl/cogl-blit.c
index 5cb5ea4c..ea457b95 100644
--- a/cogl/cogl-blit.c
+++ b/cogl/cogl-blit.c
@@ -49,16 +49,15 @@ _cogl_blit_texture_render_begin (CoglBlitData *data)
CoglFramebuffer *fb;
CoglPipeline *pipeline;
unsigned int dst_width, dst_height;
+ CoglError *ignore_error = NULL;
offscreen = _cogl_offscreen_new_to_texture_full
(data->dst_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */);
- if (offscreen == NULL)
- return FALSE;
-
fb = COGL_FRAMEBUFFER (offscreen);
- if (!cogl_framebuffer_allocate (fb, NULL))
+ if (!cogl_framebuffer_allocate (fb, &ignore_error))
{
+ cogl_error_free (ignore_error);
cogl_object_unref (fb);
return FALSE;
}
@@ -148,6 +147,7 @@ _cogl_blit_framebuffer_begin (CoglBlitData *data)
CoglContext *ctx = data->src_tex->context;
CoglOffscreen *dst_offscreen = NULL, *src_offscreen = NULL;
CoglFramebuffer *dst_fb, *src_fb;
+ CoglError *ignore_error = NULL;
/* We can only blit between FBOs if both textures are the same
format and the blit framebuffer extension is supported */
@@ -158,24 +158,25 @@ _cogl_blit_framebuffer_begin (CoglBlitData *data)
dst_offscreen = _cogl_offscreen_new_to_texture_full
(data->dst_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */);
- if (dst_offscreen == NULL)
- return FALSE;
dst_fb = COGL_FRAMEBUFFER (dst_offscreen);
- if (!cogl_framebuffer_allocate (dst_fb, NULL))
- goto error;
+ if (!cogl_framebuffer_allocate (dst_fb, &ignore_error))
+ {
+ cogl_error_free (ignore_error);
+ goto error;
+ }
src_offscreen= _cogl_offscreen_new_to_texture_full
(data->src_tex,
COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL,
0 /* level */);
- if (src_offscreen == NULL)
- goto error;
-
src_fb = COGL_FRAMEBUFFER (src_offscreen);
- if (!cogl_framebuffer_allocate (src_fb, NULL))
- goto error;
+ if (!cogl_framebuffer_allocate (src_fb, &ignore_error))
+ {
+ cogl_error_free (ignore_error);
+ goto error;
+ }
data->src_fb = src_fb;
data->dest_fb = dst_fb;
@@ -220,6 +221,7 @@ _cogl_blit_copy_tex_sub_image_begin (CoglBlitData *data)
{
CoglOffscreen *offscreen;
CoglFramebuffer *fb;
+ CoglError *ignore_error = NULL;
/* This will only work if the target texture is a CoglTexture2D */
if (!cogl_is_texture_2d (data->dst_tex))
@@ -228,12 +230,10 @@ _cogl_blit_copy_tex_sub_image_begin (CoglBlitData *data)
offscreen = _cogl_offscreen_new_to_texture_full
(data->src_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */);
- if (offscreen == NULL)
- return FALSE;
-
fb = COGL_FRAMEBUFFER (offscreen);
- if (!cogl_framebuffer_allocate (fb, NULL))
+ if (!cogl_framebuffer_allocate (fb, &ignore_error))
{
+ cogl_error_free (ignore_error);
cogl_object_unref (fb);
return FALSE;
}
diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h
index e46bec8f..0c42e716 100644
--- a/cogl/cogl-driver.h
+++ b/cogl/cogl-driver.h
@@ -138,14 +138,11 @@ struct _CoglDriverVtable
void
(* texture_2d_init) (CoglTexture2D *tex_2d);
- /* Instantiates a new CoglTexture2D object with un-initialized
- * storage for a given size and internal format */
- CoglTexture2D *
- (* texture_2d_new_with_size) (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat internal_format,
- CoglError **error);
+ /* Allocates (uninitialized) storage for the given texture according
+ * to the configured size and format of the texture */
+ CoglBool
+ (* texture_2d_allocate) (CoglTexture *tex,
+ CoglError **error);
/* Instantiates a new CoglTexture2D object with storage initialized
* with the contents of the given bitmap, using the specified
diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index 7664f7c0..a88c5918 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -306,7 +306,7 @@ _cogl_free_framebuffer_stack (GSList *stack);
CoglOffscreen *
_cogl_offscreen_new_to_texture_full (CoglTexture *texture,
CoglOffscreenFlags create_flags,
- unsigned int level);
+ int level);
/*
* _cogl_push_framebuffers:
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 148e7f46..8b95796f 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -49,6 +49,7 @@
#include "cogl-primitives-private.h"
#include "cogl-path-private.h"
#include "cogl-error-private.h"
+#include "cogl-texture-gl-private.h"
typedef struct _CoglFramebufferStackEntry
{
@@ -569,48 +570,24 @@ _cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer)
CoglOffscreen *
_cogl_offscreen_new_to_texture_full (CoglTexture *texture,
CoglOffscreenFlags create_flags,
- unsigned int level)
+ int level)
{
CoglContext *ctx = texture->context;
CoglOffscreen *offscreen;
CoglFramebuffer *fb;
int level_width;
int level_height;
- int i;
CoglOffscreen *ret;
- if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
- return NULL;
-
- /* Make texture is a valid texture object */
- if (!cogl_is_texture (texture))
- return NULL;
-
- /* The texture must not be sliced */
- if (cogl_texture_is_sliced (texture))
- return NULL;
-
- /* Calculate the size of the texture at this mipmap level to ensure
- that it's a valid level */
- level_width = cogl_texture_get_width (texture);
- level_height = cogl_texture_get_height (texture);
-
- for (i = 0; i < level; i++)
- {
- /* If neither dimension can be further divided then the level is
- invalid */
- if (level_width == 1 && level_height == 1)
- {
- g_warning ("Invalid texture level passed to "
- "_cogl_offscreen_new_to_texture_full");
- return NULL;
- }
+ _COGL_RETURN_VAL_IF_FAIL (cogl_is_texture (texture), NULL);
+ _COGL_RETURN_VAL_IF_FAIL (level < _cogl_texture_get_n_levels (texture),
+ NULL);
- if (level_width > 1)
- level_width >>= 1;
- if (level_height > 1)
- level_height >>= 1;
- }
+ _cogl_texture_get_level_size (texture,
+ level,
+ &level_width,
+ &level_height,
+ NULL);
offscreen = g_new0 (CoglOffscreen, 1);
offscreen->texture = cogl_object_ref (texture);
@@ -688,7 +665,29 @@ cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
else
{
CoglContext *ctx = framebuffer->context;
- if (!ctx->driver_vtable->offscreen_allocate (COGL_OFFSCREEN (framebuffer), error))
+ CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer);
+
+ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
+ {
+ _cogl_set_error (error, COGL_SYSTEM_ERROR,
+ COGL_SYSTEM_ERROR_UNSUPPORTED,
+ "Offscreen framebuffers not supported by system");
+ return FALSE;
+ }
+
+ if (cogl_texture_is_sliced (offscreen->texture))
+ {
+ _cogl_set_error (error, COGL_SYSTEM_ERROR,
+ COGL_SYSTEM_ERROR_UNSUPPORTED,
+ "Can't create offscreen framebuffer from "
+ "sliced texture");
+ return FALSE;
+ }
+
+ if (!cogl_texture_allocate (offscreen->texture, error))
+ return FALSE;
+
+ if (!ctx->driver_vtable->offscreen_allocate (offscreen, error))
return FALSE;
}
diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl-sub-texture.c
index 18447f83..9a308be5 100644
--- a/cogl/cogl-sub-texture.c
+++ b/cogl/cogl-sub-texture.c
@@ -259,6 +259,15 @@ cogl_sub_texture_new (CoglContext *ctx,
return _cogl_sub_texture_object_new (sub_tex);
}
+static CoglBool
+_cogl_sub_texture_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
+
+ return cogl_texture_allocate (sub_tex->full_texture, error);
+}
+
CoglTexture *
cogl_sub_texture_get_parent (CoglSubTexture *sub_texture)
{
@@ -433,6 +442,7 @@ static const CoglTextureVtable
cogl_sub_texture_vtable =
{
FALSE, /* not primitive */
+ _cogl_sub_texture_allocate,
_cogl_sub_texture_set_region,
NULL, /* get_data */
_cogl_sub_texture_foreach_sub_texture_in_region,
diff --git a/cogl/cogl-texture-2d-private.h b/cogl/cogl-texture-2d-private.h
index 3ae8ded3..12e58202 100644
--- a/cogl/cogl-texture-2d-private.h
+++ b/cogl/cogl-texture-2d-private.h
@@ -39,7 +39,7 @@ struct _CoglTexture2D
/* The internal format of the GL texture represented as a
CoglPixelFormat */
- CoglPixelFormat format;
+ CoglPixelFormat internal_format;
CoglBool auto_mipmap;
CoglBool mipmaps_dirty;
diff --git a/cogl/cogl-texture-2d-sliced-private.h b/cogl/cogl-texture-2d-sliced-private.h
index 5bc4e5f8..fbfd1982 100644
--- a/cogl/cogl-texture-2d-sliced-private.h
+++ b/cogl/cogl-texture-2d-sliced-private.h
@@ -38,6 +38,7 @@ struct _CoglTexture2DSliced
GArray *slice_y_spans;
GArray *slice_textures;
int max_waste;
+ CoglPixelFormat internal_format;
};
CoglTexture2DSliced *
diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c
index 51997bd3..ef9d72d9 100644
--- a/cogl/cogl-texture-2d-sliced.c
+++ b/cogl/cogl-texture-2d-sliced.c
@@ -656,20 +656,18 @@ _cogl_texture_2d_sliced_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
}
static CoglBool
-_cogl_texture_2d_sliced_slices_create (CoglContext *ctx,
- CoglTexture2DSliced *tex_2ds,
- int width, int height,
- CoglPixelFormat format)
+_cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
+ CoglTexture2DSliced *tex_2ds,
+ int width,
+ int height,
+ int max_waste,
+ CoglPixelFormat format,
+ CoglError **error)
{
int max_width;
int max_height;
- CoglTexture2D **slice_textures;
int n_x_slices;
int n_y_slices;
- int n_slices;
- int x, y;
- CoglSpan *x_span;
- CoglSpan *y_span;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
@@ -697,7 +695,7 @@ _cogl_texture_2d_sliced_slices_create (CoglContext *ctx,
&gl_type);
/* Negative number means no slicing forced by the user */
- if (tex_2ds->max_waste <= -1)
+ if (max_waste <= -1)
{
CoglSpan span;
@@ -710,6 +708,13 @@ _cogl_texture_2d_sliced_slices_create (CoglContext *ctx,
max_width,
max_height))
{
+ _cogl_set_error (error,
+ COGL_TEXTURE_ERROR,
+ COGL_TEXTURE_ERROR_SIZE,
+ "Sliced texture size of %d x %d not possible "
+ "with max waste set to -1",
+ width,
+ height);
return FALSE;
}
@@ -753,16 +758,25 @@ _cogl_texture_2d_sliced_slices_create (CoglContext *ctx,
max_height /= 2;
if (max_width == 0 || max_height == 0)
- return FALSE;
+ {
+ /* Maybe it would be ok to just g_warn_if_reached() for this
+ * codepath */
+ _cogl_set_error (error,
+ COGL_TEXTURE_ERROR,
+ COGL_TEXTURE_ERROR_SIZE,
+ "No suitable slice geometry found");
+ return FALSE;
+
+ }
}
/* Determine the slices required to cover the bitmap area */
n_x_slices = slices_for_size (width,
- max_width, tex_2ds->max_waste,
+ max_width, max_waste,
NULL);
n_y_slices = slices_for_size (height,
- max_height, tex_2ds->max_waste,
+ max_height, max_waste,
NULL);
/* Init span arrays with reserved size */
@@ -776,64 +790,20 @@ _cogl_texture_2d_sliced_slices_create (CoglContext *ctx,
/* Fill span arrays with info */
slices_for_size (width,
- max_width, tex_2ds->max_waste,
+ max_width, max_waste,
tex_2ds->slice_x_spans);
slices_for_size (height,
- max_height, tex_2ds->max_waste,
+ max_height, max_waste,
tex_2ds->slice_y_spans);
}
- /* Init and resize GL handle array */
- n_slices = n_x_slices * n_y_slices;
-
- tex_2ds->slice_textures = g_array_sized_new (FALSE, FALSE,
- sizeof (CoglTexture2D *),
- n_slices);
-
- g_array_set_size (tex_2ds->slice_textures, n_slices);
-
- slice_textures = (CoglTexture2D **) tex_2ds->slice_textures->data;
-
- /* Init each GL texture object */
- for (y = 0; y < n_y_slices; ++y)
- {
- y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, y);
-
- for (x = 0; x < n_x_slices; ++x)
- {
- CoglError *error = NULL;
- x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, x);
-
- COGL_NOTE (SLICING, "CREATE SLICE (%d,%d)\tsize (%d,%d)",
- x, y,
- (int)(x_span->size - x_span->waste),
- (int)(y_span->size - y_span->waste));
-
- slice_textures[y * n_x_slices + x] =
- cogl_texture_2d_new_with_size (ctx, x_span->size, y_span->size,
- format, &error);
- if (!slice_textures[y * n_x_slices + x])
- {
- g_array_set_size (tex_2ds->slice_textures, y * n_x_slices + x);
- cogl_error_free (error);
- return FALSE;
- }
- }
- }
-
return TRUE;
}
static void
_cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds)
{
- if (tex_2ds->slice_x_spans != NULL)
- g_array_free (tex_2ds->slice_x_spans, TRUE);
-
- if (tex_2ds->slice_y_spans != NULL)
- g_array_free (tex_2ds->slice_y_spans, TRUE);
-
if (tex_2ds->slice_textures != NULL)
{
int i;
@@ -854,6 +824,12 @@ _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
{
_cogl_texture_2d_sliced_slices_free (tex_2ds);
+ if (tex_2ds->slice_x_spans != NULL)
+ g_array_free (tex_2ds->slice_x_spans, TRUE);
+
+ if (tex_2ds->slice_y_spans != NULL)
+ g_array_free (tex_2ds->slice_y_spans, TRUE);
+
/* Chain up */
_cogl_texture_free (COGL_TEXTURE (tex_2ds));
}
@@ -863,76 +839,148 @@ _cogl_texture_2d_sliced_init_base (CoglContext *ctx,
CoglTexture2DSliced *tex_2ds,
int width,
int height,
- CoglPixelFormat internal_format)
+ int max_waste,
+ CoglPixelFormat internal_format,
+ CoglError **error)
{
CoglTexture *tex = COGL_TEXTURE (tex_2ds);
_cogl_texture_init (tex, ctx, width, height, &cogl_texture_2d_sliced_vtable);
- tex_2ds->slice_x_spans = NULL;
- tex_2ds->slice_y_spans = NULL;
- tex_2ds->slice_textures = NULL;
-
- /* Create slices for the given format and size */
- if (!_cogl_texture_2d_sliced_slices_create (ctx,
- tex_2ds,
- width,
- height,
- internal_format))
- return FALSE;
+ tex_2ds->max_waste = max_waste;
+ tex_2ds->internal_format = internal_format;
- return TRUE;
+ return _cogl_texture_2d_sliced_setup_spans (ctx, tex_2ds,
+ width, height,
+ max_waste,
+ internal_format,
+ error);
}
CoglTexture2DSliced *
cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
- unsigned int width,
- unsigned int height,
+ int width,
+ int height,
int max_waste,
- CoglPixelFormat internal_format,
- CoglError **error)
+ CoglPixelFormat internal_format)
{
- CoglTexture2DSliced *tex_2ds;
+ CoglTexture2DSliced *tex_2ds;
+ CoglError *ignore_error = NULL;
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
/* Init texture with empty bitmap */
- tex_2ds = g_new (CoglTexture2DSliced, 1);
-
- tex_2ds->max_waste = max_waste;
+ tex_2ds = g_new0 (CoglTexture2DSliced, 1);
if (!_cogl_texture_2d_sliced_init_base (ctx,
tex_2ds,
width, height,
- internal_format))
+ max_waste,
+ internal_format,
+ &ignore_error))
{
- _cogl_texture_2d_sliced_free (tex_2ds);
- _cogl_set_error (error,
- COGL_SYSTEM_ERROR,
- COGL_SYSTEM_ERROR_NO_MEMORY,
- "Not enough memory to allocate texture slices");
- return NULL;
+ /* In this case we failed to find any suitable slicing geometry
+ * for the given texture size.
+ *
+ * We don't need to do anything with the error here since it
+ * will be picked up on later when trying to allocate the
+ * texture.
+ */
+ cogl_error_free (ignore_error);
}
+ /* NB: We need to be sure that cogl_texture_is_sliced() will work
+ * correctly before returning since
+ * cogl_framebuffer_allocate() uses this api to determine
+ * if a texture can be rendered to which may be before the
+ * slices have been allocated.
+ */
+
return _cogl_texture_2d_sliced_object_new (tex_2ds);
}
+static CoglBool
+_cogl_texture_2d_sliced_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglContext *ctx = tex->context;
+ CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
+ int n_x_slices;
+ int n_y_slices;
+ int n_slices;
+ int x, y;
+ CoglPixelFormat format = tex_2ds->internal_format;
+ CoglSpan *x_span;
+ CoglSpan *y_span;
+
+ if (!tex_2ds->slice_x_spans || !tex_2ds->slice_y_spans)
+ {
+ _cogl_set_error (error,
+ COGL_TEXTURE_ERROR,
+ COGL_TEXTURE_ERROR_SIZE,
+ "Couldn't find suitable slicing geometry "
+ "for given size");
+ return FALSE;
+ }
+
+ n_x_slices = tex_2ds->slice_x_spans->len;
+ n_y_slices = tex_2ds->slice_y_spans->len;
+ n_slices = n_x_slices * n_y_slices;
+
+ tex_2ds->slice_textures = g_array_sized_new (FALSE, FALSE,
+ sizeof (CoglTexture2D *),
+ n_slices);
+
+ g_array_set_size (tex_2ds->slice_textures, n_slices);
+
+ /* Allocate each slice */
+ for (y = 0; y < n_y_slices; ++y)
+ {
+ y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, y);
+
+ for (x = 0; x < n_x_slices; ++x)
+ {
+ CoglTexture *slice;
+
+ x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, x);
+
+ COGL_NOTE (SLICING, "CREATE SLICE (%d,%d)\tsize (%d,%d)",
+ x, y,
+ (int)(x_span->size - x_span->waste),
+ (int)(y_span->size - y_span->waste));
+
+ slice = COGL_TEXTURE (
+ cogl_texture_2d_new_with_size (ctx,
+ x_span->size, y_span->size,
+ format));
+ g_array_append_val (tex_2ds->slice_textures, slice);
+ if (!cogl_texture_allocate (slice, error))
+ {
+ _cogl_texture_2d_sliced_slices_free (tex_2ds);
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
CoglTexture2DSliced *
_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
CoglTextureFlags flags,
CoglPixelFormat internal_format,
CoglError **error)
{
+ CoglContext *ctx;
CoglTexture2DSliced *tex_2ds;
- CoglBitmap *dst_bmp;
- GLenum gl_intformat;
- GLenum gl_format;
- GLenum gl_type;
- int width, height;
- CoglContext *ctx;
- int i;
+ CoglBitmap *dst_bmp;
+ GLenum gl_intformat;
+ GLenum gl_format;
+ GLenum gl_type;
+ int width, height, max_waste;
+ int i;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
@@ -945,9 +993,9 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
tex_2ds = g_new0 (CoglTexture2DSliced, 1);
if (flags & COGL_TEXTURE_NO_SLICING)
- tex_2ds->max_waste = -1;
+ max_waste = -1;
else
- tex_2ds->max_waste = COGL_TEXTURE_MAX_WASTE;
+ max_waste = COGL_TEXTURE_MAX_WASTE;
dst_bmp = _cogl_texture_prepare_for_upload (bmp,
internal_format,
@@ -962,10 +1010,17 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
return NULL;
}
+ /* NB: we may fail to find any suitable slicing geometry for the
+ * given texture size. */
if (!_cogl_texture_2d_sliced_init_base (ctx,
tex_2ds,
width, height,
- internal_format))
+ max_waste,
+ internal_format,
+ error))
+ goto error;
+
+ if (!cogl_texture_allocate (COGL_TEXTURE (tex_2ds), error))
goto error;
if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds,
@@ -1054,6 +1109,7 @@ _cogl_texture_2d_sliced_new_from_foreign (CoglContext *ctx,
&cogl_texture_2d_sliced_vtable);
tex_2ds->max_waste = 0;
+ tex_2ds->internal_format = format;
/* Create slice arrays */
tex_2ds->slice_x_spans =
@@ -1081,6 +1137,8 @@ _cogl_texture_2d_sliced_new_from_foreign (CoglContext *ctx,
g_array_append_val (tex_2ds->slice_textures, tex_2d);
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_2ds), TRUE);
+
return _cogl_texture_2d_sliced_object_new (tex_2ds);
}
@@ -1112,13 +1170,23 @@ _cogl_texture_2d_sliced_is_sliced (CoglTexture *tex)
{
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
- if (tex_2ds->slice_textures == NULL)
+ /* It's possible that we failed to calculate valid slicing geometry
+ * when initializing the texture due to the max_waste size and in
+ * this case we report that the texture is not sliced.
+ *
+ * In this case though we know that we will be throwing an error
+ * when this texture is later allocated so it shouldn't really
+ * matter what we report here since the texture won't be used in the
+ * end.
+ */
+ if (!tex_2ds->slice_x_spans || !tex_2ds->slice_y_spans)
return FALSE;
- if (tex_2ds->slice_textures->len <= 1)
+ if (tex_2ds->slice_x_spans->len != 1 ||
+ tex_2ds->slice_y_spans->len != 1)
+ return TRUE;
+ else
return FALSE;
-
- return TRUE;
}
static CoglBool
@@ -1223,12 +1291,10 @@ _cogl_texture_2d_sliced_gl_flush_legacy_texobj_filters (CoglTexture *tex,
GLenum mag_filter)
{
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
- CoglTexture2D *slice_tex;
- int i;
+ CoglTexture2D *slice_tex;
+ int i;
- /* Make sure slices were created */
- if (tex_2ds->slice_textures == NULL)
- return;
+ _COGL_RETURN_IF_FAIL (tex_2ds->slice_textures != NULL);
/* Apply new filters to every slice. The slice texture itself should
cache the value and avoid resubmitting the same filter value to
@@ -1246,11 +1312,9 @@ _cogl_texture_2d_sliced_pre_paint (CoglTexture *tex,
CoglTexturePrePaintFlags flags)
{
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
- int i;
+ int i;
- /* Make sure slices were created */
- if (tex_2ds->slice_textures == NULL)
- return;
+ _COGL_RETURN_IF_FAIL (tex_2ds->slice_textures != NULL);
/* Pass the pre-paint on to every slice */
for (i = 0; i < tex_2ds->slice_textures->len; i++)
@@ -1267,9 +1331,7 @@ _cogl_texture_2d_sliced_ensure_non_quad_rendering (CoglTexture *tex)
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
int i;
- /* Make sure slices were created */
- if (tex_2ds->slice_textures == NULL)
- return;
+ _COGL_RETURN_IF_FAIL (tex_2ds->slice_textures != NULL);
/* Pass the call on to every slice */
for (i = 0; i < tex_2ds->slice_textures->len; i++)
@@ -1327,15 +1389,8 @@ static CoglPixelFormat
_cogl_texture_2d_sliced_get_format (CoglTexture *tex)
{
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
- CoglTexture2D *slice_tex;
-
- /* Make sure slices were created */
- if (tex_2ds->slice_textures == NULL)
- return 0;
- /* Pass the call on to the first slice */
- slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, 0);
- return cogl_texture_get_format (COGL_TEXTURE (slice_tex));
+ return tex_2ds->internal_format;
}
static GLenum
@@ -1344,9 +1399,8 @@ _cogl_texture_2d_sliced_get_gl_format (CoglTexture *tex)
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
CoglTexture2D *slice_tex;
- /* Make sure slices were created */
- if (tex_2ds->slice_textures == NULL)
- return 0;
+ /* Assert that we've allocated our slices at this point */
+ cogl_texture_allocate (tex, NULL); /* (abort on error) */
/* Pass the call on to the first slice */
slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, 0);
@@ -1363,6 +1417,7 @@ static const CoglTextureVtable
cogl_texture_2d_sliced_vtable =
{
FALSE, /* not primitive */
+ _cogl_texture_2d_sliced_allocate,
_cogl_texture_2d_sliced_set_region,
NULL, /* get_data */
_cogl_texture_2d_sliced_foreach_sub_texture_in_region,
diff --git a/cogl/cogl-texture-2d-sliced.h b/cogl/cogl-texture-2d-sliced.h
index 8d2cc4b9..e26157e6 100644
--- a/cogl/cogl-texture-2d-sliced.h
+++ b/cogl/cogl-texture-2d-sliced.h
@@ -70,32 +70,48 @@ typedef struct _CoglTexture2DSliced CoglTexture2DSliced;
* @width: The virtual width of your sliced texture.
* @height: The virtual height of your sliced texture.
* @max_waste: The threshold of how wide a strip of wasted texels
- * are allowed in the non-power-of-two textures before
- * they must be sliced to reduce the amount of waste.
+ * are allowed along the right and bottom textures before
+ * they must be sliced to reduce the amount of waste. A
+ * negative can be passed to disable slicing.
* @internal_format: The format of the texture
- * @error: A #CoglError for exceptions.
*
* Creates a #CoglTexture2DSliced that may internally be comprised of
- * 1 or more #CoglTexture2D textures with power-of-two sizes.
+ * 1 or more #CoglTexture2D textures depending on GPU limitations.
+ * For example if the GPU only supports power-of-two sized textures
+ * then a sliced texture will turn a non-power-of-two size into a
+ * combination of smaller power-of-two sized textures. If the
+ * requested texture size is larger than is supported by the hardware
+ * then the texture will be sliced into smaller textures that can be
+ * accessed by the hardware.
+ *
* @max_waste is used as a threshold for recursively slicing the
- * right-most or bottom-most slices into smaller power-of-two sizes
- * until the wasted padding at the bottom and right of the
- * power-of-two textures is less than specified.
+ * right-most or bottom-most slices into smaller sizes until the
+ * wasted padding at the bottom and right of the textures is less than
+ * specified. A negative @max_waste will disable slicing.
+ *
+ * The storage for the texture is not allocated before this function
+ * returns. You can call cogl_texture_allocate() to explicitly
+ * allocate the underlying storage or let Cogl automatically allocate
+ * storage lazily.
+ *
+ * <note>It's possible for the allocation of a sliced texture to fail
+ * later due to impossible slicing constraints if a negative
+ * @max_waste value is given. If the given virtual texture size size
+ * is larger than is supported by the hardware but slicing is disabled
+ * the texture size would be too large to handle.</note>
*
- * Returns: A newly allocated #CoglTexture2DSliced or if there was
- * an error allocating any of the internal slices %NULL is
- * returned and @error is updated.
+ * Returns: A new #CoglTexture2DSliced object with no storage
+ * allocated yet.
*
* Since: 1.10
* Stability: unstable
*/
CoglTexture2DSliced *
cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
- unsigned int width,
- unsigned int height,
+ int width,
+ int height,
int max_waste,
- CoglPixelFormat internal_format,
- CoglError **error);
+ CoglPixelFormat internal_format);
/**
* cogl_is_texture_2d_sliced:
diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c
index 74ab1ab8..7492e128 100644
--- a/cogl/cogl-texture-2d.c
+++ b/cogl/cogl-texture-2d.c
@@ -119,7 +119,7 @@ _cogl_texture_2d_create_base (CoglContext *ctx,
tex_2d->is_foreign = FALSE;
- tex_2d->format = internal_format;
+ tex_2d->internal_format = internal_format;
ctx->driver_vtable->texture_2d_init (tex_2d);
@@ -130,27 +130,23 @@ CoglTexture2D *
cogl_texture_2d_new_with_size (CoglContext *ctx,
int width,
int height,
- CoglPixelFormat internal_format,
- CoglError **error)
+ CoglPixelFormat internal_format)
{
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
- if (!_cogl_texture_2d_can_create (ctx, width, height, internal_format))
- {
- _cogl_set_error (error, COGL_TEXTURE_ERROR,
- COGL_TEXTURE_ERROR_SIZE,
- "Failed to create texture 2d due to size/format"
- " constraints");
- return NULL;
- }
+ return _cogl_texture_2d_create_base (ctx,
+ width, height,
+ internal_format);
+}
- return ctx->driver_vtable->texture_2d_new_with_size (ctx,
- width,
- height,
- internal_format,
- error);
+static CoglBool
+_cogl_texture_2d_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglContext *ctx = tex->context;
+ return ctx->driver_vtable->texture_2d_allocate (tex, error);
}
CoglTexture2D *
@@ -178,7 +174,6 @@ cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
"Failed to create texture 2d due to size/format"
" constraints");
return NULL;
-
}
return ctx->driver_vtable->texture_2d_new_from_bitmap (bmp,
@@ -350,7 +345,11 @@ _cogl_texture_2d_copy_from_framebuffer (CoglTexture2D *tex_2d,
int dst_y,
int level)
{
- CoglContext *ctx = COGL_TEXTURE (tex_2d)->context;
+ CoglTexture *tex = COGL_TEXTURE (tex_2d);
+ CoglContext *ctx = tex->context;
+
+ /* Assert that the storage for this texture has been allocated */
+ cogl_texture_allocate (tex, NULL); /* (abort on error) */
ctx->driver_vtable->texture_2d_copy_from_framebuffer (tex_2d,
src_x,
@@ -525,7 +524,7 @@ _cogl_texture_2d_get_data (CoglTexture *tex,
static CoglPixelFormat
_cogl_texture_2d_get_format (CoglTexture *tex)
{
- return COGL_TEXTURE_2D (tex)->format;
+ return COGL_TEXTURE_2D (tex)->internal_format;
}
static GLenum
@@ -550,6 +549,7 @@ static const CoglTextureVtable
cogl_texture_2d_vtable =
{
TRUE, /* primitive */
+ _cogl_texture_2d_allocate,
_cogl_texture_2d_set_region,
_cogl_texture_2d_get_data,
NULL, /* foreach_sub_texture_in_region */
diff --git a/cogl/cogl-texture-2d.h b/cogl/cogl-texture-2d.h
index fcd86f77..5a5ff2f5 100644
--- a/cogl/cogl-texture-2d.h
+++ b/cogl/cogl-texture-2d.h
@@ -74,7 +74,6 @@ cogl_is_texture_2d (void *object);
* @width: Width of the texture to allocate
* @height: Height of the texture to allocate
* @internal_format: The format of the texture
- * @error: A #CoglError for exceptions
*
* Allocates a low-level #CoglTexture2D texture that your GPU can
* texture from directly. This is unlike sliced textures for example
@@ -82,15 +81,18 @@ cogl_is_texture_2d (void *object);
* textures where Cogl has to modify texture coordinates before they
* may be used by the GPU.
*
+ * The storage for the texture is not allocated before this function
+ * returns. You can call cogl_texture_allocate() to explicitly
+ * allocate the underlying storage or preferably let Cogl
+ * automatically allocate storage lazily when it may know more about
+ * how the texture is being used and can optimize how it is allocated.
+ *
* <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by
* checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via
* cogl_has_feature().</note>
*
- * Returns: A newly allocated #CoglTexture2D, or if the size is not
- * supported (because it is too large or a non-power-of-two
- * size that the hardware doesn't support) it will return
- * %NULL and set @error.
+ * Returns: A new #CoglTexture2D object with no storage yet allocated.
*
* Since: 2.0
*/
@@ -98,8 +100,7 @@ CoglTexture2D *
cogl_texture_2d_new_with_size (CoglContext *ctx,
int width,
int height,
- CoglPixelFormat internal_format,
- CoglError **error);
+ CoglPixelFormat internal_format);
/**
* cogl_texture_2d_new_from_data:
diff --git a/cogl/cogl-texture-3d-private.h b/cogl/cogl-texture-3d-private.h
index 88f70266..22e572eb 100644
--- a/cogl/cogl-texture-3d-private.h
+++ b/cogl/cogl-texture-3d-private.h
@@ -36,7 +36,7 @@ struct _CoglTexture3D
/* The internal format of the texture represented as a
CoglPixelFormat */
- CoglPixelFormat format;
+ CoglPixelFormat internal_format;
int depth;
CoglBool auto_mipmap;
CoglBool mipmaps_dirty;
diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c
index ab7c7e1a..b40448a7 100644
--- a/cogl/cogl-texture-3d.c
+++ b/cogl/cogl-texture-3d.c
@@ -95,7 +95,8 @@ _cogl_texture_3d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
static void
_cogl_texture_3d_free (CoglTexture3D *tex_3d)
{
- _cogl_delete_gl_texture (tex_3d->gl_texture);
+ if (tex_3d->gl_texture)
+ _cogl_delete_gl_texture (tex_3d->gl_texture);
/* Chain up */
_cogl_texture_free (COGL_TEXTURE (tex_3d));
@@ -122,6 +123,8 @@ _cogl_texture_3d_create_base (CoglContext *ctx,
_cogl_texture_init (tex, ctx, width, height, &cogl_texture_3d_vtable);
+ tex_3d->gl_texture = 0;
+
tex_3d->depth = depth;
tex_3d->mipmaps_dirty = TRUE;
tex_3d->auto_mipmap = TRUE;
@@ -135,7 +138,7 @@ _cogl_texture_3d_create_base (CoglContext *ctx,
tex_3d->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
tex_3d->gl_legacy_texobj_wrap_mode_p = GL_FALSE;
- tex_3d->format = internal_format;
+ tex_3d->internal_format = internal_format;
return _cogl_texture_3d_object_new (tex_3d);
}
@@ -206,54 +209,66 @@ cogl_texture_3d_new_with_size (CoglContext *ctx,
int width,
int height,
int depth,
- CoglPixelFormat internal_format,
- CoglError **error)
+ CoglPixelFormat internal_format)
{
- CoglTexture3D *tex_3d;
+ /* Since no data, we need some internal format */
+ if (internal_format == COGL_PIXEL_FORMAT_ANY)
+ internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
+
+ return _cogl_texture_3d_create_base (ctx,
+ width, height, depth,
+ internal_format);
+}
+
+static CoglBool
+_cogl_texture_3d_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglContext *ctx = tex->context;
+ CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
GLenum gl_error;
-
- /* Since no data, we need some internal format */
- if (internal_format == COGL_PIXEL_FORMAT_ANY)
- internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
+ GLenum gl_texture;
if (!_cogl_texture_3d_can_create (ctx,
- width, height, depth,
- internal_format,
+ tex->width,
+ tex->height,
+ tex_3d->depth,
+ tex_3d->internal_format,
error))
- return NULL;
-
- internal_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
- internal_format,
- &gl_intformat,
- &gl_format,
- &gl_type);
+ return FALSE;
- tex_3d = _cogl_texture_3d_create_base (ctx,
- width, height, depth,
- internal_format);
+ ctx->driver_vtable->pixel_format_to_gl (ctx,
+ tex_3d->internal_format,
+ &gl_intformat,
+ &gl_format,
+ &gl_type);
- tex_3d->gl_texture =
- ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
+ gl_texture =
+ ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, tex_3d->internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
- tex_3d->gl_texture,
+ gl_texture,
FALSE);
/* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat,
- width, height, depth, 0, gl_format, gl_type, NULL);
+ tex->width, tex->height, tex_3d->depth,
+ 0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{
- cogl_object_unref (tex_3d);
- return NULL;
+ GE( ctx, glDeleteTextures (1, &gl_texture) );
+ return FALSE;
}
- return tex_3d;
+ tex_3d->gl_texture = gl_texture;
+ tex_3d->gl_format = gl_intformat;
+
+ return TRUE;
}
CoglTexture3D *
@@ -354,6 +369,8 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
cogl_object_unref (dst_bmp);
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_3d), TRUE);
+
return tex_3d;
}
@@ -628,7 +645,7 @@ _cogl_texture_3d_get_data (CoglTexture *tex,
static CoglPixelFormat
_cogl_texture_3d_get_format (CoglTexture *tex)
{
- return COGL_TEXTURE_3D (tex)->format;
+ return COGL_TEXTURE_3D (tex)->internal_format;
}
static GLenum
@@ -647,6 +664,7 @@ static const CoglTextureVtable
cogl_texture_3d_vtable =
{
TRUE, /* primitive */
+ _cogl_texture_3d_allocate,
_cogl_texture_3d_set_region,
_cogl_texture_3d_get_data,
NULL, /* foreach_sub_texture_in_region */
diff --git a/cogl/cogl-texture-3d.h b/cogl/cogl-texture-3d.h
index c2700efa..0483d47f 100644
--- a/cogl/cogl-texture-3d.h
+++ b/cogl/cogl-texture-3d.h
@@ -55,18 +55,23 @@ typedef struct _CoglTexture3D CoglTexture3D;
* @depth: depth of the texture in pixels.
* @internal_format: the #CoglPixelFormat to use for the GPU
* storage of the texture.
- * @error: A CoglError return location.
*
- * Creates a new Cogl 3D texture with the specified dimensions and
- * pixel format.
+ * Creates a new #CoglTexture3D texture with the specified dimensions
+ * and pixel format.
*
- * Note that this function will throw a #CoglError if
- * %COGL_FEATURE_ID_TEXTURE_3D is not advertised. It can also fail if the
- * requested dimensions are not supported by the GPU.
+ * The storage for the texture is not allocated before this function
+ * returns. You can call cogl_texture_allocate() to explicitly
+ * allocate the underlying storage or preferably let Cogl
+ * automatically allocate storage lazily when it may know more about
+ * how the texture is going to be used and can optimize how it is
+ * allocated.
+ *
+ * <note>This texture will fail to allocate later if
+ * %COGL_FEATURE_ID_TEXTURE_3D is not advertised. Allocation can also
+ * fail if the requested dimensions are not supported by the
+ * GPU.</note>
*
- * Return value: a new #CoglTexture3D object or
- * %NULL on failure and an exception will be returned
- * in @error.
+ * Returns: A new #CoglTexture3D object with no storage yet allocated.
* Since: 1.10
* Stability: Unstable
*/
@@ -75,8 +80,7 @@ cogl_texture_3d_new_with_size (CoglContext *context,
int width,
int height,
int depth,
- CoglPixelFormat internal_format,
- CoglError **error);
+ CoglPixelFormat internal_format);
/**
* cogl_texture_3d_new_from_data:
diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h
index 6ff48605..7e70e5ef 100644
--- a/cogl/cogl-texture-private.h
+++ b/cogl/cogl-texture-private.h
@@ -60,6 +60,9 @@ struct _CoglTextureVtable
CoglBool is_primitive;
+ CoglBool (* allocate) (CoglTexture *tex,
+ CoglError **error);
+
/* This should update the specified sub region of the texture with a
sub region of the given bitmap. The bitmap is not converted
before being passed so the implementation is expected to call
@@ -144,6 +147,7 @@ struct _CoglTexture
int max_level;
int width;
int height;
+ CoglBool allocated;
const CoglTextureVtable *vtable;
};
@@ -321,4 +325,8 @@ _cogl_texture_get_level_size (CoglTexture *texture,
int *height,
int *depth);
+void
+_cogl_texture_set_allocated (CoglTexture *texture,
+ CoglBool allocated);
+
#endif /* __COGL_TEXTURE_PRIVATE_H */
diff --git a/cogl/cogl-texture-rectangle-private.h b/cogl/cogl-texture-rectangle-private.h
index e6592a54..fe4dfe83 100644
--- a/cogl/cogl-texture-rectangle-private.h
+++ b/cogl/cogl-texture-rectangle-private.h
@@ -34,7 +34,7 @@ struct _CoglTextureRectangle
/* The internal format of the texture represented as a
CoglPixelFormat */
- CoglPixelFormat format;
+ CoglPixelFormat internal_format;
/* TODO: factor out these OpenGL specific members into some form
* of driver private state. */
diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c
index ee4cfcf0..f8d0811e 100644
--- a/cogl/cogl-texture-rectangle.c
+++ b/cogl/cogl-texture-rectangle.c
@@ -102,7 +102,7 @@ _cogl_texture_rectangle_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
static void
_cogl_texture_rectangle_free (CoglTextureRectangle *tex_rect)
{
- if (!tex_rect->is_foreign)
+ if (!tex_rect->is_foreign && tex_rect->gl_texture)
_cogl_delete_gl_texture (tex_rect->gl_texture);
/* Chain up */
@@ -173,6 +173,8 @@ _cogl_texture_rectangle_create_base (CoglContext *ctx,
_cogl_texture_init (tex, ctx, width, height, &cogl_texture_rectangle_vtable);
+ tex_rect->gl_texture = 0;
+
/* We default to GL_LINEAR for both filters */
tex_rect->gl_legacy_texobj_min_filter = GL_LINEAR;
tex_rect->gl_legacy_texobj_mag_filter = GL_LINEAR;
@@ -181,7 +183,7 @@ _cogl_texture_rectangle_create_base (CoglContext *ctx,
tex_rect->gl_legacy_texobj_wrap_mode_s = GL_FALSE;
tex_rect->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
- tex_rect->format = internal_format;
+ tex_rect->internal_format = internal_format;
return _cogl_texture_rectangle_object_new (tex_rect);
}
@@ -194,36 +196,59 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
CoglError **error)
{
CoglTextureRectangle *tex_rect;
- GLenum gl_intformat;
- GLenum gl_format;
- GLenum gl_type;
- GLenum gl_error;
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
- if (!_cogl_texture_rectangle_can_create (ctx,
- width, height,
- internal_format, error))
- return NULL;
+ tex_rect =_cogl_texture_rectangle_create_base (ctx,
+ width, height,
+ internal_format);
- internal_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
- internal_format,
- &gl_intformat,
- &gl_format,
- &gl_type);
+ /* XXX: This api has been changed for Cogl 2.0 on the master branch
+ * to not take a CoglError to allow the storage to be allocated
+ * lazily but since Mutter uses this api we are currently
+ * maintaining the semantics of immediately allocating the storage
+ */
+ if (!cogl_texture_allocate (COGL_TEXTURE (tex_rect), error))
+ {
+ cogl_object_unref (tex_rect);
+ return NULL;
+ }
+ return tex_rect;
+}
- tex_rect = _cogl_texture_rectangle_create_base (ctx,
- width, height,
- internal_format);
+static CoglBool
+_cogl_texture_rectangle_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglContext *ctx = tex->context;
+ CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
+ GLenum gl_intformat;
+ GLenum gl_format;
+ GLenum gl_type;
+ GLenum gl_error;
+ GLenum gl_texture;
- tex_rect->gl_texture =
+ if (!_cogl_texture_rectangle_can_create (ctx,
+ tex->width,
+ tex->height,
+ tex_rect->internal_format,
+ error))
+ return FALSE;
+
+ ctx->driver_vtable->pixel_format_to_gl (ctx,
+ tex_rect->internal_format,
+ &gl_intformat,
+ &gl_format,
+ &gl_type);
+
+ gl_texture =
ctx->texture_driver->gen (ctx,
GL_TEXTURE_RECTANGLE_ARB,
- internal_format);
+ tex_rect->internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
- tex_rect->gl_texture,
+ gl_texture,
tex_rect->is_foreign);
/* Clear any GL errors */
@@ -231,15 +256,18 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
;
ctx->glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat,
- width, height, 0, gl_format, gl_type, NULL);
+ tex->width, tex->height, 0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{
- cogl_object_unref (tex_rect);
- return NULL;
+ GE( ctx, glDeleteTextures (1, &gl_texture) );
+ return FALSE;
}
- return tex_rect;
+ tex_rect->gl_texture = gl_texture;
+ tex_rect->gl_format = gl_intformat;
+
+ return TRUE;
}
CoglTextureRectangle *
@@ -308,6 +336,8 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
cogl_object_unref (dst_bmp);
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect), TRUE);
+
return tex_rect;
}
@@ -424,7 +454,7 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
/* Setup bitmap info */
tex_rect->is_foreign = TRUE;
- tex_rect->format = format;
+ tex_rect->internal_format = format;
tex_rect->gl_texture = gl_handle;
tex_rect->gl_format = gl_int_format;
@@ -433,6 +463,8 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
tex_rect->gl_legacy_texobj_min_filter = GL_FALSE;
tex_rect->gl_legacy_texobj_mag_filter = GL_FALSE;
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect), TRUE);
+
return tex_rect;
}
@@ -624,7 +656,7 @@ _cogl_texture_rectangle_get_data (CoglTexture *tex,
static CoglPixelFormat
_cogl_texture_rectangle_get_format (CoglTexture *tex)
{
- return COGL_TEXTURE_RECTANGLE (tex)->format;
+ return COGL_TEXTURE_RECTANGLE (tex)->internal_format;
}
static GLenum
@@ -649,6 +681,7 @@ static const CoglTextureVtable
cogl_texture_rectangle_vtable =
{
TRUE, /* primitive */
+ _cogl_texture_rectangle_allocate,
_cogl_texture_rectangle_set_region,
_cogl_texture_rectangle_get_data,
NULL, /* foreach_sub_texture_in_region */
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index 28d1f4cc..1b97648a 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -139,6 +139,7 @@ _cogl_texture_init (CoglTexture *texture,
texture->max_level = 0;
texture->width = width;
texture->height = height;
+ texture->allocated = FALSE;
texture->vtable = vtable;
texture->framebuffers = NULL;
}
@@ -440,6 +441,20 @@ _cogl_texture_get_type (CoglTexture *texture)
void
_cogl_texture_pre_paint (CoglTexture *texture, CoglTexturePrePaintFlags flags)
{
+ /* Assert that the storage for the texture exists already if we're
+ * about to reference it for painting.
+ *
+ * Note: we abort on error here since it's a bit late to do anything
+ * about it if we fail to allocate the texture and the app could
+ * have explicitly allocated the texture earlier to handle problems
+ * gracefully.
+ *
+ * XXX: Maybe it could even be considered a programmer error if the
+ * texture hasn't been allocated by this point since it implies we
+ * are abount to paint with undefined texture contents?
+ */
+ cogl_texture_allocate (texture, NULL);
+
texture->vtable->pre_paint (texture, flags);
}
@@ -465,10 +480,12 @@ _cogl_texture_set_region_from_bitmap (CoglTexture *texture,
>= width, FALSE);
_COGL_RETURN_VAL_IF_FAIL ((cogl_bitmap_get_height (bmp) - src_y)
>= height, FALSE);
+ _COGL_RETURN_VAL_IF_FAIL (width > 0, FALSE);
+ _COGL_RETURN_VAL_IF_FAIL (height > 0, FALSE);
- /* Shortcut out early if the image is empty */
- if (width == 0 || height == 0)
- return TRUE;
+ /* Assert that the storage for this texture has been allocated */
+ if (!cogl_texture_allocate (texture, error))
+ return FALSE;
/* Note that we don't prepare the bitmap for upload here because
some backends may be internally using a different format for the
@@ -897,10 +914,12 @@ get_texture_bits_via_offscreen (CoglTexture *texture,
COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL,
0);
- if (offscreen == NULL)
- return FALSE;
-
framebuffer = COGL_FRAMEBUFFER (offscreen);
+ if (!cogl_framebuffer_allocate (framebuffer, &ignore_error))
+ {
+ cogl_error_free (ignore_error);
+ return FALSE;
+ }
bitmap = cogl_bitmap_new_for_data (ctx,
width, height,
@@ -1390,3 +1409,22 @@ _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans,
}
}
}
+
+void
+_cogl_texture_set_allocated (CoglTexture *texture,
+ CoglBool allocated)
+{
+ texture->allocated = allocated;
+}
+
+CoglBool
+cogl_texture_allocate (CoglTexture *texture,
+ CoglError **error)
+{
+ if (texture->allocated)
+ return TRUE;
+
+ texture->allocated = texture->vtable->allocate (texture, error);
+
+ return texture->allocated;
+}
diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h
index 17658ead..b744babe 100644
--- a/cogl/cogl-texture.h
+++ b/cogl/cogl-texture.h
@@ -112,7 +112,14 @@ uint32_t cogl_texture_error_quark (void);
*
* Creates a new #CoglTexture with the specified dimensions and pixel format.
*
- * Return value: A newly created #CoglTexture or %NULL on failure
+ * The storage for the texture is not necesarily created before this
+ * function returns. The storage can be explicitly allocated using
+ * cogl_texture_allocate() or preferably you can let Cogl
+ * automatically allocate the storage lazily when uploading data when
+ * Cogl may know more about how the texture will be used and can
+ * optimize how it is allocated.
+ *
+ * Return value: A newly created #CoglTexture
*
* Since: 0.8
*/
@@ -517,6 +524,28 @@ cogl_texture_unref (void *texture) G_GNUC_DEPRECATED;
#endif /* COGL_DISABLE_DEPRECATED */
+/**
+ * cogl_texture_allocate:
+ * @texture: A #CoglTexture
+ * @error: A #CoglError to return exceptional errors or %NULL
+ *
+ * Explicitly allocates the storage for the given @texture which
+ * allows you to be sure that there is enough memory for the
+ * texture and if not then the error can be handled gracefully.
+ *
+ * <note>Normally applications don't need to use this api directly
+ * since the texture will be implicitly allocated when data is set on
+ * the texture, or if the texture is attached to a #CoglOffscreen
+ * framebuffer and rendered too.</note>
+ *
+ * Return value: %TRUE if the texture was successfully allocated,
+ * otherwise %FALSE and @error will be updated if it
+ * wasn't %NULL.
+ */
+CoglBool
+cogl_texture_allocate (CoglTexture *texture,
+ CoglError **error);
+
COGL_END_DECLS
#endif /* __COGL_TEXTURE_H__ */
diff --git a/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/driver/gl/cogl-framebuffer-gl.c
index a0a50cfa..043d047e 100644
--- a/cogl/driver/gl/cogl-framebuffer-gl.c
+++ b/cogl/driver/gl/cogl-framebuffer-gl.c
@@ -382,8 +382,7 @@ create_depth_texture (CoglContext *ctx,
depth_texture = cogl_texture_2d_new_with_size (ctx,
width, height,
- format,
- NULL);
+ format);
return COGL_TEXTURE (depth_texture);
}
@@ -712,14 +711,14 @@ _cogl_offscreen_gl_allocate (CoglOffscreen *offscreen,
offscreen->texture_level_width,
offscreen->texture_level_height);
- if (offscreen->depth_texture)
- _cogl_texture_associate_framebuffer (offscreen->depth_texture, fb);
- else
+ if (!cogl_texture_allocate (offscreen->depth_texture, error))
{
- _cogl_set_error (error, COGL_FRAMEBUFFER_ERROR,
- COGL_FRAMEBUFFER_ERROR_ALLOCATE,
- "Failed to allocate depth texture for framebuffer");
+ cogl_object_unref (offscreen->depth_texture);
+ offscreen->depth_texture = NULL;
+ return FALSE;
}
+
+ _cogl_texture_associate_framebuffer (offscreen->depth_texture, fb);
}
/* XXX: The framebuffer_object spec isn't clear in defining whether attaching
diff --git a/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/driver/gl/cogl-texture-2d-gl-private.h
index d77f460e..c71908fc 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl-private.h
+++ b/cogl/driver/gl/cogl-texture-2d-gl-private.h
@@ -44,12 +44,9 @@ _cogl_texture_2d_gl_can_create (CoglContext *ctx,
void
_cogl_texture_2d_gl_init (CoglTexture2D *tex_2d);
-CoglTexture2D *
-_cogl_texture_2d_gl_new_with_size (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat internal_format,
- CoglError **error);
+CoglBool
+_cogl_texture_2d_gl_allocate (CoglTexture *tex,
+ CoglError **error);
CoglTexture2D *
_cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c
index 4f57eed6..8bcfb93d 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -43,7 +43,7 @@
void
_cogl_texture_2d_gl_free (CoglTexture2D *tex_2d)
{
- if (!tex_2d->is_foreign)
+ if (!tex_2d->is_foreign && tex_2d->gl_texture)
_cogl_delete_gl_texture (tex_2d->gl_texture);
}
@@ -79,6 +79,8 @@ _cogl_texture_2d_gl_can_create (CoglContext *ctx,
void
_cogl_texture_2d_gl_init (CoglTexture2D *tex_2d)
{
+ tex_2d->gl_texture = 0;
+
/* We default to GL_LINEAR for both filters */
tex_2d->gl_legacy_texobj_min_filter = GL_LINEAR;
tex_2d->gl_legacy_texobj_mag_filter = GL_LINEAR;
@@ -88,36 +90,43 @@ _cogl_texture_2d_gl_init (CoglTexture2D *tex_2d)
tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
}
-CoglTexture2D *
-_cogl_texture_2d_gl_new_with_size (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat internal_format,
- CoglError **error)
+CoglBool
+_cogl_texture_2d_gl_allocate (CoglTexture *tex,
+ CoglError **error)
{
- CoglTexture2D *tex_2d;
+ CoglContext *ctx = tex->context;
+ CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
GLenum gl_error;
+ GLenum gl_texture;
- internal_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
- internal_format,
- &gl_intformat,
- &gl_format,
- &gl_type);
+ if (!_cogl_texture_2d_gl_can_create (ctx,
+ tex->width,
+ tex->height,
+ tex_2d->internal_format))
+ {
+ _cogl_set_error (error, COGL_TEXTURE_ERROR,
+ COGL_TEXTURE_ERROR_SIZE,
+ "Failed to create texture 2d due to size/format"
+ " constraints");
+ return FALSE;
+ }
- tex_2d = _cogl_texture_2d_create_base (ctx,
- width, height,
- internal_format);
+ ctx->driver_vtable->pixel_format_to_gl (ctx,
+ tex_2d->internal_format,
+ &gl_intformat,
+ &gl_format,
+ &gl_type);
- tex_2d->gl_texture =
- ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
+ gl_texture =
+ ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, tex_2d->internal_format);
tex_2d->gl_internal_format = gl_intformat;
_cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
- tex_2d->gl_texture,
+ gl_texture,
tex_2d->is_foreign);
/* Clear any GL errors */
@@ -125,15 +134,18 @@ _cogl_texture_2d_gl_new_with_size (CoglContext *ctx,
;
ctx->glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat,
- width, height, 0, gl_format, gl_type, NULL);
+ tex->width, tex->height, 0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{
- cogl_object_unref (tex_2d);
- return NULL;
+ GE( ctx, glDeleteTextures (1, &gl_texture) );
+ return FALSE;
}
- return tex_2d;
+ tex_2d->gl_texture = gl_texture;
+ tex_2d->gl_internal_format = gl_intformat;
+
+ return TRUE;
}
CoglTexture2D *
@@ -213,6 +225,8 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
cogl_object_unref (dst_bmp);
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE);
+
return tex_2d;
}
@@ -249,9 +263,12 @@ _cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx,
COGL_TEXTURE_ERROR_BAD_PARAMETER,
"Could not create a CoglTexture2D from a given "
"EGLImage");
+ cogl_object_unref (tex_2d);
return NULL;
}
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE);
+
return tex_2d;
}
#endif
@@ -442,8 +459,6 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
tex_2d->is_foreign = TRUE;
tex_2d->mipmaps_dirty = TRUE;
- tex_2d->format = format;
-
tex_2d->gl_texture = gl_handle;
tex_2d->gl_internal_format = gl_int_format;
@@ -451,6 +466,8 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
tex_2d->gl_legacy_texobj_min_filter = GL_FALSE;
tex_2d->gl_legacy_texobj_mag_filter = GL_FALSE;
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE);
+
return tex_2d;
}
@@ -465,7 +482,8 @@ _cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d,
int dst_y,
int level)
{
- CoglContext *ctx = COGL_TEXTURE (tex_2d)->context;
+ CoglTexture *tex = COGL_TEXTURE (tex_2d);
+ CoglContext *ctx = tex->context;
/* Make sure the current framebuffers are bound, though we don't need to
* flush the clip state here since we aren't going to draw to the
diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c
index bd12c81c..141371eb 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -638,7 +638,7 @@ _cogl_driver_gl =
_cogl_texture_2d_gl_free,
_cogl_texture_2d_gl_can_create,
_cogl_texture_2d_gl_init,
- _cogl_texture_2d_gl_new_with_size,
+ _cogl_texture_2d_gl_allocate,
_cogl_texture_2d_gl_new_from_bitmap,
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
_cogl_egl_texture_2d_gl_new_from_image,
diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c
index b4d5efd3..494b14ea 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -380,7 +380,7 @@ _cogl_driver_gles =
_cogl_texture_2d_gl_free,
_cogl_texture_2d_gl_can_create,
_cogl_texture_2d_gl_init,
- _cogl_texture_2d_gl_new_with_size,
+ _cogl_texture_2d_gl_allocate,
_cogl_texture_2d_gl_new_from_bitmap,
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
_cogl_egl_texture_2d_gl_new_from_image,
diff --git a/cogl/driver/nop/cogl-driver-nop.c b/cogl/driver/nop/cogl-driver-nop.c
index 40b101b2..7a782f9c 100644
--- a/cogl/driver/nop/cogl-driver-nop.c
+++ b/cogl/driver/nop/cogl-driver-nop.c
@@ -68,7 +68,7 @@ _cogl_driver_nop =
_cogl_texture_2d_nop_free,
_cogl_texture_2d_nop_can_create,
_cogl_texture_2d_nop_init,
- _cogl_texture_2d_nop_new_with_size,
+ _cogl_texture_2d_nop_allocate,
_cogl_texture_2d_nop_new_from_bitmap,
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
_cogl_egl_texture_2d_nop_new_from_image,
diff --git a/cogl/driver/nop/cogl-texture-2d-nop-private.h b/cogl/driver/nop/cogl-texture-2d-nop-private.h
index 2e79e667..1aa558a1 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop-private.h
+++ b/cogl/driver/nop/cogl-texture-2d-nop-private.h
@@ -44,12 +44,9 @@ _cogl_texture_2d_nop_can_create (CoglContext *ctx,
void
_cogl_texture_2d_nop_init (CoglTexture2D *tex_2d);
-CoglTexture2D *
-_cogl_texture_2d_nop_new_with_size (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat internal_format,
- CoglError **error);
+CoglBool
+_cogl_texture_2d_nop_allocate (CoglTexture *tex,
+ CoglError **error);
CoglTexture2D *
_cogl_texture_2d_nop_new_from_bitmap (CoglBitmap *bmp,
diff --git a/cogl/driver/nop/cogl-texture-2d-nop.c b/cogl/driver/nop/cogl-texture-2d-nop.c
index 948d6209..5831e279 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop.c
+++ b/cogl/driver/nop/cogl-texture-2d-nop.c
@@ -55,16 +55,11 @@ _cogl_texture_2d_nop_init (CoglTexture2D *tex_2d)
{
}
-CoglTexture2D *
-_cogl_texture_2d_nop_new_with_size (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat internal_format,
- CoglError **error)
+CoglBool
+_cogl_texture_2d_nop_allocate (CoglTexture *tex,
+ CoglError **error)
{
- return _cogl_texture_2d_create_base (ctx,
- width, height,
- internal_format);
+ return TRUE;
}
CoglTexture2D *
@@ -72,11 +67,10 @@ _cogl_texture_2d_nop_new_from_bitmap (CoglBitmap *bmp,
CoglPixelFormat internal_format,
CoglError **error)
{
- return _cogl_texture_2d_nop_new_with_size (_cogl_bitmap_get_context (bmp),
- cogl_bitmap_get_width (bmp),
- cogl_bitmap_get_height (bmp),
- internal_format,
- error);
+ return _cogl_texture_2d_create_base (_cogl_bitmap_get_context (bmp),
+ cogl_bitmap_get_width (bmp),
+ cogl_bitmap_get_height (bmp),
+ internal_format);
}
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c
index 2b66414e..71d00ea9 100644
--- a/cogl/winsys/cogl-texture-pixmap-x11.c
+++ b/cogl/winsys/cogl-texture-pixmap-x11.c
@@ -361,9 +361,18 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
if (!tex_pixmap->use_winsys_texture)
tex_pixmap->winsys = NULL;
+ _cogl_texture_set_allocated (tex, TRUE);
+
return _cogl_texture_pixmap_x11_object_new (tex_pixmap);
}
+static CoglBool
+_cogl_texture_pixmap_x11_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ return TRUE;
+}
+
/* Tries to allocate enough shared mem to handle a full size
* update size of the X Pixmap. */
static void
@@ -1001,6 +1010,7 @@ static const CoglTextureVtable
cogl_texture_pixmap_x11_vtable =
{
FALSE, /* not primitive */
+ _cogl_texture_pixmap_x11_allocate,
_cogl_texture_pixmap_x11_set_region,
_cogl_texture_pixmap_x11_get_data,
_cogl_texture_pixmap_x11_foreach_sub_texture_in_region,
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index 2bfa1908..a9f88e07 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -1980,17 +1980,17 @@ _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap,
cogl_texture_2d_new_with_size (ctx,
tex->width,
tex->height,
- texture_format,
- NULL));
+ texture_format));
- if (glx_tex_pixmap->glx_tex)
+ if (cogl_texture_allocate (glx_tex_pixmap->glx_tex, &error))
COGL_NOTE (TEXTURE_PIXMAP, "Created a texture 2d for %p",
tex_pixmap);
else
{
COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a "
- "texture 2d could not be created",
- tex_pixmap);
+ "texture 2d could not be created: %s",
+ tex_pixmap, error->message);
+ cogl_error_free (error);
free_glx_pixmap (ctx, glx_tex_pixmap);
return FALSE;
}
diff --git a/tests/conform/test-gles2-context.c b/tests/conform/test-gles2-context.c
index 9a3c8b67..9e66ab03 100644
--- a/tests/conform/test-gles2-context.c
+++ b/tests/conform/test-gles2-context.c
@@ -27,8 +27,7 @@ test_push_pop_single_context (void)
cogl_texture_2d_new_with_size (test_ctx,
cogl_framebuffer_get_width (test_fb),
cogl_framebuffer_get_height (test_fb),
- COGL_PIXEL_FORMAT_ANY,
- NULL));
+ COGL_PIXEL_FORMAT_ANY));
offscreen = cogl_offscreen_new_to_texture (offscreen_texture);
pipeline = cogl_pipeline_new (test_ctx);
@@ -152,8 +151,7 @@ create_gles2_context (CoglTexture **offscreen_texture,
cogl_texture_2d_new_with_size (test_ctx,
cogl_framebuffer_get_width (test_fb),
cogl_framebuffer_get_height (test_fb),
- COGL_PIXEL_FORMAT_ANY,
- NULL));
+ COGL_PIXEL_FORMAT_ANY));
*offscreen = cogl_offscreen_new_to_texture (*offscreen_texture);
*pipeline = cogl_pipeline_new (test_ctx);
diff --git a/tests/conform/test-offscreen.c b/tests/conform/test-offscreen.c
index 26578d55..5a4863b0 100644
--- a/tests/conform/test-offscreen.c
+++ b/tests/conform/test-offscreen.c
@@ -45,8 +45,7 @@ test_paint (TestState *state)
tex_2d = cogl_texture_2d_new_with_size (test_ctx,
state->fb_width,
state->fb_height,
- COGL_PIXEL_FORMAT_RGBA_8888_PRE,
- NULL);
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE);
tex = COGL_TEXTURE (tex_2d);
offscreen = cogl_offscreen_new_to_texture (tex);
@@ -127,8 +126,7 @@ test_flush (TestState *state)
tex_2d = cogl_texture_2d_new_with_size (test_ctx,
16, 16, /* width/height */
- COGL_PIXEL_FORMAT_RGBA_8888_PRE,
- NULL);
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE);
tex = COGL_TEXTURE (tex_2d);
offscreen = cogl_offscreen_new_to_texture (tex);
diff --git a/tests/conform/test-utils.c b/tests/conform/test-utils.c
index 684327d5..9f3a4b4d 100644
--- a/tests/conform/test-utils.c
+++ b/tests/conform/test-utils.c
@@ -122,11 +122,7 @@ test_utils_init (TestFlags requirement_flags,
CoglOffscreen *offscreen;
CoglTexture2D *tex = cogl_texture_2d_new_with_size (test_ctx,
FB_WIDTH, FB_HEIGHT,
- COGL_PIXEL_FORMAT_ANY,
- &error);
- if (!tex)
- g_critical ("Failed to allocate texture: %s", error->message);
-
+ COGL_PIXEL_FORMAT_ANY);
offscreen = cogl_offscreen_new_to_texture (COGL_TEXTURE (tex));
test_fb = COGL_FRAMEBUFFER (offscreen);
}