gl: Add BGRA download support for GLES2

Some OpenGLES2 drivers support downloading BGRA data. On little-endian
systems BGRA and GL_UNSIGNED_BYTe is equivalent to the typical
cairo_image_t format, so this can prevent CPU bit swizzling for
operations that involve images.
This commit is contained in:
Martin Robinson 2012-12-03 16:08:23 -08:00
parent a7d684e6fe
commit 9d9aa04b60
3 changed files with 44 additions and 26 deletions

View file

@ -169,6 +169,22 @@ _cairo_gl_msaa_compositor_enabled (void)
return env && strcmp(env, "msaa") == 0;
}
static cairo_bool_t
test_can_read_bgra (cairo_gl_flavor_t gl_flavor)
{
/* Desktop GL always supports BGRA formats. */
if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
return TRUE;
assert (gl_flavor == CAIRO_GL_FLAVOR_ES);
/* For OpenGL ES we have to look for the specific extension and BGRA only
* matches cairo's integer packed bytes on little-endian machines. */
if (!_cairo_is_little_endian())
return FALSE;
return _cairo_gl_has_extension ("EXT_read_format_bgra");
}
cairo_status_t
_cairo_gl_context_init (cairo_gl_context_t *ctx)
{
@ -230,6 +246,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
(gl_flavor == CAIRO_GL_FLAVOR_ES &&
_cairo_gl_has_extension ("GL_OES_mapbuffer")));
ctx->can_read_bgra = test_can_read_bgra (gl_flavor);
ctx->has_mesa_pack_invert =
_cairo_gl_has_extension ("GL_MESA_pack_invert");

View file

@ -357,6 +357,7 @@ struct _cairo_gl_context {
cairo_bool_t has_map_buffer;
cairo_bool_t has_packed_depth_stencil;
cairo_bool_t has_npot_repeat;
cairo_bool_t can_read_bgra;
cairo_bool_t thread_aware;

View file

@ -1022,6 +1022,11 @@ _cairo_gl_surface_map_to_image (void *abstract_surface,
cairo_status_t status;
int y;
status = _cairo_gl_context_acquire (surface->base.device, &ctx);
if (unlikely (status)) {
return _cairo_image_surface_create_in_error (status);
}
/* Want to use a switch statement here but the compiler gets whiny. */
if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
format = GL_BGRA;
@ -1043,25 +1048,26 @@ _cairo_gl_surface_map_to_image (void *abstract_surface,
return NULL;
}
/*
* GLES2 supports only RGBA, UNSIGNED_BYTE so use that.
* We are also using this format for ALPHA as GLES2 does not
* support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
* pixman image that is created has row_stride = row_width * bpp.
*/
if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) {
format = GL_RGBA;
if (! _cairo_is_little_endian ()) {
if (surface->base.content == CAIRO_CONTENT_COLOR)
pixman_format = PIXMAN_r8g8b8x8;
else
pixman_format = PIXMAN_r8g8b8a8;
} else {
if (surface->base.content == CAIRO_CONTENT_COLOR)
pixman_format = PIXMAN_x8b8g8r8;
else
pixman_format = PIXMAN_a8b8g8r8;
/* If only RGBA is supported, we must download data in a compatible
* format. This means that pixman will convert the data on the CPU when
* interacting with other image surfaces. For ALPHA, GLES2 does not
* support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
* pixman image that is created has row_stride = row_width * bpp. */
if (surface->base.content == CAIRO_CONTENT_ALPHA || !ctx->can_read_bgra) {
cairo_bool_t little_endian = _cairo_is_little_endian ();
format = GL_RGBA;
if (surface->base.content == CAIRO_CONTENT_COLOR) {
pixman_format = little_endian ?
PIXMAN_x8b8g8r8 : PIXMAN_r8g8b8x8;
} else {
pixman_format = little_endian ?
PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
}
}
/* GLES2 only supports GL_UNSIGNED_BYTE. */
type = GL_UNSIGNED_BYTE;
cpp = 4;
}
@ -1072,16 +1078,9 @@ _cairo_gl_surface_map_to_image (void *abstract_surface,
extents->width,
extents->height,
-1);
if (unlikely (image->base.status))
if (unlikely (image->base.status) || surface->base.serial == 0) {
status = _cairo_gl_context_release (ctx, status);
return image;
if (surface->base.serial == 0)
return image;
status = _cairo_gl_context_acquire (surface->base.device, &ctx);
if (unlikely (status)) {
cairo_surface_destroy (&image->base);
return _cairo_image_surface_create_in_error (status);
}
cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y);