cogl-texture-driver-gles: Don't copy the bitmap if alignment matches

When uploading data for GLES we need to deal with cases where the
rowstride is too large to be described only by GL_UNPACK_ALIGNMENT
because there is no GL_UNPACK_ROW_LENGTH. Previously for the
sub-region uploading code it would always copy the bitmap and for the
code to upload the whole image it would copy the bitmap unless the
rowstride == bpp*width. Neither paths took into account that we don't
need to copy if the rowstride is just an alignment of bpp*width. This
moves the bitmap copying code to a separate function that is used by
both upload methods. It only copies the bitmap if the rowstride is not
just an alignment of bpp*width.

http://bugzilla.clutter-project.org/show_bug.cgi?id=2491
This commit is contained in:
Neil Roberts 2010-12-17 16:09:26 +00:00
parent b3058c097d
commit e1cbef23f5

View File

@ -97,6 +97,32 @@ _cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
_cogl_texture_prep_gl_alignment_for_pixels_download (pixels_rowstride);
}
static CoglBitmap *
prepare_bitmap_alignment_for_upload (CoglBitmap *src_bmp)
{
CoglPixelFormat format = _cogl_bitmap_get_format (src_bmp);
int bpp = _cogl_get_format_bpp (format);
int src_rowstride = _cogl_bitmap_get_rowstride (src_bmp);
int width = _cogl_bitmap_get_width (src_bmp);
int alignment = 1;
if (src_rowstride == 0)
return cogl_object_ref (src_bmp);
/* Work out the alignment of the source rowstride */
alignment = 1 << (_cogl_util_ffs (src_rowstride) - 1);
alignment = MIN (alignment, 8);
/* If the aligned data equals the rowstride then we can upload from
the bitmap directly using GL_UNPACK_ALIGNMENT */
if (((width * bpp + alignment - 1) & ~(alignment - 1)) == src_rowstride)
return cogl_object_ref (src_bmp);
/* Otherwise we need to copy the bitmap to pack the alignment
because GLES has no GL_ROW_LENGTH */
else
return _cogl_bitmap_copy (src_bmp);
}
void
_cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
GLuint gl_handle,
@ -117,37 +143,36 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum gl_target,
CoglBitmap *slice_bmp;
int rowstride;
/* NB: GLES doesn't support the GL_UNPACK_ROW_LENGTH,
* GL_UNPACK_SKIP_PIXELS or GL_UNPACK_SKIP_ROWS pixel store options
* so we can't directly source a sub-region from source_bmp, we need
* to use a transient bitmap instead. */
/* FIXME: optimize by not copying to intermediate slice bitmap when
* source rowstride = bpp * width and the texture image is not
* sliced */
/* Setup temp bitmap for slice subregion */
rowstride = bpp * width;
slice_bmp = _cogl_bitmap_new_from_data (g_malloc (rowstride * height),
source_format,
width,
height,
rowstride,
(CoglBitmapDestroyNotify)
g_free,
NULL);
/* If we are copying a sub region of the source bitmap then we need
to copy it because GLES does not support GL_UNPACK_ROW_LENGTH */
if (src_x != 0 || src_y != 0 ||
width != _cogl_bitmap_get_width (source_bmp) ||
height != _cogl_bitmap_get_height (source_bmp))
{
rowstride = bpp * width;
rowstride = (rowstride + 3) & ~3;
slice_bmp =
_cogl_bitmap_new_from_data (g_malloc (height * rowstride),
source_format,
width, height,
rowstride,
(CoglBitmapDestroyNotify) g_free,
NULL);
_cogl_bitmap_copy_subregion (source_bmp,
slice_bmp,
src_x, src_y,
0, 0, /* dst_x/y */
width, height);
}
else
{
slice_bmp = prepare_bitmap_alignment_for_upload (source_bmp);
rowstride = _cogl_bitmap_get_rowstride (slice_bmp);
}
/* Setup gl alignment to match rowstride and top-left corner */
_cogl_texture_driver_prep_gl_for_pixels_upload (rowstride, bpp);
/* Copy subregion data */
_cogl_bitmap_copy_subregion (source_bmp,
slice_bmp,
src_x,
src_y,
0, 0,
width, height);
data = _cogl_bitmap_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0);
_cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
@ -174,32 +199,14 @@ _cogl_texture_driver_upload_to_gl (GLenum gl_target,
GLuint source_gl_type)
{
int bpp = _cogl_get_format_bpp (_cogl_bitmap_get_format (source_bmp));
int rowstride = _cogl_bitmap_get_rowstride (source_bmp);
int rowstride;
int bmp_width = _cogl_bitmap_get_width (source_bmp);
int bmp_height = _cogl_bitmap_get_height (source_bmp);
CoglBitmap *bmp;
guint8 *data;
/* If the rowstride can't be specified with just GL_ALIGNMENT alone
then we need to copy the bitmap because there is no GL_ROW_LENGTH */
if (rowstride / bpp != bmp_width)
{
bmp = _cogl_bitmap_new_from_data (g_malloc (rowstride * bmp_height),
_cogl_bitmap_get_format (source_bmp),
bmp_width,
bmp_height,
rowstride,
(CoglBitmapDestroyNotify) g_free,
NULL);
_cogl_bitmap_copy_subregion (source_bmp,
bmp,
0, 0, 0, 0,
bmp_width,
bmp_height);
}
else
bmp = cogl_object_ref (source_bmp);
bmp = prepare_bitmap_alignment_for_upload (source_bmp);
rowstride = _cogl_bitmap_get_rowstride (bmp);
/* Setup gl alignment to match rowstride and top-left corner */
_cogl_texture_driver_prep_gl_for_pixels_upload (rowstride, bpp);