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