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