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