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