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"
53 #include "cairo-surface-offset-private.h"
55 static cairo_int_status_t
56 acquire (void *abstract_dst
)
58 return CAIRO_STATUS_SUCCESS
;
61 static cairo_int_status_t
62 release (void *abstract_dst
)
64 return CAIRO_STATUS_SUCCESS
;
67 static cairo_int_status_t
68 set_clip_region (void *_surface
,
69 cairo_region_t
*region
)
71 cairo_gl_surface_t
*surface
= _surface
;
73 surface
->clip_region
= region
;
74 return CAIRO_STATUS_SUCCESS
;
77 static cairo_int_status_t
78 draw_image_boxes (void *_dst
,
79 cairo_image_surface_t
*image
,
83 cairo_gl_surface_t
*dst
= _dst
;
84 struct _cairo_boxes_chunk
*chunk
;
87 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
88 for (i
= 0; i
< chunk
->count
; i
++) {
89 cairo_box_t
*b
= &chunk
->base
[i
];
90 int x
= _cairo_fixed_integer_part (b
->p1
.x
);
91 int y
= _cairo_fixed_integer_part (b
->p1
.y
);
92 int w
= _cairo_fixed_integer_part (b
->p2
.x
) - x
;
93 int h
= _cairo_fixed_integer_part (b
->p2
.y
) - y
;
94 cairo_status_t status
;
96 status
= _cairo_gl_surface_draw_image (dst
, image
,
101 if (unlikely (status
))
106 return CAIRO_STATUS_SUCCESS
;
110 emit_aligned_boxes (cairo_gl_context_t
*ctx
,
111 const cairo_boxes_t
*boxes
)
113 const struct _cairo_boxes_chunk
*chunk
;
114 cairo_gl_emit_rect_t emit
= _cairo_gl_context_choose_emit_rect (ctx
);
117 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
118 for (i
= 0; i
< chunk
->count
; i
++) {
119 int x1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.x
);
120 int y1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.y
);
121 int x2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.x
);
122 int y2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.y
);
123 emit (ctx
, x1
, y1
, x2
, y2
);
128 static cairo_int_status_t
129 fill_boxes (void *_dst
,
131 const cairo_color_t
*color
,
132 cairo_boxes_t
*boxes
)
134 cairo_gl_composite_t setup
;
135 cairo_gl_context_t
*ctx
;
136 cairo_int_status_t status
;
138 status
= _cairo_gl_composite_init (&setup
, op
, _dst
, FALSE
);
139 if (unlikely (status
))
142 _cairo_gl_composite_set_solid_source (&setup
, color
);
144 status
= _cairo_gl_composite_begin (&setup
, &ctx
);
145 if (unlikely (status
))
148 emit_aligned_boxes (ctx
, boxes
);
149 status
= _cairo_gl_context_release (ctx
, CAIRO_STATUS_SUCCESS
);
152 _cairo_gl_composite_fini (&setup
);
156 static cairo_int_status_t
157 composite_boxes (void *_dst
,
159 cairo_surface_t
*abstract_src
,
160 cairo_surface_t
*abstract_mask
,
167 cairo_boxes_t
*boxes
,
168 const cairo_rectangle_int_t
*extents
)
170 cairo_gl_composite_t setup
;
171 cairo_gl_context_t
*ctx
;
172 cairo_int_status_t status
;
174 status
= _cairo_gl_composite_init (&setup
, op
, _dst
, FALSE
);
175 if (unlikely (status
))
178 _cairo_gl_composite_set_source_operand (&setup
,
179 source_to_operand (abstract_src
));
180 _cairo_gl_operand_translate (&setup
.src
, dst_x
-src_x
, dst_y
-src_y
);
182 _cairo_gl_composite_set_mask_operand (&setup
,
183 source_to_operand (abstract_mask
));
184 _cairo_gl_operand_translate (&setup
.mask
, dst_x
-mask_x
, dst_y
-mask_y
);
186 status
= _cairo_gl_composite_begin (&setup
, &ctx
);
187 if (unlikely (status
))
190 emit_aligned_boxes (ctx
, boxes
);
191 status
= _cairo_gl_context_release (ctx
, CAIRO_STATUS_SUCCESS
);
194 _cairo_gl_composite_fini (&setup
);
198 static cairo_int_status_t
199 composite (void *_dst
,
201 cairo_surface_t
*abstract_src
,
202 cairo_surface_t
*abstract_mask
,
212 cairo_gl_composite_t setup
;
213 cairo_gl_context_t
*ctx
;
214 cairo_int_status_t status
;
216 status
= _cairo_gl_composite_init (&setup
, op
, _dst
, FALSE
);
217 if (unlikely (status
))
220 _cairo_gl_composite_set_source_operand (&setup
,
221 source_to_operand (abstract_src
));
222 _cairo_gl_operand_translate (&setup
.src
, dst_x
-src_x
, dst_y
-src_y
);
224 _cairo_gl_composite_set_mask_operand (&setup
,
225 source_to_operand (abstract_mask
));
226 _cairo_gl_operand_translate (&setup
.mask
, dst_x
-mask_x
, dst_y
-mask_y
);
228 status
= _cairo_gl_composite_begin (&setup
, &ctx
);
229 if (unlikely (status
))
233 _cairo_gl_context_emit_rect (ctx
, dst_x
, dst_y
, dst_x
+width
, dst_y
+height
);
234 status
= _cairo_gl_context_release (ctx
, CAIRO_STATUS_SUCCESS
);
237 _cairo_gl_composite_fini (&setup
);
241 static cairo_int_status_t
243 cairo_surface_t
*src
,
244 cairo_surface_t
*mask
,
254 cairo_int_status_t status
;
256 /* we could avoid some repetition... */
257 status
= composite (dst
, CAIRO_OPERATOR_DEST_OUT
, mask
, NULL
,
262 if (unlikely (status
))
265 status
= composite (dst
, CAIRO_OPERATOR_ADD
, src
, mask
,
270 if (unlikely (status
))
273 return CAIRO_STATUS_SUCCESS
;
276 static cairo_int_status_t
277 traps_to_operand (void *_dst
,
278 const cairo_rectangle_int_t
*extents
,
279 cairo_antialias_t antialias
,
280 cairo_traps_t
*traps
,
281 cairo_gl_operand_t
*operand
,
282 int dst_x
, int dst_y
)
284 pixman_format_code_t pixman_format
;
285 pixman_image_t
*pixman_image
;
286 cairo_surface_t
*image
, *mask
;
287 cairo_surface_pattern_t pattern
;
288 cairo_status_t status
;
290 pixman_format
= antialias
!= CAIRO_ANTIALIAS_NONE
? PIXMAN_a8
: PIXMAN_a1
;
291 pixman_image
= pixman_image_create_bits (pixman_format
,
295 if (unlikely (pixman_image
== NULL
))
296 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
298 _pixman_image_add_traps (pixman_image
, extents
->x
, extents
->y
, traps
);
299 image
= _cairo_image_surface_create_for_pixman_image (pixman_image
,
301 if (unlikely (image
->status
)) {
302 pixman_image_unref (pixman_image
);
303 return image
->status
;
306 /* GLES2 only supports RGB/RGBA when uploading */
307 if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES
) {
308 cairo_surface_pattern_t pattern
;
309 cairo_surface_t
*rgba_image
;
311 /* XXX perform this fixup inside _cairo_gl_draw_image() */
314 _cairo_image_surface_create_with_pixman_format (NULL
,
315 _cairo_is_little_endian () ? PIXMAN_a8b8g8r8
: PIXMAN_r8g8b8a8
,
319 if (unlikely (rgba_image
->status
))
320 return rgba_image
->status
;
322 _cairo_pattern_init_for_surface (&pattern
, image
);
323 status
= _cairo_surface_paint (rgba_image
, CAIRO_OPERATOR_SOURCE
,
324 &pattern
.base
, NULL
);
325 _cairo_pattern_fini (&pattern
.base
);
327 cairo_surface_destroy (image
);
330 if (unlikely (status
)) {
331 cairo_surface_destroy (image
);
336 mask
= _cairo_surface_create_scratch (_dst
,
337 CAIRO_CONTENT_COLOR_ALPHA
,
341 if (unlikely (mask
->status
)) {
342 cairo_surface_destroy (image
);
346 status
= _cairo_gl_surface_draw_image ((cairo_gl_surface_t
*)mask
,
347 (cairo_image_surface_t
*)image
,
349 extents
->width
, extents
->height
,
352 cairo_surface_destroy (image
);
354 if (unlikely (status
))
357 _cairo_pattern_init_for_surface (&pattern
, mask
);
358 cairo_matrix_init_translate (&pattern
.base
.matrix
,
359 -extents
->x
+dst_x
, -extents
->y
+dst_y
);
360 pattern
.base
.filter
= CAIRO_FILTER_NEAREST
;
361 pattern
.base
.extend
= CAIRO_EXTEND_NONE
;
362 status
= _cairo_gl_operand_init (operand
, &pattern
.base
, _dst
,
363 &_cairo_unbounded_rectangle
,
364 &_cairo_unbounded_rectangle
,
366 _cairo_pattern_fini (&pattern
.base
);
368 if (unlikely (status
))
371 operand
->texture
.owns_surface
= (cairo_gl_surface_t
*)mask
;
372 return CAIRO_STATUS_SUCCESS
;
375 cairo_surface_destroy (mask
);
379 static cairo_int_status_t
380 composite_traps (void *_dst
,
382 cairo_surface_t
*abstract_src
,
387 const cairo_rectangle_int_t
*extents
,
388 cairo_antialias_t antialias
,
389 cairo_traps_t
*traps
)
391 cairo_gl_composite_t setup
;
392 cairo_gl_context_t
*ctx
;
393 cairo_int_status_t status
;
395 status
= _cairo_gl_composite_init (&setup
, op
, _dst
, FALSE
);
396 if (unlikely (status
))
399 _cairo_gl_composite_set_source_operand (&setup
,
400 source_to_operand (abstract_src
));
401 _cairo_gl_operand_translate (&setup
.src
, -src_x
-dst_x
, -src_y
-dst_y
);
402 status
= traps_to_operand (_dst
, extents
, antialias
, traps
, &setup
.mask
, dst_x
, dst_y
);
403 if (unlikely (status
))
406 status
= _cairo_gl_composite_begin (&setup
, &ctx
);
407 if (unlikely (status
))
411 _cairo_gl_context_emit_rect (ctx
,
412 extents
->x
-dst_x
, extents
->y
-dst_y
,
413 extents
->x
-dst_x
+extents
->width
,
414 extents
->y
-dst_y
+extents
->height
);
415 status
= _cairo_gl_context_release (ctx
, CAIRO_STATUS_SUCCESS
);
418 _cairo_gl_composite_fini (&setup
);
422 static cairo_gl_surface_t
*
423 tristrip_to_surface (void *_dst
,
424 const cairo_rectangle_int_t
*extents
,
425 cairo_antialias_t antialias
,
426 cairo_tristrip_t
*strip
)
428 pixman_format_code_t pixman_format
;
429 pixman_image_t
*pixman_image
;
430 cairo_surface_t
*image
, *mask
;
431 cairo_status_t status
;
433 pixman_format
= antialias
!= CAIRO_ANTIALIAS_NONE
? PIXMAN_a8
: PIXMAN_a1
,
434 pixman_image
= pixman_image_create_bits (pixman_format
,
438 if (unlikely (pixman_image
== NULL
))
439 return (cairo_gl_surface_t
*)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
441 _pixman_image_add_tristrip (pixman_image
, extents
->x
, extents
->y
, strip
);
442 image
= _cairo_image_surface_create_for_pixman_image (pixman_image
,
444 if (unlikely (image
->status
)) {
445 pixman_image_unref (pixman_image
);
446 return (cairo_gl_surface_t
*)image
;
449 mask
= _cairo_surface_create_scratch (_dst
,
450 CAIRO_CONTENT_COLOR_ALPHA
,
454 if (unlikely (mask
->status
)) {
455 cairo_surface_destroy (image
);
456 return (cairo_gl_surface_t
*)mask
;
459 status
= _cairo_gl_surface_draw_image ((cairo_gl_surface_t
*)mask
,
460 (cairo_image_surface_t
*)image
,
462 extents
->width
, extents
->height
,
465 cairo_surface_destroy (image
);
466 if (unlikely (status
)) {
467 cairo_surface_destroy (mask
);
468 return (cairo_gl_surface_t
*)_cairo_surface_create_in_error (status
);
471 return (cairo_gl_surface_t
*)mask
;
474 static cairo_int_status_t
475 composite_tristrip (void *_dst
,
477 cairo_surface_t
*abstract_src
,
482 const cairo_rectangle_int_t
*extents
,
483 cairo_antialias_t antialias
,
484 cairo_tristrip_t
*strip
)
486 cairo_gl_composite_t setup
;
487 cairo_gl_context_t
*ctx
;
488 cairo_gl_surface_t
*mask
;
489 cairo_int_status_t status
;
491 mask
= tristrip_to_surface (_dst
, extents
, antialias
, strip
);
492 if (unlikely (mask
->base
.status
))
493 return mask
->base
.status
;
495 status
= _cairo_gl_composite_init (&setup
, op
, _dst
, FALSE
);
496 if (unlikely (status
))
499 _cairo_gl_composite_set_source_operand (&setup
,
500 source_to_operand (abstract_src
));
502 //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
504 status
= _cairo_gl_composite_begin (&setup
, &ctx
);
505 if (unlikely (status
))
509 _cairo_gl_context_emit_rect (ctx
,
511 dst_x
+extents
->width
,
512 dst_y
+extents
->height
);
513 status
= _cairo_gl_context_release (ctx
, CAIRO_STATUS_SUCCESS
);
516 _cairo_gl_composite_fini (&setup
);
517 cairo_surface_destroy (&mask
->base
);
521 static cairo_int_status_t
522 check_composite (const cairo_composite_rectangles_t
*extents
)
524 if (! _cairo_gl_operator_is_supported (extents
->op
))
525 return UNSUPPORTED ("unsupported operator");
527 return CAIRO_STATUS_SUCCESS
;
530 const cairo_compositor_t
*
531 _cairo_gl_traps_compositor_get (void)
533 static cairo_traps_compositor_t compositor
;
535 if (compositor
.base
.delegate
== NULL
) {
536 _cairo_traps_compositor_init (&compositor
, &_cairo_fallback_compositor
);
537 compositor
.acquire
= acquire
;
538 compositor
.release
= release
;
539 compositor
.set_clip_region
= set_clip_region
;
540 compositor
.pattern_to_surface
= _cairo_gl_pattern_to_source
;
541 compositor
.draw_image_boxes
= draw_image_boxes
;
542 //compositor.copy_boxes = copy_boxes;
543 compositor
.fill_boxes
= fill_boxes
;
544 compositor
.check_composite
= check_composite
;
545 compositor
.composite
= composite
;
546 compositor
.lerp
= lerp
;
547 //compositor.check_composite_boxes = check_composite_boxes;
548 compositor
.composite_boxes
= composite_boxes
;
549 //compositor.check_composite_traps = check_composite_traps;
550 compositor
.composite_traps
= composite_traps
;
551 //compositor.check_composite_tristrip = check_composite_traps;
552 compositor
.composite_tristrip
= composite_tristrip
;
553 compositor
.check_composite_glyphs
= _cairo_gl_check_composite_glyphs
;
554 compositor
.composite_glyphs
= _cairo_gl_composite_glyphs
;
557 return &compositor
.base
;