summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bragg <robert@linux.intel.com>2013-06-23 16:18:18 +0100
committerRobert Bragg <robert@linux.intel.com>2014-01-01 17:43:06 +0000
commit6a83de9ef4210f380a31f410797447b365a8d02c (patch)
treeaa1870ebab7491422a4f06ca461bfbeb37681779
parent6ee425d4f10acd8b008a2c17e5c701fc1d850f59 (diff)
downloadcogl-6a83de9ef4210f380a31f410797447b365a8d02c.tar.gz
introduce texture loaders to make allocations lazy
This introduces the internal idea of texture loaders that track the state for loading and allocating a texture. This defers a lot more work until the texture is allocated. There are several intentions to this change: - provides a means for extending how textures are allocated without requiring all the parameters to be supplied in a single _texture_new() function call. - allow us to remove the internal_format argument from all _texture_new() apis since using CoglPixelFormat is bad way of expressing the internal format constraints because it is too specific. For now the internal_format arguments haven't actually been removed but this patch does introduce replacement apis for controlling the internal format: cogl_texture_set_components() lets you specify what components your texture needs when it is allocated. cogl_texture_set_premultiplied() lets you specify whether a texture data should be interpreted as premultiplied or not. - Enable us to support asynchronous texture loading + allocation in the future. Of note, the _new_from_data() texture constructors all continue to allocate textures immediately so that existing code doesn't need to be adapted to manage the lifetime of the data being uploaded. Reviewed-by: Neil Roberts <neil@linux.intel.com>
-rw-r--r--cogl/cogl-atlas-texture-private.h2
-rw-r--r--cogl/cogl-atlas-texture.c212
-rw-r--r--cogl/cogl-atlas-texture.h43
-rw-r--r--cogl/cogl-context.c54
-rw-r--r--cogl/cogl-driver.h25
-rw-r--r--cogl/cogl-sub-texture.c9
-rw-r--r--cogl/cogl-texture-2d-gl.h4
-rw-r--r--cogl/cogl-texture-2d-private.h3
-rw-r--r--cogl/cogl-texture-2d-sliced-private.h1
-rw-r--r--cogl/cogl-texture-2d-sliced.c378
-rw-r--r--cogl/cogl-texture-2d-sliced.h29
-rw-r--r--cogl/cogl-texture-2d.c105
-rw-r--r--cogl/cogl-texture-2d.h67
-rw-r--r--cogl/cogl-texture-3d.c362
-rw-r--r--cogl/cogl-texture-3d.h53
-rw-r--r--cogl/cogl-texture-private.h96
-rw-r--r--cogl/cogl-texture-rectangle.c245
-rw-r--r--cogl/cogl-texture-rectangle.h13
-rw-r--r--cogl/cogl-texture.c214
-rw-r--r--cogl/cogl-texture.h90
-rw-r--r--cogl/driver/gl/cogl-texture-2d-gl.c356
-rw-r--r--cogl/driver/gl/gl/cogl-driver-gl.c4
-rw-r--r--cogl/driver/gl/gles/cogl-driver-gles.c4
-rw-r--r--cogl/driver/nop/cogl-driver-nop.c4
-rw-r--r--cogl/driver/nop/cogl-texture-2d-nop-private.h16
-rw-r--r--cogl/driver/nop/cogl-texture-2d-nop.c30
-rw-r--r--cogl/winsys/cogl-texture-pixmap-x11.c17
-rw-r--r--examples/cogl-basic-video-player.c1
28 files changed, 1599 insertions, 838 deletions
diff --git a/cogl/cogl-atlas-texture-private.h b/cogl/cogl-atlas-texture-private.h
index ae5799da..9b226699 100644
--- a/cogl/cogl-atlas-texture-private.h
+++ b/cogl/cogl-atlas-texture-private.h
@@ -37,7 +37,7 @@ struct _CoglAtlasTexture
/* The format that the texture is in. This isn't necessarily the
same format as the atlas texture because we can store
pre-multiplied and non-pre-multiplied textures together */
- CoglPixelFormat format;
+ CoglPixelFormat internal_format;
/* The rectangle that was used to add this texture to the
atlas. This includes the 1-pixel border */
diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c
index e212a0de..93a24232 100644
--- a/cogl/cogl-atlas-texture.c
+++ b/cogl/cogl-atlas-texture.c
@@ -380,7 +380,7 @@ _cogl_atlas_texture_migrate_out_of_atlas (CoglAtlasTexture *atlas_tex)
atlas_tex->rectangle.y + 1,
atlas_tex->rectangle.width - 2,
atlas_tex->rectangle.height - 2,
- atlas_tex->format);
+ atlas_tex->internal_format);
/* Note: we simply silently ignore failures to migrate a texture
* out (most likely due to lack of memory) and hope for the
* best.
@@ -511,10 +511,10 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
static CoglBitmap *
_cogl_atlas_texture_convert_bitmap_for_upload (CoglAtlasTexture *atlas_tex,
CoglBitmap *bmp,
+ CoglPixelFormat internal_format,
CoglBool can_convert_in_place,
CoglError **error)
{
- CoglPixelFormat internal_format;
CoglBitmap *upload_bmp;
CoglBitmap *override_bmp;
@@ -527,7 +527,7 @@ _cogl_atlas_texture_convert_bitmap_for_upload (CoglAtlasTexture *atlas_tex,
orignal format so we do need to trigger the conversion */
internal_format = (COGL_PIXEL_FORMAT_RGBA_8888 |
- (atlas_tex->format & COGL_PREMULT_BIT));
+ (internal_format & COGL_PREMULT_BIT));
upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
internal_format,
@@ -578,6 +578,7 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
CoglBitmap *upload_bmp =
_cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex,
bmp,
+ atlas_tex->internal_format,
FALSE, /* can't convert
in place */
error);
@@ -615,7 +616,7 @@ _cogl_atlas_texture_get_format (CoglTexture *tex)
/* We don't want to forward this on the sub-texture because it isn't
the necessarily the same format. This will happen if the texture
isn't pre-multiplied */
- return atlas_tex->format;
+ return atlas_tex->internal_format;
}
static GLenum
@@ -641,24 +642,20 @@ _cogl_atlas_texture_can_use_format (CoglPixelFormat format)
format == COGL_PIXEL_FORMAT_RGBA_8888);
}
-CoglAtlasTexture *
-cogl_atlas_texture_new_with_size (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat internal_format,
- CoglError **error)
+static CoglAtlasTexture *
+_cogl_atlas_texture_create_base (CoglContext *ctx,
+ int width,
+ int height,
+ CoglPixelFormat internal_format,
+ CoglTextureLoader *loader)
{
CoglAtlasTexture *atlas_tex;
- /* We can't atlas zero-sized textures because it breaks the atlas
- * data structure */
- _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL);
-
COGL_NOTE (ATLAS, "Adding texture of size %ix%i", width, height);
/* We need to allocate the texture now because we need the pointer
to set as the data for the rectangle in the atlas */
- atlas_tex = g_new (CoglAtlasTexture, 1);
+ atlas_tex = g_new0 (CoglAtlasTexture, 1);
/* Mark it as having no atlas so we don't try to unref it in
_cogl_atlas_texture_post_reorganize_cb */
atlas_tex->atlas = NULL;
@@ -666,27 +663,53 @@ cogl_atlas_texture_new_with_size (CoglContext *ctx,
_cogl_texture_init (COGL_TEXTURE (atlas_tex),
ctx,
width, height,
+ internal_format,
+ loader,
&cogl_atlas_texture_vtable);
atlas_tex->sub_texture = NULL;
- atlas_tex->format = internal_format;
atlas_tex->atlas = NULL;
return _cogl_atlas_texture_object_new (atlas_tex);
}
+CoglAtlasTexture *
+cogl_atlas_texture_new_with_size (CoglContext *ctx,
+ int width,
+ int height,
+ CoglPixelFormat internal_format,
+ CoglError **error)
+{
+ CoglTextureLoader *loader;
+
+ /* We can't atlas zero-sized textures because it breaks the atlas
+ * data structure */
+ _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL);
+
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
+ loader->src.sized.width = width;
+ loader->src.sized.height = height;
+
+ return _cogl_atlas_texture_create_base (ctx, width, height,
+ internal_format, loader);
+}
+
static CoglBool
-_cogl_atlas_texture_allocate (CoglTexture *tex,
- CoglError **error)
+allocate_space (CoglAtlasTexture *atlas_tex,
+ int width,
+ int height,
+ CoglPixelFormat internal_format,
+ CoglError **error)
{
+ CoglTexture *tex = COGL_TEXTURE (atlas_tex);
CoglContext *ctx = tex->context;
- CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
CoglAtlas *atlas;
GSList *l;
/* If the texture is in a strange format then we won't use it */
- if (!_cogl_atlas_texture_can_use_format (atlas_tex->format))
+ if (!_cogl_atlas_texture_can_use_format (internal_format))
{
COGL_NOTE (ATLAS, "Texture can not be added because the "
"format is unsupported");
@@ -714,7 +737,7 @@ _cogl_atlas_texture_allocate (CoglTexture *tex,
/* 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 */
- tex->width + 2, tex->height + 2,
+ width + 2, height + 2,
atlas_tex))
{
cogl_object_ref (atlas);
@@ -728,7 +751,7 @@ _cogl_atlas_texture_allocate (CoglTexture *tex,
COGL_NOTE (ATLAS, "Created new atlas for textures: %p", atlas);
if (!_cogl_atlas_reserve_space (atlas,
/* Add two pixels for the border */
- tex->width + 2, tex->height + 2,
+ width + 2, height + 2,
atlas_tex))
{
/* Ok, this means we really can't add it to the atlas */
@@ -742,55 +765,73 @@ _cogl_atlas_texture_allocate (CoglTexture *tex,
}
}
+ atlas_tex->internal_format = internal_format;
+
atlas_tex->atlas = atlas;
return TRUE;
}
-CoglAtlasTexture *
-_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
- CoglPixelFormat internal_format,
- CoglBool can_convert_in_place,
- CoglError **error)
+static CoglBool
+allocate_with_size (CoglAtlasTexture *atlas_tex,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
- CoglContext *ctx = _cogl_bitmap_get_context (bmp);
- CoglAtlasTexture *atlas_tex;
- CoglBitmap *upload_bmp;
- int bmp_width;
- int bmp_height;
- CoglPixelFormat bmp_format;
+ CoglTexture *tex = COGL_TEXTURE (atlas_tex);
+ CoglPixelFormat internal_format =
+ _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
+
+ if (allocate_space (atlas_tex,
+ loader->src.sized.width,
+ loader->src.sized.height,
+ internal_format,
+ error))
+ {
+ _cogl_texture_set_allocated (COGL_TEXTURE (atlas_tex),
+ internal_format,
+ loader->src.sized.width,
+ loader->src.sized.height);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
- _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
+static CoglBool
+allocate_from_bitmap (CoglAtlasTexture *atlas_tex,
+ CoglTextureLoader *loader,
+ CoglError **error)
+{
+ CoglTexture *tex = COGL_TEXTURE (atlas_tex);
+ CoglBitmap *bmp = loader->src.bitmap.bitmap;
+ CoglPixelFormat bmp_format = cogl_bitmap_get_format (bmp);
+ int width = cogl_bitmap_get_width (bmp);
+ int height = cogl_bitmap_get_height (bmp);
+ CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place;
+ CoglPixelFormat internal_format;
+ CoglBitmap *upload_bmp;
- bmp_width = cogl_bitmap_get_width (bmp);
- bmp_height = cogl_bitmap_get_height (bmp);
- bmp_format = cogl_bitmap_get_format (bmp);
+ _COGL_RETURN_VAL_IF_FAIL (atlas_tex->atlas == NULL, FALSE);
- internal_format = _cogl_texture_determine_internal_format (bmp_format,
- internal_format);
-
- atlas_tex = cogl_atlas_texture_new_with_size (ctx,
- bmp_width, bmp_height,
- internal_format,
- error);
- if (!atlas_tex)
- return NULL;
-
- if (!cogl_texture_allocate (COGL_TEXTURE (atlas_tex), error))
- {
- cogl_object_unref (atlas_tex);
- return NULL;
- }
+ internal_format = _cogl_texture_determine_internal_format (tex, bmp_format);
upload_bmp =
_cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex,
bmp,
+ internal_format,
can_convert_in_place,
error);
if (upload_bmp == NULL)
+ return FALSE;
+
+ if (!allocate_space (atlas_tex,
+ width,
+ height,
+ internal_format,
+ error))
{
- cogl_object_unref (atlas_tex);
- return NULL;
+ cogl_object_unref (upload_bmp);
+ return FALSE;
}
/* Defer to set_region so that we can share the code for copying the
@@ -800,19 +841,65 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
0, /* src_y */
0, /* dst_x */
0, /* dst_y */
- bmp_width, /* dst_width */
- bmp_height, /* dst_height */
+ width, /* dst_width */
+ height, /* dst_height */
upload_bmp,
error))
{
+ _cogl_atlas_texture_remove_from_atlas (atlas_tex);
cogl_object_unref (upload_bmp);
- cogl_object_unref (atlas_tex);
- return NULL;
+ return FALSE;
}
cogl_object_unref (upload_bmp);
- return atlas_tex;
+ _cogl_texture_set_allocated (tex, internal_format, width, height);
+
+ return TRUE;
+}
+
+static CoglBool
+_cogl_atlas_texture_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
+ CoglTextureLoader *loader = tex->loader;
+
+ _COGL_RETURN_VAL_IF_FAIL (loader, FALSE);
+
+ switch (loader->src_type)
+ {
+ case COGL_TEXTURE_SOURCE_TYPE_SIZED:
+ return allocate_with_size (atlas_tex, loader, error);
+ case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
+ return allocate_from_bitmap (atlas_tex, loader, error);
+ default:
+ break;
+ }
+
+ g_return_val_if_reached (FALSE);
+}
+
+CoglAtlasTexture *
+_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
+ CoglPixelFormat internal_format,
+ CoglBool can_convert_in_place,
+ CoglError **error)
+{
+ CoglTextureLoader *loader;
+
+ _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
+
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP;
+ loader->src.bitmap.bitmap = cogl_object_ref (bmp);
+ loader->src.bitmap.can_convert_in_place = can_convert_in_place;
+
+ return _cogl_atlas_texture_create_base (_cogl_bitmap_get_context (bmp),
+ cogl_bitmap_get_width (bmp),
+ cogl_bitmap_get_height (bmp),
+ internal_format,
+ loader);
}
CoglAtlasTexture *
@@ -855,6 +942,13 @@ cogl_atlas_texture_new_from_data (CoglContext *ctx,
cogl_object_unref (bmp);
+ if (atlas_tex &&
+ !cogl_texture_allocate (COGL_TEXTURE (atlas_tex), error))
+ {
+ cogl_object_unref (atlas_tex);
+ return NULL;
+ }
+
return atlas_tex;
}
diff --git a/cogl/cogl-atlas-texture.h b/cogl/cogl-atlas-texture.h
index 4e8623da..53803c63 100644
--- a/cogl/cogl-atlas-texture.h
+++ b/cogl/cogl-atlas-texture.h
@@ -78,6 +78,11 @@ typedef struct _CoglAtlasTexture CoglAtlasTexture;
* allocate the underlying storage or let Cogl automatically allocate
* storage lazily.
*
+ * The texture is still configurable until it has been allocated so
+ * for example you can influence the internal format of the texture
+ * using cogl_texture_set_components() and
+ * cogl_texture_set_premultiplied().
+ *
* <note>This call can fail if Cogl considers the given
* @internal_format incompatible with the format of its internal
* atlases.</note>
@@ -109,7 +114,17 @@ cogl_atlas_texture_new_with_size (CoglContext *ctx,
* represents a sub-region within one of Cogl's shared texture
* atlases.
*
- * <note>This call can fail if Cogl considers the given
+ * 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.
+ *
+ * The texture is still configurable until it has been allocated so
+ * for example you can influence the internal format of the texture
+ * using cogl_texture_set_components() and
+ * cogl_texture_set_premultiplied().
+ *
+ * <note>Allocation can fail later if Cogl considers the given
* @internal_format incompatible with the format of its internal
* atlases.</note>
*
@@ -152,7 +167,18 @@ cogl_atlas_texture_new_from_file (CoglContext *ctx,
* memory. A #CoglAtlasTexture represents a sub-region within one of
* Cogl's shared texture atlases.
*
- * <note>This call can fail if Cogl considers the given
+ * <note>This api will always immediately allocate GPU memory for the
+ * texture and upload the given data so that the @data pointer does
+ * not need to remain valid once this function returns. This means it
+ * is not possible to configure the texture before it is allocated. If
+ * you do need to configure the texture before allocation (to specify
+ * constraints on the internal format for example) then you can
+ * instead create a #CoglBitmap for your data and use
+ * cogl_atlas_texture_new_from_bitmap() or use
+ * cogl_atlas_texture_new_with_size() and then upload data using
+ * cogl_texture_set_data()</note>
+ *
+ * <note>Allocation can fail if Cogl considers the given
* @internal_format incompatible with the format of its internal
* atlases.</note>
*
@@ -192,7 +218,18 @@ cogl_atlas_texture_new_from_data (CoglContext *ctx,
* @bitmap. A #CoglAtlasTexture represents a sub-region within one of
* Cogl's shared texture atlases.
*
- * <note>This call can fail if Cogl considers the given
+ * 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.
+ *
+ * The texture is still configurable until it has been allocated so
+ * for example you can influence the internal format of the texture
+ * using cogl_texture_set_components() and
+ * cogl_texture_set_premultiplied().
+ *
+ * <note>Allocation can fail if Cogl considers the given
* @internal_format incompatible with the format of its internal
* atlases.</note>
*
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index e4453f92..4e2e0b0d 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -126,8 +126,8 @@ cogl_context_new (CoglDisplay *display,
CoglError **error)
{
CoglContext *context;
- uint8_t default_texture_data[] = { 0xff, 0xff, 0xff, 0xff };
- CoglBitmap *default_texture_bitmap;
+ uint8_t white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
+ CoglBitmap *white_pixel_bitmap;
const CoglWinsysVtable *winsys;
int i;
CoglError *internal_error = NULL;
@@ -381,41 +381,53 @@ cogl_context_new (CoglDisplay *display,
_cogl_matrix_entry_cache_init (&context->builtin_flushed_projection);
_cogl_matrix_entry_cache_init (&context->builtin_flushed_modelview);
- default_texture_bitmap =
- cogl_bitmap_new_for_data (context,
- 1, 1, /* width/height */
- COGL_PIXEL_FORMAT_RGBA_8888_PRE,
- 4, /* rowstride */
- default_texture_data);
-
/* Create default textures used for fall backs */
context->default_gl_texture_2d_tex =
- cogl_texture_2d_new_from_bitmap (default_texture_bitmap,
- /* internal format */
- COGL_PIXEL_FORMAT_RGBA_8888_PRE,
- NULL);
+ cogl_texture_2d_new_from_data (context,
+ 1, 1,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 0, /* rowstride */
+ white_pixel,
+ NULL); /* abort on error */
/* If 3D or rectangle textures aren't supported then these will
* return errors that we can simply ignore. */
internal_error = NULL;
context->default_gl_texture_3d_tex =
- cogl_texture_3d_new_from_bitmap (default_texture_bitmap,
- 1, /* height */
- 1, /* depth */
- COGL_PIXEL_FORMAT_RGBA_8888_PRE,
- &internal_error);
+ cogl_texture_3d_new_from_data (context,
+ 1, 1, 1, /* width, height, depth */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 0, /* rowstride */
+ 0, /* image stride */
+ white_pixel,
+ &internal_error);
if (internal_error)
cogl_error_free (internal_error);
+ /* TODO: add cogl_texture_rectangle_new_from_data() */
+ white_pixel_bitmap =
+ cogl_bitmap_new_for_data (context,
+ 1, 1, /* width/height */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 4, /* rowstride */
+ white_pixel);
+
internal_error = NULL;
context->default_gl_texture_rect_tex =
- cogl_texture_rectangle_new_from_bitmap (default_texture_bitmap,
+ cogl_texture_rectangle_new_from_bitmap (white_pixel_bitmap,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
- &internal_error);
+ NULL); /* legacy error argument */
+
+ /* XXX: we need to allocate the texture now because the white_pixel
+ * data is on the stack */
+ cogl_texture_allocate (COGL_TEXTURE (context->default_gl_texture_rect_tex),
+ &internal_error);
if (internal_error)
cogl_error_free (internal_error);
- cogl_object_unref (default_texture_bitmap);
+ cogl_object_unref (white_pixel_bitmap);
context->atlases = NULL;
g_hook_list_init (&context->atlas_reorganize_callbacks, sizeof (GHook));
diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h
index 4642236c..7a562d54 100644
--- a/cogl/cogl-driver.h
+++ b/cogl/cogl-driver.h
@@ -141,31 +141,6 @@ struct _CoglDriverVtable
(* 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
- * internal format.
- */
- CoglTexture2D *
- (* texture_2d_new_from_bitmap) (CoglBitmap *bmp,
- CoglPixelFormat internal_format,
- CoglBool can_convert_in_place,
- CoglError **error);
-
-#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
- /* Instantiates a new CoglTexture2D object with storage initialized
- * with the contents of the given EGL image.
- *
- * This is optional for drivers to support
- */
- CoglTexture2D *
- (* egl_texture_2d_new_from_image) (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat format,
- EGLImageKHR image,
- CoglError **error);
-#endif
-
/* Initialize the specified region of storage of the given texture
* with the contents of the specified framebuffer region
*/
diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl-sub-texture.c
index 7bda7f0d..8c446b0e 100644
--- a/cogl/cogl-sub-texture.c
+++ b/cogl/cogl-sub-texture.c
@@ -235,6 +235,8 @@ cogl_sub_texture_new (CoglContext *ctx,
tex = COGL_TEXTURE (sub_tex);
_cogl_texture_init (tex, ctx, sub_width, sub_height,
+ _cogl_texture_get_format (next_texture),
+ NULL, /* no loader */
&cogl_sub_texture_vtable);
/* If the next texture is also a sub texture we can avoid one level
@@ -264,8 +266,13 @@ _cogl_sub_texture_allocate (CoglTexture *tex,
CoglError **error)
{
CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
+ CoglBool status = cogl_texture_allocate (sub_tex->full_texture, error);
- return cogl_texture_allocate (sub_tex->full_texture, error);
+ _cogl_texture_set_allocated (tex,
+ _cogl_texture_get_format (sub_tex->full_texture),
+ tex->width, tex->height);
+
+ return status;
}
CoglTexture *
diff --git a/cogl/cogl-texture-2d-gl.h b/cogl/cogl-texture-2d-gl.h
index 2686c6d0..d635e50a 100644
--- a/cogl/cogl-texture-2d-gl.h
+++ b/cogl/cogl-texture-2d-gl.h
@@ -49,6 +49,10 @@ COGL_BEGIN_DECLS
* This can be used for integrating Cogl with software using OpenGL
* directly.
*
+ * The texture is still configurable until it has been allocated so
+ * for example you can declare whether the texture is premultiplied
+ * with cogl_texture_set_premultiplied().
+ *
* <note>The results are undefined for passing an invalid @gl_handle
* or if @width or @height don't have the correct texture
* geometry.</note>
diff --git a/cogl/cogl-texture-2d-private.h b/cogl/cogl-texture-2d-private.h
index 5d193bce..3d6c3c5b 100644
--- a/cogl/cogl-texture-2d-private.h
+++ b/cogl/cogl-texture-2d-private.h
@@ -82,7 +82,8 @@ CoglTexture2D *
_cogl_texture_2d_create_base (CoglContext *ctx,
int width,
int height,
- CoglPixelFormat internal_format);
+ CoglPixelFormat internal_format,
+ CoglTextureLoader *loader);
void
_cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,
diff --git a/cogl/cogl-texture-2d-sliced-private.h b/cogl/cogl-texture-2d-sliced-private.h
index 3ceedcbe..8e8e69ca 100644
--- a/cogl/cogl-texture-2d-sliced-private.h
+++ b/cogl/cogl-texture-2d-sliced-private.h
@@ -34,6 +34,7 @@
struct _CoglTexture2DSliced
{
CoglTexture _parent;
+
GArray *slice_x_spans;
GArray *slice_y_spans;
GArray *slice_textures;
diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c
index a90c0806..e79a2dbd 100644
--- a/cogl/cogl-texture-2d-sliced.c
+++ b/cogl/cogl-texture-2d-sliced.c
@@ -659,14 +659,30 @@ _cogl_texture_2d_sliced_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
}
}
+static void
+free_spans (CoglTexture2DSliced *tex_2ds)
+{
+ if (tex_2ds->slice_x_spans != NULL)
+ {
+ g_array_free (tex_2ds->slice_x_spans, TRUE);
+ tex_2ds->slice_x_spans = NULL;
+ }
+
+ if (tex_2ds->slice_y_spans != NULL)
+ {
+ g_array_free (tex_2ds->slice_y_spans, TRUE);
+ tex_2ds->slice_y_spans = NULL;
+ }
+}
+
static CoglBool
-_cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
- CoglTexture2DSliced *tex_2ds,
- int width,
- int height,
- int max_waste,
- CoglPixelFormat internal_format,
- CoglError **error)
+setup_spans (CoglContext *ctx,
+ CoglTexture2DSliced *tex_2ds,
+ int width,
+ int height,
+ int max_waste,
+ CoglPixelFormat internal_format,
+ CoglError **error)
{
int max_width;
int max_height;
@@ -754,8 +770,8 @@ _cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
COGL_TEXTURE_ERROR,
COGL_TEXTURE_ERROR_SIZE,
"No suitable slice geometry found");
+ free_spans (tex_2ds);
return FALSE;
-
}
}
@@ -791,7 +807,7 @@ _cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
}
static void
-_cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds)
+free_slices (CoglTexture2DSliced *tex_2ds)
{
if (tex_2ds->slice_textures != NULL)
{
@@ -806,111 +822,36 @@ _cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds)
g_array_free (tex_2ds->slice_textures, TRUE);
}
-}
-
-static void
-_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));
+ free_spans (tex_2ds);
}
static CoglBool
-_cogl_texture_2d_sliced_init_base (CoglContext *ctx,
- CoglTexture2DSliced *tex_2ds,
- int width,
- int height,
- int max_waste,
- CoglPixelFormat internal_format,
- CoglError **error)
+allocate_slices (CoglTexture2DSliced *tex_2ds,
+ int width,
+ int height,
+ 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->max_waste = max_waste;
- tex_2ds->internal_format = internal_format;
-
- 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,
- int width,
- int height,
- int max_waste,
- CoglPixelFormat internal_format)
-{
- 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_new0 (CoglTexture2DSliced, 1);
-
- if (!_cogl_texture_2d_sliced_init_base (ctx,
- tex_2ds,
- width, height,
- max_waste,
- internal_format,
- &ignore_error))
- {
- /* 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)
+ tex_2ds->internal_format = internal_format;
+
+ if (!setup_spans (ctx, tex_2ds,
+ width,
+ height,
+ max_waste,
+ internal_format,
+ error))
{
- _cogl_set_error (error,
- COGL_TEXTURE_ERROR,
- COGL_TEXTURE_ERROR_SIZE,
- "Couldn't find suitable slicing geometry "
- "for given size");
return FALSE;
}
@@ -941,11 +882,11 @@ _cogl_texture_2d_sliced_allocate (CoglTexture *tex,
slice = COGL_TEXTURE (
cogl_texture_2d_new_with_size (ctx,
x_span->size, y_span->size,
- format));
+ internal_format));
g_array_append_val (tex_2ds->slice_textures, slice);
if (!cogl_texture_allocate (slice, error))
{
- _cogl_texture_2d_sliced_slices_free (tex_2ds);
+ free_slices (tex_2ds);
return FALSE;
}
}
@@ -954,68 +895,82 @@ _cogl_texture_2d_sliced_allocate (CoglTexture *tex,
return TRUE;
}
-CoglTexture2DSliced *
-_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
- int max_waste,
- CoglPixelFormat internal_format,
- CoglBool can_convert_in_place,
- CoglError **error)
+static void
+_cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
{
- CoglContext *ctx;
- CoglTexture2DSliced *tex_2ds;
- CoglBitmap *upload_bmp;
- int width, height;
+ free_slices (tex_2ds);
- _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
+ /* Chain up */
+ _cogl_texture_free (COGL_TEXTURE (tex_2ds));
+}
- ctx = _cogl_bitmap_get_context (bmp);
+static CoglTexture2DSliced *
+_cogl_texture_2d_sliced_create_base (CoglContext *ctx,
+ int width,
+ int height,
+ int max_waste,
+ CoglPixelFormat internal_format,
+ CoglTextureLoader *loader)
+{
+ CoglTexture2DSliced *tex_2ds = g_new0 (CoglTexture2DSliced, 1);
- width = cogl_bitmap_get_width (bmp);
- height = cogl_bitmap_get_height (bmp);
+ _cogl_texture_init (COGL_TEXTURE (tex_2ds), ctx, width, height,
+ internal_format, loader,
+ &cogl_texture_2d_sliced_vtable);
- /* Create new texture and fill with loaded data */
- tex_2ds = g_new0 (CoglTexture2DSliced, 1);
+ tex_2ds->max_waste = max_waste;
- internal_format =
- _cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp),
- internal_format);
+ return _cogl_texture_2d_sliced_object_new (tex_2ds);
+}
- upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
- internal_format,
- can_convert_in_place,
- error);
- if (upload_bmp == NULL)
- {
- _cogl_texture_2d_sliced_free (tex_2ds);
- return NULL;
- }
+CoglTexture2DSliced *
+cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
+ int width,
+ int height,
+ int max_waste,
+ CoglPixelFormat internal_format)
+{
+ CoglTextureLoader *loader;
- /* 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,
- max_waste,
- internal_format,
- error))
- goto 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_allocate (COGL_TEXTURE (tex_2ds), error))
- goto error;
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
+ loader->src.sized.width = width;
+ loader->src.sized.height = height;
- if (!_cogl_texture_2d_sliced_upload_bitmap (tex_2ds,
- upload_bmp,
- error))
- goto error;
+ return _cogl_texture_2d_sliced_create_base (ctx,
+ width,
+ height,
+ max_waste,
+ internal_format,
+ loader);
+}
- cogl_object_unref (upload_bmp);
+CoglTexture2DSliced *
+_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
+ int max_waste,
+ CoglPixelFormat internal_format,
+ CoglBool can_convert_in_place,
+ CoglError **error)
+{
+ CoglTextureLoader *loader;
- return _cogl_texture_2d_sliced_object_new (tex_2ds);
+ _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
- error:
- cogl_object_unref (upload_bmp);
- _cogl_texture_2d_sliced_free (tex_2ds);
- return NULL;
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP;
+ loader->src.bitmap.bitmap = cogl_object_ref (bmp);
+ loader->src.bitmap.can_convert_in_place = can_convert_in_place;
+
+ return _cogl_texture_2d_sliced_create_base (_cogl_bitmap_get_context (bmp),
+ cogl_bitmap_get_width (bmp),
+ cogl_bitmap_get_height (bmp),
+ max_waste,
+ internal_format,
+ loader);
}
CoglTexture2DSliced *
@@ -1065,6 +1020,13 @@ cogl_texture_2d_sliced_new_from_data (CoglContext *ctx,
cogl_object_unref (bmp);
+ if (tex_2ds &&
+ !cogl_texture_allocate (COGL_TEXTURE (tex_2ds), error))
+ {
+ cogl_object_unref (tex_2ds);
+ return NULL;
+ }
+
return tex_2ds;
}
@@ -1096,6 +1058,107 @@ cogl_texture_2d_sliced_new_from_file (CoglContext *ctx,
}
static CoglBool
+allocate_with_size (CoglTexture2DSliced *tex_2ds,
+ CoglTextureLoader *loader,
+ CoglError **error)
+{
+ CoglTexture *tex = COGL_TEXTURE (tex_2ds);
+ CoglPixelFormat internal_format =
+ _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
+
+ if (allocate_slices (tex_2ds,
+ loader->src.sized.width,
+ loader->src.sized.height,
+ tex_2ds->max_waste,
+ internal_format,
+ error))
+ {
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_2ds),
+ internal_format,
+ loader->src.sized.width,
+ loader->src.sized.height);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static CoglBool
+allocate_from_bitmap (CoglTexture2DSliced *tex_2ds,
+ CoglTextureLoader *loader,
+ CoglError **error)
+{
+ CoglTexture *tex = COGL_TEXTURE (tex_2ds);
+ CoglBitmap *bmp = loader->src.bitmap.bitmap;
+ int width = cogl_bitmap_get_width (bmp);
+ int height = cogl_bitmap_get_height (bmp);
+ CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place;
+ CoglPixelFormat internal_format;
+ CoglBitmap *upload_bmp;
+
+ _COGL_RETURN_VAL_IF_FAIL (tex_2ds->slice_textures == NULL, FALSE);
+
+ internal_format =
+ _cogl_texture_determine_internal_format (tex,
+ cogl_bitmap_get_format (bmp));
+
+ upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
+ internal_format,
+ can_convert_in_place,
+ error);
+ if (upload_bmp == NULL)
+ return FALSE;
+
+ if (!allocate_slices (tex_2ds,
+ width,
+ height,
+ tex_2ds->max_waste,
+ internal_format,
+ error))
+ {
+ cogl_object_unref (upload_bmp);
+ return FALSE;
+ }
+
+ if (!_cogl_texture_2d_sliced_upload_bitmap (tex_2ds,
+ upload_bmp,
+ error))
+ {
+ free_slices (tex_2ds);
+ cogl_object_unref (upload_bmp);
+ return FALSE;
+ }
+
+ cogl_object_unref (upload_bmp);
+
+ _cogl_texture_set_allocated (tex, internal_format, width, height);
+
+ return TRUE;
+}
+
+static CoglBool
+_cogl_texture_2d_sliced_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
+ CoglTextureLoader *loader = tex->loader;
+
+ _COGL_RETURN_VAL_IF_FAIL (loader, FALSE);
+
+ switch (loader->src_type)
+ {
+ case COGL_TEXTURE_SOURCE_TYPE_SIZED:
+ return allocate_with_size (tex_2ds, loader, error);
+ case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
+ return allocate_from_bitmap (tex_2ds, loader, error);
+ default:
+ break;
+ }
+
+ g_return_val_if_reached (FALSE);
+}
+
+static CoglBool
_cogl_texture_2d_sliced_is_foreign (CoglTexture *tex)
{
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
@@ -1115,17 +1178,10 @@ _cogl_texture_2d_sliced_is_sliced (CoglTexture *tex)
{
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
- /* 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;
+ /* It's only after allocating a sliced texture that we will know
+ * whether it really needed to be sliced... */
+ if (!tex->allocated)
+ cogl_texture_allocate (tex, NULL);
if (tex_2ds->slice_x_spans->len != 1 ||
tex_2ds->slice_y_spans->len != 1)
diff --git a/cogl/cogl-texture-2d-sliced.h b/cogl/cogl-texture-2d-sliced.h
index f6fdc975..c52d5d6d 100644
--- a/cogl/cogl-texture-2d-sliced.h
+++ b/cogl/cogl-texture-2d-sliced.h
@@ -147,6 +147,11 @@ cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
* 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 is
@@ -206,11 +211,22 @@ cogl_texture_2d_sliced_new_from_file (CoglContext *ctx,
* wasted padding at the bottom and right of the textures is less than
* specified. A negative @max_waste will disable slicing.
*
+ * <note>This api will always immediately allocate GPU memory for all
+ * the required texture slices and upload the given data so that the
+ * @data pointer does not need to remain valid once this function
+ * returns. This means it is not possible to configure the texture
+ * before it is allocated. If you do need to configure the texture
+ * before allocation (to specify constraints on the internal format
+ * for example) then you can instead create a #CoglBitmap for your
+ * data and use cogl_texture_2d_sliced_new_from_bitmap() or use
+ * cogl_texture_2d_sliced_new_with_size() and then upload data using
+ * cogl_texture_set_data()</note>
+ *
* <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 is
- * larger than is supported by the hardware but slicing is disabled
- * the texture size would be too large to handle.</note>
+ * due to impossible slicing constraints if a negative @max_waste
+ * value is given. If the given virtual texture size is larger than is
+ * supported by the hardware but slicing is disabled the texture size
+ * would be too large to handle.</note>
*
* Return value: (transfer full): A newly created #CoglTexture2DSliced
* or %NULL on failure and @error will be updated.
@@ -262,6 +278,11 @@ cogl_texture_2d_sliced_new_from_data (CoglContext *ctx,
* 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 is
diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c
index a238097a..3a725cd0 100644
--- a/cogl/cogl-texture-2d.c
+++ b/cogl/cogl-texture-2d.c
@@ -75,25 +75,6 @@ _cogl_texture_2d_free (CoglTexture2D *tex_2d)
_cogl_texture_free (COGL_TEXTURE (tex_2d));
}
-static CoglBool
-_cogl_texture_2d_can_create (CoglContext *ctx,
- unsigned int width,
- unsigned int height,
- CoglPixelFormat internal_format)
-{
- /* If NPOT textures aren't supported then the size must be a power
- of two */
- if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
- (!_cogl_util_is_pot (width) ||
- !_cogl_util_is_pot (height)))
- return FALSE;
-
- return ctx->driver_vtable->texture_2d_can_create (ctx,
- width,
- height,
- internal_format);
-}
-
void
_cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,
CoglBool value)
@@ -107,20 +88,20 @@ CoglTexture2D *
_cogl_texture_2d_create_base (CoglContext *ctx,
int width,
int height,
- CoglPixelFormat internal_format)
+ CoglPixelFormat internal_format,
+ CoglTextureLoader *loader)
{
CoglTexture2D *tex_2d = g_new (CoglTexture2D, 1);
CoglTexture *tex = COGL_TEXTURE (tex_2d);
- _cogl_texture_init (tex, ctx, width, height, &cogl_texture_2d_vtable);
+ _cogl_texture_init (tex, ctx, width, height, internal_format, loader,
+ &cogl_texture_2d_vtable);
tex_2d->mipmaps_dirty = TRUE;
tex_2d->auto_mipmap = TRUE;
tex_2d->is_foreign = FALSE;
- tex_2d->internal_format = internal_format;
-
ctx->driver_vtable->texture_2d_init (tex_2d);
return _cogl_texture_2d_object_new (tex_2d);
@@ -132,13 +113,19 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
int height,
CoglPixelFormat internal_format)
{
+ CoglTextureLoader *loader;
+
/* 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_2d_create_base (ctx,
- width, height,
- internal_format);
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
+ loader->src.sized.width = width;
+ loader->src.sized.height = height;
+
+ return _cogl_texture_2d_create_base (ctx, width, height,
+ internal_format, loader);
}
static CoglBool
@@ -146,6 +133,7 @@ _cogl_texture_2d_allocate (CoglTexture *tex,
CoglError **error)
{
CoglContext *ctx = tex->context;
+
return ctx->driver_vtable->texture_2d_allocate (tex, error);
}
@@ -155,32 +143,20 @@ _cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
CoglBool can_convert_in_place,
CoglError **error)
{
- CoglContext *ctx;
+ CoglTextureLoader *loader;
_COGL_RETURN_VAL_IF_FAIL (bmp != NULL, NULL);
- ctx = _cogl_bitmap_get_context (bmp);
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP;
+ loader->src.bitmap.bitmap = cogl_object_ref (bmp);
+ loader->src.bitmap.can_convert_in_place = can_convert_in_place;
- internal_format =
- _cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp),
- internal_format);
-
- if (!_cogl_texture_2d_can_create (ctx,
- cogl_bitmap_get_width (bmp),
- cogl_bitmap_get_height (bmp),
- 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 ctx->driver_vtable->texture_2d_new_from_bitmap (bmp,
- internal_format,
- can_convert_in_place,
- error);
+ return _cogl_texture_2d_create_base (_cogl_bitmap_get_context (bmp),
+ cogl_bitmap_get_width (bmp),
+ cogl_bitmap_get_height (bmp),
+ internal_format,
+ loader);
}
CoglTexture2D *
@@ -249,6 +225,13 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
cogl_object_unref (bmp);
+ if (tex_2d &&
+ !cogl_texture_allocate (COGL_TEXTURE (tex_2d), error))
+ {
+ cogl_object_unref (tex_2d);
+ return NULL;
+ }
+
return tex_2d;
}
@@ -264,6 +247,8 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
EGLImageKHR image,
CoglError **error)
{
+ CoglTextureLoader *loader;
+
_COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
COGL_RENDERER_CONSTRAINT_USES_EGL,
NULL);
@@ -273,22 +258,14 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE),
NULL);
- if (ctx->driver_vtable->egl_texture_2d_new_from_image)
- return ctx->driver_vtable->egl_texture_2d_new_from_image (ctx,
- width,
- height,
- format,
- image,
- error);
- else
- {
- _cogl_set_error (error,
- COGL_SYSTEM_ERROR,
- COGL_SYSTEM_ERROR_UNSUPPORTED,
- "Creating 2D textures from EGL images is not "
- "supported by the current driver");
- return NULL;
- }
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE;
+ loader->src.egl_image.image = image;
+ loader->src.egl_image.width = width;
+ loader->src.egl_image.height = height;
+ loader->src.egl_image.format = format;
+
+ return _cogl_texture_2d_create_base (ctx, width, height, format, loader);
}
#endif /* defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) */
diff --git a/cogl/cogl-texture-2d.h b/cogl/cogl-texture-2d.h
index 75267551..9b985c77 100644
--- a/cogl/cogl-texture-2d.h
+++ b/cogl/cogl-texture-2d.h
@@ -3,7 +3,7 @@
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
- * Copyright (C) 2011 Intel Corporation.
+ * Copyright (C) 2011,2013 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -75,11 +75,8 @@ cogl_is_texture_2d (void *object);
* @height: Height of the texture to allocate
* @internal_format: The format of the texture
*
- * Allocates a low-level #CoglTexture2D texture that your GPU can
- * texture from directly. This is unlike sliced textures for example
- * which may be comprised of multiple internal textures, or atlas
- * textures where Cogl has to modify texture coordinates before they
- * may be used by the GPU.
+ * Creates a low-level #CoglTexture2D texture with a given @width and
+ * @height that your GPU can texture from directly.
*
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
@@ -87,6 +84,11 @@ cogl_is_texture_2d (void *object);
* automatically allocate storage lazily when it may know more about
* how the texture is being used and can optimize how it is allocated.
*
+ * The texture is still configurable until it has been allocated so
+ * for example you can influence the internal format of the texture
+ * using cogl_texture_set_components() and
+ * cogl_texture_set_premultiplied().
+ *
* <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
@@ -116,7 +118,23 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
* other than straight blending.
* @error: A #CoglError to catch exceptional errors or %NULL
*
- * Creates a #CoglTexture2D from an image file.
+ * Creates a low-level #CoglTexture2D texture from an image file.
+ *
+ * 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.
+ *
+ * The texture is still configurable until it has been allocated so
+ * for example you can influence the internal format of the texture
+ * using cogl_texture_set_components() and
+ * cogl_texture_set_premultiplied().
+ *
+ * <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>
*
* Return value: (transfer full): A newly created #CoglTexture2D or %NULL on failure
* and @error will be updated.
@@ -149,10 +167,19 @@ cogl_texture_2d_new_from_file (CoglContext *ctx,
* @data: pointer the memory region where the source buffer resides
* @error: A #CoglError for exceptions
*
- * Creates a new #CoglTexture2D texture based on data residing in memory.
- * These are unlike sliced textures for example which may be comprised
- * of multiple internal textures, or atlas textures where Cogl has to
- * modify texture coordinates before they may be used by the GPU.
+ * Creates a low-level #CoglTexture2D texture based on data residing
+ * in memory.
+ *
+ * <note>This api will always immediately allocate GPU memory for the
+ * texture and upload the given data so that the @data pointer does
+ * not need to remain valid once this function returns. This means it
+ * is not possible to configure the texture before it is allocated. If
+ * you do need to configure the texture before allocation (to specify
+ * constraints on the internal format for example) then you can
+ * instead create a #CoglBitmap for your data and use
+ * cogl_texture_2d_new_from_bitmap() or use
+ * cogl_texture_2d_new_with_size() and then upload data using
+ * cogl_texture_set_data()</note>
*
* <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by
@@ -189,11 +216,19 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
* something other than straight blending.
* @error: A #CoglError for exceptions
*
- * Creates a new #CoglTexture2D texture based on data residing in a
- * bitmap. These are unlike sliced textures for example which may be
- * comprised of multiple internal textures, or atlas textures where
- * Cogl has to modify texture coordinates before they may be used by
- * the GPU.
+ * Creates a low-level #CoglTexture2D texture based on data residing
+ * in a #CoglBitmap.
+ *
+ * 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.
+ *
+ * The texture is still configurable until it has been allocated so
+ * for example you can influence the internal format of the texture
+ * using cogl_texture_set_components() and
+ * cogl_texture_set_premultiplied().
*
* <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by
diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c
index 98d1a217..14bf7d21 100644
--- a/cogl/cogl-texture-3d.c
+++ b/cogl/cogl-texture-3d.c
@@ -116,12 +116,14 @@ _cogl_texture_3d_create_base (CoglContext *ctx,
int width,
int height,
int depth,
- CoglPixelFormat internal_format)
+ CoglPixelFormat internal_format,
+ CoglTextureLoader *loader)
{
CoglTexture3D *tex_3d = g_new (CoglTexture3D, 1);
CoglTexture *tex = COGL_TEXTURE (tex_3d);
- _cogl_texture_init (tex, ctx, width, height, &cogl_texture_3d_vtable);
+ _cogl_texture_init (tex, ctx, width, height,
+ internal_format, loader, &cogl_texture_3d_vtable);
tex_3d->gl_texture = 0;
@@ -138,11 +140,153 @@ _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->internal_format = internal_format;
-
return _cogl_texture_3d_object_new (tex_3d);
}
+CoglTexture3D *
+cogl_texture_3d_new_with_size (CoglContext *ctx,
+ int width,
+ int height,
+ int depth,
+ CoglPixelFormat internal_format)
+{
+ CoglTextureLoader *loader;
+
+ /* Since no data, we need some internal format */
+ if (internal_format == COGL_PIXEL_FORMAT_ANY)
+ internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
+
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
+ loader->src.sized.width = width;
+ loader->src.sized.height = height;
+ loader->src.sized.depth = depth;
+
+ return _cogl_texture_3d_create_base (ctx, width, height, depth,
+ internal_format, loader);
+}
+
+CoglTexture3D *
+cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
+ int height,
+ int depth,
+ CoglPixelFormat internal_format,
+ CoglError **error)
+{
+ CoglTextureLoader *loader;
+
+ _COGL_RETURN_VAL_IF_FAIL (bmp, NULL);
+
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP;
+ loader->src.bitmap.bitmap = cogl_object_ref (bmp);
+ loader->src.bitmap.height = height;
+ loader->src.bitmap.depth = depth;
+ loader->src.bitmap.can_convert_in_place = FALSE; /* TODO add api for this */
+
+ return _cogl_texture_3d_create_base (_cogl_bitmap_get_context (bmp),
+ cogl_bitmap_get_width (bmp),
+ height,
+ depth,
+ internal_format,
+ loader);
+}
+
+CoglTexture3D *
+cogl_texture_3d_new_from_data (CoglContext *context,
+ int width,
+ int height,
+ int depth,
+ CoglPixelFormat format,
+ CoglPixelFormat internal_format,
+ int rowstride,
+ int image_stride,
+ const uint8_t *data,
+ CoglError **error)
+{
+ CoglBitmap *bitmap;
+ CoglTexture3D *ret;
+
+ _COGL_RETURN_VAL_IF_FAIL (data, NULL);
+ _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);
+
+ /* Rowstride from width if not given */
+ if (rowstride == 0)
+ rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
+ /* Image stride from height and rowstride if not given */
+ if (image_stride == 0)
+ image_stride = height * rowstride;
+
+ if (image_stride < rowstride * height)
+ return NULL;
+
+ /* GL doesn't support uploading when the image_stride isn't a
+ multiple of the rowstride. If this happens we'll just pack the
+ image into a new bitmap. The documentation for this function
+ recommends avoiding this situation. */
+ if (image_stride % rowstride != 0)
+ {
+ uint8_t *bmp_data;
+ int bmp_rowstride;
+ int z, y;
+
+ bitmap = _cogl_bitmap_new_with_malloc_buffer (context,
+ width,
+ depth * height,
+ format,
+ error);
+ if (!bitmap)
+ return NULL;
+
+ bmp_data = _cogl_bitmap_map (bitmap,
+ COGL_BUFFER_ACCESS_WRITE,
+ COGL_BUFFER_MAP_HINT_DISCARD,
+ error);
+
+ if (bmp_data == NULL)
+ {
+ cogl_object_unref (bitmap);
+ return NULL;
+ }
+
+ bmp_rowstride = cogl_bitmap_get_rowstride (bitmap);
+
+ /* Copy all of the images in */
+ for (z = 0; z < depth; z++)
+ for (y = 0; y < height; y++)
+ memcpy (bmp_data + (z * bmp_rowstride * height +
+ bmp_rowstride * y),
+ data + z * image_stride + rowstride * y,
+ bmp_rowstride);
+
+ _cogl_bitmap_unmap (bitmap);
+ }
+ else
+ bitmap = cogl_bitmap_new_for_data (context,
+ width,
+ image_stride / rowstride * depth,
+ format,
+ rowstride,
+ (uint8_t *) data);
+
+ ret = cogl_texture_3d_new_from_bitmap (bitmap,
+ height,
+ depth,
+ internal_format,
+ error);
+
+ cogl_object_unref (bitmap);
+
+ if (ret &&
+ !cogl_texture_allocate (COGL_TEXTURE (ret), error))
+ {
+ cogl_object_unref (ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
static CoglBool
_cogl_texture_3d_can_create (CoglContext *ctx,
int width,
@@ -204,50 +348,42 @@ _cogl_texture_3d_can_create (CoglContext *ctx,
return TRUE;
}
-CoglTexture3D *
-cogl_texture_3d_new_with_size (CoglContext *ctx,
- int width,
- int height,
- int depth,
- 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;
-
- return _cogl_texture_3d_create_base (ctx,
- width, height, depth,
- internal_format);
-}
-
static CoglBool
-_cogl_texture_3d_allocate (CoglTexture *tex,
- CoglError **error)
+allocate_with_size (CoglTexture3D *tex_3d,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
+ CoglTexture *tex = COGL_TEXTURE (tex_3d);
CoglContext *ctx = tex->context;
- CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
+ CoglPixelFormat internal_format;
+ int width = loader->src.sized.width;
+ int height = loader->src.sized.height;
+ int depth = loader->src.sized.depth;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
GLenum gl_error;
GLenum gl_texture;
+ internal_format =
+ _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
+
if (!_cogl_texture_3d_can_create (ctx,
- tex->width,
- tex->height,
- tex_3d->depth,
- tex_3d->internal_format,
+ width,
+ height,
+ depth,
+ internal_format,
error))
return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
- tex_3d->internal_format,
+ internal_format,
&gl_intformat,
&gl_format,
&gl_type);
gl_texture =
- ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, tex_3d->internal_format);
+ ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
gl_texture,
FALSE);
@@ -256,7 +392,7 @@ _cogl_texture_3d_allocate (CoglTexture *tex,
;
ctx->glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat,
- tex->width, tex->height, tex_3d->depth,
+ width, height, depth,
0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
@@ -268,47 +404,49 @@ _cogl_texture_3d_allocate (CoglTexture *tex,
tex_3d->gl_texture = gl_texture;
tex_3d->gl_format = gl_intformat;
+ tex_3d->depth = depth;
+
+ tex_3d->internal_format = internal_format;
+
+ _cogl_texture_set_allocated (tex, internal_format, width, height);
+
return TRUE;
}
-CoglTexture3D *
-cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
- unsigned int height,
- unsigned int depth,
- CoglPixelFormat internal_format,
- CoglError **error)
+static CoglBool
+allocate_from_bitmap (CoglTexture3D *tex_3d,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
- CoglTexture3D *tex_3d;
+ CoglTexture *tex = COGL_TEXTURE (tex_3d);
+ CoglContext *ctx = tex->context;
+ CoglPixelFormat internal_format;
+ CoglBitmap *bmp = loader->src.bitmap.bitmap;
+ int bmp_width = cogl_bitmap_get_width (bmp);
+ int height = loader->src.bitmap.height;
+ int depth = loader->src.bitmap.depth;
+ CoglPixelFormat bmp_format = cogl_bitmap_get_format (bmp);
+ CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place;
CoglBitmap *upload_bmp;
- CoglPixelFormat bmp_format;
CoglPixelFormat upload_format;
- unsigned int bmp_width;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
- CoglContext *ctx;
- ctx = _cogl_bitmap_get_context (bmp);
-
- bmp_width = cogl_bitmap_get_width (bmp);
- bmp_format = cogl_bitmap_get_format (bmp);
-
- internal_format = _cogl_texture_determine_internal_format (bmp_format,
- internal_format);
+ internal_format = _cogl_texture_determine_internal_format (tex, bmp_format);
if (!_cogl_texture_3d_can_create (ctx,
bmp_width, height, depth,
internal_format,
error))
- return NULL;
+ return FALSE;
- upload_bmp =
- _cogl_bitmap_convert_for_upload (bmp,
- internal_format,
- FALSE, /* can't convert in place */
- error);
+ upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
+ internal_format,
+ can_convert_in_place,
+ error);
if (upload_bmp == NULL)
- return NULL;
+ return FALSE;
upload_format = cogl_bitmap_get_format (upload_bmp);
@@ -323,10 +461,6 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
NULL,
NULL);
- tex_3d = _cogl_texture_3d_create_base (ctx,
- bmp_width, height, depth,
- internal_format);
-
/* Keep a copy of the first pixel so that if glGenerateMipmap isn't
supported we can fallback to using GL_GENERATE_MIPMAP */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
@@ -371,111 +505,43 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
error))
{
cogl_object_unref (upload_bmp);
- cogl_object_unref (tex_3d);
- return NULL;
+ return FALSE;
}
tex_3d->gl_format = gl_intformat;
cogl_object_unref (upload_bmp);
- _cogl_texture_set_allocated (COGL_TEXTURE (tex_3d), TRUE);
-
- return tex_3d;
-}
+ tex_3d->depth = loader->src.bitmap.depth;
-CoglTexture3D *
-cogl_texture_3d_new_from_data (CoglContext *context,
- int width,
- int height,
- int depth,
- CoglPixelFormat format,
- CoglPixelFormat internal_format,
- int rowstride,
- int image_stride,
- const uint8_t *data,
- CoglError **error)
-{
- CoglBitmap *bitmap;
- CoglTexture3D *ret;
+ tex_3d->internal_format = internal_format;
- /* These are considered a programmer errors so we won't set a
- CoglError. It would be nice if this was a _COGL_RETURN_IF_FAIL but the
- rest of Cogl isn't using that */
- if (format == COGL_PIXEL_FORMAT_ANY)
- return NULL;
+ _cogl_texture_set_allocated (tex, internal_format,
+ bmp_width, loader->src.bitmap.height);
- if (data == NULL)
- return NULL;
+ return TRUE;
+}
- /* Rowstride from width if not given */
- if (rowstride == 0)
- rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
- /* Image stride from height and rowstride if not given */
- if (image_stride == 0)
- image_stride = height * rowstride;
+static CoglBool
+_cogl_texture_3d_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
+ CoglTextureLoader *loader = tex->loader;
- if (image_stride < rowstride * height)
- return NULL;
+ _COGL_RETURN_VAL_IF_FAIL (loader, FALSE);
- /* GL doesn't support uploading when the image_stride isn't a
- multiple of the rowstride. If this happens we'll just pack the
- image into a new bitmap. The documentation for this function
- recommends avoiding this situation. */
- if (image_stride % rowstride != 0)
+ switch (loader->src_type)
{
- uint8_t *bmp_data;
- int bmp_rowstride;
- int z, y;
-
- bitmap = _cogl_bitmap_new_with_malloc_buffer (context,
- width,
- depth * height,
- format,
- error);
- if (!bitmap)
- return NULL;
-
- bmp_data = _cogl_bitmap_map (bitmap,
- COGL_BUFFER_ACCESS_WRITE,
- COGL_BUFFER_MAP_HINT_DISCARD,
- error);
-
- if (bmp_data == NULL)
- {
- cogl_object_unref (bitmap);
- return NULL;
- }
-
- bmp_rowstride = cogl_bitmap_get_rowstride (bitmap);
-
- /* Copy all of the images in */
- for (z = 0; z < depth; z++)
- for (y = 0; y < height; y++)
- memcpy (bmp_data + (z * bmp_rowstride * height +
- bmp_rowstride * y),
- data + z * image_stride + rowstride * y,
- bmp_rowstride);
-
- _cogl_bitmap_unmap (bitmap);
+ case COGL_TEXTURE_SOURCE_TYPE_SIZED:
+ return allocate_with_size (tex_3d, loader, error);
+ case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
+ return allocate_from_bitmap (tex_3d, loader, error);
+ default:
+ break;
}
- else
- bitmap = cogl_bitmap_new_for_data (context,
- width,
- image_stride / rowstride * depth,
- format,
- rowstride,
- (uint8_t *) data);
- ret = cogl_texture_3d_new_from_bitmap (bitmap,
- height,
- depth,
- internal_format,
- error);
-
- cogl_object_unref (bitmap);
-
- return ret;
+ g_return_val_if_reached (FALSE);
}
static CoglBool
diff --git a/cogl/cogl-texture-3d.h b/cogl/cogl-texture-3d.h
index 7aca7e2e..6ab20933 100644
--- a/cogl/cogl-texture-3d.h
+++ b/cogl/cogl-texture-3d.h
@@ -56,8 +56,8 @@ typedef struct _CoglTexture3D CoglTexture3D;
* @internal_format: the #CoglPixelFormat to use for the GPU
* storage of the texture.
*
- * Creates a new #CoglTexture3D texture with the specified dimensions
- * and pixel format.
+ * Creates a low-level #CoglTexture3D texture with the specified
+ * dimensions and pixel format.
*
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
@@ -66,6 +66,11 @@ typedef struct _CoglTexture3D CoglTexture3D;
* how the texture is going to be used and can optimize how it is
* allocated.
*
+ * The texture is still configurable until it has been allocated so
+ * for example you can influence the internal format of the texture
+ * using cogl_texture_set_components() and
+ * cogl_texture_set_premultiplied().
+ *
* <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
@@ -107,16 +112,21 @@ cogl_texture_3d_new_with_size (CoglContext *context,
* @data: pointer the memory region where the source buffer resides
* @error: A CoglError return location.
*
- * Creates a new 3D texture and initializes it with @data. The data is
- * assumed to be packed array of @depth images. There can be padding
- * between the images using @image_stride.
+ * Creates a low-level 3D texture and initializes it with @data. The
+ * data is assumed to be packed array of @depth images. There can be
+ * padding between the images using @image_stride.
*
- * 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.
+ * <note>This api will always immediately allocate GPU memory for the
+ * texture and upload the given data so that the @data pointer does
+ * not need to remain valid once this function returns. This means it
+ * is not possible to configure the texture before it is allocated. If
+ * you do need to configure the texture before allocation (to specify
+ * constraints on the internal format for example) then you can
+ * instead create a #CoglBitmap for your data and use
+ * cogl_texture_3d_new_from_bitmap().</note>
*
* Return value: (transfer full): the newly created #CoglTexture3D or
- * %NULL if there was an error an an exception will be
+ * %NULL if there was an error and an exception will be
* returned through @error.
* Since: 1.10
* Stability: Unstable
@@ -148,13 +158,30 @@ cogl_texture_3d_new_from_data (CoglContext *context,
* something other than straight blending.
* @error: A CoglError return location.
*
- * Creates a new 3D texture and initializes it with the images in
- * @bitmap. The images are assumed to be packed together after one
+ * Creates a low-level 3D texture and initializes it with the images
+ * in @bitmap. The images are assumed to be packed together after one
* another in the increasing y axis. The height of individual image is
* given as @height and the number of images is given in @depth. The
* actual height of the bitmap can be larger than @height × @depth. In
* this case it assumes there is padding between the images.
*
+ * 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.
+ *
+ * The texture is still configurable until it has been allocated so
+ * for example you can influence the internal format of the texture
+ * using cogl_texture_set_components() and
+ * cogl_texture_set_premultiplied().
+ *
+ * <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: (transfer full): the newly created texture or %NULL
* if there was an error.
* Since: 2.0
@@ -162,8 +189,8 @@ cogl_texture_3d_new_from_data (CoglContext *context,
*/
CoglTexture3D *
cogl_texture_3d_new_from_bitmap (CoglBitmap *bitmap,
- unsigned int height,
- unsigned int depth,
+ int height,
+ int depth,
CoglPixelFormat internal_format,
CoglError **error);
diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h
index aae779cb..11b536d3 100644
--- a/cogl/cogl-texture-private.h
+++ b/cogl/cogl-texture-private.h
@@ -31,6 +31,10 @@
#include "cogl-meta-texture.h"
#include "cogl-framebuffer.h"
+#ifdef COGL_HAS_EGL_SUPPORT
+#include "cogl-egl-defines.h"
+#endif
+
typedef struct _CoglTextureVtable CoglTextureVtable;
/* Encodes three possibiloities result of transforming a quad */
@@ -137,15 +141,62 @@ struct _CoglTextureVtable
CoglBool value);
};
+typedef enum _CoglTextureSoureType {
+ COGL_TEXTURE_SOURCE_TYPE_SIZED = 1,
+ COGL_TEXTURE_SOURCE_TYPE_BITMAP,
+ COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE,
+ COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN
+} CoglTextureSourceType;
+
+typedef struct _CoglTextureLoader
+{
+ CoglTextureSourceType src_type;
+ union {
+ struct {
+ int width;
+ int height;
+ int depth; /* for 3d textures */
+ } sized;
+ struct {
+ CoglBitmap *bitmap;
+ int height; /* for 3d textures */
+ int depth; /* for 3d textures */
+ CoglBool can_convert_in_place;
+ } bitmap;
+#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
+ struct {
+ EGLImageKHR image;
+ int width;
+ int height;
+ CoglPixelFormat format;
+ } egl_image;
+#endif
+ struct {
+ int width;
+ int height;
+ unsigned int gl_handle;
+ CoglPixelFormat format;
+ } gl_foreign;
+ } src;
+} CoglTextureLoader;
+
struct _CoglTexture
{
CoglObject _parent;
CoglContext *context;
+ CoglTextureLoader *loader;
GList *framebuffers;
int max_level;
int width;
int height;
CoglBool allocated;
+
+ /*
+ * Internal format
+ */
+ CoglTextureComponents components;
+ unsigned int premultiplied:1;
+
const CoglTextureVtable *vtable;
};
@@ -181,6 +232,8 @@ _cogl_texture_init (CoglTexture *texture,
CoglContext *ctx,
int width,
int height,
+ CoglPixelFormat internal_format,
+ CoglTextureLoader *loader,
const CoglTextureVtable *vtable);
void
@@ -218,12 +271,38 @@ _cogl_texture_pre_paint (CoglTexture *texture, CoglTexturePrePaintFlags flags);
void
_cogl_texture_ensure_non_quad_rendering (CoglTexture *texture);
-/* Utility function to determine which pixel format to use when
- dst_format is COGL_PIXEL_FORMAT_ANY. If dst_format is not ANY then
- it will just be returned directly */
+/*
+ * This determines a CoglPixelFormat according to texture::components
+ * and texture::premultiplied (i.e. the user required components and
+ * whether the texture should be considered premultiplied)
+ *
+ * A reference/source format can be given (or COGL_PIXEL_FORMAT_ANY)
+ * and wherever possible this function tries to simply return the
+ * given source format if its compatible with the required components.
+ *
+ * Texture backends can call this when allocating a texture to know
+ * how to convert a source image in preparation for uploading.
+ */
CoglPixelFormat
-_cogl_texture_determine_internal_format (CoglPixelFormat src_format,
- CoglPixelFormat dst_format);
+_cogl_texture_determine_internal_format (CoglTexture *texture,
+ CoglPixelFormat src_format);
+
+/* This is called by texture backends when they have successfully
+ * allocated a texture.
+ *
+ * Most texture backends currently track the internal layout of
+ * textures using a CoglPixelFormat which will be finalized when a
+ * texture is allocated. At this point we need to update
+ * texture::components and texture::premultiplied according to the
+ * determined layout.
+ *
+ * XXX: Going forward we should probably aim to stop using
+ * CoglPixelFormat at all for tracking the internal layout of
+ * textures.
+ */
+void
+_cogl_texture_set_internal_format (CoglTexture *texture,
+ CoglPixelFormat internal_format);
CoglBool
_cogl_texture_is_foreign (CoglTexture *texture);
@@ -280,9 +359,14 @@ _cogl_texture_get_level_size (CoglTexture *texture,
void
_cogl_texture_set_allocated (CoglTexture *texture,
- CoglBool allocated);
+ CoglPixelFormat internal_format,
+ int width,
+ int height);
CoglPixelFormat
_cogl_texture_get_format (CoglTexture *texture);
+CoglTextureLoader *
+_cogl_texture_create_loader (void);
+
#endif /* __COGL_TEXTURE_PRIVATE_H */
diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c
index db7968dc..d9ca1f74 100644
--- a/cogl/cogl-texture-rectangle.c
+++ b/cogl/cogl-texture-rectangle.c
@@ -166,12 +166,15 @@ static CoglTextureRectangle *
_cogl_texture_rectangle_create_base (CoglContext *ctx,
int width,
int height,
- CoglPixelFormat internal_format)
+ CoglPixelFormat internal_format,
+ CoglTextureLoader *loader)
{
CoglTextureRectangle *tex_rect = g_new (CoglTextureRectangle, 1);
CoglTexture *tex = COGL_TEXTURE (tex_rect);
- _cogl_texture_init (tex, ctx, width, height, &cogl_texture_rectangle_vtable);
+ _cogl_texture_init (tex, ctx, width, height,
+ internal_format, loader,
+ &cogl_texture_rectangle_vtable);
tex_rect->gl_texture = 0;
tex_rect->is_foreign = FALSE;
@@ -184,8 +187,6 @@ _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->internal_format = internal_format;
-
return _cogl_texture_rectangle_object_new (tex_rect);
}
@@ -195,36 +196,49 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
int height,
CoglPixelFormat internal_format)
{
+ CoglTextureLoader *loader;
+
/* 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_rectangle_create_base (ctx,
- width, height,
- internal_format);
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
+ loader->src.sized.width = width;
+ loader->src.sized.height = height;
+
+ return _cogl_texture_rectangle_create_base (ctx, width, height,
+ internal_format, loader);
}
static CoglBool
-_cogl_texture_rectangle_allocate (CoglTexture *tex,
- CoglError **error)
+allocate_with_size (CoglTextureRectangle *tex_rect,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
+ CoglTexture *tex = COGL_TEXTURE (tex_rect);
CoglContext *ctx = tex->context;
- CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
+ CoglPixelFormat internal_format;
+ int width = loader->src.sized.width;
+ int height = loader->src.sized.height;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
GLenum gl_error;
GLenum gl_texture;
+ internal_format =
+ _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
+
if (!_cogl_texture_rectangle_can_create (ctx,
- tex->width,
- tex->height,
- tex_rect->internal_format,
+ width,
+ height,
+ internal_format,
error))
return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
- tex_rect->internal_format,
+ internal_format,
&gl_intformat,
&gl_format,
&gl_type);
@@ -232,7 +246,7 @@ _cogl_texture_rectangle_allocate (CoglTexture *tex,
gl_texture =
ctx->texture_driver->gen (ctx,
GL_TEXTURE_RECTANGLE_ARB,
- tex_rect->internal_format);
+ internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
gl_texture,
tex_rect->is_foreign);
@@ -242,7 +256,7 @@ _cogl_texture_rectangle_allocate (CoglTexture *tex,
;
ctx->glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat,
- tex->width, tex->height, 0, gl_format, gl_type, NULL);
+ width, height, 0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{
@@ -250,46 +264,50 @@ _cogl_texture_rectangle_allocate (CoglTexture *tex,
return FALSE;
}
+ tex_rect->internal_format = internal_format;
+
tex_rect->gl_texture = gl_texture;
tex_rect->gl_format = gl_intformat;
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect),
+ internal_format, width, height);
+
return TRUE;
}
-CoglTextureRectangle *
-cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
- CoglPixelFormat internal_format,
- CoglError **error)
+static CoglBool
+allocate_from_bitmap (CoglTextureRectangle *tex_rect,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
- CoglTextureRectangle *tex_rect;
+ CoglTexture *tex = COGL_TEXTURE (tex_rect);
+ CoglContext *ctx = tex->context;
+ CoglPixelFormat internal_format;
+ CoglBitmap *bmp = loader->src.bitmap.bitmap;
+ int width = cogl_bitmap_get_width (bmp);
+ int height = cogl_bitmap_get_height (bmp);
+ CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place;
CoglBitmap *upload_bmp;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
- CoglContext *ctx;
-
- _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
-
- ctx = _cogl_bitmap_get_context (bmp);
internal_format =
- _cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp),
- internal_format);
+ _cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp));
if (!_cogl_texture_rectangle_can_create (ctx,
- cogl_bitmap_get_width (bmp),
- cogl_bitmap_get_height (bmp),
+ width,
+ height,
internal_format,
error))
- return NULL;
+ return FALSE;
- upload_bmp =
- _cogl_bitmap_convert_for_upload (bmp,
- internal_format,
- FALSE, /* can't convert in place */
- error);
+ upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
+ internal_format,
+ can_convert_in_place,
+ error);
if (upload_bmp == NULL)
- return NULL;
+ return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
cogl_bitmap_get_format (upload_bmp),
@@ -302,11 +320,6 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
NULL,
NULL);
- tex_rect = _cogl_texture_rectangle_create_base (ctx,
- cogl_bitmap_get_width (bmp),
- cogl_bitmap_get_height (bmp),
- internal_format);
-
tex_rect->gl_texture =
ctx->texture_driver->gen (ctx,
GL_TEXTURE_RECTANGLE_ARB,
@@ -322,38 +335,31 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
error))
{
cogl_object_unref (upload_bmp);
- cogl_object_unref (tex_rect);
- return NULL;
+ return FALSE;
}
tex_rect->gl_format = gl_intformat;
+ tex_rect->internal_format = internal_format;
cogl_object_unref (upload_bmp);
- _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect), TRUE);
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect),
+ internal_format, width, height);
- return tex_rect;
+ return TRUE;
}
-CoglTextureRectangle *
-cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
- unsigned int gl_handle,
- int width,
- int height,
- CoglPixelFormat format,
- CoglError **error)
+static CoglBool
+allocate_from_gl_foreign (CoglTextureRectangle *tex_rect,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
- /* NOTE: width, height and internal format are not queriable
- * in GLES, hence such a function prototype.
- */
-
+ CoglTexture *tex = COGL_TEXTURE (tex_rect);
+ CoglContext *ctx = tex->context;
+ CoglPixelFormat format = loader->src.gl_foreign.format;
GLenum gl_error = 0;
GLint gl_compressed = GL_FALSE;
GLenum gl_int_format = 0;
- CoglTextureRectangle *tex_rect;
-
- /* Assert that it is a valid GL texture object */
- g_return_val_if_fail (ctx->glIsTexture (gl_handle), NULL);
if (!ctx->texture_driver->allows_foreign_gl_target (ctx,
GL_TEXTURE_RECTANGLE_ARB))
@@ -363,21 +369,22 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Foreign GL_TEXTURE_RECTANGLE textures are not "
"supported by your system");
- return NULL;
+ return FALSE;
}
/* Make sure binding succeeds */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
- _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, gl_handle, TRUE);
+ _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
+ loader->src.gl_foreign.gl_handle, TRUE);
if (ctx->glGetError () != GL_NO_ERROR)
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Failed to bind foreign GL_TEXTURE_RECTANGLE texture");
- return NULL;
+ return FALSE;
}
/* Obtain texture parameters */
@@ -408,7 +415,7 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Unsupported internal format for foreign texture");
- return NULL;
+ return FALSE;
}
}
else
@@ -423,16 +430,6 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
NULL);
}
- /* Note: We always trust the given width and height without querying
- * the texture object because the user may be creating a Cogl
- * texture for a texture_from_pixmap object where glTexImage2D may
- * not have been called and the texture_from_pixmap spec doesn't
- * clarify that it is reliable to query back the size from OpenGL.
- */
-
- /* Validate width and height */
- g_return_val_if_fail (width > 0 && height > 0, NULL);
-
/* Compressed texture images not supported */
if (gl_compressed == GL_TRUE)
{
@@ -440,27 +437,107 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Compressed foreign textures aren't currently supported");
- return NULL;
+ return FALSE;
}
- /* Create new texture */
- tex_rect = _cogl_texture_rectangle_create_base (ctx, width, height, format);
-
/* Setup bitmap info */
tex_rect->is_foreign = TRUE;
- tex_rect->internal_format = format;
-
- tex_rect->gl_texture = gl_handle;
+ tex_rect->gl_texture = loader->src.gl_foreign.gl_handle;
tex_rect->gl_format = gl_int_format;
/* Unknown filter */
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);
+ tex_rect->internal_format = format;
+
+ _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect),
+ format,
+ loader->src.gl_foreign.width,
+ loader->src.gl_foreign.height);
+
+ return TRUE;
+}
+
+static CoglBool
+_cogl_texture_rectangle_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
+ CoglTextureLoader *loader = tex->loader;
+
+ _COGL_RETURN_VAL_IF_FAIL (loader, FALSE);
+
+ switch (loader->src_type)
+ {
+ case COGL_TEXTURE_SOURCE_TYPE_SIZED:
+ return allocate_with_size (tex_rect, loader, error);
+ case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
+ return allocate_from_bitmap (tex_rect, loader, error);
+ case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN:
+ return allocate_from_gl_foreign (tex_rect, loader, error);
+ default:
+ break;
+ }
+
+ g_return_val_if_reached (FALSE);
+}
+
+CoglTextureRectangle *
+cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
+ CoglPixelFormat internal_format,
+ CoglError **error)
+{
+ CoglTextureLoader *loader;
+
+ _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
+
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP;
+ loader->src.bitmap.bitmap = cogl_object_ref (bmp);
+ loader->src.bitmap.can_convert_in_place = FALSE; /* TODO add api for this */
+
+ return _cogl_texture_rectangle_create_base (_cogl_bitmap_get_context (bmp),
+ cogl_bitmap_get_width (bmp),
+ cogl_bitmap_get_height (bmp),
+ internal_format,
+ loader);
+}
+
+CoglTextureRectangle *
+cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
+ unsigned int gl_handle,
+ int width,
+ int height,
+ CoglPixelFormat format,
+ CoglError **error)
+{
+ CoglTextureLoader *loader;
+
+ /* NOTE: width, height and internal format are not queriable in
+ * GLES, hence such a function prototype. Also in the case of full
+ * opengl the user may be creating a Cogl texture for a
+ * texture_from_pixmap object where glTexImage2D may not have been
+ * called and the texture_from_pixmap spec doesn't clarify that it
+ * is reliable to query back the size from OpenGL.
+ */
+
+ /* Assert that it is a valid GL texture object */
+ _COGL_RETURN_VAL_IF_FAIL (ctx->glIsTexture (gl_handle), NULL);
+
+ /* Validate width and height */
+ _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL);
+
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN;
+ loader->src.gl_foreign.gl_handle = gl_handle;
+ loader->src.gl_foreign.width = width;
+ loader->src.gl_foreign.height = height;
+ loader->src.gl_foreign.format = format;
- return tex_rect;
+ return _cogl_texture_rectangle_create_base (ctx, width, height,
+ format, loader);
}
static CoglBool
diff --git a/cogl/cogl-texture-rectangle.h b/cogl/cogl-texture-rectangle.h
index 1e3248a5..eef20bf2 100644
--- a/cogl/cogl-texture-rectangle.h
+++ b/cogl/cogl-texture-rectangle.h
@@ -147,6 +147,13 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
* first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature
* using cogl_has_feature().</note>
*
+ * 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.
+ *
* Returns: A pointer to a newly allocated #CoglTextureRectangle texture
* or if the size was too large or there wasn't enough memory
* %NULL is returned and @error set.
@@ -187,7 +194,11 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bitmap,
* <note>Applications wanting to use #CoglTextureRectangle should
* first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature
* using cogl_has_feature().</note>
-
+ *
+ * The texture is still configurable until it has been allocated so
+ * for example you can declare whether the texture is premultiplied
+ * with cogl_texture_set_premultiplied().
+ *
* Returns: A newly allocated #CoglTextureRectangle, or if Cogl could
* not validate the @gl_handle in some way (perhaps because
* of an unsupported format) it will return %NULL and set
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index 6f1641c0..7b347f92 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -105,6 +105,8 @@ _cogl_texture_init (CoglTexture *texture,
CoglContext *context,
int width,
int height,
+ CoglPixelFormat internal_format,
+ CoglTextureLoader *loader,
const CoglTextureVtable *vtable)
{
texture->context = context;
@@ -114,11 +116,59 @@ _cogl_texture_init (CoglTexture *texture,
texture->allocated = FALSE;
texture->vtable = vtable;
texture->framebuffers = NULL;
+
+ texture->loader = loader;
+
+ _cogl_texture_set_internal_format (texture, internal_format);
+
+ /* Although we want to initialize texture::components according
+ * to the source format, we always want the internal layout to
+ * be considered premultiplied by default.
+ *
+ * NB: this ->premultiplied state is user configurable so to avoid
+ * awkward documentation, setting this to 'true' does not depend on
+ * ->components having an alpha component (we will simply ignore the
+ * premultiplied status later if there is no alpha component).
+ * This way we don't have to worry about updating the
+ * ->premultiplied state in _set_components(). Similarly we don't
+ * have to worry about updating the ->components state in
+ * _set_premultiplied().
+ */
+ texture->premultiplied = TRUE;
+}
+
+static void
+_cogl_texture_free_loader (CoglTexture *texture)
+{
+ if (texture->loader)
+ {
+ CoglTextureLoader *loader = texture->loader;
+ switch (loader->src_type)
+ {
+ case COGL_TEXTURE_SOURCE_TYPE_SIZED:
+ case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE:
+ case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN:
+ break;
+ case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
+ cogl_object_unref (loader->src.bitmap.bitmap);
+ break;
+ }
+ g_slice_free (CoglTextureLoader, loader);
+ texture->loader = NULL;
+ }
+}
+
+CoglTextureLoader *
+_cogl_texture_create_loader (void)
+{
+ return g_slice_new0 (CoglTextureLoader);
}
void
_cogl_texture_free (CoglTexture *texture)
{
+ _cogl_texture_free_loader (texture);
+
g_free (texture);
}
@@ -133,34 +183,6 @@ _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format,
(dst_format & COGL_PREMULT_BIT));
}
-CoglPixelFormat
-_cogl_texture_determine_internal_format (CoglPixelFormat src_format,
- CoglPixelFormat dst_format)
-{
- /* If the application hasn't specified a specific format then we'll
- * pick the most appropriate. By default Cogl will use a
- * premultiplied internal format. Later we will add control over
- * this. */
- if (dst_format == COGL_PIXEL_FORMAT_ANY)
- {
- if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (src_format))
- return src_format | COGL_PREMULT_BIT;
- else
- return src_format;
- }
- else
- /* XXX: It might be nice to make this match the component ordering
- of the source format when the formats are otherwise the same
- because on GL there is no way to specify the ordering of the
- internal format. However when using GLES with the
- GL_EXT_texture_format_BGRA8888 the order of the internal format
- becomes important because it must exactly match the format of
- the uploaded data. That means that if someone creates a texture
- with some RGBA data and then later tries to upload BGRA data we
- do actually have to swizzle the components */
- return dst_format;
-}
-
CoglBool
_cogl_texture_is_foreign (CoglTexture *texture)
{
@@ -1242,9 +1264,17 @@ _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans,
void
_cogl_texture_set_allocated (CoglTexture *texture,
- CoglBool allocated)
+ CoglPixelFormat internal_format,
+ int width,
+ int height)
{
- texture->allocated = allocated;
+ _cogl_texture_set_internal_format (texture, internal_format);
+
+ texture->width = width;
+ texture->height = height;
+ texture->allocated = TRUE;
+
+ _cogl_texture_free_loader (texture);
}
CoglBool
@@ -1258,3 +1288,127 @@ cogl_texture_allocate (CoglTexture *texture,
return texture->allocated;
}
+
+void
+_cogl_texture_set_internal_format (CoglTexture *texture,
+ CoglPixelFormat internal_format)
+{
+ texture->premultiplied = FALSE;
+
+ if (internal_format == COGL_PIXEL_FORMAT_ANY)
+ internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
+
+ if (internal_format == COGL_PIXEL_FORMAT_A_8)
+ {
+ texture->components = COGL_TEXTURE_COMPONENTS_A;
+ return;
+ }
+ else if (internal_format & COGL_DEPTH_BIT)
+ {
+ texture->components = COGL_TEXTURE_COMPONENTS_DEPTH;
+ return;
+ }
+ else if (internal_format & COGL_A_BIT)
+ {
+ texture->components = COGL_TEXTURE_COMPONENTS_RGBA;
+ if (internal_format & COGL_PREMULT_BIT)
+ texture->premultiplied = TRUE;
+ return;
+ }
+ else
+ texture->components = COGL_TEXTURE_COMPONENTS_RGB;
+}
+
+CoglPixelFormat
+_cogl_texture_determine_internal_format (CoglTexture *texture,
+ CoglPixelFormat src_format)
+{
+ switch (texture->components)
+ {
+ case COGL_TEXTURE_COMPONENTS_DEPTH:
+ if (src_format & COGL_DEPTH_BIT)
+ return src_format;
+ else
+ {
+ CoglContext *ctx = texture->context;
+
+ if (_cogl_has_private_feature (ctx,
+ COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) ||
+ _cogl_has_private_feature (ctx,
+ COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL))
+ {
+ return COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8;
+ }
+ else
+ return COGL_PIXEL_FORMAT_DEPTH_16;
+ }
+ case COGL_TEXTURE_COMPONENTS_A:
+ return COGL_PIXEL_FORMAT_A_8;
+ case COGL_TEXTURE_COMPONENTS_RGB:
+ if (src_format != COGL_PIXEL_FORMAT_ANY &&
+ !(src_format & COGL_A_BIT) && !(src_format & COGL_DEPTH_BIT))
+ return src_format;
+ else
+ return COGL_PIXEL_FORMAT_RGB_888;
+ case COGL_TEXTURE_COMPONENTS_RGBA:
+ {
+ CoglPixelFormat format;
+
+ if (src_format != COGL_PIXEL_FORMAT_ANY &&
+ (src_format & COGL_A_BIT) && src_format != COGL_PIXEL_FORMAT_A_8)
+ format = src_format;
+ else
+ format = COGL_PIXEL_FORMAT_RGBA_8888;
+
+ if (texture->premultiplied)
+ {
+ if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format))
+ return format |= COGL_PREMULT_BIT;
+ else
+ return COGL_PIXEL_FORMAT_RGBA_8888_PRE;
+ }
+ else
+ return format & ~COGL_PREMULT_BIT;
+ }
+ }
+
+ g_return_val_if_reached (COGL_PIXEL_FORMAT_RGBA_8888_PRE);
+}
+
+void
+cogl_texture_set_components (CoglTexture *texture,
+ CoglTextureComponents components)
+{
+ _COGL_RETURN_IF_FAIL (!texture->allocated);
+
+ if (texture->components == components)
+ return;
+
+ texture->components = components;
+}
+
+CoglBool
+cogl_texture_get_components (CoglTexture *texture)
+{
+ return texture->components;
+}
+
+void
+cogl_texture_set_premultiplied (CoglTexture *texture,
+ CoglBool premultiplied)
+{
+ _COGL_RETURN_IF_FAIL (!texture->allocated);
+
+ premultiplied = !!premultiplied;
+
+ if (texture->premultiplied == premultiplied)
+ return;
+
+ texture->premultiplied = premultiplied;
+}
+
+CoglBool
+cogl_texture_get_premultiplied (CoglTexture *texture)
+{
+ return texture->premultiplied;
+}
diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h
index 9c3d1934..09176128 100644
--- a/cogl/cogl-texture.h
+++ b/cogl/cogl-texture.h
@@ -124,6 +124,96 @@ uint32_t cogl_texture_error_domain (void);
CoglBool
cogl_is_texture (void *object);
+typedef enum _CoglTextureComponents
+{
+ COGL_TEXTURE_COMPONENTS_A = 1,
+ COGL_TEXTURE_COMPONENTS_RGB,
+ COGL_TEXTURE_COMPONENTS_RGBA,
+ COGL_TEXTURE_COMPONENTS_DEPTH
+} CoglTextureComponents;
+
+/**
+ * cogl_texture_set_components:
+ * @texture: a #CoglTexture pointer.
+ *
+ * Affects the internal storage format for this texture by
+ * determinging what components will be required for sampling later.
+ *
+ * This api affects how data is uploaded to the GPU since unused
+ * components can potentially be discarded from source data.
+ *
+ * By default the required components are automatically determined
+ * using the format of the source data that is first uploaded to
+ * the given @texture.
+ */
+void
+cogl_texture_set_components (CoglTexture *texture,
+ CoglTextureComponents components);
+
+/**
+ * cogl_texture_get_components:
+ * @texture: a #CoglTexture pointer.
+ *
+ * Queries what components the given @texture stores internally as set
+ * via cogl_texture_set_components().
+ *
+ * By default the required components are automatically determined
+ * using the format of the source data that is first uploaded to
+ * the given @texture.
+ */
+CoglBool
+cogl_texture_get_components (CoglTexture *texture);
+
+/**
+ * cogl_texture_set_premultiplied:
+ * @texture: a #CoglTexture pointer.
+ * @premultiplied: Whether any internally stored red, green or blue
+ * components are pre-multiplied by an alpha
+ * component.
+ *
+ * Affects the internal storage format for this texture by determining
+ * whether red, green and blue color components should be stored as
+ * pre-multiplied alpha values.
+ *
+ * This api affects how data is uploaded to the GPU since Cogl will
+ * convert source data to have premultiplied or unpremultiplied
+ * components according to this state.
+ *
+ * For example if you create a texture via
+ * cogl_texture_2d_new_with_size() and then upload data via
+ * cogl_texture_set_data() passing a source format of
+ * %COGL_PIXEL_FORMAT_RGBA_8888 then Cogl will internally multiply the
+ * red, green and blue components of the source data by the alpha
+ * component, for each pixel so that the internally stored data has
+ * pre-multiplied alpha components. If you instead upload data that
+ * already has pre-multiplied components by passing
+ * %COGL_PIXEL_FORMAT_RGBA_8888_PRE as the source format to
+ * cogl_texture_set_data() then the data can be uploaded without being
+ * converted.
+ *
+ * By default the @premultipled state is @TRUE.
+ */
+void
+cogl_texture_set_premultiplied (CoglTexture *texture,
+ CoglBool premultiplied);
+
+/**
+ * cogl_texture_get_premultiplied:
+ * @texture: a #CoglTexture pointer.
+ *
+ * Queries the pre-multiplied alpha status for internally stored red,
+ * green and blue components for the given @texture as set by
+ * cogl_texture_set_premultiplied().
+ *
+ * By default the pre-multipled state is @TRUE.
+ *
+ * Return value: %TRUE if red, green and blue components are
+ * internally stored pre-multiplied by the alpha
+ * value or %FALSE if not.
+ */
+CoglBool
+cogl_texture_get_premultiplied (CoglTexture *texture);
+
/**
* cogl_texture_get_width:
* @texture: a #CoglTexture pointer.
diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c
index 69288711..27e30f56 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -25,13 +25,12 @@
* Robert Bragg <robert@linux.intel.com>
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <config.h>
#include <string.h>
#include "cogl-private.h"
+#include "cogl-texture-private.h"
#include "cogl-texture-2d-gl.h"
#include "cogl-texture-2d-gl-private.h"
#include "cogl-texture-2d-private.h"
@@ -57,6 +56,13 @@ _cogl_texture_2d_gl_can_create (CoglContext *ctx,
GLenum gl_format;
GLenum gl_type;
+ /* If NPOT textures aren't supported then the size must be a power
+ of two */
+ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
+ (!_cogl_util_is_pot (width) ||
+ !_cogl_util_is_pot (height)))
+ return FALSE;
+
ctx->driver_vtable->pixel_format_to_gl (ctx,
internal_format,
&gl_intformat,
@@ -90,22 +96,29 @@ _cogl_texture_2d_gl_init (CoglTexture2D *tex_2d)
tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
}
-CoglBool
-_cogl_texture_2d_gl_allocate (CoglTexture *tex,
- CoglError **error)
+static CoglBool
+allocate_with_size (CoglTexture2D *tex_2d,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
+ CoglTexture *tex = COGL_TEXTURE (tex_2d);
+ CoglPixelFormat internal_format;
+ int width = loader->src.sized.width;
+ int height = loader->src.sized.height;
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 =
+ _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
+
if (!_cogl_texture_2d_gl_can_create (ctx,
- tex->width,
- tex->height,
- tex_2d->internal_format))
+ width,
+ height,
+ internal_format))
{
_cogl_set_error (error, COGL_TEXTURE_ERROR,
COGL_TEXTURE_ERROR_SIZE,
@@ -115,13 +128,12 @@ _cogl_texture_2d_gl_allocate (CoglTexture *tex,
}
ctx->driver_vtable->pixel_format_to_gl (ctx,
- tex_2d->internal_format,
+ internal_format,
&gl_intformat,
&gl_format,
&gl_type);
- gl_texture =
- ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, tex_2d->internal_format);
+ gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
tex_2d->gl_internal_format = gl_intformat;
@@ -134,7 +146,7 @@ _cogl_texture_2d_gl_allocate (CoglTexture *tex,
;
ctx->glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat,
- tex->width, tex->height, 0, gl_format, gl_type, NULL);
+ width, height, 0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{
@@ -145,28 +157,51 @@ _cogl_texture_2d_gl_allocate (CoglTexture *tex,
tex_2d->gl_texture = gl_texture;
tex_2d->gl_internal_format = gl_intformat;
+ tex_2d->internal_format = internal_format;
+
+ _cogl_texture_set_allocated (tex, internal_format, width, height);
+
return TRUE;
}
-CoglTexture2D *
-_cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
- CoglPixelFormat internal_format,
- CoglBool can_convert_in_place,
- CoglError **error)
+static CoglBool
+allocate_from_bitmap (CoglTexture2D *tex_2d,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
+ CoglTexture *tex = COGL_TEXTURE (tex_2d);
+ CoglBitmap *bmp = loader->src.bitmap.bitmap;
CoglContext *ctx = _cogl_bitmap_get_context (bmp);
- CoglTexture2D *tex_2d;
+ CoglPixelFormat internal_format;
+ int width = cogl_bitmap_get_width (bmp);
+ int height = cogl_bitmap_get_height (bmp);
+ CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place;
CoglBitmap *upload_bmp;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
+ internal_format =
+ _cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp));
+
+ if (!_cogl_texture_2d_gl_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 FALSE;
+ }
+
upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
internal_format,
can_convert_in_place,
error);
if (upload_bmp == NULL)
- return NULL;
+ return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
cogl_bitmap_get_format (upload_bmp),
@@ -179,11 +214,6 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
NULL,
NULL);
- tex_2d = _cogl_texture_2d_create_base (ctx,
- cogl_bitmap_get_width (bmp),
- cogl_bitmap_get_height (bmp),
- internal_format);
-
/* Keep a copy of the first pixel so that if glGenerateMipmap isn't
supported we can fallback to using GL_GENERATE_MIPMAP */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
@@ -226,44 +256,40 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
error))
{
cogl_object_unref (upload_bmp);
- cogl_object_unref (tex_2d);
- return NULL;
+ return FALSE;
}
tex_2d->gl_internal_format = gl_intformat;
cogl_object_unref (upload_bmp);
- _cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE);
+ tex_2d->internal_format = internal_format;
+
+ _cogl_texture_set_allocated (tex, internal_format, width, height);
- return tex_2d;
+ return TRUE;
}
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
-CoglTexture2D *
-_cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat format,
- EGLImageKHR image,
- CoglError **error)
+static CoglBool
+allocate_from_egl_image (CoglTexture2D *tex_2d,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
- CoglTexture2D *tex_2d;
+ CoglTexture *tex = COGL_TEXTURE (tex_2d);
+ CoglContext *ctx = tex->context;
+ CoglPixelFormat internal_format = loader->src.egl_image.format;
GLenum gl_error;
- tex_2d = _cogl_texture_2d_create_base (ctx,
- width, height,
- format);
-
tex_2d->gl_texture =
- ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, format);
+ ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
tex_2d->gl_texture,
FALSE);
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
- ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, image);
+ ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, loader->src.egl_image.image);
if (ctx->glGetError () != GL_NO_ERROR)
{
_cogl_set_error (error,
@@ -271,89 +297,32 @@ _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;
+ GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) );
+ return FALSE;
}
- _cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE);
+ tex_2d->internal_format = internal_format;
- return tex_2d;
-}
-#endif
-
-void
-_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex,
- GLenum min_filter,
- GLenum mag_filter)
-{
- CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
- CoglContext *ctx = tex->context;
-
- if (min_filter == tex_2d->gl_legacy_texobj_min_filter
- && mag_filter == tex_2d->gl_legacy_texobj_mag_filter)
- return;
-
- /* Store new values */
- tex_2d->gl_legacy_texobj_min_filter = min_filter;
- tex_2d->gl_legacy_texobj_mag_filter = mag_filter;
+ _cogl_texture_set_allocated (tex,
+ internal_format,
+ loader->src.egl_image.width,
+ loader->src.egl_image.height);
- /* Apply new filters to the texture */
- _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
- tex_2d->gl_texture,
- tex_2d->is_foreign);
- GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) );
- GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) );
+ return TRUE;
}
+#endif
-void
-_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
- GLenum wrap_mode_s,
- GLenum wrap_mode_t,
- GLenum wrap_mode_p)
+static CoglBool
+allocate_from_gl_foreign (CoglTexture2D *tex_2d,
+ CoglTextureLoader *loader,
+ CoglError **error)
{
- CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
+ CoglTexture *tex = COGL_TEXTURE (tex_2d);
CoglContext *ctx = tex->context;
-
- /* Only set the wrap mode if it's different from the current value
- to avoid too many GL calls. Texture 2D doesn't make use of the r
- coordinate so we can ignore its wrap mode */
- if (tex_2d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s ||
- tex_2d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t)
- {
- _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
- tex_2d->gl_texture,
- tex_2d->is_foreign);
- GE( ctx, glTexParameteri (GL_TEXTURE_2D,
- GL_TEXTURE_WRAP_S,
- wrap_mode_s) );
- GE( ctx, glTexParameteri (GL_TEXTURE_2D,
- GL_TEXTURE_WRAP_T,
- wrap_mode_t) );
-
- tex_2d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s;
- tex_2d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t;
- }
-}
-
-CoglTexture2D *
-cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx,
- unsigned int gl_handle,
- int width,
- int height,
- CoglPixelFormat format,
- CoglError **error)
-{
- /* NOTE: width, height and internal format are not queriable
- * in GLES, hence such a function prototype.
- */
-
+ CoglPixelFormat format = loader->src.gl_foreign.format;
GLenum gl_error = 0;
GLint gl_compressed = GL_FALSE;
GLenum gl_int_format = 0;
- CoglTexture2D *tex_2d;
-
- /* Assert it is a valid GL texture object */
- g_return_val_if_fail (ctx->glIsTexture (gl_handle), NULL);
if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_2D))
{
@@ -362,22 +331,22 @@ cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Foreign GL_TEXTURE_2D textures are not "
"supported by your system");
- return NULL;
+ return FALSE;
}
-
/* Make sure binding succeeds */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
- _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, gl_handle, TRUE);
+ _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+ loader->src.gl_foreign.gl_handle, TRUE);
if (ctx->glGetError () != GL_NO_ERROR)
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Failed to bind foreign GL_TEXTURE_2D texture");
- return NULL;
+ return FALSE;
}
/* Obtain texture parameters
@@ -411,7 +380,7 @@ cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Unsupported internal format for foreign texture");
- return NULL;
+ return FALSE;
}
}
else
@@ -426,16 +395,6 @@ cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx,
NULL);
}
- /* Note: We always trust the given width and height without querying
- * the texture object because the user may be creating a Cogl
- * texture for a texture_from_pixmap object where glTexImage2D may
- * not have been called and the texture_from_pixmap spec doesn't
- * clarify that it is reliable to query back the size from OpenGL.
- */
-
- /* Validate width and height */
- g_return_val_if_fail (width > 0 && height > 0, NULL);
-
/* Compressed texture images not supported */
if (gl_compressed == GL_TRUE)
{
@@ -443,7 +402,7 @@ cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Compressed foreign textures aren't currently supported");
- return NULL;
+ return FALSE;
}
/* Note: previously this code would query the texture object for
@@ -457,26 +416,145 @@ cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx,
GL_GENERATE_MIPMAP alone so that it would still work but without
the dirtiness tracking that Cogl would do. */
- /* Create new texture */
- tex_2d = _cogl_texture_2d_create_base (ctx,
- width, height,
- format);
_cogl_texture_2d_set_auto_mipmap (COGL_TEXTURE (tex_2d), FALSE);
/* Setup bitmap info */
tex_2d->is_foreign = TRUE;
tex_2d->mipmaps_dirty = TRUE;
- tex_2d->gl_texture = gl_handle;
+ tex_2d->gl_texture = loader->src.gl_foreign.gl_handle;
tex_2d->gl_internal_format = gl_int_format;
/* Unknown filter */
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);
+ tex_2d->internal_format = format;
+
+ _cogl_texture_set_allocated (tex,
+ format,
+ loader->src.gl_foreign.width,
+ loader->src.gl_foreign.height);
+ return TRUE;
+}
+
+CoglBool
+_cogl_texture_2d_gl_allocate (CoglTexture *tex,
+ CoglError **error)
+{
+ CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
+ CoglTextureLoader *loader = tex->loader;
+
+ _COGL_RETURN_VAL_IF_FAIL (loader, FALSE);
+
+ switch (loader->src_type)
+ {
+ case COGL_TEXTURE_SOURCE_TYPE_SIZED:
+ return allocate_with_size (tex_2d, loader, error);
+ case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
+ return allocate_from_bitmap (tex_2d, loader, error);
+ case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE:
+#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
+ return allocate_from_egl_image (tex_2d, loader, error);
+#else
+ g_return_val_if_reached (FALSE);
+#endif
+ case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN:
+ return allocate_from_gl_foreign (tex_2d, loader, error);
+ }
+
+ g_return_val_if_reached (FALSE);
+}
+
+void
+_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex,
+ GLenum min_filter,
+ GLenum mag_filter)
+{
+ CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
+ CoglContext *ctx = tex->context;
+
+ if (min_filter == tex_2d->gl_legacy_texobj_min_filter
+ && mag_filter == tex_2d->gl_legacy_texobj_mag_filter)
+ return;
+
+ /* Store new values */
+ tex_2d->gl_legacy_texobj_min_filter = min_filter;
+ tex_2d->gl_legacy_texobj_mag_filter = mag_filter;
+
+ /* Apply new filters to the texture */
+ _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+ tex_2d->gl_texture,
+ tex_2d->is_foreign);
+ GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) );
+ GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) );
+}
+
+void
+_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
+ GLenum wrap_mode_s,
+ GLenum wrap_mode_t,
+ GLenum wrap_mode_p)
+{
+ CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
+ CoglContext *ctx = tex->context;
+
+ /* Only set the wrap mode if it's different from the current value
+ to avoid too many GL calls. Texture 2D doesn't make use of the r
+ coordinate so we can ignore its wrap mode */
+ if (tex_2d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s ||
+ tex_2d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t)
+ {
+ _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+ tex_2d->gl_texture,
+ tex_2d->is_foreign);
+ GE( ctx, glTexParameteri (GL_TEXTURE_2D,
+ GL_TEXTURE_WRAP_S,
+ wrap_mode_s) );
+ GE( ctx, glTexParameteri (GL_TEXTURE_2D,
+ GL_TEXTURE_WRAP_T,
+ wrap_mode_t) );
+
+ tex_2d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s;
+ tex_2d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t;
+ }
+}
+
+CoglTexture2D *
+cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx,
+ unsigned int gl_handle,
+ int width,
+ int height,
+ CoglPixelFormat format,
+ CoglError **error)
+{
+ CoglTextureLoader *loader;
+
+ /* NOTE: width, height and internal format are not queriable
+ * in GLES, hence such a function prototype.
+ */
+
+ /* Note: We always trust the given width and height without querying
+ * the texture object because the user may be creating a Cogl
+ * texture for a texture_from_pixmap object where glTexImage2D may
+ * not have been called and the texture_from_pixmap spec doesn't
+ * clarify that it is reliable to query back the size from OpenGL.
+ */
+
+ /* Assert it is a valid GL texture object */
+ _COGL_RETURN_VAL_IF_FAIL (ctx->glIsTexture (gl_handle), FALSE);
+
+ /* Validate width and height */
+ _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL);
+
+ loader = _cogl_texture_create_loader ();
+ loader->src_type = COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN;
+ loader->src.gl_foreign.gl_handle = gl_handle;
+ loader->src.gl_foreign.width = width;
+ loader->src.gl_foreign.height = height;
+ loader->src.gl_foreign.format = format;
- return tex_2d;
+ return _cogl_texture_2d_create_base (ctx, width, height, format, loader);
}
void
diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c
index f787b0c0..92d3c23a 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -634,10 +634,6 @@ _cogl_driver_gl =
_cogl_texture_2d_gl_can_create,
_cogl_texture_2d_gl_init,
_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,
-#endif
_cogl_texture_2d_gl_copy_from_framebuffer,
_cogl_texture_2d_gl_get_gl_handle,
_cogl_texture_2d_gl_generate_mipmap,
diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c
index a013f838..27317bf2 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -364,10 +364,6 @@ _cogl_driver_gles =
_cogl_texture_2d_gl_can_create,
_cogl_texture_2d_gl_init,
_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,
-#endif
_cogl_texture_2d_gl_copy_from_framebuffer,
_cogl_texture_2d_gl_get_gl_handle,
_cogl_texture_2d_gl_generate_mipmap,
diff --git a/cogl/driver/nop/cogl-driver-nop.c b/cogl/driver/nop/cogl-driver-nop.c
index 92cd43c2..f8eaa975 100644
--- a/cogl/driver/nop/cogl-driver-nop.c
+++ b/cogl/driver/nop/cogl-driver-nop.c
@@ -68,10 +68,6 @@ _cogl_driver_nop =
_cogl_texture_2d_nop_can_create,
_cogl_texture_2d_nop_init,
_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,
-#endif
_cogl_texture_2d_nop_copy_from_framebuffer,
_cogl_texture_2d_nop_get_gl_handle,
_cogl_texture_2d_nop_generate_mipmap,
diff --git a/cogl/driver/nop/cogl-texture-2d-nop-private.h b/cogl/driver/nop/cogl-texture-2d-nop-private.h
index f822a7f1..a0722d7f 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop-private.h
+++ b/cogl/driver/nop/cogl-texture-2d-nop-private.h
@@ -48,22 +48,6 @@ CoglBool
_cogl_texture_2d_nop_allocate (CoglTexture *tex,
CoglError **error);
-CoglTexture2D *
-_cogl_texture_2d_nop_new_from_bitmap (CoglBitmap *bmp,
- CoglPixelFormat internal_format,
- CoglBool can_convert_in_place,
- CoglError **error);
-
-#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
-CoglTexture2D *
-_cogl_egl_texture_2d_nop_new_from_image (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat format,
- EGLImageKHR image,
- CoglError **error);
-#endif
-
void
_cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex,
GLenum min_filter,
diff --git a/cogl/driver/nop/cogl-texture-2d-nop.c b/cogl/driver/nop/cogl-texture-2d-nop.c
index b63a7b7a..30aadede 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop.c
+++ b/cogl/driver/nop/cogl-texture-2d-nop.c
@@ -62,36 +62,6 @@ _cogl_texture_2d_nop_allocate (CoglTexture *tex,
return TRUE;
}
-CoglTexture2D *
-_cogl_texture_2d_nop_new_from_bitmap (CoglBitmap *bmp,
- CoglPixelFormat internal_format,
- CoglBool can_convert_in_place,
- CoglError **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)
-CoglTexture2D *
-_cogl_egl_texture_2d_nop_new_from_image (CoglContext *ctx,
- int width,
- int height,
- CoglPixelFormat format,
- EGLImageKHR image,
- CoglError **error)
-{
- _cogl_set_error (error,
- COGL_SYSTEM_ERROR,
- COGL_SYSTEM_ERROR_UNSUPPORTED,
- "Creating 2D textures from an EGLImage isn't "
- "supported by the NOP backend");
- return NULL;
-}
-#endif
-
void
_cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex,
GLenum min_filter,
diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c
index 4b40166c..7e8584ad 100644
--- a/cogl/winsys/cogl-texture-pixmap-x11.c
+++ b/cogl/winsys/cogl-texture-pixmap-x11.c
@@ -287,6 +287,7 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
int pixmap_x, pixmap_y;
unsigned int pixmap_width, pixmap_height;
unsigned int pixmap_border_width;
+ CoglPixelFormat internal_format;
CoglTexture *tex = COGL_TEXTURE (tex_pixmap);
XWindowAttributes window_attributes;
int damage_base;
@@ -305,7 +306,15 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
return NULL;
}
+ /* Note: the detailed pixel layout doesn't matter here, we are just
+ * interested in RGB vs RGBA... */
+ internal_format = (tex_pixmap->depth >= 32
+ ? COGL_PIXEL_FORMAT_RGBA_8888_PRE
+ : COGL_PIXEL_FORMAT_RGB_888);
+
_cogl_texture_init (tex, ctxt, pixmap_width, pixmap_height,
+ internal_format,
+ NULL, /* no loader */
&cogl_texture_pixmap_x11_vtable);
tex_pixmap->pixmap = pixmap;
@@ -326,6 +335,7 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
"Unable to query root window attributes");
return NULL;
}
+
tex_pixmap->visual = window_attributes.visual;
/* If automatic updates are requested and the Xlib connection
@@ -346,9 +356,9 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
/* Assume the entire pixmap is damaged to begin with */
tex_pixmap->damage_rect.x1 = 0;
- tex_pixmap->damage_rect.x2 = tex->width;
+ tex_pixmap->damage_rect.x2 = pixmap_width;
tex_pixmap->damage_rect.y1 = 0;
- tex_pixmap->damage_rect.y2 = tex->height;
+ tex_pixmap->damage_rect.y2 = pixmap_height;
winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap);
if (winsys->texture_pixmap_x11_create)
@@ -362,7 +372,8 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
if (!tex_pixmap->use_winsys_texture)
tex_pixmap->winsys = NULL;
- _cogl_texture_set_allocated (tex, TRUE);
+ _cogl_texture_set_allocated (tex, internal_format,
+ pixmap_width, pixmap_height);
return _cogl_texture_pixmap_x11_object_new (tex_pixmap);
}
diff --git a/examples/cogl-basic-video-player.c b/examples/cogl-basic-video-player.c
index cc1ace29..552298ae 100644
--- a/examples/cogl-basic-video-player.c
+++ b/examples/cogl-basic-video-player.c
@@ -1,4 +1,5 @@
#include <stdbool.h>
+#include <string.h>
#include <cogl/cogl.h>
#include <cogl-gst/cogl-gst.h>