Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-cogl-surface.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2011 Intel Corporation.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it either under the terms of the GNU Lesser General Public
7  * License version 2.1 as published by the Free Software Foundation
8  * (the "LGPL") or, at your option, under the terms of the Mozilla
9  * Public License Version 1.1 (the "MPL"). If you do not alter this
10  * notice, a recipient may use your version of this file under either
11  * the MPL or the LGPL.
12  *
13  * You should have received a copy of the LGPL along with this library
14  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16  * You should have received a copy of the MPL along with this library
17  * in the file COPYING-MPL-1.1
18  *
19  * The contents of this file are subject to the Mozilla Public License
20  * Version 1.1 (the "License"); you may not use this file except in
21  * compliance with the License. You may obtain a copy of the License at
22  * http://www.mozilla.og/MPL/
23  *
24  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26  * the specific language governing rights and limitations.
27  *
28  * Contributor(s):
29  *      Robert Bragg <robert@linux.intel.com>
30  */
31 #include "cairoint.h"
32
33 #include "cairo-cache-private.h"
34 #include "cairo-error-private.h"
35 #include "cairo-path-fixed-private.h"
36 #include "cairo-recording-surface-private.h"
37 #include "cairo-surface-clipper-private.h"
38 #include "cairo-fixed-private.h"
39 #include "cairo-device-private.h"
40 #include "cairo-composite-rectangles-private.h"
41 #include "cairo-image-surface-inline.h"
42 #include "cairo-cogl-private.h"
43 #include "cairo-cogl-gradient-private.h"
44 #include "cairo-arc-private.h"
45 #include "cairo-traps-private.h"
46 #include "cairo-cogl-context-private.h"
47 #include "cairo-cogl-utils-private.h"
48 #include "cairo-box-inline.h"
49 #include "cairo-surface-subsurface-inline.h"
50 #include "cairo-surface-fallback-private.h"
51 #include "cairo-surface-offset-private.h"
52
53 #include "cairo-cogl.h"
54
55 #include <cogl/cogl2-experimental.h>
56 #include <glib.h>
57
58 #define CAIRO_COGL_DEBUG 0
59 //#define FILL_WITH_COGL_PATH
60 //#define USE_CAIRO_PATH_FLATTENER
61 #define ENABLE_PATH_CACHE
62 //#define DISABLE_BATCHING
63 #define USE_COGL_RECTANGLE_API
64 #define ENABLE_RECTANGLES_FASTPATH
65
66 #if defined (USE_COGL_RECTANGLE_API) || defined (ENABLE_PATH_CACHE)
67 #define NEED_COGL_CONTEXT
68 #endif
69
70 #if CAIRO_COGL_DEBUG && __GNUC__
71 #define UNSUPPORTED(reason) ({ \
72     g_warning ("cairo-cogl: hit unsupported operation: %s", reason); \
73     CAIRO_INT_STATUS_UNSUPPORTED; \
74 })
75 #else
76 #define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
77 #endif
78
79 #define CAIRO_COGL_PATH_META_CACHE_SIZE (1024 * 1024)
80
81 typedef struct _cairo_cogl_texture_attributes {
82     /* nabbed from cairo_surface_attributes_t... */
83     cairo_matrix_t          matrix;
84     cairo_extend_t          extend;
85     cairo_filter_t          filter;
86     cairo_bool_t            has_component_alpha;
87
88     CoglPipelineWrapMode    s_wrap;
89     CoglPipelineWrapMode    t_wrap;
90 } cairo_cogl_texture_attributes_t;
91
92 typedef enum _cairo_cogl_journal_entry_type {
93     CAIRO_COGL_JOURNAL_ENTRY_TYPE_RECTANGLE,
94     CAIRO_COGL_JOURNAL_ENTRY_TYPE_PRIMITIVE,
95     CAIRO_COGL_JOURNAL_ENTRY_TYPE_PATH,
96     CAIRO_COGL_JOURNAL_ENTRY_TYPE_CLIP
97 } cairo_cogl_journal_entry_type_t;
98
99 typedef struct _cairo_cogl_journal_entry {
100     cairo_cogl_journal_entry_type_t type;
101 } cairo_cogl_journal_entry_t;
102
103 typedef struct _cairo_cogl_journal_clip_entry {
104     cairo_cogl_journal_entry_t base;
105     cairo_clip_t *clip;
106 } cairo_cogl_journal_clip_entry_t;
107
108 typedef struct _cairo_cogl_journal_rect_entry {
109     cairo_cogl_journal_entry_t base;
110     CoglPipeline *pipeline;
111     float x;
112     float y;
113     float width;
114     float height;
115     int n_layers;
116     cairo_matrix_t ctm;
117 } cairo_cogl_journal_rect_entry_t;
118
119 typedef struct _cairo_cogl_journal_prim_entry {
120     cairo_cogl_journal_entry_t base;
121     CoglPipeline *pipeline;
122     CoglPrimitive *primitive;
123     gboolean has_transform;
124     cairo_matrix_t transform;
125 } cairo_cogl_journal_prim_entry_t;
126
127 typedef struct _cairo_cogl_journal_path_entry {
128     cairo_cogl_journal_entry_t base;
129     CoglPipeline *pipeline;
130     CoglPath *path;
131 } cairo_cogl_journal_path_entry_t;
132
133 typedef struct _cairo_cogl_path_fill_meta {
134     cairo_cache_entry_t cache_entry;
135     cairo_reference_count_t ref_count;
136     int counter;
137     cairo_path_fixed_t *user_path;
138     cairo_matrix_t ctm_inverse;
139
140     /* TODO */
141 #if 0
142     /* A cached path tessellation should be re-usable with different rotations
143      * and translations but not for different scales.
144      *
145      * one idea is to track the diagonal lenghts of a unit rectangle
146      * transformed through the original ctm use to tesselate the geometry
147      * so we can check what the lengths are for any new ctm to know if
148      * this geometry is compatible.
149      */
150 #endif
151
152     CoglPrimitive *prim;
153 } cairo_cogl_path_fill_meta_t;
154
155 typedef struct _cairo_cogl_path_stroke_meta {
156     cairo_cache_entry_t cache_entry;
157     cairo_reference_count_t ref_count;
158     int counter;
159     cairo_path_fixed_t *user_path;
160     cairo_matrix_t ctm_inverse;
161     cairo_stroke_style_t style;
162     double tolerance;
163
164     /* TODO */
165 #if 0
166     /* A cached path tessellation should be re-usable with different rotations
167      * and translations but not for different scales.
168      *
169      * one idea is to track the diagonal lenghts of a unit rectangle
170      * transformed through the original ctm use to tesselate the geometry
171      * so we can check what the lengths are for any new ctm to know if
172      * this geometry is compatible.
173      */
174 #endif
175
176     CoglPrimitive *prim;
177 } cairo_cogl_path_stroke_meta_t;
178
179 static cairo_surface_t *
180 _cairo_cogl_surface_create_full (cairo_cogl_device_t *dev,
181                                  cairo_bool_t ignore_alpha,
182                                  CoglFramebuffer *framebuffer,
183                                  CoglTexture *texture);
184
185 static cairo_int_status_t
186 _cairo_cogl_surface_fill (void                      *abstract_surface,
187                           cairo_operator_t           op,
188                           const cairo_pattern_t     *source,
189                           const cairo_path_fixed_t  *path,
190                           cairo_fill_rule_t          fill_rule,
191                           double                     tolerance,
192                           cairo_antialias_t          antialias,
193                           const cairo_clip_t        *clip);
194
195 static void
196 _cairo_cogl_journal_flush (cairo_cogl_surface_t *surface);
197
198 cairo_private extern const cairo_surface_backend_t _cairo_cogl_surface_backend;
199
200 slim_hidden_proto (cairo_cogl_device_create);
201 slim_hidden_proto (cairo_cogl_surface_create);
202 slim_hidden_proto (cairo_cogl_surface_get_framebuffer);
203 slim_hidden_proto (cairo_cogl_surface_get_texture);
204 slim_hidden_proto (cairo_cogl_surface_end_frame);
205
206 static cairo_cogl_device_t *
207 to_device (cairo_device_t *device)
208 {
209     return (cairo_cogl_device_t *)device;
210 }
211
212 /* moves trap points such that they become the actual corners of the trapezoid */
213 static void
214 _sanitize_trap (cairo_trapezoid_t *t)
215 {
216     cairo_trapezoid_t s = *t;
217
218 #define FIX(lr, tb, p) \
219     if (t->lr.p.y != t->tb) { \
220         t->lr.p.x = s.lr.p2.x + _cairo_fixed_mul_div_floor (s.lr.p1.x - s.lr.p2.x, s.tb - s.lr.p2.y, s.lr.p1.y - s.lr.p2.y); \
221         t->lr.p.y = s.tb; \
222     }
223     FIX (left,  top,    p1);
224     FIX (left,  bottom, p2);
225     FIX (right, top,    p1);
226     FIX (right, bottom, p2);
227 }
228
229 static cairo_status_t
230 _cairo_cogl_surface_ensure_framebuffer (cairo_cogl_surface_t *surface)
231 {
232     GError *error = NULL;
233
234     if (surface->framebuffer)
235         return CAIRO_STATUS_SUCCESS;
236
237     surface->framebuffer = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (surface->texture));
238     if (!cogl_framebuffer_allocate (surface->framebuffer, &error)) {
239         g_error_free (error);
240         cogl_object_unref (surface->framebuffer);
241         surface->framebuffer = NULL;
242         return CAIRO_STATUS_NO_MEMORY;
243     }
244
245     cogl_push_framebuffer (surface->framebuffer);
246     cogl_ortho (0, surface->width,
247                 surface->height, 0,
248                 -1, 100);
249     cogl_pop_framebuffer ();
250
251     return CAIRO_STATUS_SUCCESS;
252 }
253
254 static cairo_surface_t *
255 _cairo_cogl_surface_create_similar (void            *abstract_surface,
256                                     cairo_content_t  content,
257                                     int              width,
258                                     int              height)
259 {
260     cairo_cogl_surface_t *reference_surface = abstract_surface;
261     cairo_cogl_surface_t *surface;
262     CoglTexture *texture;
263     cairo_status_t status;
264
265     texture = cogl_texture_new_with_size (width, height,
266                                           COGL_TEXTURE_NO_SLICING,
267                                           (content & CAIRO_CONTENT_COLOR) ?
268                                           COGL_PIXEL_FORMAT_BGRA_8888_PRE :
269                                           COGL_PIXEL_FORMAT_A_8);
270     if (!texture)
271         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
272
273     surface = (cairo_cogl_surface_t *)
274         _cairo_cogl_surface_create_full (to_device(reference_surface->base.device),
275                                          (content & CAIRO_CONTENT_ALPHA) == 0,
276                                          NULL,
277                                          texture);
278     if (unlikely (surface->base.status))
279         return &surface->base;
280
281     status = _cairo_cogl_surface_ensure_framebuffer (surface);
282     if (unlikely (status)) {
283         cairo_surface_destroy (&surface->base);
284         return _cairo_surface_create_in_error (status);
285     }
286
287     return &surface->base;
288 }
289
290 static cairo_bool_t
291 _cairo_cogl_surface_get_extents (void *abstract_surface,
292                                  cairo_rectangle_int_t *extents)
293 {
294     cairo_cogl_surface_t *surface = abstract_surface;
295
296     extents->x = 0;
297     extents->y = 0;
298     extents->width  = surface->width;
299     extents->height = surface->height;
300
301     return TRUE;
302 }
303
304 static void
305 _cairo_cogl_journal_free (cairo_cogl_surface_t *surface)
306 {
307     GList *l;
308
309     for (l = surface->journal->head; l; l = l->next) {
310         cairo_cogl_journal_entry_t *entry = l->data;
311
312         if (entry->type == CAIRO_COGL_JOURNAL_ENTRY_TYPE_PRIMITIVE) {
313             cairo_cogl_journal_prim_entry_t *prim_entry =
314                 (cairo_cogl_journal_prim_entry_t *)entry;
315             cogl_object_unref (prim_entry->primitive);
316         } else if (entry->type == CAIRO_COGL_JOURNAL_ENTRY_TYPE_PATH) {
317             cairo_cogl_journal_path_entry_t *path_entry =
318                 (cairo_cogl_journal_path_entry_t *)entry;
319             cogl_object_unref (path_entry->path);
320         }
321     }
322
323     g_queue_free (surface->journal);
324     surface->journal = NULL;
325 }
326
327 #ifdef FILL_WITH_COGL_PATH
328 static void
329 _cairo_cogl_journal_log_path (cairo_cogl_surface_t *surface,
330                               CoglPipeline *pipeline,
331                               CoglPath *path)
332 {
333     cairo_cogl_journal_path_entry_t *entry;
334
335     if (unlikely (surface->journal == NULL))
336         surface->journal = g_queue_new ();
337
338     /* FIXME: Instead of a GList here we should stack allocate the journal
339      * entries so it would be cheaper to allocate and they can all be freed in
340      * one go after flushing! */
341     entry = g_slice_new (cairo_cogl_journal_path_entry_t);
342     entry->base.type = CAIRO_COGL_JOURNAL_ENTRY_TYPE_PATH;
343
344     entry->pipeline = cogl_object_ref (pipeline);
345     entry->path = cogl_object_ref (path);
346
347     g_queue_push_tail (surface->journal, entry);
348
349 #ifdef DISABLE_BATCHING
350     _cairo_cogl_journal_flush (surface);
351 #endif
352 }
353 #endif /* FILL_WITH_COGL_PATH */
354
355 static void
356 _cairo_cogl_journal_log_primitive (cairo_cogl_surface_t *surface,
357                                    CoglPipeline *pipeline,
358                                    CoglPrimitive *primitive,
359                                    cairo_matrix_t *transform)
360 {
361     cairo_cogl_journal_prim_entry_t *entry;
362
363     if (unlikely (surface->journal == NULL))
364         surface->journal = g_queue_new ();
365
366     /* FIXME: Instead of a GList here we should stack allocate the journal
367      * entries so it would be cheaper to allocate and they can all be freed in
368      * one go after flushing! */
369     entry = g_slice_new (cairo_cogl_journal_prim_entry_t);
370     entry->base.type = CAIRO_COGL_JOURNAL_ENTRY_TYPE_PRIMITIVE;
371
372     entry->pipeline = cogl_object_ref (pipeline);
373
374     if (transform) {
375         entry->transform = *transform;
376         entry->has_transform = TRUE;
377     } else
378         entry->has_transform = FALSE;
379
380     entry->primitive = cogl_object_ref (primitive);
381
382     g_queue_push_tail (surface->journal, entry);
383
384 #ifdef DISABLE_BATCHING
385     _cairo_cogl_journal_flush (surface);
386 #endif
387 }
388
389 static void
390 _cairo_cogl_journal_log_rectangle (cairo_cogl_surface_t *surface,
391                                    CoglPipeline *pipeline,
392                                    float x,
393                                    float y,
394                                    float width,
395                                    float height,
396                                    int n_layers,
397                                    cairo_matrix_t *ctm)
398 {
399     cairo_cogl_journal_rect_entry_t *entry;
400
401     if (unlikely (surface->journal == NULL))
402         surface->journal = g_queue_new ();
403
404     /* FIXME: Instead of a GList here we should stack allocate the journal
405      * entries so it would be cheaper to allocate and they can all be freed in
406      * one go after flushing! */
407     entry = g_slice_new (cairo_cogl_journal_rect_entry_t);
408     entry->base.type = CAIRO_COGL_JOURNAL_ENTRY_TYPE_RECTANGLE;
409
410     entry->pipeline = cogl_object_ref (pipeline);
411
412     entry->x = x;
413     entry->y = y;
414     entry->width = width;
415     entry->height = height;
416     entry->ctm = *ctm;
417
418     entry->n_layers = n_layers;
419
420     g_queue_push_tail (surface->journal, entry);
421
422 #ifdef DISABLE_BATCHING
423     _cairo_cogl_journal_flush (surface);
424 #endif
425 }
426
427 static void
428 _cairo_cogl_journal_log_clip (cairo_cogl_surface_t *surface,
429                               const cairo_clip_t *clip)
430 {
431     cairo_cogl_journal_clip_entry_t *entry;
432
433     if (unlikely (surface->journal == NULL))
434         surface->journal = g_queue_new ();
435
436     /* FIXME: Instead of a GList here we should stack allocate the journal
437      * entries so it would be cheaper to allocate and they can all be freed in
438      * one go after flushing! */
439     entry = g_slice_new (cairo_cogl_journal_clip_entry_t);
440     entry->base.type = CAIRO_COGL_JOURNAL_ENTRY_TYPE_CLIP;
441     entry->clip = _cairo_clip_copy (clip);
442
443     g_queue_push_tail (surface->journal, entry);
444 }
445
446 static void
447 _cairo_cogl_journal_discard (cairo_cogl_surface_t *surface)
448 {
449     GList *l;
450
451     if (!surface->journal) {
452         assert (surface->last_clip == NULL);
453         return;
454     }
455
456     if (surface->buffer_stack && surface->buffer_stack_offset) {
457         cogl_buffer_unmap (COGL_BUFFER (surface->buffer_stack));
458         cogl_object_unref (surface->buffer_stack);
459         surface->buffer_stack = NULL;
460     }
461
462     for (l = surface->journal->head; l; l = l->next) {
463         cairo_cogl_journal_entry_t *entry = l->data;
464         gsize entry_size;
465
466         switch (entry->type)
467         {
468         case CAIRO_COGL_JOURNAL_ENTRY_TYPE_CLIP: {
469             cairo_cogl_journal_clip_entry_t *clip_entry =
470                 (cairo_cogl_journal_clip_entry_t *)entry;
471             _cairo_clip_destroy (clip_entry->clip);
472             entry_size = sizeof (cairo_cogl_journal_clip_entry_t);
473             break;
474         }
475         case CAIRO_COGL_JOURNAL_ENTRY_TYPE_RECTANGLE: {
476             cairo_cogl_journal_rect_entry_t *rect_entry =
477                 (cairo_cogl_journal_rect_entry_t *)entry;
478             cogl_object_unref (rect_entry->pipeline);
479             entry_size = sizeof (cairo_cogl_journal_rect_entry_t);
480             break;
481         }
482         case CAIRO_COGL_JOURNAL_ENTRY_TYPE_PRIMITIVE: {
483             cairo_cogl_journal_prim_entry_t *prim_entry =
484                 (cairo_cogl_journal_prim_entry_t *)entry;
485             cogl_object_unref (prim_entry->pipeline);
486             cogl_object_unref (prim_entry->primitive);
487             entry_size = sizeof (cairo_cogl_journal_prim_entry_t);
488             break;
489         }
490         case CAIRO_COGL_JOURNAL_ENTRY_TYPE_PATH: {
491             cairo_cogl_journal_path_entry_t *path_entry =
492                 (cairo_cogl_journal_path_entry_t *)entry;
493             cogl_object_unref (path_entry->pipeline);
494             cogl_object_unref (path_entry->path);
495             entry_size = sizeof (cairo_cogl_journal_path_entry_t);
496             break;
497         }
498         default:
499             assert (0); /* not reached! */
500             entry_size = 0; /* avoid compiler warning */
501         }
502         g_slice_free1 (entry_size, entry);
503     }
504
505     g_queue_clear (surface->journal);
506
507     if (surface->last_clip) {
508         _cairo_clip_destroy (surface->last_clip);
509         surface->last_clip = NULL;
510     }
511 }
512
513 static CoglAttributeBuffer *
514 _cairo_cogl_surface_allocate_buffer_space (cairo_cogl_surface_t *surface,
515                                            size_t size,
516                                            size_t *offset,
517                                            void **pointer)
518 {
519     /* XXX: In the Cogl journal we found it more efficient to have a pool of
520      * buffers that we re-cycle but for now we simply thow away our stack
521      * buffer each time we flush. */
522     if (unlikely (surface->buffer_stack &&
523                   (surface->buffer_stack_size - surface->buffer_stack_offset) < size)) {
524         cogl_buffer_unmap (COGL_BUFFER (surface->buffer_stack));
525         cogl_object_unref (surface->buffer_stack);
526         surface->buffer_stack = NULL;
527         surface->buffer_stack_size *= 2;
528     }
529
530     if (unlikely (surface->buffer_stack_size < size))
531         surface->buffer_stack_size = size * 2;
532
533     if (unlikely (surface->buffer_stack == NULL)) {
534         surface->buffer_stack = cogl_attribute_buffer_new (surface->buffer_stack_size, NULL);
535         surface->buffer_stack_pointer =
536             cogl_buffer_map (COGL_BUFFER (surface->buffer_stack),
537                              COGL_BUFFER_ACCESS_WRITE,
538                              COGL_BUFFER_MAP_HINT_DISCARD);
539         surface->buffer_stack_offset = 0;
540     }
541
542     *pointer = surface->buffer_stack_pointer + surface->buffer_stack_offset;
543     *offset = surface->buffer_stack_offset;
544
545     surface->buffer_stack_offset += size;
546     return cogl_object_ref (surface->buffer_stack);
547 }
548
549
550 static CoglAttributeBuffer *
551 _cairo_cogl_traps_to_triangles_buffer (cairo_cogl_surface_t *surface,
552                                        cairo_traps_t *traps,
553                                        size_t *offset,
554                                        gboolean one_shot)
555 {
556     CoglAttributeBuffer *buffer;
557     int n_traps = traps->num_traps;
558     int i;
559     CoglVertexP2 *triangles;
560
561     if (one_shot) {
562         buffer = _cairo_cogl_surface_allocate_buffer_space (surface,
563                                                             n_traps * sizeof (CoglVertexP2) * 6,
564                                                             offset,
565                                                             (void **)&triangles);
566         if (!buffer)
567             return NULL;
568     } else {
569         buffer = cogl_attribute_buffer_new (n_traps * sizeof (CoglVertexP2) * 6, NULL);
570         if (!buffer)
571             return NULL;
572         triangles = cogl_buffer_map (COGL_BUFFER (buffer),
573                                      COGL_BUFFER_ACCESS_WRITE,
574                                      COGL_BUFFER_MAP_HINT_DISCARD);
575         if (!triangles)
576             return NULL;
577         *offset = 0;
578     }
579
580     /* XXX: This is can be very expensive. I'm not sure a.t.m if it's
581      * predominantly the bandwidth required or the cost of the fixed_to_float
582      * conversions but either way we should try using an index buffer to
583      * reduce the amount we upload by 1/3 (offset by allocating and uploading
584      * indices though) sadly though my experience with the intel mesa drivers
585      * is that slow paths can easily be hit when starting to use indices.
586      */
587     for (i = 0; i < n_traps; i++)
588     {
589         CoglVertexP2 *p = &triangles[i * 6];
590         cairo_trapezoid_t *trap = &traps->traps[i];
591
592         p[0].x = _cairo_cogl_util_fixed_to_float (trap->left.p1.x);
593         p[0].y = _cairo_cogl_util_fixed_to_float (trap->left.p1.y);
594
595         p[1].x = _cairo_cogl_util_fixed_to_float (trap->left.p2.x);
596         p[1].y = _cairo_cogl_util_fixed_to_float (trap->left.p2.y);
597
598         p[2].x = _cairo_cogl_util_fixed_to_float (trap->right.p2.x);
599         p[2].y = _cairo_cogl_util_fixed_to_float (trap->right.p2.y);
600
601         p[3].x = _cairo_cogl_util_fixed_to_float (trap->left.p1.x);
602         p[3].y = _cairo_cogl_util_fixed_to_float (trap->left.p1.y);
603
604         p[4].x = _cairo_cogl_util_fixed_to_float (trap->right.p2.x);
605         p[4].y = _cairo_cogl_util_fixed_to_float (trap->right.p2.y);
606
607         p[5].x = _cairo_cogl_util_fixed_to_float (trap->right.p1.x);
608         p[5].y = _cairo_cogl_util_fixed_to_float (trap->right.p1.y);
609     }
610
611     if (!one_shot)
612         cogl_buffer_unmap (COGL_BUFFER (buffer));
613
614     return buffer;
615 }
616
617 /* Used for solid fills, in this case we just need a mesh made of
618  * a single (2-component) position attribute. */
619 static CoglPrimitive *
620 _cairo_cogl_traps_to_composite_prim_p2 (cairo_cogl_surface_t *surface,
621                                         cairo_traps_t *traps,
622                                         gboolean one_shot)
623 {
624     size_t offset;
625     CoglAttributeBuffer *buffer = _cairo_cogl_traps_to_triangles_buffer (surface, traps, &offset, one_shot);
626     CoglAttribute *pos = cogl_attribute_new (buffer,
627                                              "cogl_position_in",
628                                              sizeof (CoglVertexP2),
629                                              offset,
630                                              2,
631                                              COGL_ATTRIBUTE_TYPE_FLOAT);
632     CoglPrimitive *prim;
633
634     /* The attribute will have taken a reference on the buffer */
635     cogl_object_unref (buffer);
636
637     prim = cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLES,
638                                traps->num_traps * 6, pos, NULL);
639
640     /* The primitive will now keep the attribute alive... */
641     cogl_object_unref (pos);
642
643     return prim;
644 }
645
646 /* Used for surface fills, in this case we need a mesh made of a single
647  * (2-component) position attribute + we also alias the same attribute as
648  * (2-component) texture coordinates */
649 static CoglPrimitive *
650 _cairo_cogl_traps_to_composite_prim_p2t2 (cairo_cogl_surface_t *surface,
651                                           cairo_traps_t *traps,
652                                           gboolean one_shot)
653 {
654     size_t offset;
655     CoglAttributeBuffer *buffer = _cairo_cogl_traps_to_triangles_buffer (surface, traps, &offset, one_shot);
656     CoglAttribute *pos = cogl_attribute_new (buffer,
657                                              "cogl_position_in",
658                                              sizeof (CoglVertexP2),
659                                              offset,
660                                              2,
661                                              COGL_ATTRIBUTE_TYPE_FLOAT);
662     CoglAttribute *tex_coords = cogl_attribute_new (buffer,
663                                                     "cogl_tex_coord0_in",
664                                                     sizeof (CoglVertexP2),
665                                                     0,
666                                                     2,
667                                                     COGL_ATTRIBUTE_TYPE_FLOAT);
668     CoglPrimitive *prim;
669
670     /* The attributes will have taken references on the buffer */
671     cogl_object_unref (buffer);
672
673     prim = cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLES,
674                                traps->num_traps * 6, pos, tex_coords, NULL);
675
676     /* The primitive will now keep the attributes alive... */
677     cogl_object_unref (pos);
678     cogl_object_unref (tex_coords);
679
680     return prim;
681 }
682
683 static CoglPrimitive *
684 _cairo_cogl_traps_to_composite_prim (cairo_cogl_surface_t *surface,
685                                      cairo_traps_t *traps,
686                                      int n_layers,
687                                      gboolean one_shot)
688 {
689     int n_traps = traps->num_traps;
690     int i;
691
692     /* XXX: Ideally we would skip tessellating to traps entirely since
693      * given their representation, conversion to triangles is quite expensive.
694      *
695      * This simplifies the conversion to triangles by making the end points of
696      * the two side lines actually just correspond to the corners of the
697      * traps.
698      */
699     for (i = 0; i < n_traps; i++)
700         _sanitize_trap (&traps->traps[i]);
701
702     if (n_layers == 0)
703         return _cairo_cogl_traps_to_composite_prim_p2 (surface, traps, one_shot);
704     else {
705         assert (n_layers == 1);
706         return _cairo_cogl_traps_to_composite_prim_p2t2 (surface, traps, one_shot);
707     }
708 }
709
710 static cairo_int_status_t
711 _cairo_cogl_fill_to_primitive (cairo_cogl_surface_t     *surface,
712                                const cairo_path_fixed_t *path,
713                                cairo_fill_rule_t         fill_rule,
714                                double                    tolerance,
715                                int                       n_layers,
716                                cairo_bool_t              one_shot,
717                                CoglPrimitive           **primitive,
718                                size_t                   *size)
719 {
720     cairo_traps_t traps;
721     cairo_int_status_t status;
722
723     _cairo_traps_init (&traps);
724     status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
725     if (unlikely (status))
726         goto BAIL;
727
728     if (traps.num_traps == 0) {
729         status = CAIRO_INT_STATUS_NOTHING_TO_DO;
730         goto BAIL;
731     }
732
733     *size = traps.num_traps * sizeof (CoglVertexP2) * 6;
734
735     *primitive = _cairo_cogl_traps_to_composite_prim (surface, &traps, n_layers, one_shot);
736     if (!*primitive) {
737         status = CAIRO_INT_STATUS_NO_MEMORY;
738         goto BAIL;
739     }
740
741 BAIL:
742     _cairo_traps_fini (&traps);
743     return status;
744 }
745
746 static void
747 _cairo_cogl_clip_push_box (const cairo_box_t *box)
748 {
749     if (_cairo_box_is_pixel_aligned (box)) {
750         cairo_rectangle_int_t rect;
751         _cairo_box_round_to_rectangle (box, &rect);
752         cogl_clip_push_window_rectangle (rect.x, rect.y,
753                                          rect.width, rect.height);
754     } else {
755         double x1, y1, x2, y2;
756         _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2);
757         cogl_clip_push_rectangle (x1, y1, x2, y2);
758     }
759 }
760
761 static void
762 _cairo_cogl_journal_flush (cairo_cogl_surface_t *surface)
763 {
764     GList *l;
765     int clip_stack_depth = 0;
766     int i;
767
768     if (!surface->journal)
769         return;
770
771     if (surface->buffer_stack && surface->buffer_stack_offset) {
772         cogl_buffer_unmap (COGL_BUFFER (surface->buffer_stack));
773         cogl_object_unref (surface->buffer_stack);
774         surface->buffer_stack = NULL;
775     }
776
777     cogl_set_framebuffer (surface->framebuffer);
778
779     cogl_push_matrix ();
780
781     for (l = surface->journal->head; l; l = l->next) {
782         cairo_cogl_journal_entry_t *entry = l->data;
783
784         switch (entry->type)
785         {
786         case CAIRO_COGL_JOURNAL_ENTRY_TYPE_CLIP: {
787             cairo_cogl_journal_clip_entry_t *clip_entry =
788                 (cairo_cogl_journal_clip_entry_t *)entry;
789             cairo_clip_path_t *path;
790 #if 0
791             cairo_bool_t checked_for_primitives = FALSE;
792             cairo_cogl_clip_primitives_t *clip_primitives;
793 #endif
794
795             for (i = 0; i < clip_stack_depth; i++)
796                 cogl_clip_pop ();
797             clip_stack_depth = 0;
798
799             for (path = clip_entry->clip->path, i = 0; path; path = path->prev, i++) {
800                 cairo_rectangle_int_t extents;
801                 cairo_int_status_t status;
802                 CoglPrimitive *prim;
803                 size_t prim_size;
804
805                 _cairo_path_fixed_approximate_clip_extents (&path->path, &extents);
806
807                 /* TODO - maintain a fifo of the last 10 used clips with cached
808                  * primitives to see if we can avoid tesselating the path and
809                  * uploading the vertices...
810                  */
811 #if 0
812                 if (!checked_for_primitives) {
813                     clip_primitives = find_clip_primitives (clip);
814                     checked_for_primitives = TRUE;
815                 }
816                 if (clip_primitives)
817                     prim = clip_primitives->primitives[i];
818 #endif
819                 status = _cairo_cogl_fill_to_primitive (surface,
820                                                         &path->path,
821                                                         path->fill_rule,
822                                                         path->tolerance,
823                                                         0,
824                                                         TRUE,
825                                                         &prim,
826                                                         &prim_size);
827                 if (unlikely (status)) {
828                     g_warning ("Failed to get primitive for clip path while flushing journal");
829                     continue;
830                 }
831                 clip_stack_depth++;
832                 cogl_clip_push_primitive (prim,
833                                           extents.x, extents.y,
834                                           extents.x + extents.width,
835                                           extents.y + extents.height);
836                 cogl_object_unref (prim);
837             }
838
839             for (i = 0; i < clip_entry->clip->num_boxes; i++) {
840                 clip_stack_depth++;
841                 _cairo_cogl_clip_push_box (&clip_entry->clip->boxes[i]);
842             }
843
844             surface->n_clip_updates_per_frame++;
845             break;
846         }
847         case CAIRO_COGL_JOURNAL_ENTRY_TYPE_RECTANGLE: {
848             cairo_cogl_journal_rect_entry_t *rect_entry =
849                 (cairo_cogl_journal_rect_entry_t *)entry;
850             float tex_coords[8];
851             float x1 = rect_entry->x;
852             float y1 = rect_entry->y;
853             float x2 = rect_entry->x + rect_entry->width;
854             float y2 = rect_entry->y + rect_entry->height;
855             cairo_matrix_t *ctm = &rect_entry->ctm;
856             float ctmfv[16] = {
857                 ctm->xx, ctm->yx, 0, 0,
858                 ctm->xy, ctm->yy, 0, 0,
859                 0,           0,       1, 0,
860                 ctm->x0, ctm->y0, 0, 1
861             };
862             CoglMatrix transform;
863
864             cogl_matrix_init_from_array (&transform, ctmfv);
865
866             if (rect_entry->n_layers) {
867                 g_assert (rect_entry->n_layers <= 2);
868                 tex_coords[0] = x1;
869                 tex_coords[1] = y1;
870                 tex_coords[2] = x2;
871                 tex_coords[3] = y2;
872                 if (rect_entry->n_layers > 1)
873                     memcpy (&tex_coords[4], tex_coords, sizeof (float) * 4);
874             }
875
876             cogl_set_source (rect_entry->pipeline);
877             cogl_push_matrix ();
878             cogl_transform (&transform);
879             cogl_rectangle_with_multitexture_coords (x1, y1, x2, y2,
880                                                      tex_coords, 4 * rect_entry->n_layers);
881             cogl_pop_matrix ();
882             break;
883         }
884         case CAIRO_COGL_JOURNAL_ENTRY_TYPE_PRIMITIVE: {
885             cairo_cogl_journal_prim_entry_t *prim_entry =
886                 (cairo_cogl_journal_prim_entry_t *)entry;
887             CoglMatrix transform;
888
889             cogl_push_matrix ();
890             if (prim_entry->has_transform) {
891                 cairo_matrix_t *ctm = &prim_entry->transform;
892                 float ctmfv[16] = {
893                     ctm->xx, ctm->yx, 0, 0,
894                     ctm->xy, ctm->yy, 0, 0,
895                     0,       0,       1, 0,
896                     ctm->x0, ctm->y0, 0, 1
897                 };
898                 cogl_matrix_init_from_array (&transform, ctmfv);
899                 cogl_transform (&transform);
900             } else {
901                 cogl_matrix_init_identity (&transform);
902                 cogl_set_modelview_matrix (&transform);
903             }
904
905             cogl_set_source (prim_entry->pipeline);
906             cogl_primitive_draw (prim_entry->primitive);
907             cogl_pop_matrix ();
908             break;
909         }
910         case CAIRO_COGL_JOURNAL_ENTRY_TYPE_PATH: {
911             cairo_cogl_journal_path_entry_t *path_entry =
912                 (cairo_cogl_journal_path_entry_t *)entry;
913
914             cogl_set_source (path_entry->pipeline);
915             cogl_path_fill (path_entry->path);
916             break;
917         }
918         default:
919             assert (0); /* not reached! */
920         }
921     }
922
923     cogl_pop_matrix ();
924
925     for (i = 0; i < clip_stack_depth; i++)
926         cogl_clip_pop ();
927
928     _cairo_cogl_journal_discard (surface);
929 }
930
931 static cairo_status_t
932 _cairo_cogl_surface_flush (void *abstract_surface,
933                            unsigned flags)
934 {
935     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
936
937     if (flags)
938         return CAIRO_STATUS_SUCCESS;
939
940     _cairo_cogl_journal_flush (surface);
941
942     return CAIRO_STATUS_SUCCESS;
943 }
944
945 static cairo_status_t
946 _cairo_cogl_surface_finish (void *abstract_surface)
947 {
948     cairo_cogl_surface_t *surface = abstract_surface;
949
950     if (surface->texture)
951         cogl_object_unref (surface->texture);
952
953     if (surface->framebuffer)
954         cogl_object_unref (surface->framebuffer);
955
956     if (surface->journal)
957         _cairo_cogl_journal_free (surface);
958
959     /*XXX wtf */
960     cairo_device_release (surface->base.device);
961
962     return CAIRO_STATUS_SUCCESS;
963 }
964
965 static CoglPixelFormat
966 get_cogl_format_from_cairo_format (cairo_format_t cairo_format);
967
968 /* XXX: We often use RGBA format for onscreen framebuffers so make sure
969  * to handle CAIRO_FORMAT_INVALID sensibly */
970 static cairo_format_t
971 get_cairo_format_from_cogl_format (CoglPixelFormat format)
972 {
973     switch ((int)format)
974     {
975     case COGL_PIXEL_FORMAT_A_8:
976         return CAIRO_FORMAT_A8;
977     case COGL_PIXEL_FORMAT_RGB_565:
978         return CAIRO_FORMAT_RGB16_565;
979
980     case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
981     case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
982     case COGL_PIXEL_FORMAT_RGBA_8888_PRE:
983         /* Note: this is ambiguous since CAIRO_FORMAT_RGB24
984          * would also map to the same CoglPixelFormat */
985         return CAIRO_FORMAT_ARGB32;
986
987     default:
988         g_warning("bad format: %x a? %d, bgr? %d, pre %d, format: %d\n",
989                   format,
990                   format & COGL_A_BIT,
991                   format & COGL_BGR_BIT,
992                   format & COGL_PREMULT_BIT,
993                   format & ~(COGL_A_BIT | COGL_BGR_BIT | COGL_PREMULT_BIT));
994         return CAIRO_FORMAT_INVALID;
995     }
996 }
997
998 static CoglPixelFormat
999 get_cogl_format_from_cairo_format (cairo_format_t cairo_format)
1000 {
1001     switch (cairo_format)
1002     {
1003     case CAIRO_FORMAT_ARGB32:
1004     case CAIRO_FORMAT_RGB24:
1005 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1006         return COGL_PIXEL_FORMAT_BGRA_8888_PRE;
1007 #else
1008         return COGL_PIXEL_FORMAT_ARGB_8888_PRE;
1009 #endif
1010     case CAIRO_FORMAT_A8:
1011         return COGL_PIXEL_FORMAT_A_8;
1012     case CAIRO_FORMAT_RGB16_565:
1013         return COGL_PIXEL_FORMAT_RGB_565;
1014     case CAIRO_FORMAT_INVALID:
1015     case CAIRO_FORMAT_A1:
1016     case CAIRO_FORMAT_RGB30:
1017         return 0;
1018     }
1019
1020     g_warn_if_reached ();
1021     return 0;
1022 }
1023
1024 static cairo_status_t
1025 _cairo_cogl_surface_read_rect_to_image_surface (cairo_cogl_surface_t   *surface,
1026                                                 cairo_rectangle_int_t  *interest,
1027                                                 cairo_image_surface_t **image_out)
1028 {
1029     cairo_image_surface_t *image;
1030     cairo_status_t status;
1031     cairo_format_t cairo_format;
1032     CoglPixelFormat cogl_format;
1033
1034     /* TODO: Add cogl_texture_get_region() API so we don't have to ensure the
1035      * surface is bound to an fbo to read back pixels */
1036     status = _cairo_cogl_surface_ensure_framebuffer (surface);
1037     if (unlikely (status))
1038         return status;
1039
1040     cairo_format = get_cairo_format_from_cogl_format (surface->cogl_format);
1041     if (cairo_format == CAIRO_FORMAT_INVALID) {
1042         cairo_format = CAIRO_FORMAT_ARGB32;
1043         cogl_format = get_cogl_format_from_cairo_format (cairo_format);
1044     } else {
1045         cogl_format = cogl_framebuffer_get_color_format (surface->framebuffer);
1046     }
1047
1048     image = (cairo_image_surface_t *)
1049         cairo_image_surface_create (cairo_format, surface->width, surface->height);
1050     if (image->base.status)
1051         return image->base.status;
1052
1053     /* TODO: Add cogl_framebuffer_read_pixels() API */
1054     cogl_push_framebuffer (surface->framebuffer);
1055     cogl_read_pixels (0, 0, surface->width, surface->height,
1056                       COGL_READ_PIXELS_COLOR_BUFFER,
1057                       cogl_format,
1058                       image->data);
1059     cogl_pop_framebuffer ();
1060
1061     *image_out = image;
1062
1063     return CAIRO_STATUS_SUCCESS;
1064 }
1065
1066 static cairo_status_t
1067 _cairo_cogl_surface_acquire_source_image (void                   *abstract_surface,
1068                                           cairo_image_surface_t **image_out,
1069                                           void                  **image_extra)
1070 {
1071     cairo_cogl_surface_t *surface = abstract_surface;
1072     cairo_status_t status;
1073
1074     if (surface->texture) {
1075         cairo_format_t format = get_cairo_format_from_cogl_format (surface->cogl_format);
1076         cairo_image_surface_t *image = (cairo_image_surface_t *)
1077             cairo_image_surface_create (format, surface->width, surface->height);
1078         if (image->base.status)
1079             return image->base.status;
1080
1081         cogl_texture_get_data (surface->texture,
1082                                cogl_texture_get_format (surface->texture),
1083                                0,
1084                                image->data);
1085
1086         image->base.is_clear = FALSE;
1087         *image_out = image;
1088     } else {
1089         cairo_rectangle_int_t extents = {
1090             0, 0, surface->width, surface->height
1091         };
1092         status = _cairo_cogl_surface_read_rect_to_image_surface (surface, &extents,
1093                                                                  image_out);
1094         if (unlikely (status))
1095             return status;
1096     }
1097
1098     *image_extra = NULL;
1099
1100     return CAIRO_STATUS_SUCCESS;
1101 }
1102
1103 static void
1104 _cairo_cogl_surface_release_source_image (void                  *abstract_surface,
1105                                           cairo_image_surface_t *image,
1106                                           void                  *image_extra)
1107 {
1108     cairo_surface_destroy (&image->base);
1109 }
1110
1111 static cairo_status_t
1112 _cairo_cogl_surface_clear (cairo_cogl_surface_t *surface,
1113                            const cairo_color_t *color)
1114 {
1115     /* Anything batched in the journal up until now is redundant... */
1116     _cairo_cogl_journal_discard (surface);
1117
1118     /* XXX: we currently implicitly clear the depth and stencil buffer here
1119      * but since we use the framebuffer_discard extension when available I
1120      * suppose this doesn't matter too much.
1121      *
1122      * The main concern is that we want to avoid re-loading an external z
1123      * buffer at the start of each frame, but also many gpu architectures have
1124      * optimizations for how they handle the depth/stencil buffers and can get
1125      * upset if they aren't cleared together at the start of the frame.
1126      *
1127      * FIXME: we need a way to assert that the clip stack currently isn't
1128      * using the stencil buffer before clearing it here!
1129      */
1130     cogl_framebuffer_clear4f (surface->framebuffer,
1131                               COGL_BUFFER_BIT_COLOR |
1132                               COGL_BUFFER_BIT_DEPTH |
1133                               COGL_BUFFER_BIT_STENCIL,
1134                               color->red * color->alpha,
1135                               color->green * color->alpha,
1136                               color->blue * color->alpha,
1137                               color->alpha);
1138     return CAIRO_STATUS_SUCCESS;
1139 }
1140
1141 cairo_status_t
1142 _cairo_cogl_path_fixed_rectangle (cairo_path_fixed_t *path,
1143                                   cairo_fixed_t x,
1144                                   cairo_fixed_t y,
1145                                   cairo_fixed_t width,
1146                                   cairo_fixed_t height)
1147 {
1148     cairo_status_t status;
1149
1150     status = _cairo_path_fixed_move_to (path, x, y);
1151     if (unlikely (status))
1152         return status;
1153
1154     status = _cairo_path_fixed_rel_line_to (path, width, 0);
1155     if (unlikely (status))
1156         return status;
1157
1158     status = _cairo_path_fixed_rel_line_to (path, 0, height);
1159     if (unlikely (status))
1160         return status;
1161
1162     status = _cairo_path_fixed_rel_line_to (path, -width, 0);
1163     if (unlikely (status))
1164         return status;
1165
1166     status = _cairo_path_fixed_close_path (path);
1167     if (unlikely (status))
1168         return status;
1169
1170     return CAIRO_STATUS_SUCCESS;
1171 }
1172
1173 static cairo_int_status_t
1174 _cairo_cogl_surface_paint (void                  *abstract_surface,
1175                            cairo_operator_t       op,
1176                            const cairo_pattern_t *source,
1177                            const cairo_clip_t    *clip)
1178 {
1179     cairo_cogl_surface_t *surface;
1180     cairo_path_fixed_t path;
1181     cairo_status_t status;
1182     cairo_matrix_t identity;
1183
1184     if (clip == NULL) {
1185         if (op == CAIRO_OPERATOR_CLEAR)
1186             return _cairo_cogl_surface_clear (abstract_surface, CAIRO_COLOR_TRANSPARENT);
1187         else if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
1188                 (op == CAIRO_OPERATOR_SOURCE ||
1189                  (op == CAIRO_OPERATOR_OVER && (((cairo_surface_t *)abstract_surface)->is_clear || _cairo_pattern_is_opaque_solid (source))))) {
1190             return _cairo_cogl_surface_clear (abstract_surface,
1191                                               &((cairo_solid_pattern_t *) source)->color);
1192         }
1193     }
1194
1195     /* fallback to handling the paint in terms of a fill... */
1196
1197     surface = abstract_surface;
1198
1199     _cairo_path_fixed_init (&path);
1200
1201     status = _cairo_cogl_path_fixed_rectangle (&path, 0, 0, surface->width, surface->height);
1202     if (unlikely (status))
1203         goto BAIL;
1204
1205 #ifdef NEED_COGL_CONTEXT
1206     /* XXX: in cairo-cogl-context.c we set some sideband data on the
1207      * surface before issuing a fill so we need to do that here too... */
1208     surface->user_path = &path;
1209     cairo_matrix_init_identity (&identity);
1210     surface->ctm = &identity;
1211     surface->ctm_inverse = &identity;
1212     surface->path_is_rectangle = TRUE;
1213     surface->path_rectangle_x = 0;
1214     surface->path_rectangle_y = 0;
1215     surface->path_rectangle_width = surface->width;
1216     surface->path_rectangle_height = surface->height;
1217 #endif
1218
1219     status = _cairo_cogl_surface_fill (abstract_surface,
1220                                        op,
1221                                        source,
1222                                        &path,
1223                                        CAIRO_FILL_RULE_WINDING,
1224                                        1,
1225                                        CAIRO_ANTIALIAS_DEFAULT,
1226                                        clip);
1227 BAIL:
1228     _cairo_path_fixed_fini (&path);
1229     return status;
1230 }
1231
1232 static CoglPipelineWrapMode
1233 get_cogl_wrap_mode_for_extend (cairo_extend_t extend_mode)
1234 {
1235     switch (extend_mode)
1236     {
1237     case CAIRO_EXTEND_NONE:
1238         return COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
1239     case CAIRO_EXTEND_PAD:
1240         return COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
1241     case CAIRO_EXTEND_REPEAT:
1242         return COGL_PIPELINE_WRAP_MODE_REPEAT;
1243     case CAIRO_EXTEND_REFLECT:
1244         /* TODO: return COGL_PIPELINE_WRAP_MODE_MIRROR; */
1245         return CAIRO_EXTEND_REPEAT;
1246     }
1247     assert (0); /* not reached */
1248     return COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
1249 }
1250
1251 #if 0
1252 /* Given an arbitrary texture, check if it's already a pot texture and simply
1253  * return it back if so. If not create a new pot texture, scale the old to
1254  * fill it, unref the old and return a pointer to the new pot texture. */
1255 static cairo_int_status_t
1256 _cairo_cogl_get_pot_texture (CoglContext *context,
1257                              CoglTexture *texture,
1258                              CoglTexture **pot_texture)
1259 {
1260     int width = cogl_texture_get_width (texture);
1261     int height = cogl_texture_get_height (texture);
1262     int pot_width;
1263     int pot_height;
1264     CoglHandle offscreen = NULL;
1265     CoglTexture2D *pot = NULL;
1266     GError *error;
1267
1268     pot_width = _cairo_cogl_util_next_p2 (width);
1269     pot_height = _cairo_cogl_util_next_p2 (height);
1270
1271     if (pot_width == width && pot_height == height)
1272         return CAIRO_INT_STATUS_SUCCESS;
1273
1274     for (;;) {
1275         error = NULL;
1276         pot = cogl_texture_2d_new_with_size (context,
1277                                              pot_width,
1278                                              pot_height,
1279                                              cogl_texture_get_format (texture),
1280                                              &error);
1281         if (pot)
1282             break;
1283         else
1284             g_error_free (error);
1285
1286         if (pot_width > pot_height)
1287             pot_width >>= 1;
1288         else
1289             pot_height >>= 1;
1290
1291         if (!pot_width || !pot_height)
1292             break;
1293     }
1294
1295     *pot_texture = COGL_TEXTURE (pot);
1296
1297     if (!pot)
1298         return CAIRO_INT_STATUS_NO_MEMORY;
1299
1300     /* Use the GPU to do a bilinear filtered scale from npot to pot... */
1301     offscreen = cogl_offscreen_new_to_texture (COGL_TEXTURE (pot));
1302     error = NULL;
1303     if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen), &error)) {
1304         /* NB: if we don't pass an error then Cogl is allowed to simply abort
1305          * automatically. */
1306         g_error_free (error);
1307         cogl_object_unref (pot);
1308         *pot_texture = NULL;
1309         return CAIRO_INT_STATUS_NO_MEMORY;
1310     }
1311
1312     cogl_push_framebuffer (COGL_FRAMEBUFFER (offscreen));
1313     cogl_set_source_texture (texture);
1314     cogl_rectangle (-1, 1, 1, -1);
1315     cogl_pop_framebuffer ();
1316
1317     cogl_object_unref (offscreen);
1318 }
1319 #endif
1320
1321 /* NB: a reference for the texture is transferred to the caller which should
1322  * be unrefed */
1323 static CoglTexture *
1324 _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t  *reference_surface,
1325                                      cairo_surface_t       *abstract_surface)
1326 {
1327     cairo_image_surface_t *image;
1328     cairo_image_surface_t *acquired_image = NULL;
1329     void *image_extra;
1330     CoglPixelFormat format;
1331     cairo_image_surface_t *image_clone = NULL;
1332     CoglTexture2D *texture;
1333     GError *error = NULL;
1334     cairo_surface_t *clone;
1335
1336     if (abstract_surface->device == reference_surface->base.device) {
1337         cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
1338         _cairo_cogl_surface_flush (surface, 0);
1339         return surface->texture ? cogl_object_ref (surface->texture) : NULL;
1340     }
1341
1342     if (abstract_surface->type == CAIRO_SURFACE_TYPE_COGL) {
1343         if (_cairo_surface_is_subsurface (abstract_surface)) {
1344             cairo_cogl_surface_t *surface;
1345
1346             surface = (cairo_cogl_surface_t *)
1347                 _cairo_surface_subsurface_get_target (abstract_surface);
1348             if (surface->base.device == reference_surface->base.device)
1349                 return surface->texture ? cogl_object_ref (surface->texture) : NULL;
1350         }
1351     }
1352
1353     clone = _cairo_surface_has_snapshot (abstract_surface, &_cairo_cogl_surface_backend);
1354     if (clone) {
1355         cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)clone;
1356         return surface->texture ? cogl_object_ref (surface->texture) : NULL;
1357     }
1358
1359     g_warning ("Uploading image surface to texture");
1360
1361     if (_cairo_surface_is_image (abstract_surface)) {
1362         image = (cairo_image_surface_t *)abstract_surface;
1363     } else {
1364         cairo_status_t status = _cairo_surface_acquire_source_image (abstract_surface,
1365                                                                      &acquired_image, &image_extra);
1366         if (unlikely (status)) {
1367             g_warning ("acquire_source_image failed: %s [%d]\n",
1368                        cairo_status_to_string (status), status);
1369             return NULL;
1370         }
1371         image = acquired_image;
1372     }
1373
1374     format = get_cogl_format_from_cairo_format (image->format);
1375     if (!format)
1376     {
1377         image_clone = _cairo_image_surface_coerce (image);
1378         if (unlikely (image_clone->base.status)) {
1379             g_warning ("image_surface_coerce failed");
1380             texture = NULL;
1381             goto BAIL;
1382         }
1383
1384         format = get_cogl_format_from_cairo_format (image_clone->format);
1385         assert (format);
1386     }
1387
1388     texture = cogl_texture_2d_new_from_data (to_device(reference_surface->base.device)->cogl_context,
1389                                              image->width,
1390                                              image->height,
1391                                              format, /* incoming */
1392                                              format, /* desired */
1393                                              image->stride,
1394                                              image->data,
1395                                              &error);
1396     if (!texture) {
1397         g_warning ("Failed to allocate texture: %s", error->message);
1398         g_error_free (error);
1399         goto BAIL;
1400     }
1401
1402     clone = _cairo_cogl_surface_create_full (to_device(reference_surface->base.device),
1403                                              reference_surface->ignore_alpha,
1404                                              NULL, COGL_TEXTURE (texture));
1405
1406     _cairo_surface_attach_snapshot (abstract_surface, clone, NULL);
1407
1408     /* Attaching the snapshot will take a reference on the clone surface... */
1409     cairo_surface_destroy (clone);
1410
1411 BAIL:
1412     if (image_clone)
1413         cairo_surface_destroy (&image_clone->base);
1414     if (acquired_image)
1415         _cairo_surface_release_source_image (abstract_surface, acquired_image, image_extra);
1416
1417     return COGL_TEXTURE (texture);
1418 }
1419
1420 /* NB: a reference for the texture is transferred to the caller which should
1421  * be unrefed */
1422 static CoglTexture *
1423 _cairo_cogl_acquire_pattern_texture (const cairo_pattern_t *pattern,
1424                                      cairo_cogl_surface_t *destination,
1425                                      const cairo_rectangle_int_t *extents,
1426                                      const cairo_rectangle_int_t *sample,
1427                                      cairo_cogl_texture_attributes_t *attributes)
1428 {
1429     CoglTexture *texture = NULL;
1430
1431     switch ((int)pattern->type)
1432     {
1433     case CAIRO_PATTERN_TYPE_SURFACE: {
1434         cairo_surface_t *surface = ((cairo_surface_pattern_t *)pattern)->surface;
1435         texture = _cairo_cogl_acquire_surface_texture (destination, surface);
1436         if (!texture)
1437             return NULL;
1438
1439         /* XXX: determine if it would have no effect to change the
1440          * extend mode to EXTEND_PAD instead since we can simply map
1441          * EXTEND_PAD to CLAMP_TO_EDGE without needing fragment shader
1442          * tricks or extra border texels. */
1443 #if 0
1444         /* TODO: We still need to consider HW such as SGX which doesn't have
1445          * full support for NPOT textures. */
1446         if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_REFLECT) {
1447             _cairo_cogl_get_pot_texture ();
1448         }
1449 #endif
1450
1451         cairo_matrix_init_identity (&attributes->matrix);
1452
1453         /* Convert from un-normalized source coordinates in backend
1454          * coordinates to normalized texture coordinates */
1455         cairo_matrix_scale (&attributes->matrix,
1456                             1.0f / cogl_texture_get_width (texture),
1457                             1.0f / cogl_texture_get_height (texture));
1458
1459         /* XXX: need to multiply in the pattern->matrix */
1460
1461         attributes->extend = pattern->extend;
1462         attributes->filter = CAIRO_FILTER_BILINEAR;
1463         attributes->has_component_alpha = pattern->has_component_alpha;
1464
1465         attributes->s_wrap = get_cogl_wrap_mode_for_extend (pattern->extend);
1466         attributes->t_wrap = attributes->s_wrap;
1467
1468         return texture;
1469     }
1470     case CAIRO_PATTERN_TYPE_RADIAL:
1471     case CAIRO_PATTERN_TYPE_MESH: {
1472         cairo_surface_t *surface;
1473         cairo_matrix_t texture_matrix;
1474
1475         surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1476                                               extents->width, extents->height);
1477         if (_cairo_surface_offset_paint (surface,
1478                                          extents->x, extents->y,
1479                                          CAIRO_OPERATOR_SOURCE,
1480                                          pattern, NULL)) {
1481             cairo_surface_destroy (surface);
1482             return NULL;
1483         }
1484
1485         texture = _cairo_cogl_acquire_surface_texture (destination, surface);
1486         if (!texture)
1487             goto BAIL;
1488
1489         cairo_matrix_init_identity (&texture_matrix);
1490
1491         /* Convert from un-normalized source coordinates in backend
1492          * coordinates to normalized texture coordinates */
1493         cairo_matrix_scale (&texture_matrix,
1494                             1.0f / cogl_texture_get_width (texture),
1495                             1.0f / cogl_texture_get_height (texture));
1496
1497         cairo_matrix_translate (&texture_matrix, -extents->x, -extents->y);
1498
1499         attributes->matrix = texture_matrix;
1500         attributes->extend = pattern->extend;
1501         attributes->filter = CAIRO_FILTER_NEAREST;
1502         attributes->has_component_alpha = pattern->has_component_alpha;
1503
1504         /* any pattern extend modes have already been dealt with... */
1505         attributes->s_wrap = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
1506         attributes->t_wrap = attributes->s_wrap;
1507
1508 BAIL:
1509         cairo_surface_destroy (surface);
1510
1511         return texture;
1512     }
1513     case CAIRO_PATTERN_TYPE_LINEAR: {
1514         cairo_linear_pattern_t *linear_pattern = (cairo_linear_pattern_t *)pattern;
1515         cairo_cogl_linear_gradient_t *gradient;
1516         cairo_cogl_linear_texture_entry_t *linear_texture;
1517         cairo_int_status_t status;
1518         float a, b;
1519         float dist;
1520         float scale;
1521         float angle;
1522
1523         status = _cairo_cogl_get_linear_gradient (to_device(destination->base.device),
1524                                                   pattern->extend,
1525                                                   linear_pattern->base.n_stops,
1526                                                   linear_pattern->base.stops,
1527                                                   &gradient);
1528         if (unlikely (status))
1529             return NULL;
1530
1531         linear_texture = _cairo_cogl_linear_gradient_texture_for_extend (gradient, pattern->extend);
1532
1533         attributes->extend = pattern->extend;
1534         attributes->filter = CAIRO_FILTER_BILINEAR;
1535         attributes->has_component_alpha = pattern->has_component_alpha;
1536         attributes->s_wrap = get_cogl_wrap_mode_for_extend (pattern->extend);
1537         attributes->t_wrap = COGL_PIPELINE_WRAP_MODE_REPEAT;
1538
1539         cairo_matrix_init_identity (&attributes->matrix);
1540
1541         a = linear_pattern->pd2.x - linear_pattern->pd1.x;
1542         b = linear_pattern->pd2.y - linear_pattern->pd1.y;
1543         dist = sqrtf (a*a + b*b);
1544         scale = 1.0f / dist;
1545         angle = - atan2f (b, a);
1546
1547         cairo_matrix_rotate (&attributes->matrix, angle);
1548         cairo_matrix_scale (&attributes->matrix, scale, scale);
1549
1550         cairo_matrix_translate (&attributes->matrix,
1551                                 -linear_pattern->pd1.x,
1552                                 -linear_pattern->pd1.y);
1553
1554         /* XXX: this caught me out: cairo doesn't follow the standard
1555          * maths convention for multiplying two matrices A x B - cairo
1556          * does B x A so the final matrix is as if A's transforms were
1557          * applied first.
1558          */
1559         cairo_matrix_multiply (&attributes->matrix,
1560                                &pattern->matrix,
1561                                &attributes->matrix);
1562
1563         return cogl_object_ref (linear_texture->texture);
1564     }
1565     default:
1566         g_warning ("Un-supported source type");
1567         return NULL;
1568     }
1569 }
1570
1571 static void
1572 set_layer_texture_with_attributes (CoglPipeline *pipeline,
1573                                    int layer_index,
1574                                    CoglTexture *texture,
1575                                    cairo_cogl_texture_attributes_t *attributes)
1576 {
1577     cogl_pipeline_set_layer_texture (pipeline, layer_index, texture);
1578
1579     if (!_cairo_matrix_is_identity (&attributes->matrix)) {
1580         cairo_matrix_t *m = &attributes->matrix;
1581         float texture_matrixfv[16] = {
1582             m->xx, m->yx, 0, 0,
1583             m->xy, m->yy, 0, 0,
1584             0, 0, 1, 0,
1585             m->x0, m->y0, 0, 1
1586         };
1587         CoglMatrix texture_matrix;
1588         cogl_matrix_init_from_array (&texture_matrix, texture_matrixfv);
1589         cogl_pipeline_set_layer_matrix (pipeline, layer_index, &texture_matrix);
1590     }
1591
1592     if (attributes->s_wrap != attributes->t_wrap) {
1593         cogl_pipeline_set_layer_wrap_mode_s (pipeline, layer_index, attributes->s_wrap);
1594         cogl_pipeline_set_layer_wrap_mode_t (pipeline, layer_index, attributes->t_wrap);
1595     } else
1596         cogl_pipeline_set_layer_wrap_mode (pipeline, layer_index, attributes->s_wrap);
1597 }
1598
1599 static CoglPipeline *
1600 get_source_mask_operator_destination_pipeline (const cairo_pattern_t *mask,
1601                                                const cairo_pattern_t *source,
1602                                                cairo_operator_t op,
1603                                                cairo_cogl_surface_t *destination,
1604                                                cairo_composite_rectangles_t *extents)
1605 {
1606     cairo_cogl_template_type template_type;
1607     CoglPipeline *pipeline;
1608
1609     switch ((int)source->type)
1610     {
1611     case CAIRO_PATTERN_TYPE_SOLID:
1612         template_type = mask ?
1613             CAIRO_COGL_TEMPLATE_TYPE_MASK_SOLID : CAIRO_COGL_TEMPLATE_TYPE_SOLID;
1614         break;
1615     case CAIRO_PATTERN_TYPE_SURFACE:
1616     case CAIRO_PATTERN_TYPE_LINEAR:
1617     case CAIRO_PATTERN_TYPE_RADIAL:
1618     case CAIRO_PATTERN_TYPE_MESH:
1619         template_type = mask ?
1620             CAIRO_COGL_TEMPLATE_TYPE_MASK_TEXTURE : CAIRO_COGL_TEMPLATE_TYPE_TEXTURE;
1621         break;
1622     default:
1623         g_warning ("Un-supported source type");
1624         return NULL;
1625     }
1626
1627     pipeline = cogl_pipeline_copy (to_device(destination->base.device)->template_pipelines[op][template_type]);
1628
1629     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
1630         cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)source;
1631         cogl_pipeline_set_color4f (pipeline,
1632                                    solid_pattern->color.red * solid_pattern->color.alpha,
1633                                    solid_pattern->color.green * solid_pattern->color.alpha,
1634                                    solid_pattern->color.blue * solid_pattern->color.alpha,
1635                                    solid_pattern->color.alpha);
1636     } else {
1637         cairo_cogl_texture_attributes_t attributes;
1638         CoglTexture *texture =
1639             _cairo_cogl_acquire_pattern_texture (source, destination,
1640                                                  &extents->bounded,
1641                                                  &extents->source_sample_area,
1642                                                  &attributes);
1643         if (!texture)
1644             goto BAIL;
1645         set_layer_texture_with_attributes (pipeline, 0, texture, &attributes);
1646         cogl_object_unref (texture);
1647     }
1648
1649     if (mask) {
1650         if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
1651             cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)mask;
1652             CoglColor color;
1653             cogl_color_init_from_4f (&color,
1654                                      solid_pattern->color.red * solid_pattern->color.alpha,
1655                                      solid_pattern->color.green * solid_pattern->color.alpha,
1656                                      solid_pattern->color.blue * solid_pattern->color.alpha,
1657                                      solid_pattern->color.alpha);
1658             cogl_pipeline_set_layer_combine_constant (pipeline, 1, &color);
1659         } else {
1660             cairo_cogl_texture_attributes_t attributes;
1661             CoglTexture *texture =
1662                 _cairo_cogl_acquire_pattern_texture (mask, destination,
1663                                                      &extents->bounded,
1664                                                      &extents->mask_sample_area,
1665                                                      &attributes);
1666             if (!texture)
1667                 goto BAIL;
1668             set_layer_texture_with_attributes (pipeline, 1, texture, &attributes);
1669             cogl_object_unref (texture);
1670         }
1671     }
1672
1673     return pipeline;
1674
1675 BAIL:
1676     cogl_object_unref (pipeline);
1677     return NULL;
1678 }
1679
1680 #if 0
1681 CoglPrimitive *
1682 _cairo_cogl_rectangle_new_p2t2t2 (float x,
1683                                   float y,
1684                                   float width,
1685                                   float height)
1686 {
1687     CoglVertexP2 vertices[] = {
1688         {x, y}, {x, y + height}, {x + width, y + height},
1689         {x, y}, {x + width, y + height}, {x + width, y}
1690     };
1691     CoglAttributeBuffer *buffer = cogl_attribute_buffer_new (sizeof (vertices));
1692     CoglAttribute *pos = cogl_attribute_new (buffer,
1693                                              "cogl_position_in",
1694                                              sizeof (CoglVertexP2),
1695                                              0,
1696                                              2,
1697                                              COGL_ATTRIBUTE_TYPE_FLOAT);
1698     CoglAttribute *tex_coords0 = cogl_attribute_new (buffer,
1699                                                      "cogl_tex_coord0_in",
1700                                                      sizeof (CoglVertexP2),
1701                                                      0,
1702                                                      2,
1703                                                      COGL_ATTRIBUTE_TYPE_FLOAT);
1704     CoglAttribute *tex_coords0 = cogl_attribute_new (buffer,
1705                                                      "cogl_tex_coord0_in",
1706                                                      sizeof (CoglVertexP2),
1707                                                      0,
1708                                                      2,
1709                                                      COGL_ATTRIBUTE_TYPE_FLOAT);
1710     CoglPrimitive *prim;
1711
1712     cogl_buffer_set_data (COGL_BUFFER (buffer), 0, vertices, sizeof (vertices));
1713
1714     /* The attributes will now keep the buffer alive... */
1715     cogl_object_unref (buffer);
1716
1717     prim = cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLES,
1718                                6, pos, tex_coords, NULL);
1719
1720     /* The primitive will now keep the attribute alive... */
1721     cogl_object_unref (pos);
1722
1723     return prim;
1724 }
1725 #endif
1726
1727 static void
1728 _cairo_cogl_log_clip (cairo_cogl_surface_t *surface,
1729                       const cairo_clip_t *clip)
1730 {
1731     if (!_cairo_clip_equal (clip, surface->last_clip)) {
1732         _cairo_cogl_journal_log_clip (surface, clip);
1733         _cairo_clip_destroy (surface->last_clip);
1734         surface->last_clip = _cairo_clip_copy (clip);
1735     }
1736 }
1737
1738 static void
1739 _cairo_cogl_maybe_log_clip (cairo_cogl_surface_t *surface,
1740                             cairo_composite_rectangles_t *composite)
1741 {
1742     cairo_clip_t *clip = composite->clip;
1743
1744     if (_cairo_composite_rectangles_can_reduce_clip (composite, clip))
1745         clip = NULL;
1746
1747     if (clip == NULL) {
1748         if (_cairo_composite_rectangles_can_reduce_clip (composite,
1749                                                          surface->last_clip))
1750             return;
1751     }
1752
1753     _cairo_cogl_log_clip (surface, clip);
1754 }
1755
1756 static cairo_bool_t
1757 is_operator_supported (cairo_operator_t op)
1758 {
1759     switch ((int)op) {
1760     case CAIRO_OPERATOR_SOURCE:
1761     case CAIRO_OPERATOR_OVER:
1762     case CAIRO_OPERATOR_IN:
1763     case CAIRO_OPERATOR_DEST_OVER:
1764     case CAIRO_OPERATOR_DEST_IN:
1765     case CAIRO_OPERATOR_ADD:
1766         return TRUE;
1767
1768     default:
1769         return FALSE;
1770     }
1771 }
1772
1773 static cairo_int_status_t
1774 _cairo_cogl_surface_mask (void                    *abstract_surface,
1775                           cairo_operator_t         op,
1776                           const cairo_pattern_t   *source,
1777                           const cairo_pattern_t   *mask,
1778                           const cairo_clip_t      *clip)
1779 {
1780     cairo_cogl_surface_t *surface = abstract_surface;
1781     cairo_composite_rectangles_t extents;
1782     cairo_status_t status;
1783     CoglPipeline *pipeline;
1784     cairo_matrix_t identity;
1785
1786     /* XXX: Use this to smoke test the acquire_source/dest_image fallback
1787      * paths... */
1788     //return CAIRO_INT_STATUS_UNSUPPORTED;
1789
1790     if (!is_operator_supported (op))
1791         return CAIRO_INT_STATUS_UNSUPPORTED;
1792
1793     status = _cairo_composite_rectangles_init_for_mask (&extents,
1794                                                         &surface->base,
1795                                                         op, source, mask, clip);
1796     if (unlikely (status))
1797         return status;
1798
1799     pipeline = get_source_mask_operator_destination_pipeline (mask, source,
1800                                                               op, surface, &extents);
1801     if (!pipeline){
1802         status = CAIRO_INT_STATUS_UNSUPPORTED;
1803         goto BAIL;
1804     }
1805
1806     _cairo_cogl_maybe_log_clip (surface, &extents);
1807
1808     cairo_matrix_init_identity (&identity);
1809     _cairo_cogl_journal_log_rectangle (surface, pipeline,
1810                                        extents.bounded.x,
1811                                        extents.bounded.y,
1812                                        extents.bounded.width,
1813                                        extents.bounded.height,
1814                                        2,
1815                                        &identity);
1816
1817     /* The journal will take a reference on the pipeline and clip_path... */
1818     cogl_object_unref (pipeline);
1819
1820 BAIL:
1821     return status;
1822 }
1823
1824 static int
1825 _cairo_cogl_source_n_layers (const cairo_pattern_t *source)
1826 {
1827     switch ((int)source->type)
1828     {
1829     case CAIRO_PATTERN_TYPE_SOLID:
1830         return 0;
1831     case CAIRO_PATTERN_TYPE_LINEAR:
1832     case CAIRO_PATTERN_TYPE_RADIAL:
1833     case CAIRO_PATTERN_TYPE_MESH:
1834     case CAIRO_PATTERN_TYPE_SURFACE:
1835         return 1;
1836     default:
1837         g_warning ("Unsupported source type");
1838         return 0;
1839     }
1840 }
1841
1842 static cairo_bool_t
1843 _cairo_cogl_path_fill_meta_equal (const void *key_a, const void *key_b)
1844 {
1845     const cairo_cogl_path_fill_meta_t *meta0 = key_a;
1846     const cairo_cogl_path_fill_meta_t *meta1 = key_b;
1847
1848     return _cairo_path_fixed_equal (meta0->user_path, meta1->user_path);
1849 }
1850
1851 static cairo_bool_t
1852 _cairo_cogl_stroke_style_equal (const cairo_stroke_style_t *a,
1853                                 const cairo_stroke_style_t *b)
1854 {
1855     if (a->line_width == b->line_width &&
1856         a->line_cap == b->line_cap &&
1857         a->line_join == b->line_join &&
1858         a->miter_limit == b->miter_limit &&
1859         a->num_dashes == b->num_dashes &&
1860         a->dash_offset == b->dash_offset)
1861     {
1862         unsigned int i;
1863         for (i = 0; i < a->num_dashes; i++) {
1864             if (a->dash[i] != b->dash[i])
1865                 return FALSE;
1866         }
1867     }
1868     return TRUE;
1869 }
1870
1871 static cairo_bool_t
1872 _cairo_cogl_path_stroke_meta_equal (const void *key_a, const void *key_b)
1873 {
1874     const cairo_cogl_path_stroke_meta_t *meta0 = key_a;
1875     const cairo_cogl_path_stroke_meta_t *meta1 = key_b;
1876
1877     return _cairo_cogl_stroke_style_equal (&meta0->style, &meta1->style) &&
1878         _cairo_path_fixed_equal (meta0->user_path, meta1->user_path);
1879 }
1880
1881 static cairo_cogl_path_stroke_meta_t *
1882 _cairo_cogl_path_stroke_meta_reference (cairo_cogl_path_stroke_meta_t *meta)
1883 {
1884     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count));
1885
1886     _cairo_reference_count_inc (&meta->ref_count);
1887
1888     return meta;
1889 }
1890
1891 static void
1892 _cairo_cogl_path_stroke_meta_destroy (cairo_cogl_path_stroke_meta_t *meta)
1893 {
1894     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count));
1895
1896     if (! _cairo_reference_count_dec_and_test (&meta->ref_count))
1897         return;
1898
1899     _cairo_path_fixed_fini (meta->user_path);
1900     free (meta->user_path);
1901
1902     _cairo_stroke_style_fini (&meta->style);
1903
1904     if (meta->prim)
1905         cogl_object_unref (meta->prim);
1906
1907     free (meta);
1908 }
1909
1910 static cairo_cogl_path_stroke_meta_t *
1911 _cairo_cogl_path_stroke_meta_lookup (cairo_cogl_device_t        *ctx,
1912                                      unsigned long               hash,
1913                                      cairo_path_fixed_t         *user_path,
1914                                      const cairo_stroke_style_t *style,
1915                                      double                      tolerance)
1916 {
1917     cairo_cogl_path_stroke_meta_t *ret;
1918     cairo_cogl_path_stroke_meta_t lookup;
1919
1920     lookup.cache_entry.hash = hash;
1921     lookup.user_path = user_path;
1922     lookup.style = *style;
1923     lookup.tolerance = tolerance;
1924
1925     ret = _cairo_cache_lookup (&ctx->path_stroke_staging_cache, &lookup.cache_entry);
1926     if (!ret)
1927         ret = _cairo_cache_lookup (&ctx->path_stroke_prim_cache, &lookup.cache_entry);
1928     return ret;
1929 }
1930
1931 static void
1932 _cairo_cogl_path_stroke_meta_set_prim_size (cairo_cogl_surface_t *surface,
1933                                             cairo_cogl_path_stroke_meta_t *meta,
1934                                             size_t size)
1935 {
1936     /* now that we know the meta structure is associated with a primitive
1937      * we promote it from the staging cache into the primitive cache.
1938      */
1939
1940     /* XXX: _cairo_cache borks if you try and remove an entry that's already
1941      * been evicted so we explicitly look it up first... */
1942     if (_cairo_cache_lookup (&to_device(surface->base.device)->path_stroke_staging_cache, &meta->cache_entry)) {
1943         _cairo_cogl_path_stroke_meta_reference (meta);
1944         _cairo_cache_remove (&to_device(surface->base.device)->path_stroke_staging_cache, &meta->cache_entry);
1945     }
1946
1947     meta->cache_entry.size = size;
1948     if (_cairo_cache_insert (&to_device(surface->base.device)->path_stroke_prim_cache, &meta->cache_entry) !=
1949         CAIRO_STATUS_SUCCESS)
1950         _cairo_cogl_path_stroke_meta_destroy (meta);
1951 }
1952
1953 static unsigned int
1954 _cairo_cogl_stroke_style_hash (unsigned int hash,
1955                                const cairo_stroke_style_t *style)
1956 {
1957     unsigned int i;
1958     hash = _cairo_hash_bytes (hash, &style->line_width, sizeof (style->line_width));
1959     hash = _cairo_hash_bytes (hash, &style->line_cap, sizeof (style->line_cap));
1960     hash = _cairo_hash_bytes (hash, &style->line_join, sizeof (style->line_join));
1961     hash = _cairo_hash_bytes (hash, &style->miter_limit, sizeof (style->miter_limit));
1962     hash = _cairo_hash_bytes (hash, &style->num_dashes, sizeof (style->num_dashes));
1963     hash = _cairo_hash_bytes (hash, &style->dash_offset, sizeof (style->dash_offset));
1964     for (i = 0; i < style->num_dashes; i++)
1965         hash = _cairo_hash_bytes (hash, &style->dash[i], sizeof (double));
1966     return hash;
1967 }
1968
1969 static cairo_cogl_path_stroke_meta_t *
1970 _cairo_cogl_get_path_stroke_meta (cairo_cogl_surface_t *surface,
1971                                   const cairo_stroke_style_t *style,
1972                                   double tolerance)
1973 {
1974     unsigned long hash;
1975     cairo_cogl_path_stroke_meta_t *meta = NULL;
1976     cairo_path_fixed_t *meta_path = NULL;
1977     cairo_status_t status;
1978
1979     if (!surface->user_path)
1980         return NULL;
1981
1982     hash = _cairo_path_fixed_hash (surface->user_path);
1983     hash = _cairo_cogl_stroke_style_hash (hash, style);
1984     hash = _cairo_hash_bytes (hash, &tolerance, sizeof (tolerance));
1985
1986     meta = _cairo_cogl_path_stroke_meta_lookup (to_device(surface->base.device), hash,
1987                                                 surface->user_path, style, tolerance);
1988     if (meta)
1989         return meta;
1990
1991     meta = calloc (1, sizeof (cairo_cogl_path_stroke_meta_t));
1992     if (!meta)
1993         goto BAIL;
1994     CAIRO_REFERENCE_COUNT_INIT (&meta->ref_count, 1);
1995     meta->cache_entry.hash = hash;
1996     meta->counter = 0;
1997     meta_path = malloc (sizeof (cairo_path_fixed_t));
1998     if (!meta_path)
1999         goto BAIL;
2000     /* FIXME: we should add a ref-counted wrapper for our user_paths
2001      * so we don't have to keep copying them here! */
2002     status = _cairo_path_fixed_init_copy (meta_path, surface->user_path);
2003     if (unlikely (status))
2004         goto BAIL;
2005     meta->user_path = meta_path;
2006     meta->ctm_inverse = *surface->ctm_inverse;
2007
2008     status = _cairo_stroke_style_init_copy (&meta->style, style);
2009     if (unlikely (status)) {
2010         _cairo_path_fixed_fini (meta_path);
2011         goto BAIL;
2012     }
2013     meta->tolerance = tolerance;
2014
2015     return meta;
2016
2017 BAIL:
2018     free (meta_path);
2019     free (meta);
2020     return NULL;
2021 }
2022
2023 static cairo_int_status_t
2024 _cairo_cogl_stroke_to_primitive (cairo_cogl_surface_t       *surface,
2025                                  const cairo_path_fixed_t   *path,
2026                                  const cairo_stroke_style_t *style,
2027                                  const cairo_matrix_t       *ctm,
2028                                  const cairo_matrix_t       *ctm_inverse,
2029                                  double                      tolerance,
2030                                  int                         n_layers,
2031                                  cairo_bool_t                one_shot,
2032                                  CoglPrimitive             **primitive,
2033                                  size_t                     *size)
2034 {
2035     cairo_traps_t traps;
2036     cairo_int_status_t status;
2037
2038     _cairo_traps_init (&traps);
2039
2040     status = _cairo_path_fixed_stroke_to_traps (path, style, ctm, ctm_inverse, tolerance,
2041                                                 &traps);
2042     if (unlikely (status))
2043         goto BAIL;
2044
2045     if (traps.num_traps == 0) {
2046         status = CAIRO_INT_STATUS_NOTHING_TO_DO;
2047         goto BAIL;
2048     }
2049
2050     *size = traps.num_traps * sizeof (CoglVertexP2) * 6;
2051
2052     //g_print ("new stroke prim\n");
2053     *primitive = _cairo_cogl_traps_to_composite_prim (surface, &traps, n_layers, one_shot);
2054     if (!*primitive) {
2055         status = CAIRO_INT_STATUS_NO_MEMORY;
2056         goto BAIL;
2057     }
2058
2059 BAIL:
2060     _cairo_traps_fini (&traps);
2061     return status;
2062 }
2063
2064 static cairo_int_status_t
2065 _cairo_cogl_surface_stroke (void                       *abstract_surface,
2066                             cairo_operator_t            op,
2067                             const cairo_pattern_t      *source,
2068                             const cairo_path_fixed_t   *path,
2069                             const cairo_stroke_style_t *style,
2070                             const cairo_matrix_t       *ctm,
2071                             const cairo_matrix_t       *ctm_inverse,
2072                             double                      tolerance,
2073                             cairo_antialias_t           antialias,
2074                             const cairo_clip_t         *clip)
2075 {
2076     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
2077     cairo_composite_rectangles_t extents;
2078     CoglPipeline *pipeline;
2079     cairo_status_t status;
2080 #ifdef ENABLE_PATH_CACHE
2081     cairo_cogl_path_stroke_meta_t *meta = NULL;
2082     cairo_matrix_t transform_matrix;
2083 #endif
2084     cairo_matrix_t *transform = NULL;
2085     gboolean one_shot = TRUE;
2086     CoglPrimitive *prim = NULL;
2087     cairo_bool_t new_prim = FALSE;
2088
2089     if (! is_operator_supported (op))
2090         return CAIRO_INT_STATUS_UNSUPPORTED;
2091
2092     /* FIXME - support unbounded operators */
2093     if (!_cairo_operator_bounded_by_mask (op)) {
2094         /* Currently IN this is the only unbounded operator we aim to support
2095          * in cairo-cogl. */
2096         assert (op == CAIRO_OPERATOR_IN);
2097         g_warning ("FIXME: handle stroking with unbounded operators!");
2098         return CAIRO_INT_STATUS_UNSUPPORTED;
2099     }
2100
2101     status = _cairo_composite_rectangles_init_for_stroke (&extents,
2102                                                           &surface->base,
2103                                                           op, source, path,
2104                                                           style,
2105                                                           ctm,
2106                                                           clip);
2107     if (unlikely (status))
2108         return status;
2109
2110 #ifdef ENABLE_PATH_CACHE
2111     /* FIXME: we are currently leaking the meta state if we don't reach
2112      * the cache_insert at the end. */
2113     meta = _cairo_cogl_get_path_stroke_meta (surface, style, tolerance);
2114     if (meta) {
2115         prim = meta->prim;
2116         if (prim) {
2117             cairo_matrix_multiply (&transform_matrix, &meta->ctm_inverse, surface->ctm);
2118             transform = &transform_matrix;
2119         } else if (meta->counter++ > 10)
2120             one_shot = FALSE;
2121     }
2122 #endif
2123
2124     if (!prim) {
2125         int n_layers = _cairo_cogl_source_n_layers (source);
2126         size_t prim_size = 0;
2127         status = _cairo_cogl_stroke_to_primitive (surface, path, style,
2128                                                   ctm, ctm_inverse, tolerance,
2129                                                   n_layers, one_shot,
2130                                                   &prim, &prim_size);
2131         if (unlikely (status))
2132             return status;
2133         new_prim = TRUE;
2134 #if defined (ENABLE_PATH_CACHE)
2135         if (meta) {
2136             meta->prim = cogl_object_ref (prim);
2137             _cairo_cogl_path_stroke_meta_set_prim_size (surface, meta, prim_size);
2138         }
2139 #endif
2140     }
2141
2142     pipeline = get_source_mask_operator_destination_pipeline (NULL, source,
2143                                                               op, surface, &extents);
2144     if (!pipeline)
2145         return CAIRO_INT_STATUS_UNSUPPORTED;
2146
2147     _cairo_cogl_maybe_log_clip (surface, &extents);
2148
2149     _cairo_cogl_journal_log_primitive (surface, pipeline, prim, transform);
2150
2151     /* The journal will take a reference on the pipeline and primitive... */
2152     cogl_object_unref (pipeline);
2153     if (new_prim)
2154         cogl_object_unref (prim);
2155
2156     return CAIRO_INT_STATUS_SUCCESS;
2157 }
2158
2159 static cairo_cogl_path_fill_meta_t *
2160 _cairo_cogl_path_fill_meta_reference (cairo_cogl_path_fill_meta_t *meta)
2161 {
2162     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count));
2163
2164     _cairo_reference_count_inc (&meta->ref_count);
2165
2166     return meta;
2167 }
2168
2169 static void
2170 _cairo_cogl_path_fill_meta_destroy (cairo_cogl_path_fill_meta_t *meta)
2171 {
2172     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count));
2173
2174     if (! _cairo_reference_count_dec_and_test (&meta->ref_count))
2175         return;
2176
2177     _cairo_path_fixed_fini (meta->user_path);
2178     free (meta->user_path);
2179
2180     if (meta->prim)
2181         cogl_object_unref (meta->prim);
2182
2183     free (meta);
2184 }
2185
2186 static cairo_cogl_path_fill_meta_t *
2187 _cairo_cogl_path_fill_meta_lookup (cairo_cogl_device_t  *ctx,
2188                                    unsigned long         hash,
2189                                    cairo_path_fixed_t   *user_path)
2190 {
2191     cairo_cogl_path_fill_meta_t *ret;
2192     cairo_cogl_path_fill_meta_t lookup;
2193
2194     lookup.cache_entry.hash = hash;
2195     lookup.user_path = user_path;
2196
2197     ret = _cairo_cache_lookup (&ctx->path_fill_staging_cache, &lookup.cache_entry);
2198     if (!ret)
2199         ret = _cairo_cache_lookup (&ctx->path_fill_prim_cache, &lookup.cache_entry);
2200     return ret;
2201 }
2202
2203 static void
2204 _cairo_cogl_path_fill_meta_set_prim_size (cairo_cogl_surface_t *surface,
2205                                           cairo_cogl_path_fill_meta_t *meta,
2206                                           size_t size)
2207 {
2208     /* now that we know the meta structure is associated with a primitive
2209      * we promote it from the staging cache into the primitive cache.
2210      */
2211
2212     /* XXX: _cairo_cache borks if you try and remove an entry that's already
2213      * been evicted so we explicitly look it up first... */
2214     if (_cairo_cache_lookup (&to_device(surface->base.device)->path_fill_staging_cache, &meta->cache_entry)) {
2215         _cairo_cogl_path_fill_meta_reference (meta);
2216         _cairo_cache_remove (&to_device(surface->base.device)->path_fill_staging_cache, &meta->cache_entry);
2217     }
2218
2219     meta->cache_entry.size = size;
2220     if (_cairo_cache_insert (&to_device(surface->base.device)->path_fill_prim_cache, &meta->cache_entry) !=
2221         CAIRO_STATUS_SUCCESS)
2222         _cairo_cogl_path_fill_meta_destroy (meta);
2223 }
2224
2225 static cairo_cogl_path_fill_meta_t *
2226 _cairo_cogl_get_path_fill_meta (cairo_cogl_surface_t *surface)
2227 {
2228     unsigned long hash;
2229     cairo_cogl_path_fill_meta_t *meta = NULL;
2230     cairo_path_fixed_t *meta_path = NULL;
2231     cairo_status_t status;
2232
2233     if (!surface->user_path)
2234         return NULL;
2235
2236     hash = _cairo_path_fixed_hash (surface->user_path);
2237
2238     meta = _cairo_cogl_path_fill_meta_lookup (to_device(surface->base.device),
2239                                               hash, surface->user_path);
2240     if (meta)
2241         return meta;
2242
2243     meta = calloc (1, sizeof (cairo_cogl_path_fill_meta_t));
2244     if (!meta)
2245         goto BAIL;
2246     meta->cache_entry.hash = hash;
2247     meta->counter = 0;
2248     CAIRO_REFERENCE_COUNT_INIT (&meta->ref_count, 1);
2249     meta_path = malloc (sizeof (cairo_path_fixed_t));
2250     if (!meta_path)
2251         goto BAIL;
2252     /* FIXME: we should add a ref-counted wrapper for our user_paths
2253      * so we don't have to keep copying them here! */
2254     status = _cairo_path_fixed_init_copy (meta_path, surface->user_path);
2255     if (unlikely (status))
2256         goto BAIL;
2257     meta->user_path = meta_path;
2258     meta->ctm_inverse = *surface->ctm_inverse;
2259
2260     /* To start with - until we associate a CoglPrimitive with the meta
2261      * structure - we keep the meta in a staging structure until we
2262      * see whether it actually gets re-used. */
2263     meta->cache_entry.size = 1;
2264     if (_cairo_cache_insert (&to_device(surface->base.device)->path_fill_staging_cache, &meta->cache_entry) !=
2265         CAIRO_STATUS_SUCCESS)
2266         _cairo_cogl_path_fill_meta_destroy (meta);
2267
2268     return meta;
2269
2270 BAIL:
2271     free (meta_path);
2272     free (meta);
2273     return NULL;
2274 }
2275
2276 static cairo_int_status_t
2277 _cairo_cogl_surface_fill (void                      *abstract_surface,
2278                           cairo_operator_t           op,
2279                           const cairo_pattern_t     *source,
2280                           const cairo_path_fixed_t  *path,
2281                           cairo_fill_rule_t          fill_rule,
2282                           double                     tolerance,
2283                           cairo_antialias_t          antialias,
2284                           const cairo_clip_t        *clip)
2285 {
2286     cairo_cogl_surface_t *surface = abstract_surface;
2287     cairo_composite_rectangles_t extents;
2288     cairo_status_t status;
2289 #ifdef ENABLE_PATH_CACHE
2290     cairo_cogl_path_fill_meta_t *meta = NULL;
2291     cairo_matrix_t transform_matrix;
2292 #endif
2293     cairo_matrix_t *transform = NULL;
2294     cairo_bool_t one_shot = TRUE;
2295     CoglPrimitive *prim = NULL;
2296     cairo_bool_t new_prim = FALSE;
2297     CoglPipeline *pipeline;
2298
2299     if (! is_operator_supported (op))
2300         return CAIRO_INT_STATUS_UNSUPPORTED;
2301
2302     /* FIXME - support unbounded operators */
2303     if (!_cairo_operator_bounded_by_mask (op)) {
2304         /* Currently IN this is the only unbounded operator we aim to support
2305          * in cairo-cogl. */
2306         assert (op == CAIRO_OPERATOR_IN);
2307         g_warning ("FIXME: handle filling with unbounded operators!");
2308         return CAIRO_INT_STATUS_UNSUPPORTED;
2309     }
2310
2311     status = _cairo_composite_rectangles_init_for_fill (&extents,
2312                                                         &surface->base,
2313                                                         op, source, path,
2314                                                         clip);
2315     if (unlikely (status))
2316         return status;
2317
2318 #ifndef FILL_WITH_COGL_PATH
2319 #ifdef ENABLE_PATH_CACHE
2320     meta = _cairo_cogl_get_path_fill_meta (surface);
2321     if (meta) {
2322         prim = meta->prim;
2323         if (prim) {
2324             cairo_matrix_multiply (&transform_matrix, &meta->ctm_inverse, surface->ctm);
2325             transform = &transform_matrix;
2326         } else if (meta->counter++ > 10)
2327             one_shot = FALSE;
2328     }
2329 #endif /* ENABLE_PATH_CACHE */
2330
2331     if (!prim) {
2332         int n_layers = _cairo_cogl_source_n_layers (source);
2333         size_t prim_size;
2334         status = _cairo_cogl_fill_to_primitive (surface, path, fill_rule, tolerance,
2335                                                 one_shot, n_layers, &prim, &prim_size);
2336         if (unlikely (status))
2337             return status;
2338         new_prim = TRUE;
2339 #ifdef ENABLE_PATH_CACHE
2340         if (meta) {
2341             meta->prim = cogl_object_ref (prim);
2342             _cairo_cogl_path_fill_meta_set_prim_size (surface, meta, prim_size);
2343         }
2344 #endif /* ENABLE_PATH_CACHE */
2345     }
2346
2347 #endif /* !FILL_WITH_COGL_PATH */
2348
2349     pipeline = get_source_mask_operator_destination_pipeline (NULL, source,
2350                                                               op, surface, &extents);
2351     if (!pipeline)
2352         return CAIRO_INT_STATUS_UNSUPPORTED;
2353
2354     _cairo_cogl_maybe_log_clip (surface, &extents);
2355
2356 #ifndef FILL_WITH_COGL_PATH
2357     _cairo_cogl_journal_log_primitive (surface, pipeline, prim, transform);
2358     /* The journal will take a reference on the prim */
2359     if (new_prim)
2360         cogl_object_unref (prim);
2361 #else
2362     CoglPath * cogl_path = _cairo_cogl_util_path_from_cairo (path, fill_rule, tolerance);
2363     _cairo_cogl_journal_log_path (surface, pipeline, cogl_path);
2364     cogl_object_unref (cogl_path);
2365 #endif
2366
2367     /* The journal will take a reference on the pipeline... */
2368     cogl_object_unref (pipeline);
2369
2370     return CAIRO_INT_STATUS_SUCCESS;
2371 }
2372
2373 cairo_int_status_t
2374 _cairo_cogl_surface_fill_rectangle (void                     *abstract_surface,
2375                                     cairo_operator_t          op,
2376                                     const cairo_pattern_t    *source,
2377                                     double                    x,
2378                                     double                    y,
2379                                     double                    width,
2380                                     double                    height,
2381                                     cairo_matrix_t           *ctm,
2382                                     const cairo_clip_t       *clip)
2383 {
2384     cairo_cogl_surface_t *surface = abstract_surface;
2385     CoglPipeline *pipeline;
2386
2387     if (! is_operator_supported (op))
2388         return CAIRO_INT_STATUS_UNSUPPORTED;
2389
2390     /* FIXME - support unbounded operators */
2391     if (!_cairo_operator_bounded_by_mask (op)) {
2392         /* Currently IN this is the only unbounded operator we aim to support
2393          * in cairo-cogl. */
2394         assert (op == CAIRO_OPERATOR_IN);
2395         g_warning ("FIXME: handle filling with unbounded operators!");
2396         return CAIRO_INT_STATUS_UNSUPPORTED;
2397     }
2398
2399     /* FIXME */
2400 #if 0
2401     status = _cairo_composite_rectangles_init_for_fill_rectangle (&extents,
2402                                                                   &surface->base,
2403                                                                   op, source, path,
2404                                                                   clip);
2405     if (unlikely (status))
2406         return status;
2407 #endif
2408
2409     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
2410         double x1 = x;
2411         double y1 = y;
2412         double x2 = x1 + width;
2413         double y2 = y1 + height;
2414
2415         pipeline = get_source_mask_operator_destination_pipeline (NULL, source,
2416                                                                   op, surface, NULL);
2417         if (!pipeline)
2418             return CAIRO_INT_STATUS_UNSUPPORTED;
2419
2420         _cairo_cogl_log_clip (surface, clip);
2421
2422         _cairo_cogl_journal_log_rectangle (surface,
2423                                            pipeline,
2424                                            x1, y1, x2, y2,
2425                                            0,
2426                                            ctm);
2427         return CAIRO_INT_STATUS_SUCCESS;
2428     } else
2429         return CAIRO_INT_STATUS_UNSUPPORTED;
2430
2431     /* TODO:
2432      * We need to acquire the textures here, look at the corresponding
2433      * attributes and see if this can be trivially handled by logging
2434      * a textured rectangle only needing simple scaling or translation
2435      * of texture coordinates.
2436      *
2437      * At this point we should also aim to remap the default
2438      * EXTEND_NONE mode to EXTEND_PAD which is more efficient if we
2439      * know it makes no difference either way since we can map that to
2440      * CLAMP_TO_EDGE.
2441      */
2442 }
2443
2444 static cairo_int_status_t
2445 _cairo_cogl_surface_show_glyphs (void                   *surface,
2446                                  cairo_operator_t        op,
2447                                  const cairo_pattern_t  *source,
2448                                  cairo_glyph_t          *glyphs,
2449                                  int                     num_glyphs,
2450                                  cairo_scaled_font_t    *scaled_font,
2451                                  const cairo_clip_t     *clip)
2452 {
2453     return CAIRO_INT_STATUS_UNSUPPORTED;
2454 }
2455
2456 const cairo_surface_backend_t _cairo_cogl_surface_backend = {
2457     CAIRO_SURFACE_TYPE_COGL,
2458     _cairo_cogl_surface_finish,
2459 #ifdef NEED_COGL_CONTEXT
2460     _cairo_cogl_context_create,
2461 #else
2462     _cairo_default_context_create,
2463 #endif
2464
2465     _cairo_cogl_surface_create_similar,
2466     NULL, /* create similar image */
2467     NULL, /* map to image */
2468     NULL, /* unmap image */
2469
2470     _cairo_surface_default_source,
2471     _cairo_cogl_surface_acquire_source_image,
2472     _cairo_cogl_surface_release_source_image,
2473     NULL, /* snapshot */
2474
2475     NULL, /* copy_page */
2476     NULL, /* show_page */
2477
2478     _cairo_cogl_surface_get_extents,
2479     NULL, /* get_font_options */
2480
2481     _cairo_cogl_surface_flush, /* flush */
2482     NULL, /* mark_dirty_rectangle */
2483
2484     _cairo_cogl_surface_paint,
2485     _cairo_cogl_surface_mask,
2486     _cairo_cogl_surface_stroke,
2487     _cairo_cogl_surface_fill,
2488     NULL, /* fill_stroke*/
2489     _cairo_surface_fallback_glyphs,
2490 };
2491
2492 static cairo_surface_t *
2493 _cairo_cogl_surface_create_full (cairo_cogl_device_t *dev,
2494                                  cairo_bool_t ignore_alpha,
2495                                  CoglFramebuffer *framebuffer,
2496                                  CoglTexture *texture)
2497 {
2498     cairo_cogl_surface_t *surface;
2499     cairo_status_t status;
2500
2501     status = cairo_device_acquire (&dev->base);
2502     if (unlikely (status))
2503         return _cairo_surface_create_in_error (status);
2504
2505     surface = malloc (sizeof (cairo_cogl_surface_t));
2506     if (unlikely (surface == NULL))
2507         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2508
2509     surface->ignore_alpha = ignore_alpha;
2510
2511     surface->framebuffer = framebuffer;
2512     if (framebuffer) {
2513         surface->width = cogl_framebuffer_get_width (framebuffer);
2514         surface->height = cogl_framebuffer_get_height (framebuffer);
2515         surface->cogl_format = cogl_framebuffer_get_color_format (framebuffer);
2516         cogl_object_ref (framebuffer);
2517     }
2518
2519     /* FIXME: If texture == NULL and we are given an offscreen framebuffer
2520      * then we want a way to poke inside the framebuffer to get a texture */
2521     surface->texture = texture;
2522     if (texture) {
2523         if (!framebuffer) {
2524             surface->width = cogl_texture_get_width (texture);
2525             surface->height = cogl_texture_get_height (texture);
2526             surface->cogl_format = cogl_texture_get_format (texture);
2527         }
2528         cogl_object_ref (texture);
2529     }
2530
2531     assert(surface->width && surface->height);
2532
2533     surface->journal = NULL;
2534
2535     surface->buffer_stack = NULL;
2536     surface->buffer_stack_size = 4096;
2537
2538     surface->last_clip = NULL;
2539
2540     surface->n_clip_updates_per_frame = 0;
2541
2542     _cairo_surface_init (&surface->base,
2543                          &_cairo_cogl_surface_backend,
2544                          &dev->base,
2545                          CAIRO_CONTENT_COLOR_ALPHA);
2546
2547     return &surface->base;
2548 }
2549
2550 cairo_surface_t *
2551 cairo_cogl_surface_create (cairo_device_t  *abstract_device,
2552                            CoglFramebuffer *framebuffer)
2553 {
2554     cairo_cogl_device_t *dev = (cairo_cogl_device_t *)abstract_device;
2555
2556     if (abstract_device == NULL)
2557         return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_ERROR);
2558
2559     if (abstract_device->status)
2560         return _cairo_surface_create_in_error (abstract_device->status);
2561
2562     if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_COGL)
2563         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
2564
2565     return _cairo_cogl_surface_create_full (dev, FALSE, framebuffer, NULL);
2566 }
2567 slim_hidden_def (cairo_cogl_surface_create);
2568
2569 CoglFramebuffer *
2570 cairo_cogl_surface_get_framebuffer (cairo_surface_t *abstract_surface)
2571 {
2572     cairo_cogl_surface_t *surface;
2573
2574     if (abstract_surface->backend != &_cairo_cogl_surface_backend) {
2575         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2576         return NULL;
2577     }
2578
2579     surface = (cairo_cogl_surface_t *) abstract_surface;
2580
2581     return surface->framebuffer;
2582 }
2583 slim_hidden_def (cairo_cogl_surface_get_framebuffer);
2584
2585 CoglTexture *
2586 cairo_cogl_surface_get_texture (cairo_surface_t *abstract_surface)
2587 {
2588     cairo_cogl_surface_t *surface;
2589
2590     if (abstract_surface->backend != &_cairo_cogl_surface_backend) {
2591         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2592         return NULL;
2593     }
2594
2595     surface = (cairo_cogl_surface_t *) abstract_surface;
2596
2597     return surface->texture;
2598 }
2599 slim_hidden_def (cairo_cogl_surface_get_texture);
2600
2601 static cairo_status_t
2602 _cairo_cogl_device_flush (void *device)
2603 {
2604     cairo_status_t status;
2605
2606     status = cairo_device_acquire (device);
2607     if (unlikely (status))
2608         return status;
2609
2610     /* XXX: we don't need to flush Cogl here, we just need to flush
2611      * any batching we do of compositing primitives. */
2612
2613     cairo_device_release (device);
2614
2615     return CAIRO_STATUS_SUCCESS;
2616 }
2617
2618 static void
2619 _cairo_cogl_device_finish (void *device)
2620 {
2621     cairo_status_t status;
2622
2623     status = cairo_device_acquire (device);
2624     if (unlikely (status))
2625         return;
2626
2627     /* XXX: Drop references to external resources */
2628
2629     cairo_device_release (device);
2630 }
2631
2632 static void
2633 _cairo_cogl_device_destroy (void *device)
2634 {
2635     cairo_cogl_device_t *dev = device;
2636
2637     /* FIXME: Free stuff! */
2638
2639     g_free (dev);
2640 }
2641
2642 static const cairo_device_backend_t _cairo_cogl_device_backend = {
2643     CAIRO_DEVICE_TYPE_COGL,
2644
2645     NULL, /* lock */
2646     NULL, /* unlock */
2647
2648     _cairo_cogl_device_flush,
2649     _cairo_cogl_device_finish,
2650     _cairo_cogl_device_destroy,
2651 };
2652
2653 static cairo_bool_t
2654 set_blend (CoglPipeline *pipeline, const char *blend_string)
2655 {
2656     GError *error = NULL;
2657     if (!cogl_pipeline_set_blend (pipeline, blend_string, &error)) {
2658         g_warning ("Unsupported blend string with current gpu/driver: %s", blend_string);
2659         g_error_free (error);
2660         return FALSE;
2661     }
2662     return TRUE;
2663 }
2664
2665 static cairo_bool_t
2666 _cairo_cogl_setup_op_state (CoglPipeline *pipeline, cairo_operator_t op)
2667 {
2668     cairo_bool_t status = FALSE;
2669
2670     switch ((int)op)
2671     {
2672     case CAIRO_OPERATOR_SOURCE:
2673         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR, 0)");
2674         break;
2675     case CAIRO_OPERATOR_OVER:
2676         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR, DST_COLOR * (1 - SRC_COLOR[A]))");
2677         break;
2678     case CAIRO_OPERATOR_IN:
2679         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR * DST_COLOR[A], 0)");
2680         break;
2681     case CAIRO_OPERATOR_DEST_OVER:
2682         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR * (1 - DST_COLOR[A]), DST_COLOR)");
2683         break;
2684     case CAIRO_OPERATOR_DEST_IN:
2685         status = set_blend (pipeline, "RGBA = ADD (0, DST_COLOR * SRC_COLOR[A])");
2686         break;
2687     case CAIRO_OPERATOR_ADD:
2688         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR, DST_COLOR)");
2689         break;
2690     }
2691
2692     return status;
2693 }
2694
2695 static void
2696 create_templates_for_op (cairo_cogl_device_t *dev, cairo_operator_t op)
2697 {
2698     CoglPipeline *base = cogl_pipeline_new ();
2699     CoglPipeline *pipeline;
2700     CoglColor color;
2701
2702     if (!_cairo_cogl_setup_op_state (base, op)) {
2703         cogl_object_unref (base);
2704         return;
2705     }
2706
2707     dev->template_pipelines[op][CAIRO_COGL_TEMPLATE_TYPE_SOLID] = base;
2708
2709     pipeline = cogl_pipeline_copy (base);
2710     cogl_pipeline_set_layer_texture (pipeline, 0, dev->dummy_texture);
2711     dev->template_pipelines[op][CAIRO_COGL_TEMPLATE_TYPE_TEXTURE] = pipeline;
2712
2713     pipeline = cogl_pipeline_copy (base);
2714     cogl_pipeline_set_layer_combine (pipeline, 1,
2715                                      "RGBA = MODULATE (PREVIOUS, CONSTANT[A])",
2716                                      NULL);
2717     cogl_pipeline_set_layer_combine_constant (pipeline, 1, &color);
2718     cogl_pipeline_set_layer_texture (pipeline, 1, dev->dummy_texture);
2719     dev->template_pipelines[op][CAIRO_COGL_TEMPLATE_TYPE_MASK_SOLID] = pipeline;
2720
2721     pipeline = cogl_pipeline_copy (base);
2722     cogl_pipeline_set_layer_combine (pipeline, 1,
2723                                      "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
2724                                      NULL);
2725     cogl_pipeline_set_layer_texture (pipeline, 1, dev->dummy_texture);
2726     dev->template_pipelines[op][CAIRO_COGL_TEMPLATE_TYPE_MASK_TEXTURE] = pipeline;
2727 }
2728
2729 cairo_device_t *
2730 cairo_cogl_device_create (CoglContext *cogl_context)
2731 {
2732     cairo_cogl_device_t *dev = g_new0 (cairo_cogl_device_t, 1);
2733     cairo_status_t status;
2734
2735     dev->backend_vtable_initialized = FALSE;
2736
2737     dev->cogl_context = cogl_context;
2738
2739     dev->dummy_texture = cogl_texture_new_with_size (1, 1,
2740                                                      COGL_TEXTURE_NO_SLICING,
2741                                                      COGL_PIXEL_FORMAT_ANY);
2742     if (!dev->dummy_texture)
2743         goto ERROR;
2744
2745     memset (dev->template_pipelines, 0, sizeof (dev->template_pipelines));
2746     create_templates_for_op (dev, CAIRO_OPERATOR_SOURCE);
2747     create_templates_for_op (dev, CAIRO_OPERATOR_OVER);
2748     create_templates_for_op (dev, CAIRO_OPERATOR_IN);
2749     create_templates_for_op (dev, CAIRO_OPERATOR_DEST_OVER);
2750     create_templates_for_op (dev, CAIRO_OPERATOR_DEST_IN);
2751     create_templates_for_op (dev, CAIRO_OPERATOR_ADD);
2752
2753     status = _cairo_cache_init (&dev->linear_cache,
2754                                 _cairo_cogl_linear_gradient_equal,
2755                                 NULL,
2756                                 (cairo_destroy_func_t) _cairo_cogl_linear_gradient_destroy,
2757                                 CAIRO_COGL_LINEAR_GRADIENT_CACHE_SIZE);
2758     if (unlikely (status))
2759         return _cairo_device_create_in_error(status);
2760
2761     status = _cairo_cache_init (&dev->path_fill_staging_cache,
2762                                 _cairo_cogl_path_fill_meta_equal,
2763                                 NULL,
2764                                 (cairo_destroy_func_t) _cairo_cogl_path_fill_meta_destroy,
2765                                 1000);
2766
2767     status = _cairo_cache_init (&dev->path_stroke_staging_cache,
2768                                 _cairo_cogl_path_stroke_meta_equal,
2769                                 NULL,
2770                                 (cairo_destroy_func_t) _cairo_cogl_path_stroke_meta_destroy,
2771                                 1000);
2772
2773     status = _cairo_cache_init (&dev->path_fill_prim_cache,
2774                                 _cairo_cogl_path_fill_meta_equal,
2775                                 NULL,
2776                                 (cairo_destroy_func_t) _cairo_cogl_path_fill_meta_destroy,
2777                                 CAIRO_COGL_PATH_META_CACHE_SIZE);
2778
2779     status = _cairo_cache_init (&dev->path_stroke_prim_cache,
2780                                 _cairo_cogl_path_stroke_meta_equal,
2781                                 NULL,
2782                                 (cairo_destroy_func_t) _cairo_cogl_path_stroke_meta_destroy,
2783                                 CAIRO_COGL_PATH_META_CACHE_SIZE);
2784
2785     _cairo_device_init (&dev->base, &_cairo_cogl_device_backend);
2786     return &dev->base;
2787
2788 ERROR:
2789     g_free (dev);
2790     return NULL;
2791 }
2792 slim_hidden_def (cairo_cogl_device_create);
2793
2794 void
2795 cairo_cogl_surface_end_frame (cairo_surface_t *abstract_surface)
2796 {
2797     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
2798     cairo_surface_flush (abstract_surface);
2799
2800     //g_print ("n_clip_update_per_frame = %d\n", surface->n_clip_updates_per_frame);
2801     surface->n_clip_updates_per_frame = 0;
2802 }
2803 slim_hidden_def (cairo_cogl_surface_end_frame);