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"
48 float dx; /**< X(v1) - X(v0), used only during setup */
49 float dy; /**< Y(v1) - Y(v0), used only during setup */
50 float dxdy; /**< dx/dy */
51 float sx, sy; /**< first sample point coord */
52 int lines; /**< number of lines on this edge */
57 * Triangle setup info (derived from draw_stage).
58 * Also used for line drawing (taking some liberties).
61 struct draw_stage stage; /**< This must be first (base class) */
63 struct softpipe_context *softpipe;
65 /* Vertices are just an array of floats making up each attribute in
66 * turn. Currently fixed at 4 floats, but should change in time.
67 * Codegen will help cope with this.
69 const struct vertex_header *vmax;
70 const struct vertex_header *vmid;
71 const struct vertex_header *vmin;
72 const struct vertex_header *vprovoke;
80 struct tgsi_interp_coef coef[FRAG_ATTRIB_MAX];
81 struct quad_header quad;
84 int left[2]; /**< [0] = row0, [1] = row1 */
88 unsigned mask; /**< mask of MASK_BOTTOM/TOP_LEFT/RIGHT bits */
95 * Basically a cast wrapper.
97 static INLINE struct setup_stage *setup_stage( struct draw_stage *stage )
99 return (struct setup_stage *)stage;
104 * Clip setup->quad against the scissor/surface bounds.
107 quad_clip(struct setup_stage *setup)
109 const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
110 if (setup->quad.x0 >= cliprect->maxx ||
111 setup->quad.y0 >= cliprect->maxy ||
112 setup->quad.x0 + 1 < cliprect->minx ||
113 setup->quad.y0 + 1 < cliprect->miny) {
114 /* totally clipped */
115 setup->quad.mask = 0x0;
118 if (setup->quad.x0 < cliprect->minx)
119 setup->quad.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
120 if (setup->quad.y0 < cliprect->miny)
121 setup->quad.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
122 if (setup->quad.x0 == cliprect->maxx - 1)
123 setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
124 if (setup->quad.y0 == cliprect->maxy - 1)
125 setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
130 * Emit a quad (pass to next stage) with clipping.
133 clip_emit_quad(struct setup_stage *setup)
136 if (setup->quad.mask) {
137 struct softpipe_context *sp = setup->softpipe;
138 sp->quad.first->run(sp->quad.first, &setup->quad);
144 * Emit a quad (pass to next stage). No clipping is done.
147 emit_quad( struct setup_stage *setup, int x, int y, unsigned mask )
149 struct softpipe_context *sp = setup->softpipe;
152 setup->quad.mask = mask;
153 sp->quad.first->run(sp->quad.first, &setup->quad);
158 * Given an X or Y coordinate, return the block/quad coordinate that it
161 static INLINE int block( int x )
168 * Compute mask which indicates which pixels in the 2x2 quad are actually inside
169 * the triangle's bounds.
171 * this is pretty nasty... may need to rework flush_spans again to
172 * fix it, if possible.
174 static unsigned calculate_mask( struct setup_stage *setup,
179 if (x >= setup->span.left[0] && x < setup->span.right[0])
180 mask |= MASK_BOTTOM_LEFT;
182 if (x >= setup->span.left[1] && x < setup->span.right[1])
183 mask |= MASK_TOP_LEFT;
185 if (x+1 >= setup->span.left[0] && x+1 < setup->span.right[0])
186 mask |= MASK_BOTTOM_RIGHT;
188 if (x+1 >= setup->span.left[1] && x+1 < setup->span.right[1])
189 mask |= MASK_TOP_RIGHT;
196 * Render a horizontal span of quads
198 static void flush_spans( struct setup_stage *setup )
200 int minleft, maxright;
203 switch (setup->span.y_flags) {
205 minleft = MIN2(setup->span.left[0], setup->span.left[1]);
206 maxright = MAX2(setup->span.right[0], setup->span.right[1]);
210 minleft = setup->span.left[0];
211 maxright = setup->span.right[0];
215 minleft = setup->span.left[1];
216 maxright = setup->span.right[1];
224 for (x = block(minleft); x <= block(maxright); )
226 emit_quad( setup, x, setup->span.y,
227 calculate_mask( setup, x ) );
232 setup->span.y_flags = 0;
233 setup->span.right[0] = 0;
234 setup->span.right[1] = 0;
238 static void print_vertex(const struct setup_stage *setup,
239 const struct vertex_header *v)
243 for (i = 0; i < setup->softpipe->nr_attrs; i++) {
244 printf(" %d: %f %f %f\n", i,
245 v->data[i][0], v->data[i][1], v->data[i][2]);
250 static boolean setup_sort_vertices( struct setup_stage *setup,
251 const struct prim_header *prim )
253 const struct vertex_header *v0 = prim->v[0];
254 const struct vertex_header *v1 = prim->v[1];
255 const struct vertex_header *v2 = prim->v[2];
258 printf("Triangle:\n");
259 print_vertex(setup, v0);
260 print_vertex(setup, v1);
261 print_vertex(setup, v2);
264 setup->vprovoke = v2;
266 /* determine bottom to top order of vertices */
268 float y0 = v0->data[0][1];
269 float y1 = v1->data[0][1];
270 float y2 = v2->data[0][1];
313 setup->ebot.dx = setup->vmid->data[0][0] - setup->vmin->data[0][0];
314 setup->ebot.dy = setup->vmid->data[0][1] - setup->vmin->data[0][1];
315 setup->emaj.dx = setup->vmax->data[0][0] - setup->vmin->data[0][0];
316 setup->emaj.dy = setup->vmax->data[0][1] - setup->vmin->data[0][1];
317 setup->etop.dx = setup->vmax->data[0][0] - setup->vmid->data[0][0];
318 setup->etop.dy = setup->vmax->data[0][1] - setup->vmid->data[0][1];
321 * Compute triangle's area. Use 1/area to compute partial
322 * derivatives of attributes later.
324 * The area will be the same as prim->det, but the sign may be
325 * different depending on how the vertices get sorted above.
327 * To determine whether the primitive is front or back facing we
328 * use the prim->det value because its sign is correct.
331 const float area = (setup->emaj.dx * setup->ebot.dy -
332 setup->ebot.dx * setup->emaj.dy);
334 setup->oneoverarea = 1.0 / area;
336 _mesa_printf("%s one-over-area %f area %f det %f\n",
337 __FUNCTION__, setup->oneoverarea, area, prim->det );
341 /* We need to know if this is a front or back-facing triangle for:
342 * - the GLSL gl_FrontFacing fragment attribute (bool)
343 * - two-sided stencil test
345 setup->quad.facing = (prim->det > 0.0) ^ (setup->softpipe->setup.front_winding == PIPE_WINDING_CW);
352 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
353 * The value value comes from vertex->data[slot][i].
354 * The result will be put into setup->coef[slot].a0[i].
355 * \param slot which attribute slot
356 * \param i which component of the slot (0..3)
358 static void const_coeff( struct setup_stage *setup,
362 assert(slot < FRAG_ATTRIB_MAX);
365 setup->coef[slot].dadx[i] = 0;
366 setup->coef[slot].dady[i] = 0;
368 /* need provoking vertex info!
370 setup->coef[slot].a0[i] = setup->vprovoke->data[slot][i];
375 * Compute a0, dadx and dady for a linearly interpolated coefficient,
378 static void tri_linear_coeff( struct setup_stage *setup,
382 float botda = setup->vmid->data[slot][i] - setup->vmin->data[slot][i];
383 float majda = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
384 float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
385 float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
387 assert(slot < FRAG_ATTRIB_MAX);
390 setup->coef[slot].dadx[i] = a * setup->oneoverarea;
391 setup->coef[slot].dady[i] = b * setup->oneoverarea;
393 /* calculate a0 as the value which would be sampled for the
394 * fragment at (0,0), taking into account that we want to sample at
395 * pixel centers, in other words (0.5, 0.5).
397 * this is neat but unfortunately not a good way to do things for
398 * triangles with very large values of dadx or dady as it will
399 * result in the subtraction and re-addition from a0 of a very
400 * large number, which means we'll end up loosing a lot of the
401 * fractional bits and precision from a0. the way to fix this is
402 * to define a0 as the sample at a pixel center somewhere near vmin
403 * instead - i'll switch to this later.
405 setup->coef[slot].a0[i] = (setup->vmin->data[slot][i] -
406 (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5) +
407 setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5)));
410 _mesa_printf("attr[%d].%c: %f dx:%f dy:%f\n",
412 setup->coef[slot].a0[i],
413 setup->coef[slot].dadx[i],
414 setup->coef[slot].dady[i]);
420 * Compute a0, dadx and dady for a perspective-corrected interpolant,
423 static void tri_persp_coeff( struct setup_stage *setup,
427 /* premultiply by 1/w:
429 float mina = setup->vmin->data[slot][i] * setup->vmin->data[0][3];
430 float mida = setup->vmid->data[slot][i] * setup->vmid->data[0][3];
431 float maxa = setup->vmax->data[slot][i] * setup->vmax->data[0][3];
433 float botda = mida - mina;
434 float majda = maxa - mina;
435 float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
436 float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
438 assert(slot < FRAG_ATTRIB_MAX);
441 setup->coef[slot].dadx[i] = a * setup->oneoverarea;
442 setup->coef[slot].dady[i] = b * setup->oneoverarea;
443 setup->coef[slot].a0[i] = (mina -
444 (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5) +
445 setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5)));
450 * Compute the setup->coef[] array dadx, dady, a0 values.
451 * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
453 static void setup_tri_coefficients( struct setup_stage *setup )
455 const enum interp_mode *interp = setup->softpipe->interp;
458 /* z and w are done by linear interpolation:
460 tri_linear_coeff(setup, 0, 2);
461 tri_linear_coeff(setup, 0, 3);
463 /* setup interpolation for all the remaining attributes:
465 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
466 switch (interp[slot]) {
467 case INTERP_CONSTANT:
468 for (j = 0; j < NUM_CHANNELS; j++)
469 const_coeff(setup, slot, j);
473 for (j = 0; j < NUM_CHANNELS; j++)
474 tri_linear_coeff(setup, slot, j);
477 case INTERP_PERSPECTIVE:
478 for (j = 0; j < NUM_CHANNELS; j++)
479 tri_persp_coeff(setup, slot, j);
487 static void setup_tri_edges( struct setup_stage *setup )
489 float vmin_x = setup->vmin->data[0][0] + 0.5;
490 float vmid_x = setup->vmid->data[0][0] + 0.5;
492 float vmin_y = setup->vmin->data[0][1] - 0.5;
493 float vmid_y = setup->vmid->data[0][1] - 0.5;
494 float vmax_y = setup->vmax->data[0][1] - 0.5;
496 setup->emaj.sy = ceilf(vmin_y);
497 setup->emaj.lines = (int) ceilf(vmax_y - setup->emaj.sy);
498 setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy;
499 setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy;
501 setup->etop.sy = ceilf(vmid_y);
502 setup->etop.lines = (int) ceilf(vmax_y - setup->etop.sy);
503 setup->etop.dxdy = setup->etop.dx / setup->etop.dy;
504 setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy;
506 setup->ebot.sy = ceilf(vmin_y);
507 setup->ebot.lines = (int) ceilf(vmid_y - setup->ebot.sy);
508 setup->ebot.dxdy = setup->ebot.dx / setup->ebot.dy;
509 setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy;
514 * Render the upper or lower half of a triangle.
515 * Scissoring/cliprect is applied here too.
517 static void subtriangle( struct setup_stage *setup,
522 const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
523 int y, start_y, finish_y;
524 int sy = (int)eleft->sy;
526 assert((int)eleft->sy == (int) eright->sy);
528 /* clip top/bottom */
530 finish_y = sy + lines;
532 if (start_y < cliprect->miny)
533 start_y = cliprect->miny;
535 if (finish_y > cliprect->maxy)
536 finish_y = cliprect->maxy;
542 _mesa_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);
545 for (y = start_y; y < finish_y; y++) {
547 /* avoid accumulating adds as floats don't have the precision to
548 * accurately iterate large triangle edges that way. luckily we
549 * can just multiply these days.
551 * this is all drowned out by the attribute interpolation anyway.
553 int left = (int)(eleft->sx + y * eleft->dxdy);
554 int right = (int)(eright->sx + y * eright->dxdy);
556 /* clip left/right */
557 if (left < cliprect->minx)
558 left = cliprect->minx;
559 if (right > cliprect->maxx)
560 right = cliprect->maxx;
564 if (block(_y) != setup->span.y) {
566 setup->span.y = block(_y);
569 setup->span.left[_y&1] = left;
570 setup->span.right[_y&1] = right;
571 setup->span.y_flags |= 1<<(_y&1);
576 /* save the values so that emaj can be restarted:
578 eleft->sx += lines * eleft->dxdy;
579 eright->sx += lines * eright->dxdy;
586 * Do setup for triangle rasterization, then render the triangle.
588 static void setup_tri( struct draw_stage *stage,
589 struct prim_header *prim )
591 struct setup_stage *setup = setup_stage( stage );
594 _mesa_printf("%s\n", __FUNCTION__ );
597 setup_sort_vertices( setup, prim );
598 setup_tri_coefficients( setup );
599 setup_tri_edges( setup );
601 setup->quad.prim = PRIM_TRI;
604 setup->span.y_flags = 0;
605 setup->span.right[0] = 0;
606 setup->span.right[1] = 0;
607 /* setup->span.z_mode = tri_z_mode( setup->ctx ); */
609 /* init_constant_attribs( setup ); */
611 if (setup->oneoverarea < 0.0) {
614 subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines );
615 subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines );
620 subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines );
621 subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines );
624 flush_spans( setup );
630 * Compute a0, dadx and dady for a linearly interpolated coefficient,
634 line_linear_coeff(struct setup_stage *setup, unsigned slot, unsigned i)
636 const float dz = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
637 const float dadx = dz * setup->emaj.dx * setup->oneoverarea;
638 const float dady = dz * setup->emaj.dy * setup->oneoverarea;
639 setup->coef[slot].dadx[i] = dadx;
640 setup->coef[slot].dady[i] = dady;
641 setup->coef[slot].a0[i]
642 = (setup->vmin->data[slot][i] -
643 (dadx * (setup->vmin->data[0][0] - 0.5) +
644 dady * (setup->vmin->data[0][1] - 0.5)));
649 * Compute a0, dadx and dady for a perspective-corrected interpolant,
653 line_persp_coeff(struct setup_stage *setup, unsigned slot, unsigned i)
656 line_linear_coeff(setup, slot, i); /* XXX temporary */
661 * Compute the setup->coef[] array dadx, dady, a0 values.
662 * Must be called after setup->vmin,vmax are initialized.
665 setup_line_coefficients(struct setup_stage *setup, struct prim_header *prim)
667 const enum interp_mode *interp = setup->softpipe->interp;
670 /* use setup->vmin, vmax to point to vertices */
671 setup->vprovoke = prim->v[1];
672 setup->vmin = prim->v[0];
673 setup->vmax = prim->v[1];
675 setup->emaj.dx = setup->vmax->data[0][0] - setup->vmin->data[0][0];
676 setup->emaj.dy = setup->vmax->data[0][1] - setup->vmin->data[0][1];
677 /* NOTE: this is not really 1/area */
678 setup->oneoverarea = 1.0 / (setup->emaj.dx * setup->emaj.dx +
679 setup->emaj.dy * setup->emaj.dy);
681 /* z and w are done by linear interpolation:
683 line_linear_coeff(setup, 0, 2);
684 line_linear_coeff(setup, 0, 3);
686 /* setup interpolation for all the remaining attributes:
688 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
689 switch (interp[slot]) {
690 case INTERP_CONSTANT:
691 for (j = 0; j < NUM_CHANNELS; j++)
692 const_coeff(setup, slot, j);
696 for (j = 0; j < NUM_CHANNELS; j++)
697 line_linear_coeff(setup, slot, j);
700 case INTERP_PERSPECTIVE:
701 for (j = 0; j < NUM_CHANNELS; j++)
702 line_persp_coeff(setup, slot, j);
710 * Plot a pixel in a line segment.
713 plot(struct setup_stage *setup, int x, int y)
715 const int iy = y & 1;
716 const int ix = x & 1;
717 const int quadX = x - ix;
718 const int quadY = y - iy;
719 const int mask = (1 << ix) << (2 * iy);
721 if (quadX != setup->quad.x0 ||
722 quadY != setup->quad.y0)
724 /* flush prev quad, start new quad */
726 if (setup->quad.x0 != -1)
727 clip_emit_quad(setup);
729 setup->quad.x0 = quadX;
730 setup->quad.y0 = quadY;
731 setup->quad.mask = 0x0;
734 setup->quad.mask |= mask;
739 * Determine whether or not to emit a line fragment by checking
740 * line stipple pattern.
742 static INLINE unsigned
743 stipple_test(int counter, ushort pattern, int factor)
745 int b = (counter / factor) & 0xf;
746 return (1 << b) & pattern;
751 * Do setup for line rasterization, then render the line.
752 * XXX single-pixel width, no stipple, etc
755 setup_line(struct draw_stage *stage, struct prim_header *prim)
757 const struct vertex_header *v0 = prim->v[0];
758 const struct vertex_header *v1 = prim->v[1];
759 struct setup_stage *setup = setup_stage( stage );
760 struct softpipe_context *sp = setup->softpipe;
762 int x0 = (int) v0->data[0][0];
763 int x1 = (int) v1->data[0][0];
764 int y0 = (int) v0->data[0][1];
765 int y1 = (int) v1->data[0][1];
770 if (dx == 0 && dy == 0)
773 setup_line_coefficients(setup, prim);
776 dx = -dx; /* make positive */
784 dy = -dy; /* make positive */
794 setup->quad.x0 = setup->quad.y0 = -1;
795 setup->quad.mask = 0x0;
796 setup->quad.prim = PRIM_LINE;
797 /* XXX temporary: set coverage to 1.0 so the line appears
798 * if AA mode happens to be enabled.
800 setup->quad.coverage[0] =
801 setup->quad.coverage[1] =
802 setup->quad.coverage[2] =
803 setup->quad.coverage[3] = 1.0;
806 /*** X-major line ***/
808 const int errorInc = dy + dy;
809 int error = errorInc - dx;
810 const int errorDec = error - dx;
812 for (i = 0; i < dx; i++) {
813 if (!sp->setup.line_stipple_enable ||
814 stipple_test(sp->line_stipple_counter,
815 sp->setup.line_stipple_pattern,
816 sp->setup.line_stipple_factor + 1)) {
829 sp->line_stipple_counter++;
833 /*** Y-major line ***/
835 const int errorInc = dx + dx;
836 int error = errorInc - dy;
837 const int errorDec = error - dy;
839 for (i = 0; i < dy; i++) {
840 if (!sp->setup.line_stipple_enable ||
841 stipple_test(sp->line_stipple_counter,
842 sp->setup.line_stipple_pattern,
843 sp->setup.line_stipple_factor + 1)) {
857 sp->line_stipple_counter++;
861 /* draw final quad */
862 if (setup->quad.mask) {
863 clip_emit_quad(setup);
869 * Do setup for point rasterization, then render the point.
870 * Round or square points...
871 * XXX could optimize a lot for 1-pixel points.
874 setup_point(struct draw_stage *stage, struct prim_header *prim)
876 struct setup_stage *setup = setup_stage( stage );
877 /*XXX this should be a vertex attrib! */
878 const float halfSize = 0.5 * setup->softpipe->setup.point_size;
879 const boolean round = setup->softpipe->setup.point_smooth;
880 const struct vertex_header *v0 = prim->v[0];
881 const float x = v0->data[FRAG_ATTRIB_WPOS][0];
882 const float y = v0->data[FRAG_ATTRIB_WPOS][1];
885 /* For points, all interpolants are constant-valued.
886 * However, for point sprites, we'll need to setup texcoords appropriately.
887 * XXX: which coefficients are the texcoords???
888 * We may do point sprites as textured quads...
890 * KW: We don't know which coefficients are texcoords - ultimately
891 * the choice of what interpolation mode to use for each attribute
892 * should be determined by the fragment program, using
893 * per-attribute declaration statements that include interpolation
894 * mode as a parameter. So either the fragment program will have
895 * to be adjusted for pointsprite vs normal point behaviour, or
896 * otherwise a special interpolation mode will have to be defined
897 * which matches the required behaviour for point sprites. But -
898 * the latter is not a feature of normal hardware, and as such
899 * probably should be ruled out on that basis.
901 setup->vprovoke = prim->v[0];
902 const_coeff(setup, 0, 2);
903 const_coeff(setup, 0, 3);
904 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
905 for (j = 0; j < NUM_CHANNELS; j++)
906 const_coeff(setup, slot, j);
909 setup->quad.prim = PRIM_POINT;
911 if (halfSize <= 0.5 && !round) {
912 /* special case for 1-pixel points */
913 const int ix = ((int) x) & 1;
914 const int iy = ((int) y) & 1;
915 setup->quad.x0 = x - ix;
916 setup->quad.y0 = y - iy;
917 setup->quad.mask = (1 << ix) << (2 * iy);
918 clip_emit_quad(setup);
921 const int ixmin = block((int) (x - halfSize));
922 const int ixmax = block((int) (x + halfSize));
923 const int iymin = block((int) (y - halfSize));
924 const int iymax = block((int) (y + halfSize));
929 const float rmin = halfSize - 0.7071F; /* 0.7071 = sqrt(2)/2 */
930 const float rmax = halfSize + 0.7071F;
931 const float rmin2 = MAX2(0.0F, rmin * rmin);
932 const float rmax2 = rmax * rmax;
933 const float cscale = 1.0F / (rmax2 - rmin2);
935 for (iy = iymin; iy <= iymax; iy += 2) {
936 for (ix = ixmin; ix <= ixmax; ix += 2) {
937 float dx, dy, dist2, cover;
939 setup->quad.mask = 0x0;
943 dist2 = dx * dx + dy * dy;
944 if (dist2 <= rmax2) {
945 cover = 1.0F - (dist2 - rmin2) * cscale;
946 setup->quad.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0);
947 setup->quad.mask |= MASK_BOTTOM_LEFT;
952 dist2 = dx * dx + dy * dy;
953 if (dist2 <= rmax2) {
954 cover = 1.0F - (dist2 - rmin2) * cscale;
955 setup->quad.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0);
956 setup->quad.mask |= MASK_BOTTOM_RIGHT;
961 dist2 = dx * dx + dy * dy;
962 if (dist2 <= rmax2) {
963 cover = 1.0F - (dist2 - rmin2) * cscale;
964 setup->quad.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0);
965 setup->quad.mask |= MASK_TOP_LEFT;
970 dist2 = dx * dx + dy * dy;
971 if (dist2 <= rmax2) {
972 cover = 1.0F - (dist2 - rmin2) * cscale;
973 setup->quad.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0);
974 setup->quad.mask |= MASK_TOP_RIGHT;
977 if (setup->quad.mask) {
980 clip_emit_quad(setup);
987 for (iy = iymin; iy <= iymax; iy += 2) {
988 for (ix = ixmin; ix <= ixmax; ix += 2) {
989 setup->quad.mask = 0xf;
991 if (ix + 0.5 < x - halfSize) {
992 /* fragment is past left edge of point, turn off left bits */
993 setup->quad.mask &= ~(MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
996 if (ix + 1.5 > x + halfSize) {
997 /* past the right edge */
998 setup->quad.mask &= ~(MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
1001 if (iy + 0.5 < y - halfSize) {
1002 /* below the bottom edge */
1003 setup->quad.mask &= ~(MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
1006 if (iy + 1.5 > y + halfSize) {
1007 /* above the top edge */
1008 setup->quad.mask &= ~(MASK_TOP_LEFT | MASK_TOP_RIGHT);
1011 if (setup->quad.mask) {
1012 setup->quad.x0 = ix;
1013 setup->quad.y0 = iy;
1014 clip_emit_quad(setup);
1024 static void setup_begin( struct draw_stage *stage )
1026 struct setup_stage *setup = setup_stage(stage);
1027 struct softpipe_context *sp = setup->softpipe;
1029 setup->quad.nr_attrs = setup->softpipe->nr_frag_attrs;
1031 sp->quad.first->begin(sp->quad.first);
1035 static void setup_end( struct draw_stage *stage )
1040 static void reset_stipple_counter( struct draw_stage *stage )
1042 struct setup_stage *setup = setup_stage(stage);
1043 setup->softpipe->line_stipple_counter = 0;
1048 * Create a new primitive setup/render stage.
1050 struct draw_stage *sp_draw_render_stage( struct softpipe_context *softpipe )
1052 struct setup_stage *setup = CALLOC_STRUCT(setup_stage);
1054 setup->softpipe = softpipe;
1055 setup->stage.draw = softpipe->draw;
1056 setup->stage.begin = setup_begin;
1057 setup->stage.point = setup_point;
1058 setup->stage.line = setup_line;
1059 setup->stage.tri = setup_tri;
1060 setup->stage.end = setup_end;
1061 setup->stage.reset_stipple_counter = reset_stipple_counter;
1063 setup->quad.coef = setup->coef;
1065 return &setup->stage;