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.
This commit is contained in:
Neil Roberts 2010-07-08 13:54:37 +01:00
parent 4ca1e491da
commit 0577c81c3b
8 changed files with 150 additions and 292 deletions

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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,