X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fswrast%2Fs_span.c;h=41db42e2b80726689fe1b1fdf39acdb224fab2f3;hb=1a544b0500ebacb52a7412ad17c4a2002a00ff94;hp=fce8d33c97745567f6f2385f159a33096e951d70;hpb=2ef866d1fc0a5cc5ef8543d65744dfd4da4dbbaf;p=mesa.git diff --git a/src/mesa/swrast/s_span.c b/src/mesa/swrast/s_span.c index fce8d33c977..41db42e2b80 100644 --- a/src/mesa/swrast/s_span.c +++ b/src/mesa/swrast/s_span.c @@ -1,10 +1,8 @@ -/* $Id: s_span.c,v 1.23 2002/01/21 18:12:34 brianp Exp $ */ - /* * Mesa 3-D graphics library - * Version: 4.1 + * Version: 6.1 * - * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. + * 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"), @@ -25,17 +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" @@ -45,1865 +44,1251 @@ #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" -INLINE -static void SET_MASK_TO_ONE(struct sw_span *span) { - SW_SPAN_SET_FLAG(span->filledMask); - /* init mask to 1's (all pixels are to be written) */ - MEMSET(span->mask, 1, span->end); + +/** + * Init span's Z interpolation values to the RasterPos Z. + * Used during setup for glDraw/CopyPixels. + */ +void +_swrast_span_default_z( GLcontext *ctx, struct sw_span *span ) +{ + 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; } -/* - * Apply the current polygon stipple pattern to a span of pixels. +/** + * Init span's fog interpolation values to the RasterPos fog. + * Used during setup for glDraw/CopyPixels. */ -static void -old_stipple_polygon_span( GLcontext *ctx, GLuint n, GLint x, GLint y, - GLubyte mask[] ) +void +_swrast_span_default_fog( GLcontext *ctx, struct sw_span *span ) { - const GLuint highbit = 0x80000000; - GLuint i, m, stipple; + span->fog = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance); + span->fogStep = span->dfogdx = span->dfogdy = 0.0F; + span->interpMask |= SPAN_FOG; +} - stipple = ctx->PolygonStipple[y % 32]; - m = highbit >> (GLuint) (x % 32); - for (i = 0; i < n; i++) { - if ((m & stipple) == 0) { - mask[i] = 0; +/** + * Init span's color or index interpolation values to the RasterPos color. + * Used during setup for glDraw/CopyPixels. + */ +void +_swrast_span_default_color( GLcontext *ctx, struct sw_span *span ) +{ + 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; + } + else { + span->index = FloatToFixed(ctx->Current.RasterIndex); + span->indexStep = 0; + span->interpMask |= SPAN_INDEX; + } +} + + +/** + * 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; } - m = m >> 1; - if (m == 0) { - m = highbit; + else { + 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); } + span->interpMask |= SPAN_TEXTURE; } -/* - * Apply the current polygon stipple pattern to a span of pixels. - */ + +/* Fill in the span.color.rgba array from the interpolation values */ static void -stipple_polygon_span( GLcontext *ctx, struct sw_span *span) +interpolate_colors(GLcontext *ctx, struct sw_span *span) { - const GLuint highbit = 0x80000000; - GLuint i, m, stipple; + const GLuint n = span->end; + GLchan (*rgba)[4] = span->array->rgba; + GLuint i; - ASSERT (span->filledMask == GL_TRUE); - - stipple = ctx->PolygonStipple[span->y % 32]; - m = highbit >> (GLuint) (span->x % 32); + ASSERT((span->interpMask & SPAN_RGBA) && + !(span->arrayMask & SPAN_RGBA)); - for (i = 0; i < span->end; i++) { - if ((m & stipple) == 0) { - span->mask[i] = 0; + 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); } - m = m >> 1; - if (m == 0) { - m = highbit; + } + 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->writeAll = GL_FALSE; + span->arrayMask |= SPAN_RGBA; } - -/* - * 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 - */ -static GLuint -old_clip_span( GLcontext *ctx, GLint n, GLint x, GLint y, GLubyte mask[] ) +/* Fill in the span.color.index array from the interpolation values */ +static void +interpolate_indexes(GLcontext *ctx, struct sw_span *span) { - /* Clip to top and bottom */ - if (y < 0 || y >= ctx->DrawBuffer->Height) { - return 0; + 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 ((span->interpMask & SPAN_FLAT) || (indexStep == 0)) { + /* constant color */ + index = FixedToInt(index); + for (i = 0; i < n; i++) { + indexes[i] = index; + } } + else { + /* interpolate */ + for (i = 0; i < n; i++) { + indexes[i] = FixedToInt(index); + index += indexStep; + } + } + span->arrayMask |= SPAN_INDEX; +} + - /* Clip to the left */ - if (x < 0) { - if (x + n <= 0) { - /* completely off left side */ - return 0; +/* 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 { - /* partially off left side */ - BZERO(mask, -x * sizeof(GLubyte)); + } + 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; +} + + +/* 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; - /* Clip to right */ - if (x + n > ctx->DrawBuffer->Width) { - if (x >= ctx->DrawBuffer->Width) { - /* completely off right side */ - return 0; + 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 { - /* partially off right side */ - return ctx->DrawBuffer->Width - x; + } + 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; +} + - return n; +/* + * 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 /* - * Clip a pixel span to the current buffer/window boundaries. - * Return: GL_TRUE some pixel still visible - * GL_FALSE nothing visible + * This is a faster approximation */ -static GLuint -clip_span( GLcontext *ctx, struct sw_span *span) +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) { - GLint x = span->x, y = span->y, n = span->end; + 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; +} - ASSERT (span->filledMask == GL_TRUE); - /* Clip to top and bottom */ - if (y < 0 || y >= ctx->DrawBuffer->Height) { - span->end = 0; - return GL_FALSE; - } +/** + * 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; + } - /* Clip to the left */ - if (x < 0) { - if (x + n <= 0) { - /* completely off left side */ - span->end = 0; - return GL_FALSE; + } + 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 { + /* 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; + } + 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 { - /* partially off left side */ - span->writeAll = GL_FALSE; - BZERO(span->mask, -x * sizeof(GLubyte)); - return GL_TRUE; + /* 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; + } + } + } + } +} + + +/** + * Apply the current polygon stipple pattern to a span of pixels. + */ +static void +stipple_polygon_span( GLcontext *ctx, struct sw_span *span ) +{ + const GLuint highbit = 0x80000000; + const GLuint stipple = ctx->PolygonStipple[span->y % 32]; + GLubyte *mask = span->array->mask; + GLuint i, m; + + ASSERT(ctx->Polygon.StippleFlag); + ASSERT((span->arrayMask & SPAN_XY) == 0); + + 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; +} - /* Clip to right */ - if (x + n > ctx->DrawBuffer->Width) { - if (x >= ctx->DrawBuffer->Width) { - /* completely off right side */ - span->end = 0; - return GL_FALSE; + +/** + * 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 { - /* partially off right side */ - span->end = ctx->DrawBuffer->Width - x; - return GL_TRUE; + /* 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; + + /* Trivial rejection tests */ + if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) { + span->end = 0; + return GL_FALSE; /* all pixels clipped */ + } + + /* Clip to the left */ + if (x < xmin) { + ASSERT(x + n > xmin); + span->writeAll = GL_FALSE; + _mesa_bzero(span->array->mask, (xmin - x) * sizeof(GLubyte)); + } + + /* Clip to right */ + if (x + n > xmax) { + ASSERT(x < xmax); + span->end = xmax - x; + } - return GL_TRUE; + return GL_TRUE; /* some pixels visible */ + } } -/* +/** * 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[] ) +multi_write_index_span( GLcontext *ctx, struct sw_span *span ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); 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) { + for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) { + if (bufferBit & ctx->Color._DrawDestMask) { GLuint indexTmp[MAX_WIDTH]; - ASSERT(n < MAX_WIDTH); + ASSERT(span->end < MAX_WIDTH); - 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); + /* Set the current read/draw buffer */ + swrast->CurrentBufferBit = bufferBit; + (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, bufferBit); /* make copy of incoming indexes */ - MEMCPY( indexTmp, indexes, n * sizeof(GLuint) ); + MEMCPY( indexTmp, span->array->index, span->end * sizeof(GLuint) ); + if (ctx->Color.IndexLogicOpEnabled) { - _mesa_logicop_ci_span( ctx, n, x, y, indexTmp, mask ); + _swrast_logicop_ci_span(ctx, span, indexTmp); + } + + if (ctx->Color.IndexMask != 0xffffffff) { + _swrast_mask_index_span(ctx, span, indexTmp); } - if (ctx->Color.IndexMask == 0) { - break; + + 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 if (ctx->Color.IndexMask != 0xffffffff) { - _mesa_mask_index_span( ctx, n, x, y, indexTmp ); + else { + /* horizontal run of pixels */ + (*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y, + indexTmp, span->array->mask); } - (*swrast->Driver.WriteCI32Span)( ctx, n, x, y, indexTmp, mask ); } } /* restore default dest buffer */ - (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer); + _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[] ) +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); } - (*swrast->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); } -/* - * 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 - * fog - array of fog factor values in [0,1] - * index - array of [n] color indexes - * 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 -_old_write_index_span( GLcontext *ctx, GLuint n, GLint x, GLint y, - const GLdepth z[], const GLfloat fog[], - GLuint indexIn[], const GLint coverage[], - GLenum primitive ) +_swrast_write_index_span( 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); + 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 = old_clip_span(ctx,n,x,y,mask)) == 0) { - return; - } - } + 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 ((primitive==GL_BITMAP && (swrast->_RasterMask & modBits)) - || (swrast->_RasterMask & MULTI_DRAW_BIT)) { - /* Make copy of color indexes */ - MEMCPY( indexBackup, indexIn, n * sizeof(GLuint) ); - index = indexBackup; + if (span->arrayMask & SPAN_MASK) { + /* mask was initialized by caller, probably glBitmap */ + span->writeAll = GL_FALSE; } else { - index = indexIn; + MEMSET(span->array->mask, 1, span->end); + span->writeAll = GL_TRUE; } + /* Clipping */ + if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) { + if (!clip_span(ctx, span)) { + return; + } + } - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if ((n = _old_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; } } +#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) { - old_stipple_polygon_span( ctx, n, x, y, mask ); + if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) { + stipple_polygon_span(ctx, span); } - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_old_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { - 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; + } + } + else { + ASSERT(ctx->Depth.Test); + if (!_swrast_depth_test_span(ctx, span)) { + span->arrayMask = origArrayMask; + return; + } } - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_old_depth_test_span( ctx, n, x, y, z, mask ) == 0) - 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) - _old_fog_ci_pixels( ctx, n, fog, index ); - else - _old_depth_fog_ci_pixels( ctx, n, z, index ); + _swrast_fog_ci_span(ctx, span); } /* Antialias coverage application */ - if (coverage) { + if (span->arrayMask & SPAN_COVERAGE) { GLuint i; - for (i = 0; i < n; 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) | coverage[i]; + index[i] = (index[i] & ~0xf) | ((GLuint) coverage[i]); } } if (swrast->_RasterMask & MULTI_DRAW_BIT) { - /* draw to zero or two or more buffers */ - multi_write_index_span( ctx, n, x, y, index, mask ); - } - else { - /* normal situation: draw to exactly one buffer */ - if (ctx->Color.IndexLogicOpEnabled) { - _mesa_logicop_ci_span( ctx, n, x, y, index, mask ); - } - - if (ctx->Color.IndexMask == 0) { - return; - } - else if (ctx->Color.IndexMask != 0xffffffff) { - _mesa_mask_index_span( ctx, n, x, y, index ); - } - - /* write pixels */ - (*swrast->Driver.WriteCI32Span)( ctx, n, x, y, index, mask ); - } -} - - -/* - * Apply fragment processing to a span of RGBA fragments. - * Input: - * n - number of fragments in the span - * x,y - location of first (left) fragment - * fog - array of fog factor values in [0,1] - */ -void -_old_write_rgba_span( GLcontext *ctx, GLuint n, GLint x, GLint y, - const GLdepth z[], const GLfloat fog[], - GLchan rgbaIn[][4], const GLfloat coverage[], - GLenum primitive ) -{ - 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]; - 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 = old_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; - } - else { - rgba = rgbaIn; - } - - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if ((n = _old_scissor_span( ctx, n, x, y, mask )) == 0) { - return; - } - if (mask[0] == 0) - write_all = GL_FALSE; - } - - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - old_stipple_polygon_span( ctx, n, x, y, mask ); - write_all = GL_FALSE; - } - - /* Do the alpha test */ - if (ctx->Color.AlphaEnabled) { - if (_old_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask ) == 0) { - return; - } - write_all = GL_FALSE; - } - - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_old_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 = _old_depth_test_span( ctx, n, x, y, z, mask ); - if (m == 0) { - return; - } - if (m < n) { - write_all = GL_FALSE; - } - } - - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; - - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if (fog && !swrast->_PreferPixelFog) - _old_fog_rgba_pixels( ctx, n, fog, rgba ); - else - _old_depth_fog_rgba_pixels( ctx, n, z, rgba ); - } - - /* Antialias coverage application */ - if (coverage) { - GLuint i; - for (i = 0; i < n; 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 ); - } - 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 ); - } - - /* Color component masking */ - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, n, x, y, rgba ); - } - - /* write pixels */ - (*swrast->Driver.WriteRGBASpan)( ctx, n, x, y, - (const GLchan (*)[4]) rgba, - write_all ? ((const GLubyte *) NULL) : mask ); - - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, n, x, y, - (const GLchan (*)[4]) rgba, - write_all ? ((const GLubyte *) NULL) : mask ); - } - } -} - - -/* - * Write a horizontal span of color index pixels to the frame buffer. - * Stenciling, Depth-testing, etc. are done as needed. - * Input: primitive - either GL_POINT, GL_LINE, GL_POLYGON, or GL_BITMAP - */ -void -_mesa_write_index_span( GLcontext *ctx, struct sw_span *span, - const GLfloat fog[MAX_WIDTH], GLenum primitive) -{ - const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | LOGIC_OP_BIT; - GLuint indexBackup[MAX_WIDTH]; - GLuint *index; /* points to indexIn or indexBackup */ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - - - SET_MASK_TO_ONE(span); - - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if (clip_span(ctx,span) == GL_FALSE) { - return; - } - } - - if ((primitive==GL_BITMAP && (swrast->_RasterMask & modBits)) - || (swrast->_RasterMask & MULTI_DRAW_BIT)) { - /* Make copy of color indexes */ - MEMCPY( indexBackup, span->color.index, span->end * sizeof(GLuint) ); - index = indexBackup; - } - else { - index = span->color.index; - } - - - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if (_mesa_scissor_span( ctx, span ) == GL_FALSE) { - return; - } - } - - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span(ctx, span); - } - - - /* I have to think where to put this!! */ - if (span->activeMask & SPAN_Z) { - SW_SPAN_SET_FLAG(span->filledDepth); - - if (ctx->Visual.depthBits <= 16) { - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = FixedToInt(zval); - zval += span->zStep; - } - } - else { - /* Deep Z buffer, no fixed->int shift */ - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = zval; - zval += span->zStep; - } - } - } - - - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, span) == GL_FALSE) - return; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span(ctx, span) == 0) - return; - } - - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; - - if (ctx->Color.DrawBuffer == GL_NONE) { - /* write no pixels */ - return; - } - - if (ctx->Fog.Enabled) { - if (fog != NULL && !swrast->_PreferPixelFog) - _mesa_fog_ci_pixels_with_array( ctx, span, fog, index); - else if ((span->activeMask & SPAN_FOG) && !swrast->_PreferPixelFog) - _mesa_fog_ci_pixels( ctx, span, index); - else - _mesa_depth_fog_ci_pixels( ctx, span, index); - } - - /* Antialias coverage application */ -#if 0 - if (span->coverage) { - GLuint i; - for (i = 0; i < span->end; i++) { - ASSERT(span->coverage[i] < 16); - index[i] = (index[i] & ~0xf) | span->coverage[i]; - } - } -#endif - - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - /* draw to zero or two or more buffers */ - multi_write_index_span( ctx, span->end, span->x, span->y, - index, span->mask ); - } - else { - /* normal situation: draw to exactly one buffer */ - if (ctx->Color.IndexLogicOpEnabled) { - _mesa_logicop_ci_span( ctx, span->end, span->x, span->y, - index, span->mask ); - } - - if (ctx->Color.IndexMask == 0) { - return; - } - else if (ctx->Color.IndexMask != 0xffffffff) { - _mesa_mask_index_span( ctx, span->end, span->x, span->y, index ); - } - - /* write pixels */ - (*swrast->Driver.WriteCI32Span)( ctx, span->end, span->x, - span->y, index, span->mask ); - } -} - - - - -void -_mesa_write_monoindex_span( GLcontext *ctx, struct sw_span *span, - GLuint index, GLenum primitive ) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - GLuint i; - - - SET_MASK_TO_ONE(span); - - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if (clip_span(ctx,span) == GL_FALSE) { - return; - } - } - - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if (_mesa_scissor_span( ctx, span ) == GL_FALSE) { - return; - } - } - - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, span); - } - - - /* I have to think where to put this!! */ - if (span->activeMask & SPAN_Z) { - SW_SPAN_SET_FLAG(span->filledDepth); - - if (ctx->Visual.depthBits <= 16) { - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = FixedToInt(zval); - zval += span->zStep; - } - } - else { - /* Deep Z buffer, no fixed->int shift */ - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = zval; - zval += span->zStep; - } - } - } - - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, span) == GL_FALSE) - return; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span( ctx, span) == 0) - return; - } - - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; - - if (ctx->Color.DrawBuffer == GL_NONE) { - /* write no pixels */ - return; - } - - if (ctx->Fog.Enabled - || ctx->Color.IndexLogicOpEnabled - || ctx->Color.IndexMask != 0xffffffff -#if 0 - || span->coverage) { -#else - ) { -#endif - /* different index per pixel */ - GLuint indexes[MAX_WIDTH]; - for (i = 0; i < span->end; i++) { - indexes[i] = index; - } - - if (ctx->Fog.Enabled) { - if ((span->activeMask & SPAN_FOG) && !swrast->_PreferPixelFog) - _mesa_fog_ci_pixels( ctx, span, indexes ); - else - _mesa_depth_fog_ci_pixels( ctx, span, indexes ); - } - - /* Antialias coverage application */ -#if 0 - if (span->coverage) { - GLuint i; - for (i = 0; i < span->end; i++) { - ASSERT(span->coverage[i] < 16); - indexes[i] = (indexes[i] & ~0xf) | span->coverage[i]; - } - } -#endif - - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - /* draw to zero or two or more buffers */ - multi_write_index_span( ctx, span->end, span->x, span->y, indexes, span->mask ); - } - else { - /* normal situation: draw to exactly one buffer */ - if (ctx->Color.IndexLogicOpEnabled) { - _mesa_logicop_ci_span( ctx, span->end, span->x, span->y, indexes, span->mask ); - } - if (ctx->Color.IndexMask == 0) { - return; - } - else if (ctx->Color.IndexMask != 0xffffffff) { - _mesa_mask_index_span( ctx, span->end, span->x, span->y, indexes ); - } - (*swrast->Driver.WriteCI32Span)( ctx, span->end, span->x, span->y, indexes, span->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 < span->end; i++) - indexes[i] = index; - multi_write_index_span( ctx, span->end, span->x, span->y, indexes, span->mask ); - } - else { - /* normal situation: draw to exactly one buffer */ - (*swrast->Driver.WriteMonoCISpan)( ctx, span->end, span->x, span->y, index, span->mask ); - } - } -} - - - -/* - * Apply fragment processing to a span of RGBA fragments. - * Input: - */ -void -_mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span, - const GLfloat fog[MAX_WIDTH], GLenum primitive) -{ - const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | - LOGIC_OP_BIT | TEXTURE_BIT; - GLchan rgbaBackup[MAX_WIDTH][4]; - GLchan (*rgba)[4]; - SWcontext *swrast = SWRAST_CONTEXT(ctx); - - - SET_MASK_TO_ONE(span); - - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if (clip_span( ctx,span ) == GL_FALSE) { - return; - } - } - - - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if (_mesa_scissor_span( ctx, span ) == GL_FALSE) { - return; - } - } - - - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, span); - } - - - 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, span->color.rgba, 4 * span->end * sizeof(GLchan) ); - rgba = rgbaBackup; - } - else { - rgba = span->color.rgba; - } - - - /* Do the alpha test */ - if (ctx->Color.AlphaEnabled) { - if (_mesa_alpha_test( ctx, span, (const GLchan (*)[4]) rgba) == 0) { - return; - } - } - - /* I have to think where to put this!! */ - if (span->activeMask & SPAN_Z) { - SW_SPAN_SET_FLAG(span->filledDepth); - - if (ctx->Visual.depthBits <= 16) { - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = FixedToInt(zval); - zval += span->zStep; - } - } - else { - /* Deep Z buffer, no fixed->int shift */ - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = zval; - zval += span->zStep; - } - } - } - - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, span) == GL_FALSE) - return; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span(ctx, span) == GL_FALSE) - return; - } - - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; - - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if (fog != NULL && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels_with_array( ctx, span, fog, rgba); - else if ((span->activeMask & SPAN_FOG) && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels( ctx, span, rgba ); - else - _mesa_depth_fog_rgba_pixels( ctx, span, rgba ); - } - - /* Antialias coverage application */ -#if 0 - if (span->coverage) { - GLuint i; - for (i = 0; i < span->end; i++) { - rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * span->coverage[i]); - } - } -#endif - - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - multi_write_rgba_span( ctx, span->end, span->x, span->y, (const GLchan (*)[4]) rgba, span->mask ); - } - 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, span->end, span->x, span->y, rgba, span->mask ); - } - else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, span->end, span->x, span->y, rgba, span->mask ); - } - - /* Color component masking */ - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, span->end, span->x, span->y, rgba ); - } - - /* write pixels */ - (*swrast->Driver.WriteRGBASpan)( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, - span->writeAll ? ((const GLubyte *) NULL) : span->mask ); - - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, - span->writeAll ? ((const GLubyte *) NULL) : span->mask ); - } - } -} - - -/* - * 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: r, g, b, a - the color of the pixels - * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. - */ -void -_mesa_write_monocolor_span( GLcontext *ctx, struct sw_span *span, - const GLchan color[4], GLenum primitive ) -{ - const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); - GLuint i; - GLchan rgba[MAX_WIDTH][4]; - SWcontext *swrast = SWRAST_CONTEXT(ctx); - - - SET_MASK_TO_ONE(span); - - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if (clip_span(ctx,span) == GL_FALSE) { - return; - } - } - - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if (_mesa_scissor_span( ctx, span ) == GL_FALSE) { - return; - } - } - - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, span); - } - - /* Do the alpha test */ - if (ctx->Color.AlphaEnabled) { - SW_SPAN_SET_FLAG(span->filledAlpha); - for (i = 0; i < span->end; i++) { - rgba[i][ACOMP] = color[ACOMP]; - } - if (_mesa_alpha_test( ctx, span, (const GLchan (*)[4])rgba) == 0) { - return; - } - } - - /* I have to think where to put this!! */ - if (span->activeMask & SPAN_Z) { - SW_SPAN_SET_FLAG(span->filledDepth); - - if (ctx->Visual.depthBits <= 16) { - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = FixedToInt(zval); - zval += span->zStep; - } - } - else { - /* Deep Z buffer, no fixed->int shift */ - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = zval; - zval += span->zStep; - } - } - } - - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, span) == GL_FALSE) - return; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span(ctx, span) == 0) - return; - } - - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; - - if (ctx->Color.DrawBuffer == GL_NONE) { - /* write no pixels */ - return; - } - - if (ctx->Color.ColorLogicOpEnabled || colorMask != 0xffffffff || -#if 0 - (swrast->_RasterMask & (BLEND_BIT | FOG_BIT)) || coverage) { -#else - (swrast->_RasterMask & (BLEND_BIT | FOG_BIT))) { -#endif - /* assign same color to each pixel */ - SW_SPAN_SET_FLAG(span->filledColor); - for (i = 0; i < span->end; i++) { - if (span->mask[i]) { - COPY_CHAN4(rgba[i], color); - } - } - - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if ((span->activeMask & SPAN_FOG) && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels( ctx, span, rgba ); - else - _mesa_depth_fog_rgba_pixels( ctx, span, rgba ); - } - - /* Antialias coverage application */ -#if 0 - if (span->coverage) { - GLuint i; - for (i = 0; i < span->end; i++) { - rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * span->coverage[i]); - } - } -#endif - - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - multi_write_rgba_span( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, span->mask ); - } - else { - /* normal: write to exactly one buffer */ - if (ctx->Color.ColorLogicOpEnabled) { - _mesa_logicop_rgba_span( ctx, span->end, span->x, span->y, rgba, span->mask ); - } - else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, span->end, span->x, span->y, rgba, span->mask ); - } - - /* Color component masking */ - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, span->end, span->x, span->y, rgba ); - } - - /* write pixels */ - (*swrast->Driver.WriteRGBASpan)( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, - span->writeAll ? ((const GLubyte *) NULL) : span->mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, - span->writeAll ? ((const GLubyte *) NULL) : span->mask ); - } - } - } - else { - /* same color for all pixels */ - ASSERT(!ctx->Color.BlendEnabled); - ASSERT(!ctx->Color.ColorLogicOpEnabled); - - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - SW_SPAN_SET_FLAG(span->filledColor); - for (i = 0; i < span->end; i++) { - if (span->mask[i]) { - COPY_CHAN4(rgba[i], color); - } - } - multi_write_rgba_span( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, span->mask ); - } - else { - (*swrast->Driver.WriteMonoRGBASpan)( ctx, span->end, span->x, span->y, color, span->mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_mono_alpha_span( ctx, span->end, span->x, span->y, - (GLchan) color[ACOMP], - span->writeAll ? ((const GLubyte *) NULL) : span->mask ); - } - } - } -} - - - -/* - * Add specular color to base color. This is used only when - * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR. - */ -static void -add_colors(CONST struct sw_span *span, GLchan rgba[][4]) -{ - GLuint i; - ASSERT(span->filledSpecular == GL_TRUE); - ASSERT(span->filledColor == GL_TRUE); - - for (i = 0; i < span->end; i++) { -#if CHAN_TYPE == GL_FLOAT - /* no clamping */ - rgba[i][RCOMP] += span->specular[i][RCOMP]; - rgba[i][GCOMP] += span->specular[i][GCOMP]; - rgba[i][BCOMP] += span->specular[i][BCOMP]; -#else - GLint r = rgba[i][RCOMP] + span->specular[i][RCOMP]; - GLint g = rgba[i][GCOMP] + span->specular[i][GCOMP]; - GLint b = rgba[i][BCOMP] + span->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: span - contains span-data with the exception of - * fog - array of fog factor values in [0,1] - * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. - */ -void -_mesa_write_texture_span( GLcontext *ctx, struct sw_span *span, - const GLfloat fog[MAX_WIDTH], GLenum primitive ) -{ - const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); - GLchan rgbaBackup[MAX_WIDTH][4]; - GLchan (*rgba)[4]; /* points to either rgbaIn or rgbaBackup */ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - - SET_MASK_TO_ONE(span); - - if ((swrast->_RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { - if (clip_span(ctx,span) == GL_FALSE) { - return; - } - } - - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if (_mesa_scissor_span( ctx, span ) == GL_FALSE) { - return; - } - } - - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { - stipple_polygon_span( ctx, span); - } - - - if (primitive==GL_BITMAP || (swrast->_RasterMask & MULTI_DRAW_BIT)) { - /* must make a copy of the colors since they may be modified */ - MEMCPY(rgbaBackup, span->color.rgba, 4 * span->end * sizeof(GLchan)); - rgba = rgbaBackup; - } - else { - rgba = span->color.rgba; - } - - - /* 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, span, rgba ); - - /* Do the alpha test */ - if (_mesa_alpha_test( ctx, span, (const GLchan (*)[4]) rgba ) == 0) { - return; - } - } - - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, span) == GL_FALSE) - return; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span(ctx, span) == 0) - return; - } - - /* 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, span, rgba ); - } - - - /* Add base and specular colors */ - if ((span->activeMask & SPAN_SPEC) && /* Is this right test ???*/ - (ctx->Fog.ColorSumEnabled || - (ctx->Light.Enabled && - ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))) - add_colors(span, rgba); /* rgba = rgba + spec */ - - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if (fog != NULL && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels_with_array( ctx, span, fog, rgba); - else if ((span->activeMask & SPAN_FOG) && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels( ctx, span, rgba ); - else - _mesa_depth_fog_rgba_pixels(ctx, span, rgba); - } - - - /* Antialias coverage application */ -#if 0 - if (span->coverage) { - GLuint i; - for (i = 0; i < span->end; i++) { - rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * span->coverage[i]); - } - } -#endif - - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - multi_write_rgba_span( ctx, span->end, span->x, span->y, (const GLchan (*)[4]) rgba, span->mask ); - } - else { - /* normal: write to exactly one buffer */ - if (ctx->Color.ColorLogicOpEnabled) { - _mesa_logicop_rgba_span( ctx, span->end, span->x, span->y, rgba, span->mask ); - } - else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, span->end, span->x, span->y, rgba, span->mask ); - } - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, span->end, span->x, span->y, rgba ); - } - - (*swrast->Driver.WriteRGBASpan)( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, - span->writeAll ? NULL : span->mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, - span->writeAll ? NULL : span->mask ); - } - } -} - - -/* - * Write a horizontal span of textured pixels to the frame buffer. - * The color of each pixel is different. - * Depth-testing, stenciling, scissor-testing etc. should already - * have been done, - * only if alpha-testing is used, depth-testing is still done in this - * function. - * 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 - * mask - masked pixels - * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. - * Contributed by Klaus Niederkrueger. - */ -static void -masked_texture_span( GLcontext *ctx, struct sw_span *span) -{ - const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); - GLchan rgbaBackup[MAX_WIDTH][4]; - GLchan (*rgba)[4]; /* points to either span->color.rgba or rgbaBackup */ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - - - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - /* must make a copy of the colors since they may be modified */ - MEMCPY(rgbaBackup, span->color.rgba, 4 * span->end * sizeof(GLchan)); - rgba = rgbaBackup; - } - else { - rgba = span->color.rgba; - } - - - ASSERT(ctx->Texture._ReallyEnabled); - _swrast_texture_fragments( ctx, 0, span, rgba ); - - - /* Texture with alpha test */ - if (ctx->Color.AlphaEnabled) { - /* Do the alpha test */ - if (_mesa_alpha_test( ctx, span, (const GLchan (*)[4]) rgba ) == 0) { - return; - } - - /* Depth test usually in 'rasterize_span' but if alpha test - needed, we have to wait for that test before depth test can - be done. */ - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, span) == GL_FALSE) - return; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span(ctx, span) == 0) - return; - } - } - - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; - - - /* Add base and specular colors */ - if ((span->activeMask & SPAN_SPEC) && /* Is this right test ???*/ - (ctx->Fog.ColorSumEnabled || - (ctx->Light.Enabled && - ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))) - add_colors(span, rgba); /* rgba = rgba + spec */ - - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - /* Is this the right 'if' ?? */ - if ((span->activeMask & SPAN_FOG) && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels(ctx, span, rgba); - else - _mesa_depth_fog_rgba_pixels(ctx, span, rgba); - } - - /* Antialias coverage application */ -#if 0 - if (span->coverage) { - GLuint i; - for (i = 0; i < span->end; i++) { - rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * span->coverage[i]); - } - } -#endif - - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - multi_write_rgba_span( ctx, span->end, span->x, span->y, (const GLchan (*)[4]) rgba, span->mask ); - } - else { - /* normal: write to exactly one buffer */ - if (ctx->Color.ColorLogicOpEnabled) { - _mesa_logicop_rgba_span( ctx, span->end, span->x, span->y, rgba, span->mask ); - } - else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, span->end, span->x, span->y, rgba, span->mask ); - } - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, span->end, span->x, span->y, rgba ); - } - - (*swrast->Driver.WriteRGBASpan)( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, - span->writeAll ? NULL : span->mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, - span->writeAll ? NULL : span->mask ); - } - } -} - - -/* - * As above but perform multiple stages of texture application. - * Contributed by Klaus Niederkrueger. - */ -static void -masked_multitexture_span( GLcontext *ctx, struct sw_span *span) -{ - GLchan rgbaBackup[MAX_WIDTH][4]; - GLchan (*rgba)[4]; /* points to either span->color.rgba or rgbaBackup */ - GLuint i; - const GLuint texUnits = ctx->Const.MaxTextureUnits; - SWcontext *swrast = SWRAST_CONTEXT(ctx); - - - if ( (swrast->_RasterMask & MULTI_DRAW_BIT) || texUnits > 1) { - /* must make a copy of the colors since they may be modified */ - MEMCPY(rgbaBackup, span->color.rgba, 4 * span->end * sizeof(GLchan)); - rgba = rgbaBackup; - } - else { - rgba = span->color.rgba; - } - - - ASSERT(ctx->Texture._ReallyEnabled); - for (i = 0; i < texUnits; i++) - _swrast_texture_fragments( ctx, i, span, rgba ); - - /* Texture with alpha test */ - if (ctx->Color.AlphaEnabled) { - /* Do the alpha test */ - if (_mesa_alpha_test( ctx, span, (const GLchan (*)[4])rgba ) == 0) { - return; - } - - /* Depth test usually in 'rasterize_span' but if alpha test - needed, we have to wait for that test before depth test can - be done. */ - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, span) == GL_FALSE) - return; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span(ctx, span) == GL_FALSE) - return; - } - } - - /* if we get here, something passed the depth test */ - ctx->OcclusionResult = GL_TRUE; - - - /* Add base and specular colors */ - if ((span->activeMask & SPAN_SPEC) && /* Is this right test ???*/ - (ctx->Fog.ColorSumEnabled || - (ctx->Light.Enabled && - ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))) - add_colors(span, rgba); /* rgba = rgba + spec */ - - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - /* Is this the right 'if' ?? */ - if ((span->activeMask & SPAN_FOG) && !swrast->_PreferPixelFog) - _mesa_fog_rgba_pixels( ctx, span, rgba ); - else - _mesa_depth_fog_rgba_pixels( ctx, span, rgba ); - } - - /* Antialias coverage application */ -#if 0 - if (span->coverage) { - GLuint i; - for (i = 0; i < span->end; i++) { - rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * span->coverage[i]); - } - } -#endif - - if (swrast->_RasterMask & MULTI_DRAW_BIT) { - multi_write_rgba_span( ctx, span->end, span->x, span->y, - (const GLchan (*)[4]) rgba, span->mask ); + /* draw to zero or two or more buffers */ + multi_write_index_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, span->end, span->x, span->y, rgba, span->mask ); - } - else if (ctx->Color.BlendEnabled) { - _mesa_blend_span( ctx, span->end, span->x, span->y, rgba, span->mask ); + /* normal situation: draw to exactly one buffer */ + if (ctx->Color.IndexLogicOpEnabled) { + _swrast_logicop_ci_span(ctx, span, span->array->index); } - if (colorMask == 0x0) { - return; - } - else if (colorMask != 0xffffffff) { - _mesa_mask_rgba_span( ctx, span->end, span->x, span->y, rgba ); + if (ctx->Color.IndexMask != 0xffffffff) { + _swrast_mask_index_span(ctx, span, span->array->index); } - (*swrast->Driver.WriteRGBASpan)( ctx, span->end, span->x, span->y, - (const GLchan (*)[4])rgba, - span->writeAll ? NULL : span->mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, span->end, span->x, span->y, - (const GLchan (*)[4])rgba, - span->writeAll ? NULL : span->mask ); + /* write pixels */ + 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; } -/* - * Generate arrays of fragment colors, z, fog, texcoords, etc from a - * triangle span object. Then call the span/fragment processsing - * functions in s_span.[ch]. This is used by a bunch of the textured - * triangle functions. - * Contributed by Klaus Niederkrueger. +/** + * 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 -_mesa_rasterize_span(GLcontext *ctx, struct sw_span *span) +_swrast_write_rgba_span( GLcontext *ctx, struct sw_span *span) { 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 - SET_MASK_TO_ONE(span); + 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; + } + /* 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) { - if (clip_span(ctx, span) == GL_FALSE) { - return; + /* Clipping */ + if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) { + if (!clip_span(ctx, span)) { + return; } } - /* Do the scissor test */ - if (ctx->Scissor.Enabled) { - if (_mesa_scissor_span( ctx, span ) == GL_FALSE) { + /* Depth bounds test */ + if (ctx->Depth.BoundsTest && ctx->Visual.depthBits > 0) { + if (!_swrast_depth_bounds_test(ctx, span)) { 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); + } + } + } +#endif + /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag) { - stipple_polygon_span( ctx, span ); + if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) { + stipple_polygon_span(ctx, span); } - /* I have to think where to put this!! */ - if (span->activeMask & SPAN_Z) { - SW_SPAN_SET_FLAG(span->filledDepth); - - if (ctx->Visual.depthBits <= 16) { - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = FixedToInt(zval); - zval += span->zStep; - } + /* 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; } - else { - /* Deep Z buffer, no fixed->int shift */ - GLuint i; - GLfixed zval = span->z; - for (i = 0; i < span->end; i++) { - span->depth[i] = zval; - zval += span->zStep; - } + if (span->interpMask & SPAN_SPEC) { + interpolate_specular(ctx, span); } + if ((span->interpMask & SPAN_TEXTURE) + && (span->arrayMask & SPAN_TEXTURE) == 0) + interpolate_texcoords(ctx, span); + _swrast_exec_fragment_program(ctx, span); + monoColor = GL_FALSE; } - /* Correct order: texturing --> alpha test --> depth test. But if - no alpha test needed, we can do here the depth test and - potentially avoid some of the texturing (otherwise alpha test, - depth test etc. happens in masked_texture_span(). */ - if (span->activeMask & SPAN_Z && !ctx->Color.AlphaEnabled) { - if (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_mesa_stencil_and_ztest_span(ctx, span) == GL_FALSE) - return; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - if (_mesa_depth_test_span( ctx, span) == 0) { + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + if (!_swrast_alpha_test(ctx, span)) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; return; - } - } + } } - if (span->activeMask & SPAN_RGBA) { - SW_SPAN_SET_FLAG(span->filledColor); - SW_SPAN_SET_FLAG(span->filledAlpha); - if (span->activeMask & SPAN_FLAT) { - GLuint i; - 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 < span->end; i++) { - COPY_CHAN4(span->color.rgba[i], color); + /* 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; } } else { - /* smooth interpolation */ -#if CHAN_TYPE == GL_FLOAT - GLfloat r = span->red; - GLfloat g = span->green; - GLfloat b = span->blue; - GLfloat a = span->alpha; -#else - GLfixed r = span->red; - GLfixed g = span->green; - GLfixed b = span->blue; - GLfixed a = span->alpha; -#endif - GLuint i; - for (i = 0; i < span->end; i++) { - span->color.rgba[i][RCOMP] = FixedToChan(r); - span->color.rgba[i][GCOMP] = FixedToChan(g); - span->color.rgba[i][BCOMP] = FixedToChan(b); - span->color.rgba[i][ACOMP] = FixedToChan(a); - r += span->redStep; - g += span->greenStep; - b += span->blueStep; - a += span->alphaStep; + 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 (span->activeMask & SPAN_SPEC) { - SW_SPAN_SET_FLAG(span->filledSpecular); - if (span->activeMask & SPAN_FLAT) { - 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->specular[i][RCOMP] = r; - span->specular[i][GCOMP] = g; - span->specular[i][BCOMP] = b; - } - } - else { - /* smooth interpolation */ -#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; + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + +#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 - GLuint i; - for (i = 0; i < span->end; i++) { - span->specular[i][RCOMP] = FixedToChan(r); - span->specular[i][GCOMP] = FixedToChan(g); - span->specular[i][BCOMP] = FixedToChan(b); - r += span->specRedStep; - g += span->specGreenStep; - b += span->specBlueStep; - } + + /* can't abort span-writing until after occlusion testing */ + if (colorMask == 0x0) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; + return; + } + + /* 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; + } + + /* Fog */ + if (swrast->_FogEnabled) { + _swrast_fog_rgba_span(ctx, span); + monoColor = GL_FALSE; + } + + /* 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]); } + monoColor = GL_FALSE; } - if (span->activeMask & SPAN_INDEX) { - SW_SPAN_SET_FLAG(span->filledColor); - if (span->activeMask & SPAN_FLAT) { - GLuint i; - const GLint indx = FixedToInt(span->index); - for (i = 0; i < span->end; i++) { - span->color.index[i] = indx; - } + if (swrast->_RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span(ctx, span); + } + else { + /* normal: write to exactly one buffer */ + if (ctx->Color._LogicOpEnabled) { + _swrast_logicop_rgba_span(ctx, span, span->array->rgba); + monoColor = GL_FALSE; } - else { - /* smooth interpolation */ - GLuint i; - GLfixed ind = span->index; - for (i = 0; i < span->end; i++) { - span->color.index[i] = FixedToInt(ind); - ind += span->indexStep; - } + else if (ctx->Color.BlendEnabled) { + _swrast_blend_span(ctx, span, span->array->rgba); + monoColor = GL_FALSE; } - } - if (span->activeMask & SPAN_TEXTURE) { - if (ctx->Texture._ReallyEnabled & ~TEXTURE0_ANY) { - /* multitexture */ - if (span->activeMask & SPAN_LAMBDA) { - /* with lambda */ - GLuint u; - /* multitexture, lambda */ - for (u = 0; u < MAX_TEXTURE_UNITS; u++) { - if (ctx->Texture.Unit[u]._ReallyEnabled) { - 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; - SW_SPAN_SET_FLAG(span->filledLambda[u]); - SW_SPAN_SET_FLAG(span->filledTex[u]); - for (i = 0; i < span->end; i++) { - const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); - span->texcoords[u][i][0] = s * invQ; - span->texcoords[u][i][1] = t * invQ; - span->texcoords[u][i][2] = r * invQ; - span->lambda[u][i] = (GLfloat) - (log(span->rho[u] * invQ * invQ) * 1.442695F * 0.5F); - s += span->texStep[u][0]; - t += span->texStep[u][1]; - r += span->texStep[u][2]; - q += span->texStep[u][3]; - } - } + /* 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 { - /* without lambda */ - GLuint u; - /* multitexture, no lambda */ - for (u = 0; u < MAX_TEXTURE_UNITS; u++) { - if (ctx->Texture.Unit[u]._ReallyEnabled) { - 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; - SW_SPAN_SET_FLAG(span->filledTex[u]); - for (i = 0; i < span->end; i++) { - const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); - span->texcoords[u][i][0] = s * invQ; - span->texcoords[u][i][1] = t * invQ; - span->texcoords[u][i][2] = r * invQ; - s += span->texStep[u][0]; - t += span->texStep[u][1]; - r += span->texStep[u][2]; - q += span->texStep[u][3]; - } - } + (*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 { - /* just texture unit 0 */ -#ifdef DEBUG - {GLint i; - for (i=0; ifilledTex[i] == GL_FALSE && - span->filledLambda[i] == GL_FALSE); - }} -#endif - if (span->activeMask & SPAN_LAMBDA) { - /* with lambda */ - 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; - SW_SPAN_SET_FLAG(span->filledLambda[0]); - SW_SPAN_SET_FLAG(span->filledTex[0]); - /* single texture, lambda */ - for (i = 0; i < span->end; i++) { - const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); - span->texcoords[0][i][0] = s * invQ; - span->texcoords[0][i][1] = t * invQ; - span->texcoords[0][i][2] = r * invQ; - span->lambda[0][i] = (GLfloat) - (log(span->rho[0] * invQ * invQ) * 1.442695F * 0.5F); - s += span->texStep[0][0]; - t += span->texStep[0][1]; - r += span->texStep[0][2]; - q += span->texStep[0][3]; + /* 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 { - /* without lambda */ - 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; - SW_SPAN_SET_FLAG(span->filledTex[0]); - /* single texture, no lambda */ - for (i = 0; i < span->end; i++) { - const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); - span->texcoords[0][i][0] = s * invQ; - span->texcoords[0][i][1] = t * invQ; - span->texcoords[0][i][2] = r * invQ; - s += span->texStep[0][0]; - t += span->texStep[0][1]; - r += span->texStep[0][2]; - q += span->texStep[0][3]; - } + /* 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); + } } } } - /* XXX keep this? */ - if (span->activeMask & SPAN_INT_TEXTURE) { - GLfixed s = span->intTex[0]; - GLfixed t = span->intTex[1]; - GLuint i; - for (i = 0; i < span->end; i++) { - span->itexcoords[i][0] = FixedToInt(s); - span->itexcoords[i][1] = FixedToInt(t); - s += span->intTexStep[0]; - t += span->intTexStep[1]; - } - } - - /* examine activeMask and call a s_span.c function */ - if (span->activeMask & SPAN_TEXTURE) { - - if (ctx->Texture._ReallyEnabled & ~TEXTURE0_ANY) { - /* multi texture */ - masked_multitexture_span(ctx, span); - } - else { - /* single texture */ - masked_texture_span(ctx, span); - } - } - else { - _mesa_problem(ctx, "rasterize_span() should only be used for texturing"); - } + 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 -_old_add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] ) +add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] ) { GLuint i; for (i = 0; i < n; i++) { @@ -1924,339 +1309,248 @@ _old_add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] ) } -/* - * 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 - * fog - array of fog factor values in [0,1] - * 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 -_old_write_texture_span( GLcontext *ctx, GLuint n, GLint x, GLint y, - const GLdepth z[], const GLfloat fog[], - GLfloat texcoord[][4], - GLfloat lambda[], - GLchan rgbaIn[][4], GLchan spec[][4], - const GLfloat coverage[], GLenum primitive ) +_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 */ 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=old_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 = _old_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; } +#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) { - old_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); } + /* Need texture coordinates now */ + if ((span->interpMask & SPAN_TEXTURE) + && (span->arrayMask & SPAN_TEXTURE) == 0) + interpolate_texcoords(ctx, span); + /* 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); - _old_swrast_texture_fragments( ctx, 0, n, texcoord, lambda, - (CONST GLchan (*)[4]) rgba, rgba ); - /* Do the alpha test */ - if (_old_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 (_old_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { - return; + if (span->interpMask & SPAN_SPEC) { + interpolate_specular(ctx, span); } - write_all = GL_FALSE; - } - else if (ctx->Depth.Test) { - /* regular depth testing */ - GLuint m = _old_depth_test_span( ctx, n, x, y, z, mask ); - if (m == 0) { - return; - } - if (m < n) { - write_all = GL_FALSE; - } - } - - /* 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); - _old_swrast_texture_fragments( ctx, 0, n, texcoord, lambda, - (CONST GLchan (*)[4]) rgba, rgba ); - } - /* Add base and specular colors */ - if (spec && - (ctx->Fog.ColorSumEnabled || - (ctx->Light.Enabled && - ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))) - _old_add_colors( n, rgba, spec ); /* rgba = rgba + spec */ - - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if (fog && !swrast->_PreferPixelFog) - _old_fog_rgba_pixels( ctx, n, fog, rgba ); + /* 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 - _old_depth_fog_rgba_pixels( ctx, n, z, rgba ); - } + _swrast_texture_span( ctx, span ); - /* Antialias coverage application */ - if (coverage) { - GLuint i; - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]); + /* Do the alpha test */ + if (!_swrast_alpha_test(ctx, span)) { + span->arrayMask = origArrayMask; + return; } } - 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 ); - } + /* Stencil and Z testing */ + if (ctx->Stencil.Enabled || ctx->Depth.Test) { + if (span->interpMask & SPAN_Z) + _swrast_span_interpolate_z(ctx, span); - (*swrast->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, - write_all ? ((const GLubyte *) NULL) : mask ); - if (swrast->_RasterMask & ALPHABUF_BIT) { - _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, - write_all ? ((const GLubyte *) NULL) : mask ); + if (ctx->Stencil.Enabled) { + if (!_swrast_stencil_and_ztest_span(ctx, span)) { + span->interpMask = origInterpMask; + span->arrayMask = origArrayMask; + return; + } } - } -} - - - -/* - * As above but perform multiple stages of texture application. - */ -void -_old_write_multitexture_span( GLcontext *ctx, GLuint n, GLint x, GLint y, - const GLdepth z[], const GLfloat fog[], - GLfloat texcoord[MAX_TEXTURE_UNITS][MAX_WIDTH][4], - GLfloat lambda[][MAX_WIDTH], - GLchan rgbaIn[MAX_TEXTURE_UNITS][4], - GLchan spec[MAX_TEXTURE_UNITS][4], - const GLfloat coverage[], - 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=old_clip_span(ctx, n, x, y, mask)) == 0) { - 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 = _old_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) { - old_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++) - _old_swrast_texture_fragments( ctx, i, n, texcoord[i], lambda[i], - (CONST GLchan (*)[4]) rgbaIn, 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); - /* Do the alpha test */ - if (_old_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 (ctx->Stencil.Enabled) { - /* first stencil test */ - if (_old_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 = _old_depth_test_span( ctx, n, x, y, z, mask ); - if (m == 0) { - return; - } - if (m < n) { - write_all = GL_FALSE; - } + 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; - - /* Texture without alpha test */ - if (! ctx->Color.AlphaEnabled) { - ASSERT(ctx->Texture._ReallyEnabled); - for (i = 0; i < texUnits; i++) - _old_swrast_texture_fragments( ctx, i, n, texcoord[i], lambda[i], - (CONST GLchan (*)[4]) rgbaIn, rgba ); - } + ASSERT(span->arrayMask & SPAN_RGBA); /* Add base and specular colors */ - if (spec && - (ctx->Fog.ColorSumEnabled || - (ctx->Light.Enabled && - ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))) - _old_add_colors( n, rgba, spec ); /* rgba = rgba + spec */ + 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 ); + } - /* Per-pixel fog */ - if (ctx->Fog.Enabled) { - if (fog && !swrast->_PreferPixelFog) - _old_fog_rgba_pixels( ctx, n, fog, rgba ); - else - _old_depth_fog_rgba_pixels( ctx, n, z, rgba ); + /* Fog */ + if (swrast->_FogEnabled) { + _swrast_fog_rgba_span(ctx, span); } /* Antialias coverage application */ - if (coverage) { + if (span->arrayMask & SPAN_COVERAGE) { + GLchan (*rgba)[4] = span->array->rgba; + GLfloat *coverage = span->array->coverage; GLuint i; - for (i = 0; i < n; 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); } - (*swrast->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 -_mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, +_swrast_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, GLuint n, GLint x, GLint y, GLchan rgba[][4] ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); - if (y < 0 || y >= buffer->Height - || x + (GLint) n < 0 || x >= buffer->Width) { + 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; @@ -2268,14 +1562,14 @@ _mesa_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; @@ -2289,27 +1583,27 @@ _mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, (*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 -_mesa_read_index_span( GLcontext *ctx, GLframebuffer *buffer, +_swrast_read_index_span( GLcontext *ctx, GLframebuffer *buffer, GLuint n, GLint x, GLint y, GLuint indx[] ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); - if (y < 0 || y >= buffer->Height - || x + (GLint) n < 0 || x >= buffer->Width) { + 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; @@ -2321,14 +1615,14 @@ _mesa_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;