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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it either under the terms of the GNU Lesser General Public
9  * License version 2.1 as published by the Free Software Foundation
10  * (the "LGPL") or, at your option, under the terms of the Mozilla
11  * Public License Version 1.1 (the "MPL"). If you do not alter this
12  * notice, a recipient may use your version of this file under either
13  * the MPL or the LGPL.
14  *
15  * You should have received a copy of the LGPL along with this library
16  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18  * You should have received a copy of the MPL along with this library
19  * in the file COPYING-MPL-1.1
20  *
21  * The contents of this file are subject to the Mozilla Public License
22  * Version 1.1 (the "License"); you may not use this file except in
23  * compliance with the License. You may obtain a copy of the License at
24  * http://www.mozilla.org/MPL/
25  *
26  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28  * the specific language governing rights and limitations.
29  *
30  * The Original Code is the cairo graphics library.
31  *
32  * The Initial Developer of the Original Code is Red Hat, Inc.
33  *
34  * Contributor(s):
35  *	Benjamin Otte <otte@gnome.org>
36  *	Carl Worth <cworth@cworth.org>
37  *	Chris Wilson <chris@chris-wilson.co.uk>
38  *	Eric Anholt <eric@anholt.net>
39  */
40 
41 #include "cairoint.h"
42 
43 #include "cairo-composite-rectangles-private.h"
44 #include "cairo-error-private.h"
45 #include "cairo-gl-private.h"
46 
47 static cairo_int_status_t
48 _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
49 				   cairo_operator_t	    op,
50 				   const cairo_color_t     *color,
51 				   cairo_rectangle_int_t   *rects,
52 				   int			    num_rects);
53 
54 static cairo_int_status_t
55 _cairo_gl_surface_composite (cairo_operator_t		  op,
56 			     const cairo_pattern_t	 *src,
57 			     const cairo_pattern_t	 *mask,
58 			     void			 *abstract_dst,
59 			     int			  src_x,
60 			     int			  src_y,
61 			     int			  mask_x,
62 			     int			  mask_y,
63 			     int			  dst_x,
64 			     int			  dst_y,
65 			     unsigned int		  width,
66 			     unsigned int		  height,
67 			     cairo_region_t		 *clip_region);
68 
69 static cairo_status_t
70 _cairo_gl_surface_flush (void *abstract_surface);
71 
_cairo_surface_is_gl(cairo_surface_t * surface)72 static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
73 {
74     return surface->backend == &_cairo_gl_surface_backend;
75 }
76 
77 cairo_bool_t
_cairo_gl_get_image_format_and_type(pixman_format_code_t pixman_format,GLenum * internal_format,GLenum * format,GLenum * type,cairo_bool_t * has_alpha)78 _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
79 				     GLenum *internal_format, GLenum *format,
80 				     GLenum *type, cairo_bool_t *has_alpha)
81 {
82     *has_alpha = TRUE;
83 
84     switch (pixman_format) {
85     case PIXMAN_a8r8g8b8:
86 	*internal_format = GL_RGBA;
87 	*format = GL_BGRA;
88 	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
89 	return TRUE;
90     case PIXMAN_x8r8g8b8:
91 	*internal_format = GL_RGB;
92 	*format = GL_BGRA;
93 	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
94 	*has_alpha = FALSE;
95 	return TRUE;
96     case PIXMAN_a8b8g8r8:
97 	*internal_format = GL_RGBA;
98 	*format = GL_RGBA;
99 	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
100 	return TRUE;
101     case PIXMAN_x8b8g8r8:
102 	*internal_format = GL_RGB;
103 	*format = GL_RGBA;
104 	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
105 	*has_alpha = FALSE;
106 	return TRUE;
107     case PIXMAN_b8g8r8a8:
108 	*internal_format = GL_RGBA;
109 	*format = GL_BGRA;
110 	*type = GL_UNSIGNED_INT_8_8_8_8;
111 	return TRUE;
112     case PIXMAN_b8g8r8x8:
113 	*internal_format = GL_RGB;
114 	*format = GL_BGRA;
115 	*type = GL_UNSIGNED_INT_8_8_8_8;
116 	*has_alpha = FALSE;
117 	return TRUE;
118     case PIXMAN_r8g8b8:
119 	*internal_format = GL_RGB;
120 	*format = GL_RGB;
121 	*type = GL_UNSIGNED_BYTE;
122 	return TRUE;
123     case PIXMAN_b8g8r8:
124 	*internal_format = GL_RGB;
125 	*format = GL_BGR;
126 	*type = GL_UNSIGNED_BYTE;
127 	return TRUE;
128     case PIXMAN_r5g6b5:
129 	*internal_format = GL_RGB;
130 	*format = GL_RGB;
131 	*type = GL_UNSIGNED_SHORT_5_6_5;
132 	return TRUE;
133     case PIXMAN_b5g6r5:
134 	*internal_format = GL_RGB;
135 	*format = GL_RGB;
136 	*type = GL_UNSIGNED_SHORT_5_6_5_REV;
137 	return TRUE;
138     case PIXMAN_a1r5g5b5:
139 	*internal_format = GL_RGBA;
140 	*format = GL_BGRA;
141 	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
142 	return TRUE;
143     case PIXMAN_x1r5g5b5:
144 	*internal_format = GL_RGB;
145 	*format = GL_BGRA;
146 	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
147 	*has_alpha = FALSE;
148 	return TRUE;
149     case PIXMAN_a1b5g5r5:
150 	*internal_format = GL_RGBA;
151 	*format = GL_RGBA;
152 	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
153 	return TRUE;
154     case PIXMAN_x1b5g5r5:
155 	*internal_format = GL_RGB;
156 	*format = GL_RGBA;
157 	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
158 	*has_alpha = FALSE;
159 	return TRUE;
160     case PIXMAN_a8:
161 	*internal_format = GL_ALPHA;
162 	*format = GL_ALPHA;
163 	*type = GL_UNSIGNED_BYTE;
164 	return TRUE;
165 
166     case PIXMAN_a2b10g10r10:
167     case PIXMAN_x2b10g10r10:
168     case PIXMAN_a4r4g4b4:
169     case PIXMAN_x4r4g4b4:
170     case PIXMAN_a4b4g4r4:
171     case PIXMAN_x4b4g4r4:
172     case PIXMAN_r3g3b2:
173     case PIXMAN_b2g3r3:
174     case PIXMAN_a2r2g2b2:
175     case PIXMAN_a2b2g2r2:
176     case PIXMAN_c8:
177     case PIXMAN_x4a4:
178     /* case PIXMAN_x4c4: */
179     case PIXMAN_x4g4:
180     case PIXMAN_a4:
181     case PIXMAN_r1g2b1:
182     case PIXMAN_b1g2r1:
183     case PIXMAN_a1r1g1b1:
184     case PIXMAN_a1b1g1r1:
185     case PIXMAN_c4:
186     case PIXMAN_g4:
187     case PIXMAN_a1:
188     case PIXMAN_g1:
189     case PIXMAN_yuy2:
190     case PIXMAN_yv12:
191     case PIXMAN_x2r10g10b10:
192     case PIXMAN_a2r10g10b10:
193     default:
194 	return FALSE;
195     }
196 }
197 
198 cairo_bool_t
_cairo_gl_operator_is_supported(cairo_operator_t op)199 _cairo_gl_operator_is_supported (cairo_operator_t op)
200 {
201     return op < CAIRO_OPERATOR_SATURATE;
202 }
203 
204 void
_cairo_gl_surface_init(cairo_device_t * device,cairo_gl_surface_t * surface,cairo_content_t content,int width,int height)205 _cairo_gl_surface_init (cairo_device_t *device,
206 			cairo_gl_surface_t *surface,
207 			cairo_content_t content,
208 			int width, int height)
209 {
210     _cairo_surface_init (&surface->base,
211 			 &_cairo_gl_surface_backend,
212 			 device,
213 			 content);
214 
215     surface->width = width;
216     surface->height = height;
217 }
218 
219 static cairo_surface_t *
_cairo_gl_surface_create_scratch_for_texture(cairo_gl_context_t * ctx,cairo_content_t content,GLuint tex,int width,int height)220 _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t   *ctx,
221 					      cairo_content_t	    content,
222 					      GLuint		    tex,
223 					      int		    width,
224 					      int		    height)
225 {
226     cairo_gl_surface_t *surface;
227 
228     assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size);
229 
230     surface = calloc (1, sizeof (cairo_gl_surface_t));
231     if (unlikely (surface == NULL))
232 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
233 
234     _cairo_gl_surface_init (&ctx->base, surface, content, width, height);
235     surface->tex = tex;
236 
237     /* Create the texture used to store the surface's data. */
238     _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
239     glBindTexture (ctx->tex_target, surface->tex);
240     glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
241     glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
242 
243     return &surface->base;
244 }
245 
246 static cairo_surface_t *
_cairo_gl_surface_create_scratch(cairo_gl_context_t * ctx,cairo_content_t content,int width,int height)247 _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
248 				  cairo_content_t	content,
249 				  int			width,
250 				  int			height)
251 {
252     cairo_gl_surface_t *surface;
253     GLenum format;
254     GLuint tex;
255 
256     glGenTextures (1, &tex);
257     surface = (cairo_gl_surface_t *)
258 	_cairo_gl_surface_create_scratch_for_texture (ctx, content,
259 						      tex, width, height);
260     if (unlikely (surface->base.status))
261 	return &surface->base;
262 
263     surface->owns_tex = TRUE;
264 
265     /* adjust the texture size after setting our real extents */
266     if (width < 1)
267 	width = 1;
268     if (height < 1)
269 	height = 1;
270 
271     switch (content) {
272     default:
273 	ASSERT_NOT_REACHED;
274     case CAIRO_CONTENT_COLOR_ALPHA:
275 	format = GL_RGBA;
276 	break;
277     case CAIRO_CONTENT_ALPHA:
278 	/* We want to be trying GL_ALPHA framebuffer objects here. */
279 	format = GL_RGBA;
280 	break;
281     case CAIRO_CONTENT_COLOR:
282 	/* GL_RGB is almost what we want here -- sampling 1 alpha when
283 	 * texturing, using 1 as destination alpha factor in blending,
284 	 * etc.  However, when filtering with GL_CLAMP_TO_BORDER, the
285 	 * alpha channel of the border color will also be clamped to
286 	 * 1, when we actually want the border color we explicitly
287 	 * specified.  So, we have to store RGBA, and fill the alpha
288 	 * channel with 1 when blending.
289 	 */
290 	format = GL_RGBA;
291 	break;
292     }
293 
294     glTexImage2D (ctx->tex_target, 0, format, width, height, 0,
295 		  format, GL_UNSIGNED_BYTE, NULL);
296 
297     return &surface->base;
298 }
299 
300 static cairo_status_t
_cairo_gl_surface_clear(cairo_gl_surface_t * surface,const cairo_color_t * color)301 _cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
302                          const cairo_color_t *color)
303 {
304     cairo_gl_context_t *ctx;
305     cairo_status_t status;
306     double r, g, b, a;
307 
308     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
309     if (unlikely (status))
310 	return status;
311 
312     _cairo_gl_context_set_destination (ctx, surface);
313     if (surface->base.content & CAIRO_CONTENT_COLOR) {
314         r = color->red   * color->alpha;
315         g = color->green * color->alpha;
316         b = color->blue  * color->alpha;
317     } else {
318         r = g = b = 0;
319     }
320     if (surface->base.content & CAIRO_CONTENT_ALPHA) {
321         a = color->alpha;
322     } else {
323         a = 1.0;
324     }
325 
326     glDisable (GL_SCISSOR_TEST);
327     glClearColor (r, g, b, a);
328     glClear (GL_COLOR_BUFFER_BIT);
329 
330     return _cairo_gl_context_release (ctx, status);
331 }
332 
333 cairo_surface_t *
cairo_gl_surface_create(cairo_device_t * abstract_device,cairo_content_t content,int width,int height)334 cairo_gl_surface_create (cairo_device_t		*abstract_device,
335 			 cairo_content_t	 content,
336 			 int			 width,
337 			 int			 height)
338 {
339     cairo_gl_context_t *ctx;
340     cairo_gl_surface_t *surface;
341     cairo_status_t status;
342 
343     if (! CAIRO_CONTENT_VALID (content))
344 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
345 
346     if (abstract_device == NULL) {
347 	return cairo_image_surface_create (_cairo_format_from_content (content),
348 					   width, height);
349     }
350 
351     if (abstract_device->status)
352 	return _cairo_surface_create_in_error (abstract_device->status);
353 
354     if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
355 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
356 
357     status = _cairo_gl_context_acquire (abstract_device, &ctx);
358     if (unlikely (status))
359 	return _cairo_surface_create_in_error (status);
360 
361     surface = (cairo_gl_surface_t *)
362 	_cairo_gl_surface_create_scratch (ctx, content, width, height);
363     if (unlikely (surface->base.status)) {
364 	status = _cairo_gl_context_release (ctx, surface->base.status);
365 	cairo_surface_destroy (&surface->base);
366 	return _cairo_surface_create_in_error (status);
367     }
368 
369     /* Cairo surfaces start out initialized to transparent (black) */
370     status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
371 
372     status = _cairo_gl_context_release (ctx, status);
373     if (unlikely (status)) {
374 	cairo_surface_destroy (&surface->base);
375 	return _cairo_surface_create_in_error (status);
376     }
377 
378     return &surface->base;
379 }
380 slim_hidden_def (cairo_gl_surface_create);
381 
382 
383 /**
384  * cairo_gl_surface_create_for_texture:
385  * @content: type of content in the surface
386  * @tex: name of texture to use for storage of surface pixels
387  * @width: width of the surface, in pixels
388  * @height: height of the surface, in pixels
389  *
390  * Creates a GL surface for the specified texture with the specified
391  * content and dimensions.  The texture must be kept around until the
392  * #cairo_surface_t is destroyed or cairo_surface_finish() is called
393  * on the surface.  The initial contents of @tex will be used as the
394  * initial image contents; you must explicitly clear the buffer,
395  * using, for example, cairo_rectangle() and cairo_fill() if you want
396  * it cleared.  The format of @tex should be compatible with @content,
397  * in the sense that it must have the color components required by
398  * @content.
399  *
400  * Return value: a pointer to the newly created surface. The caller
401  * owns the surface and should call cairo_surface_destroy() when done
402  * with it.
403  *
404  * This function always returns a valid pointer, but it will return a
405  * pointer to a "nil" surface if an error such as out of memory
406  * occurs. You can use cairo_surface_status() to check for this.
407  **/
408 cairo_surface_t *
cairo_gl_surface_create_for_texture(cairo_device_t * abstract_device,cairo_content_t content,unsigned int tex,int width,int height)409 cairo_gl_surface_create_for_texture (cairo_device_t	*abstract_device,
410 				     cairo_content_t	 content,
411 				     unsigned int	 tex,
412 				     int		 width,
413 				     int		 height)
414 {
415     cairo_gl_context_t *ctx;
416     cairo_gl_surface_t *surface;
417     cairo_status_t status;
418 
419     if (! CAIRO_CONTENT_VALID (content))
420 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
421 
422     if (abstract_device == NULL)
423 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
424 
425     if (abstract_device->status)
426 	return _cairo_surface_create_in_error (abstract_device->status);
427 
428     if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
429 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
430 
431     status = _cairo_gl_context_acquire (abstract_device, &ctx);
432     if (unlikely (status))
433 	return _cairo_surface_create_in_error (status);
434 
435     surface = (cairo_gl_surface_t *)
436 	_cairo_gl_surface_create_scratch_for_texture (ctx, content,
437 						      tex, width, height);
438     status = _cairo_gl_context_release (ctx, status);
439 
440     return &surface->base;
441 }
442 slim_hidden_def (cairo_gl_surface_create_for_texture);
443 
444 
445 void
cairo_gl_surface_set_size(cairo_surface_t * abstract_surface,int width,int height)446 cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
447 			   int              width,
448 			   int              height)
449 {
450     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
451     cairo_status_t status;
452 
453     if (unlikely (abstract_surface->status))
454 	return;
455     if (unlikely (abstract_surface->finished)) {
456 	status = _cairo_surface_set_error (abstract_surface,
457 		                           _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
458         return;
459     }
460 
461     if (! _cairo_surface_is_gl (abstract_surface) ||
462         ! _cairo_gl_surface_is_texture (surface)) {
463 	status = _cairo_surface_set_error (abstract_surface,
464 		                           _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
465 	return;
466     }
467 
468     surface->width = width;
469     surface->height = height;
470 }
471 
472 int
cairo_gl_surface_get_width(cairo_surface_t * abstract_surface)473 cairo_gl_surface_get_width (cairo_surface_t *abstract_surface)
474 {
475     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
476 
477     if (! _cairo_surface_is_gl (abstract_surface))
478 	return 0;
479 
480     return surface->width;
481 }
482 
483 int
cairo_gl_surface_get_height(cairo_surface_t * abstract_surface)484 cairo_gl_surface_get_height (cairo_surface_t *abstract_surface)
485 {
486     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
487 
488     if (! _cairo_surface_is_gl (abstract_surface))
489 	return 0;
490 
491     return surface->height;
492 }
493 
494 void
cairo_gl_surface_swapbuffers(cairo_surface_t * abstract_surface)495 cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
496 {
497     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
498     cairo_status_t status;
499 
500     if (unlikely (abstract_surface->status))
501 	return;
502     if (unlikely (abstract_surface->finished)) {
503 	status = _cairo_surface_set_error (abstract_surface,
504 		                           _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
505         return;
506     }
507 
508     if (! _cairo_surface_is_gl (abstract_surface)) {
509 	status = _cairo_surface_set_error (abstract_surface,
510 		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
511 	return;
512     }
513 
514     if (! _cairo_gl_surface_is_texture (surface)) {
515 	cairo_gl_context_t *ctx;
516         cairo_status_t status;
517 
518         status = _cairo_gl_context_acquire (surface->base.device, &ctx);
519         if (unlikely (status))
520             return;
521 
522         cairo_surface_flush (abstract_surface);
523 
524 	ctx->swap_buffers (ctx, surface);
525 
526         status = _cairo_gl_context_release (ctx, status);
527         if (status)
528             status = _cairo_surface_set_error (abstract_surface, status);
529     }
530 }
531 
532 static cairo_surface_t *
_cairo_gl_surface_create_similar(void * abstract_surface,cairo_content_t content,int width,int height)533 _cairo_gl_surface_create_similar (void		 *abstract_surface,
534 				  cairo_content_t  content,
535 				  int		  width,
536 				  int		  height)
537 {
538     cairo_surface_t *surface = abstract_surface;
539     cairo_gl_context_t *ctx;
540     cairo_status_t status;
541 
542     if (width < 1 || height < 1)
543         return cairo_image_surface_create (_cairo_format_from_content (content),
544                                            width, height);
545 
546     status = _cairo_gl_context_acquire (surface->device, &ctx);
547     if (unlikely (status))
548 	return _cairo_surface_create_in_error (status);
549 
550     if (width > ctx->max_framebuffer_size ||
551 	height > ctx->max_framebuffer_size)
552     {
553 	surface = NULL;
554         goto RELEASE;
555     }
556 
557     surface = _cairo_gl_surface_create_scratch (ctx, content, width, height);
558 
559 RELEASE:
560     status = _cairo_gl_context_release (ctx, status);
561     if (unlikely (status)) {
562         cairo_surface_destroy (surface);
563         return _cairo_surface_create_in_error (status);
564     }
565 
566     return surface;
567 }
568 
569 cairo_status_t
_cairo_gl_surface_draw_image(cairo_gl_surface_t * dst,cairo_image_surface_t * src,int src_x,int src_y,int width,int height,int dst_x,int dst_y)570 _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
571 			      cairo_image_surface_t *src,
572 			      int src_x, int src_y,
573 			      int width, int height,
574 			      int dst_x, int dst_y)
575 {
576     GLenum internal_format, format, type;
577     cairo_bool_t has_alpha;
578     cairo_image_surface_t *clone = NULL;
579     cairo_gl_context_t *ctx;
580     int cpp;
581     cairo_status_t status = CAIRO_STATUS_SUCCESS;
582 
583     if (! _cairo_gl_get_image_format_and_type (src->pixman_format,
584 					       &internal_format,
585 					       &format,
586 					       &type,
587 					       &has_alpha))
588     {
589 	cairo_bool_t is_supported;
590 
591 	clone = _cairo_image_surface_coerce (src);
592 	if (unlikely (clone->base.status))
593 	    return clone->base.status;
594 
595 	is_supported =
596 	    _cairo_gl_get_image_format_and_type (clone->pixman_format,
597 		                                 &internal_format,
598 						 &format,
599 						 &type,
600 						 &has_alpha);
601 	assert (is_supported);
602 	src = clone;
603     }
604 
605     cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
606 
607     status = _cairo_gl_context_acquire (dst->base.device, &ctx);
608     if (unlikely (status))
609 	return status;
610 
611     status = _cairo_gl_surface_flush (&dst->base);
612     if (unlikely (status))
613 	goto FAIL;
614 
615     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
616     glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
617     if (_cairo_gl_surface_is_texture (dst)) {
618         _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
619 	glBindTexture (ctx->tex_target, dst->tex);
620 	glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
621 	glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
622 	glTexSubImage2D (ctx->tex_target, 0,
623 			 dst_x, dst_y, width, height,
624 			 format, type,
625 			 src->data + src_y * src->stride + src_x * cpp);
626 
627 	/* If we just treated some rgb-only data as rgba, then we have to
628 	 * go back and fix up the alpha channel where we filled in this
629 	 * texture data.
630 	 */
631 	if (!has_alpha) {
632 	    cairo_rectangle_int_t rect;
633 
634 	    rect.x = dst_x;
635 	    rect.y = dst_y;
636 	    rect.width = width;
637 	    rect.height = height;
638 
639             _cairo_gl_composite_flush (ctx);
640 	    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
641 	    _cairo_gl_surface_fill_rectangles (dst,
642 					       CAIRO_OPERATOR_SOURCE,
643 					       CAIRO_COLOR_BLACK,
644 					       &rect, 1);
645             _cairo_gl_composite_flush (ctx);
646 	    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
647 	}
648     } else {
649         cairo_surface_t *tmp;
650 
651         tmp = _cairo_gl_surface_create_scratch (ctx,
652                                                 dst->base.content,
653                                                 width, height);
654         if (unlikely (tmp->status)) {
655             cairo_surface_destroy (tmp);
656             goto FAIL;
657         }
658         status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *) tmp,
659                                                src,
660                                                src_x, src_y,
661                                                width, height,
662                                                0, 0);
663         if (status == CAIRO_STATUS_SUCCESS) {
664             cairo_surface_pattern_t tmp_pattern;
665 
666             _cairo_pattern_init_for_surface (&tmp_pattern, tmp);
667             _cairo_gl_surface_composite (CAIRO_OPERATOR_SOURCE,
668                                          &tmp_pattern.base,
669                                          NULL,
670                                          dst,
671                                          0, 0,
672                                          0, 0,
673                                          dst_x, dst_y,
674                                          width, height,
675                                          NULL);
676             _cairo_pattern_fini (&tmp_pattern.base);
677         }
678 
679         cairo_surface_destroy (tmp);
680     }
681 
682 FAIL:
683     glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
684 
685     status = _cairo_gl_context_release (ctx, status);
686 
687     if (clone)
688         cairo_surface_destroy (&clone->base);
689 
690     return status;
691 }
692 
693 static cairo_status_t
_cairo_gl_surface_get_image(cairo_gl_surface_t * surface,cairo_rectangle_int_t * interest,cairo_image_surface_t ** image_out,cairo_rectangle_int_t * rect_out)694 _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
695 			     cairo_rectangle_int_t   *interest,
696 			     cairo_image_surface_t  **image_out,
697 			     cairo_rectangle_int_t   *rect_out)
698 {
699     cairo_image_surface_t *image;
700     cairo_gl_context_t *ctx;
701     GLenum format, type;
702     cairo_format_t cairo_format;
703     unsigned int cpp;
704     cairo_status_t status;
705 
706     /* Want to use a switch statement here but the compiler gets whiny. */
707     if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
708 	format = GL_BGRA;
709 	cairo_format = CAIRO_FORMAT_ARGB32;
710 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
711 	cpp = 4;
712     } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
713 	format = GL_BGRA;
714 	cairo_format = CAIRO_FORMAT_RGB24;
715 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
716 	cpp = 4;
717     } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
718 	format = GL_ALPHA;
719 	cairo_format = CAIRO_FORMAT_A8;
720 	type = GL_UNSIGNED_BYTE;
721 	cpp = 1;
722     } else {
723 	ASSERT_NOT_REACHED;
724 	return CAIRO_INT_STATUS_UNSUPPORTED;
725     }
726 
727     image = (cairo_image_surface_t*)
728 	cairo_image_surface_create (cairo_format,
729 				    interest->width, interest->height);
730     if (unlikely (image->base.status))
731 	return image->base.status;
732 
733     /* This is inefficient, as we'd rather just read the thing without making
734      * it the destination.  But then, this is the fallback path, so let's not
735      * fall back instead.
736      */
737     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
738     if (unlikely (status))
739         return status;
740 
741     _cairo_gl_composite_flush (ctx);
742     _cairo_gl_context_set_destination (ctx, surface);
743 
744     glPixelStorei (GL_PACK_ALIGNMENT, 1);
745     glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
746     if (! _cairo_gl_surface_is_texture (surface) && GLEW_MESA_pack_invert)
747 	glPixelStorei (GL_PACK_INVERT_MESA, 1);
748     glReadPixels (interest->x, interest->y,
749 		  interest->width, interest->height,
750 		  format, type, image->data);
751     if (! _cairo_gl_surface_is_texture (surface) && GLEW_MESA_pack_invert)
752 	glPixelStorei (GL_PACK_INVERT_MESA, 0);
753 
754     status = _cairo_gl_context_release (ctx, status);
755     if (unlikely (status)) {
756 	cairo_surface_destroy (&image->base);
757 	return status;
758     }
759 
760     *image_out = image;
761     if (rect_out != NULL)
762 	*rect_out = *interest;
763 
764     return CAIRO_STATUS_SUCCESS;
765 }
766 
767 static cairo_status_t
_cairo_gl_surface_finish(void * abstract_surface)768 _cairo_gl_surface_finish (void *abstract_surface)
769 {
770     cairo_gl_surface_t *surface = abstract_surface;
771     cairo_status_t status;
772     cairo_gl_context_t *ctx;
773 
774     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
775     if (unlikely (status))
776         return status;
777 
778     if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
779         ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
780         _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
781     if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
782         ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
783         _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
784     if (ctx->current_target == surface)
785 	ctx->current_target = NULL;
786 
787     if (surface->depth)
788         glDeleteFramebuffersEXT (1, &surface->depth);
789     if (surface->fb)
790         glDeleteFramebuffersEXT (1, &surface->fb);
791     if (surface->owns_tex)
792 	glDeleteTextures (1, &surface->tex);
793 
794     return _cairo_gl_context_release (ctx, status);
795 }
796 
797 static cairo_status_t
_cairo_gl_surface_acquire_source_image(void * abstract_surface,cairo_image_surface_t ** image_out,void ** image_extra)798 _cairo_gl_surface_acquire_source_image (void		       *abstract_surface,
799 					cairo_image_surface_t **image_out,
800 					void		      **image_extra)
801 {
802     cairo_gl_surface_t *surface = abstract_surface;
803     cairo_rectangle_int_t extents;
804 
805     *image_extra = NULL;
806 
807     extents.x = extents.y = 0;
808     extents.width = surface->width;
809     extents.height = surface->height;
810     return _cairo_gl_surface_get_image (surface, &extents, image_out, NULL);
811 }
812 
813 static void
_cairo_gl_surface_release_source_image(void * abstract_surface,cairo_image_surface_t * image,void * image_extra)814 _cairo_gl_surface_release_source_image (void		      *abstract_surface,
815 					cairo_image_surface_t *image,
816 					void		      *image_extra)
817 {
818     cairo_surface_destroy (&image->base);
819 }
820 
821 static cairo_status_t
_cairo_gl_surface_acquire_dest_image(void * abstract_surface,cairo_rectangle_int_t * interest_rect,cairo_image_surface_t ** image_out,cairo_rectangle_int_t * image_rect_out,void ** image_extra)822 _cairo_gl_surface_acquire_dest_image (void		      *abstract_surface,
823 				      cairo_rectangle_int_t   *interest_rect,
824 				      cairo_image_surface_t  **image_out,
825 				      cairo_rectangle_int_t   *image_rect_out,
826 				      void		     **image_extra)
827 {
828     cairo_gl_surface_t *surface = abstract_surface;
829 
830     *image_extra = NULL;
831     return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
832 					image_rect_out);
833 }
834 
835 static void
_cairo_gl_surface_release_dest_image(void * abstract_surface,cairo_rectangle_int_t * interest_rect,cairo_image_surface_t * image,cairo_rectangle_int_t * image_rect,void * image_extra)836 _cairo_gl_surface_release_dest_image (void		      *abstract_surface,
837 				      cairo_rectangle_int_t   *interest_rect,
838 				      cairo_image_surface_t   *image,
839 				      cairo_rectangle_int_t   *image_rect,
840 				      void		      *image_extra)
841 {
842     cairo_status_t status;
843 
844     status = _cairo_gl_surface_draw_image (abstract_surface, image,
845 					   0, 0,
846 					   image->width, image->height,
847 					   image_rect->x, image_rect->y);
848     /* as we created the image, its format should be directly applicable */
849     assert (status == CAIRO_STATUS_SUCCESS);
850 
851     cairo_surface_destroy (&image->base);
852 }
853 
854 static cairo_status_t
_cairo_gl_surface_clone_similar(void * abstract_surface,cairo_surface_t * src,int src_x,int src_y,int width,int height,int * clone_offset_x,int * clone_offset_y,cairo_surface_t ** clone_out)855 _cairo_gl_surface_clone_similar (void		     *abstract_surface,
856 				 cairo_surface_t     *src,
857 				 int                  src_x,
858 				 int                  src_y,
859 				 int                  width,
860 				 int                  height,
861 				 int                 *clone_offset_x,
862 				 int                 *clone_offset_y,
863 				 cairo_surface_t    **clone_out)
864 {
865     cairo_gl_surface_t *surface = abstract_surface;
866 
867     /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */
868     if (src->device == surface->base.device &&
869         _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) {
870 	*clone_offset_x = 0;
871 	*clone_offset_y = 0;
872 	*clone_out = cairo_surface_reference (src);
873 
874 	return CAIRO_STATUS_SUCCESS;
875     } else if (_cairo_surface_is_image (src)) {
876 	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
877 	cairo_gl_surface_t *clone;
878 	cairo_status_t status;
879 
880 	clone = (cairo_gl_surface_t *)
881 	    _cairo_gl_surface_create_similar (&surface->base,
882 		                              src->content,
883 					      width, height);
884 	if (clone == NULL)
885 	    return UNSUPPORTED ("create_similar failed");
886 	if (clone->base.status)
887 	    return clone->base.status;
888 
889 	status = _cairo_gl_surface_draw_image (clone, image_src,
890 					       src_x, src_y,
891 					       width, height,
892 					       0, 0);
893 	if (status) {
894 	    cairo_surface_destroy (&clone->base);
895 	    return status;
896 	}
897 
898 	*clone_out = &clone->base;
899 	*clone_offset_x = src_x;
900 	*clone_offset_y = src_y;
901 
902 	return CAIRO_STATUS_SUCCESS;
903     }
904 
905     return UNSUPPORTED ("unknown src surface type in clone_similar");
906 }
907 
908 /** Creates a cairo-gl pattern surface for the given trapezoids */
909 static cairo_status_t
_cairo_gl_get_traps_pattern(cairo_gl_surface_t * dst,int dst_x,int dst_y,int width,int height,cairo_trapezoid_t * traps,int num_traps,cairo_antialias_t antialias,cairo_surface_pattern_t * pattern)910 _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
911 			     int dst_x, int dst_y,
912 			     int width, int height,
913 			     cairo_trapezoid_t *traps,
914 			     int num_traps,
915 			     cairo_antialias_t antialias,
916 			     cairo_surface_pattern_t *pattern)
917 {
918     pixman_format_code_t pixman_format;
919     pixman_image_t *image;
920     cairo_surface_t *surface;
921     int i;
922 
923     pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
924     image = pixman_image_create_bits (pixman_format, width, height, NULL, 0);
925     if (unlikely (image == NULL))
926 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
927 
928     for (i = 0; i < num_traps; i++) {
929 	pixman_trapezoid_t trap;
930 
931 	trap.top = _cairo_fixed_to_16_16 (traps[i].top);
932 	trap.bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
933 
934 	trap.left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
935 	trap.left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
936 	trap.left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
937 	trap.left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
938 
939 	trap.right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
940 	trap.right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
941 	trap.right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
942 	trap.right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
943 
944 	pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
945     }
946 
947     surface = _cairo_image_surface_create_for_pixman_image (image,
948 							    pixman_format);
949     if (unlikely (surface->status)) {
950 	pixman_image_unref (image);
951 	return surface->status;
952     }
953 
954     _cairo_pattern_init_for_surface (pattern, surface);
955     cairo_surface_destroy (surface);
956 
957     return CAIRO_STATUS_SUCCESS;
958 }
959 
960 static cairo_int_status_t
_cairo_gl_surface_composite(cairo_operator_t op,const cairo_pattern_t * src,const cairo_pattern_t * mask,void * abstract_dst,int src_x,int src_y,int mask_x,int mask_y,int dst_x,int dst_y,unsigned int width,unsigned int height,cairo_region_t * clip_region)961 _cairo_gl_surface_composite (cairo_operator_t		  op,
962 			     const cairo_pattern_t	 *src,
963 			     const cairo_pattern_t	 *mask,
964 			     void			 *abstract_dst,
965 			     int			  src_x,
966 			     int			  src_y,
967 			     int			  mask_x,
968 			     int			  mask_y,
969 			     int			  dst_x,
970 			     int			  dst_y,
971 			     unsigned int		  width,
972 			     unsigned int		  height,
973 			     cairo_region_t		 *clip_region)
974 {
975     cairo_gl_surface_t *dst = abstract_dst;
976     cairo_gl_context_t *ctx;
977     cairo_status_t status;
978     cairo_gl_composite_t setup;
979     cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
980     int dx, dy;
981 
982     if (op == CAIRO_OPERATOR_SOURCE &&
983         mask == NULL &&
984         src->type == CAIRO_PATTERN_TYPE_SURFACE &&
985         _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) &&
986         _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) {
987         cairo_image_surface_t *image = (cairo_image_surface_t *)
988             ((cairo_surface_pattern_t *) src)->surface;
989         dx += src_x;
990         dy += src_y;
991         if (dx >= 0 &&
992             dy >= 0 &&
993             dx + width <= (unsigned int) image->width &&
994             dy + height <= (unsigned int) image->height) {
995             status = _cairo_gl_surface_draw_image (dst, image,
996                                                    dx, dy,
997                                                    width, height,
998                                                    dst_x, dst_y);
999             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1000                 return status;
1001         }
1002     }
1003 
1004     status = _cairo_gl_composite_init (&setup, op, dst,
1005                                        mask && mask->has_component_alpha,
1006                                        &rect);
1007     if (unlikely (status))
1008         goto CLEANUP;
1009 
1010     status = _cairo_gl_composite_set_source (&setup, src,
1011                                              src_x, src_y,
1012                                              dst_x, dst_y,
1013                                              width, height);
1014     if (unlikely (status))
1015         goto CLEANUP;
1016 
1017     status = _cairo_gl_composite_set_mask (&setup, mask,
1018                                            mask_x, mask_y,
1019                                            dst_x, dst_y,
1020                                            width, height);
1021     if (unlikely (status))
1022         goto CLEANUP;
1023 
1024     status = _cairo_gl_composite_begin (&setup, &ctx);
1025     if (unlikely (status))
1026 	goto CLEANUP;
1027 
1028     if (clip_region != NULL) {
1029         int i, num_rectangles;
1030 
1031         num_rectangles = cairo_region_num_rectangles (clip_region);
1032 
1033 	for (i = 0; i < num_rectangles; i++) {
1034 	    cairo_rectangle_int_t rect;
1035 
1036 	    cairo_region_get_rectangle (clip_region, i, &rect);
1037             _cairo_gl_composite_emit_rect (ctx,
1038                                            rect.x,              rect.y,
1039                                            rect.x + rect.width, rect.y + rect.height,
1040                                            0);
1041 	}
1042     } else {
1043         _cairo_gl_composite_emit_rect (ctx,
1044                                        dst_x,         dst_y,
1045                                        dst_x + width, dst_y + height,
1046                                        0);
1047     }
1048 
1049     status = _cairo_gl_context_release (ctx, status);
1050 
1051   CLEANUP:
1052     _cairo_gl_composite_fini (&setup);
1053 
1054     return status;
1055 }
1056 
1057 static cairo_int_status_t
_cairo_gl_surface_composite_trapezoids(cairo_operator_t op,const cairo_pattern_t * pattern,void * abstract_dst,cairo_antialias_t antialias,int src_x,int src_y,int dst_x,int dst_y,unsigned int width,unsigned int height,cairo_trapezoid_t * traps,int num_traps,cairo_region_t * clip_region)1058 _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
1059 					const cairo_pattern_t *pattern,
1060 					void *abstract_dst,
1061 					cairo_antialias_t antialias,
1062 					int src_x, int src_y,
1063 					int dst_x, int dst_y,
1064 					unsigned int width,
1065 					unsigned int height,
1066 					cairo_trapezoid_t *traps,
1067 					int num_traps,
1068 					cairo_region_t *clip_region)
1069 {
1070     cairo_gl_surface_t *dst = abstract_dst;
1071     cairo_surface_pattern_t traps_pattern;
1072     cairo_int_status_t status;
1073 
1074     if (! _cairo_gl_operator_is_supported (op))
1075 	return UNSUPPORTED ("unsupported operator");
1076 
1077     status = _cairo_gl_get_traps_pattern (dst,
1078 					  dst_x, dst_y, width, height,
1079 					  traps, num_traps, antialias,
1080 					  &traps_pattern);
1081     if (unlikely (status))
1082 	return status;
1083 
1084     status = _cairo_gl_surface_composite (op,
1085 					  pattern, &traps_pattern.base, dst,
1086 					  src_x, src_y,
1087 					  0, 0,
1088 					  dst_x, dst_y,
1089 					  width, height,
1090 					  clip_region);
1091 
1092     _cairo_pattern_fini (&traps_pattern.base);
1093 
1094     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
1095     return status;
1096 }
1097 
1098 static cairo_int_status_t
_cairo_gl_surface_fill_rectangles(void * abstract_dst,cairo_operator_t op,const cairo_color_t * color,cairo_rectangle_int_t * rects,int num_rects)1099 _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
1100 				   cairo_operator_t	    op,
1101 				   const cairo_color_t     *color,
1102 				   cairo_rectangle_int_t   *rects,
1103 				   int			    num_rects)
1104 {
1105     cairo_gl_surface_t *dst = abstract_dst;
1106     cairo_solid_pattern_t solid;
1107     cairo_gl_context_t *ctx;
1108     cairo_status_t status;
1109     cairo_gl_composite_t setup;
1110     int i;
1111 
1112     status = _cairo_gl_composite_init (&setup, op, dst,
1113                                        FALSE,
1114                                        /* XXX */ NULL);
1115     if (unlikely (status))
1116         goto CLEANUP;
1117 
1118     _cairo_pattern_init_solid (&solid, color);
1119     status = _cairo_gl_composite_set_source (&setup, &solid.base,
1120                                              0, 0,
1121                                              0, 0,
1122                                              0, 0);
1123     if (unlikely (status))
1124         goto CLEANUP;
1125 
1126     status = _cairo_gl_composite_set_mask (&setup, NULL,
1127                                            0, 0,
1128                                            0, 0,
1129                                            0, 0);
1130     if (unlikely (status))
1131         goto CLEANUP;
1132 
1133     status = _cairo_gl_composite_begin (&setup, &ctx);
1134     if (unlikely (status))
1135         goto CLEANUP;
1136 
1137     for (i = 0; i < num_rects; i++) {
1138         _cairo_gl_composite_emit_rect (ctx,
1139                                        rects[i].x,
1140                                        rects[i].y,
1141                                        rects[i].x + rects[i].width,
1142                                        rects[i].y + rects[i].height,
1143                                        0);
1144     }
1145 
1146     status = _cairo_gl_context_release (ctx, status);
1147 
1148   CLEANUP:
1149     _cairo_gl_composite_fini (&setup);
1150 
1151     return status;
1152 }
1153 
1154 typedef struct _cairo_gl_surface_span_renderer {
1155     cairo_span_renderer_t base;
1156 
1157     cairo_gl_composite_t setup;
1158 
1159     int xmin, xmax;
1160     int ymin, ymax;
1161 
1162     cairo_gl_context_t *ctx;
1163 } cairo_gl_surface_span_renderer_t;
1164 
1165 static cairo_status_t
_cairo_gl_render_bounded_spans(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * spans,unsigned num_spans)1166 _cairo_gl_render_bounded_spans (void *abstract_renderer,
1167 				int y, int height,
1168 				const cairo_half_open_span_t *spans,
1169 				unsigned num_spans)
1170 {
1171     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1172 
1173     if (num_spans == 0)
1174 	return CAIRO_STATUS_SUCCESS;
1175 
1176     do {
1177 	if (spans[0].coverage) {
1178             _cairo_gl_composite_emit_rect (renderer->ctx,
1179                                            spans[0].x, y,
1180                                            spans[1].x, y + height,
1181                                            spans[0].coverage);
1182 	}
1183 
1184 	spans++;
1185     } while (--num_spans > 1);
1186 
1187     return CAIRO_STATUS_SUCCESS;
1188 }
1189 
1190 static cairo_status_t
_cairo_gl_render_unbounded_spans(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * spans,unsigned num_spans)1191 _cairo_gl_render_unbounded_spans (void *abstract_renderer,
1192 				  int y, int height,
1193 				  const cairo_half_open_span_t *spans,
1194 				  unsigned num_spans)
1195 {
1196     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1197 
1198     if (y > renderer->ymin) {
1199         _cairo_gl_composite_emit_rect (renderer->ctx,
1200                                        renderer->xmin, renderer->ymin,
1201                                        renderer->xmax, y,
1202                                        0);
1203     }
1204 
1205     if (num_spans == 0) {
1206         _cairo_gl_composite_emit_rect (renderer->ctx,
1207                                        renderer->xmin, y,
1208                                        renderer->xmax, y + height,
1209                                        0);
1210     } else {
1211         if (spans[0].x != renderer->xmin) {
1212             _cairo_gl_composite_emit_rect (renderer->ctx,
1213                                            renderer->xmin, y,
1214                                            spans[0].x,     y + height,
1215                                            0);
1216         }
1217 
1218         do {
1219             _cairo_gl_composite_emit_rect (renderer->ctx,
1220                                            spans[0].x, y,
1221                                            spans[1].x, y + height,
1222                                            spans[0].coverage);
1223             spans++;
1224         } while (--num_spans > 1);
1225 
1226         if (spans[0].x != renderer->xmax) {
1227             _cairo_gl_composite_emit_rect (renderer->ctx,
1228                                            spans[0].x,     y,
1229                                            renderer->xmax, y + height,
1230                                            0);
1231         }
1232     }
1233 
1234     renderer->ymin = y + height;
1235     return CAIRO_STATUS_SUCCESS;
1236 }
1237 
1238 static cairo_status_t
_cairo_gl_finish_unbounded_spans(void * abstract_renderer)1239 _cairo_gl_finish_unbounded_spans (void *abstract_renderer)
1240 {
1241     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1242 
1243     if (renderer->ymax > renderer->ymin) {
1244         _cairo_gl_composite_emit_rect (renderer->ctx,
1245                                        renderer->xmin, renderer->ymin,
1246                                        renderer->xmax, renderer->ymax,
1247                                        0);
1248     }
1249 
1250     return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
1251 }
1252 
1253 static cairo_status_t
_cairo_gl_finish_bounded_spans(void * abstract_renderer)1254 _cairo_gl_finish_bounded_spans (void *abstract_renderer)
1255 {
1256     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1257 
1258     return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
1259 }
1260 
1261 static void
_cairo_gl_surface_span_renderer_destroy(void * abstract_renderer)1262 _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
1263 {
1264     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1265 
1266     if (!renderer)
1267 	return;
1268 
1269     _cairo_gl_composite_fini (&renderer->setup);
1270 
1271     free (renderer);
1272 }
1273 
1274 static cairo_bool_t
_cairo_gl_surface_check_span_renderer(cairo_operator_t op,const cairo_pattern_t * pattern,void * abstract_dst,cairo_antialias_t antialias)1275 _cairo_gl_surface_check_span_renderer (cairo_operator_t	       op,
1276 				       const cairo_pattern_t  *pattern,
1277 				       void		      *abstract_dst,
1278 				       cairo_antialias_t       antialias)
1279 {
1280     if (! _cairo_gl_operator_is_supported (op))
1281 	return FALSE;
1282 
1283     return TRUE;
1284 
1285     (void) pattern;
1286     (void) abstract_dst;
1287     (void) antialias;
1288 }
1289 
1290 static cairo_span_renderer_t *
_cairo_gl_surface_create_span_renderer(cairo_operator_t op,const cairo_pattern_t * src,void * abstract_dst,cairo_antialias_t antialias,const cairo_composite_rectangles_t * rects,cairo_region_t * clip_region)1291 _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
1292 					const cairo_pattern_t	*src,
1293 					void			*abstract_dst,
1294 					cairo_antialias_t	 antialias,
1295 					const cairo_composite_rectangles_t *rects,
1296 					cairo_region_t		*clip_region)
1297 {
1298     cairo_gl_surface_t *dst = abstract_dst;
1299     cairo_gl_surface_span_renderer_t *renderer;
1300     cairo_status_t status;
1301     const cairo_rectangle_int_t *extents;
1302 
1303     renderer = calloc (1, sizeof (*renderer));
1304     if (unlikely (renderer == NULL))
1305 	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
1306 
1307     renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
1308     if (rects->is_bounded) {
1309 	renderer->base.render_rows = _cairo_gl_render_bounded_spans;
1310         renderer->base.finish =      _cairo_gl_finish_bounded_spans;
1311 	extents = &rects->bounded;
1312     } else {
1313 	renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
1314         renderer->base.finish =      _cairo_gl_finish_unbounded_spans;
1315 	extents = &rects->unbounded;
1316     }
1317     renderer->xmin = extents->x;
1318     renderer->xmax = extents->x + extents->width;
1319     renderer->ymin = extents->y;
1320     renderer->ymax = extents->y + extents->height;
1321 
1322     status = _cairo_gl_composite_init (&renderer->setup,
1323                                        op, dst,
1324                                        FALSE, extents);
1325     if (unlikely (status))
1326         goto FAIL;
1327 
1328     status = _cairo_gl_composite_set_source (&renderer->setup, src,
1329                                              extents->x, extents->y,
1330                                              extents->x, extents->y,
1331                                              extents->width, extents->height);
1332     if (unlikely (status))
1333         goto FAIL;
1334 
1335     _cairo_gl_composite_set_mask_spans (&renderer->setup);
1336     _cairo_gl_composite_set_clip_region (&renderer->setup, clip_region);
1337 
1338     status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx);
1339     if (unlikely (status))
1340         goto FAIL;
1341 
1342     return &renderer->base;
1343 
1344 FAIL:
1345     _cairo_gl_composite_fini (&renderer->setup);
1346     free (renderer);
1347     return _cairo_span_renderer_create_in_error (status);
1348 }
1349 
1350 static cairo_bool_t
_cairo_gl_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * rectangle)1351 _cairo_gl_surface_get_extents (void		     *abstract_surface,
1352 			       cairo_rectangle_int_t *rectangle)
1353 {
1354     cairo_gl_surface_t *surface = abstract_surface;
1355 
1356     rectangle->x = 0;
1357     rectangle->y = 0;
1358     rectangle->width  = surface->width;
1359     rectangle->height = surface->height;
1360 
1361     return TRUE;
1362 }
1363 
1364 static void
_cairo_gl_surface_get_font_options(void * abstract_surface,cairo_font_options_t * options)1365 _cairo_gl_surface_get_font_options (void                  *abstract_surface,
1366 				    cairo_font_options_t  *options)
1367 {
1368     _cairo_font_options_init_default (options);
1369 
1370     cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
1371     _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
1372 }
1373 
1374 static cairo_status_t
_cairo_gl_surface_flush(void * abstract_surface)1375 _cairo_gl_surface_flush (void *abstract_surface)
1376 {
1377     cairo_gl_surface_t *surface = abstract_surface;
1378     cairo_status_t status;
1379     cairo_gl_context_t *ctx;
1380 
1381     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
1382     if (unlikely (status))
1383         return status;
1384 
1385     if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
1386          ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) ||
1387         (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
1388          ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) ||
1389         (ctx->current_target == surface))
1390       _cairo_gl_composite_flush (ctx);
1391 
1392     return _cairo_gl_context_release (ctx, status);
1393 }
1394 
1395 static cairo_int_status_t
_cairo_gl_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_clip_t * clip)1396 _cairo_gl_surface_paint (void *abstract_surface,
1397 			 cairo_operator_t	 op,
1398 			 const cairo_pattern_t *source,
1399 			 cairo_clip_t	    *clip)
1400 {
1401     /* simplify the common case of clearing the surface */
1402     if (clip == NULL) {
1403         if (op == CAIRO_OPERATOR_CLEAR)
1404             return _cairo_gl_surface_clear (abstract_surface, CAIRO_COLOR_TRANSPARENT);
1405        else if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
1406                 (op == CAIRO_OPERATOR_SOURCE ||
1407                  (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque_solid (source)))) {
1408             return _cairo_gl_surface_clear (abstract_surface,
1409                                             &((cairo_solid_pattern_t *) source)->color);
1410         }
1411     }
1412 
1413     return CAIRO_INT_STATUS_UNSUPPORTED;
1414 }
1415 
1416 static cairo_int_status_t
_cairo_gl_surface_polygon(cairo_gl_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * src,cairo_polygon_t * polygon,cairo_fill_rule_t fill_rule,cairo_antialias_t antialias,const cairo_composite_rectangles_t * extents,cairo_clip_t * clip)1417 _cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
1418                            cairo_operator_t op,
1419                            const cairo_pattern_t *src,
1420                            cairo_polygon_t *polygon,
1421                            cairo_fill_rule_t fill_rule,
1422                            cairo_antialias_t antialias,
1423                            const cairo_composite_rectangles_t *extents,
1424                            cairo_clip_t *clip)
1425 {
1426     cairo_status_t status;
1427     cairo_region_t *clip_region = NULL;
1428 
1429     if (clip != NULL) {
1430 	status = _cairo_clip_get_region (clip, &clip_region);
1431 	if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
1432 	    return CAIRO_STATUS_SUCCESS;
1433 	if (unlikely (_cairo_status_is_error (status)))
1434 	    return status;
1435 
1436 	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
1437             return UNSUPPORTED ("a clip surface would be required");
1438     }
1439 
1440     if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias))
1441         return UNSUPPORTED ("no span renderer");
1442 
1443     if (op == CAIRO_OPERATOR_SOURCE)
1444         return UNSUPPORTED ("SOURCE compositing doesn't work in GL");
1445     if (op == CAIRO_OPERATOR_CLEAR) {
1446         op = CAIRO_OPERATOR_DEST_OUT;
1447         src = &_cairo_pattern_white.base;
1448     }
1449 
1450     status = _cairo_surface_composite_polygon (&dst->base,
1451                                                op,
1452                                                src,
1453                                                fill_rule,
1454                                                antialias,
1455                                                extents,
1456                                                polygon,
1457                                                clip_region);
1458     return status;
1459 }
1460 
1461 static cairo_int_status_t
_cairo_gl_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,const cairo_stroke_style_t * style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)1462 _cairo_gl_surface_stroke (void			        *abstract_surface,
1463                           cairo_operator_t		 op,
1464                           const cairo_pattern_t	        *source,
1465                           cairo_path_fixed_t		*path,
1466                           const cairo_stroke_style_t	*style,
1467                           const cairo_matrix_t	        *ctm,
1468                           const cairo_matrix_t	        *ctm_inverse,
1469                           double			 tolerance,
1470                           cairo_antialias_t		 antialias,
1471                           cairo_clip_t		        *clip)
1472 {
1473     cairo_gl_surface_t *surface = abstract_surface;
1474     cairo_composite_rectangles_t extents;
1475     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1476     int num_boxes = ARRAY_LENGTH (boxes_stack);
1477     cairo_clip_t local_clip;
1478     cairo_bool_t have_clip = FALSE;
1479     cairo_polygon_t polygon;
1480     cairo_status_t status;
1481 
1482     status = _cairo_composite_rectangles_init_for_stroke (&extents,
1483 							  surface->width,
1484 							  surface->height,
1485 							  op, source,
1486 							  path, style, ctm,
1487 							  clip);
1488     if (unlikely (status))
1489 	return status;
1490 
1491     if (_cairo_clip_contains_extents (clip, &extents))
1492 	clip = NULL;
1493 
1494     if (clip != NULL) {
1495 	clip = _cairo_clip_init_copy (&local_clip, clip);
1496 	have_clip = TRUE;
1497     }
1498 
1499     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1500     if (unlikely (status)) {
1501 	if (have_clip)
1502 	    _cairo_clip_fini (&local_clip);
1503 
1504 	return status;
1505     }
1506 
1507     _cairo_polygon_init (&polygon);
1508     _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1509 
1510     status = _cairo_path_fixed_stroke_to_polygon (path,
1511                                                   style,
1512                                                   ctm, ctm_inverse,
1513                                                   tolerance,
1514                                                   &polygon);
1515     if (likely (status == CAIRO_STATUS_SUCCESS)) {
1516         status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
1517                                             CAIRO_FILL_RULE_WINDING, antialias,
1518                                             &extents, clip);
1519     }
1520 
1521     _cairo_polygon_fini (&polygon);
1522 
1523     if (have_clip)
1524 	_cairo_clip_fini (&local_clip);
1525 
1526     return status;
1527 }
1528 
1529 static cairo_int_status_t
_cairo_gl_surface_fill(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)1530 _cairo_gl_surface_fill (void			*abstract_surface,
1531                         cairo_operator_t	 op,
1532                         const cairo_pattern_t	*source,
1533                         cairo_path_fixed_t	*path,
1534                         cairo_fill_rule_t	 fill_rule,
1535                         double			 tolerance,
1536                         cairo_antialias_t	 antialias,
1537                         cairo_clip_t		*clip)
1538 {
1539     cairo_gl_surface_t *surface = abstract_surface;
1540     cairo_composite_rectangles_t extents;
1541     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1542     cairo_clip_t local_clip;
1543     cairo_bool_t have_clip = FALSE;
1544     int num_boxes = ARRAY_LENGTH (boxes_stack);
1545     cairo_polygon_t polygon;
1546     cairo_status_t status;
1547 
1548     status = _cairo_composite_rectangles_init_for_fill (&extents,
1549 							surface->width,
1550 							surface->height,
1551 							op, source, path,
1552 							clip);
1553     if (unlikely (status))
1554 	return status;
1555 
1556     if (_cairo_clip_contains_extents (clip, &extents))
1557 	clip = NULL;
1558 
1559 #if 0
1560     if (extents.is_bounded && clip != NULL) {
1561 	cairo_clip_path_t *clip_path;
1562 
1563 	if (((clip_path = _clip_get_single_path (clip)) != NULL) &&
1564 	    _cairo_path_fixed_equal (&clip_path->path, path))
1565 	{
1566 	    clip = NULL;
1567 	}
1568     }
1569 #endif
1570 
1571     if (clip != NULL) {
1572 	clip = _cairo_clip_init_copy (&local_clip, clip);
1573 	have_clip = TRUE;
1574     }
1575 
1576     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1577     if (unlikely (status)) {
1578 	if (have_clip)
1579 	    _cairo_clip_fini (&local_clip);
1580 
1581 	return status;
1582     }
1583 
1584     _cairo_polygon_init (&polygon);
1585     _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1586 
1587     status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1588     if (likely (status == CAIRO_STATUS_SUCCESS)) {
1589         status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
1590                                             fill_rule, antialias,
1591                                             &extents, clip);
1592     }
1593 
1594     _cairo_polygon_fini (&polygon);
1595 
1596     if (clip_boxes != boxes_stack)
1597 	free (clip_boxes);
1598 
1599     if (have_clip)
1600 	_cairo_clip_fini (&local_clip);
1601 
1602     return status;
1603 }
1604 
1605 const cairo_surface_backend_t _cairo_gl_surface_backend = {
1606     CAIRO_SURFACE_TYPE_GL,
1607     _cairo_gl_surface_create_similar,
1608     _cairo_gl_surface_finish,
1609 
1610     _cairo_gl_surface_acquire_source_image,
1611     _cairo_gl_surface_release_source_image,
1612     _cairo_gl_surface_acquire_dest_image,
1613     _cairo_gl_surface_release_dest_image,
1614 
1615     _cairo_gl_surface_clone_similar,
1616     _cairo_gl_surface_composite,
1617     _cairo_gl_surface_fill_rectangles,
1618     _cairo_gl_surface_composite_trapezoids,
1619     _cairo_gl_surface_create_span_renderer,
1620     _cairo_gl_surface_check_span_renderer,
1621 
1622     NULL, /* copy_page */
1623     NULL, /* show_page */
1624     _cairo_gl_surface_get_extents,
1625     NULL, /* old_show_glyphs */
1626     _cairo_gl_surface_get_font_options,
1627     _cairo_gl_surface_flush,
1628     NULL, /* mark_dirty_rectangle */
1629     _cairo_gl_surface_scaled_font_fini,
1630     _cairo_gl_surface_scaled_glyph_fini,
1631     _cairo_gl_surface_paint,
1632     NULL, /* mask */
1633     _cairo_gl_surface_stroke,
1634     _cairo_gl_surface_fill,
1635     _cairo_gl_surface_show_glyphs, /* show_glyphs */
1636     NULL  /* snapshot */
1637 };
1638