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"
38 #include "lp_state_setup.h"
39 #include "lp_context.h"
41 #define NUM_CHANNELS 4
59 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
61 static void constant_coef( struct lp_setup_context
*setup
,
62 struct lp_line_info
*info
,
67 info
->a0
[slot
][i
] = value
;
68 info
->dadx
[slot
][i
] = 0.0f
;
69 info
->dady
[slot
][i
] = 0.0f
;
74 * Compute a0, dadx and dady for a linearly interpolated coefficient,
77 static void linear_coef( struct lp_setup_context
*setup
,
78 struct lp_line_info
*info
,
83 float a1
= info
->v1
[vert_attr
][i
];
84 float a2
= info
->v2
[vert_attr
][i
];
87 float dadx
= da21
* info
->dx
* info
->oneoverarea
;
88 float dady
= da21
* info
->dy
* info
->oneoverarea
;
90 info
->dadx
[slot
][i
] = dadx
;
91 info
->dady
[slot
][i
] = dady
;
93 info
->a0
[slot
][i
] = (a1
-
94 (dadx
* (info
->v1
[0][0] - setup
->pixel_offset
) +
95 dady
* (info
->v1
[0][1] - setup
->pixel_offset
)));
100 * Compute a0, dadx and dady for a perspective-corrected interpolant,
102 * We basically multiply the vertex value by 1/w before computing
103 * the plane coefficients (a0, dadx, dady).
104 * Later, when we compute the value at a particular fragment position we'll
105 * divide the interpolated value by the interpolated W at that fragment.
107 static void perspective_coef( struct lp_setup_context
*setup
,
108 struct lp_line_info
*info
,
113 /* premultiply by 1/w (v[0][3] is always 1/w):
115 float a1
= info
->v1
[vert_attr
][i
] * info
->v1
[0][3];
116 float a2
= info
->v2
[vert_attr
][i
] * info
->v2
[0][3];
118 float da21
= a1
- a2
;
119 float dadx
= da21
* info
->dx
* info
->oneoverarea
;
120 float dady
= da21
* info
->dy
* info
->oneoverarea
;
122 info
->dadx
[slot
][i
] = dadx
;
123 info
->dady
[slot
][i
] = dady
;
125 info
->a0
[slot
][i
] = (a1
-
126 (dadx
* (info
->v1
[0][0] - setup
->pixel_offset
) +
127 dady
* (info
->v1
[0][1] - setup
->pixel_offset
)));
131 setup_fragcoord_coef( struct lp_setup_context
*setup
,
132 struct lp_line_info
*info
,
137 if (usage_mask
& TGSI_WRITEMASK_X
) {
138 info
->a0
[slot
][0] = 0.0;
139 info
->dadx
[slot
][0] = 1.0;
140 info
->dady
[slot
][0] = 0.0;
144 if (usage_mask
& TGSI_WRITEMASK_Y
) {
145 info
->a0
[slot
][1] = 0.0;
146 info
->dadx
[slot
][1] = 0.0;
147 info
->dady
[slot
][1] = 1.0;
151 if (usage_mask
& TGSI_WRITEMASK_Z
) {
152 linear_coef(setup
, info
, slot
, 0, 2);
156 if (usage_mask
& TGSI_WRITEMASK_W
) {
157 linear_coef(setup
, info
, slot
, 0, 3);
162 * Compute the tri->coef[] array dadx, dady, a0 values.
164 static void setup_line_coefficients( struct lp_setup_context
*setup
,
165 struct lp_line_info
*info
)
167 const struct lp_setup_variant_key
*key
= &setup
->setup
.variant
->key
;
168 unsigned fragcoord_usage_mask
= TGSI_WRITEMASK_XYZ
;
171 /* setup interpolation for all the remaining attributes:
173 for (slot
= 0; slot
< key
->num_inputs
; slot
++) {
174 unsigned vert_attr
= key
->inputs
[slot
].src_index
;
175 unsigned usage_mask
= key
->inputs
[slot
].usage_mask
;
178 switch (key
->inputs
[slot
].interp
) {
179 case LP_INTERP_CONSTANT
:
180 if (key
->flatshade_first
) {
181 for (i
= 0; i
< NUM_CHANNELS
; i
++)
182 if (usage_mask
& (1 << i
))
183 constant_coef(setup
, info
, slot
+1, info
->v1
[vert_attr
][i
], i
);
186 for (i
= 0; i
< NUM_CHANNELS
; i
++)
187 if (usage_mask
& (1 << i
))
188 constant_coef(setup
, info
, slot
+1, info
->v2
[vert_attr
][i
], i
);
192 case LP_INTERP_LINEAR
:
193 for (i
= 0; i
< NUM_CHANNELS
; i
++)
194 if (usage_mask
& (1 << i
))
195 linear_coef(setup
, info
, slot
+1, vert_attr
, i
);
198 case LP_INTERP_PERSPECTIVE
:
199 for (i
= 0; i
< NUM_CHANNELS
; i
++)
200 if (usage_mask
& (1 << i
))
201 perspective_coef(setup
, info
, slot
+1, vert_attr
, i
);
202 fragcoord_usage_mask
|= TGSI_WRITEMASK_W
;
205 case LP_INTERP_POSITION
:
207 * The generated pixel interpolators will pick up the coeffs from
208 * slot 0, so all need to ensure that the usage mask is covers all
211 fragcoord_usage_mask
|= usage_mask
;
214 case LP_INTERP_FACING
:
215 for (i
= 0; i
< NUM_CHANNELS
; i
++)
216 if (usage_mask
& (1 << i
))
217 constant_coef(setup
, info
, slot
+1, 1.0, i
);
225 /* The internal position input is in slot zero:
227 setup_fragcoord_coef(setup
, info
, 0,
228 fragcoord_usage_mask
);
233 static INLINE
int subpixel_snap( float a
)
235 return util_iround(FIXED_ONE
* a
);
240 * Print line vertex attribs (for debug).
243 print_line(struct lp_setup_context
*setup
,
244 const float (*v1
)[4],
245 const float (*v2
)[4])
247 const struct lp_setup_variant_key
*key
= &setup
->setup
.variant
->key
;
250 debug_printf("llvmpipe line\n");
251 for (i
= 0; i
< 1 + key
->num_inputs
; i
++) {
252 debug_printf(" v1[%d]: %f %f %f %f\n", i
,
253 v1
[i
][0], v1
[i
][1], v1
[i
][2], v1
[i
][3]);
255 for (i
= 0; i
< 1 + key
->num_inputs
; i
++) {
256 debug_printf(" v2[%d]: %f %f %f %f\n", i
,
257 v2
[i
][0], v2
[i
][1], v2
[i
][2], v2
[i
][3]);
262 static INLINE boolean
sign(float x
){
267 /* Used on positive floats only:
269 static INLINE
float fracf(float f
)
271 return f
- floorf(f
);
277 try_setup_line( struct lp_setup_context
*setup
,
278 const float (*v1
)[4],
279 const float (*v2
)[4])
281 struct lp_scene
*scene
= setup
->scene
;
282 const struct lp_setup_variant_key
*key
= &setup
->setup
.variant
->key
;
283 struct lp_rast_triangle
*line
;
284 struct lp_rast_plane
*plane
;
285 struct lp_line_info info
;
286 float width
= MAX2(1.0, setup
->line_width
);
293 unsigned scissor_index
= 0;
296 /* linewidth should be interpreted as integer */
297 int fixed_width
= util_iround(width
) * FIXED_ONE
;
301 float x_offset_end
=0;
302 float y_offset_end
=0;
313 boolean will_draw_start
;
314 boolean will_draw_end
;
317 print_line(setup
, v1
, v2
);
319 if (setup
->scissor_test
) {
321 if (setup
->viewport_index_slot
> 0) {
322 unsigned *udata
= (unsigned*)v1
[setup
->viewport_index_slot
];
323 scissor_index
= lp_clamp_scissor_idx(*udata
);
330 if (setup
->layer_slot
> 0) {
331 layer
= *(unsigned*)v1
[setup
->layer_slot
];
332 layer
= MIN2(layer
, scene
->fb_max_layer
);
335 dx
= v1
[0][0] - v2
[0][0];
336 dy
= v1
[0][1] - v2
[0][1];
337 area
= (dx
* dx
+ dy
* dy
);
339 LP_COUNT(nr_culled_tris
);
343 info
.oneoverarea
= 1.0f
/ area
;
351 if (fabsf(dx
) >= fabsf(dy
)) {
352 float dydx
= dy
/ dx
;
354 x1diff
= v1
[0][0] - (float) floor(v1
[0][0]) - 0.5;
355 y1diff
= v1
[0][1] - (float) floor(v1
[0][1]) - 0.5;
356 x2diff
= v2
[0][0] - (float) floor(v2
[0][0]) - 0.5;
357 y2diff
= v2
[0][1] - (float) floor(v2
[0][1]) - 0.5;
359 if (y2diff
==-0.5 && dy
<0){
364 * Diamond exit rule test for starting point
366 if (fabsf(x1diff
) + fabsf(y1diff
) < 0.5) {
369 else if (sign(x1diff
) == sign(-dx
)) {
372 else if (sign(-y1diff
) != sign(dy
)) {
376 /* do intersection test */
377 float yintersect
= fracf(v1
[0][1]) + x1diff
* dydx
;
378 draw_start
= (yintersect
< 1.0 && yintersect
> 0.0);
383 * Diamond exit rule test for ending point
385 if (fabsf(x2diff
) + fabsf(y2diff
) < 0.5) {
388 else if (sign(x2diff
) != sign(-dx
)) {
391 else if (sign(-y2diff
) == sign(dy
)) {
395 /* do intersection test */
396 float yintersect
= fracf(v2
[0][1]) + x2diff
* dydx
;
397 draw_end
= (yintersect
< 1.0 && yintersect
> 0.0);
400 /* Are we already drawing start/end?
402 will_draw_start
= sign(-x1diff
) != sign(dx
);
403 will_draw_end
= (sign(x2diff
) == sign(-dx
)) || x2diff
==0;
406 /* if v2 is to the right of v1, swap pointers */
407 const float (*temp
)[4] = v1
;
412 /* Otherwise shift planes appropriately */
413 if (will_draw_start
!= draw_start
) {
414 x_offset_end
= - x1diff
- 0.5;
415 y_offset_end
= x_offset_end
* dydx
;
418 if (will_draw_end
!= draw_end
) {
419 x_offset
= - x2diff
- 0.5;
420 y_offset
= x_offset
* dydx
;
425 /* Otherwise shift planes appropriately */
426 if (will_draw_start
!= draw_start
) {
427 x_offset
= - x1diff
+ 0.5;
428 y_offset
= x_offset
* dydx
;
430 if (will_draw_end
!= draw_end
) {
431 x_offset_end
= - x2diff
+ 0.5;
432 y_offset_end
= x_offset_end
* dydx
;
436 /* x/y positions in fixed point */
437 x
[0] = subpixel_snap(v1
[0][0] + x_offset
- setup
->pixel_offset
);
438 x
[1] = subpixel_snap(v2
[0][0] + x_offset_end
- setup
->pixel_offset
);
439 x
[2] = subpixel_snap(v2
[0][0] + x_offset_end
- setup
->pixel_offset
);
440 x
[3] = subpixel_snap(v1
[0][0] + x_offset
- setup
->pixel_offset
);
442 y
[0] = subpixel_snap(v1
[0][1] + y_offset
- setup
->pixel_offset
) - fixed_width
/2;
443 y
[1] = subpixel_snap(v2
[0][1] + y_offset_end
- setup
->pixel_offset
) - fixed_width
/2;
444 y
[2] = subpixel_snap(v2
[0][1] + y_offset_end
- setup
->pixel_offset
) + fixed_width
/2;
445 y
[3] = subpixel_snap(v1
[0][1] + y_offset
- setup
->pixel_offset
) + fixed_width
/2;
449 const float dxdy
= dx
/ dy
;
452 x1diff
= v1
[0][0] - (float) floor(v1
[0][0]) - 0.5;
453 y1diff
= v1
[0][1] - (float) floor(v1
[0][1]) - 0.5;
454 x2diff
= v2
[0][0] - (float) floor(v2
[0][0]) - 0.5;
455 y2diff
= v2
[0][1] - (float) floor(v2
[0][1]) - 0.5;
457 if (x2diff
==-0.5 && dx
<0) {
462 * Diamond exit rule test for starting point
464 if (fabsf(x1diff
) + fabsf(y1diff
) < 0.5) {
467 else if (sign(-y1diff
) == sign(dy
)) {
470 else if (sign(x1diff
) != sign(-dx
)) {
474 /* do intersection test */
475 float xintersect
= fracf(v1
[0][0]) + y1diff
* dxdy
;
476 draw_start
= (xintersect
< 1.0 && xintersect
> 0.0);
480 * Diamond exit rule test for ending point
482 if (fabsf(x2diff
) + fabsf(y2diff
) < 0.5) {
485 else if (sign(-y2diff
) != sign(dy
) ) {
488 else if (sign(x2diff
) == sign(-dx
) ) {
492 /* do intersection test */
493 float xintersect
= fracf(v2
[0][0]) + y2diff
* dxdy
;
494 draw_end
= (xintersect
< 1.0 && xintersect
>= 0.0);
497 /* Are we already drawing start/end?
499 will_draw_start
= sign(y1diff
) == sign(dy
);
500 will_draw_end
= (sign(-y2diff
) == sign(dy
)) || y2diff
==0;
503 /* if v2 is on top of v1, swap pointers */
504 const float (*temp
)[4] = v1
;
510 /* Otherwise shift planes appropriately */
511 if (will_draw_start
!= draw_start
) {
512 y_offset_end
= - y1diff
+ 0.5;
513 x_offset_end
= y_offset_end
* dxdy
;
515 if (will_draw_end
!= draw_end
) {
516 y_offset
= - y2diff
+ 0.5;
517 x_offset
= y_offset
* dxdy
;
521 /* Otherwise shift planes appropriately */
522 if (will_draw_start
!= draw_start
) {
523 y_offset
= - y1diff
- 0.5;
524 x_offset
= y_offset
* dxdy
;
527 if (will_draw_end
!= draw_end
) {
528 y_offset_end
= - y2diff
- 0.5;
529 x_offset_end
= y_offset_end
* dxdy
;
533 /* x/y positions in fixed point */
534 x
[0] = subpixel_snap(v1
[0][0] + x_offset
- setup
->pixel_offset
) - fixed_width
/2;
535 x
[1] = subpixel_snap(v2
[0][0] + x_offset_end
- setup
->pixel_offset
) - fixed_width
/2;
536 x
[2] = subpixel_snap(v2
[0][0] + x_offset_end
- setup
->pixel_offset
) + fixed_width
/2;
537 x
[3] = subpixel_snap(v1
[0][0] + x_offset
- setup
->pixel_offset
) + fixed_width
/2;
539 y
[0] = subpixel_snap(v1
[0][1] + y_offset
- setup
->pixel_offset
);
540 y
[1] = subpixel_snap(v2
[0][1] + y_offset_end
- setup
->pixel_offset
);
541 y
[2] = subpixel_snap(v2
[0][1] + y_offset_end
- setup
->pixel_offset
);
542 y
[3] = subpixel_snap(v1
[0][1] + y_offset
- setup
->pixel_offset
);
545 /* Bounding rectangle (in pixels) */
547 /* Yes this is necessary to accurately calculate bounding boxes
548 * with the two fill-conventions we support. GL (normally) ends
549 * up needing a bottom-left fill convention, which requires
550 * slightly different rounding.
552 int adj
= (setup
->pixel_offset
!= 0) ? 1 : 0;
554 bbox
.x0
= (MIN4(x
[0], x
[1], x
[2], x
[3]) + (FIXED_ONE
-1)) >> FIXED_ORDER
;
555 bbox
.x1
= (MAX4(x
[0], x
[1], x
[2], x
[3]) + (FIXED_ONE
-1)) >> FIXED_ORDER
;
556 bbox
.y0
= (MIN4(y
[0], y
[1], y
[2], y
[3]) + (FIXED_ONE
-1) + adj
) >> FIXED_ORDER
;
557 bbox
.y1
= (MAX4(y
[0], y
[1], y
[2], y
[3]) + (FIXED_ONE
-1) + adj
) >> FIXED_ORDER
;
559 /* Inclusive coordinates:
565 if (bbox
.x1
< bbox
.x0
||
567 if (0) debug_printf("empty bounding box\n");
568 LP_COUNT(nr_culled_tris
);
572 if (!u_rect_test_intersection(&setup
->draw_regions
[scissor_index
], &bbox
)) {
573 if (0) debug_printf("offscreen\n");
574 LP_COUNT(nr_culled_tris
);
578 /* Can safely discard negative regions:
580 bbox
.x0
= MAX2(bbox
.x0
, 0);
581 bbox
.y0
= MAX2(bbox
.y0
, 0);
583 line
= lp_setup_alloc_triangle(scene
,
591 line
->v
[0][0] = v1
[0][0];
592 line
->v
[1][0] = v2
[0][0];
593 line
->v
[0][1] = v1
[0][1];
594 line
->v
[1][1] = v2
[0][1];
599 if (setup
->active_query
[PIPE_QUERY_PIPELINE_STATISTICS
]) {
600 struct llvmpipe_context
*lp_context
= (struct llvmpipe_context
*)setup
->pipe
;
601 lp_context
->pipeline_statistics
.c_primitives
++;
604 /* calculate the deltas */
605 plane
= GET_PLANES(line
);
606 plane
[0].dcdy
= x
[0] - x
[1];
607 plane
[1].dcdy
= x
[1] - x
[2];
608 plane
[2].dcdy
= x
[2] - x
[3];
609 plane
[3].dcdy
= x
[3] - x
[0];
611 plane
[0].dcdx
= y
[0] - y
[1];
612 plane
[1].dcdx
= y
[1] - y
[2];
613 plane
[2].dcdx
= y
[2] - y
[3];
614 plane
[3].dcdx
= y
[3] - y
[0];
617 /* Setup parameter interpolants:
619 info
.a0
= GET_A0(&line
->inputs
);
620 info
.dadx
= GET_DADX(&line
->inputs
);
621 info
.dady
= GET_DADY(&line
->inputs
);
622 setup_line_coefficients(setup
, &info
);
624 line
->inputs
.frontfacing
= TRUE
;
625 line
->inputs
.disable
= FALSE
;
626 line
->inputs
.opaque
= FALSE
;
627 line
->inputs
.layer
= layer
;
629 for (i
= 0; i
< 4; i
++) {
631 /* half-edge constants, will be interated over the whole render
634 plane
[i
].c
= plane
[i
].dcdx
* x
[i
] - plane
[i
].dcdy
* y
[i
];
637 /* correct for top-left vs. bottom-left fill convention.
639 if (plane
[i
].dcdx
< 0) {
640 /* both fill conventions want this - adjust for left edges */
643 else if (plane
[i
].dcdx
== 0) {
644 if (setup
->pixel_offset
== 0) {
645 /* correct for top-left fill convention:
647 if (plane
[i
].dcdy
> 0) plane
[i
].c
++;
650 /* correct for bottom-left fill convention:
652 if (plane
[i
].dcdy
< 0) plane
[i
].c
++;
656 plane
[i
].dcdx
*= FIXED_ONE
;
657 plane
[i
].dcdy
*= FIXED_ONE
;
659 /* find trivial reject offsets for each edge for a single-pixel
660 * sized block. These will be scaled up at each recursive level to
661 * match the active blocksize. Scaling in this way works best if
662 * the blocks are square.
665 if (plane
[i
].dcdx
< 0) plane
[i
].eo
-= plane
[i
].dcdx
;
666 if (plane
[i
].dcdy
> 0) plane
[i
].eo
+= plane
[i
].dcdy
;
671 * When rasterizing scissored tris, use the intersection of the
672 * triangle bounding box and the scissor rect to generate the
675 * This permits us to cut off the triangle "tails" that are present
676 * in the intermediate recursive levels caused when two of the
677 * triangles edges don't diverge quickly enough to trivially reject
678 * exterior blocks from the triangle.
680 * It's not really clear if it's worth worrying about these tails,
681 * but since we generate the planes for each scissored tri, it's
682 * free to trim them in this case.
684 * Note that otherwise, the scissor planes only vary in 'C' value,
685 * and even then only on state-changes. Could alternatively store
686 * these planes elsewhere.
688 if (nr_planes
== 8) {
689 const struct u_rect
*scissor
=
690 &setup
->scissors
[scissor_index
];
694 plane
[4].c
= 1-scissor
->x0
;
699 plane
[5].c
= scissor
->x1
+1;
704 plane
[6].c
= 1-scissor
->y0
;
709 plane
[7].c
= scissor
->y1
+1;
713 return lp_setup_bin_triangle(setup
, line
, &bbox
, nr_planes
, scissor_index
);
717 static void lp_setup_line( struct lp_setup_context
*setup
,
718 const float (*v0
)[4],
719 const float (*v1
)[4] )
721 if (!try_setup_line( setup
, v0
, v1
))
723 if (!lp_setup_flush_and_restart(setup
))
726 if (!try_setup_line( setup
, v0
, v1
))
732 void lp_setup_choose_line( struct lp_setup_context
*setup
)
734 setup
->line
= lp_setup_line
;