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
6 * Copyright © 2011 Intel Corporation
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is Red Hat, Inc.
36 * Benjamin Otte <otte@gnome.org>
37 * Carl Worth <cworth@cworth.org>
38 * Chris Wilson <chris@chris-wilson.co.uk>
39 * Eric Anholt <eric@anholt.net>
44 #include "cairo-gl-private.h"
46 #include "cairo-composite-rectangles-private.h"
47 #include "cairo-compositor-private.h"
48 #include "cairo-default-context-private.h"
49 #include "cairo-error-private.h"
50 #include "cairo-image-surface-private.h"
51 #include "cairo-spans-compositor-private.h"
52 #include "cairo-surface-backend-private.h"
54 typedef struct _cairo_gl_span_renderer
{
55 cairo_span_renderer_t base
;
57 cairo_gl_composite_t setup
;
60 cairo_gl_emit_span_t emit
;
65 cairo_gl_context_t
*ctx
;
66 } cairo_gl_span_renderer_t
;
69 _cairo_gl_bounded_opaque_spans (void *abstract_renderer
,
71 const cairo_half_open_span_t
*spans
,
74 cairo_gl_span_renderer_t
*r
= abstract_renderer
;
75 cairo_gl_emit_span_t emit
= r
->emit
;
78 return CAIRO_STATUS_SUCCESS
;
81 if (spans
[0].coverage
) {
84 spans
[1].x
, y
+ height
,
89 } while (--num_spans
> 1);
91 return CAIRO_STATUS_SUCCESS
;
95 _cairo_gl_bounded_spans (void *abstract_renderer
,
97 const cairo_half_open_span_t
*spans
,
100 cairo_gl_span_renderer_t
*r
= abstract_renderer
;
101 cairo_gl_emit_span_t emit
= r
->emit
;
104 return CAIRO_STATUS_SUCCESS
;
107 if (spans
[0].coverage
) {
110 spans
[1].x
, y
+ height
,
111 r
->opacity
* spans
[0].coverage
);
115 } while (--num_spans
> 1);
117 return CAIRO_STATUS_SUCCESS
;
120 static cairo_status_t
121 _cairo_gl_unbounded_spans (void *abstract_renderer
,
123 const cairo_half_open_span_t
*spans
,
126 cairo_gl_span_renderer_t
*r
= abstract_renderer
;
127 cairo_gl_emit_span_t emit
= r
->emit
;
136 if (num_spans
== 0) {
142 if (spans
[0].x
!= r
->xmin
) {
145 spans
[0].x
, y
+ height
,
152 spans
[1].x
, y
+ height
,
153 r
->opacity
* spans
[0].coverage
);
155 } while (--num_spans
> 1);
157 if (spans
[0].x
!= r
->xmax
) {
165 r
->ymin
= y
+ height
;
166 return CAIRO_STATUS_SUCCESS
;
170 static cairo_status_t
171 _cairo_gl_clipped_spans (void *abstract_renderer
,
173 const cairo_half_open_span_t
*spans
,
176 cairo_gl_span_renderer_t
*r
= abstract_renderer
;
177 cairo_gl_emit_span_t emit
= r
->emit
;
186 if (num_spans
== 0) {
192 if (spans
[0].x
!= r
->xmin
) {
195 spans
[0].x
, y
+ height
,
202 spans
[1].x
, y
+ height
,
203 r
->opacity
* spans
[0].coverage
);
205 } while (--num_spans
> 1);
207 if (spans
[0].x
!= r
->xmax
) {
215 r
->ymin
= y
+ height
;
216 return CAIRO_STATUS_SUCCESS
;
219 static cairo_status_t
220 _cairo_gl_finish_unbounded_spans (void *abstract_renderer
)
222 cairo_gl_span_renderer_t
*r
= abstract_renderer
;
223 cairo_gl_emit_span_t emit
= r
->emit
;
225 if (r
->ymax
> r
->ymin
) {
232 return _cairo_gl_context_release (r
->ctx
, CAIRO_STATUS_SUCCESS
);
235 static cairo_status_t
236 _cairo_gl_finish_bounded_spans (void *abstract_renderer
)
238 cairo_gl_span_renderer_t
*r
= abstract_renderer
;
240 return _cairo_gl_context_release (r
->ctx
, CAIRO_STATUS_SUCCESS
);
244 emit_aligned_boxes (cairo_gl_context_t
*ctx
,
245 const cairo_boxes_t
*boxes
)
247 const struct _cairo_boxes_chunk
*chunk
;
248 cairo_gl_emit_rect_t emit
= _cairo_gl_context_choose_emit_rect (ctx
);
251 TRACE ((stderr
, "%s: num_boxes=%d\n", __FUNCTION__
, boxes
->num_boxes
));
252 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
253 for (i
= 0; i
< chunk
->count
; i
++) {
254 int x1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.x
);
255 int y1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.y
);
256 int x2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.x
);
257 int y2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.y
);
258 emit (ctx
, x1
, y1
, x2
, y2
);
263 static cairo_int_status_t
264 fill_boxes (void *_dst
,
266 const cairo_color_t
*color
,
267 cairo_boxes_t
*boxes
)
269 cairo_gl_composite_t setup
;
270 cairo_gl_context_t
*ctx
;
271 cairo_int_status_t status
;
273 TRACE ((stderr
, "%s\n", __FUNCTION__
));
274 status
= _cairo_gl_composite_init (&setup
, op
, _dst
, FALSE
);
275 if (unlikely (status
))
278 _cairo_gl_composite_set_solid_source (&setup
, color
);
280 status
= _cairo_gl_composite_begin (&setup
, &ctx
);
281 if (unlikely (status
))
284 emit_aligned_boxes (ctx
, boxes
);
285 status
= _cairo_gl_context_release (ctx
, CAIRO_STATUS_SUCCESS
);
288 _cairo_gl_composite_fini (&setup
);
292 static cairo_int_status_t
293 draw_image_boxes (void *_dst
,
294 cairo_image_surface_t
*image
,
295 cairo_boxes_t
*boxes
,
298 cairo_gl_surface_t
*dst
= _dst
;
299 struct _cairo_boxes_chunk
*chunk
;
302 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
303 for (i
= 0; i
< chunk
->count
; i
++) {
304 cairo_box_t
*b
= &chunk
->base
[i
];
305 int x
= _cairo_fixed_integer_part (b
->p1
.x
);
306 int y
= _cairo_fixed_integer_part (b
->p1
.y
);
307 int w
= _cairo_fixed_integer_part (b
->p2
.x
) - x
;
308 int h
= _cairo_fixed_integer_part (b
->p2
.y
) - y
;
309 cairo_status_t status
;
311 status
= _cairo_gl_surface_draw_image (dst
, image
,
315 if (unlikely (status
))
320 return CAIRO_STATUS_SUCCESS
;
323 static cairo_int_status_t
copy_boxes (void *_dst
,
324 cairo_surface_t
*_src
,
325 cairo_boxes_t
*boxes
,
326 const cairo_rectangle_int_t
*extents
,
329 cairo_gl_surface_t
*dst
= _dst
;
330 cairo_gl_surface_t
*src
= (cairo_gl_surface_t
*)_src
;
331 cairo_gl_composite_t setup
;
332 cairo_gl_context_t
*ctx
;
333 cairo_int_status_t status
;
335 TRACE ((stderr
, "%s\n", __FUNCTION__
));
336 if (! _cairo_gl_surface_is_texture (src
))
337 return CAIRO_INT_STATUS_UNSUPPORTED
;
339 if (src
->base
.device
!= dst
->base
.device
)
340 return CAIRO_INT_STATUS_UNSUPPORTED
;
342 status
= _cairo_gl_composite_init (&setup
, CAIRO_OPERATOR_SOURCE
, _dst
, FALSE
);
343 if (unlikely (status
))
346 _cairo_gl_composite_set_source_operand (&setup
, &src
->operand
);
347 _cairo_gl_operand_translate (&setup
.src
, -dx
, -dy
);
349 status
= _cairo_gl_composite_begin (&setup
, &ctx
);
350 if (unlikely (status
))
353 emit_aligned_boxes (ctx
, boxes
);
354 status
= _cairo_gl_context_release (ctx
, CAIRO_STATUS_SUCCESS
);
357 _cairo_gl_composite_fini (&setup
);
361 static cairo_int_status_t
362 composite_boxes (void *_dst
,
364 cairo_surface_t
*abstract_src
,
365 cairo_surface_t
*abstract_mask
,
372 cairo_boxes_t
*boxes
,
373 const cairo_rectangle_int_t
*extents
)
375 cairo_gl_composite_t setup
;
376 cairo_gl_context_t
*ctx
;
377 cairo_int_status_t status
;
378 cairo_gl_operand_t tmp_operand
;
379 cairo_gl_operand_t
*src_operand
;
381 TRACE ((stderr
, "%s mask=(%d,%d), dst=(%d, %d)\n", __FUNCTION__
,
382 mask_x
, mask_y
, dst_x
, dst_y
));
385 if (op
== CAIRO_OPERATOR_CLEAR
) {
386 _cairo_gl_solid_operand_init (&tmp_operand
, CAIRO_COLOR_WHITE
);
387 src_operand
= &tmp_operand
;
388 op
= CAIRO_OPERATOR_DEST_OUT
;
389 } else if (op
== CAIRO_OPERATOR_SOURCE
) {
390 /* requires a LERP in the shader between dest and source */
391 return CAIRO_INT_STATUS_UNSUPPORTED
;
393 src_operand
= source_to_operand (abstract_src
);
395 src_operand
= source_to_operand (abstract_src
);
397 status
= _cairo_gl_composite_init (&setup
, op
, _dst
, FALSE
);
398 if (unlikely (status
))
401 _cairo_gl_composite_set_source_operand (&setup
,
403 _cairo_gl_operand_translate (&setup
.src
, -src_x
, -src_y
);
405 _cairo_gl_composite_set_mask_operand (&setup
,
406 source_to_operand (abstract_mask
));
407 _cairo_gl_operand_translate (&setup
.mask
, -mask_x
, -mask_y
);
409 status
= _cairo_gl_composite_begin (&setup
, &ctx
);
410 if (unlikely (status
))
413 emit_aligned_boxes (ctx
, boxes
);
414 status
= _cairo_gl_context_release (ctx
, CAIRO_STATUS_SUCCESS
);
417 _cairo_gl_composite_fini (&setup
);
418 if (src_operand
== &tmp_operand
)
419 _cairo_gl_operand_destroy (&tmp_operand
);
423 static cairo_int_status_t
424 _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t
*_r
,
425 const cairo_composite_rectangles_t
*composite
,
426 cairo_antialias_t antialias
,
427 cairo_bool_t needs_clip
)
429 cairo_gl_span_renderer_t
*r
= (cairo_gl_span_renderer_t
*)_r
;
430 const cairo_pattern_t
*source
= &composite
->source_pattern
.base
;
431 cairo_operator_t op
= composite
->op
;
432 cairo_int_status_t status
;
434 if (op
== CAIRO_OPERATOR_SOURCE
) {
435 if (! _cairo_pattern_is_opaque (&composite
->source_pattern
.base
,
436 &composite
->source_sample_area
))
437 return CAIRO_INT_STATUS_UNSUPPORTED
;
438 op
= CAIRO_OPERATOR_OVER
;
442 if (op
== CAIRO_OPERATOR_CLEAR
) {
443 source
= &_cairo_pattern_white
.base
;
444 op
= CAIRO_OPERATOR_DEST_OUT
;
445 } else if (composite
->surface
->is_clear
&&
446 (op
== CAIRO_OPERATOR_SOURCE
||
447 op
== CAIRO_OPERATOR_OVER
||
448 op
== CAIRO_OPERATOR_ADD
)) {
449 op
= CAIRO_OPERATOR_SOURCE
;
450 } else if (op
== CAIRO_OPERATOR_SOURCE
) {
451 /* no lerp equivalent without some major PITA */
452 return CAIRO_INT_STATUS_UNSUPPORTED
;
453 } else if (! _cairo_gl_operator_is_supported (op
))
454 return CAIRO_INT_STATUS_UNSUPPORTED
;
456 status
= _cairo_gl_composite_init (&r
->setup
,
457 op
, (cairo_gl_surface_t
*)composite
->surface
,
459 if (unlikely (status
))
462 status
= _cairo_gl_composite_set_source (&r
->setup
, source
,
463 &composite
->source_sample_area
,
464 &composite
->unbounded
,
466 if (unlikely (status
))
470 if (composite
->mask_pattern
.base
.type
== CAIRO_PATTERN_TYPE_SOLID
) {
471 r
->opacity
= composite
->mask_pattern
.solid
.color
.alpha
;
473 status
= _cairo_gl_composite_set_mask (&r
->setup
,
474 &composite
->mask_pattern
.base
,
475 &composite
->mask_sample_area
,
476 &composite
->unbounded
,
478 if (unlikely (status
))
482 _cairo_gl_composite_set_spans (&r
->setup
);
484 status
= _cairo_gl_composite_begin (&r
->setup
, &r
->ctx
);
485 if (unlikely (status
))
488 r
->emit
= _cairo_gl_context_choose_emit_span (r
->ctx
);
489 if (composite
->is_bounded
) {
490 if (r
->opacity
== 1.)
491 r
->base
.render_rows
= _cairo_gl_bounded_opaque_spans
;
493 r
->base
.render_rows
= _cairo_gl_bounded_spans
;
494 r
->base
.finish
= _cairo_gl_finish_bounded_spans
;
497 r
->base
.render_rows
= _cairo_gl_clipped_spans
;
499 r
->base
.render_rows
= _cairo_gl_unbounded_spans
;
500 r
->base
.finish
= _cairo_gl_finish_unbounded_spans
;
501 r
->xmin
= composite
->unbounded
.x
;
502 r
->xmax
= composite
->unbounded
.x
+ composite
->unbounded
.width
;
503 r
->ymin
= composite
->unbounded
.y
;
504 r
->ymax
= composite
->unbounded
.y
+ composite
->unbounded
.height
;
507 return CAIRO_STATUS_SUCCESS
;
514 _cairo_gl_span_renderer_fini (cairo_abstract_span_renderer_t
*_r
,
515 cairo_int_status_t status
)
517 cairo_gl_span_renderer_t
*r
= (cairo_gl_span_renderer_t
*) _r
;
519 if (status
== CAIRO_INT_STATUS_UNSUPPORTED
)
522 if (status
== CAIRO_INT_STATUS_SUCCESS
)
525 _cairo_gl_composite_fini (&r
->setup
);
528 const cairo_compositor_t
*
529 _cairo_gl_span_compositor_get (void)
531 static cairo_spans_compositor_t spans
;
532 static cairo_compositor_t shape
;
534 if (spans
.base
.delegate
== NULL
) {
535 /* The fallback to traps here is essentially just for glyphs... */
536 _cairo_shape_mask_compositor_init (&shape
,
537 _cairo_gl_traps_compositor_get());
540 _cairo_spans_compositor_init (&spans
, &shape
);
541 spans
.fill_boxes
= fill_boxes
;
542 spans
.draw_image_boxes
= draw_image_boxes
;
543 spans
.copy_boxes
= copy_boxes
;
544 //spans.check_composite_boxes = check_composite_boxes;
545 spans
.pattern_to_surface
= _cairo_gl_pattern_to_source
;
546 spans
.composite_boxes
= composite_boxes
;
547 //spans.check_span_renderer = check_span_renderer;
548 spans
.renderer_init
= _cairo_gl_span_renderer_init
;
549 spans
.renderer_fini
= _cairo_gl_span_renderer_fini
;