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:
parent
0e49e4f204
commit
223317c500
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user