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