Tizen 2.0 Release
[framework/graphics/cairo.git] / src / drm / cairo-drm-i915-spans.c
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 *
86 i915_emit_rectangle (i915_spans_t *spans)
87 {
88     return i915_add_rectangle (spans->device);
89 }
90
91 static float *
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 = 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }