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;
CoglBitmap source_bmp;
CoglBitmap temp_bmp;
gboolean source_bmp_owner = FALSE;
CoglPixelFormat closest_format;
GLenum closest_gl_format;
GLenum closest_gl_type;
CoglBitmap tmp_bmp;
gboolean tmp_bmp_owner = FALSE;
gboolean success;
/* Check for valid format */
@ -533,25 +530,14 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
bpp = _cogl_get_format_bpp (format);
source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
/* Find closest format to internal that's supported by GL */
closest_format = _cogl_pixel_format_to_gl (atlas_tex->format,
NULL, /* don't need */
&closest_gl_format,
&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;
}
/* Prepare the bitmap so that it will do the premultiplication
conversion */
_cogl_texture_prepare_for_upload (&source_bmp,
atlas_tex->format,
NULL,
&tmp_bmp,
&tmp_bmp_owner,
NULL, NULL, NULL);
/* Upload the data ignoring the premult bit */
success =
@ -559,16 +545,16 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
src_x, src_y,
dst_x, dst_y,
dst_width, dst_height,
source_bmp.width,
source_bmp.height,
source_bmp.format &
tmp_bmp.width,
tmp_bmp.height,
tmp_bmp.format &
~COGL_PREMULT_BIT,
source_bmp.rowstride,
source_bmp.data);
tmp_bmp.rowstride,
tmp_bmp.data);
/* Free data if owner */
if (source_bmp_owner)
g_free (source_bmp.data);
if (tmp_bmp_owner)
g_free (tmp_bmp.data);
return success;
}
@ -929,7 +915,11 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle,
{
CoglAtlasTexture *atlas_tex;
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);
@ -956,18 +946,18 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle,
if (!cogl_features_available (COGL_FEATURE_TEXTURE_READ_PIXELS))
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);
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 (internal_format != COGL_PIXEL_FORMAT_RGB_888 &&
(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 "
"format is unsupported");
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE;
}
@ -984,8 +973,8 @@ _cogl_atlas_texture_new_from_bitmap (CoglHandle bmp_handle,
atlas_tex = g_new (CoglAtlasTexture, 1);
/* 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 */
atlas_tex->rectangle.width = upload_data.bitmap.width + 2;
atlas_tex->rectangle.height = upload_data.bitmap.height + 2;
atlas_tex->rectangle.width = bmp->width + 2;
atlas_tex->rectangle.height = bmp->height + 2;
/* Try to make some space in the atlas for the texture */
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))
{
g_free (atlas_tex);
_cogl_texture_upload_data_free (&upload_data);
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);
g_free (atlas_tex);
_cogl_texture_upload_data_free (&upload_data);
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,
0, 0,
0, 0,
upload_data.bitmap.width,
upload_data.bitmap.height,
upload_data.bitmap.width,
upload_data.bitmap.height,
upload_data.bitmap.format &
dst_bmp.width,
dst_bmp.height,
dst_bmp.width,
dst_bmp.height,
dst_bmp.format &
~COGL_PREMULT_BIT,
upload_data.bitmap.rowstride,
upload_data.bitmap.data);
dst_bmp.rowstride,
dst_bmp.data);
if (dst_bmp_owner)
g_free (dst_bmp.data);
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
_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 *y_span;
@ -222,11 +225,10 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
gint x,y;
guchar *waste_buf;
bpp = _cogl_get_format_bpp (upload_data->bitmap.format);
bpp = _cogl_get_format_bpp (bmp->format);
waste_buf =
_cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds,
upload_data->bitmap.format);
waste_buf = _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds,
bmp->format);
/* Iterate vertical slices */
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 */
x_span->size - x_span->waste, /* width */
y_span->size - y_span->waste, /* height */
&upload_data->bitmap,
upload_data->gl_format,
upload_data->gl_type);
bmp,
gl_format,
gl_type);
/* Keep a copy of the first pixel if needed */
if (tex_2ds->first_pixels)
{
memcpy (tex_2ds->first_pixels[slice_num].data,
upload_data->bitmap.data + x_span->start * bpp
+ y_span->start * upload_data->bitmap.rowstride,
bmp->data + x_span->start * bpp
+ y_span->start * bmp->rowstride,
bpp);
tex_2ds->first_pixels[slice_num].gl_format =
upload_data->gl_format;
tex_2ds->first_pixels[slice_num].gl_type = upload_data->gl_type;
tex_2ds->first_pixels[slice_num].gl_format = gl_format;
tex_2ds->first_pixels[slice_num].gl_type = gl_type;
}
/* Fill the waste with a copies of the rightmost pixels */
if (x_span->waste > 0)
{
const guchar *src = upload_data->bitmap.data
+ y_span->start * upload_data->bitmap.rowstride
const guchar *src = bmp->data
+ y_span->start * bmp->rowstride
+ (x_span->start + x_span->size - x_span->waste - 1) * bpp;
guchar *dst = waste_buf;
guint wx, wy;
@ -284,7 +285,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
memcpy (dst, src, bpp);
dst += bpp;
}
src += upload_data->bitmap.rowstride;
src += bmp->rowstride;
}
_cogl_texture_driver_prep_gl_for_pixels_upload (
@ -296,15 +297,15 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
0,
x_span->waste,
y_span->size - y_span->waste,
upload_data->gl_format, upload_data->gl_type,
gl_format, gl_type,
waste_buf) );
}
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)
* upload_data->bitmap.rowstride)
* bmp->rowstride)
+ x_span->start * bpp;
guchar *dst = waste_buf;
guint wy, wx;
@ -330,7 +331,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
y_span->size - y_span->waste,
x_span->size,
y_span->waste,
upload_data->gl_format, upload_data->gl_type,
gl_format, gl_type,
waste_buf) );
}
}
@ -685,7 +686,10 @@ _cogl_texture_2d_sliced_set_wrap_mode_parameter (CoglTexture *tex,
static gboolean
_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_height;
@ -703,15 +707,15 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
/* Initialize size of largest slice according to supported features */
if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT))
{
max_width = upload_data->bitmap.width;
max_height = upload_data->bitmap.height;
max_width = width;
max_height = height;
tex_2ds->gl_target = GL_TEXTURE_2D;
slices_for_size = _cogl_rect_slices_for_size;
}
else
{
max_width = cogl_util_next_p2 (upload_data->bitmap.width);
max_height = cogl_util_next_p2 (upload_data->bitmap.height);
max_width = cogl_util_next_p2 (width);
max_height = cogl_util_next_p2 (height);
tex_2ds->gl_target = GL_TEXTURE_2D;
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 */
if (!_cogl_texture_driver_size_supported (tex_2ds->gl_target,
upload_data->gl_intformat,
upload_data->gl_type,
gl_intformat,
gl_type,
max_width,
max_height))
{
@ -746,19 +750,19 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
/* Add a single span for width and height */
span.start = 0;
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);
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);
}
else
{
/* Decrease the size of largest slice until supported by GL */
while (!_cogl_texture_driver_size_supported (tex_2ds->gl_target,
upload_data->gl_intformat,
upload_data->gl_type,
gl_intformat,
gl_type,
max_width,
max_height))
{
@ -773,11 +777,11 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
}
/* 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,
NULL);
n_y_slices = slices_for_size (upload_data->bitmap.height,
n_y_slices = slices_for_size (height,
max_height, tex_2ds->max_waste,
NULL);
@ -791,11 +795,11 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
n_y_slices);
/* Fill span arrays with info */
slices_for_size (upload_data->bitmap.width,
slices_for_size (width,
max_width, tex_2ds->max_waste,
tex_2ds->slice_x_spans);
slices_for_size (upload_data->bitmap.height,
slices_for_size (height,
max_height, tex_2ds->max_waste,
tex_2ds->slice_y_spans);
}
@ -845,15 +849,15 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
/* Setup texture parameters */
GE( _cogl_texture_driver_bind (tex_2ds->gl_target,
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,
transparent_color);
/* 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,
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
_cogl_texture_2d_sliced_upload_from_data
(CoglTexture2DSliced *tex_2ds,
CoglTextureUploadData *upload_data,
CoglBitmap *bmp,
CoglPixelFormat internal_format)
{
CoglTexture *tex = COGL_TEXTURE (tex_2ds);
GLenum gl_intformat;
GLenum gl_format;
GLenum gl_type;
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->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;
/* Create slices for the given format and size */
if (!_cogl_texture_2d_sliced_slices_create (tex_2ds, upload_data))
return FALSE;
if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
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;
}
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
{
/* Find closest GL format match */
upload_data->bitmap.format =
_cogl_pixel_format_to_gl (internal_format,
&upload_data->gl_intformat,
&upload_data->gl_format,
&upload_data->gl_type);
&gl_intformat,
&gl_format,
&gl_type);
/* 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;
}
tex_2ds->gl_format = upload_data->gl_intformat;
tex_2ds->width = upload_data->bitmap.width;
tex_2ds->height = upload_data->bitmap.height;
tex_2ds->format = upload_data->bitmap.format;
tex_2ds->gl_format = gl_intformat;
tex_2ds->width = bmp->width;
tex_2ds->height = bmp->height;
tex_2ds->format = bmp->format;
return TRUE;
}
@ -956,7 +999,7 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int width,
{
CoglTexture2DSliced *tex_2ds;
CoglTexture *tex;
CoglTextureUploadData upload_data;
CoglBitmap bmp;
/* Since no data, we need some internal format */
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);
upload_data.bitmap.width = width;
upload_data.bitmap.height = height;
upload_data.bitmap.data = NULL;
upload_data.bitmap_owner = FALSE;
bmp.width = width;
bmp.height = height;
bmp.data = NULL;
if ((flags & COGL_TEXTURE_NO_SLICING))
tex_2ds->max_waste = -1;
else
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))
{
_cogl_texture_2d_sliced_free (tex_2ds);
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE;
}
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);
}
@ -1000,7 +1039,6 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle bmp_handle,
CoglTexture2DSliced *tex_2ds;
CoglTexture *tex;
CoglBitmap *bmp = (CoglBitmap *)bmp_handle;
CoglTextureUploadData upload_data;
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);
upload_data.bitmap = *bmp;
upload_data.bitmap_owner = FALSE;
if (flags & COGL_TEXTURE_NO_SLICING)
tex_2ds->max_waste = -1;
else
@ -1025,18 +1060,15 @@ _cogl_texture_2d_sliced_new_from_bitmap (CoglHandle bmp_handle,
* CoglHandle is returned, it should also be destroyed
* 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))
{
_cogl_texture_2d_sliced_free (tex_2ds);
_cogl_texture_upload_data_free (&upload_data);
return COGL_INVALID_HANDLE;
}
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);
}
@ -1398,12 +1430,10 @@ _cogl_texture_2d_sliced_set_region (CoglTexture *tex,
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
gint bpp;
CoglBitmap source_bmp;
CoglBitmap temp_bmp;
gboolean source_bmp_owner = FALSE;
CoglPixelFormat closest_format;
CoglBitmap tmp_bmp;
gboolean tmp_bmp_owner = FALSE;
GLenum closest_gl_format;
GLenum closest_gl_type;
gboolean success;
/* Check for valid format */
if (format == COGL_PIXEL_FORMAT_ANY)
@ -1423,38 +1453,30 @@ _cogl_texture_2d_sliced_set_region (CoglTexture *tex,
bpp = _cogl_get_format_bpp (format);
source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
/* Find closest format to internal that's supported by GL */
closest_format = _cogl_pixel_format_to_gl (tex_2ds->format,
NULL, /* don't need */
/* Prepare the bitmap so that it will do the premultiplication
conversion */
_cogl_texture_prepare_for_upload (&source_bmp,
tex_2ds->format,
NULL,
&tmp_bmp,
&tmp_bmp_owner,
NULL,
&closest_gl_format,
&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 */
_cogl_texture_2d_sliced_upload_subregion_to_gl (tex_2ds,
src_x, src_y,
dst_x, dst_y,
dst_width, dst_height,
&source_bmp,
&tmp_bmp,
closest_gl_format,
closest_gl_type);
/* Free data if owner */
if (source_bmp_owner)
g_free (source_bmp.data);
if (tmp_bmp_owner)
g_free (tmp_bmp.data);
return TRUE;
}

View File

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

View File

@ -32,7 +32,6 @@
typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTextureVtable CoglTextureVtable;
typedef struct _CoglTextureUploadData CoglTextureUploadData;
typedef void (*CoglTextureSliceCallback) (CoglHandle handle,
GLuint gl_handle,
@ -107,17 +106,6 @@ struct _CoglTextureVtable
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
{
CoglHandleObject _parent;
@ -162,28 +150,20 @@ _cogl_texture_ensure_mipmaps (CoglHandle handle);
void
_cogl_texture_ensure_non_quad_rendering (CoglHandle handle);
/* Utility functions to help uploading a bitmap. These are intended to
* be used by CoglTexture implementations or drivers... */
void
_cogl_texture_upload_data_free (CoglTextureUploadData *data);
void
_cogl_texture_upload_data_swap_bitmap (CoglTextureUploadData *data,
CoglBitmap *new_bitmap);
/* Utility function to help uploading a bitmap. If the bitmap needs
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
src_bmp. The GLenums needed for uploading are returned */
gboolean
_cogl_texture_upload_data_prepare_format
(CoglTextureUploadData *data,
CoglPixelFormat *internal_format);
gboolean
_cogl_texture_upload_data_convert (CoglTextureUploadData *data,
CoglPixelFormat internal_format);
gboolean
_cogl_texture_upload_data_prepare (CoglTextureUploadData *data,
CoglPixelFormat internal_format);
_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);
void
_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);
}
void
_cogl_texture_upload_data_free (CoglTextureUploadData *data)
gboolean
_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)
g_free (data->bitmap.data);
data->bitmap.data = NULL;
data->bitmap_owner = FALSE;
/* 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 ((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;
}
void
_cogl_texture_upload_data_swap_bitmap (CoglTextureUploadData *data,
CoglBitmap *new_bitmap)
if (dst_bmp)
{
if (data->bitmap.data != NULL && data->bitmap_owner)
g_free (data->bitmap.data);
*copied_bitmap = FALSE;
*dst_bmp = *src_bmp;
data->bitmap = *new_bitmap;
data->bitmap_owner = TRUE;
/* If the source format does not have the same premult flag as the
dst format then we need to copy and convert it */
if ((src_bmp->format & COGL_A_BIT) &&
src_bmp->format != COGL_PIXEL_FORMAT_A_8 &&
(src_bmp->format & COGL_PREMULT_BIT) !=
(dst_format & COGL_PREMULT_BIT))
{
dst_bmp->data = g_memdup (dst_bmp->data,
dst_bmp->height * dst_bmp->rowstride);
*copied_bitmap = TRUE;
if (!_cogl_bitmap_convert_premult_status (dst_bmp,
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
@ -157,64 +203,6 @@ _cogl_texture_set_wrap_mode_parameter (CoglHandle handle,
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
effectively assumes there is only one span from 0.0 to 1.0 */
typedef struct _CoglTextureIter