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