From 223317c5006ed5e594f4129b64e64b1ac97be9f2 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 8 Jul 2010 13:54:37 +0100 Subject: [PATCH] cogl-texture: Share the common code in the get_data virtual Previously cogl_texture_get_data would pretty much directly pass on to the get_data texture virtual function. This ended up with a lot of common code that was copied to all of the backends. For example, the method is expected to return the required data size if the data pointer is NULL and to calculate its own rowstride if the rowstride is 0. Also it needs to convert the downloaded data if GL can't support that format directly. This patch moves the common code to cogl-texture.c so the virtual is always called with a format that can be downloaded directly by GL and with a valid rowstride. If the download fails then the virtual can return FALSE in which case cogl-texture will use the draw and read fallback. --- cogl/cogl-atlas-texture.c | 2 +- cogl/cogl-sub-texture.c | 26 ++----- cogl/cogl-texture-2d-sliced.c | 93 +++------------------- cogl/cogl-texture-2d.c | 102 +++---------------------- cogl/cogl-texture-private.h | 13 +++- cogl/cogl-texture-rectangle.c | 106 ++++---------------------- cogl/cogl-texture.c | 98 +++++++++++++++++++++++- cogl/winsys/cogl-texture-pixmap-x11.c | 2 +- 8 files changed, 150 insertions(+), 292 deletions(-) diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c index 1f32a04bc..54e87e7ea 100644 --- a/cogl/cogl-atlas-texture.c +++ b/cogl/cogl-atlas-texture.c @@ -595,7 +595,7 @@ _cogl_atlas_texture_set_region (CoglTexture *tex, data); } -static int +static gboolean _cogl_atlas_texture_get_data (CoglTexture *tex, CoglPixelFormat format, unsigned int rowstride, diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl-sub-texture.c index 8fbcc4dca..bfae32bc7 100644 --- a/cogl/cogl-sub-texture.c +++ b/cogl/cogl-sub-texture.c @@ -448,7 +448,7 @@ _cogl_sub_texture_copy_region (guint8 *dst, } } -static int +static gboolean _cogl_sub_texture_get_data (CoglTexture *tex, CoglPixelFormat format, unsigned int rowstride, @@ -457,7 +457,7 @@ _cogl_sub_texture_get_data (CoglTexture *tex, CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); unsigned int full_rowstride; guint8 *full_data; - int byte_size, full_size; + gboolean ret = TRUE; int bpp; int full_tex_width, full_tex_height; @@ -466,30 +466,16 @@ _cogl_sub_texture_get_data (CoglTexture *tex, texture_get_sub_data virtual and it can just munge the texture coordinates */ - /* Default to internal format if none specified */ - if (format == COGL_PIXEL_FORMAT_ANY) - format = cogl_texture_get_format (sub_tex->full_texture); - full_tex_width = cogl_texture_get_width (sub_tex->full_texture); full_tex_height = cogl_texture_get_height (sub_tex->full_texture); - /* Rowstride from texture width if none specified */ bpp = _cogl_get_format_bpp (format); - if (rowstride == 0) - rowstride = sub_tex->sub_width * bpp; - - /* Return byte size if only that requested */ - byte_size = sub_tex->sub_height * rowstride; - if (data == NULL) - return byte_size; full_rowstride = _cogl_get_format_bpp (format) * full_tex_width; full_data = g_malloc (full_rowstride * full_tex_height); - full_size = cogl_texture_get_data (sub_tex->full_texture, format, - full_rowstride, full_data); - - if (full_size) + if (cogl_texture_get_data (sub_tex->full_texture, format, + full_rowstride, full_data)) _cogl_sub_texture_copy_region (data, full_data, 0, 0, sub_tex->sub_x, @@ -500,11 +486,11 @@ _cogl_sub_texture_get_data (CoglTexture *tex, full_rowstride, bpp); else - byte_size = 0; + ret = FALSE; g_free (full_data); - return byte_size; + return ret; } static CoglPixelFormat diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c index 2a41721ba..3f95eef51 100644 --- a/cogl/cogl-texture-2d-sliced.c +++ b/cogl/cogl-texture-2d-sliced.c @@ -1633,96 +1633,27 @@ _cogl_texture_2d_sliced_get_data (CoglTexture *tex, { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); int bpp; - int byte_size; - CoglPixelFormat closest_format; - int closest_bpp; - GLenum closest_gl_format; - GLenum closest_gl_type; + GLenum gl_format; + GLenum gl_type; CoglBitmap target_bmp; - CoglBitmap new_bmp; - gboolean success; - guint8 *src; - guint8 *dst; - int y; - /* Default to internal format if none specified */ - if (format == COGL_PIXEL_FORMAT_ANY) - format = tex_2ds->format; - - /* Rowstride from texture width if none specified */ bpp = _cogl_get_format_bpp (format); - if (rowstride == 0) - rowstride = tex_2ds->width * bpp; - /* Return byte size if only that requested */ - byte_size = tex_2ds->height * rowstride; - if (data == NULL) - return byte_size; - - closest_format = - _cogl_texture_driver_find_best_gl_get_data_format (format, - &closest_gl_format, - &closest_gl_type); - closest_bpp = _cogl_get_format_bpp (closest_format); + _cogl_pixel_format_to_gl (format, + NULL, /* internal format */ + &gl_format, + &gl_type); target_bmp.width = tex_2ds->width; target_bmp.height = tex_2ds->height; - - /* Is the requested format supported? */ - if (closest_format == format) - { - /* Target user data directly */ - target_bmp.format = format; - target_bmp.rowstride = rowstride; - target_bmp.data = data; - } - else - { - /* Target intermediate buffer */ - target_bmp.format = closest_format; - target_bmp.rowstride = target_bmp.width * closest_bpp; - target_bmp.data = g_malloc (target_bmp.height * target_bmp.rowstride); - } + target_bmp.format = format; + target_bmp.rowstride = rowstride; + target_bmp.data = data; /* Retrieve data from slices */ - if (!_cogl_texture_2d_sliced_download_from_gl (tex_2ds, &target_bmp, - closest_gl_format, - closest_gl_type)) - { - /* XXX: In some cases _cogl_texture_2d_sliced_download_from_gl may - * fail to read back the texture data; such as for GLES which doesn't - * support glGetTexImage, so here we fallback to drawing the texture - * and reading the pixels from the framebuffer. */ - _cogl_texture_draw_and_read (tex, &target_bmp, - closest_gl_format, - closest_gl_type); - } - - /* Was intermediate used? */ - if (closest_format != format) - { - /* Convert to requested format */ - success = _cogl_bitmap_convert_format_and_premult (&target_bmp, - &new_bmp, - format); - - /* Free intermediate data and return if failed */ - g_free (target_bmp.data); - if (!success) return 0; - - /* Copy to user buffer */ - for (y = 0; y < new_bmp.height; ++y) - { - src = new_bmp.data + y * new_bmp.rowstride; - dst = data + y * rowstride; - memcpy (dst, src, new_bmp.rowstride); - } - - /* Free converted data */ - g_free (new_bmp.data); - } - - return byte_size; + return _cogl_texture_2d_sliced_download_from_gl (tex_2ds, &target_bmp, + gl_format, + gl_type); } static CoglPixelFormat diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index d4d6c8aa2..32eccb143 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -513,7 +513,7 @@ _cogl_texture_2d_set_region (CoglTexture *tex, return TRUE; } -static int +static gboolean _cogl_texture_2d_get_data (CoglTexture *tex, CoglPixelFormat format, unsigned int rowstride, @@ -521,103 +521,25 @@ _cogl_texture_2d_get_data (CoglTexture *tex, { CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); int bpp; - int byte_size; - CoglPixelFormat closest_format; - int closest_bpp; - GLenum closest_gl_format; - GLenum closest_gl_type; - CoglBitmap target_bmp; - CoglBitmap new_bmp; - gboolean success; - guint8 *src; - guint8 *dst; - int y; + GLenum gl_format; + GLenum gl_type; - /* Default to internal format if none specified */ - if (format == COGL_PIXEL_FORMAT_ANY) - format = tex_2d->format; - - /* Rowstride from texture width if none specified */ bpp = _cogl_get_format_bpp (format); - if (rowstride == 0) - rowstride = tex_2d->width * bpp; - /* Return byte size if only that requested */ - byte_size = tex_2d->height * rowstride; - if (data == NULL) - return byte_size; + _cogl_pixel_format_to_gl (format, + NULL, /* internal format */ + &gl_format, + &gl_type); - closest_format = - _cogl_texture_driver_find_best_gl_get_data_format (format, - &closest_gl_format, - &closest_gl_type); - closest_bpp = _cogl_get_format_bpp (closest_format); - - target_bmp.width = tex_2d->width; - target_bmp.height = tex_2d->height; - - /* Is the requested format supported? */ - if (closest_format == format) - { - /* Target user data directly */ - target_bmp.format = format; - target_bmp.rowstride = rowstride; - target_bmp.data = data; - } - else - { - /* Target intermediate buffer */ - target_bmp.format = closest_format; - target_bmp.rowstride = target_bmp.width * closest_bpp; - target_bmp.data = g_malloc (target_bmp.height * target_bmp.rowstride); - } - - _cogl_texture_driver_prep_gl_for_pixels_download (target_bmp.rowstride, - closest_bpp); + _cogl_texture_driver_prep_gl_for_pixels_download (rowstride, bpp); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, FALSE); - if (!_cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_2D, - closest_gl_format, - closest_gl_type, - target_bmp.data)) - { - /* XXX: In some cases _cogl_texture_2d_download_from_gl may - * fail to read back the texture data; such as for GLES which doesn't - * support glGetTexImage, so here we fallback to drawing the texture - * and reading the pixels from the framebuffer. */ - _cogl_texture_draw_and_read (tex, &target_bmp, - closest_gl_format, - closest_gl_type); - } - - /* Was intermediate used? */ - if (closest_format != format) - { - /* Convert to requested format */ - success = _cogl_bitmap_convert_format_and_premult (&target_bmp, - &new_bmp, - format); - - /* Free intermediate data and return if failed */ - g_free (target_bmp.data); - if (!success) - return 0; - - /* Copy to user buffer */ - for (y = 0; y < new_bmp.height; ++y) - { - src = new_bmp.data + y * new_bmp.rowstride; - dst = data + y * rowstride; - memcpy (dst, src, new_bmp.width); - } - - /* Free converted data */ - g_free (new_bmp.data); - } - - return byte_size; + return _cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_2D, + gl_format, + gl_type, + data); } static CoglPixelFormat diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h index 56b109951..78330c618 100644 --- a/cogl/cogl-texture-private.h +++ b/cogl/cogl-texture-private.h @@ -81,10 +81,15 @@ struct _CoglTextureVtable unsigned int rowstride, const guint8 *data); - int (* get_data) (CoglTexture *tex, - CoglPixelFormat format, - unsigned int rowstride, - guint8 *data); + /* This should copy the image data of the texture into @data. The + requested format will have been first passed through + _cogl_texture_driver_find_best_gl_get_data_format so it should + always be a format that is valid for GL (ie, no conversion should + be necessary). */ + gboolean (* get_data) (CoglTexture *tex, + CoglPixelFormat format, + unsigned int rowstride, + guint8 *data); void (* foreach_sub_texture_in_region) (CoglTexture *tex, float virtual_tx_1, diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c index f797f50c0..2a61e78d3 100644 --- a/cogl/cogl-texture-rectangle.c +++ b/cogl/cogl-texture-rectangle.c @@ -507,111 +507,33 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex, return TRUE; } -static int +static gboolean _cogl_texture_rectangle_get_data (CoglTexture *tex, CoglPixelFormat format, unsigned int rowstride, guint8 *data) { - CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); - int bpp; - int byte_size; - CoglPixelFormat closest_format; - int closest_bpp; - GLenum closest_gl_format; - GLenum closest_gl_type; - CoglBitmap target_bmp; - CoglBitmap new_bmp; - gboolean success; - guint8 *src; - guint8 *dst; - int y; + CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); + int bpp; + GLenum gl_format; + GLenum gl_type; - /* Default to internal format if none specified */ - if (format == COGL_PIXEL_FORMAT_ANY) - format = tex_rect->format; - - /* Rowstride from texture width if none specified */ bpp = _cogl_get_format_bpp (format); - if (rowstride == 0) - rowstride = tex_rect->width * bpp; - /* Return byte size if only that requested */ - byte_size = tex_rect->height * rowstride; - if (data == NULL) - return byte_size; + _cogl_pixel_format_to_gl (format, + NULL, /* internal format */ + &gl_format, + &gl_type); - closest_format = - _cogl_texture_driver_find_best_gl_get_data_format (format, - &closest_gl_format, - &closest_gl_type); - closest_bpp = _cogl_get_format_bpp (closest_format); - - target_bmp.width = tex_rect->width; - target_bmp.height = tex_rect->height; - - /* Is the requested format supported? */ - if (closest_format == format) - { - /* Target user data directly */ - target_bmp.format = format; - target_bmp.rowstride = rowstride; - target_bmp.data = data; - } - else - { - /* Target intermediate buffer */ - target_bmp.format = closest_format; - target_bmp.rowstride = target_bmp.width * closest_bpp; - target_bmp.data = g_malloc (target_bmp.height * target_bmp.rowstride); - } - - _cogl_texture_driver_prep_gl_for_pixels_download (target_bmp.rowstride, - closest_bpp); + _cogl_texture_driver_prep_gl_for_pixels_download (rowstride, bpp); GE( _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, tex_rect->gl_texture, FALSE) ); - if (!_cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_RECTANGLE_ARB, - closest_gl_format, - closest_gl_type, - target_bmp.data)) - { - /* XXX: In some cases _cogl_texture_rectangle_download_from_gl may - * fail to read back the texture data; such as for GLES which doesn't - * support glGetTexImage, so here we fallback to drawing the texture - * and reading the pixels from the framebuffer. */ - _cogl_texture_draw_and_read (tex, &target_bmp, - closest_gl_format, - closest_gl_type); - } - - /* Was intermediate used? */ - if (closest_format != format) - { - /* Convert to requested format */ - success = _cogl_bitmap_convert_format_and_premult (&target_bmp, - &new_bmp, - format); - - /* Free intermediate data and return if failed */ - g_free (target_bmp.data); - if (!success) - return 0; - - /* Copy to user buffer */ - for (y = 0; y < new_bmp.height; ++y) - { - src = new_bmp.data + y * new_bmp.rowstride; - dst = data + y * rowstride; - memcpy (dst, src, new_bmp.width); - } - - /* Free converted data */ - g_free (new_bmp.data); - } - - return byte_size; + return _cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_RECTANGLE_ARB, + gl_format, + gl_type, + data); } static CoglPixelFormat diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index dd24ad341..c7be4b26b 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -1084,13 +1084,105 @@ cogl_texture_get_data (CoglHandle handle, unsigned int rowstride, guint8 *data) { - CoglTexture *tex; + CoglTexture *tex; + int bpp; + int byte_size; + CoglPixelFormat closest_format; + int closest_bpp; + GLenum closest_gl_format; + GLenum closest_gl_type; + CoglBitmap target_bmp; + CoglBitmap new_bmp; + gboolean success; + guint8 *src; + guint8 *dst; + int y; + int tex_width; + int tex_height; if (!cogl_is_texture (handle)) return FALSE; tex = COGL_TEXTURE (handle); - return tex->vtable->get_data (handle, format, rowstride, data); -} + /* Default to internal format if none specified */ + if (format == COGL_PIXEL_FORMAT_ANY) + format = cogl_texture_get_format (handle); + tex_width = cogl_texture_get_width (handle); + tex_height = cogl_texture_get_height (handle); + + /* Rowstride from texture width if none specified */ + bpp = _cogl_get_format_bpp (format); + if (rowstride == 0) + rowstride = tex_width * bpp; + + /* Return byte size if only that requested */ + byte_size = tex_height * rowstride; + if (data == NULL) + return byte_size; + + closest_format = + _cogl_texture_driver_find_best_gl_get_data_format (format, + &closest_gl_format, + &closest_gl_type); + closest_bpp = _cogl_get_format_bpp (closest_format); + + target_bmp.width = tex_width; + target_bmp.height = tex_height; + + /* Is the requested format supported? */ + if (closest_format == format) + { + /* Target user data directly */ + target_bmp.format = format; + target_bmp.rowstride = rowstride; + target_bmp.data = data; + } + else + { + /* Target intermediate buffer */ + target_bmp.format = closest_format; + target_bmp.rowstride = target_bmp.width * closest_bpp; + target_bmp.data = g_malloc (target_bmp.height * target_bmp.rowstride); + } + + if (!tex->vtable->get_data (tex, + target_bmp.format, + target_bmp.rowstride, + target_bmp.data)) + /* XXX: In some cases _cogl_texture_2d_download_from_gl may fail + * to read back the texture data; such as for GLES which doesn't + * support glGetTexImage, so here we fallback to drawing the + * texture and reading the pixels from the framebuffer. */ + _cogl_texture_draw_and_read (tex, &target_bmp, + closest_gl_format, + closest_gl_type); + + /* Was intermediate used? */ + if (closest_format != format) + { + /* Convert to requested format */ + success = _cogl_bitmap_convert_format_and_premult (&target_bmp, + &new_bmp, + format); + + /* Free intermediate data and return if failed */ + g_free (target_bmp.data); + if (!success) + return 0; + + /* Copy to user buffer */ + for (y = 0; y < new_bmp.height; ++y) + { + src = new_bmp.data + y * new_bmp.rowstride; + dst = data + y * rowstride; + memcpy (dst, src, new_bmp.width); + } + + /* Free converted data */ + g_free (new_bmp.data); + } + + return byte_size; +} diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c index e57e41bcd..c8ee42fc1 100644 --- a/cogl/winsys/cogl-texture-pixmap-x11.c +++ b/cogl/winsys/cogl-texture-pixmap-x11.c @@ -1129,7 +1129,7 @@ _cogl_texture_pixmap_x11_set_region (CoglTexture *tex, return FALSE; } -static int +static gboolean _cogl_texture_pixmap_x11_get_data (CoglTexture *tex, CoglPixelFormat format, unsigned int rowstride,