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>
(cherry picked from commit 6a83de9ef4210f380a31f410797447b365a8d02c)

Note: Compared to the original patch, the ->premultipled state for
textures isn't forced to be %TRUE in _cogl_texture_init since that
effectively ignores the users explicitly given internal_format which was
a mistake and on master that change should have been made in the patch
that followed. The gtk-doc comments for cogl_texture_set_premultiplied()
and cogl_texture_set_components() have also been updated in-line with
this fix.
This commit is contained in:
Robert Bragg 2013-06-23 16:18:18 +01:00
parent 3f780e2f3f
commit cbd6951134
28 changed files with 1791 additions and 1018 deletions

View File

@ -37,7 +37,7 @@ struct _CoglAtlasTexture
/* The format that the texture is in. This isn't necessarily the /* The format that the texture is in. This isn't necessarily the
same format as the atlas texture because we can store same format as the atlas texture because we can store
pre-multiplied and non-pre-multiplied textures together */ pre-multiplied and non-pre-multiplied textures together */
CoglPixelFormat format; CoglPixelFormat internal_format;
/* The rectangle that was used to add this texture to the /* The rectangle that was used to add this texture to the
atlas. This includes the 1-pixel border */ atlas. This includes the 1-pixel border */

View File

@ -384,7 +384,7 @@ _cogl_atlas_texture_migrate_out_of_atlas (CoglAtlasTexture *atlas_tex)
atlas_tex->rectangle.y + 1, atlas_tex->rectangle.y + 1,
atlas_tex->rectangle.width - 2, atlas_tex->rectangle.width - 2,
atlas_tex->rectangle.height - 2, atlas_tex->rectangle.height - 2,
atlas_tex->format); atlas_tex->internal_format);
/* Note: we simply silently ignore failures to migrate a texture /* Note: we simply silently ignore failures to migrate a texture
* out (most likely due to lack of memory) and hope for the * out (most likely due to lack of memory) and hope for the
* best. * best.
@ -515,10 +515,10 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
static CoglBitmap * static CoglBitmap *
_cogl_atlas_texture_convert_bitmap_for_upload (CoglAtlasTexture *atlas_tex, _cogl_atlas_texture_convert_bitmap_for_upload (CoglAtlasTexture *atlas_tex,
CoglBitmap *bmp, CoglBitmap *bmp,
CoglPixelFormat internal_format,
CoglBool can_convert_in_place, CoglBool can_convert_in_place,
CoglError **error) CoglError **error)
{ {
CoglPixelFormat internal_format;
CoglBitmap *upload_bmp; CoglBitmap *upload_bmp;
CoglBitmap *override_bmp; CoglBitmap *override_bmp;
@ -531,7 +531,7 @@ _cogl_atlas_texture_convert_bitmap_for_upload (CoglAtlasTexture *atlas_tex,
orignal format so we do need to trigger the conversion */ orignal format so we do need to trigger the conversion */
internal_format = (COGL_PIXEL_FORMAT_RGBA_8888 | 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, upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
internal_format, internal_format,
@ -582,6 +582,7 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
CoglBitmap *upload_bmp = CoglBitmap *upload_bmp =
_cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex, _cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex,
bmp, bmp,
atlas_tex->internal_format,
FALSE, /* can't convert FALSE, /* can't convert
in place */ in place */
error); error);
@ -619,7 +620,7 @@ _cogl_atlas_texture_get_format (CoglTexture *tex)
/* We don't want to forward this on the sub-texture because it isn't /* 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 the necessarily the same format. This will happen if the texture
isn't pre-multiplied */ isn't pre-multiplied */
return atlas_tex->format; return atlas_tex->internal_format;
} }
static GLenum static GLenum
@ -645,24 +646,20 @@ _cogl_atlas_texture_can_use_format (CoglPixelFormat format)
format == COGL_PIXEL_FORMAT_RGBA_8888); format == COGL_PIXEL_FORMAT_RGBA_8888);
} }
CoglAtlasTexture * static CoglAtlasTexture *
cogl_atlas_texture_new_with_size (CoglContext *ctx, _cogl_atlas_texture_create_base (CoglContext *ctx,
int width, int width,
int height, int height,
CoglPixelFormat internal_format, CoglPixelFormat internal_format,
CoglError **error) CoglTextureLoader *loader)
{ {
CoglAtlasTexture *atlas_tex; 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); COGL_NOTE (ATLAS, "Adding texture of size %ix%i", width, height);
/* We need to allocate the texture now because we need the pointer /* We need to allocate the texture now because we need the pointer
to set as the data for the rectangle in the atlas */ 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 /* Mark it as having no atlas so we don't try to unref it in
_cogl_atlas_texture_post_reorganize_cb */ _cogl_atlas_texture_post_reorganize_cb */
atlas_tex->atlas = NULL; atlas_tex->atlas = NULL;
@ -670,27 +667,53 @@ cogl_atlas_texture_new_with_size (CoglContext *ctx,
_cogl_texture_init (COGL_TEXTURE (atlas_tex), _cogl_texture_init (COGL_TEXTURE (atlas_tex),
ctx, ctx,
width, height, width, height,
internal_format,
loader,
&cogl_atlas_texture_vtable); &cogl_atlas_texture_vtable);
atlas_tex->sub_texture = NULL; atlas_tex->sub_texture = NULL;
atlas_tex->format = internal_format;
atlas_tex->atlas = NULL; atlas_tex->atlas = NULL;
return _cogl_atlas_texture_object_new (atlas_tex); return _cogl_atlas_texture_object_new (atlas_tex);
} }
static CoglBool CoglAtlasTexture *
_cogl_atlas_texture_allocate (CoglTexture *tex, cogl_atlas_texture_new_with_size (CoglContext *ctx,
int width,
int height,
CoglPixelFormat internal_format,
CoglError **error) 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
allocate_space (CoglAtlasTexture *atlas_tex,
int width,
int height,
CoglPixelFormat internal_format,
CoglError **error)
{
CoglTexture *tex = COGL_TEXTURE (atlas_tex);
CoglContext *ctx = tex->context; CoglContext *ctx = tex->context;
CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
CoglAtlas *atlas; CoglAtlas *atlas;
GSList *l; GSList *l;
/* If the texture is in a strange format then we won't use it */ /* 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 " COGL_NOTE (ATLAS, "Texture can not be added because the "
"format is unsupported"); "format is unsupported");
@ -718,7 +741,7 @@ _cogl_atlas_texture_allocate (CoglTexture *tex,
/* Try to make some space in the atlas for the texture */ /* Try to make some space in the atlas for the texture */
if (_cogl_atlas_reserve_space (atlas = l->data, if (_cogl_atlas_reserve_space (atlas = l->data,
/* Add two pixels for the border */ /* Add two pixels for the border */
tex->width + 2, tex->height + 2, width + 2, height + 2,
atlas_tex)) atlas_tex))
{ {
cogl_object_ref (atlas); cogl_object_ref (atlas);
@ -732,7 +755,7 @@ _cogl_atlas_texture_allocate (CoglTexture *tex,
COGL_NOTE (ATLAS, "Created new atlas for textures: %p", atlas); COGL_NOTE (ATLAS, "Created new atlas for textures: %p", atlas);
if (!_cogl_atlas_reserve_space (atlas, if (!_cogl_atlas_reserve_space (atlas,
/* Add two pixels for the border */ /* Add two pixels for the border */
tex->width + 2, tex->height + 2, width + 2, height + 2,
atlas_tex)) atlas_tex))
{ {
/* Ok, this means we really can't add it to the atlas */ /* Ok, this means we really can't add it to the atlas */
@ -746,55 +769,73 @@ _cogl_atlas_texture_allocate (CoglTexture *tex,
} }
} }
atlas_tex->internal_format = internal_format;
atlas_tex->atlas = atlas; atlas_tex->atlas = atlas;
return TRUE; return TRUE;
} }
CoglAtlasTexture * static CoglBool
_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, allocate_with_size (CoglAtlasTexture *atlas_tex,
CoglPixelFormat internal_format, CoglTextureLoader *loader,
CoglBool can_convert_in_place,
CoglError **error) CoglError **error)
{ {
CoglContext *ctx = _cogl_bitmap_get_context (bmp); CoglTexture *tex = COGL_TEXTURE (atlas_tex);
CoglAtlasTexture *atlas_tex; CoglPixelFormat internal_format =
CoglBitmap *upload_bmp; _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
int bmp_width;
int bmp_height;
CoglPixelFormat bmp_format;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL); if (allocate_space (atlas_tex,
loader->src.sized.width,
bmp_width = cogl_bitmap_get_width (bmp); loader->src.sized.height,
bmp_height = cogl_bitmap_get_height (bmp);
bmp_format = cogl_bitmap_get_format (bmp);
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, internal_format,
error); error))
if (!atlas_tex)
return NULL;
if (!cogl_texture_allocate (COGL_TEXTURE (atlas_tex), error))
{ {
cogl_object_unref (atlas_tex); _cogl_texture_set_allocated (COGL_TEXTURE (atlas_tex),
return NULL; internal_format,
loader->src.sized.width,
loader->src.sized.height);
return TRUE;
} }
else
return FALSE;
}
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;
_COGL_RETURN_VAL_IF_FAIL (atlas_tex->atlas == NULL, FALSE);
internal_format = _cogl_texture_determine_internal_format (tex, bmp_format);
upload_bmp = upload_bmp =
_cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex, _cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex,
bmp, bmp,
internal_format,
can_convert_in_place, can_convert_in_place,
error); error);
if (upload_bmp == NULL) if (upload_bmp == NULL)
return FALSE;
if (!allocate_space (atlas_tex,
width,
height,
internal_format,
error))
{ {
cogl_object_unref (atlas_tex); cogl_object_unref (upload_bmp);
return NULL; return FALSE;
} }
/* Defer to set_region so that we can share the code for copying the /* Defer to set_region so that we can share the code for copying the
@ -804,19 +845,65 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
0, /* src_y */ 0, /* src_y */
0, /* dst_x */ 0, /* dst_x */
0, /* dst_y */ 0, /* dst_y */
bmp_width, /* dst_width */ width, /* dst_width */
bmp_height, /* dst_height */ height, /* dst_height */
upload_bmp, upload_bmp,
error)) error))
{ {
_cogl_atlas_texture_remove_from_atlas (atlas_tex);
cogl_object_unref (upload_bmp); cogl_object_unref (upload_bmp);
cogl_object_unref (atlas_tex); return FALSE;
return NULL;
} }
cogl_object_unref (upload_bmp); 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 * CoglAtlasTexture *
@ -859,6 +946,13 @@ cogl_atlas_texture_new_from_data (CoglContext *ctx,
cogl_object_unref (bmp); 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; return atlas_tex;
} }

View File

@ -78,6 +78,11 @@ typedef struct _CoglAtlasTexture CoglAtlasTexture;
* allocate the underlying storage or let Cogl automatically allocate * allocate the underlying storage or let Cogl automatically allocate
* storage lazily. * 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 * <note>This call can fail if Cogl considers the given
* @internal_format incompatible with the format of its internal * @internal_format incompatible with the format of its internal
* atlases.</note> * 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 * represents a sub-region within one of Cogl's shared texture
* atlases. * 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 * @internal_format incompatible with the format of its internal
* atlases.</note> * atlases.</note>
* *
@ -152,7 +167,18 @@ cogl_atlas_texture_new_from_file (CoglContext *ctx,
* memory. A #CoglAtlasTexture represents a sub-region within one of * memory. A #CoglAtlasTexture represents a sub-region within one of
* Cogl's shared texture atlases. * 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 * @internal_format incompatible with the format of its internal
* atlases.</note> * atlases.</note>
* *
@ -192,7 +218,18 @@ cogl_atlas_texture_new_from_data (CoglContext *ctx,
* @bitmap. A #CoglAtlasTexture represents a sub-region within one of * @bitmap. A #CoglAtlasTexture represents a sub-region within one of
* Cogl's shared texture atlases. * 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 * @internal_format incompatible with the format of its internal
* atlases.</note> * atlases.</note>
* *

View File

@ -135,8 +135,8 @@ cogl_context_new (CoglDisplay *display,
CoglError **error) CoglError **error)
{ {
CoglContext *context; CoglContext *context;
uint8_t default_texture_data[] = { 0xff, 0xff, 0xff, 0xff }; uint8_t white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
CoglBitmap *default_texture_bitmap; CoglBitmap *white_pixel_bitmap;
const CoglWinsysVtable *winsys; const CoglWinsysVtable *winsys;
int i; int i;
CoglError *internal_error = NULL; CoglError *internal_error = NULL;
@ -429,41 +429,53 @@ cogl_context_new (CoglDisplay *display,
_cogl_matrix_entry_cache_init (&context->builtin_flushed_projection); _cogl_matrix_entry_cache_init (&context->builtin_flushed_projection);
_cogl_matrix_entry_cache_init (&context->builtin_flushed_modelview); _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 */ /* Create default textures used for fall backs */
context->default_gl_texture_2d_tex = context->default_gl_texture_2d_tex =
cogl_texture_2d_new_from_bitmap (default_texture_bitmap, cogl_texture_2d_new_from_data (context,
/* internal format */ 1, 1,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_RGBA_8888_PRE,
NULL); 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 /* If 3D or rectangle textures aren't supported then these will
* return errors that we can simply ignore. */ * return errors that we can simply ignore. */
internal_error = NULL; internal_error = NULL;
context->default_gl_texture_3d_tex = context->default_gl_texture_3d_tex =
cogl_texture_3d_new_from_bitmap (default_texture_bitmap, cogl_texture_3d_new_from_data (context,
1, /* height */ 1, 1, 1, /* width, height, depth */
1, /* depth */
COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
0, /* rowstride */
0, /* image stride */
white_pixel,
&internal_error); &internal_error);
if (internal_error) if (internal_error)
cogl_error_free (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; internal_error = NULL;
context->default_gl_texture_rect_tex = 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, COGL_PIXEL_FORMAT_RGBA_8888_PRE,
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); &internal_error);
if (internal_error) if (internal_error)
cogl_error_free (internal_error); cogl_error_free (internal_error);
cogl_object_unref (default_texture_bitmap); cogl_object_unref (white_pixel_bitmap);
cogl_push_source (context->opaque_color_pipeline); cogl_push_source (context->opaque_color_pipeline);

View File

@ -141,31 +141,6 @@ struct _CoglDriverVtable
(* texture_2d_allocate) (CoglTexture *tex, (* texture_2d_allocate) (CoglTexture *tex,
CoglError **error); 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 /* Initialize the specified region of storage of the given texture
* with the contents of the specified framebuffer region * with the contents of the specified framebuffer region
*/ */

View File

@ -235,6 +235,8 @@ cogl_sub_texture_new (CoglContext *ctx,
tex = COGL_TEXTURE (sub_tex); tex = COGL_TEXTURE (sub_tex);
_cogl_texture_init (tex, ctx, sub_width, sub_height, _cogl_texture_init (tex, ctx, sub_width, sub_height,
_cogl_texture_get_format (next_texture),
NULL, /* no loader */
&cogl_sub_texture_vtable); &cogl_sub_texture_vtable);
/* If the next texture is also a sub texture we can avoid one level /* 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) CoglError **error)
{ {
CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); 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 * CoglTexture *

View File

@ -49,6 +49,10 @@ COGL_BEGIN_DECLS
* This can be used for integrating Cogl with software using OpenGL * This can be used for integrating Cogl with software using OpenGL
* directly. * 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 * <note>The results are undefined for passing an invalid @gl_handle
* or if @width or @height don't have the correct texture * or if @width or @height don't have the correct texture
* geometry.</note> * geometry.</note>

View File

@ -82,7 +82,8 @@ CoglTexture2D *
_cogl_texture_2d_create_base (CoglContext *ctx, _cogl_texture_2d_create_base (CoglContext *ctx,
int width, int width,
int height, int height,
CoglPixelFormat internal_format); CoglPixelFormat internal_format,
CoglTextureLoader *loader);
void void
_cogl_texture_2d_set_auto_mipmap (CoglTexture *tex, _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,

View File

@ -34,6 +34,7 @@
struct _CoglTexture2DSliced struct _CoglTexture2DSliced
{ {
CoglTexture _parent; CoglTexture _parent;
GArray *slice_x_spans; GArray *slice_x_spans;
GArray *slice_y_spans; GArray *slice_y_spans;
GArray *slice_textures; GArray *slice_textures;

View File

@ -659,8 +659,24 @@ _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 static CoglBool
_cogl_texture_2d_sliced_setup_spans (CoglContext *ctx, setup_spans (CoglContext *ctx,
CoglTexture2DSliced *tex_2ds, CoglTexture2DSliced *tex_2ds,
int width, int width,
int height, int height,
@ -754,8 +770,8 @@ _cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR,
COGL_TEXTURE_ERROR_SIZE, COGL_TEXTURE_ERROR_SIZE,
"No suitable slice geometry found"); "No suitable slice geometry found");
free_spans (tex_2ds);
return FALSE; return FALSE;
} }
} }
@ -791,7 +807,7 @@ _cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
} }
static void static void
_cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds) free_slices (CoglTexture2DSliced *tex_2ds)
{ {
if (tex_2ds->slice_textures != NULL) if (tex_2ds->slice_textures != NULL)
{ {
@ -806,26 +822,12 @@ _cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds)
g_array_free (tex_2ds->slice_textures, TRUE); g_array_free (tex_2ds->slice_textures, TRUE);
} }
}
static void free_spans (tex_2ds);
_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));
} }
static CoglBool static CoglBool
_cogl_texture_2d_sliced_init_base (CoglContext *ctx, allocate_slices (CoglTexture2DSliced *tex_2ds,
CoglTexture2DSliced *tex_2ds,
int width, int width,
int height, int height,
int max_waste, int max_waste,
@ -833,84 +835,23 @@ _cogl_texture_2d_sliced_init_base (CoglContext *ctx,
CoglError **error) CoglError **error)
{ {
CoglTexture *tex = COGL_TEXTURE (tex_2ds); 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; CoglContext *ctx = tex->context;
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
int n_x_slices; int n_x_slices;
int n_y_slices; int n_y_slices;
int n_slices; int n_slices;
int x, y; int x, y;
CoglPixelFormat format = tex_2ds->internal_format;
CoglSpan *x_span; CoglSpan *x_span;
CoglSpan *y_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; return FALSE;
} }
@ -941,11 +882,11 @@ _cogl_texture_2d_sliced_allocate (CoglTexture *tex,
slice = COGL_TEXTURE ( slice = COGL_TEXTURE (
cogl_texture_2d_new_with_size (ctx, cogl_texture_2d_new_with_size (ctx,
x_span->size, y_span->size, x_span->size, y_span->size,
format)); internal_format));
g_array_append_val (tex_2ds->slice_textures, slice); g_array_append_val (tex_2ds->slice_textures, slice);
if (!cogl_texture_allocate (slice, error)) if (!cogl_texture_allocate (slice, error))
{ {
_cogl_texture_2d_sliced_slices_free (tex_2ds); free_slices (tex_2ds);
return FALSE; return FALSE;
} }
} }
@ -954,6 +895,60 @@ _cogl_texture_2d_sliced_allocate (CoglTexture *tex,
return TRUE; return TRUE;
} }
static void
_cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
{
free_slices (tex_2ds);
/* Chain up */
_cogl_texture_free (COGL_TEXTURE (tex_2ds));
}
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);
_cogl_texture_init (COGL_TEXTURE (tex_2ds), ctx, width, height,
internal_format, loader,
&cogl_texture_2d_sliced_vtable);
tex_2ds->max_waste = max_waste;
return _cogl_texture_2d_sliced_object_new (tex_2ds);
}
CoglTexture2DSliced *
cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
int width,
int height,
int max_waste,
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;
return _cogl_texture_2d_sliced_create_base (ctx,
width,
height,
max_waste,
internal_format,
loader);
}
CoglTexture2DSliced * CoglTexture2DSliced *
_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
int max_waste, int max_waste,
@ -961,61 +956,21 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
CoglBool can_convert_in_place, CoglBool can_convert_in_place,
CoglError **error) CoglError **error)
{ {
CoglContext *ctx; CoglTextureLoader *loader;
CoglTexture2DSliced *tex_2ds;
CoglBitmap *upload_bmp;
int width, height;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL); _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), 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;
width = cogl_bitmap_get_width (bmp); return _cogl_texture_2d_sliced_create_base (_cogl_bitmap_get_context (bmp),
height = cogl_bitmap_get_height (bmp); cogl_bitmap_get_width (bmp),
cogl_bitmap_get_height (bmp),
/* Create new texture and fill with loaded data */
tex_2ds = g_new0 (CoglTexture2DSliced, 1);
internal_format =
_cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp),
internal_format);
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;
}
/* 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, max_waste,
internal_format, internal_format,
error)) loader);
goto error;
if (!cogl_texture_allocate (COGL_TEXTURE (tex_2ds), error))
goto error;
if (!_cogl_texture_2d_sliced_upload_bitmap (tex_2ds,
upload_bmp,
error))
goto error;
cogl_object_unref (upload_bmp);
return _cogl_texture_2d_sliced_object_new (tex_2ds);
error:
cogl_object_unref (upload_bmp);
_cogl_texture_2d_sliced_free (tex_2ds);
return NULL;
} }
CoglTexture2DSliced * CoglTexture2DSliced *
@ -1042,85 +997,40 @@ _cogl_texture_2d_sliced_new_from_foreign (CoglContext *ctx,
CoglPixelFormat format, CoglPixelFormat format,
CoglError **error) CoglError **error)
{ {
CoglTextureLoader *loader;
/* NOTE: width, height and internal format are not queriable /* NOTE: width, height and internal format are not queriable
* in GLES, hence such a function prototype. * in GLES, hence such a function prototype.
*/ */
int gl_width = 0;
int gl_height = 0;
CoglTexture2DSliced *tex_2ds;
CoglTexture *tex;
CoglSpan x_span;
CoglSpan y_span;
CoglTexture2D *tex_2d;
/* This should only be called when the texture target is 2D. If a /* This should only be called when the texture target is 2D. If a
rectangle texture is used then _cogl_texture_new_from_foreign rectangle texture is used then _cogl_texture_new_from_foreign
will create a cogl_texture_rectangle instead */ will create a cogl_texture_rectangle instead */
_COGL_RETURN_VAL_IF_FAIL (gl_target == GL_TEXTURE_2D, NULL); _COGL_RETURN_VAL_IF_FAIL (gl_target == GL_TEXTURE_2D, NULL);
gl_width = width + x_pot_waste; /* Assert it is a valid GL texture object */
gl_height = height + y_pot_waste; _COGL_RETURN_VAL_IF_FAIL (ctx->glIsTexture (gl_handle), FALSE);
/* Validate width and height */
_COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL);
/* Validate pot waste */ /* Validate pot waste */
if (x_pot_waste < 0 || x_pot_waste >= width || _COGL_RETURN_VAL_IF_FAIL (x_pot_waste >= 0 && x_pot_waste < width &&
y_pot_waste < 0 || y_pot_waste >= height) y_pot_waste >= 0 && y_pot_waste < height,
return NULL; NULL);
tex_2d = cogl_texture_2d_new_from_foreign (ctx, loader = _cogl_texture_create_loader ();
gl_target, loader->src_type = COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN;
gl_width, loader->src.gl_foreign.gl_handle = gl_handle;
gl_height, loader->src.gl_foreign.width = width + x_pot_waste;
format, loader->src.gl_foreign.height = height + y_pot_waste;
error); loader->src.gl_foreign.format = format;
if (!tex_2d) return _cogl_texture_2d_sliced_create_base (ctx,
return NULL; width,
height,
/* The texture 2d backend may use a different pixel format if it 0, /* max waste */
queries the actual texture so we'll refetch the format it format, loader);
actually used */
format = _cogl_texture_get_format (COGL_TEXTURE (tex_2d));
/* Create new texture */
tex_2ds = g_new0 (CoglTexture2DSliced, 1);
tex = COGL_TEXTURE (tex_2ds);
_cogl_texture_init (tex, ctx, gl_width, gl_height,
&cogl_texture_2d_sliced_vtable);
tex_2ds->max_waste = 0;
tex_2ds->internal_format = format;
/* Create slice arrays */
tex_2ds->slice_x_spans =
g_array_sized_new (FALSE, FALSE,
sizeof (CoglSpan), 1);
tex_2ds->slice_y_spans =
g_array_sized_new (FALSE, FALSE,
sizeof (CoglSpan), 1);
tex_2ds->slice_textures =
g_array_sized_new (FALSE, FALSE,
sizeof (CoglTexture2D *), 1);
/* Store info for a single slice */
x_span.start = 0;
x_span.size = gl_width;
x_span.waste = x_pot_waste;
g_array_append_val (tex_2ds->slice_x_spans, x_span);
y_span.start = 0;
y_span.size = gl_height;
y_span.waste = y_pot_waste;
g_array_append_val (tex_2ds->slice_y_spans, y_span);
g_array_append_val (tex_2ds->slice_textures, tex_2d);
_cogl_texture_set_allocated (COGL_TEXTURE (tex_2ds), TRUE);
return _cogl_texture_2d_sliced_object_new (tex_2ds);
} }
CoglTexture2DSliced * CoglTexture2DSliced *
@ -1157,6 +1067,13 @@ cogl_texture_2d_sliced_new_from_data (CoglContext *ctx,
cogl_object_unref (bmp); 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; return tex_2ds;
} }
@ -1187,6 +1104,175 @@ cogl_texture_2d_sliced_new_from_file (CoglContext *ctx,
return tex_2ds; return tex_2ds;
} }
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
allocate_from_gl_foreign (CoglTexture2DSliced *tex_2ds,
CoglTextureLoader *loader,
CoglError **error)
{
CoglTexture *tex = COGL_TEXTURE (tex_2ds);
CoglContext *ctx = tex->context;
CoglPixelFormat format = loader->src.gl_foreign.format;
int gl_width = loader->src.gl_foreign.width;
int gl_height = loader->src.gl_foreign.height;
int x_pot_waste = gl_width - tex->width;
int y_pot_waste = gl_height - tex->height;
CoglSpan x_span;
CoglSpan y_span;
CoglTexture2D *tex_2d =
cogl_texture_2d_new_from_foreign (ctx,
loader->src.gl_foreign.gl_handle,
gl_width,
gl_height,
format,
error);
if (!tex_2d)
return FALSE;
if (!cogl_texture_allocate (COGL_TEXTURE (tex_2d), error))
return FALSE;
/* The texture 2d backend may use a different pixel format if it
queries the actual texture so we'll refetch the format it
actually used */
format = _cogl_texture_get_format (tex);
tex_2ds->internal_format = format;
/* Create slice arrays */
tex_2ds->slice_x_spans =
g_array_sized_new (FALSE, FALSE, sizeof (CoglSpan), 1);
tex_2ds->slice_y_spans =
g_array_sized_new (FALSE, FALSE, sizeof (CoglSpan), 1);
tex_2ds->slice_textures =
g_array_sized_new (FALSE, FALSE, sizeof (CoglTexture2D *), 1);
/* Store info for a single slice */
x_span.start = 0;
x_span.size = gl_width;
x_span.waste = x_pot_waste;
g_array_append_val (tex_2ds->slice_x_spans, x_span);
y_span.start = 0;
y_span.size = gl_height;
y_span.waste = y_pot_waste;
g_array_append_val (tex_2ds->slice_y_spans, y_span);
g_array_append_val (tex_2ds->slice_textures, tex_2d);
_cogl_texture_set_allocated (tex,
format,
tex->width,
tex->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);
case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN:
return allocate_from_gl_foreign (tex_2ds, loader, error);
default:
break;
}
g_return_val_if_reached (FALSE);
}
static CoglBool static CoglBool
_cogl_texture_2d_sliced_is_foreign (CoglTexture *tex) _cogl_texture_2d_sliced_is_foreign (CoglTexture *tex)
{ {
@ -1215,17 +1301,10 @@ _cogl_texture_2d_sliced_is_sliced (CoglTexture *tex)
{ {
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
/* It's possible that we failed to calculate valid slicing geometry /* It's only after allocating a sliced texture that we will know
* when initializing the texture due to the max_waste size and in * whether it really needed to be sliced... */
* this case we report that the texture is not sliced. if (!tex->allocated)
* cogl_texture_allocate (tex, NULL);
* In this case though we know that we will be throwing an error
* when this texture is later allocated so it shouldn't really
* matter what we report here since the texture won't be used in the
* end.
*/
if (!tex_2ds->slice_x_spans || !tex_2ds->slice_y_spans)
return FALSE;
if (tex_2ds->slice_x_spans->len != 1 || if (tex_2ds->slice_x_spans->len != 1 ||
tex_2ds->slice_y_spans->len != 1) tex_2ds->slice_y_spans->len != 1)

View File

@ -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 * wasted padding at the bottom and right of the textures is less than
* specified. A negative @max_waste will disable slicing. * 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 * <note>It's possible for the allocation of a sliced texture to fail
* later due to impossible slicing constraints if a negative * later due to impossible slicing constraints if a negative
* @max_waste value is given. If the given virtual texture size is * @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 * wasted padding at the bottom and right of the textures is less than
* specified. A negative @max_waste will disable slicing. * 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 * <note>It's possible for the allocation of a sliced texture to fail
* later due to impossible slicing constraints if a negative * due to impossible slicing constraints if a negative @max_waste
* @max_waste value is given. If the given virtual texture size is * value is given. If the given virtual texture size is larger than is
* larger than is supported by the hardware but slicing is disabled * supported by the hardware but slicing is disabled the texture size
* the texture size would be too large to handle.</note> * would be too large to handle.</note>
* *
* Return value: (transfer full): A newly created #CoglTexture2DSliced * Return value: (transfer full): A newly created #CoglTexture2DSliced
* or %NULL on failure and @error will be updated. * 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 * wasted padding at the bottom and right of the textures is less than
* specified. A negative @max_waste will disable slicing. * 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 * <note>It's possible for the allocation of a sliced texture to fail
* later due to impossible slicing constraints if a negative * later due to impossible slicing constraints if a negative
* @max_waste value is given. If the given virtual texture size is * @max_waste value is given. If the given virtual texture size is

View File

@ -75,25 +75,6 @@ _cogl_texture_2d_free (CoglTexture2D *tex_2d)
_cogl_texture_free (COGL_TEXTURE (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 void
_cogl_texture_2d_set_auto_mipmap (CoglTexture *tex, _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,
CoglBool value) CoglBool value)
@ -107,20 +88,20 @@ CoglTexture2D *
_cogl_texture_2d_create_base (CoglContext *ctx, _cogl_texture_2d_create_base (CoglContext *ctx,
int width, int width,
int height, int height,
CoglPixelFormat internal_format) CoglPixelFormat internal_format,
CoglTextureLoader *loader)
{ {
CoglTexture2D *tex_2d = g_new (CoglTexture2D, 1); CoglTexture2D *tex_2d = g_new (CoglTexture2D, 1);
CoglTexture *tex = COGL_TEXTURE (tex_2d); 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->mipmaps_dirty = TRUE;
tex_2d->auto_mipmap = TRUE; tex_2d->auto_mipmap = TRUE;
tex_2d->is_foreign = FALSE; tex_2d->is_foreign = FALSE;
tex_2d->internal_format = internal_format;
ctx->driver_vtable->texture_2d_init (tex_2d); ctx->driver_vtable->texture_2d_init (tex_2d);
return _cogl_texture_2d_object_new (tex_2d); return _cogl_texture_2d_object_new (tex_2d);
@ -132,13 +113,19 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
int height, int height,
CoglPixelFormat internal_format) CoglPixelFormat internal_format)
{ {
CoglTextureLoader *loader;
/* Since no data, we need some internal format */ /* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY) if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
return _cogl_texture_2d_create_base (ctx, loader = _cogl_texture_create_loader ();
width, height, loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
internal_format); loader->src.sized.width = width;
loader->src.sized.height = height;
return _cogl_texture_2d_create_base (ctx, width, height,
internal_format, loader);
} }
static CoglBool static CoglBool
@ -146,6 +133,7 @@ _cogl_texture_2d_allocate (CoglTexture *tex,
CoglError **error) CoglError **error)
{ {
CoglContext *ctx = tex->context; CoglContext *ctx = tex->context;
return ctx->driver_vtable->texture_2d_allocate (tex, error); 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, CoglBool can_convert_in_place,
CoglError **error) CoglError **error)
{ {
CoglContext *ctx; CoglTextureLoader *loader;
_COGL_RETURN_VAL_IF_FAIL (bmp != NULL, NULL); _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 = return _cogl_texture_2d_create_base (_cogl_bitmap_get_context (bmp),
_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_width (bmp),
cogl_bitmap_get_height (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, internal_format,
can_convert_in_place, loader);
error);
} }
CoglTexture2D * CoglTexture2D *
@ -249,6 +225,13 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
cogl_object_unref (bmp); 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; return tex_2d;
} }
@ -264,6 +247,8 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
EGLImageKHR image, EGLImageKHR image,
CoglError **error) CoglError **error)
{ {
CoglTextureLoader *loader;
_COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints & _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
COGL_RENDERER_CONSTRAINT_USES_EGL, COGL_RENDERER_CONSTRAINT_USES_EGL,
NULL); NULL);
@ -273,22 +258,14 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE), COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE),
NULL); NULL);
if (ctx->driver_vtable->egl_texture_2d_new_from_image) loader = _cogl_texture_create_loader ();
return ctx->driver_vtable->egl_texture_2d_new_from_image (ctx, loader->src_type = COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE;
width, loader->src.egl_image.image = image;
height, loader->src.egl_image.width = width;
format, loader->src.egl_image.height = height;
image, loader->src.egl_image.format = format;
error);
else return _cogl_texture_2d_create_base (ctx, width, height, format, loader);
{
_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;
}
} }
#endif /* defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) */ #endif /* defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) */

View File

@ -3,7 +3,7 @@
* *
* An object oriented GL/GLES Abstraction/Utility Layer * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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 * @height: Height of the texture to allocate
* @internal_format: The format of the texture * @internal_format: The format of the texture
* *
* Allocates a low-level #CoglTexture2D texture that your GPU can * Creates a low-level #CoglTexture2D texture with a given @width and
* texture from directly. This is unlike sliced textures for example * @height that your GPU can texture from directly.
* 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.
* *
* The storage for the texture is not allocated before this function * The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly * 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 * automatically allocate storage lazily when it may know more about
* how the texture is being used and can optimize how it is allocated. * 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 * <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by * textures. You can check support for non power of two textures by
* checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via * 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. * other than straight blending.
* @error: A #CoglError to catch exceptional errors or %NULL * @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 * Return value: (transfer full): A newly created #CoglTexture2D or %NULL on failure
* and @error will be updated. * 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 * @data: pointer the memory region where the source buffer resides
* @error: A #CoglError for exceptions * @error: A #CoglError for exceptions
* *
* Creates a new #CoglTexture2D texture based on data residing in memory. * Creates a low-level #CoglTexture2D texture based on data residing
* These are unlike sliced textures for example which may be comprised * in memory.
* of multiple internal textures, or atlas textures where Cogl has to *
* modify texture coordinates before they may be used 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_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 * <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by * 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. * something other than straight blending.
* @error: A #CoglError for exceptions * @error: A #CoglError for exceptions
* *
* Creates a new #CoglTexture2D texture based on data residing in a * Creates a low-level #CoglTexture2D texture based on data residing
* bitmap. These are unlike sliced textures for example which may be * in a #CoglBitmap.
* comprised of multiple internal textures, or atlas textures where *
* Cogl has to modify texture coordinates before they may be used by * The storage for the texture is not allocated before this function
* the GPU. * 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 * <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by * textures. You can check support for non power of two textures by

View File

@ -116,12 +116,14 @@ _cogl_texture_3d_create_base (CoglContext *ctx,
int width, int width,
int height, int height,
int depth, int depth,
CoglPixelFormat internal_format) CoglPixelFormat internal_format,
CoglTextureLoader *loader)
{ {
CoglTexture3D *tex_3d = g_new (CoglTexture3D, 1); CoglTexture3D *tex_3d = g_new (CoglTexture3D, 1);
CoglTexture *tex = COGL_TEXTURE (tex_3d); 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; tex_3d->gl_texture = 0;
@ -138,72 +140,9 @@ _cogl_texture_3d_create_base (CoglContext *ctx,
tex_3d->gl_legacy_texobj_wrap_mode_t = GL_FALSE; tex_3d->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
tex_3d->gl_legacy_texobj_wrap_mode_p = 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); return _cogl_texture_3d_object_new (tex_3d);
} }
static CoglBool
_cogl_texture_3d_can_create (CoglContext *ctx,
int width,
int height,
int depth,
CoglPixelFormat internal_format,
CoglError **error)
{
GLenum gl_intformat;
GLenum gl_type;
/* This should only happen on GLES */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"3D textures are not supported by the GPU");
return FALSE;
}
/* 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) &&
(!_cogl_util_is_pot (width) ||
!_cogl_util_is_pot (height) ||
!_cogl_util_is_pot (depth)))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"A non-power-of-two size was requested but this is not "
"supported by the GPU");
return FALSE;
}
ctx->driver_vtable->pixel_format_to_gl (ctx,
internal_format,
&gl_intformat,
NULL,
&gl_type);
/* Check that the driver can create a texture with that size */
if (!ctx->texture_driver->size_supported_3d (ctx,
GL_TEXTURE_3D,
gl_intformat,
gl_type,
width,
height,
depth))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"The requested dimensions are not supported by the GPU");
return FALSE;
}
return TRUE;
}
CoglTexture3D * CoglTexture3D *
cogl_texture_3d_new_with_size (CoglContext *ctx, cogl_texture_3d_new_with_size (CoglContext *ctx,
int width, int width,
@ -211,177 +150,46 @@ cogl_texture_3d_new_with_size (CoglContext *ctx,
int depth, int depth,
CoglPixelFormat internal_format) CoglPixelFormat internal_format)
{ {
CoglTextureLoader *loader;
/* Since no data, we need some internal format */ /* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY) if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
return _cogl_texture_3d_create_base (ctx, loader = _cogl_texture_create_loader ();
width, height, depth, loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
internal_format); loader->src.sized.width = width;
} loader->src.sized.height = height;
loader->src.sized.depth = depth;
static CoglBool return _cogl_texture_3d_create_base (ctx, width, height, depth,
_cogl_texture_3d_allocate (CoglTexture *tex, internal_format, loader);
CoglError **error)
{
CoglContext *ctx = tex->context;
CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
GLenum gl_error;
GLenum gl_texture;
if (!_cogl_texture_3d_can_create (ctx,
tex->width,
tex->height,
tex_3d->depth,
tex_3d->internal_format,
error))
return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
tex_3d->internal_format,
&gl_intformat,
&gl_format,
&gl_type);
gl_texture =
ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, tex_3d->internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
gl_texture,
FALSE);
/* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat,
tex->width, tex->height, tex_3d->depth,
0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{
GE( ctx, glDeleteTextures (1, &gl_texture) );
return FALSE;
}
tex_3d->gl_texture = gl_texture;
tex_3d->gl_format = gl_intformat;
return TRUE;
} }
CoglTexture3D * CoglTexture3D *
cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp, cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
unsigned int height, int height,
unsigned int depth, int depth,
CoglPixelFormat internal_format, CoglPixelFormat internal_format,
CoglError **error) CoglError **error)
{ {
CoglTexture3D *tex_3d; CoglTextureLoader *loader;
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); _COGL_RETURN_VAL_IF_FAIL (bmp, NULL);
bmp_width = cogl_bitmap_get_width (bmp); loader = _cogl_texture_create_loader ();
bmp_format = cogl_bitmap_get_format (bmp); 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 */
internal_format = _cogl_texture_determine_internal_format (bmp_format, return _cogl_texture_3d_create_base (_cogl_bitmap_get_context (bmp),
internal_format); cogl_bitmap_get_width (bmp),
if (!_cogl_texture_3d_can_create (ctx,
bmp_width, height, depth,
internal_format,
error))
return NULL;
upload_bmp =
_cogl_bitmap_convert_for_upload (bmp,
internal_format,
FALSE, /* can't convert in place */
error);
if (upload_bmp == NULL)
return NULL;
upload_format = cogl_bitmap_get_format (upload_bmp);
ctx->driver_vtable->pixel_format_to_gl (ctx,
upload_format,
NULL, /* internal format */
&gl_format,
&gl_type);
ctx->driver_vtable->pixel_format_to_gl (ctx,
internal_format,
&gl_intformat,
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))
{
CoglError *ignore = NULL;
uint8_t *data = _cogl_bitmap_map (upload_bmp,
COGL_BUFFER_ACCESS_READ, 0,
&ignore);
tex_3d->first_pixel.gl_format = gl_format;
tex_3d->first_pixel.gl_type = gl_type;
if (data)
{
memcpy (tex_3d->first_pixel.data, data,
_cogl_pixel_format_get_bytes_per_pixel (upload_format));
_cogl_bitmap_unmap (upload_bmp);
}
else
{
g_warning ("Failed to read first pixel of bitmap for "
"glGenerateMipmap fallback");
cogl_error_free (ignore);
memset (tex_3d->first_pixel.data, 0,
_cogl_pixel_format_get_bytes_per_pixel (upload_format));
}
}
tex_3d->gl_texture =
ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
if (!ctx->texture_driver->upload_to_gl_3d (ctx,
GL_TEXTURE_3D,
tex_3d->gl_texture,
FALSE, /* is_foreign */
height, height,
depth, depth,
upload_bmp, internal_format,
gl_intformat, loader);
gl_format,
gl_type,
error))
{
cogl_object_unref (upload_bmp);
cogl_object_unref (tex_3d);
return NULL;
}
tex_3d->gl_format = gl_intformat;
cogl_object_unref (upload_bmp);
_cogl_texture_set_allocated (COGL_TEXTURE (tex_3d), TRUE);
return tex_3d;
} }
CoglTexture3D * CoglTexture3D *
@ -399,14 +207,8 @@ cogl_texture_3d_new_from_data (CoglContext *context,
CoglBitmap *bitmap; CoglBitmap *bitmap;
CoglTexture3D *ret; CoglTexture3D *ret;
/* These are considered a programmer errors so we won't set a _COGL_RETURN_VAL_IF_FAIL (data, NULL);
CoglError. It would be nice if this was a _COGL_RETURN_IF_FAIL but the _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);
rest of Cogl isn't using that */
if (format == COGL_PIXEL_FORMAT_ANY)
return NULL;
if (data == NULL)
return NULL;
/* Rowstride from width if not given */ /* Rowstride from width if not given */
if (rowstride == 0) if (rowstride == 0)
@ -475,9 +277,273 @@ cogl_texture_3d_new_from_data (CoglContext *context,
cogl_object_unref (bitmap); cogl_object_unref (bitmap);
if (ret &&
!cogl_texture_allocate (COGL_TEXTURE (ret), error))
{
cogl_object_unref (ret);
return NULL;
}
return ret; return ret;
} }
static CoglBool
_cogl_texture_3d_can_create (CoglContext *ctx,
int width,
int height,
int depth,
CoglPixelFormat internal_format,
CoglError **error)
{
GLenum gl_intformat;
GLenum gl_type;
/* This should only happen on GLES */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"3D textures are not supported by the GPU");
return FALSE;
}
/* 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) &&
(!_cogl_util_is_pot (width) ||
!_cogl_util_is_pot (height) ||
!_cogl_util_is_pot (depth)))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"A non-power-of-two size was requested but this is not "
"supported by the GPU");
return FALSE;
}
ctx->driver_vtable->pixel_format_to_gl (ctx,
internal_format,
&gl_intformat,
NULL,
&gl_type);
/* Check that the driver can create a texture with that size */
if (!ctx->texture_driver->size_supported_3d (ctx,
GL_TEXTURE_3D,
gl_intformat,
gl_type,
width,
height,
depth))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"The requested dimensions are not supported by the GPU");
return FALSE;
}
return TRUE;
}
static CoglBool
allocate_with_size (CoglTexture3D *tex_3d,
CoglTextureLoader *loader,
CoglError **error)
{
CoglTexture *tex = COGL_TEXTURE (tex_3d);
CoglContext *ctx = tex->context;
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,
width,
height,
depth,
internal_format,
error))
return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
internal_format,
&gl_intformat,
&gl_format,
&gl_type);
gl_texture =
ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
gl_texture,
FALSE);
/* Clear any GL errors */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat,
width, height, depth,
0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{
GE( ctx, glDeleteTextures (1, &gl_texture) );
return FALSE;
}
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;
}
static CoglBool
allocate_from_bitmap (CoglTexture3D *tex_3d,
CoglTextureLoader *loader,
CoglError **error)
{
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 upload_format;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
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 FALSE;
upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
internal_format,
can_convert_in_place,
error);
if (upload_bmp == NULL)
return FALSE;
upload_format = cogl_bitmap_get_format (upload_bmp);
ctx->driver_vtable->pixel_format_to_gl (ctx,
upload_format,
NULL, /* internal format */
&gl_format,
&gl_type);
ctx->driver_vtable->pixel_format_to_gl (ctx,
internal_format,
&gl_intformat,
NULL,
NULL);
/* 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))
{
CoglError *ignore = NULL;
uint8_t *data = _cogl_bitmap_map (upload_bmp,
COGL_BUFFER_ACCESS_READ, 0,
&ignore);
tex_3d->first_pixel.gl_format = gl_format;
tex_3d->first_pixel.gl_type = gl_type;
if (data)
{
memcpy (tex_3d->first_pixel.data, data,
_cogl_pixel_format_get_bytes_per_pixel (upload_format));
_cogl_bitmap_unmap (upload_bmp);
}
else
{
g_warning ("Failed to read first pixel of bitmap for "
"glGenerateMipmap fallback");
cogl_error_free (ignore);
memset (tex_3d->first_pixel.data, 0,
_cogl_pixel_format_get_bytes_per_pixel (upload_format));
}
}
tex_3d->gl_texture =
ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
if (!ctx->texture_driver->upload_to_gl_3d (ctx,
GL_TEXTURE_3D,
tex_3d->gl_texture,
FALSE, /* is_foreign */
height,
depth,
upload_bmp,
gl_intformat,
gl_format,
gl_type,
error))
{
cogl_object_unref (upload_bmp);
return FALSE;
}
tex_3d->gl_format = gl_intformat;
cogl_object_unref (upload_bmp);
tex_3d->depth = loader->src.bitmap.depth;
tex_3d->internal_format = internal_format;
_cogl_texture_set_allocated (tex, internal_format,
bmp_width, loader->src.bitmap.height);
return TRUE;
}
static CoglBool
_cogl_texture_3d_allocate (CoglTexture *tex,
CoglError **error)
{
CoglTexture3D *tex_3d = COGL_TEXTURE_3D (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_3d, loader, error);
case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
return allocate_from_bitmap (tex_3d, loader, error);
default:
break;
}
g_return_val_if_reached (FALSE);
}
static int static int
_cogl_texture_3d_get_max_waste (CoglTexture *tex) _cogl_texture_3d_get_max_waste (CoglTexture *tex)
{ {

View File

@ -56,8 +56,8 @@ typedef struct _CoglTexture3D CoglTexture3D;
* @internal_format: the #CoglPixelFormat to use for the GPU * @internal_format: the #CoglPixelFormat to use for the GPU
* storage of the texture. * storage of the texture.
* *
* Creates a new #CoglTexture3D texture with the specified dimensions * Creates a low-level #CoglTexture3D texture with the specified
* and pixel format. * dimensions and pixel format.
* *
* The storage for the texture is not allocated before this function * The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly * 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 * how the texture is going to be used and can optimize how it is
* allocated. * 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 * <note>This texture will fail to allocate later if
* %COGL_FEATURE_ID_TEXTURE_3D is not advertised. Allocation can also * %COGL_FEATURE_ID_TEXTURE_3D is not advertised. Allocation can also
* fail if the requested dimensions are not supported by the * 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 * @data: pointer the memory region where the source buffer resides
* @error: A CoglError return location. * @error: A CoglError return location.
* *
* Creates a new 3D texture and initializes it with @data. The data is * Creates a low-level 3D texture and initializes it with @data. The
* assumed to be packed array of @depth images. There can be padding * data is assumed to be packed array of @depth images. There can be
* between the images using @image_stride. * padding between the images using @image_stride.
* *
* Note that this function will throw a #CoglError if * <note>This api will always immediately allocate GPU memory for the
* %COGL_FEATURE_ID_TEXTURE_3D is not advertised. It can also fail if the * texture and upload the given data so that the @data pointer does
* requested dimensions are not supported by the GPU. * 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 * 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. * returned through @error.
* Since: 1.10 * Since: 1.10
* Stability: Unstable * Stability: Unstable
@ -148,13 +158,30 @@ cogl_texture_3d_new_from_data (CoglContext *context,
* something other than straight blending. * something other than straight blending.
* @error: A CoglError return location. * @error: A CoglError return location.
* *
* Creates a new 3D texture and initializes it with the images in * Creates a low-level 3D texture and initializes it with the images
* @bitmap. The images are assumed to be packed together after one * in @bitmap. The images are assumed to be packed together after one
* another in the increasing y axis. The height of individual image is * 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 * 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 * actual height of the bitmap can be larger than @height × @depth. In
* this case it assumes there is padding between the images. * 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 * Return value: (transfer full): the newly created texture or %NULL
* if there was an error. * if there was an error.
* Since: 2.0 * Since: 2.0
@ -162,8 +189,8 @@ cogl_texture_3d_new_from_data (CoglContext *context,
*/ */
CoglTexture3D * CoglTexture3D *
cogl_texture_3d_new_from_bitmap (CoglBitmap *bitmap, cogl_texture_3d_new_from_bitmap (CoglBitmap *bitmap,
unsigned int height, int height,
unsigned int depth, int depth,
CoglPixelFormat internal_format, CoglPixelFormat internal_format,
CoglError **error); CoglError **error);

View File

@ -31,6 +31,10 @@
#include "cogl-meta-texture.h" #include "cogl-meta-texture.h"
#include "cogl-framebuffer.h" #include "cogl-framebuffer.h"
#ifdef COGL_HAS_EGL_SUPPORT
#include "cogl-egl-defines.h"
#endif
typedef struct _CoglTextureVtable CoglTextureVtable; typedef struct _CoglTextureVtable CoglTextureVtable;
/* Encodes three possibiloities result of transforming a quad */ /* Encodes three possibiloities result of transforming a quad */
@ -139,15 +143,62 @@ struct _CoglTextureVtable
CoglBool value); 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 struct _CoglTexture
{ {
CoglObject _parent; CoglObject _parent;
CoglContext *context; CoglContext *context;
CoglTextureLoader *loader;
GList *framebuffers; GList *framebuffers;
int max_level; int max_level;
int width; int width;
int height; int height;
CoglBool allocated; CoglBool allocated;
/*
* Internal format
*/
CoglTextureComponents components;
unsigned int premultiplied:1;
const CoglTextureVtable *vtable; const CoglTextureVtable *vtable;
}; };
@ -183,6 +234,8 @@ _cogl_texture_init (CoglTexture *texture,
CoglContext *ctx, CoglContext *ctx,
int width, int width,
int height, int height,
CoglPixelFormat internal_format,
CoglTextureLoader *loader,
const CoglTextureVtable *vtable); const CoglTextureVtable *vtable);
void void
@ -220,12 +273,38 @@ _cogl_texture_pre_paint (CoglTexture *texture, CoglTexturePrePaintFlags flags);
void void
_cogl_texture_ensure_non_quad_rendering (CoglTexture *texture); _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 * This determines a CoglPixelFormat according to texture::components
it will just be returned directly */ * 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 CoglPixelFormat
_cogl_texture_determine_internal_format (CoglPixelFormat src_format, _cogl_texture_determine_internal_format (CoglTexture *texture,
CoglPixelFormat dst_format); 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 CoglBool
_cogl_texture_is_foreign (CoglTexture *texture); _cogl_texture_is_foreign (CoglTexture *texture);
@ -306,9 +385,14 @@ _cogl_texture_get_level_size (CoglTexture *texture,
void void
_cogl_texture_set_allocated (CoglTexture *texture, _cogl_texture_set_allocated (CoglTexture *texture,
CoglBool allocated); CoglPixelFormat internal_format,
int width,
int height);
CoglPixelFormat CoglPixelFormat
_cogl_texture_get_format (CoglTexture *texture); _cogl_texture_get_format (CoglTexture *texture);
CoglTextureLoader *
_cogl_texture_create_loader (void);
#endif /* __COGL_TEXTURE_PRIVATE_H */ #endif /* __COGL_TEXTURE_PRIVATE_H */

View File

@ -166,12 +166,15 @@ static CoglTextureRectangle *
_cogl_texture_rectangle_create_base (CoglContext *ctx, _cogl_texture_rectangle_create_base (CoglContext *ctx,
int width, int width,
int height, int height,
CoglPixelFormat internal_format) CoglPixelFormat internal_format,
CoglTextureLoader *loader)
{ {
CoglTextureRectangle *tex_rect = g_new (CoglTextureRectangle, 1); CoglTextureRectangle *tex_rect = g_new (CoglTextureRectangle, 1);
CoglTexture *tex = COGL_TEXTURE (tex_rect); 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->gl_texture = 0;
tex_rect->is_foreign = FALSE; 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_s = GL_FALSE;
tex_rect->gl_legacy_texobj_wrap_mode_t = 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); return _cogl_texture_rectangle_object_new (tex_rect);
} }
@ -196,16 +197,20 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
CoglPixelFormat internal_format, CoglPixelFormat internal_format,
CoglError **error) CoglError **error)
{ {
CoglTextureLoader *loader;
CoglTextureRectangle *tex_rect; CoglTextureRectangle *tex_rect;
/* Since no data, we need some internal format */ /* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY) if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
tex_rect =_cogl_texture_rectangle_create_base (ctx, loader = _cogl_texture_create_loader ();
width, height, loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
internal_format); loader->src.sized.width = width;
loader->src.sized.height = height;
tex_rect = _cogl_texture_rectangle_create_base (ctx, width, height,
internal_format, loader);
/* XXX: This api has been changed for Cogl 2.0 on the master branch /* XXX: This api has been changed for Cogl 2.0 on the master branch
* to not take a CoglError to allow the storage to be allocated * to not take a CoglError to allow the storage to be allocated
* lazily but since Mutter uses this api we are currently * lazily but since Mutter uses this api we are currently
@ -216,30 +221,38 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
cogl_object_unref (tex_rect); cogl_object_unref (tex_rect);
return NULL; return NULL;
} }
return tex_rect; return tex_rect;
} }
static CoglBool static CoglBool
_cogl_texture_rectangle_allocate (CoglTexture *tex, allocate_with_size (CoglTextureRectangle *tex_rect,
CoglTextureLoader *loader,
CoglError **error) CoglError **error)
{ {
CoglTexture *tex = COGL_TEXTURE (tex_rect);
CoglContext *ctx = tex->context; 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_intformat;
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
GLenum gl_error; GLenum gl_error;
GLenum gl_texture; GLenum gl_texture;
internal_format =
_cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
if (!_cogl_texture_rectangle_can_create (ctx, if (!_cogl_texture_rectangle_can_create (ctx,
tex->width, width,
tex->height, height,
tex_rect->internal_format, internal_format,
error)) error))
return FALSE; return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx, ctx->driver_vtable->pixel_format_to_gl (ctx,
tex_rect->internal_format, internal_format,
&gl_intformat, &gl_intformat,
&gl_format, &gl_format,
&gl_type); &gl_type);
@ -247,7 +260,7 @@ _cogl_texture_rectangle_allocate (CoglTexture *tex,
gl_texture = gl_texture =
ctx->texture_driver->gen (ctx, ctx->texture_driver->gen (ctx,
GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_RECTANGLE_ARB,
tex_rect->internal_format); internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
gl_texture, gl_texture,
tex_rect->is_foreign); tex_rect->is_foreign);
@ -257,7 +270,7 @@ _cogl_texture_rectangle_allocate (CoglTexture *tex,
; ;
ctx->glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat, 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)) if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{ {
@ -265,46 +278,50 @@ _cogl_texture_rectangle_allocate (CoglTexture *tex,
return FALSE; return FALSE;
} }
tex_rect->internal_format = internal_format;
tex_rect->gl_texture = gl_texture; tex_rect->gl_texture = gl_texture;
tex_rect->gl_format = gl_intformat; tex_rect->gl_format = gl_intformat;
_cogl_texture_set_allocated (COGL_TEXTURE (tex_rect),
internal_format, width, height);
return TRUE; return TRUE;
} }
CoglTextureRectangle * static CoglBool
cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp, allocate_from_bitmap (CoglTextureRectangle *tex_rect,
CoglPixelFormat internal_format, CoglTextureLoader *loader,
CoglError **error) 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; CoglBitmap *upload_bmp;
GLenum gl_intformat; GLenum gl_intformat;
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
CoglContext *ctx;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
ctx = _cogl_bitmap_get_context (bmp);
internal_format = internal_format =
_cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp), _cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp));
internal_format);
if (!_cogl_texture_rectangle_can_create (ctx, if (!_cogl_texture_rectangle_can_create (ctx,
cogl_bitmap_get_width (bmp), width,
cogl_bitmap_get_height (bmp), height,
internal_format, internal_format,
error)) error))
return NULL; return FALSE;
upload_bmp = upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
_cogl_bitmap_convert_for_upload (bmp,
internal_format, internal_format,
FALSE, /* can't convert in place */ can_convert_in_place,
error); error);
if (upload_bmp == NULL) if (upload_bmp == NULL)
return NULL; return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx, ctx->driver_vtable->pixel_format_to_gl (ctx,
cogl_bitmap_get_format (upload_bmp), cogl_bitmap_get_format (upload_bmp),
@ -317,11 +334,6 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
NULL, NULL,
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 = tex_rect->gl_texture =
ctx->texture_driver->gen (ctx, ctx->texture_driver->gen (ctx,
GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_RECTANGLE_ARB,
@ -337,38 +349,31 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
error)) error))
{ {
cogl_object_unref (upload_bmp); cogl_object_unref (upload_bmp);
cogl_object_unref (tex_rect); return FALSE;
return NULL;
} }
tex_rect->gl_format = gl_intformat; tex_rect->gl_format = gl_intformat;
tex_rect->internal_format = internal_format;
cogl_object_unref (upload_bmp); 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 * static CoglBool
cogl_texture_rectangle_new_from_foreign (CoglContext *ctx, allocate_from_gl_foreign (CoglTextureRectangle *tex_rect,
unsigned int gl_handle, CoglTextureLoader *loader,
int width,
int height,
CoglPixelFormat format,
CoglError **error) CoglError **error)
{ {
/* NOTE: width, height and internal format are not queriable CoglTexture *tex = COGL_TEXTURE (tex_rect);
* in GLES, hence such a function prototype. CoglContext *ctx = tex->context;
*/ CoglPixelFormat format = loader->src.gl_foreign.format;
GLenum gl_error = 0; GLenum gl_error = 0;
GLint gl_compressed = GL_FALSE; GLint gl_compressed = GL_FALSE;
GLenum gl_int_format = 0; 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, if (!ctx->texture_driver->allows_foreign_gl_target (ctx,
GL_TEXTURE_RECTANGLE_ARB)) GL_TEXTURE_RECTANGLE_ARB))
@ -378,21 +383,22 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR_UNSUPPORTED, COGL_SYSTEM_ERROR_UNSUPPORTED,
"Foreign GL_TEXTURE_RECTANGLE textures are not " "Foreign GL_TEXTURE_RECTANGLE textures are not "
"supported by your system"); "supported by your system");
return NULL; return FALSE;
} }
/* Make sure binding succeeds */ /* Make sure binding succeeds */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) 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) if (ctx->glGetError () != GL_NO_ERROR)
{ {
_cogl_set_error (error, _cogl_set_error (error,
COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED, COGL_SYSTEM_ERROR_UNSUPPORTED,
"Failed to bind foreign GL_TEXTURE_RECTANGLE texture"); "Failed to bind foreign GL_TEXTURE_RECTANGLE texture");
return NULL; return FALSE;
} }
/* Obtain texture parameters */ /* Obtain texture parameters */
@ -423,7 +429,7 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED, COGL_SYSTEM_ERROR_UNSUPPORTED,
"Unsupported internal format for foreign texture"); "Unsupported internal format for foreign texture");
return NULL; return FALSE;
} }
} }
else else
@ -438,16 +444,6 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
NULL); 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 */ /* Compressed texture images not supported */
if (gl_compressed == GL_TRUE) if (gl_compressed == GL_TRUE)
{ {
@ -455,27 +451,107 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED, COGL_SYSTEM_ERROR_UNSUPPORTED,
"Compressed foreign textures aren't currently supported"); "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 */ /* Setup bitmap info */
tex_rect->is_foreign = TRUE; tex_rect->is_foreign = TRUE;
tex_rect->internal_format = format; tex_rect->gl_texture = loader->src.gl_foreign.gl_handle;
tex_rect->gl_texture = gl_handle;
tex_rect->gl_format = gl_int_format; tex_rect->gl_format = gl_int_format;
/* Unknown filter */ /* Unknown filter */
tex_rect->gl_legacy_texobj_min_filter = GL_FALSE; tex_rect->gl_legacy_texobj_min_filter = GL_FALSE;
tex_rect->gl_legacy_texobj_mag_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;
return tex_rect; _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 _cogl_texture_rectangle_create_base (ctx, width, height,
format, loader);
} }
static int static int

View File

@ -102,6 +102,11 @@ cogl_is_texture_rectangle (void *object);
* first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature * first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature
* using cogl_has_feature().</note> * using cogl_has_feature().</note>
* *
* <note>For compatibility, unlike other texture constructors, this
* api allocates texture storage synchronously and returns %NULL on
* failure so it is not possible to configure rectangle textures
* created with this api before allocation.</note>
*
* Return value: (transfer full): A pointer to a newly allocated * Return value: (transfer full): A pointer to a newly allocated
* #CoglTextureRectangle texture or if the size was too large * #CoglTextureRectangle texture or if the size was too large
* or there wasn't enough memory %NULL is returned and @error * or there wasn't enough memory %NULL is returned and @error
@ -144,10 +149,18 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
* first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature * first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature
* using cogl_has_feature().</note> * 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.
*
* Return value: (transfer full): A pointer to a newly allocated * Return value: (transfer full): A pointer to a newly allocated
* #CoglTextureRectangle texture or if the size was too large * #CoglTextureRectangle texture or if the size was too large
* or there wasn't enough memory %NULL is returned and @error * or there wasn't enough memory %NULL is returned and @error
* set. * set.
*
* Since: 2.0 * Since: 2.0
* Stability: unstable * Stability: unstable
*/ */
@ -185,12 +198,15 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bitmap,
* <note>Applications wanting to use #CoglTextureRectangle should * <note>Applications wanting to use #CoglTextureRectangle should
* first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature * first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature
* using cogl_has_feature().</note> * 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().
*
* Return value: (transfer full): A newly allocated * Return value: (transfer full): A newly allocated
* #CoglTextureRectangle, or if Cogl could not validate the * #CoglTextureRectangle, or if Cogl could not validate the
* @gl_handle in some way (perhaps because of an unsupported * @gl_handle in some way (perhaps because of an unsupported
* format) it will return %NULL and set @error. * format) it will return %NULL and set @error.
*
*/ */
CoglTextureRectangle * CoglTextureRectangle *
cogl_texture_rectangle_new_from_foreign (CoglContext *ctx, cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,

View File

@ -107,6 +107,8 @@ _cogl_texture_init (CoglTexture *texture,
CoglContext *context, CoglContext *context,
int width, int width,
int height, int height,
CoglPixelFormat internal_format,
CoglTextureLoader *loader,
const CoglTextureVtable *vtable) const CoglTextureVtable *vtable)
{ {
texture->context = context; texture->context = context;
@ -116,11 +118,44 @@ _cogl_texture_init (CoglTexture *texture,
texture->allocated = FALSE; texture->allocated = FALSE;
texture->vtable = vtable; texture->vtable = vtable;
texture->framebuffers = NULL; texture->framebuffers = NULL;
texture->loader = loader;
_cogl_texture_set_internal_format (texture, internal_format);
}
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 void
_cogl_texture_free (CoglTexture *texture) _cogl_texture_free (CoglTexture *texture)
{ {
_cogl_texture_free_loader (texture);
g_free (texture); g_free (texture);
} }
@ -135,34 +170,6 @@ _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format,
(dst_format & COGL_PREMULT_BIT)); (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 CoglBool
_cogl_texture_is_foreign (CoglTexture *texture) _cogl_texture_is_foreign (CoglTexture *texture)
{ {
@ -1348,9 +1355,17 @@ _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans,
void void
_cogl_texture_set_allocated (CoglTexture *texture, _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 CoglBool
@ -1364,3 +1379,127 @@ cogl_texture_allocate (CoglTexture *texture,
return texture->allocated; 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;
}

View File

@ -256,6 +256,96 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
CoglBool CoglBool
cogl_is_texture (void *object); 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: * cogl_texture_get_width:
* @texture: a #CoglTexture pointer. * @texture: a #CoglTexture pointer.

View File

@ -25,13 +25,12 @@
* Robert Bragg <robert@linux.intel.com> * Robert Bragg <robert@linux.intel.com>
*/ */
#ifdef HAVE_CONFIG_H #include <config.h>
#include "config.h"
#endif
#include <string.h> #include <string.h>
#include "cogl-private.h" #include "cogl-private.h"
#include "cogl-texture-private.h"
#include "cogl-texture-2d-gl.h" #include "cogl-texture-2d-gl.h"
#include "cogl-texture-2d-gl-private.h" #include "cogl-texture-2d-gl-private.h"
#include "cogl-texture-2d-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_format;
GLenum gl_type; 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, ctx->driver_vtable->pixel_format_to_gl (ctx,
internal_format, internal_format,
&gl_intformat, &gl_intformat,
@ -90,22 +96,29 @@ _cogl_texture_2d_gl_init (CoglTexture2D *tex_2d)
tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE; tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
} }
CoglBool static CoglBool
_cogl_texture_2d_gl_allocate (CoglTexture *tex, allocate_with_size (CoglTexture2D *tex_2d,
CoglTextureLoader *loader,
CoglError **error) 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; CoglContext *ctx = tex->context;
CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
GLenum gl_intformat; GLenum gl_intformat;
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
GLenum gl_error; GLenum gl_error;
GLenum gl_texture; GLenum gl_texture;
internal_format =
_cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
if (!_cogl_texture_2d_gl_can_create (ctx, if (!_cogl_texture_2d_gl_can_create (ctx,
tex->width, width,
tex->height, height,
tex_2d->internal_format)) internal_format))
{ {
_cogl_set_error (error, COGL_TEXTURE_ERROR, _cogl_set_error (error, COGL_TEXTURE_ERROR,
COGL_TEXTURE_ERROR_SIZE, COGL_TEXTURE_ERROR_SIZE,
@ -115,13 +128,12 @@ _cogl_texture_2d_gl_allocate (CoglTexture *tex,
} }
ctx->driver_vtable->pixel_format_to_gl (ctx, ctx->driver_vtable->pixel_format_to_gl (ctx,
tex_2d->internal_format, internal_format,
&gl_intformat, &gl_intformat,
&gl_format, &gl_format,
&gl_type); &gl_type);
gl_texture = gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, tex_2d->internal_format);
tex_2d->gl_internal_format = gl_intformat; 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, 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)) 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_texture = gl_texture;
tex_2d->gl_internal_format = gl_intformat; tex_2d->gl_internal_format = gl_intformat;
tex_2d->internal_format = internal_format;
_cogl_texture_set_allocated (tex, internal_format, width, height);
return TRUE; return TRUE;
} }
CoglTexture2D * static CoglBool
_cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp, allocate_from_bitmap (CoglTexture2D *tex_2d,
CoglPixelFormat internal_format, CoglTextureLoader *loader,
CoglBool can_convert_in_place,
CoglError **error) CoglError **error)
{ {
CoglTexture *tex = COGL_TEXTURE (tex_2d);
CoglBitmap *bmp = loader->src.bitmap.bitmap;
CoglContext *ctx = _cogl_bitmap_get_context (bmp); 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; CoglBitmap *upload_bmp;
GLenum gl_intformat; GLenum gl_intformat;
GLenum gl_format; GLenum gl_format;
GLenum gl_type; 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, upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
internal_format, internal_format,
can_convert_in_place, can_convert_in_place,
error); error);
if (upload_bmp == NULL) if (upload_bmp == NULL)
return NULL; return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx, ctx->driver_vtable->pixel_format_to_gl (ctx,
cogl_bitmap_get_format (upload_bmp), cogl_bitmap_get_format (upload_bmp),
@ -179,11 +214,6 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
NULL, NULL,
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 /* Keep a copy of the first pixel so that if glGenerateMipmap isn't
supported we can fallback to using GL_GENERATE_MIPMAP */ supported we can fallback to using GL_GENERATE_MIPMAP */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
@ -226,44 +256,40 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
error)) error))
{ {
cogl_object_unref (upload_bmp); cogl_object_unref (upload_bmp);
cogl_object_unref (tex_2d); return FALSE;
return NULL;
} }
tex_2d->gl_internal_format = gl_intformat; tex_2d->gl_internal_format = gl_intformat;
cogl_object_unref (upload_bmp); cogl_object_unref (upload_bmp);
_cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE); tex_2d->internal_format = internal_format;
return tex_2d; _cogl_texture_set_allocated (tex, internal_format, width, height);
return TRUE;
} }
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
CoglTexture2D * static CoglBool
_cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx, allocate_from_egl_image (CoglTexture2D *tex_2d,
int width, CoglTextureLoader *loader,
int height,
CoglPixelFormat format,
EGLImageKHR image,
CoglError **error) 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; GLenum gl_error;
tex_2d = _cogl_texture_2d_create_base (ctx,
width, height,
format);
tex_2d->gl_texture = 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, _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
tex_2d->gl_texture, tex_2d->gl_texture,
FALSE); FALSE);
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) 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) if (ctx->glGetError () != GL_NO_ERROR)
{ {
_cogl_set_error (error, _cogl_set_error (error,
@ -271,16 +297,175 @@ _cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx,
COGL_TEXTURE_ERROR_BAD_PARAMETER, COGL_TEXTURE_ERROR_BAD_PARAMETER,
"Could not create a CoglTexture2D from a given " "Could not create a CoglTexture2D from a given "
"EGLImage"); "EGLImage");
cogl_object_unref (tex_2d); GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) );
return NULL; return FALSE;
} }
_cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE); tex_2d->internal_format = internal_format;
return tex_2d; _cogl_texture_set_allocated (tex,
internal_format,
loader->src.egl_image.width,
loader->src.egl_image.height);
return TRUE;
} }
#endif #endif
static CoglBool
allocate_from_gl_foreign (CoglTexture2D *tex_2d,
CoglTextureLoader *loader,
CoglError **error)
{
CoglTexture *tex = COGL_TEXTURE (tex_2d);
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;
if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_2D))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Foreign GL_TEXTURE_2D textures are not "
"supported by your system");
return FALSE;
}
/* Make sure binding succeeds */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
_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 FALSE;
}
/* Obtain texture parameters
(only level 0 we are interested in) */
#ifdef HAVE_COGL_GL
if (_cogl_has_private_feature
(ctx, COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS))
{
GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
GL_TEXTURE_COMPRESSED,
&gl_compressed) );
{
GLint val;
GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
GL_TEXTURE_INTERNAL_FORMAT,
&val) );
gl_int_format = val;
}
/* If we can query GL for the actual pixel format then we'll ignore
the passed in format and use that. */
if (!ctx->driver_vtable->pixel_format_from_gl_internal (ctx,
gl_int_format,
&format))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Unsupported internal format for foreign texture");
return FALSE;
}
}
else
#endif
{
/* Otherwise we'll assume we can derive the GL format from the
passed in format */
ctx->driver_vtable->pixel_format_to_gl (ctx,
format,
&gl_int_format,
NULL,
NULL);
}
/* Compressed texture images not supported */
if (gl_compressed == GL_TRUE)
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Compressed foreign textures aren't currently supported");
return FALSE;
}
/* Note: previously this code would query the texture object for
whether it has GL_GENERATE_MIPMAP enabled to determine whether to
auto-generate the mipmap. This doesn't make much sense any more
since Cogl switch to using glGenerateMipmap. Ideally I think
cogl_texture_2d_new_from_foreign should take a flags parameter so
that the application can decide whether it wants
auto-mipmapping. To be compatible with existing code, Cogl now
disables its own auto-mipmapping but leaves the value of
GL_GENERATE_MIPMAP alone so that it would still work but without
the dirtiness tracking that Cogl would do. */
_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 = 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;
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 void
_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex, _cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex,
GLenum min_filter, GLenum min_filter,
@ -343,89 +528,12 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
CoglPixelFormat format, CoglPixelFormat format,
CoglError **error) CoglError **error)
{ {
CoglTextureLoader *loader;
/* NOTE: width, height and internal format are not queriable /* NOTE: width, height and internal format are not queriable
* in GLES, hence such a function prototype. * in GLES, hence such a function prototype.
*/ */
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))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Foreign GL_TEXTURE_2D textures are not "
"supported by your system");
return NULL;
}
/* Make sure binding succeeds */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
_cogl_bind_gl_texture_transient (GL_TEXTURE_2D, 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;
}
/* Obtain texture parameters
(only level 0 we are interested in) */
#ifdef HAVE_COGL_GL
if (_cogl_has_private_feature
(ctx, COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS))
{
GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
GL_TEXTURE_COMPRESSED,
&gl_compressed) );
{
GLint val;
GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
GL_TEXTURE_INTERNAL_FORMAT,
&val) );
gl_int_format = val;
}
/* If we can query GL for the actual pixel format then we'll ignore
the passed in format and use that. */
if (!ctx->driver_vtable->pixel_format_from_gl_internal (ctx,
gl_int_format,
&format))
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Unsupported internal format for foreign texture");
return NULL;
}
}
else
#endif
{
/* Otherwise we'll assume we can derive the GL format from the
passed in format */
ctx->driver_vtable->pixel_format_to_gl (ctx,
format,
&gl_int_format,
NULL,
NULL);
}
/* Note: We always trust the given width and height without querying /* Note: We always trust the given width and height without querying
* the texture object because the user may be creating a Cogl * the texture object because the user may be creating a Cogl
* texture for a texture_from_pixmap object where glTexImage2D may * texture for a texture_from_pixmap object where glTexImage2D may
@ -433,50 +541,20 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
* clarify that it is reliable to query back the size from OpenGL. * 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 */ /* Validate width and height */
g_return_val_if_fail (width > 0 && height > 0, NULL); _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL);
/* Compressed texture images not supported */ loader = _cogl_texture_create_loader ();
if (gl_compressed == GL_TRUE) loader->src_type = COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN;
{ loader->src.gl_foreign.gl_handle = gl_handle;
_cogl_set_error (error, loader->src.gl_foreign.width = width;
COGL_SYSTEM_ERROR, loader->src.gl_foreign.height = height;
COGL_SYSTEM_ERROR_UNSUPPORTED, loader->src.gl_foreign.format = format;
"Compressed foreign textures aren't currently supported");
return NULL;
}
/* Note: previously this code would query the texture object for return _cogl_texture_2d_create_base (ctx, width, height, format, loader);
whether it has GL_GENERATE_MIPMAP enabled to determine whether to
auto-generate the mipmap. This doesn't make much sense any more
since Cogl switch to using glGenerateMipmap. Ideally I think
cogl_texture_2d_new_from_foreign should take a flags parameter so
that the application can decide whether it wants
auto-mipmapping. To be compatible with existing code, Cogl now
disables its own auto-mipmapping but leaves the value of
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_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);
return tex_2d;
} }
void void

View File

@ -678,10 +678,6 @@ _cogl_driver_gl =
_cogl_texture_2d_gl_can_create, _cogl_texture_2d_gl_can_create,
_cogl_texture_2d_gl_init, _cogl_texture_2d_gl_init,
_cogl_texture_2d_gl_allocate, _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_copy_from_framebuffer,
_cogl_texture_2d_gl_get_gl_handle, _cogl_texture_2d_gl_get_gl_handle,
_cogl_texture_2d_gl_generate_mipmap, _cogl_texture_2d_gl_generate_mipmap,

View File

@ -397,10 +397,6 @@ _cogl_driver_gles =
_cogl_texture_2d_gl_can_create, _cogl_texture_2d_gl_can_create,
_cogl_texture_2d_gl_init, _cogl_texture_2d_gl_init,
_cogl_texture_2d_gl_allocate, _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_copy_from_framebuffer,
_cogl_texture_2d_gl_get_gl_handle, _cogl_texture_2d_gl_get_gl_handle,
_cogl_texture_2d_gl_generate_mipmap, _cogl_texture_2d_gl_generate_mipmap,

View File

@ -69,10 +69,6 @@ _cogl_driver_nop =
_cogl_texture_2d_nop_can_create, _cogl_texture_2d_nop_can_create,
_cogl_texture_2d_nop_init, _cogl_texture_2d_nop_init,
_cogl_texture_2d_nop_allocate, _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_copy_from_framebuffer,
_cogl_texture_2d_nop_get_gl_handle, _cogl_texture_2d_nop_get_gl_handle,
_cogl_texture_2d_nop_generate_mipmap, _cogl_texture_2d_nop_generate_mipmap,

View File

@ -48,22 +48,6 @@ CoglBool
_cogl_texture_2d_nop_allocate (CoglTexture *tex, _cogl_texture_2d_nop_allocate (CoglTexture *tex,
CoglError **error); 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 void
_cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex, _cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex,
GLenum min_filter, GLenum min_filter,

View File

@ -62,36 +62,6 @@ _cogl_texture_2d_nop_allocate (CoglTexture *tex,
return TRUE; 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 void
_cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex, _cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex,
GLenum min_filter, GLenum min_filter,

View File

@ -287,6 +287,7 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
int pixmap_x, pixmap_y; int pixmap_x, pixmap_y;
unsigned int pixmap_width, pixmap_height; unsigned int pixmap_width, pixmap_height;
unsigned int pixmap_border_width; unsigned int pixmap_border_width;
CoglPixelFormat internal_format;
CoglTexture *tex = COGL_TEXTURE (tex_pixmap); CoglTexture *tex = COGL_TEXTURE (tex_pixmap);
XWindowAttributes window_attributes; XWindowAttributes window_attributes;
int damage_base; int damage_base;
@ -305,7 +306,15 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
return NULL; 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, _cogl_texture_init (tex, ctxt, pixmap_width, pixmap_height,
internal_format,
NULL, /* no loader */
&cogl_texture_pixmap_x11_vtable); &cogl_texture_pixmap_x11_vtable);
tex_pixmap->pixmap = pixmap; tex_pixmap->pixmap = pixmap;
@ -326,6 +335,7 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
"Unable to query root window attributes"); "Unable to query root window attributes");
return NULL; return NULL;
} }
tex_pixmap->visual = window_attributes.visual; tex_pixmap->visual = window_attributes.visual;
/* If automatic updates are requested and the Xlib connection /* 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 */ /* Assume the entire pixmap is damaged to begin with */
tex_pixmap->damage_rect.x1 = 0; 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.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); winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap);
if (winsys->texture_pixmap_x11_create) if (winsys->texture_pixmap_x11_create)
@ -362,7 +372,8 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
if (!tex_pixmap->use_winsys_texture) if (!tex_pixmap->use_winsys_texture)
tex_pixmap->winsys = NULL; 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); return _cogl_texture_pixmap_x11_object_new (tex_pixmap);
} }

View File

@ -1,4 +1,5 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include <cogl/cogl.h> #include <cogl/cogl.h>
#include <cogl-gst/cogl-gst.h> #include <cogl-gst/cogl-gst.h>