cogl: Let GL do the format conversion when uploading texture data

Cogl accepts a pixel format for both the data in memory and the
internal format to be used for the texture. If they do not match then
it would convert them using the CoglBitmap functions before uploading
the data. However, GL also lets you specify both formats so it makes
more sense to let GL do the conversion. The driver may need the
texture in a specific format so it may end up being converted anyway.

The cogl_texture_upload_data functions have been removed and replaced
with a single function to prepare the bitmap. This will only do the
premultiplication conversion because that is the only part that GL
can't do directly.
This commit is contained in:
Neil Roberts 2010-02-01 12:11:58 +00:00
parent e83ffb1fa3
commit abe91784c4
5 changed files with 289 additions and 312 deletions

View File

@ -508,11 +508,8 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
{ {
gint bpp; gint bpp;
CoglBitmap source_bmp; CoglBitmap source_bmp;
CoglBitmap temp_bmp; CoglBitmap tmp_bmp;
gboolean source_bmp_owner = FALSE; gboolean tmp_bmp_owner = FALSE;
CoglPixelFormat closest_format;
GLenum closest_gl_format;
GLenum closest_gl_type;
gboolean success; gboolean success;
/* Check for valid format */ /* Check for valid format */
@ -533,25 +530,14 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
bpp = _cogl_get_format_bpp (format); bpp = _cogl_get_format_bpp (format);
source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride; source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
/* Find closest format to internal that's supported by GL */ /* Prepare the bitmap so that it will do the premultiplication
closest_format = _cogl_pixel_format_to_gl (atlas_tex->format, conversion */
NULL, /* don't need */ _cogl_texture_prepare_for_upload (&source_bmp,
&closest_gl_format, atlas_tex->format,
&closest_gl_type); NULL,
&tmp_bmp,
/* If no direct match, convert */ &tmp_bmp_owner,
if (closest_format != format) NULL, NULL, NULL);
{
/* Convert to required format */
success = _cogl_bitmap_convert_format_and_premult (&source_bmp,
&temp_bmp,
closest_format);
/* Swap bitmaps if succeeded */
if (!success) return FALSE;
source_bmp = temp_bmp;
source_bmp_owner = TRUE;
}
/* Upload the data ignoring the premult bit */ /* Upload the data ignoring the premult bit */
success = success =
@ -559,16 +545,16 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
dst_width, dst_height, dst_width, dst_height,
source_bmp.width, tmp_bmp.width,
source_bmp.height, tmp_bmp.height,
source_bmp.format & tmp_bmp.format &
~COGL_PREMULT_BIT, ~COGL_PREMULT_BIT,
source_bmp.rowstride, tmp_bmp.rowstride,
source_bmp.data); tmp_bmp.data);
/* Free data if owner */ /* Free data if owner */
if (source_bmp_owner) if (tmp_bmp_owner)
g_free (source_bmp.data); g_free (tmp_bmp.data);
return success; return success;
} }
@ -929,7 +915,11 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle,
{ {
CoglAtlasTexture *atlas_tex; CoglAtlasTexture *atlas_tex;
CoglBitmap *bmp = (CoglBitmap *) bmp_handle; CoglBitmap *bmp = (CoglBitmap *) bmp_handle;
CoglTextureUploadData upload_data; CoglBitmap dst_bmp;
gboolean dst_bmp_owner;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
@ -956,18 +946,18 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle,
if (!cogl_features_available (COGL_FEATURE_TEXTURE_READ_PIXELS)) if (!cogl_features_available (COGL_FEATURE_TEXTURE_READ_PIXELS))
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
upload_data.bitmap = *bmp;
upload_data.bitmap_owner = FALSE;
if (!_cogl_texture_upload_data_prepare_format (&upload_data,
&internal_format))
{
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE;
}
COGL_NOTE (ATLAS, "Adding texture of size %ix%i", bmp->width, bmp->height); COGL_NOTE (ATLAS, "Adding texture of size %ix%i", bmp->width, bmp->height);
if (!_cogl_texture_prepare_for_upload (bmp,
internal_format,
&internal_format,
NULL,
NULL,
&gl_intformat,
&gl_format,
&gl_type))
return COGL_INVALID_HANDLE;
/* If the texture is in a strange format then we can't use it */ /* If the texture is in a strange format then we can't use it */
if (internal_format != COGL_PIXEL_FORMAT_RGB_888 && if (internal_format != COGL_PIXEL_FORMAT_RGB_888 &&
(internal_format & ~COGL_PREMULT_BIT) != COGL_PIXEL_FORMAT_RGBA_8888) (internal_format & ~COGL_PREMULT_BIT) != COGL_PIXEL_FORMAT_RGBA_8888)
@ -975,7 +965,6 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle,
COGL_NOTE (ATLAS, "Texture can not be added because the " COGL_NOTE (ATLAS, "Texture can not be added because the "
"format is unsupported"); "format is unsupported");
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
} }
@ -984,8 +973,8 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle,
atlas_tex = g_new (CoglAtlasTexture, 1); atlas_tex = g_new (CoglAtlasTexture, 1);
/* We need to fill in the texture size now because it is used in the /* We need to fill in the texture size now because it is used in the
reserve_space function below. We add two pixels for the border */ reserve_space function below. We add two pixels for the border */
atlas_tex->rectangle.width = upload_data.bitmap.width + 2; atlas_tex->rectangle.width = bmp->width + 2;
atlas_tex->rectangle.height = upload_data.bitmap.height + 2; atlas_tex->rectangle.height = bmp->height + 2;
/* Try to make some space in the atlas for the texture */ /* Try to make some space in the atlas for the texture */
if (!_cogl_atlas_texture_reserve_space (atlas_tex, if (!_cogl_atlas_texture_reserve_space (atlas_tex,
@ -993,15 +982,20 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle,
atlas_tex->rectangle.height)) atlas_tex->rectangle.height))
{ {
g_free (atlas_tex); g_free (atlas_tex);
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
} }
if (!_cogl_texture_upload_data_convert (&upload_data, internal_format)) if (!_cogl_texture_prepare_for_upload (bmp,
internal_format,
&internal_format,
&dst_bmp,
&dst_bmp_owner,
&gl_intformat,
&gl_format,
&gl_type))
{ {
cogl_atlas_remove_rectangle (ctx->atlas, &atlas_tex->rectangle); cogl_atlas_remove_rectangle (ctx->atlas, &atlas_tex->rectangle);
g_free (atlas_tex); g_free (atlas_tex);
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
} }
@ -1019,14 +1013,17 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle,
_cogl_atlas_texture_set_region_with_border (atlas_tex, _cogl_atlas_texture_set_region_with_border (atlas_tex,
0, 0, 0, 0,
0, 0, 0, 0,
upload_data.bitmap.width, dst_bmp.width,
upload_data.bitmap.height, dst_bmp.height,
upload_data.bitmap.width, dst_bmp.width,
upload_data.bitmap.height, dst_bmp.height,
upload_data.bitmap.format & dst_bmp.format &
~COGL_PREMULT_BIT, ~COGL_PREMULT_BIT,
upload_data.bitmap.rowstride, dst_bmp.rowstride,
upload_data.bitmap.data); dst_bmp.data);
if (dst_bmp_owner)
g_free (dst_bmp.data);
return _cogl_atlas_texture_handle_new (atlas_tex); return _cogl_atlas_texture_handle_new (atlas_tex);
} }

View File

@ -213,7 +213,10 @@ _cogl_texture_2d_sliced_allocate_waste_buffer (CoglTexture2DSliced *tex_2ds,
static gboolean static gboolean
_cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds, _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
CoglTextureUploadData *upload_data) CoglBitmap *bmp,
GLenum gl_intformat,
GLenum gl_format,
GLenum gl_type)
{ {
CoglSpan *x_span; CoglSpan *x_span;
CoglSpan *y_span; CoglSpan *y_span;
@ -222,11 +225,10 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
gint x,y; gint x,y;
guchar *waste_buf; guchar *waste_buf;
bpp = _cogl_get_format_bpp (upload_data->bitmap.format); bpp = _cogl_get_format_bpp (bmp->format);
waste_buf = waste_buf = _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds,
_cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds, bmp->format);
upload_data->bitmap.format);
/* Iterate vertical slices */ /* Iterate vertical slices */
for (y = 0; y < tex_2ds->slice_y_spans->len; ++y) for (y = 0; y < tex_2ds->slice_y_spans->len; ++y)
@ -252,27 +254,26 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
0, /* dst y */ 0, /* dst y */
x_span->size - x_span->waste, /* width */ x_span->size - x_span->waste, /* width */
y_span->size - y_span->waste, /* height */ y_span->size - y_span->waste, /* height */
&upload_data->bitmap, bmp,
upload_data->gl_format, gl_format,
upload_data->gl_type); gl_type);
/* Keep a copy of the first pixel if needed */ /* Keep a copy of the first pixel if needed */
if (tex_2ds->first_pixels) if (tex_2ds->first_pixels)
{ {
memcpy (tex_2ds->first_pixels[slice_num].data, memcpy (tex_2ds->first_pixels[slice_num].data,
upload_data->bitmap.data + x_span->start * bpp bmp->data + x_span->start * bpp
+ y_span->start * upload_data->bitmap.rowstride, + y_span->start * bmp->rowstride,
bpp); bpp);
tex_2ds->first_pixels[slice_num].gl_format = tex_2ds->first_pixels[slice_num].gl_format = gl_format;
upload_data->gl_format; tex_2ds->first_pixels[slice_num].gl_type = gl_type;
tex_2ds->first_pixels[slice_num].gl_type = upload_data->gl_type;
} }
/* Fill the waste with a copies of the rightmost pixels */ /* Fill the waste with a copies of the rightmost pixels */
if (x_span->waste > 0) if (x_span->waste > 0)
{ {
const guchar *src = upload_data->bitmap.data const guchar *src = bmp->data
+ y_span->start * upload_data->bitmap.rowstride + y_span->start * bmp->rowstride
+ (x_span->start + x_span->size - x_span->waste - 1) * bpp; + (x_span->start + x_span->size - x_span->waste - 1) * bpp;
guchar *dst = waste_buf; guchar *dst = waste_buf;
guint wx, wy; guint wx, wy;
@ -284,7 +285,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
memcpy (dst, src, bpp); memcpy (dst, src, bpp);
dst += bpp; dst += bpp;
} }
src += upload_data->bitmap.rowstride; src += bmp->rowstride;
} }
_cogl_texture_driver_prep_gl_for_pixels_upload ( _cogl_texture_driver_prep_gl_for_pixels_upload (
@ -296,15 +297,15 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
0, 0,
x_span->waste, x_span->waste,
y_span->size - y_span->waste, y_span->size - y_span->waste,
upload_data->gl_format, upload_data->gl_type, gl_format, gl_type,
waste_buf) ); waste_buf) );
} }
if (y_span->waste > 0) if (y_span->waste > 0)
{ {
const guchar *src = upload_data->bitmap.data const guchar *src = bmp->data
+ ((y_span->start + y_span->size - y_span->waste - 1) + ((y_span->start + y_span->size - y_span->waste - 1)
* upload_data->bitmap.rowstride) * bmp->rowstride)
+ x_span->start * bpp; + x_span->start * bpp;
guchar *dst = waste_buf; guchar *dst = waste_buf;
guint wy, wx; guint wy, wx;
@ -330,7 +331,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
y_span->size - y_span->waste, y_span->size - y_span->waste,
x_span->size, x_span->size,
y_span->waste, y_span->waste,
upload_data->gl_format, upload_data->gl_type, gl_format, gl_type,
waste_buf) ); waste_buf) );
} }
} }
@ -685,7 +686,10 @@ _cogl_texture_2d_sliced_set_wrap_mode_parameter (CoglTexture *tex,
static gboolean static gboolean
_cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds, _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
const CoglTextureUploadData *upload_data) gint width, gint height,
GLenum gl_intformat,
GLenum gl_format,
GLenum gl_type)
{ {
gint max_width; gint max_width;
gint max_height; gint max_height;
@ -703,15 +707,15 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
/* Initialize size of largest slice according to supported features */ /* Initialize size of largest slice according to supported features */
if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)) if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT))
{ {
max_width = upload_data->bitmap.width; max_width = width;
max_height = upload_data->bitmap.height; max_height = height;
tex_2ds->gl_target = GL_TEXTURE_2D; tex_2ds->gl_target = GL_TEXTURE_2D;
slices_for_size = _cogl_rect_slices_for_size; slices_for_size = _cogl_rect_slices_for_size;
} }
else else
{ {
max_width = cogl_util_next_p2 (upload_data->bitmap.width); max_width = cogl_util_next_p2 (width);
max_height = cogl_util_next_p2 (upload_data->bitmap.height); max_height = cogl_util_next_p2 (height);
tex_2ds->gl_target = GL_TEXTURE_2D; tex_2ds->gl_target = GL_TEXTURE_2D;
slices_for_size = _cogl_pot_slices_for_size; slices_for_size = _cogl_pot_slices_for_size;
} }
@ -723,8 +727,8 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
/* Check if size supported else bail out */ /* Check if size supported else bail out */
if (!_cogl_texture_driver_size_supported (tex_2ds->gl_target, if (!_cogl_texture_driver_size_supported (tex_2ds->gl_target,
upload_data->gl_intformat, gl_intformat,
upload_data->gl_type, gl_type,
max_width, max_width,
max_height)) max_height))
{ {
@ -746,19 +750,19 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
/* Add a single span for width and height */ /* Add a single span for width and height */
span.start = 0; span.start = 0;
span.size = max_width; span.size = max_width;
span.waste = max_width - upload_data->bitmap.width; span.waste = max_width - width;
g_array_append_val (tex_2ds->slice_x_spans, span); g_array_append_val (tex_2ds->slice_x_spans, span);
span.size = max_height; span.size = max_height;
span.waste = max_height - upload_data->bitmap.height; span.waste = max_height - height;
g_array_append_val (tex_2ds->slice_y_spans, span); g_array_append_val (tex_2ds->slice_y_spans, span);
} }
else else
{ {
/* Decrease the size of largest slice until supported by GL */ /* Decrease the size of largest slice until supported by GL */
while (!_cogl_texture_driver_size_supported (tex_2ds->gl_target, while (!_cogl_texture_driver_size_supported (tex_2ds->gl_target,
upload_data->gl_intformat, gl_intformat,
upload_data->gl_type, gl_type,
max_width, max_width,
max_height)) max_height))
{ {
@ -773,11 +777,11 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
} }
/* Determine the slices required to cover the bitmap area */ /* Determine the slices required to cover the bitmap area */
n_x_slices = slices_for_size (upload_data->bitmap.width, n_x_slices = slices_for_size (width,
max_width, tex_2ds->max_waste, max_width, tex_2ds->max_waste,
NULL); NULL);
n_y_slices = slices_for_size (upload_data->bitmap.height, n_y_slices = slices_for_size (height,
max_height, tex_2ds->max_waste, max_height, tex_2ds->max_waste,
NULL); NULL);
@ -791,11 +795,11 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
n_y_slices); n_y_slices);
/* Fill span arrays with info */ /* Fill span arrays with info */
slices_for_size (upload_data->bitmap.width, slices_for_size (width,
max_width, tex_2ds->max_waste, max_width, tex_2ds->max_waste,
tex_2ds->slice_x_spans); tex_2ds->slice_x_spans);
slices_for_size (upload_data->bitmap.height, slices_for_size (height,
max_height, tex_2ds->max_waste, max_height, tex_2ds->max_waste,
tex_2ds->slice_y_spans); tex_2ds->slice_y_spans);
} }
@ -845,15 +849,15 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
/* Setup texture parameters */ /* Setup texture parameters */
GE( _cogl_texture_driver_bind (tex_2ds->gl_target, GE( _cogl_texture_driver_bind (tex_2ds->gl_target,
gl_handles[y * n_x_slices + x], gl_handles[y * n_x_slices + x],
upload_data->gl_intformat) ); gl_intformat) );
_cogl_texture_driver_try_setting_gl_border_color (tex_2ds->gl_target, _cogl_texture_driver_try_setting_gl_border_color (tex_2ds->gl_target,
transparent_color); transparent_color);
/* Pass NULL data to init size and internal format */ /* Pass NULL data to init size and internal format */
GE( glTexImage2D (tex_2ds->gl_target, 0, upload_data->gl_intformat, GE( glTexImage2D (tex_2ds->gl_target, 0, gl_intformat,
x_span->size, y_span->size, 0, x_span->size, y_span->size, 0,
upload_data->gl_format, upload_data->gl_type, 0) ); gl_format, gl_type, 0) );
} }
} }
@ -894,10 +898,13 @@ _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
static gboolean static gboolean
_cogl_texture_2d_sliced_upload_from_data _cogl_texture_2d_sliced_upload_from_data
(CoglTexture2DSliced *tex_2ds, (CoglTexture2DSliced *tex_2ds,
CoglTextureUploadData *upload_data, CoglBitmap *bmp,
CoglPixelFormat internal_format) CoglPixelFormat internal_format)
{ {
CoglTexture *tex = COGL_TEXTURE (tex_2ds); CoglTexture *tex = COGL_TEXTURE (tex_2ds);
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
tex->vtable = &cogl_texture_2d_sliced_vtable; tex->vtable = &cogl_texture_2d_sliced_vtable;
@ -914,36 +921,72 @@ _cogl_texture_2d_sliced_upload_from_data
tex_2ds->min_filter = GL_FALSE; tex_2ds->min_filter = GL_FALSE;
tex_2ds->mag_filter = GL_FALSE; tex_2ds->mag_filter = GL_FALSE;
if (upload_data->bitmap.data) if (bmp->data)
{ {
if (!_cogl_texture_upload_data_prepare (upload_data, internal_format)) CoglBitmap dst_bmp;
gboolean dst_bmp_owner;
if (!_cogl_texture_prepare_for_upload (bmp,
internal_format,
&internal_format,
&dst_bmp,
&dst_bmp_owner,
&gl_intformat,
&gl_format,
&gl_type))
return FALSE; return FALSE;
/* Create slices for the given format and size */ /* Create slices for the given format and size */
if (!_cogl_texture_2d_sliced_slices_create (tex_2ds, upload_data)) if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
return FALSE; bmp->width,
bmp->height,
gl_intformat,
gl_format,
gl_type))
{
if (dst_bmp_owner)
g_free (dst_bmp.data);
if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds, upload_data))
return FALSE; return FALSE;
} }
if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds,
bmp,
gl_intformat,
gl_format,
gl_type))
{
if (dst_bmp_owner)
g_free (dst_bmp.data);
return FALSE;
}
if (dst_bmp_owner)
g_free (dst_bmp.data);
}
else else
{ {
/* Find closest GL format match */ /* Find closest GL format match */
upload_data->bitmap.format =
_cogl_pixel_format_to_gl (internal_format, _cogl_pixel_format_to_gl (internal_format,
&upload_data->gl_intformat, &gl_intformat,
&upload_data->gl_format, &gl_format,
&upload_data->gl_type); &gl_type);
/* Create slices for the given format and size */ /* Create slices for the given format and size */
if (!_cogl_texture_2d_sliced_slices_create (tex_2ds, upload_data)) if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
bmp->width,
bmp->height,
gl_intformat,
gl_format,
gl_type))
return FALSE; return FALSE;
} }
tex_2ds->gl_format = upload_data->gl_intformat; tex_2ds->gl_format = gl_intformat;
tex_2ds->width = upload_data->bitmap.width; tex_2ds->width = bmp->width;
tex_2ds->height = upload_data->bitmap.height; tex_2ds->height = bmp->height;
tex_2ds->format = upload_data->bitmap.format; tex_2ds->format = bmp->format;
return TRUE; return TRUE;
} }
@ -956,7 +999,7 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int width,
{ {
CoglTexture2DSliced *tex_2ds; CoglTexture2DSliced *tex_2ds;
CoglTexture *tex; CoglTexture *tex;
CoglTextureUploadData upload_data; CoglBitmap bmp;
/* Since no data, we need some internal format */ /* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY) if (internal_format == COGL_PIXEL_FORMAT_ANY)
@ -967,28 +1010,24 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int width,
tex = COGL_TEXTURE (tex_2ds); tex = COGL_TEXTURE (tex_2ds);
upload_data.bitmap.width = width; bmp.width = width;
upload_data.bitmap.height = height; bmp.height = height;
upload_data.bitmap.data = NULL; bmp.data = NULL;
upload_data.bitmap_owner = FALSE;
if ((flags & COGL_TEXTURE_NO_SLICING)) if ((flags & COGL_TEXTURE_NO_SLICING))
tex_2ds->max_waste = -1; tex_2ds->max_waste = -1;
else else
tex_2ds->max_waste = COGL_TEXTURE_MAX_WASTE; tex_2ds->max_waste = COGL_TEXTURE_MAX_WASTE;
if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, &upload_data, if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, &bmp,
internal_format)) internal_format))
{ {
_cogl_texture_2d_sliced_free (tex_2ds); _cogl_texture_2d_sliced_free (tex_2ds);
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
} }
tex_2ds->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; tex_2ds->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
_cogl_texture_upload_data_free (&upload_data);
return _cogl_texture_2d_sliced_handle_new (tex_2ds); return _cogl_texture_2d_sliced_handle_new (tex_2ds);
} }
@ -1000,7 +1039,6 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle bmp_handle,
CoglTexture2DSliced *tex_2ds; CoglTexture2DSliced *tex_2ds;
CoglTexture *tex; CoglTexture *tex;
CoglBitmap *bmp = (CoglBitmap *)bmp_handle; CoglBitmap *bmp = (CoglBitmap *)bmp_handle;
CoglTextureUploadData upload_data;
g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE); g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
@ -1009,9 +1047,6 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle bmp_handle,
tex = COGL_TEXTURE (tex_2ds); tex = COGL_TEXTURE (tex_2ds);
upload_data.bitmap = *bmp;
upload_data.bitmap_owner = FALSE;
if (flags & COGL_TEXTURE_NO_SLICING) if (flags & COGL_TEXTURE_NO_SLICING)
tex_2ds->max_waste = -1; tex_2ds->max_waste = -1;
else else
@ -1025,18 +1060,15 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle bmp_handle,
* CoglHandle is returned, it should also be destroyed * CoglHandle is returned, it should also be destroyed
* with cogl_handle_unref at some point! */ * with cogl_handle_unref at some point! */
if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, &upload_data, if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, bmp,
internal_format)) internal_format))
{ {
_cogl_texture_2d_sliced_free (tex_2ds); _cogl_texture_2d_sliced_free (tex_2ds);
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
} }
tex_2ds->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; tex_2ds->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
_cogl_texture_upload_data_free (&upload_data);
return _cogl_texture_2d_sliced_handle_new (tex_2ds); return _cogl_texture_2d_sliced_handle_new (tex_2ds);
} }
@ -1398,12 +1430,10 @@ _cogl_texture_2d_sliced_set_region (CoglTexture *tex,
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
gint bpp; gint bpp;
CoglBitmap source_bmp; CoglBitmap source_bmp;
CoglBitmap temp_bmp; CoglBitmap tmp_bmp;
gboolean source_bmp_owner = FALSE; gboolean tmp_bmp_owner = FALSE;
CoglPixelFormat closest_format;
GLenum closest_gl_format; GLenum closest_gl_format;
GLenum closest_gl_type; GLenum closest_gl_type;
gboolean success;
/* Check for valid format */ /* Check for valid format */
if (format == COGL_PIXEL_FORMAT_ANY) if (format == COGL_PIXEL_FORMAT_ANY)
@ -1423,38 +1453,30 @@ _cogl_texture_2d_sliced_set_region (CoglTexture *tex,
bpp = _cogl_get_format_bpp (format); bpp = _cogl_get_format_bpp (format);
source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride; source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
/* Find closest format to internal that's supported by GL */ /* Prepare the bitmap so that it will do the premultiplication
closest_format = _cogl_pixel_format_to_gl (tex_2ds->format, conversion */
NULL, /* don't need */ _cogl_texture_prepare_for_upload (&source_bmp,
tex_2ds->format,
NULL,
&tmp_bmp,
&tmp_bmp_owner,
NULL,
&closest_gl_format, &closest_gl_format,
&closest_gl_type); &closest_gl_type);
/* If no direct match, convert */
if (closest_format != format)
{
/* Convert to required format */
success = _cogl_bitmap_convert_format_and_premult (&source_bmp,
&temp_bmp,
closest_format);
/* Swap bitmaps if succeeded */
if (!success) return FALSE;
source_bmp = temp_bmp;
source_bmp_owner = TRUE;
}
/* Send data to GL */ /* Send data to GL */
_cogl_texture_2d_sliced_upload_subregion_to_gl (tex_2ds, _cogl_texture_2d_sliced_upload_subregion_to_gl (tex_2ds,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
dst_width, dst_height, dst_width, dst_height,
&source_bmp, &tmp_bmp,
closest_gl_format, closest_gl_format,
closest_gl_type); closest_gl_type);
/* Free data if owner */ /* Free data if owner */
if (source_bmp_owner) if (tmp_bmp_owner)
g_free (source_bmp.data); g_free (tmp_bmp.data);
return TRUE; return TRUE;
} }

View File

@ -277,40 +277,41 @@ _cogl_texture_2d_new_from_bitmap (CoglHandle bmp_handle,
{ {
CoglTexture2D *tex_2d; CoglTexture2D *tex_2d;
CoglBitmap *bmp = (CoglBitmap *)bmp_handle; CoglBitmap *bmp = (CoglBitmap *)bmp_handle;
CoglTextureUploadData upload_data; CoglBitmap dst_bmp;
gboolean dst_bmp_owner;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE); g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
upload_data.bitmap = *bmp; if (!_cogl_texture_prepare_for_upload (bmp,
upload_data.bitmap_owner = FALSE; internal_format,
&internal_format,
if (!_cogl_texture_upload_data_prepare_format (&upload_data, &dst_bmp,
&internal_format) || &dst_bmp_owner,
!_cogl_texture_2d_can_create (upload_data.bitmap.width, &gl_intformat,
upload_data.bitmap.height, &gl_format,
internal_format) || &gl_type))
!_cogl_texture_upload_data_convert (&upload_data, internal_format))
{
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
}
tex_2d = _cogl_texture_2d_create_base (upload_data.bitmap.width, tex_2d = _cogl_texture_2d_create_base (bmp->width,
upload_data.bitmap.height, bmp->height,
flags, flags,
upload_data.bitmap.format); internal_format);
GE( glGenTextures (1, &tex_2d->gl_texture) ); GE( glGenTextures (1, &tex_2d->gl_texture) );
_cogl_texture_driver_upload_to_gl (GL_TEXTURE_2D, _cogl_texture_driver_upload_to_gl (GL_TEXTURE_2D,
tex_2d->gl_texture, tex_2d->gl_texture,
&upload_data.bitmap, &dst_bmp,
upload_data.gl_intformat, gl_intformat,
upload_data.gl_format, gl_format,
upload_data.gl_type); gl_type);
tex_2d->gl_format = upload_data.gl_intformat; tex_2d->gl_format = gl_intformat;
_cogl_texture_upload_data_free (&upload_data); if (dst_bmp_owner)
g_free (dst_bmp.data);
return _cogl_texture_2d_handle_new (tex_2d); return _cogl_texture_2d_handle_new (tex_2d);
} }
@ -431,12 +432,10 @@ _cogl_texture_2d_set_region (CoglTexture *tex,
CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
gint bpp; gint bpp;
CoglBitmap source_bmp; CoglBitmap source_bmp;
CoglBitmap temp_bmp; CoglBitmap tmp_bmp;
gboolean source_bmp_owner = FALSE; gboolean tmp_bmp_owner = FALSE;
CoglPixelFormat closest_format;
GLenum closest_gl_format; GLenum closest_gl_format;
GLenum closest_gl_type; GLenum closest_gl_type;
gboolean success;
/* Check for valid format */ /* Check for valid format */
if (format == COGL_PIXEL_FORMAT_ANY) if (format == COGL_PIXEL_FORMAT_ANY)
@ -456,39 +455,30 @@ _cogl_texture_2d_set_region (CoglTexture *tex,
bpp = _cogl_get_format_bpp (format); bpp = _cogl_get_format_bpp (format);
source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride; source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
/* Find closest format to internal that's supported by GL */ /* Prepare the bitmap so that it will do the premultiplication
closest_format = _cogl_pixel_format_to_gl (tex_2d->format, conversion */
NULL, /* don't need */ _cogl_texture_prepare_for_upload (&source_bmp,
tex_2d->format,
NULL,
&tmp_bmp,
&tmp_bmp_owner,
NULL,
&closest_gl_format, &closest_gl_format,
&closest_gl_type); &closest_gl_type);
/* If no direct match, convert */
if (closest_format != format)
{
/* Convert to required format */
success = _cogl_bitmap_convert_format_and_premult (&source_bmp,
&temp_bmp,
closest_format);
/* Swap bitmaps if succeeded */
if (!success) return FALSE;
source_bmp = temp_bmp;
source_bmp_owner = TRUE;
}
/* Send data to GL */ /* Send data to GL */
_cogl_texture_driver_upload_subregion_to_gl (GL_TEXTURE_2D, _cogl_texture_driver_upload_subregion_to_gl (GL_TEXTURE_2D,
tex_2d->gl_texture, tex_2d->gl_texture,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
dst_width, dst_height, dst_width, dst_height,
&source_bmp, &tmp_bmp,
closest_gl_format, closest_gl_format,
closest_gl_type); closest_gl_type);
/* Free data if owner */ /* Free data if owner */
if (source_bmp_owner) if (tmp_bmp_owner)
g_free (source_bmp.data); g_free (tmp_bmp.data);
return TRUE; return TRUE;
} }

View File

@ -32,7 +32,6 @@
typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTextureVtable CoglTextureVtable; typedef struct _CoglTextureVtable CoglTextureVtable;
typedef struct _CoglTextureUploadData CoglTextureUploadData;
typedef void (*CoglTextureSliceCallback) (CoglHandle handle, typedef void (*CoglTextureSliceCallback) (CoglHandle handle,
GLuint gl_handle, GLuint gl_handle,
@ -107,17 +106,6 @@ struct _CoglTextureVtable
gint (* get_height) (CoglTexture *tex); gint (* get_height) (CoglTexture *tex);
}; };
/* This represents the state needed to upload texture data. There are
utility functions in cogl-texture which use this state */
struct _CoglTextureUploadData
{
CoglBitmap bitmap;
gboolean bitmap_owner;
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
};
struct _CoglTexture struct _CoglTexture
{ {
CoglHandleObject _parent; CoglHandleObject _parent;
@ -162,28 +150,20 @@ _cogl_texture_ensure_mipmaps (CoglHandle handle);
void void
_cogl_texture_ensure_non_quad_rendering (CoglHandle handle); _cogl_texture_ensure_non_quad_rendering (CoglHandle handle);
/* Utility functions to help uploading a bitmap. These are intended to /* Utility function to help uploading a bitmap. If the bitmap needs
* be used by CoglTexture implementations or drivers... */ premult conversion then it will be copied and *copied_bitmap will
be set to TRUE. Otherwise dst_bmp will be set to a shallow copy of
void src_bmp. The GLenums needed for uploading are returned */
_cogl_texture_upload_data_free (CoglTextureUploadData *data);
void
_cogl_texture_upload_data_swap_bitmap (CoglTextureUploadData *data,
CoglBitmap *new_bitmap);
gboolean gboolean
_cogl_texture_upload_data_prepare_format _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
(CoglTextureUploadData *data, CoglPixelFormat dst_format,
CoglPixelFormat *internal_format); CoglPixelFormat *dst_format_out,
CoglBitmap *dst_bmp,
gboolean gboolean *copied_bitmap,
_cogl_texture_upload_data_convert (CoglTextureUploadData *data, GLenum *out_glintformat,
CoglPixelFormat internal_format); GLenum *out_glformat,
GLenum *out_gltype);
gboolean
_cogl_texture_upload_data_prepare (CoglTextureUploadData *data,
CoglPixelFormat internal_format);
void void
_cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride); _cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride);

View File

@ -100,25 +100,71 @@ cogl_texture_unref (CoglHandle handle)
cogl_handle_unref (handle); cogl_handle_unref (handle);
} }
void gboolean
_cogl_texture_upload_data_free (CoglTextureUploadData *data) _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
CoglPixelFormat dst_format,
CoglPixelFormat *dst_format_out,
CoglBitmap *dst_bmp,
gboolean *copied_bitmap,
GLenum *out_glintformat,
GLenum *out_glformat,
GLenum *out_gltype)
{ {
if (data->bitmap.data != NULL && data->bitmap_owner) /* If the application hasn't specified a specific format then we'll
g_free (data->bitmap.data); * 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 ((src_bmp->format & COGL_A_BIT) &&
src_bmp->format != COGL_PIXEL_FORMAT_A_8)
dst_format = src_bmp->format | COGL_PREMULT_BIT;
else
dst_format = src_bmp->format;
}
data->bitmap.data = NULL; if (dst_bmp)
data->bitmap_owner = FALSE; {
} *copied_bitmap = FALSE;
*dst_bmp = *src_bmp;
void /* If the source format does not have the same premult flag as the
_cogl_texture_upload_data_swap_bitmap (CoglTextureUploadData *data, dst format then we need to copy and convert it */
CoglBitmap *new_bitmap) if ((src_bmp->format & COGL_A_BIT) &&
{ src_bmp->format != COGL_PIXEL_FORMAT_A_8 &&
if (data->bitmap.data != NULL && data->bitmap_owner) (src_bmp->format & COGL_PREMULT_BIT) !=
g_free (data->bitmap.data); (dst_format & COGL_PREMULT_BIT))
{
dst_bmp->data = g_memdup (dst_bmp->data,
dst_bmp->height * dst_bmp->rowstride);
*copied_bitmap = TRUE;
data->bitmap = *new_bitmap; if (!_cogl_bitmap_convert_premult_status (dst_bmp,
data->bitmap_owner = TRUE; src_bmp->format ^
COGL_PREMULT_BIT))
{
g_free (dst_bmp->data);
return FALSE;
}
}
}
/* Use the source format from the src bitmap type and the internal
format from the dst format type so that GL can do the
conversion */
_cogl_pixel_format_to_gl (src_bmp->format,
NULL, /* internal format */
out_glformat,
out_gltype);
_cogl_pixel_format_to_gl (dst_format,
out_glintformat,
NULL,
NULL);
if (dst_format_out)
*dst_format_out = dst_format;
return TRUE;
} }
void void
@ -157,64 +203,6 @@ _cogl_texture_set_wrap_mode_parameter (CoglHandle handle,
tex->vtable->set_wrap_mode_parameter (tex, wrap_mode); tex->vtable->set_wrap_mode_parameter (tex, wrap_mode);
} }
gboolean
_cogl_texture_upload_data_prepare_format
(CoglTextureUploadData *data,
CoglPixelFormat *internal_format)
{
/* Was there any internal conversion requested?
* By default Cogl will use a premultiplied internal format. Later we will
* add control over this. */
if (*internal_format == COGL_PIXEL_FORMAT_ANY)
{
if ((data->bitmap.format & COGL_A_BIT) &&
data->bitmap.format != COGL_PIXEL_FORMAT_A_8)
*internal_format = data->bitmap.format | COGL_PREMULT_BIT;
else
*internal_format = data->bitmap.format;
}
/* Find closest format accepted by GL */
*internal_format = _cogl_pixel_format_to_gl (*internal_format,
&data->gl_intformat,
&data->gl_format,
&data->gl_type);
return TRUE;
}
gboolean
_cogl_texture_upload_data_convert (CoglTextureUploadData *data,
CoglPixelFormat internal_format)
{
CoglBitmap new_bitmap;
gboolean success;
/* Convert to internal format */
if (internal_format != data->bitmap.format)
{
success = _cogl_bitmap_convert_format_and_premult (&data->bitmap,
&new_bitmap,
internal_format);
if (!success)
return FALSE;
/* Update texture with new data */
_cogl_texture_upload_data_swap_bitmap (data, &new_bitmap);
}
return TRUE;
}
gboolean
_cogl_texture_upload_data_prepare (CoglTextureUploadData *data,
CoglPixelFormat internal_format)
{
return (_cogl_texture_upload_data_prepare_format (data, &internal_format) &&
_cogl_texture_upload_data_convert (data, internal_format));
}
/* This is like CoglSpanIter except it deals with floats and it /* This is like CoglSpanIter except it deals with floats and it
effectively assumes there is only one span from 0.0 to 1.0 */ effectively assumes there is only one span from 0.0 to 1.0 */
typedef struct _CoglTextureIter typedef struct _CoglTextureIter