From 0f43e01cbcac72d3e8de07b2c2472ad2410f13a9 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 17 Dec 2010 16:09:26 +0000 Subject: [PATCH] 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 --- cogl/driver/gles/cogl-texture-driver-gles.c | 103 +++++++++++--------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/cogl/driver/gles/cogl-texture-driver-gles.c b/cogl/driver/gles/cogl-texture-driver-gles.c index b7a573d59..02b9816cb 100644 --- a/cogl/driver/gles/cogl-texture-driver-gles.c +++ b/cogl/driver/gles/cogl-texture-driver-gles.c @@ -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);