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