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