Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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 © 2009 Eric Anholt
4
 * Copyright © 2009 Chris Wilson
5
 * Copyright © 2005,2010 Red Hat, Inc
6
 * Copyright © 2011 Intel Corporation
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it either under the terms of the GNU Lesser General Public
10
 * License version 2.1 as published by the Free Software Foundation
11
 * (the "LGPL") or, at your option, under the terms of the Mozilla
12
 * Public License Version 1.1 (the "MPL"). If you do not alter this
13
 * notice, a recipient may use your version of this file under either
14
 * the MPL or the LGPL.
15
 *
16
 * You should have received a copy of the LGPL along with this library
17
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19
 * You should have received a copy of the MPL along with this library
20
 * in the file COPYING-MPL-1.1
21
 *
22
 * The contents of this file are subject to the Mozilla Public License
23
 * Version 1.1 (the "License"); you may not use this file except in
24
 * compliance with the License. You may obtain a copy of the License at
25
 * http://www.mozilla.org/MPL/
26
 *
27
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29
 * the specific language governing rights and limitations.
30
 *
31
 * The Original Code is the cairo graphics library.
32
 *
33
 * The Initial Developer of the Original Code is Red Hat, Inc.
34
 *
35
 * Contributor(s):
36
 *	Benjamin Otte 
37
 *	Carl Worth 
38
 *	Chris Wilson 
39
 *	Eric Anholt 
40
 */
41
 
42
#include "cairoint.h"
43
 
44
#include "cairo-gl-private.h"
45
 
46
#include "cairo-composite-rectangles-private.h"
47
#include "cairo-compositor-private.h"
48
#include "cairo-default-context-private.h"
49
#include "cairo-error-private.h"
50
#include "cairo-image-surface-private.h"
51
#include "cairo-surface-backend-private.h"
52
#include "cairo-surface-offset-private.h"
53
#include "cairo-surface-subsurface-inline.h"
54
 
55
static cairo_int_status_t
56
_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
57
				   const cairo_gradient_pattern_t *pattern,
58
                                   cairo_gl_gradient_t **gradient)
59
{
60
    cairo_gl_context_t *ctx;
61
    cairo_status_t status;
62
 
63
    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
64
    if (unlikely (status))
65
	return status;
66
 
67
    status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
68
 
69
    return _cairo_gl_context_release (ctx, status);
70
}
71
 
72
static cairo_status_t
73
_cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
74
					 const cairo_pattern_t *_src,
75
					 cairo_gl_surface_t *dst,
76
					 const cairo_rectangle_int_t *sample,
77
					 const cairo_rectangle_int_t *extents,
78
					 cairo_bool_t use_texgen)
79
{
80
    const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
81
    cairo_surface_pattern_t local_pattern;
82
    cairo_surface_subsurface_t *sub;
83
    cairo_gl_surface_t *surface;
84
    cairo_gl_context_t *ctx;
85
    cairo_surface_attributes_t *attributes;
86
    cairo_status_t status;
87
 
88
    sub = (cairo_surface_subsurface_t *) src->surface;
89
 
90
    if (sub->snapshot &&
91
	sub->snapshot->type == CAIRO_SURFACE_TYPE_GL &&
92
	sub->snapshot->device == dst->base.device)
93
    {
94
	surface = (cairo_gl_surface_t *)
95
	    cairo_surface_reference (sub->snapshot);
96
    }
97
    else
98
    {
99
	status = _cairo_gl_context_acquire (dst->base.device, &ctx);
100
	if (unlikely (status))
101
	    return status;
102
 
103
	/* XXX Trim surface to the sample area within the subsurface? */
104
	surface = (cairo_gl_surface_t *)
105
	    _cairo_gl_surface_create_scratch (ctx,
106
					      sub->target->content,
107
					      sub->extents.width,
108
					      sub->extents.height);
109
	if (surface->base.status)
110
	    return _cairo_gl_context_release (ctx, surface->base.status);
111
 
112
	_cairo_pattern_init_for_surface (&local_pattern, sub->target);
113
	cairo_matrix_init_translate (&local_pattern.base.matrix,
114
				     sub->extents.x, sub->extents.y);
115
	local_pattern.base.filter = CAIRO_FILTER_NEAREST;
116
	status = _cairo_surface_paint (&surface->base,
117
				       CAIRO_OPERATOR_SOURCE,
118
				       &local_pattern.base,
119
				       NULL);
120
	_cairo_pattern_fini (&local_pattern.base);
121
 
122
	status = _cairo_gl_context_release (ctx, status);
123
	if (unlikely (status)) {
124
	    cairo_surface_destroy (&surface->base);
125
	    return status;
126
	}
127
 
128
	_cairo_surface_subsurface_set_snapshot (&sub->base, &surface->base);
129
    }
130
 
131
    status = _cairo_gl_surface_resolve_multisampling (surface);
132
    if (unlikely (status))
133
        return status;
134
 
135
    attributes = &operand->texture.attributes;
136
 
137
    operand->type = CAIRO_GL_OPERAND_TEXTURE;
138
    operand->texture.surface = surface;
139
    operand->texture.owns_surface = surface;
140
    operand->texture.tex = surface->tex;
141
 
142
    if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
143
	attributes->matrix = src->base.matrix;
144
    } else {
145
	cairo_matrix_t m;
146
 
147
	cairo_matrix_init_scale (&m,
148
				 1.0 / surface->width,
149
				 1.0 / surface->height);
150
	cairo_matrix_multiply (&attributes->matrix, &src->base.matrix, &m);
151
    }
152
 
153
    attributes->extend = src->base.extend;
154
    attributes->filter = src->base.filter;
155
    attributes->has_component_alpha = src->base.has_component_alpha;
156
 
157
    operand->texture.texgen = use_texgen;
158
    return CAIRO_STATUS_SUCCESS;
159
}
160
 
161
static cairo_status_t
162
_cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
163
				   const cairo_pattern_t *_src,
164
				   cairo_gl_surface_t *dst,
165
				   const cairo_rectangle_int_t *sample,
166
				   const cairo_rectangle_int_t *extents,
167
				   cairo_bool_t use_texgen)
168
{
169
    const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
170
    cairo_surface_subsurface_t *sub;
171
    cairo_gl_surface_t *surface;
172
    cairo_surface_attributes_t *attributes;
173
    cairo_int_status_t status;
174
 
175
    sub = (cairo_surface_subsurface_t *) src->surface;
176
 
177
    if (sample->x < 0 || sample->y < 0 ||
178
	sample->x + sample->width  > sub->extents.width ||
179
	sample->y + sample->height > sub->extents.height)
180
    {
181
	return _cairo_gl_subsurface_clone_operand_init (operand, _src,
182
							dst, sample, extents,
183
							use_texgen);
184
    }
185
 
186
    surface = (cairo_gl_surface_t *) sub->target;
187
    if (surface->base.device && surface->base.device != dst->base.device)
188
	return CAIRO_INT_STATUS_UNSUPPORTED;
189
 
190
    if (! _cairo_gl_surface_is_texture (surface))
191
	return CAIRO_INT_STATUS_UNSUPPORTED;
192
 
193
    status = _cairo_gl_surface_resolve_multisampling (surface);
194
    if (unlikely (status))
195
	return status;
196
 
197
    /* Translate the matrix from
198
     * (unnormalized src -> unnormalized src) to
199
     * (unnormalized dst -> unnormalized src)
200
     */
201
    _cairo_gl_operand_copy(operand, &surface->operand);
202
 
203
    attributes = &operand->texture.attributes;
204
    attributes->matrix = src->base.matrix;
205
    attributes->matrix.x0 += sub->extents.x;
206
    attributes->matrix.y0 += sub->extents.y;
207
    cairo_matrix_multiply (&attributes->matrix,
208
			   &attributes->matrix,
209
			   &surface->operand.texture.attributes.matrix);
210
 
211
    attributes->extend = src->base.extend;
212
    attributes->filter = src->base.filter;
213
    attributes->has_component_alpha = src->base.has_component_alpha;
214
 
215
    operand->texture.texgen = use_texgen;
216
    return CAIRO_STATUS_SUCCESS;
217
}
218
 
219
static cairo_status_t
220
_cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
221
				const cairo_pattern_t *_src,
222
				cairo_gl_surface_t *dst,
223
				const cairo_rectangle_int_t *sample,
224
				const cairo_rectangle_int_t *extents,
225
				cairo_bool_t use_texgen)
226
{
227
    const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
228
    cairo_gl_surface_t *surface;
229
    cairo_surface_attributes_t *attributes;
230
    cairo_int_status_t status;
231
 
232
    surface = (cairo_gl_surface_t *) src->surface;
233
    if (surface->base.type != CAIRO_SURFACE_TYPE_GL)
234
	return CAIRO_INT_STATUS_UNSUPPORTED;
235
 
236
    if (surface->base.backend->type != CAIRO_SURFACE_TYPE_GL) {
237
	if (_cairo_surface_is_subsurface (&surface->base))
238
	    return _cairo_gl_subsurface_operand_init (operand, _src, dst,
239
						      sample, extents,
240
						      use_texgen);
241
 
242
	return CAIRO_INT_STATUS_UNSUPPORTED;
243
    }
244
 
245
    if (surface->base.device && surface->base.device != dst->base.device)
246
	return CAIRO_INT_STATUS_UNSUPPORTED;
247
 
248
    if (surface->base.device && ! _cairo_gl_surface_is_texture (surface))
249
	return CAIRO_INT_STATUS_UNSUPPORTED;
250
 
251
    status = _cairo_gl_surface_resolve_multisampling (surface);
252
    if (unlikely (status))
253
	return status;
254
 
255
    _cairo_gl_operand_copy(operand, &surface->operand);
256
 
257
    attributes = &operand->texture.attributes;
258
    cairo_matrix_multiply (&attributes->matrix,
259
			   &src->base.matrix,
260
			   &attributes->matrix);
261
 
262
    attributes->extend = src->base.extend;
263
    attributes->filter = src->base.filter;
264
    attributes->has_component_alpha = src->base.has_component_alpha;
265
 
266
    operand->texture.texgen = use_texgen;
267
    return CAIRO_STATUS_SUCCESS;
268
}
269
 
270
static cairo_status_t
271
_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
272
				 const cairo_pattern_t *_src,
273
				 cairo_gl_surface_t *dst,
274
				 const cairo_rectangle_int_t *extents)
275
{
276
    cairo_status_t status;
277
    cairo_gl_surface_t *surface;
278
    cairo_gl_context_t *ctx;
279
    cairo_image_surface_t *image;
280
    cairo_bool_t src_is_gl_surface = FALSE;
281
    cairo_rectangle_int_t map_extents;
282
 
283
    if (_src->type == CAIRO_PATTERN_TYPE_SURFACE) {
284
	cairo_surface_t* src_surface = ((cairo_surface_pattern_t *) _src)->surface;
285
	src_is_gl_surface = src_surface->type == CAIRO_SURFACE_TYPE_GL;
286
    }
287
 
288
    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
289
    if (unlikely (status))
290
	return status;
291
 
292
    surface = (cairo_gl_surface_t *)
293
	_cairo_gl_surface_create_scratch (ctx,
294
					  CAIRO_CONTENT_COLOR_ALPHA,
295
					  extents->width, extents->height);
296
    map_extents = *extents;
297
    map_extents.x = map_extents.y = 0;
298
    image = _cairo_surface_map_to_image (&surface->base, &map_extents);
299
 
300
    /* If the pattern is a GL surface, it belongs to some other GL context,
301
       so we need to release this device while we paint it to the image. */
302
    if (src_is_gl_surface) {
303
	status = _cairo_gl_context_release (ctx, status);
304
	if (unlikely (status))
305
	    goto fail;
306
    }
307
 
308
    status = _cairo_surface_offset_paint (&image->base, extents->x, extents->y,
309
					  CAIRO_OPERATOR_SOURCE, _src, NULL);
310
 
311
    if (src_is_gl_surface) {
312
	status = _cairo_gl_context_acquire (dst->base.device, &ctx);
313
	if (unlikely (status))
314
	    goto fail;
315
    }
316
 
317
    status = _cairo_surface_unmap_image (&surface->base, image);
318
    status = _cairo_gl_context_release (ctx, status);
319
    if (unlikely (status))
320
	goto fail;
321
 
322
    *operand = surface->operand;
323
    operand->texture.owns_surface = surface;
324
    operand->texture.attributes.matrix.x0 -= extents->x * operand->texture.attributes.matrix.xx;
325
    operand->texture.attributes.matrix.y0 -= extents->y * operand->texture.attributes.matrix.yy;
326
    return CAIRO_STATUS_SUCCESS;
327
 
328
fail:
329
    cairo_surface_destroy (&surface->base);
330
    return status;
331
}
332
 
333
void
334
_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
335
	                      const cairo_color_t *color)
336
{
337
    operand->type = CAIRO_GL_OPERAND_CONSTANT;
338
    operand->constant.color[0] = color->red   * color->alpha;
339
    operand->constant.color[1] = color->green * color->alpha;
340
    operand->constant.color[2] = color->blue  * color->alpha;
341
    operand->constant.color[3] = color->alpha;
342
}
343
 
344
void
345
_cairo_gl_operand_translate (cairo_gl_operand_t *operand,
346
			     double tx, double ty)
347
{
348
    switch (operand->type) {
349
    case CAIRO_GL_OPERAND_TEXTURE:
350
	operand->texture.attributes.matrix.x0 -= tx * operand->texture.attributes.matrix.xx;
351
	operand->texture.attributes.matrix.y0 -= ty * operand->texture.attributes.matrix.yy;
352
	break;
353
 
354
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
355
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
356
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
357
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
358
	operand->gradient.m.x0 -= tx * operand->gradient.m.xx;
359
	operand->gradient.m.y0 -= ty * operand->gradient.m.yy;
360
	break;
361
 
362
    case CAIRO_GL_OPERAND_NONE:
363
    case CAIRO_GL_OPERAND_CONSTANT:
364
    case CAIRO_GL_OPERAND_COUNT:
365
    default:
366
	break;
367
    }
368
}
369
 
370
static cairo_status_t
371
_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
372
                                 const cairo_pattern_t *pattern,
373
				 cairo_gl_surface_t *dst,
374
				 cairo_bool_t use_texgen)
375
{
376
    const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
377
    cairo_status_t status;
378
 
379
    assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
380
	    gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
381
 
382
    if (! _cairo_gl_device_has_glsl (dst->base.device))
383
	return CAIRO_INT_STATUS_UNSUPPORTED;
384
 
385
    status = _cairo_gl_create_gradient_texture (dst,
386
						gradient,
387
						&operand->gradient.gradient);
388
    if (unlikely (status))
389
	return status;
390
 
391
    if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
392
	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
393
	double x0, y0, dx, dy, sf, offset;
394
 
395
	dx = linear->pd2.x - linear->pd1.x;
396
	dy = linear->pd2.y - linear->pd1.y;
397
	sf = 1.0 / (dx * dx + dy * dy);
398
	dx *= sf;
399
	dy *= sf;
400
 
401
	x0 = linear->pd1.x;
402
	y0 = linear->pd1.y;
403
	offset = dx * x0 + dy * y0;
404
 
405
	operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
406
 
407
	cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
408
	if (! _cairo_matrix_is_identity (&pattern->matrix)) {
409
	    cairo_matrix_multiply (&operand->gradient.m,
410
				   &pattern->matrix,
411
				   &operand->gradient.m);
412
	}
413
    } else {
414
	cairo_matrix_t m;
415
	cairo_circle_double_t circles[2];
416
	double x0, y0, r0, dx, dy, dr;
417
 
418
	/*
419
	 * Some fragment shader implementations use half-floats to
420
	 * represent numbers, so the maximum number they can represent
421
	 * is about 2^14. Some intermediate computations used in the
422
	 * radial gradient shaders can produce results of up to 2*k^4.
423
	 * Setting k=8 makes the maximum result about 8192 (assuming
424
	 * that the extreme circles are not much smaller than the
425
	 * destination image).
426
	 */
427
	_cairo_gradient_pattern_fit_to_range (gradient, 8.,
428
					      &operand->gradient.m, circles);
429
 
430
	x0 = circles[0].center.x;
431
	y0 = circles[0].center.y;
432
	r0 = circles[0].radius;
433
	dx = circles[1].center.x - x0;
434
	dy = circles[1].center.y - y0;
435
	dr = circles[1].radius   - r0;
436
 
437
	operand->gradient.a = dx * dx + dy * dy - dr * dr;
438
	operand->gradient.radius_0 = r0;
439
	operand->gradient.circle_d.center.x = dx;
440
	operand->gradient.circle_d.center.y = dy;
441
	operand->gradient.circle_d.radius   = dr;
442
 
443
	if (operand->gradient.a == 0)
444
	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
445
	else if (pattern->extend == CAIRO_EXTEND_NONE)
446
	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE;
447
	else
448
	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT;
449
 
450
	cairo_matrix_init_translate (&m, -x0, -y0);
451
	cairo_matrix_multiply (&operand->gradient.m,
452
			       &operand->gradient.m,
453
			       &m);
454
    }
455
 
456
    operand->gradient.extend = pattern->extend;
457
    operand->gradient.texgen = use_texgen;
458
 
459
    return CAIRO_STATUS_SUCCESS;
460
}
461
 
462
void
463
_cairo_gl_operand_copy (cairo_gl_operand_t *dst,
464
			const cairo_gl_operand_t *src)
465
{
466
    *dst = *src;
467
    switch (dst->type) {
468
    case CAIRO_GL_OPERAND_CONSTANT:
469
	break;
470
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
471
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
472
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
473
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
474
	_cairo_gl_gradient_reference (dst->gradient.gradient);
475
	break;
476
    case CAIRO_GL_OPERAND_TEXTURE:
477
	cairo_surface_reference (&dst->texture.owns_surface->base);
478
	break;
479
    default:
480
    case CAIRO_GL_OPERAND_COUNT:
481
        ASSERT_NOT_REACHED;
482
    case CAIRO_GL_OPERAND_NONE:
483
        break;
484
    }
485
}
486
 
487
void
488
_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
489
{
490
    switch (operand->type) {
491
    case CAIRO_GL_OPERAND_CONSTANT:
492
	break;
493
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
494
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
495
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
496
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
497
	_cairo_gl_gradient_destroy (operand->gradient.gradient);
498
	break;
499
    case CAIRO_GL_OPERAND_TEXTURE:
500
	cairo_surface_destroy (&operand->texture.owns_surface->base);
501
	break;
502
    default:
503
    case CAIRO_GL_OPERAND_COUNT:
504
        ASSERT_NOT_REACHED;
505
    case CAIRO_GL_OPERAND_NONE:
506
        break;
507
    }
508
 
509
    operand->type = CAIRO_GL_OPERAND_NONE;
510
}
511
 
512
cairo_int_status_t
513
_cairo_gl_operand_init (cairo_gl_operand_t *operand,
514
		        const cairo_pattern_t *pattern,
515
		        cairo_gl_surface_t *dst,
516
			const cairo_rectangle_int_t *sample,
517
			const cairo_rectangle_int_t *extents,
518
			cairo_bool_t use_texgen)
519
{
520
    cairo_int_status_t status;
521
 
522
    TRACE ((stderr, "%s: type=%d\n", __FUNCTION__, pattern->type));
523
    switch (pattern->type) {
524
    case CAIRO_PATTERN_TYPE_SOLID:
525
	_cairo_gl_solid_operand_init (operand,
526
				      &((cairo_solid_pattern_t *) pattern)->color);
527
	return CAIRO_STATUS_SUCCESS;
528
    case CAIRO_PATTERN_TYPE_SURFACE:
529
	status = _cairo_gl_surface_operand_init (operand, pattern, dst,
530
						 sample, extents, use_texgen);
531
	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
532
	    break;
533
 
534
	return status;
535
 
536
    case CAIRO_PATTERN_TYPE_LINEAR:
537
    case CAIRO_PATTERN_TYPE_RADIAL:
538
	status = _cairo_gl_gradient_operand_init (operand, pattern, dst,
539
						  use_texgen);
540
	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
541
	    break;
542
 
543
	return status;
544
 
545
    default:
546
    case CAIRO_PATTERN_TYPE_MESH:
547
    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
548
	break;
549
    }
550
 
551
    return _cairo_gl_pattern_texture_setup (operand, pattern, dst, extents);
552
}
553
 
554
cairo_filter_t
555
_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand)
556
{
557
    cairo_filter_t filter;
558
 
559
    switch ((int) operand->type) {
560
    case CAIRO_GL_OPERAND_TEXTURE:
561
	filter = operand->texture.attributes.filter;
562
	break;
563
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
564
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
565
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
566
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
567
	filter = CAIRO_FILTER_BILINEAR;
568
	break;
569
    default:
570
	filter = CAIRO_FILTER_DEFAULT;
571
	break;
572
    }
573
 
574
    return filter;
575
}
576
 
577
GLint
578
_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand)
579
{
580
    cairo_filter_t filter = _cairo_gl_operand_get_filter (operand);
581
 
582
    return filter != CAIRO_FILTER_FAST && filter != CAIRO_FILTER_NEAREST ?
583
	   GL_LINEAR :
584
	   GL_NEAREST;
585
}
586
 
587
cairo_extend_t
588
_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand)
589
{
590
    cairo_extend_t extend;
591
 
592
    switch ((int) operand->type) {
593
    case CAIRO_GL_OPERAND_TEXTURE:
594
	extend = operand->texture.attributes.extend;
595
	break;
596
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
597
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
598
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
599
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
600
	extend = operand->gradient.extend;
601
	break;
602
    default:
603
	extend = CAIRO_EXTEND_NONE;
604
	break;
605
    }
606
 
607
    return extend;
608
}
609
 
610
 
611
void
612
_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
613
                                  cairo_gl_operand_t *operand,
614
                                  cairo_gl_tex_t      tex_unit)
615
{
616
    const cairo_matrix_t *texgen = NULL;
617
 
618
    switch (operand->type) {
619
    default:
620
    case CAIRO_GL_OPERAND_COUNT:
621
        ASSERT_NOT_REACHED;
622
    case CAIRO_GL_OPERAND_NONE:
623
	return;
624
 
625
    case CAIRO_GL_OPERAND_CONSTANT:
626
	_cairo_gl_shader_bind_vec4 (ctx,
627
                                    ctx->current_shader->constant_location[tex_unit],
628
                                    operand->constant.color[0],
629
                                    operand->constant.color[1],
630
                                    operand->constant.color[2],
631
                                    operand->constant.color[3]);
632
	return;
633
 
634
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
635
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
636
	_cairo_gl_shader_bind_float  (ctx,
637
				      ctx->current_shader->a_location[tex_unit],
638
				      operand->gradient.a);
639
	/* fall through */
640
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
641
	_cairo_gl_shader_bind_vec3   (ctx,
642
				      ctx->current_shader->circle_d_location[tex_unit],
643
				      operand->gradient.circle_d.center.x,
644
				      operand->gradient.circle_d.center.y,
645
				      operand->gradient.circle_d.radius);
646
	_cairo_gl_shader_bind_float  (ctx,
647
				      ctx->current_shader->radius_0_location[tex_unit],
648
				      operand->gradient.radius_0);
649
        /* fall through */
650
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
651
    case CAIRO_GL_OPERAND_TEXTURE:
652
	/*
653
	 * For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
654
	 * with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
655
	 * these shaders need the texture dimensions for their calculations.
656
	 */
657
	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
658
	    _cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
659
	    _cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
660
	{
661
	    float width, height;
662
	    if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
663
		width = operand->texture.surface->width;
664
		height = operand->texture.surface->height;
665
	    }
666
	    else {
667
		width = operand->gradient.gradient->cache_entry.size,
668
		height = 1;
669
	    }
670
	    _cairo_gl_shader_bind_vec2 (ctx,
671
					ctx->current_shader->texdims_location[tex_unit],
672
					width, height);
673
	}
674
	break;
675
    }
676
 
677
    if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
678
	    if (operand->texture.texgen)
679
		    texgen = &operand->texture.attributes.matrix;
680
    } else {
681
	    if (operand->gradient.texgen)
682
		    texgen = &operand->gradient.m;
683
    }
684
    if (texgen) {
685
	    _cairo_gl_shader_bind_matrix(ctx,
686
					 ctx->current_shader->texgen_location[tex_unit],
687
					 texgen);
688
    }
689
}
690
 
691
 
692
cairo_bool_t
693
_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
694
                               cairo_gl_operand_t *source,
695
                               unsigned int        vertex_offset)
696
{
697
    if (dest->type != source->type)
698
        return TRUE;
699
    if (dest->vertex_offset != vertex_offset)
700
        return TRUE;
701
 
702
    switch (source->type) {
703
    case CAIRO_GL_OPERAND_NONE:
704
        return FALSE;
705
    case CAIRO_GL_OPERAND_CONSTANT:
706
        return dest->constant.color[0] != source->constant.color[0] ||
707
               dest->constant.color[1] != source->constant.color[1] ||
708
               dest->constant.color[2] != source->constant.color[2] ||
709
               dest->constant.color[3] != source->constant.color[3];
710
    case CAIRO_GL_OPERAND_TEXTURE:
711
        return dest->texture.surface != source->texture.surface ||
712
               dest->texture.attributes.extend != source->texture.attributes.extend ||
713
               dest->texture.attributes.filter != source->texture.attributes.filter ||
714
               dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha;
715
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
716
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
717
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
718
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
719
        /* XXX: improve this */
720
        return TRUE;
721
    default:
722
    case CAIRO_GL_OPERAND_COUNT:
723
        ASSERT_NOT_REACHED;
724
        break;
725
    }
726
    return TRUE;
727
}
728
 
729
unsigned int
730
_cairo_gl_operand_get_vertex_size (const cairo_gl_operand_t *operand)
731
{
732
    switch (operand->type) {
733
    default:
734
    case CAIRO_GL_OPERAND_COUNT:
735
        ASSERT_NOT_REACHED;
736
    case CAIRO_GL_OPERAND_NONE:
737
    case CAIRO_GL_OPERAND_CONSTANT:
738
        return 0;
739
    case CAIRO_GL_OPERAND_TEXTURE:
740
        return operand->texture.texgen ? 0 : 2 * sizeof (GLfloat);
741
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
742
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
743
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
744
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
745
        return operand->gradient.texgen ? 0 : 2 * sizeof (GLfloat);
746
    }
747
}
748
 
749
void
750
_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
751
                        GLfloat ** vb,
752
                        GLfloat x,
753
                        GLfloat y)
754
{
755
    switch (operand->type) {
756
    default:
757
    case CAIRO_GL_OPERAND_COUNT:
758
        ASSERT_NOT_REACHED;
759
    case CAIRO_GL_OPERAND_NONE:
760
    case CAIRO_GL_OPERAND_CONSTANT:
761
        break;
762
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
763
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
764
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
765
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
766
	if (! operand->gradient.texgen) {
767
	    double s = x;
768
	    double t = y;
769
 
770
	    cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
771
 
772
	    *(*vb)++ = s;
773
	    *(*vb)++ = t;
774
        }
775
	break;
776
    case CAIRO_GL_OPERAND_TEXTURE:
777
	if (! operand->texture.texgen) {
778
            cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
779
            double s = x;
780
            double t = y;
781
 
782
            cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
783
            *(*vb)++ = s;
784
            *(*vb)++ = t;
785
        }
786
        break;
787
    }
788
}