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