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
same format as the atlas texture because we can store
pre-multiplied and non-pre-multiplied textures together */
CoglPixelFormat format;
CoglPixelFormat internal_format;
/* The rectangle that was used to add this texture to the
atlas. This includes the 1-pixel border */

View File

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

View File

@ -78,6 +78,11 @@ typedef struct _CoglAtlasTexture CoglAtlasTexture;
* allocate the underlying storage or let Cogl automatically allocate
* storage lazily.
*
* The texture is still configurable until it has been allocated so
* for example you can influence the internal format of the texture
* using cogl_texture_set_components() and
* cogl_texture_set_premultiplied().
*
* <note>This call can fail if Cogl considers the given
* @internal_format incompatible with the format of its internal
* atlases.</note>
@ -109,7 +114,17 @@ cogl_atlas_texture_new_with_size (CoglContext *ctx,
* represents a sub-region within one of Cogl's shared texture
* atlases.
*
* <note>This call can fail if Cogl considers the given
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
* allocate the underlying storage or let Cogl automatically allocate
* storage lazily.
*
* The texture is still configurable until it has been allocated so
* for example you can influence the internal format of the texture
* using cogl_texture_set_components() and
* cogl_texture_set_premultiplied().
*
* <note>Allocation can fail later if Cogl considers the given
* @internal_format incompatible with the format of its internal
* atlases.</note>
*
@ -152,7 +167,18 @@ cogl_atlas_texture_new_from_file (CoglContext *ctx,
* memory. A #CoglAtlasTexture represents a sub-region within one of
* Cogl's shared texture atlases.
*
* <note>This call can fail if Cogl considers the given
* <note>This api will always immediately allocate GPU memory for the
* texture and upload the given data so that the @data pointer does
* not need to remain valid once this function returns. This means it
* is not possible to configure the texture before it is allocated. If
* you do need to configure the texture before allocation (to specify
* constraints on the internal format for example) then you can
* instead create a #CoglBitmap for your data and use
* cogl_atlas_texture_new_from_bitmap() or use
* cogl_atlas_texture_new_with_size() and then upload data using
* cogl_texture_set_data()</note>
*
* <note>Allocation can fail if Cogl considers the given
* @internal_format incompatible with the format of its internal
* atlases.</note>
*
@ -192,7 +218,18 @@ cogl_atlas_texture_new_from_data (CoglContext *ctx,
* @bitmap. A #CoglAtlasTexture represents a sub-region within one of
* Cogl's shared texture atlases.
*
* <note>This call can fail if Cogl considers the given
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
* allocate the underlying storage or preferably let Cogl
* automatically allocate storage lazily when it may know more about
* how the texture is being used and can optimize how it is allocated.
*
* The texture is still configurable until it has been allocated so
* for example you can influence the internal format of the texture
* using cogl_texture_set_components() and
* cogl_texture_set_premultiplied().
*
* <note>Allocation can fail if Cogl considers the given
* @internal_format incompatible with the format of its internal
* atlases.</note>
*

View File

@ -135,8 +135,8 @@ cogl_context_new (CoglDisplay *display,
CoglError **error)
{
CoglContext *context;
uint8_t default_texture_data[] = { 0xff, 0xff, 0xff, 0xff };
CoglBitmap *default_texture_bitmap;
uint8_t white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
CoglBitmap *white_pixel_bitmap;
const CoglWinsysVtable *winsys;
int i;
CoglError *internal_error = NULL;
@ -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_modelview);
default_texture_bitmap =
cogl_bitmap_new_for_data (context,
1, 1, /* width/height */
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
4, /* rowstride */
default_texture_data);
/* Create default textures used for fall backs */
context->default_gl_texture_2d_tex =
cogl_texture_2d_new_from_bitmap (default_texture_bitmap,
/* internal format */
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
NULL);
cogl_texture_2d_new_from_data (context,
1, 1,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
0, /* rowstride */
white_pixel,
NULL); /* abort on error */
/* If 3D or rectangle textures aren't supported then these will
* return errors that we can simply ignore. */
internal_error = NULL;
context->default_gl_texture_3d_tex =
cogl_texture_3d_new_from_bitmap (default_texture_bitmap,
1, /* height */
1, /* depth */
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
&internal_error);
cogl_texture_3d_new_from_data (context,
1, 1, 1, /* width, height, depth */
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
0, /* rowstride */
0, /* image stride */
white_pixel,
&internal_error);
if (internal_error)
cogl_error_free (internal_error);
/* TODO: add cogl_texture_rectangle_new_from_data() */
white_pixel_bitmap =
cogl_bitmap_new_for_data (context,
1, 1, /* width/height */
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
4, /* rowstride */
white_pixel);
internal_error = NULL;
context->default_gl_texture_rect_tex =
cogl_texture_rectangle_new_from_bitmap (default_texture_bitmap,
cogl_texture_rectangle_new_from_bitmap (white_pixel_bitmap,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
&internal_error);
NULL); /* legacy error argument */
/* XXX: we need to allocate the texture now because the white_pixel
* data is on the stack */
cogl_texture_allocate (COGL_TEXTURE (context->default_gl_texture_rect_tex),
&internal_error);
if (internal_error)
cogl_error_free (internal_error);
cogl_object_unref (default_texture_bitmap);
cogl_object_unref (white_pixel_bitmap);
cogl_push_source (context->opaque_color_pipeline);

View File

@ -141,31 +141,6 @@ struct _CoglDriverVtable
(* texture_2d_allocate) (CoglTexture *tex,
CoglError **error);
/* Instantiates a new CoglTexture2D object with storage initialized
* with the contents of the given bitmap, using the specified
* internal format.
*/
CoglTexture2D *
(* texture_2d_new_from_bitmap) (CoglBitmap *bmp,
CoglPixelFormat internal_format,
CoglBool can_convert_in_place,
CoglError **error);
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
/* Instantiates a new CoglTexture2D object with storage initialized
* with the contents of the given EGL image.
*
* This is optional for drivers to support
*/
CoglTexture2D *
(* egl_texture_2d_new_from_image) (CoglContext *ctx,
int width,
int height,
CoglPixelFormat format,
EGLImageKHR image,
CoglError **error);
#endif
/* Initialize the specified region of storage of the given texture
* with the contents of the specified framebuffer region
*/

View File

@ -235,6 +235,8 @@ cogl_sub_texture_new (CoglContext *ctx,
tex = COGL_TEXTURE (sub_tex);
_cogl_texture_init (tex, ctx, sub_width, sub_height,
_cogl_texture_get_format (next_texture),
NULL, /* no loader */
&cogl_sub_texture_vtable);
/* If the next texture is also a sub texture we can avoid one level
@ -264,8 +266,13 @@ _cogl_sub_texture_allocate (CoglTexture *tex,
CoglError **error)
{
CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
CoglBool status = cogl_texture_allocate (sub_tex->full_texture, error);
return cogl_texture_allocate (sub_tex->full_texture, error);
_cogl_texture_set_allocated (tex,
_cogl_texture_get_format (sub_tex->full_texture),
tex->width, tex->height);
return status;
}
CoglTexture *

View File

@ -49,6 +49,10 @@ COGL_BEGIN_DECLS
* This can be used for integrating Cogl with software using OpenGL
* directly.
*
* The texture is still configurable until it has been allocated so
* for example you can declare whether the texture is premultiplied
* with cogl_texture_set_premultiplied().
*
* <note>The results are undefined for passing an invalid @gl_handle
* or if @width or @height don't have the correct texture
* geometry.</note>

View File

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

View File

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

View File

@ -659,14 +659,30 @@ _cogl_texture_2d_sliced_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
}
}
static void
free_spans (CoglTexture2DSliced *tex_2ds)
{
if (tex_2ds->slice_x_spans != NULL)
{
g_array_free (tex_2ds->slice_x_spans, TRUE);
tex_2ds->slice_x_spans = NULL;
}
if (tex_2ds->slice_y_spans != NULL)
{
g_array_free (tex_2ds->slice_y_spans, TRUE);
tex_2ds->slice_y_spans = NULL;
}
}
static CoglBool
_cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
CoglTexture2DSliced *tex_2ds,
int width,
int height,
int max_waste,
CoglPixelFormat internal_format,
CoglError **error)
setup_spans (CoglContext *ctx,
CoglTexture2DSliced *tex_2ds,
int width,
int height,
int max_waste,
CoglPixelFormat internal_format,
CoglError **error)
{
int max_width;
int max_height;
@ -754,8 +770,8 @@ _cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
COGL_TEXTURE_ERROR,
COGL_TEXTURE_ERROR_SIZE,
"No suitable slice geometry found");
free_spans (tex_2ds);
return FALSE;
}
}
@ -791,7 +807,7 @@ _cogl_texture_2d_sliced_setup_spans (CoglContext *ctx,
}
static void
_cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds)
free_slices (CoglTexture2DSliced *tex_2ds)
{
if (tex_2ds->slice_textures != NULL)
{
@ -806,111 +822,36 @@ _cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds)
g_array_free (tex_2ds->slice_textures, TRUE);
}
}
static void
_cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
{
_cogl_texture_2d_sliced_slices_free (tex_2ds);
if (tex_2ds->slice_x_spans != NULL)
g_array_free (tex_2ds->slice_x_spans, TRUE);
if (tex_2ds->slice_y_spans != NULL)
g_array_free (tex_2ds->slice_y_spans, TRUE);
/* Chain up */
_cogl_texture_free (COGL_TEXTURE (tex_2ds));
free_spans (tex_2ds);
}
static CoglBool
_cogl_texture_2d_sliced_init_base (CoglContext *ctx,
CoglTexture2DSliced *tex_2ds,
int width,
int height,
int max_waste,
CoglPixelFormat internal_format,
CoglError **error)
allocate_slices (CoglTexture2DSliced *tex_2ds,
int width,
int height,
int max_waste,
CoglPixelFormat internal_format,
CoglError **error)
{
CoglTexture *tex = COGL_TEXTURE (tex_2ds);
_cogl_texture_init (tex, ctx, width, height, &cogl_texture_2d_sliced_vtable);
tex_2ds->max_waste = max_waste;
tex_2ds->internal_format = internal_format;
return _cogl_texture_2d_sliced_setup_spans (ctx, tex_2ds,
width, height,
max_waste,
internal_format,
error);
}
CoglTexture2DSliced *
cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
int width,
int height,
int max_waste,
CoglPixelFormat internal_format)
{
CoglTexture2DSliced *tex_2ds;
CoglError *ignore_error = NULL;
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
/* Init texture with empty bitmap */
tex_2ds = g_new0 (CoglTexture2DSliced, 1);
if (!_cogl_texture_2d_sliced_init_base (ctx,
tex_2ds,
width, height,
max_waste,
internal_format,
&ignore_error))
{
/* In this case we failed to find any suitable slicing geometry
* for the given texture size.
*
* We don't need to do anything with the error here since it
* will be picked up on later when trying to allocate the
* texture.
*/
cogl_error_free (ignore_error);
}
/* NB: We need to be sure that cogl_texture_is_sliced() will work
* correctly before returning since
* cogl_framebuffer_allocate() uses this api to determine
* if a texture can be rendered to which may be before the
* slices have been allocated.
*/
return _cogl_texture_2d_sliced_object_new (tex_2ds);
}
static CoglBool
_cogl_texture_2d_sliced_allocate (CoglTexture *tex,
CoglError **error)
{
CoglContext *ctx = tex->context;
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
int n_x_slices;
int n_y_slices;
int n_slices;
int x, y;
CoglPixelFormat format = tex_2ds->internal_format;
CoglSpan *x_span;
CoglSpan *y_span;
if (!tex_2ds->slice_x_spans || !tex_2ds->slice_y_spans)
tex_2ds->internal_format = internal_format;
if (!setup_spans (ctx, tex_2ds,
width,
height,
max_waste,
internal_format,
error))
{
_cogl_set_error (error,
COGL_TEXTURE_ERROR,
COGL_TEXTURE_ERROR_SIZE,
"Couldn't find suitable slicing geometry "
"for given size");
return FALSE;
}
@ -941,11 +882,11 @@ _cogl_texture_2d_sliced_allocate (CoglTexture *tex,
slice = COGL_TEXTURE (
cogl_texture_2d_new_with_size (ctx,
x_span->size, y_span->size,
format));
internal_format));
g_array_append_val (tex_2ds->slice_textures, slice);
if (!cogl_texture_allocate (slice, error))
{
_cogl_texture_2d_sliced_slices_free (tex_2ds);
free_slices (tex_2ds);
return FALSE;
}
}
@ -954,6 +895,60 @@ _cogl_texture_2d_sliced_allocate (CoglTexture *tex,
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 *
_cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
int max_waste,
@ -961,61 +956,21 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp,
CoglBool can_convert_in_place,
CoglError **error)
{
CoglContext *ctx;
CoglTexture2DSliced *tex_2ds;
CoglBitmap *upload_bmp;
int width, height;
CoglTextureLoader *loader;
_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);
height = 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,
internal_format,
error))
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;
return _cogl_texture_2d_sliced_create_base (_cogl_bitmap_get_context (bmp),
cogl_bitmap_get_width (bmp),
cogl_bitmap_get_height (bmp),
max_waste,
internal_format,
loader);
}
CoglTexture2DSliced *
@ -1042,85 +997,40 @@ _cogl_texture_2d_sliced_new_from_foreign (CoglContext *ctx,
CoglPixelFormat format,
CoglError **error)
{
CoglTextureLoader *loader;
/* NOTE: width, height and internal format are not queriable
* 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
rectangle texture is used then _cogl_texture_new_from_foreign
will create a cogl_texture_rectangle instead */
_COGL_RETURN_VAL_IF_FAIL (gl_target == GL_TEXTURE_2D, NULL);
gl_width = width + x_pot_waste;
gl_height = height + y_pot_waste;
/* Assert it is a valid GL texture object */
_COGL_RETURN_VAL_IF_FAIL (ctx->glIsTexture (gl_handle), FALSE);
/* Validate width and height */
_COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL);
/* Validate pot waste */
if (x_pot_waste < 0 || x_pot_waste >= width ||
y_pot_waste < 0 || y_pot_waste >= height)
return NULL;
_COGL_RETURN_VAL_IF_FAIL (x_pot_waste >= 0 && x_pot_waste < width &&
y_pot_waste >= 0 && y_pot_waste < height,
NULL);
tex_2d = cogl_texture_2d_new_from_foreign (ctx,
gl_target,
gl_width,
gl_height,
format,
error);
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 + x_pot_waste;
loader->src.gl_foreign.height = height + y_pot_waste;
loader->src.gl_foreign.format = format;
if (!tex_2d)
return NULL;
/* 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 (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);
return _cogl_texture_2d_sliced_create_base (ctx,
width,
height,
0, /* max waste */
format, loader);
}
CoglTexture2DSliced *
@ -1157,6 +1067,13 @@ cogl_texture_2d_sliced_new_from_data (CoglContext *ctx,
cogl_object_unref (bmp);
if (tex_2ds &&
!cogl_texture_allocate (COGL_TEXTURE (tex_2ds), error))
{
cogl_object_unref (tex_2ds);
return NULL;
}
return tex_2ds;
}
@ -1187,6 +1104,175 @@ cogl_texture_2d_sliced_new_from_file (CoglContext *ctx,
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
_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);
/* It's possible that we failed to calculate valid slicing geometry
* when initializing the texture due to the max_waste size and in
* this case we report that the texture is not sliced.
*
* In this case though we know that we will be throwing an error
* when this texture is later allocated so it shouldn't really
* matter what we report here since the texture won't be used in the
* end.
*/
if (!tex_2ds->slice_x_spans || !tex_2ds->slice_y_spans)
return FALSE;
/* It's only after allocating a sliced texture that we will know
* whether it really needed to be sliced... */
if (!tex->allocated)
cogl_texture_allocate (tex, NULL);
if (tex_2ds->slice_x_spans->len != 1 ||
tex_2ds->slice_y_spans->len != 1)

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
* specified. A negative @max_waste will disable slicing.
*
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
* allocate the underlying storage or let Cogl automatically allocate
* storage lazily.
*
* <note>It's possible for the allocation of a sliced texture to fail
* later due to impossible slicing constraints if a negative
* @max_waste value is given. If the given virtual texture size is
@ -206,11 +211,22 @@ cogl_texture_2d_sliced_new_from_file (CoglContext *ctx,
* wasted padding at the bottom and right of the textures is less than
* specified. A negative @max_waste will disable slicing.
*
* <note>This api will always immediately allocate GPU memory for all
* the required texture slices and upload the given data so that the
* @data pointer does not need to remain valid once this function
* returns. This means it is not possible to configure the texture
* before it is allocated. If you do need to configure the texture
* before allocation (to specify constraints on the internal format
* for example) then you can instead create a #CoglBitmap for your
* data and use cogl_texture_2d_sliced_new_from_bitmap() or use
* cogl_texture_2d_sliced_new_with_size() and then upload data using
* cogl_texture_set_data()</note>
*
* <note>It's possible for the allocation of a sliced texture to fail
* later due to impossible slicing constraints if a negative
* @max_waste value is given. If the given virtual texture size is
* larger than is supported by the hardware but slicing is disabled
* the texture size would be too large to handle.</note>
* due to impossible slicing constraints if a negative @max_waste
* value is given. If the given virtual texture size is larger than is
* supported by the hardware but slicing is disabled the texture size
* would be too large to handle.</note>
*
* Return value: (transfer full): A newly created #CoglTexture2DSliced
* or %NULL on failure and @error will be updated.
@ -262,6 +278,11 @@ cogl_texture_2d_sliced_new_from_data (CoglContext *ctx,
* wasted padding at the bottom and right of the textures is less than
* specified. A negative @max_waste will disable slicing.
*
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
* allocate the underlying storage or let Cogl automatically allocate
* storage lazily.
*
* <note>It's possible for the allocation of a sliced texture to fail
* later due to impossible slicing constraints if a negative
* @max_waste value is given. If the given virtual texture size is

View File

@ -75,25 +75,6 @@ _cogl_texture_2d_free (CoglTexture2D *tex_2d)
_cogl_texture_free (COGL_TEXTURE (tex_2d));
}
static CoglBool
_cogl_texture_2d_can_create (CoglContext *ctx,
unsigned int width,
unsigned int height,
CoglPixelFormat internal_format)
{
/* If NPOT textures aren't supported then the size must be a power
of two */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
(!_cogl_util_is_pot (width) ||
!_cogl_util_is_pot (height)))
return FALSE;
return ctx->driver_vtable->texture_2d_can_create (ctx,
width,
height,
internal_format);
}
void
_cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,
CoglBool value)
@ -107,20 +88,20 @@ CoglTexture2D *
_cogl_texture_2d_create_base (CoglContext *ctx,
int width,
int height,
CoglPixelFormat internal_format)
CoglPixelFormat internal_format,
CoglTextureLoader *loader)
{
CoglTexture2D *tex_2d = g_new (CoglTexture2D, 1);
CoglTexture *tex = COGL_TEXTURE (tex_2d);
_cogl_texture_init (tex, ctx, width, height, &cogl_texture_2d_vtable);
_cogl_texture_init (tex, ctx, width, height, internal_format, loader,
&cogl_texture_2d_vtable);
tex_2d->mipmaps_dirty = TRUE;
tex_2d->auto_mipmap = TRUE;
tex_2d->is_foreign = FALSE;
tex_2d->internal_format = internal_format;
ctx->driver_vtable->texture_2d_init (tex_2d);
return _cogl_texture_2d_object_new (tex_2d);
@ -132,13 +113,19 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
int height,
CoglPixelFormat internal_format)
{
CoglTextureLoader *loader;
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
return _cogl_texture_2d_create_base (ctx,
width, height,
internal_format);
loader = _cogl_texture_create_loader ();
loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
loader->src.sized.width = width;
loader->src.sized.height = height;
return _cogl_texture_2d_create_base (ctx, width, height,
internal_format, loader);
}
static CoglBool
@ -146,6 +133,7 @@ _cogl_texture_2d_allocate (CoglTexture *tex,
CoglError **error)
{
CoglContext *ctx = tex->context;
return ctx->driver_vtable->texture_2d_allocate (tex, error);
}
@ -155,32 +143,20 @@ _cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
CoglBool can_convert_in_place,
CoglError **error)
{
CoglContext *ctx;
CoglTextureLoader *loader;
_COGL_RETURN_VAL_IF_FAIL (bmp != NULL, NULL);
ctx = _cogl_bitmap_get_context (bmp);
loader = _cogl_texture_create_loader ();
loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP;
loader->src.bitmap.bitmap = cogl_object_ref (bmp);
loader->src.bitmap.can_convert_in_place = can_convert_in_place;
internal_format =
_cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp),
internal_format);
if (!_cogl_texture_2d_can_create (ctx,
cogl_bitmap_get_width (bmp),
cogl_bitmap_get_height (bmp),
internal_format))
{
_cogl_set_error (error, COGL_TEXTURE_ERROR,
COGL_TEXTURE_ERROR_SIZE,
"Failed to create texture 2d due to size/format"
" constraints");
return NULL;
}
return ctx->driver_vtable->texture_2d_new_from_bitmap (bmp,
internal_format,
can_convert_in_place,
error);
return _cogl_texture_2d_create_base (_cogl_bitmap_get_context (bmp),
cogl_bitmap_get_width (bmp),
cogl_bitmap_get_height (bmp),
internal_format,
loader);
}
CoglTexture2D *
@ -249,6 +225,13 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
cogl_object_unref (bmp);
if (tex_2d &&
!cogl_texture_allocate (COGL_TEXTURE (tex_2d), error))
{
cogl_object_unref (tex_2d);
return NULL;
}
return tex_2d;
}
@ -264,6 +247,8 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
EGLImageKHR image,
CoglError **error)
{
CoglTextureLoader *loader;
_COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
COGL_RENDERER_CONSTRAINT_USES_EGL,
NULL);
@ -273,22 +258,14 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE),
NULL);
if (ctx->driver_vtable->egl_texture_2d_new_from_image)
return ctx->driver_vtable->egl_texture_2d_new_from_image (ctx,
width,
height,
format,
image,
error);
else
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Creating 2D textures from EGL images is not "
"supported by the current driver");
return NULL;
}
loader = _cogl_texture_create_loader ();
loader->src_type = COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE;
loader->src.egl_image.image = image;
loader->src.egl_image.width = width;
loader->src.egl_image.height = height;
loader->src.egl_image.format = format;
return _cogl_texture_2d_create_base (ctx, width, height, format, loader);
}
#endif /* defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) */

View File

@ -3,7 +3,7 @@
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2011 Intel Corporation.
* Copyright (C) 2011,2013 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -75,11 +75,8 @@ cogl_is_texture_2d (void *object);
* @height: Height of the texture to allocate
* @internal_format: The format of the texture
*
* Allocates a low-level #CoglTexture2D texture that your GPU can
* texture from directly. This is unlike sliced textures for example
* which may be comprised of multiple internal textures, or atlas
* textures where Cogl has to modify texture coordinates before they
* may be used by the GPU.
* Creates a low-level #CoglTexture2D texture with a given @width and
* @height that your GPU can texture from directly.
*
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
@ -87,6 +84,11 @@ cogl_is_texture_2d (void *object);
* automatically allocate storage lazily when it may know more about
* how the texture is being used and can optimize how it is allocated.
*
* The texture is still configurable until it has been allocated so
* for example you can influence the internal format of the texture
* using cogl_texture_set_components() and
* cogl_texture_set_premultiplied().
*
* <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by
* checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via
@ -116,7 +118,23 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
* other than straight blending.
* @error: A #CoglError to catch exceptional errors or %NULL
*
* Creates a #CoglTexture2D from an image file.
* Creates a low-level #CoglTexture2D texture from an image file.
*
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
* allocate the underlying storage or preferably let Cogl
* automatically allocate storage lazily when it may know more about
* how the texture is being used and can optimize how it is allocated.
*
* The texture is still configurable until it has been allocated so
* for example you can influence the internal format of the texture
* using cogl_texture_set_components() and
* cogl_texture_set_premultiplied().
*
* <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by
* checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via
* cogl_has_feature().</note>
*
* Return value: (transfer full): A newly created #CoglTexture2D or %NULL on failure
* and @error will be updated.
@ -149,10 +167,19 @@ cogl_texture_2d_new_from_file (CoglContext *ctx,
* @data: pointer the memory region where the source buffer resides
* @error: A #CoglError for exceptions
*
* Creates a new #CoglTexture2D texture based on data residing in memory.
* These are unlike sliced textures for example which may be comprised
* of multiple internal textures, or atlas textures where Cogl has to
* modify texture coordinates before they may be used by the GPU.
* Creates a low-level #CoglTexture2D texture based on data residing
* in memory.
*
* <note>This api will always immediately allocate GPU memory for the
* texture and upload the given data so that the @data pointer does
* not need to remain valid once this function returns. This means it
* is not possible to configure the texture before it is allocated. If
* you do need to configure the texture before allocation (to specify
* constraints on the internal format for example) then you can
* instead create a #CoglBitmap for your data and use
* cogl_texture_2d_new_from_bitmap() or use
* cogl_texture_2d_new_with_size() and then upload data using
* cogl_texture_set_data()</note>
*
* <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by
@ -189,11 +216,19 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
* something other than straight blending.
* @error: A #CoglError for exceptions
*
* Creates a new #CoglTexture2D texture based on data residing in a
* bitmap. These are unlike sliced textures for example which may be
* comprised of multiple internal textures, or atlas textures where
* Cogl has to modify texture coordinates before they may be used by
* the GPU.
* Creates a low-level #CoglTexture2D texture based on data residing
* in a #CoglBitmap.
*
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
* allocate the underlying storage or preferably let Cogl
* automatically allocate storage lazily when it may know more about
* how the texture is being used and can optimize how it is allocated.
*
* The texture is still configurable until it has been allocated so
* for example you can influence the internal format of the texture
* using cogl_texture_set_components() and
* cogl_texture_set_premultiplied().
*
* <note>Many GPUs only support power of two sizes for #CoglTexture2D
* textures. You can check support for non power of two textures by

View File

@ -116,12 +116,14 @@ _cogl_texture_3d_create_base (CoglContext *ctx,
int width,
int height,
int depth,
CoglPixelFormat internal_format)
CoglPixelFormat internal_format,
CoglTextureLoader *loader)
{
CoglTexture3D *tex_3d = g_new (CoglTexture3D, 1);
CoglTexture *tex = COGL_TEXTURE (tex_3d);
_cogl_texture_init (tex, ctx, width, height, &cogl_texture_3d_vtable);
_cogl_texture_init (tex, ctx, width, height,
internal_format, loader, &cogl_texture_3d_vtable);
tex_3d->gl_texture = 0;
@ -138,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_p = GL_FALSE;
tex_3d->internal_format = internal_format;
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 *
cogl_texture_3d_new_with_size (CoglContext *ctx,
int width,
@ -211,177 +150,46 @@ cogl_texture_3d_new_with_size (CoglContext *ctx,
int depth,
CoglPixelFormat internal_format)
{
CoglTextureLoader *loader;
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
return _cogl_texture_3d_create_base (ctx,
width, height, depth,
internal_format);
}
loader = _cogl_texture_create_loader ();
loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
loader->src.sized.width = width;
loader->src.sized.height = height;
loader->src.sized.depth = depth;
static CoglBool
_cogl_texture_3d_allocate (CoglTexture *tex,
CoglError **error)
{
CoglContext *ctx = tex->context;
CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
GLenum gl_error;
GLenum gl_texture;
if (!_cogl_texture_3d_can_create (ctx,
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;
return _cogl_texture_3d_create_base (ctx, width, height, depth,
internal_format, loader);
}
CoglTexture3D *
cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
unsigned int height,
unsigned int depth,
int height,
int depth,
CoglPixelFormat internal_format,
CoglError **error)
{
CoglTexture3D *tex_3d;
CoglBitmap *upload_bmp;
CoglPixelFormat bmp_format;
CoglPixelFormat upload_format;
unsigned int bmp_width;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
CoglContext *ctx;
CoglTextureLoader *loader;
ctx = _cogl_bitmap_get_context (bmp);
_COGL_RETURN_VAL_IF_FAIL (bmp, NULL);
bmp_width = cogl_bitmap_get_width (bmp);
bmp_format = cogl_bitmap_get_format (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.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,
internal_format);
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,
depth,
upload_bmp,
gl_intformat,
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;
return _cogl_texture_3d_create_base (_cogl_bitmap_get_context (bmp),
cogl_bitmap_get_width (bmp),
height,
depth,
internal_format,
loader);
}
CoglTexture3D *
@ -399,14 +207,8 @@ cogl_texture_3d_new_from_data (CoglContext *context,
CoglBitmap *bitmap;
CoglTexture3D *ret;
/* These are considered a programmer errors so we won't set a
CoglError. It would be nice if this was a _COGL_RETURN_IF_FAIL but the
rest of Cogl isn't using that */
if (format == COGL_PIXEL_FORMAT_ANY)
return NULL;
if (data == NULL)
return NULL;
_COGL_RETURN_VAL_IF_FAIL (data, NULL);
_COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);
/* Rowstride from width if not given */
if (rowstride == 0)
@ -475,9 +277,273 @@ cogl_texture_3d_new_from_data (CoglContext *context,
cogl_object_unref (bitmap);
if (ret &&
!cogl_texture_allocate (COGL_TEXTURE (ret), error))
{
cogl_object_unref (ret);
return NULL;
}
return ret;
}
static CoglBool
_cogl_texture_3d_can_create (CoglContext *ctx,
int width,
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
_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
* storage of the texture.
*
* Creates a new #CoglTexture3D texture with the specified dimensions
* and pixel format.
* Creates a low-level #CoglTexture3D texture with the specified
* dimensions and pixel format.
*
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
@ -66,6 +66,11 @@ typedef struct _CoglTexture3D CoglTexture3D;
* how the texture is going to be used and can optimize how it is
* allocated.
*
* The texture is still configurable until it has been allocated so
* for example you can influence the internal format of the texture
* using cogl_texture_set_components() and
* cogl_texture_set_premultiplied().
*
* <note>This texture will fail to allocate later if
* %COGL_FEATURE_ID_TEXTURE_3D is not advertised. Allocation can also
* fail if the requested dimensions are not supported by the
@ -107,16 +112,21 @@ cogl_texture_3d_new_with_size (CoglContext *context,
* @data: pointer the memory region where the source buffer resides
* @error: A CoglError return location.
*
* Creates a new 3D texture and initializes it with @data. The data is
* assumed to be packed array of @depth images. There can be padding
* between the images using @image_stride.
* Creates a low-level 3D texture and initializes it with @data. The
* data is assumed to be packed array of @depth images. There can be
* padding between the images using @image_stride.
*
* Note that this function will throw a #CoglError if
* %COGL_FEATURE_ID_TEXTURE_3D is not advertised. It can also fail if the
* requested dimensions are not supported by the GPU.
* <note>This api will always immediately allocate GPU memory for the
* texture and upload the given data so that the @data pointer does
* not need to remain valid once this function returns. This means it
* is not possible to configure the texture before it is allocated. If
* you do need to configure the texture before allocation (to specify
* constraints on the internal format for example) then you can
* instead create a #CoglBitmap for your data and use
* cogl_texture_3d_new_from_bitmap().</note>
*
* Return value: (transfer full): the newly created #CoglTexture3D or
* %NULL if there was an error an an exception will be
* %NULL if there was an error and an exception will be
* returned through @error.
* Since: 1.10
* Stability: Unstable
@ -148,13 +158,30 @@ cogl_texture_3d_new_from_data (CoglContext *context,
* something other than straight blending.
* @error: A CoglError return location.
*
* Creates a new 3D texture and initializes it with the images in
* @bitmap. The images are assumed to be packed together after one
* Creates a low-level 3D texture and initializes it with the images
* in @bitmap. The images are assumed to be packed together after one
* another in the increasing y axis. The height of individual image is
* given as @height and the number of images is given in @depth. The
* actual height of the bitmap can be larger than @height × @depth. In
* this case it assumes there is padding between the images.
*
* The storage for the texture is not allocated before this function
* returns. You can call cogl_texture_allocate() to explicitly
* allocate the underlying storage or preferably let Cogl
* automatically allocate storage lazily when it may know more about
* how the texture is going to be used and can optimize how it is
* allocated.
*
* The texture is still configurable until it has been allocated so
* for example you can influence the internal format of the texture
* using cogl_texture_set_components() and
* cogl_texture_set_premultiplied().
*
* <note>This texture will fail to allocate later if
* %COGL_FEATURE_ID_TEXTURE_3D is not advertised. Allocation can also
* fail if the requested dimensions are not supported by the
* GPU.</note>
*
* Return value: (transfer full): the newly created texture or %NULL
* if there was an error.
* Since: 2.0
@ -162,8 +189,8 @@ cogl_texture_3d_new_from_data (CoglContext *context,
*/
CoglTexture3D *
cogl_texture_3d_new_from_bitmap (CoglBitmap *bitmap,
unsigned int height,
unsigned int depth,
int height,
int depth,
CoglPixelFormat internal_format,
CoglError **error);

View File

@ -31,6 +31,10 @@
#include "cogl-meta-texture.h"
#include "cogl-framebuffer.h"
#ifdef COGL_HAS_EGL_SUPPORT
#include "cogl-egl-defines.h"
#endif
typedef struct _CoglTextureVtable CoglTextureVtable;
/* Encodes three possibiloities result of transforming a quad */
@ -139,15 +143,62 @@ struct _CoglTextureVtable
CoglBool value);
};
typedef enum _CoglTextureSoureType {
COGL_TEXTURE_SOURCE_TYPE_SIZED = 1,
COGL_TEXTURE_SOURCE_TYPE_BITMAP,
COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE,
COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN
} CoglTextureSourceType;
typedef struct _CoglTextureLoader
{
CoglTextureSourceType src_type;
union {
struct {
int width;
int height;
int depth; /* for 3d textures */
} sized;
struct {
CoglBitmap *bitmap;
int height; /* for 3d textures */
int depth; /* for 3d textures */
CoglBool can_convert_in_place;
} bitmap;
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
struct {
EGLImageKHR image;
int width;
int height;
CoglPixelFormat format;
} egl_image;
#endif
struct {
int width;
int height;
unsigned int gl_handle;
CoglPixelFormat format;
} gl_foreign;
} src;
} CoglTextureLoader;
struct _CoglTexture
{
CoglObject _parent;
CoglContext *context;
CoglTextureLoader *loader;
GList *framebuffers;
int max_level;
int width;
int height;
CoglBool allocated;
/*
* Internal format
*/
CoglTextureComponents components;
unsigned int premultiplied:1;
const CoglTextureVtable *vtable;
};
@ -183,6 +234,8 @@ _cogl_texture_init (CoglTexture *texture,
CoglContext *ctx,
int width,
int height,
CoglPixelFormat internal_format,
CoglTextureLoader *loader,
const CoglTextureVtable *vtable);
void
@ -220,12 +273,38 @@ _cogl_texture_pre_paint (CoglTexture *texture, CoglTexturePrePaintFlags flags);
void
_cogl_texture_ensure_non_quad_rendering (CoglTexture *texture);
/* Utility function to determine which pixel format to use when
dst_format is COGL_PIXEL_FORMAT_ANY. If dst_format is not ANY then
it will just be returned directly */
/*
* This determines a CoglPixelFormat according to texture::components
* and texture::premultiplied (i.e. the user required components and
* whether the texture should be considered premultiplied)
*
* A reference/source format can be given (or COGL_PIXEL_FORMAT_ANY)
* and wherever possible this function tries to simply return the
* given source format if its compatible with the required components.
*
* Texture backends can call this when allocating a texture to know
* how to convert a source image in preparation for uploading.
*/
CoglPixelFormat
_cogl_texture_determine_internal_format (CoglPixelFormat src_format,
CoglPixelFormat dst_format);
_cogl_texture_determine_internal_format (CoglTexture *texture,
CoglPixelFormat src_format);
/* This is called by texture backends when they have successfully
* allocated a texture.
*
* Most texture backends currently track the internal layout of
* textures using a CoglPixelFormat which will be finalized when a
* texture is allocated. At this point we need to update
* texture::components and texture::premultiplied according to the
* determined layout.
*
* XXX: Going forward we should probably aim to stop using
* CoglPixelFormat at all for tracking the internal layout of
* textures.
*/
void
_cogl_texture_set_internal_format (CoglTexture *texture,
CoglPixelFormat internal_format);
CoglBool
_cogl_texture_is_foreign (CoglTexture *texture);
@ -306,9 +385,14 @@ _cogl_texture_get_level_size (CoglTexture *texture,
void
_cogl_texture_set_allocated (CoglTexture *texture,
CoglBool allocated);
CoglPixelFormat internal_format,
int width,
int height);
CoglPixelFormat
_cogl_texture_get_format (CoglTexture *texture);
CoglTextureLoader *
_cogl_texture_create_loader (void);
#endif /* __COGL_TEXTURE_PRIVATE_H */

View File

@ -166,12 +166,15 @@ static CoglTextureRectangle *
_cogl_texture_rectangle_create_base (CoglContext *ctx,
int width,
int height,
CoglPixelFormat internal_format)
CoglPixelFormat internal_format,
CoglTextureLoader *loader)
{
CoglTextureRectangle *tex_rect = g_new (CoglTextureRectangle, 1);
CoglTexture *tex = COGL_TEXTURE (tex_rect);
_cogl_texture_init (tex, ctx, width, height, &cogl_texture_rectangle_vtable);
_cogl_texture_init (tex, ctx, width, height,
internal_format, loader,
&cogl_texture_rectangle_vtable);
tex_rect->gl_texture = 0;
tex_rect->is_foreign = FALSE;
@ -184,8 +187,6 @@ _cogl_texture_rectangle_create_base (CoglContext *ctx,
tex_rect->gl_legacy_texobj_wrap_mode_s = GL_FALSE;
tex_rect->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
tex_rect->internal_format = internal_format;
return _cogl_texture_rectangle_object_new (tex_rect);
}
@ -196,16 +197,20 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
CoglPixelFormat internal_format,
CoglError **error)
{
CoglTextureLoader *loader;
CoglTextureRectangle *tex_rect;
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
tex_rect =_cogl_texture_rectangle_create_base (ctx,
width, height,
internal_format);
loader = _cogl_texture_create_loader ();
loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
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
* to not take a CoglError to allow the storage to be allocated
* 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);
return NULL;
}
return tex_rect;
}
static CoglBool
_cogl_texture_rectangle_allocate (CoglTexture *tex,
CoglError **error)
allocate_with_size (CoglTextureRectangle *tex_rect,
CoglTextureLoader *loader,
CoglError **error)
{
CoglTexture *tex = COGL_TEXTURE (tex_rect);
CoglContext *ctx = tex->context;
CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
CoglPixelFormat internal_format;
int width = loader->src.sized.width;
int height = loader->src.sized.height;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
GLenum gl_error;
GLenum gl_texture;
internal_format =
_cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
if (!_cogl_texture_rectangle_can_create (ctx,
tex->width,
tex->height,
tex_rect->internal_format,
width,
height,
internal_format,
error))
return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
tex_rect->internal_format,
internal_format,
&gl_intformat,
&gl_format,
&gl_type);
@ -247,7 +260,7 @@ _cogl_texture_rectangle_allocate (CoglTexture *tex,
gl_texture =
ctx->texture_driver->gen (ctx,
GL_TEXTURE_RECTANGLE_ARB,
tex_rect->internal_format);
internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
gl_texture,
tex_rect->is_foreign);
@ -257,7 +270,7 @@ _cogl_texture_rectangle_allocate (CoglTexture *tex,
;
ctx->glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat,
tex->width, tex->height, 0, gl_format, gl_type, NULL);
width, height, 0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{
@ -265,46 +278,50 @@ _cogl_texture_rectangle_allocate (CoglTexture *tex,
return FALSE;
}
tex_rect->internal_format = internal_format;
tex_rect->gl_texture = gl_texture;
tex_rect->gl_format = gl_intformat;
_cogl_texture_set_allocated (COGL_TEXTURE (tex_rect),
internal_format, width, height);
return TRUE;
}
CoglTextureRectangle *
cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
CoglPixelFormat internal_format,
CoglError **error)
static CoglBool
allocate_from_bitmap (CoglTextureRectangle *tex_rect,
CoglTextureLoader *loader,
CoglError **error)
{
CoglTextureRectangle *tex_rect;
CoglTexture *tex = COGL_TEXTURE (tex_rect);
CoglContext *ctx = tex->context;
CoglPixelFormat internal_format;
CoglBitmap *bmp = loader->src.bitmap.bitmap;
int width = cogl_bitmap_get_width (bmp);
int height = cogl_bitmap_get_height (bmp);
CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place;
CoglBitmap *upload_bmp;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
CoglContext *ctx;
_COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
ctx = _cogl_bitmap_get_context (bmp);
internal_format =
_cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp),
internal_format);
_cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp));
if (!_cogl_texture_rectangle_can_create (ctx,
cogl_bitmap_get_width (bmp),
cogl_bitmap_get_height (bmp),
width,
height,
internal_format,
error))
return NULL;
return FALSE;
upload_bmp =
_cogl_bitmap_convert_for_upload (bmp,
internal_format,
FALSE, /* can't convert in place */
error);
upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
internal_format,
can_convert_in_place,
error);
if (upload_bmp == NULL)
return NULL;
return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
cogl_bitmap_get_format (upload_bmp),
@ -317,11 +334,6 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
NULL,
NULL);
tex_rect = _cogl_texture_rectangle_create_base (ctx,
cogl_bitmap_get_width (bmp),
cogl_bitmap_get_height (bmp),
internal_format);
tex_rect->gl_texture =
ctx->texture_driver->gen (ctx,
GL_TEXTURE_RECTANGLE_ARB,
@ -337,38 +349,31 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp,
error))
{
cogl_object_unref (upload_bmp);
cogl_object_unref (tex_rect);
return NULL;
return FALSE;
}
tex_rect->gl_format = gl_intformat;
tex_rect->internal_format = internal_format;
cogl_object_unref (upload_bmp);
_cogl_texture_set_allocated (COGL_TEXTURE (tex_rect), TRUE);
_cogl_texture_set_allocated (COGL_TEXTURE (tex_rect),
internal_format, width, height);
return tex_rect;
return TRUE;
}
CoglTextureRectangle *
cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
unsigned int gl_handle,
int width,
int height,
CoglPixelFormat format,
CoglError **error)
static CoglBool
allocate_from_gl_foreign (CoglTextureRectangle *tex_rect,
CoglTextureLoader *loader,
CoglError **error)
{
/* NOTE: width, height and internal format are not queriable
* in GLES, hence such a function prototype.
*/
CoglTexture *tex = COGL_TEXTURE (tex_rect);
CoglContext *ctx = tex->context;
CoglPixelFormat format = loader->src.gl_foreign.format;
GLenum gl_error = 0;
GLint gl_compressed = GL_FALSE;
GLenum gl_int_format = 0;
CoglTextureRectangle *tex_rect;
/* Assert that it is a valid GL texture object */
g_return_val_if_fail (ctx->glIsTexture (gl_handle), NULL);
if (!ctx->texture_driver->allows_foreign_gl_target (ctx,
GL_TEXTURE_RECTANGLE_ARB))
@ -378,21 +383,22 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Foreign GL_TEXTURE_RECTANGLE textures are not "
"supported by your system");
return NULL;
return FALSE;
}
/* Make sure binding succeeds */
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
_cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, gl_handle, TRUE);
_cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
loader->src.gl_foreign.gl_handle, TRUE);
if (ctx->glGetError () != GL_NO_ERROR)
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Failed to bind foreign GL_TEXTURE_RECTANGLE texture");
return NULL;
return FALSE;
}
/* Obtain texture parameters */
@ -423,7 +429,7 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Unsupported internal format for foreign texture");
return NULL;
return FALSE;
}
}
else
@ -438,16 +444,6 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
NULL);
}
/* Note: We always trust the given width and height without querying
* the texture object because the user may be creating a Cogl
* texture for a texture_from_pixmap object where glTexImage2D may
* not have been called and the texture_from_pixmap spec doesn't
* clarify that it is reliable to query back the size from OpenGL.
*/
/* Validate width and height */
g_return_val_if_fail (width > 0 && height > 0, NULL);
/* Compressed texture images not supported */
if (gl_compressed == GL_TRUE)
{
@ -455,27 +451,107 @@ cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Compressed foreign textures aren't currently supported");
return NULL;
return FALSE;
}
/* Create new texture */
tex_rect = _cogl_texture_rectangle_create_base (ctx, width, height, format);
/* Setup bitmap info */
tex_rect->is_foreign = TRUE;
tex_rect->internal_format = format;
tex_rect->gl_texture = gl_handle;
tex_rect->gl_texture = loader->src.gl_foreign.gl_handle;
tex_rect->gl_format = gl_int_format;
/* Unknown filter */
tex_rect->gl_legacy_texobj_min_filter = GL_FALSE;
tex_rect->gl_legacy_texobj_mag_filter = GL_FALSE;
_cogl_texture_set_allocated (COGL_TEXTURE (tex_rect), TRUE);
tex_rect->internal_format = format;
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

View File

@ -102,6 +102,11 @@ cogl_is_texture_rectangle (void *object);
* first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature
* 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
* #CoglTextureRectangle texture or if the size was too large
* 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
* 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
* #CoglTextureRectangle texture or if the size was too large
* or there wasn't enough memory %NULL is returned and @error
* set.
*
* Since: 2.0
* Stability: unstable
*/
@ -185,12 +198,15 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bitmap,
* <note>Applications wanting to use #CoglTextureRectangle should
* first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature
* using cogl_has_feature().</note>
*
* The texture is still configurable until it has been allocated so
* for example you can declare whether the texture is premultiplied
* with cogl_texture_set_premultiplied().
*
* Return value: (transfer full): A newly allocated
* #CoglTextureRectangle, or if Cogl could not validate the
* @gl_handle in some way (perhaps because of an unsupported
* format) it will return %NULL and set @error.
*
*/
CoglTextureRectangle *
cogl_texture_rectangle_new_from_foreign (CoglContext *ctx,

View File

@ -107,6 +107,8 @@ _cogl_texture_init (CoglTexture *texture,
CoglContext *context,
int width,
int height,
CoglPixelFormat internal_format,
CoglTextureLoader *loader,
const CoglTextureVtable *vtable)
{
texture->context = context;
@ -116,11 +118,44 @@ _cogl_texture_init (CoglTexture *texture,
texture->allocated = FALSE;
texture->vtable = vtable;
texture->framebuffers = NULL;
texture->loader = loader;
_cogl_texture_set_internal_format (texture, internal_format);
}
static void
_cogl_texture_free_loader (CoglTexture *texture)
{
if (texture->loader)
{
CoglTextureLoader *loader = texture->loader;
switch (loader->src_type)
{
case COGL_TEXTURE_SOURCE_TYPE_SIZED:
case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE:
case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN:
break;
case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
cogl_object_unref (loader->src.bitmap.bitmap);
break;
}
g_slice_free (CoglTextureLoader, loader);
texture->loader = NULL;
}
}
CoglTextureLoader *
_cogl_texture_create_loader (void)
{
return g_slice_new0 (CoglTextureLoader);
}
void
_cogl_texture_free (CoglTexture *texture)
{
_cogl_texture_free_loader (texture);
g_free (texture);
}
@ -135,34 +170,6 @@ _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format,
(dst_format & COGL_PREMULT_BIT));
}
CoglPixelFormat
_cogl_texture_determine_internal_format (CoglPixelFormat src_format,
CoglPixelFormat dst_format)
{
/* If the application hasn't specified a specific format then we'll
* pick the most appropriate. By default Cogl will use a
* premultiplied internal format. Later we will add control over
* this. */
if (dst_format == COGL_PIXEL_FORMAT_ANY)
{
if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (src_format))
return src_format | COGL_PREMULT_BIT;
else
return src_format;
}
else
/* XXX: It might be nice to make this match the component ordering
of the source format when the formats are otherwise the same
because on GL there is no way to specify the ordering of the
internal format. However when using GLES with the
GL_EXT_texture_format_BGRA8888 the order of the internal format
becomes important because it must exactly match the format of
the uploaded data. That means that if someone creates a texture
with some RGBA data and then later tries to upload BGRA data we
do actually have to swizzle the components */
return dst_format;
}
CoglBool
_cogl_texture_is_foreign (CoglTexture *texture)
{
@ -1348,9 +1355,17 @@ _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans,
void
_cogl_texture_set_allocated (CoglTexture *texture,
CoglBool allocated)
CoglPixelFormat internal_format,
int width,
int height)
{
texture->allocated = allocated;
_cogl_texture_set_internal_format (texture, internal_format);
texture->width = width;
texture->height = height;
texture->allocated = TRUE;
_cogl_texture_free_loader (texture);
}
CoglBool
@ -1364,3 +1379,127 @@ cogl_texture_allocate (CoglTexture *texture,
return texture->allocated;
}
void
_cogl_texture_set_internal_format (CoglTexture *texture,
CoglPixelFormat internal_format)
{
texture->premultiplied = FALSE;
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
if (internal_format == COGL_PIXEL_FORMAT_A_8)
{
texture->components = COGL_TEXTURE_COMPONENTS_A;
return;
}
else if (internal_format & COGL_DEPTH_BIT)
{
texture->components = COGL_TEXTURE_COMPONENTS_DEPTH;
return;
}
else if (internal_format & COGL_A_BIT)
{
texture->components = COGL_TEXTURE_COMPONENTS_RGBA;
if (internal_format & COGL_PREMULT_BIT)
texture->premultiplied = TRUE;
return;
}
else
texture->components = COGL_TEXTURE_COMPONENTS_RGB;
}
CoglPixelFormat
_cogl_texture_determine_internal_format (CoglTexture *texture,
CoglPixelFormat src_format)
{
switch (texture->components)
{
case COGL_TEXTURE_COMPONENTS_DEPTH:
if (src_format & COGL_DEPTH_BIT)
return src_format;
else
{
CoglContext *ctx = texture->context;
if (_cogl_has_private_feature (ctx,
COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) ||
_cogl_has_private_feature (ctx,
COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL))
{
return COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8;
}
else
return COGL_PIXEL_FORMAT_DEPTH_16;
}
case COGL_TEXTURE_COMPONENTS_A:
return COGL_PIXEL_FORMAT_A_8;
case COGL_TEXTURE_COMPONENTS_RGB:
if (src_format != COGL_PIXEL_FORMAT_ANY &&
!(src_format & COGL_A_BIT) && !(src_format & COGL_DEPTH_BIT))
return src_format;
else
return COGL_PIXEL_FORMAT_RGB_888;
case COGL_TEXTURE_COMPONENTS_RGBA:
{
CoglPixelFormat format;
if (src_format != COGL_PIXEL_FORMAT_ANY &&
(src_format & COGL_A_BIT) && src_format != COGL_PIXEL_FORMAT_A_8)
format = src_format;
else
format = COGL_PIXEL_FORMAT_RGBA_8888;
if (texture->premultiplied)
{
if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format))
return format |= COGL_PREMULT_BIT;
else
return COGL_PIXEL_FORMAT_RGBA_8888_PRE;
}
else
return format & ~COGL_PREMULT_BIT;
}
}
g_return_val_if_reached (COGL_PIXEL_FORMAT_RGBA_8888_PRE);
}
void
cogl_texture_set_components (CoglTexture *texture,
CoglTextureComponents components)
{
_COGL_RETURN_IF_FAIL (!texture->allocated);
if (texture->components == components)
return;
texture->components = components;
}
CoglBool
cogl_texture_get_components (CoglTexture *texture)
{
return texture->components;
}
void
cogl_texture_set_premultiplied (CoglTexture *texture,
CoglBool premultiplied)
{
_COGL_RETURN_IF_FAIL (!texture->allocated);
premultiplied = !!premultiplied;
if (texture->premultiplied == premultiplied)
return;
texture->premultiplied = premultiplied;
}
CoglBool
cogl_texture_get_premultiplied (CoglTexture *texture)
{
return texture->premultiplied;
}

View File

@ -256,6 +256,96 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
CoglBool
cogl_is_texture (void *object);
typedef enum _CoglTextureComponents
{
COGL_TEXTURE_COMPONENTS_A = 1,
COGL_TEXTURE_COMPONENTS_RGB,
COGL_TEXTURE_COMPONENTS_RGBA,
COGL_TEXTURE_COMPONENTS_DEPTH
} CoglTextureComponents;
/**
* cogl_texture_set_components:
* @texture: a #CoglTexture pointer.
*
* Affects the internal storage format for this texture by
* determinging what components will be required for sampling later.
*
* This api affects how data is uploaded to the GPU since unused
* components can potentially be discarded from source data.
*
* By default the required components are automatically determined
* using the format of the source data that is first uploaded to
* the given @texture.
*/
void
cogl_texture_set_components (CoglTexture *texture,
CoglTextureComponents components);
/**
* cogl_texture_get_components:
* @texture: a #CoglTexture pointer.
*
* Queries what components the given @texture stores internally as set
* via cogl_texture_set_components().
*
* By default the required components are automatically determined
* using the format of the source data that is first uploaded to
* the given @texture.
*/
CoglBool
cogl_texture_get_components (CoglTexture *texture);
/**
* cogl_texture_set_premultiplied:
* @texture: a #CoglTexture pointer.
* @premultiplied: Whether any internally stored red, green or blue
* components are pre-multiplied by an alpha
* component.
*
* Affects the internal storage format for this texture by determining
* whether red, green and blue color components should be stored as
* pre-multiplied alpha values.
*
* This api affects how data is uploaded to the GPU since Cogl will
* convert source data to have premultiplied or unpremultiplied
* components according to this state.
*
* For example if you create a texture via
* cogl_texture_2d_new_with_size() and then upload data via
* cogl_texture_set_data() passing a source format of
* %COGL_PIXEL_FORMAT_RGBA_8888 then Cogl will internally multiply the
* red, green and blue components of the source data by the alpha
* component, for each pixel so that the internally stored data has
* pre-multiplied alpha components. If you instead upload data that
* already has pre-multiplied components by passing
* %COGL_PIXEL_FORMAT_RGBA_8888_PRE as the source format to
* cogl_texture_set_data() then the data can be uploaded without being
* converted.
*
* By default the @premultipled state is @TRUE.
*/
void
cogl_texture_set_premultiplied (CoglTexture *texture,
CoglBool premultiplied);
/**
* cogl_texture_get_premultiplied:
* @texture: a #CoglTexture pointer.
*
* Queries the pre-multiplied alpha status for internally stored red,
* green and blue components for the given @texture as set by
* cogl_texture_set_premultiplied().
*
* By default the pre-multipled state is @TRUE.
*
* Return value: %TRUE if red, green and blue components are
* internally stored pre-multiplied by the alpha
* value or %FALSE if not.
*/
CoglBool
cogl_texture_get_premultiplied (CoglTexture *texture);
/**
* cogl_texture_get_width:
* @texture: a #CoglTexture pointer.

View File

@ -25,13 +25,12 @@
* Robert Bragg <robert@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <config.h>
#include <string.h>
#include "cogl-private.h"
#include "cogl-texture-private.h"
#include "cogl-texture-2d-gl.h"
#include "cogl-texture-2d-gl-private.h"
#include "cogl-texture-2d-private.h"
@ -57,6 +56,13 @@ _cogl_texture_2d_gl_can_create (CoglContext *ctx,
GLenum gl_format;
GLenum gl_type;
/* If NPOT textures aren't supported then the size must be a power
of two */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
(!_cogl_util_is_pot (width) ||
!_cogl_util_is_pot (height)))
return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
internal_format,
&gl_intformat,
@ -90,22 +96,29 @@ _cogl_texture_2d_gl_init (CoglTexture2D *tex_2d)
tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
}
CoglBool
_cogl_texture_2d_gl_allocate (CoglTexture *tex,
CoglError **error)
static CoglBool
allocate_with_size (CoglTexture2D *tex_2d,
CoglTextureLoader *loader,
CoglError **error)
{
CoglTexture *tex = COGL_TEXTURE (tex_2d);
CoglPixelFormat internal_format;
int width = loader->src.sized.width;
int height = loader->src.sized.height;
CoglContext *ctx = tex->context;
CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
GLenum gl_error;
GLenum gl_texture;
internal_format =
_cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
if (!_cogl_texture_2d_gl_can_create (ctx,
tex->width,
tex->height,
tex_2d->internal_format))
width,
height,
internal_format))
{
_cogl_set_error (error, COGL_TEXTURE_ERROR,
COGL_TEXTURE_ERROR_SIZE,
@ -115,13 +128,12 @@ _cogl_texture_2d_gl_allocate (CoglTexture *tex,
}
ctx->driver_vtable->pixel_format_to_gl (ctx,
tex_2d->internal_format,
internal_format,
&gl_intformat,
&gl_format,
&gl_type);
gl_texture =
ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, tex_2d->internal_format);
gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
tex_2d->gl_internal_format = gl_intformat;
@ -134,7 +146,7 @@ _cogl_texture_2d_gl_allocate (CoglTexture *tex,
;
ctx->glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat,
tex->width, tex->height, 0, gl_format, gl_type, NULL);
width, height, 0, gl_format, gl_type, NULL);
if (_cogl_gl_util_catch_out_of_memory (ctx, error))
{
@ -145,28 +157,51 @@ _cogl_texture_2d_gl_allocate (CoglTexture *tex,
tex_2d->gl_texture = gl_texture;
tex_2d->gl_internal_format = gl_intformat;
tex_2d->internal_format = internal_format;
_cogl_texture_set_allocated (tex, internal_format, width, height);
return TRUE;
}
CoglTexture2D *
_cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
CoglPixelFormat internal_format,
CoglBool can_convert_in_place,
CoglError **error)
static CoglBool
allocate_from_bitmap (CoglTexture2D *tex_2d,
CoglTextureLoader *loader,
CoglError **error)
{
CoglTexture *tex = COGL_TEXTURE (tex_2d);
CoglBitmap *bmp = loader->src.bitmap.bitmap;
CoglContext *ctx = _cogl_bitmap_get_context (bmp);
CoglTexture2D *tex_2d;
CoglPixelFormat internal_format;
int width = cogl_bitmap_get_width (bmp);
int height = cogl_bitmap_get_height (bmp);
CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place;
CoglBitmap *upload_bmp;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
internal_format =
_cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp));
if (!_cogl_texture_2d_gl_can_create (ctx,
width,
height,
internal_format))
{
_cogl_set_error (error, COGL_TEXTURE_ERROR,
COGL_TEXTURE_ERROR_SIZE,
"Failed to create texture 2d due to size/format"
" constraints");
return FALSE;
}
upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
internal_format,
can_convert_in_place,
error);
if (upload_bmp == NULL)
return NULL;
return FALSE;
ctx->driver_vtable->pixel_format_to_gl (ctx,
cogl_bitmap_get_format (upload_bmp),
@ -179,11 +214,6 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
NULL,
NULL);
tex_2d = _cogl_texture_2d_create_base (ctx,
cogl_bitmap_get_width (bmp),
cogl_bitmap_get_height (bmp),
internal_format);
/* Keep a copy of the first pixel so that if glGenerateMipmap isn't
supported we can fallback to using GL_GENERATE_MIPMAP */
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
@ -226,44 +256,40 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
error))
{
cogl_object_unref (upload_bmp);
cogl_object_unref (tex_2d);
return NULL;
return FALSE;
}
tex_2d->gl_internal_format = gl_intformat;
cogl_object_unref (upload_bmp);
_cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE);
tex_2d->internal_format = internal_format;
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)
CoglTexture2D *
_cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx,
int width,
int height,
CoglPixelFormat format,
EGLImageKHR image,
CoglError **error)
static CoglBool
allocate_from_egl_image (CoglTexture2D *tex_2d,
CoglTextureLoader *loader,
CoglError **error)
{
CoglTexture2D *tex_2d;
CoglTexture *tex = COGL_TEXTURE (tex_2d);
CoglContext *ctx = tex->context;
CoglPixelFormat internal_format = loader->src.egl_image.format;
GLenum gl_error;
tex_2d = _cogl_texture_2d_create_base (ctx,
width, height,
format);
tex_2d->gl_texture =
ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, format);
ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
_cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
tex_2d->gl_texture,
FALSE);
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, image);
ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, loader->src.egl_image.image);
if (ctx->glGetError () != GL_NO_ERROR)
{
_cogl_set_error (error,
@ -271,16 +297,175 @@ _cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx,
COGL_TEXTURE_ERROR_BAD_PARAMETER,
"Could not create a CoglTexture2D from a given "
"EGLImage");
cogl_object_unref (tex_2d);
return NULL;
GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) );
return FALSE;
}
_cogl_texture_set_allocated (COGL_TEXTURE (tex_2d), TRUE);
tex_2d->internal_format = internal_format;
return tex_2d;
_cogl_texture_set_allocated (tex,
internal_format,
loader->src.egl_image.width,
loader->src.egl_image.height);
return TRUE;
}
#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
_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex,
GLenum min_filter,
@ -343,89 +528,12 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
CoglPixelFormat format,
CoglError **error)
{
CoglTextureLoader *loader;
/* NOTE: width, height and internal format are not queriable
* 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
* the texture object because the user may be creating a Cogl
* 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.
*/
/* Assert it is a valid GL texture object */
_COGL_RETURN_VAL_IF_FAIL (ctx->glIsTexture (gl_handle), FALSE);
/* 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 */
if (gl_compressed == GL_TRUE)
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Compressed foreign textures aren't currently supported");
return 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;
/* 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. */
/* 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;
return _cogl_texture_2d_create_base (ctx, width, height, format, loader);
}
void

View File

@ -678,10 +678,6 @@ _cogl_driver_gl =
_cogl_texture_2d_gl_can_create,
_cogl_texture_2d_gl_init,
_cogl_texture_2d_gl_allocate,
_cogl_texture_2d_gl_new_from_bitmap,
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
_cogl_egl_texture_2d_gl_new_from_image,
#endif
_cogl_texture_2d_gl_copy_from_framebuffer,
_cogl_texture_2d_gl_get_gl_handle,
_cogl_texture_2d_gl_generate_mipmap,

View File

@ -397,10 +397,6 @@ _cogl_driver_gles =
_cogl_texture_2d_gl_can_create,
_cogl_texture_2d_gl_init,
_cogl_texture_2d_gl_allocate,
_cogl_texture_2d_gl_new_from_bitmap,
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
_cogl_egl_texture_2d_gl_new_from_image,
#endif
_cogl_texture_2d_gl_copy_from_framebuffer,
_cogl_texture_2d_gl_get_gl_handle,
_cogl_texture_2d_gl_generate_mipmap,

View File

@ -69,10 +69,6 @@ _cogl_driver_nop =
_cogl_texture_2d_nop_can_create,
_cogl_texture_2d_nop_init,
_cogl_texture_2d_nop_allocate,
_cogl_texture_2d_nop_new_from_bitmap,
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
_cogl_egl_texture_2d_nop_new_from_image,
#endif
_cogl_texture_2d_nop_copy_from_framebuffer,
_cogl_texture_2d_nop_get_gl_handle,
_cogl_texture_2d_nop_generate_mipmap,

View File

@ -48,22 +48,6 @@ CoglBool
_cogl_texture_2d_nop_allocate (CoglTexture *tex,
CoglError **error);
CoglTexture2D *
_cogl_texture_2d_nop_new_from_bitmap (CoglBitmap *bmp,
CoglPixelFormat internal_format,
CoglBool can_convert_in_place,
CoglError **error);
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
CoglTexture2D *
_cogl_egl_texture_2d_nop_new_from_image (CoglContext *ctx,
int width,
int height,
CoglPixelFormat format,
EGLImageKHR image,
CoglError **error);
#endif
void
_cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex,
GLenum min_filter,

View File

@ -62,36 +62,6 @@ _cogl_texture_2d_nop_allocate (CoglTexture *tex,
return TRUE;
}
CoglTexture2D *
_cogl_texture_2d_nop_new_from_bitmap (CoglBitmap *bmp,
CoglPixelFormat internal_format,
CoglBool can_convert_in_place,
CoglError **error)
{
return _cogl_texture_2d_create_base (_cogl_bitmap_get_context (bmp),
cogl_bitmap_get_width (bmp),
cogl_bitmap_get_height (bmp),
internal_format);
}
#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
CoglTexture2D *
_cogl_egl_texture_2d_nop_new_from_image (CoglContext *ctx,
int width,
int height,
CoglPixelFormat format,
EGLImageKHR image,
CoglError **error)
{
_cogl_set_error (error,
COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,
"Creating 2D textures from an EGLImage isn't "
"supported by the NOP backend");
return NULL;
}
#endif
void
_cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex,
GLenum min_filter,

View File

@ -287,6 +287,7 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
int pixmap_x, pixmap_y;
unsigned int pixmap_width, pixmap_height;
unsigned int pixmap_border_width;
CoglPixelFormat internal_format;
CoglTexture *tex = COGL_TEXTURE (tex_pixmap);
XWindowAttributes window_attributes;
int damage_base;
@ -305,7 +306,15 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
return NULL;
}
/* Note: the detailed pixel layout doesn't matter here, we are just
* interested in RGB vs RGBA... */
internal_format = (tex_pixmap->depth >= 32
? COGL_PIXEL_FORMAT_RGBA_8888_PRE
: COGL_PIXEL_FORMAT_RGB_888);
_cogl_texture_init (tex, ctxt, pixmap_width, pixmap_height,
internal_format,
NULL, /* no loader */
&cogl_texture_pixmap_x11_vtable);
tex_pixmap->pixmap = pixmap;
@ -326,6 +335,7 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
"Unable to query root window attributes");
return NULL;
}
tex_pixmap->visual = window_attributes.visual;
/* If automatic updates are requested and the Xlib connection
@ -346,9 +356,9 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
/* Assume the entire pixmap is damaged to begin with */
tex_pixmap->damage_rect.x1 = 0;
tex_pixmap->damage_rect.x2 = tex->width;
tex_pixmap->damage_rect.x2 = pixmap_width;
tex_pixmap->damage_rect.y1 = 0;
tex_pixmap->damage_rect.y2 = tex->height;
tex_pixmap->damage_rect.y2 = pixmap_height;
winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap);
if (winsys->texture_pixmap_x11_create)
@ -362,7 +372,8 @@ cogl_texture_pixmap_x11_new (CoglContext *ctxt,
if (!tex_pixmap->use_winsys_texture)
tex_pixmap->winsys = NULL;
_cogl_texture_set_allocated (tex, TRUE);
_cogl_texture_set_allocated (tex, internal_format,
pixmap_width, pixmap_height);
return _cogl_texture_pixmap_x11_object_new (tex_pixmap);
}

View File

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