Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-gl-surface-legacy.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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it either under the terms of the GNU Lesser General Public
9  * License version 2.1 as published by the Free Software Foundation
10  * (the "LGPL") or, at your option, under the terms of the Mozilla
11  * Public License Version 1.1 (the "MPL"). If you do not alter this
12  * notice, a recipient may use your version of this file under either
13  * the MPL or the LGPL.
14  *
15  * You should have received a copy of the LGPL along with this library
16  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18  * You should have received a copy of the MPL along with this library
19  * in the file COPYING-MPL-1.1
20  *
21  * The contents of this file are subject to the Mozilla Public License
22  * Version 1.1 (the "License"); you may not use this file except in
23  * compliance with the License. You may obtain a copy of the License at
24  * http://www.mozilla.org/MPL/
25  *
26  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28  * the specific language governing rights and limitations.
29  *
30  * The Original Code is the cairo graphics library.
31  *
32  * The Initial Developer of the Original Code is Red Hat, Inc.
33  *
34  * Contributor(s):
35  *      Benjamin Otte <otte@gnome.org>
36  *      Carl Worth <cworth@cworth.org>
37  *      Chris Wilson <chris@chris-wilson.co.uk>
38  *      Eric Anholt <eric@anholt.net>
39  */
40
41 #include "cairoint.h"
42
43 #include "cairo-composite-rectangles-private.h"
44 #include "cairo-default-context-private.h"
45 #include "cairo-error-private.h"
46 #include "cairo-gl-private.h"
47 #include "cairo-image-surface-inline.h"
48
49 cairo_status_t
50 _cairo_gl_surface_acquire_dest_image (void                    *abstract_surface,
51                                       cairo_rectangle_int_t   *interest_rect,
52                                       cairo_image_surface_t  **image_out,
53                                       cairo_rectangle_int_t   *image_rect_out,
54                                       void                   **image_extra)
55 {
56     cairo_gl_surface_t *surface = abstract_surface;
57     cairo_int_status_t status;
58
59     status = _cairo_gl_surface_deferred_clear (surface);
60     if (unlikely (status))
61         return status;
62
63     *image_extra = NULL;
64     return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
65                                         image_rect_out);
66 }
67
68 void
69 _cairo_gl_surface_release_dest_image (void                    *abstract_surface,
70                                       cairo_rectangle_int_t   *interest_rect,
71                                       cairo_image_surface_t   *image,
72                                       cairo_rectangle_int_t   *image_rect,
73                                       void                    *image_extra)
74 {
75     cairo_status_t status;
76
77     status = _cairo_gl_surface_draw_image (abstract_surface, image,
78                                            0, 0,
79                                            image->width, image->height,
80                                            image_rect->x, image_rect->y);
81     /* as we created the image, its format should be directly applicable */
82     assert (status == CAIRO_STATUS_SUCCESS);
83
84     cairo_surface_destroy (&image->base);
85 }
86
87 cairo_status_t
88 _cairo_gl_surface_clone_similar (void                *abstract_surface,
89                                  cairo_surface_t     *src,
90                                  int                  src_x,
91                                  int                  src_y,
92                                  int                  width,
93                                  int                  height,
94                                  int                 *clone_offset_x,
95                                  int                 *clone_offset_y,
96                                  cairo_surface_t    **clone_out)
97 {
98     cairo_gl_surface_t *surface = abstract_surface;
99     cairo_int_status_t status;
100
101     /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */
102     if (src->device == surface->base.device &&
103         _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) {
104         status = _cairo_gl_surface_deferred_clear ((cairo_gl_surface_t *)src);
105         if (unlikely (status))
106             return status;
107
108         *clone_offset_x = 0;
109         *clone_offset_y = 0;
110         *clone_out = cairo_surface_reference (src);
111
112         return CAIRO_STATUS_SUCCESS;
113     } else if (_cairo_surface_is_image (src)) {
114         cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
115         cairo_gl_surface_t *clone;
116
117         clone = (cairo_gl_surface_t *)
118                 _cairo_gl_surface_create_similar (&surface->base,
119                                                   src->content,
120                                                   width, height);
121         if (clone == NULL)
122             return UNSUPPORTED ("create_similar failed");
123         if (clone->base.status)
124             return clone->base.status;
125
126         status = _cairo_gl_surface_draw_image (clone, image_src,
127                                                src_x, src_y,
128                                                width, height,
129                                                0, 0);
130         if (status) {
131             cairo_surface_destroy (&clone->base);
132             return status;
133         }
134
135         *clone_out = &clone->base;
136         *clone_offset_x = src_x;
137         *clone_offset_y = src_y;
138
139         return CAIRO_STATUS_SUCCESS;
140     }
141
142     return UNSUPPORTED ("unknown src surface type in clone_similar");
143 }
144
145 /* Creates a cairo-gl pattern surface for the given trapezoids */
146 static cairo_status_t
147 _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
148                              int dst_x, int dst_y,
149                              int width, int height,
150                              cairo_trapezoid_t *traps,
151                              int num_traps,
152                              cairo_antialias_t antialias,
153                              cairo_surface_pattern_t *pattern)
154 {
155     pixman_format_code_t pixman_format;
156     pixman_image_t *image;
157     cairo_surface_t *surface;
158     int i;
159
160     pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
161     image = pixman_image_create_bits (pixman_format, width, height, NULL, 0);
162     if (unlikely (image == NULL))
163         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
164
165     for (i = 0; i < num_traps; i++) {
166         pixman_trapezoid_t trap;
167
168         trap.top = _cairo_fixed_to_16_16 (traps[i].top);
169         trap.bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
170
171         trap.left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
172         trap.left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
173         trap.left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
174         trap.left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
175
176         trap.right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
177         trap.right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
178         trap.right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
179         trap.right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
180
181         pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
182     }
183
184     surface = _cairo_image_surface_create_for_pixman_image (image,
185                                                             pixman_format);
186     if (unlikely (surface->status)) {
187         pixman_image_unref (image);
188         return surface->status;
189     }
190
191     _cairo_pattern_init_for_surface (pattern, surface);
192     cairo_surface_destroy (surface);
193
194     return CAIRO_STATUS_SUCCESS;
195 }
196
197 cairo_int_status_t
198 _cairo_gl_surface_composite (cairo_operator_t             op,
199                              const cairo_pattern_t       *src,
200                              const cairo_pattern_t       *mask,
201                              void                        *abstract_dst,
202                              int                          src_x,
203                              int                          src_y,
204                              int                          mask_x,
205                              int                          mask_y,
206                              int                          dst_x,
207                              int                          dst_y,
208                              unsigned int                 width,
209                              unsigned int                 height,
210                              cairo_region_t              *clip_region)
211 {
212     cairo_gl_surface_t *dst = abstract_dst;
213     cairo_gl_context_t *ctx;
214     cairo_status_t status;
215     cairo_gl_composite_t setup;
216     cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
217     int dx, dy;
218
219     status = _cairo_gl_surface_deferred_clear (dst);
220     if (unlikely (status))
221             return status;
222
223     if (op == CAIRO_OPERATOR_SOURCE &&
224         mask == NULL &&
225         src->type == CAIRO_PATTERN_TYPE_SURFACE &&
226         _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) &&
227         _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) {
228         cairo_image_surface_t *image = (cairo_image_surface_t *)
229             ((cairo_surface_pattern_t *) src)->surface;
230         dx += src_x;
231         dy += src_y;
232         if (dx >= 0 &&
233             dy >= 0 &&
234             dx + width <= (unsigned int) image->width &&
235             dy + height <= (unsigned int) image->height) {
236             status = _cairo_gl_surface_draw_image (dst, image,
237                                                    dx, dy,
238                                                    width, height,
239                                                    dst_x, dst_y);
240             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
241                 return status;
242         }
243     }
244
245     status = _cairo_gl_composite_init (&setup, op, dst,
246                                        mask && mask->has_component_alpha,
247                                        &rect);
248     if (unlikely (status))
249         goto CLEANUP;
250
251     status = _cairo_gl_composite_set_source (&setup, src,
252                                              src_x, src_y,
253                                              dst_x, dst_y,
254                                              width, height,
255                                              FALSE);
256     if (unlikely (status))
257         goto CLEANUP;
258
259     status = _cairo_gl_composite_set_mask (&setup, mask,
260                                            mask_x, mask_y,
261                                            dst_x, dst_y,
262                                            width, height);
263     if (unlikely (status))
264         goto CLEANUP;
265
266     status = _cairo_gl_composite_begin (&setup, &ctx);
267     if (unlikely (status))
268         goto CLEANUP;
269
270     if (clip_region != NULL) {
271         int i, num_rectangles;
272
273         num_rectangles = cairo_region_num_rectangles (clip_region);
274
275         for (i = 0; i < num_rectangles; i++) {
276             cairo_rectangle_int_t rect;
277
278             cairo_region_get_rectangle (clip_region, i, &rect);
279             _cairo_gl_composite_emit_rect (ctx,
280                                            rect.x,              rect.y,
281                                            rect.x + rect.width, rect.y + rect.height,
282                                            0);
283         }
284     } else {
285         _cairo_gl_composite_emit_rect (ctx,
286                                        dst_x,         dst_y,
287                                        dst_x + width, dst_y + height,
288                                        0);
289     }
290
291     status = _cairo_gl_context_release (ctx, status);
292
293   CLEANUP:
294     _cairo_gl_composite_fini (&setup);
295
296     return status;
297 }
298
299 cairo_int_status_t
300 _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
301                                         const cairo_pattern_t *pattern,
302                                         void *abstract_dst,
303                                         cairo_antialias_t antialias,
304                                         int src_x, int src_y,
305                                         int dst_x, int dst_y,
306                                         unsigned int width,
307                                         unsigned int height,
308                                         cairo_trapezoid_t *traps,
309                                         int num_traps,
310                                         cairo_region_t *clip_region)
311 {
312     cairo_gl_surface_t *dst = abstract_dst;
313     cairo_surface_pattern_t traps_pattern;
314     cairo_int_status_t status;
315
316     if (! _cairo_gl_operator_is_supported (op))
317         return UNSUPPORTED ("unsupported operator");
318
319     status = _cairo_gl_surface_deferred_clear (dst);
320     if (unlikely (status))
321             return status;
322
323     status = _cairo_gl_get_traps_pattern (dst,
324                                           dst_x, dst_y, width, height,
325                                           traps, num_traps, antialias,
326                                           &traps_pattern);
327     if (unlikely (status))
328         return status;
329
330     status = _cairo_gl_surface_composite (op,
331                                           pattern, &traps_pattern.base, dst,
332                                           src_x, src_y,
333                                           0, 0,
334                                           dst_x, dst_y,
335                                           width, height,
336                                           clip_region);
337
338     _cairo_pattern_fini (&traps_pattern.base);
339
340     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
341     return status;
342 }
343
344 cairo_int_status_t
345 _cairo_gl_surface_fill_rectangles (void                    *abstract_dst,
346                                    cairo_operator_t         op,
347                                    const cairo_color_t     *color,
348                                    cairo_rectangle_int_t   *rects,
349                                    int                      num_rects)
350 {
351     cairo_gl_surface_t *dst = abstract_dst;
352     cairo_solid_pattern_t solid;
353     cairo_gl_context_t *ctx;
354     cairo_status_t status;
355     cairo_gl_composite_t setup;
356     int i;
357
358     status = _cairo_gl_surface_deferred_clear (dst);
359     if (unlikely (status))
360             return status;
361
362     status = _cairo_gl_composite_init (&setup, op, dst,
363                                        FALSE,
364                                        /* XXX */ NULL);
365     if (unlikely (status))
366         goto CLEANUP;
367
368     _cairo_pattern_init_solid (&solid, color);
369     status = _cairo_gl_composite_set_source (&setup, &solid.base,
370                                              0, 0,
371                                              0, 0,
372                                              0, 0,
373                                              FALSE);
374     if (unlikely (status))
375         goto CLEANUP;
376
377     status = _cairo_gl_composite_set_mask (&setup, NULL,
378                                            0, 0,
379                                            0, 0,
380                                            0, 0);
381     if (unlikely (status))
382         goto CLEANUP;
383
384     status = _cairo_gl_composite_begin (&setup, &ctx);
385     if (unlikely (status))
386         goto CLEANUP;
387
388     for (i = 0; i < num_rects; i++) {
389         _cairo_gl_composite_emit_rect (ctx,
390                                        rects[i].x,
391                                        rects[i].y,
392                                        rects[i].x + rects[i].width,
393                                        rects[i].y + rects[i].height,
394                                        0);
395     }
396
397     status = _cairo_gl_context_release (ctx, status);
398
399   CLEANUP:
400     _cairo_gl_composite_fini (&setup);
401
402     return status;
403 }
404
405 typedef struct _cairo_gl_surface_span_renderer {
406     cairo_span_renderer_t base;
407
408     cairo_gl_composite_t setup;
409
410     int xmin, xmax;
411     int ymin, ymax;
412
413     cairo_gl_context_t *ctx;
414 } cairo_gl_surface_span_renderer_t;
415
416 static cairo_status_t
417 _cairo_gl_render_bounded_spans (void *abstract_renderer,
418                                 int y, int height,
419                                 const cairo_half_open_span_t *spans,
420                                 unsigned num_spans)
421 {
422     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
423
424     if (num_spans == 0)
425         return CAIRO_STATUS_SUCCESS;
426
427     do {
428         if (spans[0].coverage) {
429             _cairo_gl_composite_emit_rect (renderer->ctx,
430                                            spans[0].x, y,
431                                            spans[1].x, y + height,
432                                            spans[0].coverage);
433         }
434
435         spans++;
436     } while (--num_spans > 1);
437
438     return CAIRO_STATUS_SUCCESS;
439 }
440
441 static cairo_status_t
442 _cairo_gl_render_unbounded_spans (void *abstract_renderer,
443                                   int y, int height,
444                                   const cairo_half_open_span_t *spans,
445                                   unsigned num_spans)
446 {
447     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
448
449     if (y > renderer->ymin) {
450         _cairo_gl_composite_emit_rect (renderer->ctx,
451                                        renderer->xmin, renderer->ymin,
452                                        renderer->xmax, y,
453                                        0);
454     }
455
456     if (num_spans == 0) {
457         _cairo_gl_composite_emit_rect (renderer->ctx,
458                                        renderer->xmin, y,
459                                        renderer->xmax, y + height,
460                                        0);
461     } else {
462         if (spans[0].x != renderer->xmin) {
463             _cairo_gl_composite_emit_rect (renderer->ctx,
464                                            renderer->xmin, y,
465                                            spans[0].x,     y + height,
466                                            0);
467         }
468
469         do {
470             _cairo_gl_composite_emit_rect (renderer->ctx,
471                                            spans[0].x, y,
472                                            spans[1].x, y + height,
473                                            spans[0].coverage);
474             spans++;
475         } while (--num_spans > 1);
476
477         if (spans[0].x != renderer->xmax) {
478             _cairo_gl_composite_emit_rect (renderer->ctx,
479                                            spans[0].x,     y,
480                                            renderer->xmax, y + height,
481                                            0);
482         }
483     }
484
485     renderer->ymin = y + height;
486     return CAIRO_STATUS_SUCCESS;
487 }
488
489 static cairo_status_t
490 _cairo_gl_finish_unbounded_spans (void *abstract_renderer)
491 {
492     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
493
494     if (renderer->ymax > renderer->ymin) {
495         _cairo_gl_composite_emit_rect (renderer->ctx,
496                                        renderer->xmin, renderer->ymin,
497                                        renderer->xmax, renderer->ymax,
498                                        0);
499     }
500
501     return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
502 }
503
504 static cairo_status_t
505 _cairo_gl_finish_bounded_spans (void *abstract_renderer)
506 {
507     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
508
509     return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
510 }
511
512 static void
513 _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
514 {
515     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
516
517     if (!renderer)
518         return;
519
520     _cairo_gl_composite_fini (&renderer->setup);
521
522     free (renderer);
523 }
524
525 cairo_bool_t
526 _cairo_gl_surface_check_span_renderer (cairo_operator_t        op,
527                                        const cairo_pattern_t  *pattern,
528                                        void                   *abstract_dst,
529                                        cairo_antialias_t       antialias)
530 {
531     if (! _cairo_gl_operator_is_supported (op))
532         return FALSE;
533
534     return TRUE;
535
536     (void) pattern;
537     (void) abstract_dst;
538     (void) antialias;
539 }
540
541 cairo_span_renderer_t *
542 _cairo_gl_surface_create_span_renderer (cairo_operator_t         op,
543                                         const cairo_pattern_t   *src,
544                                         void                    *abstract_dst,
545                                         cairo_antialias_t        antialias,
546                                         const cairo_composite_rectangles_t *rects)
547 {
548     cairo_gl_surface_t *dst = abstract_dst;
549     cairo_gl_surface_span_renderer_t *renderer;
550     cairo_status_t status;
551     const cairo_rectangle_int_t *extents;
552
553     status = _cairo_gl_surface_deferred_clear (dst);
554     if (unlikely (status))
555         return _cairo_span_renderer_create_in_error (status);
556
557     renderer = calloc (1, sizeof (*renderer));
558     if (unlikely (renderer == NULL))
559         return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
560
561     renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
562     if (rects->is_bounded) {
563         renderer->base.render_rows = _cairo_gl_render_bounded_spans;
564         renderer->base.finish =      _cairo_gl_finish_bounded_spans;
565         extents = &rects->bounded;
566     } else {
567         renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
568         renderer->base.finish =      _cairo_gl_finish_unbounded_spans;
569         extents = &rects->unbounded;
570     }
571     renderer->xmin = extents->x;
572     renderer->xmax = extents->x + extents->width;
573     renderer->ymin = extents->y;
574     renderer->ymax = extents->y + extents->height;
575
576     status = _cairo_gl_composite_init (&renderer->setup,
577                                        op, dst,
578                                        FALSE, extents);
579     if (unlikely (status))
580         goto FAIL;
581
582     status = _cairo_gl_composite_set_source (&renderer->setup, src,
583                                              extents->x, extents->y,
584                                              extents->x, extents->y,
585                                              extents->width, extents->height,
586                                              FALSE);
587     if (unlikely (status))
588         goto FAIL;
589
590     _cairo_gl_composite_set_spans (&renderer->setup);
591     _cairo_gl_composite_set_clip_region (&renderer->setup,
592                                          _cairo_clip_get_region (rects->clip));
593
594     status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx);
595     if (unlikely (status))
596         goto FAIL;
597
598     return &renderer->base;
599
600 FAIL:
601     _cairo_gl_composite_fini (&renderer->setup);
602     free (renderer);
603     return _cairo_span_renderer_create_in_error (status);
604 }
605