llvmpipe: native line rasterization with correct pixel rasterization
[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
39 #define NUM_CHANNELS 4
40
41
42 static const int step_scissor_minx[16] = {
43 0, 1, 0, 1,
44 2, 3, 2, 3,
45 0, 1, 0, 1,
46 2, 3, 2, 3
47 };
48
49 static const int step_scissor_maxx[16] = {
50 0, -1, 0, -1,
51 -2, -3, -2, -3,
52 0, -1, 0, -1,
53 -2, -3, -2, -3
54 };
55
56 static const int step_scissor_miny[16] = {
57 0, 0, 1, 1,
58 0, 0, 1, 1,
59 2, 2, 3, 3,
60 2, 2, 3, 3
61 };
62
63 static const int step_scissor_maxy[16] = {
64 0, 0, -1, -1,
65 0, 0, -1, -1,
66 -2, -2, -3, -3,
67 -2, -2, -3, -3
68 };
69
70
71
72 /**
73 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
74 */
75 static void constant_coef( struct lp_setup_context *setup,
76 struct lp_rast_triangle *tri,
77 unsigned slot,
78 const float value,
79 unsigned i )
80 {
81 tri->inputs.a0[slot][i] = value;
82 tri->inputs.dadx[slot][i] = 0.0f;
83 tri->inputs.dady[slot][i] = 0.0f;
84 }
85
86
87 /**
88 * Compute a0, dadx and dady for a linearly interpolated coefficient,
89 * for a triangle.
90 */
91 static void linear_coef( struct lp_setup_context *setup,
92 struct lp_rast_triangle *tri,
93 float oneoverarea,
94 unsigned slot,
95 const float (*v1)[4],
96 const float (*v2)[4],
97 unsigned vert_attr,
98 unsigned i)
99 {
100 float a1 = v1[vert_attr][i];
101 float a2 = v2[vert_attr][i];
102
103 float da21 = a1 - a2;
104 float dadx = da21 * tri->dx * oneoverarea;
105 float dady = da21 * tri->dy * oneoverarea;
106
107 tri->inputs.dadx[slot][i] = dadx;
108 tri->inputs.dady[slot][i] = dady;
109
110 tri->inputs.a0[slot][i] = (a1 -
111 (dadx * (v1[0][0] - setup->pixel_offset) +
112 dady * (v1[0][1] - setup->pixel_offset)));
113 }
114
115
116 /**
117 * Compute a0, dadx and dady for a perspective-corrected interpolant,
118 * for a triangle.
119 * We basically multiply the vertex value by 1/w before computing
120 * the plane coefficients (a0, dadx, dady).
121 * Later, when we compute the value at a particular fragment position we'll
122 * divide the interpolated value by the interpolated W at that fragment.
123 */
124 static void perspective_coef( struct lp_setup_context *setup,
125 struct lp_rast_triangle *tri,
126 float oneoverarea,
127 unsigned slot,
128 const float (*v1)[4],
129 const float (*v2)[4],
130 unsigned vert_attr,
131 unsigned i)
132 {
133 /* premultiply by 1/w (v[0][3] is always 1/w):
134 */
135 float a1 = v1[vert_attr][i] * v1[0][3];
136 float a2 = v2[vert_attr][i] * v2[0][3];
137
138 float da21 = a1 - a2;
139 float dadx = da21 * tri->dx * oneoverarea;
140 float dady = da21 * tri->dy * oneoverarea;
141
142 tri->inputs.dadx[slot][i] = dadx;
143 tri->inputs.dady[slot][i] = dady;
144
145 tri->inputs.a0[slot][i] = (a1 -
146 (dadx * (v1[0][0] - setup->pixel_offset) +
147 dady * (v1[0][1] - setup->pixel_offset)));
148 }
149
150 /**
151 * Compute the tri->coef[] array dadx, dady, a0 values.
152 */
153 static void setup_line_coefficients( struct lp_setup_context *setup,
154 struct lp_rast_triangle *tri,
155 float oneoverarea,
156 const float (*v1)[4],
157 const float (*v2)[4])
158 {
159 unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ;
160 unsigned slot;
161
162 /* setup interpolation for all the remaining attributes:
163 */
164 for (slot = 0; slot < setup->fs.nr_inputs; slot++) {
165 unsigned vert_attr = setup->fs.input[slot].src_index;
166 unsigned usage_mask = setup->fs.input[slot].usage_mask;
167 unsigned i;
168
169 switch (setup->fs.input[slot].interp) {
170 case LP_INTERP_CONSTANT:
171 if (setup->flatshade_first) {
172 for (i = 0; i < NUM_CHANNELS; i++)
173 if (usage_mask & (1 << i))
174 constant_coef(setup, tri, slot+1, v1[vert_attr][i], i);
175 }
176 else {
177 for (i = 0; i < NUM_CHANNELS; i++)
178 if (usage_mask & (1 << i))
179 constant_coef(setup, tri, slot+1, v2[vert_attr][i], i);
180 }
181 break;
182
183 case LP_INTERP_LINEAR:
184 for (i = 0; i < NUM_CHANNELS; i++)
185 if (usage_mask & (1 << i))
186 linear_coef(setup, tri, oneoverarea, slot+1, v1, v2, vert_attr, i);
187 break;
188
189 case LP_INTERP_PERSPECTIVE:
190 for (i = 0; i < NUM_CHANNELS; i++)
191 if (usage_mask & (1 << i))
192 perspective_coef(setup, tri, oneoverarea, slot+1, v1, v2, vert_attr, i);
193 fragcoord_usage_mask |= TGSI_WRITEMASK_W;
194 break;
195
196 case LP_INTERP_POSITION:
197 /*
198 * The generated pixel interpolators will pick up the coeffs from
199 * slot 0, so all need to ensure that the usage mask is covers all
200 * usages.
201 */
202 fragcoord_usage_mask |= usage_mask;
203 break;
204
205 default:
206 assert(0);
207 }
208 }
209
210 /* The internal position input is in slot zero:
211 */
212 lp_setup_fragcoord_coef(setup, tri, oneoverarea, 0, v1, v2, v2,
213 fragcoord_usage_mask);
214 }
215
216
217
218 static INLINE int subpixel_snap( float a )
219 {
220 return util_iround(FIXED_ONE * a);
221 }
222
223
224 /**
225 * Print line vertex attribs (for debug).
226 */
227 static void
228 print_line(struct lp_setup_context *setup,
229 const float (*v1)[4],
230 const float (*v2)[4])
231 {
232 uint i;
233
234 debug_printf("llvmpipe line\n");
235 for (i = 0; i < 1 + setup->fs.nr_inputs; i++) {
236 debug_printf(" v1[%d]: %f %f %f %f\n", i,
237 v1[i][0], v1[i][1], v1[i][2], v1[i][3]);
238 }
239 for (i = 0; i < 1 + setup->fs.nr_inputs; i++) {
240 debug_printf(" v2[%d]: %f %f %f %f\n", i,
241 v2[i][0], v2[i][1], v2[i][2], v2[i][3]);
242 }
243 }
244
245
246 static INLINE boolean sign(float x){
247 return x >= 0;
248 }
249
250
251 static void
252 lp_setup_line( struct lp_setup_context *setup,
253 const float (*v1)[4],
254 const float (*v2)[4])
255 {
256 struct lp_scene *scene = lp_setup_get_current_scene(setup);
257 struct lp_rast_triangle *line;
258 float oneoverarea;
259 float width = MAX2(1.0, setup->line_width);
260 int minx, maxx, miny, maxy;
261 int ix0, ix1, iy0, iy1;
262 unsigned tri_bytes;
263 int x[4];
264 int y[4];
265 int i;
266 int nr_planes = 4;
267 boolean opaque;
268
269 /* linewidth should be interpreted as integer */
270 int fixed_width = subpixel_snap(round(width));
271
272 float xdiamond_offset=0;
273 float ydiamond_offset=0;
274 float xdiamond_offset_end=0;
275 float ydiamond_offset_end=0;
276
277 float x1diff;
278 float y1diff;
279 float x2diff;
280 float y2diff;
281
282 boolean draw_start;
283 boolean draw_end;
284 boolean will_draw_start;
285 boolean will_draw_end;
286
287 if (0)
288 print_line(setup, v1, v2);
289
290 if (setup->scissor_test) {
291 nr_planes = 8;
292 }
293 else {
294 nr_planes = 4;
295 }
296
297 line = lp_setup_alloc_triangle(scene,
298 setup->fs.nr_inputs,
299 nr_planes,
300 &tri_bytes);
301 if (!line)
302 return;
303
304 #ifdef DEBUG
305 line->v[0][0] = v1[0][0];
306 line->v[1][0] = v2[0][0];
307 line->v[0][1] = v1[0][1];
308 line->v[1][1] = v2[0][1];
309 #endif
310
311 line->dx = v1[0][0] - v2[0][0];
312 line->dy = v1[0][1] - v2[0][1];
313
314 /* X-MAJOR LINE */
315 if (fabsf(line->dx) >= fabsf(line->dy)) {
316
317 x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5;
318 y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5;
319 x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5;
320 y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5;
321
322 if (y2diff==-0.5 && line->dy<0){
323 y2diff = 0.5;
324 }
325
326 /*
327 * Diamond exit rule test for starting point
328 */
329 if (fabsf(x1diff) + fabsf(y1diff) < 0.5) {
330 draw_start = TRUE;
331 }
332 else if (sign(x1diff) == sign(-line->dx)) {
333 draw_start = FALSE;
334 }
335 else if (sign(-y1diff) != sign(line->dy)) {
336 draw_start = TRUE;
337 }
338 else {
339 /* do intersection test */
340 float yintersect = v1[0][1] + x1diff*((float)line->dy/(float)line->dx);
341 if (yintersect < ceil(v1[0][1]) && yintersect > floor(v1[0][1])){
342 draw_start = TRUE;
343 }
344 else draw_start = FALSE;
345 }
346
347
348 /*
349 * Diamond exit rule test for ending point
350 */
351 if (fabsf(x2diff) + fabsf(y2diff) < 0.5) {
352 draw_end = FALSE;
353 }
354 else if (sign(x2diff) != sign(-line->dx)) {
355 draw_end = FALSE;
356 }
357 else if (sign(-y2diff) == sign(line->dy)) {
358 draw_end = TRUE;
359 }
360 else {
361 /* do intersection test */
362 float yintersect = v2[0][1] + x2diff*((float)line->dy/(float)line->dx);
363 if (yintersect < ceil(v2[0][1]) && yintersect > floor(v2[0][1])){
364 draw_end = TRUE;
365 }
366 else draw_end = FALSE;
367 }
368
369 /* Are we already drawing start/end?
370 */
371 will_draw_start = sign(-x1diff) != sign(line->dx);
372 will_draw_end = (sign(x2diff) == sign(-line->dx)) || x2diff==0;
373
374 if (line->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 line->dx = -line->dx;
380 line->dy = -line->dy;
381 /* Otherwise shift planes appropriately */
382 if (will_draw_start != draw_start) {
383 xdiamond_offset_end = - x1diff - 0.5;
384 ydiamond_offset_end = xdiamond_offset_end*(float)line->dy/(float)line->dx;
385
386 }
387 if (will_draw_end != draw_end) {
388 xdiamond_offset = - x2diff - 0.5;
389 ydiamond_offset = xdiamond_offset*(float)line->dy/(float)line->dx;
390 }
391
392 }
393 else{
394 /* Otherwise shift planes appropriately */
395 if (will_draw_start != draw_start) {
396 xdiamond_offset = - x1diff + 0.5;
397 ydiamond_offset = xdiamond_offset*(float)line->dy/(float)line->dx;
398 }
399 if (will_draw_end != draw_end) {
400 xdiamond_offset_end = - x2diff + 0.5;
401 ydiamond_offset_end = xdiamond_offset_end*(float)line->dy/(float)line->dx;
402 }
403 }
404
405 /* x/y positions in fixed point */
406 x[0] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset);
407 x[1] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset);
408 x[2] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset);
409 x[3] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset);
410
411 y[0] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset) - fixed_width/2;
412 y[1] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset) - fixed_width/2;
413 y[2] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset) + fixed_width/2;
414 y[3] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset) + fixed_width/2;
415
416 }
417
418
419 else{
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 && line->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(line->dy)) {
437 draw_start = FALSE;
438 }
439 else if (sign(x1diff) != sign(-line->dx)) {
440 draw_start = TRUE;
441 }
442 else {
443 /* do intersection test */
444 float xintersect = v1[0][0] + y1diff*((float)line->dx/(float)line->dy);
445 if (xintersect < ceil(v1[0][0]) && xintersect > floor(v1[0][0])){
446 draw_start = TRUE;
447 }
448 else draw_start = FALSE;
449 }
450
451 /*
452 * Diamond exit rule test for ending point
453 */
454 if (fabsf(x2diff) + fabsf(y2diff) < 0.5) {
455 draw_end = FALSE;
456 }
457 else if (sign(-y2diff) != sign(line->dy) ) {
458 draw_end = FALSE;
459 }
460 else if (sign(x2diff) == sign(-line->dx) ) {
461 draw_end = TRUE;
462 }
463 else {
464 /* do intersection test */
465 float xintersect = v2[0][0] + y2diff*((float)line->dx/(float)line->dy);
466 if (xintersect < ceil(v2[0][0]) && xintersect > floor(v2[0][0])){
467 draw_end = TRUE;
468 }
469 else draw_end = FALSE;
470 }
471
472 /* Are we already drawing start/end?
473 */
474 will_draw_start = sign(y1diff) == sign(line->dy);
475 will_draw_end = (sign(-y2diff) == sign(line->dy)) || y2diff==0;
476
477 if (line->dy > 0) {
478 /* if v2 is on top of v1, swap pointers */
479 const float (*temp)[4] = v1;
480 v1 = v2;
481 v2 = temp;
482 line->dx = -line->dx;
483 line->dy = -line->dy;
484
485 /* Otherwise shift planes appropriately */
486 if (will_draw_start != draw_start) {
487 ydiamond_offset_end = - y1diff + 0.5;
488 xdiamond_offset_end = ydiamond_offset_end*(float)line->dx/(float)line->dy;
489 }
490 if (will_draw_end != draw_end) {
491 ydiamond_offset = - y2diff + 0.5;
492 xdiamond_offset = ydiamond_offset*(float)line->dx/(float)line->dy;
493 }
494 }
495
496 else{
497 /* Otherwise shift planes appropriately */
498 if (will_draw_start != draw_start) {
499 ydiamond_offset = - y1diff - 0.5;
500 xdiamond_offset = ydiamond_offset*(float)line->dx/(float)line->dy;
501
502 }
503 if (will_draw_end != draw_end) {
504 ydiamond_offset_end = - y2diff - 0.5;
505 xdiamond_offset_end = ydiamond_offset_end*(float)line->dx/(float)line->dy;
506 }
507 }
508
509 /* x/y positions in fixed point */
510 x[0] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset) - fixed_width/2;
511 x[1] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset) - fixed_width/2;
512 x[2] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset) + fixed_width/2;
513 x[3] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset) + fixed_width/2;
514
515 y[0] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset);
516 y[1] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset);
517 y[2] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset);
518 y[3] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset);
519 }
520
521
522 /* calculate the deltas */
523 line->plane[0].dcdy = x[0] - x[1];
524 line->plane[1].dcdy = x[1] - x[2];
525 line->plane[2].dcdy = x[2] - x[3];
526 line->plane[3].dcdy = x[3] - x[0];
527
528 line->plane[0].dcdx = y[0] - y[1];
529 line->plane[1].dcdx = y[1] - y[2];
530 line->plane[2].dcdx = y[2] - y[3];
531 line->plane[3].dcdx = y[3] - y[0];
532
533
534 LP_COUNT(nr_tris);
535
536
537 /* Bounding rectangle (in pixels) */
538 {
539 /* Yes this is necessary to accurately calculate bounding boxes
540 * with the two fill-conventions we support. GL (normally) ends
541 * up needing a bottom-left fill convention, which requires
542 * slightly different rounding.
543 */
544 int adj = (setup->pixel_offset != 0) ? 1 : 0;
545
546 minx = (MIN4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER;
547 maxx = (MAX4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER;
548 miny = (MIN4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
549 maxy = (MAX4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
550 }
551
552 if (setup->scissor_test) {
553 minx = MAX2(minx, setup->scissor.current.minx);
554 maxx = MIN2(maxx, setup->scissor.current.maxx);
555 miny = MAX2(miny, setup->scissor.current.miny);
556 maxy = MIN2(maxy, setup->scissor.current.maxy);
557 }
558 else {
559 minx = MAX2(minx, 0);
560 miny = MAX2(miny, 0);
561 maxx = MIN2(maxx, scene->fb.width);
562 maxy = MIN2(maxy, scene->fb.height);
563 }
564
565
566 if (miny >= maxy || minx >= maxx) {
567 lp_scene_putback_data( scene, tri_bytes );
568 return;
569 }
570
571 oneoverarea = 1.0f / (line->dx * line->dx + line->dy * line->dy);
572
573 /* Setup parameter interpolants:
574 */
575 setup_line_coefficients( setup, line, oneoverarea, v1, v2);
576
577 for (i = 0; i < 4; i++) {
578 struct lp_rast_plane *plane = &line->plane[i];
579
580 /* half-edge constants, will be interated over the whole render
581 * target.
582 */
583 plane->c = plane->dcdx * x[i] - plane->dcdy * y[i];
584
585
586 /* correct for top-left vs. bottom-left fill convention.
587 *
588 * note that we're overloading gl_rasterization_rules to mean
589 * both (0.5,0.5) pixel centers *and* bottom-left filling
590 * convention.
591 *
592 * GL actually has a top-left filling convention, but GL's
593 * notion of "top" differs from gallium's...
594 *
595 * Also, sometimes (in FBO cases) GL will render upside down
596 * to its usual method, in which case it will probably want
597 * to use the opposite, top-left convention.
598 */
599 if (plane->dcdx < 0) {
600 /* both fill conventions want this - adjust for left edges */
601 plane->c++;
602 }
603 else if (plane->dcdx == 0) {
604 if (setup->pixel_offset == 0) {
605 /* correct for top-left fill convention:
606 */
607 if (plane->dcdy > 0) plane->c++;
608 }
609 else {
610 /* correct for bottom-left fill convention:
611 */
612 if (plane->dcdy < 0) plane->c++;
613 }
614 }
615
616 plane->dcdx *= FIXED_ONE;
617 plane->dcdy *= FIXED_ONE;
618
619 /* find trivial reject offsets for each edge for a single-pixel
620 * sized block. These will be scaled up at each recursive level to
621 * match the active blocksize. Scaling in this way works best if
622 * the blocks are square.
623 */
624 plane->eo = 0;
625 if (plane->dcdx < 0) plane->eo -= plane->dcdx;
626 if (plane->dcdy > 0) plane->eo += plane->dcdy;
627
628 /* Calculate trivial accept offsets from the above.
629 */
630 plane->ei = plane->dcdy - plane->dcdx - plane->eo;
631
632 plane->step = line->step[i];
633
634 /* Fill in the inputs.step[][] arrays.
635 * We've manually unrolled some loops here.
636 */
637 #define SETUP_STEP(j, x, y) \
638 line->step[i][j] = y * plane->dcdy - x * plane->dcdx
639
640 SETUP_STEP(0, 0, 0);
641 SETUP_STEP(1, 1, 0);
642 SETUP_STEP(2, 0, 1);
643 SETUP_STEP(3, 1, 1);
644
645 SETUP_STEP(4, 2, 0);
646 SETUP_STEP(5, 3, 0);
647 SETUP_STEP(6, 2, 1);
648 SETUP_STEP(7, 3, 1);
649
650 SETUP_STEP(8, 0, 2);
651 SETUP_STEP(9, 1, 2);
652 SETUP_STEP(10, 0, 3);
653 SETUP_STEP(11, 1, 3);
654
655 SETUP_STEP(12, 2, 2);
656 SETUP_STEP(13, 3, 2);
657 SETUP_STEP(14, 2, 3);
658 SETUP_STEP(15, 3, 3);
659 #undef STEP
660 }
661
662
663 /*
664 * When rasterizing scissored tris, use the intersection of the
665 * triangle bounding box and the scissor rect to generate the
666 * scissor planes.
667 *
668 * This permits us to cut off the triangle "tails" that are present
669 * in the intermediate recursive levels caused when two of the
670 * triangles edges don't diverge quickly enough to trivially reject
671 * exterior blocks from the triangle.
672 *
673 * It's not really clear if it's worth worrying about these tails,
674 * but since we generate the planes for each scissored tri, it's
675 * free to trim them in this case.
676 *
677 * Note that otherwise, the scissor planes only vary in 'C' value,
678 * and even then only on state-changes. Could alternatively store
679 * these planes elsewhere.
680 */
681 if (nr_planes == 8) {
682 line->plane[4].step = step_scissor_maxx;
683 line->plane[4].dcdx = 1;
684 line->plane[4].dcdy = 0;
685 line->plane[4].c = maxx;
686 line->plane[4].ei = -1;
687 line->plane[4].eo = 0;
688
689 line->plane[5].step = step_scissor_miny;
690 line->plane[5].dcdx = 0;
691 line->plane[5].dcdy = 1;
692 line->plane[5].c = 1-miny;
693 line->plane[5].ei = 0;
694 line->plane[5].eo = 1;
695
696 line->plane[6].step = step_scissor_maxy;
697 line->plane[6].dcdx = 0;
698 line->plane[6].dcdy = -1;
699 line->plane[6].c = maxy;
700 line->plane[6].ei = -1;
701 line->plane[6].eo = 0;
702
703 line->plane[7].step = step_scissor_minx;
704 line->plane[7].dcdx = -1;
705 line->plane[7].dcdy = 0;
706 line->plane[7].c = 1-minx;
707 line->plane[7].ei = 0;
708 line->plane[7].eo = 1;
709 }
710
711
712 /*
713 * All fields of 'line' are now set. The remaining code here is
714 * concerned with binning.
715 */
716
717 /* Convert to tile coordinates, and inclusive ranges:
718 */
719 ix0 = minx / TILE_SIZE;
720 iy0 = miny / TILE_SIZE;
721 ix1 = (maxx-1) / TILE_SIZE;
722 iy1 = (maxy-1) / TILE_SIZE;
723
724 /*
725 * Clamp to framebuffer size
726 */
727 assert(ix0 == MAX2(ix0, 0));
728 assert(iy0 == MAX2(iy0, 0));
729 assert(ix1 == MIN2(ix1, scene->tiles_x - 1));
730 assert(iy1 == MIN2(iy1, scene->tiles_y - 1));
731
732 /* Determine which tile(s) intersect the triangle's bounding box
733 */
734 if (iy0 == iy1 && ix0 == ix1)
735 {
736 /* Triangle is contained in a single tile:
737 */
738 lp_scene_bin_command( scene, ix0, iy0,
739 lp_rast_tri_tab[nr_planes],
740 lp_rast_arg_triangle(line, (1<<nr_planes)-1) );
741 }
742 else
743 {
744 int c[8];
745 int ei[8];
746 int eo[8];
747 int xstep[8];
748 int ystep[8];
749 int x, y;
750 int is_blit = -1; /* undetermined */
751
752 for (i = 0; i < nr_planes; i++) {
753 c[i] = (line->plane[i].c +
754 line->plane[i].dcdy * iy0 * TILE_SIZE -
755 line->plane[i].dcdx * ix0 * TILE_SIZE);
756
757 ei[i] = line->plane[i].ei << TILE_ORDER;
758 eo[i] = line->plane[i].eo << TILE_ORDER;
759 xstep[i] = -(line->plane[i].dcdx << TILE_ORDER);
760 ystep[i] = line->plane[i].dcdy << TILE_ORDER;
761 }
762
763
764
765 /* Test tile-sized blocks against the triangle.
766 * Discard blocks fully outside the tri. If the block is fully
767 * contained inside the tri, bin an lp_rast_shade_tile command.
768 * Else, bin a lp_rast_triangle command.
769 */
770 for (y = iy0; y <= iy1; y++)
771 {
772 boolean in = FALSE; /* are we inside the triangle? */
773 int cx[8];
774
775 for (i = 0; i < nr_planes; i++)
776 cx[i] = c[i];
777
778 for (x = ix0; x <= ix1; x++)
779 {
780 int out = 0;
781 int partial = 0;
782
783 for (i = 0; i < nr_planes; i++) {
784 int planeout = cx[i] + eo[i];
785 int planepartial = cx[i] + ei[i] - 1;
786 out |= (planeout >> 31);
787 partial |= (planepartial >> 31) & (1<<i);
788 }
789 if (out) {
790 /* do nothing */
791 if (in)
792 break; /* exiting triangle, all done with this row */
793 LP_COUNT(nr_empty_64);
794 }
795 else if (partial) {
796 /* Not trivially accepted by at least one plane -
797 * rasterize/shade partial tile
798 */
799 int count = util_bitcount(partial);
800 in = TRUE;
801 lp_scene_bin_command( scene, x, y,
802 lp_rast_tri_tab[count],
803 lp_rast_arg_triangle(line, partial) );
804
805 LP_COUNT(nr_partially_covered_64);
806 }
807 else {
808 /* triangle covers the whole tile- shade whole tile */
809 LP_COUNT(nr_fully_covered_64);
810 in = TRUE;
811 /* leverages on existing code in lp_setup_tri.c */
812 do_triangle_ccw_whole_tile(setup, scene, line, x, y,
813 opaque, &is_blit);
814 }
815
816 /* Iterate cx values across the region:
817 */
818 for (i = 0; i < nr_planes; i++)
819 cx[i] += xstep[i];
820 }
821
822 /* Iterate c values down the region:
823 */
824 for (i = 0; i < nr_planes; i++)
825 c[i] += ystep[i];
826 }
827 }
828 }
829
830
831 void lp_setup_choose_line( struct lp_setup_context *setup )
832 {
833 setup->line = lp_setup_line;
834 }
835
836