Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / llvmpipe / lp_setup_line.c
1 /**************************************************************************
2  *
3  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27
28 /*
29  * Binning code for lines
30  */
31
32 #include "util/u_math.h"
33 #include "util/u_memory.h"
34 #include "lp_perf.h"
35 #include "lp_setup_context.h"
36 #include "lp_rast.h"
37 #include "lp_state_fs.h"
38 #include "lp_state_setup.h"
39
40 #define NUM_CHANNELS 4
41
42 struct lp_line_info {
43
44    float dx;
45    float dy;
46    float oneoverarea;
47
48    const float (*v1)[4];
49    const float (*v2)[4];
50
51    float (*a0)[4];
52    float (*dadx)[4];
53    float (*dady)[4];
54 };
55
56
57 /**
58  * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
59  */
60 static void constant_coef( struct lp_setup_context *setup,
61                            struct lp_line_info *info,
62                            unsigned slot,
63                            const float value,
64                            unsigned i )
65 {
66    info->a0[slot][i] = value;
67    info->dadx[slot][i] = 0.0f;
68    info->dady[slot][i] = 0.0f;
69 }
70
71
72 /**
73  * Compute a0, dadx and dady for a linearly interpolated coefficient,
74  * for a triangle.
75  */
76 static void linear_coef( struct lp_setup_context *setup,
77                          struct lp_line_info *info,
78                          unsigned slot,
79                          unsigned vert_attr,
80                          unsigned i)
81 {
82    float a1 = info->v1[vert_attr][i]; 
83    float a2 = info->v2[vert_attr][i];
84       
85    float da21 = a1 - a2;   
86    float dadx = da21 * info->dx * info->oneoverarea;
87    float dady = da21 * info->dy * info->oneoverarea;
88
89    info->dadx[slot][i] = dadx;
90    info->dady[slot][i] = dady;  
91    
92    info->a0[slot][i] = (a1 -
93                               (dadx * (info->v1[0][0] - setup->pixel_offset) +
94                                dady * (info->v1[0][1] - setup->pixel_offset)));
95 }
96
97
98 /**
99  * Compute a0, dadx and dady for a perspective-corrected interpolant,
100  * for a triangle.
101  * We basically multiply the vertex value by 1/w before computing
102  * the plane coefficients (a0, dadx, dady).
103  * Later, when we compute the value at a particular fragment position we'll
104  * divide the interpolated value by the interpolated W at that fragment.
105  */
106 static void perspective_coef( struct lp_setup_context *setup,
107                               struct lp_line_info *info,
108                               unsigned slot,
109                               unsigned vert_attr,
110                               unsigned i)
111 {
112    /* premultiply by 1/w  (v[0][3] is always 1/w):
113     */
114    float a1 = info->v1[vert_attr][i] * info->v1[0][3];
115    float a2 = info->v2[vert_attr][i] * info->v2[0][3];
116
117    float da21 = a1 - a2;   
118    float dadx = da21 * info->dx * info->oneoverarea;
119    float dady = da21 * info->dy * info->oneoverarea;
120
121    info->dadx[slot][i] = dadx;
122    info->dady[slot][i] = dady;
123    
124    info->a0[slot][i] = (a1 -
125                         (dadx * (info->v1[0][0] - setup->pixel_offset) +
126                          dady * (info->v1[0][1] - setup->pixel_offset)));
127 }
128
129 static void
130 setup_fragcoord_coef( struct lp_setup_context *setup,
131                       struct lp_line_info *info,
132                       unsigned slot,
133                       unsigned usage_mask)
134 {
135    /*X*/
136    if (usage_mask & TGSI_WRITEMASK_X) {
137       info->a0[slot][0] = 0.0;
138       info->dadx[slot][0] = 1.0;
139       info->dady[slot][0] = 0.0;
140    }
141
142    /*Y*/
143    if (usage_mask & TGSI_WRITEMASK_Y) {
144       info->a0[slot][1] = 0.0;
145       info->dadx[slot][1] = 0.0;
146       info->dady[slot][1] = 1.0;
147    }
148
149    /*Z*/
150    if (usage_mask & TGSI_WRITEMASK_Z) {
151       linear_coef(setup, info, slot, 0, 2);
152    }
153
154    /*W*/
155    if (usage_mask & TGSI_WRITEMASK_W) {
156       linear_coef(setup, info, slot, 0, 3);
157    }
158 }
159
160 /**
161  * Compute the tri->coef[] array dadx, dady, a0 values.
162  */
163 static void setup_line_coefficients( struct lp_setup_context *setup,
164                                      struct lp_line_info *info)
165 {
166    const struct lp_setup_variant_key *key = &setup->setup.variant->key;
167    unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ;
168    unsigned slot;
169
170    /* setup interpolation for all the remaining attributes:
171     */
172    for (slot = 0; slot < key->num_inputs; slot++) {
173       unsigned vert_attr = key->inputs[slot].src_index;
174       unsigned usage_mask = key->inputs[slot].usage_mask;
175       unsigned i;
176            
177       switch (key->inputs[slot].interp) {
178       case LP_INTERP_CONSTANT:
179          if (key->flatshade_first) {
180             for (i = 0; i < NUM_CHANNELS; i++)
181                if (usage_mask & (1 << i))
182                   constant_coef(setup, info, slot+1, info->v1[vert_attr][i], i);
183          }
184          else {
185             for (i = 0; i < NUM_CHANNELS; i++)
186                if (usage_mask & (1 << i))
187                   constant_coef(setup, info, slot+1, info->v2[vert_attr][i], i);
188          }
189          break;
190
191       case LP_INTERP_LINEAR:
192          for (i = 0; i < NUM_CHANNELS; i++)
193             if (usage_mask & (1 << i))
194                linear_coef(setup, info, slot+1, vert_attr, i);
195          break;
196
197       case LP_INTERP_PERSPECTIVE:
198          for (i = 0; i < NUM_CHANNELS; i++)
199             if (usage_mask & (1 << i))
200                perspective_coef(setup, info, slot+1, vert_attr, i);
201          fragcoord_usage_mask |= TGSI_WRITEMASK_W;
202          break;
203
204       case LP_INTERP_POSITION:
205          /*
206           * The generated pixel interpolators will pick up the coeffs from
207           * slot 0, so all need to ensure that the usage mask is covers all
208           * usages.
209           */
210          fragcoord_usage_mask |= usage_mask;
211          break;
212
213       case LP_INTERP_FACING:
214          for (i = 0; i < NUM_CHANNELS; i++)
215             if (usage_mask & (1 << i))
216                constant_coef(setup, info, slot+1, 1.0, i);
217          break;
218
219       default:
220          assert(0);
221       }
222    }
223
224    /* The internal position input is in slot zero:
225     */
226    setup_fragcoord_coef(setup, info, 0,
227                         fragcoord_usage_mask);
228 }
229
230
231
232 static INLINE int subpixel_snap( float a )
233 {
234    return util_iround(FIXED_ONE * a);
235 }
236
237
238 /**
239  * Print line vertex attribs (for debug).
240  */
241 static void
242 print_line(struct lp_setup_context *setup,
243            const float (*v1)[4],
244            const float (*v2)[4])
245 {
246    const struct lp_setup_variant_key *key = &setup->setup.variant->key;
247    uint i;
248
249    debug_printf("llvmpipe line\n");
250    for (i = 0; i < 1 + key->num_inputs; i++) {
251       debug_printf("  v1[%d]:  %f %f %f %f\n", i,
252                    v1[i][0], v1[i][1], v1[i][2], v1[i][3]);
253    }
254    for (i = 0; i < 1 + key->num_inputs; i++) {
255       debug_printf("  v2[%d]:  %f %f %f %f\n", i,
256                    v2[i][0], v2[i][1], v2[i][2], v2[i][3]);
257    }
258 }
259
260
261 static INLINE boolean sign(float x){
262    return x >= 0;  
263 }  
264
265
266 /* Used on positive floats only:
267  */
268 static INLINE float fracf(float f)
269 {
270    return f - floorf(f);
271 }
272
273
274
275 static boolean
276 try_setup_line( struct lp_setup_context *setup,
277                const float (*v1)[4],
278                const float (*v2)[4])
279 {
280    struct lp_scene *scene = setup->scene;
281    const struct lp_setup_variant_key *key = &setup->setup.variant->key;
282    struct lp_rast_triangle *line;
283    struct lp_rast_plane *plane;
284    struct lp_line_info info;
285    float width = MAX2(1.0, setup->line_width);
286    struct u_rect bbox;
287    unsigned tri_bytes;
288    int x[4]; 
289    int y[4];
290    int i;
291    int nr_planes = 4;
292    
293    /* linewidth should be interpreted as integer */
294    int fixed_width = util_iround(width) * FIXED_ONE;
295
296    float x_offset=0;
297    float y_offset=0;
298    float x_offset_end=0;
299    float y_offset_end=0;
300       
301    float x1diff;
302    float y1diff;
303    float x2diff;
304    float y2diff;
305    float dx, dy;
306    float area;
307
308    boolean draw_start;
309    boolean draw_end;
310    boolean will_draw_start;
311    boolean will_draw_end;
312
313    if (0)
314       print_line(setup, v1, v2);
315
316    if (setup->scissor_test) {
317       nr_planes = 8;
318    }
319    else {
320       nr_planes = 4;
321    }
322
323
324    dx = v1[0][0] - v2[0][0];
325    dy = v1[0][1] - v2[0][1];
326    area = (dx * dx  + dy * dy);
327    if (area == 0) {
328       LP_COUNT(nr_culled_tris);
329       return TRUE;
330    }
331
332    info.oneoverarea = 1.0f / area;
333    info.dx = dx;
334    info.dy = dy;
335    info.v1 = v1;
336    info.v2 = v2;
337
338   
339    /* X-MAJOR LINE */
340    if (fabsf(dx) >= fabsf(dy)) {
341       float dydx = dy / dx;
342
343       x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5;
344       y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5;
345       x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5;
346       y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5;
347
348       if (y2diff==-0.5 && dy<0){
349          y2diff = 0.5;
350       }
351       
352       /* 
353        * Diamond exit rule test for starting point 
354        */    
355       if (fabsf(x1diff) + fabsf(y1diff) < 0.5) {
356          draw_start = TRUE;
357       }
358       else if (sign(x1diff) == sign(-dx)) {
359          draw_start = FALSE;
360       }
361       else if (sign(-y1diff) != sign(dy)) {
362          draw_start = TRUE;
363       }
364       else {
365          /* do intersection test */
366          float yintersect = fracf(v1[0][1]) + x1diff * dydx;
367          draw_start = (yintersect < 1.0 && yintersect > 0.0);
368       }
369
370
371       /* 
372        * Diamond exit rule test for ending point 
373        */    
374       if (fabsf(x2diff) + fabsf(y2diff) < 0.5) {
375          draw_end = FALSE;
376       }
377       else if (sign(x2diff) != sign(-dx)) {
378          draw_end = FALSE;
379       }
380       else if (sign(-y2diff) == sign(dy)) {
381          draw_end = TRUE;
382       }
383       else {
384          /* do intersection test */
385          float yintersect = fracf(v2[0][1]) + x2diff * dydx;
386          draw_end = (yintersect < 1.0 && yintersect > 0.0);
387       }
388
389       /* Are we already drawing start/end?
390        */
391       will_draw_start = sign(-x1diff) != sign(dx);
392       will_draw_end = (sign(x2diff) == sign(-dx)) || x2diff==0;
393
394       if (dx < 0) {
395          /* if v2 is to the right of v1, swap pointers */
396          const float (*temp)[4] = v1;
397          v1 = v2;
398          v2 = temp;
399          dx = -dx;
400          dy = -dy;
401          /* Otherwise shift planes appropriately */
402          if (will_draw_start != draw_start) {
403             x_offset_end = - x1diff - 0.5;
404             y_offset_end = x_offset_end * dydx;
405
406          }
407          if (will_draw_end != draw_end) {
408             x_offset = - x2diff - 0.5;
409             y_offset = x_offset * dydx;
410          }
411
412       }
413       else{
414          /* Otherwise shift planes appropriately */
415          if (will_draw_start != draw_start) {
416             x_offset = - x1diff + 0.5;
417             y_offset = x_offset * dydx;
418          }
419          if (will_draw_end != draw_end) {
420             x_offset_end = - x2diff + 0.5;
421             y_offset_end = x_offset_end * dydx;
422          }
423       }
424   
425       /* x/y positions in fixed point */
426       x[0] = subpixel_snap(v1[0][0] + x_offset     - setup->pixel_offset);
427       x[1] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset);
428       x[2] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset);
429       x[3] = subpixel_snap(v1[0][0] + x_offset     - setup->pixel_offset);
430       
431       y[0] = subpixel_snap(v1[0][1] + y_offset     - setup->pixel_offset) - fixed_width/2;
432       y[1] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset) - fixed_width/2;
433       y[2] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset) + fixed_width/2;
434       y[3] = subpixel_snap(v1[0][1] + y_offset     - setup->pixel_offset) + fixed_width/2;
435       
436    }
437    else {
438       const float dxdy = dx / dy;
439
440       /* Y-MAJOR LINE */      
441       x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5;
442       y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5;
443       x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5;
444       y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5;
445
446       if (x2diff==-0.5 && dx<0) {
447          x2diff = 0.5;
448       }
449
450       /* 
451        * Diamond exit rule test for starting point 
452        */    
453       if (fabsf(x1diff) + fabsf(y1diff) < 0.5) {
454          draw_start = TRUE;
455       }
456       else if (sign(-y1diff) == sign(dy)) {
457          draw_start = FALSE;
458       }
459       else if (sign(x1diff) != sign(-dx)) {
460          draw_start = TRUE;
461       }
462       else {
463          /* do intersection test */
464          float xintersect = fracf(v1[0][0]) + y1diff * dxdy;
465          draw_start = (xintersect < 1.0 && xintersect > 0.0);
466       }
467
468       /* 
469        * Diamond exit rule test for ending point 
470        */    
471       if (fabsf(x2diff) + fabsf(y2diff) < 0.5) {
472          draw_end = FALSE;
473       }
474       else if (sign(-y2diff) != sign(dy) ) {
475          draw_end = FALSE;
476       }
477       else if (sign(x2diff) == sign(-dx) ) {
478          draw_end = TRUE;
479       }
480       else {
481          /* do intersection test */
482          float xintersect = fracf(v2[0][0]) + y2diff * dxdy;
483          draw_end = (xintersect < 1.0 && xintersect >= 0.0);
484       }
485
486       /* Are we already drawing start/end?
487        */
488       will_draw_start = sign(y1diff) == sign(dy);
489       will_draw_end = (sign(-y2diff) == sign(dy)) || y2diff==0;
490
491       if (dy > 0) {
492          /* if v2 is on top of v1, swap pointers */
493          const float (*temp)[4] = v1;
494          v1 = v2;
495          v2 = temp; 
496          dx = -dx;
497          dy = -dy;
498
499          /* Otherwise shift planes appropriately */
500          if (will_draw_start != draw_start) {
501             y_offset_end = - y1diff + 0.5;
502             x_offset_end = y_offset_end * dxdy;
503          }
504          if (will_draw_end != draw_end) {
505             y_offset = - y2diff + 0.5;
506             x_offset = y_offset * dxdy;
507          }
508       }
509       else {
510          /* Otherwise shift planes appropriately */
511          if (will_draw_start != draw_start) {
512             y_offset = - y1diff - 0.5;
513             x_offset = y_offset * dxdy;
514                      
515          }
516          if (will_draw_end != draw_end) {
517             y_offset_end = - y2diff - 0.5;
518             x_offset_end = y_offset_end * dxdy;
519          }
520       }
521
522       /* x/y positions in fixed point */
523       x[0] = subpixel_snap(v1[0][0] + x_offset     - setup->pixel_offset) - fixed_width/2;
524       x[1] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset) - fixed_width/2;
525       x[2] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset) + fixed_width/2;
526       x[3] = subpixel_snap(v1[0][0] + x_offset     - setup->pixel_offset) + fixed_width/2;
527      
528       y[0] = subpixel_snap(v1[0][1] + y_offset     - setup->pixel_offset); 
529       y[1] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset);
530       y[2] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset);
531       y[3] = subpixel_snap(v1[0][1] + y_offset     - setup->pixel_offset);
532    }
533
534
535
536    LP_COUNT(nr_tris);
537
538  
539    /* Bounding rectangle (in pixels) */
540    {
541       /* Yes this is necessary to accurately calculate bounding boxes
542        * with the two fill-conventions we support.  GL (normally) ends
543        * up needing a bottom-left fill convention, which requires
544        * slightly different rounding.
545        */
546       int adj = (setup->pixel_offset != 0) ? 1 : 0;
547
548       bbox.x0 = (MIN4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER;
549       bbox.x1 = (MAX4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER;
550       bbox.y0 = (MIN4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
551       bbox.y1 = (MAX4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
552
553       /* Inclusive coordinates:
554        */
555       bbox.x1--;
556       bbox.y1--;
557    }
558
559    if (bbox.x1 < bbox.x0 ||
560        bbox.y1 < bbox.y0) {
561       if (0) debug_printf("empty bounding box\n");
562       LP_COUNT(nr_culled_tris);
563       return TRUE;
564    }
565
566    if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
567       if (0) debug_printf("offscreen\n");
568       LP_COUNT(nr_culled_tris);
569       return TRUE;
570    }
571
572    /* Can safely discard negative regions:
573     */
574    bbox.x0 = MAX2(bbox.x0, 0);
575    bbox.y0 = MAX2(bbox.y0, 0);
576
577    line = lp_setup_alloc_triangle(scene,
578                                   key->num_inputs,
579                                   nr_planes,
580                                   &tri_bytes);
581    if (!line)
582       return FALSE;
583
584 #ifdef DEBUG
585    line->v[0][0] = v1[0][0];
586    line->v[1][0] = v2[0][0];   
587    line->v[0][1] = v1[0][1];
588    line->v[1][1] = v2[0][1];
589 #endif
590
591    /* calculate the deltas */
592    plane = GET_PLANES(line);
593    plane[0].dcdy = x[0] - x[1];
594    plane[1].dcdy = x[1] - x[2];
595    plane[2].dcdy = x[2] - x[3];
596    plane[3].dcdy = x[3] - x[0];
597
598    plane[0].dcdx = y[0] - y[1];
599    plane[1].dcdx = y[1] - y[2];
600    plane[2].dcdx = y[2] - y[3];
601    plane[3].dcdx = y[3] - y[0];
602
603
604    /* Setup parameter interpolants:
605     */
606    info.a0 = GET_A0(&line->inputs);
607    info.dadx = GET_DADX(&line->inputs);
608    info.dady = GET_DADY(&line->inputs);
609    setup_line_coefficients(setup, &info); 
610
611    line->inputs.frontfacing = TRUE;
612    line->inputs.disable = FALSE;
613    line->inputs.opaque = FALSE;
614
615    for (i = 0; i < 4; i++) {
616
617       /* half-edge constants, will be interated over the whole render
618        * target.
619        */
620       plane[i].c = plane[i].dcdx * x[i] - plane[i].dcdy * y[i];
621
622       
623       /* correct for top-left vs. bottom-left fill convention.  
624        *
625        * note that we're overloading gl_rasterization_rules to mean
626        * both (0.5,0.5) pixel centers *and* bottom-left filling
627        * convention.
628        *
629        * GL actually has a top-left filling convention, but GL's
630        * notion of "top" differs from gallium's...
631        *
632        * Also, sometimes (in FBO cases) GL will render upside down
633        * to its usual method, in which case it will probably want
634        * to use the opposite, top-left convention.
635        */         
636       if (plane[i].dcdx < 0) {
637          /* both fill conventions want this - adjust for left edges */
638          plane[i].c++;            
639       }
640       else if (plane[i].dcdx == 0) {
641          if (setup->pixel_offset == 0) {
642             /* correct for top-left fill convention:
643              */
644             if (plane[i].dcdy > 0) plane[i].c++;
645          }
646          else {
647             /* correct for bottom-left fill convention:
648              */
649             if (plane[i].dcdy < 0) plane[i].c++;
650          }
651       }
652
653       plane[i].dcdx *= FIXED_ONE;
654       plane[i].dcdy *= FIXED_ONE;
655
656       /* find trivial reject offsets for each edge for a single-pixel
657        * sized block.  These will be scaled up at each recursive level to
658        * match the active blocksize.  Scaling in this way works best if
659        * the blocks are square.
660        */
661       plane[i].eo = 0;
662       if (plane[i].dcdx < 0) plane[i].eo -= plane[i].dcdx;
663       if (plane[i].dcdy > 0) plane[i].eo += plane[i].dcdy;
664    }
665
666
667    /* 
668     * When rasterizing scissored tris, use the intersection of the
669     * triangle bounding box and the scissor rect to generate the
670     * scissor planes.
671     *
672     * This permits us to cut off the triangle "tails" that are present
673     * in the intermediate recursive levels caused when two of the
674     * triangles edges don't diverge quickly enough to trivially reject
675     * exterior blocks from the triangle.
676     *
677     * It's not really clear if it's worth worrying about these tails,
678     * but since we generate the planes for each scissored tri, it's
679     * free to trim them in this case.
680     * 
681     * Note that otherwise, the scissor planes only vary in 'C' value,
682     * and even then only on state-changes.  Could alternatively store
683     * these planes elsewhere.
684     */
685    if (nr_planes == 8) {
686       const struct u_rect *scissor = &setup->scissor;
687
688       plane[4].dcdx = -1;
689       plane[4].dcdy = 0;
690       plane[4].c = 1-scissor->x0;
691       plane[4].eo = 1;
692
693       plane[5].dcdx = 1;
694       plane[5].dcdy = 0;
695       plane[5].c = scissor->x1+1;
696       plane[5].eo = 0;
697
698       plane[6].dcdx = 0;
699       plane[6].dcdy = 1;
700       plane[6].c = 1-scissor->y0;
701       plane[6].eo = 1;
702
703       plane[7].dcdx = 0;
704       plane[7].dcdy = -1;
705       plane[7].c = scissor->y1+1;
706       plane[7].eo = 0;
707    }
708
709    return lp_setup_bin_triangle(setup, line, &bbox, nr_planes);
710 }
711
712
713 static void lp_setup_line( struct lp_setup_context *setup,
714                            const float (*v0)[4],
715                            const float (*v1)[4] )
716 {
717    if (!try_setup_line( setup, v0, v1 ))
718    {
719       if (!lp_setup_flush_and_restart(setup))
720          return;
721
722       if (!try_setup_line( setup, v0, v1 ))
723          return;
724    }
725 }
726
727
728 void lp_setup_choose_line( struct lp_setup_context *setup ) 
729
730    setup->line = lp_setup_line;
731 }
732
733