7129f6139d6de6d77b16ff816fdc52ae05c1c606
[framework/graphics/cairo.git] / src / cairo-gl-traps-compositor.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 Eric Anholt
4  * Copyright © 2009 Chris Wilson
5  * Copyright © 2005,2010 Red Hat, Inc
6  * Copyright © 2011 Intel Corporation
7  *
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.
15  *
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
21  *
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/
26  *
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.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is Red Hat, Inc.
34  *
35  * Contributor(s):
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>
40  */
41
42 #include "cairoint.h"
43
44 #include "cairo-gl-private.h"
45
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
54 static cairo_int_status_t
55 acquire (void *abstract_dst)
56 {
57     return CAIRO_STATUS_SUCCESS;
58 }
59
60 static cairo_int_status_t
61 release (void *abstract_dst)
62 {
63     return CAIRO_STATUS_SUCCESS;
64 }
65
66 static cairo_int_status_t
67 set_clip_region (void *_surface,
68                  cairo_region_t *region)
69 {
70     cairo_gl_surface_t *surface = _surface;
71
72     surface->clip_region = region;
73     return CAIRO_STATUS_SUCCESS;
74 }
75
76 static cairo_int_status_t
77 draw_image_boxes (void *_dst,
78                   cairo_image_surface_t *image,
79                   cairo_boxes_t *boxes,
80                   int dx, int dy)
81 {
82     cairo_gl_surface_t *dst = _dst;
83     struct _cairo_boxes_chunk *chunk;
84     int i;
85
86     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
87         for (i = 0; i < chunk->count; i++) {
88             cairo_box_t *b = &chunk->base[i];
89             int x = _cairo_fixed_integer_part (b->p1.x);
90             int y = _cairo_fixed_integer_part (b->p1.y);
91             int w = _cairo_fixed_integer_part (b->p2.x) - x;
92             int h = _cairo_fixed_integer_part (b->p2.y) - y;
93             cairo_status_t status;
94
95             status = _cairo_gl_surface_draw_image (dst, image,
96                                                    x + dx, y + dy,
97                                                    w, h,
98                                                    x, y);
99             if (unlikely (status))
100                 return status;
101         }
102     }
103
104     return CAIRO_STATUS_SUCCESS;
105 }
106
107 static void
108 emit_aligned_boxes (cairo_gl_context_t *ctx,
109                     const cairo_boxes_t *boxes)
110 {
111     const struct _cairo_boxes_chunk *chunk;
112     int i;
113
114     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
115         for (i = 0; i < chunk->count; i++) {
116             int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
117             int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
118             int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
119             int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
120             _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
121         }
122     }
123 }
124
125 static cairo_int_status_t
126 fill_boxes (void                *_dst,
127             cairo_operator_t     op,
128             const cairo_color_t *color,
129             cairo_boxes_t       *boxes)
130 {
131     cairo_gl_composite_t setup;
132     cairo_gl_context_t *ctx;
133     cairo_int_status_t status;
134
135     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
136     if (unlikely (status))
137         goto FAIL;
138
139    _cairo_gl_composite_set_solid_source (&setup, color);
140
141     status = _cairo_gl_composite_begin (&setup, &ctx);
142     if (unlikely (status))
143         goto FAIL;
144
145     emit_aligned_boxes (ctx, boxes);
146     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
147
148 FAIL:
149     _cairo_gl_composite_fini (&setup);
150     return status;
151 }
152
153 static cairo_int_status_t
154 composite_boxes (void                   *_dst,
155                  cairo_operator_t       op,
156                  cairo_surface_t        *abstract_src,
157                  cairo_surface_t        *abstract_mask,
158                  int                    src_x,
159                  int                    src_y,
160                  int                    mask_x,
161                  int                    mask_y,
162                  int                    dst_x,
163                  int                    dst_y,
164                  cairo_boxes_t          *boxes,
165                  const cairo_rectangle_int_t  *extents)
166 {
167     cairo_gl_composite_t setup;
168     cairo_gl_context_t *ctx;
169     cairo_int_status_t status;
170
171     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
172     if (unlikely (status))
173         goto FAIL;
174
175     _cairo_gl_composite_set_source_operand (&setup,
176                                             source_to_operand (abstract_src));
177
178     _cairo_gl_composite_set_mask_operand (&setup,
179                                           source_to_operand (abstract_mask));
180
181     status = _cairo_gl_composite_begin (&setup, &ctx);
182     if (unlikely (status))
183         goto FAIL;
184
185     emit_aligned_boxes (ctx, boxes);
186     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
187
188 FAIL:
189     _cairo_gl_composite_fini (&setup);
190     return status;
191 }
192
193 static cairo_int_status_t
194 composite (void                 *_dst,
195            cairo_operator_t     op,
196            cairo_surface_t      *abstract_src,
197            cairo_surface_t      *abstract_mask,
198            int                  src_x,
199            int                  src_y,
200            int                  mask_x,
201            int                  mask_y,
202            int                  dst_x,
203            int                  dst_y,
204            unsigned int         width,
205            unsigned int         height)
206 {
207     cairo_gl_composite_t setup;
208     cairo_gl_context_t *ctx;
209     cairo_int_status_t status;
210
211     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
212     if (unlikely (status))
213         goto FAIL;
214
215     _cairo_gl_composite_set_source_operand (&setup,
216                                             source_to_operand (abstract_src));
217
218     _cairo_gl_composite_set_mask_operand (&setup,
219                                           source_to_operand (abstract_mask));
220
221     status = _cairo_gl_composite_begin (&setup, &ctx);
222     if (unlikely (status))
223         goto FAIL;
224
225     /* XXX clip */
226     _cairo_gl_composite_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height, 0);
227     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
228
229 FAIL:
230     _cairo_gl_composite_fini (&setup);
231     return status;
232 }
233
234 static cairo_int_status_t
235 lerp (void                      *dst,
236       cairo_surface_t           *src,
237       cairo_surface_t           *mask,
238       int                       src_x,
239       int                       src_y,
240       int                       mask_x,
241       int                       mask_y,
242       int                       dst_x,
243       int                       dst_y,
244       unsigned int              width,
245       unsigned int              height)
246 {
247     cairo_int_status_t status;
248
249     /* we could avoid some repetition... */
250     status = composite (dst, CAIRO_OPERATOR_DEST_OUT, src, mask,
251                         src_x, src_y,
252                         mask_x, mask_y,
253                         dst_x, dst_y,
254                         width, height);
255     if (unlikely (status))
256         return status;
257
258     status = composite (dst, CAIRO_OPERATOR_ADD, src, mask,
259                         src_x, src_y,
260                         mask_x, mask_y,
261                         dst_x, dst_y,
262                         width, height);
263     if (unlikely (status))
264         return status;
265
266     return CAIRO_STATUS_SUCCESS;
267 }
268
269 static cairo_int_status_t
270 traps_to_operand (void *_dst,
271                   const cairo_rectangle_int_t *extents,
272                   cairo_antialias_t     antialias,
273                   cairo_traps_t         *traps,
274                   cairo_gl_operand_t    *operand)
275 {
276     pixman_format_code_t pixman_format;
277     pixman_image_t *pixman_image;
278     cairo_surface_t *image, *mask;
279     cairo_surface_pattern_t pattern;
280     cairo_status_t status;
281
282     pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1;
283     pixman_image = pixman_image_create_bits (pixman_format,
284                                              extents->width,
285                                              extents->height,
286                                              NULL, 0);
287     if (unlikely (pixman_image == NULL))
288         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
289
290     _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps);
291     image = _cairo_image_surface_create_for_pixman_image (pixman_image,
292                                                           pixman_format);
293     if (unlikely (image->status)) {
294         pixman_image_unref (pixman_image);
295         return image->status;
296     }
297
298     mask = _cairo_surface_create_similar_scratch (_dst,
299                                                   CAIRO_CONTENT_COLOR_ALPHA,
300                                                   extents->width,
301                                                   extents->height);
302     if (unlikely (mask->status)) {
303         cairo_surface_destroy (image);
304         return mask->status;
305     }
306
307     status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
308                                            (cairo_image_surface_t *)image,
309                                            0, 0,
310                                            extents->width, extents->height,
311                                            0, 0);
312     cairo_surface_destroy (image);
313     if (unlikely (status))
314         goto error;
315
316     _cairo_pattern_init_for_surface (&pattern, mask);
317     cairo_matrix_init_translate (&pattern.base.matrix,
318                                  -extents->x, -extents->y);
319     pattern.base.filter = CAIRO_FILTER_NEAREST;
320     pattern.base.extend = CAIRO_EXTEND_NONE;
321     status = _cairo_gl_operand_init (operand, &pattern.base, _dst,
322                                      &_cairo_unbounded_rectangle,
323                                      &_cairo_unbounded_rectangle,
324                                      FALSE);
325     _cairo_pattern_fini (&pattern.base);
326
327     if (unlikely (status))
328         goto error;
329
330     operand->texture.owns_surface = mask;
331     return CAIRO_STATUS_SUCCESS;
332
333 error:
334     cairo_surface_destroy (mask);
335     return status;
336 }
337
338 static cairo_int_status_t
339 composite_traps (void                   *_dst,
340                  cairo_operator_t       op,
341                  cairo_surface_t        *abstract_src,
342                  int                    src_x,
343                  int                    src_y,
344                  int                    dst_x,
345                  int                    dst_y,
346                  const cairo_rectangle_int_t *extents,
347                  cairo_antialias_t      antialias,
348                  cairo_traps_t          *traps)
349 {
350     cairo_gl_composite_t setup;
351     cairo_gl_context_t *ctx;
352     cairo_int_status_t status;
353
354     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
355     if (unlikely (status))
356         goto FAIL;
357
358     _cairo_gl_composite_set_source_operand (&setup,
359                                             source_to_operand (abstract_src));
360     status = traps_to_operand (_dst, extents, antialias, traps, &setup.mask);
361     if (unlikely (status))
362         goto FAIL;
363
364     status = _cairo_gl_composite_begin (&setup, &ctx);
365     if (unlikely (status))
366         goto FAIL;
367
368     /* XXX clip */
369     _cairo_gl_composite_emit_rect (ctx,
370                                    dst_x, dst_y,
371                                    dst_x+extents->width,
372                                    dst_y+extents->height, 0);
373     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
374
375 FAIL:
376     _cairo_gl_composite_fini (&setup);
377     return status;
378 }
379
380 static cairo_gl_surface_t *
381 tristrip_to_surface (void *_dst,
382                   const cairo_rectangle_int_t *extents,
383                   cairo_antialias_t     antialias,
384                   cairo_tristrip_t      *strip)
385 {
386     pixman_format_code_t pixman_format;
387     pixman_image_t *pixman_image;
388     cairo_surface_t *image, *mask;
389     cairo_status_t status;
390
391     pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
392     pixman_image = pixman_image_create_bits (pixman_format,
393                                              extents->width,
394                                              extents->height,
395                                              NULL, 0);
396     if (unlikely (pixman_image == NULL))
397         return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
398
399     _pixman_image_add_tristrip (pixman_image, extents->x, extents->y, strip);
400     image = _cairo_image_surface_create_for_pixman_image (pixman_image,
401                                                           pixman_format);
402     if (unlikely (image->status)) {
403         pixman_image_unref (pixman_image);
404         return (cairo_gl_surface_t *)image;
405     }
406
407     mask = _cairo_surface_create_similar_scratch (_dst,
408                                                   CAIRO_CONTENT_COLOR_ALPHA,
409                                                   extents->width,
410                                                   extents->height);
411     if (unlikely (mask->status)) {
412         cairo_surface_destroy (image);
413         return (cairo_gl_surface_t *)mask;
414     }
415
416     status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
417                                            (cairo_image_surface_t *)image,
418                                            0, 0,
419                                            extents->width, extents->height,
420                                            0, 0);
421     cairo_surface_destroy (image);
422     if (unlikely (status)) {
423         cairo_surface_destroy (mask);
424         return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
425     }
426
427     return (cairo_gl_surface_t*)mask;
428 }
429
430 static cairo_int_status_t
431 composite_tristrip (void                *_dst,
432                     cairo_operator_t    op,
433                     cairo_surface_t     *abstract_src,
434                     int                 src_x,
435                     int                 src_y,
436                     int                 dst_x,
437                     int                 dst_y,
438                     const cairo_rectangle_int_t *extents,
439                     cairo_antialias_t   antialias,
440                     cairo_tristrip_t    *strip)
441 {
442     cairo_gl_composite_t setup;
443     cairo_gl_context_t *ctx;
444     cairo_gl_surface_t *mask;
445     cairo_int_status_t status;
446
447     mask = tristrip_to_surface (_dst, extents, antialias, strip);
448     if (unlikely (mask->base.status))
449         return mask->base.status;
450
451     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
452     if (unlikely (status))
453         goto FAIL;
454
455     _cairo_gl_composite_set_source_operand (&setup,
456                                             source_to_operand (abstract_src));
457
458     //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
459
460     status = _cairo_gl_composite_begin (&setup, &ctx);
461     if (unlikely (status))
462         goto FAIL;
463
464     /* XXX clip */
465     _cairo_gl_composite_emit_rect (ctx,
466                                    dst_x, dst_y,
467                                    dst_x+extents->width,
468                                    dst_y+extents->height, 0);
469     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
470
471 FAIL:
472     _cairo_gl_composite_fini (&setup);
473     cairo_surface_destroy (&mask->base);
474     return status;
475 }
476
477 static cairo_int_status_t
478 check_composite (const cairo_composite_rectangles_t *extents)
479 {
480     if (! _cairo_gl_operator_is_supported (extents->op))
481         return UNSUPPORTED ("unsupported operator");
482
483     return CAIRO_STATUS_SUCCESS;
484 }
485
486 const cairo_compositor_t *
487 _cairo_gl_traps_compositor_get (void)
488 {
489     static cairo_traps_compositor_t compositor;
490
491     if (compositor.base.delegate == NULL) {
492         _cairo_traps_compositor_init (&compositor, &_cairo_fallback_compositor);
493         compositor.acquire = acquire;
494         compositor.release = release;
495         compositor.set_clip_region = set_clip_region;
496         compositor.pattern_to_surface = _cairo_gl_pattern_to_source;
497         compositor.draw_image_boxes = draw_image_boxes;
498         //compositor.copy_boxes = copy_boxes;
499         compositor.fill_boxes = fill_boxes;
500         compositor.check_composite = check_composite;
501         compositor.composite = composite;
502         compositor.lerp = lerp;
503         //compositor.check_composite_boxes = check_composite_boxes;
504         compositor.composite_boxes = composite_boxes;
505         //compositor.check_composite_traps = check_composite_traps;
506         compositor.composite_traps = composite_traps;
507         //compositor.check_composite_tristrip = check_composite_traps;
508         compositor.composite_tristrip = composite_tristrip;
509         compositor.check_composite_glyphs = _cairo_gl_check_composite_glyphs;
510         compositor.composite_glyphs = _cairo_gl_composite_glyphs;
511     }
512
513     return &compositor.base;
514 }