1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6848b8605Smrg *
7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
8848b8605Smrg * copy of this software and associated documentation files (the "Software"),
9848b8605Smrg * to deal in the Software without restriction, including without limitation
10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
12848b8605Smrg * Software is furnished to do so, subject to the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice shall be included
15848b8605Smrg * in all copies or substantial portions of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
24848b8605Smrg */
25848b8605Smrg
26848b8605Smrg
27848b8605Smrg/**
28848b8605Smrg * \file swrast/s_span.c
29848b8605Smrg * \brief Span processing functions used by all rasterization functions.
30848b8605Smrg * This is where all the per-fragment tests are performed
31848b8605Smrg * \author Brian Paul
32848b8605Smrg */
33848b8605Smrg
34b8e80941Smrg#include "c99_math.h"
35b8e80941Smrg#include "main/errors.h"
36848b8605Smrg#include "main/glheader.h"
37848b8605Smrg#include "main/format_pack.h"
38848b8605Smrg#include "main/format_unpack.h"
39848b8605Smrg#include "main/macros.h"
40848b8605Smrg#include "main/imports.h"
41848b8605Smrg#include "main/image.h"
42848b8605Smrg#include "main/samplerobj.h"
43b8e80941Smrg#include "main/state.h"
44b8e80941Smrg#include "main/stencil.h"
45b8e80941Smrg#include "main/teximage.h"
46848b8605Smrg
47848b8605Smrg#include "s_atifragshader.h"
48848b8605Smrg#include "s_alpha.h"
49848b8605Smrg#include "s_blend.h"
50848b8605Smrg#include "s_context.h"
51848b8605Smrg#include "s_depth.h"
52848b8605Smrg#include "s_fog.h"
53848b8605Smrg#include "s_logic.h"
54848b8605Smrg#include "s_masking.h"
55848b8605Smrg#include "s_fragprog.h"
56848b8605Smrg#include "s_span.h"
57848b8605Smrg#include "s_stencil.h"
58848b8605Smrg#include "s_texcombine.h"
59848b8605Smrg
60848b8605Smrg#include <stdbool.h>
61848b8605Smrg
62848b8605Smrg/**
63848b8605Smrg * Set default fragment attributes for the span using the
64848b8605Smrg * current raster values.  Used prior to glDraw/CopyPixels
65848b8605Smrg * and glBitmap.
66848b8605Smrg */
67848b8605Smrgvoid
68848b8605Smrg_swrast_span_default_attribs(struct gl_context *ctx, SWspan *span)
69848b8605Smrg{
70848b8605Smrg   GLchan r, g, b, a;
71848b8605Smrg   /* Z*/
72848b8605Smrg   {
73848b8605Smrg      const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
74848b8605Smrg      if (ctx->DrawBuffer->Visual.depthBits <= 16)
75848b8605Smrg         span->z = FloatToFixed(ctx->Current.RasterPos[2] * depthMax + 0.5F);
76848b8605Smrg      else {
77848b8605Smrg         GLfloat tmpf = ctx->Current.RasterPos[2] * depthMax;
78848b8605Smrg         tmpf = MIN2(tmpf, depthMax);
79848b8605Smrg         span->z = (GLint)tmpf;
80848b8605Smrg      }
81848b8605Smrg      span->zStep = 0;
82848b8605Smrg      span->interpMask |= SPAN_Z;
83848b8605Smrg   }
84848b8605Smrg
85848b8605Smrg   /* W (for perspective correction) */
86848b8605Smrg   span->attrStart[VARYING_SLOT_POS][3] = 1.0;
87848b8605Smrg   span->attrStepX[VARYING_SLOT_POS][3] = 0.0;
88848b8605Smrg   span->attrStepY[VARYING_SLOT_POS][3] = 0.0;
89848b8605Smrg
90848b8605Smrg   /* primary color, or color index */
91848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
92848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
93848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
94848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
95848b8605Smrg#if CHAN_TYPE == GL_FLOAT
96848b8605Smrg   span->red = r;
97848b8605Smrg   span->green = g;
98848b8605Smrg   span->blue = b;
99848b8605Smrg   span->alpha = a;
100848b8605Smrg#else
101848b8605Smrg   span->red   = IntToFixed(r);
102848b8605Smrg   span->green = IntToFixed(g);
103848b8605Smrg   span->blue  = IntToFixed(b);
104848b8605Smrg   span->alpha = IntToFixed(a);
105848b8605Smrg#endif
106848b8605Smrg   span->redStep = 0;
107848b8605Smrg   span->greenStep = 0;
108848b8605Smrg   span->blueStep = 0;
109848b8605Smrg   span->alphaStep = 0;
110848b8605Smrg   span->interpMask |= SPAN_RGBA;
111848b8605Smrg
112848b8605Smrg   COPY_4V(span->attrStart[VARYING_SLOT_COL0], ctx->Current.RasterColor);
113848b8605Smrg   ASSIGN_4V(span->attrStepX[VARYING_SLOT_COL0], 0.0, 0.0, 0.0, 0.0);
114848b8605Smrg   ASSIGN_4V(span->attrStepY[VARYING_SLOT_COL0], 0.0, 0.0, 0.0, 0.0);
115848b8605Smrg
116848b8605Smrg   /* Secondary color */
117848b8605Smrg   if (ctx->Light.Enabled || ctx->Fog.ColorSumEnabled)
118848b8605Smrg   {
119848b8605Smrg      COPY_4V(span->attrStart[VARYING_SLOT_COL1], ctx->Current.RasterSecondaryColor);
120848b8605Smrg      ASSIGN_4V(span->attrStepX[VARYING_SLOT_COL1], 0.0, 0.0, 0.0, 0.0);
121848b8605Smrg      ASSIGN_4V(span->attrStepY[VARYING_SLOT_COL1], 0.0, 0.0, 0.0, 0.0);
122848b8605Smrg   }
123848b8605Smrg
124848b8605Smrg   /* fog */
125848b8605Smrg   {
126848b8605Smrg      const SWcontext *swrast = SWRAST_CONTEXT(ctx);
127848b8605Smrg      GLfloat fogVal; /* a coord or a blend factor */
128848b8605Smrg      if (swrast->_PreferPixelFog) {
129848b8605Smrg         /* fog blend factors will be computed from fog coordinates per pixel */
130848b8605Smrg         fogVal = ctx->Current.RasterDistance;
131848b8605Smrg      }
132848b8605Smrg      else {
133848b8605Smrg         /* fog blend factor should be computed from fogcoord now */
134848b8605Smrg         fogVal = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
135848b8605Smrg      }
136848b8605Smrg      span->attrStart[VARYING_SLOT_FOGC][0] = fogVal;
137848b8605Smrg      span->attrStepX[VARYING_SLOT_FOGC][0] = 0.0;
138848b8605Smrg      span->attrStepY[VARYING_SLOT_FOGC][0] = 0.0;
139848b8605Smrg   }
140848b8605Smrg
141848b8605Smrg   /* texcoords */
142848b8605Smrg   {
143848b8605Smrg      GLuint i;
144848b8605Smrg      for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
145848b8605Smrg         const GLuint attr = VARYING_SLOT_TEX0 + i;
146848b8605Smrg         const GLfloat *tc = ctx->Current.RasterTexCoords[i];
147848b8605Smrg         if (_swrast_use_fragment_program(ctx) ||
148b8e80941Smrg             _mesa_ati_fragment_shader_enabled(ctx)) {
149848b8605Smrg            COPY_4V(span->attrStart[attr], tc);
150848b8605Smrg         }
151848b8605Smrg         else if (tc[3] > 0.0F) {
152848b8605Smrg            /* use (s/q, t/q, r/q, 1) */
153848b8605Smrg            span->attrStart[attr][0] = tc[0] / tc[3];
154848b8605Smrg            span->attrStart[attr][1] = tc[1] / tc[3];
155848b8605Smrg            span->attrStart[attr][2] = tc[2] / tc[3];
156848b8605Smrg            span->attrStart[attr][3] = 1.0;
157848b8605Smrg         }
158848b8605Smrg         else {
159848b8605Smrg            ASSIGN_4V(span->attrStart[attr], 0.0F, 0.0F, 0.0F, 1.0F);
160848b8605Smrg         }
161848b8605Smrg         ASSIGN_4V(span->attrStepX[attr], 0.0F, 0.0F, 0.0F, 0.0F);
162848b8605Smrg         ASSIGN_4V(span->attrStepY[attr], 0.0F, 0.0F, 0.0F, 0.0F);
163848b8605Smrg      }
164848b8605Smrg   }
165848b8605Smrg}
166848b8605Smrg
167848b8605Smrg
168848b8605Smrg/**
169848b8605Smrg * Interpolate the active attributes (and'd with attrMask) to
170848b8605Smrg * fill in span->array->attribs[].
171848b8605Smrg * Perspective correction will be done.  The point/line/triangle function
172848b8605Smrg * should have computed attrStart/Step values for VARYING_SLOT_POS[3]!
173848b8605Smrg */
174848b8605Smrgstatic inline void
175848b8605Smrginterpolate_active_attribs(struct gl_context *ctx, SWspan *span,
176848b8605Smrg                           GLbitfield64 attrMask)
177848b8605Smrg{
178848b8605Smrg   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
179848b8605Smrg
180848b8605Smrg   /*
181848b8605Smrg    * Don't overwrite existing array values, such as colors that may have
182848b8605Smrg    * been produced by glDraw/CopyPixels.
183848b8605Smrg    */
184848b8605Smrg   attrMask &= ~span->arrayAttribs;
185848b8605Smrg
186848b8605Smrg   ATTRIB_LOOP_BEGIN
187848b8605Smrg      if (attrMask & BITFIELD64_BIT(attr)) {
188848b8605Smrg         const GLfloat dwdx = span->attrStepX[VARYING_SLOT_POS][3];
189848b8605Smrg         GLfloat w = span->attrStart[VARYING_SLOT_POS][3];
190848b8605Smrg         const GLfloat dv0dx = span->attrStepX[attr][0];
191848b8605Smrg         const GLfloat dv1dx = span->attrStepX[attr][1];
192848b8605Smrg         const GLfloat dv2dx = span->attrStepX[attr][2];
193848b8605Smrg         const GLfloat dv3dx = span->attrStepX[attr][3];
194848b8605Smrg         GLfloat v0 = span->attrStart[attr][0] + span->leftClip * dv0dx;
195848b8605Smrg         GLfloat v1 = span->attrStart[attr][1] + span->leftClip * dv1dx;
196848b8605Smrg         GLfloat v2 = span->attrStart[attr][2] + span->leftClip * dv2dx;
197848b8605Smrg         GLfloat v3 = span->attrStart[attr][3] + span->leftClip * dv3dx;
198848b8605Smrg         GLuint k;
199848b8605Smrg         for (k = 0; k < span->end; k++) {
200848b8605Smrg            const GLfloat invW = 1.0f / w;
201848b8605Smrg            span->array->attribs[attr][k][0] = v0 * invW;
202848b8605Smrg            span->array->attribs[attr][k][1] = v1 * invW;
203848b8605Smrg            span->array->attribs[attr][k][2] = v2 * invW;
204848b8605Smrg            span->array->attribs[attr][k][3] = v3 * invW;
205848b8605Smrg            v0 += dv0dx;
206848b8605Smrg            v1 += dv1dx;
207848b8605Smrg            v2 += dv2dx;
208848b8605Smrg            v3 += dv3dx;
209848b8605Smrg            w += dwdx;
210848b8605Smrg         }
211b8e80941Smrg         assert((span->arrayAttribs & BITFIELD64_BIT(attr)) == 0);
212848b8605Smrg         span->arrayAttribs |= BITFIELD64_BIT(attr);
213848b8605Smrg      }
214848b8605Smrg   ATTRIB_LOOP_END
215848b8605Smrg}
216848b8605Smrg
217848b8605Smrg
218848b8605Smrg/**
219848b8605Smrg * Interpolate primary colors to fill in the span->array->rgba8 (or rgb16)
220848b8605Smrg * color array.
221848b8605Smrg */
222848b8605Smrgstatic inline void
223848b8605Smrginterpolate_int_colors(struct gl_context *ctx, SWspan *span)
224848b8605Smrg{
225848b8605Smrg#if CHAN_BITS != 32
226848b8605Smrg   const GLuint n = span->end;
227848b8605Smrg   GLuint i;
228848b8605Smrg
229b8e80941Smrg   assert(!(span->arrayMask & SPAN_RGBA));
230848b8605Smrg#endif
231848b8605Smrg
232848b8605Smrg   switch (span->array->ChanType) {
233848b8605Smrg#if CHAN_BITS != 32
234848b8605Smrg   case GL_UNSIGNED_BYTE:
235848b8605Smrg      {
236848b8605Smrg         GLubyte (*rgba)[4] = span->array->rgba8;
237848b8605Smrg         if (span->interpMask & SPAN_FLAT) {
238848b8605Smrg            GLubyte color[4];
239848b8605Smrg            color[RCOMP] = FixedToInt(span->red);
240848b8605Smrg            color[GCOMP] = FixedToInt(span->green);
241848b8605Smrg            color[BCOMP] = FixedToInt(span->blue);
242848b8605Smrg            color[ACOMP] = FixedToInt(span->alpha);
243848b8605Smrg            for (i = 0; i < n; i++) {
244848b8605Smrg               COPY_4UBV(rgba[i], color);
245848b8605Smrg            }
246848b8605Smrg         }
247848b8605Smrg         else {
248848b8605Smrg            GLfixed r = span->red;
249848b8605Smrg            GLfixed g = span->green;
250848b8605Smrg            GLfixed b = span->blue;
251848b8605Smrg            GLfixed a = span->alpha;
252848b8605Smrg            GLint dr = span->redStep;
253848b8605Smrg            GLint dg = span->greenStep;
254848b8605Smrg            GLint db = span->blueStep;
255848b8605Smrg            GLint da = span->alphaStep;
256848b8605Smrg            for (i = 0; i < n; i++) {
257848b8605Smrg               rgba[i][RCOMP] = FixedToChan(r);
258848b8605Smrg               rgba[i][GCOMP] = FixedToChan(g);
259848b8605Smrg               rgba[i][BCOMP] = FixedToChan(b);
260848b8605Smrg               rgba[i][ACOMP] = FixedToChan(a);
261848b8605Smrg               r += dr;
262848b8605Smrg               g += dg;
263848b8605Smrg               b += db;
264848b8605Smrg               a += da;
265848b8605Smrg            }
266848b8605Smrg         }
267848b8605Smrg      }
268848b8605Smrg      break;
269848b8605Smrg   case GL_UNSIGNED_SHORT:
270848b8605Smrg      {
271848b8605Smrg         GLushort (*rgba)[4] = span->array->rgba16;
272848b8605Smrg         if (span->interpMask & SPAN_FLAT) {
273848b8605Smrg            GLushort color[4];
274848b8605Smrg            color[RCOMP] = FixedToInt(span->red);
275848b8605Smrg            color[GCOMP] = FixedToInt(span->green);
276848b8605Smrg            color[BCOMP] = FixedToInt(span->blue);
277848b8605Smrg            color[ACOMP] = FixedToInt(span->alpha);
278848b8605Smrg            for (i = 0; i < n; i++) {
279848b8605Smrg               COPY_4V(rgba[i], color);
280848b8605Smrg            }
281848b8605Smrg         }
282848b8605Smrg         else {
283848b8605Smrg            GLushort (*rgba)[4] = span->array->rgba16;
284848b8605Smrg            GLfixed r, g, b, a;
285848b8605Smrg            GLint dr, dg, db, da;
286848b8605Smrg            r = span->red;
287848b8605Smrg            g = span->green;
288848b8605Smrg            b = span->blue;
289848b8605Smrg            a = span->alpha;
290848b8605Smrg            dr = span->redStep;
291848b8605Smrg            dg = span->greenStep;
292848b8605Smrg            db = span->blueStep;
293848b8605Smrg            da = span->alphaStep;
294848b8605Smrg            for (i = 0; i < n; i++) {
295848b8605Smrg               rgba[i][RCOMP] = FixedToChan(r);
296848b8605Smrg               rgba[i][GCOMP] = FixedToChan(g);
297848b8605Smrg               rgba[i][BCOMP] = FixedToChan(b);
298848b8605Smrg               rgba[i][ACOMP] = FixedToChan(a);
299848b8605Smrg               r += dr;
300848b8605Smrg               g += dg;
301848b8605Smrg               b += db;
302848b8605Smrg               a += da;
303848b8605Smrg            }
304848b8605Smrg         }
305848b8605Smrg      }
306848b8605Smrg      break;
307848b8605Smrg#endif
308848b8605Smrg   case GL_FLOAT:
309848b8605Smrg      interpolate_active_attribs(ctx, span, VARYING_BIT_COL0);
310848b8605Smrg      break;
311848b8605Smrg   default:
312848b8605Smrg      _mesa_problem(ctx, "bad datatype 0x%x in interpolate_int_colors",
313848b8605Smrg                    span->array->ChanType);
314848b8605Smrg   }
315848b8605Smrg   span->arrayMask |= SPAN_RGBA;
316848b8605Smrg}
317848b8605Smrg
318848b8605Smrg
319848b8605Smrg/**
320848b8605Smrg * Populate the VARYING_SLOT_COL0 array.
321848b8605Smrg */
322848b8605Smrgstatic inline void
323848b8605Smrginterpolate_float_colors(SWspan *span)
324848b8605Smrg{
325848b8605Smrg   GLfloat (*col0)[4] = span->array->attribs[VARYING_SLOT_COL0];
326848b8605Smrg   const GLuint n = span->end;
327848b8605Smrg   GLuint i;
328848b8605Smrg
329848b8605Smrg   assert(!(span->arrayAttribs & VARYING_BIT_COL0));
330848b8605Smrg
331848b8605Smrg   if (span->arrayMask & SPAN_RGBA) {
332848b8605Smrg      /* convert array of int colors */
333848b8605Smrg      for (i = 0; i < n; i++) {
334848b8605Smrg         col0[i][0] = UBYTE_TO_FLOAT(span->array->rgba8[i][0]);
335848b8605Smrg         col0[i][1] = UBYTE_TO_FLOAT(span->array->rgba8[i][1]);
336848b8605Smrg         col0[i][2] = UBYTE_TO_FLOAT(span->array->rgba8[i][2]);
337848b8605Smrg         col0[i][3] = UBYTE_TO_FLOAT(span->array->rgba8[i][3]);
338848b8605Smrg      }
339848b8605Smrg   }
340848b8605Smrg   else {
341848b8605Smrg      /* interpolate red/green/blue/alpha to get float colors */
342b8e80941Smrg      assert(span->interpMask & SPAN_RGBA);
343848b8605Smrg      if (span->interpMask & SPAN_FLAT) {
344848b8605Smrg         GLfloat r = FixedToFloat(span->red);
345848b8605Smrg         GLfloat g = FixedToFloat(span->green);
346848b8605Smrg         GLfloat b = FixedToFloat(span->blue);
347848b8605Smrg         GLfloat a = FixedToFloat(span->alpha);
348848b8605Smrg         for (i = 0; i < n; i++) {
349848b8605Smrg            ASSIGN_4V(col0[i], r, g, b, a);
350848b8605Smrg         }
351848b8605Smrg      }
352848b8605Smrg      else {
353848b8605Smrg         GLfloat r = FixedToFloat(span->red);
354848b8605Smrg         GLfloat g = FixedToFloat(span->green);
355848b8605Smrg         GLfloat b = FixedToFloat(span->blue);
356848b8605Smrg         GLfloat a = FixedToFloat(span->alpha);
357848b8605Smrg         GLfloat dr = FixedToFloat(span->redStep);
358848b8605Smrg         GLfloat dg = FixedToFloat(span->greenStep);
359848b8605Smrg         GLfloat db = FixedToFloat(span->blueStep);
360848b8605Smrg         GLfloat da = FixedToFloat(span->alphaStep);
361848b8605Smrg         for (i = 0; i < n; i++) {
362848b8605Smrg            col0[i][0] = r;
363848b8605Smrg            col0[i][1] = g;
364848b8605Smrg            col0[i][2] = b;
365848b8605Smrg            col0[i][3] = a;
366848b8605Smrg            r += dr;
367848b8605Smrg            g += dg;
368848b8605Smrg            b += db;
369848b8605Smrg            a += da;
370848b8605Smrg         }
371848b8605Smrg      }
372848b8605Smrg   }
373848b8605Smrg
374848b8605Smrg   span->arrayAttribs |= VARYING_BIT_COL0;
375848b8605Smrg   span->array->ChanType = GL_FLOAT;
376848b8605Smrg}
377848b8605Smrg
378848b8605Smrg
379848b8605Smrg
380848b8605Smrg/**
381848b8605Smrg * Fill in the span.zArray array from the span->z, zStep values.
382848b8605Smrg */
383848b8605Smrgvoid
384848b8605Smrg_swrast_span_interpolate_z( const struct gl_context *ctx, SWspan *span )
385848b8605Smrg{
386848b8605Smrg   const GLuint n = span->end;
387848b8605Smrg   GLuint i;
388848b8605Smrg
389b8e80941Smrg   assert(!(span->arrayMask & SPAN_Z));
390848b8605Smrg
391848b8605Smrg   if (ctx->DrawBuffer->Visual.depthBits <= 16) {
392848b8605Smrg      GLfixed zval = span->z;
393848b8605Smrg      GLuint *z = span->array->z;
394848b8605Smrg      for (i = 0; i < n; i++) {
395848b8605Smrg         z[i] = FixedToInt(zval);
396848b8605Smrg         zval += span->zStep;
397848b8605Smrg      }
398848b8605Smrg   }
399848b8605Smrg   else {
400848b8605Smrg      /* Deep Z buffer, no fixed->int shift */
401848b8605Smrg      GLuint zval = span->z;
402848b8605Smrg      GLuint *z = span->array->z;
403848b8605Smrg      for (i = 0; i < n; i++) {
404848b8605Smrg         z[i] = zval;
405848b8605Smrg         zval += span->zStep;
406848b8605Smrg      }
407848b8605Smrg   }
408848b8605Smrg   span->interpMask &= ~SPAN_Z;
409848b8605Smrg   span->arrayMask |= SPAN_Z;
410848b8605Smrg}
411848b8605Smrg
412848b8605Smrg
413848b8605Smrg/**
414848b8605Smrg * Compute mipmap LOD from partial derivatives.
415848b8605Smrg * This the ideal solution, as given in the OpenGL spec.
416848b8605Smrg */
417848b8605SmrgGLfloat
418848b8605Smrg_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
419848b8605Smrg                       GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
420848b8605Smrg                       GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
421848b8605Smrg{
422848b8605Smrg   GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
423848b8605Smrg   GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
424848b8605Smrg   GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
425848b8605Smrg   GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
426848b8605Smrg   GLfloat x = sqrtf(dudx * dudx + dvdx * dvdx);
427848b8605Smrg   GLfloat y = sqrtf(dudy * dudy + dvdy * dvdy);
428848b8605Smrg   GLfloat rho = MAX2(x, y);
429848b8605Smrg   GLfloat lambda = LOG2(rho);
430848b8605Smrg   return lambda;
431848b8605Smrg}
432848b8605Smrg
433848b8605Smrg
434848b8605Smrg/**
435848b8605Smrg * Compute mipmap LOD from partial derivatives.
436848b8605Smrg * This is a faster approximation than above function.
437848b8605Smrg */
438848b8605Smrg#if 0
439848b8605SmrgGLfloat
440848b8605Smrg_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
441848b8605Smrg                     GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
442848b8605Smrg                     GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
443848b8605Smrg{
444848b8605Smrg   GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
445848b8605Smrg   GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
446848b8605Smrg   GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
447848b8605Smrg   GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
448848b8605Smrg   GLfloat maxU, maxV, rho, lambda;
449b8e80941Smrg   dsdx2 = fabsf(dsdx2);
450b8e80941Smrg   dsdy2 = fabsf(dsdy2);
451b8e80941Smrg   dtdx2 = fabsf(dtdx2);
452b8e80941Smrg   dtdy2 = fabsf(dtdy2);
453848b8605Smrg   maxU = MAX2(dsdx2, dsdy2) * texW;
454848b8605Smrg   maxV = MAX2(dtdx2, dtdy2) * texH;
455848b8605Smrg   rho = MAX2(maxU, maxV);
456848b8605Smrg   lambda = LOG2(rho);
457848b8605Smrg   return lambda;
458848b8605Smrg}
459848b8605Smrg#endif
460848b8605Smrg
461848b8605Smrg
462848b8605Smrg/**
463848b8605Smrg * Fill in the span.array->attrib[VARYING_SLOT_TEXn] arrays from the
464848b8605Smrg * using the attrStart/Step values.
465848b8605Smrg *
466848b8605Smrg * This function only used during fixed-function fragment processing.
467848b8605Smrg *
468848b8605Smrg * Note: in the places where we divide by Q (or mult by invQ) we're
469848b8605Smrg * really doing two things: perspective correction and texcoord
470848b8605Smrg * projection.  Remember, for texcoord (s,t,r,q) we need to index
471848b8605Smrg * texels with (s/q, t/q, r/q).
472848b8605Smrg */
473848b8605Smrgstatic void
474848b8605Smrginterpolate_texcoords(struct gl_context *ctx, SWspan *span)
475848b8605Smrg{
476848b8605Smrg   const GLuint maxUnit
477848b8605Smrg      = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
478848b8605Smrg   GLuint u;
479848b8605Smrg
480848b8605Smrg   /* XXX CoordUnits vs. ImageUnits */
481848b8605Smrg   for (u = 0; u < maxUnit; u++) {
482848b8605Smrg      if (ctx->Texture._EnabledCoordUnits & (1 << u)) {
483848b8605Smrg         const GLuint attr = VARYING_SLOT_TEX0 + u;
484848b8605Smrg         const struct gl_texture_object *obj = ctx->Texture.Unit[u]._Current;
485848b8605Smrg         GLfloat texW, texH;
486848b8605Smrg         GLboolean needLambda;
487848b8605Smrg         GLfloat (*texcoord)[4] = span->array->attribs[attr];
488848b8605Smrg         GLfloat *lambda = span->array->lambda[u];
489848b8605Smrg         const GLfloat dsdx = span->attrStepX[attr][0];
490848b8605Smrg         const GLfloat dsdy = span->attrStepY[attr][0];
491848b8605Smrg         const GLfloat dtdx = span->attrStepX[attr][1];
492848b8605Smrg         const GLfloat dtdy = span->attrStepY[attr][1];
493848b8605Smrg         const GLfloat drdx = span->attrStepX[attr][2];
494848b8605Smrg         const GLfloat dqdx = span->attrStepX[attr][3];
495848b8605Smrg         const GLfloat dqdy = span->attrStepY[attr][3];
496848b8605Smrg         GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
497848b8605Smrg         GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
498848b8605Smrg         GLfloat r = span->attrStart[attr][2] + span->leftClip * drdx;
499848b8605Smrg         GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
500848b8605Smrg
501848b8605Smrg         if (obj) {
502b8e80941Smrg            const struct gl_texture_image *img = _mesa_base_tex_image(obj);
503848b8605Smrg            const struct swrast_texture_image *swImg =
504848b8605Smrg               swrast_texture_image_const(img);
505848b8605Smrg            const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, u);
506848b8605Smrg
507848b8605Smrg            needLambda = (samp->MinFilter != samp->MagFilter)
508848b8605Smrg               || _swrast_use_fragment_program(ctx);
509848b8605Smrg            /* LOD is calculated directly in the ansiotropic filter, we can
510848b8605Smrg             * skip the normal lambda function as the result is ignored.
511848b8605Smrg             */
512b8e80941Smrg            if (samp->MaxAnisotropy > 1.0F &&
513848b8605Smrg                samp->MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
514848b8605Smrg               needLambda = GL_FALSE;
515848b8605Smrg            }
516848b8605Smrg            texW = swImg->WidthScale;
517848b8605Smrg            texH = swImg->HeightScale;
518848b8605Smrg         }
519848b8605Smrg         else {
520848b8605Smrg            /* using a fragment program */
521848b8605Smrg            texW = 1.0;
522848b8605Smrg            texH = 1.0;
523848b8605Smrg            needLambda = GL_FALSE;
524848b8605Smrg         }
525848b8605Smrg
526848b8605Smrg         if (needLambda) {
527848b8605Smrg            GLuint i;
528848b8605Smrg            if (_swrast_use_fragment_program(ctx)
529b8e80941Smrg                || _mesa_ati_fragment_shader_enabled(ctx)) {
530848b8605Smrg               /* do perspective correction but don't divide s, t, r by q */
531848b8605Smrg               const GLfloat dwdx = span->attrStepX[VARYING_SLOT_POS][3];
532848b8605Smrg               GLfloat w = span->attrStart[VARYING_SLOT_POS][3] + span->leftClip * dwdx;
533848b8605Smrg               for (i = 0; i < span->end; i++) {
534848b8605Smrg                  const GLfloat invW = 1.0F / w;
535848b8605Smrg                  texcoord[i][0] = s * invW;
536848b8605Smrg                  texcoord[i][1] = t * invW;
537848b8605Smrg                  texcoord[i][2] = r * invW;
538848b8605Smrg                  texcoord[i][3] = q * invW;
539848b8605Smrg                  lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
540848b8605Smrg                                                     dqdx, dqdy, texW, texH,
541848b8605Smrg                                                     s, t, q, invW);
542848b8605Smrg                  s += dsdx;
543848b8605Smrg                  t += dtdx;
544848b8605Smrg                  r += drdx;
545848b8605Smrg                  q += dqdx;
546848b8605Smrg                  w += dwdx;
547848b8605Smrg               }
548848b8605Smrg            }
549848b8605Smrg            else {
550848b8605Smrg               for (i = 0; i < span->end; i++) {
551848b8605Smrg                  const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
552848b8605Smrg                  texcoord[i][0] = s * invQ;
553848b8605Smrg                  texcoord[i][1] = t * invQ;
554848b8605Smrg                  texcoord[i][2] = r * invQ;
555848b8605Smrg                  texcoord[i][3] = q;
556848b8605Smrg                  lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
557848b8605Smrg                                                     dqdx, dqdy, texW, texH,
558848b8605Smrg                                                     s, t, q, invQ);
559848b8605Smrg                  s += dsdx;
560848b8605Smrg                  t += dtdx;
561848b8605Smrg                  r += drdx;
562848b8605Smrg                  q += dqdx;
563848b8605Smrg               }
564848b8605Smrg            }
565848b8605Smrg            span->arrayMask |= SPAN_LAMBDA;
566848b8605Smrg         }
567848b8605Smrg         else {
568848b8605Smrg            GLuint i;
569848b8605Smrg            if (_swrast_use_fragment_program(ctx) ||
570b8e80941Smrg                _mesa_ati_fragment_shader_enabled(ctx)) {
571848b8605Smrg               /* do perspective correction but don't divide s, t, r by q */
572848b8605Smrg               const GLfloat dwdx = span->attrStepX[VARYING_SLOT_POS][3];
573848b8605Smrg               GLfloat w = span->attrStart[VARYING_SLOT_POS][3] + span->leftClip * dwdx;
574848b8605Smrg               for (i = 0; i < span->end; i++) {
575848b8605Smrg                  const GLfloat invW = 1.0F / w;
576848b8605Smrg                  texcoord[i][0] = s * invW;
577848b8605Smrg                  texcoord[i][1] = t * invW;
578848b8605Smrg                  texcoord[i][2] = r * invW;
579848b8605Smrg                  texcoord[i][3] = q * invW;
580848b8605Smrg                  lambda[i] = 0.0;
581848b8605Smrg                  s += dsdx;
582848b8605Smrg                  t += dtdx;
583848b8605Smrg                  r += drdx;
584848b8605Smrg                  q += dqdx;
585848b8605Smrg                  w += dwdx;
586848b8605Smrg               }
587848b8605Smrg            }
588848b8605Smrg            else if (dqdx == 0.0F) {
589848b8605Smrg               /* Ortho projection or polygon's parallel to window X axis */
590848b8605Smrg               const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
591848b8605Smrg               for (i = 0; i < span->end; i++) {
592848b8605Smrg                  texcoord[i][0] = s * invQ;
593848b8605Smrg                  texcoord[i][1] = t * invQ;
594848b8605Smrg                  texcoord[i][2] = r * invQ;
595848b8605Smrg                  texcoord[i][3] = q;
596848b8605Smrg                  lambda[i] = 0.0;
597848b8605Smrg                  s += dsdx;
598848b8605Smrg                  t += dtdx;
599848b8605Smrg                  r += drdx;
600848b8605Smrg               }
601848b8605Smrg            }
602848b8605Smrg            else {
603848b8605Smrg               for (i = 0; i < span->end; i++) {
604848b8605Smrg                  const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
605848b8605Smrg                  texcoord[i][0] = s * invQ;
606848b8605Smrg                  texcoord[i][1] = t * invQ;
607848b8605Smrg                  texcoord[i][2] = r * invQ;
608848b8605Smrg                  texcoord[i][3] = q;
609848b8605Smrg                  lambda[i] = 0.0;
610848b8605Smrg                  s += dsdx;
611848b8605Smrg                  t += dtdx;
612848b8605Smrg                  r += drdx;
613848b8605Smrg                  q += dqdx;
614848b8605Smrg               }
615848b8605Smrg            }
616848b8605Smrg         } /* lambda */
617848b8605Smrg      } /* if */
618848b8605Smrg   } /* for */
619848b8605Smrg}
620848b8605Smrg
621848b8605Smrg
622848b8605Smrg/**
623848b8605Smrg * Fill in the arrays->attribs[VARYING_SLOT_POS] array.
624848b8605Smrg */
625848b8605Smrgstatic inline void
626848b8605Smrginterpolate_wpos(struct gl_context *ctx, SWspan *span)
627848b8605Smrg{
628848b8605Smrg   GLfloat (*wpos)[4] = span->array->attribs[VARYING_SLOT_POS];
629848b8605Smrg   GLuint i;
630848b8605Smrg   const GLfloat zScale = 1.0F / ctx->DrawBuffer->_DepthMaxF;
631848b8605Smrg   GLfloat w, dw;
632848b8605Smrg
633848b8605Smrg   if (span->arrayMask & SPAN_XY) {
634848b8605Smrg      for (i = 0; i < span->end; i++) {
635848b8605Smrg         wpos[i][0] = (GLfloat) span->array->x[i];
636848b8605Smrg         wpos[i][1] = (GLfloat) span->array->y[i];
637848b8605Smrg      }
638848b8605Smrg   }
639848b8605Smrg   else {
640848b8605Smrg      for (i = 0; i < span->end; i++) {
641848b8605Smrg         wpos[i][0] = (GLfloat) span->x + i;
642848b8605Smrg         wpos[i][1] = (GLfloat) span->y;
643848b8605Smrg      }
644848b8605Smrg   }
645848b8605Smrg
646848b8605Smrg   dw = span->attrStepX[VARYING_SLOT_POS][3];
647848b8605Smrg   w = span->attrStart[VARYING_SLOT_POS][3] + span->leftClip * dw;
648848b8605Smrg   for (i = 0; i < span->end; i++) {
649848b8605Smrg      wpos[i][2] = (GLfloat) span->array->z[i] * zScale;
650848b8605Smrg      wpos[i][3] = w;
651848b8605Smrg      w += dw;
652848b8605Smrg   }
653848b8605Smrg}
654848b8605Smrg
655848b8605Smrg
656848b8605Smrg/**
657848b8605Smrg * Apply the current polygon stipple pattern to a span of pixels.
658848b8605Smrg */
659848b8605Smrgstatic inline void
660848b8605Smrgstipple_polygon_span(struct gl_context *ctx, SWspan *span)
661848b8605Smrg{
662848b8605Smrg   GLubyte *mask = span->array->mask;
663848b8605Smrg
664b8e80941Smrg   assert(ctx->Polygon.StippleFlag);
665848b8605Smrg
666848b8605Smrg   if (span->arrayMask & SPAN_XY) {
667848b8605Smrg      /* arrays of x/y pixel coords */
668848b8605Smrg      GLuint i;
669848b8605Smrg      for (i = 0; i < span->end; i++) {
670848b8605Smrg         const GLint col = span->array->x[i] % 32;
671848b8605Smrg         const GLint row = span->array->y[i] % 32;
672848b8605Smrg         const GLuint stipple = ctx->PolygonStipple[row];
673848b8605Smrg         if (((1 << col) & stipple) == 0) {
674848b8605Smrg            mask[i] = 0;
675848b8605Smrg         }
676848b8605Smrg      }
677848b8605Smrg   }
678848b8605Smrg   else {
679848b8605Smrg      /* horizontal span of pixels */
680848b8605Smrg      const GLuint highBit = 1 << 31;
681848b8605Smrg      const GLuint stipple = ctx->PolygonStipple[span->y % 32];
682848b8605Smrg      GLuint i, m = highBit >> (GLuint) (span->x % 32);
683848b8605Smrg      for (i = 0; i < span->end; i++) {
684848b8605Smrg         if ((m & stipple) == 0) {
685848b8605Smrg            mask[i] = 0;
686848b8605Smrg         }
687848b8605Smrg         m = m >> 1;
688848b8605Smrg         if (m == 0) {
689848b8605Smrg            m = highBit;
690848b8605Smrg         }
691848b8605Smrg      }
692848b8605Smrg   }
693848b8605Smrg   span->writeAll = GL_FALSE;
694848b8605Smrg}
695848b8605Smrg
696848b8605Smrg
697848b8605Smrg/**
698848b8605Smrg * Clip a pixel span to the current buffer/window boundaries:
699848b8605Smrg * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax.  This will accomplish
700848b8605Smrg * window clipping and scissoring.
701848b8605Smrg * Return:   GL_TRUE   some pixels still visible
702848b8605Smrg *           GL_FALSE  nothing visible
703848b8605Smrg */
704848b8605Smrgstatic inline GLuint
705848b8605Smrgclip_span( struct gl_context *ctx, SWspan *span )
706848b8605Smrg{
707848b8605Smrg   const GLint xmin = ctx->DrawBuffer->_Xmin;
708848b8605Smrg   const GLint xmax = ctx->DrawBuffer->_Xmax;
709848b8605Smrg   const GLint ymin = ctx->DrawBuffer->_Ymin;
710848b8605Smrg   const GLint ymax = ctx->DrawBuffer->_Ymax;
711848b8605Smrg
712848b8605Smrg   span->leftClip = 0;
713848b8605Smrg
714848b8605Smrg   if (span->arrayMask & SPAN_XY) {
715848b8605Smrg      /* arrays of x/y pixel coords */
716848b8605Smrg      const GLint *x = span->array->x;
717848b8605Smrg      const GLint *y = span->array->y;
718848b8605Smrg      const GLint n = span->end;
719848b8605Smrg      GLubyte *mask = span->array->mask;
720848b8605Smrg      GLint i;
721848b8605Smrg      GLuint passed = 0;
722848b8605Smrg      if (span->arrayMask & SPAN_MASK) {
723848b8605Smrg         /* note: using & intead of && to reduce branches */
724848b8605Smrg         for (i = 0; i < n; i++) {
725848b8605Smrg            mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
726848b8605Smrg                     & (y[i] >= ymin) & (y[i] < ymax);
727848b8605Smrg            passed += mask[i];
728848b8605Smrg         }
729848b8605Smrg      }
730848b8605Smrg      else {
731848b8605Smrg         /* note: using & intead of && to reduce branches */
732848b8605Smrg         for (i = 0; i < n; i++) {
733848b8605Smrg            mask[i] = (x[i] >= xmin) & (x[i] < xmax)
734848b8605Smrg                    & (y[i] >= ymin) & (y[i] < ymax);
735848b8605Smrg            passed += mask[i];
736848b8605Smrg         }
737848b8605Smrg      }
738848b8605Smrg      return passed > 0;
739848b8605Smrg   }
740848b8605Smrg   else {
741848b8605Smrg      /* horizontal span of pixels */
742848b8605Smrg      const GLint x = span->x;
743848b8605Smrg      const GLint y = span->y;
744848b8605Smrg      GLint n = span->end;
745848b8605Smrg
746848b8605Smrg      /* Trivial rejection tests */
747848b8605Smrg      if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
748848b8605Smrg         span->end = 0;
749848b8605Smrg         return GL_FALSE;  /* all pixels clipped */
750848b8605Smrg      }
751848b8605Smrg
752848b8605Smrg      /* Clip to right */
753848b8605Smrg      if (x + n > xmax) {
754b8e80941Smrg         assert(x < xmax);
755848b8605Smrg         n = span->end = xmax - x;
756848b8605Smrg      }
757848b8605Smrg
758848b8605Smrg      /* Clip to the left */
759848b8605Smrg      if (x < xmin) {
760848b8605Smrg         const GLint leftClip = xmin - x;
761848b8605Smrg         GLuint i;
762848b8605Smrg
763b8e80941Smrg         assert(leftClip > 0);
764b8e80941Smrg         assert(x + n > xmin);
765848b8605Smrg
766848b8605Smrg         /* Clip 'leftClip' pixels from the left side.
767848b8605Smrg          * The span->leftClip field will be applied when we interpolate
768848b8605Smrg          * fragment attributes.
769848b8605Smrg          * For arrays of values, shift them left.
770848b8605Smrg          */
771848b8605Smrg         for (i = 0; i < VARYING_SLOT_MAX; i++) {
772b8e80941Smrg            if (span->interpMask & (1u << i)) {
773848b8605Smrg               GLuint j;
774848b8605Smrg               for (j = 0; j < 4; j++) {
775848b8605Smrg                  span->attrStart[i][j] += leftClip * span->attrStepX[i][j];
776848b8605Smrg               }
777848b8605Smrg            }
778848b8605Smrg         }
779848b8605Smrg
780848b8605Smrg         span->red += leftClip * span->redStep;
781848b8605Smrg         span->green += leftClip * span->greenStep;
782848b8605Smrg         span->blue += leftClip * span->blueStep;
783848b8605Smrg         span->alpha += leftClip * span->alphaStep;
784848b8605Smrg         span->index += leftClip * span->indexStep;
785848b8605Smrg         span->z += leftClip * span->zStep;
786848b8605Smrg         span->intTex[0] += leftClip * span->intTexStep[0];
787848b8605Smrg         span->intTex[1] += leftClip * span->intTexStep[1];
788848b8605Smrg
789848b8605Smrg#define SHIFT_ARRAY(ARRAY, SHIFT, LEN) \
790848b8605Smrg         memmove(ARRAY, ARRAY + (SHIFT), (LEN) * sizeof(ARRAY[0]))
791848b8605Smrg
792848b8605Smrg         for (i = 0; i < VARYING_SLOT_MAX; i++) {
793b8e80941Smrg            if (span->arrayAttribs & BITFIELD64_BIT(i)) {
794848b8605Smrg               /* shift array elements left by 'leftClip' */
795848b8605Smrg               SHIFT_ARRAY(span->array->attribs[i], leftClip, n - leftClip);
796848b8605Smrg            }
797848b8605Smrg         }
798848b8605Smrg
799848b8605Smrg         SHIFT_ARRAY(span->array->mask, leftClip, n - leftClip);
800848b8605Smrg         SHIFT_ARRAY(span->array->rgba8, leftClip, n - leftClip);
801848b8605Smrg         SHIFT_ARRAY(span->array->rgba16, leftClip, n - leftClip);
802848b8605Smrg         SHIFT_ARRAY(span->array->x, leftClip, n - leftClip);
803848b8605Smrg         SHIFT_ARRAY(span->array->y, leftClip, n - leftClip);
804848b8605Smrg         SHIFT_ARRAY(span->array->z, leftClip, n - leftClip);
805848b8605Smrg         SHIFT_ARRAY(span->array->index, leftClip, n - leftClip);
806848b8605Smrg         for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
807848b8605Smrg            SHIFT_ARRAY(span->array->lambda[i], leftClip, n - leftClip);
808848b8605Smrg         }
809848b8605Smrg         SHIFT_ARRAY(span->array->coverage, leftClip, n - leftClip);
810848b8605Smrg
811848b8605Smrg#undef SHIFT_ARRAY
812848b8605Smrg
813848b8605Smrg         span->leftClip = leftClip;
814848b8605Smrg         span->x = xmin;
815848b8605Smrg         span->end -= leftClip;
816848b8605Smrg         span->writeAll = GL_FALSE;
817848b8605Smrg      }
818848b8605Smrg
819b8e80941Smrg      assert(span->x >= xmin);
820b8e80941Smrg      assert(span->x + span->end <= xmax);
821b8e80941Smrg      assert(span->y >= ymin);
822b8e80941Smrg      assert(span->y < ymax);
823848b8605Smrg
824848b8605Smrg      return GL_TRUE;  /* some pixels visible */
825848b8605Smrg   }
826848b8605Smrg}
827848b8605Smrg
828848b8605Smrg
829848b8605Smrg/**
830848b8605Smrg * Add specular colors to primary colors.
831848b8605Smrg * Only called during fixed-function operation.
832848b8605Smrg * Result is float color array (VARYING_SLOT_COL0).
833848b8605Smrg */
834848b8605Smrgstatic inline void
835848b8605Smrgadd_specular(struct gl_context *ctx, SWspan *span)
836848b8605Smrg{
837848b8605Smrg   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
838848b8605Smrg   const GLubyte *mask = span->array->mask;
839848b8605Smrg   GLfloat (*col0)[4] = span->array->attribs[VARYING_SLOT_COL0];
840848b8605Smrg   GLfloat (*col1)[4] = span->array->attribs[VARYING_SLOT_COL1];
841848b8605Smrg   GLuint i;
842848b8605Smrg
843b8e80941Smrg   assert(!_swrast_use_fragment_program(ctx));
844b8e80941Smrg   assert(span->arrayMask & SPAN_RGBA);
845b8e80941Smrg   assert(swrast->_ActiveAttribMask & VARYING_BIT_COL1);
846848b8605Smrg   (void) swrast; /* silence warning */
847848b8605Smrg
848848b8605Smrg   if (span->array->ChanType == GL_FLOAT) {
849848b8605Smrg      if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) {
850848b8605Smrg         interpolate_active_attribs(ctx, span, VARYING_BIT_COL0);
851848b8605Smrg      }
852848b8605Smrg   }
853848b8605Smrg   else {
854848b8605Smrg      /* need float colors */
855848b8605Smrg      if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) {
856848b8605Smrg         interpolate_float_colors(span);
857848b8605Smrg      }
858848b8605Smrg   }
859848b8605Smrg
860848b8605Smrg   if ((span->arrayAttribs & VARYING_BIT_COL1) == 0) {
861848b8605Smrg      /* XXX could avoid this and interpolate COL1 in the loop below */
862848b8605Smrg      interpolate_active_attribs(ctx, span, VARYING_BIT_COL1);
863848b8605Smrg   }
864848b8605Smrg
865b8e80941Smrg   assert(span->arrayAttribs & VARYING_BIT_COL0);
866b8e80941Smrg   assert(span->arrayAttribs & VARYING_BIT_COL1);
867848b8605Smrg
868848b8605Smrg   for (i = 0; i < span->end; i++) {
869848b8605Smrg      if (mask[i]) {
870848b8605Smrg         col0[i][0] += col1[i][0];
871848b8605Smrg         col0[i][1] += col1[i][1];
872848b8605Smrg         col0[i][2] += col1[i][2];
873848b8605Smrg      }
874848b8605Smrg   }
875848b8605Smrg
876848b8605Smrg   span->array->ChanType = GL_FLOAT;
877848b8605Smrg}
878848b8605Smrg
879848b8605Smrg
880848b8605Smrg/**
881848b8605Smrg * Apply antialiasing coverage value to alpha values.
882848b8605Smrg */
883848b8605Smrgstatic inline void
884848b8605Smrgapply_aa_coverage(SWspan *span)
885848b8605Smrg{
886848b8605Smrg   const GLfloat *coverage = span->array->coverage;
887848b8605Smrg   GLuint i;
888848b8605Smrg   if (span->array->ChanType == GL_UNSIGNED_BYTE) {
889848b8605Smrg      GLubyte (*rgba)[4] = span->array->rgba8;
890848b8605Smrg      for (i = 0; i < span->end; i++) {
891848b8605Smrg         const GLfloat a = rgba[i][ACOMP] * coverage[i];
892b8e80941Smrg         rgba[i][ACOMP] = (GLubyte) CLAMP(a, 0.0F, 255.0F);
893b8e80941Smrg         assert(coverage[i] >= 0.0F);
894b8e80941Smrg         assert(coverage[i] <= 1.0F);
895848b8605Smrg      }
896848b8605Smrg   }
897848b8605Smrg   else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
898848b8605Smrg      GLushort (*rgba)[4] = span->array->rgba16;
899848b8605Smrg      for (i = 0; i < span->end; i++) {
900848b8605Smrg         const GLfloat a = rgba[i][ACOMP] * coverage[i];
901b8e80941Smrg         rgba[i][ACOMP] = (GLushort) CLAMP(a, 0.0F, 65535.0F);
902848b8605Smrg      }
903848b8605Smrg   }
904848b8605Smrg   else {
905848b8605Smrg      GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
906848b8605Smrg      for (i = 0; i < span->end; i++) {
907848b8605Smrg         rgba[i][ACOMP] = rgba[i][ACOMP] * coverage[i];
908848b8605Smrg         /* clamp later */
909848b8605Smrg      }
910848b8605Smrg   }
911848b8605Smrg}
912848b8605Smrg
913848b8605Smrg
914848b8605Smrg/**
915848b8605Smrg * Clamp span's float colors to [0,1]
916848b8605Smrg */
917848b8605Smrgstatic inline void
918848b8605Smrgclamp_colors(SWspan *span)
919848b8605Smrg{
920848b8605Smrg   GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
921848b8605Smrg   GLuint i;
922b8e80941Smrg   assert(span->array->ChanType == GL_FLOAT);
923848b8605Smrg   for (i = 0; i < span->end; i++) {
924848b8605Smrg      rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F);
925848b8605Smrg      rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F);
926848b8605Smrg      rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F);
927848b8605Smrg      rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F);
928848b8605Smrg   }
929848b8605Smrg}
930848b8605Smrg
931848b8605Smrg
932848b8605Smrg/**
933848b8605Smrg * Convert the span's color arrays to the given type.
934848b8605Smrg * The only way 'output' can be greater than zero is when we have a fragment
935848b8605Smrg * program that writes to gl_FragData[1] or higher.
936848b8605Smrg * \param output  which fragment program color output is being processed
937848b8605Smrg */
938848b8605Smrgstatic inline void
939b8e80941Smrgconvert_color_type(SWspan *span, GLenum srcType, GLenum newType, GLuint output)
940848b8605Smrg{
941848b8605Smrg   GLvoid *src, *dst;
942848b8605Smrg
943b8e80941Smrg   if (output > 0 || srcType == GL_FLOAT) {
944848b8605Smrg      src = span->array->attribs[VARYING_SLOT_COL0 + output];
945848b8605Smrg      span->array->ChanType = GL_FLOAT;
946848b8605Smrg   }
947b8e80941Smrg   else if (srcType == GL_UNSIGNED_BYTE) {
948848b8605Smrg      src = span->array->rgba8;
949848b8605Smrg   }
950848b8605Smrg   else {
951b8e80941Smrg      assert(srcType == GL_UNSIGNED_SHORT);
952848b8605Smrg      src = span->array->rgba16;
953848b8605Smrg   }
954848b8605Smrg
955848b8605Smrg   if (newType == GL_UNSIGNED_BYTE) {
956848b8605Smrg      dst = span->array->rgba8;
957848b8605Smrg   }
958848b8605Smrg   else if (newType == GL_UNSIGNED_SHORT) {
959848b8605Smrg      dst = span->array->rgba16;
960848b8605Smrg   }
961848b8605Smrg   else {
962848b8605Smrg      dst = span->array->attribs[VARYING_SLOT_COL0];
963848b8605Smrg   }
964848b8605Smrg
965848b8605Smrg   _mesa_convert_colors(span->array->ChanType, src,
966848b8605Smrg                        newType, dst,
967848b8605Smrg                        span->end, span->array->mask);
968848b8605Smrg
969848b8605Smrg   span->array->ChanType = newType;
970848b8605Smrg   span->array->rgba = dst;
971848b8605Smrg}
972848b8605Smrg
973848b8605Smrg
974848b8605Smrg
975848b8605Smrg/**
976848b8605Smrg * Apply fragment shader, fragment program or normal texturing to span.
977848b8605Smrg */
978848b8605Smrgstatic inline void
979848b8605Smrgshade_texture_span(struct gl_context *ctx, SWspan *span)
980848b8605Smrg{
981848b8605Smrg   if (_swrast_use_fragment_program(ctx) ||
982b8e80941Smrg       _mesa_ati_fragment_shader_enabled(ctx)) {
983848b8605Smrg      /* programmable shading */
984848b8605Smrg      if (span->primitive == GL_BITMAP && span->array->ChanType != GL_FLOAT) {
985b8e80941Smrg         convert_color_type(span, span->array->ChanType, GL_FLOAT, 0);
986848b8605Smrg      }
987848b8605Smrg      else {
988848b8605Smrg         span->array->rgba = (void *) span->array->attribs[VARYING_SLOT_COL0];
989848b8605Smrg      }
990848b8605Smrg
991848b8605Smrg      if (span->primitive != GL_POINT ||
992848b8605Smrg	  (span->interpMask & SPAN_RGBA) ||
993848b8605Smrg	  ctx->Point.PointSprite) {
994848b8605Smrg         /* for single-pixel points, we populated the arrays already */
995848b8605Smrg         interpolate_active_attribs(ctx, span, ~0);
996848b8605Smrg      }
997848b8605Smrg      span->array->ChanType = GL_FLOAT;
998848b8605Smrg
999848b8605Smrg      if (!(span->arrayMask & SPAN_Z))
1000848b8605Smrg         _swrast_span_interpolate_z (ctx, span);
1001848b8605Smrg
1002848b8605Smrg#if 0
1003848b8605Smrg      if (inputsRead & VARYING_BIT_POS)
1004848b8605Smrg#else
1005848b8605Smrg      /* XXX always interpolate wpos so that DDX/DDY work */
1006848b8605Smrg#endif
1007848b8605Smrg         interpolate_wpos(ctx, span);
1008848b8605Smrg
1009848b8605Smrg      /* Run fragment program/shader now */
1010848b8605Smrg      if (_swrast_use_fragment_program(ctx)) {
1011848b8605Smrg         _swrast_exec_fragment_program(ctx, span);
1012848b8605Smrg      }
1013848b8605Smrg      else {
1014b8e80941Smrg         assert(_mesa_ati_fragment_shader_enabled(ctx));
1015848b8605Smrg         _swrast_exec_fragment_shader(ctx, span);
1016848b8605Smrg      }
1017848b8605Smrg   }
1018848b8605Smrg   else if (ctx->Texture._EnabledCoordUnits) {
1019848b8605Smrg      /* conventional texturing */
1020848b8605Smrg
1021848b8605Smrg#if CHAN_BITS == 32
1022848b8605Smrg      if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) {
1023848b8605Smrg         interpolate_int_colors(ctx, span);
1024848b8605Smrg      }
1025848b8605Smrg#else
1026848b8605Smrg      if (!(span->arrayMask & SPAN_RGBA))
1027848b8605Smrg         interpolate_int_colors(ctx, span);
1028848b8605Smrg#endif
1029848b8605Smrg      if ((span->arrayAttribs & VARYING_BITS_TEX_ANY) == 0x0)
1030848b8605Smrg         interpolate_texcoords(ctx, span);
1031848b8605Smrg
1032848b8605Smrg      _swrast_texture_span(ctx, span);
1033848b8605Smrg   }
1034848b8605Smrg}
1035848b8605Smrg
1036848b8605Smrg
1037848b8605Smrg/** Put colors at x/y locations into a renderbuffer */
1038848b8605Smrgstatic void
1039848b8605Smrgput_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
1040848b8605Smrg           GLenum datatype,
1041848b8605Smrg           GLuint count, const GLint x[], const GLint y[],
1042848b8605Smrg           const void *values, const GLubyte *mask)
1043848b8605Smrg{
1044848b8605Smrg   gl_pack_ubyte_rgba_func pack_ubyte = NULL;
1045848b8605Smrg   gl_pack_float_rgba_func pack_float = NULL;
1046848b8605Smrg   GLuint i;
1047848b8605Smrg
1048848b8605Smrg   if (datatype == GL_UNSIGNED_BYTE)
1049848b8605Smrg      pack_ubyte = _mesa_get_pack_ubyte_rgba_function(rb->Format);
1050848b8605Smrg   else
1051848b8605Smrg      pack_float = _mesa_get_pack_float_rgba_function(rb->Format);
1052848b8605Smrg
1053848b8605Smrg   for (i = 0; i < count; i++) {
1054848b8605Smrg      if (mask[i]) {
1055848b8605Smrg         GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]);
1056848b8605Smrg
1057848b8605Smrg         if (datatype == GL_UNSIGNED_BYTE) {
1058848b8605Smrg            pack_ubyte((const GLubyte *) values + 4 * i, dst);
1059848b8605Smrg         }
1060848b8605Smrg         else {
1061848b8605Smrg            assert(datatype == GL_FLOAT);
1062848b8605Smrg            pack_float((const GLfloat *) values + 4 * i, dst);
1063848b8605Smrg         }
1064848b8605Smrg      }
1065848b8605Smrg   }
1066848b8605Smrg}
1067848b8605Smrg
1068848b8605Smrg
1069848b8605Smrg/** Put row of colors into renderbuffer */
1070848b8605Smrgvoid
1071848b8605Smrg_swrast_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
1072848b8605Smrg                GLenum datatype,
1073848b8605Smrg                GLuint count, GLint x, GLint y,
1074848b8605Smrg                const void *values, const GLubyte *mask)
1075848b8605Smrg{
1076848b8605Smrg   GLubyte *dst = _swrast_pixel_address(rb, x, y);
1077848b8605Smrg
1078848b8605Smrg   if (!mask) {
1079848b8605Smrg      if (datatype == GL_UNSIGNED_BYTE) {
1080848b8605Smrg         _mesa_pack_ubyte_rgba_row(rb->Format, count,
1081848b8605Smrg                                   (const GLubyte (*)[4]) values, dst);
1082848b8605Smrg      }
1083848b8605Smrg      else {
1084848b8605Smrg         assert(datatype == GL_FLOAT);
1085848b8605Smrg         _mesa_pack_float_rgba_row(rb->Format, count,
1086848b8605Smrg                                   (const GLfloat (*)[4]) values, dst);
1087848b8605Smrg      }
1088848b8605Smrg   }
1089848b8605Smrg   else {
1090848b8605Smrg      const GLuint bpp = _mesa_get_format_bytes(rb->Format);
1091848b8605Smrg      GLuint i, runLen, runStart;
1092848b8605Smrg      /* We can't pass a 'mask' array to the _mesa_pack_rgba_row() functions
1093848b8605Smrg       * so look for runs where mask=1...
1094848b8605Smrg       */
1095848b8605Smrg      runLen = runStart = 0;
1096848b8605Smrg      for (i = 0; i < count; i++) {
1097848b8605Smrg         if (mask[i]) {
1098848b8605Smrg            if (runLen == 0)
1099848b8605Smrg               runStart = i;
1100848b8605Smrg            runLen++;
1101848b8605Smrg         }
1102848b8605Smrg
1103848b8605Smrg         if (!mask[i] || i == count - 1) {
1104848b8605Smrg            /* might be the end of a run of pixels */
1105848b8605Smrg            if (runLen > 0) {
1106848b8605Smrg               if (datatype == GL_UNSIGNED_BYTE) {
1107848b8605Smrg                  _mesa_pack_ubyte_rgba_row(rb->Format, runLen,
1108848b8605Smrg                                     (const GLubyte (*)[4]) values + runStart,
1109848b8605Smrg                                     dst + runStart * bpp);
1110848b8605Smrg               }
1111848b8605Smrg               else {
1112848b8605Smrg                  assert(datatype == GL_FLOAT);
1113848b8605Smrg                  _mesa_pack_float_rgba_row(rb->Format, runLen,
1114848b8605Smrg                                   (const GLfloat (*)[4]) values + runStart,
1115848b8605Smrg                                   dst + runStart * bpp);
1116848b8605Smrg               }
1117848b8605Smrg               runLen = 0;
1118848b8605Smrg            }
1119848b8605Smrg         }
1120848b8605Smrg      }
1121848b8605Smrg   }
1122848b8605Smrg}
1123848b8605Smrg
1124848b8605Smrg
1125848b8605Smrg
1126848b8605Smrg/**
1127848b8605Smrg * Apply all the per-fragment operations to a span.
1128848b8605Smrg * This now includes texturing (_swrast_write_texture_span() is history).
1129848b8605Smrg * This function may modify any of the array values in the span.
1130848b8605Smrg * span->interpMask and span->arrayMask may be changed but will be restored
1131848b8605Smrg * to their original values before returning.
1132848b8605Smrg */
1133848b8605Smrgvoid
1134848b8605Smrg_swrast_write_rgba_span( struct gl_context *ctx, SWspan *span)
1135848b8605Smrg{
1136848b8605Smrg   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
1137848b8605Smrg   const GLbitfield origInterpMask = span->interpMask;
1138848b8605Smrg   const GLbitfield origArrayMask = span->arrayMask;
1139848b8605Smrg   const GLbitfield64 origArrayAttribs = span->arrayAttribs;
1140848b8605Smrg   const GLenum origChanType = span->array->ChanType;
1141848b8605Smrg   void * const origRgba = span->array->rgba;
1142848b8605Smrg   const GLboolean shader = (_swrast_use_fragment_program(ctx)
1143b8e80941Smrg                             || _mesa_ati_fragment_shader_enabled(ctx));
1144848b8605Smrg   const GLboolean shaderOrTexture = shader || ctx->Texture._EnabledCoordUnits;
1145848b8605Smrg   struct gl_framebuffer *fb = ctx->DrawBuffer;
1146848b8605Smrg
1147848b8605Smrg   /*
1148b8e80941Smrg   printf("%s()  interp 0x%x  array 0x%x\n", __func__,
1149848b8605Smrg          span->interpMask, span->arrayMask);
1150848b8605Smrg   */
1151848b8605Smrg
1152b8e80941Smrg   assert(span->primitive == GL_POINT ||
1153848b8605Smrg          span->primitive == GL_LINE ||
1154848b8605Smrg	  span->primitive == GL_POLYGON ||
1155848b8605Smrg          span->primitive == GL_BITMAP);
1156848b8605Smrg
1157848b8605Smrg   /* Fragment write masks */
1158848b8605Smrg   if (span->arrayMask & SPAN_MASK) {
1159848b8605Smrg      /* mask was initialized by caller, probably glBitmap */
1160848b8605Smrg      span->writeAll = GL_FALSE;
1161848b8605Smrg   }
1162848b8605Smrg   else {
1163848b8605Smrg      memset(span->array->mask, 1, span->end);
1164848b8605Smrg      span->writeAll = GL_TRUE;
1165848b8605Smrg   }
1166848b8605Smrg
1167848b8605Smrg   /* Clip to window/scissor box */
1168848b8605Smrg   if (!clip_span(ctx, span)) {
1169848b8605Smrg      return;
1170848b8605Smrg   }
1171848b8605Smrg
1172b8e80941Smrg   assert(span->end <= SWRAST_MAX_WIDTH);
1173848b8605Smrg
1174848b8605Smrg   /* Depth bounds test */
1175848b8605Smrg   if (ctx->Depth.BoundsTest && fb->Visual.depthBits > 0) {
1176848b8605Smrg      if (!_swrast_depth_bounds_test(ctx, span)) {
1177848b8605Smrg         return;
1178848b8605Smrg      }
1179848b8605Smrg   }
1180848b8605Smrg
1181848b8605Smrg#ifdef DEBUG
1182848b8605Smrg   /* Make sure all fragments are within window bounds */
1183848b8605Smrg   if (span->arrayMask & SPAN_XY) {
1184848b8605Smrg      /* array of pixel locations */
1185848b8605Smrg      GLuint i;
1186848b8605Smrg      for (i = 0; i < span->end; i++) {
1187848b8605Smrg         if (span->array->mask[i]) {
1188848b8605Smrg            assert(span->array->x[i] >= fb->_Xmin);
1189848b8605Smrg            assert(span->array->x[i] < fb->_Xmax);
1190848b8605Smrg            assert(span->array->y[i] >= fb->_Ymin);
1191848b8605Smrg            assert(span->array->y[i] < fb->_Ymax);
1192848b8605Smrg         }
1193848b8605Smrg      }
1194848b8605Smrg   }
1195848b8605Smrg#endif
1196848b8605Smrg
1197848b8605Smrg   /* Polygon Stippling */
1198848b8605Smrg   if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
1199848b8605Smrg      stipple_polygon_span(ctx, span);
1200848b8605Smrg   }
1201848b8605Smrg
1202848b8605Smrg   /* This is the normal place to compute the fragment color/Z
1203848b8605Smrg    * from texturing or shading.
1204848b8605Smrg    */
1205848b8605Smrg   if (shaderOrTexture && !swrast->_DeferredTexture) {
1206848b8605Smrg      shade_texture_span(ctx, span);
1207848b8605Smrg   }
1208848b8605Smrg
1209848b8605Smrg   /* Do the alpha test */
1210848b8605Smrg   if (ctx->Color.AlphaEnabled) {
1211848b8605Smrg      if (!_swrast_alpha_test(ctx, span)) {
1212848b8605Smrg         /* all fragments failed test */
1213848b8605Smrg         goto end;
1214848b8605Smrg      }
1215848b8605Smrg   }
1216848b8605Smrg
1217848b8605Smrg   /* Stencil and Z testing */
1218b8e80941Smrg   if (_mesa_stencil_is_enabled(ctx) || ctx->Depth.Test) {
1219848b8605Smrg      if (!(span->arrayMask & SPAN_Z))
1220848b8605Smrg         _swrast_span_interpolate_z(ctx, span);
1221848b8605Smrg
1222b8e80941Smrg      if (ctx->Transform.DepthClampNear && ctx->Transform.DepthClampFar)
1223848b8605Smrg	 _swrast_depth_clamp_span(ctx, span);
1224848b8605Smrg
1225b8e80941Smrg      if (_mesa_stencil_is_enabled(ctx)) {
1226848b8605Smrg         /* Combined Z/stencil tests */
1227848b8605Smrg         if (!_swrast_stencil_and_ztest_span(ctx, span)) {
1228848b8605Smrg            /* all fragments failed test */
1229848b8605Smrg            goto end;
1230848b8605Smrg         }
1231848b8605Smrg      }
1232848b8605Smrg      else if (fb->Visual.depthBits > 0) {
1233848b8605Smrg         /* Just regular depth testing */
1234b8e80941Smrg         assert(ctx->Depth.Test);
1235b8e80941Smrg         assert(span->arrayMask & SPAN_Z);
1236848b8605Smrg         if (!_swrast_depth_test_span(ctx, span)) {
1237848b8605Smrg            /* all fragments failed test */
1238848b8605Smrg            goto end;
1239848b8605Smrg         }
1240848b8605Smrg      }
1241848b8605Smrg   }
1242848b8605Smrg
1243848b8605Smrg   if (ctx->Query.CurrentOcclusionObject) {
1244848b8605Smrg      /* update count of 'passed' fragments */
1245848b8605Smrg      struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;
1246848b8605Smrg      GLuint i;
1247848b8605Smrg      for (i = 0; i < span->end; i++)
1248848b8605Smrg         q->Result += span->array->mask[i];
1249848b8605Smrg   }
1250848b8605Smrg
1251848b8605Smrg   /* We had to wait until now to check for glColorMask(0,0,0,0) because of
1252848b8605Smrg    * the occlusion test.
1253848b8605Smrg    */
1254b8e80941Smrg   if (fb->_NumColorDrawBuffers == 1 &&
1255b8e80941Smrg       !GET_COLORMASK(ctx->Color.ColorMask, 0)) {
1256848b8605Smrg      /* no colors to write */
1257848b8605Smrg      goto end;
1258848b8605Smrg   }
1259848b8605Smrg
1260848b8605Smrg   /* If we were able to defer fragment color computation to now, there's
1261848b8605Smrg    * a good chance that many fragments will have already been killed by
1262848b8605Smrg    * Z/stencil testing.
1263848b8605Smrg    */
1264848b8605Smrg   if (shaderOrTexture && swrast->_DeferredTexture) {
1265848b8605Smrg      shade_texture_span(ctx, span);
1266848b8605Smrg   }
1267848b8605Smrg
1268848b8605Smrg#if CHAN_BITS == 32
1269848b8605Smrg   if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) {
1270848b8605Smrg      interpolate_active_attribs(ctx, span, VARYING_BIT_COL0);
1271848b8605Smrg   }
1272848b8605Smrg#else
1273848b8605Smrg   if ((span->arrayMask & SPAN_RGBA) == 0) {
1274848b8605Smrg      interpolate_int_colors(ctx, span);
1275848b8605Smrg   }
1276848b8605Smrg#endif
1277848b8605Smrg
1278b8e80941Smrg   assert(span->arrayMask & SPAN_RGBA);
1279848b8605Smrg
1280848b8605Smrg   if (span->primitive == GL_BITMAP || !swrast->SpecularVertexAdd) {
1281848b8605Smrg      /* Add primary and specular (diffuse + specular) colors */
1282848b8605Smrg      if (!shader) {
1283848b8605Smrg         if (ctx->Fog.ColorSumEnabled ||
1284848b8605Smrg             (ctx->Light.Enabled &&
1285848b8605Smrg              ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
1286848b8605Smrg            add_specular(ctx, span);
1287848b8605Smrg         }
1288848b8605Smrg      }
1289848b8605Smrg   }
1290848b8605Smrg
1291848b8605Smrg   /* Fog */
1292848b8605Smrg   if (swrast->_FogEnabled) {
1293848b8605Smrg      _swrast_fog_rgba_span(ctx, span);
1294848b8605Smrg   }
1295848b8605Smrg
1296848b8605Smrg   /* Antialias coverage application */
1297848b8605Smrg   if (span->arrayMask & SPAN_COVERAGE) {
1298848b8605Smrg      apply_aa_coverage(span);
1299848b8605Smrg   }
1300848b8605Smrg
1301848b8605Smrg   /* Clamp color/alpha values over the range [0.0, 1.0] before storage */
1302848b8605Smrg   if (ctx->Color.ClampFragmentColor == GL_TRUE &&
1303848b8605Smrg       span->array->ChanType == GL_FLOAT) {
1304848b8605Smrg      clamp_colors(span);
1305848b8605Smrg   }
1306848b8605Smrg
1307848b8605Smrg   /*
1308848b8605Smrg    * Write to renderbuffers.
1309848b8605Smrg    * Depending on glDrawBuffer() state and the which color outputs are
1310848b8605Smrg    * written by the fragment shader, we may either replicate one color to
1311848b8605Smrg    * all renderbuffers or write a different color to each renderbuffer.
1312848b8605Smrg    * multiFragOutputs=TRUE for the later case.
1313848b8605Smrg    */
1314848b8605Smrg   {
1315848b8605Smrg      const GLuint numBuffers = fb->_NumColorDrawBuffers;
1316b8e80941Smrg      const struct gl_program *fp = ctx->FragmentProgram._Current;
1317848b8605Smrg      const GLboolean multiFragOutputs =
1318848b8605Smrg         _swrast_use_fragment_program(ctx)
1319b8e80941Smrg         && fp->info.outputs_written >= (1 << FRAG_RESULT_DATA0);
1320b8e80941Smrg      /* Save srcColorType because convert_color_type() can change it */
1321b8e80941Smrg      const GLenum srcColorType = span->array->ChanType;
1322848b8605Smrg      GLuint buf;
1323848b8605Smrg
1324848b8605Smrg      for (buf = 0; buf < numBuffers; buf++) {
1325848b8605Smrg         struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf];
1326848b8605Smrg
1327848b8605Smrg         /* color[fragOutput] will be written to buffer[buf] */
1328848b8605Smrg
1329848b8605Smrg         if (rb) {
1330848b8605Smrg            /* re-use one of the attribute array buffers for rgbaSave */
1331848b8605Smrg            GLchan (*rgbaSave)[4] = (GLchan (*)[4]) span->array->attribs[0];
1332848b8605Smrg            struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
1333b8e80941Smrg            const GLenum dstColorType = srb->ColorType;
1334848b8605Smrg
1335b8e80941Smrg            assert(dstColorType == GL_UNSIGNED_BYTE ||
1336b8e80941Smrg                   dstColorType == GL_FLOAT);
1337848b8605Smrg
1338848b8605Smrg            /* set span->array->rgba to colors for renderbuffer's datatype */
1339b8e80941Smrg            if (srcColorType != dstColorType) {
1340b8e80941Smrg               convert_color_type(span, srcColorType, dstColorType,
1341b8e80941Smrg                                  multiFragOutputs ? buf : 0);
1342848b8605Smrg            }
1343848b8605Smrg            else {
1344b8e80941Smrg               if (srcColorType == GL_UNSIGNED_BYTE) {
1345848b8605Smrg                  span->array->rgba = span->array->rgba8;
1346848b8605Smrg               }
1347848b8605Smrg               else {
1348848b8605Smrg                  span->array->rgba = (void *)
1349848b8605Smrg                     span->array->attribs[VARYING_SLOT_COL0];
1350848b8605Smrg               }
1351848b8605Smrg            }
1352848b8605Smrg
1353848b8605Smrg            if (!multiFragOutputs && numBuffers > 1) {
1354848b8605Smrg               /* save colors for second, third renderbuffer writes */
1355848b8605Smrg               memcpy(rgbaSave, span->array->rgba,
1356848b8605Smrg                      4 * span->end * sizeof(GLchan));
1357848b8605Smrg            }
1358848b8605Smrg
1359b8e80941Smrg            assert(rb->_BaseFormat == GL_RGBA ||
1360848b8605Smrg                   rb->_BaseFormat == GL_RGB ||
1361848b8605Smrg                   rb->_BaseFormat == GL_RED ||
1362848b8605Smrg                   rb->_BaseFormat == GL_RG ||
1363848b8605Smrg		   rb->_BaseFormat == GL_ALPHA);
1364848b8605Smrg
1365848b8605Smrg            if (ctx->Color.ColorLogicOpEnabled) {
1366848b8605Smrg               _swrast_logicop_rgba_span(ctx, rb, span);
1367848b8605Smrg            }
1368848b8605Smrg            else if ((ctx->Color.BlendEnabled >> buf) & 1) {
1369848b8605Smrg               _swrast_blend_span(ctx, rb, span);
1370848b8605Smrg            }
1371848b8605Smrg
1372b8e80941Smrg            if (GET_COLORMASK(ctx->Color.ColorMask, buf) != 0xf) {
1373848b8605Smrg               _swrast_mask_rgba_span(ctx, rb, span, buf);
1374848b8605Smrg            }
1375848b8605Smrg
1376848b8605Smrg            if (span->arrayMask & SPAN_XY) {
1377848b8605Smrg               /* array of pixel coords */
1378848b8605Smrg               put_values(ctx, rb,
1379848b8605Smrg                          span->array->ChanType, span->end,
1380848b8605Smrg                          span->array->x, span->array->y,
1381848b8605Smrg                          span->array->rgba, span->array->mask);
1382848b8605Smrg            }
1383848b8605Smrg            else {
1384848b8605Smrg               /* horizontal run of pixels */
1385848b8605Smrg               _swrast_put_row(ctx, rb,
1386848b8605Smrg                               span->array->ChanType,
1387848b8605Smrg                               span->end, span->x, span->y,
1388848b8605Smrg                               span->array->rgba,
1389848b8605Smrg                               span->writeAll ? NULL: span->array->mask);
1390848b8605Smrg            }
1391848b8605Smrg
1392848b8605Smrg            if (!multiFragOutputs && numBuffers > 1) {
1393848b8605Smrg               /* restore original span values */
1394848b8605Smrg               memcpy(span->array->rgba, rgbaSave,
1395848b8605Smrg                      4 * span->end * sizeof(GLchan));
1396848b8605Smrg            }
1397848b8605Smrg
1398848b8605Smrg         } /* if rb */
1399848b8605Smrg      } /* for buf */
1400848b8605Smrg   }
1401848b8605Smrg
1402848b8605Smrgend:
1403848b8605Smrg   /* restore these values before returning */
1404848b8605Smrg   span->interpMask = origInterpMask;
1405848b8605Smrg   span->arrayMask = origArrayMask;
1406848b8605Smrg   span->arrayAttribs = origArrayAttribs;
1407848b8605Smrg   span->array->ChanType = origChanType;
1408848b8605Smrg   span->array->rgba = origRgba;
1409848b8605Smrg}
1410848b8605Smrg
1411848b8605Smrg
1412848b8605Smrg/**
1413848b8605Smrg * Read float RGBA pixels from a renderbuffer.  Clipping will be done to
1414848b8605Smrg * prevent reading ouside the buffer's boundaries.
1415848b8605Smrg * \param rgba  the returned colors
1416848b8605Smrg */
1417848b8605Smrgvoid
1418848b8605Smrg_swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb,
1419848b8605Smrg                        GLuint n, GLint x, GLint y,
1420848b8605Smrg                        GLvoid *rgba)
1421848b8605Smrg{
1422848b8605Smrg   struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
1423848b8605Smrg   GLenum dstType = GL_FLOAT;
1424848b8605Smrg   const GLint bufWidth = (GLint) rb->Width;
1425848b8605Smrg   const GLint bufHeight = (GLint) rb->Height;
1426848b8605Smrg
1427848b8605Smrg   if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1428848b8605Smrg      /* completely above, below, or right */
1429848b8605Smrg      /* XXX maybe leave rgba values undefined? */
1430848b8605Smrg      memset(rgba, 0, 4 * n * sizeof(GLchan));
1431848b8605Smrg   }
1432848b8605Smrg   else {
1433848b8605Smrg      GLint skip, length;
1434848b8605Smrg      GLubyte *src;
1435848b8605Smrg
1436848b8605Smrg      if (x < 0) {
1437848b8605Smrg         /* left edge clipping */
1438848b8605Smrg         skip = -x;
1439848b8605Smrg         length = (GLint) n - skip;
1440848b8605Smrg         if (length < 0) {
1441848b8605Smrg            /* completely left of window */
1442848b8605Smrg            return;
1443848b8605Smrg         }
1444848b8605Smrg         if (length > bufWidth) {
1445848b8605Smrg            length = bufWidth;
1446848b8605Smrg         }
1447848b8605Smrg      }
1448848b8605Smrg      else if ((GLint) (x + n) > bufWidth) {
1449848b8605Smrg         /* right edge clipping */
1450848b8605Smrg         skip = 0;
1451848b8605Smrg         length = bufWidth - x;
1452848b8605Smrg         if (length < 0) {
1453848b8605Smrg            /* completely to right of window */
1454848b8605Smrg            return;
1455848b8605Smrg         }
1456848b8605Smrg      }
1457848b8605Smrg      else {
1458848b8605Smrg         /* no clipping */
1459848b8605Smrg         skip = 0;
1460848b8605Smrg         length = (GLint) n;
1461848b8605Smrg      }
1462848b8605Smrg
1463b8e80941Smrg      assert(rb);
1464b8e80941Smrg      assert(rb->_BaseFormat == GL_RGBA ||
1465848b8605Smrg	     rb->_BaseFormat == GL_RGB ||
1466848b8605Smrg	     rb->_BaseFormat == GL_RG ||
1467848b8605Smrg	     rb->_BaseFormat == GL_RED ||
1468848b8605Smrg	     rb->_BaseFormat == GL_LUMINANCE ||
1469848b8605Smrg	     rb->_BaseFormat == GL_INTENSITY ||
1470848b8605Smrg	     rb->_BaseFormat == GL_LUMINANCE_ALPHA ||
1471848b8605Smrg	     rb->_BaseFormat == GL_ALPHA);
1472848b8605Smrg
1473848b8605Smrg      assert(srb->Map);
1474b8e80941Smrg      (void) srb; /* silence unused var warning */
1475848b8605Smrg
1476848b8605Smrg      src = _swrast_pixel_address(rb, x + skip, y);
1477848b8605Smrg
1478848b8605Smrg      if (dstType == GL_UNSIGNED_BYTE) {
1479848b8605Smrg         _mesa_unpack_ubyte_rgba_row(rb->Format, length, src,
1480848b8605Smrg                                     (GLubyte (*)[4]) rgba + skip);
1481848b8605Smrg      }
1482848b8605Smrg      else if (dstType == GL_FLOAT) {
1483848b8605Smrg         _mesa_unpack_rgba_row(rb->Format, length, src,
1484848b8605Smrg                               (GLfloat (*)[4]) rgba + skip);
1485848b8605Smrg      }
1486848b8605Smrg      else {
1487848b8605Smrg         _mesa_problem(ctx, "unexpected type in _swrast_read_rgba_span()");
1488848b8605Smrg      }
1489848b8605Smrg   }
1490848b8605Smrg}
1491848b8605Smrg
1492848b8605Smrg
1493848b8605Smrg/**
1494848b8605Smrg * Get colors at x/y positions with clipping.
1495848b8605Smrg * \param type  type of values to return
1496848b8605Smrg */
1497848b8605Smrgstatic void
1498848b8605Smrgget_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
1499848b8605Smrg           GLuint count, const GLint x[], const GLint y[],
1500848b8605Smrg           void *values, GLenum type)
1501848b8605Smrg{
1502848b8605Smrg   GLuint i;
1503848b8605Smrg
1504848b8605Smrg   for (i = 0; i < count; i++) {
1505848b8605Smrg      if (x[i] >= 0 && y[i] >= 0 &&
1506848b8605Smrg	  x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) {
1507848b8605Smrg         /* inside */
1508848b8605Smrg         const GLubyte *src = _swrast_pixel_address(rb, x[i], y[i]);
1509848b8605Smrg
1510848b8605Smrg         if (type == GL_UNSIGNED_BYTE) {
1511848b8605Smrg            _mesa_unpack_ubyte_rgba_row(rb->Format, 1, src,
1512848b8605Smrg                                        (GLubyte (*)[4]) values + i);
1513848b8605Smrg         }
1514848b8605Smrg         else if (type == GL_FLOAT) {
1515848b8605Smrg            _mesa_unpack_rgba_row(rb->Format, 1, src,
1516848b8605Smrg                                  (GLfloat (*)[4]) values + i);
1517848b8605Smrg         }
1518848b8605Smrg         else {
1519848b8605Smrg            _mesa_problem(ctx, "unexpected type in get_values()");
1520848b8605Smrg         }
1521848b8605Smrg      }
1522848b8605Smrg   }
1523848b8605Smrg}
1524848b8605Smrg
1525848b8605Smrg
1526848b8605Smrg/**
1527848b8605Smrg * Get row of colors with clipping.
1528848b8605Smrg * \param type  type of values to return
1529848b8605Smrg */
1530848b8605Smrgstatic void
1531848b8605Smrgget_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
1532848b8605Smrg        GLuint count, GLint x, GLint y,
1533848b8605Smrg        GLvoid *values, GLenum type)
1534848b8605Smrg{
1535848b8605Smrg   GLint skip = 0;
1536848b8605Smrg   GLubyte *src;
1537848b8605Smrg
1538848b8605Smrg   if (y < 0 || y >= (GLint) rb->Height)
1539848b8605Smrg      return; /* above or below */
1540848b8605Smrg
1541848b8605Smrg   if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
1542848b8605Smrg      return; /* entirely left or right */
1543848b8605Smrg
1544848b8605Smrg   if (x + count > rb->Width) {
1545848b8605Smrg      /* right clip */
1546848b8605Smrg      GLint clip = x + count - rb->Width;
1547848b8605Smrg      count -= clip;
1548848b8605Smrg   }
1549848b8605Smrg
1550848b8605Smrg   if (x < 0) {
1551848b8605Smrg      /* left clip */
1552848b8605Smrg      skip = -x;
1553848b8605Smrg      x = 0;
1554848b8605Smrg      count -= skip;
1555848b8605Smrg   }
1556848b8605Smrg
1557848b8605Smrg   src = _swrast_pixel_address(rb, x, y);
1558848b8605Smrg
1559848b8605Smrg   if (type == GL_UNSIGNED_BYTE) {
1560848b8605Smrg      _mesa_unpack_ubyte_rgba_row(rb->Format, count, src,
1561848b8605Smrg                                  (GLubyte (*)[4]) values + skip);
1562848b8605Smrg   }
1563848b8605Smrg   else if (type == GL_FLOAT) {
1564848b8605Smrg      _mesa_unpack_rgba_row(rb->Format, count, src,
1565848b8605Smrg                            (GLfloat (*)[4]) values + skip);
1566848b8605Smrg   }
1567848b8605Smrg   else {
1568848b8605Smrg      _mesa_problem(ctx, "unexpected type in get_row()");
1569848b8605Smrg   }
1570848b8605Smrg}
1571848b8605Smrg
1572848b8605Smrg
1573848b8605Smrg/**
1574848b8605Smrg * Get RGBA pixels from the given renderbuffer.
1575848b8605Smrg * Used by blending, logicop and masking functions.
1576848b8605Smrg * \return pointer to the colors we read.
1577848b8605Smrg */
1578848b8605Smrgvoid *
1579848b8605Smrg_swrast_get_dest_rgba(struct gl_context *ctx, struct gl_renderbuffer *rb,
1580848b8605Smrg                      SWspan *span)
1581848b8605Smrg{
1582848b8605Smrg   void *rbPixels;
1583848b8605Smrg
1584848b8605Smrg   /* Point rbPixels to a temporary space */
1585848b8605Smrg   rbPixels = span->array->attribs[VARYING_SLOT_MAX - 1];
1586848b8605Smrg
1587848b8605Smrg   /* Get destination values from renderbuffer */
1588848b8605Smrg   if (span->arrayMask & SPAN_XY) {
1589848b8605Smrg      get_values(ctx, rb, span->end, span->array->x, span->array->y,
1590848b8605Smrg                 rbPixels, span->array->ChanType);
1591848b8605Smrg   }
1592848b8605Smrg   else {
1593848b8605Smrg      get_row(ctx, rb, span->end, span->x, span->y,
1594848b8605Smrg              rbPixels, span->array->ChanType);
1595848b8605Smrg   }
1596848b8605Smrg
1597848b8605Smrg   return rbPixels;
1598848b8605Smrg}
1599