static cairo_int_status_t fill_boxes (void *_dst, cairo_operator_t op, const cairo_color_t *color, cairo_boxes_t *boxes) { cairo_gl_composite_t setup; cairo_gl_context_t *ctx; cairo_int_status_t status; status = _cairo_gl_composite_init (&setup, op, _dst, FALSE); if (unlikely (status)) goto FAIL; _cairo_gl_composite_set_solid_source (&setup, color); status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto FAIL; emit_aligned_boxes (ctx, boxes); status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS); FAIL: _cairo_gl_composite_fini (&setup); return status; }
cairo_int_status_t _cairo_gl_surface_fill_rectangles (void *abstract_dst, cairo_operator_t op, const cairo_color_t *color, cairo_rectangle_int_t *rects, int num_rects) { cairo_gl_surface_t *dst = abstract_dst; cairo_solid_pattern_t solid; cairo_gl_context_t *ctx; cairo_status_t status; cairo_gl_composite_t setup; int i; status = _cairo_gl_surface_deferred_clear (dst); if (unlikely (status)) return status; status = _cairo_gl_composite_init (&setup, op, dst, FALSE, /* XXX */ NULL); if (unlikely (status)) goto CLEANUP; _cairo_pattern_init_solid (&solid, color); status = _cairo_gl_composite_set_source (&setup, &solid.base, 0, 0, 0, 0, 0, 0, FALSE); if (unlikely (status)) goto CLEANUP; status = _cairo_gl_composite_set_mask (&setup, NULL, 0, 0, 0, 0, 0, 0); if (unlikely (status)) goto CLEANUP; status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto CLEANUP; for (i = 0; i < num_rects; i++) { _cairo_gl_composite_emit_rect (ctx, rects[i].x, rects[i].y, rects[i].x + rects[i].width, rects[i].y + rects[i].height, 0); } status = _cairo_gl_context_release (ctx, status); CLEANUP: _cairo_gl_composite_fini (&setup); return status; }
static cairo_int_status_t _cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t *dst, cairo_gl_context_t *ctx, int x, int y, int width, int height) { cairo_gl_composite_t setup; cairo_status_t status; _cairo_gl_composite_flush (ctx); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_SOURCE, dst, FALSE, NULL); if (unlikely (status)) goto CLEANUP; _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_BLACK); status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto CLEANUP; _cairo_gl_composite_emit_rect (ctx, x, y, x + width, y + height, 0); status = _cairo_gl_context_release (ctx, status); CLEANUP: _cairo_gl_composite_fini (&setup); _cairo_gl_composite_flush (ctx); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); return status; }
cairo_status_t _cairo_gl_composite_begin (cairo_gl_composite_t *setup, cairo_gl_context_t **ctx_out) { cairo_gl_context_t *ctx; cairo_status_t status; assert (setup->dst); status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx); if (unlikely (status)) return status; _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample); glEnable (GL_BLEND); status = _cairo_gl_set_operands_and_operator (setup, ctx); if (unlikely (status)) goto FAIL; status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size); if (unlikely (status)) goto FAIL; *ctx_out = ctx; FAIL: if (unlikely (status)) status = _cairo_gl_context_release (ctx, status); return status; }
static void query_surface_capabilities (cairo_gl_surface_t *surface) { GLint samples, stencil_bits; cairo_gl_context_t *ctx; cairo_int_status_t status; /* Texture surfaces are create in such a way that they always have stencil and multisample bits if possible, so we don't need to query their capabilities lazily. */ if (_cairo_gl_surface_is_texture (surface)) return; if (surface->stencil_and_msaa_caps_initialized) return; surface->stencil_and_msaa_caps_initialized = TRUE; surface->supports_stencil = FALSE; surface->supports_msaa = FALSE; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return; _cairo_gl_context_set_destination (ctx, surface, FALSE); glGetIntegerv(GL_SAMPLES, &samples); glGetIntegerv(GL_STENCIL_BITS, &stencil_bits); surface->supports_stencil = stencil_bits > 0; surface->supports_msaa = samples > 1; status = _cairo_gl_context_release (ctx, status); }
static cairo_status_t _cairo_gl_surface_finish (void *abstract_surface) { cairo_gl_surface_t *surface = abstract_surface; cairo_status_t status; cairo_gl_context_t *ctx; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return status; if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE && ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE); if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE && ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK); if (ctx->current_target == surface) ctx->current_target = NULL; if (surface->fb) ctx->dispatch.DeleteFramebuffers (1, &surface->fb); if (surface->depth_stencil) ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil); if (surface->owns_tex) glDeleteTextures (1, &surface->tex); return _cairo_gl_context_release (ctx, status); }
/** * cairo_gl_surface_create_for_texture: * @content: type of content in the surface * @tex: name of texture to use for storage of surface pixels * @width: width of the surface, in pixels * @height: height of the surface, in pixels * * Creates a GL surface for the specified texture with the specified * content and dimensions. The texture must be kept around until the * #cairo_surface_t is destroyed or cairo_surface_finish() is called * on the surface. The initial contents of @tex will be used as the * initial image contents; you must explicitly clear the buffer, * using, for example, cairo_rectangle() and cairo_fill() if you want * it cleared. The format of @tex should be compatible with @content, * in the sense that it must have the color components required by * @content. * * Return value: a pointer to the newly created surface. The caller * owns the surface and should call cairo_surface_destroy() when done * with it. * * This function always returns a valid pointer, but it will return a * pointer to a "nil" surface if an error such as out of memory * occurs. You can use cairo_surface_status() to check for this. **/ cairo_surface_t * cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device, cairo_content_t content, unsigned int tex, int width, int height) { cairo_gl_context_t *ctx; cairo_gl_surface_t *surface; cairo_status_t status; if (! CAIRO_CONTENT_VALID (content)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); if (abstract_device == NULL) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); if (abstract_device->status) return _cairo_surface_create_in_error (abstract_device->status); if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH)); status = _cairo_gl_context_acquire (abstract_device, &ctx); if (unlikely (status)) return _cairo_surface_create_in_error (status); surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch_for_texture (ctx, content, tex, width, height); status = _cairo_gl_context_release (ctx, status); return &surface->base; }
static cairo_status_t _cairo_gl_surface_clear (cairo_gl_surface_t *surface, const cairo_color_t *color) { cairo_gl_context_t *ctx; cairo_status_t status; double r, g, b, a; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return status; _cairo_gl_context_set_destination (ctx, surface); if (surface->base.content & CAIRO_CONTENT_COLOR) { r = color->red * color->alpha; g = color->green * color->alpha; b = color->blue * color->alpha; } else { r = g = b = 0; } if (surface->base.content & CAIRO_CONTENT_ALPHA) { a = color->alpha; } else { a = 1.0; } glDisable (GL_SCISSOR_TEST); glClearColor (r, g, b, a); glClear (GL_COLOR_BUFFER_BIT); return _cairo_gl_context_release (ctx, status); }
static cairo_status_t _gl_flush (void *device) { cairo_gl_context_t *ctx; cairo_status_t status; status = _cairo_gl_context_acquire (device, &ctx); if (unlikely (status)) return status; _cairo_gl_composite_flush (ctx); _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE); _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK); if (ctx->clip_region) { cairo_region_destroy (ctx->clip_region); ctx->clip_region = NULL; } ctx->current_target = NULL; ctx->current_operator = -1; ctx->vertex_size = 0; ctx->pre_shader = NULL; _cairo_gl_set_shader (ctx, NULL); ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0); glDisable (GL_SCISSOR_TEST); glDisable (GL_BLEND); return _cairo_gl_context_release (ctx, status); }
static cairo_status_t _cairo_gl_finish_bounded_spans (void *abstract_renderer) { cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS); }
static cairo_surface_t * _cairo_gl_surface_create_similar (void *abstract_surface, cairo_content_t content, int width, int height) { cairo_surface_t *surface = abstract_surface; cairo_gl_context_t *ctx; cairo_status_t status; if (! _cairo_gl_surface_size_valid (abstract_surface, width, height)) return _cairo_image_surface_create_with_content (content, width, height); status = _cairo_gl_context_acquire (surface->device, &ctx); if (unlikely (status)) return _cairo_surface_create_in_error (status); surface = _cairo_gl_surface_create_scratch (ctx, content, width, height); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) { cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); } return surface; }
cairo_surface_t * cairo_gl_surface_create (cairo_device_t *abstract_device, cairo_content_t content, int width, int height) { cairo_gl_context_t *ctx; cairo_gl_surface_t *surface; cairo_status_t status; if (! CAIRO_CONTENT_VALID (content)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); if (abstract_device == NULL) return _cairo_image_surface_create_with_content (content, width, height); if (abstract_device->status) return _cairo_surface_create_in_error (abstract_device->status); if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); status = _cairo_gl_context_acquire (abstract_device, &ctx); if (unlikely (status)) return _cairo_surface_create_in_error (status); surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_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); return _cairo_surface_create_in_error (status); } return &surface->base; }
cairo_status_t _cairo_gl_composite_begin_tristrip (cairo_gl_composite_t *setup, cairo_gl_context_t **ctx_out) { cairo_gl_context_t *ctx; cairo_status_t status; cairo_gl_shader_t *shader; int src_size, dst_size; cairo_gl_operand_t default_mask; memset (&default_mask, 0, sizeof (cairo_gl_operand_t)); assert (setup->dst); status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx); if (unlikely (status)) return status; *ctx_out = ctx; /* Finish any pending operations from other GL compositors. */ if (! _cairo_gl_context_is_flushed (ctx)) _cairo_gl_composite_flush (ctx); glEnable (GL_BLEND); status = _cairo_gl_get_shader_by_type (ctx, &setup->src, &default_mask, setup->spans, CAIRO_GL_SHADER_IN_NORMAL, &shader); if (unlikely (status)) { status = _cairo_gl_context_release (ctx, status); return status; } _cairo_gl_context_set_destination (ctx, setup->dst); _cairo_gl_set_operator (ctx, setup->op, FALSE); _cairo_gl_set_shader (ctx, shader); _cairo_gl_composite_bind_to_shader (ctx, setup); dst_size = 2 * sizeof (GLfloat); src_size = _cairo_gl_operand_get_vertex_size (setup->src.type); ctx->vertex_size = dst_size + src_size; ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo); ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2, GL_FLOAT, GL_FALSE, ctx->vertex_size, NULL); ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, ctx->vertex_size, dst_size); return status; }
static cairo_int_status_t _cairo_gl_msaa_compositor_fill_rectilinear (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; int i; status = _cairo_gl_composite_init (&setup, composite->op, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) goto cleanup_setup; status = _cairo_gl_composite_set_source (&setup, composite->original_source_pattern, &composite->source_sample_area, &composite->bounded, TRUE); if (unlikely (status)) goto cleanup_setup; status = _cairo_gl_composite_begin_multisample (&setup, &ctx, antialias != CAIRO_ANTIALIAS_NONE); if (unlikely (status)) goto cleanup_setup; for (i = 0; i < clip->num_boxes; i++) { status = _cairo_gl_msaa_compositor_draw_quad (ctx, &setup, &clip->boxes[i]); if (unlikely (status)) goto cleanup_setup; } cleanup_setup: _cairo_gl_composite_fini (&setup); if (ctx) status = _cairo_gl_context_release (ctx, status); return status; }
static cairo_status_t _cairo_gl_finish_unbounded_spans (void *abstract_renderer) { cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; if (renderer->ymax > renderer->ymin) { _cairo_gl_composite_emit_rect (renderer->ctx, renderer->xmin, renderer->ymin, renderer->xmax, renderer->ymax, 0); } return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS); }
static cairo_int_status_t _cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst, const cairo_gradient_pattern_t *pattern, cairo_gl_gradient_t **gradient) { cairo_gl_context_t *ctx; cairo_status_t status; status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (unlikely (status)) return status; status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient); return _cairo_gl_context_release (ctx, status); }
static cairo_int_status_t composite_tristrip (void *_dst, cairo_operator_t op, cairo_surface_t *abstract_src, int src_x, int src_y, int dst_x, int dst_y, const cairo_rectangle_int_t *extents, cairo_antialias_t antialias, cairo_tristrip_t *strip) { cairo_gl_composite_t setup; cairo_gl_context_t *ctx; cairo_gl_surface_t *mask; cairo_int_status_t status; mask = tristrip_to_surface (_dst, extents, antialias, strip); if (unlikely (mask->base.status)) return mask->base.status; status = _cairo_gl_composite_init (&setup, op, _dst, FALSE); if (unlikely (status)) goto FAIL; _cairo_gl_composite_set_source_operand (&setup, source_to_operand (abstract_src)); //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0); status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto FAIL; /* XXX clip */ _cairo_gl_context_emit_rect (ctx, dst_x, dst_y, dst_x+extents->width, dst_y+extents->height); status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS); FAIL: _cairo_gl_composite_fini (&setup); cairo_surface_destroy (&mask->base); return status; }
void _cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient) { cairo_gl_context_t *ctx; cairo_status_t ignore; assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count)); if (! _cairo_reference_count_dec_and_test (&gradient->ref_count)) return; if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) { glDeleteTextures (1, &gradient->tex); ignore = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS); } free (gradient); }
static cairo_int_status_t composite_traps (void *_dst, cairo_operator_t op, cairo_surface_t *abstract_src, int src_x, int src_y, int dst_x, int dst_y, const cairo_rectangle_int_t *extents, cairo_antialias_t antialias, cairo_traps_t *traps) { cairo_gl_composite_t setup; cairo_gl_context_t *ctx; cairo_int_status_t status; status = _cairo_gl_composite_init (&setup, op, _dst, FALSE); if (unlikely (status)) goto FAIL; _cairo_gl_composite_set_source_operand (&setup, source_to_operand (abstract_src)); _cairo_gl_operand_translate (&setup.src, -src_x-dst_x, -src_y-dst_y); status = traps_to_operand (_dst, extents, antialias, traps, &setup.mask, dst_x, dst_y); if (unlikely (status)) goto FAIL; status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto FAIL; /* XXX clip */ _cairo_gl_context_emit_rect (ctx, extents->x-dst_x, extents->y-dst_y, extents->x-dst_x+extents->width, extents->y-dst_y+extents->height); status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS); FAIL: _cairo_gl_composite_fini (&setup); return status; }
static cairo_int_status_t composite (void *_dst, cairo_operator_t op, cairo_surface_t *abstract_src, cairo_surface_t *abstract_mask, int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, unsigned int height) { cairo_gl_composite_t setup; cairo_gl_context_t *ctx; cairo_int_status_t status; status = _cairo_gl_composite_init (&setup, op, _dst, FALSE); if (unlikely (status)) goto FAIL; _cairo_gl_composite_set_source_operand (&setup, source_to_operand (abstract_src)); _cairo_gl_operand_translate (&setup.src, dst_x-src_x, dst_y-src_y); _cairo_gl_composite_set_mask_operand (&setup, source_to_operand (abstract_mask)); _cairo_gl_operand_translate (&setup.mask, dst_x-mask_x, dst_y-mask_y); status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto FAIL; /* XXX clip */ _cairo_gl_context_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height); status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS); FAIL: _cairo_gl_composite_fini (&setup); return status; }
void _cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient) { cairo_gl_context_t *ctx; cairo_status_t ignore; assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count)); if (! _cairo_reference_count_dec_and_test (&gradient->ref_count)) return; if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) { /* The gradient my still be active in the last operation, so flush */ _cairo_gl_composite_flush (ctx); glDeleteTextures (1, &gradient->tex); ignore = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS); } free (gradient); }
static cairo_status_t _cairo_gl_surface_flush (void *abstract_surface) { cairo_gl_surface_t *surface = abstract_surface; cairo_status_t status; cairo_gl_context_t *ctx; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return status; if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE && ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) || (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE && ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) || (ctx->current_target == surface)) _cairo_gl_composite_flush (ctx); return _cairo_gl_context_release (ctx, status); }
static cairo_int_status_t composite_boxes (void *_dst, cairo_operator_t op, cairo_surface_t *abstract_src, cairo_surface_t *abstract_mask, int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, cairo_boxes_t *boxes, const cairo_rectangle_int_t *extents) { cairo_gl_composite_t setup; cairo_gl_context_t *ctx; cairo_int_status_t status; status = _cairo_gl_composite_init (&setup, op, _dst, FALSE); if (unlikely (status)) goto FAIL; _cairo_gl_composite_set_source_operand (&setup, source_to_operand (abstract_src)); _cairo_gl_operand_translate (&setup.src, dst_x-src_x, dst_y-src_y); _cairo_gl_composite_set_mask_operand (&setup, source_to_operand (abstract_mask)); _cairo_gl_operand_translate (&setup.mask, dst_x-mask_x, dst_y-mask_y); status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto FAIL; emit_aligned_boxes (ctx, boxes); status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS); FAIL: _cairo_gl_composite_fini (&setup); return status; }
void cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) { cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (! _cairo_surface_is_gl (abstract_surface)) { _cairo_surface_set_error (abstract_surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return; } if (! _cairo_gl_surface_is_texture (surface)) { cairo_gl_context_t *ctx; cairo_status_t status; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return; /* For swapping on EGL, at least, we need a valid context/target. */ _cairo_gl_context_set_destination (ctx, surface); /* And in any case we should flush any pending operations. */ _cairo_gl_composite_flush (ctx); ctx->swap_buffers (ctx, surface); status = _cairo_gl_context_release (ctx, status); if (status) status = _cairo_surface_set_error (abstract_surface, status); } }
static cairo_status_t render_glyphs (cairo_gl_surface_t *dst, int dst_x, int dst_y, cairo_operator_t op, cairo_surface_t *source, cairo_composite_glyphs_info_t *info, cairo_bool_t *has_component_alpha, cairo_clip_t *clip, cairo_bool_t via_msaa_compositor) { cairo_format_t last_format = CAIRO_FORMAT_INVALID; cairo_gl_glyph_cache_t *cache = NULL; cairo_gl_context_t *ctx; cairo_gl_composite_t setup; cairo_int_status_t status; int i = 0; cairo_bool_t is_argb32; TRACE ((stderr, "%s (%d, %d)x(%d, %d)\n", __FUNCTION__, info->extents.x, info->extents.y, info->extents.width, info->extents.height)); *has_component_alpha = FALSE; status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (unlikely (status)) return status; /* Traps compositor never has CLEAR operator. */ is_argb32 = info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL || info->font->options.antialias == CAIRO_ANTIALIAS_BEST; /* If we are invoked by traps compositor, we keep what is in code otherwise, we handle non-subpixel/best directly in msaa compositor. */ if (!via_msaa_compositor) status = _cairo_gl_composite_init (&setup, op, dst, TRUE); else if (info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL || info->font->options.antialias == CAIRO_ANTIALIAS_BEST) status = _cairo_gl_composite_init (&setup, op, dst, TRUE); else status = _cairo_gl_composite_init (&setup, op, dst, FALSE); if (unlikely (status)) goto FINISH; if (source == NULL) { _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE); } else { _cairo_gl_composite_set_source_operand (&setup, source_to_operand (source)); } if (setup.src.type == CAIRO_GL_OPERAND_CONSTANT) setup.src.use_color_attribute = TRUE; _cairo_gl_composite_set_clip (&setup, clip); for (i = 0; i < info->num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; cairo_gl_glyph_t *glyph; double x_offset, y_offset; double x1, x2, y1, y2; status = _cairo_scaled_glyph_lookup (info->font, info->glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); if (unlikely (status)) goto FINISH; if (scaled_glyph->surface->width == 0 || scaled_glyph->surface->height == 0) { continue; } if (scaled_glyph->surface->format != last_format) { status = cairo_gl_context_get_glyph_cache (ctx, scaled_glyph->surface->format, &cache); if (unlikely (status)) goto FINISH; last_format = scaled_glyph->surface->format; /* In msaa compositor, clear operator needs component alpha, we need to reset to FALSE if previously clear operator has set it to TRUE. */ if (via_msaa_compositor) { if (op == CAIRO_OPERATOR_CLEAR || is_argb32) cache->surface->operand.texture.attributes.has_component_alpha = TRUE; else cache->surface->operand.texture.attributes.has_component_alpha = FALSE; } _cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand); *has_component_alpha |= cache->surface->operand.texture.attributes.has_component_alpha; /* XXX Shoot me. */ status = _cairo_gl_composite_begin (&setup, &ctx); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) goto FINISH; } if (scaled_glyph->dev_private_key != cache) { cairo_scaled_glyph_private_t *priv; priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache); if (priv) { scaled_glyph->dev_private_key = cache; scaled_glyph->dev_private = cairo_container_of (priv, cairo_gl_glyph_t, base); } else { status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); if (status == CAIRO_INT_STATUS_UNSUPPORTED) { /* Cache is full, so flush existing prims and try again. */ _cairo_gl_composite_flush (ctx); _cairo_gl_glyph_cache_unlock (cache); status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); } if (unlikely (_cairo_int_status_is_error (status))) goto FINISH; } } x_offset = scaled_glyph->surface->base.device_transform.x0; y_offset = scaled_glyph->surface->base.device_transform.y0; x1 = _cairo_lround (info->glyphs[i].x - x_offset - dst_x); y1 = _cairo_lround (info->glyphs[i].y - y_offset - dst_y); x2 = x1 + scaled_glyph->surface->width; y2 = y1 + scaled_glyph->surface->height; glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph); _cairo_gl_composite_emit_glyph (ctx, x1, y1, x2, y2, glyph->p1.x, glyph->p1.y, glyph->p2.x, glyph->p2.y); } status = CAIRO_STATUS_SUCCESS; FINISH: status = _cairo_gl_context_release (ctx, status); _cairo_gl_composite_fini (&setup); return status; }
static cairo_int_status_t _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_traps_t traps; cairo_bool_t use_color_attr = FALSE; if (! can_use_msaa_compositor (dst, antialias)) return CAIRO_INT_STATUS_UNSUPPORTED; if (composite->is_bounded == FALSE) { cairo_surface_t* surface = _prepare_unbounded_surface (dst); if (unlikely (surface == NULL)) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_compositor_fill (compositor, surface, CAIRO_OPERATOR_SOURCE, &composite->source_pattern.base, path, fill_rule, tolerance, antialias, NULL); if (unlikely (status)) { cairo_surface_destroy (surface); return status; } return _paint_back_unbounded_surface (compositor, composite, surface); } if (_cairo_path_fixed_fill_is_rectilinear (path) && composite->clip != NULL && composite->clip->num_boxes == 1 && composite->clip->path == NULL) { cairo_clip_t *clip = _cairo_clip_copy (composite->clip); clip = _cairo_clip_intersect_rectilinear_path (clip, path, fill_rule, antialias); if (clip->num_boxes) status = _cairo_gl_msaa_compositor_fill_rectilinear (compositor, composite, path, fill_rule, tolerance, antialias, clip); _cairo_clip_destroy (clip); return status; } status = _cairo_gl_composite_init (&setup, composite->op, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) { _cairo_gl_composite_fini (&setup); return status; } _cairo_traps_init (&traps); if (_cairo_path_fixed_fill_is_rectilinear (path)) { status = _cairo_path_fixed_fill_rectilinear_to_traps (path, fill_rule, antialias, &traps); use_color_attr = TRUE; } else status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (unlikely (status)) goto cleanup_traps; status = _cairo_gl_composite_set_source (&setup, composite->original_source_pattern, &composite->source_sample_area, &composite->bounded, use_color_attr); if (unlikely (status)) goto cleanup_setup; _cairo_gl_msaa_compositor_set_clip (composite, &setup); status = _cairo_gl_composite_begin_multisample (&setup, &ctx, antialias != CAIRO_ANTIALIAS_NONE); if (unlikely (status)) goto cleanup_setup; status = _draw_traps (ctx, &setup, &traps); if (unlikely (status)) goto cleanup_setup; cleanup_setup: _cairo_gl_composite_fini (&setup); if (ctx) status = _cairo_gl_context_release (ctx, status); cleanup_traps: _cairo_traps_fini (&traps); return status; }
static cairo_int_status_t _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias) { cairo_int_status_t status; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; struct _tristrip_composite_info info; cairo_bool_t use_color_attribute; if (! can_use_msaa_compositor (dst, antialias)) return CAIRO_INT_STATUS_UNSUPPORTED; if (composite->is_bounded == FALSE) { cairo_surface_t* surface = _prepare_unbounded_surface (dst); if (unlikely (surface == NULL)) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_compositor_stroke (compositor, surface, CAIRO_OPERATOR_SOURCE, &composite->source_pattern.base, path, style, ctm, ctm_inverse, tolerance, antialias, NULL); if (unlikely (status)) { cairo_surface_destroy (surface); return status; } return _paint_back_unbounded_surface (compositor, composite, surface); } status = _cairo_gl_composite_init (&info.setup, composite->op, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) return status; info.ctx = NULL; use_color_attribute = _cairo_path_fixed_stroke_is_rectilinear (path) || _cairo_gl_hairline_style_is_hairline (style, ctm); status = _cairo_gl_composite_set_source (&info.setup, composite->original_source_pattern, &composite->source_sample_area, &composite->bounded, use_color_attribute); if (unlikely (status)) goto finish; _cairo_gl_msaa_compositor_set_clip (composite, &info.setup); status = _cairo_gl_composite_begin_multisample (&info.setup, &info.ctx, antialias != CAIRO_ANTIALIAS_NONE); if (unlikely (status)) goto finish; if (_cairo_gl_hairline_style_is_hairline (style, ctm)) { cairo_gl_hairline_closure_t closure; if (! (_is_continuous_arc (path, style) || _is_continuous_single_line (path, style))) { status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite, path, style, ctm); if (unlikely (status)) goto finish; } closure.ctx = info.ctx; closure.tolerance = tolerance; status = _cairo_gl_path_fixed_stroke_to_hairline (path, &closure, style, ctm, ctm_inverse, _cairo_gl_hairline_move_to, style->dash ? _cairo_gl_hairline_line_to_dashed : _cairo_gl_hairline_line_to, _cairo_gl_hairline_curve_to, _cairo_gl_hairline_close_path); goto finish; } if (use_color_attribute) { cairo_traps_t traps; _cairo_traps_init (&traps); status = _cairo_path_fixed_stroke_to_traps (path, style, ctm, ctm_inverse, tolerance, &traps); if (unlikely (status)) { _cairo_traps_fini (&traps); goto finish; } status = _draw_traps (info.ctx, &info.setup, &traps); _cairo_traps_fini (&traps); } else { if (!_is_continuous_single_line (path, style)) { status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite, path, style, ctm); if (unlikely (status)) goto finish; } status = _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path, style, ctm, ctm_inverse, tolerance, _stroke_shaper_add_triangle, _stroke_shaper_add_triangle_fan, _stroke_shaper_add_quad, &info); if (unlikely (status)) goto finish; } finish: _cairo_gl_composite_fini (&info.setup); if (info.ctx) status = _cairo_gl_context_release (info.ctx, status); return status; }
static cairo_status_t _cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand, const cairo_pattern_t *_src, cairo_gl_surface_t *dst, const cairo_rectangle_int_t *sample, const cairo_rectangle_int_t *extents, cairo_bool_t use_texgen) { const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src; cairo_surface_pattern_t local_pattern; cairo_surface_subsurface_t *sub; cairo_gl_surface_t *surface; cairo_gl_context_t *ctx; cairo_surface_attributes_t *attributes; cairo_status_t status; sub = (cairo_surface_subsurface_t *) src->surface; if (sub->snapshot && sub->snapshot->type == CAIRO_SURFACE_TYPE_GL && sub->snapshot->device == dst->base.device) { surface = (cairo_gl_surface_t *) cairo_surface_reference (sub->snapshot); } else { status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (unlikely (status)) return status; /* XXX Trim surface to the sample area within the subsurface? */ surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch (ctx, sub->target->content, sub->extents.width, sub->extents.height); if (surface->base.status) return _cairo_gl_context_release (ctx, surface->base.status); _cairo_pattern_init_for_surface (&local_pattern, sub->target); cairo_matrix_init_translate (&local_pattern.base.matrix, sub->extents.x, sub->extents.y); local_pattern.base.filter = CAIRO_FILTER_NEAREST; status = _cairo_surface_paint (&surface->base, CAIRO_OPERATOR_SOURCE, &local_pattern.base, NULL); _cairo_pattern_fini (&local_pattern.base); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) { cairo_surface_destroy (&surface->base); return status; } _cairo_surface_subsurface_set_snapshot (&sub->base, &surface->base); } status = _cairo_gl_surface_resolve_multisampling (surface); if (unlikely (status)) return status; attributes = &operand->texture.attributes; operand->type = CAIRO_GL_OPERAND_TEXTURE; operand->texture.surface = surface; operand->texture.owns_surface = surface; operand->texture.tex = surface->tex; if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) { attributes->matrix = src->base.matrix; } else { cairo_matrix_t m; cairo_matrix_init_scale (&m, 1.0 / surface->width, 1.0 / surface->height); cairo_matrix_multiply (&attributes->matrix, &src->base.matrix, &m); } attributes->extend = src->base.extend; attributes->filter = src->base.filter; attributes->has_component_alpha = src->base.has_component_alpha; operand->texture.texgen = use_texgen; return CAIRO_STATUS_SUCCESS; }
static cairo_int_status_t _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; cairo_operator_t op = composite->op; cairo_traps_t traps; cairo_bool_t use_color_attribute = FALSE; if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT)) return CAIRO_INT_STATUS_UNSUPPORTED; /* GL compositing operators cannot properly represent a mask operation using the SOURCE compositing operator in one pass. This only matters if there actually is a mask (there isn't in a paint operation) and if the mask isn't totally opaque. */ if (op == CAIRO_OPERATOR_SOURCE && composite->original_mask_pattern != NULL && ! _cairo_pattern_is_opaque (&composite->mask_pattern.base, &composite->mask_sample_area)) { /* If the source is opaque the operation reduces to OVER. */ if (_cairo_pattern_is_opaque (&composite->source_pattern.base, &composite->source_sample_area)) op = CAIRO_OPERATOR_OVER; else return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite); } if (_should_use_unbounded_surface (composite)) { cairo_surface_t* surface = _prepare_unbounded_surface (dst); if (unlikely (surface == NULL)) return CAIRO_INT_STATUS_UNSUPPORTED; /* This may be a paint operation. */ if (composite->original_mask_pattern == NULL) { status = _cairo_compositor_paint (compositor, surface, CAIRO_OPERATOR_SOURCE, &composite->source_pattern.base, NULL); } else { status = _cairo_compositor_mask (compositor, surface, CAIRO_OPERATOR_SOURCE, &composite->source_pattern.base, &composite->mask_pattern.base, NULL); } if (unlikely (status)) { cairo_surface_destroy (surface); return status; } return _paint_back_unbounded_surface (compositor, composite, surface); } status = _cairo_gl_composite_init (&setup, op, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) goto finish; _gl_pattern_fix_reference_count (composite->original_source_pattern); if (! composite->clip || (composite->clip->num_boxes == 1 && ! composite->clip->path)) use_color_attribute = TRUE; status = _cairo_gl_composite_set_source (&setup, composite->original_source_pattern, &composite->source_sample_area, &composite->bounded, use_color_attribute); if (unlikely (status)) goto finish; if (composite->original_mask_pattern != NULL) { status = _cairo_gl_composite_set_mask (&setup, composite->original_mask_pattern, &composite->mask_sample_area, &composite->bounded); } if (unlikely (status)) goto finish; /* We always use multisampling here, because we do not yet have the smarts to calculate when the clip or the source requires it. */ status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE); if (unlikely (status)) goto finish; _cairo_traps_init (&traps); if (! composite->clip) status = _draw_int_rect (ctx, &setup, &composite->bounded); else status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps); _cairo_traps_fini (&traps); finish: _cairo_gl_composite_fini (&setup); if (ctx) status = _cairo_gl_context_release (ctx, status); return status; }
/* The first pass, we use mask as source, to get dst1 = (1 - ma) * dst) with * DEST_OUT operator. In the second pass, we use ADD operator to achieve * result = (src * ma) + dst1. Combining two passes, we have * result = (src * ma) + (1 - ma) * dst */ static cairo_int_status_t _cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; cairo_traps_t traps; _cairo_traps_init (&traps); status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_DEST_OUT, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) goto finish; _gl_pattern_fix_reference_count (composite->original_mask_pattern); status = _cairo_gl_composite_set_source (&setup, &composite->mask_pattern.base, &composite->mask_sample_area, &composite->bounded, FALSE); if (unlikely (status)) goto finish; status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE); if (unlikely (status)) goto finish; if (! composite->clip) status = _draw_int_rect (ctx, &setup, &composite->bounded); else status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps); _cairo_gl_composite_fini (&setup); status = _cairo_gl_context_release (ctx, status); ctx = NULL; if (unlikely (status)) return status; /* second pass */ status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_ADD, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) goto finish; _gl_pattern_fix_reference_count (composite->original_source_pattern); status = _cairo_gl_composite_set_source (&setup, &composite->source_pattern.base, &composite->source_sample_area, &composite->bounded, FALSE); if (unlikely (status)) goto finish; status = _cairo_gl_composite_set_mask (&setup, &composite->mask_pattern.base, &composite->source_sample_area, &composite->bounded); if (unlikely (status)) goto finish; /* We always use multisampling here, because we do not yet have the smarts to calculate when the clip or the source requires it. */ status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE); if (unlikely (status)) goto finish; if (! composite->clip) status = _draw_int_rect (ctx, &setup, &composite->bounded); else status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps); finish: _cairo_traps_fini (&traps); _cairo_gl_composite_fini (&setup); if (ctx) status = _cairo_gl_context_release (ctx, status); return status; }