Implement AA points and AA coverage application in quad pipeline.
[mesa.git] / src / mesa / pipe / softpipe / sp_prim_setup.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
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.
25 *
26 **************************************************************************/
27
28 /**
29 * \brief Primitive rasterization/rendering (points, lines, triangles)
30 *
31 * \author Keith Whitwell <keith@tungstengraphics.com>
32 * \author Brian Paul
33 */
34
35
36 #include "imports.h"
37 #include "macros.h"
38
39 #include "sp_context.h"
40 #include "sp_headers.h"
41 #include "pipe/draw/draw_private.h"
42 #include "sp_quad.h"
43 #include "sp_prim_setup.h"
44
45
46
47 /**
48 * Emit/render a quad.
49 * This passes the quad to the first stage of per-fragment operations.
50 */
51 static INLINE void
52 quad_emit(struct softpipe_context *sp, struct quad_header *quad)
53 {
54 sp->quad.first->run(sp->quad.first, quad);
55 }
56
57
58 /**
59 * Triangle edge info
60 */
61 struct edge {
62 GLfloat dx; /* X(v1) - X(v0), used only during setup */
63 GLfloat dy; /* Y(v1) - Y(v0), used only during setup */
64 GLfloat dxdy; /* dx/dy */
65 GLfloat sx; /* first sample point x coord */
66 GLfloat sy;
67 GLint lines; /* number of lines on this edge */
68 };
69
70
71 /**
72 * Triangle setup info (derived from draw_stage).
73 * Also used for line drawing (taking some liberties).
74 */
75 struct setup_stage {
76 struct draw_stage stage; /**< This must be first (base class) */
77
78 /*XXX NEW */
79 struct softpipe_context *softpipe;
80
81 /* Vertices are just an array of floats making up each attribute in
82 * turn. Currently fixed at 4 floats, but should change in time.
83 * Codegen will help cope with this.
84 */
85 const struct vertex_header *vmax;
86 const struct vertex_header *vmid;
87 const struct vertex_header *vmin;
88 const struct vertex_header *vprovoke;
89
90 struct edge ebot;
91 struct edge etop;
92 struct edge emaj;
93
94 GLfloat oneoverarea;
95
96 struct setup_coefficient coef[FRAG_ATTRIB_MAX];
97 struct quad_header quad;
98
99 struct {
100 GLint left[2]; /**< [0] = row0, [1] = row1 */
101 GLint right[2];
102 GLint y;
103 GLuint y_flags;
104 GLuint mask; /**< mask of MASK_BOTTOM/TOP_LEFT/RIGHT bits */
105 } span;
106 };
107
108
109
110 /**
111 * Basically a cast wrapper.
112 */
113 static inline struct setup_stage *setup_stage( struct draw_stage *stage )
114 {
115 return (struct setup_stage *)stage;
116 }
117
118
119 /**
120 * Given an X or Y coordinate, return the block/quad coordinate that it
121 * belongs to.
122 */
123 static inline GLint block( GLint x )
124 {
125 return x & ~1;
126 }
127
128
129
130 /**
131 * Run shader on a quad/block.
132 */
133 static void run_shader_block( struct setup_stage *setup,
134 GLint x, GLint y, GLuint mask )
135 {
136 setup->quad.x0 = x;
137 setup->quad.y0 = y;
138 setup->quad.mask = mask;
139
140 quad_emit(setup->softpipe, &setup->quad);
141 }
142
143
144 /**
145 * Compute mask which indicates which pixels in the 2x2 quad are actually inside
146 * the triangle's bounds.
147 *
148 * this is pretty nasty... may need to rework flush_spans again to
149 * fix it, if possible.
150 */
151 static GLuint calculate_mask( struct setup_stage *setup,
152 GLint x )
153 {
154 GLuint mask = 0;
155
156 if (x >= setup->span.left[0] && x < setup->span.right[0])
157 mask |= MASK_BOTTOM_LEFT;
158
159 if (x >= setup->span.left[1] && x < setup->span.right[1])
160 mask |= MASK_TOP_LEFT;
161
162 if (x+1 >= setup->span.left[0] && x+1 < setup->span.right[0])
163 mask |= MASK_BOTTOM_RIGHT;
164
165 if (x+1 >= setup->span.left[1] && x+1 < setup->span.right[1])
166 mask |= MASK_TOP_RIGHT;
167
168 return mask;
169 }
170
171
172 /**
173 * Render a horizontal span of quads
174 */
175 static void flush_spans( struct setup_stage *setup )
176 {
177 GLint minleft, maxright;
178 GLint x;
179
180 switch (setup->span.y_flags) {
181 case 3:
182 minleft = MIN2(setup->span.left[0], setup->span.left[1]);
183 maxright = MAX2(setup->span.right[0], setup->span.right[1]);
184 break;
185
186 case 1:
187 minleft = setup->span.left[0];
188 maxright = setup->span.right[0];
189 break;
190
191 case 2:
192 minleft = setup->span.left[1];
193 maxright = setup->span.right[1];
194 break;
195
196 default:
197 return;
198 }
199
200
201 for (x = block(minleft); x <= block(maxright); )
202 {
203 run_shader_block( setup, x,
204 setup->span.y,
205 calculate_mask( setup, x ) );
206 x += 2;
207 }
208
209 setup->span.y = 0;
210 setup->span.y_flags = 0;
211 setup->span.right[0] = 0;
212 setup->span.right[1] = 0;
213 }
214
215
216 static GLboolean setup_sort_vertices( struct setup_stage *setup,
217 const struct prim_header *prim )
218 {
219 const struct vertex_header *v0 = prim->v[0];
220 const struct vertex_header *v1 = prim->v[1];
221 const struct vertex_header *v2 = prim->v[2];
222
223 setup->vprovoke = v2;
224
225 /* determine bottom to top order of vertices */
226 {
227 GLfloat y0 = v0->data[0][1];
228 GLfloat y1 = v1->data[0][1];
229 GLfloat y2 = v2->data[0][1];
230 if (y0 <= y1) {
231 if (y1 <= y2) {
232 /* y0<=y1<=y2 */
233 setup->vmin = v0;
234 setup->vmid = v1;
235 setup->vmax = v2;
236 }
237 else if (y2 <= y0) {
238 /* y2<=y0<=y1 */
239 setup->vmin = v2;
240 setup->vmid = v0;
241 setup->vmax = v1;
242 }
243 else {
244 /* y0<=y2<=y1 */
245 setup->vmin = v0;
246 setup->vmid = v2;
247 setup->vmax = v1;
248 }
249 }
250 else {
251 if (y0 <= y2) {
252 /* y1<=y0<=y2 */
253 setup->vmin = v1;
254 setup->vmid = v0;
255 setup->vmax = v2;
256 }
257 else if (y2 <= y1) {
258 /* y2<=y1<=y0 */
259 setup->vmin = v2;
260 setup->vmid = v1;
261 setup->vmax = v0;
262 }
263 else {
264 /* y1<=y2<=y0 */
265 setup->vmin = v1;
266 setup->vmid = v2;
267 setup->vmax = v0;
268 }
269 }
270 }
271
272 setup->ebot.dx = setup->vmid->data[0][0] - setup->vmin->data[0][0];
273 setup->ebot.dy = setup->vmid->data[0][1] - setup->vmin->data[0][1];
274 setup->emaj.dx = setup->vmax->data[0][0] - setup->vmin->data[0][0];
275 setup->emaj.dy = setup->vmax->data[0][1] - setup->vmin->data[0][1];
276 setup->etop.dx = setup->vmax->data[0][0] - setup->vmid->data[0][0];
277 setup->etop.dy = setup->vmax->data[0][1] - setup->vmid->data[0][1];
278
279 /*
280 * Compute triangle's area. Use 1/area to compute partial
281 * derivatives of attributes later.
282 *
283 * The area will be the same as prim->det, but the sign may be
284 * different depending on how the vertices get sorted above.
285 *
286 * To determine whether the primitive is front or back facing we
287 * use the prim->det value because its sign is correct.
288 */
289 {
290 const GLfloat area = (setup->emaj.dx * setup->ebot.dy -
291 setup->ebot.dx * setup->emaj.dy);
292
293 setup->oneoverarea = 1.0 / area;
294 /*
295 _mesa_printf("%s one-over-area %f area %f det %f\n",
296 __FUNCTION__, setup->oneoverarea, area, prim->det );
297 */
298 }
299
300 /* We need to know if this is a front or back-facing triangle for:
301 * - the GLSL gl_FrontFacing fragment attribute (bool)
302 * - two-sided stencil test
303 */
304 setup->quad.facing = (prim->det > 0.0) ^ (setup->softpipe->setup.front_winding == PIPE_WINDING_CW);
305
306 return GL_TRUE;
307 }
308
309
310 /**
311 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
312 * The value value comes from vertex->data[slot][i].
313 * The result will be put into setup->coef[slot].a0[i].
314 * \param slot which attribute slot
315 * \param i which component of the slot (0..3)
316 */
317 static void const_coeff( struct setup_stage *setup,
318 GLuint slot,
319 GLuint i )
320 {
321 assert(slot < FRAG_ATTRIB_MAX);
322 assert(i <= 3);
323
324 setup->coef[slot].dadx[i] = 0;
325 setup->coef[slot].dady[i] = 0;
326
327 /* need provoking vertex info!
328 */
329 setup->coef[slot].a0[i] = setup->vprovoke->data[slot][i];
330 }
331
332
333 /**
334 * Compute a0, dadx and dady for a linearly interpolated coefficient,
335 * for a triangle.
336 */
337 static void tri_linear_coeff( struct setup_stage *setup,
338 GLuint slot,
339 GLuint i)
340 {
341 GLfloat botda = setup->vmid->data[slot][i] - setup->vmin->data[slot][i];
342 GLfloat majda = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
343 GLfloat a = setup->ebot.dy * majda - botda * setup->emaj.dy;
344 GLfloat b = setup->emaj.dx * botda - majda * setup->ebot.dx;
345
346 assert(slot < FRAG_ATTRIB_MAX);
347 assert(i <= 3);
348
349 setup->coef[slot].dadx[i] = a * setup->oneoverarea;
350 setup->coef[slot].dady[i] = b * setup->oneoverarea;
351
352 /* calculate a0 as the value which would be sampled for the
353 * fragment at (0,0), taking into account that we want to sample at
354 * pixel centers, in other words (0.5, 0.5).
355 *
356 * this is neat but unfortunately not a good way to do things for
357 * triangles with very large values of dadx or dady as it will
358 * result in the subtraction and re-addition from a0 of a very
359 * large number, which means we'll end up loosing a lot of the
360 * fractional bits and precision from a0. the way to fix this is
361 * to define a0 as the sample at a pixel center somewhere near vmin
362 * instead - i'll switch to this later.
363 */
364 setup->coef[slot].a0[i] = (setup->vmin->data[slot][i] -
365 (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5) +
366 setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5)));
367
368 /*
369 _mesa_printf("attr[%d].%c: %f dx:%f dy:%f\n",
370 slot, "xyzw"[i],
371 setup->coef[slot].a0[i],
372 setup->coef[slot].dadx[i],
373 setup->coef[slot].dady[i]);
374 */
375 }
376
377
378 /**
379 * Compute a0, dadx and dady for a perspective-corrected interpolant,
380 * for a triangle.
381 */
382 static void tri_persp_coeff( struct setup_stage *setup,
383 GLuint slot,
384 GLuint i )
385 {
386 /* premultiply by 1/w:
387 */
388 GLfloat mina = setup->vmin->data[slot][i] * setup->vmin->data[0][3];
389 GLfloat mida = setup->vmid->data[slot][i] * setup->vmid->data[0][3];
390 GLfloat maxa = setup->vmax->data[slot][i] * setup->vmax->data[0][3];
391
392 GLfloat botda = mida - mina;
393 GLfloat majda = maxa - mina;
394 GLfloat a = setup->ebot.dy * majda - botda * setup->emaj.dy;
395 GLfloat b = setup->emaj.dx * botda - majda * setup->ebot.dx;
396
397 assert(slot < FRAG_ATTRIB_MAX);
398 assert(i <= 3);
399
400 setup->coef[slot].dadx[i] = a * setup->oneoverarea;
401 setup->coef[slot].dady[i] = b * setup->oneoverarea;
402 setup->coef[slot].a0[i] = (mina -
403 (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5) +
404 setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5)));
405 }
406
407
408
409 /**
410 * Compute the setup->coef[] array dadx, dady, a0 values.
411 * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
412 */
413 static void setup_tri_coefficients( struct setup_stage *setup )
414 {
415 const enum interp_mode *interp = setup->softpipe->interp;
416 GLuint slot, j;
417
418 /* z and w are done by linear interpolation:
419 */
420 tri_linear_coeff(setup, 0, 2);
421 tri_linear_coeff(setup, 0, 3);
422
423 /* setup interpolation for all the remaining attributes:
424 */
425 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
426 switch (interp[slot]) {
427 case INTERP_CONSTANT:
428 for (j = 0; j < NUM_CHANNELS; j++)
429 const_coeff(setup, slot, j);
430 break;
431
432 case INTERP_LINEAR:
433 for (j = 0; j < NUM_CHANNELS; j++)
434 tri_linear_coeff(setup, slot, j);
435 break;
436
437 case INTERP_PERSPECTIVE:
438 for (j = 0; j < NUM_CHANNELS; j++)
439 tri_persp_coeff(setup, slot, j);
440 break;
441 }
442 }
443 }
444
445
446
447 static void setup_tri_edges( struct setup_stage *setup )
448 {
449 GLfloat vmin_x = setup->vmin->data[0][0] + 0.5;
450 GLfloat vmid_x = setup->vmid->data[0][0] + 0.5;
451
452 GLfloat vmin_y = setup->vmin->data[0][1] - 0.5;
453 GLfloat vmid_y = setup->vmid->data[0][1] - 0.5;
454 GLfloat vmax_y = setup->vmax->data[0][1] - 0.5;
455
456 setup->emaj.sy = ceilf(vmin_y);
457 setup->emaj.lines = (GLint) ceilf(vmax_y - setup->emaj.sy);
458 setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy;
459 setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy;
460
461 setup->etop.sy = ceilf(vmid_y);
462 setup->etop.lines = (GLint) ceilf(vmax_y - setup->etop.sy);
463 setup->etop.dxdy = setup->etop.dx / setup->etop.dy;
464 setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy;
465
466 setup->ebot.sy = ceilf(vmin_y);
467 setup->ebot.lines = (GLint) ceilf(vmid_y - setup->ebot.sy);
468 setup->ebot.dxdy = setup->ebot.dx / setup->ebot.dy;
469 setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy;
470 }
471
472
473 /**
474 * Render the upper or lower half of a triangle.
475 * Scissoring is applied here too.
476 */
477 static void subtriangle( struct setup_stage *setup,
478 struct edge *eleft,
479 struct edge *eright,
480 GLuint lines )
481 {
482 GLint y, start_y, finish_y;
483 GLint sy = (GLint)eleft->sy;
484
485 assert((GLint)eleft->sy == (GLint) eright->sy);
486 assert((GLint)eleft->sy >= 0); /* catch bug in x64? */
487
488 /* scissor y:
489 */
490 if (setup->softpipe->setup.scissor) {
491 start_y = sy;
492 finish_y = start_y + lines;
493
494 if (start_y < setup->softpipe->scissor.miny)
495 start_y = setup->softpipe->scissor.miny;
496
497 if (finish_y > setup->softpipe->scissor.maxy)
498 finish_y = setup->softpipe->scissor.maxy;
499
500 start_y -= sy;
501 finish_y -= sy;
502 }
503 else {
504 start_y = 0;
505 finish_y = lines;
506 }
507
508 /*
509 _mesa_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);
510 */
511
512 for (y = start_y; y < finish_y; y++) {
513
514 /* avoid accumulating adds as floats don't have the precision to
515 * accurately iterate large triangle edges that way. luckily we
516 * can just multiply these days.
517 *
518 * this is all drowned out by the attribute interpolation anyway.
519 */
520 GLint left = (GLint)(eleft->sx + y * eleft->dxdy);
521 GLint right = (GLint)(eright->sx + y * eright->dxdy);
522
523 /* scissor x:
524 */
525 if (setup->softpipe->setup.scissor) {
526 if (left < setup->softpipe->scissor.minx)
527 left = setup->softpipe->scissor.minx;
528
529 if (right > setup->softpipe->scissor.maxx)
530 right = setup->softpipe->scissor.maxx;
531 }
532
533 if (left < right) {
534 GLint _y = sy+y;
535 if (block(_y) != setup->span.y) {
536 flush_spans(setup);
537 setup->span.y = block(_y);
538 }
539
540 setup->span.left[_y&1] = left;
541 setup->span.right[_y&1] = right;
542 setup->span.y_flags |= 1<<(_y&1);
543 }
544 }
545
546
547 /* save the values so that emaj can be restarted:
548 */
549 eleft->sx += lines * eleft->dxdy;
550 eright->sx += lines * eright->dxdy;
551 eleft->sy += lines;
552 eright->sy += lines;
553 }
554
555
556 /**
557 * Do setup for triangle rasterization, then render the triangle.
558 */
559 static void setup_tri( struct draw_stage *stage,
560 struct prim_header *prim )
561 {
562 struct setup_stage *setup = setup_stage( stage );
563
564 /*
565 _mesa_printf("%s\n", __FUNCTION__ );
566 */
567
568 setup_sort_vertices( setup, prim );
569 setup_tri_coefficients( setup );
570 setup_tri_edges( setup );
571
572 setup->span.y = 0;
573 setup->span.y_flags = 0;
574 setup->span.right[0] = 0;
575 setup->span.right[1] = 0;
576 /* setup->span.z_mode = tri_z_mode( setup->ctx ); */
577
578 /* init_constant_attribs( setup ); */
579
580 if (setup->oneoverarea < 0.0) {
581 /* emaj on left:
582 */
583 subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines );
584 subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines );
585 }
586 else {
587 /* emaj on right:
588 */
589 subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines );
590 subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines );
591 }
592
593 flush_spans( setup );
594 }
595
596
597
598 /**
599 * Compute a0, dadx and dady for a linearly interpolated coefficient,
600 * for a line.
601 */
602 static void
603 line_linear_coeff(struct setup_stage *setup, GLuint slot, GLuint i)
604 {
605 const GLfloat dz = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
606 const GLfloat dadx = dz * setup->emaj.dx * setup->oneoverarea;
607 const GLfloat dady = dz * setup->emaj.dy * setup->oneoverarea;
608 setup->coef[slot].dadx[i] = dadx;
609 setup->coef[slot].dady[i] = dady;
610 setup->coef[slot].a0[i]
611 = (setup->vmin->data[slot][i] -
612 (dadx * (setup->vmin->data[0][0] - 0.5) +
613 dady * (setup->vmin->data[0][1] - 0.5)));
614 }
615
616
617 /**
618 * Compute a0, dadx and dady for a perspective-corrected interpolant,
619 * for a line.
620 */
621 static void
622 line_persp_coeff(struct setup_stage *setup, GLuint slot, GLuint i)
623 {
624 /* XXX to do */
625 line_linear_coeff(setup, slot, i); /* XXX temporary */
626 }
627
628
629 /**
630 * Compute the setup->coef[] array dadx, dady, a0 values.
631 * Must be called after setup->vmin,vmax are initialized.
632 */
633 static INLINE void
634 setup_line_coefficients(struct setup_stage *setup, struct prim_header *prim)
635 {
636 const enum interp_mode *interp = setup->softpipe->interp;
637 GLuint slot, j;
638
639 /* use setup->vmin, vmax to point to vertices */
640 setup->vprovoke = prim->v[1];
641 setup->vmin = prim->v[0];
642 setup->vmax = prim->v[1];
643
644 setup->emaj.dx = setup->vmax->data[0][0] - setup->vmin->data[0][0];
645 setup->emaj.dy = setup->vmax->data[0][1] - setup->vmin->data[0][1];
646 /* NOTE: this is not really 1/area */
647 setup->oneoverarea = 1.0 / (setup->emaj.dx * setup->emaj.dx +
648 setup->emaj.dy * setup->emaj.dy);
649
650 /* z and w are done by linear interpolation:
651 */
652 line_linear_coeff(setup, 0, 2);
653 line_linear_coeff(setup, 0, 3);
654
655 /* setup interpolation for all the remaining attributes:
656 */
657 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
658 switch (interp[slot]) {
659 case INTERP_CONSTANT:
660 for (j = 0; j < NUM_CHANNELS; j++)
661 const_coeff(setup, slot, j);
662 break;
663
664 case INTERP_LINEAR:
665 for (j = 0; j < NUM_CHANNELS; j++)
666 line_linear_coeff(setup, slot, j);
667 break;
668
669 case INTERP_PERSPECTIVE:
670 for (j = 0; j < NUM_CHANNELS; j++)
671 line_persp_coeff(setup, slot, j);
672 break;
673 }
674 }
675 }
676
677
678 /**
679 * Plot a pixel in a line segment.
680 */
681 static INLINE void
682 plot(struct setup_stage *setup, GLint x, GLint y)
683 {
684 const GLint iy = y & 1;
685 const GLint ix = x & 1;
686 const GLint quadX = x - ix;
687 const GLint quadY = y - iy;
688 const GLint mask = (1 << ix) << (2 * iy);
689
690 if (quadX != setup->quad.x0 ||
691 quadY != setup->quad.y0)
692 {
693 /* flush prev quad, start new quad */
694
695 if (setup->quad.x0 != -1)
696 quad_emit(setup->softpipe, &setup->quad);
697
698 setup->quad.x0 = quadX;
699 setup->quad.y0 = quadY;
700 setup->quad.mask = 0x0;
701 }
702
703 setup->quad.mask |= mask;
704 }
705
706
707
708 /**
709 * Do setup for line rasterization, then render the line.
710 * XXX single-pixel width, no stipple, etc
711 * XXX no scissoring yet.
712 */
713 static void
714 setup_line(struct draw_stage *stage, struct prim_header *prim)
715 {
716 const struct vertex_header *v0 = prim->v[0];
717 const struct vertex_header *v1 = prim->v[1];
718 struct setup_stage *setup = setup_stage( stage );
719
720 GLint x0 = (GLint) v0->data[0][0];
721 GLint x1 = (GLint) v1->data[0][0];
722 GLint y0 = (GLint) v0->data[0][1];
723 GLint y1 = (GLint) v1->data[0][1];
724 GLint dx = x1 - x0;
725 GLint dy = y1 - y0;
726 GLint xstep, ystep;
727
728 if (dx == 0 && dy == 0)
729 return;
730
731 setup_line_coefficients(setup, prim);
732
733 if (dx < 0) {
734 dx = -dx; /* make positive */
735 xstep = -1;
736 }
737 else {
738 xstep = 1;
739 }
740
741 if (dy < 0) {
742 dy = -dy; /* make positive */
743 ystep = -1;
744 }
745 else {
746 ystep = 1;
747 }
748
749 assert(dx >= 0);
750 assert(dy >= 0);
751
752 setup->quad.x0 = setup->quad.y0 = -1;
753 setup->quad.mask = 0x0;
754
755 if (dx > dy) {
756 /*** X-major line ***/
757 GLint i;
758 const GLint errorInc = dy + dy;
759 GLint error = errorInc - dx;
760 const GLint errorDec = error - dx;
761
762 for (i = 0; i < dx; i++) {
763 plot(setup, x0, y0);
764
765 x0 += xstep;
766 if (error < 0) {
767 error += errorInc;
768 }
769 else {
770 error += errorDec;
771 y0 += ystep;
772 }
773 }
774 }
775 else {
776 /*** Y-major line ***/
777 GLint i;
778 const GLint errorInc = dx + dx;
779 GLint error = errorInc - dy;
780 const GLint errorDec = error - dy;
781
782 for (i = 0; i < dy; i++) {
783 plot(setup, x0, y0);
784
785 y0 += ystep;
786
787 if (error < 0) {
788 error += errorInc;
789 }
790 else {
791 error += errorDec;
792 x0 += xstep;
793 }
794 }
795 }
796
797 /* draw final quad */
798 if (setup->quad.mask) {
799 quad_emit(setup->softpipe, &setup->quad);
800 }
801 }
802
803
804 /**
805 * Do setup for point rasterization, then render the point.
806 * Round or square points...
807 * XXX could optimize a lot for 1-pixel points.
808 */
809 static void
810 setup_point(struct draw_stage *stage, struct prim_header *prim)
811 {
812 struct setup_stage *setup = setup_stage( stage );
813 /*XXX this should be a vertex attrib! */
814 GLfloat halfSize = 0.5 * setup->softpipe->setup.point_size;
815 GLboolean round = setup->softpipe->setup.point_smooth;
816 const struct vertex_header *v0 = prim->v[0];
817 const GLfloat x = v0->data[FRAG_ATTRIB_WPOS][0];
818 const GLfloat y = v0->data[FRAG_ATTRIB_WPOS][1];
819 GLuint slot, j;
820
821 /* For points, all interpolants are constant-valued.
822 * However, for point sprites, we'll need to setup texcoords appropriately.
823 * XXX: which coefficients are the texcoords???
824 * We may do point sprites as textured quads...
825 *
826 * KW: We don't know which coefficients are texcoords - ultimately
827 * the choice of what interpolation mode to use for each attribute
828 * should be determined by the fragment program, using
829 * per-attribute declaration statements that include interpolation
830 * mode as a parameter. So either the fragment program will have
831 * to be adjusted for pointsprite vs normal point behaviour, or
832 * otherwise a special interpolation mode will have to be defined
833 * which matches the required behaviour for point sprites. But -
834 * the latter is not a feature of normal hardware, and as such
835 * probably should be ruled out on that basis.
836 */
837 setup->vprovoke = prim->v[0];
838 const_coeff(setup, 0, 2);
839 const_coeff(setup, 0, 3);
840 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
841 for (j = 0; j < NUM_CHANNELS; j++)
842 const_coeff(setup, slot, j);
843 }
844
845 /* XXX need to clip against scissor bounds too */
846
847 if (halfSize <= 0.5 && !round) {
848 /* special case for 1-pixel points */
849 const GLint ix = ((GLint) x) & 1;
850 const GLint iy = ((GLint) y) & 1;
851 setup->quad.x0 = x - ix;
852 setup->quad.y0 = y - iy;
853 setup->quad.mask = (1 << ix) << (2 * iy);
854 quad_emit(setup->softpipe, &setup->quad);
855 }
856 else {
857 const GLint ixmin = block((GLint) (x - halfSize));
858 const GLint ixmax = block((GLint) (x + halfSize));
859 const GLint iymin = block((GLint) (y - halfSize));
860 const GLint iymax = block((GLint) (y + halfSize));
861 GLint ix, iy;
862
863 if (round) {
864 /* rounded points */
865 const GLfloat rmin = halfSize - 0.7071F; /* 0.7071 = sqrt(2)/2 */
866 const GLfloat rmax = halfSize + 0.7071F;
867 const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
868 const GLfloat rmax2 = rmax * rmax;
869 const GLfloat cscale = 1.0F / (rmax2 - rmin2);
870
871 for (iy = iymin; iy <= iymax; iy += 2) {
872 for (ix = ixmin; ix <= ixmax; ix += 2) {
873 GLfloat dx, dy, dist2, cover;
874
875 setup->quad.mask = 0x0;
876
877 dx = (ix + 0.5) - x;
878 dy = (iy + 0.5) - y;
879 dist2 = dx * dx + dy * dy;
880 if (dist2 <= rmax2) {
881 cover = 1.0F - (dist2 - rmin2) * cscale;
882 setup->quad.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0);
883 setup->quad.mask |= MASK_BOTTOM_LEFT;
884 }
885
886 dx = (ix + 1.5) - x;
887 dy = (iy + 0.5) - y;
888 dist2 = dx * dx + dy * dy;
889 if (dist2 <= rmax2) {
890 cover = 1.0F - (dist2 - rmin2) * cscale;
891 setup->quad.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0);
892 setup->quad.mask |= MASK_BOTTOM_RIGHT;
893 }
894
895 dx = (ix + 0.5) - x;
896 dy = (iy + 1.5) - y;
897 dist2 = dx * dx + dy * dy;
898 if (dist2 <= rmax2) {
899 cover = 1.0F - (dist2 - rmin2) * cscale;
900 setup->quad.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0);
901 setup->quad.mask |= MASK_TOP_LEFT;
902 }
903
904 dx = (ix + 1.5) - x;
905 dy = (iy + 1.5) - y;
906 dist2 = dx * dx + dy * dy;
907 if (dist2 <= rmax2) {
908 cover = 1.0F - (dist2 - rmin2) * cscale;
909 setup->quad.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0);
910 setup->quad.mask |= MASK_TOP_RIGHT;
911 }
912
913 if (setup->quad.mask) {
914 setup->quad.x0 = ix;
915 setup->quad.y0 = iy;
916 quad_emit( setup->softpipe, &setup->quad );
917 }
918 }
919 }
920 }
921 else {
922 /* square points */
923 for (iy = iymin; iy <= iymax; iy += 2) {
924 for (ix = ixmin; ix <= ixmax; ix += 2) {
925 setup->quad.mask = 0xf;
926
927 if (ix + 0.5 < x - halfSize) {
928 /* fragment is past left edge of point, turn off left bits */
929 setup->quad.mask &= ~(MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
930 }
931
932 if (ix + 1.5 > x + halfSize) {
933 /* past the right edge */
934 setup->quad.mask &= ~(MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
935 }
936
937 if (iy + 0.5 < y - halfSize) {
938 /* below the bottom edge */
939 setup->quad.mask &= ~(MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
940 }
941
942 if (iy + 1.5 > y + halfSize) {
943 /* above the top edge */
944 setup->quad.mask &= ~(MASK_TOP_LEFT | MASK_TOP_RIGHT);
945 }
946
947 if (setup->quad.mask) {
948 setup->quad.x0 = ix;
949 setup->quad.y0 = iy;
950 quad_emit( setup->softpipe, &setup->quad );
951 }
952 }
953 }
954 }
955 }
956 }
957
958
959
960 static void setup_begin( struct draw_stage *stage )
961 {
962 struct setup_stage *setup = setup_stage(stage);
963
964 setup->quad.nr_attrs = setup->softpipe->nr_frag_attrs;
965
966 /*
967 * XXX this is where we might map() the renderbuffers to begin
968 * s/w rendering.
969 */
970 }
971
972
973 static void setup_end( struct draw_stage *stage )
974 {
975 /*
976 * XXX this is where we might unmap() the renderbuffers after
977 * s/w rendering.
978 */
979 }
980
981
982 /**
983 * Create a new primitive setup/render stage.
984 */
985 struct draw_stage *sp_draw_render_stage( struct softpipe_context *softpipe )
986 {
987 struct setup_stage *setup = CALLOC_STRUCT(setup_stage);
988
989 setup->softpipe = softpipe;
990 setup->stage.draw = softpipe->draw;
991 setup->stage.begin = setup_begin;
992 setup->stage.point = setup_point;
993 setup->stage.line = setup_line;
994 setup->stage.tri = setup_tri;
995 setup->stage.end = setup_end;
996
997 setup->quad.coef = setup->coef;
998
999 return &setup->stage;
1000 }