comments
[mesa.git] / src / mesa / swrast / s_span.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * \file swrast/s_span.c
28 * \brief Span processing functions used by all rasterization functions.
29 * This is where all the per-fragment tests are performed
30 * \author Brian Paul
31 */
32
33 #include "glheader.h"
34 #include "colormac.h"
35 #include "context.h"
36 #include "macros.h"
37 #include "imports.h"
38 #include "image.h"
39
40 #include "s_atifragshader.h"
41 #include "s_alpha.h"
42 #include "s_blend.h"
43 #include "s_context.h"
44 #include "s_depth.h"
45 #include "s_fog.h"
46 #include "s_logic.h"
47 #include "s_masking.h"
48 #include "s_fragprog.h"
49 #include "s_span.h"
50 #include "s_stencil.h"
51 #include "s_texcombine.h"
52
53
54 /**
55 * Init span's Z interpolation values to the RasterPos Z.
56 * Used during setup for glDraw/CopyPixels.
57 */
58 void
59 _swrast_span_default_z( GLcontext *ctx, SWspan *span )
60 {
61 const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
62 if (ctx->DrawBuffer->Visual.depthBits <= 16)
63 span->z = FloatToFixed(ctx->Current.RasterPos[2] * depthMax + 0.5F);
64 else
65 span->z = (GLint) (ctx->Current.RasterPos[2] * depthMax + 0.5F);
66 span->zStep = 0;
67 span->interpMask |= SPAN_Z;
68 }
69
70
71 /**
72 * Init span's fog interpolation values to the RasterPos fog.
73 * Used during setup for glDraw/CopyPixels.
74 */
75 void
76 _swrast_span_default_fog( GLcontext *ctx, SWspan *span )
77 {
78 span->fog = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
79 span->fogStep = span->dfogdx = span->dfogdy = 0.0F;
80 span->interpMask |= SPAN_FOG;
81 }
82
83
84 /**
85 * Init span's rgba or index interpolation values to the RasterPos color.
86 * Used during setup for glDraw/CopyPixels.
87 */
88 void
89 _swrast_span_default_color( GLcontext *ctx, SWspan *span )
90 {
91 if (ctx->Visual.rgbMode) {
92 GLchan r, g, b, a;
93 UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
94 UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
95 UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
96 UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
97 #if CHAN_TYPE == GL_FLOAT
98 span->red = r;
99 span->green = g;
100 span->blue = b;
101 span->alpha = a;
102 #else
103 span->red = IntToFixed(r);
104 span->green = IntToFixed(g);
105 span->blue = IntToFixed(b);
106 span->alpha = IntToFixed(a);
107 #endif
108 span->redStep = 0;
109 span->greenStep = 0;
110 span->blueStep = 0;
111 span->alphaStep = 0;
112 span->interpMask |= SPAN_RGBA;
113 }
114 else {
115 span->index = FloatToFixed(ctx->Current.RasterIndex);
116 span->indexStep = 0;
117 span->interpMask |= SPAN_INDEX;
118 }
119 }
120
121
122 /**
123 * Init span's texcoord interpolation values to the RasterPos texcoords.
124 * Used during setup for glDraw/CopyPixels.
125 */
126 void
127 _swrast_span_default_texcoords( GLcontext *ctx, SWspan *span )
128 {
129 GLuint i;
130 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
131 const GLfloat *tc = ctx->Current.RasterTexCoords[i];
132 if (ctx->FragmentProgram._Current || ctx->ATIFragmentShader._Enabled) {
133 COPY_4V(span->tex[i], tc);
134 }
135 else if (tc[3] > 0.0F) {
136 /* use (s/q, t/q, r/q, 1) */
137 span->tex[i][0] = tc[0] / tc[3];
138 span->tex[i][1] = tc[1] / tc[3];
139 span->tex[i][2] = tc[2] / tc[3];
140 span->tex[i][3] = 1.0;
141 }
142 else {
143 ASSIGN_4V(span->tex[i], 0.0F, 0.0F, 0.0F, 1.0F);
144 }
145 ASSIGN_4V(span->texStepX[i], 0.0F, 0.0F, 0.0F, 0.0F);
146 ASSIGN_4V(span->texStepY[i], 0.0F, 0.0F, 0.0F, 0.0F);
147 }
148 span->interpMask |= SPAN_TEXTURE;
149 }
150
151
152 /**
153 * Interpolate primary colors to fill in the span->array->color array.
154 */
155 static INLINE void
156 interpolate_colors(SWspan *span)
157 {
158 const GLuint n = span->end;
159 GLuint i;
160
161 ASSERT((span->interpMask & SPAN_RGBA) &&
162 !(span->arrayMask & SPAN_RGBA));
163
164 switch (span->array->ChanType) {
165 #if CHAN_BITS != 32
166 case GL_UNSIGNED_BYTE:
167 {
168 GLubyte (*rgba)[4] = span->array->color.sz1.rgba;
169 if (span->interpMask & SPAN_FLAT) {
170 GLubyte color[4];
171 color[RCOMP] = FixedToInt(span->red);
172 color[GCOMP] = FixedToInt(span->green);
173 color[BCOMP] = FixedToInt(span->blue);
174 color[ACOMP] = FixedToInt(span->alpha);
175 for (i = 0; i < n; i++) {
176 COPY_4UBV(rgba[i], color);
177 }
178 }
179 else {
180 GLfixed r = span->red;
181 GLfixed g = span->green;
182 GLfixed b = span->blue;
183 GLfixed a = span->alpha;
184 GLint dr = span->redStep;
185 GLint dg = span->greenStep;
186 GLint db = span->blueStep;
187 GLint da = span->alphaStep;
188 for (i = 0; i < n; i++) {
189 rgba[i][RCOMP] = FixedToChan(r);
190 rgba[i][GCOMP] = FixedToChan(g);
191 rgba[i][BCOMP] = FixedToChan(b);
192 rgba[i][ACOMP] = FixedToChan(a);
193 r += dr;
194 g += dg;
195 b += db;
196 a += da;
197 }
198 }
199 }
200 break;
201 case GL_UNSIGNED_SHORT:
202 {
203 GLushort (*rgba)[4] = span->array->color.sz2.rgba;
204 if (span->interpMask & SPAN_FLAT) {
205 GLushort color[4];
206 color[RCOMP] = FixedToInt(span->red);
207 color[GCOMP] = FixedToInt(span->green);
208 color[BCOMP] = FixedToInt(span->blue);
209 color[ACOMP] = FixedToInt(span->alpha);
210 for (i = 0; i < n; i++) {
211 COPY_4V(rgba[i], color);
212 }
213 }
214 else {
215 GLushort (*rgba)[4] = span->array->color.sz2.rgba;
216 GLfixed r, g, b, a;
217 GLint dr, dg, db, da;
218 r = span->red;
219 g = span->green;
220 b = span->blue;
221 a = span->alpha;
222 dr = span->redStep;
223 dg = span->greenStep;
224 db = span->blueStep;
225 da = span->alphaStep;
226 for (i = 0; i < n; i++) {
227 rgba[i][RCOMP] = FixedToChan(r);
228 rgba[i][GCOMP] = FixedToChan(g);
229 rgba[i][BCOMP] = FixedToChan(b);
230 rgba[i][ACOMP] = FixedToChan(a);
231 r += dr;
232 g += dg;
233 b += db;
234 a += da;
235 }
236 }
237 }
238 break;
239 #endif
240 case GL_FLOAT:
241 {
242 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
243 GLfloat r, g, b, a, dr, dg, db, da;
244 r = span->red;
245 g = span->green;
246 b = span->blue;
247 a = span->alpha;
248 if (span->interpMask & SPAN_FLAT) {
249 dr = dg = db = da = 0.0;
250 }
251 else {
252 dr = span->redStep;
253 dg = span->greenStep;
254 db = span->blueStep;
255 da = span->alphaStep;
256 }
257 for (i = 0; i < n; i++) {
258 rgba[i][RCOMP] = r;
259 rgba[i][GCOMP] = g;
260 rgba[i][BCOMP] = b;
261 rgba[i][ACOMP] = a;
262 r += dr;
263 g += dg;
264 b += db;
265 a += da;
266 }
267 }
268 break;
269 default:
270 _mesa_problem(NULL, "bad datatype in interpolate_colors");
271 }
272 span->arrayMask |= SPAN_RGBA;
273 }
274
275
276 /**
277 * Interpolate specular/secondary colors.
278 */
279 static INLINE void
280 interpolate_specular(SWspan *span)
281 {
282 const GLuint n = span->end;
283 GLuint i;
284
285 switch (span->array->ChanType) {
286 #if CHAN_BITS != 32
287 case GL_UNSIGNED_BYTE:
288 {
289 GLubyte (*spec)[4] = span->array->color.sz1.spec;
290 if (span->interpMask & SPAN_FLAT) {
291 GLubyte color[4];
292 color[RCOMP] = FixedToInt(span->specRed);
293 color[GCOMP] = FixedToInt(span->specGreen);
294 color[BCOMP] = FixedToInt(span->specBlue);
295 color[ACOMP] = 0;
296 for (i = 0; i < n; i++) {
297 COPY_4UBV(spec[i], color);
298 }
299 }
300 else {
301 GLfixed r = span->specRed;
302 GLfixed g = span->specGreen;
303 GLfixed b = span->specBlue;
304 GLint dr = span->specRedStep;
305 GLint dg = span->specGreenStep;
306 GLint db = span->specBlueStep;
307 for (i = 0; i < n; i++) {
308 spec[i][RCOMP] = CLAMP(FixedToChan(r), 0, 255);
309 spec[i][GCOMP] = CLAMP(FixedToChan(g), 0, 255);
310 spec[i][BCOMP] = CLAMP(FixedToChan(b), 0, 255);
311 spec[i][ACOMP] = 0;
312 r += dr;
313 g += dg;
314 b += db;
315 }
316 }
317 }
318 break;
319 case GL_UNSIGNED_SHORT:
320 {
321 GLushort (*spec)[4] = span->array->color.sz2.spec;
322 if (span->interpMask & SPAN_FLAT) {
323 GLushort color[4];
324 color[RCOMP] = FixedToInt(span->specRed);
325 color[GCOMP] = FixedToInt(span->specGreen);
326 color[BCOMP] = FixedToInt(span->specBlue);
327 color[ACOMP] = 0;
328 for (i = 0; i < n; i++) {
329 COPY_4V(spec[i], color);
330 }
331 }
332 else {
333 GLfixed r = FloatToFixed(span->specRed);
334 GLfixed g = FloatToFixed(span->specGreen);
335 GLfixed b = FloatToFixed(span->specBlue);
336 GLint dr = FloatToFixed(span->specRedStep);
337 GLint dg = FloatToFixed(span->specGreenStep);
338 GLint db = FloatToFixed(span->specBlueStep);
339 for (i = 0; i < n; i++) {
340 spec[i][RCOMP] = FixedToInt(r);
341 spec[i][GCOMP] = FixedToInt(g);
342 spec[i][BCOMP] = FixedToInt(b);
343 spec[i][ACOMP] = 0;
344 r += dr;
345 g += dg;
346 b += db;
347 }
348 }
349 }
350 break;
351 #endif
352 case GL_FLOAT:
353 {
354 GLfloat (*spec)[4] = span->array->attribs[FRAG_ATTRIB_COL1];
355 #if CHAN_BITS <= 16
356 GLfloat r = CHAN_TO_FLOAT(FixedToChan(span->specRed));
357 GLfloat g = CHAN_TO_FLOAT(FixedToChan(span->specGreen));
358 GLfloat b = CHAN_TO_FLOAT(FixedToChan(span->specBlue));
359 #else
360 GLfloat r = span->specRed;
361 GLfloat g = span->specGreen;
362 GLfloat b = span->specBlue;
363 #endif
364 GLfloat dr, dg, db;
365 if (span->interpMask & SPAN_FLAT) {
366 dr = dg = db = 0.0;
367 }
368 else {
369 #if CHAN_BITS <= 16
370 dr = CHAN_TO_FLOAT(FixedToChan(span->specRedStep));
371 dg = CHAN_TO_FLOAT(FixedToChan(span->specGreenStep));
372 db = CHAN_TO_FLOAT(FixedToChan(span->specBlueStep));
373 #else
374 dr = span->specRedStep;
375 dg = span->specGreenStep;
376 db = span->specBlueStep;
377 #endif
378 }
379 for (i = 0; i < n; i++) {
380 spec[i][RCOMP] = r;
381 spec[i][GCOMP] = g;
382 spec[i][BCOMP] = b;
383 spec[i][ACOMP] = 0.0F;
384 r += dr;
385 g += dg;
386 b += db;
387 }
388 }
389 break;
390 default:
391 _mesa_problem(NULL, "bad datatype in interpolate_specular");
392 }
393 span->arrayMask |= SPAN_SPEC;
394 }
395
396
397 /* Fill in the span.color.index array from the interpolation values */
398 static INLINE void
399 interpolate_indexes(GLcontext *ctx, SWspan *span)
400 {
401 GLfixed index = span->index;
402 const GLint indexStep = span->indexStep;
403 const GLuint n = span->end;
404 GLuint *indexes = span->array->index;
405 GLuint i;
406 (void) ctx;
407 ASSERT((span->interpMask & SPAN_INDEX) &&
408 !(span->arrayMask & SPAN_INDEX));
409
410 if ((span->interpMask & SPAN_FLAT) || (indexStep == 0)) {
411 /* constant color */
412 index = FixedToInt(index);
413 for (i = 0; i < n; i++) {
414 indexes[i] = index;
415 }
416 }
417 else {
418 /* interpolate */
419 for (i = 0; i < n; i++) {
420 indexes[i] = FixedToInt(index);
421 index += indexStep;
422 }
423 }
424 span->arrayMask |= SPAN_INDEX;
425 span->interpMask &= ~SPAN_INDEX;
426 }
427
428
429 /* Fill in the span.array.fog values from the interpolation values */
430 static INLINE void
431 interpolate_fog(const GLcontext *ctx, SWspan *span)
432 {
433 GLfloat (*fog)[4] = span->array->attribs[FRAG_ATTRIB_FOGC];
434 const GLfloat fogStep = span->fogStep;
435 GLfloat fogCoord = span->fog;
436 const GLuint haveW = (span->interpMask & SPAN_W);
437 const GLfloat wStep = haveW ? span->dwdx : 0.0F;
438 GLfloat w = haveW ? span->w : 1.0F;
439 GLuint i;
440 for (i = 0; i < span->end; i++) {
441 fog[i][0] = fogCoord / w;
442 fogCoord += fogStep;
443 w += wStep;
444 }
445 span->arrayMask |= SPAN_FOG;
446 }
447
448
449 /* Fill in the span.zArray array from the interpolation values */
450 void
451 _swrast_span_interpolate_z( const GLcontext *ctx, SWspan *span )
452 {
453 const GLuint n = span->end;
454 GLuint i;
455
456 ASSERT((span->interpMask & SPAN_Z) &&
457 !(span->arrayMask & SPAN_Z));
458
459 if (ctx->DrawBuffer->Visual.depthBits <= 16) {
460 GLfixed zval = span->z;
461 GLuint *z = span->array->z;
462 for (i = 0; i < n; i++) {
463 z[i] = FixedToInt(zval);
464 zval += span->zStep;
465 }
466 }
467 else {
468 /* Deep Z buffer, no fixed->int shift */
469 GLuint zval = span->z;
470 GLuint *z = span->array->z;
471 for (i = 0; i < n; i++) {
472 z[i] = zval;
473 zval += span->zStep;
474 }
475 }
476 span->interpMask &= ~SPAN_Z;
477 span->arrayMask |= SPAN_Z;
478 }
479
480
481 /*
482 * This the ideal solution, as given in the OpenGL spec.
483 */
484 #if 0
485 static GLfloat
486 compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
487 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
488 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
489 {
490 GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
491 GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
492 GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
493 GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
494 GLfloat x = SQRTF(dudx * dudx + dvdx * dvdx);
495 GLfloat y = SQRTF(dudy * dudy + dvdy * dvdy);
496 GLfloat rho = MAX2(x, y);
497 GLfloat lambda = LOG2(rho);
498 return lambda;
499 }
500 #endif
501
502
503 /*
504 * This is a faster approximation
505 */
506 GLfloat
507 _swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
508 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
509 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
510 {
511 GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
512 GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
513 GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
514 GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
515 GLfloat maxU, maxV, rho, lambda;
516 dsdx2 = FABSF(dsdx2);
517 dsdy2 = FABSF(dsdy2);
518 dtdx2 = FABSF(dtdx2);
519 dtdy2 = FABSF(dtdy2);
520 maxU = MAX2(dsdx2, dsdy2) * texW;
521 maxV = MAX2(dtdx2, dtdy2) * texH;
522 rho = MAX2(maxU, maxV);
523 lambda = LOG2(rho);
524 return lambda;
525 }
526
527
528 /**
529 * Fill in the span.texcoords array from the interpolation values.
530 * Note: in the places where we divide by Q (or mult by invQ) we're
531 * really doing two things: perspective correction and texcoord
532 * projection. Remember, for texcoord (s,t,r,q) we need to index
533 * texels with (s/q, t/q, r/q).
534 * If we're using a fragment program, we never do the division
535 * for texcoord projection. That's done by the TXP instruction
536 * or user-written code.
537 */
538 static void
539 interpolate_texcoords(GLcontext *ctx, SWspan *span)
540 {
541 ASSERT(span->interpMask & SPAN_TEXTURE);
542 ASSERT(!(span->arrayMask & SPAN_TEXTURE));
543
544 if (ctx->Texture._EnabledCoordUnits > 1) {
545 /* multitexture */
546 GLuint u;
547 span->arrayMask |= SPAN_TEXTURE;
548 /* XXX CoordUnits vs. ImageUnits */
549 for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
550 if (ctx->Texture._EnabledCoordUnits & (1 << u)) {
551 const struct gl_texture_object *obj =ctx->Texture.Unit[u]._Current;
552 GLfloat texW, texH;
553 GLboolean needLambda;
554 if (obj) {
555 const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
556 needLambda = (obj->MinFilter != obj->MagFilter)
557 || ctx->FragmentProgram._Current;
558 texW = img->WidthScale;
559 texH = img->HeightScale;
560 }
561 else {
562 /* using a fragment program */
563 texW = 1.0;
564 texH = 1.0;
565 needLambda = GL_FALSE;
566 }
567 if (needLambda) {
568 GLfloat (*texcoord)[4] = span->array->attribs[FRAG_ATTRIB_TEX0 + u];
569 GLfloat *lambda = span->array->lambda[u];
570 const GLfloat dsdx = span->texStepX[u][0];
571 const GLfloat dsdy = span->texStepY[u][0];
572 const GLfloat dtdx = span->texStepX[u][1];
573 const GLfloat dtdy = span->texStepY[u][1];
574 const GLfloat drdx = span->texStepX[u][2];
575 const GLfloat dqdx = span->texStepX[u][3];
576 const GLfloat dqdy = span->texStepY[u][3];
577 GLfloat s = span->tex[u][0];
578 GLfloat t = span->tex[u][1];
579 GLfloat r = span->tex[u][2];
580 GLfloat q = span->tex[u][3];
581 GLuint i;
582 if (ctx->FragmentProgram._Current
583 || ctx->ATIFragmentShader._Enabled) {
584 /* do perspective correction but don't divide s, t, r by q */
585 const GLfloat dwdx = span->dwdx;
586 GLfloat w = span->w;
587 for (i = 0; i < span->end; i++) {
588 const GLfloat invW = 1.0F / w;
589 texcoord[i][0] = s * invW;
590 texcoord[i][1] = t * invW;
591 texcoord[i][2] = r * invW;
592 texcoord[i][3] = q * invW;
593 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
594 dqdx, dqdy, texW, texH,
595 s, t, q, invW);
596 s += dsdx;
597 t += dtdx;
598 r += drdx;
599 q += dqdx;
600 w += dwdx;
601 }
602 }
603 else {
604 for (i = 0; i < span->end; i++) {
605 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
606 texcoord[i][0] = s * invQ;
607 texcoord[i][1] = t * invQ;
608 texcoord[i][2] = r * invQ;
609 texcoord[i][3] = q;
610 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
611 dqdx, dqdy, texW, texH,
612 s, t, q, invQ);
613 s += dsdx;
614 t += dtdx;
615 r += drdx;
616 q += dqdx;
617 }
618 }
619 span->arrayMask |= SPAN_LAMBDA;
620 }
621 else {
622 GLfloat (*texcoord)[4] = span->array->attribs[FRAG_ATTRIB_TEX0 + u];
623 GLfloat *lambda = span->array->lambda[u];
624 const GLfloat dsdx = span->texStepX[u][0];
625 const GLfloat dtdx = span->texStepX[u][1];
626 const GLfloat drdx = span->texStepX[u][2];
627 const GLfloat dqdx = span->texStepX[u][3];
628 GLfloat s = span->tex[u][0];
629 GLfloat t = span->tex[u][1];
630 GLfloat r = span->tex[u][2];
631 GLfloat q = span->tex[u][3];
632 GLuint i;
633 if (ctx->FragmentProgram._Current ||
634 ctx->ATIFragmentShader._Enabled) {
635 /* do perspective correction but don't divide s, t, r by q */
636 const GLfloat dwdx = span->dwdx;
637 GLfloat w = span->w;
638 for (i = 0; i < span->end; i++) {
639 const GLfloat invW = 1.0F / w;
640 texcoord[i][0] = s * invW;
641 texcoord[i][1] = t * invW;
642 texcoord[i][2] = r * invW;
643 texcoord[i][3] = q * invW;
644 lambda[i] = 0.0;
645 s += dsdx;
646 t += dtdx;
647 r += drdx;
648 q += dqdx;
649 w += dwdx;
650 }
651 }
652 else if (dqdx == 0.0F) {
653 /* Ortho projection or polygon's parallel to window X axis */
654 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
655 for (i = 0; i < span->end; i++) {
656 texcoord[i][0] = s * invQ;
657 texcoord[i][1] = t * invQ;
658 texcoord[i][2] = r * invQ;
659 texcoord[i][3] = q;
660 lambda[i] = 0.0;
661 s += dsdx;
662 t += dtdx;
663 r += drdx;
664 }
665 }
666 else {
667 for (i = 0; i < span->end; i++) {
668 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
669 texcoord[i][0] = s * invQ;
670 texcoord[i][1] = t * invQ;
671 texcoord[i][2] = r * invQ;
672 texcoord[i][3] = q;
673 lambda[i] = 0.0;
674 s += dsdx;
675 t += dtdx;
676 r += drdx;
677 q += dqdx;
678 }
679 }
680 } /* lambda */
681 } /* if */
682 } /* for */
683 }
684 else {
685 /* single texture */
686 const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;
687 GLfloat texW, texH;
688 GLboolean needLambda;
689 if (obj) {
690 const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
691 needLambda = (obj->MinFilter != obj->MagFilter)
692 || ctx->FragmentProgram._Current;
693 texW = (GLfloat) img->WidthScale;
694 texH = (GLfloat) img->HeightScale;
695 }
696 else {
697 needLambda = GL_FALSE;
698 texW = texH = 1.0;
699 }
700 span->arrayMask |= SPAN_TEXTURE;
701 if (needLambda) {
702 /* just texture unit 0, with lambda */
703 GLfloat (*texcoord)[4] = span->array->attribs[FRAG_ATTRIB_TEX0];
704 GLfloat *lambda = span->array->lambda[0];
705 const GLfloat dsdx = span->texStepX[0][0];
706 const GLfloat dsdy = span->texStepY[0][0];
707 const GLfloat dtdx = span->texStepX[0][1];
708 const GLfloat dtdy = span->texStepY[0][1];
709 const GLfloat drdx = span->texStepX[0][2];
710 const GLfloat dqdx = span->texStepX[0][3];
711 const GLfloat dqdy = span->texStepY[0][3];
712 GLfloat s = span->tex[0][0];
713 GLfloat t = span->tex[0][1];
714 GLfloat r = span->tex[0][2];
715 GLfloat q = span->tex[0][3];
716 GLuint i;
717 if (ctx->FragmentProgram._Current
718 || ctx->ATIFragmentShader._Enabled) {
719 /* do perspective correction but don't divide s, t, r by q */
720 const GLfloat dwdx = span->dwdx;
721 GLfloat w = span->w;
722 for (i = 0; i < span->end; i++) {
723 const GLfloat invW = 1.0F / w;
724 texcoord[i][0] = s * invW;
725 texcoord[i][1] = t * invW;
726 texcoord[i][2] = r * invW;
727 texcoord[i][3] = q * invW;
728 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
729 dqdx, dqdy, texW, texH,
730 s, t, q, invW);
731 s += dsdx;
732 t += dtdx;
733 r += drdx;
734 q += dqdx;
735 w += dwdx;
736 }
737 }
738 else {
739 /* tex.c */
740 for (i = 0; i < span->end; i++) {
741 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
742 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
743 dqdx, dqdy, texW, texH,
744 s, t, q, invQ);
745 texcoord[i][0] = s * invQ;
746 texcoord[i][1] = t * invQ;
747 texcoord[i][2] = r * invQ;
748 texcoord[i][3] = q;
749 s += dsdx;
750 t += dtdx;
751 r += drdx;
752 q += dqdx;
753 }
754 }
755 span->arrayMask |= SPAN_LAMBDA;
756 }
757 else {
758 /* just texture 0, without lambda */
759 GLfloat (*texcoord)[4] = span->array->attribs[FRAG_ATTRIB_TEX0];
760 const GLfloat dsdx = span->texStepX[0][0];
761 const GLfloat dtdx = span->texStepX[0][1];
762 const GLfloat drdx = span->texStepX[0][2];
763 const GLfloat dqdx = span->texStepX[0][3];
764 GLfloat s = span->tex[0][0];
765 GLfloat t = span->tex[0][1];
766 GLfloat r = span->tex[0][2];
767 GLfloat q = span->tex[0][3];
768 GLuint i;
769 if (ctx->FragmentProgram._Current
770 || ctx->ATIFragmentShader._Enabled) {
771 /* do perspective correction but don't divide s, t, r by q */
772 const GLfloat dwdx = span->dwdx;
773 GLfloat w = span->w;
774 for (i = 0; i < span->end; i++) {
775 const GLfloat invW = 1.0F / w;
776 texcoord[i][0] = s * invW;
777 texcoord[i][1] = t * invW;
778 texcoord[i][2] = r * invW;
779 texcoord[i][3] = q * invW;
780 s += dsdx;
781 t += dtdx;
782 r += drdx;
783 q += dqdx;
784 w += dwdx;
785 }
786 }
787 else if (dqdx == 0.0F) {
788 /* Ortho projection or polygon's parallel to window X axis */
789 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
790 for (i = 0; i < span->end; i++) {
791 texcoord[i][0] = s * invQ;
792 texcoord[i][1] = t * invQ;
793 texcoord[i][2] = r * invQ;
794 texcoord[i][3] = q;
795 s += dsdx;
796 t += dtdx;
797 r += drdx;
798 }
799 }
800 else {
801 for (i = 0; i < span->end; i++) {
802 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
803 texcoord[i][0] = s * invQ;
804 texcoord[i][1] = t * invQ;
805 texcoord[i][2] = r * invQ;
806 texcoord[i][3] = q;
807 s += dsdx;
808 t += dtdx;
809 r += drdx;
810 q += dqdx;
811 }
812 }
813 }
814 }
815 }
816
817
818 /**
819 * Fill in the arrays->attribs[FRAG_ATTRIB_VARx] arrays from the
820 * interpolation values.
821 * XXX since interpolants/arrays are getting uniformed, we might merge
822 * this with interpolate_texcoords(), interpolate_Fog(), etc. someday.
823 */
824 static INLINE void
825 interpolate_varying(GLcontext *ctx, SWspan *span)
826 {
827 GLuint var;
828 const GLbitfield inputsUsed = ctx->FragmentProgram._Current->Base.InputsRead;
829
830 ASSERT(span->interpMask & SPAN_VARYING);
831 ASSERT(!(span->arrayMask & SPAN_VARYING));
832
833 span->arrayMask |= SPAN_VARYING;
834
835 for (var = 0; var < MAX_VARYING; var++) {
836 if (inputsUsed & FRAG_BIT_VAR(var)) {
837 GLuint j;
838 for (j = 0; j < 4; j++) {
839 const GLfloat dvdx = span->varStepX[var][j];
840 GLfloat v = span->var[var][j];
841 const GLfloat dwdx = span->dwdx;
842 GLfloat w = span->w;
843 GLuint k;
844 for (k = 0; k < span->end; k++) {
845 GLfloat invW = 1.0f / w;
846 span->array->attribs[FRAG_ATTRIB_VAR0 + var][k][j] = v * invW;
847 v += dvdx;
848 w += dwdx;
849 }
850 }
851 }
852 }
853 }
854
855
856 /**
857 * Fill in the arrays->attribs[FRAG_ATTRIB_WPOS] array.
858 */
859 static INLINE void
860 interpolate_wpos(GLcontext *ctx, SWspan *span)
861 {
862 GLfloat (*wpos)[4] = span->array->attribs[FRAG_ATTRIB_WPOS];
863 GLuint i;
864 if (span->arrayMask & SPAN_XY) {
865 for (i = 0; i < span->end; i++) {
866 wpos[i][0] = (GLfloat) span->array->x[i];
867 wpos[i][1] = (GLfloat) span->array->y[i];
868 }
869 }
870 else {
871 for (i = 0; i < span->end; i++) {
872 wpos[i][0] = (GLfloat) span->x + i;
873 wpos[i][1] = (GLfloat) span->y;
874 }
875 }
876 for (i = 0; i < span->end; i++) {
877 wpos[i][2] = (GLfloat) span->array->z[i] / ctx->DrawBuffer->_DepthMaxF;
878 wpos[i][3] = span->w + i * span->dwdx;
879 }
880 }
881
882
883 /**
884 * Apply the current polygon stipple pattern to a span of pixels.
885 */
886 static INLINE void
887 stipple_polygon_span(GLcontext *ctx, SWspan *span)
888 {
889 GLubyte *mask = span->array->mask;
890
891 ASSERT(ctx->Polygon.StippleFlag);
892
893 if (span->arrayMask & SPAN_XY) {
894 /* arrays of x/y pixel coords */
895 GLuint i;
896 for (i = 0; i < span->end; i++) {
897 const GLint col = span->array->x[i] % 32;
898 const GLint row = span->array->y[i] % 32;
899 const GLuint stipple = ctx->PolygonStipple[row];
900 if (((1 << col) & stipple) == 0) {
901 mask[i] = 0;
902 }
903 }
904 }
905 else {
906 /* horizontal span of pixels */
907 const GLuint highBit = 1 << 31;
908 const GLuint stipple = ctx->PolygonStipple[span->y % 32];
909 GLuint i, m = highBit >> (GLuint) (span->x % 32);
910 for (i = 0; i < span->end; i++) {
911 if ((m & stipple) == 0) {
912 mask[i] = 0;
913 }
914 m = m >> 1;
915 if (m == 0) {
916 m = highBit;
917 }
918 }
919 }
920 span->writeAll = GL_FALSE;
921 }
922
923
924 /**
925 * Clip a pixel span to the current buffer/window boundaries:
926 * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax. This will accomplish
927 * window clipping and scissoring.
928 * Return: GL_TRUE some pixels still visible
929 * GL_FALSE nothing visible
930 */
931 static INLINE GLuint
932 clip_span( GLcontext *ctx, SWspan *span )
933 {
934 const GLint xmin = ctx->DrawBuffer->_Xmin;
935 const GLint xmax = ctx->DrawBuffer->_Xmax;
936 const GLint ymin = ctx->DrawBuffer->_Ymin;
937 const GLint ymax = ctx->DrawBuffer->_Ymax;
938
939 if (span->arrayMask & SPAN_XY) {
940 /* arrays of x/y pixel coords */
941 const GLint *x = span->array->x;
942 const GLint *y = span->array->y;
943 const GLint n = span->end;
944 GLubyte *mask = span->array->mask;
945 GLint i;
946 if (span->arrayMask & SPAN_MASK) {
947 /* note: using & intead of && to reduce branches */
948 for (i = 0; i < n; i++) {
949 mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
950 & (y[i] >= ymin) & (y[i] < ymax);
951 }
952 }
953 else {
954 /* note: using & intead of && to reduce branches */
955 for (i = 0; i < n; i++) {
956 mask[i] = (x[i] >= xmin) & (x[i] < xmax)
957 & (y[i] >= ymin) & (y[i] < ymax);
958 }
959 }
960 return GL_TRUE; /* some pixels visible */
961 }
962 else {
963 /* horizontal span of pixels */
964 const GLint x = span->x;
965 const GLint y = span->y;
966 const GLint n = span->end;
967
968 /* Trivial rejection tests */
969 if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
970 span->end = 0;
971 return GL_FALSE; /* all pixels clipped */
972 }
973
974 /* Clip to the left */
975 if (x < xmin) {
976 ASSERT(x + n > xmin);
977 span->writeAll = GL_FALSE;
978 _mesa_bzero(span->array->mask, (xmin - x) * sizeof(GLubyte));
979 }
980
981 /* Clip to right */
982 if (x + n > xmax) {
983 ASSERT(x < xmax);
984 span->end = xmax - x;
985 }
986
987 return GL_TRUE; /* some pixels visible */
988 }
989 }
990
991
992 /**
993 * Apply all the per-fragment opertions to a span of color index fragments
994 * and write them to the enabled color drawbuffers.
995 * The 'span' parameter can be considered to be const. Note that
996 * span->interpMask and span->arrayMask may be changed but will be restored
997 * to their original values before returning.
998 */
999 void
1000 _swrast_write_index_span( GLcontext *ctx, SWspan *span)
1001 {
1002 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
1003 const GLbitfield origInterpMask = span->interpMask;
1004 const GLbitfield origArrayMask = span->arrayMask;
1005
1006 ASSERT(span->end <= MAX_WIDTH);
1007 ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
1008 span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
1009 ASSERT((span->interpMask | span->arrayMask) & SPAN_INDEX);
1010 ASSERT((span->interpMask & span->arrayMask) == 0);
1011
1012 if (span->arrayMask & SPAN_MASK) {
1013 /* mask was initialized by caller, probably glBitmap */
1014 span->writeAll = GL_FALSE;
1015 }
1016 else {
1017 _mesa_memset(span->array->mask, 1, span->end);
1018 span->writeAll = GL_TRUE;
1019 }
1020
1021 /* Clipping */
1022 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
1023 if (!clip_span(ctx, span)) {
1024 return;
1025 }
1026 }
1027
1028 /* Depth bounds test */
1029 if (ctx->Depth.BoundsTest && ctx->DrawBuffer->Visual.depthBits > 0) {
1030 if (!_swrast_depth_bounds_test(ctx, span)) {
1031 return;
1032 }
1033 }
1034
1035 #ifdef DEBUG
1036 /* Make sure all fragments are within window bounds */
1037 if (span->arrayMask & SPAN_XY) {
1038 GLuint i;
1039 for (i = 0; i < span->end; i++) {
1040 if (span->array->mask[i]) {
1041 assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
1042 assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
1043 assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
1044 assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
1045 }
1046 }
1047 }
1048 #endif
1049
1050 /* Polygon Stippling */
1051 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
1052 stipple_polygon_span(ctx, span);
1053 }
1054
1055 /* Stencil and Z testing */
1056 if (ctx->Depth.Test || ctx->Stencil.Enabled) {
1057 if (span->interpMask & SPAN_Z)
1058 _swrast_span_interpolate_z(ctx, span);
1059
1060 if (ctx->Stencil.Enabled) {
1061 if (!_swrast_stencil_and_ztest_span(ctx, span)) {
1062 span->arrayMask = origArrayMask;
1063 return;
1064 }
1065 }
1066 else {
1067 ASSERT(ctx->Depth.Test);
1068 if (!_swrast_depth_test_span(ctx, span)) {
1069 span->interpMask = origInterpMask;
1070 span->arrayMask = origArrayMask;
1071 return;
1072 }
1073 }
1074 }
1075
1076 #if FEATURE_ARB_occlusion_query
1077 if (ctx->Query.CurrentOcclusionObject) {
1078 /* update count of 'passed' fragments */
1079 struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;
1080 GLuint i;
1081 for (i = 0; i < span->end; i++)
1082 q->Result += span->array->mask[i];
1083 }
1084 #endif
1085
1086 /* we have to wait until after occlusion to do this test */
1087 if (ctx->Color.DrawBuffer == GL_NONE || ctx->Color.IndexMask == 0) {
1088 /* write no pixels */
1089 span->arrayMask = origArrayMask;
1090 return;
1091 }
1092
1093 /* Interpolate the color indexes if needed */
1094 if (swrast->_FogEnabled ||
1095 ctx->Color.IndexLogicOpEnabled ||
1096 ctx->Color.IndexMask != 0xffffffff ||
1097 (span->arrayMask & SPAN_COVERAGE)) {
1098 if (span->interpMask & SPAN_INDEX) {
1099 interpolate_indexes(ctx, span);
1100 }
1101 }
1102
1103 /* Fog */
1104 if (swrast->_FogEnabled) {
1105 _swrast_fog_ci_span(ctx, span);
1106 }
1107
1108 /* Antialias coverage application */
1109 if (span->arrayMask & SPAN_COVERAGE) {
1110 const GLfloat *coverage = span->array->coverage;
1111 GLuint *index = span->array->index;
1112 GLuint i;
1113 for (i = 0; i < span->end; i++) {
1114 ASSERT(coverage[i] < 16);
1115 index[i] = (index[i] & ~0xf) | ((GLuint) coverage[i]);
1116 }
1117 }
1118
1119 /*
1120 * Write to renderbuffers
1121 */
1122 {
1123 struct gl_framebuffer *fb = ctx->DrawBuffer;
1124 const GLuint output = 0; /* only frag progs can write to other outputs */
1125 const GLuint numDrawBuffers = fb->_NumColorDrawBuffers[output];
1126 GLuint indexSave[MAX_WIDTH];
1127 GLuint buf;
1128
1129 if (numDrawBuffers > 1) {
1130 /* save indexes for second, third renderbuffer writes */
1131 _mesa_memcpy(indexSave, span->array->index,
1132 span->end * sizeof(indexSave[0]));
1133 }
1134
1135 for (buf = 0; buf < fb->_NumColorDrawBuffers[output]; buf++) {
1136 struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[output][buf];
1137 ASSERT(rb->_BaseFormat == GL_COLOR_INDEX);
1138
1139 if (ctx->Color.IndexLogicOpEnabled) {
1140 _swrast_logicop_ci_span(ctx, rb, span);
1141 }
1142
1143 if (ctx->Color.IndexMask != 0xffffffff) {
1144 _swrast_mask_ci_span(ctx, rb, span);
1145 }
1146
1147 if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
1148 /* all fragments have same color index */
1149 GLubyte index8;
1150 GLushort index16;
1151 GLuint index32;
1152 void *value;
1153
1154 if (rb->DataType == GL_UNSIGNED_BYTE) {
1155 index8 = FixedToInt(span->index);
1156 value = &index8;
1157 }
1158 else if (rb->DataType == GL_UNSIGNED_SHORT) {
1159 index16 = FixedToInt(span->index);
1160 value = &index16;
1161 }
1162 else {
1163 ASSERT(rb->DataType == GL_UNSIGNED_INT);
1164 index32 = FixedToInt(span->index);
1165 value = &index32;
1166 }
1167
1168 if (span->arrayMask & SPAN_XY) {
1169 rb->PutMonoValues(ctx, rb, span->end, span->array->x,
1170 span->array->y, value, span->array->mask);
1171 }
1172 else {
1173 rb->PutMonoRow(ctx, rb, span->end, span->x, span->y,
1174 value, span->array->mask);
1175 }
1176 }
1177 else {
1178 /* each fragment is a different color */
1179 GLubyte index8[MAX_WIDTH];
1180 GLushort index16[MAX_WIDTH];
1181 void *values;
1182
1183 if (rb->DataType == GL_UNSIGNED_BYTE) {
1184 GLuint k;
1185 for (k = 0; k < span->end; k++) {
1186 index8[k] = (GLubyte) span->array->index[k];
1187 }
1188 values = index8;
1189 }
1190 else if (rb->DataType == GL_UNSIGNED_SHORT) {
1191 GLuint k;
1192 for (k = 0; k < span->end; k++) {
1193 index16[k] = (GLushort) span->array->index[k];
1194 }
1195 values = index16;
1196 }
1197 else {
1198 ASSERT(rb->DataType == GL_UNSIGNED_INT);
1199 values = span->array->index;
1200 }
1201
1202 if (span->arrayMask & SPAN_XY) {
1203 rb->PutValues(ctx, rb, span->end,
1204 span->array->x, span->array->y,
1205 values, span->array->mask);
1206 }
1207 else {
1208 rb->PutRow(ctx, rb, span->end, span->x, span->y,
1209 values, span->array->mask);
1210 }
1211 }
1212
1213 if (buf + 1 < numDrawBuffers) {
1214 /* restore original span values */
1215 _mesa_memcpy(span->array->index, indexSave,
1216 span->end * sizeof(indexSave[0]));
1217 }
1218 } /* for buf */
1219 }
1220
1221 span->interpMask = origInterpMask;
1222 span->arrayMask = origArrayMask;
1223 }
1224
1225
1226 /**
1227 * Add specular color to base color. This is used only when
1228 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
1229 */
1230 static INLINE void
1231 add_specular(GLcontext *ctx, SWspan *span)
1232 {
1233 switch (span->array->ChanType) {
1234 case GL_UNSIGNED_BYTE:
1235 {
1236 GLubyte (*rgba)[4] = span->array->color.sz1.rgba;
1237 GLubyte (*spec)[4] = span->array->color.sz1.spec;
1238 GLuint i;
1239 for (i = 0; i < span->end; i++) {
1240 GLint r = rgba[i][RCOMP] + spec[i][RCOMP];
1241 GLint g = rgba[i][GCOMP] + spec[i][GCOMP];
1242 GLint b = rgba[i][BCOMP] + spec[i][BCOMP];
1243 GLint a = rgba[i][ACOMP] + spec[i][ACOMP];
1244 rgba[i][RCOMP] = MIN2(r, 255);
1245 rgba[i][GCOMP] = MIN2(g, 255);
1246 rgba[i][BCOMP] = MIN2(b, 255);
1247 rgba[i][ACOMP] = MIN2(a, 255);
1248 }
1249 }
1250 break;
1251 case GL_UNSIGNED_SHORT:
1252 {
1253 GLushort (*rgba)[4] = span->array->color.sz2.rgba;
1254 GLushort (*spec)[4] = span->array->color.sz2.spec;
1255 GLuint i;
1256 for (i = 0; i < span->end; i++) {
1257 GLint r = rgba[i][RCOMP] + spec[i][RCOMP];
1258 GLint g = rgba[i][GCOMP] + spec[i][GCOMP];
1259 GLint b = rgba[i][BCOMP] + spec[i][BCOMP];
1260 GLint a = rgba[i][ACOMP] + spec[i][ACOMP];
1261 rgba[i][RCOMP] = MIN2(r, 65535);
1262 rgba[i][GCOMP] = MIN2(g, 65535);
1263 rgba[i][BCOMP] = MIN2(b, 65535);
1264 rgba[i][ACOMP] = MIN2(a, 65535);
1265 }
1266 }
1267 break;
1268 case GL_FLOAT:
1269 {
1270 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
1271 GLfloat (*spec)[4] = span->array->attribs[FRAG_ATTRIB_COL1];
1272 GLuint i;
1273 for (i = 0; i < span->end; i++) {
1274 rgba[i][RCOMP] += spec[i][RCOMP];
1275 rgba[i][GCOMP] += spec[i][GCOMP];
1276 rgba[i][BCOMP] += spec[i][BCOMP];
1277 rgba[i][ACOMP] += spec[i][ACOMP];
1278 }
1279 }
1280 break;
1281 default:
1282 _mesa_problem(ctx, "Invalid datatype in add_specular");
1283 }
1284 }
1285
1286
1287 /**
1288 * Apply antialiasing coverage value to alpha values.
1289 */
1290 static INLINE void
1291 apply_aa_coverage(SWspan *span)
1292 {
1293 const GLfloat *coverage = span->array->coverage;
1294 GLuint i;
1295 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
1296 GLubyte (*rgba)[4] = span->array->color.sz1.rgba;
1297 for (i = 0; i < span->end; i++) {
1298 const GLfloat a = rgba[i][ACOMP] * coverage[i];
1299 rgba[i][ACOMP] = (GLubyte) CLAMP(a, 0.0, 255.0);
1300 ASSERT(coverage[i] >= 0.0);
1301 ASSERT(coverage[i] <= 1.0);
1302 }
1303 }
1304 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
1305 GLushort (*rgba)[4] = span->array->color.sz2.rgba;
1306 for (i = 0; i < span->end; i++) {
1307 const GLfloat a = rgba[i][ACOMP] * coverage[i];
1308 rgba[i][ACOMP] = (GLushort) CLAMP(a, 0.0, 65535.0);
1309 }
1310 }
1311 else {
1312 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
1313 for (i = 0; i < span->end; i++) {
1314 rgba[i][ACOMP] = rgba[i][ACOMP] * coverage[i];
1315 }
1316 }
1317 }
1318
1319
1320 /**
1321 * Clamp span's float colors to [0,1]
1322 */
1323 static INLINE void
1324 clamp_colors(SWspan *span)
1325 {
1326 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
1327 GLuint i;
1328 ASSERT(span->array->ChanType == GL_FLOAT);
1329 for (i = 0; i < span->end; i++) {
1330 rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F);
1331 rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F);
1332 rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F);
1333 rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F);
1334 }
1335 }
1336
1337
1338 /**
1339 * Convert the span's color arrays to the given type.
1340 */
1341 static INLINE void
1342 convert_color_type(SWspan *span, GLenum newType)
1343 {
1344 GLvoid *src, *dst;
1345 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
1346 src = span->array->color.sz1.rgba;
1347 }
1348 else if (span->array->ChanType == GL_UNSIGNED_BYTE) {
1349 src = span->array->color.sz2.rgba;
1350 }
1351 else {
1352 src = span->array->attribs[FRAG_ATTRIB_COL0];
1353 }
1354 if (newType == GL_UNSIGNED_BYTE) {
1355 dst = span->array->color.sz1.rgba;
1356 }
1357 else if (newType == GL_UNSIGNED_BYTE) {
1358 dst = span->array->color.sz2.rgba;
1359 }
1360 else {
1361 dst = span->array->attribs[FRAG_ATTRIB_COL0];
1362 }
1363
1364 _mesa_convert_colors(span->array->ChanType, src,
1365 newType, dst,
1366 span->end, span->array->mask);
1367
1368 span->array->ChanType = newType;
1369 }
1370
1371
1372
1373 /**
1374 * Apply fragment shader, fragment program or normal texturing to span.
1375 */
1376 static INLINE void
1377 shade_texture_span(GLcontext *ctx, SWspan *span)
1378 {
1379 /* Now we need the rgba array, fill it in if needed */
1380 if (span->interpMask & SPAN_RGBA)
1381 interpolate_colors(span);
1382
1383 if (ctx->Texture._EnabledCoordUnits && (span->interpMask & SPAN_TEXTURE))
1384 interpolate_texcoords(ctx, span);
1385
1386 if (ctx->FragmentProgram._Current ||
1387 ctx->ATIFragmentShader._Enabled) {
1388
1389 /* use float colors if running a fragment program or shader */
1390 const GLenum oldType = span->array->ChanType;
1391 const GLenum newType = GL_FLOAT;
1392 if (oldType != newType) {
1393 GLvoid *src = (oldType == GL_UNSIGNED_BYTE)
1394 ? (GLvoid *) span->array->color.sz1.rgba
1395 : (GLvoid *) span->array->color.sz2.rgba;
1396 _mesa_convert_colors(oldType, src,
1397 newType, span->array->attribs[FRAG_ATTRIB_COL0],
1398 span->end, span->array->mask);
1399 span->array->ChanType = newType;
1400 }
1401
1402 /* fragment programs/shaders may need specular, fog and Z coords */
1403 if (span->interpMask & SPAN_SPEC)
1404 interpolate_specular(span);
1405
1406 if (span->interpMask & SPAN_FOG)
1407 interpolate_fog(ctx, span);
1408
1409 if (span->interpMask & SPAN_Z)
1410 _swrast_span_interpolate_z (ctx, span);
1411
1412 if (ctx->Shader.CurrentProgram && span->interpMask & SPAN_VARYING)
1413 interpolate_varying(ctx, span);
1414
1415 if (ctx->FragmentProgram._Current &&
1416 (ctx->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_WPOS))
1417 interpolate_wpos(ctx, span);
1418
1419 /* Run fragment program/shader now */
1420 if (ctx->FragmentProgram._Current) {
1421 _swrast_exec_fragment_program(ctx, span);
1422 }
1423 else {
1424 ASSERT(ctx->ATIFragmentShader._Enabled);
1425 _swrast_exec_fragment_shader(ctx, span);
1426 }
1427 }
1428 else if (ctx->Texture._EnabledUnits && (span->arrayMask & SPAN_TEXTURE)) {
1429 /* conventional texturing */
1430 _swrast_texture_span(ctx, span);
1431 }
1432 }
1433
1434
1435
1436 /**
1437 * Apply all the per-fragment operations to a span.
1438 * This now includes texturing (_swrast_write_texture_span() is history).
1439 * This function may modify any of the array values in the span.
1440 * span->interpMask and span->arrayMask may be changed but will be restored
1441 * to their original values before returning.
1442 */
1443 void
1444 _swrast_write_rgba_span( GLcontext *ctx, SWspan *span)
1445 {
1446 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
1447 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
1448 const GLbitfield origInterpMask = span->interpMask;
1449 const GLbitfield origArrayMask = span->arrayMask;
1450 const GLenum chanType = span->array->ChanType;
1451 const GLboolean shader = (ctx->FragmentProgram._Current
1452 || ctx->ATIFragmentShader._Enabled);
1453 const GLboolean shaderOrTexture = shader || ctx->Texture._EnabledUnits;
1454 GLboolean deferredTexture;
1455
1456 /*
1457 printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__,
1458 span->interpMask, span->arrayMask);
1459 */
1460
1461 ASSERT(span->primitive == GL_POINT ||
1462 span->primitive == GL_LINE ||
1463 span->primitive == GL_POLYGON ||
1464 span->primitive == GL_BITMAP);
1465 ASSERT(span->end <= MAX_WIDTH);
1466 ASSERT((span->interpMask & span->arrayMask) == 0);
1467 ASSERT((span->interpMask & SPAN_RGBA) ^ (span->arrayMask & SPAN_RGBA));
1468
1469 /* check for conditions that prevent deferred shading */
1470 if (ctx->Color.AlphaEnabled) {
1471 /* alpha test depends on post-texture/shader colors */
1472 deferredTexture = GL_FALSE;
1473 }
1474 else if (shaderOrTexture) {
1475 if (ctx->FragmentProgram._Current) {
1476 if (ctx->FragmentProgram.Current->Base.OutputsWritten
1477 & (1 << FRAG_RESULT_DEPR)) {
1478 /* Z comes from fragment program/shader */
1479 deferredTexture = GL_FALSE;
1480 }
1481 else {
1482 deferredTexture = GL_TRUE;
1483 }
1484 }
1485 else {
1486 /* ATI frag shader or conventional texturing */
1487 deferredTexture = GL_TRUE;
1488 }
1489 }
1490 else {
1491 /* no texturing or shadering */
1492 deferredTexture = GL_FALSE;
1493 }
1494
1495 /* Fragment write masks */
1496 if (span->arrayMask & SPAN_MASK) {
1497 /* mask was initialized by caller, probably glBitmap */
1498 span->writeAll = GL_FALSE;
1499 }
1500 else {
1501 _mesa_memset(span->array->mask, 1, span->end);
1502 span->writeAll = GL_TRUE;
1503 }
1504
1505 /* Clip to window/scissor box */
1506 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
1507 if (!clip_span(ctx, span)) {
1508 return;
1509 }
1510 }
1511
1512 #ifdef DEBUG
1513 /* Make sure all fragments are within window bounds */
1514 if (span->arrayMask & SPAN_XY) {
1515 GLuint i;
1516 for (i = 0; i < span->end; i++) {
1517 if (span->array->mask[i]) {
1518 assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
1519 assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
1520 assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
1521 assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
1522 }
1523 }
1524 }
1525 #endif
1526
1527 /* Polygon Stippling */
1528 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
1529 stipple_polygon_span(ctx, span);
1530 }
1531
1532 /* This is the normal place to compute the resulting fragment color/Z.
1533 * As an optimization, we try to defer this until after Z/stencil
1534 * testing in order to try to avoid computing colors that we won't
1535 * actually need.
1536 */
1537 if (shaderOrTexture && !deferredTexture) {
1538 shade_texture_span(ctx, span);
1539 }
1540
1541 /* Do the alpha test */
1542 if (ctx->Color.AlphaEnabled) {
1543 if (!_swrast_alpha_test(ctx, span)) {
1544 goto end;
1545 }
1546 }
1547
1548 /* Stencil and Z testing */
1549 if (ctx->Stencil.Enabled || ctx->Depth.Test) {
1550 if (span->interpMask & SPAN_Z)
1551 _swrast_span_interpolate_z(ctx, span);
1552
1553 if (ctx->Stencil.Enabled && ctx->DrawBuffer->Visual.stencilBits > 0) {
1554 /* Combined Z/stencil tests */
1555 if (!_swrast_stencil_and_ztest_span(ctx, span)) {
1556 goto end;
1557 }
1558 }
1559 else if (ctx->DrawBuffer->Visual.depthBits > 0) {
1560 /* Just regular depth testing */
1561 ASSERT(ctx->Depth.Test);
1562 ASSERT(span->arrayMask & SPAN_Z);
1563 if (!_swrast_depth_test_span(ctx, span)) {
1564 goto end;
1565 }
1566 }
1567 }
1568
1569 #if FEATURE_ARB_occlusion_query
1570 if (ctx->Query.CurrentOcclusionObject) {
1571 /* update count of 'passed' fragments */
1572 struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;
1573 GLuint i;
1574 for (i = 0; i < span->end; i++)
1575 q->Result += span->array->mask[i];
1576 }
1577 #endif
1578
1579 /* We had to wait until now to check for glColorMask(0,0,0,0) because of
1580 * the occlusion test.
1581 */
1582 if (colorMask == 0x0) {
1583 goto end;
1584 }
1585
1586 /* If we were able to defer fragment color computation to now, there's
1587 * a good chance that many fragments will have already been killed by
1588 * Z/stencil testing.
1589 */
1590 if (deferredTexture) {
1591 ASSERT(shaderOrTexture);
1592 shade_texture_span(ctx, span);
1593 }
1594
1595 if ((span->arrayMask & SPAN_RGBA) == 0) {
1596 interpolate_colors(span);
1597 }
1598
1599 ASSERT(span->arrayMask & SPAN_RGBA);
1600
1601 if (!shader) {
1602 /* Add base and specular colors */
1603 if (ctx->Fog.ColorSumEnabled ||
1604 (ctx->Light.Enabled &&
1605 ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
1606 if (span->interpMask & SPAN_SPEC) {
1607 interpolate_specular(span);
1608 }
1609 if (span->arrayMask & SPAN_SPEC) {
1610 add_specular(ctx, span);
1611 }
1612 else {
1613 /* We probably added the base/specular colors during the
1614 * vertex stage!
1615 */
1616 }
1617 }
1618 }
1619
1620 /* Fog */
1621 if (swrast->_FogEnabled) {
1622 _swrast_fog_rgba_span(ctx, span);
1623 }
1624
1625 /* Antialias coverage application */
1626 if (span->arrayMask & SPAN_COVERAGE) {
1627 apply_aa_coverage(span);
1628 }
1629
1630 /* Clamp color/alpha values over the range [0.0, 1.0] before storage */
1631 if (ctx->Color.ClampFragmentColor == GL_TRUE &&
1632 span->array->ChanType == GL_FLOAT) {
1633 clamp_colors(span);
1634 }
1635
1636 /*
1637 * Write to renderbuffers
1638 */
1639 {
1640 struct gl_framebuffer *fb = ctx->DrawBuffer;
1641 const GLuint output = 0; /* only frag progs can write to other outputs */
1642 const GLuint numDrawBuffers = fb->_NumColorDrawBuffers[output];
1643 GLchan rgbaSave[MAX_WIDTH][4];
1644 GLuint buf;
1645
1646 if (numDrawBuffers > 0) {
1647 if (fb->_ColorDrawBuffers[output][0]->DataType
1648 != span->array->ChanType) {
1649 convert_color_type(span,
1650 fb->_ColorDrawBuffers[output][0]->DataType);
1651 }
1652 }
1653
1654 if (numDrawBuffers > 1) {
1655 /* save colors for second, third renderbuffer writes */
1656 _mesa_memcpy(rgbaSave, span->array->rgba,
1657 4 * span->end * sizeof(GLchan));
1658 }
1659
1660 for (buf = 0; buf < numDrawBuffers; buf++) {
1661 struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[output][buf];
1662 ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB);
1663
1664 if (ctx->Color._LogicOpEnabled) {
1665 _swrast_logicop_rgba_span(ctx, rb, span);
1666 }
1667 else if (ctx->Color.BlendEnabled) {
1668 _swrast_blend_span(ctx, rb, span);
1669 }
1670
1671 if (colorMask != 0xffffffff) {
1672 _swrast_mask_rgba_span(ctx, rb, span);
1673 }
1674
1675 if (span->arrayMask & SPAN_XY) {
1676 /* array of pixel coords */
1677 ASSERT(rb->PutValues);
1678 rb->PutValues(ctx, rb, span->end,
1679 span->array->x, span->array->y,
1680 span->array->rgba, span->array->mask);
1681 }
1682 else {
1683 /* horizontal run of pixels */
1684 ASSERT(rb->PutRow);
1685 rb->PutRow(ctx, rb, span->end, span->x, span->y, span->array->rgba,
1686 span->writeAll ? NULL: span->array->mask);
1687 }
1688
1689 if (buf + 1 < numDrawBuffers) {
1690 /* restore original span values */
1691 _mesa_memcpy(span->array->rgba, rgbaSave,
1692 4 * span->end * sizeof(GLchan));
1693 }
1694 } /* for buf */
1695
1696 }
1697
1698 end:
1699 /* restore these values before returning */
1700 span->interpMask = origInterpMask;
1701 span->arrayMask = origArrayMask;
1702 span->array->ChanType = chanType;
1703 }
1704
1705
1706 /**
1707 * Read RGBA pixels from a renderbuffer. Clipping will be done to prevent
1708 * reading ouside the buffer's boundaries.
1709 * \param dstType datatype for returned colors
1710 * \param rgba the returned colors
1711 */
1712 void
1713 _swrast_read_rgba_span( GLcontext *ctx, struct gl_renderbuffer *rb,
1714 GLuint n, GLint x, GLint y, GLenum dstType,
1715 GLvoid *rgba)
1716 {
1717 const GLint bufWidth = (GLint) rb->Width;
1718 const GLint bufHeight = (GLint) rb->Height;
1719
1720 if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1721 /* completely above, below, or right */
1722 /* XXX maybe leave rgba values undefined? */
1723 _mesa_bzero(rgba, 4 * n * sizeof(GLchan));
1724 }
1725 else {
1726 GLint skip, length;
1727 if (x < 0) {
1728 /* left edge clipping */
1729 skip = -x;
1730 length = (GLint) n - skip;
1731 if (length < 0) {
1732 /* completely left of window */
1733 return;
1734 }
1735 if (length > bufWidth) {
1736 length = bufWidth;
1737 }
1738 }
1739 else if ((GLint) (x + n) > bufWidth) {
1740 /* right edge clipping */
1741 skip = 0;
1742 length = bufWidth - x;
1743 if (length < 0) {
1744 /* completely to right of window */
1745 return;
1746 }
1747 }
1748 else {
1749 /* no clipping */
1750 skip = 0;
1751 length = (GLint) n;
1752 }
1753
1754 ASSERT(rb);
1755 ASSERT(rb->GetRow);
1756 ASSERT(rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RGBA);
1757
1758 if (rb->DataType == dstType) {
1759 rb->GetRow(ctx, rb, length, x + skip, y,
1760 (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(rb->DataType));
1761 }
1762 else {
1763 GLuint temp[MAX_WIDTH * 4];
1764 rb->GetRow(ctx, rb, length, x + skip, y, temp);
1765 _mesa_convert_colors(rb->DataType, temp,
1766 dstType, (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(dstType),
1767 length, NULL);
1768 }
1769 }
1770 }
1771
1772
1773 /**
1774 * Read CI pixels from a renderbuffer. Clipping will be done to prevent
1775 * reading ouside the buffer's boundaries.
1776 */
1777 void
1778 _swrast_read_index_span( GLcontext *ctx, struct gl_renderbuffer *rb,
1779 GLuint n, GLint x, GLint y, GLuint index[] )
1780 {
1781 const GLint bufWidth = (GLint) rb->Width;
1782 const GLint bufHeight = (GLint) rb->Height;
1783
1784 if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1785 /* completely above, below, or right */
1786 _mesa_bzero(index, n * sizeof(GLuint));
1787 }
1788 else {
1789 GLint skip, length;
1790 if (x < 0) {
1791 /* left edge clipping */
1792 skip = -x;
1793 length = (GLint) n - skip;
1794 if (length < 0) {
1795 /* completely left of window */
1796 return;
1797 }
1798 if (length > bufWidth) {
1799 length = bufWidth;
1800 }
1801 }
1802 else if ((GLint) (x + n) > bufWidth) {
1803 /* right edge clipping */
1804 skip = 0;
1805 length = bufWidth - x;
1806 if (length < 0) {
1807 /* completely to right of window */
1808 return;
1809 }
1810 }
1811 else {
1812 /* no clipping */
1813 skip = 0;
1814 length = (GLint) n;
1815 }
1816
1817 ASSERT(rb->GetRow);
1818 ASSERT(rb->_BaseFormat == GL_COLOR_INDEX);
1819
1820 if (rb->DataType == GL_UNSIGNED_BYTE) {
1821 GLubyte index8[MAX_WIDTH];
1822 GLint i;
1823 rb->GetRow(ctx, rb, length, x + skip, y, index8);
1824 for (i = 0; i < length; i++)
1825 index[skip + i] = index8[i];
1826 }
1827 else if (rb->DataType == GL_UNSIGNED_SHORT) {
1828 GLushort index16[MAX_WIDTH];
1829 GLint i;
1830 rb->GetRow(ctx, rb, length, x + skip, y, index16);
1831 for (i = 0; i < length; i++)
1832 index[skip + i] = index16[i];
1833 }
1834 else if (rb->DataType == GL_UNSIGNED_INT) {
1835 rb->GetRow(ctx, rb, length, x + skip, y, index + skip);
1836 }
1837 }
1838 }
1839
1840
1841 /**
1842 * Wrapper for gl_renderbuffer::GetValues() which does clipping to avoid
1843 * reading values outside the buffer bounds.
1844 * We can use this for reading any format/type of renderbuffer.
1845 * \param valueSize is the size in bytes of each value (pixel) put into the
1846 * values array.
1847 */
1848 void
1849 _swrast_get_values(GLcontext *ctx, struct gl_renderbuffer *rb,
1850 GLuint count, const GLint x[], const GLint y[],
1851 void *values, GLuint valueSize)
1852 {
1853 GLuint i, inCount = 0, inStart = 0;
1854
1855 for (i = 0; i < count; i++) {
1856 if (x[i] >= 0 && y[i] >= 0 &&
1857 x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) {
1858 /* inside */
1859 if (inCount == 0)
1860 inStart = i;
1861 inCount++;
1862 }
1863 else {
1864 if (inCount > 0) {
1865 /* read [inStart, inStart + inCount) */
1866 rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart,
1867 (GLubyte *) values + inStart * valueSize);
1868 inCount = 0;
1869 }
1870 }
1871 }
1872 if (inCount > 0) {
1873 /* read last values */
1874 rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart,
1875 (GLubyte *) values + inStart * valueSize);
1876 }
1877 }
1878
1879
1880 /**
1881 * Wrapper for gl_renderbuffer::PutRow() which does clipping.
1882 * \param valueSize size of each value (pixel) in bytes
1883 */
1884 void
1885 _swrast_put_row(GLcontext *ctx, struct gl_renderbuffer *rb,
1886 GLuint count, GLint x, GLint y,
1887 const GLvoid *values, GLuint valueSize)
1888 {
1889 GLint skip = 0;
1890
1891 if (y < 0 || y >= (GLint) rb->Height)
1892 return; /* above or below */
1893
1894 if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
1895 return; /* entirely left or right */
1896
1897 if ((GLint) (x + count) > (GLint) rb->Width) {
1898 /* right clip */
1899 GLint clip = x + count - rb->Width;
1900 count -= clip;
1901 }
1902
1903 if (x < 0) {
1904 /* left clip */
1905 skip = -x;
1906 x = 0;
1907 count -= skip;
1908 }
1909
1910 rb->PutRow(ctx, rb, count, x, y,
1911 (const GLubyte *) values + skip * valueSize, NULL);
1912 }
1913
1914
1915 /**
1916 * Wrapper for gl_renderbuffer::GetRow() which does clipping.
1917 * \param valueSize size of each value (pixel) in bytes
1918 */
1919 void
1920 _swrast_get_row(GLcontext *ctx, struct gl_renderbuffer *rb,
1921 GLuint count, GLint x, GLint y,
1922 GLvoid *values, GLuint valueSize)
1923 {
1924 GLint skip = 0;
1925
1926 if (y < 0 || y >= (GLint) rb->Height)
1927 return; /* above or below */
1928
1929 if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
1930 return; /* entirely left or right */
1931
1932 if (x + count > rb->Width) {
1933 /* right clip */
1934 GLint clip = x + count - rb->Width;
1935 count -= clip;
1936 }
1937
1938 if (x < 0) {
1939 /* left clip */
1940 skip = -x;
1941 x = 0;
1942 count -= skip;
1943 }
1944
1945 rb->GetRow(ctx, rb, count, x, y, (GLubyte *) values + skip * valueSize);
1946 }
1947
1948
1949 /**
1950 * Get RGBA pixels from the given renderbuffer. Put the pixel colors into
1951 * the span's specular color arrays. The specular color arrays should no
1952 * longer be needed by time this function is called.
1953 * Used by blending, logicop and masking functions.
1954 * \return pointer to the colors we read.
1955 */
1956 void *
1957 _swrast_get_dest_rgba(GLcontext *ctx, struct gl_renderbuffer *rb,
1958 SWspan *span)
1959 {
1960 const GLuint pixelSize = RGBA_PIXEL_SIZE(span->array->ChanType);
1961 void *rbPixels;
1962
1963 /*
1964 * Determine pixel size (in bytes).
1965 * Point rbPixels to a temporary space (use specular color arrays).
1966 */
1967 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
1968 rbPixels = span->array->color.sz1.spec;
1969 }
1970 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
1971 rbPixels = span->array->color.sz2.spec;
1972 }
1973 else {
1974 rbPixels = span->array->attribs[FRAG_ATTRIB_COL1];
1975 }
1976
1977 /* Get destination values from renderbuffer */
1978 if (span->arrayMask & SPAN_XY) {
1979 _swrast_get_values(ctx, rb, span->end, span->array->x, span->array->y,
1980 rbPixels, pixelSize);
1981 }
1982 else {
1983 _swrast_get_row(ctx, rb, span->end, span->x, span->y,
1984 rbPixels, pixelSize);
1985 }
1986
1987 return rbPixels;
1988 }