Maintain cliprect (scissor) info in sp_state_derived.c.
[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 * XXX no scissoring yet.
754 */
755 static void
756 setup_line(struct draw_stage *stage, struct prim_header *prim)
757 {
758 const struct vertex_header *v0 = prim->v[0];
759 const struct vertex_header *v1 = prim->v[1];
760 struct setup_stage *setup = setup_stage( stage );
761 struct softpipe_context *sp = setup->softpipe;
762
763 GLint x0 = (GLint) v0->data[0][0];
764 GLint x1 = (GLint) v1->data[0][0];
765 GLint y0 = (GLint) v0->data[0][1];
766 GLint y1 = (GLint) v1->data[0][1];
767 GLint dx = x1 - x0;
768 GLint dy = y1 - y0;
769 GLint xstep, ystep;
770
771 if (dx == 0 && dy == 0)
772 return;
773
774 setup_line_coefficients(setup, prim);
775
776 if (dx < 0) {
777 dx = -dx; /* make positive */
778 xstep = -1;
779 }
780 else {
781 xstep = 1;
782 }
783
784 if (dy < 0) {
785 dy = -dy; /* make positive */
786 ystep = -1;
787 }
788 else {
789 ystep = 1;
790 }
791
792 assert(dx >= 0);
793 assert(dy >= 0);
794
795 setup->quad.x0 = setup->quad.y0 = -1;
796 setup->quad.mask = 0x0;
797 setup->quad.prim = PRIM_LINE;
798 /* XXX temporary: set coverage to 1.0 so the line appears
799 * if AA mode happens to be enabled.
800 */
801 setup->quad.coverage[0] =
802 setup->quad.coverage[1] =
803 setup->quad.coverage[2] =
804 setup->quad.coverage[3] = 1.0;
805
806 if (dx > dy) {
807 /*** X-major line ***/
808 GLint i;
809 const GLint errorInc = dy + dy;
810 GLint error = errorInc - dx;
811 const GLint errorDec = error - dx;
812
813 for (i = 0; i < dx; i++) {
814 if (!sp->setup.line_stipple_enable ||
815 stipple_test(sp->line_stipple_counter,
816 sp->setup.line_stipple_pattern,
817 sp->setup.line_stipple_factor + 1)) {
818 plot(setup, x0, y0);
819 }
820
821 x0 += xstep;
822 if (error < 0) {
823 error += errorInc;
824 }
825 else {
826 error += errorDec;
827 y0 += ystep;
828 }
829
830 sp->line_stipple_counter++;
831 }
832 }
833 else {
834 /*** Y-major line ***/
835 GLint i;
836 const GLint errorInc = dx + dx;
837 GLint error = errorInc - dy;
838 const GLint errorDec = error - dy;
839
840 for (i = 0; i < dy; i++) {
841 if (!sp->setup.line_stipple_enable ||
842 stipple_test(sp->line_stipple_counter,
843 sp->setup.line_stipple_pattern,
844 sp->setup.line_stipple_factor + 1)) {
845 plot(setup, x0, y0);
846 }
847
848 y0 += ystep;
849
850 if (error < 0) {
851 error += errorInc;
852 }
853 else {
854 error += errorDec;
855 x0 += xstep;
856 }
857
858 sp->line_stipple_counter++;
859 }
860 }
861
862 /* draw final quad */
863 if (setup->quad.mask) {
864 quad_emit(setup);
865 }
866 }
867
868
869 /**
870 * Do setup for point rasterization, then render the point.
871 * Round or square points...
872 * XXX could optimize a lot for 1-pixel points.
873 */
874 static void
875 setup_point(struct draw_stage *stage, struct prim_header *prim)
876 {
877 struct setup_stage *setup = setup_stage( stage );
878 /*XXX this should be a vertex attrib! */
879 GLfloat halfSize = 0.5 * setup->softpipe->setup.point_size;
880 GLboolean round = setup->softpipe->setup.point_smooth;
881 const struct vertex_header *v0 = prim->v[0];
882 const GLfloat x = v0->data[FRAG_ATTRIB_WPOS][0];
883 const GLfloat y = v0->data[FRAG_ATTRIB_WPOS][1];
884 GLuint slot, j;
885
886 /* For points, all interpolants are constant-valued.
887 * However, for point sprites, we'll need to setup texcoords appropriately.
888 * XXX: which coefficients are the texcoords???
889 * We may do point sprites as textured quads...
890 *
891 * KW: We don't know which coefficients are texcoords - ultimately
892 * the choice of what interpolation mode to use for each attribute
893 * should be determined by the fragment program, using
894 * per-attribute declaration statements that include interpolation
895 * mode as a parameter. So either the fragment program will have
896 * to be adjusted for pointsprite vs normal point behaviour, or
897 * otherwise a special interpolation mode will have to be defined
898 * which matches the required behaviour for point sprites. But -
899 * the latter is not a feature of normal hardware, and as such
900 * probably should be ruled out on that basis.
901 */
902 setup->vprovoke = prim->v[0];
903 const_coeff(setup, 0, 2);
904 const_coeff(setup, 0, 3);
905 for (slot = 1; slot < setup->quad.nr_attrs; slot++) {
906 for (j = 0; j < NUM_CHANNELS; j++)
907 const_coeff(setup, slot, j);
908 }
909
910 setup->quad.prim = PRIM_POINT;
911
912 /* XXX need to clip against scissor bounds too */
913
914 if (halfSize <= 0.5 && !round) {
915 /* special case for 1-pixel points */
916 const GLint ix = ((GLint) x) & 1;
917 const GLint iy = ((GLint) y) & 1;
918 setup->quad.x0 = x - ix;
919 setup->quad.y0 = y - iy;
920 setup->quad.mask = (1 << ix) << (2 * iy);
921 quad_emit(setup);
922 }
923 else {
924 const GLint ixmin = block((GLint) (x - halfSize));
925 const GLint ixmax = block((GLint) (x + halfSize));
926 const GLint iymin = block((GLint) (y - halfSize));
927 const GLint iymax = block((GLint) (y + halfSize));
928 GLint ix, iy;
929
930 if (round) {
931 /* rounded points */
932 const GLfloat rmin = halfSize - 0.7071F; /* 0.7071 = sqrt(2)/2 */
933 const GLfloat rmax = halfSize + 0.7071F;
934 const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
935 const GLfloat rmax2 = rmax * rmax;
936 const GLfloat cscale = 1.0F / (rmax2 - rmin2);
937
938 for (iy = iymin; iy <= iymax; iy += 2) {
939 for (ix = ixmin; ix <= ixmax; ix += 2) {
940 GLfloat dx, dy, dist2, cover;
941
942 setup->quad.mask = 0x0;
943
944 dx = (ix + 0.5) - x;
945 dy = (iy + 0.5) - y;
946 dist2 = dx * dx + dy * dy;
947 if (dist2 <= rmax2) {
948 cover = 1.0F - (dist2 - rmin2) * cscale;
949 setup->quad.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0);
950 setup->quad.mask |= MASK_BOTTOM_LEFT;
951 }
952
953 dx = (ix + 1.5) - x;
954 dy = (iy + 0.5) - y;
955 dist2 = dx * dx + dy * dy;
956 if (dist2 <= rmax2) {
957 cover = 1.0F - (dist2 - rmin2) * cscale;
958 setup->quad.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0);
959 setup->quad.mask |= MASK_BOTTOM_RIGHT;
960 }
961
962 dx = (ix + 0.5) - x;
963 dy = (iy + 1.5) - y;
964 dist2 = dx * dx + dy * dy;
965 if (dist2 <= rmax2) {
966 cover = 1.0F - (dist2 - rmin2) * cscale;
967 setup->quad.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0);
968 setup->quad.mask |= MASK_TOP_LEFT;
969 }
970
971 dx = (ix + 1.5) - x;
972 dy = (iy + 1.5) - y;
973 dist2 = dx * dx + dy * dy;
974 if (dist2 <= rmax2) {
975 cover = 1.0F - (dist2 - rmin2) * cscale;
976 setup->quad.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0);
977 setup->quad.mask |= MASK_TOP_RIGHT;
978 }
979
980 if (setup->quad.mask) {
981 setup->quad.x0 = ix;
982 setup->quad.y0 = iy;
983 quad_emit(setup);
984 }
985 }
986 }
987 }
988 else {
989 /* square points */
990 for (iy = iymin; iy <= iymax; iy += 2) {
991 for (ix = ixmin; ix <= ixmax; ix += 2) {
992 setup->quad.mask = 0xf;
993
994 if (ix + 0.5 < x - halfSize) {
995 /* fragment is past left edge of point, turn off left bits */
996 setup->quad.mask &= ~(MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
997 }
998
999 if (ix + 1.5 > x + halfSize) {
1000 /* past the right edge */
1001 setup->quad.mask &= ~(MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
1002 }
1003
1004 if (iy + 0.5 < y - halfSize) {
1005 /* below the bottom edge */
1006 setup->quad.mask &= ~(MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
1007 }
1008
1009 if (iy + 1.5 > y + halfSize) {
1010 /* above the top edge */
1011 setup->quad.mask &= ~(MASK_TOP_LEFT | MASK_TOP_RIGHT);
1012 }
1013
1014 if (setup->quad.mask) {
1015 setup->quad.x0 = ix;
1016 setup->quad.y0 = iy;
1017 quad_emit(setup);
1018 }
1019 }
1020 }
1021 }
1022 }
1023 }
1024
1025
1026
1027 static void setup_begin( struct draw_stage *stage )
1028 {
1029 struct setup_stage *setup = setup_stage(stage);
1030
1031 setup->quad.nr_attrs = setup->softpipe->nr_frag_attrs;
1032
1033 /*
1034 * XXX this is where we might map() the renderbuffers to begin
1035 * s/w rendering.
1036 */
1037 }
1038
1039
1040 static void setup_end( struct draw_stage *stage )
1041 {
1042 /*
1043 * XXX this is where we might unmap() the renderbuffers after
1044 * s/w rendering.
1045 */
1046 }
1047
1048
1049 static void reset_stipple_counter( struct draw_stage *stage )
1050 {
1051 struct setup_stage *setup = setup_stage(stage);
1052 setup->softpipe->line_stipple_counter = 0;
1053 }
1054
1055
1056 /**
1057 * Create a new primitive setup/render stage.
1058 */
1059 struct draw_stage *sp_draw_render_stage( struct softpipe_context *softpipe )
1060 {
1061 struct setup_stage *setup = CALLOC_STRUCT(setup_stage);
1062
1063 setup->softpipe = softpipe;
1064 setup->stage.draw = softpipe->draw;
1065 setup->stage.begin = setup_begin;
1066 setup->stage.point = setup_point;
1067 setup->stage.line = setup_line;
1068 setup->stage.tri = setup_tri;
1069 setup->stage.end = setup_end;
1070 setup->stage.reset_stipple_counter = reset_stipple_counter;
1071
1072 setup->quad.coef = setup->coef;
1073
1074 return &setup->stage;
1075 }