diff options
Diffstat (limited to 'src/cairo-gl-surface.c')
-rw-r--r-- | src/cairo-gl-surface.c | 148 |
1 files changed, 103 insertions, 45 deletions
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index c0ee79f..1d7515a 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -424,11 +424,12 @@ _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx, return &surface->base; } -cairo_surface_t * -_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx, - cairo_content_t content, - int width, - int height) +static cairo_surface_t * +_create_scratch_internal (cairo_gl_context_t *ctx, + cairo_content_t content, + int width, + int height, + cairo_bool_t for_caching) { cairo_gl_surface_t *surface; GLenum format; @@ -456,8 +457,13 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx, format = GL_RGBA; break; case CAIRO_CONTENT_ALPHA: - /* We want to be trying GL_ALPHA framebuffer objects here. */ - format = GL_RGBA; + /* When using GL_ALPHA, compositing doesn't work properly, but for + * caching surfaces, we are just uploading pixel data, so it isn't + * an issue. */ + if (for_caching) + format = GL_ALPHA; + else + format = GL_RGBA; break; case CAIRO_CONTENT_COLOR: /* GL_RGB is almost what we want here -- sampling 1 alpha when @@ -478,6 +484,24 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx, return &surface->base; } +cairo_surface_t * +_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx, + cairo_content_t content, + int width, + int height) +{ + return _create_scratch_internal (ctx, content, width, height, FALSE); +} + +cairo_surface_t * +_cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx, + cairo_content_t content, + int width, + int height) +{ + return _create_scratch_internal (ctx, content, width, height, TRUE); +} + static cairo_status_t _cairo_gl_surface_clear (cairo_gl_surface_t *surface, const cairo_color_t *color) @@ -508,9 +532,36 @@ _cairo_gl_surface_clear (cairo_gl_surface_t *surface, glClearColor (r, g, b, a); glClear (GL_COLOR_BUFFER_BIT); + if (a == 0) + surface->base.is_clear = TRUE; + return _cairo_gl_context_release (ctx, status); } +static cairo_surface_t * +_cairo_gl_surface_create_and_clear_scratch (cairo_gl_context_t *ctx, + cairo_content_t content, + int width, + int height) +{ + cairo_gl_surface_t *surface; + cairo_int_status_t status; + + surface = (cairo_gl_surface_t *) + _cairo_gl_surface_create_scratch (ctx, content, width, height); + if (unlikely (surface->base.status)) + return &surface->base; + + /* Cairo surfaces start out initialized to transparent (black) */ + status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT); + if (unlikely (status)) { + cairo_surface_destroy (&surface->base); + return _cairo_surface_create_in_error (status); + } + + return &surface->base; +} + cairo_surface_t * cairo_gl_surface_create (cairo_device_t *abstract_device, cairo_content_t content, @@ -538,16 +589,13 @@ cairo_gl_surface_create (cairo_device_t *abstract_device, return _cairo_surface_create_in_error (status); surface = (cairo_gl_surface_t *) - _cairo_gl_surface_create_scratch (ctx, content, width, height); + _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height); if (unlikely (surface->base.status)) { status = _cairo_gl_context_release (ctx, surface->base.status); cairo_surface_destroy (&surface->base); return _cairo_surface_create_in_error (status); } - /* Cairo surfaces start out initialized to transparent (black) */ - status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT); - status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) { cairo_surface_destroy (&surface->base); @@ -740,7 +788,7 @@ _cairo_gl_surface_create_similar (void *abstract_surface, if (unlikely (status)) return _cairo_surface_create_in_error (status); - surface = _cairo_gl_surface_create_scratch (ctx, content, width, height); + surface = _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) { @@ -774,7 +822,7 @@ _cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t *dst, if (unlikely (status)) goto CLEANUP; - _cairo_gl_composite_emit_rect (ctx, x, y, x + width, y + height, 0); + _cairo_gl_context_emit_rect (ctx, x, y, x + width, y + height); status = _cairo_gl_context_release (ctx, status); @@ -792,7 +840,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, cairo_image_surface_t *src, int src_x, int src_y, int width, int height, - int dst_x, int dst_y) + int dst_x, int dst_y, + cairo_bool_t force_flush) { GLenum internal_format, format, type; cairo_bool_t has_alpha, needs_swap; @@ -834,9 +883,11 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8; - status = _cairo_gl_surface_flush (&dst->base, 0); - if (unlikely (status)) - goto FAIL; + if (force_flush) { + status = _cairo_gl_surface_flush (&dst->base, 0); + if (unlikely (status)) + goto FAIL; + } if (_cairo_gl_surface_is_texture (dst)) { void *data_start = src->data + src_y * src->stride + src_x * cpp; @@ -903,7 +954,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, src, src_x, src_y, width, height, - 0, 0); + 0, 0, force_flush); if (status == CAIRO_INT_STATUS_SUCCESS) { cairo_surface_pattern_t tmp_pattern; cairo_rectangle_int_t r; @@ -999,6 +1050,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; @@ -1020,25 +1076,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; } @@ -1049,20 +1106,20 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, extents->width, extents->height, -1); - if (unlikely (image->base.status)) - return image; - - if (surface->base.serial == 0) + if (unlikely (image->base.status)) { + status = _cairo_gl_context_release (ctx, status); 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); + /* If the original surface has not been modified or + * is clear, we can avoid downloading data. */ + if (surface->base.is_clear || surface->base.serial == 0) { + status = _cairo_gl_context_release (ctx, status); + return image; + } + /* This is inefficient, as we'd rather just read the thing without making * it the destination. But then, this is the fallback path, so let's not * fall back instead. @@ -1177,7 +1234,8 @@ _cairo_gl_surface_unmap_image (void *abstract_surface, 0, 0, image->width, image->height, image->base.device_transform_inverse.x0, - image->base.device_transform_inverse.y0); + image->base.device_transform_inverse.y0, + TRUE); cairo_surface_finish (&image->base); cairo_surface_destroy (&image->base); |