1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 Intel Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it either under the terms of the GNU Lesser General Public
7  * License version 2.1 as published by the Free Software Foundation
8  * (the "LGPL") or, at your option, under the terms of the Mozilla
9  * Public License Version 1.1 (the "MPL"). If you do not alter this
10  * notice, a recipient may use your version of this file under either
11  * the MPL or the LGPL.
12  *
13  * You should have received a copy of the LGPL along with this library
14  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16  * You should have received a copy of the MPL along with this library
17  * in the file COPYING-MPL-1.1
18  *
19  * The contents of this file are subject to the Mozilla Public License
20  * Version 1.1 (the "License"); you may not use this file except in
21  * compliance with the License. You may obtain a copy of the License at
22  * http://www.mozilla.org/MPL/
23  *
24  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26  * the specific language governing rights and limitations.
27  *
28  * The Original Code is the cairo graphics library.
29  *
30  * The Initial Developer of the Original Code is Red Hat, Inc.
31  *
32  * Contributor(s):
33  *	Chris Wilson <chris@chris-wilson.co.uk>
34  */
35 
36 #include "cairoint.h"
37 
38 #include "cairo-composite-rectangles-private.h"
39 #include "cairo-boxes-private.h"
40 #include "cairo-error-private.h"
41 #include "cairo-drm-i915-private.h"
42 
43 /* Operates in either immediate or retained mode.
44  * When given a clip region we record the sequence of vbo and then
45  * replay them for each clip rectangle, otherwise we simply emit
46  * the vbo straight into the command stream.
47  */
48 
49 typedef struct _i915_spans i915_spans_t;
50 
51 typedef float *
52 (*i915_get_rectangle_func_t) (i915_spans_t *spans);
53 
54 typedef void
55 (*i915_span_func_t) (i915_spans_t *spans,
56 		     int x0, int x1, int y0, int y1,
57 		     int alpha);
58 
59 struct _i915_spans {
60     cairo_span_renderer_t renderer;
61 
62     i915_device_t *device;
63 
64     int xmin, xmax;
65     cairo_bool_t is_bounded;
66     const cairo_rectangle_int_t *extents;
67 
68     i915_get_rectangle_func_t get_rectangle;
69     i915_span_func_t span;
70     i915_shader_t shader;
71 
72     cairo_region_t *clip_region;
73     cairo_bool_t need_clip_surface;
74 
75     struct vbo {
76 	struct vbo *next;
77 	intel_bo_t *bo;
78 	unsigned int count;
79     } head, *tail;
80 
81     unsigned int vbo_offset;
82     float *vbo_base;
83 };
84 
85 static float *
i915_emit_rectangle(i915_spans_t * spans)86 i915_emit_rectangle (i915_spans_t *spans)
87 {
88     return i915_add_rectangle (spans->device);
89 }
90 
91 static float *
i915_accumulate_rectangle(i915_spans_t * spans)92 i915_accumulate_rectangle (i915_spans_t *spans)
93 {
94     float *vertices;
95     uint32_t size;
96 
97     size = spans->device->rectangle_size;
98     if (unlikely (spans->vbo_offset + size > I915_VBO_SIZE)) {
99 	struct vbo *vbo;
100 
101 	vbo = _cairo_malloc (sizeof (struct vbo));
102 	if (unlikely (vbo == NULL)) {
103 	    /* throw error! */
104 	}
105 
106 	spans->tail->next = vbo;
107 	spans->tail = vbo;
108 
109 	vbo->next = NULL;
110 	vbo->bo = intel_bo_create (&spans->device->intel,
111 				   I915_VBO_SIZE, I915_VBO_SIZE,
112 				   FALSE, I915_TILING_NONE, 0);
113 	vbo->count = 0;
114 
115 	spans->vbo_offset = 0;
116 	spans->vbo_base = intel_bo_map (&spans->device->intel, vbo->bo);
117     }
118 
119     vertices = spans->vbo_base + spans->vbo_offset;
120     spans->vbo_offset += size;
121     spans->tail->count += 3;
122 
123     return vertices;
124 }
125 
126 static void
i915_span_zero(i915_spans_t * spans,int x0,int x1,int y0,int y1,int alpha)127 i915_span_zero (i915_spans_t *spans,
128 		int x0, int x1, int y0, int y1,
129 		int alpha)
130 {
131     float *vertices;
132 
133     vertices = spans->get_rectangle (spans);
134 
135     *vertices++ = x1;
136     *vertices++ = y1;
137 
138     *vertices++ = x0;
139     *vertices++ = y1;
140 
141     *vertices++ = x0;
142     *vertices++ = y0;
143 }
144 
145 static void
i915_span_constant(i915_spans_t * spans,int x0,int x1,int y0,int y1,int alpha)146 i915_span_constant (i915_spans_t *spans,
147 		    int x0, int x1, int y0, int y1,
148 		    int alpha)
149 {
150     float *vertices;
151     float a = alpha / 255.;
152 
153     vertices = spans->get_rectangle (spans);
154 
155     *vertices++ = x1;
156     *vertices++ = y1;
157     *vertices++ = a;
158 
159     *vertices++ = x0;
160     *vertices++ = y1;
161     *vertices++ = a;
162 
163     *vertices++ = x0;
164     *vertices++ = y0;
165     *vertices++ = a;
166 }
167 
168 static void
i915_span_linear(i915_spans_t * spans,int x0,int x1,int y0,int y1,int alpha)169 i915_span_linear (i915_spans_t *spans,
170 		  int x0, int x1, int y0, int y1,
171 		  int alpha)
172 {
173     float *vertices;
174     float a = alpha / 255.;
175     double s, t;
176 
177     vertices = spans->get_rectangle (spans);
178 
179     *vertices++ = x1;
180     *vertices++ = y1;
181     s = x0, t = y0;
182     *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
183     *vertices++ = a;
184 
185     *vertices++ = x0;
186     *vertices++ = y1;
187     s = x1, t = y0;
188     *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
189     *vertices++ = a;
190 
191     *vertices++ = x0;
192     *vertices++ = y0;
193     s = x1, t = y1;
194     *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
195     *vertices++ = a;
196 }
197 
198 static void
i915_span_texture(i915_spans_t * spans,int x0,int x1,int y0,int y1,int alpha)199 i915_span_texture (i915_spans_t *spans,
200 		   int x0, int x1, int y0, int y1,
201 		   int alpha)
202 {
203     float *vertices;
204     float a = alpha / 255.;
205     double s, t;
206 
207     vertices = spans->get_rectangle (spans);
208 
209     *vertices++ = x1;
210     *vertices++ = y1;
211     s = x0, t = y0;
212     cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
213     *vertices++ = s; *vertices++ = t;
214     *vertices++ = a;
215 
216     *vertices++ = x0;
217     *vertices++ = y1;
218     s = x1, t = y0;
219     cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
220     *vertices++ = s; *vertices++ = t;
221     *vertices++ = a;
222 
223     *vertices++ = x0;
224     *vertices++ = y0;
225     s = x1, t = y1;
226     cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
227     *vertices++ = s; *vertices++ = t;
228     *vertices++ = a;
229 }
230 
231 static void
i915_span_texture16(i915_spans_t * spans,int x0,int x1,int y0,int y1,int alpha)232 i915_span_texture16 (i915_spans_t *spans,
233 		     int x0, int x1, int y0, int y1, int alpha)
234 {
235     float *vertices;
236     float a = alpha / 255.;
237     double s, t;
238 
239     vertices = spans->get_rectangle (spans);
240 
241     *vertices++ = x1;
242     *vertices++ = y1;
243     s = x0, t = y0;
244     cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
245     *vertices++ = texcoord_2d_16 (s, t);
246     *vertices++ = a;
247 
248     *vertices++ = x0;
249     *vertices++ = y1;
250     s = x1, t = y0;
251     cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
252     *vertices++ = texcoord_2d_16 (s, t);
253     *vertices++ = a;
254 
255     *vertices++ = x0;
256     *vertices++ = y0;
257     s = x1, t = y1;
258     cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
259     *vertices++ = texcoord_2d_16 (s, t);
260     *vertices++ = a;
261 }
262 
263 static void
i915_span_generic(i915_spans_t * spans,int x0,int x1,int y0,int y1,int alpha)264 i915_span_generic (i915_spans_t *spans,
265 		   int x0, int x1, int y0, int y1, int alpha)
266 {
267     double s, t;
268     float *vertices;
269     float a = alpha / 255.;
270 
271     /* Each vertex is:
272      *   2 vertex coordinates
273      *   [0-2] source texture coordinates
274      *   1 alpha value.
275      *   [0,2] clip mask coordinates
276      */
277 
278     vertices = spans->get_rectangle (spans);
279 
280     /* bottom right */
281     *vertices++ = x1; *vertices++ = y1;
282     s = x1, t = y1;
283     switch (spans->shader.source.type.vertex) {
284     case VS_ZERO:
285     case VS_CONSTANT:
286 	break;
287     case VS_LINEAR:
288 	*vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
289 	break;
290     case VS_TEXTURE:
291 	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
292 	*vertices++ = s; *vertices++ = t;
293 	break;
294     case VS_TEXTURE_16:
295 	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
296 	*vertices++ = texcoord_2d_16 (s, t);
297 	break;
298     }
299     *vertices++ = a;
300     if (spans->need_clip_surface) {
301 	s = x1, t = y1;
302 	cairo_matrix_transform_point (&spans->shader.clip.base.matrix, &s, &t);
303 	*vertices++ = texcoord_2d_16 (s, t);
304     }
305     if (spans->shader.need_combine) {
306 	s = x1, t = y1;
307 	cairo_matrix_transform_point (&spans->shader.dst.base.matrix, &s, &t);
308 	*vertices++ = texcoord_2d_16 (s, t);
309     }
310 
311     /* bottom left */
312     *vertices++ = x0; *vertices++ = y1;
313     s = x0, t = y1;
314     switch (spans->shader.source.type.vertex) {
315     case VS_ZERO:
316     case VS_CONSTANT:
317 	break;
318     case VS_LINEAR:
319 	*vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
320 	break;
321     case VS_TEXTURE:
322 	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
323 	*vertices++ = s; *vertices++ = t;
324 	break;
325     case VS_TEXTURE_16:
326 	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
327 	*vertices++ = texcoord_2d_16 (s, t);
328 	break;
329     }
330     *vertices++ = a;
331     if (spans->need_clip_surface) {
332 	s = x0, t = y1;
333 	cairo_matrix_transform_point (&spans->shader.clip.base.matrix, &s, &t);
334 	*vertices++ = texcoord_2d_16 (s, t);
335     }
336     if (spans->shader.need_combine) {
337 	s = x0, t = y1;
338 	cairo_matrix_transform_point (&spans->shader.dst.base.matrix, &s, &t);
339 	*vertices++ = texcoord_2d_16 (s, t);
340     }
341 
342     /* top left */
343     *vertices++ = x0; *vertices++ = y0;
344     s = x0, t = y0;
345     switch (spans->shader.source.type.vertex) {
346     case VS_ZERO:
347     case VS_CONSTANT:
348 	break;
349     case VS_LINEAR:
350 	*vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
351 	break;
352     case VS_TEXTURE:
353 	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
354 	*vertices++ = s; *vertices++ = t;
355 	break;
356     case VS_TEXTURE_16:
357 	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
358 	*vertices++ = texcoord_2d_16 (s, t);
359 	break;
360     }
361     *vertices++ = a;
362     if (spans->need_clip_surface) {
363 	s = x0, t = y0;
364 	cairo_matrix_transform_point (&spans->shader.clip.base.matrix, &s, &t);
365 	*vertices++ = texcoord_2d_16 (s, t);
366     }
367     if (spans->shader.need_combine) {
368 	s = x0, t = y0;
369 	cairo_matrix_transform_point (&spans->shader.dst.base.matrix, &s, &t);
370 	*vertices++ = texcoord_2d_16 (s, t);
371     }
372 }
373 
374 static cairo_status_t
i915_zero_spans_mono(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)375 i915_zero_spans_mono (void *abstract_renderer,
376 		      int y, int height,
377 		      const cairo_half_open_span_t *half,
378 		      unsigned num_spans)
379 {
380     i915_spans_t *spans = abstract_renderer;
381     int x0, x1;
382 
383     if (num_spans == 0)
384 	return CAIRO_STATUS_SUCCESS;
385 
386     do {
387 	while (num_spans && half[0].coverage < 128)
388 	    half++, num_spans--;
389 	if (num_spans == 0)
390 	    break;
391 
392 	x0 = x1 = half[0].x;
393 	while (num_spans--) {
394 	    half++;
395 
396 	    x1 = half[0].x;
397 	    if (half[0].coverage < 128)
398 		break;
399 	}
400 
401 	i915_span_zero (spans,
402 			x0, x1,
403 			y, y + height,
404 			0);
405     } while (num_spans);
406 
407     return CAIRO_STATUS_SUCCESS;
408 }
409 
410 static cairo_status_t
i915_zero_spans(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)411 i915_zero_spans (void *abstract_renderer,
412 		 int y, int height,
413 		 const cairo_half_open_span_t *half,
414 		 unsigned num_spans)
415 {
416     i915_spans_t *spans = abstract_renderer;
417     int x0, x1;
418 
419     if (num_spans == 0)
420 	return CAIRO_STATUS_SUCCESS;
421 
422     do {
423 	while (num_spans && half[0].coverage == 0)
424 	    half++, num_spans--;
425 	if (num_spans == 0)
426 	    break;
427 
428 	x0 = x1 = half[0].x;
429 	while (num_spans--) {
430 	    half++;
431 
432 	    x1 = half[0].x;
433 	    if (half[0].coverage == 0)
434 		break;
435 	}
436 
437 	i915_span_zero (spans,
438 			x0, x1,
439 			y, y + height,
440 			0);
441     } while (num_spans);
442 
443     return CAIRO_STATUS_SUCCESS;
444 }
445 
446 static cairo_status_t
i915_bounded_spans_mono(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)447 i915_bounded_spans_mono (void *abstract_renderer,
448 			 int y, int height,
449 			 const cairo_half_open_span_t *half,
450 			 unsigned num_spans)
451 {
452     i915_spans_t *spans = abstract_renderer;
453 
454     if (num_spans == 0)
455 	return CAIRO_STATUS_SUCCESS;
456 
457     do {
458 	if (half[0].coverage >= 128) {
459 	    spans->span (spans,
460 			 half[0].x, half[1].x,
461 			 y, y + height,
462 			 255);
463 	}
464 	half++;
465     } while (--num_spans > 1);
466 
467     return CAIRO_STATUS_SUCCESS;
468 }
469 
470 static cairo_status_t
i915_bounded_spans(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)471 i915_bounded_spans (void *abstract_renderer,
472 		    int y, int height,
473 		    const cairo_half_open_span_t *half,
474 		    unsigned num_spans)
475 {
476     i915_spans_t *spans = abstract_renderer;
477 
478     if (num_spans == 0)
479 	return CAIRO_STATUS_SUCCESS;
480 
481     do {
482 	if (half[0].coverage) {
483 	    spans->span (spans,
484 			 half[0].x, half[1].x,
485 			 y, y + height,
486 			 half[0].coverage);
487 	}
488 	half++;
489     } while (--num_spans > 1);
490 
491     return CAIRO_STATUS_SUCCESS;
492 }
493 
494 static cairo_status_t
i915_unbounded_spans(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)495 i915_unbounded_spans (void *abstract_renderer,
496 		      int y, int height,
497 		      const cairo_half_open_span_t *half,
498 		      unsigned num_spans)
499 {
500     i915_spans_t *spans = abstract_renderer;
501 
502     if (num_spans == 0) {
503 	spans->span (spans,
504 		     spans->xmin, spans->xmax,
505 		     y, y + height,
506 		     0);
507 	return CAIRO_STATUS_SUCCESS;
508     }
509 
510     if (half[0].x != spans->xmin) {
511 	spans->span (spans,
512 		     spans->xmin, half[0].x,
513 		     y, y + height,
514 		     0);
515     }
516 
517     do {
518 	spans->span (spans,
519 		     half[0].x, half[1].x,
520 		     y, y + height,
521 		     half[0].coverage);
522 	half++;
523     } while (--num_spans > 1);
524 
525     if (half[0].x != spans->xmax) {
526 	spans->span (spans,
527 		     half[0].x, spans->xmax,
528 		     y, y + height,
529 		     0);
530     }
531 
532     return CAIRO_STATUS_SUCCESS;
533 }
534 
535 static cairo_status_t
i915_unbounded_spans_mono(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * half,unsigned num_spans)536 i915_unbounded_spans_mono (void *abstract_renderer,
537 			   int y, int height,
538 			   const cairo_half_open_span_t *half,
539 			   unsigned num_spans)
540 {
541     i915_spans_t *spans = abstract_renderer;
542 
543     if (num_spans == 0) {
544 	spans->span (spans,
545 		     spans->xmin, spans->xmax,
546 		     y, y + height,
547 		     0);
548 	return CAIRO_STATUS_SUCCESS;
549     }
550 
551     if (half[0].x != spans->xmin) {
552 	spans->span (spans,
553 		     spans->xmin, half[0].x,
554 		     y, y + height,
555 		     0);
556     }
557 
558     do {
559 	int alpha = 0;
560 	if (half[0].coverage >= 128)
561 	    alpha = 255;
562 	spans->span (spans,
563 		     half[0].x, half[1].x,
564 		     y, y + height,
565 		     alpha);
566 	half++;
567     } while (--num_spans > 1);
568 
569     if (half[0].x != spans->xmax) {
570 	spans->span (spans,
571 		     half[0].x, spans->xmax,
572 		     y, y + height,
573 		     0);
574     }
575 
576     return CAIRO_STATUS_SUCCESS;
577 }
578 
579 static cairo_status_t
i915_spans_init(i915_spans_t * spans,i915_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * pattern,cairo_antialias_t antialias,cairo_clip_t * clip,double opacity,const cairo_composite_rectangles_t * extents)580 i915_spans_init (i915_spans_t *spans,
581 		 i915_surface_t *dst,
582 		 cairo_operator_t op,
583 		 const cairo_pattern_t *pattern,
584 		 cairo_antialias_t antialias,
585 		 cairo_clip_t *clip,
586 		 double opacity,
587 		 const cairo_composite_rectangles_t *extents)
588 {
589     cairo_status_t status;
590 
591     spans->device = (i915_device_t *) dst->intel.drm.base.device;
592 
593     spans->is_bounded = extents->is_bounded;
594     if (extents->is_bounded) {
595 	if (antialias == CAIRO_ANTIALIAS_NONE)
596 	    spans->renderer.render_rows = i915_bounded_spans_mono;
597 	else
598 	    spans->renderer.render_rows = i915_bounded_spans;
599 
600 	spans->extents = &extents->bounded;
601     } else {
602 	if (antialias == CAIRO_ANTIALIAS_NONE)
603 	    spans->renderer.render_rows = i915_unbounded_spans_mono;
604 	else
605 	    spans->renderer.render_rows = i915_unbounded_spans;
606 
607 	spans->extents = &extents->unbounded;
608     }
609     spans->xmin = spans->extents->x;
610     spans->xmax = spans->extents->x + spans->extents->width;
611 
612     spans->clip_region = NULL;
613     spans->need_clip_surface = FALSE;
614     if (clip != NULL) {
615 	cairo_region_t *clip_region = NULL;
616 
617 	status = _cairo_clip_get_region (clip, &clip_region);
618 	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
619 
620 	if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
621 	    clip_region = NULL;
622 
623 	spans->clip_region = clip_region;
624 	spans->need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
625     }
626 
627     spans->head.next = NULL;
628     spans->head.bo = NULL;
629     spans->head.count = 0;
630     spans->tail = &spans->head;
631 
632     if (spans->clip_region == NULL) {
633 	spans->get_rectangle = i915_emit_rectangle;
634     } else {
635 	assert (! extents->is_bounded);
636 	spans->get_rectangle = i915_accumulate_rectangle;
637 	spans->head.bo = intel_bo_create (&spans->device->intel,
638 					  I915_VBO_SIZE, I915_VBO_SIZE,
639 					  FALSE, I915_TILING_NONE, 0);
640 	if (unlikely (spans->head.bo == NULL))
641 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
642 
643 	spans->vbo_base = intel_bo_map (&spans->device->intel, spans->head.bo);
644     }
645     spans->vbo_offset = 0;
646 
647     i915_shader_init (&spans->shader, dst, op, opacity);
648     if (spans->need_clip_surface)
649 	i915_shader_set_clip (&spans->shader, clip);
650 
651     status = i915_shader_acquire_pattern (&spans->shader, &spans->shader.source,
652 					  pattern, &extents->bounded);
653     if (unlikely (status))
654 	return status;
655 
656     return CAIRO_STATUS_SUCCESS;
657 }
658 
659 static void
i915_spans_fini(i915_spans_t * spans)660 i915_spans_fini (i915_spans_t *spans)
661 {
662     i915_shader_fini (&spans->shader);
663 
664     if (spans->head.bo != NULL) {
665 	struct vbo *vbo, *next;
666 
667 	intel_bo_destroy (&spans->device->intel, spans->head.bo);
668 	for (vbo = spans->head.next; vbo != NULL; vbo = next) {
669 	    next = vbo->next;
670 	    intel_bo_destroy (&spans->device->intel, vbo->bo);
671 	    free (vbo);
672 	}
673     }
674 }
675 
676 cairo_status_t
i915_clip_and_composite_spans(i915_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * pattern,cairo_antialias_t antialias,i915_spans_func_t draw_func,void * draw_closure,const cairo_composite_rectangles_t * extents,cairo_clip_t * clip,double opacity)677 i915_clip_and_composite_spans (i915_surface_t		*dst,
678 			       cairo_operator_t		 op,
679 			       const cairo_pattern_t	*pattern,
680 			       cairo_antialias_t	 antialias,
681 			       i915_spans_func_t	 draw_func,
682 			       void			*draw_closure,
683 			       const cairo_composite_rectangles_t*extents,
684 			       cairo_clip_t		*clip,
685 			       double opacity)
686 {
687     i915_spans_t spans;
688     i915_device_t *device;
689     cairo_status_t status;
690     struct vbo *vbo;
691 
692     if (i915_surface_needs_tiling (dst)) {
693 	ASSERT_NOT_REACHED;
694 	return CAIRO_INT_STATUS_UNSUPPORTED;
695     }
696 
697     if (op == CAIRO_OPERATOR_CLEAR) {
698 	pattern = &_cairo_pattern_white.base;
699 	op = CAIRO_OPERATOR_DEST_OUT;
700     }
701 
702     status = i915_spans_init (&spans, dst, op, pattern, antialias, clip, opacity, extents);
703     if (unlikely (status))
704 	return status;
705 
706     spans.shader.mask.base.texfmt = TEXCOORDFMT_1D;
707     spans.shader.mask.base.content = CAIRO_CONTENT_ALPHA;
708     spans.shader.mask.type.fragment = FS_SPANS;
709 
710     status = cairo_device_acquire (dst->intel.drm.base.device);
711     if (unlikely (status))
712 	goto CLEANUP_SPANS;
713 
714     if (dst->deferred_clear) {
715 	status = i915_surface_clear (dst);
716 	if (unlikely (status))
717 	    goto CLEANUP_SPANS;
718     }
719 
720     device = i915_device (dst);
721     status = i915_shader_commit (&spans.shader, device);
722     if (unlikely (status))
723 	goto CLEANUP_DEVICE;
724 
725     if (! spans.shader.need_combine && ! spans.need_clip_surface) {
726 	switch (spans.shader.source.type.vertex) {
727 	case VS_ZERO:
728 	    spans.span = i915_span_zero;
729 	    if (extents->is_bounded) {
730 		if (antialias == CAIRO_ANTIALIAS_NONE)
731 		    spans.renderer.render_rows = i915_zero_spans_mono;
732 		else
733 		    spans.renderer.render_rows = i915_zero_spans;
734 	    }
735 	    break;
736 	case VS_CONSTANT:
737 	    spans.span = i915_span_constant;
738 	    break;
739 	case VS_LINEAR:
740 	    spans.span = i915_span_linear;
741 	    break;
742 	case VS_TEXTURE:
743 	    spans.span = i915_span_texture;
744 	    break;
745 	case VS_TEXTURE_16:
746 	    spans.span = i915_span_texture16;
747 	    break;
748 	default:
749 	    spans.span = i915_span_generic;
750 	    break;
751 	}
752     } else {
753 	spans.span = i915_span_generic;
754     }
755 
756     status = draw_func (draw_closure, &spans.renderer, spans.extents);
757     if (spans.clip_region != NULL && status == CAIRO_STATUS_SUCCESS) {
758 	i915_vbo_finish (device);
759 
760 	OUT_DWORD (_3DSTATE_SCISSOR_ENABLE_CMD | ENABLE_SCISSOR_RECT);
761 	for (vbo = &spans.head; vbo != NULL; vbo = vbo->next) {
762 	    int i, num_rectangles;
763 
764 	    /* XXX require_space & batch_flush */
765 
766 	    OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S (0) | I1_LOAD_S (1) | 1);
767 	    i915_batch_emit_reloc (device, vbo->bo, 0,
768 				   I915_GEM_DOMAIN_VERTEX, 0,
769 				   FALSE);
770 	    OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
771 		       (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT) |
772 		       vbo->count);
773 
774 	    num_rectangles = cairo_region_num_rectangles (spans.clip_region);
775 	    for (i = 0; i < num_rectangles; i++) {
776 		cairo_rectangle_int_t rect;
777 
778 		cairo_region_get_rectangle (spans.clip_region, i, &rect);
779 
780 		OUT_DWORD (_3DSTATE_SCISSOR_RECT_0_CMD);
781 		OUT_DWORD (SCISSOR_RECT_0_XMIN (rect.x) |
782 			   SCISSOR_RECT_0_YMIN (rect.y));
783 		OUT_DWORD (SCISSOR_RECT_0_XMAX (rect.x + rect.width) |
784 			   SCISSOR_RECT_0_YMAX (rect.y + rect.height));
785 
786 		OUT_DWORD (PRIM3D_RECTLIST | PRIM3D_INDIRECT_SEQUENTIAL | vbo->count);
787 		OUT_DWORD (0);
788 	    }
789 	}
790 	OUT_DWORD (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
791     }
792 
793 CLEANUP_DEVICE:
794     cairo_device_release (dst->intel.drm.base.device);
795 CLEANUP_SPANS:
796     i915_spans_fini (&spans);
797 
798     return status;
799 }
800