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