X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fswrast%2Fs_span.c;h=41db42e2b80726689fe1b1fdf39acdb224fab2f3;hb=1a544b0500ebacb52a7412ad17c4a2002a00ff94;hp=cb62a8a10bf1edebb0214ecb7ec017fc932260f2;hpb=c499ce31baf820e84d133c2189f88e15a1a36672;p=mesa.git diff --git a/src/mesa/swrast/s_span.c b/src/mesa/swrast/s_span.c index cb62a8a10bf..41db42e2b80 100644 --- a/src/mesa/swrast/s_span.c +++ b/src/mesa/swrast/s_span.c @@ -1,21 +1,19 @@ -/* $Id: s_span.c,v 1.9 2001/02/20 16:42:26 brianp Exp $ */ - /* * Mesa 3-D graphics library - * Version: 3.5 - * - * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. - * + * Version: 6.1 + * + * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. + * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -25,16 +23,18 @@ */ -/* - * pixel span rasterization: - * These functions implement the rasterization pipeline. +/** + * \file swrast/s_span.c + * \brief Span processing functions used by all rasterization functions. + * This is where all the per-fragment tests are performed + * \author Brian Paul */ - #include "glheader.h" #include "colormac.h" +#include "context.h" #include "macros.h" -#include "mem.h" +#include "imports.h" #include "s_alpha.h" #include "s_alphabuf.h" @@ -44,1028 +44,1513 @@ #include "s_fog.h" #include "s_logic.h" #include "s_masking.h" -#include "s_scissor.h" +#include "s_nvfragprog.h" #include "s_span.h" #include "s_stencil.h" #include "s_texture.h" - - -/* - * Apply the current polygon stipple pattern to a span of pixels. +/** + * Init span's Z interpolation values to the RasterPos Z. + * Used during setup for glDraw/CopyPixels. */ -static void stipple_polygon_span( GLcontext *ctx, - GLuint n, GLint x, GLint y, GLubyte mask[] ) +void +_swrast_span_default_z( GLcontext *ctx, struct sw_span *span ) { - const GLuint highbit = 0x80000000; - GLuint i, m, stipple; + if (ctx->Visual.depthBits <= 16) + span->z = FloatToFixed(ctx->Current.RasterPos[2] * ctx->DepthMax + 0.5F); + else + span->z = (GLint) (ctx->Current.RasterPos[2] * ctx->DepthMax + 0.5F); + span->zStep = 0; + span->interpMask |= SPAN_Z; +} - stipple = ctx->PolygonStipple[y % 32]; - m = highbit >> (GLuint) (x % 32); - for (i = 0; i < n; i++) { - if ((m & stipple) == 0) { - mask[i] = 0; - } - m = m >> 1; - if (m == 0) { - m = highbit; - } - } +/** + * Init span's fog interpolation values to the RasterPos fog. + * Used during setup for glDraw/CopyPixels. + */ +void +_swrast_span_default_fog( GLcontext *ctx, struct sw_span *span ) +{ + span->fog = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance); + span->fogStep = span->dfogdx = span->dfogdy = 0.0F; + span->interpMask |= SPAN_FOG; } - -/* - * Clip a pixel span to the current buffer/window boundaries. - * Return: 'n' such that pixel 'n', 'n+1' etc. are clipped, - * as a special case: - * 0 = all pixels clipped +/** + * Init span's color or index interpolation values to the RasterPos color. + * Used during setup for glDraw/CopyPixels. */ -static GLuint clip_span( GLcontext *ctx, - GLint n, GLint x, GLint y, GLubyte mask[] ) +void +_swrast_span_default_color( GLcontext *ctx, struct sw_span *span ) { - /* Clip to top and bottom */ - if (y < 0 || y >= ctx->DrawBuffer->Height) { - return 0; + if (ctx->Visual.rgbMode) { + GLchan r, g, b, a; + UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]); + UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]); + UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]); + UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]); +#if CHAN_TYPE == GL_FLOAT + span->red = r; + span->green = g; + span->blue = b; + span->alpha = a; +#else + span->red = IntToFixed(r); + span->green = IntToFixed(g); + span->blue = IntToFixed(b); + span->alpha = IntToFixed(a); +#endif + span->redStep = 0; + span->greenStep = 0; + span->blueStep = 0; + span->alphaStep = 0; + span->interpMask |= SPAN_RGBA; } - - /* Clip to the left */ - if (x < 0) { - if (x + n <= 0) { - /* completely off left side */ - return 0; - } - else { - /* partially off left side */ - BZERO(mask, -x * sizeof(GLubyte)); - } + else { + span->index = FloatToFixed(ctx->Current.RasterIndex); + span->indexStep = 0; + span->interpMask |= SPAN_INDEX; } +} - /* Clip to right */ - if (x + n > ctx->DrawBuffer->Width) { - if (x >= ctx->DrawBuffer->Width) { - /* completely off right side */ - return 0; + +/** + * Init span's texcoord interpolation values to the RasterPos texcoords. + * Used during setup for glDraw/CopyPixels. + */ +void +_swrast_span_default_texcoords( GLcontext *ctx, struct sw_span *span ) +{ + GLuint i; + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + const GLfloat *tc = ctx->Current.RasterTexCoords[i]; + if (tc[3] > 0.0F) { + /* use (s/q, t/q, r/q, 1) */ + span->tex[i][0] = tc[0] / tc[3]; + span->tex[i][1] = tc[1] / tc[3]; + span->tex[i][2] = tc[2] / tc[3]; + span->tex[i][3] = 1.0; } else { - /* partially off right side */ - return ctx->DrawBuffer->Width - x; + ASSIGN_4V(span->tex[i], 0.0F, 0.0F, 0.0F, 1.0F); } + ASSIGN_4V(span->texStepX[i], 0.0F, 0.0F, 0.0F, 0.0F); + ASSIGN_4V(span->texStepY[i], 0.0F, 0.0F, 0.0F, 0.0F); } - - return n; + span->interpMask |= SPAN_TEXTURE; } - -/* - * Draw to more than one color buffer (or none). - */ -static void multi_write_index_span( GLcontext *ctx, GLuint n, - GLint x, GLint y, const GLuint indexes[], - const GLubyte mask[] ) +/* Fill in the span.color.rgba array from the interpolation values */ +static void +interpolate_colors(GLcontext *ctx, struct sw_span *span) { - GLuint bufferBit; - - if (ctx->Color.DrawBuffer == GL_NONE) - return; - - /* loop over four possible dest color buffers */ - for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) { - if (bufferBit & ctx->Color.DrawDestMask) { - GLuint indexTmp[MAX_WIDTH]; - ASSERT(n < MAX_WIDTH); + const GLuint n = span->end; + GLchan (*rgba)[4] = span->array->rgba; + GLuint i; - if (bufferBit == FRONT_LEFT_BIT) - (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT); - else if (bufferBit == FRONT_RIGHT_BIT) - (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT); - else if (bufferBit == BACK_LEFT_BIT) - (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT); - else - (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT); + ASSERT((span->interpMask & SPAN_RGBA) && + !(span->arrayMask & SPAN_RGBA)); - /* make copy of incoming indexes */ - MEMCPY( indexTmp, indexes, n * sizeof(GLuint) ); - if (ctx->Color.IndexLogicOpEnabled) { - _mesa_logicop_ci_span( ctx, n, x, y, indexTmp, mask ); - } - if (ctx->Color.IndexMask == 0) { - break; - } - else if (ctx->Color.IndexMask != 0xffffffff) { - _mesa_mask_index_span( ctx, n, x, y, indexTmp ); - } - (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexTmp, mask ); + if (span->interpMask & SPAN_FLAT) { + /* constant color */ + GLchan color[4]; + color[RCOMP] = FixedToChan(span->red); + color[GCOMP] = FixedToChan(span->green); + color[BCOMP] = FixedToChan(span->blue); + color[ACOMP] = FixedToChan(span->alpha); + for (i = 0; i < n; i++) { + COPY_CHAN4(span->array->rgba[i], color); } } - - /* restore default dest buffer */ - (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer); + else { + /* interpolate */ +#if CHAN_TYPE == GL_FLOAT + GLfloat r = span->red; + GLfloat g = span->green; + GLfloat b = span->blue; + GLfloat a = span->alpha; + const GLfloat dr = span->redStep; + const GLfloat dg = span->greenStep; + const GLfloat db = span->blueStep; + const GLfloat da = span->alphaStep; +#else + GLfixed r = span->red; + GLfixed g = span->green; + GLfixed b = span->blue; + GLfixed a = span->alpha; + const GLint dr = span->redStep; + const GLint dg = span->greenStep; + const GLint db = span->blueStep; + const GLint da = span->alphaStep; +#endif + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = FixedToChan(r); + rgba[i][GCOMP] = FixedToChan(g); + rgba[i][BCOMP] = FixedToChan(b); + rgba[i][ACOMP] = FixedToChan(a); + r += dr; + g += dg; + b += db; + a += da; + } + } + span->arrayMask |= SPAN_RGBA; } - -/* - * Write a horizontal span of color index pixels to the frame buffer. - * Stenciling, Depth-testing, etc. are done as needed. - * Input: n - number of pixels in the span - * x, y - location of leftmost pixel in the span - * z - array of [n] z-values - * index - array of [n] color indexes - * primitive - either GL_POINT, GL_LINE, GL_POLYGON, or GL_BITMAP - */ -void gl_write_index_span( GLcontext *ctx, - GLuint n, GLint x, GLint y, const GLdepth z[], - const GLfixed fog[], - GLuint indexIn[], GLenum primitive ) +/* Fill in the span.color.index array from the interpolation values */ +static void +interpolate_indexes(GLcontext *ctx, struct sw_span *span) { - const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | LOGIC_OP_BIT; - GLubyte mask[MAX_WIDTH]; - GLuint indexBackup[MAX_WIDTH]; - GLuint *index; /* points to indexIn or indexBackup */ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - - /* init mask to 1's (all pixels are to be written) */ - MEMSET(mask, 1, n); + GLfixed index = span->index; + const GLint indexStep = span->indexStep; + const GLuint n = span->end; + GLuint *indexes = span->array->index; + GLuint i; + ASSERT((span->interpMask & SPAN_INDEX) && + !(span->arrayMask & SPAN_INDEX)); - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if ((n = clip_span(ctx,n,x,y,mask)) == 0) { - return; + if ((span->interpMask & SPAN_FLAT) || (indexStep == 0)) { + /* constant color */ + index = FixedToInt(index); + for (i = 0; i < n; i++) { + indexes[i] = index; } } - - if ((primitive==GL_BITMAP && (swrast->_RasterMask & modBits)) - || (swrast->_RasterMask & MULTI_DRAW_BIT)) { - /* Make copy of color indexes */ - MEMCPY( indexBackup, indexIn, n * sizeof(GLuint) ); - index = indexBackup; - } else { - index = indexIn; + /* interpolate */ + for (i = 0; i < n; i++) { + indexes[i] = FixedToInt(index); + index += indexStep; + } } + span->arrayMask |= SPAN_INDEX; +} - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { - return; +/* Fill in the span.->array->spec array from the interpolation values */ +static void +interpolate_specular(GLcontext *ctx, struct sw_span *span) +{ + if (span->interpMask & SPAN_FLAT) { + /* constant color */ + const GLchan r = FixedToChan(span->specRed); + const GLchan g = FixedToChan(span->specGreen); + const GLchan b = FixedToChan(span->specBlue); + GLuint i; + for (i = 0; i < span->end; i++) { + span->array->spec[i][RCOMP] = r; + span->array->spec[i][GCOMP] = g; + span->array->spec[i][BCOMP] = b; } } + else { + /* interpolate */ +#if CHAN_TYPE == GL_FLOAT + GLfloat r = span->specRed; + GLfloat g = span->specGreen; + GLfloat b = span->specBlue; +#else + GLfixed r = span->specRed; + GLfixed g = span->specGreen; + GLfixed b = span->specBlue; +#endif + GLuint i; + for (i = 0; i < span->end; i++) { + span->array->spec[i][RCOMP] = FixedToChan(r); + span->array->spec[i][GCOMP] = FixedToChan(g); + span->array->spec[i][BCOMP] = FixedToChan(b); + r += span->specRedStep; + g += span->specGreenStep; + b += span->specBlueStep; + } + } + span->arrayMask |= SPAN_SPEC; +} - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, n, x, y, mask ); - } - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { - return; +/* Fill in the span.zArray array from the interpolation values */ +void +_swrast_span_interpolate_z( const GLcontext *ctx, struct sw_span *span ) +{ + const GLuint n = span->end; + GLuint i; + + ASSERT((span->interpMask & SPAN_Z) && + !(span->arrayMask & SPAN_Z)); + + if (ctx->Visual.depthBits <= 16) { + GLfixed zval = span->z; + GLdepth *z = span->array->z; + for (i = 0; i < n; i++) { + z[i] = FixedToInt(zval); + zval += span->zStep; } } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span( ctx, n, x, y, z, mask ) == 0) - return; + else { + /* Deep Z buffer, no fixed->int shift */ + GLfixed zval = span->z; + GLdepth *z = span->array->z; + for (i = 0; i < n; i++) { + z[i] = zval; + zval += span->zStep; + } } + span->arrayMask |= SPAN_Z; +} - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if (fog && !swrast->_PreferPixelFog) - _mesa_fog_ci_pixels( ctx, n, fog, index ); - else - _mesa_depth_fog_ci_pixels( ctx, n, z, index ); - } +/* + * This the ideal solution, as given in the OpenGL spec. + */ +#if 0 +static GLfloat +compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy, + GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH, + GLfloat s, GLfloat t, GLfloat q, GLfloat invQ) +{ + GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ); + GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ); + GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ); + GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ); + GLfloat x = SQRTF(dudx * dudx + dvdx * dvdx); + GLfloat y = SQRTF(dudy * dudy + dvdy * dvdy); + GLfloat rho = MAX2(x, y); + GLfloat lambda = LOG2(rho); + return lambda; +} +#endif - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - /* draw to zero or two or more buffers */ - multi_write_index_span( ctx, n, x, y, index, mask ); + +/* + * This is a faster approximation + */ +GLfloat +_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy, + GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH, + GLfloat s, GLfloat t, GLfloat q, GLfloat invQ) +{ + GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ; + GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ; + GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ; + GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ; + GLfloat maxU, maxV, rho, lambda; + dsdx2 = FABSF(dsdx2); + dsdy2 = FABSF(dsdy2); + dtdx2 = FABSF(dtdx2); + dtdy2 = FABSF(dtdy2); + maxU = MAX2(dsdx2, dsdy2) * texW; + maxV = MAX2(dtdx2, dtdy2) * texH; + rho = MAX2(maxU, maxV); + lambda = LOG2(rho); + return lambda; +} + + +/** + * Fill in the span.texcoords array from the interpolation values. + * Note: in the places where we divide by Q (or mult by invQ) we're + * really doing two things: perspective correction and texcoord + * projection. Remember, for texcoord (s,t,r,q) we need to index + * texels with (s/q, t/q, r/q). + * If we're using a fragment program, we never do the division + * for texcoord projection. That's done by the TXP instruction + * or user-written code. + */ +static void +interpolate_texcoords(GLcontext *ctx, struct sw_span *span) +{ + ASSERT(span->interpMask & SPAN_TEXTURE); + ASSERT(!(span->arrayMask & SPAN_TEXTURE)); + + if (ctx->Texture._EnabledCoordUnits > 1) { + /* multitexture */ + GLuint u; + span->arrayMask |= SPAN_TEXTURE; + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + if (ctx->Texture._EnabledCoordUnits & (1 << u)) { + const struct gl_texture_object *obj =ctx->Texture.Unit[u]._Current; + GLfloat texW, texH; + GLboolean needLambda; + if (obj) { + const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel]; + needLambda = (obj->MinFilter != obj->MagFilter) + || ctx->FragmentProgram._Enabled; + texW = img->WidthScale; + texH = img->HeightScale; + } + else { + /* using a fragment program */ + texW = 1.0; + texH = 1.0; + needLambda = GL_FALSE; + } + if (needLambda) { + GLfloat (*texcoord)[4] = span->array->texcoords[u]; + GLfloat *lambda = span->array->lambda[u]; + const GLfloat dsdx = span->texStepX[u][0]; + const GLfloat dsdy = span->texStepY[u][0]; + const GLfloat dtdx = span->texStepX[u][1]; + const GLfloat dtdy = span->texStepY[u][1]; + const GLfloat drdx = span->texStepX[u][2]; + const GLfloat dqdx = span->texStepX[u][3]; + const GLfloat dqdy = span->texStepY[u][3]; + GLfloat s = span->tex[u][0]; + GLfloat t = span->tex[u][1]; + GLfloat r = span->tex[u][2]; + GLfloat q = span->tex[u][3]; + GLuint i; + if (ctx->FragmentProgram._Enabled) { + /* do perspective correction but don't divide s, t, r by q */ + const GLfloat dwdx = span->dwdx; + GLfloat w = span->w; + for (i = 0; i < span->end; i++) { + const GLfloat invW = 1.0F / w; + texcoord[i][0] = s * invW; + texcoord[i][1] = t * invW; + texcoord[i][2] = r * invW; + texcoord[i][3] = q * invW; + lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy, + dqdx, dqdy, texW, texH, + s, t, q, invW); + s += dsdx; + t += dtdx; + r += drdx; + q += dqdx; + w += dwdx; + } + + } + else { + for (i = 0; i < span->end; i++) { + const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); + texcoord[i][0] = s * invQ; + texcoord[i][1] = t * invQ; + texcoord[i][2] = r * invQ; + texcoord[i][3] = q; + lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy, + dqdx, dqdy, texW, texH, + s, t, q, invQ); + s += dsdx; + t += dtdx; + r += drdx; + q += dqdx; + } + } + span->arrayMask |= SPAN_LAMBDA; + } + else { + GLfloat (*texcoord)[4] = span->array->texcoords[u]; + GLfloat *lambda = span->array->lambda[u]; + const GLfloat dsdx = span->texStepX[u][0]; + const GLfloat dtdx = span->texStepX[u][1]; + const GLfloat drdx = span->texStepX[u][2]; + const GLfloat dqdx = span->texStepX[u][3]; + GLfloat s = span->tex[u][0]; + GLfloat t = span->tex[u][1]; + GLfloat r = span->tex[u][2]; + GLfloat q = span->tex[u][3]; + GLuint i; + if (ctx->FragmentProgram._Enabled) { + /* do perspective correction but don't divide s, t, r by q */ + const GLfloat dwdx = span->dwdx; + GLfloat w = span->w; + for (i = 0; i < span->end; i++) { + const GLfloat invW = 1.0F / w; + texcoord[i][0] = s * invW; + texcoord[i][1] = t * invW; + texcoord[i][2] = r * invW; + texcoord[i][3] = q * invW; + lambda[i] = 0.0; + s += dsdx; + t += dtdx; + r += drdx; + q += dqdx; + w += dwdx; + } + } + else if (dqdx == 0.0F) { + /* Ortho projection or polygon's parallel to window X axis */ + const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); + for (i = 0; i < span->end; i++) { + texcoord[i][0] = s * invQ; + texcoord[i][1] = t * invQ; + texcoord[i][2] = r * invQ; + texcoord[i][3] = q; + lambda[i] = 0.0; + s += dsdx; + t += dtdx; + r += drdx; + } + } + else { + for (i = 0; i < span->end; i++) { + const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); + texcoord[i][0] = s * invQ; + texcoord[i][1] = t * invQ; + texcoord[i][2] = r * invQ; + texcoord[i][3] = q; + lambda[i] = 0.0; + s += dsdx; + t += dtdx; + r += drdx; + q += dqdx; + } + } + } /* lambda */ + } /* if */ + } /* for */ } else { - /* normal situation: draw to exactly one buffer */ - if (ctx->Color.IndexLogicOpEnabled) { - _mesa_logicop_ci_span( ctx, n, x, y, index, mask ); + /* single texture */ + const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current; + GLfloat texW, texH; + GLboolean needLambda; + if (obj) { + const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel]; + needLambda = (obj->MinFilter != obj->MagFilter) + || ctx->FragmentProgram._Enabled; + texW = (GLfloat) img->WidthScale; + texH = (GLfloat) img->HeightScale; } - - if (ctx->Color.IndexMask == 0) { - return; + else { + needLambda = GL_FALSE; + texW = texH = 1.0; + } + span->arrayMask |= SPAN_TEXTURE; + if (needLambda) { + /* just texture unit 0, with lambda */ + GLfloat (*texcoord)[4] = span->array->texcoords[0]; + GLfloat *lambda = span->array->lambda[0]; + const GLfloat dsdx = span->texStepX[0][0]; + const GLfloat dsdy = span->texStepY[0][0]; + const GLfloat dtdx = span->texStepX[0][1]; + const GLfloat dtdy = span->texStepY[0][1]; + const GLfloat drdx = span->texStepX[0][2]; + const GLfloat dqdx = span->texStepX[0][3]; + const GLfloat dqdy = span->texStepY[0][3]; + GLfloat s = span->tex[0][0]; + GLfloat t = span->tex[0][1]; + GLfloat r = span->tex[0][2]; + GLfloat q = span->tex[0][3]; + GLuint i; + if (ctx->FragmentProgram._Enabled) { + /* do perspective correction but don't divide s, t, r by q */ + const GLfloat dwdx = span->dwdx; + GLfloat w = span->w; + for (i = 0; i < span->end; i++) { + const GLfloat invW = 1.0F / w; + texcoord[i][0] = s * invW; + texcoord[i][1] = t * invW; + texcoord[i][2] = r * invW; + texcoord[i][3] = q * invW; + lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy, + dqdx, dqdy, texW, texH, + s, t, q, invW); + s += dsdx; + t += dtdx; + r += drdx; + q += dqdx; + w += dwdx; + } + } + else { + /* tex.c */ + for (i = 0; i < span->end; i++) { + const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); + lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy, + dqdx, dqdy, texW, texH, + s, t, q, invQ); + texcoord[i][0] = s * invQ; + texcoord[i][1] = t * invQ; + texcoord[i][2] = r * invQ; + texcoord[i][3] = q; + s += dsdx; + t += dtdx; + r += drdx; + q += dqdx; + } + } + span->arrayMask |= SPAN_LAMBDA; } - else if (ctx->Color.IndexMask != 0xffffffff) { - _mesa_mask_index_span( ctx, n, x, y, index ); + else { + /* just texture 0, without lambda */ + GLfloat (*texcoord)[4] = span->array->texcoords[0]; + const GLfloat dsdx = span->texStepX[0][0]; + const GLfloat dtdx = span->texStepX[0][1]; + const GLfloat drdx = span->texStepX[0][2]; + const GLfloat dqdx = span->texStepX[0][3]; + GLfloat s = span->tex[0][0]; + GLfloat t = span->tex[0][1]; + GLfloat r = span->tex[0][2]; + GLfloat q = span->tex[0][3]; + GLuint i; + if (ctx->FragmentProgram._Enabled) { + /* do perspective correction but don't divide s, t, r by q */ + const GLfloat dwdx = span->dwdx; + GLfloat w = span->w; + for (i = 0; i < span->end; i++) { + const GLfloat invW = 1.0F / w; + texcoord[i][0] = s * invW; + texcoord[i][1] = t * invW; + texcoord[i][2] = r * invW; + texcoord[i][3] = q * invW; + s += dsdx; + t += dtdx; + r += drdx; + q += dqdx; + w += dwdx; + } + } + else if (dqdx == 0.0F) { + /* Ortho projection or polygon's parallel to window X axis */ + const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); + for (i = 0; i < span->end; i++) { + texcoord[i][0] = s * invQ; + texcoord[i][1] = t * invQ; + texcoord[i][2] = r * invQ; + texcoord[i][3] = q; + s += dsdx; + t += dtdx; + r += drdx; + } + } + else { + for (i = 0; i < span->end; i++) { + const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); + texcoord[i][0] = s * invQ; + texcoord[i][1] = t * invQ; + texcoord[i][2] = r * invQ; + texcoord[i][3] = q; + s += dsdx; + t += dtdx; + r += drdx; + q += dqdx; + } + } } - - /* write pixels */ - (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, index, mask ); } } - - -void gl_write_monoindex_span( GLcontext *ctx, - GLuint n, GLint x, GLint y, - const GLdepth z[], - const GLfixed fog[], - GLuint index, GLenum primitive ) +/** + * Apply the current polygon stipple pattern to a span of pixels. + */ +static void +stipple_polygon_span( GLcontext *ctx, struct sw_span *span ) { - SWcontext *swrast = SWRAST_CONTEXT(ctx); - GLubyte mask[MAX_WIDTH]; - GLuint i; + const GLuint highbit = 0x80000000; + const GLuint stipple = ctx->PolygonStipple[span->y % 32]; + GLubyte *mask = span->array->mask; + GLuint i, m; - /* init mask to 1's (all pixels are to be written) */ - MEMSET(mask, 1, n); + ASSERT(ctx->Polygon.StippleFlag); + ASSERT((span->arrayMask & SPAN_XY) == 0); - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if ((n = clip_span( ctx, n, x, y, mask)) == 0) { - return; + m = highbit >> (GLuint) (span->x % 32); + + for (i = 0; i < span->end; i++) { + if ((m & stipple) == 0) { + mask[i] = 0; + } + m = m >> 1; + if (m == 0) { + m = highbit; } } + span->writeAll = GL_FALSE; +} - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { - return; + +/** + * Clip a pixel span to the current buffer/window boundaries: + * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax. This will accomplish + * window clipping and scissoring. + * Return: GL_TRUE some pixels still visible + * GL_FALSE nothing visible + */ +static GLuint +clip_span( GLcontext *ctx, struct sw_span *span ) +{ + const GLint xmin = ctx->DrawBuffer->_Xmin; + const GLint xmax = ctx->DrawBuffer->_Xmax; + const GLint ymin = ctx->DrawBuffer->_Ymin; + const GLint ymax = ctx->DrawBuffer->_Ymax; + + if (span->arrayMask & SPAN_XY) { + /* arrays of x/y pixel coords */ + const GLint *x = span->array->x; + const GLint *y = span->array->y; + const GLint n = span->end; + GLubyte *mask = span->array->mask; + GLint i; + if (span->arrayMask & SPAN_MASK) { + /* note: using & intead of && to reduce branches */ + for (i = 0; i < n; i++) { + mask[i] &= (x[i] >= xmin) & (x[i] < xmax) + & (y[i] >= ymin) & (y[i] < ymax); + } } + else { + /* note: using & intead of && to reduce branches */ + for (i = 0; i < n; i++) { + mask[i] = (x[i] >= xmin) & (x[i] < xmax) + & (y[i] >= ymin) & (y[i] < ymax); + } + } + return GL_TRUE; /* some pixels visible */ } + else { + /* horizontal span of pixels */ + const GLint x = span->x; + const GLint y = span->y; + const GLint n = span->end; - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, n, x, y, mask ); - } + /* Trivial rejection tests */ + if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) { + span->end = 0; + return GL_FALSE; /* all pixels clipped */ + } - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { - return; + /* Clip to the left */ + if (x < xmin) { + ASSERT(x + n > xmin); + span->writeAll = GL_FALSE; + _mesa_bzero(span->array->mask, (xmin - x) * sizeof(GLubyte)); } - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span( ctx, n, x, y, z, mask ) == 0) - return; - } - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; + /* Clip to right */ + if (x + n > xmax) { + ASSERT(x < xmax); + span->end = xmax - x; + } - if (ctx->Color.DrawBuffer == GL_NONE) { - /* write no pixels */ - return; + return GL_TRUE; /* some pixels visible */ } +} - if (ctx->Fog.Enabled - || ctx->Color.IndexLogicOpEnabled - || ctx->Color.IndexMask != 0xffffffff) { - /* different index per pixel */ - GLuint indexes[MAX_WIDTH]; - for (i = 0; i < n; i++) { - indexes[i] = index; - } - if (ctx->Fog.Enabled) { - if (fog && !swrast->_PreferPixelFog) - _mesa_fog_ci_pixels( ctx, n, fog, indexes ); - else - _mesa_depth_fog_ci_pixels( ctx, n, z, indexes ); - } - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - /* draw to zero or two or more buffers */ - multi_write_index_span( ctx, n, x, y, indexes, mask ); - } - else { - /* normal situation: draw to exactly one buffer */ +/** + * Draw to more than one color buffer (or none). + */ +static void +multi_write_index_span( GLcontext *ctx, struct sw_span *span ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + GLuint bufferBit; + + /* loop over four possible dest color buffers */ + for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) { + if (bufferBit & ctx->Color._DrawDestMask) { + GLuint indexTmp[MAX_WIDTH]; + ASSERT(span->end < MAX_WIDTH); + + /* Set the current read/draw buffer */ + swrast->CurrentBufferBit = bufferBit; + (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, bufferBit); + + /* make copy of incoming indexes */ + MEMCPY( indexTmp, span->array->index, span->end * sizeof(GLuint) ); + if (ctx->Color.IndexLogicOpEnabled) { - _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask ); + _swrast_logicop_ci_span(ctx, span, indexTmp); } - if (ctx->Color.IndexMask == 0) { - return; + + if (ctx->Color.IndexMask != 0xffffffff) { + _swrast_mask_index_span(ctx, span, indexTmp); } - else if (ctx->Color.IndexMask != 0xffffffff) { - _mesa_mask_index_span( ctx, n, x, y, indexes ); + + if (span->arrayMask & SPAN_XY) { + /* array of pixel coords */ + (*swrast->Driver.WriteCI32Pixels)(ctx, span->end, + span->array->x, span->array->y, + indexTmp, span->array->mask); + } + else { + /* horizontal run of pixels */ + (*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y, + indexTmp, span->array->mask); } - (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexes, mask ); - } - } - else { - /* same color index for all pixels */ - ASSERT(!ctx->Color.IndexLogicOpEnabled); - ASSERT(ctx->Color.IndexMask == 0xffffffff); - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - /* draw to zero or two or more buffers */ - GLuint indexes[MAX_WIDTH]; - for (i = 0; i < n; i++) - indexes[i] = index; - multi_write_index_span( ctx, n, x, y, indexes, mask ); - } - else { - /* normal situation: draw to exactly one buffer */ - (*ctx->Driver.WriteMonoCISpan)( ctx, n, x, y, index, mask ); } } -} + /* restore default dest buffer */ + _swrast_use_draw_buffer(ctx); +} -/* +/** * Draw to more than one RGBA color buffer (or none). + * All fragment operations, up to (but not) blending/logicop should + * have been done first. */ -static void multi_write_rgba_span( GLcontext *ctx, GLuint n, - GLint x, GLint y, CONST GLchan rgba[][4], - const GLubyte mask[] ) +static void +multi_write_rgba_span( GLcontext *ctx, struct sw_span *span ) { const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); GLuint bufferBit; SWcontext *swrast = SWRAST_CONTEXT(ctx); + ASSERT(colorMask != 0x0); + if (ctx->Color.DrawBuffer == GL_NONE) return; /* loop over four possible dest color buffers */ - for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) { - if (bufferBit & ctx->Color.DrawDestMask) { + for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) { + if (bufferBit & ctx->Color._DrawDestMask) { GLchan rgbaTmp[MAX_WIDTH][4]; - ASSERT(n < MAX_WIDTH); + ASSERT(span->end < MAX_WIDTH); - if (bufferBit == FRONT_LEFT_BIT) { - (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT); - ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha; - } - else if (bufferBit == FRONT_RIGHT_BIT) { - (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT); - ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha; - } - else if (bufferBit == BACK_LEFT_BIT) { - (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT); - ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha; - } - else { - (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT); - ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha; - } + /* Set the current read/draw buffer */ + swrast->CurrentBufferBit = bufferBit; + (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, bufferBit); /* make copy of incoming colors */ - MEMCPY( rgbaTmp, rgba, 4 * n * sizeof(GLchan) ); + MEMCPY( rgbaTmp, span->array->rgba, 4 * span->end * sizeof(GLchan) ); - if (ctx->Color.ColorLogicOpEnabled) { - _mesa_logicop_rgba_span( ctx, n, x, y, rgbaTmp, mask ); + if (ctx->Color._LogicOpEnabled) { + _swrast_logicop_rgba_span(ctx, span, rgbaTmp); } else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, n, x, y, rgbaTmp, mask ); - } - if (colorMask == 0x0) { - break; + _swrast_blend_span(ctx, span, rgbaTmp); } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, n, x, y, rgbaTmp ); + + if (colorMask != 0xffffffff) { + _swrast_mask_rgba_span(ctx, span, rgbaTmp); } - (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, - (const GLchan (*)[4]) rgbaTmp, mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, n, x, y, - (const GLchan (*)[4])rgbaTmp, mask ); + if (span->arrayMask & SPAN_XY) { + /* array of pixel coords */ + (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, + span->array->x, span->array->y, + (const GLchan (*)[4]) rgbaTmp, + span->array->mask); + if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) { + _swrast_write_alpha_pixels(ctx, span->end, + span->array->x, span->array->y, + (const GLchan (*)[4]) rgbaTmp, + span->array->mask); + } + } + else { + /* horizontal run of pixels */ + (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y, + (const GLchan (*)[4]) rgbaTmp, + span->array->mask); + if (swrast->_RasterMask & ALPHABUF_BIT) { + _swrast_write_alpha_span(ctx, span->end, span->x, span->y, + (const GLchan (*)[4]) rgbaTmp, + span->array->mask); + } } } } /* restore default dest buffer */ - (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer ); + _swrast_use_draw_buffer(ctx); } -void gl_write_rgba_span( GLcontext *ctx, - GLuint n, GLint x, GLint y, const GLdepth z[], - const GLfixed *fog, - GLchan rgbaIn[][4], - GLenum primitive ) +/** + * This function may modify any of the array values in the span. + * span->interpMask and span->arrayMask may be changed but will be restored + * to their original values before returning. + */ +void +_swrast_write_index_span( GLcontext *ctx, struct sw_span *span) { - const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | - LOGIC_OP_BIT | TEXTURE_BIT; - GLubyte mask[MAX_WIDTH]; - GLboolean write_all = GL_TRUE; - GLchan rgbaBackup[MAX_WIDTH][4]; - GLchan (*rgba)[4]; - const GLubyte *Null = 0; SWcontext *swrast = SWRAST_CONTEXT(ctx); + const GLuint origInterpMask = span->interpMask; + const GLuint origArrayMask = span->arrayMask; - /* init mask to 1's (all pixels are to be written) */ - MEMSET(mask, 1, n); + ASSERT(span->end <= MAX_WIDTH); + ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE || + span->primitive == GL_POLYGON || span->primitive == GL_BITMAP); + ASSERT((span->interpMask | span->arrayMask) & SPAN_INDEX); + ASSERT((span->interpMask & span->arrayMask) == 0); - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if ((n = clip_span( ctx,n,x,y,mask)) == 0) { - return; - } - if (mask[0] == 0) - write_all = GL_FALSE; - } - - if ((primitive==GL_BITMAP && (swrast->_RasterMask & modBits)) - || (swrast->_RasterMask & MULTI_DRAW_BIT)) { - /* must make a copy of the colors since they may be modified */ - MEMCPY( rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan) ); - rgba = rgbaBackup; + if (span->arrayMask & SPAN_MASK) { + /* mask was initialized by caller, probably glBitmap */ + span->writeAll = GL_FALSE; } else { - rgba = rgbaIn; + MEMSET(span->array->mask, 1, span->end); + span->writeAll = GL_TRUE; } - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { + /* Clipping */ + if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) { + if (!clip_span(ctx, span)) { return; } - if (mask[0] == 0) - write_all = GL_FALSE; } - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, n, x, y, mask ); - write_all = GL_FALSE; + /* Depth bounds test */ + if (ctx->Depth.BoundsTest && ctx->Visual.depthBits > 0) { + if (!_swrast_depth_bounds_test(ctx, span)) { + return; + } } - /* Do the alpha test */ - if (ctx->Color.AlphaEnabled) { - if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask ) == 0) { - return; +#ifdef DEBUG + if (span->arrayMask & SPAN_XY) { + GLuint i; + for (i = 0; i < span->end; i++) { + if (span->array->mask[i]) { + assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin); + assert(span->array->x[i] < ctx->DrawBuffer->_Xmax); + assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin); + assert(span->array->y[i] < ctx->DrawBuffer->_Ymax); + } } - write_all = GL_FALSE; } +#endif - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { - return; - } - write_all = GL_FALSE; + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) { + stipple_polygon_span(ctx, span); } - else if (ctx->Depth.Test) { - /* regular depth testing */ - GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); - if (m == 0) { - return; + + /* Depth test and stencil */ + if (ctx->Depth.Test || ctx->Stencil.Enabled) { + if (span->interpMask & SPAN_Z) + _swrast_span_interpolate_z(ctx, span); + + if (ctx->Stencil.Enabled) { + if (!_swrast_stencil_and_ztest_span(ctx, span)) { + span->arrayMask = origArrayMask; + return; + } } - if (m < n) { - write_all = GL_FALSE; + else { + ASSERT(ctx->Depth.Test); + if (!_swrast_depth_test_span(ctx, span)) { + span->arrayMask = origArrayMask; + return; + } } } /* if we get here, something passed the depth test */ ctx->OcclusionResult = GL_TRUE; - /* Per-pixel fog */ +#if FEATURE_ARB_occlusion_query + if (ctx->Occlusion.Active) { + GLuint i; + for (i = 0; i < span->end; i++) + ctx->Occlusion.PassedCounter += span->array->mask[i]; + } +#endif + + /* we have to wait until after occlusion to do this test */ + if (ctx->Color.DrawBuffer == GL_NONE || ctx->Color.IndexMask == 0) { + /* write no pixels */ + span->arrayMask = origArrayMask; + return; + } + + /* Interpolate the color indexes if needed */ + if (span->interpMask & SPAN_INDEX) { + interpolate_indexes(ctx, span); + /* clear the bit - this allows the WriteMonoCISpan optimization below */ + span->interpMask &= ~SPAN_INDEX; + } + + /* Fog */ if (ctx->Fog.Enabled) { - if (fog && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); - else - _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + _swrast_fog_ci_span(ctx, span); + } + + /* Antialias coverage application */ + if (span->arrayMask & SPAN_COVERAGE) { + GLuint i; + GLuint *index = span->array->index; + GLfloat *coverage = span->array->coverage; + for (i = 0; i < span->end; i++) { + ASSERT(coverage[i] < 16); + index[i] = (index[i] & ~0xf) | ((GLuint) coverage[i]); + } } if (swrast->_RasterMask & MULTI_DRAW_BIT) { - multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); + /* draw to zero or two or more buffers */ + multi_write_index_span(ctx, span); } else { - /* normal: write to exactly one buffer */ - /* logic op or blending */ - const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); - - if (ctx->Color.ColorLogicOpEnabled) { - _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); - } - else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, n, x, y, rgba, mask ); + /* normal situation: draw to exactly one buffer */ + if (ctx->Color.IndexLogicOpEnabled) { + _swrast_logicop_ci_span(ctx, span, span->array->index); } - /* Color component masking */ - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + if (ctx->Color.IndexMask != 0xffffffff) { + _swrast_mask_index_span(ctx, span, span->array->index); } /* write pixels */ - (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, - (const GLchan (*)[4]) rgba, - write_all ? Null : mask ); - - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, n, x, y, - (const GLchan (*)[4]) rgba, - write_all ? Null : mask ); + if (span->arrayMask & SPAN_XY) { + /* array of pixel coords */ + if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) { + /* all pixels have same color index */ + (*swrast->Driver.WriteMonoCIPixels)(ctx, span->end, + span->array->x, span->array->y, + FixedToInt(span->index), + span->array->mask); + } + else { + (*swrast->Driver.WriteCI32Pixels)(ctx, span->end, span->array->x, + span->array->y, span->array->index, + span->array->mask ); + } + } + else { + /* horizontal run of pixels */ + if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) { + /* all pixels have same color index */ + (*swrast->Driver.WriteMonoCISpan)(ctx, span->end, span->x, span->y, + FixedToInt(span->index), + span->array->mask); + } + else { + (*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y, + span->array->index, + span->array->mask); + } } } -} + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; +} -/* - * Write a horizontal span of color pixels to the frame buffer. - * The color is initially constant for the whole span. - * Alpha-testing, stenciling, depth-testing, and blending are done as needed. - * Input: n - number of pixels in the span - * x, y - location of leftmost pixel in the span - * z - array of [n] z-values - * r, g, b, a - the color of the pixels - * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. +/** + * This function may modify any of the array values in the span. + * span->interpMask and span->arrayMask may be changed but will be restored + * to their original values before returning. */ -void gl_write_monocolor_span( GLcontext *ctx, - GLuint n, GLint x, GLint y, const GLdepth z[], - const GLfixed fog[], - const GLchan color[4], - GLenum primitive ) +void +_swrast_write_rgba_span( GLcontext *ctx, struct sw_span *span) { - const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); - GLuint i; - GLubyte mask[MAX_WIDTH]; - GLboolean write_all = GL_TRUE; - GLchan rgba[MAX_WIDTH][4]; - const GLubyte *Null = 0; SWcontext *swrast = SWRAST_CONTEXT(ctx); + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + const GLuint origInterpMask = span->interpMask; + const GLuint origArrayMask = span->arrayMask; + GLboolean monoColor; + + ASSERT(span->end <= MAX_WIDTH); + ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE || + span->primitive == GL_POLYGON || span->primitive == GL_BITMAP); + ASSERT((span->interpMask & span->arrayMask) == 0); + ASSERT((span->interpMask | span->arrayMask) & SPAN_RGBA); +#ifdef DEBUG + if (ctx->Fog.Enabled) + ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG); + if (ctx->Depth.Test) + ASSERT((span->interpMask | span->arrayMask) & SPAN_Z); +#endif + + if (span->arrayMask & SPAN_MASK) { + /* mask was initialized by caller, probably glBitmap */ + span->writeAll = GL_FALSE; + } + else { + MEMSET(span->array->mask, 1, span->end); + span->writeAll = GL_TRUE; + } - /* init mask to 1's (all pixels are to be written) */ - MEMSET(mask, 1, n); + /* Determine if we have mono-chromatic colors */ + monoColor = (span->interpMask & SPAN_RGBA) && + span->redStep == 0 && span->greenStep == 0 && + span->blueStep == 0 && span->alphaStep == 0; - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if ((n = clip_span( ctx,n,x,y,mask)) == 0) { - return; + /* Clipping */ + if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) { + if (!clip_span(ctx, span)) { + return; } - if (mask[0] == 0) - write_all = GL_FALSE; } - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { + /* Depth bounds test */ + if (ctx->Depth.BoundsTest && ctx->Visual.depthBits > 0) { + if (!_swrast_depth_bounds_test(ctx, span)) { return; } - if (mask[0] == 0) - write_all = GL_FALSE; } +#ifdef DEBUG + if (span->arrayMask & SPAN_XY) { + GLuint i; + for (i = 0; i < span->end; i++) { + if (span->array->mask[i]) { + assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin); + assert(span->array->x[i] < ctx->DrawBuffer->_Xmax); + assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin); + assert(span->array->y[i] < ctx->DrawBuffer->_Ymax); + } + } + } +#endif + /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, n, x, y, mask ); - write_all = GL_FALSE; + if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) { + stipple_polygon_span(ctx, span); } - /* Do the alpha test */ - if (ctx->Color.AlphaEnabled) { - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = color[ACOMP]; + /* Fragment program */ + if (ctx->FragmentProgram._Enabled) { + /* Now we may need to interpolate the colors and texcoords */ + if ((span->interpMask & SPAN_RGBA) && + (span->arrayMask & SPAN_RGBA) == 0) { + interpolate_colors(ctx, span); + span->interpMask &= ~SPAN_RGBA; } - if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask ) == 0) { - return; + if (span->interpMask & SPAN_SPEC) { + interpolate_specular(ctx, span); } - write_all = GL_FALSE; + if ((span->interpMask & SPAN_TEXTURE) + && (span->arrayMask & SPAN_TEXTURE) == 0) + interpolate_texcoords(ctx, span); + _swrast_exec_fragment_program(ctx, span); + monoColor = GL_FALSE; } - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + if (!_swrast_alpha_test(ctx, span)) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; return; } - write_all = GL_FALSE; } - else if (ctx->Depth.Test) { - /* regular depth testing */ - GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); - if (m == 0) { - return; + + /* Stencil and Z testing */ + if (ctx->Stencil.Enabled || ctx->Depth.Test) { + if (span->interpMask & SPAN_Z) + _swrast_span_interpolate_z(ctx, span); + + if (ctx->Stencil.Enabled) { + if (!_swrast_stencil_and_ztest_span(ctx, span)) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; + return; + } } - if (m < n) { - write_all = GL_FALSE; + else { + ASSERT(ctx->Depth.Test); + ASSERT(span->arrayMask & SPAN_Z); + /* regular depth testing */ + if (!_swrast_depth_test_span(ctx, span)) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; + return; + } } } /* if we get here, something passed the depth test */ ctx->OcclusionResult = GL_TRUE; - if (ctx->Color.DrawBuffer == GL_NONE) { - /* write no pixels */ +#if FEATURE_ARB_occlusion_query + if (ctx->Occlusion.Active) { + GLuint i; + for (i = 0; i < span->end; i++) + ctx->Occlusion.PassedCounter += span->array->mask[i]; + } +#endif + + /* can't abort span-writing until after occlusion testing */ + if (colorMask == 0x0) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; return; } - if (ctx->Color.ColorLogicOpEnabled || colorMask != 0xffffffff || - (swrast->_RasterMask & (BLEND_BIT | FOG_BIT))) { - /* assign same color to each pixel */ - for (i = 0; i < n; i++) { - if (mask[i]) { - COPY_CHAN4(rgba[i], color); - } - } + /* Now we may need to interpolate the colors */ + if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0) { + interpolate_colors(ctx, span); + /* clear the bit - this allows the WriteMonoCISpan optimization below */ + span->interpMask &= ~SPAN_RGBA; + } - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if (fog && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); - else - _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); - } + /* Fog */ + if (swrast->_FogEnabled) { + _swrast_fog_rgba_span(ctx, span); + monoColor = GL_FALSE; + } - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - multi_write_rgba_span( ctx, n, x, y, - (const GLchan (*)[4]) rgba, mask ); + /* Antialias coverage application */ + if (span->arrayMask & SPAN_COVERAGE) { + GLchan (*rgba)[4] = span->array->rgba; + GLfloat *coverage = span->array->coverage; + GLuint i; + for (i = 0; i < span->end; i++) { + rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]); } - else { - /* normal: write to exactly one buffer */ - if (ctx->Color.ColorLogicOpEnabled) { - _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); - } - else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, n, x, y, rgba, mask ); - } - - /* Color component masking */ - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, n, x, y, rgba ); - } + monoColor = GL_FALSE; + } - /* write pixels */ - (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, - (const GLchan (*)[4]) rgba, - write_all ? Null : mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, n, x, y, - (const GLchan (*)[4]) rgba, - write_all ? Null : mask ); - } - } + if (swrast->_RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span(ctx, span); } else { - /* same color for all pixels */ - ASSERT(!ctx->Color.BlendEnabled); - ASSERT(!ctx->Color.ColorLogicOpEnabled); + /* normal: write to exactly one buffer */ + if (ctx->Color._LogicOpEnabled) { + _swrast_logicop_rgba_span(ctx, span, span->array->rgba); + monoColor = GL_FALSE; + } + else if (ctx->Color.BlendEnabled) { + _swrast_blend_span(ctx, span, span->array->rgba); + monoColor = GL_FALSE; + } - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - for (i = 0; i < n; i++) { - if (mask[i]) { - COPY_CHAN4(rgba[i], color); + /* Color component masking */ + if (colorMask != 0xffffffff) { + _swrast_mask_rgba_span(ctx, span, span->array->rgba); + monoColor = GL_FALSE; + } + + /* write pixels */ + if (span->arrayMask & SPAN_XY) { + /* array of pixel coords */ + if (monoColor) { + /* all pixels have same color */ + GLchan color[4]; + color[RCOMP] = FixedToChan(span->red); + color[GCOMP] = FixedToChan(span->green); + color[BCOMP] = FixedToChan(span->blue); + color[ACOMP] = FixedToChan(span->alpha); + (*swrast->Driver.WriteMonoRGBAPixels)(ctx, span->end, + span->array->x, span->array->y, color, span->array->mask); + if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) { + _swrast_write_mono_alpha_pixels(ctx, span->end, + span->array->x, span->array->y, + color[ACOMP], span->array->mask); + } + } + else { + (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, + span->array->x, span->array->y, + (const GLchan (*)[4]) span->array->rgba, + span->array->mask); + if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) { + _swrast_write_alpha_pixels(ctx, span->end, + span->array->x, span->array->y, + (const GLchan (*)[4]) span->array->rgba, + span->array->mask); } } - multi_write_rgba_span( ctx, n, x, y, - (const GLchan (*)[4]) rgba, mask ); } else { - (*ctx->Driver.WriteMonoRGBASpan)( ctx, n, x, y, color, mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_mono_alpha_span( ctx, n, x, y, (GLchan) color[ACOMP], - write_all ? Null : mask ); + /* horizontal run of pixels */ + if (monoColor) { + /* all pixels have same color */ + GLchan color[4]; + color[RCOMP] = FixedToChan(span->red); + color[GCOMP] = FixedToChan(span->green); + color[BCOMP] = FixedToChan(span->blue); + color[ACOMP] = FixedToChan(span->alpha); + (*swrast->Driver.WriteMonoRGBASpan)(ctx, span->end, span->x, + span->y, color, span->array->mask); + if (swrast->_RasterMask & ALPHABUF_BIT) { + _swrast_write_mono_alpha_span(ctx, span->end, span->x, span->y, + color[ACOMP], + span->writeAll ? ((const GLubyte *) NULL) : span->array->mask); + } + } + else { + /* each pixel is a different color */ + (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y, + (const GLchan (*)[4]) span->array->rgba, + span->writeAll ? ((const GLubyte *) NULL) : span->array->mask); + if (swrast->_RasterMask & ALPHABUF_BIT) { + _swrast_write_alpha_span(ctx, span->end, span->x, span->y, + (const GLchan (*)[4]) span->array->rgba, + span->writeAll ? ((const GLubyte *) NULL) : span->array->mask); + } } } } -} + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; +} -/* +/** * Add specular color to base color. This is used only when * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR. */ -static void add_colors(GLuint n, GLchan rgba[][4], CONST GLchan specular[][4] ) +static void +add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] ) { GLuint i; for (i = 0; i < n; i++) { +#if CHAN_TYPE == GL_FLOAT + /* no clamping */ + rgba[i][RCOMP] += specular[i][RCOMP]; + rgba[i][GCOMP] += specular[i][GCOMP]; + rgba[i][BCOMP] += specular[i][BCOMP]; +#else GLint r = rgba[i][RCOMP] + specular[i][RCOMP]; GLint g = rgba[i][GCOMP] + specular[i][GCOMP]; GLint b = rgba[i][BCOMP] + specular[i][BCOMP]; rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX); rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX); rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX); +#endif } } -/* - * Write a horizontal span of textured pixels to the frame buffer. - * The color of each pixel is different. - * Alpha-testing, stenciling, depth-testing, and blending are done - * as needed. - * Input: n - number of pixels in the span - * x, y - location of leftmost pixel in the span - * z - array of [n] z-values - * s, t - array of (s,t) texture coordinates for each pixel - * lambda - array of texture lambda values - * rgba - array of [n] color components - * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. +/** + * This function may modify any of the array values in the span. + * span->interpMask and span->arrayMask may be changed but will be restored + * to their original values before returning. */ -void gl_write_texture_span( GLcontext *ctx, - GLuint n, GLint x, GLint y, const GLdepth z[], - const GLfixed fog[], - const GLfloat s[], const GLfloat t[], - const GLfloat u[], GLfloat lambda[], - GLchan rgbaIn[][4], CONST GLchan spec[][4], - GLenum primitive ) +void +_swrast_write_texture_span( GLcontext *ctx, struct sw_span *span) { const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); - GLubyte mask[MAX_WIDTH]; - GLboolean write_all = GL_TRUE; - GLchan rgbaBackup[MAX_WIDTH][4]; - GLchan (*rgba)[4]; /* points to either rgbaIn or rgbaBackup */ - const GLubyte *Null = 0; SWcontext *swrast = SWRAST_CONTEXT(ctx); + const GLuint origInterpMask = span->interpMask; + const GLuint origArrayMask = span->arrayMask; - /* init mask to 1's (all pixels are to be written) */ - MEMSET(mask, 1, n); - - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if ((n=clip_span(ctx, n, x, y, mask)) == 0) { - return; - } - if (mask[0] == 0) - write_all = GL_FALSE; - } + ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE || + span->primitive == GL_POLYGON || span->primitive == GL_BITMAP); + ASSERT(span->end <= MAX_WIDTH); + ASSERT((span->interpMask & span->arrayMask) == 0); + ASSERT(ctx->Texture._EnabledCoordUnits || ctx->FragmentProgram._Enabled); + /* + printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__, span->interpMask, span->arrayMask); + */ - if (primitive==GL_BITMAP || (swrast->_RasterMask & MULTI_DRAW_BIT)) { - /* must make a copy of the colors since they may be modified */ - MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan)); - rgba = rgbaBackup; + if (span->arrayMask & SPAN_MASK) { + /* mask was initialized by caller, probably glBitmap */ + span->writeAll = GL_FALSE; } else { - rgba = rgbaIn; + MEMSET(span->array->mask, 1, span->end); + span->writeAll = GL_TRUE; } - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { - return; + /* Clipping */ + if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) { + if (!clip_span(ctx, span)) { + return; } - if (mask[0] == 0) - write_all = GL_FALSE; } - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, n, x, y, mask ); - write_all = GL_FALSE; - } - - /* Texture with alpha test*/ - if (ctx->Color.AlphaEnabled) { - /* Texturing without alpha is done after depth-testing which - gives a potential speed-up. */ - ASSERT(ctx->Texture._ReallyEnabled); - _swrast_texture_fragments( ctx, 0, n, s, t, u, lambda, - (CONST GLchan (*)[4]) rgba, rgba ); - - /* Do the alpha test */ - if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask ) == 0) { - return; +#ifdef DEBUG + if (span->arrayMask & SPAN_XY) { + GLuint i; + for (i = 0; i < span->end; i++) { + if (span->array->mask[i]) { + assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin); + assert(span->array->x[i] < ctx->DrawBuffer->_Xmax); + assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin); + assert(span->array->y[i] < ctx->DrawBuffer->_Ymax); + } } - write_all = GL_FALSE; } +#endif - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { - return; - } - write_all = GL_FALSE; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); - if (m == 0) { - return; - } - if (m < n) { - write_all = GL_FALSE; - } + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) { + stipple_polygon_span(ctx, span); } - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; - - /* Texture without alpha test */ - if (! ctx->Color.AlphaEnabled) { - ASSERT(ctx->Texture._ReallyEnabled); - _swrast_texture_fragments( ctx, 0, n, s, t, u, lambda, - (CONST GLchan (*)[4]) rgba, rgba ); - } + /* Need texture coordinates now */ + if ((span->interpMask & SPAN_TEXTURE) + && (span->arrayMask & SPAN_TEXTURE) == 0) + interpolate_texcoords(ctx, span); - /* Add base and specular colors */ - if (spec && - (ctx->Fog.ColorSumEnabled || - (ctx->Light.Enabled && ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))) - add_colors( n, rgba, spec ); /* rgba = rgba + spec */ + /* Texture with alpha test */ + if (ctx->Color.AlphaEnabled) { - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if (fog && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); - else - _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); - } + /* Now we need the rgba array, fill it in if needed */ + if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0) + interpolate_colors(ctx, span); - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); - } - else { - /* normal: write to exactly one buffer */ - if (ctx->Color.ColorLogicOpEnabled) { - _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); - } - else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, n, x, y, rgba, mask ); - } - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + if (span->interpMask & SPAN_SPEC) { + interpolate_specular(ctx, span); } - (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, - write_all ? Null : mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, - write_all ? Null : mask ); + /* Texturing without alpha is done after depth-testing which + * gives a potential speed-up. + */ + if (ctx->FragmentProgram._Enabled) + _swrast_exec_fragment_program( ctx, span ); + else + _swrast_texture_span( ctx, span ); + + /* Do the alpha test */ + if (!_swrast_alpha_test(ctx, span)) { + span->arrayMask = origArrayMask; + return; } } -} - + /* Stencil and Z testing */ + if (ctx->Stencil.Enabled || ctx->Depth.Test) { + if (span->interpMask & SPAN_Z) + _swrast_span_interpolate_z(ctx, span); -/* - * As above but perform multiple stages of texture application. - */ -void -gl_write_multitexture_span( GLcontext *ctx, - GLuint n, GLint x, GLint y, - const GLdepth z[], - const GLfixed fog[], - CONST GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH], - CONST GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH], - CONST GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH], - GLfloat lambda[][MAX_WIDTH], - GLchan rgbaIn[MAX_TEXTURE_UNITS][4], - CONST GLchan spec[MAX_TEXTURE_UNITS][4], - GLenum primitive ) -{ - GLubyte mask[MAX_WIDTH]; - GLboolean write_all = GL_TRUE; - GLchan rgbaBackup[MAX_WIDTH][4]; - GLchan (*rgba)[4]; /* points to either rgbaIn or rgbaBackup */ - GLuint i; - const GLubyte *Null = 0; - const GLuint texUnits = ctx->Const.MaxTextureUnits; - SWcontext *swrast = SWRAST_CONTEXT(ctx); - - /* init mask to 1's (all pixels are to be written) */ - MEMSET(mask, 1, n); - - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if ((n=clip_span(ctx, n, x, y, mask)) == 0) { - return; + if (ctx->Stencil.Enabled) { + if (!_swrast_stencil_and_ztest_span(ctx, span)) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; + return; + } + } + else { + ASSERT(ctx->Depth.Test); + ASSERT(span->arrayMask & SPAN_Z); + /* regular depth testing */ + if (!_swrast_depth_test_span(ctx, span)) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; + return; + } } - if (mask[0] == 0) - write_all = GL_FALSE; } + /* if we get here, some fragments passed the depth test */ + ctx->OcclusionResult = GL_TRUE; - if (primitive==GL_BITMAP || (swrast->_RasterMask & MULTI_DRAW_BIT) - || texUnits > 1) { - /* must make a copy of the colors since they may be modified */ - MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan)); - rgba = rgbaBackup; - } - else { - rgba = rgbaIn; +#if FEATURE_ARB_occlusion_query + if (ctx->Occlusion.Active) { + GLuint i; + for (i = 0; i < span->end; i++) + ctx->Occlusion.PassedCounter += span->array->mask[i]; } +#endif - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if ((n = _mesa_scissor_span( ctx, n, x, y, mask )) == 0) { - return; - } - if (mask[0] == 0) - write_all = GL_FALSE; + /* We had to wait until now to check for glColorMask(F,F,F,F) because of + * the occlusion test. + */ + if (colorMask == 0x0) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; + return; } - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, n, x, y, mask ); - write_all = GL_FALSE; - } + /* Texture without alpha test */ + if (!ctx->Color.AlphaEnabled) { - /* Texture with alpha test*/ - if (ctx->Color.AlphaEnabled) { - /* Texturing without alpha is done after depth-testing which - * gives a potential speed-up. - */ - ASSERT(ctx->Texture._ReallyEnabled); - for (i = 0; i < texUnits; i++) - _swrast_texture_fragments( ctx, i, n, s[i], t[i], u[i], lambda[i], - (CONST GLchan (*)[4]) rgbaIn, rgba ); - - /* Do the alpha test */ - if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask ) == 0) { - return; - } - write_all = GL_FALSE; - } + /* Now we need the rgba array, fill it in if needed */ + if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0) + interpolate_colors(ctx, span); - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { - return; - } - write_all = GL_FALSE; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); - if (m == 0) { - return; - } - if (m < n) { - write_all = GL_FALSE; + if (span->interpMask & SPAN_SPEC) { + interpolate_specular(ctx, span); } + + if (ctx->FragmentProgram._Enabled) + _swrast_exec_fragment_program( ctx, span ); + else + _swrast_texture_span( ctx, span ); } - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; + ASSERT(span->arrayMask & SPAN_RGBA); - /* Texture without alpha test */ - if (! ctx->Color.AlphaEnabled) { - ASSERT(ctx->Texture._ReallyEnabled); - for (i = 0; i < texUnits; i++) - _swrast_texture_fragments( ctx, i, n, s[i], t[i], u[i], lambda[i], - (CONST GLchan (*)[4]) rgbaIn, rgba ); + /* Add base and specular colors */ + if (ctx->Fog.ColorSumEnabled || + (ctx->Light.Enabled && + ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) { + if (span->interpMask & SPAN_SPEC) { + interpolate_specular(ctx, span); + } + ASSERT(span->arrayMask & SPAN_SPEC); + add_colors( span->end, span->array->rgba, span->array->spec ); } - /* Add base and specular colors */ - if (spec && - (ctx->Fog.ColorSumEnabled || - (ctx->Light.Enabled && - ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))) - add_colors( n, rgba, spec ); /* rgba = rgba + spec */ + /* Fog */ + if (swrast->_FogEnabled) { + _swrast_fog_rgba_span(ctx, span); + } - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if (fog && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); - else - _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + /* Antialias coverage application */ + if (span->arrayMask & SPAN_COVERAGE) { + GLchan (*rgba)[4] = span->array->rgba; + GLfloat *coverage = span->array->coverage; + GLuint i; + for (i = 0; i < span->end; i++) { + rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]); + } } if (swrast->_RasterMask & MULTI_DRAW_BIT) { - multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); + multi_write_rgba_span(ctx, span); } else { /* normal: write to exactly one buffer */ - const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); - - if (ctx->Color.ColorLogicOpEnabled) { - _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); + if (ctx->Color._LogicOpEnabled) { + _swrast_logicop_rgba_span(ctx, span, span->array->rgba); } - else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, n, x, y, rgba, mask ); + else if (ctx->Color.BlendEnabled) { + _swrast_blend_span(ctx, span, span->array->rgba); } - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + /* Color component masking */ + if (colorMask != 0xffffffff) { + _swrast_mask_rgba_span(ctx, span, span->array->rgba); } - (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, - write_all ? Null : mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4])rgba, - write_all ? Null : mask ); + /* write pixels */ + if (span->arrayMask & SPAN_XY) { + /* array of pixel coords */ + (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->array->x, + span->array->y, (const GLchan (*)[4]) span->array->rgba, span->array->mask); + if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) { + _swrast_write_alpha_pixels(ctx, span->end, + span->array->x, span->array->y, + (const GLchan (*)[4]) span->array->rgba, + span->array->mask); + } + } + else { + /* horizontal run of pixels */ + (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y, + (const GLchan (*)[4]) span->array->rgba, + span->writeAll ? NULL : span->array->mask); + if (swrast->_RasterMask & ALPHABUF_BIT) { + _swrast_write_alpha_span(ctx, span->end, span->x, span->y, + (const GLchan (*)[4]) span->array->rgba, + span->writeAll ? NULL : span->array->mask); + } } } + + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; } -/* +/** * Read RGBA pixels from frame buffer. Clipping will be done to prevent * reading ouside the buffer's boundaries. */ -void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, - GLuint n, GLint x, GLint y, - GLchan rgba[][4] ) +void +_swrast_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, + GLuint n, GLint x, GLint y, GLchan rgba[][4] ) { - if (y < 0 || y >= buffer->Height - || x + (GLint) n < 0 || x >= buffer->Width) { + SWcontext *swrast = SWRAST_CONTEXT(ctx); + const GLint bufWidth = (GLint) buffer->Width; + const GLint bufHeight = (GLint) buffer->Height; + + if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) { /* completely above, below, or right */ /* XXX maybe leave undefined? */ - BZERO(rgba, 4 * n * sizeof(GLchan)); + _mesa_bzero(rgba, 4 * n * sizeof(GLchan)); } else { GLint skip, length; @@ -1077,14 +1562,14 @@ void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, /* completely left of window */ return; } - if (length > buffer->Width) { - length = buffer->Width; + if (length > bufWidth) { + length = bufWidth; } } - else if ((GLint) (x + n) > buffer->Width) { + else if ((GLint) (x + n) > bufWidth) { /* right edge clipping */ skip = 0; - length = buffer->Width - x; + length = bufWidth - x; if (length < 0) { /* completely to right of window */ return; @@ -1096,27 +1581,29 @@ void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, length = (GLint) n; } - (*ctx->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip ); + (*swrast->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip ); if (buffer->UseSoftwareAlphaBuffers) { - _mesa_read_alpha_span( ctx, length, x + skip, y, rgba + skip ); + _swrast_read_alpha_span(ctx, length, x + skip, y, rgba + skip); } } } - - -/* +/** * Read CI pixels from frame buffer. Clipping will be done to prevent * reading ouside the buffer's boundaries. */ -void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer, - GLuint n, GLint x, GLint y, GLuint indx[] ) +void +_swrast_read_index_span( GLcontext *ctx, GLframebuffer *buffer, + GLuint n, GLint x, GLint y, GLuint indx[] ) { - if (y < 0 || y >= buffer->Height - || x + (GLint) n < 0 || x >= buffer->Width) { + SWcontext *swrast = SWRAST_CONTEXT(ctx); + const GLint bufWidth = (GLint) buffer->Width; + const GLint bufHeight = (GLint) buffer->Height; + + if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) { /* completely above, below, or right */ - BZERO(indx, n * sizeof(GLuint)); + _mesa_bzero(indx, n * sizeof(GLuint)); } else { GLint skip, length; @@ -1128,14 +1615,14 @@ void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer, /* completely left of window */ return; } - if (length > buffer->Width) { - length = buffer->Width; + if (length > bufWidth) { + length = bufWidth; } } - else if ((GLint) (x + n) > buffer->Width) { + else if ((GLint) (x + n) > bufWidth) { /* right edge clipping */ skip = 0; - length = buffer->Width - x; + length = bufWidth - x; if (length < 0) { /* completely to right of window */ return; @@ -1147,6 +1634,6 @@ void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer, length = (GLint) n; } - (*ctx->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip ); + (*swrast->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip ); } }