s_span.c revision a44d715d2b19dc2f8f48b01144cc38e4e2c5015a
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.5
4 *
5 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6 * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27/**
28 * \file swrast/s_span.c
29 * \brief Span processing functions used by all rasterization functions.
30 * This is where all the per-fragment tests are performed
31 * \author Brian Paul
32 */
33
34#include "main/glheader.h"
35#include "main/colormac.h"
36#include "main/macros.h"
37#include "main/imports.h"
38#include "main/image.h"
39
40#include "s_atifragshader.h"
41#include "s_alpha.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_fragprog.h"
49#include "s_span.h"
50#include "s_stencil.h"
51#include "s_texcombine.h"
52
53
54/**
55 * Set default fragment attributes for the span using the
56 * current raster values.  Used prior to glDraw/CopyPixels
57 * and glBitmap.
58 */
59void
60_swrast_span_default_attribs(struct gl_context *ctx, SWspan *span)
61{
62   GLchan r, g, b, a;
63   /* Z*/
64   {
65      const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
66      if (ctx->DrawBuffer->Visual.depthBits <= 16)
67         span->z = FloatToFixed(ctx->Current.RasterPos[2] * depthMax + 0.5F);
68      else {
69         GLfloat tmpf = ctx->Current.RasterPos[2] * depthMax;
70         tmpf = MIN2(tmpf, depthMax);
71         span->z = (GLint)tmpf;
72      }
73      span->zStep = 0;
74      span->interpMask |= SPAN_Z;
75   }
76
77   /* W (for perspective correction) */
78   span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0;
79   span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0;
80   span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0;
81
82   /* primary color, or color index */
83   UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
84   UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
85   UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
86   UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
87#if CHAN_TYPE == GL_FLOAT
88   span->red = r;
89   span->green = g;
90   span->blue = b;
91   span->alpha = a;
92#else
93   span->red   = IntToFixed(r);
94   span->green = IntToFixed(g);
95   span->blue  = IntToFixed(b);
96   span->alpha = IntToFixed(a);
97#endif
98   span->redStep = 0;
99   span->greenStep = 0;
100   span->blueStep = 0;
101   span->alphaStep = 0;
102   span->interpMask |= SPAN_RGBA;
103
104   COPY_4V(span->attrStart[FRAG_ATTRIB_COL0], ctx->Current.RasterColor);
105   ASSIGN_4V(span->attrStepX[FRAG_ATTRIB_COL0], 0.0, 0.0, 0.0, 0.0);
106   ASSIGN_4V(span->attrStepY[FRAG_ATTRIB_COL0], 0.0, 0.0, 0.0, 0.0);
107
108   /* Secondary color */
109   if (ctx->Light.Enabled || ctx->Fog.ColorSumEnabled)
110   {
111      COPY_4V(span->attrStart[FRAG_ATTRIB_COL1], ctx->Current.RasterSecondaryColor);
112      ASSIGN_4V(span->attrStepX[FRAG_ATTRIB_COL1], 0.0, 0.0, 0.0, 0.0);
113      ASSIGN_4V(span->attrStepY[FRAG_ATTRIB_COL1], 0.0, 0.0, 0.0, 0.0);
114   }
115
116   /* fog */
117   {
118      const SWcontext *swrast = SWRAST_CONTEXT(ctx);
119      GLfloat fogVal; /* a coord or a blend factor */
120      if (swrast->_PreferPixelFog) {
121         /* fog blend factors will be computed from fog coordinates per pixel */
122         fogVal = ctx->Current.RasterDistance;
123      }
124      else {
125         /* fog blend factor should be computed from fogcoord now */
126         fogVal = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
127      }
128      span->attrStart[FRAG_ATTRIB_FOGC][0] = fogVal;
129      span->attrStepX[FRAG_ATTRIB_FOGC][0] = 0.0;
130      span->attrStepY[FRAG_ATTRIB_FOGC][0] = 0.0;
131   }
132
133   /* texcoords */
134   {
135      GLuint i;
136      for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
137         const GLuint attr = FRAG_ATTRIB_TEX0 + i;
138         const GLfloat *tc = ctx->Current.RasterTexCoords[i];
139         if (ctx->FragmentProgram._Current || ctx->ATIFragmentShader._Enabled) {
140            COPY_4V(span->attrStart[attr], tc);
141         }
142         else if (tc[3] > 0.0F) {
143            /* use (s/q, t/q, r/q, 1) */
144            span->attrStart[attr][0] = tc[0] / tc[3];
145            span->attrStart[attr][1] = tc[1] / tc[3];
146            span->attrStart[attr][2] = tc[2] / tc[3];
147            span->attrStart[attr][3] = 1.0;
148         }
149         else {
150            ASSIGN_4V(span->attrStart[attr], 0.0F, 0.0F, 0.0F, 1.0F);
151         }
152         ASSIGN_4V(span->attrStepX[attr], 0.0F, 0.0F, 0.0F, 0.0F);
153         ASSIGN_4V(span->attrStepY[attr], 0.0F, 0.0F, 0.0F, 0.0F);
154      }
155   }
156}
157
158
159/**
160 * Interpolate the active attributes (and'd with attrMask) to
161 * fill in span->array->attribs[].
162 * Perspective correction will be done.  The point/line/triangle function
163 * should have computed attrStart/Step values for FRAG_ATTRIB_WPOS[3]!
164 */
165static inline void
166interpolate_active_attribs(struct gl_context *ctx, SWspan *span, GLbitfield attrMask)
167{
168   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
169
170   /*
171    * Don't overwrite existing array values, such as colors that may have
172    * been produced by glDraw/CopyPixels.
173    */
174   attrMask &= ~span->arrayAttribs;
175
176   ATTRIB_LOOP_BEGIN
177      if (attrMask & (1 << attr)) {
178         const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3];
179         GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3];
180         const GLfloat dv0dx = span->attrStepX[attr][0];
181         const GLfloat dv1dx = span->attrStepX[attr][1];
182         const GLfloat dv2dx = span->attrStepX[attr][2];
183         const GLfloat dv3dx = span->attrStepX[attr][3];
184         GLfloat v0 = span->attrStart[attr][0] + span->leftClip * dv0dx;
185         GLfloat v1 = span->attrStart[attr][1] + span->leftClip * dv1dx;
186         GLfloat v2 = span->attrStart[attr][2] + span->leftClip * dv2dx;
187         GLfloat v3 = span->attrStart[attr][3] + span->leftClip * dv3dx;
188         GLuint k;
189         for (k = 0; k < span->end; k++) {
190            const GLfloat invW = 1.0f / w;
191            span->array->attribs[attr][k][0] = v0 * invW;
192            span->array->attribs[attr][k][1] = v1 * invW;
193            span->array->attribs[attr][k][2] = v2 * invW;
194            span->array->attribs[attr][k][3] = v3 * invW;
195            v0 += dv0dx;
196            v1 += dv1dx;
197            v2 += dv2dx;
198            v3 += dv3dx;
199            w += dwdx;
200         }
201         ASSERT((span->arrayAttribs & (1 << attr)) == 0);
202         span->arrayAttribs |= (1 << attr);
203      }
204   ATTRIB_LOOP_END
205}
206
207
208/**
209 * Interpolate primary colors to fill in the span->array->rgba8 (or rgb16)
210 * color array.
211 */
212static inline void
213interpolate_int_colors(struct gl_context *ctx, SWspan *span)
214{
215#if CHAN_BITS != 32
216   const GLuint n = span->end;
217   GLuint i;
218
219   ASSERT(!(span->arrayMask & SPAN_RGBA));
220#endif
221
222   switch (span->array->ChanType) {
223#if CHAN_BITS != 32
224   case GL_UNSIGNED_BYTE:
225      {
226         GLubyte (*rgba)[4] = span->array->rgba8;
227         if (span->interpMask & SPAN_FLAT) {
228            GLubyte color[4];
229            color[RCOMP] = FixedToInt(span->red);
230            color[GCOMP] = FixedToInt(span->green);
231            color[BCOMP] = FixedToInt(span->blue);
232            color[ACOMP] = FixedToInt(span->alpha);
233            for (i = 0; i < n; i++) {
234               COPY_4UBV(rgba[i], color);
235            }
236         }
237         else {
238            GLfixed r = span->red;
239            GLfixed g = span->green;
240            GLfixed b = span->blue;
241            GLfixed a = span->alpha;
242            GLint dr = span->redStep;
243            GLint dg = span->greenStep;
244            GLint db = span->blueStep;
245            GLint da = span->alphaStep;
246            for (i = 0; i < n; i++) {
247               rgba[i][RCOMP] = FixedToChan(r);
248               rgba[i][GCOMP] = FixedToChan(g);
249               rgba[i][BCOMP] = FixedToChan(b);
250               rgba[i][ACOMP] = FixedToChan(a);
251               r += dr;
252               g += dg;
253               b += db;
254               a += da;
255            }
256         }
257      }
258      break;
259   case GL_UNSIGNED_SHORT:
260      {
261         GLushort (*rgba)[4] = span->array->rgba16;
262         if (span->interpMask & SPAN_FLAT) {
263            GLushort color[4];
264            color[RCOMP] = FixedToInt(span->red);
265            color[GCOMP] = FixedToInt(span->green);
266            color[BCOMP] = FixedToInt(span->blue);
267            color[ACOMP] = FixedToInt(span->alpha);
268            for (i = 0; i < n; i++) {
269               COPY_4V(rgba[i], color);
270            }
271         }
272         else {
273            GLushort (*rgba)[4] = span->array->rgba16;
274            GLfixed r, g, b, a;
275            GLint dr, dg, db, da;
276            r = span->red;
277            g = span->green;
278            b = span->blue;
279            a = span->alpha;
280            dr = span->redStep;
281            dg = span->greenStep;
282            db = span->blueStep;
283            da = span->alphaStep;
284            for (i = 0; i < n; i++) {
285               rgba[i][RCOMP] = FixedToChan(r);
286               rgba[i][GCOMP] = FixedToChan(g);
287               rgba[i][BCOMP] = FixedToChan(b);
288               rgba[i][ACOMP] = FixedToChan(a);
289               r += dr;
290               g += dg;
291               b += db;
292               a += da;
293            }
294         }
295      }
296      break;
297#endif
298   case GL_FLOAT:
299      interpolate_active_attribs(ctx, span, FRAG_BIT_COL0);
300      break;
301   default:
302      _mesa_problem(ctx, "bad datatype 0x%x in interpolate_int_colors",
303                    span->array->ChanType);
304   }
305   span->arrayMask |= SPAN_RGBA;
306}
307
308
309/**
310 * Populate the FRAG_ATTRIB_COL0 array.
311 */
312static inline void
313interpolate_float_colors(SWspan *span)
314{
315   GLfloat (*col0)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
316   const GLuint n = span->end;
317   GLuint i;
318
319   assert(!(span->arrayAttribs & FRAG_BIT_COL0));
320
321   if (span->arrayMask & SPAN_RGBA) {
322      /* convert array of int colors */
323      for (i = 0; i < n; i++) {
324         col0[i][0] = UBYTE_TO_FLOAT(span->array->rgba8[i][0]);
325         col0[i][1] = UBYTE_TO_FLOAT(span->array->rgba8[i][1]);
326         col0[i][2] = UBYTE_TO_FLOAT(span->array->rgba8[i][2]);
327         col0[i][3] = UBYTE_TO_FLOAT(span->array->rgba8[i][3]);
328      }
329   }
330   else {
331      /* interpolate red/green/blue/alpha to get float colors */
332      ASSERT(span->interpMask & SPAN_RGBA);
333      if (span->interpMask & SPAN_FLAT) {
334         GLfloat r = FixedToFloat(span->red);
335         GLfloat g = FixedToFloat(span->green);
336         GLfloat b = FixedToFloat(span->blue);
337         GLfloat a = FixedToFloat(span->alpha);
338         for (i = 0; i < n; i++) {
339            ASSIGN_4V(col0[i], r, g, b, a);
340         }
341      }
342      else {
343         GLfloat r = FixedToFloat(span->red);
344         GLfloat g = FixedToFloat(span->green);
345         GLfloat b = FixedToFloat(span->blue);
346         GLfloat a = FixedToFloat(span->alpha);
347         GLfloat dr = FixedToFloat(span->redStep);
348         GLfloat dg = FixedToFloat(span->greenStep);
349         GLfloat db = FixedToFloat(span->blueStep);
350         GLfloat da = FixedToFloat(span->alphaStep);
351         for (i = 0; i < n; i++) {
352            col0[i][0] = r;
353            col0[i][1] = g;
354            col0[i][2] = b;
355            col0[i][3] = a;
356            r += dr;
357            g += dg;
358            b += db;
359            a += da;
360         }
361      }
362   }
363
364   span->arrayAttribs |= FRAG_BIT_COL0;
365   span->array->ChanType = GL_FLOAT;
366}
367
368
369
370/**
371 * Fill in the span.zArray array from the span->z, zStep values.
372 */
373void
374_swrast_span_interpolate_z( const struct gl_context *ctx, SWspan *span )
375{
376   const GLuint n = span->end;
377   GLuint i;
378
379   ASSERT(!(span->arrayMask & SPAN_Z));
380
381   if (ctx->DrawBuffer->Visual.depthBits <= 16) {
382      GLfixed zval = span->z;
383      GLuint *z = span->array->z;
384      for (i = 0; i < n; i++) {
385         z[i] = FixedToInt(zval);
386         zval += span->zStep;
387      }
388   }
389   else {
390      /* Deep Z buffer, no fixed->int shift */
391      GLuint zval = span->z;
392      GLuint *z = span->array->z;
393      for (i = 0; i < n; i++) {
394         z[i] = zval;
395         zval += span->zStep;
396      }
397   }
398   span->interpMask &= ~SPAN_Z;
399   span->arrayMask |= SPAN_Z;
400}
401
402
403/**
404 * Compute mipmap LOD from partial derivatives.
405 * This the ideal solution, as given in the OpenGL spec.
406 */
407GLfloat
408_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
409                       GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
410                       GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
411{
412   GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
413   GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
414   GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
415   GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
416   GLfloat x = SQRTF(dudx * dudx + dvdx * dvdx);
417   GLfloat y = SQRTF(dudy * dudy + dvdy * dvdy);
418   GLfloat rho = MAX2(x, y);
419   GLfloat lambda = LOG2(rho);
420   return lambda;
421}
422
423
424/**
425 * Compute mipmap LOD from partial derivatives.
426 * This is a faster approximation than above function.
427 */
428#if 0
429GLfloat
430_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
431                     GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
432                     GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
433{
434   GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
435   GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
436   GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
437   GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
438   GLfloat maxU, maxV, rho, lambda;
439   dsdx2 = FABSF(dsdx2);
440   dsdy2 = FABSF(dsdy2);
441   dtdx2 = FABSF(dtdx2);
442   dtdy2 = FABSF(dtdy2);
443   maxU = MAX2(dsdx2, dsdy2) * texW;
444   maxV = MAX2(dtdx2, dtdy2) * texH;
445   rho = MAX2(maxU, maxV);
446   lambda = LOG2(rho);
447   return lambda;
448}
449#endif
450
451
452/**
453 * Fill in the span.array->attrib[FRAG_ATTRIB_TEXn] arrays from the
454 * using the attrStart/Step values.
455 *
456 * This function only used during fixed-function fragment processing.
457 *
458 * Note: in the places where we divide by Q (or mult by invQ) we're
459 * really doing two things: perspective correction and texcoord
460 * projection.  Remember, for texcoord (s,t,r,q) we need to index
461 * texels with (s/q, t/q, r/q).
462 */
463static void
464interpolate_texcoords(struct gl_context *ctx, SWspan *span)
465{
466   const GLuint maxUnit
467      = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
468   GLuint u;
469
470   /* XXX CoordUnits vs. ImageUnits */
471   for (u = 0; u < maxUnit; u++) {
472      if (ctx->Texture._EnabledCoordUnits & (1 << u)) {
473         const GLuint attr = FRAG_ATTRIB_TEX0 + u;
474         const struct gl_texture_object *obj = ctx->Texture.Unit[u]._Current;
475         GLfloat texW, texH;
476         GLboolean needLambda;
477         GLfloat (*texcoord)[4] = span->array->attribs[attr];
478         GLfloat *lambda = span->array->lambda[u];
479         const GLfloat dsdx = span->attrStepX[attr][0];
480         const GLfloat dsdy = span->attrStepY[attr][0];
481         const GLfloat dtdx = span->attrStepX[attr][1];
482         const GLfloat dtdy = span->attrStepY[attr][1];
483         const GLfloat drdx = span->attrStepX[attr][2];
484         const GLfloat dqdx = span->attrStepX[attr][3];
485         const GLfloat dqdy = span->attrStepY[attr][3];
486         GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
487         GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
488         GLfloat r = span->attrStart[attr][2] + span->leftClip * drdx;
489         GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
490
491         if (obj) {
492            const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
493            const struct swrast_texture_image *swImg =
494               swrast_texture_image_const(img);
495
496            needLambda = (obj->Sampler.MinFilter != obj->Sampler.MagFilter)
497               || ctx->FragmentProgram._Current;
498            /* LOD is calculated directly in the ansiotropic filter, we can
499             * skip the normal lambda function as the result is ignored.
500             */
501            if (obj->Sampler.MaxAnisotropy > 1.0 &&
502                obj->Sampler.MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
503               needLambda = GL_FALSE;
504            }
505            texW = swImg->WidthScale;
506            texH = swImg->HeightScale;
507         }
508         else {
509            /* using a fragment program */
510            texW = 1.0;
511            texH = 1.0;
512            needLambda = GL_FALSE;
513         }
514
515         if (needLambda) {
516            GLuint i;
517            if (ctx->FragmentProgram._Current
518                || ctx->ATIFragmentShader._Enabled) {
519               /* do perspective correction but don't divide s, t, r by q */
520               const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3];
521               GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dwdx;
522               for (i = 0; i < span->end; i++) {
523                  const GLfloat invW = 1.0F / w;
524                  texcoord[i][0] = s * invW;
525                  texcoord[i][1] = t * invW;
526                  texcoord[i][2] = r * invW;
527                  texcoord[i][3] = q * invW;
528                  lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
529                                                     dqdx, dqdy, texW, texH,
530                                                     s, t, q, invW);
531                  s += dsdx;
532                  t += dtdx;
533                  r += drdx;
534                  q += dqdx;
535                  w += dwdx;
536               }
537            }
538            else {
539               for (i = 0; i < span->end; i++) {
540                  const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
541                  texcoord[i][0] = s * invQ;
542                  texcoord[i][1] = t * invQ;
543                  texcoord[i][2] = r * invQ;
544                  texcoord[i][3] = q;
545                  lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
546                                                     dqdx, dqdy, texW, texH,
547                                                     s, t, q, invQ);
548                  s += dsdx;
549                  t += dtdx;
550                  r += drdx;
551                  q += dqdx;
552               }
553            }
554            span->arrayMask |= SPAN_LAMBDA;
555         }
556         else {
557            GLuint i;
558            if (ctx->FragmentProgram._Current ||
559                ctx->ATIFragmentShader._Enabled) {
560               /* do perspective correction but don't divide s, t, r by q */
561               const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3];
562               GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dwdx;
563               for (i = 0; i < span->end; i++) {
564                  const GLfloat invW = 1.0F / w;
565                  texcoord[i][0] = s * invW;
566                  texcoord[i][1] = t * invW;
567                  texcoord[i][2] = r * invW;
568                  texcoord[i][3] = q * invW;
569                  lambda[i] = 0.0;
570                  s += dsdx;
571                  t += dtdx;
572                  r += drdx;
573                  q += dqdx;
574                  w += dwdx;
575               }
576            }
577            else if (dqdx == 0.0F) {
578               /* Ortho projection or polygon's parallel to window X axis */
579               const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
580               for (i = 0; i < span->end; i++) {
581                  texcoord[i][0] = s * invQ;
582                  texcoord[i][1] = t * invQ;
583                  texcoord[i][2] = r * invQ;
584                  texcoord[i][3] = q;
585                  lambda[i] = 0.0;
586                  s += dsdx;
587                  t += dtdx;
588                  r += drdx;
589               }
590            }
591            else {
592               for (i = 0; i < span->end; i++) {
593                  const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
594                  texcoord[i][0] = s * invQ;
595                  texcoord[i][1] = t * invQ;
596                  texcoord[i][2] = r * invQ;
597                  texcoord[i][3] = q;
598                  lambda[i] = 0.0;
599                  s += dsdx;
600                  t += dtdx;
601                  r += drdx;
602                  q += dqdx;
603               }
604            }
605         } /* lambda */
606      } /* if */
607   } /* for */
608}
609
610
611/**
612 * Fill in the arrays->attribs[FRAG_ATTRIB_WPOS] array.
613 */
614static inline void
615interpolate_wpos(struct gl_context *ctx, SWspan *span)
616{
617   GLfloat (*wpos)[4] = span->array->attribs[FRAG_ATTRIB_WPOS];
618   GLuint i;
619   const GLfloat zScale = 1.0F / ctx->DrawBuffer->_DepthMaxF;
620   GLfloat w, dw;
621
622   if (span->arrayMask & SPAN_XY) {
623      for (i = 0; i < span->end; i++) {
624         wpos[i][0] = (GLfloat) span->array->x[i];
625         wpos[i][1] = (GLfloat) span->array->y[i];
626      }
627   }
628   else {
629      for (i = 0; i < span->end; i++) {
630         wpos[i][0] = (GLfloat) span->x + i;
631         wpos[i][1] = (GLfloat) span->y;
632      }
633   }
634
635   dw = span->attrStepX[FRAG_ATTRIB_WPOS][3];
636   w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dw;
637   for (i = 0; i < span->end; i++) {
638      wpos[i][2] = (GLfloat) span->array->z[i] * zScale;
639      wpos[i][3] = w;
640      w += dw;
641   }
642}
643
644
645/**
646 * Apply the current polygon stipple pattern to a span of pixels.
647 */
648static inline void
649stipple_polygon_span(struct gl_context *ctx, SWspan *span)
650{
651   GLubyte *mask = span->array->mask;
652
653   ASSERT(ctx->Polygon.StippleFlag);
654
655   if (span->arrayMask & SPAN_XY) {
656      /* arrays of x/y pixel coords */
657      GLuint i;
658      for (i = 0; i < span->end; i++) {
659         const GLint col = span->array->x[i] % 32;
660         const GLint row = span->array->y[i] % 32;
661         const GLuint stipple = ctx->PolygonStipple[row];
662         if (((1 << col) & stipple) == 0) {
663            mask[i] = 0;
664         }
665      }
666   }
667   else {
668      /* horizontal span of pixels */
669      const GLuint highBit = 1 << 31;
670      const GLuint stipple = ctx->PolygonStipple[span->y % 32];
671      GLuint i, m = highBit >> (GLuint) (span->x % 32);
672      for (i = 0; i < span->end; i++) {
673         if ((m & stipple) == 0) {
674            mask[i] = 0;
675         }
676         m = m >> 1;
677         if (m == 0) {
678            m = highBit;
679         }
680      }
681   }
682   span->writeAll = GL_FALSE;
683}
684
685
686/**
687 * Clip a pixel span to the current buffer/window boundaries:
688 * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax.  This will accomplish
689 * window clipping and scissoring.
690 * Return:   GL_TRUE   some pixels still visible
691 *           GL_FALSE  nothing visible
692 */
693static inline GLuint
694clip_span( struct gl_context *ctx, SWspan *span )
695{
696   const GLint xmin = ctx->DrawBuffer->_Xmin;
697   const GLint xmax = ctx->DrawBuffer->_Xmax;
698   const GLint ymin = ctx->DrawBuffer->_Ymin;
699   const GLint ymax = ctx->DrawBuffer->_Ymax;
700
701   span->leftClip = 0;
702
703   if (span->arrayMask & SPAN_XY) {
704      /* arrays of x/y pixel coords */
705      const GLint *x = span->array->x;
706      const GLint *y = span->array->y;
707      const GLint n = span->end;
708      GLubyte *mask = span->array->mask;
709      GLint i;
710      GLuint passed = 0;
711      if (span->arrayMask & SPAN_MASK) {
712         /* note: using & intead of && to reduce branches */
713         for (i = 0; i < n; i++) {
714            mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
715                     & (y[i] >= ymin) & (y[i] < ymax);
716            passed += mask[i];
717         }
718      }
719      else {
720         /* note: using & intead of && to reduce branches */
721         for (i = 0; i < n; i++) {
722            mask[i] = (x[i] >= xmin) & (x[i] < xmax)
723                    & (y[i] >= ymin) & (y[i] < ymax);
724            passed += mask[i];
725         }
726      }
727      return passed > 0;
728   }
729   else {
730      /* horizontal span of pixels */
731      const GLint x = span->x;
732      const GLint y = span->y;
733      GLint n = span->end;
734
735      /* Trivial rejection tests */
736      if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
737         span->end = 0;
738         return GL_FALSE;  /* all pixels clipped */
739      }
740
741      /* Clip to right */
742      if (x + n > xmax) {
743         ASSERT(x < xmax);
744         n = span->end = xmax - x;
745      }
746
747      /* Clip to the left */
748      if (x < xmin) {
749         const GLint leftClip = xmin - x;
750         GLuint i;
751
752         ASSERT(leftClip > 0);
753         ASSERT(x + n > xmin);
754
755         /* Clip 'leftClip' pixels from the left side.
756          * The span->leftClip field will be applied when we interpolate
757          * fragment attributes.
758          * For arrays of values, shift them left.
759          */
760         for (i = 0; i < FRAG_ATTRIB_MAX; i++) {
761            if (span->interpMask & (1 << i)) {
762               GLuint j;
763               for (j = 0; j < 4; j++) {
764                  span->attrStart[i][j] += leftClip * span->attrStepX[i][j];
765               }
766            }
767         }
768
769         span->red += leftClip * span->redStep;
770         span->green += leftClip * span->greenStep;
771         span->blue += leftClip * span->blueStep;
772         span->alpha += leftClip * span->alphaStep;
773         span->index += leftClip * span->indexStep;
774         span->z += leftClip * span->zStep;
775         span->intTex[0] += leftClip * span->intTexStep[0];
776         span->intTex[1] += leftClip * span->intTexStep[1];
777
778#define SHIFT_ARRAY(ARRAY, SHIFT, LEN) \
779         memmove(ARRAY, ARRAY + (SHIFT), (LEN) * sizeof(ARRAY[0]))
780
781         for (i = 0; i < FRAG_ATTRIB_MAX; i++) {
782            if (span->arrayAttribs & (1 << i)) {
783               /* shift array elements left by 'leftClip' */
784               SHIFT_ARRAY(span->array->attribs[i], leftClip, n - leftClip);
785            }
786         }
787
788         SHIFT_ARRAY(span->array->mask, leftClip, n - leftClip);
789         SHIFT_ARRAY(span->array->rgba8, leftClip, n - leftClip);
790         SHIFT_ARRAY(span->array->rgba16, leftClip, n - leftClip);
791         SHIFT_ARRAY(span->array->x, leftClip, n - leftClip);
792         SHIFT_ARRAY(span->array->y, leftClip, n - leftClip);
793         SHIFT_ARRAY(span->array->z, leftClip, n - leftClip);
794         SHIFT_ARRAY(span->array->index, leftClip, n - leftClip);
795         for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
796            SHIFT_ARRAY(span->array->lambda[i], leftClip, n - leftClip);
797         }
798         SHIFT_ARRAY(span->array->coverage, leftClip, n - leftClip);
799
800#undef SHIFT_ARRAY
801
802         span->leftClip = leftClip;
803         span->x = xmin;
804         span->end -= leftClip;
805         span->writeAll = GL_FALSE;
806      }
807
808      ASSERT(span->x >= xmin);
809      ASSERT(span->x + span->end <= xmax);
810      ASSERT(span->y >= ymin);
811      ASSERT(span->y < ymax);
812
813      return GL_TRUE;  /* some pixels visible */
814   }
815}
816
817
818/**
819 * Add specular colors to primary colors.
820 * Only called during fixed-function operation.
821 * Result is float color array (FRAG_ATTRIB_COL0).
822 */
823static inline void
824add_specular(struct gl_context *ctx, SWspan *span)
825{
826   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
827   const GLubyte *mask = span->array->mask;
828   GLfloat (*col0)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
829   GLfloat (*col1)[4] = span->array->attribs[FRAG_ATTRIB_COL1];
830   GLuint i;
831
832   ASSERT(!ctx->FragmentProgram._Current);
833   ASSERT(span->arrayMask & SPAN_RGBA);
834   ASSERT(swrast->_ActiveAttribMask & FRAG_BIT_COL1);
835   (void) swrast; /* silence warning */
836
837   if (span->array->ChanType == GL_FLOAT) {
838      if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
839         interpolate_active_attribs(ctx, span, FRAG_BIT_COL0);
840      }
841   }
842   else {
843      /* need float colors */
844      if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
845         interpolate_float_colors(span);
846      }
847   }
848
849   if ((span->arrayAttribs & FRAG_BIT_COL1) == 0) {
850      /* XXX could avoid this and interpolate COL1 in the loop below */
851      interpolate_active_attribs(ctx, span, FRAG_BIT_COL1);
852   }
853
854   ASSERT(span->arrayAttribs & FRAG_BIT_COL0);
855   ASSERT(span->arrayAttribs & FRAG_BIT_COL1);
856
857   for (i = 0; i < span->end; i++) {
858      if (mask[i]) {
859         col0[i][0] += col1[i][0];
860         col0[i][1] += col1[i][1];
861         col0[i][2] += col1[i][2];
862      }
863   }
864
865   span->array->ChanType = GL_FLOAT;
866}
867
868
869/**
870 * Apply antialiasing coverage value to alpha values.
871 */
872static inline void
873apply_aa_coverage(SWspan *span)
874{
875   const GLfloat *coverage = span->array->coverage;
876   GLuint i;
877   if (span->array->ChanType == GL_UNSIGNED_BYTE) {
878      GLubyte (*rgba)[4] = span->array->rgba8;
879      for (i = 0; i < span->end; i++) {
880         const GLfloat a = rgba[i][ACOMP] * coverage[i];
881         rgba[i][ACOMP] = (GLubyte) CLAMP(a, 0.0, 255.0);
882         ASSERT(coverage[i] >= 0.0);
883         ASSERT(coverage[i] <= 1.0);
884      }
885   }
886   else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
887      GLushort (*rgba)[4] = span->array->rgba16;
888      for (i = 0; i < span->end; i++) {
889         const GLfloat a = rgba[i][ACOMP] * coverage[i];
890         rgba[i][ACOMP] = (GLushort) CLAMP(a, 0.0, 65535.0);
891      }
892   }
893   else {
894      GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
895      for (i = 0; i < span->end; i++) {
896         rgba[i][ACOMP] = rgba[i][ACOMP] * coverage[i];
897         /* clamp later */
898      }
899   }
900}
901
902
903/**
904 * Clamp span's float colors to [0,1]
905 */
906static inline void
907clamp_colors(SWspan *span)
908{
909   GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
910   GLuint i;
911   ASSERT(span->array->ChanType == GL_FLOAT);
912   for (i = 0; i < span->end; i++) {
913      rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F);
914      rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F);
915      rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F);
916      rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F);
917   }
918}
919
920
921/**
922 * Convert the span's color arrays to the given type.
923 * The only way 'output' can be greater than zero is when we have a fragment
924 * program that writes to gl_FragData[1] or higher.
925 * \param output  which fragment program color output is being processed
926 */
927static inline void
928convert_color_type(SWspan *span, GLenum newType, GLuint output)
929{
930   GLvoid *src, *dst;
931
932   if (output > 0 || span->array->ChanType == GL_FLOAT) {
933      src = span->array->attribs[FRAG_ATTRIB_COL0 + output];
934      span->array->ChanType = GL_FLOAT;
935   }
936   else if (span->array->ChanType == GL_UNSIGNED_BYTE) {
937      src = span->array->rgba8;
938   }
939   else {
940      ASSERT(span->array->ChanType == GL_UNSIGNED_SHORT);
941      src = span->array->rgba16;
942   }
943
944   if (newType == GL_UNSIGNED_BYTE) {
945      dst = span->array->rgba8;
946   }
947   else if (newType == GL_UNSIGNED_SHORT) {
948      dst = span->array->rgba16;
949   }
950   else {
951      dst = span->array->attribs[FRAG_ATTRIB_COL0];
952   }
953
954   _mesa_convert_colors(span->array->ChanType, src,
955                        newType, dst,
956                        span->end, span->array->mask);
957
958   span->array->ChanType = newType;
959   span->array->rgba = dst;
960}
961
962
963
964/**
965 * Apply fragment shader, fragment program or normal texturing to span.
966 */
967static inline void
968shade_texture_span(struct gl_context *ctx, SWspan *span)
969{
970   if (ctx->FragmentProgram._Current ||
971       ctx->ATIFragmentShader._Enabled) {
972      /* programmable shading */
973      if (span->primitive == GL_BITMAP && span->array->ChanType != GL_FLOAT) {
974         convert_color_type(span, GL_FLOAT, 0);
975      }
976      else {
977         span->array->rgba = (void *) span->array->attribs[FRAG_ATTRIB_COL0];
978      }
979
980      if (span->primitive != GL_POINT ||
981	  (span->interpMask & SPAN_RGBA) ||
982	  ctx->Point.PointSprite) {
983         /* for single-pixel points, we populated the arrays already */
984         interpolate_active_attribs(ctx, span, ~0);
985      }
986      span->array->ChanType = GL_FLOAT;
987
988      if (!(span->arrayMask & SPAN_Z))
989         _swrast_span_interpolate_z (ctx, span);
990
991#if 0
992      if (inputsRead & FRAG_BIT_WPOS)
993#else
994      /* XXX always interpolate wpos so that DDX/DDY work */
995#endif
996         interpolate_wpos(ctx, span);
997
998      /* Run fragment program/shader now */
999      if (ctx->FragmentProgram._Current) {
1000         _swrast_exec_fragment_program(ctx, span);
1001      }
1002      else {
1003         ASSERT(ctx->ATIFragmentShader._Enabled);
1004         _swrast_exec_fragment_shader(ctx, span);
1005      }
1006   }
1007   else if (ctx->Texture._EnabledCoordUnits) {
1008      /* conventional texturing */
1009
1010#if CHAN_BITS == 32
1011      if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
1012         interpolate_int_colors(ctx, span);
1013      }
1014#else
1015      if (!(span->arrayMask & SPAN_RGBA))
1016         interpolate_int_colors(ctx, span);
1017#endif
1018      if ((span->arrayAttribs & FRAG_BITS_TEX_ANY) == 0x0)
1019         interpolate_texcoords(ctx, span);
1020
1021      _swrast_texture_span(ctx, span);
1022   }
1023}
1024
1025
1026
1027/**
1028 * Apply all the per-fragment operations to a span.
1029 * This now includes texturing (_swrast_write_texture_span() is history).
1030 * This function may modify any of the array values in the span.
1031 * span->interpMask and span->arrayMask may be changed but will be restored
1032 * to their original values before returning.
1033 */
1034void
1035_swrast_write_rgba_span( struct gl_context *ctx, SWspan *span)
1036{
1037   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
1038   const GLuint *colorMask = (GLuint *) ctx->Color.ColorMask;
1039   const GLbitfield origInterpMask = span->interpMask;
1040   const GLbitfield origArrayMask = span->arrayMask;
1041   const GLbitfield origArrayAttribs = span->arrayAttribs;
1042   const GLenum origChanType = span->array->ChanType;
1043   void * const origRgba = span->array->rgba;
1044   const GLboolean shader = (ctx->FragmentProgram._Current
1045                             || ctx->ATIFragmentShader._Enabled);
1046   const GLboolean shaderOrTexture = shader || ctx->Texture._EnabledCoordUnits;
1047   struct gl_framebuffer *fb = ctx->DrawBuffer;
1048
1049   /*
1050   printf("%s()  interp 0x%x  array 0x%x\n", __FUNCTION__,
1051          span->interpMask, span->arrayMask);
1052   */
1053
1054   ASSERT(span->primitive == GL_POINT ||
1055          span->primitive == GL_LINE ||
1056	  span->primitive == GL_POLYGON ||
1057          span->primitive == GL_BITMAP);
1058
1059   /* Fragment write masks */
1060   if (span->arrayMask & SPAN_MASK) {
1061      /* mask was initialized by caller, probably glBitmap */
1062      span->writeAll = GL_FALSE;
1063   }
1064   else {
1065      memset(span->array->mask, 1, span->end);
1066      span->writeAll = GL_TRUE;
1067   }
1068
1069   /* Clip to window/scissor box */
1070   if (!clip_span(ctx, span)) {
1071      return;
1072   }
1073
1074   ASSERT(span->end <= MAX_WIDTH);
1075
1076   /* Depth bounds test */
1077   if (ctx->Depth.BoundsTest && fb->Visual.depthBits > 0) {
1078      if (!_swrast_depth_bounds_test(ctx, span)) {
1079         return;
1080      }
1081   }
1082
1083#ifdef DEBUG
1084   /* Make sure all fragments are within window bounds */
1085   if (span->arrayMask & SPAN_XY) {
1086      /* array of pixel locations */
1087      GLuint i;
1088      for (i = 0; i < span->end; i++) {
1089         if (span->array->mask[i]) {
1090            assert(span->array->x[i] >= fb->_Xmin);
1091            assert(span->array->x[i] < fb->_Xmax);
1092            assert(span->array->y[i] >= fb->_Ymin);
1093            assert(span->array->y[i] < fb->_Ymax);
1094         }
1095      }
1096   }
1097#endif
1098
1099   /* Polygon Stippling */
1100   if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
1101      stipple_polygon_span(ctx, span);
1102   }
1103
1104   /* This is the normal place to compute the fragment color/Z
1105    * from texturing or shading.
1106    */
1107   if (shaderOrTexture && !swrast->_DeferredTexture) {
1108      shade_texture_span(ctx, span);
1109   }
1110
1111   /* Do the alpha test */
1112   if (ctx->Color.AlphaEnabled) {
1113      if (!_swrast_alpha_test(ctx, span)) {
1114         /* all fragments failed test */
1115         goto end;
1116      }
1117   }
1118
1119   /* Stencil and Z testing */
1120   if (ctx->Stencil._Enabled || ctx->Depth.Test) {
1121      if (!(span->arrayMask & SPAN_Z))
1122         _swrast_span_interpolate_z(ctx, span);
1123
1124      if (ctx->Transform.DepthClamp)
1125	 _swrast_depth_clamp_span(ctx, span);
1126
1127      if (ctx->Stencil._Enabled) {
1128         /* Combined Z/stencil tests */
1129         if (!_swrast_stencil_and_ztest_span(ctx, span)) {
1130            /* all fragments failed test */
1131            goto end;
1132         }
1133      }
1134      else if (fb->Visual.depthBits > 0) {
1135         /* Just regular depth testing */
1136         ASSERT(ctx->Depth.Test);
1137         ASSERT(span->arrayMask & SPAN_Z);
1138         if (!_swrast_depth_test_span(ctx, span)) {
1139            /* all fragments failed test */
1140            goto end;
1141         }
1142      }
1143   }
1144
1145   if (ctx->Query.CurrentOcclusionObject) {
1146      /* update count of 'passed' fragments */
1147      struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;
1148      GLuint i;
1149      for (i = 0; i < span->end; i++)
1150         q->Result += span->array->mask[i];
1151   }
1152
1153   /* We had to wait until now to check for glColorMask(0,0,0,0) because of
1154    * the occlusion test.
1155    */
1156   if (fb->_NumColorDrawBuffers == 1 && colorMask[0] == 0x0) {
1157      /* no colors to write */
1158      goto end;
1159   }
1160
1161   /* If we were able to defer fragment color computation to now, there's
1162    * a good chance that many fragments will have already been killed by
1163    * Z/stencil testing.
1164    */
1165   if (shaderOrTexture && swrast->_DeferredTexture) {
1166      shade_texture_span(ctx, span);
1167   }
1168
1169#if CHAN_BITS == 32
1170   if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
1171      interpolate_active_attribs(ctx, span, FRAG_BIT_COL0);
1172   }
1173#else
1174   if ((span->arrayMask & SPAN_RGBA) == 0) {
1175      interpolate_int_colors(ctx, span);
1176   }
1177#endif
1178
1179   ASSERT(span->arrayMask & SPAN_RGBA);
1180
1181   if (span->primitive == GL_BITMAP || !swrast->SpecularVertexAdd) {
1182      /* Add primary and specular (diffuse + specular) colors */
1183      if (!shader) {
1184         if (ctx->Fog.ColorSumEnabled ||
1185             (ctx->Light.Enabled &&
1186              ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
1187            add_specular(ctx, span);
1188         }
1189      }
1190   }
1191
1192   /* Fog */
1193   if (swrast->_FogEnabled) {
1194      _swrast_fog_rgba_span(ctx, span);
1195   }
1196
1197   /* Antialias coverage application */
1198   if (span->arrayMask & SPAN_COVERAGE) {
1199      apply_aa_coverage(span);
1200   }
1201
1202   /* Clamp color/alpha values over the range [0.0, 1.0] before storage */
1203   if (ctx->Color.ClampFragmentColor == GL_TRUE &&
1204       span->array->ChanType == GL_FLOAT) {
1205      clamp_colors(span);
1206   }
1207
1208   /*
1209    * Write to renderbuffers.
1210    * Depending on glDrawBuffer() state and the which color outputs are
1211    * written by the fragment shader, we may either replicate one color to
1212    * all renderbuffers or write a different color to each renderbuffer.
1213    * multiFragOutputs=TRUE for the later case.
1214    */
1215   {
1216      const GLuint numBuffers = fb->_NumColorDrawBuffers;
1217      const struct gl_fragment_program *fp = ctx->FragmentProgram._Current;
1218      const GLboolean multiFragOutputs =
1219         (fp && fp->Base.OutputsWritten >= (1 << FRAG_RESULT_DATA0));
1220      GLuint buf;
1221
1222      for (buf = 0; buf < numBuffers; buf++) {
1223         struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf];
1224
1225         /* color[fragOutput] will be written to buffer[buf] */
1226
1227         if (rb) {
1228            GLchan rgbaSave[MAX_WIDTH][4];
1229            const GLuint fragOutput = multiFragOutputs ? buf : 0;
1230
1231            /* set span->array->rgba to colors for render buffer's datatype */
1232            if (rb->DataType != span->array->ChanType || fragOutput > 0) {
1233               convert_color_type(span, rb->DataType, fragOutput);
1234            }
1235            else {
1236               if (rb->DataType == GL_UNSIGNED_BYTE) {
1237                  span->array->rgba = span->array->rgba8;
1238               }
1239               else if (rb->DataType == GL_UNSIGNED_SHORT) {
1240                  span->array->rgba = (void *) span->array->rgba16;
1241               }
1242               else {
1243                  span->array->rgba = (void *)
1244                     span->array->attribs[FRAG_ATTRIB_COL0];
1245               }
1246            }
1247
1248            if (!multiFragOutputs && numBuffers > 1) {
1249               /* save colors for second, third renderbuffer writes */
1250               memcpy(rgbaSave, span->array->rgba,
1251                      4 * span->end * sizeof(GLchan));
1252            }
1253
1254            ASSERT(rb->_BaseFormat == GL_RGBA ||
1255                   rb->_BaseFormat == GL_RGB ||
1256                   rb->_BaseFormat == GL_RED ||
1257                   rb->_BaseFormat == GL_RG ||
1258		   rb->_BaseFormat == GL_ALPHA);
1259
1260            if (ctx->Color.ColorLogicOpEnabled) {
1261               _swrast_logicop_rgba_span(ctx, rb, span);
1262            }
1263            else if ((ctx->Color.BlendEnabled >> buf) & 1) {
1264               _swrast_blend_span(ctx, rb, span);
1265            }
1266
1267            if (colorMask[buf] != 0xffffffff) {
1268               _swrast_mask_rgba_span(ctx, rb, span, buf);
1269            }
1270
1271            if (span->arrayMask & SPAN_XY) {
1272               /* array of pixel coords */
1273               ASSERT(rb->PutValues);
1274               rb->PutValues(ctx, rb, span->end,
1275                             span->array->x, span->array->y,
1276                             span->array->rgba, span->array->mask);
1277            }
1278            else {
1279               /* horizontal run of pixels */
1280               ASSERT(rb->PutRow);
1281               rb->PutRow(ctx, rb, span->end, span->x, span->y,
1282                          span->array->rgba,
1283                          span->writeAll ? NULL: span->array->mask);
1284            }
1285
1286            if (!multiFragOutputs && numBuffers > 1) {
1287               /* restore original span values */
1288               memcpy(span->array->rgba, rgbaSave,
1289                      4 * span->end * sizeof(GLchan));
1290            }
1291
1292         } /* if rb */
1293      } /* for buf */
1294   }
1295
1296end:
1297   /* restore these values before returning */
1298   span->interpMask = origInterpMask;
1299   span->arrayMask = origArrayMask;
1300   span->arrayAttribs = origArrayAttribs;
1301   span->array->ChanType = origChanType;
1302   span->array->rgba = origRgba;
1303}
1304
1305
1306/**
1307 * Read RGBA pixels from a renderbuffer.  Clipping will be done to prevent
1308 * reading ouside the buffer's boundaries.
1309 * \param dstType  datatype for returned colors
1310 * \param rgba  the returned colors
1311 */
1312void
1313_swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb,
1314                        GLuint n, GLint x, GLint y, GLenum dstType,
1315                        GLvoid *rgba)
1316{
1317   const GLint bufWidth = (GLint) rb->Width;
1318   const GLint bufHeight = (GLint) rb->Height;
1319
1320   if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1321      /* completely above, below, or right */
1322      /* XXX maybe leave rgba values undefined? */
1323      memset(rgba, 0, 4 * n * sizeof(GLchan));
1324   }
1325   else {
1326      GLint skip, length;
1327      if (x < 0) {
1328         /* left edge clipping */
1329         skip = -x;
1330         length = (GLint) n - skip;
1331         if (length < 0) {
1332            /* completely left of window */
1333            return;
1334         }
1335         if (length > bufWidth) {
1336            length = bufWidth;
1337         }
1338      }
1339      else if ((GLint) (x + n) > bufWidth) {
1340         /* right edge clipping */
1341         skip = 0;
1342         length = bufWidth - x;
1343         if (length < 0) {
1344            /* completely to right of window */
1345            return;
1346         }
1347      }
1348      else {
1349         /* no clipping */
1350         skip = 0;
1351         length = (GLint) n;
1352      }
1353
1354      ASSERT(rb);
1355      ASSERT(rb->GetRow);
1356      ASSERT(rb->_BaseFormat == GL_RGBA ||
1357	     rb->_BaseFormat == GL_RGB ||
1358	     rb->_BaseFormat == GL_RG ||
1359	     rb->_BaseFormat == GL_RED ||
1360	     rb->_BaseFormat == GL_LUMINANCE ||
1361	     rb->_BaseFormat == GL_INTENSITY ||
1362	     rb->_BaseFormat == GL_LUMINANCE_ALPHA ||
1363	     rb->_BaseFormat == GL_ALPHA);
1364
1365      if (rb->DataType == dstType) {
1366         rb->GetRow(ctx, rb, length, x + skip, y,
1367                    (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(rb->DataType));
1368      }
1369      else {
1370         GLuint temp[MAX_WIDTH * 4];
1371         rb->GetRow(ctx, rb, length, x + skip, y, temp);
1372         _mesa_convert_colors(rb->DataType, temp,
1373                   dstType, (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(dstType),
1374                   length, NULL);
1375      }
1376   }
1377}
1378
1379
1380/**
1381 * Wrapper for gl_renderbuffer::GetValues() which does clipping to avoid
1382 * reading values outside the buffer bounds.
1383 * We can use this for reading any format/type of renderbuffer.
1384 * \param valueSize is the size in bytes of each value (pixel) put into the
1385 *                  values array.
1386 */
1387void
1388_swrast_get_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
1389                   GLuint count, const GLint x[], const GLint y[],
1390                   void *values, GLuint valueSize)
1391{
1392   GLuint i, inCount = 0, inStart = 0;
1393
1394   for (i = 0; i < count; i++) {
1395      if (x[i] >= 0 && y[i] >= 0 &&
1396	  x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) {
1397         /* inside */
1398         if (inCount == 0)
1399            inStart = i;
1400         inCount++;
1401      }
1402      else {
1403         if (inCount > 0) {
1404            /* read [inStart, inStart + inCount) */
1405            rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart,
1406                          (GLubyte *) values + inStart * valueSize);
1407            inCount = 0;
1408         }
1409      }
1410   }
1411   if (inCount > 0) {
1412      /* read last values */
1413      rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart,
1414                    (GLubyte *) values + inStart * valueSize);
1415   }
1416}
1417
1418
1419/**
1420 * Wrapper for gl_renderbuffer::PutRow() which does clipping.
1421 * \param valueSize  size of each value (pixel) in bytes
1422 */
1423void
1424_swrast_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
1425                GLuint count, GLint x, GLint y,
1426                const GLvoid *values, GLuint valueSize)
1427{
1428   GLint skip = 0;
1429
1430   if (y < 0 || y >= (GLint) rb->Height)
1431      return; /* above or below */
1432
1433   if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
1434      return; /* entirely left or right */
1435
1436   if ((GLint) (x + count) > (GLint) rb->Width) {
1437      /* right clip */
1438      GLint clip = x + count - rb->Width;
1439      count -= clip;
1440   }
1441
1442   if (x < 0) {
1443      /* left clip */
1444      skip = -x;
1445      x = 0;
1446      count -= skip;
1447   }
1448
1449   rb->PutRow(ctx, rb, count, x, y,
1450              (const GLubyte *) values + skip * valueSize, NULL);
1451}
1452
1453
1454/**
1455 * Wrapper for gl_renderbuffer::GetRow() which does clipping.
1456 * \param valueSize  size of each value (pixel) in bytes
1457 */
1458void
1459_swrast_get_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
1460                GLuint count, GLint x, GLint y,
1461                GLvoid *values, GLuint valueSize)
1462{
1463   GLint skip = 0;
1464
1465   if (y < 0 || y >= (GLint) rb->Height)
1466      return; /* above or below */
1467
1468   if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
1469      return; /* entirely left or right */
1470
1471   if (x + count > rb->Width) {
1472      /* right clip */
1473      GLint clip = x + count - rb->Width;
1474      count -= clip;
1475   }
1476
1477   if (x < 0) {
1478      /* left clip */
1479      skip = -x;
1480      x = 0;
1481      count -= skip;
1482   }
1483
1484   rb->GetRow(ctx, rb, count, x, y, (GLubyte *) values + skip * valueSize);
1485}
1486
1487
1488/**
1489 * Get RGBA pixels from the given renderbuffer.
1490 * Used by blending, logicop and masking functions.
1491 * \return pointer to the colors we read.
1492 */
1493void *
1494_swrast_get_dest_rgba(struct gl_context *ctx, struct gl_renderbuffer *rb,
1495                      SWspan *span)
1496{
1497   const GLuint pixelSize = RGBA_PIXEL_SIZE(span->array->ChanType);
1498   void *rbPixels;
1499
1500   /* Point rbPixels to a temporary space */
1501   rbPixels = span->array->attribs[FRAG_ATTRIB_MAX - 1];
1502
1503   /* Get destination values from renderbuffer */
1504   if (span->arrayMask & SPAN_XY) {
1505      _swrast_get_values(ctx, rb, span->end, span->array->x, span->array->y,
1506                         rbPixels, pixelSize);
1507   }
1508   else {
1509      _swrast_get_row(ctx, rb, span->end, span->x, span->y,
1510                      rbPixels, pixelSize);
1511   }
1512
1513   return rbPixels;
1514}
1515