gallium: Fix memory leak.
[mesa.git] / src / mesa / swrast / s_points.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "glheader.h"
27 #include "colormac.h"
28 #include "context.h"
29 #include "macros.h"
30 #include "texstate.h"
31 #include "s_context.h"
32 #include "s_feedback.h"
33 #include "s_points.h"
34 #include "s_span.h"
35
36
37 /**
38 * Used to cull points with invalid coords
39 */
40 #define CULL_INVALID(V) \
41 do { \
42 float tmp = (V)->attrib[FRAG_ATTRIB_WPOS][0] \
43 + (V)->attrib[FRAG_ATTRIB_WPOS][1]; \
44 if (IS_INF_OR_NAN(tmp)) \
45 return; \
46 } while(0)
47
48
49 /**
50 * Draw a point sprite
51 */
52 static void
53 sprite_point(GLcontext *ctx, const SWvertex *vert)
54 {
55 SWcontext *swrast = SWRAST_CONTEXT(ctx);
56 SWspan span;
57 GLfloat size;
58 GLuint tCoords[MAX_TEXTURE_COORD_UNITS + 1];
59 GLuint numTcoords = 0;
60 GLfloat t0, dtdy;
61
62 CULL_INVALID(vert);
63
64 /* z coord */
65 if (ctx->DrawBuffer->Visual.depthBits <= 16)
66 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
67 else
68 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
69 span.zStep = 0;
70
71 /* compute size */
72 if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) {
73 /* use vertex's point size */
74 /* first, clamp attenuated size to the user-specifed range */
75 size = CLAMP(vert->pointSize, ctx->Point.MinSize, ctx->Point.MaxSize);
76 }
77 else {
78 /* use constant point size */
79 size = ctx->Point.Size;
80 }
81 /* clamp to non-AA implementation limits */
82 size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize);
83
84 /* span init */
85 INIT_SPAN(span, GL_POINT);
86 span.interpMask = SPAN_Z | SPAN_RGBA;
87
88 span.red = ChanToFixed(vert->color[0]);
89 span.green = ChanToFixed(vert->color[1]);
90 span.blue = ChanToFixed(vert->color[2]);
91 span.alpha = ChanToFixed(vert->color[3]);
92 span.redStep = 0;
93 span.greenStep = 0;
94 span.blueStep = 0;
95 span.alphaStep = 0;
96
97 /* need these for fragment programs */
98 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
99 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
100 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
101
102 {
103 GLfloat s, r, dsdx;
104
105 /* texcoord / pointcoord interpolants */
106 s = 0.0;
107 dsdx = 1.0 / size;
108 if (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) {
109 t0 = 0.0;
110 dtdy = 1.0 / size;
111 }
112 else {
113 /* GL_UPPER_LEFT */
114 t0 = 1.0;
115 dtdy = -1.0 / size;
116 }
117
118 ATTRIB_LOOP_BEGIN
119 if (attr >= FRAG_ATTRIB_TEX0 && attr < FRAG_ATTRIB_VAR0) {
120 const GLuint u = attr - FRAG_ATTRIB_TEX0;
121 /* a texcoord */
122 if (ctx->Point.CoordReplace[u]) {
123 tCoords[numTcoords++] = attr;
124
125 if (ctx->Point.SpriteRMode == GL_ZERO)
126 r = 0.0F;
127 else if (ctx->Point.SpriteRMode == GL_S)
128 r = vert->attrib[attr][0];
129 else /* GL_R */
130 r = vert->attrib[attr][2];
131
132 span.attrStart[attr][0] = s;
133 span.attrStart[attr][1] = 0.0; /* overwritten below */
134 span.attrStart[attr][2] = r;
135 span.attrStart[attr][3] = 1.0;
136
137 span.attrStepX[attr][0] = dsdx;
138 span.attrStepX[attr][1] = 0.0;
139 span.attrStepX[attr][2] = 0.0;
140 span.attrStepX[attr][3] = 0.0;
141
142 span.attrStepY[attr][0] = 0.0;
143 span.attrStepY[attr][1] = dtdy;
144 span.attrStepY[attr][2] = 0.0;
145 span.attrStepY[attr][3] = 0.0;
146
147 continue;
148 }
149 }
150 else if (attr == FRAG_ATTRIB_FOGC) {
151 /* GLSL gl_PointCoord is stored in fog.zw */
152 span.attrStart[FRAG_ATTRIB_FOGC][2] = 0.0;
153 span.attrStart[FRAG_ATTRIB_FOGC][3] = 0.0; /* t0 set below */
154 span.attrStepX[FRAG_ATTRIB_FOGC][2] = dsdx;
155 span.attrStepX[FRAG_ATTRIB_FOGC][3] = 0.0;
156 span.attrStepY[FRAG_ATTRIB_FOGC][2] = 0.0;
157 span.attrStepY[FRAG_ATTRIB_FOGC][3] = dtdy;
158 tCoords[numTcoords++] = FRAG_ATTRIB_FOGC;
159 continue;
160 }
161 /* use vertex's texcoord/attrib */
162 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
163 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
164 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
165 ATTRIB_LOOP_END;
166 }
167
168 /* compute pos, bounds and render */
169 {
170 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
171 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
172 GLint iSize = (GLint) (size + 0.5F);
173 GLint xmin, xmax, ymin, ymax, iy;
174 GLint iRadius;
175 GLfloat tcoord = t0;
176
177 iSize = MAX2(1, iSize);
178 iRadius = iSize / 2;
179
180 if (iSize & 1) {
181 /* odd size */
182 xmin = (GLint) (x - iRadius);
183 xmax = (GLint) (x + iRadius);
184 ymin = (GLint) (y - iRadius);
185 ymax = (GLint) (y + iRadius);
186 }
187 else {
188 /* even size */
189 xmin = (GLint) x - iRadius + 1;
190 xmax = xmin + iSize - 1;
191 ymin = (GLint) y - iRadius + 1;
192 ymax = ymin + iSize - 1;
193 }
194
195 /* render spans */
196 for (iy = ymin; iy <= ymax; iy++) {
197 GLuint i;
198 /* setup texcoord T for this row */
199 for (i = 0; i < numTcoords; i++) {
200 if (tCoords[i] == FRAG_ATTRIB_FOGC)
201 span.attrStart[FRAG_ATTRIB_FOGC][3] = tcoord;
202 else
203 span.attrStart[tCoords[i]][1] = tcoord;
204 }
205
206 /* these might get changed by span clipping */
207 span.x = xmin;
208 span.y = iy;
209 span.end = xmax - xmin + 1;
210
211 _swrast_write_rgba_span(ctx, &span);
212
213 tcoord += dtdy;
214 }
215 }
216 }
217
218
219 /**
220 * Draw smooth/antialiased point. RGB or CI mode.
221 */
222 static void
223 smooth_point(GLcontext *ctx, const SWvertex *vert)
224 {
225 SWcontext *swrast = SWRAST_CONTEXT(ctx);
226 const GLboolean ciMode = !ctx->Visual.rgbMode;
227 SWspan span;
228 GLfloat size, alphaAtten;
229
230 CULL_INVALID(vert);
231
232 /* z coord */
233 if (ctx->DrawBuffer->Visual.depthBits <= 16)
234 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
235 else
236 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
237 span.zStep = 0;
238
239 /* compute size */
240 if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) {
241 /* use vertex's point size */
242 /* first, clamp attenuated size to the user-specifed range */
243 size = CLAMP(vert->pointSize, ctx->Point.MinSize, ctx->Point.MaxSize);
244 }
245 else {
246 /* use constant point size */
247 size = ctx->Point.Size;
248 }
249 /* clamp to AA implementation limits */
250 size = CLAMP(size, ctx->Const.MinPointSizeAA, ctx->Const.MaxPointSizeAA);
251
252 /* alpha attenuation / fade factor */
253 if (ctx->Multisample.Enabled) {
254 if (vert->pointSize >= ctx->Point.Threshold) {
255 alphaAtten = 1.0F;
256 }
257 else {
258 GLfloat dsize = vert->pointSize / ctx->Point.Threshold;
259 alphaAtten = dsize * dsize;
260 }
261 }
262 else {
263 alphaAtten = 1.0;
264 }
265 (void) alphaAtten; /* not used */
266
267 /* span init */
268 INIT_SPAN(span, GL_POINT);
269 span.interpMask = SPAN_Z | SPAN_RGBA;
270 span.arrayMask = SPAN_COVERAGE | SPAN_MASK;
271
272 span.red = ChanToFixed(vert->color[0]);
273 span.green = ChanToFixed(vert->color[1]);
274 span.blue = ChanToFixed(vert->color[2]);
275 span.alpha = ChanToFixed(vert->color[3]);
276 span.redStep = 0;
277 span.greenStep = 0;
278 span.blueStep = 0;
279 span.alphaStep = 0;
280
281 /* need these for fragment programs */
282 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
283 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
284 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
285
286 ATTRIB_LOOP_BEGIN
287 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
288 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
289 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
290 ATTRIB_LOOP_END
291
292 /* compute pos, bounds and render */
293 {
294 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
295 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
296 const GLfloat radius = 0.5F * size;
297 const GLfloat rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
298 const GLfloat rmax = radius + 0.7071F;
299 const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
300 const GLfloat rmax2 = rmax * rmax;
301 const GLfloat cscale = 1.0F / (rmax2 - rmin2);
302 const GLint xmin = (GLint) (x - radius);
303 const GLint xmax = (GLint) (x + radius);
304 const GLint ymin = (GLint) (y - radius);
305 const GLint ymax = (GLint) (y + radius);
306 GLint ix, iy;
307
308 for (iy = ymin; iy <= ymax; iy++) {
309
310 /* these might get changed by span clipping */
311 span.x = xmin;
312 span.y = iy;
313 span.end = xmax - xmin + 1;
314
315 /* compute coverage for each pixel in span */
316 for (ix = xmin; ix <= xmax; ix++) {
317 const GLfloat dx = ix - x + 0.5F;
318 const GLfloat dy = iy - y + 0.5F;
319 const GLfloat dist2 = dx * dx + dy * dy;
320 GLfloat coverage;
321
322 if (dist2 < rmax2) {
323 if (dist2 >= rmin2) {
324 /* compute partial coverage */
325 coverage = 1.0F - (dist2 - rmin2) * cscale;
326 if (ciMode) {
327 /* coverage in [0,15] */
328 coverage *= 15.0;
329 }
330 }
331 else {
332 /* full coverage */
333 coverage = 1.0F;
334 }
335 span.array->mask[ix - xmin] = 1;
336 }
337 else {
338 /* zero coverage - fragment outside the radius */
339 coverage = 0.0;
340 span.array->mask[ix - xmin] = 0;
341 }
342 span.array->coverage[ix - xmin] = coverage;
343 }
344
345 /* render span */
346 _swrast_write_rgba_span(ctx, &span);
347
348 }
349 }
350 }
351
352
353 /**
354 * Draw large (size >= 1) non-AA point. RGB or CI mode.
355 */
356 static void
357 large_point(GLcontext *ctx, const SWvertex *vert)
358 {
359 SWcontext *swrast = SWRAST_CONTEXT(ctx);
360 const GLboolean ciMode = !ctx->Visual.rgbMode;
361 SWspan span;
362 GLfloat size;
363
364 CULL_INVALID(vert);
365
366 /* z coord */
367 if (ctx->DrawBuffer->Visual.depthBits <= 16)
368 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
369 else
370 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
371 span.zStep = 0;
372
373 /* compute size */
374 if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) {
375 /* use vertex's point size */
376 /* first, clamp attenuated size to the user-specifed range */
377 size = CLAMP(vert->pointSize, ctx->Point.MinSize, ctx->Point.MaxSize);
378 }
379 else {
380 /* use constant point size */
381 size = ctx->Point.Size;
382 }
383 /* clamp to non-AA implementation limits */
384 size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize);
385
386 /* span init */
387 INIT_SPAN(span, GL_POINT);
388 span.arrayMask = SPAN_XY;
389
390 if (ciMode) {
391 span.interpMask = SPAN_Z | SPAN_INDEX;
392 span.index = FloatToFixed(vert->attrib[FRAG_ATTRIB_CI][0]);
393 span.indexStep = 0;
394 }
395 else {
396 span.interpMask = SPAN_Z | SPAN_RGBA;
397 span.red = ChanToFixed(vert->color[0]);
398 span.green = ChanToFixed(vert->color[1]);
399 span.blue = ChanToFixed(vert->color[2]);
400 span.alpha = ChanToFixed(vert->color[3]);
401 span.redStep = 0;
402 span.greenStep = 0;
403 span.blueStep = 0;
404 span.alphaStep = 0;
405 }
406
407 /* need these for fragment programs */
408 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
409 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
410 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
411
412 ATTRIB_LOOP_BEGIN
413 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
414 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
415 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
416 ATTRIB_LOOP_END
417
418 /* compute pos, bounds and render */
419 {
420 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
421 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
422 GLint iSize = (GLint) (size + 0.5F);
423 GLint xmin, xmax, ymin, ymax, ix, iy;
424 GLint iRadius;
425
426 iSize = MAX2(1, iSize);
427 iRadius = iSize / 2;
428
429 if (iSize & 1) {
430 /* odd size */
431 xmin = (GLint) (x - iRadius);
432 xmax = (GLint) (x + iRadius);
433 ymin = (GLint) (y - iRadius);
434 ymax = (GLint) (y + iRadius);
435 }
436 else {
437 /* even size */
438 xmin = (GLint) x - iRadius + 1;
439 xmax = xmin + iSize - 1;
440 ymin = (GLint) y - iRadius + 1;
441 ymax = ymin + iSize - 1;
442 }
443
444 /* generate fragments */
445 span.end = 0;
446 for (iy = ymin; iy <= ymax; iy++) {
447 for (ix = xmin; ix <= xmax; ix++) {
448 span.array->x[span.end] = ix;
449 span.array->y[span.end] = iy;
450 span.end++;
451 }
452 }
453 assert(span.end <= MAX_WIDTH);
454 _swrast_write_rgba_span(ctx, &span);
455 }
456 }
457
458
459 /**
460 * Draw size=1, single-pixel point
461 */
462 static void
463 pixel_point(GLcontext *ctx, const SWvertex *vert)
464 {
465 SWcontext *swrast = SWRAST_CONTEXT(ctx);
466 const GLboolean ciMode = !ctx->Visual.rgbMode;
467 /*
468 * Note that unlike the other functions, we put single-pixel points
469 * into a special span array in order to render as many points as
470 * possible with a single _swrast_write_rgba_span() call.
471 */
472 SWspan *span = &(swrast->PointSpan);
473 GLuint count;
474
475 CULL_INVALID(vert);
476
477 /* Span init */
478 span->interpMask = 0;
479 span->arrayMask = SPAN_XY | SPAN_Z;
480 if (ciMode)
481 span->arrayMask |= SPAN_INDEX;
482 else
483 span->arrayMask |= SPAN_RGBA;
484 /*span->arrayMask |= SPAN_LAMBDA;*/
485 span->arrayAttribs = swrast->_ActiveAttribMask; /* we'll produce these vals */
486
487 /* need these for fragment programs */
488 span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
489 span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
490 span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
491
492 /* check if we need to flush */
493 if (span->end >= MAX_WIDTH ||
494 (swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT))) {
495 if (ciMode)
496 _swrast_write_index_span(ctx, span);
497 else
498 _swrast_write_rgba_span(ctx, span);
499 span->end = 0;
500 }
501
502 count = span->end;
503
504 /* fragment attributes */
505 if (ciMode) {
506 span->array->index[count] = (GLuint) vert->attrib[FRAG_ATTRIB_CI][0];
507 }
508 else {
509 span->array->rgba[count][RCOMP] = vert->color[0];
510 span->array->rgba[count][GCOMP] = vert->color[1];
511 span->array->rgba[count][BCOMP] = vert->color[2];
512 span->array->rgba[count][ACOMP] = vert->color[3];
513 }
514 ATTRIB_LOOP_BEGIN
515 COPY_4V(span->array->attribs[attr][count], vert->attrib[attr]);
516 ATTRIB_LOOP_END
517
518 /* fragment position */
519 span->array->x[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][0];
520 span->array->y[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][1];
521 span->array->z[count] = (GLint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
522
523 span->end = count + 1;
524 ASSERT(span->end <= MAX_WIDTH);
525 }
526
527
528 /**
529 * Add specular color to primary color, draw point, restore original
530 * primary color.
531 */
532 void
533 _swrast_add_spec_terms_point(GLcontext *ctx, const SWvertex *v0)
534 {
535 SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */
536 GLfloat rSum, gSum, bSum;
537 GLchan cSave[4];
538
539 /* save */
540 COPY_CHAN4(cSave, ncv0->color);
541 /* sum */
542 rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0];
543 gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1];
544 bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2];
545 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
546 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
547 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
548 /* draw */
549 SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0);
550 /* restore */
551 COPY_CHAN4(ncv0->color, cSave);
552 }
553
554
555 /**
556 * Examine current state to determine which point drawing function to use.
557 */
558 void
559 _swrast_choose_point(GLcontext *ctx)
560 {
561 SWcontext *swrast = SWRAST_CONTEXT(ctx);
562
563 if (ctx->RenderMode == GL_RENDER) {
564 if (ctx->Point.PointSprite) {
565 swrast->Point = sprite_point;
566 }
567 else if (ctx->Point.SmoothFlag) {
568 swrast->Point = smooth_point;
569 }
570 else if (ctx->Point.Size > 1.0 ||
571 ctx->Point._Attenuated ||
572 ctx->VertexProgram.PointSizeEnabled) {
573 swrast->Point = large_point;
574 }
575 else {
576 swrast->Point = pixel_point;
577 }
578 }
579 else if (ctx->RenderMode == GL_FEEDBACK) {
580 swrast->Point = _swrast_feedback_point;
581 }
582 else {
583 /* GL_SELECT mode */
584 swrast->Point = _swrast_select_point;
585 }
586 }