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 * \brief Primitive rasterization/rendering (points, lines, triangles)
31 * \author Keith Whitwell <keith@tungstengraphics.com>
36 #include "sp_context.h"
37 #include "sp_headers.h"
40 #include "sp_prim_setup.h"
41 #include "draw/draw_private.h"
42 #include "draw/draw_vertex.h"
43 #include "pipe/p_util.h"
44 #include "pipe/p_shader_tokens.h"
52 float dx
; /**< X(v1) - X(v0), used only during setup */
53 float dy
; /**< Y(v1) - Y(v0), used only during setup */
54 float dxdy
; /**< dx/dy */
55 float sx
, sy
; /**< first sample point coord */
56 int lines
; /**< number of lines on this edge */
61 * Triangle setup info (derived from draw_stage).
62 * Also used for line drawing (taking some liberties).
65 struct draw_stage stage
; /**< This must be first (base class) */
67 struct softpipe_context
*softpipe
;
69 /* Vertices are just an array of floats making up each attribute in
70 * turn. Currently fixed at 4 floats, but should change in time.
71 * Codegen will help cope with this.
73 const struct vertex_header
*vmax
;
74 const struct vertex_header
*vmid
;
75 const struct vertex_header
*vmin
;
76 const struct vertex_header
*vprovoke
;
84 struct tgsi_interp_coef coef
[PIPE_MAX_SHADER_INPUTS
];
85 struct tgsi_interp_coef posCoef
; /* For Z, W */
86 struct quad_header quad
;
89 int left
[2]; /**< [0] = row0, [1] = row1 */
93 unsigned mask
; /**< mask of MASK_BOTTOM/TOP_LEFT/RIGHT bits */
100 * Basically a cast wrapper.
102 static INLINE
struct setup_stage
*setup_stage( struct draw_stage
*stage
)
104 return (struct setup_stage
*)stage
;
109 * Clip setup->quad against the scissor/surface bounds.
112 quad_clip(struct setup_stage
*setup
)
114 const struct pipe_scissor_state
*cliprect
= &setup
->softpipe
->cliprect
;
115 const int minx
= (int) cliprect
->minx
;
116 const int maxx
= (int) cliprect
->maxx
;
117 const int miny
= (int) cliprect
->miny
;
118 const int maxy
= (int) cliprect
->maxy
;
120 if (setup
->quad
.x0
>= maxx
||
121 setup
->quad
.y0
>= maxy
||
122 setup
->quad
.x0
+ 1 < minx
||
123 setup
->quad
.y0
+ 1 < miny
) {
124 /* totally clipped */
125 setup
->quad
.mask
= 0x0;
128 if (setup
->quad
.x0
< minx
)
129 setup
->quad
.mask
&= (MASK_BOTTOM_RIGHT
| MASK_TOP_RIGHT
);
130 if (setup
->quad
.y0
< miny
)
131 setup
->quad
.mask
&= (MASK_BOTTOM_LEFT
| MASK_BOTTOM_RIGHT
);
132 if (setup
->quad
.x0
== maxx
- 1)
133 setup
->quad
.mask
&= (MASK_BOTTOM_LEFT
| MASK_TOP_LEFT
);
134 if (setup
->quad
.y0
== maxy
- 1)
135 setup
->quad
.mask
&= (MASK_TOP_LEFT
| MASK_TOP_RIGHT
);
140 * Emit a quad (pass to next stage) with clipping.
143 clip_emit_quad(struct setup_stage
*setup
)
146 if (setup
->quad
.mask
) {
147 struct softpipe_context
*sp
= setup
->softpipe
;
148 sp
->quad
.first
->run(sp
->quad
.first
, &setup
->quad
);
154 * Emit a quad (pass to next stage). No clipping is done.
157 emit_quad( struct setup_stage
*setup
, int x
, int y
, unsigned mask
)
159 struct softpipe_context
*sp
= setup
->softpipe
;
162 setup
->quad
.mask
= mask
;
163 sp
->quad
.first
->run(sp
->quad
.first
, &setup
->quad
);
168 * Given an X or Y coordinate, return the block/quad coordinate that it
171 static INLINE
int block( int x
)
178 * Compute mask which indicates which pixels in the 2x2 quad are actually inside
179 * the triangle's bounds.
181 * this is pretty nasty... may need to rework flush_spans again to
182 * fix it, if possible.
184 static unsigned calculate_mask( struct setup_stage
*setup
, int x
)
188 if (x
>= setup
->span
.left
[0] && x
< setup
->span
.right
[0])
189 mask
|= MASK_TOP_LEFT
;
191 if (x
>= setup
->span
.left
[1] && x
< setup
->span
.right
[1])
192 mask
|= MASK_BOTTOM_LEFT
;
194 if (x
+1 >= setup
->span
.left
[0] && x
+1 < setup
->span
.right
[0])
195 mask
|= MASK_TOP_RIGHT
;
197 if (x
+1 >= setup
->span
.left
[1] && x
+1 < setup
->span
.right
[1])
198 mask
|= MASK_BOTTOM_RIGHT
;
205 * Render a horizontal span of quads
207 static void flush_spans( struct setup_stage
*setup
)
209 int minleft
, maxright
;
212 switch (setup
->span
.y_flags
) {
214 /* both odd and even lines written (both quad rows) */
215 minleft
= MIN2(setup
->span
.left
[0], setup
->span
.left
[1]);
216 maxright
= MAX2(setup
->span
.right
[0], setup
->span
.right
[1]);
220 /* only even line written (quad top row) */
221 minleft
= setup
->span
.left
[0];
222 maxright
= setup
->span
.right
[0];
226 /* only odd line written (quad bottom row) */
227 minleft
= setup
->span
.left
[1];
228 maxright
= setup
->span
.right
[1];
235 /* XXX this loop could be moved into the above switch cases and
236 * calculate_mask() could be simplified a bit...
238 for (x
= block(minleft
); x
<= block(maxright
); x
+= 2) {
239 emit_quad( setup
, x
, setup
->span
.y
,
240 calculate_mask( setup
, x
) );
244 setup
->span
.y_flags
= 0;
245 setup
->span
.right
[0] = 0;
246 setup
->span
.right
[1] = 0;
250 static void print_vertex(const struct setup_stage
*setup
,
251 const struct vertex_header
*v
)
254 debug_printf("Vertex: (%p)\n", v
);
255 for (i
= 0; i
< setup
->quad
.nr_attrs
; i
++) {
256 debug_printf(" %d: %f %f %f %f\n", i
,
257 v
->data
[i
][0], v
->data
[i
][1], v
->data
[i
][2], v
->data
[i
][3]);
262 static boolean
setup_sort_vertices( struct setup_stage
*setup
,
263 const struct prim_header
*prim
)
265 const struct vertex_header
*v0
= prim
->v
[0];
266 const struct vertex_header
*v1
= prim
->v
[1];
267 const struct vertex_header
*v2
= prim
->v
[2];
270 debug_printf("Triangle:\n");
271 print_vertex(setup
, v0
);
272 print_vertex(setup
, v1
);
273 print_vertex(setup
, v2
);
276 setup
->vprovoke
= v2
;
278 /* determine bottom to top order of vertices */
280 float y0
= v0
->data
[0][1];
281 float y1
= v1
->data
[0][1];
282 float y2
= v2
->data
[0][1];
325 setup
->ebot
.dx
= setup
->vmid
->data
[0][0] - setup
->vmin
->data
[0][0];
326 setup
->ebot
.dy
= setup
->vmid
->data
[0][1] - setup
->vmin
->data
[0][1];
327 setup
->emaj
.dx
= setup
->vmax
->data
[0][0] - setup
->vmin
->data
[0][0];
328 setup
->emaj
.dy
= setup
->vmax
->data
[0][1] - setup
->vmin
->data
[0][1];
329 setup
->etop
.dx
= setup
->vmax
->data
[0][0] - setup
->vmid
->data
[0][0];
330 setup
->etop
.dy
= setup
->vmax
->data
[0][1] - setup
->vmid
->data
[0][1];
333 * Compute triangle's area. Use 1/area to compute partial
334 * derivatives of attributes later.
336 * The area will be the same as prim->det, but the sign may be
337 * different depending on how the vertices get sorted above.
339 * To determine whether the primitive is front or back facing we
340 * use the prim->det value because its sign is correct.
343 const float area
= (setup
->emaj
.dx
* setup
->ebot
.dy
-
344 setup
->ebot
.dx
* setup
->emaj
.dy
);
346 setup
->oneoverarea
= 1.0f
/ area
;
348 debug_printf("%s one-over-area %f area %f det %f\n",
349 __FUNCTION__, setup->oneoverarea, area, prim->det );
353 /* We need to know if this is a front or back-facing triangle for:
354 * - the GLSL gl_FrontFacing fragment attribute (bool)
355 * - two-sided stencil test
357 setup
->quad
.facing
= (prim
->det
> 0.0) ^ (setup
->softpipe
->rasterizer
->front_winding
== PIPE_WINDING_CW
);
364 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
365 * The value value comes from vertex->data[slot][i].
366 * The result will be put into setup->coef[slot].a0[i].
367 * \param slot which attribute slot
368 * \param i which component of the slot (0..3)
370 static void const_coeff( struct setup_stage
*setup
,
371 struct tgsi_interp_coef
*coef
,
372 uint vertSlot
, uint i
)
379 /* need provoking vertex info!
381 coef
->a0
[i
] = setup
->vprovoke
->data
[vertSlot
][i
];
386 * Compute a0, dadx and dady for a linearly interpolated coefficient,
389 static void tri_linear_coeff( struct setup_stage
*setup
,
390 struct tgsi_interp_coef
*coef
,
391 uint vertSlot
, uint i
)
393 float botda
= setup
->vmid
->data
[vertSlot
][i
] - setup
->vmin
->data
[vertSlot
][i
];
394 float majda
= setup
->vmax
->data
[vertSlot
][i
] - setup
->vmin
->data
[vertSlot
][i
];
395 float a
= setup
->ebot
.dy
* majda
- botda
* setup
->emaj
.dy
;
396 float b
= setup
->emaj
.dx
* botda
- majda
* setup
->ebot
.dx
;
397 float dadx
= a
* setup
->oneoverarea
;
398 float dady
= b
* setup
->oneoverarea
;
402 coef
->dadx
[i
] = dadx
;
403 coef
->dady
[i
] = dady
;
405 /* calculate a0 as the value which would be sampled for the
406 * fragment at (0,0), taking into account that we want to sample at
407 * pixel centers, in other words (0.5, 0.5).
409 * this is neat but unfortunately not a good way to do things for
410 * triangles with very large values of dadx or dady as it will
411 * result in the subtraction and re-addition from a0 of a very
412 * large number, which means we'll end up loosing a lot of the
413 * fractional bits and precision from a0. the way to fix this is
414 * to define a0 as the sample at a pixel center somewhere near vmin
415 * instead - i'll switch to this later.
417 coef
->a0
[i
] = (setup
->vmin
->data
[vertSlot
][i
] -
418 (dadx
* (setup
->vmin
->data
[0][0] - 0.5f
) +
419 dady
* (setup
->vmin
->data
[0][1] - 0.5f
)));
422 debug_printf("attr[%d].%c: %f dx:%f dy:%f\n",
424 setup->coef[slot].a0[i],
425 setup->coef[slot].dadx[i],
426 setup->coef[slot].dady[i]);
432 * Compute a0, dadx and dady for a perspective-corrected interpolant,
434 * We basically multiply the vertex value by 1/w before computing
435 * the plane coefficients (a0, dadx, dady).
436 * Later, when we compute the value at a particular fragment position we'll
437 * divide the interpolated value by the interpolated W at that fragment.
439 static void tri_persp_coeff( struct setup_stage
*setup
,
440 struct tgsi_interp_coef
*coef
,
441 uint vertSlot
, uint i
)
443 /* premultiply by 1/w (v->data[0][3] is always W):
445 float mina
= setup
->vmin
->data
[vertSlot
][i
] * setup
->vmin
->data
[0][3];
446 float mida
= setup
->vmid
->data
[vertSlot
][i
] * setup
->vmid
->data
[0][3];
447 float maxa
= setup
->vmax
->data
[vertSlot
][i
] * setup
->vmax
->data
[0][3];
448 float botda
= mida
- mina
;
449 float majda
= maxa
- mina
;
450 float a
= setup
->ebot
.dy
* majda
- botda
* setup
->emaj
.dy
;
451 float b
= setup
->emaj
.dx
* botda
- majda
* setup
->ebot
.dx
;
452 float dadx
= a
* setup
->oneoverarea
;
453 float dady
= b
* setup
->oneoverarea
;
456 debug_printf("tri persp %d,%d: %f %f %f\n", vertSlot, i,
457 setup->vmin->data[vertSlot][i],
458 setup->vmid->data[vertSlot][i],
459 setup->vmax->data[vertSlot][i]
464 coef
->dadx
[i
] = dadx
;
465 coef
->dady
[i
] = dady
;
466 coef
->a0
[i
] = (mina
-
467 (dadx
* (setup
->vmin
->data
[0][0] - 0.5f
) +
468 dady
* (setup
->vmin
->data
[0][1] - 0.5f
)));
473 * Special coefficient setup for gl_FragCoord.
474 * X and Y are trivial, though Y has to be inverted for OpenGL.
475 * Z and W are copied from posCoef which should have already been computed.
476 * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
479 setup_fragcoord_coeff(struct setup_stage
*setup
)
482 setup
->coef
[0].a0
[0] = 0;
483 setup
->coef
[0].dadx
[0] = 1.0;
484 setup
->coef
[0].dady
[0] = 0.0;
486 if (setup
->softpipe
->rasterizer
->origin_lower_left
) {
488 const int winHeight
= setup
->softpipe
->framebuffer
.cbufs
[0]->height
;
489 setup
->coef
[0].a0
[1] = (float) (winHeight
- 1);
490 setup
->coef
[0].dady
[1] = -1.0;
494 setup
->coef
[0].a0
[1] = 0.0;
495 setup
->coef
[0].dady
[1] = 1.0;
497 setup
->coef
[0].dadx
[1] = 0.0;
499 setup
->coef
[0].a0
[2] = setup
->posCoef
.a0
[2];
500 setup
->coef
[0].dadx
[2] = setup
->posCoef
.dadx
[2];
501 setup
->coef
[0].dady
[2] = setup
->posCoef
.dady
[2];
503 setup
->coef
[0].a0
[3] = setup
->posCoef
.a0
[3];
504 setup
->coef
[0].dadx
[3] = setup
->posCoef
.dadx
[3];
505 setup
->coef
[0].dady
[3] = setup
->posCoef
.dady
[3];
511 * Compute the setup->coef[] array dadx, dady, a0 values.
512 * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
514 static void setup_tri_coefficients( struct setup_stage
*setup
)
516 struct softpipe_context
*softpipe
= setup
->softpipe
;
517 const struct pipe_shader_state
*fs
= &softpipe
->fs
->shader
;
518 const struct vertex_info
*vinfo
= softpipe_get_vertex_info(softpipe
);
521 /* z and w are done by linear interpolation:
523 tri_linear_coeff(setup
, &setup
->posCoef
, 0, 2);
524 tri_linear_coeff(setup
, &setup
->posCoef
, 0, 3);
526 /* setup interpolation for all the remaining attributes:
528 for (fragSlot
= 0; fragSlot
< fs
->num_inputs
; fragSlot
++) {
529 const uint vertSlot
= vinfo
->src_index
[fragSlot
];
532 switch (vinfo
->interp_mode
[fragSlot
]) {
533 case INTERP_CONSTANT
:
534 for (j
= 0; j
< NUM_CHANNELS
; j
++)
535 const_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
538 for (j
= 0; j
< NUM_CHANNELS
; j
++)
539 tri_linear_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
541 case INTERP_PERSPECTIVE
:
542 for (j
= 0; j
< NUM_CHANNELS
; j
++)
543 tri_persp_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
546 assert(fragSlot
== 0);
547 setup_fragcoord_coeff(setup
);
553 if (fs
->input_semantic_name
[fragSlot
] == TGSI_SEMANTIC_FOG
) {
554 /* FOG.y = front/back facing XXX fix this */
555 setup
->coef
[fragSlot
].a0
[1] = 1.0f
- setup
->quad
.facing
;
556 setup
->coef
[fragSlot
].dadx
[1] = 0.0;
557 setup
->coef
[fragSlot
].dady
[1] = 0.0;
564 static void setup_tri_edges( struct setup_stage
*setup
)
566 float vmin_x
= setup
->vmin
->data
[0][0] + 0.5f
;
567 float vmid_x
= setup
->vmid
->data
[0][0] + 0.5f
;
569 float vmin_y
= setup
->vmin
->data
[0][1] - 0.5f
;
570 float vmid_y
= setup
->vmid
->data
[0][1] - 0.5f
;
571 float vmax_y
= setup
->vmax
->data
[0][1] - 0.5f
;
573 setup
->emaj
.sy
= CEILF(vmin_y
);
574 setup
->emaj
.lines
= (int) CEILF(vmax_y
- setup
->emaj
.sy
);
575 setup
->emaj
.dxdy
= setup
->emaj
.dx
/ setup
->emaj
.dy
;
576 setup
->emaj
.sx
= vmin_x
+ (setup
->emaj
.sy
- vmin_y
) * setup
->emaj
.dxdy
;
578 setup
->etop
.sy
= CEILF(vmid_y
);
579 setup
->etop
.lines
= (int) CEILF(vmax_y
- setup
->etop
.sy
);
580 setup
->etop
.dxdy
= setup
->etop
.dx
/ setup
->etop
.dy
;
581 setup
->etop
.sx
= vmid_x
+ (setup
->etop
.sy
- vmid_y
) * setup
->etop
.dxdy
;
583 setup
->ebot
.sy
= CEILF(vmin_y
);
584 setup
->ebot
.lines
= (int) CEILF(vmid_y
- setup
->ebot
.sy
);
585 setup
->ebot
.dxdy
= setup
->ebot
.dx
/ setup
->ebot
.dy
;
586 setup
->ebot
.sx
= vmin_x
+ (setup
->ebot
.sy
- vmin_y
) * setup
->ebot
.dxdy
;
591 * Render the upper or lower half of a triangle.
592 * Scissoring/cliprect is applied here too.
594 static void subtriangle( struct setup_stage
*setup
,
599 const struct pipe_scissor_state
*cliprect
= &setup
->softpipe
->cliprect
;
600 const int minx
= (int) cliprect
->minx
;
601 const int maxx
= (int) cliprect
->maxx
;
602 const int miny
= (int) cliprect
->miny
;
603 const int maxy
= (int) cliprect
->maxy
;
604 int y
, start_y
, finish_y
;
605 int sy
= (int)eleft
->sy
;
607 assert((int)eleft
->sy
== (int) eright
->sy
);
609 /* clip top/bottom */
611 finish_y
= sy
+ lines
;
623 debug_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);
626 for (y
= start_y
; y
< finish_y
; y
++) {
628 /* avoid accumulating adds as floats don't have the precision to
629 * accurately iterate large triangle edges that way. luckily we
630 * can just multiply these days.
632 * this is all drowned out by the attribute interpolation anyway.
634 int left
= (int)(eleft
->sx
+ y
* eleft
->dxdy
);
635 int right
= (int)(eright
->sx
+ y
* eright
->dxdy
);
637 /* clip left/right */
645 if (block(_y
) != setup
->span
.y
) {
647 setup
->span
.y
= block(_y
);
650 setup
->span
.left
[_y
&1] = left
;
651 setup
->span
.right
[_y
&1] = right
;
652 setup
->span
.y_flags
|= 1<<(_y
&1);
657 /* save the values so that emaj can be restarted:
659 eleft
->sx
+= lines
* eleft
->dxdy
;
660 eright
->sx
+= lines
* eright
->dxdy
;
667 * Do setup for triangle rasterization, then render the triangle.
669 static void setup_tri( struct draw_stage
*stage
,
670 struct prim_header
*prim
)
672 struct setup_stage
*setup
= setup_stage( stage
);
675 debug_printf("%s\n", __FUNCTION__ );
678 setup_sort_vertices( setup
, prim
);
679 setup_tri_coefficients( setup
);
680 setup_tri_edges( setup
);
682 setup
->quad
.prim
= PRIM_TRI
;
685 setup
->span
.y_flags
= 0;
686 setup
->span
.right
[0] = 0;
687 setup
->span
.right
[1] = 0;
688 /* setup->span.z_mode = tri_z_mode( setup->ctx ); */
690 /* init_constant_attribs( setup ); */
692 if (setup
->oneoverarea
< 0.0) {
695 subtriangle( setup
, &setup
->emaj
, &setup
->ebot
, setup
->ebot
.lines
);
696 subtriangle( setup
, &setup
->emaj
, &setup
->etop
, setup
->etop
.lines
);
701 subtriangle( setup
, &setup
->ebot
, &setup
->emaj
, setup
->ebot
.lines
);
702 subtriangle( setup
, &setup
->etop
, &setup
->emaj
, setup
->etop
.lines
);
705 flush_spans( setup
);
711 * Compute a0, dadx and dady for a linearly interpolated coefficient,
715 line_linear_coeff(struct setup_stage
*setup
,
716 struct tgsi_interp_coef
*coef
,
717 uint vertSlot
, uint i
)
719 const float da
= setup
->vmax
->data
[vertSlot
][i
] - setup
->vmin
->data
[vertSlot
][i
];
720 const float dadx
= da
* setup
->emaj
.dx
* setup
->oneoverarea
;
721 const float dady
= da
* setup
->emaj
.dy
* setup
->oneoverarea
;
722 coef
->dadx
[i
] = dadx
;
723 coef
->dady
[i
] = dady
;
724 coef
->a0
[i
] = (setup
->vmin
->data
[vertSlot
][i
] -
725 (dadx
* (setup
->vmin
->data
[0][0] - 0.5f
) +
726 dady
* (setup
->vmin
->data
[0][1] - 0.5f
)));
731 * Compute a0, dadx and dady for a perspective-corrected interpolant,
735 line_persp_coeff(struct setup_stage
*setup
,
736 struct tgsi_interp_coef
*coef
,
737 uint vertSlot
, uint i
)
739 /* XXX double-check/verify this arithmetic */
740 const float a0
= setup
->vmin
->data
[vertSlot
][i
] * setup
->vmin
->data
[0][3];
741 const float a1
= setup
->vmax
->data
[vertSlot
][i
] * setup
->vmax
->data
[0][3];
742 const float da
= a1
- a0
;
743 const float dadx
= da
* setup
->emaj
.dx
* setup
->oneoverarea
;
744 const float dady
= da
* setup
->emaj
.dy
* setup
->oneoverarea
;
745 coef
->dadx
[i
] = dadx
;
746 coef
->dady
[i
] = dady
;
747 coef
->a0
[i
] = (setup
->vmin
->data
[vertSlot
][i
] -
748 (dadx
* (setup
->vmin
->data
[0][0] - 0.5f
) +
749 dady
* (setup
->vmin
->data
[0][1] - 0.5f
)));
754 * Compute the setup->coef[] array dadx, dady, a0 values.
755 * Must be called after setup->vmin,vmax are initialized.
758 setup_line_coefficients(struct setup_stage
*setup
, struct prim_header
*prim
)
760 struct softpipe_context
*softpipe
= setup
->softpipe
;
761 const struct pipe_shader_state
*fs
= &setup
->softpipe
->fs
->shader
;
762 const struct vertex_info
*vinfo
= softpipe_get_vertex_info(softpipe
);
765 /* use setup->vmin, vmax to point to vertices */
766 setup
->vprovoke
= prim
->v
[1];
767 setup
->vmin
= prim
->v
[0];
768 setup
->vmax
= prim
->v
[1];
770 setup
->emaj
.dx
= setup
->vmax
->data
[0][0] - setup
->vmin
->data
[0][0];
771 setup
->emaj
.dy
= setup
->vmax
->data
[0][1] - setup
->vmin
->data
[0][1];
772 /* NOTE: this is not really 1/area */
773 setup
->oneoverarea
= 1.0f
/ (setup
->emaj
.dx
* setup
->emaj
.dx
+
774 setup
->emaj
.dy
* setup
->emaj
.dy
);
776 /* z and w are done by linear interpolation:
778 line_linear_coeff(setup
, &setup
->posCoef
, 0, 2);
779 line_linear_coeff(setup
, &setup
->posCoef
, 0, 3);
781 /* setup interpolation for all the remaining attributes:
783 for (fragSlot
= 0; fragSlot
< fs
->num_inputs
; fragSlot
++) {
784 const uint vertSlot
= vinfo
->src_index
[fragSlot
];
787 switch (vinfo
->interp_mode
[fragSlot
]) {
788 case INTERP_CONSTANT
:
789 for (j
= 0; j
< NUM_CHANNELS
; j
++)
790 const_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
793 for (j
= 0; j
< NUM_CHANNELS
; j
++)
794 line_linear_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
796 case INTERP_PERSPECTIVE
:
797 for (j
= 0; j
< NUM_CHANNELS
; j
++)
798 line_persp_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
801 assert(fragSlot
== 0);
802 assert(0); /* XXX fix this: */
803 setup_fragcoord_coeff(setup
);
809 if (fs
->input_semantic_name
[fragSlot
] == TGSI_SEMANTIC_FOG
) {
810 /* FOG.y = front/back facing XXX fix this */
811 setup
->coef
[fragSlot
].a0
[1] = 1.0f
- setup
->quad
.facing
;
812 setup
->coef
[fragSlot
].dadx
[1] = 0.0;
813 setup
->coef
[fragSlot
].dady
[1] = 0.0;
820 * Plot a pixel in a line segment.
823 plot(struct setup_stage
*setup
, int x
, int y
)
825 const int iy
= y
& 1;
826 const int ix
= x
& 1;
827 const int quadX
= x
- ix
;
828 const int quadY
= y
- iy
;
829 const int mask
= (1 << ix
) << (2 * iy
);
831 if (quadX
!= setup
->quad
.x0
||
832 quadY
!= setup
->quad
.y0
)
834 /* flush prev quad, start new quad */
836 if (setup
->quad
.x0
!= -1)
837 clip_emit_quad(setup
);
839 setup
->quad
.x0
= quadX
;
840 setup
->quad
.y0
= quadY
;
841 setup
->quad
.mask
= 0x0;
844 setup
->quad
.mask
|= mask
;
849 * Do setup for line rasterization, then render the line.
850 * Single-pixel width, no stipple, etc. We rely on the 'draw' module
851 * to handle stippling and wide lines.
854 setup_line(struct draw_stage
*stage
, struct prim_header
*prim
)
856 const struct vertex_header
*v0
= prim
->v
[0];
857 const struct vertex_header
*v1
= prim
->v
[1];
858 struct setup_stage
*setup
= setup_stage( stage
);
859 int x0
= (int) v0
->data
[0][0];
860 int x1
= (int) v1
->data
[0][0];
861 int y0
= (int) v0
->data
[0][1];
862 int y1
= (int) v1
->data
[0][1];
867 if (dx
== 0 && dy
== 0)
870 setup_line_coefficients(setup
, prim
);
873 dx
= -dx
; /* make positive */
881 dy
= -dy
; /* make positive */
891 setup
->quad
.x0
= setup
->quad
.y0
= -1;
892 setup
->quad
.mask
= 0x0;
893 setup
->quad
.prim
= PRIM_LINE
;
894 /* XXX temporary: set coverage to 1.0 so the line appears
895 * if AA mode happens to be enabled.
897 setup
->quad
.coverage
[0] =
898 setup
->quad
.coverage
[1] =
899 setup
->quad
.coverage
[2] =
900 setup
->quad
.coverage
[3] = 1.0;
903 /*** X-major line ***/
905 const int errorInc
= dy
+ dy
;
906 int error
= errorInc
- dx
;
907 const int errorDec
= error
- dx
;
909 for (i
= 0; i
< dx
; i
++) {
923 /*** Y-major line ***/
925 const int errorInc
= dx
+ dx
;
926 int error
= errorInc
- dy
;
927 const int errorDec
= error
- dy
;
929 for (i
= 0; i
< dy
; i
++) {
943 /* draw final quad */
944 if (setup
->quad
.mask
) {
945 clip_emit_quad(setup
);
951 point_persp_coeff(struct setup_stage
*setup
,
952 const struct vertex_header
*vert
,
953 struct tgsi_interp_coef
*coef
,
954 uint vertSlot
, uint i
)
957 coef
->dadx
[i
] = 0.0F
;
958 coef
->dady
[i
] = 0.0F
;
959 coef
->a0
[i
] = vert
->data
[vertSlot
][i
] * vert
->data
[0][3];
964 * Do setup for point rasterization, then render the point.
965 * Round or square points...
966 * XXX could optimize a lot for 1-pixel points.
969 setup_point(struct draw_stage
*stage
, struct prim_header
*prim
)
971 struct setup_stage
*setup
= setup_stage( stage
);
972 struct softpipe_context
*softpipe
= setup
->softpipe
;
973 const struct pipe_shader_state
*fs
= &softpipe
->fs
->shader
;
974 const struct vertex_header
*v0
= prim
->v
[0];
975 const int sizeAttr
= setup
->softpipe
->psize_slot
;
977 = sizeAttr
> 0 ? v0
->data
[sizeAttr
][0]
978 : setup
->softpipe
->rasterizer
->point_size
;
979 const float halfSize
= 0.5F
* size
;
980 const boolean round
= (boolean
) setup
->softpipe
->rasterizer
->point_smooth
;
981 const float x
= v0
->data
[0][0]; /* Note: data[0] is always position */
982 const float y
= v0
->data
[0][1];
983 const struct vertex_info
*vinfo
= softpipe_get_vertex_info(softpipe
);
986 /* For points, all interpolants are constant-valued.
987 * However, for point sprites, we'll need to setup texcoords appropriately.
988 * XXX: which coefficients are the texcoords???
989 * We may do point sprites as textured quads...
991 * KW: We don't know which coefficients are texcoords - ultimately
992 * the choice of what interpolation mode to use for each attribute
993 * should be determined by the fragment program, using
994 * per-attribute declaration statements that include interpolation
995 * mode as a parameter. So either the fragment program will have
996 * to be adjusted for pointsprite vs normal point behaviour, or
997 * otherwise a special interpolation mode will have to be defined
998 * which matches the required behaviour for point sprites. But -
999 * the latter is not a feature of normal hardware, and as such
1000 * probably should be ruled out on that basis.
1002 setup
->vprovoke
= prim
->v
[0];
1005 const_coeff(setup
, &setup
->posCoef
, 0, 2);
1006 const_coeff(setup
, &setup
->posCoef
, 0, 3);
1008 for (fragSlot
= 0; fragSlot
< fs
->num_inputs
; fragSlot
++) {
1009 const uint vertSlot
= vinfo
->src_index
[fragSlot
];
1012 switch (vinfo
->interp_mode
[fragSlot
]) {
1013 case INTERP_CONSTANT
:
1016 for (j
= 0; j
< NUM_CHANNELS
; j
++)
1017 const_coeff(setup
, &setup
->coef
[fragSlot
], vertSlot
, j
);
1019 case INTERP_PERSPECTIVE
:
1020 for (j
= 0; j
< NUM_CHANNELS
; j
++)
1021 point_persp_coeff(setup
, setup
->vprovoke
,
1022 &setup
->coef
[fragSlot
], vertSlot
, j
);
1025 assert(fragSlot
== 0);
1026 assert(0); /* XXX fix this: */
1027 setup_fragcoord_coeff(setup
);
1033 if (fs
->input_semantic_name
[fragSlot
] == TGSI_SEMANTIC_FOG
) {
1034 /* FOG.y = front/back facing XXX fix this */
1035 setup
->coef
[fragSlot
].a0
[1] = 1.0f
- setup
->quad
.facing
;
1036 setup
->coef
[fragSlot
].dadx
[1] = 0.0;
1037 setup
->coef
[fragSlot
].dady
[1] = 0.0;
1041 setup
->quad
.prim
= PRIM_POINT
;
1043 if (halfSize
<= 0.5 && !round
) {
1044 /* special case for 1-pixel points */
1045 const int ix
= ((int) x
) & 1;
1046 const int iy
= ((int) y
) & 1;
1047 setup
->quad
.x0
= (int) x
- ix
;
1048 setup
->quad
.y0
= (int) y
- iy
;
1049 setup
->quad
.mask
= (1 << ix
) << (2 * iy
);
1050 clip_emit_quad(setup
);
1054 /* rounded points */
1055 const int ixmin
= block((int) (x
- halfSize
));
1056 const int ixmax
= block((int) (x
+ halfSize
));
1057 const int iymin
= block((int) (y
- halfSize
));
1058 const int iymax
= block((int) (y
+ halfSize
));
1059 const float rmin
= halfSize
- 0.7071F
; /* 0.7071 = sqrt(2)/2 */
1060 const float rmax
= halfSize
+ 0.7071F
;
1061 const float rmin2
= MAX2(0.0F
, rmin
* rmin
);
1062 const float rmax2
= rmax
* rmax
;
1063 const float cscale
= 1.0F
/ (rmax2
- rmin2
);
1066 for (iy
= iymin
; iy
<= iymax
; iy
+= 2) {
1067 for (ix
= ixmin
; ix
<= ixmax
; ix
+= 2) {
1068 float dx
, dy
, dist2
, cover
;
1070 setup
->quad
.mask
= 0x0;
1072 dx
= (ix
+ 0.5f
) - x
;
1073 dy
= (iy
+ 0.5f
) - y
;
1074 dist2
= dx
* dx
+ dy
* dy
;
1075 if (dist2
<= rmax2
) {
1076 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
1077 setup
->quad
.coverage
[QUAD_TOP_LEFT
] = MIN2(cover
, 1.0f
);
1078 setup
->quad
.mask
|= MASK_TOP_LEFT
;
1081 dx
= (ix
+ 1.5f
) - x
;
1082 dy
= (iy
+ 0.5f
) - y
;
1083 dist2
= dx
* dx
+ dy
* dy
;
1084 if (dist2
<= rmax2
) {
1085 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
1086 setup
->quad
.coverage
[QUAD_TOP_RIGHT
] = MIN2(cover
, 1.0f
);
1087 setup
->quad
.mask
|= MASK_TOP_RIGHT
;
1090 dx
= (ix
+ 0.5f
) - x
;
1091 dy
= (iy
+ 1.5f
) - y
;
1092 dist2
= dx
* dx
+ dy
* dy
;
1093 if (dist2
<= rmax2
) {
1094 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
1095 setup
->quad
.coverage
[QUAD_BOTTOM_LEFT
] = MIN2(cover
, 1.0f
);
1096 setup
->quad
.mask
|= MASK_BOTTOM_LEFT
;
1099 dx
= (ix
+ 1.5f
) - x
;
1100 dy
= (iy
+ 1.5f
) - y
;
1101 dist2
= dx
* dx
+ dy
* dy
;
1102 if (dist2
<= rmax2
) {
1103 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
1104 setup
->quad
.coverage
[QUAD_BOTTOM_RIGHT
] = MIN2(cover
, 1.0f
);
1105 setup
->quad
.mask
|= MASK_BOTTOM_RIGHT
;
1108 if (setup
->quad
.mask
) {
1109 setup
->quad
.x0
= ix
;
1110 setup
->quad
.y0
= iy
;
1111 clip_emit_quad(setup
);
1118 const int xmin
= (int) (x
+ 0.75 - halfSize
);
1119 const int ymin
= (int) (y
+ 0.25 - halfSize
);
1120 const int xmax
= xmin
+ (int) size
;
1121 const int ymax
= ymin
+ (int) size
;
1122 /* XXX could apply scissor to xmin,ymin,xmax,ymax now */
1123 const int ixmin
= block(xmin
);
1124 const int ixmax
= block(xmax
- 1);
1125 const int iymin
= block(ymin
);
1126 const int iymax
= block(ymax
- 1);
1130 debug_printf("(%f, %f) -> X:%d..%d Y:%d..%d\n", x, y, xmin, xmax,ymin,ymax);
1132 for (iy
= iymin
; iy
<= iymax
; iy
+= 2) {
1135 /* above the top edge */
1136 rowMask
&= (MASK_BOTTOM_LEFT
| MASK_BOTTOM_RIGHT
);
1138 if (iy
+ 1 >= ymax
) {
1139 /* below the bottom edge */
1140 rowMask
&= (MASK_TOP_LEFT
| MASK_TOP_RIGHT
);
1143 for (ix
= ixmin
; ix
<= ixmax
; ix
+= 2) {
1144 uint mask
= rowMask
;
1147 /* fragment is past left edge of point, turn off left bits */
1148 mask
&= (MASK_BOTTOM_RIGHT
| MASK_TOP_RIGHT
);
1150 if (ix
+ 1 >= xmax
) {
1151 /* past the right edge */
1152 mask
&= (MASK_BOTTOM_LEFT
| MASK_TOP_LEFT
);
1155 setup
->quad
.mask
= mask
;
1156 setup
->quad
.x0
= ix
;
1157 setup
->quad
.y0
= iy
;
1158 clip_emit_quad(setup
);
1167 static void setup_begin( struct draw_stage
*stage
)
1169 struct setup_stage
*setup
= setup_stage(stage
);
1170 struct softpipe_context
*sp
= setup
->softpipe
;
1171 const struct pipe_shader_state
*fs
= &setup
->softpipe
->fs
->shader
;
1173 setup
->quad
.nr_attrs
= fs
->num_inputs
;
1175 sp
->quad
.first
->begin(sp
->quad
.first
);
1177 stage
->point
= setup_point
;
1178 stage
->line
= setup_line
;
1179 stage
->tri
= setup_tri
;
1183 static void setup_first_point( struct draw_stage
*stage
,
1184 struct prim_header
*header
)
1187 stage
->point( stage
, header
);
1190 static void setup_first_line( struct draw_stage
*stage
,
1191 struct prim_header
*header
)
1194 stage
->line( stage
, header
);
1198 static void setup_first_tri( struct draw_stage
*stage
,
1199 struct prim_header
*header
)
1202 stage
->tri( stage
, header
);
1207 static void setup_flush( struct draw_stage
*stage
,
1210 stage
->point
= setup_first_point
;
1211 stage
->line
= setup_first_line
;
1212 stage
->tri
= setup_first_tri
;
1216 static void reset_stipple_counter( struct draw_stage
*stage
)
1221 static void render_destroy( struct draw_stage
*stage
)
1228 * Create a new primitive setup/render stage.
1230 struct draw_stage
*sp_draw_render_stage( struct softpipe_context
*softpipe
)
1232 struct setup_stage
*setup
= CALLOC_STRUCT(setup_stage
);
1234 setup
->softpipe
= softpipe
;
1235 setup
->stage
.draw
= softpipe
->draw
;
1236 setup
->stage
.point
= setup_first_point
;
1237 setup
->stage
.line
= setup_first_line
;
1238 setup
->stage
.tri
= setup_first_tri
;
1239 setup
->stage
.flush
= setup_flush
;
1240 setup
->stage
.reset_stipple_counter
= reset_stipple_counter
;
1241 setup
->stage
.destroy
= render_destroy
;
1243 setup
->quad
.coef
= setup
->coef
;
1244 setup
->quad
.posCoef
= &setup
->posCoef
;
1246 return &setup
->stage
;