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