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