Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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_polygon_to_traps (path, style,
  2041.                                                         ctm, ctm_inverse,
  2042.                                                         tolerance,
  2043.                                                         &traps);
  2044.     if (unlikely (status))
  2045.         goto BAIL;
  2046.  
  2047.     if (traps.num_traps == 0) {
  2048.         status = CAIRO_INT_STATUS_NOTHING_TO_DO;
  2049.         goto BAIL;
  2050.     }
  2051.  
  2052.     *size = traps.num_traps * sizeof (CoglVertexP2) * 6;
  2053.  
  2054.     //g_print ("new stroke prim\n");
  2055.     *primitive = _cairo_cogl_traps_to_composite_prim (surface, &traps, n_layers, one_shot);
  2056.     if (!*primitive) {
  2057.         status = CAIRO_INT_STATUS_NO_MEMORY;
  2058.         goto BAIL;
  2059.     }
  2060.  
  2061. BAIL:
  2062.     _cairo_traps_fini (&traps);
  2063.     return status;
  2064. }
  2065.  
  2066. static cairo_int_status_t
  2067. _cairo_cogl_surface_stroke (void                       *abstract_surface,
  2068.                             cairo_operator_t            op,
  2069.                             const cairo_pattern_t      *source,
  2070.                             const cairo_path_fixed_t   *path,
  2071.                             const cairo_stroke_style_t *style,
  2072.                             const cairo_matrix_t       *ctm,
  2073.                             const cairo_matrix_t       *ctm_inverse,
  2074.                             double                      tolerance,
  2075.                             cairo_antialias_t           antialias,
  2076.                             const cairo_clip_t         *clip)
  2077. {
  2078.     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
  2079.     cairo_composite_rectangles_t extents;
  2080.     CoglPipeline *pipeline;
  2081.     cairo_status_t status;
  2082. #ifdef ENABLE_PATH_CACHE
  2083.     cairo_cogl_path_stroke_meta_t *meta = NULL;
  2084.     cairo_matrix_t transform_matrix;
  2085. #endif
  2086.     cairo_matrix_t *transform = NULL;
  2087.     gboolean one_shot = TRUE;
  2088.     CoglPrimitive *prim = NULL;
  2089.     cairo_bool_t new_prim = FALSE;
  2090.  
  2091.     if (! is_operator_supported (op))
  2092.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2093.  
  2094.     /* FIXME - support unbounded operators */
  2095.     if (!_cairo_operator_bounded_by_mask (op)) {
  2096.         /* Currently IN this is the only unbounded operator we aim to support
  2097.          * in cairo-cogl. */
  2098.         assert (op == CAIRO_OPERATOR_IN);
  2099.         g_warning ("FIXME: handle stroking with unbounded operators!");
  2100.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2101.     }
  2102.  
  2103.     status = _cairo_composite_rectangles_init_for_stroke (&extents,
  2104.                                                           &surface->base,
  2105.                                                           op, source, path,
  2106.                                                           style,
  2107.                                                           ctm,
  2108.                                                           clip);
  2109.     if (unlikely (status))
  2110.         return status;
  2111.  
  2112. #ifdef ENABLE_PATH_CACHE
  2113.     /* FIXME: we are currently leaking the meta state if we don't reach
  2114.      * the cache_insert at the end. */
  2115.     meta = _cairo_cogl_get_path_stroke_meta (surface, style, tolerance);
  2116.     if (meta) {
  2117.         prim = meta->prim;
  2118.         if (prim) {
  2119.             cairo_matrix_multiply (&transform_matrix, &meta->ctm_inverse, surface->ctm);
  2120.             transform = &transform_matrix;
  2121.         } else if (meta->counter++ > 10)
  2122.             one_shot = FALSE;
  2123.     }
  2124. #endif
  2125.  
  2126.     if (!prim) {
  2127.         int n_layers = _cairo_cogl_source_n_layers (source);
  2128.         size_t prim_size = 0;
  2129.         status = _cairo_cogl_stroke_to_primitive (surface, path, style,
  2130.                                                   ctm, ctm_inverse, tolerance,
  2131.                                                   n_layers, one_shot,
  2132.                                                   &prim, &prim_size);
  2133.         if (unlikely (status))
  2134.             return status;
  2135.         new_prim = TRUE;
  2136. #if defined (ENABLE_PATH_CACHE)
  2137.         if (meta) {
  2138.             meta->prim = cogl_object_ref (prim);
  2139.             _cairo_cogl_path_stroke_meta_set_prim_size (surface, meta, prim_size);
  2140.         }
  2141. #endif
  2142.     }
  2143.  
  2144.     pipeline = get_source_mask_operator_destination_pipeline (NULL, source,
  2145.                                                               op, surface, &extents);
  2146.     if (!pipeline)
  2147.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2148.  
  2149.     _cairo_cogl_maybe_log_clip (surface, &extents);
  2150.  
  2151.     _cairo_cogl_journal_log_primitive (surface, pipeline, prim, transform);
  2152.  
  2153.     /* The journal will take a reference on the pipeline and primitive... */
  2154.     cogl_object_unref (pipeline);
  2155.     if (new_prim)
  2156.         cogl_object_unref (prim);
  2157.  
  2158.     return CAIRO_INT_STATUS_SUCCESS;
  2159. }
  2160.  
  2161. static cairo_cogl_path_fill_meta_t *
  2162. _cairo_cogl_path_fill_meta_reference (cairo_cogl_path_fill_meta_t *meta)
  2163. {
  2164.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count));
  2165.  
  2166.     _cairo_reference_count_inc (&meta->ref_count);
  2167.  
  2168.     return meta;
  2169. }
  2170.  
  2171. static void
  2172. _cairo_cogl_path_fill_meta_destroy (cairo_cogl_path_fill_meta_t *meta)
  2173. {
  2174.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta->ref_count));
  2175.  
  2176.     if (! _cairo_reference_count_dec_and_test (&meta->ref_count))
  2177.         return;
  2178.  
  2179.     _cairo_path_fixed_fini (meta->user_path);
  2180.     free (meta->user_path);
  2181.  
  2182.     if (meta->prim)
  2183.         cogl_object_unref (meta->prim);
  2184.  
  2185.     free (meta);
  2186. }
  2187.  
  2188. static cairo_cogl_path_fill_meta_t *
  2189. _cairo_cogl_path_fill_meta_lookup (cairo_cogl_device_t  *ctx,
  2190.                                    unsigned long         hash,
  2191.                                    cairo_path_fixed_t   *user_path)
  2192. {
  2193.     cairo_cogl_path_fill_meta_t *ret;
  2194.     cairo_cogl_path_fill_meta_t lookup;
  2195.  
  2196.     lookup.cache_entry.hash = hash;
  2197.     lookup.user_path = user_path;
  2198.  
  2199.     ret = _cairo_cache_lookup (&ctx->path_fill_staging_cache, &lookup.cache_entry);
  2200.     if (!ret)
  2201.         ret = _cairo_cache_lookup (&ctx->path_fill_prim_cache, &lookup.cache_entry);
  2202.     return ret;
  2203. }
  2204.  
  2205. static void
  2206. _cairo_cogl_path_fill_meta_set_prim_size (cairo_cogl_surface_t *surface,
  2207.                                           cairo_cogl_path_fill_meta_t *meta,
  2208.                                           size_t size)
  2209. {
  2210.     /* now that we know the meta structure is associated with a primitive
  2211.      * we promote it from the staging cache into the primitive cache.
  2212.      */
  2213.  
  2214.     /* XXX: _cairo_cache borks if you try and remove an entry that's already
  2215.      * been evicted so we explicitly look it up first... */
  2216.     if (_cairo_cache_lookup (&to_device(surface->base.device)->path_fill_staging_cache, &meta->cache_entry)) {
  2217.         _cairo_cogl_path_fill_meta_reference (meta);
  2218.         _cairo_cache_remove (&to_device(surface->base.device)->path_fill_staging_cache, &meta->cache_entry);
  2219.     }
  2220.  
  2221.     meta->cache_entry.size = size;
  2222.     if (_cairo_cache_insert (&to_device(surface->base.device)->path_fill_prim_cache, &meta->cache_entry) !=
  2223.         CAIRO_STATUS_SUCCESS)
  2224.         _cairo_cogl_path_fill_meta_destroy (meta);
  2225. }
  2226.  
  2227. static cairo_cogl_path_fill_meta_t *
  2228. _cairo_cogl_get_path_fill_meta (cairo_cogl_surface_t *surface)
  2229. {
  2230.     unsigned long hash;
  2231.     cairo_cogl_path_fill_meta_t *meta = NULL;
  2232.     cairo_path_fixed_t *meta_path = NULL;
  2233.     cairo_status_t status;
  2234.  
  2235.     if (!surface->user_path)
  2236.         return NULL;
  2237.  
  2238.     hash = _cairo_path_fixed_hash (surface->user_path);
  2239.  
  2240.     meta = _cairo_cogl_path_fill_meta_lookup (to_device(surface->base.device),
  2241.                                               hash, surface->user_path);
  2242.     if (meta)
  2243.         return meta;
  2244.  
  2245.     meta = calloc (1, sizeof (cairo_cogl_path_fill_meta_t));
  2246.     if (!meta)
  2247.         goto BAIL;
  2248.     meta->cache_entry.hash = hash;
  2249.     meta->counter = 0;
  2250.     CAIRO_REFERENCE_COUNT_INIT (&meta->ref_count, 1);
  2251.     meta_path = malloc (sizeof (cairo_path_fixed_t));
  2252.     if (!meta_path)
  2253.         goto BAIL;
  2254.     /* FIXME: we should add a ref-counted wrapper for our user_paths
  2255.      * so we don't have to keep copying them here! */
  2256.     status = _cairo_path_fixed_init_copy (meta_path, surface->user_path);
  2257.     if (unlikely (status))
  2258.         goto BAIL;
  2259.     meta->user_path = meta_path;
  2260.     meta->ctm_inverse = *surface->ctm_inverse;
  2261.  
  2262.     /* To start with - until we associate a CoglPrimitive with the meta
  2263.      * structure - we keep the meta in a staging structure until we
  2264.      * see whether it actually gets re-used. */
  2265.     meta->cache_entry.size = 1;
  2266.     if (_cairo_cache_insert (&to_device(surface->base.device)->path_fill_staging_cache, &meta->cache_entry) !=
  2267.         CAIRO_STATUS_SUCCESS)
  2268.         _cairo_cogl_path_fill_meta_destroy (meta);
  2269.  
  2270.     return meta;
  2271.  
  2272. BAIL:
  2273.     free (meta_path);
  2274.     free (meta);
  2275.     return NULL;
  2276. }
  2277.  
  2278. static cairo_int_status_t
  2279. _cairo_cogl_surface_fill (void                      *abstract_surface,
  2280.                           cairo_operator_t           op,
  2281.                           const cairo_pattern_t     *source,
  2282.                           const cairo_path_fixed_t  *path,
  2283.                           cairo_fill_rule_t          fill_rule,
  2284.                           double                     tolerance,
  2285.                           cairo_antialias_t          antialias,
  2286.                           const cairo_clip_t        *clip)
  2287. {
  2288.     cairo_cogl_surface_t *surface = abstract_surface;
  2289.     cairo_composite_rectangles_t extents;
  2290.     cairo_status_t status;
  2291. #ifdef ENABLE_PATH_CACHE
  2292.     cairo_cogl_path_fill_meta_t *meta = NULL;
  2293.     cairo_matrix_t transform_matrix;
  2294. #endif
  2295.     cairo_matrix_t *transform = NULL;
  2296.     cairo_bool_t one_shot = TRUE;
  2297.     CoglPrimitive *prim = NULL;
  2298.     cairo_bool_t new_prim = FALSE;
  2299.     CoglPipeline *pipeline;
  2300.  
  2301.     if (! is_operator_supported (op))
  2302.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2303.  
  2304.     /* FIXME - support unbounded operators */
  2305.     if (!_cairo_operator_bounded_by_mask (op)) {
  2306.         /* Currently IN this is the only unbounded operator we aim to support
  2307.          * in cairo-cogl. */
  2308.         assert (op == CAIRO_OPERATOR_IN);
  2309.         g_warning ("FIXME: handle filling with unbounded operators!");
  2310.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2311.     }
  2312.  
  2313.     status = _cairo_composite_rectangles_init_for_fill (&extents,
  2314.                                                         &surface->base,
  2315.                                                         op, source, path,
  2316.                                                         clip);
  2317.     if (unlikely (status))
  2318.         return status;
  2319.  
  2320. #ifndef FILL_WITH_COGL_PATH
  2321. #ifdef ENABLE_PATH_CACHE
  2322.     meta = _cairo_cogl_get_path_fill_meta (surface);
  2323.     if (meta) {
  2324.         prim = meta->prim;
  2325.         if (prim) {
  2326.             cairo_matrix_multiply (&transform_matrix, &meta->ctm_inverse, surface->ctm);
  2327.             transform = &transform_matrix;
  2328.         } else if (meta->counter++ > 10)
  2329.             one_shot = FALSE;
  2330.     }
  2331. #endif /* ENABLE_PATH_CACHE */
  2332.  
  2333.     if (!prim) {
  2334.         int n_layers = _cairo_cogl_source_n_layers (source);
  2335.         size_t prim_size;
  2336.         status = _cairo_cogl_fill_to_primitive (surface, path, fill_rule, tolerance,
  2337.                                                 one_shot, n_layers, &prim, &prim_size);
  2338.         if (unlikely (status))
  2339.             return status;
  2340.         new_prim = TRUE;
  2341. #ifdef ENABLE_PATH_CACHE
  2342.         if (meta) {
  2343.             meta->prim = cogl_object_ref (prim);
  2344.             _cairo_cogl_path_fill_meta_set_prim_size (surface, meta, prim_size);
  2345.         }
  2346. #endif /* ENABLE_PATH_CACHE */
  2347.     }
  2348.  
  2349. #endif /* !FILL_WITH_COGL_PATH */
  2350.  
  2351.     pipeline = get_source_mask_operator_destination_pipeline (NULL, source,
  2352.                                                               op, surface, &extents);
  2353.     if (!pipeline)
  2354.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2355.  
  2356.     _cairo_cogl_maybe_log_clip (surface, &extents);
  2357.  
  2358. #ifndef FILL_WITH_COGL_PATH
  2359.     _cairo_cogl_journal_log_primitive (surface, pipeline, prim, transform);
  2360.     /* The journal will take a reference on the prim */
  2361.     if (new_prim)
  2362.         cogl_object_unref (prim);
  2363. #else
  2364.     CoglPath * cogl_path = _cairo_cogl_util_path_from_cairo (path, fill_rule, tolerance);
  2365.     _cairo_cogl_journal_log_path (surface, pipeline, cogl_path);
  2366.     cogl_object_unref (cogl_path);
  2367. #endif
  2368.  
  2369.     /* The journal will take a reference on the pipeline... */
  2370.     cogl_object_unref (pipeline);
  2371.  
  2372.     return CAIRO_INT_STATUS_SUCCESS;
  2373. }
  2374.  
  2375. cairo_int_status_t
  2376. _cairo_cogl_surface_fill_rectangle (void                     *abstract_surface,
  2377.                                     cairo_operator_t          op,
  2378.                                     const cairo_pattern_t    *source,
  2379.                                     double                    x,
  2380.                                     double                    y,
  2381.                                     double                    width,
  2382.                                     double                    height,
  2383.                                     cairo_matrix_t           *ctm,
  2384.                                     const cairo_clip_t       *clip)
  2385. {
  2386.     cairo_cogl_surface_t *surface = abstract_surface;
  2387.     CoglPipeline *pipeline;
  2388.  
  2389.     if (! is_operator_supported (op))
  2390.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2391.  
  2392.     /* FIXME - support unbounded operators */
  2393.     if (!_cairo_operator_bounded_by_mask (op)) {
  2394.         /* Currently IN this is the only unbounded operator we aim to support
  2395.          * in cairo-cogl. */
  2396.         assert (op == CAIRO_OPERATOR_IN);
  2397.         g_warning ("FIXME: handle filling with unbounded operators!");
  2398.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2399.     }
  2400.  
  2401.     /* FIXME */
  2402. #if 0
  2403.     status = _cairo_composite_rectangles_init_for_fill_rectangle (&extents,
  2404.                                                                   &surface->base,
  2405.                                                                   op, source, path,
  2406.                                                                   clip);
  2407.     if (unlikely (status))
  2408.         return status;
  2409. #endif
  2410.  
  2411.     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
  2412.         double x1 = x;
  2413.         double y1 = y;
  2414.         double x2 = x1 + width;
  2415.         double y2 = y1 + height;
  2416.  
  2417.         pipeline = get_source_mask_operator_destination_pipeline (NULL, source,
  2418.                                                                   op, surface, NULL);
  2419.         if (!pipeline)
  2420.             return CAIRO_INT_STATUS_UNSUPPORTED;
  2421.  
  2422.         _cairo_cogl_log_clip (surface, clip);
  2423.  
  2424.         _cairo_cogl_journal_log_rectangle (surface,
  2425.                                            pipeline,
  2426.                                            x1, y1, x2, y2,
  2427.                                            0,
  2428.                                            ctm);
  2429.         return CAIRO_INT_STATUS_SUCCESS;
  2430.     } else
  2431.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2432.  
  2433.     /* TODO:
  2434.      * We need to acquire the textures here, look at the corresponding
  2435.      * attributes and see if this can be trivially handled by logging
  2436.      * a textured rectangle only needing simple scaling or translation
  2437.      * of texture coordinates.
  2438.      *
  2439.      * At this point we should also aim to remap the default
  2440.      * EXTEND_NONE mode to EXTEND_PAD which is more efficient if we
  2441.      * know it makes no difference either way since we can map that to
  2442.      * CLAMP_TO_EDGE.
  2443.      */
  2444. }
  2445.  
  2446. static cairo_int_status_t
  2447. _cairo_cogl_surface_show_glyphs (void                   *surface,
  2448.                                  cairo_operator_t        op,
  2449.                                  const cairo_pattern_t  *source,
  2450.                                  cairo_glyph_t          *glyphs,
  2451.                                  int                     num_glyphs,
  2452.                                  cairo_scaled_font_t    *scaled_font,
  2453.                                  const cairo_clip_t     *clip)
  2454. {
  2455.     return CAIRO_INT_STATUS_UNSUPPORTED;
  2456. }
  2457.  
  2458. const cairo_surface_backend_t _cairo_cogl_surface_backend = {
  2459.     CAIRO_SURFACE_TYPE_COGL,
  2460.     _cairo_cogl_surface_finish,
  2461. #ifdef NEED_COGL_CONTEXT
  2462.     _cairo_cogl_context_create,
  2463. #else
  2464.     _cairo_default_context_create,
  2465. #endif
  2466.  
  2467.     _cairo_cogl_surface_create_similar,
  2468.     NULL, /* create similar image */
  2469.     NULL, /* map to image */
  2470.     NULL, /* unmap image */
  2471.  
  2472.     _cairo_surface_default_source,
  2473.     _cairo_cogl_surface_acquire_source_image,
  2474.     _cairo_cogl_surface_release_source_image,
  2475.     NULL, /* snapshot */
  2476.  
  2477.     NULL, /* copy_page */
  2478.     NULL, /* show_page */
  2479.  
  2480.     _cairo_cogl_surface_get_extents,
  2481.     NULL, /* get_font_options */
  2482.  
  2483.     _cairo_cogl_surface_flush, /* flush */
  2484.     NULL, /* mark_dirty_rectangle */
  2485.  
  2486.     _cairo_cogl_surface_paint,
  2487.     _cairo_cogl_surface_mask,
  2488.     _cairo_cogl_surface_stroke,
  2489.     _cairo_cogl_surface_fill,
  2490.     NULL, /* fill_stroke*/
  2491.     _cairo_surface_fallback_glyphs,
  2492. };
  2493.  
  2494. static cairo_surface_t *
  2495. _cairo_cogl_surface_create_full (cairo_cogl_device_t *dev,
  2496.                                  cairo_bool_t ignore_alpha,
  2497.                                  CoglFramebuffer *framebuffer,
  2498.                                  CoglTexture *texture)
  2499. {
  2500.     cairo_cogl_surface_t *surface;
  2501.     cairo_status_t status;
  2502.  
  2503.     status = cairo_device_acquire (&dev->base);
  2504.     if (unlikely (status))
  2505.         return _cairo_surface_create_in_error (status);
  2506.  
  2507.     surface = malloc (sizeof (cairo_cogl_surface_t));
  2508.     if (unlikely (surface == NULL))
  2509.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  2510.  
  2511.     surface->ignore_alpha = ignore_alpha;
  2512.  
  2513.     surface->framebuffer = framebuffer;
  2514.     if (framebuffer) {
  2515.         surface->width = cogl_framebuffer_get_width (framebuffer);
  2516.         surface->height = cogl_framebuffer_get_height (framebuffer);
  2517.         surface->cogl_format = cogl_framebuffer_get_color_format (framebuffer);
  2518.         cogl_object_ref (framebuffer);
  2519.     }
  2520.  
  2521.     /* FIXME: If texture == NULL and we are given an offscreen framebuffer
  2522.      * then we want a way to poke inside the framebuffer to get a texture */
  2523.     surface->texture = texture;
  2524.     if (texture) {
  2525.         if (!framebuffer) {
  2526.             surface->width = cogl_texture_get_width (texture);
  2527.             surface->height = cogl_texture_get_height (texture);
  2528.             surface->cogl_format = cogl_texture_get_format (texture);
  2529.         }
  2530.         cogl_object_ref (texture);
  2531.     }
  2532.  
  2533.     assert(surface->width && surface->height);
  2534.  
  2535.     surface->journal = NULL;
  2536.  
  2537.     surface->buffer_stack = NULL;
  2538.     surface->buffer_stack_size = 4096;
  2539.  
  2540.     surface->last_clip = NULL;
  2541.  
  2542.     surface->n_clip_updates_per_frame = 0;
  2543.  
  2544.     _cairo_surface_init (&surface->base,
  2545.                          &_cairo_cogl_surface_backend,
  2546.                          &dev->base,
  2547.                          CAIRO_CONTENT_COLOR_ALPHA);
  2548.  
  2549.     return &surface->base;
  2550. }
  2551.  
  2552. cairo_surface_t *
  2553. cairo_cogl_surface_create (cairo_device_t  *abstract_device,
  2554.                            CoglFramebuffer *framebuffer)
  2555. {
  2556.     cairo_cogl_device_t *dev = (cairo_cogl_device_t *)abstract_device;
  2557.  
  2558.     if (abstract_device == NULL)
  2559.         return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_ERROR);
  2560.  
  2561.     if (abstract_device->status)
  2562.         return _cairo_surface_create_in_error (abstract_device->status);
  2563.  
  2564.     if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_COGL)
  2565.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
  2566.  
  2567.     return _cairo_cogl_surface_create_full (dev, FALSE, framebuffer, NULL);
  2568. }
  2569. slim_hidden_def (cairo_cogl_surface_create);
  2570.  
  2571. CoglFramebuffer *
  2572. cairo_cogl_surface_get_framebuffer (cairo_surface_t *abstract_surface)
  2573. {
  2574.     cairo_cogl_surface_t *surface;
  2575.  
  2576.     if (abstract_surface->backend != &_cairo_cogl_surface_backend) {
  2577.         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  2578.         return NULL;
  2579.     }
  2580.  
  2581.     surface = (cairo_cogl_surface_t *) abstract_surface;
  2582.  
  2583.     return surface->framebuffer;
  2584. }
  2585. slim_hidden_def (cairo_cogl_surface_get_framebuffer);
  2586.  
  2587. CoglTexture *
  2588. cairo_cogl_surface_get_texture (cairo_surface_t *abstract_surface)
  2589. {
  2590.     cairo_cogl_surface_t *surface;
  2591.  
  2592.     if (abstract_surface->backend != &_cairo_cogl_surface_backend) {
  2593.         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  2594.         return NULL;
  2595.     }
  2596.  
  2597.     surface = (cairo_cogl_surface_t *) abstract_surface;
  2598.  
  2599.     return surface->texture;
  2600. }
  2601. slim_hidden_def (cairo_cogl_surface_get_texture);
  2602.  
  2603. static cairo_status_t
  2604. _cairo_cogl_device_flush (void *device)
  2605. {
  2606.     cairo_status_t status;
  2607.  
  2608.     status = cairo_device_acquire (device);
  2609.     if (unlikely (status))
  2610.         return status;
  2611.  
  2612.     /* XXX: we don't need to flush Cogl here, we just need to flush
  2613.      * any batching we do of compositing primitives. */
  2614.  
  2615.     cairo_device_release (device);
  2616.  
  2617.     return CAIRO_STATUS_SUCCESS;
  2618. }
  2619.  
  2620. static void
  2621. _cairo_cogl_device_finish (void *device)
  2622. {
  2623.     cairo_status_t status;
  2624.  
  2625.     status = cairo_device_acquire (device);
  2626.     if (unlikely (status))
  2627.         return;
  2628.  
  2629.     /* XXX: Drop references to external resources */
  2630.  
  2631.     cairo_device_release (device);
  2632. }
  2633.  
  2634. static void
  2635. _cairo_cogl_device_destroy (void *device)
  2636. {
  2637.     cairo_cogl_device_t *dev = device;
  2638.  
  2639.     /* FIXME: Free stuff! */
  2640.  
  2641.     g_free (dev);
  2642. }
  2643.  
  2644. static const cairo_device_backend_t _cairo_cogl_device_backend = {
  2645.     CAIRO_DEVICE_TYPE_COGL,
  2646.  
  2647.     NULL, /* lock */
  2648.     NULL, /* unlock */
  2649.  
  2650.     _cairo_cogl_device_flush,
  2651.     _cairo_cogl_device_finish,
  2652.     _cairo_cogl_device_destroy,
  2653. };
  2654.  
  2655. static cairo_bool_t
  2656. set_blend (CoglPipeline *pipeline, const char *blend_string)
  2657. {
  2658.     GError *error = NULL;
  2659.     if (!cogl_pipeline_set_blend (pipeline, blend_string, &error)) {
  2660.         g_warning ("Unsupported blend string with current gpu/driver: %s", blend_string);
  2661.         g_error_free (error);
  2662.         return FALSE;
  2663.     }
  2664.     return TRUE;
  2665. }
  2666.  
  2667. static cairo_bool_t
  2668. _cairo_cogl_setup_op_state (CoglPipeline *pipeline, cairo_operator_t op)
  2669. {
  2670.     cairo_bool_t status = FALSE;
  2671.  
  2672.     switch ((int)op)
  2673.     {
  2674.     case CAIRO_OPERATOR_SOURCE:
  2675.         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR, 0)");
  2676.         break;
  2677.     case CAIRO_OPERATOR_OVER:
  2678.         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR, DST_COLOR * (1 - SRC_COLOR[A]))");
  2679.         break;
  2680.     case CAIRO_OPERATOR_IN:
  2681.         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR * DST_COLOR[A], 0)");
  2682.         break;
  2683.     case CAIRO_OPERATOR_DEST_OVER:
  2684.         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR * (1 - DST_COLOR[A]), DST_COLOR)");
  2685.         break;
  2686.     case CAIRO_OPERATOR_DEST_IN:
  2687.         status = set_blend (pipeline, "RGBA = ADD (0, DST_COLOR * SRC_COLOR[A])");
  2688.         break;
  2689.     case CAIRO_OPERATOR_ADD:
  2690.         status = set_blend (pipeline, "RGBA = ADD (SRC_COLOR, DST_COLOR)");
  2691.         break;
  2692.     }
  2693.  
  2694.     return status;
  2695. }
  2696.  
  2697. static void
  2698. create_templates_for_op (cairo_cogl_device_t *dev, cairo_operator_t op)
  2699. {
  2700.     CoglPipeline *base = cogl_pipeline_new ();
  2701.     CoglPipeline *pipeline;
  2702.     CoglColor color;
  2703.  
  2704.     if (!_cairo_cogl_setup_op_state (base, op)) {
  2705.         cogl_object_unref (base);
  2706.         return;
  2707.     }
  2708.  
  2709.     dev->template_pipelines[op][CAIRO_COGL_TEMPLATE_TYPE_SOLID] = base;
  2710.  
  2711.     pipeline = cogl_pipeline_copy (base);
  2712.     cogl_pipeline_set_layer_texture (pipeline, 0, dev->dummy_texture);
  2713.     dev->template_pipelines[op][CAIRO_COGL_TEMPLATE_TYPE_TEXTURE] = pipeline;
  2714.  
  2715.     pipeline = cogl_pipeline_copy (base);
  2716.     cogl_pipeline_set_layer_combine (pipeline, 1,
  2717.                                      "RGBA = MODULATE (PREVIOUS, CONSTANT[A])",
  2718.                                      NULL);
  2719.     cogl_pipeline_set_layer_combine_constant (pipeline, 1, &color);
  2720.     cogl_pipeline_set_layer_texture (pipeline, 1, dev->dummy_texture);
  2721.     dev->template_pipelines[op][CAIRO_COGL_TEMPLATE_TYPE_MASK_SOLID] = pipeline;
  2722.  
  2723.     pipeline = cogl_pipeline_copy (base);
  2724.     cogl_pipeline_set_layer_combine (pipeline, 1,
  2725.                                      "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
  2726.                                      NULL);
  2727.     cogl_pipeline_set_layer_texture (pipeline, 1, dev->dummy_texture);
  2728.     dev->template_pipelines[op][CAIRO_COGL_TEMPLATE_TYPE_MASK_TEXTURE] = pipeline;
  2729. }
  2730.  
  2731. cairo_device_t *
  2732. cairo_cogl_device_create (CoglContext *cogl_context)
  2733. {
  2734.     cairo_cogl_device_t *dev = g_new0 (cairo_cogl_device_t, 1);
  2735.     cairo_status_t status;
  2736.  
  2737.     dev->backend_vtable_initialized = FALSE;
  2738.  
  2739.     dev->cogl_context = cogl_context;
  2740.  
  2741.     dev->dummy_texture = cogl_texture_new_with_size (1, 1,
  2742.                                                      COGL_TEXTURE_NO_SLICING,
  2743.                                                      COGL_PIXEL_FORMAT_ANY);
  2744.     if (!dev->dummy_texture)
  2745.         goto ERROR;
  2746.  
  2747.     memset (dev->template_pipelines, 0, sizeof (dev->template_pipelines));
  2748.     create_templates_for_op (dev, CAIRO_OPERATOR_SOURCE);
  2749.     create_templates_for_op (dev, CAIRO_OPERATOR_OVER);
  2750.     create_templates_for_op (dev, CAIRO_OPERATOR_IN);
  2751.     create_templates_for_op (dev, CAIRO_OPERATOR_DEST_OVER);
  2752.     create_templates_for_op (dev, CAIRO_OPERATOR_DEST_IN);
  2753.     create_templates_for_op (dev, CAIRO_OPERATOR_ADD);
  2754.  
  2755.     status = _cairo_cache_init (&dev->linear_cache,
  2756.                                 _cairo_cogl_linear_gradient_equal,
  2757.                                 NULL,
  2758.                                 (cairo_destroy_func_t) _cairo_cogl_linear_gradient_destroy,
  2759.                                 CAIRO_COGL_LINEAR_GRADIENT_CACHE_SIZE);
  2760.     if (unlikely (status))
  2761.         return _cairo_device_create_in_error(status);
  2762.  
  2763.     status = _cairo_cache_init (&dev->path_fill_staging_cache,
  2764.                                 _cairo_cogl_path_fill_meta_equal,
  2765.                                 NULL,
  2766.                                 (cairo_destroy_func_t) _cairo_cogl_path_fill_meta_destroy,
  2767.                                 1000);
  2768.  
  2769.     status = _cairo_cache_init (&dev->path_stroke_staging_cache,
  2770.                                 _cairo_cogl_path_stroke_meta_equal,
  2771.                                 NULL,
  2772.                                 (cairo_destroy_func_t) _cairo_cogl_path_stroke_meta_destroy,
  2773.                                 1000);
  2774.  
  2775.     status = _cairo_cache_init (&dev->path_fill_prim_cache,
  2776.                                 _cairo_cogl_path_fill_meta_equal,
  2777.                                 NULL,
  2778.                                 (cairo_destroy_func_t) _cairo_cogl_path_fill_meta_destroy,
  2779.                                 CAIRO_COGL_PATH_META_CACHE_SIZE);
  2780.  
  2781.     status = _cairo_cache_init (&dev->path_stroke_prim_cache,
  2782.                                 _cairo_cogl_path_stroke_meta_equal,
  2783.                                 NULL,
  2784.                                 (cairo_destroy_func_t) _cairo_cogl_path_stroke_meta_destroy,
  2785.                                 CAIRO_COGL_PATH_META_CACHE_SIZE);
  2786.  
  2787.     _cairo_device_init (&dev->base, &_cairo_cogl_device_backend);
  2788.     return &dev->base;
  2789.  
  2790. ERROR:
  2791.     g_free (dev);
  2792.     return NULL;
  2793. }
  2794. slim_hidden_def (cairo_cogl_device_create);
  2795.  
  2796. void
  2797. cairo_cogl_surface_end_frame (cairo_surface_t *abstract_surface)
  2798. {
  2799.     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
  2800.     cairo_surface_flush (abstract_surface);
  2801.  
  2802.     //g_print ("n_clip_update_per_frame = %d\n", surface->n_clip_updates_per_frame);
  2803.     surface->n_clip_updates_per_frame = 0;
  2804. }
  2805. slim_hidden_def (cairo_cogl_surface_end_frame);
  2806.