*** empty log message ***
[mesa.git] / src / mesa / swrast / s_span.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.1
4 *
5 * Copyright (C) 1999-2004 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 /**
27 * \file swrast/s_span.c
28 * \brief Span processing functions used by all rasterization functions.
29 * This is where all the per-fragment tests are performed
30 * \author Brian Paul
31 */
32
33 #include "glheader.h"
34 #include "colormac.h"
35 #include "context.h"
36 #include "macros.h"
37 #include "imports.h"
38
39 #include "s_alpha.h"
40 #include "s_alphabuf.h"
41 #include "s_blend.h"
42 #include "s_context.h"
43 #include "s_depth.h"
44 #include "s_fog.h"
45 #include "s_logic.h"
46 #include "s_masking.h"
47 #include "s_nvfragprog.h"
48 #include "s_span.h"
49 #include "s_stencil.h"
50 #include "s_texture.h"
51
52
53 /**
54 * Init span's Z interpolation values to the RasterPos Z.
55 * Used during setup for glDraw/CopyPixels.
56 */
57 void
58 _swrast_span_default_z( GLcontext *ctx, struct sw_span *span )
59 {
60 if (ctx->Visual.depthBits <= 16)
61 span->z = FloatToFixed(ctx->Current.RasterPos[2] * ctx->DepthMax + 0.5F);
62 else
63 span->z = (GLint) (ctx->Current.RasterPos[2] * ctx->DepthMax + 0.5F);
64 span->zStep = 0;
65 span->interpMask |= SPAN_Z;
66 }
67
68
69 /**
70 * Init span's fog interpolation values to the RasterPos fog.
71 * Used during setup for glDraw/CopyPixels.
72 */
73 void
74 _swrast_span_default_fog( GLcontext *ctx, struct sw_span *span )
75 {
76 span->fog = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
77 span->fogStep = span->dfogdx = span->dfogdy = 0.0F;
78 span->interpMask |= SPAN_FOG;
79 }
80
81
82 /**
83 * Init span's color or index interpolation values to the RasterPos color.
84 * Used during setup for glDraw/CopyPixels.
85 */
86 void
87 _swrast_span_default_color( GLcontext *ctx, struct sw_span *span )
88 {
89 if (ctx->Visual.rgbMode) {
90 GLchan r, g, b, a;
91 UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
92 UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
93 UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
94 UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
95 #if CHAN_TYPE == GL_FLOAT
96 span->red = r;
97 span->green = g;
98 span->blue = b;
99 span->alpha = a;
100 #else
101 span->red = IntToFixed(r);
102 span->green = IntToFixed(g);
103 span->blue = IntToFixed(b);
104 span->alpha = IntToFixed(a);
105 #endif
106 span->redStep = 0;
107 span->greenStep = 0;
108 span->blueStep = 0;
109 span->alphaStep = 0;
110 span->interpMask |= SPAN_RGBA;
111 }
112 else {
113 span->index = FloatToFixed(ctx->Current.RasterIndex);
114 span->indexStep = 0;
115 span->interpMask |= SPAN_INDEX;
116 }
117 }
118
119
120 /**
121 * Init span's texcoord interpolation values to the RasterPos texcoords.
122 * Used during setup for glDraw/CopyPixels.
123 */
124 void
125 _swrast_span_default_texcoords( GLcontext *ctx, struct sw_span *span )
126 {
127 GLuint i;
128 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
129 const GLfloat *tc = ctx->Current.RasterTexCoords[i];
130 if (tc[3] > 0.0F) {
131 /* use (s/q, t/q, r/q, 1) */
132 span->tex[i][0] = tc[0] / tc[3];
133 span->tex[i][1] = tc[1] / tc[3];
134 span->tex[i][2] = tc[2] / tc[3];
135 span->tex[i][3] = 1.0;
136 }
137 else {
138 ASSIGN_4V(span->tex[i], 0.0F, 0.0F, 0.0F, 1.0F);
139 }
140 ASSIGN_4V(span->texStepX[i], 0.0F, 0.0F, 0.0F, 0.0F);
141 ASSIGN_4V(span->texStepY[i], 0.0F, 0.0F, 0.0F, 0.0F);
142 }
143 span->interpMask |= SPAN_TEXTURE;
144 }
145
146
147 /* Fill in the span.color.rgba array from the interpolation values */
148 static void
149 interpolate_colors(GLcontext *ctx, struct sw_span *span)
150 {
151 const GLuint n = span->end;
152 GLchan (*rgba)[4] = span->array->rgba;
153 GLuint i;
154 (void) ctx;
155
156 ASSERT((span->interpMask & SPAN_RGBA) &&
157 !(span->arrayMask & SPAN_RGBA));
158
159 if (span->interpMask & SPAN_FLAT) {
160 /* constant color */
161 GLchan color[4];
162 color[RCOMP] = FixedToChan(span->red);
163 color[GCOMP] = FixedToChan(span->green);
164 color[BCOMP] = FixedToChan(span->blue);
165 color[ACOMP] = FixedToChan(span->alpha);
166 for (i = 0; i < n; i++) {
167 COPY_CHAN4(span->array->rgba[i], color);
168 }
169 }
170 else {
171 /* interpolate */
172 #if CHAN_TYPE == GL_FLOAT
173 GLfloat r = span->red;
174 GLfloat g = span->green;
175 GLfloat b = span->blue;
176 GLfloat a = span->alpha;
177 const GLfloat dr = span->redStep;
178 const GLfloat dg = span->greenStep;
179 const GLfloat db = span->blueStep;
180 const GLfloat da = span->alphaStep;
181 #else
182 GLfixed r = span->red;
183 GLfixed g = span->green;
184 GLfixed b = span->blue;
185 GLfixed a = span->alpha;
186 const GLint dr = span->redStep;
187 const GLint dg = span->greenStep;
188 const GLint db = span->blueStep;
189 const GLint da = span->alphaStep;
190 #endif
191 for (i = 0; i < n; i++) {
192 rgba[i][RCOMP] = FixedToChan(r);
193 rgba[i][GCOMP] = FixedToChan(g);
194 rgba[i][BCOMP] = FixedToChan(b);
195 rgba[i][ACOMP] = FixedToChan(a);
196 r += dr;
197 g += dg;
198 b += db;
199 a += da;
200 }
201 }
202 span->arrayMask |= SPAN_RGBA;
203 }
204
205
206 /* Fill in the span.color.index array from the interpolation values */
207 static void
208 interpolate_indexes(GLcontext *ctx, struct sw_span *span)
209 {
210 GLfixed index = span->index;
211 const GLint indexStep = span->indexStep;
212 const GLuint n = span->end;
213 GLuint *indexes = span->array->index;
214 GLuint i;
215 (void) ctx;
216 ASSERT((span->interpMask & SPAN_INDEX) &&
217 !(span->arrayMask & SPAN_INDEX));
218
219 if ((span->interpMask & SPAN_FLAT) || (indexStep == 0)) {
220 /* constant color */
221 index = FixedToInt(index);
222 for (i = 0; i < n; i++) {
223 indexes[i] = index;
224 }
225 }
226 else {
227 /* interpolate */
228 for (i = 0; i < n; i++) {
229 indexes[i] = FixedToInt(index);
230 index += indexStep;
231 }
232 }
233 span->arrayMask |= SPAN_INDEX;
234 }
235
236
237 /* Fill in the span.->array->spec array from the interpolation values */
238 static void
239 interpolate_specular(GLcontext *ctx, struct sw_span *span)
240 {
241 (void) ctx;
242 if (span->interpMask & SPAN_FLAT) {
243 /* constant color */
244 const GLchan r = FixedToChan(span->specRed);
245 const GLchan g = FixedToChan(span->specGreen);
246 const GLchan b = FixedToChan(span->specBlue);
247 GLuint i;
248 for (i = 0; i < span->end; i++) {
249 span->array->spec[i][RCOMP] = r;
250 span->array->spec[i][GCOMP] = g;
251 span->array->spec[i][BCOMP] = b;
252 }
253 }
254 else {
255 /* interpolate */
256 #if CHAN_TYPE == GL_FLOAT
257 GLfloat r = span->specRed;
258 GLfloat g = span->specGreen;
259 GLfloat b = span->specBlue;
260 #else
261 GLfixed r = span->specRed;
262 GLfixed g = span->specGreen;
263 GLfixed b = span->specBlue;
264 #endif
265 GLuint i;
266 for (i = 0; i < span->end; i++) {
267 span->array->spec[i][RCOMP] = FixedToChan(r);
268 span->array->spec[i][GCOMP] = FixedToChan(g);
269 span->array->spec[i][BCOMP] = FixedToChan(b);
270 r += span->specRedStep;
271 g += span->specGreenStep;
272 b += span->specBlueStep;
273 }
274 }
275 span->arrayMask |= SPAN_SPEC;
276 }
277
278
279 /* Fill in the span.zArray array from the interpolation values */
280 void
281 _swrast_span_interpolate_z( const GLcontext *ctx, struct sw_span *span )
282 {
283 const GLuint n = span->end;
284 GLuint i;
285
286 ASSERT((span->interpMask & SPAN_Z) &&
287 !(span->arrayMask & SPAN_Z));
288
289 if (ctx->Visual.depthBits <= 16) {
290 GLfixed zval = span->z;
291 GLdepth *z = span->array->z;
292 for (i = 0; i < n; i++) {
293 z[i] = FixedToInt(zval);
294 zval += span->zStep;
295 }
296 }
297 else {
298 /* Deep Z buffer, no fixed->int shift */
299 GLfixed zval = span->z;
300 GLdepth *z = span->array->z;
301 for (i = 0; i < n; i++) {
302 z[i] = zval;
303 zval += span->zStep;
304 }
305 }
306 span->arrayMask |= SPAN_Z;
307 }
308
309
310 /*
311 * This the ideal solution, as given in the OpenGL spec.
312 */
313 #if 0
314 static GLfloat
315 compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
316 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
317 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
318 {
319 GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
320 GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
321 GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
322 GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
323 GLfloat x = SQRTF(dudx * dudx + dvdx * dvdx);
324 GLfloat y = SQRTF(dudy * dudy + dvdy * dvdy);
325 GLfloat rho = MAX2(x, y);
326 GLfloat lambda = LOG2(rho);
327 return lambda;
328 }
329 #endif
330
331
332 /*
333 * This is a faster approximation
334 */
335 GLfloat
336 _swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
337 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
338 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
339 {
340 GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
341 GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
342 GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
343 GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
344 GLfloat maxU, maxV, rho, lambda;
345 dsdx2 = FABSF(dsdx2);
346 dsdy2 = FABSF(dsdy2);
347 dtdx2 = FABSF(dtdx2);
348 dtdy2 = FABSF(dtdy2);
349 maxU = MAX2(dsdx2, dsdy2) * texW;
350 maxV = MAX2(dtdx2, dtdy2) * texH;
351 rho = MAX2(maxU, maxV);
352 lambda = LOG2(rho);
353 return lambda;
354 }
355
356
357 /**
358 * Fill in the span.texcoords array from the interpolation values.
359 * Note: in the places where we divide by Q (or mult by invQ) we're
360 * really doing two things: perspective correction and texcoord
361 * projection. Remember, for texcoord (s,t,r,q) we need to index
362 * texels with (s/q, t/q, r/q).
363 * If we're using a fragment program, we never do the division
364 * for texcoord projection. That's done by the TXP instruction
365 * or user-written code.
366 */
367 static void
368 interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
369 {
370 ASSERT(span->interpMask & SPAN_TEXTURE);
371 ASSERT(!(span->arrayMask & SPAN_TEXTURE));
372
373 if (ctx->Texture._EnabledCoordUnits > 1) {
374 /* multitexture */
375 GLuint u;
376 span->arrayMask |= SPAN_TEXTURE;
377 for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
378 if (ctx->Texture._EnabledCoordUnits & (1 << u)) {
379 const struct gl_texture_object *obj =ctx->Texture.Unit[u]._Current;
380 GLfloat texW, texH;
381 GLboolean needLambda;
382 if (obj) {
383 const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
384 needLambda = (obj->MinFilter != obj->MagFilter)
385 || ctx->FragmentProgram._Enabled;
386 texW = img->WidthScale;
387 texH = img->HeightScale;
388 }
389 else {
390 /* using a fragment program */
391 texW = 1.0;
392 texH = 1.0;
393 needLambda = GL_FALSE;
394 }
395 if (needLambda) {
396 GLfloat (*texcoord)[4] = span->array->texcoords[u];
397 GLfloat *lambda = span->array->lambda[u];
398 const GLfloat dsdx = span->texStepX[u][0];
399 const GLfloat dsdy = span->texStepY[u][0];
400 const GLfloat dtdx = span->texStepX[u][1];
401 const GLfloat dtdy = span->texStepY[u][1];
402 const GLfloat drdx = span->texStepX[u][2];
403 const GLfloat dqdx = span->texStepX[u][3];
404 const GLfloat dqdy = span->texStepY[u][3];
405 GLfloat s = span->tex[u][0];
406 GLfloat t = span->tex[u][1];
407 GLfloat r = span->tex[u][2];
408 GLfloat q = span->tex[u][3];
409 GLuint i;
410 if (ctx->FragmentProgram._Enabled) {
411 /* do perspective correction but don't divide s, t, r by q */
412 const GLfloat dwdx = span->dwdx;
413 GLfloat w = span->w;
414 for (i = 0; i < span->end; i++) {
415 const GLfloat invW = 1.0F / w;
416 texcoord[i][0] = s * invW;
417 texcoord[i][1] = t * invW;
418 texcoord[i][2] = r * invW;
419 texcoord[i][3] = q * invW;
420 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
421 dqdx, dqdy, texW, texH,
422 s, t, q, invW);
423 s += dsdx;
424 t += dtdx;
425 r += drdx;
426 q += dqdx;
427 w += dwdx;
428 }
429
430 }
431 else {
432 for (i = 0; i < span->end; i++) {
433 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
434 texcoord[i][0] = s * invQ;
435 texcoord[i][1] = t * invQ;
436 texcoord[i][2] = r * invQ;
437 texcoord[i][3] = q;
438 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
439 dqdx, dqdy, texW, texH,
440 s, t, q, invQ);
441 s += dsdx;
442 t += dtdx;
443 r += drdx;
444 q += dqdx;
445 }
446 }
447 span->arrayMask |= SPAN_LAMBDA;
448 }
449 else {
450 GLfloat (*texcoord)[4] = span->array->texcoords[u];
451 GLfloat *lambda = span->array->lambda[u];
452 const GLfloat dsdx = span->texStepX[u][0];
453 const GLfloat dtdx = span->texStepX[u][1];
454 const GLfloat drdx = span->texStepX[u][2];
455 const GLfloat dqdx = span->texStepX[u][3];
456 GLfloat s = span->tex[u][0];
457 GLfloat t = span->tex[u][1];
458 GLfloat r = span->tex[u][2];
459 GLfloat q = span->tex[u][3];
460 GLuint i;
461 if (ctx->FragmentProgram._Enabled) {
462 /* do perspective correction but don't divide s, t, r by q */
463 const GLfloat dwdx = span->dwdx;
464 GLfloat w = span->w;
465 for (i = 0; i < span->end; i++) {
466 const GLfloat invW = 1.0F / w;
467 texcoord[i][0] = s * invW;
468 texcoord[i][1] = t * invW;
469 texcoord[i][2] = r * invW;
470 texcoord[i][3] = q * invW;
471 lambda[i] = 0.0;
472 s += dsdx;
473 t += dtdx;
474 r += drdx;
475 q += dqdx;
476 w += dwdx;
477 }
478 }
479 else if (dqdx == 0.0F) {
480 /* Ortho projection or polygon's parallel to window X axis */
481 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
482 for (i = 0; i < span->end; i++) {
483 texcoord[i][0] = s * invQ;
484 texcoord[i][1] = t * invQ;
485 texcoord[i][2] = r * invQ;
486 texcoord[i][3] = q;
487 lambda[i] = 0.0;
488 s += dsdx;
489 t += dtdx;
490 r += drdx;
491 }
492 }
493 else {
494 for (i = 0; i < span->end; i++) {
495 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
496 texcoord[i][0] = s * invQ;
497 texcoord[i][1] = t * invQ;
498 texcoord[i][2] = r * invQ;
499 texcoord[i][3] = q;
500 lambda[i] = 0.0;
501 s += dsdx;
502 t += dtdx;
503 r += drdx;
504 q += dqdx;
505 }
506 }
507 } /* lambda */
508 } /* if */
509 } /* for */
510 }
511 else {
512 /* single texture */
513 const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;
514 GLfloat texW, texH;
515 GLboolean needLambda;
516 if (obj) {
517 const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
518 needLambda = (obj->MinFilter != obj->MagFilter)
519 || ctx->FragmentProgram._Enabled;
520 texW = (GLfloat) img->WidthScale;
521 texH = (GLfloat) img->HeightScale;
522 }
523 else {
524 needLambda = GL_FALSE;
525 texW = texH = 1.0;
526 }
527 span->arrayMask |= SPAN_TEXTURE;
528 if (needLambda) {
529 /* just texture unit 0, with lambda */
530 GLfloat (*texcoord)[4] = span->array->texcoords[0];
531 GLfloat *lambda = span->array->lambda[0];
532 const GLfloat dsdx = span->texStepX[0][0];
533 const GLfloat dsdy = span->texStepY[0][0];
534 const GLfloat dtdx = span->texStepX[0][1];
535 const GLfloat dtdy = span->texStepY[0][1];
536 const GLfloat drdx = span->texStepX[0][2];
537 const GLfloat dqdx = span->texStepX[0][3];
538 const GLfloat dqdy = span->texStepY[0][3];
539 GLfloat s = span->tex[0][0];
540 GLfloat t = span->tex[0][1];
541 GLfloat r = span->tex[0][2];
542 GLfloat q = span->tex[0][3];
543 GLuint i;
544 if (ctx->FragmentProgram._Enabled) {
545 /* do perspective correction but don't divide s, t, r by q */
546 const GLfloat dwdx = span->dwdx;
547 GLfloat w = span->w;
548 for (i = 0; i < span->end; i++) {
549 const GLfloat invW = 1.0F / w;
550 texcoord[i][0] = s * invW;
551 texcoord[i][1] = t * invW;
552 texcoord[i][2] = r * invW;
553 texcoord[i][3] = q * invW;
554 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
555 dqdx, dqdy, texW, texH,
556 s, t, q, invW);
557 s += dsdx;
558 t += dtdx;
559 r += drdx;
560 q += dqdx;
561 w += dwdx;
562 }
563 }
564 else {
565 /* tex.c */
566 for (i = 0; i < span->end; i++) {
567 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
568 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
569 dqdx, dqdy, texW, texH,
570 s, t, q, invQ);
571 texcoord[i][0] = s * invQ;
572 texcoord[i][1] = t * invQ;
573 texcoord[i][2] = r * invQ;
574 texcoord[i][3] = q;
575 s += dsdx;
576 t += dtdx;
577 r += drdx;
578 q += dqdx;
579 }
580 }
581 span->arrayMask |= SPAN_LAMBDA;
582 }
583 else {
584 /* just texture 0, without lambda */
585 GLfloat (*texcoord)[4] = span->array->texcoords[0];
586 const GLfloat dsdx = span->texStepX[0][0];
587 const GLfloat dtdx = span->texStepX[0][1];
588 const GLfloat drdx = span->texStepX[0][2];
589 const GLfloat dqdx = span->texStepX[0][3];
590 GLfloat s = span->tex[0][0];
591 GLfloat t = span->tex[0][1];
592 GLfloat r = span->tex[0][2];
593 GLfloat q = span->tex[0][3];
594 GLuint i;
595 if (ctx->FragmentProgram._Enabled) {
596 /* do perspective correction but don't divide s, t, r by q */
597 const GLfloat dwdx = span->dwdx;
598 GLfloat w = span->w;
599 for (i = 0; i < span->end; i++) {
600 const GLfloat invW = 1.0F / w;
601 texcoord[i][0] = s * invW;
602 texcoord[i][1] = t * invW;
603 texcoord[i][2] = r * invW;
604 texcoord[i][3] = q * invW;
605 s += dsdx;
606 t += dtdx;
607 r += drdx;
608 q += dqdx;
609 w += dwdx;
610 }
611 }
612 else if (dqdx == 0.0F) {
613 /* Ortho projection or polygon's parallel to window X axis */
614 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
615 for (i = 0; i < span->end; i++) {
616 texcoord[i][0] = s * invQ;
617 texcoord[i][1] = t * invQ;
618 texcoord[i][2] = r * invQ;
619 texcoord[i][3] = q;
620 s += dsdx;
621 t += dtdx;
622 r += drdx;
623 }
624 }
625 else {
626 for (i = 0; i < span->end; i++) {
627 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
628 texcoord[i][0] = s * invQ;
629 texcoord[i][1] = t * invQ;
630 texcoord[i][2] = r * invQ;
631 texcoord[i][3] = q;
632 s += dsdx;
633 t += dtdx;
634 r += drdx;
635 q += dqdx;
636 }
637 }
638 }
639 }
640 }
641
642
643 /**
644 * Apply the current polygon stipple pattern to a span of pixels.
645 */
646 static void
647 stipple_polygon_span( GLcontext *ctx, struct sw_span *span )
648 {
649 const GLuint highbit = 0x80000000;
650 const GLuint stipple = ctx->PolygonStipple[span->y % 32];
651 GLubyte *mask = span->array->mask;
652 GLuint i, m;
653
654 ASSERT(ctx->Polygon.StippleFlag);
655 ASSERT((span->arrayMask & SPAN_XY) == 0);
656
657 m = highbit >> (GLuint) (span->x % 32);
658
659 for (i = 0; i < span->end; i++) {
660 if ((m & stipple) == 0) {
661 mask[i] = 0;
662 }
663 m = m >> 1;
664 if (m == 0) {
665 m = highbit;
666 }
667 }
668 span->writeAll = GL_FALSE;
669 }
670
671
672 /**
673 * Clip a pixel span to the current buffer/window boundaries:
674 * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax. This will accomplish
675 * window clipping and scissoring.
676 * Return: GL_TRUE some pixels still visible
677 * GL_FALSE nothing visible
678 */
679 static GLuint
680 clip_span( GLcontext *ctx, struct sw_span *span )
681 {
682 const GLint xmin = ctx->DrawBuffer->_Xmin;
683 const GLint xmax = ctx->DrawBuffer->_Xmax;
684 const GLint ymin = ctx->DrawBuffer->_Ymin;
685 const GLint ymax = ctx->DrawBuffer->_Ymax;
686
687 if (span->arrayMask & SPAN_XY) {
688 /* arrays of x/y pixel coords */
689 const GLint *x = span->array->x;
690 const GLint *y = span->array->y;
691 const GLint n = span->end;
692 GLubyte *mask = span->array->mask;
693 GLint i;
694 if (span->arrayMask & SPAN_MASK) {
695 /* note: using & intead of && to reduce branches */
696 for (i = 0; i < n; i++) {
697 mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
698 & (y[i] >= ymin) & (y[i] < ymax);
699 }
700 }
701 else {
702 /* note: using & intead of && to reduce branches */
703 for (i = 0; i < n; i++) {
704 mask[i] = (x[i] >= xmin) & (x[i] < xmax)
705 & (y[i] >= ymin) & (y[i] < ymax);
706 }
707 }
708 return GL_TRUE; /* some pixels visible */
709 }
710 else {
711 /* horizontal span of pixels */
712 const GLint x = span->x;
713 const GLint y = span->y;
714 const GLint n = span->end;
715
716 /* Trivial rejection tests */
717 if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
718 span->end = 0;
719 return GL_FALSE; /* all pixels clipped */
720 }
721
722 /* Clip to the left */
723 if (x < xmin) {
724 ASSERT(x + n > xmin);
725 span->writeAll = GL_FALSE;
726 _mesa_bzero(span->array->mask, (xmin - x) * sizeof(GLubyte));
727 }
728
729 /* Clip to right */
730 if (x + n > xmax) {
731 ASSERT(x < xmax);
732 span->end = xmax - x;
733 }
734
735 return GL_TRUE; /* some pixels visible */
736 }
737 }
738
739
740
741 /**
742 * Draw to more than one color buffer (or none).
743 */
744 static void
745 multi_write_index_span( GLcontext *ctx, struct sw_span *span )
746 {
747 SWcontext *swrast = SWRAST_CONTEXT(ctx);
748 GLuint bufferBit;
749
750 /* loop over four possible dest color buffers */
751 for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) {
752 if (bufferBit & ctx->Color._DrawDestMask[0]) {
753 GLuint indexTmp[MAX_WIDTH];
754 ASSERT(span->end < MAX_WIDTH);
755
756 /* Set the current read/draw buffer */
757 swrast->CurrentBufferBit = bufferBit;
758 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, bufferBit);
759
760 /* make copy of incoming indexes */
761 MEMCPY( indexTmp, span->array->index, span->end * sizeof(GLuint) );
762
763 if (ctx->Color.IndexLogicOpEnabled) {
764 _swrast_logicop_ci_span(ctx, span, indexTmp);
765 }
766
767 if (ctx->Color.IndexMask != 0xffffffff) {
768 _swrast_mask_index_span(ctx, span, indexTmp);
769 }
770
771 if (span->arrayMask & SPAN_XY) {
772 /* array of pixel coords */
773 (*swrast->Driver.WriteCI32Pixels)(ctx, span->end,
774 span->array->x, span->array->y,
775 indexTmp, span->array->mask);
776 }
777 else {
778 /* horizontal run of pixels */
779 (*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y,
780 indexTmp, span->array->mask);
781 }
782 }
783 }
784
785 /* restore default dest buffer */
786 _swrast_use_draw_buffer(ctx);
787 }
788
789
790 /**
791 * Draw to more than one RGBA color buffer (or none).
792 * All fragment operations, up to (but not) blending/logicop should
793 * have been done first.
794 */
795 static void
796 multi_write_rgba_span( GLcontext *ctx, struct sw_span *span )
797 {
798 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
799 GLuint bufferBit;
800 SWcontext *swrast = SWRAST_CONTEXT(ctx);
801
802 ASSERT(colorMask != 0x0);
803
804 if (ctx->Color.DrawBuffer == GL_NONE)
805 return;
806
807 /* loop over four possible dest color buffers */
808 for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) {
809 if (bufferBit & ctx->Color._DrawDestMask[0]) {
810 GLchan rgbaTmp[MAX_WIDTH][4];
811 ASSERT(span->end < MAX_WIDTH);
812
813 /* Set the current read/draw buffer */
814 swrast->CurrentBufferBit = bufferBit;
815 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, bufferBit);
816
817 /* make copy of incoming colors */
818 MEMCPY( rgbaTmp, span->array->rgba, 4 * span->end * sizeof(GLchan) );
819
820 if (ctx->Color._LogicOpEnabled) {
821 _swrast_logicop_rgba_span(ctx, span, rgbaTmp);
822 }
823 else if (ctx->Color.BlendEnabled) {
824 _swrast_blend_span(ctx, span, rgbaTmp);
825 }
826
827 if (colorMask != 0xffffffff) {
828 _swrast_mask_rgba_span(ctx, span, rgbaTmp);
829 }
830
831 if (span->arrayMask & SPAN_XY) {
832 /* array of pixel coords */
833 (*swrast->Driver.WriteRGBAPixels)(ctx, span->end,
834 span->array->x, span->array->y,
835 (const GLchan (*)[4]) rgbaTmp,
836 span->array->mask);
837 if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
838 _swrast_write_alpha_pixels(ctx, span->end,
839 span->array->x, span->array->y,
840 (const GLchan (*)[4]) rgbaTmp,
841 span->array->mask);
842 }
843 }
844 else {
845 /* horizontal run of pixels */
846 (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
847 (const GLchan (*)[4]) rgbaTmp,
848 span->array->mask);
849 if (swrast->_RasterMask & ALPHABUF_BIT) {
850 _swrast_write_alpha_span(ctx, span->end, span->x, span->y,
851 (const GLchan (*)[4]) rgbaTmp,
852 span->array->mask);
853 }
854 }
855 }
856 }
857
858 /* restore default dest buffer */
859 _swrast_use_draw_buffer(ctx);
860 }
861
862
863
864 /**
865 * This function may modify any of the array values in the span.
866 * span->interpMask and span->arrayMask may be changed but will be restored
867 * to their original values before returning.
868 */
869 void
870 _swrast_write_index_span( GLcontext *ctx, struct sw_span *span)
871 {
872 SWcontext *swrast = SWRAST_CONTEXT(ctx);
873 const GLuint origInterpMask = span->interpMask;
874 const GLuint origArrayMask = span->arrayMask;
875
876 ASSERT(span->end <= MAX_WIDTH);
877 ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
878 span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
879 ASSERT((span->interpMask | span->arrayMask) & SPAN_INDEX);
880 ASSERT((span->interpMask & span->arrayMask) == 0);
881
882 if (span->arrayMask & SPAN_MASK) {
883 /* mask was initialized by caller, probably glBitmap */
884 span->writeAll = GL_FALSE;
885 }
886 else {
887 MEMSET(span->array->mask, 1, span->end);
888 span->writeAll = GL_TRUE;
889 }
890
891 /* Clipping */
892 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
893 if (!clip_span(ctx, span)) {
894 return;
895 }
896 }
897
898 /* Depth bounds test */
899 if (ctx->Depth.BoundsTest && ctx->Visual.depthBits > 0) {
900 if (!_swrast_depth_bounds_test(ctx, span)) {
901 return;
902 }
903 }
904
905 #ifdef DEBUG
906 if (span->arrayMask & SPAN_XY) {
907 GLuint i;
908 for (i = 0; i < span->end; i++) {
909 if (span->array->mask[i]) {
910 assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
911 assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
912 assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
913 assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
914 }
915 }
916 }
917 #endif
918
919 /* Polygon Stippling */
920 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
921 stipple_polygon_span(ctx, span);
922 }
923
924 /* Depth test and stencil */
925 if (ctx->Depth.Test || ctx->Stencil.Enabled) {
926 if (span->interpMask & SPAN_Z)
927 _swrast_span_interpolate_z(ctx, span);
928
929 if (ctx->Stencil.Enabled) {
930 if (!_swrast_stencil_and_ztest_span(ctx, span)) {
931 span->arrayMask = origArrayMask;
932 return;
933 }
934 }
935 else {
936 ASSERT(ctx->Depth.Test);
937 if (!_swrast_depth_test_span(ctx, span)) {
938 span->arrayMask = origArrayMask;
939 return;
940 }
941 }
942 }
943
944 /* if we get here, something passed the depth test */
945 if (ctx->Depth.OcclusionTest) {
946 ctx->OcclusionResult = GL_TRUE;
947 }
948
949 #if FEATURE_ARB_occlusion_query
950 if (ctx->Occlusion.Active) {
951 /* update count of 'passed' fragments */
952 GLuint i;
953 for (i = 0; i < span->end; i++)
954 ctx->Occlusion.PassedCounter += span->array->mask[i];
955 }
956 #endif
957
958 /* we have to wait until after occlusion to do this test */
959 if (ctx->Color.DrawBuffer == GL_NONE || ctx->Color.IndexMask == 0) {
960 /* write no pixels */
961 span->arrayMask = origArrayMask;
962 return;
963 }
964
965 /* Interpolate the color indexes if needed */
966 if (span->interpMask & SPAN_INDEX) {
967 interpolate_indexes(ctx, span);
968 /* clear the bit - this allows the WriteMonoCISpan optimization below */
969 span->interpMask &= ~SPAN_INDEX;
970 }
971
972 /* Fog */
973 if (ctx->Fog.Enabled) {
974 _swrast_fog_ci_span(ctx, span);
975 }
976
977 /* Antialias coverage application */
978 if (span->arrayMask & SPAN_COVERAGE) {
979 GLuint i;
980 GLuint *index = span->array->index;
981 GLfloat *coverage = span->array->coverage;
982 for (i = 0; i < span->end; i++) {
983 ASSERT(coverage[i] < 16);
984 index[i] = (index[i] & ~0xf) | ((GLuint) coverage[i]);
985 }
986 }
987
988 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
989 /* draw to zero or two or more buffers */
990 multi_write_index_span(ctx, span);
991 }
992 else {
993 /* normal situation: draw to exactly one buffer */
994 if (ctx->Color.IndexLogicOpEnabled) {
995 _swrast_logicop_ci_span(ctx, span, span->array->index);
996 }
997
998 if (ctx->Color.IndexMask != 0xffffffff) {
999 _swrast_mask_index_span(ctx, span, span->array->index);
1000 }
1001
1002 /* write pixels */
1003 if (span->arrayMask & SPAN_XY) {
1004 /* array of pixel coords */
1005 if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
1006 /* all pixels have same color index */
1007 (*swrast->Driver.WriteMonoCIPixels)(ctx, span->end,
1008 span->array->x, span->array->y,
1009 FixedToInt(span->index),
1010 span->array->mask);
1011 }
1012 else {
1013 (*swrast->Driver.WriteCI32Pixels)(ctx, span->end, span->array->x,
1014 span->array->y, span->array->index,
1015 span->array->mask );
1016 }
1017 }
1018 else {
1019 /* horizontal run of pixels */
1020 if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
1021 /* all pixels have same color index */
1022 (*swrast->Driver.WriteMonoCISpan)(ctx, span->end, span->x, span->y,
1023 FixedToInt(span->index),
1024 span->array->mask);
1025 }
1026 else {
1027 (*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y,
1028 span->array->index,
1029 span->array->mask);
1030 }
1031 }
1032 }
1033
1034 span->interpMask = origInterpMask;
1035 span->arrayMask = origArrayMask;
1036 }
1037
1038
1039 /**
1040 * This function may modify any of the array values in the span.
1041 * span->interpMask and span->arrayMask may be changed but will be restored
1042 * to their original values before returning.
1043 */
1044 void
1045 _swrast_write_rgba_span( GLcontext *ctx, struct sw_span *span)
1046 {
1047 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1048 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
1049 const GLuint origInterpMask = span->interpMask;
1050 const GLuint origArrayMask = span->arrayMask;
1051 GLboolean monoColor;
1052
1053 ASSERT(span->end <= MAX_WIDTH);
1054 ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
1055 span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
1056 ASSERT((span->interpMask & span->arrayMask) == 0);
1057 ASSERT((span->interpMask | span->arrayMask) & SPAN_RGBA);
1058 #ifdef DEBUG
1059 if (ctx->Fog.Enabled)
1060 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
1061 if (ctx->Depth.Test)
1062 ASSERT((span->interpMask | span->arrayMask) & SPAN_Z);
1063 #endif
1064
1065 if (span->arrayMask & SPAN_MASK) {
1066 /* mask was initialized by caller, probably glBitmap */
1067 span->writeAll = GL_FALSE;
1068 }
1069 else {
1070 MEMSET(span->array->mask, 1, span->end);
1071 span->writeAll = GL_TRUE;
1072 }
1073
1074 /* Determine if we have mono-chromatic colors */
1075 monoColor = (span->interpMask & SPAN_RGBA) &&
1076 span->redStep == 0 && span->greenStep == 0 &&
1077 span->blueStep == 0 && span->alphaStep == 0;
1078
1079 /* Clipping */
1080 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
1081 if (!clip_span(ctx, span)) {
1082 return;
1083 }
1084 }
1085
1086 /* Depth bounds test */
1087 if (ctx->Depth.BoundsTest && ctx->Visual.depthBits > 0) {
1088 if (!_swrast_depth_bounds_test(ctx, span)) {
1089 return;
1090 }
1091 }
1092
1093 #ifdef DEBUG
1094 if (span->arrayMask & SPAN_XY) {
1095 GLuint i;
1096 for (i = 0; i < span->end; i++) {
1097 if (span->array->mask[i]) {
1098 assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
1099 assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
1100 assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
1101 assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
1102 }
1103 }
1104 }
1105 #endif
1106
1107 /* Polygon Stippling */
1108 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
1109 stipple_polygon_span(ctx, span);
1110 }
1111
1112 /* Fragment program */
1113 if (ctx->FragmentProgram._Enabled) {
1114 /* Now we may need to interpolate the colors and texcoords */
1115 if ((span->interpMask & SPAN_RGBA) &&
1116 (span->arrayMask & SPAN_RGBA) == 0) {
1117 interpolate_colors(ctx, span);
1118 span->interpMask &= ~SPAN_RGBA;
1119 }
1120 if (span->interpMask & SPAN_SPEC) {
1121 interpolate_specular(ctx, span);
1122 }
1123 if ((span->interpMask & SPAN_TEXTURE)
1124 && (span->arrayMask & SPAN_TEXTURE) == 0)
1125 interpolate_texcoords(ctx, span);
1126 _swrast_exec_fragment_program(ctx, span);
1127 monoColor = GL_FALSE;
1128 }
1129
1130 /* Do the alpha test */
1131 if (ctx->Color.AlphaEnabled) {
1132 if (!_swrast_alpha_test(ctx, span)) {
1133 span->interpMask = origInterpMask;
1134 span->arrayMask = origArrayMask;
1135 return;
1136 }
1137 }
1138
1139 /* Stencil and Z testing */
1140 if (ctx->Stencil.Enabled || ctx->Depth.Test) {
1141 if (span->interpMask & SPAN_Z)
1142 _swrast_span_interpolate_z(ctx, span);
1143
1144 if (ctx->Stencil.Enabled) {
1145 if (!_swrast_stencil_and_ztest_span(ctx, span)) {
1146 span->interpMask = origInterpMask;
1147 span->arrayMask = origArrayMask;
1148 return;
1149 }
1150 }
1151 else {
1152 ASSERT(ctx->Depth.Test);
1153 ASSERT(span->arrayMask & SPAN_Z);
1154 /* regular depth testing */
1155 if (!_swrast_depth_test_span(ctx, span)) {
1156 span->interpMask = origInterpMask;
1157 span->arrayMask = origArrayMask;
1158 return;
1159 }
1160 }
1161 }
1162
1163 /* if we get here, something passed the depth test */
1164 if (ctx->Depth.OcclusionTest) {
1165 ctx->OcclusionResult = GL_TRUE;
1166 }
1167
1168 #if FEATURE_ARB_occlusion_query
1169 if (ctx->Occlusion.Active) {
1170 /* update count of 'passed' fragments */
1171 GLuint i;
1172 for (i = 0; i < span->end; i++)
1173 ctx->Occlusion.PassedCounter += span->array->mask[i];
1174 }
1175 #endif
1176
1177 /* can't abort span-writing until after occlusion testing */
1178 if (colorMask == 0x0) {
1179 span->interpMask = origInterpMask;
1180 span->arrayMask = origArrayMask;
1181 return;
1182 }
1183
1184 /* Now we may need to interpolate the colors */
1185 if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0) {
1186 interpolate_colors(ctx, span);
1187 /* clear the bit - this allows the WriteMonoCISpan optimization below */
1188 span->interpMask &= ~SPAN_RGBA;
1189 }
1190
1191 /* Fog */
1192 if (swrast->_FogEnabled) {
1193 _swrast_fog_rgba_span(ctx, span);
1194 monoColor = GL_FALSE;
1195 }
1196
1197 /* Antialias coverage application */
1198 if (span->arrayMask & SPAN_COVERAGE) {
1199 GLchan (*rgba)[4] = span->array->rgba;
1200 GLfloat *coverage = span->array->coverage;
1201 GLuint i;
1202 for (i = 0; i < span->end; i++) {
1203 rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]);
1204 }
1205 monoColor = GL_FALSE;
1206 }
1207
1208 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
1209 multi_write_rgba_span(ctx, span);
1210 }
1211 else {
1212 /* normal: write to exactly one buffer */
1213 if (ctx->Color._LogicOpEnabled) {
1214 _swrast_logicop_rgba_span(ctx, span, span->array->rgba);
1215 monoColor = GL_FALSE;
1216 }
1217 else if (ctx->Color.BlendEnabled) {
1218 _swrast_blend_span(ctx, span, span->array->rgba);
1219 monoColor = GL_FALSE;
1220 }
1221
1222 /* Color component masking */
1223 if (colorMask != 0xffffffff) {
1224 _swrast_mask_rgba_span(ctx, span, span->array->rgba);
1225 monoColor = GL_FALSE;
1226 }
1227
1228 /* write pixels */
1229 if (span->arrayMask & SPAN_XY) {
1230 /* array of pixel coords */
1231 if (monoColor) {
1232 /* all pixels have same color */
1233 GLchan color[4];
1234 color[RCOMP] = FixedToChan(span->red);
1235 color[GCOMP] = FixedToChan(span->green);
1236 color[BCOMP] = FixedToChan(span->blue);
1237 color[ACOMP] = FixedToChan(span->alpha);
1238 (*swrast->Driver.WriteMonoRGBAPixels)(ctx, span->end,
1239 span->array->x, span->array->y, color, span->array->mask);
1240 if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
1241 _swrast_write_mono_alpha_pixels(ctx, span->end,
1242 span->array->x, span->array->y,
1243 color[ACOMP], span->array->mask);
1244 }
1245 }
1246 else {
1247 (*swrast->Driver.WriteRGBAPixels)(ctx, span->end,
1248 span->array->x, span->array->y,
1249 (const GLchan (*)[4]) span->array->rgba,
1250 span->array->mask);
1251 if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
1252 _swrast_write_alpha_pixels(ctx, span->end,
1253 span->array->x, span->array->y,
1254 (const GLchan (*)[4]) span->array->rgba,
1255 span->array->mask);
1256 }
1257 }
1258 }
1259 else {
1260 /* horizontal run of pixels */
1261 if (monoColor) {
1262 /* all pixels have same color */
1263 GLchan color[4];
1264 color[RCOMP] = FixedToChan(span->red);
1265 color[GCOMP] = FixedToChan(span->green);
1266 color[BCOMP] = FixedToChan(span->blue);
1267 color[ACOMP] = FixedToChan(span->alpha);
1268 (*swrast->Driver.WriteMonoRGBASpan)(ctx, span->end, span->x,
1269 span->y, color, span->array->mask);
1270 if (swrast->_RasterMask & ALPHABUF_BIT) {
1271 _swrast_write_mono_alpha_span(ctx, span->end, span->x, span->y,
1272 color[ACOMP],
1273 span->writeAll ? ((const GLubyte *) NULL) : span->array->mask);
1274 }
1275 }
1276 else {
1277 /* each pixel is a different color */
1278 (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
1279 (const GLchan (*)[4]) span->array->rgba,
1280 span->writeAll ? ((const GLubyte *) NULL) : span->array->mask);
1281 if (swrast->_RasterMask & ALPHABUF_BIT) {
1282 _swrast_write_alpha_span(ctx, span->end, span->x, span->y,
1283 (const GLchan (*)[4]) span->array->rgba,
1284 span->writeAll ? ((const GLubyte *) NULL) : span->array->mask);
1285 }
1286 }
1287 }
1288 }
1289
1290 span->interpMask = origInterpMask;
1291 span->arrayMask = origArrayMask;
1292 }
1293
1294
1295 /**
1296 * Add specular color to base color. This is used only when
1297 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
1298 */
1299 static void
1300 add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] )
1301 {
1302 GLuint i;
1303 for (i = 0; i < n; i++) {
1304 #if CHAN_TYPE == GL_FLOAT
1305 /* no clamping */
1306 rgba[i][RCOMP] += specular[i][RCOMP];
1307 rgba[i][GCOMP] += specular[i][GCOMP];
1308 rgba[i][BCOMP] += specular[i][BCOMP];
1309 #else
1310 GLint r = rgba[i][RCOMP] + specular[i][RCOMP];
1311 GLint g = rgba[i][GCOMP] + specular[i][GCOMP];
1312 GLint b = rgba[i][BCOMP] + specular[i][BCOMP];
1313 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
1314 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
1315 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
1316 #endif
1317 }
1318 }
1319
1320
1321 /**
1322 * This function may modify any of the array values in the span.
1323 * span->interpMask and span->arrayMask may be changed but will be restored
1324 * to their original values before returning.
1325 */
1326 void
1327 _swrast_write_texture_span( GLcontext *ctx, struct sw_span *span)
1328 {
1329 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
1330 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1331 const GLuint origInterpMask = span->interpMask;
1332 const GLuint origArrayMask = span->arrayMask;
1333
1334 ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
1335 span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
1336 ASSERT(span->end <= MAX_WIDTH);
1337 ASSERT((span->interpMask & span->arrayMask) == 0);
1338 ASSERT(ctx->Texture._EnabledCoordUnits || ctx->FragmentProgram._Enabled);
1339
1340 /*
1341 printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__, span->interpMask, span->arrayMask);
1342 */
1343
1344 if (span->arrayMask & SPAN_MASK) {
1345 /* mask was initialized by caller, probably glBitmap */
1346 span->writeAll = GL_FALSE;
1347 }
1348 else {
1349 MEMSET(span->array->mask, 1, span->end);
1350 span->writeAll = GL_TRUE;
1351 }
1352
1353 /* Clipping */
1354 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
1355 if (!clip_span(ctx, span)) {
1356 return;
1357 }
1358 }
1359
1360 #ifdef DEBUG
1361 if (span->arrayMask & SPAN_XY) {
1362 GLuint i;
1363 for (i = 0; i < span->end; i++) {
1364 if (span->array->mask[i]) {
1365 assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
1366 assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
1367 assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
1368 assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
1369 }
1370 }
1371 }
1372 #endif
1373
1374 /* Polygon Stippling */
1375 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
1376 stipple_polygon_span(ctx, span);
1377 }
1378
1379 /* Need texture coordinates now */
1380 if ((span->interpMask & SPAN_TEXTURE)
1381 && (span->arrayMask & SPAN_TEXTURE) == 0)
1382 interpolate_texcoords(ctx, span);
1383
1384 /* Texture with alpha test */
1385 if (ctx->Color.AlphaEnabled) {
1386
1387 /* Now we need the rgba array, fill it in if needed */
1388 if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
1389 interpolate_colors(ctx, span);
1390
1391 if (span->interpMask & SPAN_SPEC) {
1392 interpolate_specular(ctx, span);
1393 }
1394
1395 /* Texturing without alpha is done after depth-testing which
1396 * gives a potential speed-up.
1397 */
1398 if (ctx->FragmentProgram._Enabled)
1399 _swrast_exec_fragment_program( ctx, span );
1400 else
1401 _swrast_texture_span( ctx, span );
1402
1403 /* Do the alpha test */
1404 if (!_swrast_alpha_test(ctx, span)) {
1405 span->arrayMask = origArrayMask;
1406 return;
1407 }
1408 }
1409
1410 /* Stencil and Z testing */
1411 if (ctx->Stencil.Enabled || ctx->Depth.Test) {
1412 if (span->interpMask & SPAN_Z)
1413 _swrast_span_interpolate_z(ctx, span);
1414
1415 if (ctx->Stencil.Enabled) {
1416 if (!_swrast_stencil_and_ztest_span(ctx, span)) {
1417 span->interpMask = origInterpMask;
1418 span->arrayMask = origArrayMask;
1419 return;
1420 }
1421 }
1422 else {
1423 ASSERT(ctx->Depth.Test);
1424 ASSERT(span->arrayMask & SPAN_Z);
1425 /* regular depth testing */
1426 if (!_swrast_depth_test_span(ctx, span)) {
1427 span->interpMask = origInterpMask;
1428 span->arrayMask = origArrayMask;
1429 return;
1430 }
1431 }
1432 }
1433
1434 /* if we get here, some fragments passed the depth test */
1435 if (ctx->Depth.OcclusionTest) {
1436 ctx->OcclusionResult = GL_TRUE;
1437 }
1438
1439 #if FEATURE_ARB_occlusion_query
1440 if (ctx->Occlusion.Active) {
1441 /* update count of 'passed' fragments */
1442 GLuint i;
1443 for (i = 0; i < span->end; i++)
1444 ctx->Occlusion.PassedCounter += span->array->mask[i];
1445 }
1446 #endif
1447
1448 /* We had to wait until now to check for glColorMask(F,F,F,F) because of
1449 * the occlusion test.
1450 */
1451 if (colorMask == 0x0) {
1452 span->interpMask = origInterpMask;
1453 span->arrayMask = origArrayMask;
1454 return;
1455 }
1456
1457 /* Texture without alpha test */
1458 if (!ctx->Color.AlphaEnabled) {
1459
1460 /* Now we need the rgba array, fill it in if needed */
1461 if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
1462 interpolate_colors(ctx, span);
1463
1464 if (span->interpMask & SPAN_SPEC) {
1465 interpolate_specular(ctx, span);
1466 }
1467
1468 if (ctx->FragmentProgram._Enabled)
1469 _swrast_exec_fragment_program( ctx, span );
1470 else
1471 _swrast_texture_span( ctx, span );
1472 }
1473
1474 ASSERT(span->arrayMask & SPAN_RGBA);
1475
1476 /* Add base and specular colors */
1477 if (ctx->Fog.ColorSumEnabled ||
1478 (ctx->Light.Enabled &&
1479 ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
1480 if (span->interpMask & SPAN_SPEC) {
1481 interpolate_specular(ctx, span);
1482 }
1483 ASSERT(span->arrayMask & SPAN_SPEC);
1484 add_colors( span->end, span->array->rgba, span->array->spec );
1485 }
1486
1487 /* Fog */
1488 if (swrast->_FogEnabled) {
1489 _swrast_fog_rgba_span(ctx, span);
1490 }
1491
1492 /* Antialias coverage application */
1493 if (span->arrayMask & SPAN_COVERAGE) {
1494 GLchan (*rgba)[4] = span->array->rgba;
1495 GLfloat *coverage = span->array->coverage;
1496 GLuint i;
1497 for (i = 0; i < span->end; i++) {
1498 rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]);
1499 }
1500 }
1501
1502 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
1503 multi_write_rgba_span(ctx, span);
1504 }
1505 else {
1506 /* normal: write to exactly one buffer */
1507 if (ctx->Color._LogicOpEnabled) {
1508 _swrast_logicop_rgba_span(ctx, span, span->array->rgba);
1509 }
1510 else if (ctx->Color.BlendEnabled) {
1511 _swrast_blend_span(ctx, span, span->array->rgba);
1512 }
1513
1514 /* Color component masking */
1515 if (colorMask != 0xffffffff) {
1516 _swrast_mask_rgba_span(ctx, span, span->array->rgba);
1517 }
1518
1519 /* write pixels */
1520 if (span->arrayMask & SPAN_XY) {
1521 /* array of pixel coords */
1522 (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->array->x,
1523 span->array->y, (const GLchan (*)[4]) span->array->rgba, span->array->mask);
1524 if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
1525 _swrast_write_alpha_pixels(ctx, span->end,
1526 span->array->x, span->array->y,
1527 (const GLchan (*)[4]) span->array->rgba,
1528 span->array->mask);
1529 }
1530 }
1531 else {
1532 /* horizontal run of pixels */
1533 (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
1534 (const GLchan (*)[4]) span->array->rgba,
1535 span->writeAll ? NULL : span->array->mask);
1536 if (swrast->_RasterMask & ALPHABUF_BIT) {
1537 _swrast_write_alpha_span(ctx, span->end, span->x, span->y,
1538 (const GLchan (*)[4]) span->array->rgba,
1539 span->writeAll ? NULL : span->array->mask);
1540 }
1541 }
1542 }
1543
1544 span->interpMask = origInterpMask;
1545 span->arrayMask = origArrayMask;
1546 }
1547
1548
1549
1550 /**
1551 * Read RGBA pixels from frame buffer. Clipping will be done to prevent
1552 * reading ouside the buffer's boundaries.
1553 */
1554 void
1555 _swrast_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
1556 GLuint n, GLint x, GLint y, GLchan rgba[][4] )
1557 {
1558 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1559 const GLint bufWidth = (GLint) buffer->Width;
1560 const GLint bufHeight = (GLint) buffer->Height;
1561
1562 if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1563 /* completely above, below, or right */
1564 /* XXX maybe leave undefined? */
1565 _mesa_bzero(rgba, 4 * n * sizeof(GLchan));
1566 }
1567 else {
1568 GLint skip, length;
1569 if (x < 0) {
1570 /* left edge clippping */
1571 skip = -x;
1572 length = (GLint) n - skip;
1573 if (length < 0) {
1574 /* completely left of window */
1575 return;
1576 }
1577 if (length > bufWidth) {
1578 length = bufWidth;
1579 }
1580 }
1581 else if ((GLint) (x + n) > bufWidth) {
1582 /* right edge clipping */
1583 skip = 0;
1584 length = bufWidth - x;
1585 if (length < 0) {
1586 /* completely to right of window */
1587 return;
1588 }
1589 }
1590 else {
1591 /* no clipping */
1592 skip = 0;
1593 length = (GLint) n;
1594 }
1595
1596 (*swrast->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip );
1597 if (buffer->UseSoftwareAlphaBuffers) {
1598 _swrast_read_alpha_span(ctx, length, x + skip, y, rgba + skip);
1599 }
1600 }
1601 }
1602
1603
1604 /**
1605 * Read CI pixels from frame buffer. Clipping will be done to prevent
1606 * reading ouside the buffer's boundaries.
1607 */
1608 void
1609 _swrast_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
1610 GLuint n, GLint x, GLint y, GLuint indx[] )
1611 {
1612 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1613 const GLint bufWidth = (GLint) buffer->Width;
1614 const GLint bufHeight = (GLint) buffer->Height;
1615
1616 if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1617 /* completely above, below, or right */
1618 _mesa_bzero(indx, n * sizeof(GLuint));
1619 }
1620 else {
1621 GLint skip, length;
1622 if (x < 0) {
1623 /* left edge clippping */
1624 skip = -x;
1625 length = (GLint) n - skip;
1626 if (length < 0) {
1627 /* completely left of window */
1628 return;
1629 }
1630 if (length > bufWidth) {
1631 length = bufWidth;
1632 }
1633 }
1634 else if ((GLint) (x + n) > bufWidth) {
1635 /* right edge clipping */
1636 skip = 0;
1637 length = bufWidth - x;
1638 if (length < 0) {
1639 /* completely to right of window */
1640 return;
1641 }
1642 }
1643 else {
1644 /* no clipping */
1645 skip = 0;
1646 length = (GLint) n;
1647 }
1648
1649 (*swrast->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip );
1650 }
1651 }