diff options
Diffstat (limited to 'src/cairo-gl-surface.c')
-rw-r--r--[-rwxr-xr-x] | src/cairo-gl-surface.c | 173 |
1 files changed, 109 insertions, 64 deletions
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index ac19a13ad..665ab244a 100755..100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -76,7 +76,7 @@ _cairo_gl_surface_shadow_surface (void *surface, return NULL; shadow_surface = ctx->shadow_scratch_surfaces[0]; - + if (shadow_surface) { shadow_width = shadow_surface->width; shadow_height = shadow_surface->height; @@ -258,7 +258,7 @@ _cairo_gl_surface_glyph_shadow_surface (void *surface, shadow_surface = ctx->shadow_scratch_surfaces[1]; else shadow_surface = ctx->shadow_scratch_surfaces[2]; - + if (shadow_surface) { shadow_width = shadow_surface->width; shadow_height = shadow_surface->height; @@ -273,7 +273,7 @@ _cairo_gl_surface_glyph_shadow_surface (void *surface, if (! shadow_surface) { shadow_surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch (ctx, - CAIRO_CONTENT_COLOR_ALPHA, + CAIRO_CONTENT_COLOR_ALPHA, width, height); if (unlikely (shadow_surface->base.status)) { cairo_surface_destroy (&shadow_surface->base); @@ -309,10 +309,10 @@ _cairo_gl_surface_glyph_shadow_mask_surface (void *surface, return NULL; mask_surface = ctx->shadow_masks[index + 2]; - + if (mask_surface) { if (mask_surface->width != width || - mask_surface->height != height) { + mask_surface->height != height) { cairo_surface_destroy (&mask_surface->base); mask_surface = NULL; ctx->shadow_masks[index + 2] = NULL; @@ -542,6 +542,9 @@ _cairo_gl_get_image_format_and_type_gl (pixman_format_code_t pixman_format, *type = GL_UNSIGNED_BYTE; return TRUE; +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,27,2) + case PIXMAN_a8r8g8b8_sRGB: +#endif case PIXMAN_a2b10g10r10: case PIXMAN_x2b10g10r10: case PIXMAN_a4r4g4b4: @@ -690,17 +693,32 @@ _cairo_gl_surface_init (cairo_device_t *device, _cairo_gl_surface_embedded_operand_init (surface); } +static cairo_bool_t +_cairo_gl_surface_size_valid_for_context (cairo_gl_context_t *ctx, + int width, int height) +{ + return width > 0 && height > 0 && + width <= ctx->max_framebuffer_size && + height <= ctx->max_framebuffer_size; +} + +static cairo_bool_t +_cairo_gl_surface_size_valid (cairo_gl_surface_t *surface, + int width, int height) +{ + cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device; + return _cairo_gl_surface_size_valid_for_context (ctx, width, height); +} + static cairo_surface_t * _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx, cairo_content_t content, GLuint tex, int width, - int height, - cairo_bool_t set_tex_param) + int height) { cairo_gl_surface_t *surface; - assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size); surface = calloc (1, sizeof (cairo_gl_surface_t)); if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); @@ -713,12 +731,10 @@ _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx, surface->supports_stencil = TRUE; /* Create the texture used to store the surface's data. */ - if (!set_tex_param) { _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); ctx->dispatch.BindTexture (ctx->tex_target, surface->tex); ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } return &surface->base; } @@ -737,7 +753,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, ctx->dispatch.GenTextures (1, &tex); surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch_for_texture (ctx, content, - tex, width, height, FALSE); + tex, width, height); if (unlikely (surface->base.status)) return &surface->base; @@ -753,7 +769,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, default: ASSERT_NOT_REACHED; case CAIRO_CONTENT_COLOR_ALPHA: - if (ctx->can_read_bgra) + if(ctx->can_read_bgra) format = GL_BGRA; else format = GL_RGBA; @@ -762,7 +778,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, /* 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) + if (for_caching && !ctx->is_gl33) format = GL_ALPHA; else format = GL_RGBA; @@ -776,7 +792,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, * specified. So, we have to store RGBA, and fill the alpha * channel with 1 when blending. */ - if (ctx->can_read_bgra) + if(ctx->can_read_bgra) format = GL_BGRA; else format = GL_RGBA; @@ -785,7 +801,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, ctx->dispatch.TexImage2D (ctx->tex_target, 0, format, width, height, 0, - format, GL_UNSIGNED_BYTE, NULL); + format, GL_UNSIGNED_BYTE, NULL); return &surface->base; } @@ -861,15 +877,14 @@ _cairo_gl_surface_clear (cairo_gl_surface_t *surface, } /* optimize for mobile gl driver with deferred rendering */ - if (surface->clip_on_stencil_buffer || - ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) + if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT); else { - if (surface->clip_on_stencil_buffer) { - _cairo_clip_destroy(surface->clip_on_stencil_buffer); - surface->clip_on_stencil_buffer = NULL; - } - ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (surface->clip_on_stencil_buffer) { + _cairo_clip_destroy (surface->clip_on_stencil_buffer); + surface->clip_on_stencil_buffer = NULL; + } + ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } if (a == 0) @@ -931,6 +946,11 @@ cairo_gl_surface_create (cairo_device_t *abstract_device, if (unlikely (status)) return _cairo_surface_create_in_error (status); + if (! _cairo_gl_surface_size_valid_for_context (ctx, width, height)) { + status = _cairo_gl_context_release (ctx, status); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + } + surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height); if (unlikely (surface->base.status)) { @@ -1003,9 +1023,14 @@ cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device, if (unlikely (status)) return _cairo_surface_create_in_error (status); + if (! _cairo_gl_surface_size_valid_for_context (ctx, width, height)) { + status = _cairo_gl_context_release (ctx, status); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + } + surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch_for_texture (ctx, content, - tex, width, height, TRUE); + tex, width, height); status = _cairo_gl_context_release (ctx, status); return &surface->base; @@ -1090,7 +1115,6 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return; - /* And in any case we should flush any pending operations. */ _cairo_gl_composite_flush (ctx); @@ -1099,7 +1123,7 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) ctx->swap_buffers (ctx, surface); - /* according to khronos specs on egl 1.4, stencil buffer is + /* according to khronos specs on egl 1.4, stencil buffer is * not preserved after eglSwapBuffers */ if (surface->clip_on_stencil_buffer) { _cairo_clip_destroy (surface->clip_on_stencil_buffer); @@ -1112,16 +1136,6 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) } } -static cairo_bool_t -_cairo_gl_surface_size_valid (cairo_gl_surface_t *surface, - int width, int height) -{ - cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device; - return width > 0 && height > 0 && - width <= ctx->max_framebuffer_size && - height <= ctx->max_framebuffer_size; -} - static cairo_surface_t * _cairo_gl_surface_create_similar (void *abstract_surface, cairo_content_t content, @@ -1214,8 +1228,10 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, pixman_format = _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8; if (src->base.content != CAIRO_CONTENT_ALPHA) { - if (src->pixman_format != pixman_format) - require_conversion = TRUE; + if (src->pixman_format != pixman_format) { + if (!ctx->can_read_bgra) + require_conversion = TRUE; + } } else if (dst->base.content != CAIRO_CONTENT_ALPHA) require_conversion = TRUE; @@ -1227,6 +1243,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, } if (require_conversion) { + src->base.is_clear = FALSE; rgba_clone = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, @@ -1246,7 +1263,32 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, src = rgba_clone; } - } + } else if (ctx->is_gl33 && src->base.content == CAIRO_CONTENT_ALPHA) { + /* use RGBA for ALPHA */ + pixman_format_code_t pixman_format; + cairo_surface_pattern_t pattern; + src->base.is_clear = FALSE; + pixman_format = _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8; + + rgba_clone = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (NULL, + pixman_format, + src->width, + src->height, + 0); + if (unlikely (rgba_clone->base.status)) + goto FAIL; + + _cairo_pattern_init_for_surface (&pattern, &src->base); + status = _cairo_surface_paint (&rgba_clone->base, + CAIRO_OPERATOR_SOURCE, + &pattern.base, NULL); + _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) + goto FAIL; + + src = rgba_clone; + } if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor, src->pixman_format, @@ -1311,6 +1353,9 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, } else { + /* When cpp != 4, setting GL_UNPACK_ALIGNMENT to cpp + causes many failures in cairo tests with respect to + GLESV2 */ ctx->dispatch.PixelStorei (GL_UNPACK_ALIGNMENT, 4); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP || ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) @@ -1320,18 +1365,18 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, /* we must resolve the renderbuffer to texture before we upload image */ status = _cairo_gl_surface_resolve_multisampling (dst); - if (unlikely (status)) { - free (data_start_gles2); - goto FAIL; - } + if (unlikely (status)) { + free (data_start_gles2); + goto FAIL; + } _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); ctx->dispatch.BindTexture (ctx->tex_target, dst->tex); ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); ctx->dispatch.TexSubImage2D (ctx->tex_target, 0, - dst_x, dst_y, width, height, - format, type, data_start); + dst_x, dst_y, width, height, + format, type, data_start); free (data_start_gles2); @@ -1498,8 +1543,8 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, return NULL; } - if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES2 || - _cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES3) { + /*if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES2 || + _cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES3)*/ { /* 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 @@ -1538,11 +1583,11 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, /* 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) { +/* 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. @@ -1554,10 +1599,11 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, flipped = ! _cairo_gl_surface_is_texture (surface); mesa_invert = flipped && ctx->has_mesa_pack_invert; - ctx->dispatch.PixelStorei (GL_PACK_ALIGNMENT, 4); + ctx->dispatch.PixelStorei (GL_PACK_ALIGNMENT, cpp); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP || ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) ctx->dispatch.PixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp); + if (mesa_invert) ctx->dispatch.PixelStorei (GL_PACK_INVERT_MESA, 1); @@ -1566,8 +1612,9 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, y = surface->height - extents->y - extents->height; ctx->dispatch.ReadPixels (extents->x, y, - extents->width, extents->height, - format, type, image->data); + extents->width, extents->height, + format, type, image->data); + if (mesa_invert) ctx->dispatch.PixelStorei (GL_PACK_INVERT_MESA, 0); @@ -1707,9 +1754,10 @@ _cairo_gl_surface_flush (void *abstract_surface, unsigned flags) _cairo_gl_composite_flush (ctx); status = _cairo_gl_surface_resolve_multisampling (surface); - +#if 0 if (ctx->msaa_type != CAIRO_GL_NONE_MULTISAMPLE_TO_TEXTURE) - ctx->dispatch.Flush (); + ctx->dispatch.Flush (); +#endif return _cairo_gl_context_release (ctx, status); } @@ -1772,7 +1820,7 @@ _cairo_gl_surface_paint (void *surface, &source->shadow); ctx->source_scratch_in_use = FALSE; if (unlikely (status)) { - cairo_device_release (dst->base.device); + cairo_device_release (dst->base.device); return status; } @@ -1781,13 +1829,12 @@ _cairo_gl_surface_paint (void *surface, dst->content_changed = TRUE; dst->content_synced = FALSE; } - + ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); return status; } -#if 0 // Currently glClear does not get flushed to GPU so do not use this fast path for the time being /* simplify the common case of clearing the surface */ if (clip == NULL) { if (op == CAIRO_OPERATOR_CLEAR) { @@ -1800,11 +1847,10 @@ _cairo_gl_surface_paint (void *surface, (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque_solid (source)))) { status = _cairo_gl_surface_clear (surface, &((cairo_solid_pattern_t *) source)->color); - cairo_device_release (dst->base.device); + cairo_device_release (dst->base.device); return status; } } -#endif status = _cairo_compositor_paint (get_compositor (surface), surface, op, source, clip); @@ -1812,7 +1858,7 @@ _cairo_gl_surface_paint (void *surface, dst->content_changed = TRUE; dst->content_synced = FALSE; } - + ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); return status; @@ -1837,7 +1883,7 @@ _cairo_gl_surface_mask (void *surface, &source->shadow); ctx->source_scratch_in_use = FALSE; if (unlikely (status)) { - cairo_device_release (dst->base.device); + cairo_device_release (dst->base.device); return status; } @@ -1845,8 +1891,8 @@ _cairo_gl_surface_mask (void *surface, if (status == CAIRO_INT_STATUS_SUCCESS) { dst->content_changed = TRUE; dst->content_synced = FALSE; - } - + } + ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); return status; @@ -1857,7 +1903,7 @@ _cairo_gl_surface_mask (void *surface, if (status == CAIRO_INT_STATUS_SUCCESS) { dst->content_changed = TRUE; dst->content_synced = FALSE; - + ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); return status; @@ -2016,7 +2062,6 @@ _cairo_gl_surface_fill (void *surface, ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); - return status; } |