1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
29 * Binning code for lines
32 #include "util/u_math.h"
33 #include "util/u_memory.h"
35 #include "lp_setup_context.h"
37 #include "lp_state_fs.h"
39 #define NUM_CHANNELS 4
44 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
46 static void constant_coef( struct lp_setup_context
*setup
,
47 struct lp_rast_triangle
*tri
,
52 tri
->inputs
.a0
[slot
][i
] = value
;
53 tri
->inputs
.dadx
[slot
][i
] = 0.0f
;
54 tri
->inputs
.dady
[slot
][i
] = 0.0f
;
59 * Compute a0, dadx and dady for a linearly interpolated coefficient,
62 static void linear_coef( struct lp_setup_context
*setup
,
63 struct lp_rast_triangle
*tri
,
71 float a1
= v1
[vert_attr
][i
];
72 float a2
= v2
[vert_attr
][i
];
75 float dadx
= da21
* tri
->dx
* oneoverarea
;
76 float dady
= da21
* tri
->dy
* oneoverarea
;
78 tri
->inputs
.dadx
[slot
][i
] = dadx
;
79 tri
->inputs
.dady
[slot
][i
] = dady
;
81 tri
->inputs
.a0
[slot
][i
] = (a1
-
82 (dadx
* (v1
[0][0] - setup
->pixel_offset
) +
83 dady
* (v1
[0][1] - setup
->pixel_offset
)));
88 * Compute a0, dadx and dady for a perspective-corrected interpolant,
90 * We basically multiply the vertex value by 1/w before computing
91 * the plane coefficients (a0, dadx, dady).
92 * Later, when we compute the value at a particular fragment position we'll
93 * divide the interpolated value by the interpolated W at that fragment.
95 static void perspective_coef( struct lp_setup_context
*setup
,
96 struct lp_rast_triangle
*tri
,
100 const float (*v2
)[4],
104 /* premultiply by 1/w (v[0][3] is always 1/w):
106 float a1
= v1
[vert_attr
][i
] * v1
[0][3];
107 float a2
= v2
[vert_attr
][i
] * v2
[0][3];
109 float da21
= a1
- a2
;
110 float dadx
= da21
* tri
->dx
* oneoverarea
;
111 float dady
= da21
* tri
->dy
* oneoverarea
;
113 tri
->inputs
.dadx
[slot
][i
] = dadx
;
114 tri
->inputs
.dady
[slot
][i
] = dady
;
116 tri
->inputs
.a0
[slot
][i
] = (a1
-
117 (dadx
* (v1
[0][0] - setup
->pixel_offset
) +
118 dady
* (v1
[0][1] - setup
->pixel_offset
)));
122 setup_fragcoord_coef( struct lp_setup_context
*setup
,
123 struct lp_rast_triangle
*tri
,
126 const float (*v1
)[4],
127 const float (*v2
)[4],
131 if (usage_mask
& TGSI_WRITEMASK_X
) {
132 tri
->inputs
.a0
[slot
][0] = 0.0;
133 tri
->inputs
.dadx
[slot
][0] = 1.0;
134 tri
->inputs
.dady
[slot
][0] = 0.0;
138 if (usage_mask
& TGSI_WRITEMASK_Y
) {
139 tri
->inputs
.a0
[slot
][1] = 0.0;
140 tri
->inputs
.dadx
[slot
][1] = 0.0;
141 tri
->inputs
.dady
[slot
][1] = 1.0;
145 if (usage_mask
& TGSI_WRITEMASK_Z
) {
146 linear_coef(setup
, tri
, oneoverarea
, slot
, v1
, v2
, 0, 2);
150 if (usage_mask
& TGSI_WRITEMASK_W
) {
151 linear_coef(setup
, tri
, oneoverarea
, slot
, v1
, v2
, 0, 3);
156 * Compute the tri->coef[] array dadx, dady, a0 values.
158 static void setup_line_coefficients( struct lp_setup_context
*setup
,
159 struct lp_rast_triangle
*tri
,
161 const float (*v1
)[4],
162 const float (*v2
)[4])
164 unsigned fragcoord_usage_mask
= TGSI_WRITEMASK_XYZ
;
167 /* setup interpolation for all the remaining attributes:
169 for (slot
= 0; slot
< setup
->fs
.nr_inputs
; slot
++) {
170 unsigned vert_attr
= setup
->fs
.input
[slot
].src_index
;
171 unsigned usage_mask
= setup
->fs
.input
[slot
].usage_mask
;
174 switch (setup
->fs
.input
[slot
].interp
) {
175 case LP_INTERP_CONSTANT
:
176 if (setup
->flatshade_first
) {
177 for (i
= 0; i
< NUM_CHANNELS
; i
++)
178 if (usage_mask
& (1 << i
))
179 constant_coef(setup
, tri
, slot
+1, v1
[vert_attr
][i
], i
);
182 for (i
= 0; i
< NUM_CHANNELS
; i
++)
183 if (usage_mask
& (1 << i
))
184 constant_coef(setup
, tri
, slot
+1, v2
[vert_attr
][i
], i
);
188 case LP_INTERP_LINEAR
:
189 for (i
= 0; i
< NUM_CHANNELS
; i
++)
190 if (usage_mask
& (1 << i
))
191 linear_coef(setup
, tri
, oneoverarea
, slot
+1, v1
, v2
, vert_attr
, i
);
194 case LP_INTERP_PERSPECTIVE
:
195 for (i
= 0; i
< NUM_CHANNELS
; i
++)
196 if (usage_mask
& (1 << i
))
197 perspective_coef(setup
, tri
, oneoverarea
, slot
+1, v1
, v2
, vert_attr
, i
);
198 fragcoord_usage_mask
|= TGSI_WRITEMASK_W
;
201 case LP_INTERP_POSITION
:
203 * The generated pixel interpolators will pick up the coeffs from
204 * slot 0, so all need to ensure that the usage mask is covers all
207 fragcoord_usage_mask
|= usage_mask
;
215 /* The internal position input is in slot zero:
217 setup_fragcoord_coef(setup
, tri
, oneoverarea
, 0, v1
, v2
,
218 fragcoord_usage_mask
);
223 static INLINE
int subpixel_snap( float a
)
225 return util_iround(FIXED_ONE
* a
);
230 * Print line vertex attribs (for debug).
233 print_line(struct lp_setup_context
*setup
,
234 const float (*v1
)[4],
235 const float (*v2
)[4])
239 debug_printf("llvmpipe line\n");
240 for (i
= 0; i
< 1 + setup
->fs
.nr_inputs
; i
++) {
241 debug_printf(" v1[%d]: %f %f %f %f\n", i
,
242 v1
[i
][0], v1
[i
][1], v1
[i
][2], v1
[i
][3]);
244 for (i
= 0; i
< 1 + setup
->fs
.nr_inputs
; i
++) {
245 debug_printf(" v2[%d]: %f %f %f %f\n", i
,
246 v2
[i
][0], v2
[i
][1], v2
[i
][2], v2
[i
][3]);
251 static INLINE boolean
sign(float x
){
256 /* Used on positive floats only:
258 static INLINE
float fracf(float f
)
260 return f
- floorf(f
);
266 lp_setup_line( struct lp_setup_context
*setup
,
267 const float (*v1
)[4],
268 const float (*v2
)[4])
270 struct lp_scene
*scene
= lp_setup_get_current_scene(setup
);
271 struct lp_rast_triangle
*line
;
273 float width
= MAX2(1.0, setup
->line_width
);
281 /* linewidth should be interpreted as integer */
282 int fixed_width
= subpixel_snap(round(width
));
286 float x_offset_end
=0;
287 float y_offset_end
=0;
297 boolean will_draw_start
;
298 boolean will_draw_end
;
301 print_line(setup
, v1
, v2
);
303 if (setup
->scissor_test
) {
311 dx
= v1
[0][0] - v2
[0][0];
312 dy
= v1
[0][1] - v2
[0][1];
315 if (fabsf(dx
) >= fabsf(dy
)) {
316 float dydx
= dy
/ dx
;
318 x1diff
= v1
[0][0] - (float) floor(v1
[0][0]) - 0.5;
319 y1diff
= v1
[0][1] - (float) floor(v1
[0][1]) - 0.5;
320 x2diff
= v2
[0][0] - (float) floor(v2
[0][0]) - 0.5;
321 y2diff
= v2
[0][1] - (float) floor(v2
[0][1]) - 0.5;
323 if (y2diff
==-0.5 && dy
<0){
328 * Diamond exit rule test for starting point
330 if (fabsf(x1diff
) + fabsf(y1diff
) < 0.5) {
333 else if (sign(x1diff
) == sign(-dx
)) {
336 else if (sign(-y1diff
) != sign(dy
)) {
340 /* do intersection test */
341 float yintersect
= fracf(v1
[0][1]) + x1diff
* dydx
;
342 draw_start
= (yintersect
< 1.0 && yintersect
> 0.0);
347 * Diamond exit rule test for ending point
349 if (fabsf(x2diff
) + fabsf(y2diff
) < 0.5) {
352 else if (sign(x2diff
) != sign(-dx
)) {
355 else if (sign(-y2diff
) == sign(dy
)) {
359 /* do intersection test */
360 float yintersect
= fracf(v2
[0][1]) + x2diff
* dydx
;
361 draw_end
= (yintersect
< 1.0 && yintersect
> 0.0);
364 /* Are we already drawing start/end?
366 will_draw_start
= sign(-x1diff
) != sign(dx
);
367 will_draw_end
= (sign(x2diff
) == sign(-dx
)) || x2diff
==0;
370 /* if v2 is to the right of v1, swap pointers */
371 const float (*temp
)[4] = v1
;
376 /* Otherwise shift planes appropriately */
377 if (will_draw_start
!= draw_start
) {
378 x_offset_end
= - x1diff
- 0.5;
379 y_offset_end
= x_offset_end
* dydx
;
382 if (will_draw_end
!= draw_end
) {
383 x_offset
= - x2diff
- 0.5;
384 y_offset
= x_offset
* dydx
;
389 /* Otherwise shift planes appropriately */
390 if (will_draw_start
!= draw_start
) {
391 x_offset
= - x1diff
+ 0.5;
392 y_offset
= x_offset
* dydx
;
394 if (will_draw_end
!= draw_end
) {
395 x_offset_end
= - x2diff
+ 0.5;
396 y_offset_end
= x_offset_end
* dydx
;
400 /* x/y positions in fixed point */
401 x
[0] = subpixel_snap(v1
[0][0] + x_offset
- setup
->pixel_offset
);
402 x
[1] = subpixel_snap(v2
[0][0] + x_offset_end
- setup
->pixel_offset
);
403 x
[2] = subpixel_snap(v2
[0][0] + x_offset_end
- setup
->pixel_offset
);
404 x
[3] = subpixel_snap(v1
[0][0] + x_offset
- setup
->pixel_offset
);
406 y
[0] = subpixel_snap(v1
[0][1] + y_offset
- setup
->pixel_offset
) - fixed_width
/2;
407 y
[1] = subpixel_snap(v2
[0][1] + y_offset_end
- setup
->pixel_offset
) - fixed_width
/2;
408 y
[2] = subpixel_snap(v2
[0][1] + y_offset_end
- setup
->pixel_offset
) + fixed_width
/2;
409 y
[3] = subpixel_snap(v1
[0][1] + y_offset
- setup
->pixel_offset
) + fixed_width
/2;
413 const float dxdy
= dx
/ dy
;
416 x1diff
= v1
[0][0] - (float) floor(v1
[0][0]) - 0.5;
417 y1diff
= v1
[0][1] - (float) floor(v1
[0][1]) - 0.5;
418 x2diff
= v2
[0][0] - (float) floor(v2
[0][0]) - 0.5;
419 y2diff
= v2
[0][1] - (float) floor(v2
[0][1]) - 0.5;
421 if (x2diff
==-0.5 && dx
<0) {
426 * Diamond exit rule test for starting point
428 if (fabsf(x1diff
) + fabsf(y1diff
) < 0.5) {
431 else if (sign(-y1diff
) == sign(dy
)) {
434 else if (sign(x1diff
) != sign(-dx
)) {
438 /* do intersection test */
439 float xintersect
= fracf(v1
[0][0]) + y1diff
* dxdy
;
440 draw_start
= (xintersect
< 1.0 && xintersect
> 0.0);
444 * Diamond exit rule test for ending point
446 if (fabsf(x2diff
) + fabsf(y2diff
) < 0.5) {
449 else if (sign(-y2diff
) != sign(dy
) ) {
452 else if (sign(x2diff
) == sign(-dx
) ) {
456 /* do intersection test */
457 float xintersect
= fracf(v2
[0][0]) + y2diff
* dxdy
;
458 draw_end
= (xintersect
< 1.0 && xintersect
> 0.0);
461 /* Are we already drawing start/end?
463 will_draw_start
= sign(y1diff
) == sign(dy
);
464 will_draw_end
= (sign(-y2diff
) == sign(dy
)) || y2diff
==0;
467 /* if v2 is on top of v1, swap pointers */
468 const float (*temp
)[4] = v1
;
474 /* Otherwise shift planes appropriately */
475 if (will_draw_start
!= draw_start
) {
476 y_offset_end
= - y1diff
+ 0.5;
477 x_offset_end
= y_offset_end
* dxdy
;
479 if (will_draw_end
!= draw_end
) {
480 y_offset
= - y2diff
+ 0.5;
481 x_offset
= y_offset
* dxdy
;
485 /* Otherwise shift planes appropriately */
486 if (will_draw_start
!= draw_start
) {
487 y_offset
= - y1diff
- 0.5;
488 x_offset
= y_offset
* dxdy
;
491 if (will_draw_end
!= draw_end
) {
492 y_offset_end
= - y2diff
- 0.5;
493 x_offset_end
= y_offset_end
* dxdy
;
497 /* x/y positions in fixed point */
498 x
[0] = subpixel_snap(v1
[0][0] + x_offset
- setup
->pixel_offset
) - fixed_width
/2;
499 x
[1] = subpixel_snap(v2
[0][0] + x_offset_end
- setup
->pixel_offset
) - fixed_width
/2;
500 x
[2] = subpixel_snap(v2
[0][0] + x_offset_end
- setup
->pixel_offset
) + fixed_width
/2;
501 x
[3] = subpixel_snap(v1
[0][0] + x_offset
- setup
->pixel_offset
) + fixed_width
/2;
503 y
[0] = subpixel_snap(v1
[0][1] + y_offset
- setup
->pixel_offset
);
504 y
[1] = subpixel_snap(v2
[0][1] + y_offset_end
- setup
->pixel_offset
);
505 y
[2] = subpixel_snap(v2
[0][1] + y_offset_end
- setup
->pixel_offset
);
506 y
[3] = subpixel_snap(v1
[0][1] + y_offset
- setup
->pixel_offset
);
514 /* Bounding rectangle (in pixels) */
516 /* Yes this is necessary to accurately calculate bounding boxes
517 * with the two fill-conventions we support. GL (normally) ends
518 * up needing a bottom-left fill convention, which requires
519 * slightly different rounding.
521 int adj
= (setup
->pixel_offset
!= 0) ? 1 : 0;
523 bbox
.x0
= (MIN4(x
[0], x
[1], x
[2], x
[3]) + (FIXED_ONE
-1)) >> FIXED_ORDER
;
524 bbox
.x1
= (MAX4(x
[0], x
[1], x
[2], x
[3]) + (FIXED_ONE
-1)) >> FIXED_ORDER
;
525 bbox
.y0
= (MIN4(y
[0], y
[1], y
[2], y
[3]) + (FIXED_ONE
-1) + adj
) >> FIXED_ORDER
;
526 bbox
.y1
= (MAX4(y
[0], y
[1], y
[2], y
[3]) + (FIXED_ONE
-1) + adj
) >> FIXED_ORDER
;
528 /* Inclusive coordinates:
534 if (bbox
.x1
< bbox
.x0
||
536 if (0) debug_printf("empty bounding box\n");
537 LP_COUNT(nr_culled_tris
);
541 if (!u_rect_test_intersection(&setup
->draw_region
, &bbox
)) {
542 if (0) debug_printf("offscreen\n");
543 LP_COUNT(nr_culled_tris
);
547 u_rect_find_intersection(&setup
->draw_region
, &bbox
);
549 line
= lp_setup_alloc_triangle(scene
,
557 line
->v
[0][0] = v1
[0][0];
558 line
->v
[1][0] = v2
[0][0];
559 line
->v
[0][1] = v1
[0][1];
560 line
->v
[1][1] = v2
[0][1];
566 /* calculate the deltas */
567 line
->plane
[0].dcdy
= x
[0] - x
[1];
568 line
->plane
[1].dcdy
= x
[1] - x
[2];
569 line
->plane
[2].dcdy
= x
[2] - x
[3];
570 line
->plane
[3].dcdy
= x
[3] - x
[0];
572 line
->plane
[0].dcdx
= y
[0] - y
[1];
573 line
->plane
[1].dcdx
= y
[1] - y
[2];
574 line
->plane
[2].dcdx
= y
[2] - y
[3];
575 line
->plane
[3].dcdx
= y
[3] - y
[0];
578 oneoverarea
= 1.0f
/ (dx
* dx
+ dy
* dy
);
580 /* Setup parameter interpolants:
582 setup_line_coefficients( setup
, line
, oneoverarea
, v1
, v2
);
584 line
->inputs
.facing
= 1.0F
;
585 line
->inputs
.state
= setup
->fs
.stored
;
587 for (i
= 0; i
< 4; i
++) {
588 struct lp_rast_plane
*plane
= &line
->plane
[i
];
590 /* half-edge constants, will be interated over the whole render
593 plane
->c
= plane
->dcdx
* x
[i
] - plane
->dcdy
* y
[i
];
596 /* correct for top-left vs. bottom-left fill convention.
598 * note that we're overloading gl_rasterization_rules to mean
599 * both (0.5,0.5) pixel centers *and* bottom-left filling
602 * GL actually has a top-left filling convention, but GL's
603 * notion of "top" differs from gallium's...
605 * Also, sometimes (in FBO cases) GL will render upside down
606 * to its usual method, in which case it will probably want
607 * to use the opposite, top-left convention.
609 if (plane
->dcdx
< 0) {
610 /* both fill conventions want this - adjust for left edges */
613 else if (plane
->dcdx
== 0) {
614 if (setup
->pixel_offset
== 0) {
615 /* correct for top-left fill convention:
617 if (plane
->dcdy
> 0) plane
->c
++;
620 /* correct for bottom-left fill convention:
622 if (plane
->dcdy
< 0) plane
->c
++;
626 plane
->dcdx
*= FIXED_ONE
;
627 plane
->dcdy
*= FIXED_ONE
;
629 /* find trivial reject offsets for each edge for a single-pixel
630 * sized block. These will be scaled up at each recursive level to
631 * match the active blocksize. Scaling in this way works best if
632 * the blocks are square.
635 if (plane
->dcdx
< 0) plane
->eo
-= plane
->dcdx
;
636 if (plane
->dcdy
> 0) plane
->eo
+= plane
->dcdy
;
638 /* Calculate trivial accept offsets from the above.
640 plane
->ei
= plane
->dcdy
- plane
->dcdx
- plane
->eo
;
645 * When rasterizing scissored tris, use the intersection of the
646 * triangle bounding box and the scissor rect to generate the
649 * This permits us to cut off the triangle "tails" that are present
650 * in the intermediate recursive levels caused when two of the
651 * triangles edges don't diverge quickly enough to trivially reject
652 * exterior blocks from the triangle.
654 * It's not really clear if it's worth worrying about these tails,
655 * but since we generate the planes for each scissored tri, it's
656 * free to trim them in this case.
658 * Note that otherwise, the scissor planes only vary in 'C' value,
659 * and even then only on state-changes. Could alternatively store
660 * these planes elsewhere.
662 if (nr_planes
== 8) {
663 line
->plane
[4].dcdx
= -1;
664 line
->plane
[4].dcdy
= 0;
665 line
->plane
[4].c
= 1-bbox
.x0
;
666 line
->plane
[4].ei
= 0;
667 line
->plane
[4].eo
= 1;
669 line
->plane
[5].dcdx
= 1;
670 line
->plane
[5].dcdy
= 0;
671 line
->plane
[5].c
= bbox
.x1
+1;
672 line
->plane
[5].ei
= -1;
673 line
->plane
[5].eo
= 0;
675 line
->plane
[6].dcdx
= 0;
676 line
->plane
[6].dcdy
= 1;
677 line
->plane
[6].c
= 1-bbox
.y0
;
678 line
->plane
[6].ei
= 0;
679 line
->plane
[6].eo
= 1;
681 line
->plane
[7].dcdx
= 0;
682 line
->plane
[7].dcdy
= -1;
683 line
->plane
[7].c
= bbox
.y1
+1;
684 line
->plane
[7].ei
= -1;
685 line
->plane
[7].eo
= 0;
688 lp_setup_bin_triangle(setup
, line
, &bbox
, nr_planes
);
692 void lp_setup_choose_line( struct lp_setup_context
*setup
)
694 setup
->line
= lp_setup_line
;