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 0e49e4f204
commit 223317c500
8 changed files with 150 additions and 292 deletions

View File

@ -595,7 +595,7 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
data); data);
} }
static int static gboolean
_cogl_atlas_texture_get_data (CoglTexture *tex, _cogl_atlas_texture_get_data (CoglTexture *tex,
CoglPixelFormat format, CoglPixelFormat format,
unsigned int rowstride, 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, _cogl_sub_texture_get_data (CoglTexture *tex,
CoglPixelFormat format, CoglPixelFormat format,
unsigned int rowstride, unsigned int rowstride,
@ -457,7 +457,7 @@ _cogl_sub_texture_get_data (CoglTexture *tex,
CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
unsigned int full_rowstride; unsigned int full_rowstride;
guint8 *full_data; guint8 *full_data;
int byte_size, full_size; gboolean ret = TRUE;
int bpp; int bpp;
int full_tex_width, full_tex_height; 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 texture_get_sub_data virtual and it can just munge the texture
coordinates */ 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_width = cogl_texture_get_width (sub_tex->full_texture);
full_tex_height = cogl_texture_get_height (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); 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_rowstride = _cogl_get_format_bpp (format) * full_tex_width;
full_data = g_malloc (full_rowstride * full_tex_height); full_data = g_malloc (full_rowstride * full_tex_height);
full_size = cogl_texture_get_data (sub_tex->full_texture, format, if (cogl_texture_get_data (sub_tex->full_texture, format,
full_rowstride, full_data); full_rowstride, full_data))
if (full_size)
_cogl_sub_texture_copy_region (data, full_data, _cogl_sub_texture_copy_region (data, full_data,
0, 0, 0, 0,
sub_tex->sub_x, sub_tex->sub_x,
@ -500,11 +486,11 @@ _cogl_sub_texture_get_data (CoglTexture *tex,
full_rowstride, full_rowstride,
bpp); bpp);
else else
byte_size = 0; ret = FALSE;
g_free (full_data); g_free (full_data);
return byte_size; return ret;
} }
static CoglPixelFormat static CoglPixelFormat

View File

@ -1633,96 +1633,27 @@ _cogl_texture_2d_sliced_get_data (CoglTexture *tex,
{ {
CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
int bpp; int bpp;
int byte_size; GLenum gl_format;
CoglPixelFormat closest_format; GLenum gl_type;
int closest_bpp;
GLenum closest_gl_format;
GLenum closest_gl_type;
CoglBitmap target_bmp; 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); bpp = _cogl_get_format_bpp (format);
if (rowstride == 0)
rowstride = tex_2ds->width * bpp;
/* Return byte size if only that requested */ _cogl_pixel_format_to_gl (format,
byte_size = tex_2ds->height * rowstride; NULL, /* internal format */
if (data == NULL) &gl_format,
return byte_size; &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_2ds->width; target_bmp.width = tex_2ds->width;
target_bmp.height = tex_2ds->height; 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.format = format;
target_bmp.rowstride = rowstride; target_bmp.rowstride = rowstride;
target_bmp.data = data; 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);
}
/* Retrieve data from slices */ /* Retrieve data from slices */
if (!_cogl_texture_2d_sliced_download_from_gl (tex_2ds, &target_bmp, return _cogl_texture_2d_sliced_download_from_gl (tex_2ds, &target_bmp,
closest_gl_format, gl_format,
closest_gl_type)) 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;
} }
static CoglPixelFormat static CoglPixelFormat

View File

@ -513,7 +513,7 @@ _cogl_texture_2d_set_region (CoglTexture *tex,
return TRUE; return TRUE;
} }
static int static gboolean
_cogl_texture_2d_get_data (CoglTexture *tex, _cogl_texture_2d_get_data (CoglTexture *tex,
CoglPixelFormat format, CoglPixelFormat format,
unsigned int rowstride, unsigned int rowstride,
@ -521,103 +521,25 @@ _cogl_texture_2d_get_data (CoglTexture *tex,
{ {
CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
int bpp; int bpp;
int byte_size; GLenum gl_format;
CoglPixelFormat closest_format; GLenum gl_type;
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;
/* 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); bpp = _cogl_get_format_bpp (format);
if (rowstride == 0)
rowstride = tex_2d->width * bpp;
/* Return byte size if only that requested */ _cogl_pixel_format_to_gl (format,
byte_size = tex_2d->height * rowstride; NULL, /* internal format */
if (data == NULL) &gl_format,
return byte_size; &gl_type);
closest_format = _cogl_texture_driver_prep_gl_for_pixels_download (rowstride, bpp);
_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_bind_gl_texture_transient (GL_TEXTURE_2D, _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
tex_2d->gl_texture, tex_2d->gl_texture,
FALSE); FALSE);
if (!_cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_2D, return _cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_2D,
closest_gl_format, gl_format,
closest_gl_type, gl_type,
target_bmp.data)) 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;
} }
static CoglPixelFormat static CoglPixelFormat

View File

@ -81,7 +81,12 @@ struct _CoglTextureVtable
unsigned int rowstride, unsigned int rowstride,
const guint8 *data); const guint8 *data);
int (* get_data) (CoglTexture *tex, /* 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, CoglPixelFormat format,
unsigned int rowstride, unsigned int rowstride,
guint8 *data); guint8 *data);

View File

@ -507,7 +507,7 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex,
return TRUE; return TRUE;
} }
static int static gboolean
_cogl_texture_rectangle_get_data (CoglTexture *tex, _cogl_texture_rectangle_get_data (CoglTexture *tex,
CoglPixelFormat format, CoglPixelFormat format,
unsigned int rowstride, unsigned int rowstride,
@ -515,103 +515,25 @@ _cogl_texture_rectangle_get_data (CoglTexture *tex,
{ {
CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
int bpp; int bpp;
int byte_size; GLenum gl_format;
CoglPixelFormat closest_format; GLenum gl_type;
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;
/* 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); bpp = _cogl_get_format_bpp (format);
if (rowstride == 0)
rowstride = tex_rect->width * bpp;
/* Return byte size if only that requested */ _cogl_pixel_format_to_gl (format,
byte_size = tex_rect->height * rowstride; NULL, /* internal format */
if (data == NULL) &gl_format,
return byte_size; &gl_type);
closest_format = _cogl_texture_driver_prep_gl_for_pixels_download (rowstride, bpp);
_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);
GE( _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, GE( _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
tex_rect->gl_texture, tex_rect->gl_texture,
FALSE) ); FALSE) );
if (!_cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_RECTANGLE_ARB, return _cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_RECTANGLE_ARB,
closest_gl_format, gl_format,
closest_gl_type, gl_type,
target_bmp.data)) 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;
} }
static CoglPixelFormat static CoglPixelFormat

View File

@ -1085,12 +1085,104 @@ cogl_texture_get_data (CoglHandle handle,
guint8 *data) 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)) if (!cogl_is_texture (handle))
return FALSE; return FALSE;
tex = COGL_TEXTURE (handle); 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; return FALSE;
} }
static int static gboolean
_cogl_texture_pixmap_x11_get_data (CoglTexture *tex, _cogl_texture_pixmap_x11_get_data (CoglTexture *tex,
CoglPixelFormat format, CoglPixelFormat format,
unsigned int rowstride, unsigned int rowstride,