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 | }>> |