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