1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Eric Anholt
4 * Copyright © 2009 Chris Wilson
5 * Copyright © 2005,2010 Red Hat, Inc
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is Red Hat, Inc.
35 * Benjamin Otte <otte@gnome.org>
36 * Carl Worth <cworth@cworth.org>
37 * Chris Wilson <chris@chris-wilson.co.uk>
38 * Eric Anholt <eric@anholt.net>
43 #include "cairo-composite-rectangles-private.h"
44 #include "cairo-default-context-private.h"
45 #include "cairo-error-private.h"
46 #include "cairo-gl-private.h"
47 #include "cairo-image-surface-inline.h"
50 _cairo_gl_surface_acquire_dest_image (void *abstract_surface,
51 cairo_rectangle_int_t *interest_rect,
52 cairo_image_surface_t **image_out,
53 cairo_rectangle_int_t *image_rect_out,
56 cairo_gl_surface_t *surface = abstract_surface;
57 cairo_int_status_t status;
59 status = _cairo_gl_surface_deferred_clear (surface);
60 if (unlikely (status))
64 return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
69 _cairo_gl_surface_release_dest_image (void *abstract_surface,
70 cairo_rectangle_int_t *interest_rect,
71 cairo_image_surface_t *image,
72 cairo_rectangle_int_t *image_rect,
75 cairo_status_t status;
77 status = _cairo_gl_surface_draw_image (abstract_surface, image,
79 image->width, image->height,
80 image_rect->x, image_rect->y);
81 /* as we created the image, its format should be directly applicable */
82 assert (status == CAIRO_STATUS_SUCCESS);
84 cairo_surface_destroy (&image->base);
88 _cairo_gl_surface_clone_similar (void *abstract_surface,
96 cairo_surface_t **clone_out)
98 cairo_gl_surface_t *surface = abstract_surface;
99 cairo_int_status_t status;
101 /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */
102 if (src->device == surface->base.device &&
103 _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) {
104 status = _cairo_gl_surface_deferred_clear ((cairo_gl_surface_t *)src);
105 if (unlikely (status))
110 *clone_out = cairo_surface_reference (src);
112 return CAIRO_STATUS_SUCCESS;
113 } else if (_cairo_surface_is_image (src)) {
114 cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
115 cairo_gl_surface_t *clone;
117 clone = (cairo_gl_surface_t *)
118 _cairo_gl_surface_create_similar (&surface->base,
122 return UNSUPPORTED ("create_similar failed");
123 if (clone->base.status)
124 return clone->base.status;
126 status = _cairo_gl_surface_draw_image (clone, image_src,
131 cairo_surface_destroy (&clone->base);
135 *clone_out = &clone->base;
136 *clone_offset_x = src_x;
137 *clone_offset_y = src_y;
139 return CAIRO_STATUS_SUCCESS;
142 return UNSUPPORTED ("unknown src surface type in clone_similar");
145 /* Creates a cairo-gl pattern surface for the given trapezoids */
146 static cairo_status_t
147 _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
148 int dst_x, int dst_y,
149 int width, int height,
150 cairo_trapezoid_t *traps,
152 cairo_antialias_t antialias,
153 cairo_surface_pattern_t *pattern)
155 pixman_format_code_t pixman_format;
156 pixman_image_t *image;
157 cairo_surface_t *surface;
160 pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
161 image = pixman_image_create_bits (pixman_format, width, height, NULL, 0);
162 if (unlikely (image == NULL))
163 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
165 for (i = 0; i < num_traps; i++) {
166 pixman_trapezoid_t trap;
168 trap.top = _cairo_fixed_to_16_16 (traps[i].top);
169 trap.bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
171 trap.left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
172 trap.left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
173 trap.left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
174 trap.left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
176 trap.right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
177 trap.right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
178 trap.right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
179 trap.right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
181 pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
184 surface = _cairo_image_surface_create_for_pixman_image (image,
186 if (unlikely (surface->status)) {
187 pixman_image_unref (image);
188 return surface->status;
191 _cairo_pattern_init_for_surface (pattern, surface);
192 cairo_surface_destroy (surface);
194 return CAIRO_STATUS_SUCCESS;
198 _cairo_gl_surface_composite (cairo_operator_t op,
199 const cairo_pattern_t *src,
200 const cairo_pattern_t *mask,
210 cairo_region_t *clip_region)
212 cairo_gl_surface_t *dst = abstract_dst;
213 cairo_gl_context_t *ctx;
214 cairo_status_t status;
215 cairo_gl_composite_t setup;
216 cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
219 status = _cairo_gl_surface_deferred_clear (dst);
220 if (unlikely (status))
223 if (op == CAIRO_OPERATOR_SOURCE &&
225 src->type == CAIRO_PATTERN_TYPE_SURFACE &&
226 _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) &&
227 _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) {
228 cairo_image_surface_t *image = (cairo_image_surface_t *)
229 ((cairo_surface_pattern_t *) src)->surface;
234 dx + width <= (unsigned int) image->width &&
235 dy + height <= (unsigned int) image->height) {
236 status = _cairo_gl_surface_draw_image (dst, image,
240 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
245 status = _cairo_gl_composite_init (&setup, op, dst,
246 mask && mask->has_component_alpha,
248 if (unlikely (status))
251 status = _cairo_gl_composite_set_source (&setup, src,
256 if (unlikely (status))
259 status = _cairo_gl_composite_set_mask (&setup, mask,
263 if (unlikely (status))
266 status = _cairo_gl_composite_begin (&setup, &ctx);
267 if (unlikely (status))
270 if (clip_region != NULL) {
271 int i, num_rectangles;
273 num_rectangles = cairo_region_num_rectangles (clip_region);
275 for (i = 0; i < num_rectangles; i++) {
276 cairo_rectangle_int_t rect;
278 cairo_region_get_rectangle (clip_region, i, &rect);
279 _cairo_gl_composite_emit_rect (ctx,
281 rect.x + rect.width, rect.y + rect.height,
285 _cairo_gl_composite_emit_rect (ctx,
287 dst_x + width, dst_y + height,
291 status = _cairo_gl_context_release (ctx, status);
294 _cairo_gl_composite_fini (&setup);
300 _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
301 const cairo_pattern_t *pattern,
303 cairo_antialias_t antialias,
304 int src_x, int src_y,
305 int dst_x, int dst_y,
308 cairo_trapezoid_t *traps,
310 cairo_region_t *clip_region)
312 cairo_gl_surface_t *dst = abstract_dst;
313 cairo_surface_pattern_t traps_pattern;
314 cairo_int_status_t status;
316 if (! _cairo_gl_operator_is_supported (op))
317 return UNSUPPORTED ("unsupported operator");
319 status = _cairo_gl_surface_deferred_clear (dst);
320 if (unlikely (status))
323 status = _cairo_gl_get_traps_pattern (dst,
324 dst_x, dst_y, width, height,
325 traps, num_traps, antialias,
327 if (unlikely (status))
330 status = _cairo_gl_surface_composite (op,
331 pattern, &traps_pattern.base, dst,
338 _cairo_pattern_fini (&traps_pattern.base);
340 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
345 _cairo_gl_surface_fill_rectangles (void *abstract_dst,
347 const cairo_color_t *color,
348 cairo_rectangle_int_t *rects,
351 cairo_gl_surface_t *dst = abstract_dst;
352 cairo_solid_pattern_t solid;
353 cairo_gl_context_t *ctx;
354 cairo_status_t status;
355 cairo_gl_composite_t setup;
358 status = _cairo_gl_surface_deferred_clear (dst);
359 if (unlikely (status))
362 status = _cairo_gl_composite_init (&setup, op, dst,
365 if (unlikely (status))
368 _cairo_pattern_init_solid (&solid, color);
369 status = _cairo_gl_composite_set_source (&setup, &solid.base,
374 if (unlikely (status))
377 status = _cairo_gl_composite_set_mask (&setup, NULL,
381 if (unlikely (status))
384 status = _cairo_gl_composite_begin (&setup, &ctx);
385 if (unlikely (status))
388 for (i = 0; i < num_rects; i++) {
389 _cairo_gl_composite_emit_rect (ctx,
392 rects[i].x + rects[i].width,
393 rects[i].y + rects[i].height,
397 status = _cairo_gl_context_release (ctx, status);
400 _cairo_gl_composite_fini (&setup);
405 typedef struct _cairo_gl_surface_span_renderer {
406 cairo_span_renderer_t base;
408 cairo_gl_composite_t setup;
413 cairo_gl_context_t *ctx;
414 } cairo_gl_surface_span_renderer_t;
416 static cairo_status_t
417 _cairo_gl_render_bounded_spans (void *abstract_renderer,
419 const cairo_half_open_span_t *spans,
422 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
425 return CAIRO_STATUS_SUCCESS;
428 if (spans[0].coverage) {
429 _cairo_gl_composite_emit_rect (renderer->ctx,
431 spans[1].x, y + height,
436 } while (--num_spans > 1);
438 return CAIRO_STATUS_SUCCESS;
441 static cairo_status_t
442 _cairo_gl_render_unbounded_spans (void *abstract_renderer,
444 const cairo_half_open_span_t *spans,
447 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
449 if (y > renderer->ymin) {
450 _cairo_gl_composite_emit_rect (renderer->ctx,
451 renderer->xmin, renderer->ymin,
456 if (num_spans == 0) {
457 _cairo_gl_composite_emit_rect (renderer->ctx,
459 renderer->xmax, y + height,
462 if (spans[0].x != renderer->xmin) {
463 _cairo_gl_composite_emit_rect (renderer->ctx,
465 spans[0].x, y + height,
470 _cairo_gl_composite_emit_rect (renderer->ctx,
472 spans[1].x, y + height,
475 } while (--num_spans > 1);
477 if (spans[0].x != renderer->xmax) {
478 _cairo_gl_composite_emit_rect (renderer->ctx,
480 renderer->xmax, y + height,
485 renderer->ymin = y + height;
486 return CAIRO_STATUS_SUCCESS;
489 static cairo_status_t
490 _cairo_gl_finish_unbounded_spans (void *abstract_renderer)
492 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
494 if (renderer->ymax > renderer->ymin) {
495 _cairo_gl_composite_emit_rect (renderer->ctx,
496 renderer->xmin, renderer->ymin,
497 renderer->xmax, renderer->ymax,
501 return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
504 static cairo_status_t
505 _cairo_gl_finish_bounded_spans (void *abstract_renderer)
507 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
509 return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
513 _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
515 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
520 _cairo_gl_composite_fini (&renderer->setup);
526 _cairo_gl_surface_check_span_renderer (cairo_operator_t op,
527 const cairo_pattern_t *pattern,
529 cairo_antialias_t antialias)
531 if (! _cairo_gl_operator_is_supported (op))
541 cairo_span_renderer_t *
542 _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
543 const cairo_pattern_t *src,
545 cairo_antialias_t antialias,
546 const cairo_composite_rectangles_t *rects)
548 cairo_gl_surface_t *dst = abstract_dst;
549 cairo_gl_surface_span_renderer_t *renderer;
550 cairo_status_t status;
551 const cairo_rectangle_int_t *extents;
553 status = _cairo_gl_surface_deferred_clear (dst);
554 if (unlikely (status))
555 return _cairo_span_renderer_create_in_error (status);
557 renderer = calloc (1, sizeof (*renderer));
558 if (unlikely (renderer == NULL))
559 return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
561 renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
562 if (rects->is_bounded) {
563 renderer->base.render_rows = _cairo_gl_render_bounded_spans;
564 renderer->base.finish = _cairo_gl_finish_bounded_spans;
565 extents = &rects->bounded;
567 renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
568 renderer->base.finish = _cairo_gl_finish_unbounded_spans;
569 extents = &rects->unbounded;
571 renderer->xmin = extents->x;
572 renderer->xmax = extents->x + extents->width;
573 renderer->ymin = extents->y;
574 renderer->ymax = extents->y + extents->height;
576 status = _cairo_gl_composite_init (&renderer->setup,
579 if (unlikely (status))
582 status = _cairo_gl_composite_set_source (&renderer->setup, src,
583 extents->x, extents->y,
584 extents->x, extents->y,
585 extents->width, extents->height,
587 if (unlikely (status))
590 _cairo_gl_composite_set_spans (&renderer->setup);
591 _cairo_gl_composite_set_clip_region (&renderer->setup,
592 _cairo_clip_get_region (rects->clip));
594 status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx);
595 if (unlikely (status))
598 return &renderer->base;
601 _cairo_gl_composite_fini (&renderer->setup);
603 return _cairo_span_renderer_create_in_error (status);