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"
39 #include "sp_prim_setup.h"
40 #include "pipe/draw/draw_private.h"
41 #include "pipe/p_util.h"
45 #define FRAG_ATTRIB_WPOS 0
46 #define FRAG_ATTRIB_MAX 13
53 float dx
; /**< X(v1) - X(v0), used only during setup */
54 float dy
; /**< Y(v1) - Y(v0), used only during setup */
55 float dxdy
; /**< dx/dy */
56 float sx
, sy
; /**< first sample point coord */
57 int lines
; /**< number of lines on this edge */
62 * Triangle setup info (derived from draw_stage).
63 * Also used for line drawing (taking some liberties).
66 struct draw_stage stage
; /**< This must be first (base class) */
68 struct softpipe_context
*softpipe
;
70 /* Vertices are just an array of floats making up each attribute in
71 * turn. Currently fixed at 4 floats, but should change in time.
72 * Codegen will help cope with this.
74 const struct vertex_header
*vmax
;
75 const struct vertex_header
*vmid
;
76 const struct vertex_header
*vmin
;
77 const struct vertex_header
*vprovoke
;
85 struct tgsi_interp_coef coef
[FRAG_ATTRIB_MAX
];
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_TOP_LEFT
| MASK_TOP_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_BOTTOM_LEFT
| MASK_BOTTOM_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
,
189 if (x
>= setup
->span
.left
[0] && x
< setup
->span
.right
[0])
190 mask
|= MASK_BOTTOM_LEFT
;
192 if (x
>= setup
->span
.left
[1] && x
< setup
->span
.right
[1])
193 mask
|= MASK_TOP_LEFT
;
195 if (x
+1 >= setup
->span
.left
[0] && x
+1 < setup
->span
.right
[0])
196 mask
|= MASK_BOTTOM_RIGHT
;
198 if (x
+1 >= setup
->span
.left
[1] && x
+1 < setup
->span
.right
[1])
199 mask
|= MASK_TOP_RIGHT
;
206 * Render a horizontal span of quads
208 static void flush_spans( struct setup_stage
*setup
)
210 int minleft
, maxright
;
213 switch (setup
->span
.y_flags
) {
215 minleft
= MIN2(setup
->span
.left
[0], setup
->span
.left
[1]);
216 maxright
= MAX2(setup
->span
.right
[0], setup
->span
.right
[1]);
220 minleft
= setup
->span
.left
[0];
221 maxright
= setup
->span
.right
[0];
225 minleft
= setup
->span
.left
[1];
226 maxright
= setup
->span
.right
[1];
234 for (x
= block(minleft
); x
<= block(maxright
); )
236 emit_quad( setup
, x
, setup
->span
.y
,
237 calculate_mask( setup
, x
) );
242 setup
->span
.y_flags
= 0;
243 setup
->span
.right
[0] = 0;
244 setup
->span
.right
[1] = 0;
248 static void print_vertex(const struct setup_stage
*setup
,
249 const struct vertex_header
*v
)
253 for (i
= 0; i
< setup
->softpipe
->nr_attrs
; i
++) {
254 printf(" %d: %f %f %f\n", i
,
255 v
->data
[i
][0], v
->data
[i
][1], v
->data
[i
][2]);
260 static boolean
setup_sort_vertices( struct setup_stage
*setup
,
261 const struct prim_header
*prim
)
263 const struct vertex_header
*v0
= prim
->v
[0];
264 const struct vertex_header
*v1
= prim
->v
[1];
265 const struct vertex_header
*v2
= prim
->v
[2];
268 printf("Triangle:\n");
269 print_vertex(setup
, v0
);
270 print_vertex(setup
, v1
);
271 print_vertex(setup
, v2
);
274 setup
->vprovoke
= v2
;
276 /* determine bottom to top order of vertices */
278 float y0
= v0
->data
[0][1];
279 float y1
= v1
->data
[0][1];
280 float y2
= v2
->data
[0][1];
323 setup
->ebot
.dx
= setup
->vmid
->data
[0][0] - setup
->vmin
->data
[0][0];
324 setup
->ebot
.dy
= setup
->vmid
->data
[0][1] - setup
->vmin
->data
[0][1];
325 setup
->emaj
.dx
= setup
->vmax
->data
[0][0] - setup
->vmin
->data
[0][0];
326 setup
->emaj
.dy
= setup
->vmax
->data
[0][1] - setup
->vmin
->data
[0][1];
327 setup
->etop
.dx
= setup
->vmax
->data
[0][0] - setup
->vmid
->data
[0][0];
328 setup
->etop
.dy
= setup
->vmax
->data
[0][1] - setup
->vmid
->data
[0][1];
331 * Compute triangle's area. Use 1/area to compute partial
332 * derivatives of attributes later.
334 * The area will be the same as prim->det, but the sign may be
335 * different depending on how the vertices get sorted above.
337 * To determine whether the primitive is front or back facing we
338 * use the prim->det value because its sign is correct.
341 const float area
= (setup
->emaj
.dx
* setup
->ebot
.dy
-
342 setup
->ebot
.dx
* setup
->emaj
.dy
);
344 setup
->oneoverarea
= 1.0f
/ area
;
346 _mesa_printf("%s one-over-area %f area %f det %f\n",
347 __FUNCTION__, setup->oneoverarea, area, prim->det );
351 /* We need to know if this is a front or back-facing triangle for:
352 * - the GLSL gl_FrontFacing fragment attribute (bool)
353 * - two-sided stencil test
355 setup
->quad
.facing
= (prim
->det
> 0.0) ^ (setup
->softpipe
->setup
.front_winding
== PIPE_WINDING_CW
);
362 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
363 * The value value comes from vertex->data[slot][i].
364 * The result will be put into setup->coef[slot].a0[i].
365 * \param slot which attribute slot
366 * \param i which component of the slot (0..3)
368 static void const_coeff( struct setup_stage
*setup
,
372 assert(slot
< FRAG_ATTRIB_MAX
);
375 setup
->coef
[slot
].dadx
[i
] = 0;
376 setup
->coef
[slot
].dady
[i
] = 0;
378 /* need provoking vertex info!
380 setup
->coef
[slot
].a0
[i
] = setup
->vprovoke
->data
[slot
][i
];
385 * Compute a0, dadx and dady for a linearly interpolated coefficient,
388 static void tri_linear_coeff( struct setup_stage
*setup
,
392 float botda
= setup
->vmid
->data
[slot
][i
] - setup
->vmin
->data
[slot
][i
];
393 float majda
= setup
->vmax
->data
[slot
][i
] - setup
->vmin
->data
[slot
][i
];
394 float a
= setup
->ebot
.dy
* majda
- botda
* setup
->emaj
.dy
;
395 float b
= setup
->emaj
.dx
* botda
- majda
* setup
->ebot
.dx
;
397 assert(slot
< FRAG_ATTRIB_MAX
);
400 setup
->coef
[slot
].dadx
[i
] = a
* setup
->oneoverarea
;
401 setup
->coef
[slot
].dady
[i
] = b
* setup
->oneoverarea
;
403 /* calculate a0 as the value which would be sampled for the
404 * fragment at (0,0), taking into account that we want to sample at
405 * pixel centers, in other words (0.5, 0.5).
407 * this is neat but unfortunately not a good way to do things for
408 * triangles with very large values of dadx or dady as it will
409 * result in the subtraction and re-addition from a0 of a very
410 * large number, which means we'll end up loosing a lot of the
411 * fractional bits and precision from a0. the way to fix this is
412 * to define a0 as the sample at a pixel center somewhere near vmin
413 * instead - i'll switch to this later.
415 setup
->coef
[slot
].a0
[i
] = (setup
->vmin
->data
[slot
][i
] -
416 (setup
->coef
[slot
].dadx
[i
] * (setup
->vmin
->data
[0][0] - 0.5f
) +
417 setup
->coef
[slot
].dady
[i
] * (setup
->vmin
->data
[0][1] - 0.5f
)));
420 _mesa_printf("attr[%d].%c: %f dx:%f dy:%f\n",
422 setup->coef[slot].a0[i],
423 setup->coef[slot].dadx[i],
424 setup->coef[slot].dady[i]);
430 * Compute a0, dadx and dady for a perspective-corrected interpolant,
433 static void tri_persp_coeff( struct setup_stage
*setup
,
437 /* premultiply by 1/w:
439 float mina
= setup
->vmin
->data
[slot
][i
] * setup
->vmin
->data
[0][3];
440 float mida
= setup
->vmid
->data
[slot
][i
] * setup
->vmid
->data
[0][3];
441 float maxa
= setup
->vmax
->data
[slot
][i
] * setup
->vmax
->data
[0][3];
443 float botda
= mida
- mina
;
444 float majda
= maxa
- mina
;
445 float a
= setup
->ebot
.dy
* majda
- botda
* setup
->emaj
.dy
;
446 float b
= setup
->emaj
.dx
* botda
- majda
* setup
->ebot
.dx
;
448 assert(slot
< FRAG_ATTRIB_MAX
);
451 setup
->coef
[slot
].dadx
[i
] = a
* setup
->oneoverarea
;
452 setup
->coef
[slot
].dady
[i
] = b
* setup
->oneoverarea
;
453 setup
->coef
[slot
].a0
[i
] = (mina
-
454 (setup
->coef
[slot
].dadx
[i
] * (setup
->vmin
->data
[0][0] - 0.5f
) +
455 setup
->coef
[slot
].dady
[i
] * (setup
->vmin
->data
[0][1] - 0.5f
)));
460 * Compute the setup->coef[] array dadx, dady, a0 values.
461 * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
463 static void setup_tri_coefficients( struct setup_stage
*setup
)
465 const enum interp_mode
*interp
= setup
->softpipe
->interp
;
468 /* z and w are done by linear interpolation:
470 tri_linear_coeff(setup
, 0, 2);
471 tri_linear_coeff(setup
, 0, 3);
473 /* setup interpolation for all the remaining attributes:
475 for (slot
= 1; slot
< setup
->quad
.nr_attrs
; slot
++) {
476 switch (interp
[slot
]) {
477 case INTERP_CONSTANT
:
478 for (j
= 0; j
< NUM_CHANNELS
; j
++)
479 const_coeff(setup
, slot
, j
);
483 for (j
= 0; j
< NUM_CHANNELS
; j
++)
484 tri_linear_coeff(setup
, slot
, j
);
487 case INTERP_PERSPECTIVE
:
488 for (j
= 0; j
< NUM_CHANNELS
; j
++)
489 tri_persp_coeff(setup
, slot
, j
);
497 static void setup_tri_edges( struct setup_stage
*setup
)
499 float vmin_x
= setup
->vmin
->data
[0][0] + 0.5f
;
500 float vmid_x
= setup
->vmid
->data
[0][0] + 0.5f
;
502 float vmin_y
= setup
->vmin
->data
[0][1] - 0.5f
;
503 float vmid_y
= setup
->vmid
->data
[0][1] - 0.5f
;
504 float vmax_y
= setup
->vmax
->data
[0][1] - 0.5f
;
506 setup
->emaj
.sy
= ceilf(vmin_y
);
507 setup
->emaj
.lines
= (int) ceilf(vmax_y
- setup
->emaj
.sy
);
508 setup
->emaj
.dxdy
= setup
->emaj
.dx
/ setup
->emaj
.dy
;
509 setup
->emaj
.sx
= vmin_x
+ (setup
->emaj
.sy
- vmin_y
) * setup
->emaj
.dxdy
;
511 setup
->etop
.sy
= ceilf(vmid_y
);
512 setup
->etop
.lines
= (int) ceilf(vmax_y
- setup
->etop
.sy
);
513 setup
->etop
.dxdy
= setup
->etop
.dx
/ setup
->etop
.dy
;
514 setup
->etop
.sx
= vmid_x
+ (setup
->etop
.sy
- vmid_y
) * setup
->etop
.dxdy
;
516 setup
->ebot
.sy
= ceilf(vmin_y
);
517 setup
->ebot
.lines
= (int) ceilf(vmid_y
- setup
->ebot
.sy
);
518 setup
->ebot
.dxdy
= setup
->ebot
.dx
/ setup
->ebot
.dy
;
519 setup
->ebot
.sx
= vmin_x
+ (setup
->ebot
.sy
- vmin_y
) * setup
->ebot
.dxdy
;
524 * Render the upper or lower half of a triangle.
525 * Scissoring/cliprect is applied here too.
527 static void subtriangle( struct setup_stage
*setup
,
532 const struct pipe_scissor_state
*cliprect
= &setup
->softpipe
->cliprect
;
533 const int minx
= (int) cliprect
->minx
;
534 const int maxx
= (int) cliprect
->maxx
;
535 const int miny
= (int) cliprect
->miny
;
536 const int maxy
= (int) cliprect
->maxy
;
537 int y
, start_y
, finish_y
;
538 int sy
= (int)eleft
->sy
;
540 assert((int)eleft
->sy
== (int) eright
->sy
);
542 /* clip top/bottom */
544 finish_y
= sy
+ lines
;
556 _mesa_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);
559 for (y
= start_y
; y
< finish_y
; y
++) {
561 /* avoid accumulating adds as floats don't have the precision to
562 * accurately iterate large triangle edges that way. luckily we
563 * can just multiply these days.
565 * this is all drowned out by the attribute interpolation anyway.
567 int left
= (int)(eleft
->sx
+ y
* eleft
->dxdy
);
568 int right
= (int)(eright
->sx
+ y
* eright
->dxdy
);
570 /* clip left/right */
578 if (block(_y
) != setup
->span
.y
) {
580 setup
->span
.y
= block(_y
);
583 setup
->span
.left
[_y
&1] = left
;setup
->span
.right
[_y
&1] = right
;
584 setup
->span
.y_flags
|= 1<<(_y
&1);
589 /* save the values so that emaj can be restarted:
591 eleft
->sx
+= lines
* eleft
->dxdy
;
592 eright
->sx
+= lines
* eright
->dxdy
;
599 * Do setup for triangle rasterization, then render the triangle.
601 static void setup_tri( struct draw_stage
*stage
,
602 struct prim_header
*prim
)
604 struct setup_stage
*setup
= setup_stage( stage
);
607 _mesa_printf("%s\n", __FUNCTION__ );
610 setup_sort_vertices( setup
, prim
);
611 setup_tri_coefficients( setup
);
612 setup_tri_edges( setup
);
614 setup
->quad
.prim
= PRIM_TRI
;
617 setup
->span
.y_flags
= 0;
618 setup
->span
.right
[0] = 0;
619 setup
->span
.right
[1] = 0;
620 /* setup->span.z_mode = tri_z_mode( setup->ctx ); */
622 /* init_constant_attribs( setup ); */
624 if (setup
->oneoverarea
< 0.0) {
627 subtriangle( setup
, &setup
->emaj
, &setup
->ebot
, setup
->ebot
.lines
);
628 subtriangle( setup
, &setup
->emaj
, &setup
->etop
, setup
->etop
.lines
);
633 subtriangle( setup
, &setup
->ebot
, &setup
->emaj
, setup
->ebot
.lines
);
634 subtriangle( setup
, &setup
->etop
, &setup
->emaj
, setup
->etop
.lines
);
637 flush_spans( setup
);
643 * Compute a0, dadx and dady for a linearly interpolated coefficient,
647 line_linear_coeff(struct setup_stage
*setup
, unsigned slot
, unsigned i
)
649 const float dz
= setup
->vmax
->data
[slot
][i
] - setup
->vmin
->data
[slot
][i
];
650 const float dadx
= dz
* setup
->emaj
.dx
* setup
->oneoverarea
;
651 const float dady
= dz
* setup
->emaj
.dy
* setup
->oneoverarea
;
652 setup
->coef
[slot
].dadx
[i
] = dadx
;
653 setup
->coef
[slot
].dady
[i
] = dady
;
654 setup
->coef
[slot
].a0
[i
]
655 = (setup
->vmin
->data
[slot
][i
] -
656 (dadx
* (setup
->vmin
->data
[0][0] - 0.5f
) +
657 dady
* (setup
->vmin
->data
[0][1] - 0.5f
)));
662 * Compute a0, dadx and dady for a perspective-corrected interpolant,
666 line_persp_coeff(struct setup_stage
*setup
, unsigned slot
, unsigned i
)
669 line_linear_coeff(setup
, slot
, i
); /* XXX temporary */
674 * Compute the setup->coef[] array dadx, dady, a0 values.
675 * Must be called after setup->vmin,vmax are initialized.
678 setup_line_coefficients(struct setup_stage
*setup
, struct prim_header
*prim
)
680 const enum interp_mode
*interp
= setup
->softpipe
->interp
;
683 /* use setup->vmin, vmax to point to vertices */
684 setup
->vprovoke
= prim
->v
[1];
685 setup
->vmin
= prim
->v
[0];
686 setup
->vmax
= prim
->v
[1];
688 setup
->emaj
.dx
= setup
->vmax
->data
[0][0] - setup
->vmin
->data
[0][0];
689 setup
->emaj
.dy
= setup
->vmax
->data
[0][1] - setup
->vmin
->data
[0][1];
690 /* NOTE: this is not really 1/area */
691 setup
->oneoverarea
= 1.0f
/ (setup
->emaj
.dx
* setup
->emaj
.dx
+
692 setup
->emaj
.dy
* setup
->emaj
.dy
);
694 /* z and w are done by linear interpolation:
696 line_linear_coeff(setup
, 0, 2);
697 line_linear_coeff(setup
, 0, 3);
699 /* setup interpolation for all the remaining attributes:
701 for (slot
= 1; slot
< setup
->quad
.nr_attrs
; slot
++) {
702 switch (interp
[slot
]) {
703 case INTERP_CONSTANT
:
704 for (j
= 0; j
< NUM_CHANNELS
; j
++)
705 const_coeff(setup
, slot
, j
);
709 for (j
= 0; j
< NUM_CHANNELS
; j
++)
710 line_linear_coeff(setup
, slot
, j
);
713 case INTERP_PERSPECTIVE
:
714 for (j
= 0; j
< NUM_CHANNELS
; j
++)
715 line_persp_coeff(setup
, slot
, j
);
723 * Plot a pixel in a line segment.
726 plot(struct setup_stage
*setup
, int x
, int y
)
728 const int iy
= y
& 1;
729 const int ix
= x
& 1;
730 const int quadX
= x
- ix
;
731 const int quadY
= y
- iy
;
732 const int mask
= (1 << ix
) << (2 * iy
);
734 if (quadX
!= setup
->quad
.x0
||
735 quadY
!= setup
->quad
.y0
)
737 /* flush prev quad, start new quad */
739 if (setup
->quad
.x0
!= -1)
740 clip_emit_quad(setup
);
742 setup
->quad
.x0
= quadX
;
743 setup
->quad
.y0
= quadY
;
744 setup
->quad
.mask
= 0x0;
747 setup
->quad
.mask
|= mask
;
752 * Determine whether or not to emit a line fragment by checking
753 * line stipple pattern.
755 static INLINE
unsigned
756 stipple_test(int counter
, ushort pattern
, int factor
)
758 int b
= (counter
/ factor
) & 0xf;
759 return (1 << b
) & pattern
;
764 * Do setup for line rasterization, then render the line.
765 * XXX single-pixel width, no stipple, etc
768 setup_line(struct draw_stage
*stage
, struct prim_header
*prim
)
770 const struct vertex_header
*v0
= prim
->v
[0];
771 const struct vertex_header
*v1
= prim
->v
[1];
772 struct setup_stage
*setup
= setup_stage( stage
);
773 struct softpipe_context
*sp
= setup
->softpipe
;
775 int x0
= (int) v0
->data
[0][0];
776 int x1
= (int) v1
->data
[0][0];
777 int y0
= (int) v0
->data
[0][1];
778 int y1
= (int) v1
->data
[0][1];
783 if (dx
== 0 && dy
== 0)
786 setup_line_coefficients(setup
, prim
);
789 dx
= -dx
; /* make positive */
797 dy
= -dy
; /* make positive */
807 setup
->quad
.x0
= setup
->quad
.y0
= -1;
808 setup
->quad
.mask
= 0x0;
809 setup
->quad
.prim
= PRIM_LINE
;
810 /* XXX temporary: set coverage to 1.0 so the line appears
811 * if AA mode happens to be enabled.
813 setup
->quad
.coverage
[0] =
814 setup
->quad
.coverage
[1] =
815 setup
->quad
.coverage
[2] =
816 setup
->quad
.coverage
[3] = 1.0;
819 /*** X-major line ***/
821 const int errorInc
= dy
+ dy
;
822 int error
= errorInc
- dx
;
823 const int errorDec
= error
- dx
;
825 for (i
= 0; i
< dx
; i
++) {
826 if (!sp
->setup
.line_stipple_enable
||
827 stipple_test(sp
->line_stipple_counter
,
828 sp
->setup
.line_stipple_pattern
,
829 sp
->setup
.line_stipple_factor
+ 1)) {
842 sp
->line_stipple_counter
++;
846 /*** Y-major line ***/
848 const int errorInc
= dx
+ dx
;
849 int error
= errorInc
- dy
;
850 const int errorDec
= error
- dy
;
852 for (i
= 0; i
< dy
; i
++) {
853 if (!sp
->setup
.line_stipple_enable
||
854 stipple_test(sp
->line_stipple_counter
,
855 sp
->setup
.line_stipple_pattern
,
856 sp
->setup
.line_stipple_factor
+ 1)) {
870 sp
->line_stipple_counter
++;
874 /* draw final quad */
875 if (setup
->quad
.mask
) {
876 clip_emit_quad(setup
);
882 * Do setup for point rasterization, then render the point.
883 * Round or square points...
884 * XXX could optimize a lot for 1-pixel points.
887 setup_point(struct draw_stage
*stage
, struct prim_header
*prim
)
889 struct setup_stage
*setup
= setup_stage( stage
);
890 /*XXX this should be a vertex attrib! */
891 const float halfSize
= 0.5f
* setup
->softpipe
->setup
.point_size
;
892 const boolean round
= setup
->softpipe
->setup
.point_smooth
;
893 const struct vertex_header
*v0
= prim
->v
[0];
894 const float x
= v0
->data
[FRAG_ATTRIB_WPOS
][0];
895 const float y
= v0
->data
[FRAG_ATTRIB_WPOS
][1];
898 /* For points, all interpolants are constant-valued.
899 * However, for point sprites, we'll need to setup texcoords appropriately.
900 * XXX: which coefficients are the texcoords???
901 * We may do point sprites as textured quads...
903 * KW: We don't know which coefficients are texcoords - ultimately
904 * the choice of what interpolation mode to use for each attribute
905 * should be determined by the fragment program, using
906 * per-attribute declaration statements that include interpolation
907 * mode as a parameter. So either the fragment program will have
908 * to be adjusted for pointsprite vs normal point behaviour, or
909 * otherwise a special interpolation mode will have to be defined
910 * which matches the required behaviour for point sprites. But -
911 * the latter is not a feature of normal hardware, and as such
912 * probably should be ruled out on that basis.
914 setup
->vprovoke
= prim
->v
[0];
915 const_coeff(setup
, 0, 2);
916 const_coeff(setup
, 0, 3);
917 for (slot
= 1; slot
< setup
->quad
.nr_attrs
; slot
++) {
918 for (j
= 0; j
< NUM_CHANNELS
; j
++)
919 const_coeff(setup
, slot
, j
);
922 setup
->quad
.prim
= PRIM_POINT
;
924 if (halfSize
<= 0.5 && !round
) {
925 /* special case for 1-pixel points */
926 const int ix
= ((int) x
) & 1;
927 const int iy
= ((int) y
) & 1;
928 setup
->quad
.x0
= (int) x
- ix
;
929 setup
->quad
.y0
= (int) y
- iy
;
930 setup
->quad
.mask
= (1 << ix
) << (2 * iy
);
931 clip_emit_quad(setup
);
934 const int ixmin
= block((int) (x
- halfSize
));
935 const int ixmax
= block((int) (x
+ halfSize
));
936 const int iymin
= block((int) (y
- halfSize
));
937 const int iymax
= block((int) (y
+ halfSize
));
942 const float rmin
= halfSize
- 0.7071F
; /* 0.7071 = sqrt(2)/2 */
943 const float rmax
= halfSize
+ 0.7071F
;
944 const float rmin2
= MAX2(0.0F
, rmin
* rmin
);
945 const float rmax2
= rmax
* rmax
;
946 const float cscale
= 1.0F
/ (rmax2
- rmin2
);
948 for (iy
= iymin
; iy
<= iymax
; iy
+= 2) {
949 for (ix
= ixmin
; ix
<= ixmax
; ix
+= 2) {
950 float dx
, dy
, dist2
, cover
;
952 setup
->quad
.mask
= 0x0;
954 dx
= (ix
+ 0.5f
) - x
;
955 dy
= (iy
+ 0.5f
) - y
;
956 dist2
= dx
* dx
+ dy
* dy
;
957 if (dist2
<= rmax2
) {
958 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
959 setup
->quad
.coverage
[QUAD_BOTTOM_LEFT
] = MIN2(cover
, 1.0f
);
960 setup
->quad
.mask
|= MASK_BOTTOM_LEFT
;
963 dx
= (ix
+ 1.5f
) - x
;
964 dy
= (iy
+ 0.5f
) - y
;
965 dist2
= dx
* dx
+ dy
* dy
;
966 if (dist2
<= rmax2
) {
967 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
968 setup
->quad
.coverage
[QUAD_BOTTOM_RIGHT
] = MIN2(cover
, 1.0f
);
969 setup
->quad
.mask
|= MASK_BOTTOM_RIGHT
;
972 dx
= (ix
+ 0.5f
) - x
;
973 dy
= (iy
+ 1.5f
) - y
;
974 dist2
= dx
* dx
+ dy
* dy
;
975 if (dist2
<= rmax2
) {
976 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
977 setup
->quad
.coverage
[QUAD_TOP_LEFT
] = MIN2(cover
, 1.0f
);
978 setup
->quad
.mask
|= MASK_TOP_LEFT
;
981 dx
= (ix
+ 1.5f
) - x
;
982 dy
= (iy
+ 1.5f
) - y
;
983 dist2
= dx
* dx
+ dy
* dy
;
984 if (dist2
<= rmax2
) {
985 cover
= 1.0F
- (dist2
- rmin2
) * cscale
;
986 setup
->quad
.coverage
[QUAD_TOP_RIGHT
] = MIN2(cover
, 1.0f
);
987 setup
->quad
.mask
|= MASK_TOP_RIGHT
;
990 if (setup
->quad
.mask
) {
993 clip_emit_quad(setup
);
1000 for (iy
= iymin
; iy
<= iymax
; iy
+= 2) {
1001 for (ix
= ixmin
; ix
<= ixmax
; ix
+= 2) {
1002 setup
->quad
.mask
= 0xf;
1004 if (ix
+ 0.5 < x
- halfSize
) {
1005 /* fragment is past left edge of point, turn off left bits */
1006 setup
->quad
.mask
&= ~(MASK_BOTTOM_LEFT
| MASK_TOP_LEFT
);
1009 if (ix
+ 1.5 > x
+ halfSize
) {
1010 /* past the right edge */
1011 setup
->quad
.mask
&= ~(MASK_BOTTOM_RIGHT
| MASK_TOP_RIGHT
);
1014 if (iy
+ 0.5 < y
- halfSize
) {
1015 /* below the bottom edge */
1016 setup
->quad
.mask
&= ~(MASK_BOTTOM_LEFT
| MASK_BOTTOM_RIGHT
);
1019 if (iy
+ 1.5 > y
+ halfSize
) {
1020 /* above the top edge */
1021 setup
->quad
.mask
&= ~(MASK_TOP_LEFT
| MASK_TOP_RIGHT
);
1024 if (setup
->quad
.mask
) {
1025 setup
->quad
.x0
= ix
;
1026 setup
->quad
.y0
= iy
;
1027 clip_emit_quad(setup
);
1037 static void setup_begin( struct draw_stage
*stage
)
1039 struct setup_stage
*setup
= setup_stage(stage
);
1040 struct softpipe_context
*sp
= setup
->softpipe
;
1042 setup
->quad
.nr_attrs
= setup
->softpipe
->nr_frag_attrs
;
1044 sp
->quad
.first
->begin(sp
->quad
.first
);
1048 static void setup_end( struct draw_stage
*stage
)
1053 static void reset_stipple_counter( struct draw_stage
*stage
)
1055 struct setup_stage
*setup
= setup_stage(stage
);
1056 setup
->softpipe
->line_stipple_counter
= 0;
1061 * Create a new primitive setup/render stage.
1063 struct draw_stage
*sp_draw_render_stage( struct softpipe_context
*softpipe
)
1065 struct setup_stage
*setup
= CALLOC_STRUCT(setup_stage
);
1067 setup
->softpipe
= softpipe
;
1068 setup
->stage
.draw
= softpipe
->draw
;
1069 setup
->stage
.begin
= setup_begin
;
1070 setup
->stage
.point
= setup_point
;
1071 setup
->stage
.line
= setup_line
;
1072 setup
->stage
.tri
= setup_tri
;
1073 setup
->stage
.end
= setup_end
;
1074 setup
->stage
.reset_stipple_counter
= reset_stipple_counter
;
1076 setup
->quad
.coef
= setup
->coef
;
1078 return &setup
->stage
;