1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg
26848b8605Smrg/*
27848b8605Smrg * When the device driver doesn't implement triangle rasterization it
28848b8605Smrg * can hook in _swrast_Triangle, which eventually calls one of these
29848b8605Smrg * functions to draw triangles.
30848b8605Smrg */
31848b8605Smrg
32848b8605Smrg#include "main/glheader.h"
33848b8605Smrg#include "main/context.h"
34848b8605Smrg#include "main/imports.h"
35848b8605Smrg#include "main/macros.h"
36848b8605Smrg#include "main/mtypes.h"
37848b8605Smrg#include "main/state.h"
38848b8605Smrg#include "main/samplerobj.h"
39b8e80941Smrg#include "main/stencil.h"
40b8e80941Smrg#include "main/teximage.h"
41848b8605Smrg#include "program/prog_instruction.h"
42848b8605Smrg
43848b8605Smrg#include "s_aatriangle.h"
44848b8605Smrg#include "s_context.h"
45848b8605Smrg#include "s_feedback.h"
46848b8605Smrg#include "s_span.h"
47848b8605Smrg#include "s_triangle.h"
48848b8605Smrg
49848b8605Smrg
50848b8605Smrg/**
51848b8605Smrg * Test if a triangle should be culled.  Used for feedback and selection mode.
52848b8605Smrg * \return GL_TRUE if the triangle is to be culled, GL_FALSE otherwise.
53848b8605Smrg */
54848b8605SmrgGLboolean
55848b8605Smrg_swrast_culltriangle( struct gl_context *ctx,
56848b8605Smrg                      const SWvertex *v0,
57848b8605Smrg                      const SWvertex *v1,
58848b8605Smrg                      const SWvertex *v2 )
59848b8605Smrg{
60848b8605Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
61848b8605Smrg   GLfloat ex = v1->attrib[VARYING_SLOT_POS][0] - v0->attrib[VARYING_SLOT_POS][0];
62848b8605Smrg   GLfloat ey = v1->attrib[VARYING_SLOT_POS][1] - v0->attrib[VARYING_SLOT_POS][1];
63848b8605Smrg   GLfloat fx = v2->attrib[VARYING_SLOT_POS][0] - v0->attrib[VARYING_SLOT_POS][0];
64848b8605Smrg   GLfloat fy = v2->attrib[VARYING_SLOT_POS][1] - v0->attrib[VARYING_SLOT_POS][1];
65848b8605Smrg   GLfloat c = ex*fy-ey*fx;
66848b8605Smrg
67848b8605Smrg   if (c * swrast->_BackfaceSign * swrast->_BackfaceCullSign <= 0.0F)
68848b8605Smrg      return GL_FALSE;
69848b8605Smrg
70848b8605Smrg   return GL_TRUE;
71848b8605Smrg}
72848b8605Smrg
73848b8605Smrg
74848b8605Smrg
75848b8605Smrg/*
76848b8605Smrg * Render a flat-shaded RGBA triangle.
77848b8605Smrg */
78848b8605Smrg#define NAME flat_rgba_triangle
79848b8605Smrg#define INTERP_Z 1
80848b8605Smrg#define SETUP_CODE				\
81b8e80941Smrg   assert(ctx->Texture._EnabledCoordUnits == 0);\
82b8e80941Smrg   assert(ctx->Light.ShadeModel==GL_FLAT);	\
83848b8605Smrg   span.interpMask |= SPAN_RGBA;		\
84848b8605Smrg   span.red = ChanToFixed(v2->color[0]);	\
85848b8605Smrg   span.green = ChanToFixed(v2->color[1]);	\
86848b8605Smrg   span.blue = ChanToFixed(v2->color[2]);	\
87848b8605Smrg   span.alpha = ChanToFixed(v2->color[3]);	\
88848b8605Smrg   span.redStep = 0;				\
89848b8605Smrg   span.greenStep = 0;				\
90848b8605Smrg   span.blueStep = 0;				\
91848b8605Smrg   span.alphaStep = 0;
92848b8605Smrg#define RENDER_SPAN( span )  _swrast_write_rgba_span(ctx, &span);
93848b8605Smrg#include "s_tritemp.h"
94848b8605Smrg
95848b8605Smrg
96848b8605Smrg
97848b8605Smrg/*
98848b8605Smrg * Render a smooth-shaded RGBA triangle.
99848b8605Smrg */
100848b8605Smrg#define NAME smooth_rgba_triangle
101848b8605Smrg#define INTERP_Z 1
102848b8605Smrg#define INTERP_RGB 1
103848b8605Smrg#define INTERP_ALPHA 1
104848b8605Smrg#define SETUP_CODE				\
105848b8605Smrg   {						\
106848b8605Smrg      /* texturing must be off */		\
107b8e80941Smrg      assert(ctx->Texture._EnabledCoordUnits == 0);	\
108b8e80941Smrg      assert(ctx->Light.ShadeModel==GL_SMOOTH);	\
109848b8605Smrg   }
110848b8605Smrg#define RENDER_SPAN( span )  _swrast_write_rgba_span(ctx, &span);
111848b8605Smrg#include "s_tritemp.h"
112848b8605Smrg
113848b8605Smrg
114848b8605Smrg
115848b8605Smrg/*
116848b8605Smrg * Render an RGB, GL_DECAL, textured triangle.
117848b8605Smrg * Interpolate S,T only w/out mipmapping or perspective correction.
118848b8605Smrg *
119848b8605Smrg * No fog.  No depth testing.
120848b8605Smrg */
121848b8605Smrg#define NAME simple_textured_triangle
122848b8605Smrg#define INTERP_INT_TEX 1
123848b8605Smrg#define S_SCALE twidth
124848b8605Smrg#define T_SCALE theight
125848b8605Smrg
126848b8605Smrg#define SETUP_CODE							\
127848b8605Smrg   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];	\
128848b8605Smrg   const struct gl_texture_object *obj = 				\
129848b8605Smrg      ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX];		\
130848b8605Smrg   const struct gl_texture_image *texImg =				\
131b8e80941Smrg      _mesa_base_tex_image(obj);					\
132848b8605Smrg   const struct swrast_texture_image *swImg =				\
133848b8605Smrg      swrast_texture_image_const(texImg);				\
134848b8605Smrg   const GLfloat twidth = (GLfloat) texImg->Width;			\
135848b8605Smrg   const GLfloat theight = (GLfloat) texImg->Height;			\
136848b8605Smrg   const GLint twidth_log2 = texImg->WidthLog2;				\
137848b8605Smrg   const GLubyte *texture = (const GLubyte *) swImg->ImageSlices[0];	\
138848b8605Smrg   const GLint smask = texImg->Width - 1;				\
139848b8605Smrg   const GLint tmask = texImg->Height - 1;				\
140b8e80941Smrg   assert(texImg->TexFormat == MESA_FORMAT_BGR_UNORM8);			\
141848b8605Smrg   if (!rb || !texture) {						\
142848b8605Smrg      return;								\
143848b8605Smrg   }
144848b8605Smrg
145848b8605Smrg#define RENDER_SPAN( span )						\
146848b8605Smrg   GLuint i;								\
147848b8605Smrg   GLubyte (*rgba)[4] = swrast->SpanArrays->rgba8;			\
148848b8605Smrg   span.intTex[0] -= FIXED_HALF; /* off-by-one error? */		\
149848b8605Smrg   span.intTex[1] -= FIXED_HALF;					\
150848b8605Smrg   for (i = 0; i < span.end; i++) {					\
151848b8605Smrg      GLint s = FixedToInt(span.intTex[0]) & smask;			\
152848b8605Smrg      GLint t = FixedToInt(span.intTex[1]) & tmask;			\
153848b8605Smrg      GLint pos = (t << twidth_log2) + s;				\
154848b8605Smrg      pos = pos + pos + pos;  /* multiply by 3 */			\
155848b8605Smrg      rgba[i][RCOMP] = texture[pos+2];					\
156848b8605Smrg      rgba[i][GCOMP] = texture[pos+1];					\
157848b8605Smrg      rgba[i][BCOMP] = texture[pos+0];					\
158848b8605Smrg      rgba[i][ACOMP] = 0xff;                                            \
159848b8605Smrg      span.intTex[0] += span.intTexStep[0];				\
160848b8605Smrg      span.intTex[1] += span.intTexStep[1];				\
161848b8605Smrg   }									\
162848b8605Smrg   _swrast_put_row(ctx, rb, GL_UNSIGNED_BYTE, span.end,                 \
163848b8605Smrg                   span.x, span.y, rgba, NULL);
164848b8605Smrg
165848b8605Smrg#include "s_tritemp.h"
166848b8605Smrg
167848b8605Smrg
168848b8605Smrg
169848b8605Smrg/*
170848b8605Smrg * Render an RGB, GL_DECAL, textured triangle.
171848b8605Smrg * Interpolate S,T, GL_LESS depth test, w/out mipmapping or
172848b8605Smrg * perspective correction.
173848b8605Smrg * Depth buffer bits must be <= sizeof(DEFAULT_SOFTWARE_DEPTH_TYPE)
174848b8605Smrg *
175848b8605Smrg * No fog.
176848b8605Smrg */
177848b8605Smrg#define NAME simple_z_textured_triangle
178848b8605Smrg#define INTERP_Z 1
179848b8605Smrg#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
180848b8605Smrg#define INTERP_INT_TEX 1
181848b8605Smrg#define S_SCALE twidth
182848b8605Smrg#define T_SCALE theight
183848b8605Smrg
184848b8605Smrg#define SETUP_CODE							\
185848b8605Smrg   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];	\
186848b8605Smrg   const struct gl_texture_object *obj = 				\
187848b8605Smrg      ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX];		\
188848b8605Smrg   const struct gl_texture_image *texImg = 				\
189b8e80941Smrg      _mesa_base_tex_image(obj);					\
190848b8605Smrg   const struct swrast_texture_image *swImg =				\
191848b8605Smrg      swrast_texture_image_const(texImg);				\
192848b8605Smrg   const GLfloat twidth = (GLfloat) texImg->Width;			\
193848b8605Smrg   const GLfloat theight = (GLfloat) texImg->Height;			\
194848b8605Smrg   const GLint twidth_log2 = texImg->WidthLog2;				\
195848b8605Smrg   const GLubyte *texture = (const GLubyte *) swImg->ImageSlices[0];	\
196848b8605Smrg   const GLint smask = texImg->Width - 1;				\
197848b8605Smrg   const GLint tmask = texImg->Height - 1;				\
198b8e80941Smrg   assert(texImg->TexFormat == MESA_FORMAT_BGR_UNORM8);			\
199848b8605Smrg   if (!rb || !texture) {						\
200848b8605Smrg      return;								\
201848b8605Smrg   }
202848b8605Smrg
203848b8605Smrg#define RENDER_SPAN( span )						\
204848b8605Smrg   GLuint i;				    				\
205848b8605Smrg   GLubyte (*rgba)[4] = swrast->SpanArrays->rgba8;			\
206848b8605Smrg   GLubyte *mask = swrast->SpanArrays->mask;                            \
207848b8605Smrg   span.intTex[0] -= FIXED_HALF; /* off-by-one error? */		\
208848b8605Smrg   span.intTex[1] -= FIXED_HALF;					\
209848b8605Smrg   for (i = 0; i < span.end; i++) {					\
210848b8605Smrg      const GLuint z = FixedToDepth(span.z);				\
211848b8605Smrg      if (z < zRow[i]) {						\
212848b8605Smrg         GLint s = FixedToInt(span.intTex[0]) & smask;			\
213848b8605Smrg         GLint t = FixedToInt(span.intTex[1]) & tmask;			\
214848b8605Smrg         GLint pos = (t << twidth_log2) + s;				\
215848b8605Smrg         pos = pos + pos + pos;  /* multiply by 3 */			\
216848b8605Smrg         rgba[i][RCOMP] = texture[pos+2];				\
217848b8605Smrg         rgba[i][GCOMP] = texture[pos+1];				\
218848b8605Smrg         rgba[i][BCOMP] = texture[pos+0];				\
219848b8605Smrg         rgba[i][ACOMP] = 0xff;          				\
220848b8605Smrg         zRow[i] = z;							\
221848b8605Smrg         mask[i] = 1;							\
222848b8605Smrg      }									\
223848b8605Smrg      else {								\
224848b8605Smrg         mask[i] = 0;							\
225848b8605Smrg      }									\
226848b8605Smrg      span.intTex[0] += span.intTexStep[0];				\
227848b8605Smrg      span.intTex[1] += span.intTexStep[1];				\
228848b8605Smrg      span.z += span.zStep;						\
229848b8605Smrg   }									\
230848b8605Smrg   _swrast_put_row(ctx, rb, GL_UNSIGNED_BYTE,                           \
231848b8605Smrg                   span.end, span.x, span.y, rgba, mask);
232848b8605Smrg
233848b8605Smrg#include "s_tritemp.h"
234848b8605Smrg
235848b8605Smrg
236848b8605Smrg#if CHAN_TYPE != GL_FLOAT
237848b8605Smrg
238848b8605Smrgstruct affine_info
239848b8605Smrg{
240848b8605Smrg   GLenum filter;
241848b8605Smrg   GLenum format;
242848b8605Smrg   GLenum envmode;
243848b8605Smrg   GLint smask, tmask;
244848b8605Smrg   GLint twidth_log2;
245848b8605Smrg   const GLchan *texture;
246848b8605Smrg   GLfixed er, eg, eb, ea;
247848b8605Smrg   GLint tbytesline, tsize;
248848b8605Smrg};
249848b8605Smrg
250848b8605Smrg
251848b8605Smrgstatic inline GLint
252848b8605Smrgilerp(GLint t, GLint a, GLint b)
253848b8605Smrg{
254848b8605Smrg   return a + ((t * (b - a)) >> FIXED_SHIFT);
255848b8605Smrg}
256848b8605Smrg
257848b8605Smrgstatic inline GLint
258848b8605Smrgilerp_2d(GLint ia, GLint ib, GLint v00, GLint v10, GLint v01, GLint v11)
259848b8605Smrg{
260848b8605Smrg   const GLint temp0 = ilerp(ia, v00, v10);
261848b8605Smrg   const GLint temp1 = ilerp(ia, v01, v11);
262848b8605Smrg   return ilerp(ib, temp0, temp1);
263848b8605Smrg}
264848b8605Smrg
265848b8605Smrg
266848b8605Smrg/* This function can handle GL_NEAREST or GL_LINEAR sampling of 2D RGB or RGBA
267848b8605Smrg * textures with GL_REPLACE, GL_MODULATE, GL_BLEND, GL_DECAL or GL_ADD
268848b8605Smrg * texture env modes.
269848b8605Smrg */
270848b8605Smrgstatic inline void
271848b8605Smrgaffine_span(struct gl_context *ctx, SWspan *span,
272848b8605Smrg            struct affine_info *info)
273848b8605Smrg{
274848b8605Smrg   GLchan sample[4];  /* the filtered texture sample */
275848b8605Smrg   const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits;
276848b8605Smrg
277848b8605Smrg   /* Instead of defining a function for each mode, a test is done
278848b8605Smrg    * between the outer and inner loops. This is to reduce code size
279848b8605Smrg    * and complexity. Observe that an optimizing compiler kills
280848b8605Smrg    * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
281848b8605Smrg    */
282848b8605Smrg
283848b8605Smrg#define NEAREST_RGB		\
284848b8605Smrg   sample[RCOMP] = tex00[2];	\
285848b8605Smrg   sample[GCOMP] = tex00[1];	\
286848b8605Smrg   sample[BCOMP] = tex00[0];	\
287848b8605Smrg   sample[ACOMP] = CHAN_MAX;
288848b8605Smrg
289848b8605Smrg#define LINEAR_RGB							\
290848b8605Smrg   sample[RCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\
291848b8605Smrg   sample[GCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\
292848b8605Smrg   sample[BCOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0]);\
293848b8605Smrg   sample[ACOMP] = CHAN_MAX;
294848b8605Smrg
295848b8605Smrg#define NEAREST_RGBA  \
296848b8605Smrg   sample[RCOMP] = tex00[3];	\
297848b8605Smrg   sample[GCOMP] = tex00[2];	\
298848b8605Smrg   sample[BCOMP] = tex00[1];	\
299848b8605Smrg   sample[ACOMP] = tex00[0];
300848b8605Smrg
301848b8605Smrg#define LINEAR_RGBA							\
302848b8605Smrg   sample[RCOMP] = ilerp_2d(sf, tf, tex00[3], tex01[3], tex10[3], tex11[3]);\
303848b8605Smrg   sample[GCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\
304848b8605Smrg   sample[BCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\
305848b8605Smrg   sample[ACOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0])
306848b8605Smrg
307848b8605Smrg#define MODULATE							  \
308848b8605Smrg   dest[RCOMP] = span->red   * (sample[RCOMP] + 1u) >> (FIXED_SHIFT + 8); \
309848b8605Smrg   dest[GCOMP] = span->green * (sample[GCOMP] + 1u) >> (FIXED_SHIFT + 8); \
310848b8605Smrg   dest[BCOMP] = span->blue  * (sample[BCOMP] + 1u) >> (FIXED_SHIFT + 8); \
311848b8605Smrg   dest[ACOMP] = span->alpha * (sample[ACOMP] + 1u) >> (FIXED_SHIFT + 8)
312848b8605Smrg
313848b8605Smrg#define DECAL								\
314848b8605Smrg   dest[RCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->red +		\
315848b8605Smrg               ((sample[ACOMP] + 1) * sample[RCOMP] << FIXED_SHIFT))	\
316848b8605Smrg               >> (FIXED_SHIFT + 8);					\
317848b8605Smrg   dest[GCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->green +		\
318848b8605Smrg               ((sample[ACOMP] + 1) * sample[GCOMP] << FIXED_SHIFT))	\
319848b8605Smrg               >> (FIXED_SHIFT + 8);					\
320848b8605Smrg   dest[BCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->blue +		\
321848b8605Smrg               ((sample[ACOMP] + 1) * sample[BCOMP] << FIXED_SHIFT))	\
322848b8605Smrg               >> (FIXED_SHIFT + 8);					\
323848b8605Smrg   dest[ACOMP] = FixedToInt(span->alpha)
324848b8605Smrg
325848b8605Smrg#define BLEND								\
326848b8605Smrg   dest[RCOMP] = ((CHAN_MAX - sample[RCOMP]) * span->red		\
327848b8605Smrg               + (sample[RCOMP] + 1) * info->er) >> (FIXED_SHIFT + 8);	\
328848b8605Smrg   dest[GCOMP] = ((CHAN_MAX - sample[GCOMP]) * span->green		\
329848b8605Smrg               + (sample[GCOMP] + 1) * info->eg) >> (FIXED_SHIFT + 8);	\
330848b8605Smrg   dest[BCOMP] = ((CHAN_MAX - sample[BCOMP]) * span->blue		\
331848b8605Smrg               + (sample[BCOMP] + 1) * info->eb) >> (FIXED_SHIFT + 8);	\
332848b8605Smrg   dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8)
333848b8605Smrg
334848b8605Smrg#define REPLACE  COPY_CHAN4(dest, sample)
335848b8605Smrg
336848b8605Smrg#define ADD								\
337848b8605Smrg   {									\
338848b8605Smrg      GLint rSum = FixedToInt(span->red)   + (GLint) sample[RCOMP];	\
339848b8605Smrg      GLint gSum = FixedToInt(span->green) + (GLint) sample[GCOMP];	\
340848b8605Smrg      GLint bSum = FixedToInt(span->blue)  + (GLint) sample[BCOMP];	\
341848b8605Smrg      dest[RCOMP] = MIN2(rSum, CHAN_MAX);				\
342848b8605Smrg      dest[GCOMP] = MIN2(gSum, CHAN_MAX);				\
343848b8605Smrg      dest[BCOMP] = MIN2(bSum, CHAN_MAX);				\
344848b8605Smrg      dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8); \
345848b8605Smrg  }
346848b8605Smrg
347848b8605Smrg/* shortcuts */
348848b8605Smrg
349848b8605Smrg#define NEAREST_RGB_REPLACE		\
350848b8605Smrg   NEAREST_RGB;				\
351848b8605Smrg   dest[0] = sample[0];			\
352848b8605Smrg   dest[1] = sample[1];			\
353848b8605Smrg   dest[2] = sample[2];			\
354848b8605Smrg   dest[3] = FixedToInt(span->alpha);
355848b8605Smrg
356848b8605Smrg#define NEAREST_RGBA_REPLACE  \
357848b8605Smrg   dest[RCOMP] = tex00[3]; \
358848b8605Smrg   dest[GCOMP] = tex00[2]; \
359848b8605Smrg   dest[BCOMP] = tex00[1]; \
360848b8605Smrg   dest[ACOMP] = tex00[0]
361848b8605Smrg
362848b8605Smrg#define SPAN_NEAREST(DO_TEX, COMPS)					\
363848b8605Smrg	for (i = 0; i < span->end; i++) {				\
364848b8605Smrg           /* Isn't it necessary to use FixedFloor below?? */		\
365848b8605Smrg           GLint s = FixedToInt(span->intTex[0]) & info->smask;		\
366848b8605Smrg           GLint t = FixedToInt(span->intTex[1]) & info->tmask;		\
367848b8605Smrg           GLint pos = (t << info->twidth_log2) + s;			\
368848b8605Smrg           const GLchan *tex00 = info->texture + COMPS * pos;		\
369848b8605Smrg           DO_TEX;							\
370848b8605Smrg           span->red += span->redStep;					\
371848b8605Smrg	   span->green += span->greenStep;				\
372848b8605Smrg           span->blue += span->blueStep;				\
373848b8605Smrg	   span->alpha += span->alphaStep;				\
374848b8605Smrg	   span->intTex[0] += span->intTexStep[0];			\
375848b8605Smrg	   span->intTex[1] += span->intTexStep[1];			\
376848b8605Smrg           dest += 4;							\
377848b8605Smrg	}
378848b8605Smrg
379848b8605Smrg#define SPAN_LINEAR(DO_TEX, COMPS)					\
380848b8605Smrg	for (i = 0; i < span->end; i++) {				\
381848b8605Smrg           /* Isn't it necessary to use FixedFloor below?? */		\
382848b8605Smrg           const GLint s = FixedToInt(span->intTex[0]) & info->smask;	\
383848b8605Smrg           const GLint t = FixedToInt(span->intTex[1]) & info->tmask;	\
384848b8605Smrg           const GLfixed sf = span->intTex[0] & FIXED_FRAC_MASK;	\
385848b8605Smrg           const GLfixed tf = span->intTex[1] & FIXED_FRAC_MASK;	\
386848b8605Smrg           const GLint pos = (t << info->twidth_log2) + s;		\
387848b8605Smrg           const GLchan *tex00 = info->texture + COMPS * pos;		\
388848b8605Smrg           const GLchan *tex10 = tex00 + info->tbytesline;		\
389848b8605Smrg           const GLchan *tex01 = tex00 + COMPS;				\
390848b8605Smrg           const GLchan *tex11 = tex10 + COMPS;				\
391848b8605Smrg           if (t == info->tmask) {					\
392848b8605Smrg              tex10 -= info->tsize;					\
393848b8605Smrg              tex11 -= info->tsize;					\
394848b8605Smrg           }								\
395848b8605Smrg           if (s == info->smask) {					\
396848b8605Smrg              tex01 -= info->tbytesline;				\
397848b8605Smrg              tex11 -= info->tbytesline;				\
398848b8605Smrg           }								\
399848b8605Smrg           DO_TEX;							\
400848b8605Smrg           span->red += span->redStep;					\
401848b8605Smrg	   span->green += span->greenStep;				\
402848b8605Smrg           span->blue += span->blueStep;				\
403848b8605Smrg	   span->alpha += span->alphaStep;				\
404848b8605Smrg	   span->intTex[0] += span->intTexStep[0];			\
405848b8605Smrg	   span->intTex[1] += span->intTexStep[1];			\
406848b8605Smrg           dest += 4;							\
407848b8605Smrg	}
408848b8605Smrg
409848b8605Smrg
410848b8605Smrg   GLuint i;
411848b8605Smrg   GLchan *dest = span->array->rgba[0];
412848b8605Smrg
413848b8605Smrg   /* Disable tex units so they're not re-applied in swrast_write_rgba_span */
414848b8605Smrg   ctx->Texture._EnabledCoordUnits = 0x0;
415848b8605Smrg
416848b8605Smrg   span->intTex[0] -= FIXED_HALF;
417848b8605Smrg   span->intTex[1] -= FIXED_HALF;
418848b8605Smrg   switch (info->filter) {
419848b8605Smrg   case GL_NEAREST:
420848b8605Smrg      switch (info->format) {
421848b8605Smrg      case MESA_FORMAT_BGR_UNORM8:
422848b8605Smrg         switch (info->envmode) {
423848b8605Smrg         case GL_MODULATE:
424848b8605Smrg            SPAN_NEAREST(NEAREST_RGB;MODULATE,3);
425848b8605Smrg            break;
426848b8605Smrg         case GL_DECAL:
427848b8605Smrg         case GL_REPLACE:
428848b8605Smrg            SPAN_NEAREST(NEAREST_RGB_REPLACE,3);
429848b8605Smrg            break;
430848b8605Smrg         case GL_BLEND:
431848b8605Smrg            SPAN_NEAREST(NEAREST_RGB;BLEND,3);
432848b8605Smrg            break;
433848b8605Smrg         case GL_ADD:
434848b8605Smrg            SPAN_NEAREST(NEAREST_RGB;ADD,3);
435848b8605Smrg            break;
436848b8605Smrg         default:
437848b8605Smrg            _mesa_problem(ctx, "bad tex env mode in SPAN_LINEAR");
438848b8605Smrg            return;
439848b8605Smrg         }
440848b8605Smrg         break;
441848b8605Smrg      case MESA_FORMAT_A8B8G8R8_UNORM:
442848b8605Smrg         switch(info->envmode) {
443848b8605Smrg         case GL_MODULATE:
444848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA;MODULATE,4);
445848b8605Smrg            break;
446848b8605Smrg         case GL_DECAL:
447848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA;DECAL,4);
448848b8605Smrg            break;
449848b8605Smrg         case GL_BLEND:
450848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA;BLEND,4);
451848b8605Smrg            break;
452848b8605Smrg         case GL_ADD:
453848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA;ADD,4);
454848b8605Smrg            break;
455848b8605Smrg         case GL_REPLACE:
456848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA_REPLACE,4);
457848b8605Smrg            break;
458848b8605Smrg         default:
459848b8605Smrg            _mesa_problem(ctx, "bad tex env mode (2) in SPAN_LINEAR");
460848b8605Smrg            return;
461848b8605Smrg         }
462848b8605Smrg         break;
463848b8605Smrg      }
464848b8605Smrg      break;
465848b8605Smrg
466848b8605Smrg   case GL_LINEAR:
467848b8605Smrg      span->intTex[0] -= FIXED_HALF;
468848b8605Smrg      span->intTex[1] -= FIXED_HALF;
469848b8605Smrg      switch (info->format) {
470848b8605Smrg      case MESA_FORMAT_BGR_UNORM8:
471848b8605Smrg         switch (info->envmode) {
472848b8605Smrg         case GL_MODULATE:
473848b8605Smrg            SPAN_LINEAR(LINEAR_RGB;MODULATE,3);
474848b8605Smrg            break;
475848b8605Smrg         case GL_DECAL:
476848b8605Smrg         case GL_REPLACE:
477848b8605Smrg            SPAN_LINEAR(LINEAR_RGB;REPLACE,3);
478848b8605Smrg            break;
479848b8605Smrg         case GL_BLEND:
480848b8605Smrg            SPAN_LINEAR(LINEAR_RGB;BLEND,3);
481848b8605Smrg            break;
482848b8605Smrg         case GL_ADD:
483848b8605Smrg            SPAN_LINEAR(LINEAR_RGB;ADD,3);
484848b8605Smrg            break;
485848b8605Smrg         default:
486848b8605Smrg            _mesa_problem(ctx, "bad tex env mode (3) in SPAN_LINEAR");
487848b8605Smrg            return;
488848b8605Smrg         }
489848b8605Smrg         break;
490848b8605Smrg      case MESA_FORMAT_A8B8G8R8_UNORM:
491848b8605Smrg         switch (info->envmode) {
492848b8605Smrg         case GL_MODULATE:
493848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;MODULATE,4);
494848b8605Smrg            break;
495848b8605Smrg         case GL_DECAL:
496848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;DECAL,4);
497848b8605Smrg            break;
498848b8605Smrg         case GL_BLEND:
499848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;BLEND,4);
500848b8605Smrg            break;
501848b8605Smrg         case GL_ADD:
502848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;ADD,4);
503848b8605Smrg            break;
504848b8605Smrg         case GL_REPLACE:
505848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;REPLACE,4);
506848b8605Smrg            break;
507848b8605Smrg         default:
508848b8605Smrg            _mesa_problem(ctx, "bad tex env mode (4) in SPAN_LINEAR");
509848b8605Smrg            return;
510848b8605Smrg         }
511848b8605Smrg         break;
512848b8605Smrg      }
513848b8605Smrg      break;
514848b8605Smrg   }
515848b8605Smrg   span->interpMask &= ~SPAN_RGBA;
516b8e80941Smrg   assert(span->arrayMask & SPAN_RGBA);
517848b8605Smrg
518848b8605Smrg   _swrast_write_rgba_span(ctx, span);
519848b8605Smrg
520848b8605Smrg   /* re-enable texture units */
521848b8605Smrg   ctx->Texture._EnabledCoordUnits = texEnableSave;
522848b8605Smrg
523848b8605Smrg#undef SPAN_NEAREST
524848b8605Smrg#undef SPAN_LINEAR
525848b8605Smrg}
526848b8605Smrg
527848b8605Smrg
528848b8605Smrg
529848b8605Smrg/*
530848b8605Smrg * Render an RGB/RGBA textured triangle without perspective correction.
531848b8605Smrg */
532848b8605Smrg#define NAME affine_textured_triangle
533848b8605Smrg#define INTERP_Z 1
534848b8605Smrg#define INTERP_RGB 1
535848b8605Smrg#define INTERP_ALPHA 1
536848b8605Smrg#define INTERP_INT_TEX 1
537848b8605Smrg#define S_SCALE twidth
538848b8605Smrg#define T_SCALE theight
539848b8605Smrg
540848b8605Smrg#define SETUP_CODE							\
541848b8605Smrg   struct affine_info info;						\
542b8e80941Smrg   struct gl_fixedfunc_texture_unit *unit = ctx->Texture.FixedFuncUnit+0; \
543848b8605Smrg   const struct gl_texture_object *obj = 				\
544848b8605Smrg      ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX];		\
545848b8605Smrg   const struct gl_texture_image *texImg = 				\
546b8e80941Smrg      _mesa_base_tex_image(obj);					\
547848b8605Smrg   const struct swrast_texture_image *swImg =				\
548848b8605Smrg      swrast_texture_image_const(texImg);				\
549848b8605Smrg   const GLfloat twidth = (GLfloat) texImg->Width;			\
550848b8605Smrg   const GLfloat theight = (GLfloat) texImg->Height;			\
551848b8605Smrg   info.texture = (const GLchan *) swImg->ImageSlices[0];		\
552848b8605Smrg   info.twidth_log2 = texImg->WidthLog2;				\
553848b8605Smrg   info.smask = texImg->Width - 1;					\
554848b8605Smrg   info.tmask = texImg->Height - 1;					\
555848b8605Smrg   info.format = texImg->TexFormat;					\
556848b8605Smrg   info.filter = obj->Sampler.MinFilter;				\
557848b8605Smrg   info.envmode = unit->EnvMode;					\
558848b8605Smrg   info.er = 0;					\
559848b8605Smrg   info.eg = 0;					\
560848b8605Smrg   info.eb = 0;					\
561848b8605Smrg   span.arrayMask |= SPAN_RGBA;						\
562848b8605Smrg									\
563848b8605Smrg   if (info.envmode == GL_BLEND) {					\
564848b8605Smrg      /* potential off-by-one error here? (1.0f -> 2048 -> 0) */	\
565848b8605Smrg      info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF);	\
566848b8605Smrg      info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF);	\
567848b8605Smrg      info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF);	\
568848b8605Smrg      info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF);	\
569848b8605Smrg   }									\
570848b8605Smrg   if (!info.texture) {							\
571848b8605Smrg      /* this shouldn't happen */					\
572848b8605Smrg      return;								\
573848b8605Smrg   }									\
574848b8605Smrg									\
575848b8605Smrg   switch (info.format) {						\
576848b8605Smrg   case MESA_FORMAT_BGR_UNORM8:						\
577848b8605Smrg      info.tbytesline = texImg->Width * 3;				\
578848b8605Smrg      break;								\
579848b8605Smrg   case MESA_FORMAT_A8B8G8R8_UNORM:						\
580848b8605Smrg      info.tbytesline = texImg->Width * 4;				\
581848b8605Smrg      break;								\
582848b8605Smrg   default:								\
583848b8605Smrg      _mesa_problem(NULL, "Bad texture format in affine_texture_triangle");\
584848b8605Smrg      return;								\
585848b8605Smrg   }									\
586848b8605Smrg   info.tsize = texImg->Height * info.tbytesline;
587848b8605Smrg
588848b8605Smrg#define RENDER_SPAN( span )   affine_span(ctx, &span, &info);
589848b8605Smrg
590848b8605Smrg#include "s_tritemp.h"
591848b8605Smrg
592848b8605Smrg
593848b8605Smrg
594848b8605Smrgstruct persp_info
595848b8605Smrg{
596848b8605Smrg   GLenum filter;
597848b8605Smrg   GLenum format;
598848b8605Smrg   GLenum envmode;
599848b8605Smrg   GLint smask, tmask;
600848b8605Smrg   GLint twidth_log2;
601848b8605Smrg   const GLchan *texture;
602848b8605Smrg   GLfixed er, eg, eb, ea;   /* texture env color */
603848b8605Smrg   GLint tbytesline, tsize;
604848b8605Smrg};
605848b8605Smrg
606848b8605Smrg
607848b8605Smrgstatic inline void
608848b8605Smrgfast_persp_span(struct gl_context *ctx, SWspan *span,
609848b8605Smrg		struct persp_info *info)
610848b8605Smrg{
611848b8605Smrg   GLchan sample[4];  /* the filtered texture sample */
612848b8605Smrg
613848b8605Smrg  /* Instead of defining a function for each mode, a test is done
614848b8605Smrg   * between the outer and inner loops. This is to reduce code size
615848b8605Smrg   * and complexity. Observe that an optimizing compiler kills
616848b8605Smrg   * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
617848b8605Smrg   */
618848b8605Smrg#define SPAN_NEAREST(DO_TEX,COMP)					\
619848b8605Smrg	for (i = 0; i < span->end; i++) {				\
620848b8605Smrg           GLdouble invQ = tex_coord[2] ?				\
621848b8605Smrg                                 (1.0 / tex_coord[2]) : 1.0;            \
622848b8605Smrg           GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ);		\
623848b8605Smrg           GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ);		\
624848b8605Smrg           GLint s = IFLOOR(s_tmp) & info->smask;	        	\
625848b8605Smrg           GLint t = IFLOOR(t_tmp) & info->tmask;	        	\
626848b8605Smrg           GLint pos = (t << info->twidth_log2) + s;			\
627848b8605Smrg           const GLchan *tex00 = info->texture + COMP * pos;		\
628848b8605Smrg           DO_TEX;							\
629848b8605Smrg           span->red += span->redStep;					\
630848b8605Smrg	   span->green += span->greenStep;				\
631848b8605Smrg           span->blue += span->blueStep;				\
632848b8605Smrg	   span->alpha += span->alphaStep;				\
633848b8605Smrg	   tex_coord[0] += tex_step[0];					\
634848b8605Smrg	   tex_coord[1] += tex_step[1];					\
635848b8605Smrg	   tex_coord[2] += tex_step[2];					\
636848b8605Smrg           dest += 4;							\
637848b8605Smrg	}
638848b8605Smrg
639848b8605Smrg#define SPAN_LINEAR(DO_TEX,COMP)					\
640848b8605Smrg	for (i = 0; i < span->end; i++) {				\
641848b8605Smrg           GLdouble invQ = tex_coord[2] ?				\
642848b8605Smrg                                 (1.0 / tex_coord[2]) : 1.0;            \
643848b8605Smrg           const GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ);	\
644848b8605Smrg           const GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ);	\
645848b8605Smrg           const GLfixed s_fix = FloatToFixed(s_tmp) - FIXED_HALF;	\
646848b8605Smrg           const GLfixed t_fix = FloatToFixed(t_tmp) - FIXED_HALF;      \
647848b8605Smrg           const GLint s = FixedToInt(FixedFloor(s_fix)) & info->smask;	\
648848b8605Smrg           const GLint t = FixedToInt(FixedFloor(t_fix)) & info->tmask;	\
649848b8605Smrg           const GLfixed sf = s_fix & FIXED_FRAC_MASK;			\
650848b8605Smrg           const GLfixed tf = t_fix & FIXED_FRAC_MASK;			\
651848b8605Smrg           const GLint pos = (t << info->twidth_log2) + s;		\
652848b8605Smrg           const GLchan *tex00 = info->texture + COMP * pos;		\
653848b8605Smrg           const GLchan *tex10 = tex00 + info->tbytesline;		\
654848b8605Smrg           const GLchan *tex01 = tex00 + COMP;				\
655848b8605Smrg           const GLchan *tex11 = tex10 + COMP;				\
656848b8605Smrg           if (t == info->tmask) {					\
657848b8605Smrg              tex10 -= info->tsize;					\
658848b8605Smrg              tex11 -= info->tsize;					\
659848b8605Smrg           }								\
660848b8605Smrg           if (s == info->smask) {					\
661848b8605Smrg              tex01 -= info->tbytesline;				\
662848b8605Smrg              tex11 -= info->tbytesline;				\
663848b8605Smrg           }								\
664848b8605Smrg           DO_TEX;							\
665848b8605Smrg           span->red   += span->redStep;				\
666848b8605Smrg	   span->green += span->greenStep;				\
667848b8605Smrg           span->blue  += span->blueStep;				\
668848b8605Smrg	   span->alpha += span->alphaStep;				\
669848b8605Smrg	   tex_coord[0] += tex_step[0];					\
670848b8605Smrg	   tex_coord[1] += tex_step[1];					\
671848b8605Smrg	   tex_coord[2] += tex_step[2];					\
672848b8605Smrg           dest += 4;							\
673848b8605Smrg	}
674848b8605Smrg
675848b8605Smrg   GLuint i;
676848b8605Smrg   GLfloat tex_coord[3], tex_step[3];
677848b8605Smrg   GLchan *dest = span->array->rgba[0];
678848b8605Smrg
679848b8605Smrg   const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits;
680848b8605Smrg   ctx->Texture._EnabledCoordUnits = 0;
681848b8605Smrg
682848b8605Smrg   tex_coord[0] = span->attrStart[VARYING_SLOT_TEX0][0]  * (info->smask + 1);
683848b8605Smrg   tex_step[0] = span->attrStepX[VARYING_SLOT_TEX0][0] * (info->smask + 1);
684848b8605Smrg   tex_coord[1] = span->attrStart[VARYING_SLOT_TEX0][1] * (info->tmask + 1);
685848b8605Smrg   tex_step[1] = span->attrStepX[VARYING_SLOT_TEX0][1] * (info->tmask + 1);
686848b8605Smrg   /* span->attrStart[VARYING_SLOT_TEX0][2] only if 3D-texturing, here only 2D */
687848b8605Smrg   tex_coord[2] = span->attrStart[VARYING_SLOT_TEX0][3];
688848b8605Smrg   tex_step[2] = span->attrStepX[VARYING_SLOT_TEX0][3];
689848b8605Smrg
690848b8605Smrg   switch (info->filter) {
691848b8605Smrg   case GL_NEAREST:
692848b8605Smrg      switch (info->format) {
693848b8605Smrg      case MESA_FORMAT_BGR_UNORM8:
694848b8605Smrg         switch (info->envmode) {
695848b8605Smrg         case GL_MODULATE:
696848b8605Smrg            SPAN_NEAREST(NEAREST_RGB;MODULATE,3);
697848b8605Smrg            break;
698848b8605Smrg         case GL_DECAL:
699848b8605Smrg         case GL_REPLACE:
700848b8605Smrg            SPAN_NEAREST(NEAREST_RGB_REPLACE,3);
701848b8605Smrg            break;
702848b8605Smrg         case GL_BLEND:
703848b8605Smrg            SPAN_NEAREST(NEAREST_RGB;BLEND,3);
704848b8605Smrg            break;
705848b8605Smrg         case GL_ADD:
706848b8605Smrg            SPAN_NEAREST(NEAREST_RGB;ADD,3);
707848b8605Smrg            break;
708848b8605Smrg         default:
709848b8605Smrg            _mesa_problem(ctx, "bad tex env mode (5) in SPAN_LINEAR");
710848b8605Smrg            return;
711848b8605Smrg         }
712848b8605Smrg         break;
713848b8605Smrg      case MESA_FORMAT_A8B8G8R8_UNORM:
714848b8605Smrg         switch(info->envmode) {
715848b8605Smrg         case GL_MODULATE:
716848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA;MODULATE,4);
717848b8605Smrg            break;
718848b8605Smrg         case GL_DECAL:
719848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA;DECAL,4);
720848b8605Smrg            break;
721848b8605Smrg         case GL_BLEND:
722848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA;BLEND,4);
723848b8605Smrg            break;
724848b8605Smrg         case GL_ADD:
725848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA;ADD,4);
726848b8605Smrg            break;
727848b8605Smrg         case GL_REPLACE:
728848b8605Smrg            SPAN_NEAREST(NEAREST_RGBA_REPLACE,4);
729848b8605Smrg            break;
730848b8605Smrg         default:
731848b8605Smrg            _mesa_problem(ctx, "bad tex env mode (6) in SPAN_LINEAR");
732848b8605Smrg            return;
733848b8605Smrg         }
734848b8605Smrg         break;
735848b8605Smrg      }
736848b8605Smrg      break;
737848b8605Smrg
738848b8605Smrg   case GL_LINEAR:
739848b8605Smrg      switch (info->format) {
740848b8605Smrg      case MESA_FORMAT_BGR_UNORM8:
741848b8605Smrg         switch (info->envmode) {
742848b8605Smrg         case GL_MODULATE:
743848b8605Smrg            SPAN_LINEAR(LINEAR_RGB;MODULATE,3);
744848b8605Smrg            break;
745848b8605Smrg         case GL_DECAL:
746848b8605Smrg         case GL_REPLACE:
747848b8605Smrg            SPAN_LINEAR(LINEAR_RGB;REPLACE,3);
748848b8605Smrg            break;
749848b8605Smrg         case GL_BLEND:
750848b8605Smrg            SPAN_LINEAR(LINEAR_RGB;BLEND,3);
751848b8605Smrg            break;
752848b8605Smrg         case GL_ADD:
753848b8605Smrg            SPAN_LINEAR(LINEAR_RGB;ADD,3);
754848b8605Smrg            break;
755848b8605Smrg         default:
756848b8605Smrg            _mesa_problem(ctx, "bad tex env mode (7) in SPAN_LINEAR");
757848b8605Smrg            return;
758848b8605Smrg         }
759848b8605Smrg         break;
760848b8605Smrg      case MESA_FORMAT_A8B8G8R8_UNORM:
761848b8605Smrg         switch (info->envmode) {
762848b8605Smrg         case GL_MODULATE:
763848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;MODULATE,4);
764848b8605Smrg            break;
765848b8605Smrg         case GL_DECAL:
766848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;DECAL,4);
767848b8605Smrg            break;
768848b8605Smrg         case GL_BLEND:
769848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;BLEND,4);
770848b8605Smrg            break;
771848b8605Smrg         case GL_ADD:
772848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;ADD,4);
773848b8605Smrg            break;
774848b8605Smrg         case GL_REPLACE:
775848b8605Smrg            SPAN_LINEAR(LINEAR_RGBA;REPLACE,4);
776848b8605Smrg            break;
777848b8605Smrg         default:
778848b8605Smrg            _mesa_problem(ctx, "bad tex env mode (8) in SPAN_LINEAR");
779848b8605Smrg            return;
780848b8605Smrg         }
781848b8605Smrg         break;
782848b8605Smrg      }
783848b8605Smrg      break;
784848b8605Smrg   }
785848b8605Smrg
786b8e80941Smrg   assert(span->arrayMask & SPAN_RGBA);
787848b8605Smrg   _swrast_write_rgba_span(ctx, span);
788848b8605Smrg
789848b8605Smrg#undef SPAN_NEAREST
790848b8605Smrg#undef SPAN_LINEAR
791848b8605Smrg
792848b8605Smrg   /* restore state */
793848b8605Smrg   ctx->Texture._EnabledCoordUnits = texEnableSave;
794848b8605Smrg}
795848b8605Smrg
796848b8605Smrg
797848b8605Smrg/*
798848b8605Smrg * Render an perspective corrected RGB/RGBA textured triangle.
799848b8605Smrg * The Q (aka V in Mesa) coordinate must be zero such that the divide
800848b8605Smrg * by interpolated Q/W comes out right.
801848b8605Smrg *
802848b8605Smrg */
803848b8605Smrg#define NAME persp_textured_triangle
804848b8605Smrg#define INTERP_Z 1
805848b8605Smrg#define INTERP_RGB 1
806848b8605Smrg#define INTERP_ALPHA 1
807848b8605Smrg#define INTERP_ATTRIBS 1
808848b8605Smrg
809848b8605Smrg#define SETUP_CODE							\
810848b8605Smrg   struct persp_info info;						\
811b8e80941Smrg   const struct gl_fixedfunc_texture_unit *unit = ctx->Texture.FixedFuncUnit+0; \
812848b8605Smrg   const struct gl_texture_object *obj = 				\
813848b8605Smrg      ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX];		\
814848b8605Smrg   const struct gl_texture_image *texImg = 				\
815b8e80941Smrg      _mesa_base_tex_image(obj);					\
816848b8605Smrg   const struct swrast_texture_image *swImg =				\
817848b8605Smrg      swrast_texture_image_const(texImg);				\
818848b8605Smrg   info.texture = (const GLchan *) swImg->ImageSlices[0];		\
819848b8605Smrg   info.twidth_log2 = texImg->WidthLog2;				\
820848b8605Smrg   info.smask = texImg->Width - 1;					\
821848b8605Smrg   info.tmask = texImg->Height - 1;					\
822848b8605Smrg   info.format = texImg->TexFormat;					\
823848b8605Smrg   info.filter = obj->Sampler.MinFilter;				\
824848b8605Smrg   info.envmode = unit->EnvMode;					\
825848b8605Smrg   info.er = 0;					\
826848b8605Smrg   info.eg = 0;					\
827848b8605Smrg   info.eb = 0;					\
828848b8605Smrg									\
829848b8605Smrg   if (info.envmode == GL_BLEND) {					\
830848b8605Smrg      /* potential off-by-one error here? (1.0f -> 2048 -> 0) */	\
831848b8605Smrg      info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF);	\
832848b8605Smrg      info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF);	\
833848b8605Smrg      info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF);	\
834848b8605Smrg      info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF);	\
835848b8605Smrg   }									\
836848b8605Smrg   if (!info.texture) {							\
837848b8605Smrg      /* this shouldn't happen */					\
838848b8605Smrg      return;								\
839848b8605Smrg   }									\
840848b8605Smrg									\
841848b8605Smrg   switch (info.format) {						\
842848b8605Smrg   case MESA_FORMAT_BGR_UNORM8:						\
843848b8605Smrg      info.tbytesline = texImg->Width * 3;				\
844848b8605Smrg      break;								\
845848b8605Smrg   case MESA_FORMAT_A8B8G8R8_UNORM:						\
846848b8605Smrg      info.tbytesline = texImg->Width * 4;				\
847848b8605Smrg      break;								\
848848b8605Smrg   default:								\
849848b8605Smrg      _mesa_problem(NULL, "Bad texture format in persp_textured_triangle");\
850848b8605Smrg      return;								\
851848b8605Smrg   }									\
852848b8605Smrg   info.tsize = texImg->Height * info.tbytesline;
853848b8605Smrg
854848b8605Smrg#define RENDER_SPAN( span )			\
855848b8605Smrg   span.interpMask &= ~SPAN_RGBA;		\
856848b8605Smrg   span.arrayMask |= SPAN_RGBA;			\
857848b8605Smrg   fast_persp_span(ctx, &span, &info);
858848b8605Smrg
859848b8605Smrg#include "s_tritemp.h"
860848b8605Smrg
861848b8605Smrg#endif /*CHAN_TYPE != GL_FLOAT*/
862848b8605Smrg
863848b8605Smrg
864848b8605Smrg
865848b8605Smrg/*
866848b8605Smrg * Render an RGBA triangle with arbitrary attributes.
867848b8605Smrg */
868848b8605Smrg#define NAME general_triangle
869848b8605Smrg#define INTERP_Z 1
870848b8605Smrg#define INTERP_RGB 1
871848b8605Smrg#define INTERP_ALPHA 1
872848b8605Smrg#define INTERP_ATTRIBS 1
873848b8605Smrg#define RENDER_SPAN( span )   _swrast_write_rgba_span(ctx, &span);
874848b8605Smrg#include "s_tritemp.h"
875848b8605Smrg
876848b8605Smrg
877848b8605Smrg
878848b8605Smrg
879848b8605Smrg/*
880848b8605Smrg * Special tri function for occlusion testing
881848b8605Smrg */
882848b8605Smrg#define NAME occlusion_zless_16_triangle
883848b8605Smrg#define INTERP_Z 1
884848b8605Smrg#define SETUP_CODE							\
885848b8605Smrg   struct gl_renderbuffer *rb =                                         \
886848b8605Smrg      ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;           \
887848b8605Smrg   struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;	\
888b8e80941Smrg   assert(ctx->Depth.Test);						\
889b8e80941Smrg   assert(!ctx->Depth.Mask);						\
890b8e80941Smrg   assert(ctx->Depth.Func == GL_LESS);					\
891848b8605Smrg   assert(rb->Format == MESA_FORMAT_Z_UNORM16);                               \
892848b8605Smrg   if (!q) {								\
893848b8605Smrg      return;								\
894848b8605Smrg   }
895848b8605Smrg#define RENDER_SPAN( span )						\
896848b8605Smrg   {                                                                    \
897848b8605Smrg      GLuint i;								\
898848b8605Smrg      const GLushort *zRow = (const GLushort *)				\
899848b8605Smrg         _swrast_pixel_address(rb, span.x, span.y);                     \
900848b8605Smrg      for (i = 0; i < span.end; i++) {					\
901848b8605Smrg         GLuint z = FixedToDepth(span.z);				\
902848b8605Smrg         if (z < zRow[i]) {						\
903848b8605Smrg            q->Result++;						\
904848b8605Smrg         }								\
905848b8605Smrg         span.z += span.zStep;						\
906848b8605Smrg      }									\
907848b8605Smrg   }
908848b8605Smrg#include "s_tritemp.h"
909848b8605Smrg
910848b8605Smrg
911848b8605Smrg
912848b8605Smrgstatic void
913848b8605Smrgnodraw_triangle( struct gl_context *ctx,
914848b8605Smrg                 const SWvertex *v0,
915848b8605Smrg                 const SWvertex *v1,
916848b8605Smrg                 const SWvertex *v2 )
917848b8605Smrg{
918848b8605Smrg   (void) (ctx && v0 && v1 && v2);
919848b8605Smrg}
920848b8605Smrg
921848b8605Smrg
922848b8605Smrg/*
923848b8605Smrg * This is used when separate specular color is enabled, but not
924848b8605Smrg * texturing.  We add the specular color to the primary color,
925848b8605Smrg * draw the triangle, then restore the original primary color.
926848b8605Smrg * Inefficient, but seldom needed.
927848b8605Smrg */
928848b8605Smrgvoid
929848b8605Smrg_swrast_add_spec_terms_triangle(struct gl_context *ctx, const SWvertex *v0,
930848b8605Smrg                                const SWvertex *v1, const SWvertex *v2)
931848b8605Smrg{
932848b8605Smrg   SWvertex *ncv0 = (SWvertex *)v0; /* drop const qualifier */
933848b8605Smrg   SWvertex *ncv1 = (SWvertex *)v1;
934848b8605Smrg   SWvertex *ncv2 = (SWvertex *)v2;
935848b8605Smrg   GLfloat rSum, gSum, bSum;
936848b8605Smrg   GLchan cSave[3][4];
937848b8605Smrg
938848b8605Smrg   /* save original colors */
939848b8605Smrg   COPY_CHAN4( cSave[0], ncv0->color );
940848b8605Smrg   COPY_CHAN4( cSave[1], ncv1->color );
941848b8605Smrg   COPY_CHAN4( cSave[2], ncv2->color );
942848b8605Smrg   /* sum v0 */
943848b8605Smrg   rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[VARYING_SLOT_COL1][0];
944848b8605Smrg   gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[VARYING_SLOT_COL1][1];
945848b8605Smrg   bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[VARYING_SLOT_COL1][2];
946848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
947848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
948848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
949848b8605Smrg   /* sum v1 */
950848b8605Smrg   rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[VARYING_SLOT_COL1][0];
951848b8605Smrg   gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[VARYING_SLOT_COL1][1];
952848b8605Smrg   bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[VARYING_SLOT_COL1][2];
953848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum);
954848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum);
955848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum);
956848b8605Smrg   /* sum v2 */
957848b8605Smrg   rSum = CHAN_TO_FLOAT(ncv2->color[0]) + ncv2->attrib[VARYING_SLOT_COL1][0];
958848b8605Smrg   gSum = CHAN_TO_FLOAT(ncv2->color[1]) + ncv2->attrib[VARYING_SLOT_COL1][1];
959848b8605Smrg   bSum = CHAN_TO_FLOAT(ncv2->color[2]) + ncv2->attrib[VARYING_SLOT_COL1][2];
960848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[0], rSum);
961848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[1], gSum);
962848b8605Smrg   UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[2], bSum);
963848b8605Smrg   /* draw */
964848b8605Smrg   SWRAST_CONTEXT(ctx)->SpecTriangle( ctx, ncv0, ncv1, ncv2 );
965848b8605Smrg   /* restore original colors */
966848b8605Smrg   COPY_CHAN4( ncv0->color, cSave[0] );
967848b8605Smrg   COPY_CHAN4( ncv1->color, cSave[1] );
968848b8605Smrg   COPY_CHAN4( ncv2->color, cSave[2] );
969848b8605Smrg}
970848b8605Smrg
971848b8605Smrg
972848b8605Smrg
973848b8605Smrg#ifdef DEBUG
974848b8605Smrg
975848b8605Smrg/* record the current triangle function name */
976848b8605Smrgconst char *_mesa_triFuncName = NULL;
977848b8605Smrg
978848b8605Smrg#define USE(triFunc)				\
979848b8605Smrgdo {						\
980848b8605Smrg    _mesa_triFuncName = #triFunc;		\
981848b8605Smrg    /*printf("%s\n", _mesa_triFuncName);*/	\
982848b8605Smrg    swrast->Triangle = triFunc;			\
983848b8605Smrg} while (0)
984848b8605Smrg
985848b8605Smrg#else
986848b8605Smrg
987848b8605Smrg#define USE(triFunc)  swrast->Triangle = triFunc;
988848b8605Smrg
989848b8605Smrg#endif
990848b8605Smrg
991848b8605Smrg
992848b8605Smrg
993848b8605Smrg
994848b8605Smrg/*
995848b8605Smrg * Determine which triangle rendering function to use given the current
996848b8605Smrg * rendering context.
997848b8605Smrg *
998848b8605Smrg * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or
999848b8605Smrg * remove tests to this code.
1000848b8605Smrg */
1001848b8605Smrgvoid
1002848b8605Smrg_swrast_choose_triangle( struct gl_context *ctx )
1003848b8605Smrg{
1004848b8605Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
1005848b8605Smrg
1006848b8605Smrg   if (ctx->Polygon.CullFlag &&
1007848b8605Smrg       ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) {
1008848b8605Smrg      USE(nodraw_triangle);
1009848b8605Smrg      return;
1010848b8605Smrg   }
1011848b8605Smrg
1012848b8605Smrg   if (ctx->RenderMode==GL_RENDER) {
1013848b8605Smrg      struct gl_renderbuffer *depthRb =
1014848b8605Smrg         ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
1015848b8605Smrg
1016848b8605Smrg      if (ctx->Polygon.SmoothFlag) {
1017848b8605Smrg         _swrast_set_aa_triangle_function(ctx);
1018b8e80941Smrg         assert(swrast->Triangle);
1019848b8605Smrg         return;
1020848b8605Smrg      }
1021848b8605Smrg
1022848b8605Smrg      /* special case for occlusion testing */
1023848b8605Smrg      if (ctx->Query.CurrentOcclusionObject &&
1024848b8605Smrg          ctx->Depth.Test &&
1025848b8605Smrg          ctx->Depth.Mask == GL_FALSE &&
1026848b8605Smrg          ctx->Depth.Func == GL_LESS &&
1027b8e80941Smrg          !_mesa_stencil_is_enabled(ctx) &&
1028848b8605Smrg          depthRb &&
1029848b8605Smrg          depthRb->Format == MESA_FORMAT_Z_UNORM16) {
1030b8e80941Smrg         if (GET_COLORMASK_BIT(ctx->Color.ColorMask, 0, 0) == 0 &&
1031b8e80941Smrg	     GET_COLORMASK_BIT(ctx->Color.ColorMask, 0, 1) == 0 &&
1032b8e80941Smrg	     GET_COLORMASK_BIT(ctx->Color.ColorMask, 0, 2) == 0 &&
1033b8e80941Smrg	     GET_COLORMASK_BIT(ctx->Color.ColorMask, 0, 3) == 0) {
1034848b8605Smrg            USE(occlusion_zless_16_triangle);
1035848b8605Smrg            return;
1036848b8605Smrg         }
1037848b8605Smrg      }
1038848b8605Smrg
1039848b8605Smrg      /*
1040848b8605Smrg       * XXX should examine swrast->_ActiveAttribMask to determine what
1041848b8605Smrg       * needs to be interpolated.
1042848b8605Smrg       */
1043848b8605Smrg      if (ctx->Texture._EnabledCoordUnits ||
1044848b8605Smrg	  _swrast_use_fragment_program(ctx) ||
1045b8e80941Smrg          _mesa_ati_fragment_shader_enabled(ctx) ||
1046848b8605Smrg          _mesa_need_secondary_color(ctx) ||
1047848b8605Smrg          swrast->_FogEnabled) {
1048848b8605Smrg         /* Ugh, we do a _lot_ of tests to pick the best textured tri func */
1049848b8605Smrg         const struct gl_texture_object *texObj2D;
1050848b8605Smrg         const struct gl_sampler_object *samp;
1051848b8605Smrg         const struct gl_texture_image *texImg;
1052848b8605Smrg         const struct swrast_texture_image *swImg;
1053848b8605Smrg         GLenum minFilter, magFilter, envMode;
1054848b8605Smrg         mesa_format format;
1055848b8605Smrg         texObj2D = ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX];
1056848b8605Smrg         if (ctx->Texture.Unit[0].Sampler)
1057848b8605Smrg            samp = ctx->Texture.Unit[0].Sampler;
1058848b8605Smrg         else if (texObj2D)
1059848b8605Smrg            samp = &texObj2D->Sampler;
1060848b8605Smrg         else
1061848b8605Smrg            samp = NULL;
1062848b8605Smrg
1063b8e80941Smrg         texImg = texObj2D ? _mesa_base_tex_image(texObj2D) : NULL;
1064848b8605Smrg         swImg = swrast_texture_image_const(texImg);
1065848b8605Smrg
1066848b8605Smrg         format = texImg ? texImg->TexFormat : MESA_FORMAT_NONE;
1067848b8605Smrg         minFilter = texObj2D ? samp->MinFilter : GL_NONE;
1068848b8605Smrg         magFilter = texObj2D ? samp->MagFilter : GL_NONE;
1069b8e80941Smrg         envMode = ctx->Texture.FixedFuncUnit[0].EnvMode;
1070848b8605Smrg
1071848b8605Smrg         /* First see if we can use an optimized 2-D texture function */
1072848b8605Smrg         if (ctx->Texture._EnabledCoordUnits == 0x1
1073848b8605Smrg             && !_swrast_use_fragment_program(ctx)
1074b8e80941Smrg             && !_mesa_ati_fragment_shader_enabled(ctx)
1075848b8605Smrg             && ctx->Texture._MaxEnabledTexImageUnit == 0
1076848b8605Smrg             && ctx->Texture.Unit[0]._Current->Target == GL_TEXTURE_2D
1077848b8605Smrg             && samp->WrapS == GL_REPEAT
1078848b8605Smrg             && samp->WrapT == GL_REPEAT
1079848b8605Smrg             && texObj2D->_Swizzle == SWIZZLE_NOOP
1080848b8605Smrg             && swImg->_IsPowerOfTwo
1081848b8605Smrg             && texImg->Border == 0
1082848b8605Smrg             && (_mesa_format_row_stride(format, texImg->Width) ==
1083848b8605Smrg                 swImg->RowStride)
1084848b8605Smrg             && (format == MESA_FORMAT_BGR_UNORM8 || format == MESA_FORMAT_A8B8G8R8_UNORM)
1085848b8605Smrg             && minFilter == magFilter
1086848b8605Smrg             && ctx->Light.Model.ColorControl == GL_SINGLE_COLOR
1087848b8605Smrg             && !swrast->_FogEnabled
1088b8e80941Smrg             && ctx->Texture.FixedFuncUnit[0].EnvMode != GL_COMBINE_EXT
1089b8e80941Smrg             && ctx->Texture.FixedFuncUnit[0].EnvMode != GL_COMBINE4_NV) {
1090848b8605Smrg	    if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) {
1091848b8605Smrg	       if (minFilter == GL_NEAREST
1092848b8605Smrg		   && format == MESA_FORMAT_BGR_UNORM8
1093848b8605Smrg		   && (envMode == GL_REPLACE || envMode == GL_DECAL)
1094848b8605Smrg		   && ((swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)
1095848b8605Smrg			&& ctx->Depth.Func == GL_LESS
1096848b8605Smrg			&& ctx->Depth.Mask == GL_TRUE)
1097848b8605Smrg		       || swrast->_RasterMask == TEXTURE_BIT)
1098848b8605Smrg		   && ctx->Polygon.StippleFlag == GL_FALSE
1099848b8605Smrg                   && ctx->DrawBuffer->Visual.depthBits <= 16) {
1100848b8605Smrg		  if (swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)) {
1101848b8605Smrg		     USE(simple_z_textured_triangle);
1102848b8605Smrg		  }
1103848b8605Smrg		  else {
1104848b8605Smrg		     USE(simple_textured_triangle);
1105848b8605Smrg		  }
1106848b8605Smrg	       }
1107848b8605Smrg	       else {
1108848b8605Smrg#if CHAN_BITS != 8
1109848b8605Smrg                  USE(general_triangle);
1110848b8605Smrg#else
1111848b8605Smrg                  if (format == MESA_FORMAT_A8B8G8R8_UNORM && !_mesa_little_endian()) {
1112848b8605Smrg                     /* We only handle RGBA8888 correctly on little endian
1113848b8605Smrg                      * in the optimized code above.
1114848b8605Smrg                      */
1115848b8605Smrg                     USE(general_triangle);
1116848b8605Smrg                  }
1117848b8605Smrg                  else {
1118848b8605Smrg                     USE(affine_textured_triangle);
1119848b8605Smrg                 }
1120848b8605Smrg#endif
1121848b8605Smrg	       }
1122848b8605Smrg	    }
1123848b8605Smrg	    else {
1124848b8605Smrg#if CHAN_BITS != 8
1125848b8605Smrg               USE(general_triangle);
1126848b8605Smrg#else
1127848b8605Smrg               USE(persp_textured_triangle);
1128848b8605Smrg#endif
1129848b8605Smrg	    }
1130848b8605Smrg	 }
1131848b8605Smrg         else {
1132848b8605Smrg            /* general case textured triangles */
1133848b8605Smrg            USE(general_triangle);
1134848b8605Smrg         }
1135848b8605Smrg      }
1136848b8605Smrg      else {
1137b8e80941Smrg         assert(!swrast->_FogEnabled);
1138b8e80941Smrg         assert(!_mesa_need_secondary_color(ctx));
1139848b8605Smrg	 if (ctx->Light.ShadeModel==GL_SMOOTH) {
1140848b8605Smrg	    /* smooth shaded, no texturing, stippled or some raster ops */
1141848b8605Smrg#if CHAN_BITS != 8
1142848b8605Smrg               USE(general_triangle);
1143848b8605Smrg#else
1144848b8605Smrg               USE(smooth_rgba_triangle);
1145848b8605Smrg#endif
1146848b8605Smrg	 }
1147848b8605Smrg	 else {
1148848b8605Smrg	    /* flat shaded, no texturing, stippled or some raster ops */
1149848b8605Smrg#if CHAN_BITS != 8
1150848b8605Smrg            USE(general_triangle);
1151848b8605Smrg#else
1152848b8605Smrg            USE(flat_rgba_triangle);
1153848b8605Smrg#endif
1154848b8605Smrg	 }
1155848b8605Smrg      }
1156848b8605Smrg   }
1157848b8605Smrg   else if (ctx->RenderMode==GL_FEEDBACK) {
1158848b8605Smrg      USE(_swrast_feedback_triangle);
1159848b8605Smrg   }
1160848b8605Smrg   else {
1161848b8605Smrg      /* GL_SELECT mode */
1162848b8605Smrg      USE(_swrast_select_triangle);
1163848b8605Smrg   }
1164848b8605Smrg}
1165