Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2009 Eric Anholt
4
 * Copyright © 2009 Chris Wilson
5
 * Copyright © 2005,2010 Red Hat, Inc
6
 * Copyright © 2011 Linaro Limited
7
 * Copyright © 2011 Samsung Electronics
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it either under the terms of the GNU Lesser General Public
11
 * License version 2.1 as published by the Free Software Foundation
12
 * (the "LGPL") or, at your option, under the terms of the Mozilla
13
 * Public License Version 1.1 (the "MPL"). If you do not alter this
14
 * notice, a recipient may use your version of this file under either
15
 * the MPL or the LGPL.
16
 *
17
 * You should have received a copy of the LGPL along with this library
18
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
20
 * You should have received a copy of the MPL along with this library
21
 * in the file COPYING-MPL-1.1
22
 *
23
 * The contents of this file are subject to the Mozilla Public License
24
 * Version 1.1 (the "License"); you may not use this file except in
25
 * compliance with the License. You may obtain a copy of the License at
26
 * http://www.mozilla.org/MPL/
27
 *
28
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
29
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
30
 * the specific language governing rights and limitations.
31
 *
32
 * The Original Code is the cairo graphics library.
33
 *
34
 * The Initial Developer of the Original Code is Red Hat, Inc.
35
 *
36
 * Contributor(s):
37
 *	Benjamin Otte 
38
 *	Carl Worth 
39
 *	Chris Wilson 
40
 *	Eric Anholt 
41
 *	Alexandros Frantzis 
42
 *	Henry Song 
43
 *	Martin Robinson 
44
 */
45
 
46
#include "cairoint.h"
47
 
48
#include "cairo-gl-private.h"
49
 
50
#include "cairo-composite-rectangles-private.h"
51
#include "cairo-clip-private.h"
52
#include "cairo-error-private.h"
53
#include "cairo-image-surface-private.h"
54
 
55
cairo_int_status_t
56
_cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
57
			        const cairo_pattern_t *pattern,
58
				const cairo_rectangle_int_t *sample,
59
				const cairo_rectangle_int_t *extents,
60
				cairo_bool_t use_texgen)
61
{
62
    _cairo_gl_operand_destroy (&setup->src);
63
    return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
64
				   sample, extents, use_texgen);
65
}
66
 
67
void
68
_cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
69
					const cairo_gl_operand_t *source)
70
{
71
    _cairo_gl_operand_destroy (&setup->src);
72
    _cairo_gl_operand_copy (&setup->src, source);
73
}
74
 
75
void
76
_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
77
				      const cairo_color_t *color)
78
{
79
    _cairo_gl_operand_destroy (&setup->src);
80
    _cairo_gl_solid_operand_init (&setup->src, color);
81
}
82
 
83
cairo_int_status_t
84
_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
85
			      const cairo_pattern_t *pattern,
86
			      const cairo_rectangle_int_t *sample,
87
			      const cairo_rectangle_int_t *extents,
88
			      cairo_bool_t use_texgen)
89
{
90
    _cairo_gl_operand_destroy (&setup->mask);
91
    if (pattern == NULL)
92
        return CAIRO_STATUS_SUCCESS;
93
 
94
    return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
95
				   sample, extents, use_texgen);
96
}
97
 
98
void
99
_cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
100
				      const cairo_gl_operand_t *mask)
101
{
102
    _cairo_gl_operand_destroy (&setup->mask);
103
    if (mask)
104
	_cairo_gl_operand_copy (&setup->mask, mask);
105
}
106
 
107
void
108
_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
109
{
110
    setup->spans = TRUE;
111
}
112
 
113
void
114
_cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
115
{
116
    setup->multisample = TRUE;
117
}
118
 
119
void
120
_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
121
                                     cairo_region_t *clip_region)
122
{
123
    setup->clip_region = clip_region;
124
}
125
 
126
void
127
_cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
128
			      cairo_clip_t *clip)
129
{
130
    setup->clip = clip;
131
}
132
 
133
static void
134
_cairo_gl_composite_bind_to_shader (cairo_gl_context_t   *ctx,
135
				    cairo_gl_composite_t *setup)
136
{
137
    _cairo_gl_shader_bind_matrix4f(ctx, ctx->current_shader->mvp_location,
138
				   ctx->modelviewprojection_matrix);
139
    _cairo_gl_operand_bind_to_shader (ctx, &setup->src,  CAIRO_GL_TEX_SOURCE);
140
    _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
141
}
142
 
143
static void
144
_cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
145
                              GLuint              target,
146
                              cairo_filter_t      filter)
147
{
148
    switch (filter) {
149
    case CAIRO_FILTER_FAST:
150
    case CAIRO_FILTER_NEAREST:
151
	glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
152
	glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
153
	break;
154
    case CAIRO_FILTER_GOOD:
155
    case CAIRO_FILTER_BEST:
156
    case CAIRO_FILTER_BILINEAR:
157
	glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
158
	glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
159
	break;
160
    default:
161
    case CAIRO_FILTER_GAUSSIAN:
162
	ASSERT_NOT_REACHED;
163
    }
164
}
165
 
166
static void
167
_cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
168
                              GLuint              target,
169
                              cairo_extend_t      extend)
170
{
171
    GLint wrap_mode;
172
    assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
173
            (extend != CAIRO_EXTEND_REPEAT && extend != CAIRO_EXTEND_REFLECT));
174
 
175
    switch (extend) {
176
    case CAIRO_EXTEND_NONE:
177
	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES)
178
	    wrap_mode = GL_CLAMP_TO_EDGE;
179
	else
180
	    wrap_mode = GL_CLAMP_TO_BORDER;
181
	break;
182
    case CAIRO_EXTEND_PAD:
183
	wrap_mode = GL_CLAMP_TO_EDGE;
184
	break;
185
    case CAIRO_EXTEND_REPEAT:
186
	if (ctx->has_npot_repeat)
187
	    wrap_mode = GL_REPEAT;
188
	else
189
	    wrap_mode = GL_CLAMP_TO_EDGE;
190
	break;
191
    case CAIRO_EXTEND_REFLECT:
192
	if (ctx->has_npot_repeat)
193
	    wrap_mode = GL_MIRRORED_REPEAT;
194
	else
195
	    wrap_mode = GL_CLAMP_TO_EDGE;
196
	break;
197
    default:
198
	wrap_mode = 0;
199
    }
200
 
201
    if (likely (wrap_mode)) {
202
	glTexParameteri (target, GL_TEXTURE_WRAP_S, wrap_mode);
203
	glTexParameteri (target, GL_TEXTURE_WRAP_T, wrap_mode);
204
    }
205
}
206
 
207
 
208
static void
209
_cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
210
                                 cairo_gl_tex_t      tex_unit,
211
                                 cairo_gl_operand_t *operand,
212
                                 unsigned int        vertex_offset,
213
                                 cairo_bool_t        vertex_size_changed)
214
{
215
    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
216
    cairo_bool_t needs_setup;
217
 
218
    /* XXX: we need to do setup when switching from shaders
219
     * to no shaders (or back) */
220
    needs_setup = vertex_size_changed;
221
    needs_setup |= _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
222
                                                 operand,
223
                                                 vertex_offset);
224
 
225
    if (needs_setup) {
226
        _cairo_gl_composite_flush (ctx);
227
        _cairo_gl_context_destroy_operand (ctx, tex_unit);
228
    }
229
 
230
    memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
231
    ctx->operands[tex_unit].vertex_offset = vertex_offset;
232
 
233
    if (! needs_setup)
234
        return;
235
 
236
    switch (operand->type) {
237
    default:
238
    case CAIRO_GL_OPERAND_COUNT:
239
        ASSERT_NOT_REACHED;
240
    case CAIRO_GL_OPERAND_NONE:
241
        break;
242
        /* fall through */
243
    case CAIRO_GL_OPERAND_CONSTANT:
244
        break;
245
    case CAIRO_GL_OPERAND_TEXTURE:
246
        glActiveTexture (GL_TEXTURE0 + tex_unit);
247
        glBindTexture (ctx->tex_target, operand->texture.tex);
248
        _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
249
                                      operand->texture.attributes.extend);
250
        _cairo_gl_texture_set_filter (ctx, ctx->tex_target,
251
                                      operand->texture.attributes.filter);
252
 
253
	if (! operand->texture.texgen) {
254
	    dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
255
					   GL_FLOAT, GL_FALSE, ctx->vertex_size,
256
					   ctx->vb + vertex_offset);
257
	    dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
258
	}
259
        break;
260
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
261
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
262
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
263
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
264
        glActiveTexture (GL_TEXTURE0 + tex_unit);
265
        glBindTexture (ctx->tex_target, operand->gradient.gradient->tex);
266
        _cairo_gl_texture_set_extend (ctx, ctx->tex_target, operand->gradient.extend);
267
        _cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR);
268
 
269
	if (! operand->gradient.texgen) {
270
	    dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
271
					   GL_FLOAT, GL_FALSE, ctx->vertex_size,
272
					   ctx->vb + vertex_offset);
273
	    dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
274
	}
275
	break;
276
    }
277
}
278
 
279
static void
280
_cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
281
			       cairo_bool_t        spans_enabled,
282
			       unsigned int        vertex_size,
283
			       unsigned int        vertex_offset)
284
{
285
    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
286
 
287
    if (! spans_enabled) {
288
	dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
289
	ctx->spans = FALSE;
290
	return;
291
    }
292
 
293
    dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
294
				   GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
295
				   ctx->vb + vertex_offset);
296
    dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
297
    ctx->spans = TRUE;
298
}
299
 
300
void
301
_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
302
                                   cairo_gl_tex_t tex_unit)
303
{
304
    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
305
 
306
    if  (!_cairo_gl_context_is_flushed (ctx))
307
	_cairo_gl_composite_flush (ctx);
308
 
309
    switch (ctx->operands[tex_unit].type) {
310
    default:
311
    case CAIRO_GL_OPERAND_COUNT:
312
        ASSERT_NOT_REACHED;
313
    case CAIRO_GL_OPERAND_NONE:
314
        break;
315
        /* fall through */
316
    case CAIRO_GL_OPERAND_CONSTANT:
317
        break;
318
    case CAIRO_GL_OPERAND_TEXTURE:
319
        dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
320
        break;
321
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
322
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
323
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
324
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
325
        dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
326
        break;
327
    }
328
 
329
    memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
330
}
331
 
332
static void
333
_cairo_gl_set_operator (cairo_gl_context_t *ctx,
334
                        cairo_operator_t    op,
335
			cairo_bool_t        component_alpha)
336
{
337
    struct {
338
	GLenum src;
339
	GLenum dst;
340
    } blend_factors[] = {
341
	{ GL_ZERO, GL_ZERO }, /* Clear */
342
	{ GL_ONE, GL_ZERO }, /* Source */
343
	{ GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */
344
	{ GL_DST_ALPHA, GL_ZERO }, /* In */
345
	{ GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */
346
	{ GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */
347
 
348
	{ GL_ZERO, GL_ONE }, /* Dest */
349
	{ GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */
350
	{ GL_ZERO, GL_SRC_ALPHA }, /* DestIn */
351
	{ GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */
352
	{ GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */
353
 
354
	{ GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
355
	{ GL_ONE, GL_ONE }, /* Add */
356
    };
357
    GLenum src_factor, dst_factor;
358
 
359
    assert (op < ARRAY_LENGTH (blend_factors));
360
    /* different dst and component_alpha changes cause flushes elsewhere */
361
    if (ctx->current_operator != op)
362
        _cairo_gl_composite_flush (ctx);
363
    ctx->current_operator = op;
364
 
365
    src_factor = blend_factors[op].src;
366
    dst_factor = blend_factors[op].dst;
367
 
368
    /* Even when the user requests CAIRO_CONTENT_COLOR, we use GL_RGBA
369
     * due to texture filtering of GL_CLAMP_TO_BORDER.  So fix those
370
     * bits in that case.
371
     */
372
    if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
373
	if (src_factor == GL_ONE_MINUS_DST_ALPHA)
374
	    src_factor = GL_ZERO;
375
	if (src_factor == GL_DST_ALPHA)
376
	    src_factor = GL_ONE;
377
    }
378
 
379
    if (component_alpha) {
380
	if (dst_factor == GL_ONE_MINUS_SRC_ALPHA)
381
	    dst_factor = GL_ONE_MINUS_SRC_COLOR;
382
	if (dst_factor == GL_SRC_ALPHA)
383
	    dst_factor = GL_SRC_COLOR;
384
    }
385
 
386
    if (ctx->current_target->base.content == CAIRO_CONTENT_ALPHA) {
387
        glBlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
388
    } else if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
389
        glBlendFuncSeparate (src_factor, dst_factor, GL_ONE, GL_ONE);
390
    } else {
391
        glBlendFunc (src_factor, dst_factor);
392
    }
393
}
394
 
395
static cairo_status_t
396
_cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
397
                                            cairo_gl_composite_t *setup)
398
{
399
    cairo_gl_shader_t *pre_shader = NULL;
400
    cairo_status_t status;
401
 
402
    /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
403
     * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
404
     * is:
405
     *     mask IN clip ? src OP dest : dest
406
     * or more simply:
407
     *     mask IN CLIP ? 0 : dest
408
     *
409
     * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
410
     *
411
     * The model we use in _cairo_gl_set_operator() is Render's:
412
     *     src IN mask IN clip OP dest
413
     * which would boil down to:
414
     *     0 (bounded by the extents of the drawing).
415
     *
416
     * However, we can do a Render operation using an opaque source
417
     * and DEST_OUT to produce:
418
     *    1 IN mask IN clip DEST_OUT dest
419
     * which is
420
     *    mask IN clip ? 0 : dest
421
     */
422
    if (setup->op == CAIRO_OPERATOR_CLEAR) {
423
        _cairo_gl_solid_operand_init (&setup->src, CAIRO_COLOR_WHITE);
424
	setup->op = CAIRO_OPERATOR_DEST_OUT;
425
    }
426
 
427
    /*
428
     * implements component-alpha %CAIRO_OPERATOR_OVER using two passes of
429
     * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
430
     *
431
     * From http://anholt.livejournal.com/32058.html:
432
     *
433
     * The trouble is that component-alpha rendering requires two different sources
434
     * for blending: one for the source value to the blender, which is the
435
     * per-channel multiplication of source and mask, and one for the source alpha
436
     * for multiplying with the destination channels, which is the multiplication
437
     * of the source channels by the mask alpha. So the equation for Over is:
438
     *
439
     * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
440
     * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
441
     * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
442
     * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
443
     *
444
     * But we can do some simpler operations, right? How about PictOpOutReverse,
445
     * which has a source factor of 0 and dest factor of (1 - source alpha). We
446
     * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
447
     * blenders pretty easily. So we can do a component-alpha OutReverse, which
448
     * gets us:
449
     *
450
     * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
451
     * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
452
     * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
453
     * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
454
     *
455
     * OK. And if an op doesn't use the source alpha value for the destination
456
     * factor, then we can do the channel multiplication in the texture blenders
457
     * to get the source value, and ignore the source alpha that we wouldn't use.
458
     * We've supported this in the Radeon driver for a long time. An example would
459
     * be PictOpAdd, which does:
460
     *
461
     * dst.A = src.A * mask.A + dst.A
462
     * dst.R = src.R * mask.R + dst.R
463
     * dst.G = src.G * mask.G + dst.G
464
     * dst.B = src.B * mask.B + dst.B
465
     *
466
     * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
467
     * after it, we get:
468
     *
469
     * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
470
     * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
471
     * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
472
     * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
473
     *
474
     * This two-pass trickery could be avoided using a new GL extension that
475
     * lets two values come out of the shader and into the blend unit.
476
     */
477
    if (setup->op == CAIRO_OPERATOR_OVER) {
478
	setup->op = CAIRO_OPERATOR_ADD;
479
	status = _cairo_gl_get_shader_by_type (ctx,
480
                                               &setup->src,
481
                                               &setup->mask,
482
					       setup->spans,
483
                                               CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
484
                                               &pre_shader);
485
        if (unlikely (status))
486
            return status;
487
    }
488
 
489
    if (ctx->pre_shader != pre_shader)
490
        _cairo_gl_composite_flush (ctx);
491
    ctx->pre_shader = pre_shader;
492
 
493
    return CAIRO_STATUS_SUCCESS;
494
}
495
 
496
static void
497
_scissor_to_doubles (cairo_gl_surface_t	*surface,
498
		     double x1, double y1,
499
		     double x2, double y2)
500
{
501
    double height;
502
 
503
    height = y2 - y1;
504
    if (_cairo_gl_surface_is_texture (surface) == FALSE)
505
	y1 = surface->height - (y1 + height);
506
    glScissor (x1, y1, x2 - x1, height);
507
    glEnable (GL_SCISSOR_TEST);
508
}
509
 
510
void
511
_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
512
		       const cairo_rectangle_int_t *r)
513
{
514
    _scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
515
}
516
 
517
static void
518
_scissor_to_box (cairo_gl_surface_t	*surface,
519
		 const cairo_box_t	*box)
520
{
521
    double x1, y1, x2, y2;
522
    _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2);
523
    _scissor_to_doubles (surface, x1, y1, x2, y2);
524
}
525
 
526
static cairo_bool_t
527
_cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
528
			       unsigned int size_per_vertex)
529
{
530
    cairo_bool_t vertex_size_changed = ctx->vertex_size != size_per_vertex;
531
    if (vertex_size_changed) {
532
	ctx->vertex_size = size_per_vertex;
533
	_cairo_gl_composite_flush (ctx);
534
    }
535
 
536
    if (_cairo_gl_context_is_flushed (ctx)) {
537
	ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
538
					   GL_FLOAT, GL_FALSE, size_per_vertex,
539
					   ctx->vb);
540
	ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
541
    }
542
 
543
    return vertex_size_changed;
544
}
545
 
546
static void
547
_disable_stencil_buffer (void)
548
{
549
    glDisable (GL_STENCIL_TEST);
550
    glDepthMask (GL_FALSE);
551
}
552
 
553
static cairo_int_status_t
554
_cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
555
					    cairo_gl_context_t *ctx,
556
					    int vertex_size)
557
{
558
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
559
 
560
    cairo_gl_surface_t *dst = setup->dst;
561
    cairo_clip_t *clip = setup->clip;
562
 
563
    if (clip->num_boxes == 1 && clip->path == NULL) {
564
	_scissor_to_box (dst, &clip->boxes[0]);
565
	goto disable_stencil_buffer_and_return;
566
    }
567
 
568
    if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
569
	status = CAIRO_INT_STATUS_UNSUPPORTED;
570
	goto disable_stencil_buffer_and_return;
571
    }
572
 
573
    /* We only want to clear the part of the stencil buffer
574
     * that we are about to use. It also does not hurt to
575
     * scissor around the painted clip. */
576
    _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip));
577
 
578
    /* The clip is not rectangular, so use the stencil buffer. */
579
    glDepthMask (GL_TRUE);
580
    glEnable (GL_STENCIL_TEST);
581
 
582
    /* Texture surfaces have private depth/stencil buffers, so we can
583
     * rely on any previous clip being cached there. */
584
    if (_cairo_gl_surface_is_texture (setup->dst)) {
585
	cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
586
	if (_cairo_clip_equal (old_clip, setup->clip))
587
	    goto activate_stencil_buffer_and_return;
588
 
589
	if (old_clip) {
590
	    _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
591
	}
592
 
593
	setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
594
    }
595
 
596
    glClearStencil (0);
597
    glClear (GL_STENCIL_BUFFER_BIT);
598
 
599
    glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
600
    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
601
    glColorMask (0, 0, 0, 0);
602
 
603
    status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
604
 
605
    if (unlikely (status)) {
606
	glColorMask (1, 1, 1, 1);
607
	goto disable_stencil_buffer_and_return;
608
    }
609
 
610
    /* We want to only render to the stencil buffer, so draw everything now.
611
       Flushing also unbinds the VBO, which we want to rebind for regular
612
       drawing. */
613
    _cairo_gl_composite_flush (ctx);
614
    _cairo_gl_composite_setup_vbo (ctx, vertex_size);
615
 
616
activate_stencil_buffer_and_return:
617
    glColorMask (1, 1, 1, 1);
618
    glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
619
    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
620
    return CAIRO_INT_STATUS_SUCCESS;
621
 
622
disable_stencil_buffer_and_return:
623
    _disable_stencil_buffer ();
624
    return status;
625
}
626
 
627
static cairo_int_status_t
628
_cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
629
				    cairo_gl_context_t *ctx,
630
				    int vertex_size)
631
{
632
    cairo_bool_t clip_changing = TRUE;
633
    cairo_bool_t clip_region_changing = TRUE;
634
 
635
    if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
636
	goto disable_all_clipping;
637
 
638
    clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
639
    clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
640
    if (! _cairo_gl_context_is_flushed (ctx) &&
641
	(clip_region_changing || clip_changing))
642
	_cairo_gl_composite_flush (ctx);
643
 
644
    assert (!setup->clip_region || !setup->clip);
645
 
646
    /* setup->clip is only used by the msaa compositor and setup->clip_region
647
     * only by the other compositors, so it's safe to wait to clean up obsolete
648
     * clips. */
649
    if (clip_region_changing) {
650
	cairo_region_destroy (ctx->clip_region);
651
	ctx->clip_region = cairo_region_reference (setup->clip_region);
652
    }
653
    if (clip_changing) {
654
	_cairo_clip_destroy (ctx->clip);
655
	ctx->clip = _cairo_clip_copy (setup->clip);
656
    }
657
 
658
    /* For clip regions, we scissor right before drawing. */
659
    if (setup->clip_region)
660
	goto disable_all_clipping;
661
 
662
    if (setup->clip)
663
	return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
664
                                                           vertex_size);
665
disable_all_clipping:
666
    _disable_stencil_buffer ();
667
    glDisable (GL_SCISSOR_TEST);
668
    return CAIRO_INT_STATUS_SUCCESS;
669
}
670
 
671
cairo_status_t
672
_cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
673
				     cairo_gl_context_t *ctx)
674
{
675
    unsigned int dst_size, src_size, mask_size, vertex_size;
676
    cairo_status_t status;
677
    cairo_gl_shader_t *shader;
678
    cairo_bool_t component_alpha;
679
    cairo_bool_t vertex_size_changed;
680
 
681
    component_alpha =
682
	setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
683
	setup->mask.texture.attributes.has_component_alpha;
684
 
685
    /* Do various magic for component alpha */
686
    if (component_alpha) {
687
	status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
688
	if (unlikely (status))
689
	    return status;
690
     } else {
691
	if (ctx->pre_shader) {
692
	    _cairo_gl_composite_flush (ctx);
693
	    ctx->pre_shader = NULL;
694
	}
695
    }
696
 
697
    status = _cairo_gl_get_shader_by_type (ctx,
698
					   &setup->src,
699
					   &setup->mask,
700
					   setup->spans,
701
					   component_alpha ?
702
					   CAIRO_GL_SHADER_IN_CA_SOURCE :
703
					   CAIRO_GL_SHADER_IN_NORMAL,
704
                                           &shader);
705
    if (unlikely (status)) {
706
	ctx->pre_shader = NULL;
707
	return status;
708
    }
709
    if (ctx->current_shader != shader)
710
        _cairo_gl_composite_flush (ctx);
711
 
712
    status = CAIRO_STATUS_SUCCESS;
713
 
714
    dst_size = 2 * sizeof (GLfloat);
715
    src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
716
    mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
717
    vertex_size = dst_size + src_size + mask_size;
718
 
719
    if (setup->spans)
720
	vertex_size += sizeof (GLfloat);
721
 
722
    vertex_size_changed = _cairo_gl_composite_setup_vbo (ctx, vertex_size);
723
 
724
    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size, vertex_size_changed);
725
    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size, vertex_size_changed);
726
 
727
    _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
728
				   dst_size + src_size + mask_size);
729
 
730
    _cairo_gl_set_operator (ctx, setup->op, component_alpha);
731
 
732
    if (_cairo_gl_context_is_flushed (ctx)) {
733
	if (ctx->pre_shader) {
734
	    _cairo_gl_set_shader (ctx, ctx->pre_shader);
735
	    _cairo_gl_composite_bind_to_shader (ctx, setup);
736
	}
737
	_cairo_gl_set_shader (ctx, shader);
738
	_cairo_gl_composite_bind_to_shader (ctx, setup);
739
    }
740
 
741
    return status;
742
}
743
 
744
cairo_status_t
745
_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
746
			   cairo_gl_context_t **ctx_out)
747
{
748
    cairo_gl_context_t *ctx;
749
    cairo_status_t status;
750
 
751
    assert (setup->dst);
752
 
753
    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
754
    if (unlikely (status))
755
	return status;
756
 
757
    _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
758
    glEnable (GL_BLEND);
759
 
760
    status = _cairo_gl_set_operands_and_operator (setup, ctx);
761
    if (unlikely (status))
762
	goto FAIL;
763
 
764
    status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
765
    if (unlikely (status))
766
	goto FAIL;
767
 
768
    *ctx_out = ctx;
769
 
770
FAIL:
771
    if (unlikely (status))
772
        status = _cairo_gl_context_release (ctx, status);
773
 
774
    return status;
775
}
776
 
777
static inline void
778
_cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
779
{
780
    cairo_array_t* indices = &ctx->tristrip_indices;
781
    const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
782
 
783
    if (ctx->pre_shader) {
784
	cairo_gl_shader_t *prev_shader = ctx->current_shader;
785
 
786
	_cairo_gl_set_shader (ctx, ctx->pre_shader);
787
	_cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
788
	glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
789
 
790
	_cairo_gl_set_shader (ctx, prev_shader);
791
	_cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
792
    }
793
 
794
    glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
795
    _cairo_array_truncate (indices, 0);
796
}
797
 
798
static inline void
799
_cairo_gl_composite_draw_triangles (cairo_gl_context_t *ctx,
800
				    unsigned int count)
801
{
802
    if (! ctx->pre_shader) {
803
        glDrawArrays (GL_TRIANGLES, 0, count);
804
    } else {
805
        cairo_gl_shader_t *prev_shader = ctx->current_shader;
806
 
807
        _cairo_gl_set_shader (ctx, ctx->pre_shader);
808
        _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
809
        glDrawArrays (GL_TRIANGLES, 0, count);
810
 
811
        _cairo_gl_set_shader (ctx, prev_shader);
812
        _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
813
        glDrawArrays (GL_TRIANGLES, 0, count);
814
    }
815
}
816
 
817
static void
818
_cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
819
						     unsigned int count)
820
{
821
    int i, num_rectangles;
822
 
823
    if (!ctx->clip_region) {
824
	_cairo_gl_composite_draw_triangles (ctx, count);
825
	return;
826
    }
827
 
828
    num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
829
    for (i = 0; i < num_rectangles; i++) {
830
	cairo_rectangle_int_t rect;
831
 
832
	cairo_region_get_rectangle (ctx->clip_region, i, &rect);
833
 
834
	_cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
835
	_cairo_gl_composite_draw_triangles (ctx, count);
836
    }
837
}
838
 
839
static void
840
_cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
841
{
842
    ctx->vb_offset = 0;
843
}
844
 
845
void
846
_cairo_gl_composite_flush (cairo_gl_context_t *ctx)
847
{
848
    unsigned int count;
849
    int i;
850
 
851
    if (_cairo_gl_context_is_flushed (ctx))
852
        return;
853
 
854
    count = ctx->vb_offset / ctx->vertex_size;
855
    _cairo_gl_composite_unmap_vertex_buffer (ctx);
856
 
857
    if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) {
858
	_cairo_gl_composite_draw_tristrip (ctx);
859
    } else {
860
	assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
861
	_cairo_gl_composite_draw_triangles_with_clip_region (ctx, count);
862
    }
863
 
864
    for (i = 0; i < ARRAY_LENGTH (&ctx->glyph_cache); i++)
865
	_cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
866
}
867
 
868
static void
869
_cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
870
				    unsigned int n_vertices,
871
				    cairo_gl_primitive_type_t primitive_type)
872
{
873
    if (ctx->primitive_type != primitive_type) {
874
	_cairo_gl_composite_flush (ctx);
875
	ctx->primitive_type = primitive_type;
876
    }
877
 
878
    if (ctx->vb_offset + n_vertices * ctx->vertex_size > CAIRO_GL_VBO_SIZE)
879
	_cairo_gl_composite_flush (ctx);
880
}
881
 
882
static inline void
883
_cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
884
				 GLfloat x, GLfloat y)
885
{
886
    GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
887
 
888
    *vb++ = x;
889
    *vb++ = y;
890
 
891
    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
892
    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y);
893
 
894
    ctx->vb_offset += ctx->vertex_size;
895
}
896
 
897
static inline void
898
_cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
899
				       GLfloat x, GLfloat y, uint8_t alpha)
900
{
901
    GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
902
    union fi {
903
	float f;
904
	GLbyte bytes[4];
905
    } fi;
906
 
907
    *vb++ = x;
908
    *vb++ = y;
909
 
910
    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
911
    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y);
912
 
913
    fi.bytes[0] = 0;
914
    fi.bytes[1] = 0;
915
    fi.bytes[2] = 0;
916
    fi.bytes[3] = alpha;
917
    *vb++ = fi.f;
918
 
919
    ctx->vb_offset += ctx->vertex_size;
920
}
921
 
922
static void
923
_cairo_gl_composite_emit_point (cairo_gl_context_t	*ctx,
924
				const cairo_point_t	*point)
925
{
926
    _cairo_gl_composite_emit_vertex (ctx,
927
				     _cairo_fixed_to_double (point->x),
928
				     _cairo_fixed_to_double (point->y));
929
}
930
 
931
static void
932
_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
933
                               GLfloat x1, GLfloat y1,
934
                               GLfloat x2, GLfloat y2)
935
{
936
    _cairo_gl_composite_prepare_buffer (ctx, 6,
937
					CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
938
 
939
    _cairo_gl_composite_emit_vertex (ctx, x1, y1);
940
    _cairo_gl_composite_emit_vertex (ctx, x2, y1);
941
    _cairo_gl_composite_emit_vertex (ctx, x1, y2);
942
 
943
    _cairo_gl_composite_emit_vertex (ctx, x2, y1);
944
    _cairo_gl_composite_emit_vertex (ctx, x2, y2);
945
    _cairo_gl_composite_emit_vertex (ctx, x1, y2);
946
}
947
 
948
cairo_gl_emit_rect_t
949
_cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
950
{
951
    return _cairo_gl_composite_emit_rect;
952
}
953
 
954
void
955
_cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
956
			     GLfloat x1, GLfloat y1,
957
			     GLfloat x2, GLfloat y2)
958
{
959
    _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
960
}
961
 
962
static void
963
_cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
964
                               GLfloat x1, GLfloat y1,
965
                               GLfloat x2, GLfloat y2,
966
                               uint8_t alpha)
967
{
968
    _cairo_gl_composite_prepare_buffer (ctx, 6,
969
					CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
970
 
971
    _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
972
    _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
973
    _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
974
 
975
    _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
976
    _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
977
    _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
978
}
979
 
980
static void
981
_cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
982
				     GLfloat x1, GLfloat y1,
983
				     GLfloat x2, GLfloat y2,
984
				     uint8_t alpha)
985
{
986
    GLfloat *v;
987
    union fi {
988
	float f;
989
	GLbyte bytes[4];
990
    } fi;
991
 
992
    _cairo_gl_composite_prepare_buffer (ctx, 6,
993
					CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
994
    v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
995
 
996
    v[15] = v[ 6] = v[0] = x1;
997
    v[10] = v[ 4] = v[1] = y1;
998
    v[12] = v[ 9] = v[3] = x2;
999
    v[16] = v[13] = v[7] = y2;
1000
 
1001
    fi.bytes[0] = 0;
1002
    fi.bytes[1] = 0;
1003
    fi.bytes[2] = 0;
1004
    fi.bytes[3] = alpha;
1005
    v[17] =v[14] = v[11] = v[8] = v[5] = v[2] = fi.f;
1006
 
1007
    ctx->vb_offset += 6*3 * sizeof(GLfloat);
1008
}
1009
 
1010
cairo_gl_emit_span_t
1011
_cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
1012
{
1013
    if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE) {
1014
	    switch (ctx->operands[CAIRO_GL_TEX_MASK].type) {
1015
	    default:
1016
	    case CAIRO_GL_OPERAND_COUNT:
1017
		    ASSERT_NOT_REACHED;
1018
	    case CAIRO_GL_OPERAND_NONE:
1019
	    case CAIRO_GL_OPERAND_CONSTANT:
1020
		    break;
1021
 
1022
	    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1023
	    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1024
	    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1025
	    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1026
		    if (!ctx->operands[CAIRO_GL_TEX_MASK].gradient.texgen)
1027
			    return _cairo_gl_composite_emit_span;
1028
		    break;
1029
 
1030
	    case CAIRO_GL_OPERAND_TEXTURE:
1031
		    if (!ctx->operands[CAIRO_GL_TEX_MASK].texture.texgen)
1032
			    return _cairo_gl_composite_emit_span;
1033
		    break;
1034
	    }
1035
    }
1036
 
1037
    switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1038
    default:
1039
    case CAIRO_GL_OPERAND_COUNT:
1040
        ASSERT_NOT_REACHED;
1041
    case CAIRO_GL_OPERAND_NONE:
1042
    case CAIRO_GL_OPERAND_CONSTANT:
1043
	break;
1044
 
1045
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1046
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1047
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1048
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1049
	if (!ctx->operands[CAIRO_GL_TEX_SOURCE].gradient.texgen)
1050
		return _cairo_gl_composite_emit_span;
1051
	break;
1052
 
1053
    case CAIRO_GL_OPERAND_TEXTURE:
1054
	if (!ctx->operands[CAIRO_GL_TEX_SOURCE].texture.texgen)
1055
		return _cairo_gl_composite_emit_span;
1056
    }
1057
 
1058
    return _cairo_gl_composite_emit_solid_span;
1059
}
1060
 
1061
static inline void
1062
_cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
1063
				       GLfloat x, GLfloat y,
1064
				       GLfloat glyph_x, GLfloat glyph_y)
1065
{
1066
    GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1067
 
1068
    *vb++ = x;
1069
    *vb++ = y;
1070
 
1071
    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1072
 
1073
    *vb++ = glyph_x;
1074
    *vb++ = glyph_y;
1075
 
1076
    ctx->vb_offset += ctx->vertex_size;
1077
}
1078
 
1079
static void
1080
_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
1081
                                GLfloat x1, GLfloat y1,
1082
                                GLfloat x2, GLfloat y2,
1083
                                GLfloat glyph_x1, GLfloat glyph_y1,
1084
                                GLfloat glyph_x2, GLfloat glyph_y2)
1085
{
1086
    _cairo_gl_composite_prepare_buffer (ctx, 6,
1087
					CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1088
 
1089
    _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
1090
    _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1091
    _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1092
 
1093
    _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1094
    _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
1095
    _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1096
}
1097
 
1098
static void
1099
_cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
1100
				      GLfloat x1, GLfloat y1,
1101
				      GLfloat x2, GLfloat y2,
1102
				      GLfloat glyph_x1, GLfloat glyph_y1,
1103
				      GLfloat glyph_x2, GLfloat glyph_y2)
1104
{
1105
    GLfloat *v;
1106
 
1107
    _cairo_gl_composite_prepare_buffer (ctx, 6,
1108
					CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1109
 
1110
    v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1111
 
1112
    v[20] = v[ 8] = v[0] = x1;
1113
    v[13] = v[ 5] = v[1] = y1;
1114
    v[22] = v[10] = v[2] = glyph_x1;
1115
    v[15] = v[ 7] = v[3] = glyph_y1;
1116
 
1117
    v[16] = v[12] = v[4] = x2;
1118
    v[18] = v[14] = v[6] = glyph_x2;
1119
 
1120
    v[21] = v[17] = v[ 9] = y2;
1121
    v[23] = v[19] = v[11] = glyph_y2;
1122
 
1123
    ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
1124
}
1125
 
1126
cairo_gl_emit_glyph_t
1127
_cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx)
1128
{
1129
    switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1130
    default:
1131
    case CAIRO_GL_OPERAND_COUNT:
1132
        ASSERT_NOT_REACHED;
1133
    case CAIRO_GL_OPERAND_NONE:
1134
    case CAIRO_GL_OPERAND_CONSTANT:
1135
	return _cairo_gl_composite_emit_solid_glyph;
1136
 
1137
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1138
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1139
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1140
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1141
    case CAIRO_GL_OPERAND_TEXTURE:
1142
	return _cairo_gl_composite_emit_glyph;
1143
    }
1144
}
1145
 
1146
void
1147
_cairo_gl_composite_fini (cairo_gl_composite_t *setup)
1148
{
1149
    _cairo_gl_operand_destroy (&setup->src);
1150
    _cairo_gl_operand_destroy (&setup->mask);
1151
}
1152
 
1153
cairo_status_t
1154
_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
1155
				  cairo_operator_t op,
1156
				  cairo_bool_t assume_component_alpha)
1157
{
1158
    if (assume_component_alpha) {
1159
        if (op != CAIRO_OPERATOR_CLEAR &&
1160
            op != CAIRO_OPERATOR_OVER &&
1161
            op != CAIRO_OPERATOR_ADD)
1162
            return UNSUPPORTED ("unsupported component alpha operator");
1163
    } else {
1164
        if (! _cairo_gl_operator_is_supported (op))
1165
            return UNSUPPORTED ("unsupported operator");
1166
    }
1167
 
1168
    setup->op = op;
1169
    return CAIRO_STATUS_SUCCESS;
1170
}
1171
 
1172
cairo_status_t
1173
_cairo_gl_composite_init (cairo_gl_composite_t *setup,
1174
                          cairo_operator_t op,
1175
                          cairo_gl_surface_t *dst,
1176
                          cairo_bool_t assume_component_alpha)
1177
{
1178
    cairo_status_t status;
1179
 
1180
    memset (setup, 0, sizeof (cairo_gl_composite_t));
1181
 
1182
    status = _cairo_gl_composite_set_operator (setup, op,
1183
					       assume_component_alpha);
1184
    if (status)
1185
	return status;
1186
 
1187
    setup->dst = dst;
1188
    setup->clip_region = dst->clip_region;
1189
 
1190
    return CAIRO_STATUS_SUCCESS;
1191
}
1192
 
1193
static cairo_int_status_t
1194
_cairo_gl_composite_append_vertex_indices (cairo_gl_context_t	*ctx,
1195
					   int			 number_of_new_indices)
1196
{
1197
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1198
    cairo_array_t *indices = &ctx->tristrip_indices;
1199
    int number_of_indices = _cairo_array_num_elements (indices);
1200
    unsigned short current_vertex_index = 0;
1201
    int i;
1202
 
1203
    assert (number_of_new_indices > 0);
1204
 
1205
    /* If any preexisting triangle triangle strip indices exist on this
1206
       context, we insert a set of degenerate triangles from the last
1207
       preexisting vertex to our first one. */
1208
    if (number_of_indices > 0) {
1209
	const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
1210
	current_vertex_index = indices_array[number_of_indices - 1];
1211
 
1212
	status = _cairo_array_append (indices, ¤t_vertex_index);
1213
	if (unlikely (status))
1214
	    return status;
1215
 
1216
	current_vertex_index++;
1217
	status =_cairo_array_append (indices, ¤t_vertex_index);
1218
	if (unlikely (status))
1219
	    return status;
1220
    }
1221
 
1222
    for (i = 0; i < number_of_new_indices; i++) {
1223
	status = _cairo_array_append (indices, ¤t_vertex_index);
1224
	current_vertex_index++;
1225
	if (unlikely (status))
1226
	    return status;
1227
    }
1228
 
1229
    return CAIRO_STATUS_SUCCESS;
1230
}
1231
 
1232
cairo_int_status_t
1233
_cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t	*ctx,
1234
					   cairo_gl_composite_t	*setup,
1235
					   const cairo_point_t	quad[4])
1236
{
1237
    _cairo_gl_composite_prepare_buffer (ctx, 4,
1238
					CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1239
 
1240
    _cairo_gl_composite_emit_point (ctx, &quad[0]);
1241
    _cairo_gl_composite_emit_point (ctx, &quad[1]);
1242
 
1243
    /* Cairo stores quad vertices in counter-clockwise order, but we need to
1244
       emit them from top to bottom in the triangle strip, so we need to reverse
1245
       the order of the last two vertices. */
1246
    _cairo_gl_composite_emit_point (ctx, &quad[3]);
1247
    _cairo_gl_composite_emit_point (ctx, &quad[2]);
1248
 
1249
    return _cairo_gl_composite_append_vertex_indices (ctx, 4);
1250
}
1251
 
1252
cairo_int_status_t
1253
_cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t	*ctx,
1254
					       cairo_gl_composite_t	*setup,
1255
					       const cairo_point_t	 triangle[3])
1256
{
1257
    _cairo_gl_composite_prepare_buffer (ctx, 3,
1258
					CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1259
 
1260
    _cairo_gl_composite_emit_point (ctx, &triangle[0]);
1261
    _cairo_gl_composite_emit_point (ctx, &triangle[1]);
1262
    _cairo_gl_composite_emit_point (ctx, &triangle[2]);
1263
    return _cairo_gl_composite_append_vertex_indices (ctx, 3);
1264
}