1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2011 Intel Corporation.
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.
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
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/
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.
29 * Robert Bragg <robert@linux.intel.com>
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"
53 #include "cairo-cogl.h"
55 #include <cogl/cogl2-experimental.h>
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
66 #if defined (USE_COGL_RECTANGLE_API) || defined (ENABLE_PATH_CACHE)
67 #define NEED_COGL_CONTEXT
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; \
76 #define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
79 #define CAIRO_COGL_PATH_META_CACHE_SIZE (1024 * 1024)
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
;
88 CoglPipelineWrapMode s_wrap
;
89 CoglPipelineWrapMode t_wrap
;
90 } cairo_cogl_texture_attributes_t
;
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
;
99 typedef struct _cairo_cogl_journal_entry
{
100 cairo_cogl_journal_entry_type_t type
;
101 } cairo_cogl_journal_entry_t
;
103 typedef struct _cairo_cogl_journal_clip_entry
{
104 cairo_cogl_journal_entry_t base
;
106 } cairo_cogl_journal_clip_entry_t
;
108 typedef struct _cairo_cogl_journal_rect_entry
{
109 cairo_cogl_journal_entry_t base
;
110 CoglPipeline
*pipeline
;
117 } cairo_cogl_journal_rect_entry_t
;
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
;
127 typedef struct _cairo_cogl_journal_path_entry
{
128 cairo_cogl_journal_entry_t base
;
129 CoglPipeline
*pipeline
;
131 } cairo_cogl_journal_path_entry_t
;
133 typedef struct _cairo_cogl_path_fill_meta
{
134 cairo_cache_entry_t cache_entry
;
135 cairo_reference_count_t ref_count
;
137 cairo_path_fixed_t
*user_path
;
138 cairo_matrix_t ctm_inverse
;
142 /* A cached path tessellation should be re-usable with different rotations
143 * and translations but not for different scales.
145 * one idea is to track the diagonal lenghts of a unit rectangle
146 * transformed through the original ctm use to tessellate the geometry
147 * so we can check what the lengths are for any new ctm to know if
148 * this geometry is compatible.
153 } cairo_cogl_path_fill_meta_t
;
155 typedef struct _cairo_cogl_path_stroke_meta
{
156 cairo_cache_entry_t cache_entry
;
157 cairo_reference_count_t ref_count
;
159 cairo_path_fixed_t
*user_path
;
160 cairo_matrix_t ctm_inverse
;
161 cairo_stroke_style_t style
;
166 /* A cached path tessellation should be re-usable with different rotations
167 * and translations but not for different scales.
169 * one idea is to track the diagonal lenghts of a unit rectangle
170 * transformed through the original ctm use to tessellate the geometry
171 * so we can check what the lengths are for any new ctm to know if
172 * this geometry is compatible.
177 } cairo_cogl_path_stroke_meta_t
;
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
);
185 static cairo_int_status_t
186 _cairo_cogl_surface_fill (void *abstract_surface
,
188 const cairo_pattern_t
*source
,
189 const cairo_path_fixed_t
*path
,
190 cairo_fill_rule_t fill_rule
,
192 cairo_antialias_t antialias
,
193 const cairo_clip_t
*clip
);
196 _cairo_cogl_journal_flush (cairo_cogl_surface_t
*surface
);
198 cairo_private
extern const cairo_surface_backend_t _cairo_cogl_surface_backend
;
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
);
206 static cairo_cogl_device_t
*
207 to_device (cairo_device_t
*device
)
209 return (cairo_cogl_device_t
*)device
;
212 /* moves trap points such that they become the actual corners of the trapezoid */
214 _sanitize_trap (cairo_trapezoid_t
*t
)
216 cairo_trapezoid_t s
= *t
;
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); \
224 FIX (left
, bottom
, p2
);
225 FIX (right
, top
, p1
);
226 FIX (right
, bottom
, p2
);
229 static cairo_status_t
230 _cairo_cogl_surface_ensure_framebuffer (cairo_cogl_surface_t
*surface
)
232 GError
*error
= NULL
;
234 if (surface
->framebuffer
)
235 return CAIRO_STATUS_SUCCESS
;
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
;
245 cogl_push_framebuffer (surface
->framebuffer
);
246 cogl_ortho (0, surface
->width
,
249 cogl_pop_framebuffer ();
251 return CAIRO_STATUS_SUCCESS
;
254 static cairo_surface_t
*
255 _cairo_cogl_surface_create_similar (void *abstract_surface
,
256 cairo_content_t content
,
260 cairo_cogl_surface_t
*reference_surface
= abstract_surface
;
261 cairo_cogl_surface_t
*surface
;
262 CoglTexture
*texture
;
263 cairo_status_t status
;
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
);
271 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
273 surface
= (cairo_cogl_surface_t
*)
274 _cairo_cogl_surface_create_full (to_device(reference_surface
->base
.device
),
275 (content
& CAIRO_CONTENT_ALPHA
) == 0,
278 if (unlikely (surface
->base
.status
))
279 return &surface
->base
;
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
);
287 return &surface
->base
;
291 _cairo_cogl_surface_get_extents (void *abstract_surface
,
292 cairo_rectangle_int_t
*extents
)
294 cairo_cogl_surface_t
*surface
= abstract_surface
;
298 extents
->width
= surface
->width
;
299 extents
->height
= surface
->height
;
305 _cairo_cogl_journal_free (cairo_cogl_surface_t
*surface
)
309 for (l
= surface
->journal
->head
; l
; l
= l
->next
) {
310 cairo_cogl_journal_entry_t
*entry
= l
->data
;
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
);
323 g_queue_free (surface
->journal
);
324 surface
->journal
= NULL
;
327 #ifdef FILL_WITH_COGL_PATH
329 _cairo_cogl_journal_log_path (cairo_cogl_surface_t
*surface
,
330 CoglPipeline
*pipeline
,
333 cairo_cogl_journal_path_entry_t
*entry
;
335 if (unlikely (surface
->journal
== NULL
))
336 surface
->journal
= g_queue_new ();
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
;
344 entry
->pipeline
= cogl_object_ref (pipeline
);
345 entry
->path
= cogl_object_ref (path
);
347 g_queue_push_tail (surface
->journal
, entry
);
349 #ifdef DISABLE_BATCHING
350 _cairo_cogl_journal_flush (surface
);
353 #endif /* FILL_WITH_COGL_PATH */
356 _cairo_cogl_journal_log_primitive (cairo_cogl_surface_t
*surface
,
357 CoglPipeline
*pipeline
,
358 CoglPrimitive
*primitive
,
359 cairo_matrix_t
*transform
)
361 cairo_cogl_journal_prim_entry_t
*entry
;
363 if (unlikely (surface
->journal
== NULL
))
364 surface
->journal
= g_queue_new ();
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
;
372 entry
->pipeline
= cogl_object_ref (pipeline
);
375 entry
->transform
= *transform
;
376 entry
->has_transform
= TRUE
;
378 entry
->has_transform
= FALSE
;
380 entry
->primitive
= cogl_object_ref (primitive
);
382 g_queue_push_tail (surface
->journal
, entry
);
384 #ifdef DISABLE_BATCHING
385 _cairo_cogl_journal_flush (surface
);
390 _cairo_cogl_journal_log_rectangle (cairo_cogl_surface_t
*surface
,
391 CoglPipeline
*pipeline
,
399 cairo_cogl_journal_rect_entry_t
*entry
;
401 if (unlikely (surface
->journal
== NULL
))
402 surface
->journal
= g_queue_new ();
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
;
410 entry
->pipeline
= cogl_object_ref (pipeline
);
414 entry
->width
= width
;
415 entry
->height
= height
;
418 entry
->n_layers
= n_layers
;
420 g_queue_push_tail (surface
->journal
, entry
);
422 #ifdef DISABLE_BATCHING
423 _cairo_cogl_journal_flush (surface
);
428 _cairo_cogl_journal_log_clip (cairo_cogl_surface_t
*surface
,
429 const cairo_clip_t
*clip
)
431 cairo_cogl_journal_clip_entry_t
*entry
;
433 if (unlikely (surface
->journal
== NULL
))
434 surface
->journal
= g_queue_new ();
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
);
443 g_queue_push_tail (surface
->journal
, entry
);
447 _cairo_cogl_journal_discard (cairo_cogl_surface_t
*surface
)
451 if (!surface
->journal
) {
452 assert (surface
->last_clip
== NULL
);
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
;
462 for (l
= surface
->journal
->head
; l
; l
= l
->next
) {
463 cairo_cogl_journal_entry_t
*entry
= l
->data
;
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
);
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
);
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
);
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
);
499 assert (0); /* not reached! */
500 entry_size
= 0; /* avoid compiler warning */
502 g_slice_free1 (entry_size
, entry
);
505 g_queue_clear (surface
->journal
);
507 if (surface
->last_clip
) {
508 _cairo_clip_destroy (surface
->last_clip
);
509 surface
->last_clip
= NULL
;
513 static CoglAttributeBuffer
*
514 _cairo_cogl_surface_allocate_buffer_space (cairo_cogl_surface_t
*surface
,
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;
530 if (unlikely (surface
->buffer_stack_size
< size
))
531 surface
->buffer_stack_size
= size
* 2;
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;
542 *pointer
= surface
->buffer_stack_pointer
+ surface
->buffer_stack_offset
;
543 *offset
= surface
->buffer_stack_offset
;
545 surface
->buffer_stack_offset
+= size
;
546 return cogl_object_ref (surface
->buffer_stack
);
550 static CoglAttributeBuffer
*
551 _cairo_cogl_traps_to_triangles_buffer (cairo_cogl_surface_t
*surface
,
552 cairo_traps_t
*traps
,
556 CoglAttributeBuffer
*buffer
;
557 int n_traps
= traps
->num_traps
;
559 CoglVertexP2
*triangles
;
562 buffer
= _cairo_cogl_surface_allocate_buffer_space (surface
,
563 n_traps
* sizeof (CoglVertexP2
) * 6,
565 (void **)&triangles
);
569 buffer
= cogl_attribute_buffer_new (n_traps
* sizeof (CoglVertexP2
) * 6, NULL
);
572 triangles
= cogl_buffer_map (COGL_BUFFER (buffer
),
573 COGL_BUFFER_ACCESS_WRITE
,
574 COGL_BUFFER_MAP_HINT_DISCARD
);
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.
587 for (i
= 0; i
< n_traps
; i
++)
589 CoglVertexP2
*p
= &triangles
[i
* 6];
590 cairo_trapezoid_t
*trap
= &traps
->traps
[i
];
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
);
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
);
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
);
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
);
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
);
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
);
612 cogl_buffer_unmap (COGL_BUFFER (buffer
));
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
,
625 CoglAttributeBuffer
*buffer
= _cairo_cogl_traps_to_triangles_buffer (surface
, traps
, &offset
, one_shot
);
626 CoglAttribute
*pos
= cogl_attribute_new (buffer
,
628 sizeof (CoglVertexP2
),
631 COGL_ATTRIBUTE_TYPE_FLOAT
);
634 /* The attribute will have taken a reference on the buffer */
635 cogl_object_unref (buffer
);
637 prim
= cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLES
,
638 traps
->num_traps
* 6, pos
, NULL
);
640 /* The primitive will now keep the attribute alive... */
641 cogl_object_unref (pos
);
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
,
655 CoglAttributeBuffer
*buffer
= _cairo_cogl_traps_to_triangles_buffer (surface
, traps
, &offset
, one_shot
);
656 CoglAttribute
*pos
= cogl_attribute_new (buffer
,
658 sizeof (CoglVertexP2
),
661 COGL_ATTRIBUTE_TYPE_FLOAT
);
662 CoglAttribute
*tex_coords
= cogl_attribute_new (buffer
,
663 "cogl_tex_coord0_in",
664 sizeof (CoglVertexP2
),
667 COGL_ATTRIBUTE_TYPE_FLOAT
);
670 /* The attributes will have taken references on the buffer */
671 cogl_object_unref (buffer
);
673 prim
= cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLES
,
674 traps
->num_traps
* 6, pos
, tex_coords
, NULL
);
676 /* The primitive will now keep the attributes alive... */
677 cogl_object_unref (pos
);
678 cogl_object_unref (tex_coords
);
683 static CoglPrimitive
*
684 _cairo_cogl_traps_to_composite_prim (cairo_cogl_surface_t
*surface
,
685 cairo_traps_t
*traps
,
689 int n_traps
= traps
->num_traps
;
692 /* XXX: Ideally we would skip tessellating to traps entirely since
693 * given their representation, conversion to triangles is quite expensive.
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
699 for (i
= 0; i
< n_traps
; i
++)
700 _sanitize_trap (&traps
->traps
[i
]);
703 return _cairo_cogl_traps_to_composite_prim_p2 (surface
, traps
, one_shot
);
705 assert (n_layers
== 1);
706 return _cairo_cogl_traps_to_composite_prim_p2t2 (surface
, traps
, one_shot
);
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
,
716 cairo_bool_t one_shot
,
717 CoglPrimitive
**primitive
,
721 cairo_int_status_t status
;
723 _cairo_traps_init (&traps
);
724 status
= _cairo_path_fixed_fill_to_traps (path
, fill_rule
, tolerance
, &traps
);
725 if (unlikely (status
))
728 if (traps
.num_traps
== 0) {
729 status
= CAIRO_INT_STATUS_NOTHING_TO_DO
;
733 *size
= traps
.num_traps
* sizeof (CoglVertexP2
) * 6;
735 *primitive
= _cairo_cogl_traps_to_composite_prim (surface
, &traps
, n_layers
, one_shot
);
737 status
= CAIRO_INT_STATUS_NO_MEMORY
;
742 _cairo_traps_fini (&traps
);
747 _cairo_cogl_clip_push_box (const cairo_box_t
*box
)
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
);
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
);
762 _cairo_cogl_journal_flush (cairo_cogl_surface_t
*surface
)
765 int clip_stack_depth
= 0;
768 if (!surface
->journal
)
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
;
777 cogl_set_framebuffer (surface
->framebuffer
);
781 for (l
= surface
->journal
->head
; l
; l
= l
->next
) {
782 cairo_cogl_journal_entry_t
*entry
= l
->data
;
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
;
791 cairo_bool_t checked_for_primitives
= FALSE
;
792 cairo_cogl_clip_primitives_t
*clip_primitives
;
795 for (i
= 0; i
< clip_stack_depth
; i
++)
797 clip_stack_depth
= 0;
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
;
805 _cairo_path_fixed_approximate_clip_extents (&path
->path
, &extents
);
807 /* TODO - maintain a fifo of the last 10 used clips with cached
808 * primitives to see if we can avoid tessellating the path and
809 * uploading the vertices...
812 if (!checked_for_primitives
) {
813 clip_primitives
= find_clip_primitives (clip
);
814 checked_for_primitives
= TRUE
;
817 prim
= clip_primitives
->primitives
[i
];
819 status
= _cairo_cogl_fill_to_primitive (surface
,
827 if (unlikely (status
)) {
828 g_warning ("Failed to get primitive for clip path while flushing journal");
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
);
839 for (i
= 0; i
< clip_entry
->clip
->num_boxes
; i
++) {
841 _cairo_cogl_clip_push_box (&clip_entry
->clip
->boxes
[i
]);
844 surface
->n_clip_updates_per_frame
++;
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
;
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
;
857 ctm
->xx
, ctm
->yx
, 0, 0,
858 ctm
->xy
, ctm
->yy
, 0, 0,
860 ctm
->x0
, ctm
->y0
, 0, 1
862 CoglMatrix transform
;
864 cogl_matrix_init_from_array (&transform
, ctmfv
);
866 if (rect_entry
->n_layers
) {
867 g_assert (rect_entry
->n_layers
<= 2);
872 if (rect_entry
->n_layers
> 1)
873 memcpy (&tex_coords
[4], tex_coords
, sizeof (float) * 4);
876 cogl_set_source (rect_entry
->pipeline
);
878 cogl_transform (&transform
);
879 cogl_rectangle_with_multitexture_coords (x1
, y1
, x2
, y2
,
880 tex_coords
, 4 * rect_entry
->n_layers
);
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
;
890 if (prim_entry
->has_transform
) {
891 cairo_matrix_t
*ctm
= &prim_entry
->transform
;
893 ctm
->xx
, ctm
->yx
, 0, 0,
894 ctm
->xy
, ctm
->yy
, 0, 0,
896 ctm
->x0
, ctm
->y0
, 0, 1
898 cogl_matrix_init_from_array (&transform
, ctmfv
);
899 cogl_transform (&transform
);
901 cogl_matrix_init_identity (&transform
);
902 cogl_set_modelview_matrix (&transform
);
905 cogl_set_source (prim_entry
->pipeline
);
906 cogl_primitive_draw (prim_entry
->primitive
);
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
;
914 cogl_set_source (path_entry
->pipeline
);
915 cogl_path_fill (path_entry
->path
);
919 assert (0); /* not reached! */
925 for (i
= 0; i
< clip_stack_depth
; i
++)
928 _cairo_cogl_journal_discard (surface
);
931 static cairo_status_t
932 _cairo_cogl_surface_flush (void *abstract_surface
,
935 cairo_cogl_surface_t
*surface
= (cairo_cogl_surface_t
*)abstract_surface
;
938 return CAIRO_STATUS_SUCCESS
;
940 _cairo_cogl_journal_flush (surface
);
942 return CAIRO_STATUS_SUCCESS
;
945 static cairo_status_t
946 _cairo_cogl_surface_finish (void *abstract_surface
)
948 cairo_cogl_surface_t
*surface
= abstract_surface
;
950 if (surface
->texture
)
951 cogl_object_unref (surface
->texture
);
953 if (surface
->framebuffer
)
954 cogl_object_unref (surface
->framebuffer
);
956 if (surface
->journal
)
957 _cairo_cogl_journal_free (surface
);
960 cairo_device_release (surface
->base
.device
);
962 return CAIRO_STATUS_SUCCESS
;
965 static CoglPixelFormat
966 get_cogl_format_from_cairo_format (cairo_format_t cairo_format
);
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
)
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
;
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
;
988 g_warning("bad format: %x a? %d, bgr? %d, pre %d, format: %d\n",
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
;
998 static CoglPixelFormat
999 get_cogl_format_from_cairo_format (cairo_format_t cairo_format
)
1001 switch (cairo_format
)
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
;
1008 return COGL_PIXEL_FORMAT_ARGB_8888_PRE
;
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
:
1020 g_warn_if_reached ();
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
)
1029 cairo_image_surface_t
*image
;
1030 cairo_status_t status
;
1031 cairo_format_t cairo_format
;
1032 CoglPixelFormat cogl_format
;
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
))
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
);
1045 cogl_format
= cogl_framebuffer_get_color_format (surface
->framebuffer
);
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
;
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
,
1059 cogl_pop_framebuffer ();
1063 return CAIRO_STATUS_SUCCESS
;
1066 static cairo_status_t
1067 _cairo_cogl_surface_acquire_source_image (void *abstract_surface
,
1068 cairo_image_surface_t
**image_out
,
1071 cairo_cogl_surface_t
*surface
= abstract_surface
;
1072 cairo_status_t status
;
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
;
1081 cogl_texture_get_data (surface
->texture
,
1082 cogl_texture_get_format (surface
->texture
),
1086 image
->base
.is_clear
= FALSE
;
1089 cairo_rectangle_int_t extents
= {
1090 0, 0, surface
->width
, surface
->height
1092 status
= _cairo_cogl_surface_read_rect_to_image_surface (surface
, &extents
,
1094 if (unlikely (status
))
1098 *image_extra
= NULL
;
1100 return CAIRO_STATUS_SUCCESS
;
1104 _cairo_cogl_surface_release_source_image (void *abstract_surface
,
1105 cairo_image_surface_t
*image
,
1108 cairo_surface_destroy (&image
->base
);
1111 static cairo_status_t
1112 _cairo_cogl_surface_clear (cairo_cogl_surface_t
*surface
,
1113 const cairo_color_t
*color
)
1115 /* Anything batched in the journal up until now is redundant... */
1116 _cairo_cogl_journal_discard (surface
);
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.
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.
1127 * FIXME: we need a way to assert that the clip stack currently isn't
1128 * using the stencil buffer before clearing it here!
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
,
1138 return CAIRO_STATUS_SUCCESS
;
1142 _cairo_cogl_path_fixed_rectangle (cairo_path_fixed_t
*path
,
1145 cairo_fixed_t width
,
1146 cairo_fixed_t height
)
1148 cairo_status_t status
;
1150 status
= _cairo_path_fixed_move_to (path
, x
, y
);
1151 if (unlikely (status
))
1154 status
= _cairo_path_fixed_rel_line_to (path
, width
, 0);
1155 if (unlikely (status
))
1158 status
= _cairo_path_fixed_rel_line_to (path
, 0, height
);
1159 if (unlikely (status
))
1162 status
= _cairo_path_fixed_rel_line_to (path
, -width
, 0);
1163 if (unlikely (status
))
1166 status
= _cairo_path_fixed_close_path (path
);
1167 if (unlikely (status
))
1170 return CAIRO_STATUS_SUCCESS
;
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
)
1179 cairo_cogl_surface_t
*surface
;
1180 cairo_path_fixed_t path
;
1181 cairo_status_t status
;
1182 cairo_matrix_t identity
;
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
);
1195 /* fallback to handling the paint in terms of a fill... */
1197 surface
= abstract_surface
;
1199 _cairo_path_fixed_init (&path
);
1201 status
= _cairo_cogl_path_fixed_rectangle (&path
, 0, 0, surface
->width
, surface
->height
);
1202 if (unlikely (status
))
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
;
1219 status
= _cairo_cogl_surface_fill (abstract_surface
,
1223 CAIRO_FILL_RULE_WINDING
,
1225 CAIRO_ANTIALIAS_DEFAULT
,
1228 _cairo_path_fixed_fini (&path
);
1232 static CoglPipelineWrapMode
1233 get_cogl_wrap_mode_for_extend (cairo_extend_t extend_mode
)
1235 switch (extend_mode
)
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
;
1247 assert (0); /* not reached */
1248 return COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE
;
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
)
1260 int width
= cogl_texture_get_width (texture
);
1261 int height
= cogl_texture_get_height (texture
);
1264 CoglHandle offscreen
= NULL
;
1265 CoglTexture2D
*pot
= NULL
;
1268 pot_width
= _cairo_cogl_util_next_p2 (width
);
1269 pot_height
= _cairo_cogl_util_next_p2 (height
);
1271 if (pot_width
== width
&& pot_height
== height
)
1272 return CAIRO_INT_STATUS_SUCCESS
;
1276 pot
= cogl_texture_2d_new_with_size (context
,
1279 cogl_texture_get_format (texture
),
1284 g_error_free (error
);
1286 if (pot_width
> pot_height
)
1291 if (!pot_width
|| !pot_height
)
1295 *pot_texture
= COGL_TEXTURE (pot
);
1298 return CAIRO_INT_STATUS_NO_MEMORY
;
1300 /* Use the GPU to do a bilinear filtered scale from npot to pot... */
1301 offscreen
= cogl_offscreen_new_to_texture (COGL_TEXTURE (pot
));
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
1306 g_error_free (error
);
1307 cogl_object_unref (pot
);
1308 *pot_texture
= NULL
;
1309 return CAIRO_INT_STATUS_NO_MEMORY
;
1312 cogl_push_framebuffer (COGL_FRAMEBUFFER (offscreen
));
1313 cogl_set_source_texture (texture
);
1314 cogl_rectangle (-1, 1, 1, -1);
1315 cogl_pop_framebuffer ();
1317 cogl_object_unref (offscreen
);
1321 /* NB: a reference for the texture is transferred to the caller which should
1323 static CoglTexture
*
1324 _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t
*reference_surface
,
1325 cairo_surface_t
*abstract_surface
)
1327 cairo_image_surface_t
*image
;
1328 cairo_image_surface_t
*acquired_image
= NULL
;
1330 CoglPixelFormat format
;
1331 cairo_image_surface_t
*image_clone
= NULL
;
1332 CoglTexture2D
*texture
;
1333 GError
*error
= NULL
;
1334 cairo_surface_t
*clone
;
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
;
1342 if (abstract_surface
->type
== CAIRO_SURFACE_TYPE_COGL
) {
1343 if (_cairo_surface_is_subsurface (abstract_surface
)) {
1344 cairo_cogl_surface_t
*surface
;
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
;
1353 clone
= _cairo_surface_has_snapshot (abstract_surface
, &_cairo_cogl_surface_backend
);
1355 cairo_cogl_surface_t
*surface
= (cairo_cogl_surface_t
*)clone
;
1356 return surface
->texture
? cogl_object_ref (surface
->texture
) : NULL
;
1359 g_warning ("Uploading image surface to texture");
1361 if (_cairo_surface_is_image (abstract_surface
)) {
1362 image
= (cairo_image_surface_t
*)abstract_surface
;
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
);
1371 image
= acquired_image
;
1374 format
= get_cogl_format_from_cairo_format (image
->format
);
1377 image_clone
= _cairo_image_surface_coerce (image
);
1378 if (unlikely (image_clone
->base
.status
)) {
1379 g_warning ("image_surface_coerce failed");
1384 format
= get_cogl_format_from_cairo_format (image_clone
->format
);
1388 texture
= cogl_texture_2d_new_from_data (to_device(reference_surface
->base
.device
)->cogl_context
,
1391 format
, /* incoming */
1392 format
, /* desired */
1397 g_warning ("Failed to allocate texture: %s", error
->message
);
1398 g_error_free (error
);
1402 clone
= _cairo_cogl_surface_create_full (to_device(reference_surface
->base
.device
),
1403 reference_surface
->ignore_alpha
,
1404 NULL
, COGL_TEXTURE (texture
));
1406 _cairo_surface_attach_snapshot (abstract_surface
, clone
, NULL
);
1408 /* Attaching the snapshot will take a reference on the clone surface... */
1409 cairo_surface_destroy (clone
);
1413 cairo_surface_destroy (&image_clone
->base
);
1415 _cairo_surface_release_source_image (abstract_surface
, acquired_image
, image_extra
);
1417 return COGL_TEXTURE (texture
);
1420 /* NB: a reference for the texture is transferred to the caller which should
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
)
1429 CoglTexture
*texture
= NULL
;
1431 switch ((int)pattern
->type
)
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
);
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. */
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 ();
1451 cairo_matrix_init_identity (&attributes
->matrix
);
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
));
1459 /* XXX: need to multiply in the pattern->matrix */
1461 attributes
->extend
= pattern
->extend
;
1462 attributes
->filter
= CAIRO_FILTER_BILINEAR
;
1463 attributes
->has_component_alpha
= pattern
->has_component_alpha
;
1465 attributes
->s_wrap
= get_cogl_wrap_mode_for_extend (pattern
->extend
);
1466 attributes
->t_wrap
= attributes
->s_wrap
;
1470 case CAIRO_PATTERN_TYPE_RADIAL
:
1471 case CAIRO_PATTERN_TYPE_MESH
: {
1472 cairo_surface_t
*surface
;
1473 cairo_matrix_t texture_matrix
;
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
,
1481 cairo_surface_destroy (surface
);
1485 texture
= _cairo_cogl_acquire_surface_texture (destination
, surface
);
1489 cairo_matrix_init_identity (&texture_matrix
);
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
));
1497 cairo_matrix_translate (&texture_matrix
, -extents
->x
, -extents
->y
);
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
;
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
;
1509 cairo_surface_destroy (surface
);
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
;
1523 status
= _cairo_cogl_get_linear_gradient (to_device(destination
->base
.device
),
1525 linear_pattern
->base
.n_stops
,
1526 linear_pattern
->base
.stops
,
1528 if (unlikely (status
))
1531 linear_texture
= _cairo_cogl_linear_gradient_texture_for_extend (gradient
, pattern
->extend
);
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
;
1539 cairo_matrix_init_identity (&attributes
->matrix
);
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
);
1547 cairo_matrix_rotate (&attributes
->matrix
, angle
);
1548 cairo_matrix_scale (&attributes
->matrix
, scale
, scale
);
1550 cairo_matrix_translate (&attributes
->matrix
,
1551 -linear_pattern
->pd1
.x
,
1552 -linear_pattern
->pd1
.y
);
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
1559 cairo_matrix_multiply (&attributes
->matrix
,
1561 &attributes
->matrix
);
1563 return cogl_object_ref (linear_texture
->texture
);
1566 g_warning ("Un-supported source type");
1572 set_layer_texture_with_attributes (CoglPipeline
*pipeline
,
1574 CoglTexture
*texture
,
1575 cairo_cogl_texture_attributes_t
*attributes
)
1577 cogl_pipeline_set_layer_texture (pipeline
, layer_index
, texture
);
1579 if (!_cairo_matrix_is_identity (&attributes
->matrix
)) {
1580 cairo_matrix_t
*m
= &attributes
->matrix
;
1581 float texture_matrixfv
[16] = {
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
);
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
);
1596 cogl_pipeline_set_layer_wrap_mode (pipeline
, layer_index
, attributes
->s_wrap
);
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
)
1606 cairo_cogl_template_type template_type
;
1607 CoglPipeline
*pipeline
;
1609 switch ((int)source
->type
)
1611 case CAIRO_PATTERN_TYPE_SOLID
:
1612 template_type
= mask
?
1613 CAIRO_COGL_TEMPLATE_TYPE_MASK_SOLID
: CAIRO_COGL_TEMPLATE_TYPE_SOLID
;
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
;
1623 g_warning ("Un-supported source type");
1627 pipeline
= cogl_pipeline_copy (to_device(destination
->base
.device
)->template_pipelines
[op
][template_type
]);
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
);
1637 cairo_cogl_texture_attributes_t attributes
;
1638 CoglTexture
*texture
=
1639 _cairo_cogl_acquire_pattern_texture (source
, destination
,
1641 &extents
->source_sample_area
,
1645 set_layer_texture_with_attributes (pipeline
, 0, texture
, &attributes
);
1646 cogl_object_unref (texture
);
1650 if (mask
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
1651 cairo_solid_pattern_t
*solid_pattern
= (cairo_solid_pattern_t
*)mask
;
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
);
1660 cairo_cogl_texture_attributes_t attributes
;
1661 CoglTexture
*texture
=
1662 _cairo_cogl_acquire_pattern_texture (mask
, destination
,
1664 &extents
->mask_sample_area
,
1668 set_layer_texture_with_attributes (pipeline
, 1, texture
, &attributes
);
1669 cogl_object_unref (texture
);
1676 cogl_object_unref (pipeline
);
1682 _cairo_cogl_rectangle_new_p2t2t2 (float x
,
1687 CoglVertexP2 vertices
[] = {
1688 {x
, y
}, {x
, y
+ height
}, {x
+ width
, y
+ height
},
1689 {x
, y
}, {x
+ width
, y
+ height
}, {x
+ width
, y
}
1691 CoglAttributeBuffer
*buffer
= cogl_attribute_buffer_new (sizeof (vertices
));
1692 CoglAttribute
*pos
= cogl_attribute_new (buffer
,
1694 sizeof (CoglVertexP2
),
1697 COGL_ATTRIBUTE_TYPE_FLOAT
);
1698 CoglAttribute
*tex_coords0
= cogl_attribute_new (buffer
,
1699 "cogl_tex_coord0_in",
1700 sizeof (CoglVertexP2
),
1703 COGL_ATTRIBUTE_TYPE_FLOAT
);
1704 CoglAttribute
*tex_coords0
= cogl_attribute_new (buffer
,
1705 "cogl_tex_coord0_in",
1706 sizeof (CoglVertexP2
),
1709 COGL_ATTRIBUTE_TYPE_FLOAT
);
1710 CoglPrimitive
*prim
;
1712 cogl_buffer_set_data (COGL_BUFFER (buffer
), 0, vertices
, sizeof (vertices
));
1714 /* The attributes will now keep the buffer alive... */
1715 cogl_object_unref (buffer
);
1717 prim
= cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLES
,
1718 6, pos
, tex_coords
, NULL
);
1720 /* The primitive will now keep the attribute alive... */
1721 cogl_object_unref (pos
);
1728 _cairo_cogl_log_clip (cairo_cogl_surface_t
*surface
,
1729 const cairo_clip_t
*clip
)
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
);
1739 _cairo_cogl_maybe_log_clip (cairo_cogl_surface_t
*surface
,
1740 cairo_composite_rectangles_t
*composite
)
1742 cairo_clip_t
*clip
= composite
->clip
;
1744 if (_cairo_composite_rectangles_can_reduce_clip (composite
, clip
))
1748 if (_cairo_composite_rectangles_can_reduce_clip (composite
,
1749 surface
->last_clip
))
1753 _cairo_cogl_log_clip (surface
, clip
);
1757 is_operator_supported (cairo_operator_t 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
:
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
)
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
;
1786 /* XXX: Use this to smoke test the acquire_source/dest_image fallback
1788 //return CAIRO_INT_STATUS_UNSUPPORTED;
1790 if (!is_operator_supported (op
))
1791 return CAIRO_INT_STATUS_UNSUPPORTED
;
1793 status
= _cairo_composite_rectangles_init_for_mask (&extents
,
1795 op
, source
, mask
, clip
);
1796 if (unlikely (status
))
1799 pipeline
= get_source_mask_operator_destination_pipeline (mask
, source
,
1800 op
, surface
, &extents
);
1802 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
1806 _cairo_cogl_maybe_log_clip (surface
, &extents
);
1808 cairo_matrix_init_identity (&identity
);
1809 _cairo_cogl_journal_log_rectangle (surface
, pipeline
,
1812 extents
.bounded
.width
,
1813 extents
.bounded
.height
,
1817 /* The journal will take a reference on the pipeline and clip_path... */
1818 cogl_object_unref (pipeline
);
1825 _cairo_cogl_source_n_layers (const cairo_pattern_t
*source
)
1827 switch ((int)source
->type
)
1829 case CAIRO_PATTERN_TYPE_SOLID
:
1831 case CAIRO_PATTERN_TYPE_LINEAR
:
1832 case CAIRO_PATTERN_TYPE_RADIAL
:
1833 case CAIRO_PATTERN_TYPE_MESH
:
1834 case CAIRO_PATTERN_TYPE_SURFACE
:
1837 g_warning ("Unsupported source type");
1843 _cairo_cogl_path_fill_meta_equal (const void *key_a
, const void *key_b
)
1845 const cairo_cogl_path_fill_meta_t
*meta0
= key_a
;
1846 const cairo_cogl_path_fill_meta_t
*meta1
= key_b
;
1848 return _cairo_path_fixed_equal (meta0
->user_path
, meta1
->user_path
);
1852 _cairo_cogl_stroke_style_equal (const cairo_stroke_style_t
*a
,
1853 const cairo_stroke_style_t
*b
)
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
)
1863 for (i
= 0; i
< a
->num_dashes
; i
++) {
1864 if (a
->dash
[i
] != b
->dash
[i
])
1872 _cairo_cogl_path_stroke_meta_equal (const void *key_a
, const void *key_b
)
1874 const cairo_cogl_path_stroke_meta_t
*meta0
= key_a
;
1875 const cairo_cogl_path_stroke_meta_t
*meta1
= key_b
;
1877 return _cairo_cogl_stroke_style_equal (&meta0
->style
, &meta1
->style
) &&
1878 _cairo_path_fixed_equal (meta0
->user_path
, meta1
->user_path
);
1881 static cairo_cogl_path_stroke_meta_t
*
1882 _cairo_cogl_path_stroke_meta_reference (cairo_cogl_path_stroke_meta_t
*meta
)
1884 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta
->ref_count
));
1886 _cairo_reference_count_inc (&meta
->ref_count
);
1892 _cairo_cogl_path_stroke_meta_destroy (cairo_cogl_path_stroke_meta_t
*meta
)
1894 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta
->ref_count
));
1896 if (! _cairo_reference_count_dec_and_test (&meta
->ref_count
))
1899 _cairo_path_fixed_fini (meta
->user_path
);
1900 free (meta
->user_path
);
1902 _cairo_stroke_style_fini (&meta
->style
);
1905 cogl_object_unref (meta
->prim
);
1910 static cairo_cogl_path_stroke_meta_t
*
1911 _cairo_cogl_path_stroke_meta_lookup (cairo_cogl_device_t
*ctx
,
1913 cairo_path_fixed_t
*user_path
,
1914 const cairo_stroke_style_t
*style
,
1917 cairo_cogl_path_stroke_meta_t
*ret
;
1918 cairo_cogl_path_stroke_meta_t lookup
;
1920 lookup
.cache_entry
.hash
= hash
;
1921 lookup
.user_path
= user_path
;
1922 lookup
.style
= *style
;
1923 lookup
.tolerance
= tolerance
;
1925 ret
= _cairo_cache_lookup (&ctx
->path_stroke_staging_cache
, &lookup
.cache_entry
);
1927 ret
= _cairo_cache_lookup (&ctx
->path_stroke_prim_cache
, &lookup
.cache_entry
);
1932 _cairo_cogl_path_stroke_meta_set_prim_size (cairo_cogl_surface_t
*surface
,
1933 cairo_cogl_path_stroke_meta_t
*meta
,
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.
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
);
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
);
1954 _cairo_cogl_stroke_style_hash (unsigned int hash
,
1955 const cairo_stroke_style_t
*style
)
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));
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
,
1975 cairo_cogl_path_stroke_meta_t
*meta
= NULL
;
1976 cairo_path_fixed_t
*meta_path
= NULL
;
1977 cairo_status_t status
;
1979 if (!surface
->user_path
)
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
));
1986 meta
= _cairo_cogl_path_stroke_meta_lookup (to_device(surface
->base
.device
), hash
,
1987 surface
->user_path
, style
, tolerance
);
1991 meta
= calloc (1, sizeof (cairo_cogl_path_stroke_meta_t
));
1994 CAIRO_REFERENCE_COUNT_INIT (&meta
->ref_count
, 1);
1995 meta
->cache_entry
.hash
= hash
;
1997 meta_path
= malloc (sizeof (cairo_path_fixed_t
));
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
))
2005 meta
->user_path
= meta_path
;
2006 meta
->ctm_inverse
= *surface
->ctm_inverse
;
2008 status
= _cairo_stroke_style_init_copy (&meta
->style
, style
);
2009 if (unlikely (status
)) {
2010 _cairo_path_fixed_fini (meta_path
);
2013 meta
->tolerance
= tolerance
;
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
,
2031 cairo_bool_t one_shot
,
2032 CoglPrimitive
**primitive
,
2035 cairo_traps_t traps
;
2036 cairo_int_status_t status
;
2038 _cairo_traps_init (&traps
);
2040 status
= _cairo_path_fixed_stroke_polygon_to_traps (path
, style
,
2044 if (unlikely (status
))
2047 if (traps
.num_traps
== 0) {
2048 status
= CAIRO_INT_STATUS_NOTHING_TO_DO
;
2052 *size
= traps
.num_traps
* sizeof (CoglVertexP2
) * 6;
2054 //g_print ("new stroke prim\n");
2055 *primitive
= _cairo_cogl_traps_to_composite_prim (surface
, &traps
, n_layers
, one_shot
);
2057 status
= CAIRO_INT_STATUS_NO_MEMORY
;
2062 _cairo_traps_fini (&traps
);
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
,
2075 cairo_antialias_t antialias
,
2076 const cairo_clip_t
*clip
)
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
;
2086 cairo_matrix_t
*transform
= NULL
;
2087 gboolean one_shot
= TRUE
;
2088 CoglPrimitive
*prim
= NULL
;
2089 cairo_bool_t new_prim
= FALSE
;
2091 if (! is_operator_supported (op
))
2092 return CAIRO_INT_STATUS_UNSUPPORTED
;
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
2098 assert (op
== CAIRO_OPERATOR_IN
);
2099 g_warning ("FIXME: handle stroking with unbounded operators!");
2100 return CAIRO_INT_STATUS_UNSUPPORTED
;
2103 status
= _cairo_composite_rectangles_init_for_stroke (&extents
,
2109 if (unlikely (status
))
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
);
2119 cairo_matrix_multiply (&transform_matrix
, &meta
->ctm_inverse
, surface
->ctm
);
2120 transform
= &transform_matrix
;
2121 } else if (meta
->counter
++ > 10)
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
,
2133 if (unlikely (status
))
2136 #if defined (ENABLE_PATH_CACHE)
2138 meta
->prim
= cogl_object_ref (prim
);
2139 _cairo_cogl_path_stroke_meta_set_prim_size (surface
, meta
, prim_size
);
2144 pipeline
= get_source_mask_operator_destination_pipeline (NULL
, source
,
2145 op
, surface
, &extents
);
2147 return CAIRO_INT_STATUS_UNSUPPORTED
;
2149 _cairo_cogl_maybe_log_clip (surface
, &extents
);
2151 _cairo_cogl_journal_log_primitive (surface
, pipeline
, prim
, transform
);
2153 /* The journal will take a reference on the pipeline and primitive... */
2154 cogl_object_unref (pipeline
);
2156 cogl_object_unref (prim
);
2158 return CAIRO_INT_STATUS_SUCCESS
;
2161 static cairo_cogl_path_fill_meta_t
*
2162 _cairo_cogl_path_fill_meta_reference (cairo_cogl_path_fill_meta_t
*meta
)
2164 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta
->ref_count
));
2166 _cairo_reference_count_inc (&meta
->ref_count
);
2172 _cairo_cogl_path_fill_meta_destroy (cairo_cogl_path_fill_meta_t
*meta
)
2174 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&meta
->ref_count
));
2176 if (! _cairo_reference_count_dec_and_test (&meta
->ref_count
))
2179 _cairo_path_fixed_fini (meta
->user_path
);
2180 free (meta
->user_path
);
2183 cogl_object_unref (meta
->prim
);
2188 static cairo_cogl_path_fill_meta_t
*
2189 _cairo_cogl_path_fill_meta_lookup (cairo_cogl_device_t
*ctx
,
2191 cairo_path_fixed_t
*user_path
)
2193 cairo_cogl_path_fill_meta_t
*ret
;
2194 cairo_cogl_path_fill_meta_t lookup
;
2196 lookup
.cache_entry
.hash
= hash
;
2197 lookup
.user_path
= user_path
;
2199 ret
= _cairo_cache_lookup (&ctx
->path_fill_staging_cache
, &lookup
.cache_entry
);
2201 ret
= _cairo_cache_lookup (&ctx
->path_fill_prim_cache
, &lookup
.cache_entry
);
2206 _cairo_cogl_path_fill_meta_set_prim_size (cairo_cogl_surface_t
*surface
,
2207 cairo_cogl_path_fill_meta_t
*meta
,
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.
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
);
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
);
2227 static cairo_cogl_path_fill_meta_t
*
2228 _cairo_cogl_get_path_fill_meta (cairo_cogl_surface_t
*surface
)
2231 cairo_cogl_path_fill_meta_t
*meta
= NULL
;
2232 cairo_path_fixed_t
*meta_path
= NULL
;
2233 cairo_status_t status
;
2235 if (!surface
->user_path
)
2238 hash
= _cairo_path_fixed_hash (surface
->user_path
);
2240 meta
= _cairo_cogl_path_fill_meta_lookup (to_device(surface
->base
.device
),
2241 hash
, surface
->user_path
);
2245 meta
= calloc (1, sizeof (cairo_cogl_path_fill_meta_t
));
2248 meta
->cache_entry
.hash
= hash
;
2250 CAIRO_REFERENCE_COUNT_INIT (&meta
->ref_count
, 1);
2251 meta_path
= malloc (sizeof (cairo_path_fixed_t
));
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
))
2259 meta
->user_path
= meta_path
;
2260 meta
->ctm_inverse
= *surface
->ctm_inverse
;
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
);
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
,
2285 cairo_antialias_t antialias
,
2286 const cairo_clip_t
*clip
)
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
;
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
;
2301 if (! is_operator_supported (op
))
2302 return CAIRO_INT_STATUS_UNSUPPORTED
;
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
2308 assert (op
== CAIRO_OPERATOR_IN
);
2309 g_warning ("FIXME: handle filling with unbounded operators!");
2310 return CAIRO_INT_STATUS_UNSUPPORTED
;
2313 status
= _cairo_composite_rectangles_init_for_fill (&extents
,
2317 if (unlikely (status
))
2320 #ifndef FILL_WITH_COGL_PATH
2321 #ifdef ENABLE_PATH_CACHE
2322 meta
= _cairo_cogl_get_path_fill_meta (surface
);
2326 cairo_matrix_multiply (&transform_matrix
, &meta
->ctm_inverse
, surface
->ctm
);
2327 transform
= &transform_matrix
;
2328 } else if (meta
->counter
++ > 10)
2331 #endif /* ENABLE_PATH_CACHE */
2334 int n_layers
= _cairo_cogl_source_n_layers (source
);
2336 status
= _cairo_cogl_fill_to_primitive (surface
, path
, fill_rule
, tolerance
,
2337 one_shot
, n_layers
, &prim
, &prim_size
);
2338 if (unlikely (status
))
2341 #ifdef ENABLE_PATH_CACHE
2343 meta
->prim
= cogl_object_ref (prim
);
2344 _cairo_cogl_path_fill_meta_set_prim_size (surface
, meta
, prim_size
);
2346 #endif /* ENABLE_PATH_CACHE */
2349 #endif /* !FILL_WITH_COGL_PATH */
2351 pipeline
= get_source_mask_operator_destination_pipeline (NULL
, source
,
2352 op
, surface
, &extents
);
2354 return CAIRO_INT_STATUS_UNSUPPORTED
;
2356 _cairo_cogl_maybe_log_clip (surface
, &extents
);
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 */
2362 cogl_object_unref (prim
);
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
);
2369 /* The journal will take a reference on the pipeline... */
2370 cogl_object_unref (pipeline
);
2372 return CAIRO_INT_STATUS_SUCCESS
;
2376 _cairo_cogl_surface_fill_rectangle (void *abstract_surface
,
2377 cairo_operator_t op
,
2378 const cairo_pattern_t
*source
,
2383 cairo_matrix_t
*ctm
,
2384 const cairo_clip_t
*clip
)
2386 cairo_cogl_surface_t
*surface
= abstract_surface
;
2387 CoglPipeline
*pipeline
;
2389 if (! is_operator_supported (op
))
2390 return CAIRO_INT_STATUS_UNSUPPORTED
;
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
2396 assert (op
== CAIRO_OPERATOR_IN
);
2397 g_warning ("FIXME: handle filling with unbounded operators!");
2398 return CAIRO_INT_STATUS_UNSUPPORTED
;
2403 status
= _cairo_composite_rectangles_init_for_fill_rectangle (&extents
,
2407 if (unlikely (status
))
2411 if (source
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
2414 double x2
= x1
+ width
;
2415 double y2
= y1
+ height
;
2417 pipeline
= get_source_mask_operator_destination_pipeline (NULL
, source
,
2420 return CAIRO_INT_STATUS_UNSUPPORTED
;
2422 _cairo_cogl_log_clip (surface
, clip
);
2424 _cairo_cogl_journal_log_rectangle (surface
,
2429 return CAIRO_INT_STATUS_SUCCESS
;
2431 return CAIRO_INT_STATUS_UNSUPPORTED
;
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.
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
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
,
2452 cairo_scaled_font_t
*scaled_font
,
2453 const cairo_clip_t
*clip
)
2455 return CAIRO_INT_STATUS_UNSUPPORTED
;
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
,
2464 _cairo_default_context_create
,
2467 _cairo_cogl_surface_create_similar
,
2468 NULL
, /* create similar image */
2469 NULL
, /* map to image */
2470 NULL
, /* unmap image */
2472 _cairo_surface_default_source
,
2473 _cairo_cogl_surface_acquire_source_image
,
2474 _cairo_cogl_surface_release_source_image
,
2475 NULL
, /* snapshot */
2477 NULL
, /* copy_page */
2478 NULL
, /* show_page */
2480 _cairo_cogl_surface_get_extents
,
2481 NULL
, /* get_font_options */
2483 _cairo_cogl_surface_flush
, /* flush */
2484 NULL
, /* mark_dirty_rectangle */
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
,
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
)
2500 cairo_cogl_surface_t
*surface
;
2501 cairo_status_t status
;
2503 status
= cairo_device_acquire (&dev
->base
);
2504 if (unlikely (status
))
2505 return _cairo_surface_create_in_error (status
);
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
));
2511 surface
->ignore_alpha
= ignore_alpha
;
2513 surface
->framebuffer
= 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
);
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
;
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
);
2530 cogl_object_ref (texture
);
2533 assert(surface
->width
&& surface
->height
);
2535 surface
->journal
= NULL
;
2537 surface
->buffer_stack
= NULL
;
2538 surface
->buffer_stack_size
= 4096;
2540 surface
->last_clip
= NULL
;
2542 surface
->n_clip_updates_per_frame
= 0;
2544 _cairo_surface_init (&surface
->base
,
2545 &_cairo_cogl_surface_backend
,
2547 CAIRO_CONTENT_COLOR_ALPHA
);
2549 return &surface
->base
;
2553 cairo_cogl_surface_create (cairo_device_t
*abstract_device
,
2554 CoglFramebuffer
*framebuffer
)
2556 cairo_cogl_device_t
*dev
= (cairo_cogl_device_t
*)abstract_device
;
2558 if (abstract_device
== NULL
)
2559 return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_ERROR
);
2561 if (abstract_device
->status
)
2562 return _cairo_surface_create_in_error (abstract_device
->status
);
2564 if (abstract_device
->backend
->type
!= CAIRO_DEVICE_TYPE_COGL
)
2565 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
));
2567 return _cairo_cogl_surface_create_full (dev
, FALSE
, framebuffer
, NULL
);
2569 slim_hidden_def (cairo_cogl_surface_create
);
2572 cairo_cogl_surface_get_framebuffer (cairo_surface_t
*abstract_surface
)
2574 cairo_cogl_surface_t
*surface
;
2576 if (abstract_surface
->backend
!= &_cairo_cogl_surface_backend
) {
2577 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
2581 surface
= (cairo_cogl_surface_t
*) abstract_surface
;
2583 return surface
->framebuffer
;
2585 slim_hidden_def (cairo_cogl_surface_get_framebuffer
);
2588 cairo_cogl_surface_get_texture (cairo_surface_t
*abstract_surface
)
2590 cairo_cogl_surface_t
*surface
;
2592 if (abstract_surface
->backend
!= &_cairo_cogl_surface_backend
) {
2593 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
2597 surface
= (cairo_cogl_surface_t
*) abstract_surface
;
2599 return surface
->texture
;
2601 slim_hidden_def (cairo_cogl_surface_get_texture
);
2603 static cairo_status_t
2604 _cairo_cogl_device_flush (void *device
)
2606 cairo_status_t status
;
2608 status
= cairo_device_acquire (device
);
2609 if (unlikely (status
))
2612 /* XXX: we don't need to flush Cogl here, we just need to flush
2613 * any batching we do of compositing primitives. */
2615 cairo_device_release (device
);
2617 return CAIRO_STATUS_SUCCESS
;
2621 _cairo_cogl_device_finish (void *device
)
2623 cairo_status_t status
;
2625 status
= cairo_device_acquire (device
);
2626 if (unlikely (status
))
2629 /* XXX: Drop references to external resources */
2631 cairo_device_release (device
);
2635 _cairo_cogl_device_destroy (void *device
)
2637 cairo_cogl_device_t
*dev
= device
;
2639 /* FIXME: Free stuff! */
2644 static const cairo_device_backend_t _cairo_cogl_device_backend
= {
2645 CAIRO_DEVICE_TYPE_COGL
,
2650 _cairo_cogl_device_flush
,
2651 _cairo_cogl_device_finish
,
2652 _cairo_cogl_device_destroy
,
2656 set_blend (CoglPipeline
*pipeline
, const char *blend_string
)
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
);
2668 _cairo_cogl_setup_op_state (CoglPipeline
*pipeline
, cairo_operator_t op
)
2670 cairo_bool_t status
= FALSE
;
2674 case CAIRO_OPERATOR_SOURCE
:
2675 status
= set_blend (pipeline
, "RGBA = ADD (SRC_COLOR, 0)");
2677 case CAIRO_OPERATOR_OVER
:
2678 status
= set_blend (pipeline
, "RGBA = ADD (SRC_COLOR, DST_COLOR * (1 - SRC_COLOR[A]))");
2680 case CAIRO_OPERATOR_IN
:
2681 status
= set_blend (pipeline
, "RGBA = ADD (SRC_COLOR * DST_COLOR[A], 0)");
2683 case CAIRO_OPERATOR_DEST_OVER
:
2684 status
= set_blend (pipeline
, "RGBA = ADD (SRC_COLOR * (1 - DST_COLOR[A]), DST_COLOR)");
2686 case CAIRO_OPERATOR_DEST_IN
:
2687 status
= set_blend (pipeline
, "RGBA = ADD (0, DST_COLOR * SRC_COLOR[A])");
2689 case CAIRO_OPERATOR_ADD
:
2690 status
= set_blend (pipeline
, "RGBA = ADD (SRC_COLOR, DST_COLOR)");
2698 create_templates_for_op (cairo_cogl_device_t
*dev
, cairo_operator_t op
)
2700 CoglPipeline
*base
= cogl_pipeline_new ();
2701 CoglPipeline
*pipeline
;
2704 if (!_cairo_cogl_setup_op_state (base
, op
)) {
2705 cogl_object_unref (base
);
2709 dev
->template_pipelines
[op
][CAIRO_COGL_TEMPLATE_TYPE_SOLID
] = base
;
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
;
2715 pipeline
= cogl_pipeline_copy (base
);
2716 cogl_pipeline_set_layer_combine (pipeline
, 1,
2717 "RGBA = MODULATE (PREVIOUS, CONSTANT[A])",
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
;
2723 pipeline
= cogl_pipeline_copy (base
);
2724 cogl_pipeline_set_layer_combine (pipeline
, 1,
2725 "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
2727 cogl_pipeline_set_layer_texture (pipeline
, 1, dev
->dummy_texture
);
2728 dev
->template_pipelines
[op
][CAIRO_COGL_TEMPLATE_TYPE_MASK_TEXTURE
] = pipeline
;
2732 cairo_cogl_device_create (CoglContext
*cogl_context
)
2734 cairo_cogl_device_t
*dev
= g_new0 (cairo_cogl_device_t
, 1);
2735 cairo_status_t status
;
2737 dev
->backend_vtable_initialized
= FALSE
;
2739 dev
->cogl_context
= cogl_context
;
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
)
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
);
2755 status
= _cairo_cache_init (&dev
->linear_cache
,
2756 _cairo_cogl_linear_gradient_equal
,
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
);
2763 status
= _cairo_cache_init (&dev
->path_fill_staging_cache
,
2764 _cairo_cogl_path_fill_meta_equal
,
2766 (cairo_destroy_func_t
) _cairo_cogl_path_fill_meta_destroy
,
2769 status
= _cairo_cache_init (&dev
->path_stroke_staging_cache
,
2770 _cairo_cogl_path_stroke_meta_equal
,
2772 (cairo_destroy_func_t
) _cairo_cogl_path_stroke_meta_destroy
,
2775 status
= _cairo_cache_init (&dev
->path_fill_prim_cache
,
2776 _cairo_cogl_path_fill_meta_equal
,
2778 (cairo_destroy_func_t
) _cairo_cogl_path_fill_meta_destroy
,
2779 CAIRO_COGL_PATH_META_CACHE_SIZE
);
2781 status
= _cairo_cache_init (&dev
->path_stroke_prim_cache
,
2782 _cairo_cogl_path_stroke_meta_equal
,
2784 (cairo_destroy_func_t
) _cairo_cogl_path_stroke_meta_destroy
,
2785 CAIRO_COGL_PATH_META_CACHE_SIZE
);
2787 _cairo_device_init (&dev
->base
, &_cairo_cogl_device_backend
);
2792 return _cairo_device_create_in_error (CAIRO_STATUS_DEVICE_ERROR
);
2794 slim_hidden_def (cairo_cogl_device_create
);
2797 cairo_cogl_surface_end_frame (cairo_surface_t
*abstract_surface
)
2799 cairo_cogl_surface_t
*surface
= (cairo_cogl_surface_t
*)abstract_surface
;
2800 cairo_surface_flush (abstract_surface
);
2802 //g_print ("n_clip_update_per_frame = %d\n", surface->n_clip_updates_per_frame);
2803 surface
->n_clip_updates_per_frame
= 0;
2805 slim_hidden_def (cairo_cogl_surface_end_frame
);