Fix bug in _cairo_gl_has_extension
[platform/core/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     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;
95
96             status = _cairo_gl_surface_draw_image (dst, image,
97                                                    x + dx, y + dy,
98                                                    w, h,
99                                                    x, y,
100                                                    TRUE);
101             if (unlikely (status))
102                 return status;
103         }
104     }
105
106     return CAIRO_STATUS_SUCCESS;
107 }
108
109 static void
110 emit_aligned_boxes (cairo_gl_context_t *ctx,
111                     const cairo_boxes_t *boxes)
112 {
113     const struct _cairo_boxes_chunk *chunk;
114     cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
115     int i;
116
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);
124         }
125     }
126 }
127
128 static cairo_int_status_t
129 fill_boxes (void                *_dst,
130             cairo_operator_t     op,
131             const cairo_color_t *color,
132             cairo_boxes_t       *boxes)
133 {
134     cairo_gl_composite_t setup;
135     cairo_gl_context_t *ctx;
136     cairo_int_status_t status;
137
138     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
139     if (unlikely (status))
140         goto FAIL;
141
142    _cairo_gl_composite_set_solid_source (&setup, color);
143
144     status = _cairo_gl_composite_begin (&setup, &ctx);
145     if (unlikely (status))
146         goto FAIL;
147
148     emit_aligned_boxes (ctx, boxes);
149     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
150
151 FAIL:
152     _cairo_gl_composite_fini (&setup);
153     return status;
154 }
155
156 static cairo_int_status_t
157 composite_boxes (void                   *_dst,
158                  cairo_operator_t       op,
159                  cairo_surface_t        *abstract_src,
160                  cairo_surface_t        *abstract_mask,
161                  int                    src_x,
162                  int                    src_y,
163                  int                    mask_x,
164                  int                    mask_y,
165                  int                    dst_x,
166                  int                    dst_y,
167                  cairo_boxes_t          *boxes,
168                  const cairo_rectangle_int_t  *extents)
169 {
170     cairo_gl_composite_t setup;
171     cairo_gl_context_t *ctx;
172     cairo_int_status_t status;
173
174     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
175     if (unlikely (status))
176         goto FAIL;
177
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);
181
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);
185
186     status = _cairo_gl_composite_begin (&setup, &ctx);
187     if (unlikely (status))
188         goto FAIL;
189
190     emit_aligned_boxes (ctx, boxes);
191     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
192
193 FAIL:
194     _cairo_gl_composite_fini (&setup);
195     return status;
196 }
197
198 static cairo_int_status_t
199 composite (void                 *_dst,
200            cairo_operator_t     op,
201            cairo_surface_t      *abstract_src,
202            cairo_surface_t      *abstract_mask,
203            int                  src_x,
204            int                  src_y,
205            int                  mask_x,
206            int                  mask_y,
207            int                  dst_x,
208            int                  dst_y,
209            unsigned int         width,
210            unsigned int         height)
211 {
212     cairo_gl_composite_t setup;
213     cairo_gl_context_t *ctx;
214     cairo_int_status_t status;
215     cairo_gl_operand_t *temp_operand = NULL;
216
217     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
218     if (unlikely (status))
219         goto FAIL;
220
221     temp_operand = source_to_operand (abstract_src);
222     if (temp_operand == NULL) {
223         status = CAIRO_STATUS_NULL_POINTER;
224         goto FAIL;
225     }
226
227     _cairo_gl_composite_set_source_operand (&setup, temp_operand);
228     _cairo_gl_operand_translate (&setup.src, dst_x-src_x, dst_y-src_y);
229
230     _cairo_gl_composite_set_mask_operand (&setup,
231                                           source_to_operand (abstract_mask));
232     _cairo_gl_operand_translate (&setup.mask, dst_x-mask_x, dst_y-mask_y);
233
234     status = _cairo_gl_composite_begin (&setup, &ctx);
235     if (unlikely (status))
236         goto FAIL;
237
238     /* XXX clip */
239     _cairo_gl_context_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height);
240     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
241
242 FAIL:
243     _cairo_gl_composite_fini (&setup);
244     return status;
245 }
246
247 static cairo_int_status_t
248 lerp (void                      *dst,
249       cairo_surface_t           *src,
250       cairo_surface_t           *mask,
251       int                       src_x,
252       int                       src_y,
253       int                       mask_x,
254       int                       mask_y,
255       int                       dst_x,
256       int                       dst_y,
257       unsigned int              width,
258       unsigned int              height)
259 {
260     cairo_int_status_t status;
261
262     /* we could avoid some repetition... */
263     status = composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
264                         mask_x, mask_y,
265                         0, 0,
266                         dst_x, dst_y,
267                         width, height);
268     if (unlikely (status))
269         return status;
270
271     status = composite (dst, CAIRO_OPERATOR_ADD, src, mask,
272                         src_x, src_y,
273                         mask_x, mask_y,
274                         dst_x, dst_y,
275                         width, height);
276     if (unlikely (status))
277         return status;
278
279     return CAIRO_STATUS_SUCCESS;
280 }
281
282 static cairo_int_status_t
283 lerp_color_glyph (void                  *dst,
284                   cairo_surface_t       *src,
285                   cairo_surface_t       *mask,
286                   int                   src_x,
287                   int                   src_y,
288                   int                   mask_x,
289                   int                   mask_y,
290                   int                   dst_x,
291                   int                   dst_y,
292                   unsigned int          width,
293       unsigned int              height)
294 {
295     cairo_int_status_t status;
296
297     /* we could avoid some repetition... */
298     status = composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, src,
299                         mask_x, mask_y,
300                         0, 0,
301                         dst_x, dst_y,
302                         width, height);
303     if (unlikely (status))
304         return status;
305
306     status = composite (dst, CAIRO_OPERATOR_ADD, src, mask,
307                         src_x, src_y,
308                         mask_x, mask_y,
309                         dst_x, dst_y,
310                         width, height);
311     if (unlikely (status))
312         return status;
313
314     return CAIRO_STATUS_SUCCESS;
315 }
316
317 static cairo_int_status_t
318 traps_to_operand (void *_dst,
319                   const cairo_rectangle_int_t *extents,
320                   cairo_antialias_t     antialias,
321                   cairo_traps_t         *traps,
322                   cairo_gl_operand_t    *operand,
323                   int dst_x, int dst_y)
324 {
325     pixman_format_code_t pixman_format;
326     pixman_image_t *pixman_image;
327     cairo_surface_t *image, *mask;
328     cairo_surface_pattern_t pattern;
329     cairo_status_t status;
330
331     pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1;
332     pixman_image = pixman_image_create_bits (pixman_format,
333                                              extents->width,
334                                              extents->height,
335                                              NULL, 0);
336     if (unlikely (pixman_image == NULL))
337         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
338
339     _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps);
340     image = _cairo_image_surface_create_for_pixman_image (pixman_image,
341                                                           pixman_format);
342     if (unlikely (image->status)) {
343         pixman_image_unref (pixman_image);
344         status = image->status;
345         cairo_surface_destroy (image);
346         return status;
347     }
348
349     mask = _cairo_surface_create_scratch (_dst,
350                                           CAIRO_CONTENT_COLOR_ALPHA,
351                                           extents->width,
352                                           extents->height,
353                                           NULL);
354     
355     if (unlikely (mask->status)) {
356         cairo_surface_destroy (image);
357         return mask->status;
358     }
359
360     status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
361                                            (cairo_image_surface_t *)image,
362                                            0, 0,
363                                            extents->width, extents->height,
364                                            0, 0,
365                                            TRUE);
366     cairo_surface_destroy (image);
367
368     if (unlikely (status))
369         goto error;
370
371     _cairo_pattern_init_for_surface (&pattern, mask);
372     cairo_matrix_init_translate (&pattern.base.matrix,
373                                  -extents->x+dst_x, -extents->y+dst_y);
374     pattern.base.filter = CAIRO_FILTER_NEAREST;
375     pattern.base.extend = CAIRO_EXTEND_NONE;
376     status = _cairo_gl_operand_init (operand, &pattern.base, _dst,
377                                      &_cairo_unbounded_rectangle,
378                                      &_cairo_unbounded_rectangle,
379                                      FALSE, FALSE);
380     _cairo_pattern_fini (&pattern.base);
381
382     if (unlikely (status))
383         goto error;
384
385     operand->texture.owns_surface = (cairo_gl_surface_t *)mask;
386     return CAIRO_STATUS_SUCCESS;
387
388 error:
389     cairo_surface_destroy (mask);
390     return status;
391 }
392
393 static cairo_int_status_t
394 composite_traps (void                   *_dst,
395                  cairo_operator_t       op,
396                  cairo_surface_t        *abstract_src,
397                  int                    src_x,
398                  int                    src_y,
399                  int                    dst_x,
400                  int                    dst_y,
401                  const cairo_rectangle_int_t *extents,
402                  cairo_antialias_t      antialias,
403                  cairo_traps_t          *traps)
404 {
405     cairo_gl_composite_t setup;
406     cairo_gl_context_t *ctx;
407     cairo_int_status_t status;
408     cairo_surface_t *src = (cairo_surface_t *) abstract_src;
409     cairo_surface_t *dst = (cairo_surface_t *) _dst;
410     cairo_surface_t *new_surface = NULL;
411     cairo_surface_t *new_src = (cairo_surface_t *) abstract_src;
412     int new_src_x, new_src_y;
413     cairo_surface_pattern_t new_surface_pattern;
414
415     if (dst == src) {
416         new_surface = _cairo_surface_create_similar_scratch (src,
417                                                              src->content,
418                                                              extents->width,
419                                                              extents->height);
420         status = new_surface->status;
421         if (unlikely (status)) {
422             cairo_surface_destroy (new_surface);
423             return status;
424         }
425
426         _cairo_pattern_init_for_surface (&new_surface_pattern, src);
427         new_surface_pattern.base.extend = CAIRO_EXTEND_NONE;
428         new_surface_pattern.base.filter = CAIRO_FILTER_NEAREST;
429         status = _cairo_surface_paint (new_surface, CAIRO_OPERATOR_SOURCE,
430                                        &new_surface_pattern.base, NULL);
431
432         if (unlikely (status)) {
433             _cairo_pattern_fini (&new_surface_pattern.base);
434             cairo_surface_destroy (new_surface);
435             return status;
436         }
437
438         new_src = _cairo_gl_pattern_to_source (dst,
439                                                &new_surface_pattern.base,
440                                                FALSE,
441                                                extents, extents,
442                                                &new_src_x, &new_src_y);
443     }
444
445     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
446     if (unlikely (status))
447         goto FAIL;
448
449     _cairo_gl_composite_set_source_operand (&setup,
450                                             source_to_operand (new_src));
451     if (src == new_src)
452         _cairo_gl_operand_translate (&setup.src, -src_x-dst_x, -src_y-dst_y);
453     status = traps_to_operand (_dst, extents, antialias, traps, &setup.mask, dst_x, dst_y);
454     if (unlikely (status))
455         goto FAIL;
456
457     status = _cairo_gl_composite_begin (&setup, &ctx);
458     if (unlikely (status))
459         goto FAIL;
460
461     /* XXX clip */
462     _cairo_gl_context_emit_rect (ctx,
463                                  extents->x-dst_x, extents->y-dst_y,
464                                  extents->x-dst_x+extents->width,
465                                  extents->y-dst_y+extents->height);
466     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
467
468 FAIL:
469     _cairo_gl_composite_fini (&setup);
470
471     if (new_src != src) {
472         cairo_surface_destroy (new_src);
473         cairo_surface_destroy (new_surface);
474         _cairo_pattern_fini (&new_surface_pattern.base);
475     }
476         
477     return status;
478 }
479
480 static cairo_gl_surface_t *
481 tristrip_to_surface (void *_dst,
482                   const cairo_rectangle_int_t *extents,
483                   cairo_antialias_t     antialias,
484                   cairo_tristrip_t      *strip)
485 {
486     pixman_format_code_t pixman_format;
487     pixman_image_t *pixman_image;
488     cairo_surface_t *image, *mask;
489     cairo_status_t status;
490
491     pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
492     pixman_image = pixman_image_create_bits (pixman_format,
493                                              extents->width,
494                                              extents->height,
495                                              NULL, 0);
496     if (unlikely (pixman_image == NULL))
497         return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
498
499     _pixman_image_add_tristrip (pixman_image, extents->x, extents->y, strip);
500     image = _cairo_image_surface_create_for_pixman_image (pixman_image,
501                                                           pixman_format);
502     if (unlikely (image->status)) {
503         pixman_image_unref (pixman_image);
504         return (cairo_gl_surface_t *)image;
505     }
506
507     mask = _cairo_surface_create_scratch (_dst,
508                                           CAIRO_CONTENT_COLOR_ALPHA,
509                                           extents->width,
510                                           extents->height,
511                                           NULL);
512     if (unlikely (mask->status)) {
513         cairo_surface_destroy (image);
514         return (cairo_gl_surface_t *)mask;
515     }
516
517     status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
518                                            (cairo_image_surface_t *)image,
519                                            0, 0,
520                                            extents->width, extents->height,
521                                            0, 0,
522                                            TRUE);
523     cairo_surface_destroy (image);
524     if (unlikely (status)) {
525         cairo_surface_destroy (mask);
526         return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
527     }
528
529     return (cairo_gl_surface_t*)mask;
530 }
531
532 static cairo_int_status_t
533 composite_tristrip (void                *_dst,
534                     cairo_operator_t    op,
535                     cairo_surface_t     *abstract_src,
536                     int                 src_x,
537                     int                 src_y,
538                     int                 dst_x,
539                     int                 dst_y,
540                     const cairo_rectangle_int_t *extents,
541                     cairo_antialias_t   antialias,
542                     cairo_tristrip_t    *strip)
543 {
544     cairo_gl_composite_t setup;
545     cairo_gl_context_t *ctx;
546     cairo_gl_surface_t *mask;
547     cairo_int_status_t status;
548     cairo_gl_operand_t *temp_operand = NULL;
549
550     mask = tristrip_to_surface (_dst, extents, antialias, strip);
551     if (unlikely (mask->base.status)) {
552         status = mask->base.status;
553         cairo_surface_destroy (&mask->base);
554         return status;
555     }
556
557     status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
558     if (unlikely (status))
559         goto FAIL;
560
561     temp_operand = source_to_operand (abstract_src);
562     if (temp_operand == NULL) {
563         status = CAIRO_STATUS_NULL_POINTER;
564         goto FAIL;
565     }
566     _cairo_gl_composite_set_source_operand (&setup,
567                                             temp_operand);
568
569     //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
570
571     status = _cairo_gl_composite_begin (&setup, &ctx);
572     if (unlikely (status))
573         goto FAIL;
574
575     /* XXX clip */
576     _cairo_gl_context_emit_rect (ctx,
577                                  dst_x, dst_y,
578                                  dst_x+extents->width,
579                                  dst_y+extents->height);
580     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
581
582 FAIL:
583     _cairo_gl_composite_fini (&setup);
584     cairo_surface_destroy (&mask->base);
585     return status;
586 }
587
588 static cairo_int_status_t
589 check_composite (const cairo_composite_rectangles_t *extents)
590 {
591     if (! _cairo_gl_operator_is_supported (extents->op))
592         return UNSUPPORTED ("unsupported operator");
593
594     return CAIRO_STATUS_SUCCESS;
595 }
596
597 const cairo_compositor_t *
598 _cairo_gl_traps_compositor_get (void)
599 {
600     static cairo_traps_compositor_t compositor;
601
602     if (compositor.base.delegate == NULL) {
603         _cairo_traps_compositor_init (&compositor, &_cairo_fallback_compositor);
604         compositor.acquire = acquire;
605         compositor.release = release;
606         compositor.set_clip_region = set_clip_region;
607         compositor.pattern_to_surface = _cairo_gl_pattern_to_source;
608         compositor.draw_image_boxes = draw_image_boxes;
609         //compositor.copy_boxes = copy_boxes;
610         compositor.fill_boxes = fill_boxes;
611         compositor.check_composite = check_composite;
612         compositor.composite = composite;
613         compositor.lerp = lerp;
614         // FIXME:
615         compositor.lerp_color_glyph = lerp_color_glyph;
616         //compositor.check_composite_boxes = check_composite_boxes;
617         compositor.composite_boxes = composite_boxes;
618         //compositor.check_composite_traps = check_composite_traps;
619         compositor.composite_traps = composite_traps;
620         //compositor.check_composite_tristrip = check_composite_traps;
621         compositor.composite_tristrip = composite_tristrip;
622         compositor.check_composite_glyphs = _cairo_gl_check_composite_glyphs;
623         compositor.composite_glyphs = _cairo_gl_composite_glyphs;
624     }
625
626     return &compositor.base;
627 }