lp_setup_line.c revision b91553355f848f2174d53429699b116734781ad7
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
42static 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
49static 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
56static 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
63static 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 */
75static 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 */
91static 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 */
124static 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 */
153static 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
218static 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 */
227static void
228print_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
246static INLINE boolean sign(float x){
247   return x >= 0;
248}
249
250
251static void
252lp_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
831void lp_setup_choose_line( struct lp_setup_context *setup )
832{
833   setup->line = lp_setup_line;
834}
835
836
837