Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3959 Serge 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 
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 
56
#include 
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);