diff --git a/cogl-pango/cogl-pango-glyph-cache.c b/cogl-pango/cogl-pango-glyph-cache.c index 14c8295a7..59cb5f430 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 52fdf0693..670eea454 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 c37908adb..7f62efceb 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 62b11f850..d6c0e74f1 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 bcbb1d0c0..ff7673b94 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 5cb5ea4c3..ea457b958 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 e46bec8fe..0c42e716c 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 7664f7c08..a88c59181 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 148e7f461..8b95796f3 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; + _COGL_RETURN_VAL_IF_FAIL (cogl_is_texture (texture), NULL); + _COGL_RETURN_VAL_IF_FAIL (level < _cogl_texture_get_n_levels (texture), + 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; - } - - 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 18447f83e..9a308be57 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 3ae8ded3e..12e582024 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 5bc4e5f83..fbfd1982b 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 51997bd3a..ef9d72d9f 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; + tex_2ds->max_waste = max_waste; + tex_2ds->internal_format = internal_format; - /* Create slices for the given format and size */ - if (!_cogl_texture_2d_sliced_slices_create (ctx, - tex_2ds, - width, - height, - internal_format)) - return FALSE; - - 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 8d2cc4b90..e26157e6b 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. - * @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. + * 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. * - * Returns: A newly allocated #CoglTexture2DSliced or if there was - * an error allocating any of the internal slices %NULL is - * returned and @error is updated. + * @max_waste is used as a threshold for recursively slicing the + * 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. + * + * 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. + * + * 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 74ab1ab83..7492e128e 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 fcd86f77a..5a5ff2f54 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. + * * 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(). * - * 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 88f702665..22e572ebd 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 ab7c7e1a7..b40448a7f 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; - 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; + 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; + 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; + return FALSE; - internal_format = ctx->driver_vtable->pixel_format_to_gl (ctx, - internal_format, - &gl_intformat, - &gl_format, - &gl_type); + ctx->driver_vtable->pixel_format_to_gl (ctx, + tex_3d->internal_format, + &gl_intformat, + &gl_format, + &gl_type); - tex_3d = _cogl_texture_3d_create_base (ctx, - width, height, depth, - internal_format); - - 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 c2700efa4..0483d47fa 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. * - * Return value: a new #CoglTexture3D object or - * %NULL on failure and an exception will be returned - * in @error. + * 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. + * + * 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 6ff48605b..7e70e5efa 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 e6592a547..fe4dfe834 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 ee4cfcf0e..f8d0811e6 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; + tex_rect =_cogl_texture_rectangle_create_base (ctx, + width, height, + internal_format); + + /* 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; +} + +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; + if (!_cogl_texture_rectangle_can_create (ctx, - width, height, - internal_format, error)) - return NULL; + tex->width, + tex->height, + tex_rect->internal_format, + error)) + return FALSE; - internal_format = ctx->driver_vtable->pixel_format_to_gl (ctx, - internal_format, - &gl_intformat, - &gl_format, - &gl_type); + ctx->driver_vtable->pixel_format_to_gl (ctx, + tex_rect->internal_format, + &gl_intformat, + &gl_format, + &gl_type); - tex_rect = _cogl_texture_rectangle_create_base (ctx, - width, height, - internal_format); - - tex_rect->gl_texture = + 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 28d1f4cc9..1b97648ab 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 17658ead7..b744babe2 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. + * + * 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. + * + * 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 a0a50cfaa..043d047ec 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 d77f460e8..c71908fc0 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 4f57eed61..8bcfb93d5 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 bd12c81c8..141371eb9 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 b4d5efd3d..494b14eaa 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 40b101b26..7a782f9cf 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 2e79e667f..1aa558a15 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 948d62094..5831e2790 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 2b66414ea..71d00ea95 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 2bfa19085..a9f88e075 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 9a3c8b67f..9e66ab03f 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 26578d55a..5a4863b06 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 684327d55..9f3a4b4dd 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); }