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