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