diff options
Diffstat (limited to 'mesalib/src/mesa/swrast/s_span.c')
-rw-r--r-- | mesalib/src/mesa/swrast/s_span.c | 3006 |
1 files changed, 1503 insertions, 1503 deletions
diff --git a/mesalib/src/mesa/swrast/s_span.c b/mesalib/src/mesa/swrast/s_span.c index 9cfecc9e3..f0222f5a0 100644 --- a/mesalib/src/mesa/swrast/s_span.c +++ b/mesalib/src/mesa/swrast/s_span.c @@ -1,1503 +1,1503 @@ -/* - * Mesa 3-D graphics library - * Version: 7.5 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/** - * \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 "main/glheader.h" -#include "main/colormac.h" -#include "main/macros.h" -#include "main/imports.h" -#include "main/image.h" - -#include "s_atifragshader.h" -#include "s_alpha.h" -#include "s_blend.h" -#include "s_context.h" -#include "s_depth.h" -#include "s_fog.h" -#include "s_logic.h" -#include "s_masking.h" -#include "s_fragprog.h" -#include "s_span.h" -#include "s_stencil.h" -#include "s_texcombine.h" - - -/** - * Set default fragment attributes for the span using the - * current raster values. Used prior to glDraw/CopyPixels - * and glBitmap. - */ -void -_swrast_span_default_attribs(struct gl_context *ctx, SWspan *span) -{ - GLchan r, g, b, a; - /* Z*/ - { - const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF; - if (ctx->DrawBuffer->Visual.depthBits <= 16) - span->z = FloatToFixed(ctx->Current.RasterPos[2] * depthMax + 0.5F); - else { - GLfloat tmpf = ctx->Current.RasterPos[2] * depthMax; - tmpf = MIN2(tmpf, depthMax); - span->z = (GLint)tmpf; - } - span->zStep = 0; - span->interpMask |= SPAN_Z; - } - - /* W (for perspective correction) */ - span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0; - span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0; - span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0; - - /* primary color, or color index */ - 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; - - COPY_4V(span->attrStart[FRAG_ATTRIB_COL0], ctx->Current.RasterColor); - ASSIGN_4V(span->attrStepX[FRAG_ATTRIB_COL0], 0.0, 0.0, 0.0, 0.0); - ASSIGN_4V(span->attrStepY[FRAG_ATTRIB_COL0], 0.0, 0.0, 0.0, 0.0); - - /* Secondary color */ - if (ctx->Light.Enabled || ctx->Fog.ColorSumEnabled) - { - COPY_4V(span->attrStart[FRAG_ATTRIB_COL1], ctx->Current.RasterSecondaryColor); - ASSIGN_4V(span->attrStepX[FRAG_ATTRIB_COL1], 0.0, 0.0, 0.0, 0.0); - ASSIGN_4V(span->attrStepY[FRAG_ATTRIB_COL1], 0.0, 0.0, 0.0, 0.0); - } - - /* fog */ - { - const SWcontext *swrast = SWRAST_CONTEXT(ctx); - GLfloat fogVal; /* a coord or a blend factor */ - if (swrast->_PreferPixelFog) { - /* fog blend factors will be computed from fog coordinates per pixel */ - fogVal = ctx->Current.RasterDistance; - } - else { - /* fog blend factor should be computed from fogcoord now */ - fogVal = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance); - } - span->attrStart[FRAG_ATTRIB_FOGC][0] = fogVal; - span->attrStepX[FRAG_ATTRIB_FOGC][0] = 0.0; - span->attrStepY[FRAG_ATTRIB_FOGC][0] = 0.0; - } - - /* texcoords */ - { - GLuint i; - for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { - const GLuint attr = FRAG_ATTRIB_TEX0 + i; - const GLfloat *tc = ctx->Current.RasterTexCoords[i]; - if (ctx->FragmentProgram._Current || ctx->ATIFragmentShader._Enabled) { - COPY_4V(span->attrStart[attr], tc); - } - else if (tc[3] > 0.0F) { - /* use (s/q, t/q, r/q, 1) */ - span->attrStart[attr][0] = tc[0] / tc[3]; - span->attrStart[attr][1] = tc[1] / tc[3]; - span->attrStart[attr][2] = tc[2] / tc[3]; - span->attrStart[attr][3] = 1.0; - } - else { - ASSIGN_4V(span->attrStart[attr], 0.0F, 0.0F, 0.0F, 1.0F); - } - ASSIGN_4V(span->attrStepX[attr], 0.0F, 0.0F, 0.0F, 0.0F); - ASSIGN_4V(span->attrStepY[attr], 0.0F, 0.0F, 0.0F, 0.0F); - } - } -} - - -/** - * Interpolate the active attributes (and'd with attrMask) to - * fill in span->array->attribs[]. - * Perspective correction will be done. The point/line/triangle function - * should have computed attrStart/Step values for FRAG_ATTRIB_WPOS[3]! - */ -static INLINE void -interpolate_active_attribs(struct gl_context *ctx, SWspan *span, GLbitfield attrMask) -{ - const SWcontext *swrast = SWRAST_CONTEXT(ctx); - - /* - * Don't overwrite existing array values, such as colors that may have - * been produced by glDraw/CopyPixels. - */ - attrMask &= ~span->arrayAttribs; - - ATTRIB_LOOP_BEGIN - if (attrMask & (1 << attr)) { - const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3]; - GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3]; - const GLfloat dv0dx = span->attrStepX[attr][0]; - const GLfloat dv1dx = span->attrStepX[attr][1]; - const GLfloat dv2dx = span->attrStepX[attr][2]; - const GLfloat dv3dx = span->attrStepX[attr][3]; - GLfloat v0 = span->attrStart[attr][0] + span->leftClip * dv0dx; - GLfloat v1 = span->attrStart[attr][1] + span->leftClip * dv1dx; - GLfloat v2 = span->attrStart[attr][2] + span->leftClip * dv2dx; - GLfloat v3 = span->attrStart[attr][3] + span->leftClip * dv3dx; - GLuint k; - for (k = 0; k < span->end; k++) { - const GLfloat invW = 1.0f / w; - span->array->attribs[attr][k][0] = v0 * invW; - span->array->attribs[attr][k][1] = v1 * invW; - span->array->attribs[attr][k][2] = v2 * invW; - span->array->attribs[attr][k][3] = v3 * invW; - v0 += dv0dx; - v1 += dv1dx; - v2 += dv2dx; - v3 += dv3dx; - w += dwdx; - } - ASSERT((span->arrayAttribs & (1 << attr)) == 0); - span->arrayAttribs |= (1 << attr); - } - ATTRIB_LOOP_END -} - - -/** - * Interpolate primary colors to fill in the span->array->rgba8 (or rgb16) - * color array. - */ -static INLINE void -interpolate_int_colors(struct gl_context *ctx, SWspan *span) -{ - const GLuint n = span->end; - GLuint i; - -#if CHAN_BITS != 32 - ASSERT(!(span->arrayMask & SPAN_RGBA)); -#endif - - switch (span->array->ChanType) { -#if CHAN_BITS != 32 - case GL_UNSIGNED_BYTE: - { - GLubyte (*rgba)[4] = span->array->rgba8; - if (span->interpMask & SPAN_FLAT) { - GLubyte color[4]; - color[RCOMP] = FixedToInt(span->red); - color[GCOMP] = FixedToInt(span->green); - color[BCOMP] = FixedToInt(span->blue); - color[ACOMP] = FixedToInt(span->alpha); - for (i = 0; i < n; i++) { - COPY_4UBV(rgba[i], color); - } - } - else { - GLfixed r = span->red; - GLfixed g = span->green; - GLfixed b = span->blue; - GLfixed a = span->alpha; - GLint dr = span->redStep; - GLint dg = span->greenStep; - GLint db = span->blueStep; - GLint da = span->alphaStep; - 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; - } - } - } - break; - case GL_UNSIGNED_SHORT: - { - GLushort (*rgba)[4] = span->array->rgba16; - if (span->interpMask & SPAN_FLAT) { - GLushort color[4]; - color[RCOMP] = FixedToInt(span->red); - color[GCOMP] = FixedToInt(span->green); - color[BCOMP] = FixedToInt(span->blue); - color[ACOMP] = FixedToInt(span->alpha); - for (i = 0; i < n; i++) { - COPY_4V(rgba[i], color); - } - } - else { - GLushort (*rgba)[4] = span->array->rgba16; - GLfixed r, g, b, a; - GLint dr, dg, db, da; - r = span->red; - g = span->green; - b = span->blue; - a = span->alpha; - dr = span->redStep; - dg = span->greenStep; - db = span->blueStep; - da = span->alphaStep; - 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; - } - } - } - break; -#endif - case GL_FLOAT: - interpolate_active_attribs(ctx, span, FRAG_BIT_COL0); - break; - default: - _mesa_problem(ctx, "bad datatype 0x%x in interpolate_int_colors", - span->array->ChanType); - } - span->arrayMask |= SPAN_RGBA; -} - - -/** - * Populate the FRAG_ATTRIB_COL0 array. - */ -static INLINE void -interpolate_float_colors(SWspan *span) -{ - GLfloat (*col0)[4] = span->array->attribs[FRAG_ATTRIB_COL0]; - const GLuint n = span->end; - GLuint i; - - assert(!(span->arrayAttribs & FRAG_BIT_COL0)); - - if (span->arrayMask & SPAN_RGBA) { - /* convert array of int colors */ - for (i = 0; i < n; i++) { - col0[i][0] = UBYTE_TO_FLOAT(span->array->rgba8[i][0]); - col0[i][1] = UBYTE_TO_FLOAT(span->array->rgba8[i][1]); - col0[i][2] = UBYTE_TO_FLOAT(span->array->rgba8[i][2]); - col0[i][3] = UBYTE_TO_FLOAT(span->array->rgba8[i][3]); - } - } - else { - /* interpolate red/green/blue/alpha to get float colors */ - ASSERT(span->interpMask & SPAN_RGBA); - if (span->interpMask & SPAN_FLAT) { - GLfloat r = FixedToFloat(span->red); - GLfloat g = FixedToFloat(span->green); - GLfloat b = FixedToFloat(span->blue); - GLfloat a = FixedToFloat(span->alpha); - for (i = 0; i < n; i++) { - ASSIGN_4V(col0[i], r, g, b, a); - } - } - else { - GLfloat r = FixedToFloat(span->red); - GLfloat g = FixedToFloat(span->green); - GLfloat b = FixedToFloat(span->blue); - GLfloat a = FixedToFloat(span->alpha); - GLfloat dr = FixedToFloat(span->redStep); - GLfloat dg = FixedToFloat(span->greenStep); - GLfloat db = FixedToFloat(span->blueStep); - GLfloat da = FixedToFloat(span->alphaStep); - for (i = 0; i < n; i++) { - col0[i][0] = r; - col0[i][1] = g; - col0[i][2] = b; - col0[i][3] = a; - r += dr; - g += dg; - b += db; - a += da; - } - } - } - - span->arrayAttribs |= FRAG_BIT_COL0; - span->array->ChanType = GL_FLOAT; -} - - - -/** - * Fill in the span.zArray array from the span->z, zStep values. - */ -void -_swrast_span_interpolate_z( const struct gl_context *ctx, SWspan *span ) -{ - const GLuint n = span->end; - GLuint i; - - ASSERT(!(span->arrayMask & SPAN_Z)); - - if (ctx->DrawBuffer->Visual.depthBits <= 16) { - GLfixed zval = span->z; - GLuint *z = span->array->z; - for (i = 0; i < n; i++) { - z[i] = FixedToInt(zval); - zval += span->zStep; - } - } - else { - /* Deep Z buffer, no fixed->int shift */ - GLuint zval = span->z; - GLuint *z = span->array->z; - for (i = 0; i < n; i++) { - z[i] = zval; - zval += span->zStep; - } - } - span->interpMask &= ~SPAN_Z; - span->arrayMask |= SPAN_Z; -} - - -/** - * Compute mipmap LOD from partial derivatives. - * This the ideal solution, as given in the OpenGL spec. - */ -GLfloat -_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy, - GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH, - GLfloat s, GLfloat t, GLfloat q, GLfloat invQ) -{ - GLfloat 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; -} - - -/** - * Compute mipmap LOD from partial derivatives. - * This is a faster approximation than above function. - */ -#if 0 -GLfloat -_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy, - GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH, - GLfloat s, GLfloat t, GLfloat q, GLfloat invQ) -{ - GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ; - GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ; - GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ; - GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ; - GLfloat maxU, maxV, rho, lambda; - dsdx2 = FABSF(dsdx2); - dsdy2 = FABSF(dsdy2); - dtdx2 = FABSF(dtdx2); - dtdy2 = FABSF(dtdy2); - maxU = MAX2(dsdx2, dsdy2) * texW; - maxV = MAX2(dtdx2, dtdy2) * texH; - rho = MAX2(maxU, maxV); - lambda = LOG2(rho); - return lambda; -} -#endif - - -/** - * Fill in the span.array->attrib[FRAG_ATTRIB_TEXn] arrays from the - * using the attrStart/Step values. - * - * This function only used during fixed-function fragment processing. - * - * 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). - */ -static void -interpolate_texcoords(struct gl_context *ctx, SWspan *span) -{ - const GLuint maxUnit - = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1; - GLuint u; - - /* XXX CoordUnits vs. ImageUnits */ - for (u = 0; u < maxUnit; u++) { - if (ctx->Texture._EnabledCoordUnits & (1 << u)) { - const GLuint attr = FRAG_ATTRIB_TEX0 + u; - const struct gl_texture_object *obj = ctx->Texture.Unit[u]._Current; - GLfloat texW, texH; - GLboolean needLambda; - GLfloat (*texcoord)[4] = span->array->attribs[attr]; - GLfloat *lambda = span->array->lambda[u]; - const GLfloat dsdx = span->attrStepX[attr][0]; - const GLfloat dsdy = span->attrStepY[attr][0]; - const GLfloat dtdx = span->attrStepX[attr][1]; - const GLfloat dtdy = span->attrStepY[attr][1]; - const GLfloat drdx = span->attrStepX[attr][2]; - const GLfloat dqdx = span->attrStepX[attr][3]; - const GLfloat dqdy = span->attrStepY[attr][3]; - GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx; - GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx; - GLfloat r = span->attrStart[attr][2] + span->leftClip * drdx; - GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx; - - if (obj) { - const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel]; - needLambda = (obj->Sampler.MinFilter != obj->Sampler.MagFilter) - || ctx->FragmentProgram._Current; - texW = img->WidthScale; - texH = img->HeightScale; - } - else { - /* using a fragment program */ - texW = 1.0; - texH = 1.0; - needLambda = GL_FALSE; - } - - if (needLambda) { - GLuint i; - if (ctx->FragmentProgram._Current - || ctx->ATIFragmentShader._Enabled) { - /* do perspective correction but don't divide s, t, r by q */ - const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3]; - GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dwdx; - for (i = 0; i < span->end; i++) { - const GLfloat invW = 1.0F / w; - texcoord[i][0] = s * invW; - texcoord[i][1] = t * invW; - texcoord[i][2] = r * invW; - texcoord[i][3] = q * invW; - lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy, - dqdx, dqdy, texW, texH, - s, t, q, invW); - s += dsdx; - t += dtdx; - r += drdx; - q += dqdx; - w += dwdx; - } - } - else { - for (i = 0; i < span->end; i++) { - const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); - texcoord[i][0] = s * invQ; - texcoord[i][1] = t * invQ; - texcoord[i][2] = r * invQ; - texcoord[i][3] = q; - lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy, - dqdx, dqdy, texW, texH, - s, t, q, invQ); - s += dsdx; - t += dtdx; - r += drdx; - q += dqdx; - } - } - span->arrayMask |= SPAN_LAMBDA; - } - else { - GLuint i; - if (ctx->FragmentProgram._Current || - ctx->ATIFragmentShader._Enabled) { - /* do perspective correction but don't divide s, t, r by q */ - const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3]; - GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dwdx; - 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 */ -} - - -/** - * Fill in the arrays->attribs[FRAG_ATTRIB_WPOS] array. - */ -static INLINE void -interpolate_wpos(struct gl_context *ctx, SWspan *span) -{ - GLfloat (*wpos)[4] = span->array->attribs[FRAG_ATTRIB_WPOS]; - GLuint i; - const GLfloat zScale = 1.0F / ctx->DrawBuffer->_DepthMaxF; - GLfloat w, dw; - - if (span->arrayMask & SPAN_XY) { - for (i = 0; i < span->end; i++) { - wpos[i][0] = (GLfloat) span->array->x[i]; - wpos[i][1] = (GLfloat) span->array->y[i]; - } - } - else { - for (i = 0; i < span->end; i++) { - wpos[i][0] = (GLfloat) span->x + i; - wpos[i][1] = (GLfloat) span->y; - } - } - - dw = span->attrStepX[FRAG_ATTRIB_WPOS][3]; - w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dw; - for (i = 0; i < span->end; i++) { - wpos[i][2] = (GLfloat) span->array->z[i] * zScale; - wpos[i][3] = w; - w += dw; - } -} - - -/** - * Apply the current polygon stipple pattern to a span of pixels. - */ -static INLINE void -stipple_polygon_span(struct gl_context *ctx, SWspan *span) -{ - GLubyte *mask = span->array->mask; - - ASSERT(ctx->Polygon.StippleFlag); - - if (span->arrayMask & SPAN_XY) { - /* arrays of x/y pixel coords */ - GLuint i; - for (i = 0; i < span->end; i++) { - const GLint col = span->array->x[i] % 32; - const GLint row = span->array->y[i] % 32; - const GLuint stipple = ctx->PolygonStipple[row]; - if (((1 << col) & stipple) == 0) { - mask[i] = 0; - } - } - } - else { - /* horizontal span of pixels */ - const GLuint highBit = 1 << 31; - const GLuint stipple = ctx->PolygonStipple[span->y % 32]; - GLuint i, 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 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 INLINE GLuint -clip_span( struct gl_context *ctx, SWspan *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; - - span->leftClip = 0; - - if (span->arrayMask & SPAN_XY) { - /* arrays of x/y pixel coords */ - const GLint *x = span->array->x; - const GLint *y = span->array->y; - const GLint n = span->end; - GLubyte *mask = span->array->mask; - GLint i; - if (span->arrayMask & SPAN_MASK) { - /* note: using & intead of && to reduce branches */ - for (i = 0; i < n; i++) { - mask[i] &= (x[i] >= xmin) & (x[i] < xmax) - & (y[i] >= ymin) & (y[i] < ymax); - } - } - else { - /* note: using & intead of && to reduce branches */ - for (i = 0; i < n; i++) { - mask[i] = (x[i] >= xmin) & (x[i] < xmax) - & (y[i] >= ymin) & (y[i] < ymax); - } - } - return GL_TRUE; /* some pixels visible */ - } - else { - /* horizontal span of pixels */ - const GLint x = span->x; - const GLint y = span->y; - 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 right */ - if (x + n > xmax) { - ASSERT(x < xmax); - n = span->end = xmax - x; - } - - /* Clip to the left */ - if (x < xmin) { - const GLint leftClip = xmin - x; - GLuint i; - - ASSERT(leftClip > 0); - ASSERT(x + n > xmin); - - /* Clip 'leftClip' pixels from the left side. - * The span->leftClip field will be applied when we interpolate - * fragment attributes. - * For arrays of values, shift them left. - */ - for (i = 0; i < FRAG_ATTRIB_MAX; i++) { - if (span->interpMask & (1 << i)) { - GLuint j; - for (j = 0; j < 4; j++) { - span->attrStart[i][j] += leftClip * span->attrStepX[i][j]; - } - } - } - - span->red += leftClip * span->redStep; - span->green += leftClip * span->greenStep; - span->blue += leftClip * span->blueStep; - span->alpha += leftClip * span->alphaStep; - span->index += leftClip * span->indexStep; - span->z += leftClip * span->zStep; - span->intTex[0] += leftClip * span->intTexStep[0]; - span->intTex[1] += leftClip * span->intTexStep[1]; - -#define SHIFT_ARRAY(ARRAY, SHIFT, LEN) \ - memcpy(ARRAY, ARRAY + (SHIFT), (LEN) * sizeof(ARRAY[0])) - - for (i = 0; i < FRAG_ATTRIB_MAX; i++) { - if (span->arrayAttribs & (1 << i)) { - /* shift array elements left by 'leftClip' */ - SHIFT_ARRAY(span->array->attribs[i], leftClip, n - leftClip); - } - } - - SHIFT_ARRAY(span->array->mask, leftClip, n - leftClip); - SHIFT_ARRAY(span->array->rgba8, leftClip, n - leftClip); - SHIFT_ARRAY(span->array->rgba16, leftClip, n - leftClip); - SHIFT_ARRAY(span->array->x, leftClip, n - leftClip); - SHIFT_ARRAY(span->array->y, leftClip, n - leftClip); - SHIFT_ARRAY(span->array->z, leftClip, n - leftClip); - SHIFT_ARRAY(span->array->index, leftClip, n - leftClip); - for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { - SHIFT_ARRAY(span->array->lambda[i], leftClip, n - leftClip); - } - SHIFT_ARRAY(span->array->coverage, leftClip, n - leftClip); - -#undef SHIFT_ARRAY - - span->leftClip = leftClip; - span->x = xmin; - span->end -= leftClip; - span->writeAll = GL_FALSE; - } - - ASSERT(span->x >= xmin); - ASSERT(span->x + span->end <= xmax); - ASSERT(span->y >= ymin); - ASSERT(span->y < ymax); - - return GL_TRUE; /* some pixels visible */ - } -} - - -/** - * Add specular colors to primary colors. - * Only called during fixed-function operation. - * Result is float color array (FRAG_ATTRIB_COL0). - */ -static INLINE void -add_specular(struct gl_context *ctx, SWspan *span) -{ - const SWcontext *swrast = SWRAST_CONTEXT(ctx); - const GLubyte *mask = span->array->mask; - GLfloat (*col0)[4] = span->array->attribs[FRAG_ATTRIB_COL0]; - GLfloat (*col1)[4] = span->array->attribs[FRAG_ATTRIB_COL1]; - GLuint i; - - ASSERT(!ctx->FragmentProgram._Current); - ASSERT(span->arrayMask & SPAN_RGBA); - ASSERT(swrast->_ActiveAttribMask & FRAG_BIT_COL1); - (void) swrast; /* silence warning */ - - if (span->array->ChanType == GL_FLOAT) { - if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) { - interpolate_active_attribs(ctx, span, FRAG_BIT_COL0); - } - } - else { - /* need float colors */ - if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) { - interpolate_float_colors(span); - } - } - - if ((span->arrayAttribs & FRAG_BIT_COL1) == 0) { - /* XXX could avoid this and interpolate COL1 in the loop below */ - interpolate_active_attribs(ctx, span, FRAG_BIT_COL1); - } - - ASSERT(span->arrayAttribs & FRAG_BIT_COL0); - ASSERT(span->arrayAttribs & FRAG_BIT_COL1); - - for (i = 0; i < span->end; i++) { - if (mask[i]) { - col0[i][0] += col1[i][0]; - col0[i][1] += col1[i][1]; - col0[i][2] += col1[i][2]; - } - } - - span->array->ChanType = GL_FLOAT; -} - - -/** - * Apply antialiasing coverage value to alpha values. - */ -static INLINE void -apply_aa_coverage(SWspan *span) -{ - const GLfloat *coverage = span->array->coverage; - GLuint i; - if (span->array->ChanType == GL_UNSIGNED_BYTE) { - GLubyte (*rgba)[4] = span->array->rgba8; - for (i = 0; i < span->end; i++) { - const GLfloat a = rgba[i][ACOMP] * coverage[i]; - rgba[i][ACOMP] = (GLubyte) CLAMP(a, 0.0, 255.0); - ASSERT(coverage[i] >= 0.0); - ASSERT(coverage[i] <= 1.0); - } - } - else if (span->array->ChanType == GL_UNSIGNED_SHORT) { - GLushort (*rgba)[4] = span->array->rgba16; - for (i = 0; i < span->end; i++) { - const GLfloat a = rgba[i][ACOMP] * coverage[i]; - rgba[i][ACOMP] = (GLushort) CLAMP(a, 0.0, 65535.0); - } - } - else { - GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0]; - for (i = 0; i < span->end; i++) { - rgba[i][ACOMP] = rgba[i][ACOMP] * coverage[i]; - /* clamp later */ - } - } -} - - -/** - * Clamp span's float colors to [0,1] - */ -static INLINE void -clamp_colors(SWspan *span) -{ - GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0]; - GLuint i; - ASSERT(span->array->ChanType == GL_FLOAT); - for (i = 0; i < span->end; i++) { - rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F); - rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F); - rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F); - rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F); - } -} - - -/** - * Convert the span's color arrays to the given type. - * The only way 'output' can be greater than zero is when we have a fragment - * program that writes to gl_FragData[1] or higher. - * \param output which fragment program color output is being processed - */ -static INLINE void -convert_color_type(SWspan *span, GLenum newType, GLuint output) -{ - GLvoid *src, *dst; - - if (output > 0 || span->array->ChanType == GL_FLOAT) { - src = span->array->attribs[FRAG_ATTRIB_COL0 + output]; - span->array->ChanType = GL_FLOAT; - } - else if (span->array->ChanType == GL_UNSIGNED_BYTE) { - src = span->array->rgba8; - } - else { - ASSERT(span->array->ChanType == GL_UNSIGNED_SHORT); - src = span->array->rgba16; - } - - if (newType == GL_UNSIGNED_BYTE) { - dst = span->array->rgba8; - } - else if (newType == GL_UNSIGNED_SHORT) { - dst = span->array->rgba16; - } - else { - dst = span->array->attribs[FRAG_ATTRIB_COL0]; - } - - _mesa_convert_colors(span->array->ChanType, src, - newType, dst, - span->end, span->array->mask); - - span->array->ChanType = newType; - span->array->rgba = dst; -} - - - -/** - * Apply fragment shader, fragment program or normal texturing to span. - */ -static INLINE void -shade_texture_span(struct gl_context *ctx, SWspan *span) -{ - GLbitfield inputsRead; - - /* Determine which fragment attributes are actually needed */ - if (ctx->FragmentProgram._Current) { - inputsRead = ctx->FragmentProgram._Current->Base.InputsRead; - } - else { - /* XXX we could be a bit smarter about this */ - inputsRead = ~0; - } - - if (ctx->FragmentProgram._Current || - ctx->ATIFragmentShader._Enabled) { - /* programmable shading */ - if (span->primitive == GL_BITMAP && span->array->ChanType != GL_FLOAT) { - convert_color_type(span, GL_FLOAT, 0); - } - else { - span->array->rgba = (void *) span->array->attribs[FRAG_ATTRIB_COL0]; - } - - if (span->primitive != GL_POINT || - (span->interpMask & SPAN_RGBA) || - ctx->Point.PointSprite) { - /* for single-pixel points, we populated the arrays already */ - interpolate_active_attribs(ctx, span, ~0); - } - span->array->ChanType = GL_FLOAT; - - if (!(span->arrayMask & SPAN_Z)) - _swrast_span_interpolate_z (ctx, span); - -#if 0 - if (inputsRead & FRAG_BIT_WPOS) -#else - /* XXX always interpolate wpos so that DDX/DDY work */ -#endif - interpolate_wpos(ctx, span); - - /* Run fragment program/shader now */ - if (ctx->FragmentProgram._Current) { - _swrast_exec_fragment_program(ctx, span); - } - else { - ASSERT(ctx->ATIFragmentShader._Enabled); - _swrast_exec_fragment_shader(ctx, span); - } - } - else if (ctx->Texture._EnabledCoordUnits) { - /* conventional texturing */ - -#if CHAN_BITS == 32 - if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) { - interpolate_int_colors(ctx, span); - } -#else - if (!(span->arrayMask & SPAN_RGBA)) - interpolate_int_colors(ctx, span); -#endif - if ((span->arrayAttribs & FRAG_BITS_TEX_ANY) == 0x0) - interpolate_texcoords(ctx, span); - - _swrast_texture_span(ctx, span); - } -} - - - -/** - * Apply all the per-fragment operations to a span. - * This now includes texturing (_swrast_write_texture_span() is history). - * This function may modify any of the array values in the span. - * span->interpMask and span->arrayMask may be changed but will be restored - * to their original values before returning. - */ -void -_swrast_write_rgba_span( struct gl_context *ctx, SWspan *span) -{ - const SWcontext *swrast = SWRAST_CONTEXT(ctx); - const GLuint *colorMask = (GLuint *) ctx->Color.ColorMask; - const GLbitfield origInterpMask = span->interpMask; - const GLbitfield origArrayMask = span->arrayMask; - const GLbitfield origArrayAttribs = span->arrayAttribs; - const GLenum origChanType = span->array->ChanType; - void * const origRgba = span->array->rgba; - const GLboolean shader = (ctx->FragmentProgram._Current - || ctx->ATIFragmentShader._Enabled); - const GLboolean shaderOrTexture = shader || ctx->Texture._EnabledCoordUnits; - struct gl_framebuffer *fb = ctx->DrawBuffer; - - /* - printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__, - span->interpMask, span->arrayMask); - */ - - ASSERT(span->primitive == GL_POINT || - span->primitive == GL_LINE || - span->primitive == GL_POLYGON || - span->primitive == GL_BITMAP); - - /* Fragment write masks */ - 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; - } - - /* Clip to window/scissor box */ - if (!clip_span(ctx, span)) { - return; - } - - ASSERT(span->end <= MAX_WIDTH); - - /* Depth bounds test */ - if (ctx->Depth.BoundsTest && fb->Visual.depthBits > 0) { - if (!_swrast_depth_bounds_test(ctx, span)) { - return; - } - } - -#ifdef DEBUG - /* Make sure all fragments are within window bounds */ - if (span->arrayMask & SPAN_XY) { - /* array of pixel locations */ - GLuint i; - for (i = 0; i < span->end; i++) { - if (span->array->mask[i]) { - assert(span->array->x[i] >= fb->_Xmin); - assert(span->array->x[i] < fb->_Xmax); - assert(span->array->y[i] >= fb->_Ymin); - assert(span->array->y[i] < fb->_Ymax); - } - } - } -#endif - - /* Polygon Stippling */ - if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) { - stipple_polygon_span(ctx, span); - } - - /* This is the normal place to compute the fragment color/Z - * from texturing or shading. - */ - if (shaderOrTexture && !swrast->_DeferredTexture) { - shade_texture_span(ctx, span); - } - - /* Do the alpha test */ - if (ctx->Color.AlphaEnabled) { - if (!_swrast_alpha_test(ctx, span)) { - /* all fragments failed test */ - goto end; - } - } - - /* Stencil and Z testing */ - if (ctx->Stencil._Enabled || ctx->Depth.Test) { - if (!(span->arrayMask & SPAN_Z)) - _swrast_span_interpolate_z(ctx, span); - - if (ctx->Transform.DepthClamp) - _swrast_depth_clamp_span(ctx, span); - - if (ctx->Stencil._Enabled) { - /* Combined Z/stencil tests */ - if (!_swrast_stencil_and_ztest_span(ctx, span)) { - /* all fragments failed test */ - goto end; - } - } - else if (fb->Visual.depthBits > 0) { - /* Just regular depth testing */ - ASSERT(ctx->Depth.Test); - ASSERT(span->arrayMask & SPAN_Z); - if (!_swrast_depth_test_span(ctx, span)) { - /* all fragments failed test */ - goto end; - } - } - } - - if (ctx->Query.CurrentOcclusionObject) { - /* update count of 'passed' fragments */ - struct gl_query_object *q = ctx->Query.CurrentOcclusionObject; - GLuint i; - for (i = 0; i < span->end; i++) - q->Result += span->array->mask[i]; - } - - /* We had to wait until now to check for glColorMask(0,0,0,0) because of - * the occlusion test. - */ - if (fb->_NumColorDrawBuffers == 1 && colorMask[0] == 0x0) { - /* no colors to write */ - goto end; - } - - /* If we were able to defer fragment color computation to now, there's - * a good chance that many fragments will have already been killed by - * Z/stencil testing. - */ - if (shaderOrTexture && swrast->_DeferredTexture) { - shade_texture_span(ctx, span); - } - -#if CHAN_BITS == 32 - if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) { - interpolate_active_attribs(ctx, span, FRAG_BIT_COL0); - } -#else - if ((span->arrayMask & SPAN_RGBA) == 0) { - interpolate_int_colors(ctx, span); - } -#endif - - ASSERT(span->arrayMask & SPAN_RGBA); - - if (span->primitive == GL_BITMAP || !swrast->SpecularVertexAdd) { - /* Add primary and specular (diffuse + specular) colors */ - if (!shader) { - if (ctx->Fog.ColorSumEnabled || - (ctx->Light.Enabled && - ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) { - add_specular(ctx, span); - } - } - } - - /* Fog */ - if (swrast->_FogEnabled) { - _swrast_fog_rgba_span(ctx, span); - } - - /* Antialias coverage application */ - if (span->arrayMask & SPAN_COVERAGE) { - apply_aa_coverage(span); - } - - /* Clamp color/alpha values over the range [0.0, 1.0] before storage */ - if (ctx->Color.ClampFragmentColor == GL_TRUE && - span->array->ChanType == GL_FLOAT) { - clamp_colors(span); - } - - /* - * Write to renderbuffers. - * Depending on glDrawBuffer() state and the which color outputs are - * written by the fragment shader, we may either replicate one color to - * all renderbuffers or write a different color to each renderbuffer. - * multiFragOutputs=TRUE for the later case. - */ - { - const GLuint numBuffers = fb->_NumColorDrawBuffers; - const struct gl_fragment_program *fp = ctx->FragmentProgram._Current; - const GLboolean multiFragOutputs = - (fp && fp->Base.OutputsWritten >= (1 << FRAG_RESULT_DATA0)); - GLuint buf; - - for (buf = 0; buf < numBuffers; buf++) { - struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf]; - - /* color[fragOutput] will be written to buffer[buf] */ - - if (rb) { - GLchan rgbaSave[MAX_WIDTH][4]; - const GLuint fragOutput = multiFragOutputs ? buf : 0; - - /* set span->array->rgba to colors for render buffer's datatype */ - if (rb->DataType != span->array->ChanType || fragOutput > 0) { - convert_color_type(span, rb->DataType, fragOutput); - } - else { - if (rb->DataType == GL_UNSIGNED_BYTE) { - span->array->rgba = span->array->rgba8; - } - else if (rb->DataType == GL_UNSIGNED_SHORT) { - span->array->rgba = (void *) span->array->rgba16; - } - else { - span->array->rgba = (void *) - span->array->attribs[FRAG_ATTRIB_COL0]; - } - } - - if (!multiFragOutputs && numBuffers > 1) { - /* save colors for second, third renderbuffer writes */ - memcpy(rgbaSave, span->array->rgba, - 4 * span->end * sizeof(GLchan)); - } - - ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB || - rb->_BaseFormat == GL_ALPHA); - - if (ctx->Color._LogicOpEnabled) { - _swrast_logicop_rgba_span(ctx, rb, span); - } - else if ((ctx->Color.BlendEnabled >> buf) & 1) { - _swrast_blend_span(ctx, rb, span); - } - - if (colorMask[buf] != 0xffffffff) { - _swrast_mask_rgba_span(ctx, rb, span, buf); - } - - if (span->arrayMask & SPAN_XY) { - /* array of pixel coords */ - ASSERT(rb->PutValues); - rb->PutValues(ctx, rb, span->end, - span->array->x, span->array->y, - span->array->rgba, span->array->mask); - } - else { - /* horizontal run of pixels */ - ASSERT(rb->PutRow); - rb->PutRow(ctx, rb, span->end, span->x, span->y, - span->array->rgba, - span->writeAll ? NULL: span->array->mask); - } - - if (!multiFragOutputs && numBuffers > 1) { - /* restore original span values */ - memcpy(span->array->rgba, rgbaSave, - 4 * span->end * sizeof(GLchan)); - } - - } /* if rb */ - } /* for buf */ - } - -end: - /* restore these values before returning */ - span->interpMask = origInterpMask; - span->arrayMask = origArrayMask; - span->arrayAttribs = origArrayAttribs; - span->array->ChanType = origChanType; - span->array->rgba = origRgba; -} - - -/** - * Read RGBA pixels from a renderbuffer. Clipping will be done to prevent - * reading ouside the buffer's boundaries. - * \param dstType datatype for returned colors - * \param rgba the returned colors - */ -void -_swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, GLenum dstType, - GLvoid *rgba) -{ - const GLint bufWidth = (GLint) rb->Width; - const GLint bufHeight = (GLint) rb->Height; - - if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) { - /* completely above, below, or right */ - /* XXX maybe leave rgba values undefined? */ - memset(rgba, 0, 4 * n * sizeof(GLchan)); - } - else { - GLint skip, length; - if (x < 0) { - /* left edge clipping */ - skip = -x; - length = (GLint) n - skip; - if (length < 0) { - /* completely left of window */ - return; - } - if (length > bufWidth) { - length = bufWidth; - } - } - else if ((GLint) (x + n) > bufWidth) { - /* right edge clipping */ - skip = 0; - length = bufWidth - x; - if (length < 0) { - /* completely to right of window */ - return; - } - } - else { - /* no clipping */ - skip = 0; - length = (GLint) n; - } - - ASSERT(rb); - ASSERT(rb->GetRow); - ASSERT(rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RGBA || - rb->_BaseFormat == GL_ALPHA); - - if (rb->DataType == dstType) { - rb->GetRow(ctx, rb, length, x + skip, y, - (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(rb->DataType)); - } - else { - GLuint temp[MAX_WIDTH * 4]; - rb->GetRow(ctx, rb, length, x + skip, y, temp); - _mesa_convert_colors(rb->DataType, temp, - dstType, (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(dstType), - length, NULL); - } - } -} - - -/** - * Wrapper for gl_renderbuffer::GetValues() which does clipping to avoid - * reading values outside the buffer bounds. - * We can use this for reading any format/type of renderbuffer. - * \param valueSize is the size in bytes of each value (pixel) put into the - * values array. - */ -void -_swrast_get_values(struct gl_context *ctx, struct gl_renderbuffer *rb, - GLuint count, const GLint x[], const GLint y[], - void *values, GLuint valueSize) -{ - GLuint i, inCount = 0, inStart = 0; - - for (i = 0; i < count; i++) { - if (x[i] >= 0 && y[i] >= 0 && - x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) { - /* inside */ - if (inCount == 0) - inStart = i; - inCount++; - } - else { - if (inCount > 0) { - /* read [inStart, inStart + inCount) */ - rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart, - (GLubyte *) values + inStart * valueSize); - inCount = 0; - } - } - } - if (inCount > 0) { - /* read last values */ - rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart, - (GLubyte *) values + inStart * valueSize); - } -} - - -/** - * Wrapper for gl_renderbuffer::PutRow() which does clipping. - * \param valueSize size of each value (pixel) in bytes - */ -void -_swrast_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb, - GLuint count, GLint x, GLint y, - const GLvoid *values, GLuint valueSize) -{ - GLint skip = 0; - - if (y < 0 || y >= (GLint) rb->Height) - return; /* above or below */ - - if (x + (GLint) count <= 0 || x >= (GLint) rb->Width) - return; /* entirely left or right */ - - if ((GLint) (x + count) > (GLint) rb->Width) { - /* right clip */ - GLint clip = x + count - rb->Width; - count -= clip; - } - - if (x < 0) { - /* left clip */ - skip = -x; - x = 0; - count -= skip; - } - - rb->PutRow(ctx, rb, count, x, y, - (const GLubyte *) values + skip * valueSize, NULL); -} - - -/** - * Wrapper for gl_renderbuffer::GetRow() which does clipping. - * \param valueSize size of each value (pixel) in bytes - */ -void -_swrast_get_row(struct gl_context *ctx, struct gl_renderbuffer *rb, - GLuint count, GLint x, GLint y, - GLvoid *values, GLuint valueSize) -{ - GLint skip = 0; - - if (y < 0 || y >= (GLint) rb->Height) - return; /* above or below */ - - if (x + (GLint) count <= 0 || x >= (GLint) rb->Width) - return; /* entirely left or right */ - - if (x + count > rb->Width) { - /* right clip */ - GLint clip = x + count - rb->Width; - count -= clip; - } - - if (x < 0) { - /* left clip */ - skip = -x; - x = 0; - count -= skip; - } - - rb->GetRow(ctx, rb, count, x, y, (GLubyte *) values + skip * valueSize); -} - - -/** - * Get RGBA pixels from the given renderbuffer. - * Used by blending, logicop and masking functions. - * \return pointer to the colors we read. - */ -void * -_swrast_get_dest_rgba(struct gl_context *ctx, struct gl_renderbuffer *rb, - SWspan *span) -{ - const GLuint pixelSize = RGBA_PIXEL_SIZE(span->array->ChanType); - void *rbPixels; - - /* Point rbPixels to a temporary space */ - rbPixels = span->array->attribs[FRAG_ATTRIB_MAX - 1]; - - /* Get destination values from renderbuffer */ - if (span->arrayMask & SPAN_XY) { - _swrast_get_values(ctx, rb, span->end, span->array->x, span->array->y, - rbPixels, pixelSize); - } - else { - _swrast_get_row(ctx, rb, span->end, span->x, span->y, - rbPixels, pixelSize); - } - - return rbPixels; -} +/*
+ * Mesa 3-D graphics library
+ * Version: 7.5
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/**
+ * \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 "main/glheader.h"
+#include "main/colormac.h"
+#include "main/macros.h"
+#include "main/imports.h"
+#include "main/image.h"
+
+#include "s_atifragshader.h"
+#include "s_alpha.h"
+#include "s_blend.h"
+#include "s_context.h"
+#include "s_depth.h"
+#include "s_fog.h"
+#include "s_logic.h"
+#include "s_masking.h"
+#include "s_fragprog.h"
+#include "s_span.h"
+#include "s_stencil.h"
+#include "s_texcombine.h"
+
+
+/**
+ * Set default fragment attributes for the span using the
+ * current raster values. Used prior to glDraw/CopyPixels
+ * and glBitmap.
+ */
+void
+_swrast_span_default_attribs(struct gl_context *ctx, SWspan *span)
+{
+ GLchan r, g, b, a;
+ /* Z*/
+ {
+ const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
+ if (ctx->DrawBuffer->Visual.depthBits <= 16)
+ span->z = FloatToFixed(ctx->Current.RasterPos[2] * depthMax + 0.5F);
+ else {
+ GLfloat tmpf = ctx->Current.RasterPos[2] * depthMax;
+ tmpf = MIN2(tmpf, depthMax);
+ span->z = (GLint)tmpf;
+ }
+ span->zStep = 0;
+ span->interpMask |= SPAN_Z;
+ }
+
+ /* W (for perspective correction) */
+ span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0;
+ span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0;
+ span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0;
+
+ /* primary color, or color index */
+ 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;
+
+ COPY_4V(span->attrStart[FRAG_ATTRIB_COL0], ctx->Current.RasterColor);
+ ASSIGN_4V(span->attrStepX[FRAG_ATTRIB_COL0], 0.0, 0.0, 0.0, 0.0);
+ ASSIGN_4V(span->attrStepY[FRAG_ATTRIB_COL0], 0.0, 0.0, 0.0, 0.0);
+
+ /* Secondary color */
+ if (ctx->Light.Enabled || ctx->Fog.ColorSumEnabled)
+ {
+ COPY_4V(span->attrStart[FRAG_ATTRIB_COL1], ctx->Current.RasterSecondaryColor);
+ ASSIGN_4V(span->attrStepX[FRAG_ATTRIB_COL1], 0.0, 0.0, 0.0, 0.0);
+ ASSIGN_4V(span->attrStepY[FRAG_ATTRIB_COL1], 0.0, 0.0, 0.0, 0.0);
+ }
+
+ /* fog */
+ {
+ const SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ GLfloat fogVal; /* a coord or a blend factor */
+ if (swrast->_PreferPixelFog) {
+ /* fog blend factors will be computed from fog coordinates per pixel */
+ fogVal = ctx->Current.RasterDistance;
+ }
+ else {
+ /* fog blend factor should be computed from fogcoord now */
+ fogVal = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
+ }
+ span->attrStart[FRAG_ATTRIB_FOGC][0] = fogVal;
+ span->attrStepX[FRAG_ATTRIB_FOGC][0] = 0.0;
+ span->attrStepY[FRAG_ATTRIB_FOGC][0] = 0.0;
+ }
+
+ /* texcoords */
+ {
+ GLuint i;
+ for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
+ const GLuint attr = FRAG_ATTRIB_TEX0 + i;
+ const GLfloat *tc = ctx->Current.RasterTexCoords[i];
+ if (ctx->FragmentProgram._Current || ctx->ATIFragmentShader._Enabled) {
+ COPY_4V(span->attrStart[attr], tc);
+ }
+ else if (tc[3] > 0.0F) {
+ /* use (s/q, t/q, r/q, 1) */
+ span->attrStart[attr][0] = tc[0] / tc[3];
+ span->attrStart[attr][1] = tc[1] / tc[3];
+ span->attrStart[attr][2] = tc[2] / tc[3];
+ span->attrStart[attr][3] = 1.0;
+ }
+ else {
+ ASSIGN_4V(span->attrStart[attr], 0.0F, 0.0F, 0.0F, 1.0F);
+ }
+ ASSIGN_4V(span->attrStepX[attr], 0.0F, 0.0F, 0.0F, 0.0F);
+ ASSIGN_4V(span->attrStepY[attr], 0.0F, 0.0F, 0.0F, 0.0F);
+ }
+ }
+}
+
+
+/**
+ * Interpolate the active attributes (and'd with attrMask) to
+ * fill in span->array->attribs[].
+ * Perspective correction will be done. The point/line/triangle function
+ * should have computed attrStart/Step values for FRAG_ATTRIB_WPOS[3]!
+ */
+static INLINE void
+interpolate_active_attribs(struct gl_context *ctx, SWspan *span, GLbitfield attrMask)
+{
+ const SWcontext *swrast = SWRAST_CONTEXT(ctx);
+
+ /*
+ * Don't overwrite existing array values, such as colors that may have
+ * been produced by glDraw/CopyPixels.
+ */
+ attrMask &= ~span->arrayAttribs;
+
+ ATTRIB_LOOP_BEGIN
+ if (attrMask & (1 << attr)) {
+ const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3];
+ GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3];
+ const GLfloat dv0dx = span->attrStepX[attr][0];
+ const GLfloat dv1dx = span->attrStepX[attr][1];
+ const GLfloat dv2dx = span->attrStepX[attr][2];
+ const GLfloat dv3dx = span->attrStepX[attr][3];
+ GLfloat v0 = span->attrStart[attr][0] + span->leftClip * dv0dx;
+ GLfloat v1 = span->attrStart[attr][1] + span->leftClip * dv1dx;
+ GLfloat v2 = span->attrStart[attr][2] + span->leftClip * dv2dx;
+ GLfloat v3 = span->attrStart[attr][3] + span->leftClip * dv3dx;
+ GLuint k;
+ for (k = 0; k < span->end; k++) {
+ const GLfloat invW = 1.0f / w;
+ span->array->attribs[attr][k][0] = v0 * invW;
+ span->array->attribs[attr][k][1] = v1 * invW;
+ span->array->attribs[attr][k][2] = v2 * invW;
+ span->array->attribs[attr][k][3] = v3 * invW;
+ v0 += dv0dx;
+ v1 += dv1dx;
+ v2 += dv2dx;
+ v3 += dv3dx;
+ w += dwdx;
+ }
+ ASSERT((span->arrayAttribs & (1 << attr)) == 0);
+ span->arrayAttribs |= (1 << attr);
+ }
+ ATTRIB_LOOP_END
+}
+
+
+/**
+ * Interpolate primary colors to fill in the span->array->rgba8 (or rgb16)
+ * color array.
+ */
+static INLINE void
+interpolate_int_colors(struct gl_context *ctx, SWspan *span)
+{
+ const GLuint n = span->end;
+ GLuint i;
+
+#if CHAN_BITS != 32
+ ASSERT(!(span->arrayMask & SPAN_RGBA));
+#endif
+
+ switch (span->array->ChanType) {
+#if CHAN_BITS != 32
+ case GL_UNSIGNED_BYTE:
+ {
+ GLubyte (*rgba)[4] = span->array->rgba8;
+ if (span->interpMask & SPAN_FLAT) {
+ GLubyte color[4];
+ color[RCOMP] = FixedToInt(span->red);
+ color[GCOMP] = FixedToInt(span->green);
+ color[BCOMP] = FixedToInt(span->blue);
+ color[ACOMP] = FixedToInt(span->alpha);
+ for (i = 0; i < n; i++) {
+ COPY_4UBV(rgba[i], color);
+ }
+ }
+ else {
+ GLfixed r = span->red;
+ GLfixed g = span->green;
+ GLfixed b = span->blue;
+ GLfixed a = span->alpha;
+ GLint dr = span->redStep;
+ GLint dg = span->greenStep;
+ GLint db = span->blueStep;
+ GLint da = span->alphaStep;
+ 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;
+ }
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ {
+ GLushort (*rgba)[4] = span->array->rgba16;
+ if (span->interpMask & SPAN_FLAT) {
+ GLushort color[4];
+ color[RCOMP] = FixedToInt(span->red);
+ color[GCOMP] = FixedToInt(span->green);
+ color[BCOMP] = FixedToInt(span->blue);
+ color[ACOMP] = FixedToInt(span->alpha);
+ for (i = 0; i < n; i++) {
+ COPY_4V(rgba[i], color);
+ }
+ }
+ else {
+ GLushort (*rgba)[4] = span->array->rgba16;
+ GLfixed r, g, b, a;
+ GLint dr, dg, db, da;
+ r = span->red;
+ g = span->green;
+ b = span->blue;
+ a = span->alpha;
+ dr = span->redStep;
+ dg = span->greenStep;
+ db = span->blueStep;
+ da = span->alphaStep;
+ 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;
+ }
+ }
+ }
+ break;
+#endif
+ case GL_FLOAT:
+ interpolate_active_attribs(ctx, span, FRAG_BIT_COL0);
+ break;
+ default:
+ _mesa_problem(ctx, "bad datatype 0x%x in interpolate_int_colors",
+ span->array->ChanType);
+ }
+ span->arrayMask |= SPAN_RGBA;
+}
+
+
+/**
+ * Populate the FRAG_ATTRIB_COL0 array.
+ */
+static INLINE void
+interpolate_float_colors(SWspan *span)
+{
+ GLfloat (*col0)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
+ const GLuint n = span->end;
+ GLuint i;
+
+ assert(!(span->arrayAttribs & FRAG_BIT_COL0));
+
+ if (span->arrayMask & SPAN_RGBA) {
+ /* convert array of int colors */
+ for (i = 0; i < n; i++) {
+ col0[i][0] = UBYTE_TO_FLOAT(span->array->rgba8[i][0]);
+ col0[i][1] = UBYTE_TO_FLOAT(span->array->rgba8[i][1]);
+ col0[i][2] = UBYTE_TO_FLOAT(span->array->rgba8[i][2]);
+ col0[i][3] = UBYTE_TO_FLOAT(span->array->rgba8[i][3]);
+ }
+ }
+ else {
+ /* interpolate red/green/blue/alpha to get float colors */
+ ASSERT(span->interpMask & SPAN_RGBA);
+ if (span->interpMask & SPAN_FLAT) {
+ GLfloat r = FixedToFloat(span->red);
+ GLfloat g = FixedToFloat(span->green);
+ GLfloat b = FixedToFloat(span->blue);
+ GLfloat a = FixedToFloat(span->alpha);
+ for (i = 0; i < n; i++) {
+ ASSIGN_4V(col0[i], r, g, b, a);
+ }
+ }
+ else {
+ GLfloat r = FixedToFloat(span->red);
+ GLfloat g = FixedToFloat(span->green);
+ GLfloat b = FixedToFloat(span->blue);
+ GLfloat a = FixedToFloat(span->alpha);
+ GLfloat dr = FixedToFloat(span->redStep);
+ GLfloat dg = FixedToFloat(span->greenStep);
+ GLfloat db = FixedToFloat(span->blueStep);
+ GLfloat da = FixedToFloat(span->alphaStep);
+ for (i = 0; i < n; i++) {
+ col0[i][0] = r;
+ col0[i][1] = g;
+ col0[i][2] = b;
+ col0[i][3] = a;
+ r += dr;
+ g += dg;
+ b += db;
+ a += da;
+ }
+ }
+ }
+
+ span->arrayAttribs |= FRAG_BIT_COL0;
+ span->array->ChanType = GL_FLOAT;
+}
+
+
+
+/**
+ * Fill in the span.zArray array from the span->z, zStep values.
+ */
+void
+_swrast_span_interpolate_z( const struct gl_context *ctx, SWspan *span )
+{
+ const GLuint n = span->end;
+ GLuint i;
+
+ ASSERT(!(span->arrayMask & SPAN_Z));
+
+ if (ctx->DrawBuffer->Visual.depthBits <= 16) {
+ GLfixed zval = span->z;
+ GLuint *z = span->array->z;
+ for (i = 0; i < n; i++) {
+ z[i] = FixedToInt(zval);
+ zval += span->zStep;
+ }
+ }
+ else {
+ /* Deep Z buffer, no fixed->int shift */
+ GLuint zval = span->z;
+ GLuint *z = span->array->z;
+ for (i = 0; i < n; i++) {
+ z[i] = zval;
+ zval += span->zStep;
+ }
+ }
+ span->interpMask &= ~SPAN_Z;
+ span->arrayMask |= SPAN_Z;
+}
+
+
+/**
+ * Compute mipmap LOD from partial derivatives.
+ * This the ideal solution, as given in the OpenGL spec.
+ */
+GLfloat
+_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
+ GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
+ GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
+{
+ GLfloat 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;
+}
+
+
+/**
+ * Compute mipmap LOD from partial derivatives.
+ * This is a faster approximation than above function.
+ */
+#if 0
+GLfloat
+_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
+ GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
+ GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
+{
+ GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
+ GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
+ GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
+ GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
+ GLfloat maxU, maxV, rho, lambda;
+ dsdx2 = FABSF(dsdx2);
+ dsdy2 = FABSF(dsdy2);
+ dtdx2 = FABSF(dtdx2);
+ dtdy2 = FABSF(dtdy2);
+ maxU = MAX2(dsdx2, dsdy2) * texW;
+ maxV = MAX2(dtdx2, dtdy2) * texH;
+ rho = MAX2(maxU, maxV);
+ lambda = LOG2(rho);
+ return lambda;
+}
+#endif
+
+
+/**
+ * Fill in the span.array->attrib[FRAG_ATTRIB_TEXn] arrays from the
+ * using the attrStart/Step values.
+ *
+ * This function only used during fixed-function fragment processing.
+ *
+ * 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).
+ */
+static void
+interpolate_texcoords(struct gl_context *ctx, SWspan *span)
+{
+ const GLuint maxUnit
+ = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
+ GLuint u;
+
+ /* XXX CoordUnits vs. ImageUnits */
+ for (u = 0; u < maxUnit; u++) {
+ if (ctx->Texture._EnabledCoordUnits & (1 << u)) {
+ const GLuint attr = FRAG_ATTRIB_TEX0 + u;
+ const struct gl_texture_object *obj = ctx->Texture.Unit[u]._Current;
+ GLfloat texW, texH;
+ GLboolean needLambda;
+ GLfloat (*texcoord)[4] = span->array->attribs[attr];
+ GLfloat *lambda = span->array->lambda[u];
+ const GLfloat dsdx = span->attrStepX[attr][0];
+ const GLfloat dsdy = span->attrStepY[attr][0];
+ const GLfloat dtdx = span->attrStepX[attr][1];
+ const GLfloat dtdy = span->attrStepY[attr][1];
+ const GLfloat drdx = span->attrStepX[attr][2];
+ const GLfloat dqdx = span->attrStepX[attr][3];
+ const GLfloat dqdy = span->attrStepY[attr][3];
+ GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
+ GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
+ GLfloat r = span->attrStart[attr][2] + span->leftClip * drdx;
+ GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
+
+ if (obj) {
+ const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
+ needLambda = (obj->Sampler.MinFilter != obj->Sampler.MagFilter)
+ || ctx->FragmentProgram._Current;
+ texW = img->WidthScale;
+ texH = img->HeightScale;
+ }
+ else {
+ /* using a fragment program */
+ texW = 1.0;
+ texH = 1.0;
+ needLambda = GL_FALSE;
+ }
+
+ if (needLambda) {
+ GLuint i;
+ if (ctx->FragmentProgram._Current
+ || ctx->ATIFragmentShader._Enabled) {
+ /* do perspective correction but don't divide s, t, r by q */
+ const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3];
+ GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dwdx;
+ for (i = 0; i < span->end; i++) {
+ const GLfloat invW = 1.0F / w;
+ texcoord[i][0] = s * invW;
+ texcoord[i][1] = t * invW;
+ texcoord[i][2] = r * invW;
+ texcoord[i][3] = q * invW;
+ lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
+ dqdx, dqdy, texW, texH,
+ s, t, q, invW);
+ s += dsdx;
+ t += dtdx;
+ r += drdx;
+ q += dqdx;
+ w += dwdx;
+ }
+ }
+ else {
+ for (i = 0; i < span->end; i++) {
+ const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
+ texcoord[i][0] = s * invQ;
+ texcoord[i][1] = t * invQ;
+ texcoord[i][2] = r * invQ;
+ texcoord[i][3] = q;
+ lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
+ dqdx, dqdy, texW, texH,
+ s, t, q, invQ);
+ s += dsdx;
+ t += dtdx;
+ r += drdx;
+ q += dqdx;
+ }
+ }
+ span->arrayMask |= SPAN_LAMBDA;
+ }
+ else {
+ GLuint i;
+ if (ctx->FragmentProgram._Current ||
+ ctx->ATIFragmentShader._Enabled) {
+ /* do perspective correction but don't divide s, t, r by q */
+ const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3];
+ GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dwdx;
+ 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 */
+}
+
+
+/**
+ * Fill in the arrays->attribs[FRAG_ATTRIB_WPOS] array.
+ */
+static INLINE void
+interpolate_wpos(struct gl_context *ctx, SWspan *span)
+{
+ GLfloat (*wpos)[4] = span->array->attribs[FRAG_ATTRIB_WPOS];
+ GLuint i;
+ const GLfloat zScale = 1.0F / ctx->DrawBuffer->_DepthMaxF;
+ GLfloat w, dw;
+
+ if (span->arrayMask & SPAN_XY) {
+ for (i = 0; i < span->end; i++) {
+ wpos[i][0] = (GLfloat) span->array->x[i];
+ wpos[i][1] = (GLfloat) span->array->y[i];
+ }
+ }
+ else {
+ for (i = 0; i < span->end; i++) {
+ wpos[i][0] = (GLfloat) span->x + i;
+ wpos[i][1] = (GLfloat) span->y;
+ }
+ }
+
+ dw = span->attrStepX[FRAG_ATTRIB_WPOS][3];
+ w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dw;
+ for (i = 0; i < span->end; i++) {
+ wpos[i][2] = (GLfloat) span->array->z[i] * zScale;
+ wpos[i][3] = w;
+ w += dw;
+ }
+}
+
+
+/**
+ * Apply the current polygon stipple pattern to a span of pixels.
+ */
+static INLINE void
+stipple_polygon_span(struct gl_context *ctx, SWspan *span)
+{
+ GLubyte *mask = span->array->mask;
+
+ ASSERT(ctx->Polygon.StippleFlag);
+
+ if (span->arrayMask & SPAN_XY) {
+ /* arrays of x/y pixel coords */
+ GLuint i;
+ for (i = 0; i < span->end; i++) {
+ const GLint col = span->array->x[i] % 32;
+ const GLint row = span->array->y[i] % 32;
+ const GLuint stipple = ctx->PolygonStipple[row];
+ if (((1 << col) & stipple) == 0) {
+ mask[i] = 0;
+ }
+ }
+ }
+ else {
+ /* horizontal span of pixels */
+ const GLuint highBit = 1 << 31;
+ const GLuint stipple = ctx->PolygonStipple[span->y % 32];
+ GLuint i, 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 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 INLINE GLuint
+clip_span( struct gl_context *ctx, SWspan *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;
+
+ span->leftClip = 0;
+
+ if (span->arrayMask & SPAN_XY) {
+ /* arrays of x/y pixel coords */
+ const GLint *x = span->array->x;
+ const GLint *y = span->array->y;
+ const GLint n = span->end;
+ GLubyte *mask = span->array->mask;
+ GLint i;
+ if (span->arrayMask & SPAN_MASK) {
+ /* note: using & intead of && to reduce branches */
+ for (i = 0; i < n; i++) {
+ mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
+ & (y[i] >= ymin) & (y[i] < ymax);
+ }
+ }
+ else {
+ /* note: using & intead of && to reduce branches */
+ for (i = 0; i < n; i++) {
+ mask[i] = (x[i] >= xmin) & (x[i] < xmax)
+ & (y[i] >= ymin) & (y[i] < ymax);
+ }
+ }
+ return GL_TRUE; /* some pixels visible */
+ }
+ else {
+ /* horizontal span of pixels */
+ const GLint x = span->x;
+ const GLint y = span->y;
+ 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 right */
+ if (x + n > xmax) {
+ ASSERT(x < xmax);
+ n = span->end = xmax - x;
+ }
+
+ /* Clip to the left */
+ if (x < xmin) {
+ const GLint leftClip = xmin - x;
+ GLuint i;
+
+ ASSERT(leftClip > 0);
+ ASSERT(x + n > xmin);
+
+ /* Clip 'leftClip' pixels from the left side.
+ * The span->leftClip field will be applied when we interpolate
+ * fragment attributes.
+ * For arrays of values, shift them left.
+ */
+ for (i = 0; i < FRAG_ATTRIB_MAX; i++) {
+ if (span->interpMask & (1 << i)) {
+ GLuint j;
+ for (j = 0; j < 4; j++) {
+ span->attrStart[i][j] += leftClip * span->attrStepX[i][j];
+ }
+ }
+ }
+
+ span->red += leftClip * span->redStep;
+ span->green += leftClip * span->greenStep;
+ span->blue += leftClip * span->blueStep;
+ span->alpha += leftClip * span->alphaStep;
+ span->index += leftClip * span->indexStep;
+ span->z += leftClip * span->zStep;
+ span->intTex[0] += leftClip * span->intTexStep[0];
+ span->intTex[1] += leftClip * span->intTexStep[1];
+
+#define SHIFT_ARRAY(ARRAY, SHIFT, LEN) \
+ memcpy(ARRAY, ARRAY + (SHIFT), (LEN) * sizeof(ARRAY[0]))
+
+ for (i = 0; i < FRAG_ATTRIB_MAX; i++) {
+ if (span->arrayAttribs & (1 << i)) {
+ /* shift array elements left by 'leftClip' */
+ SHIFT_ARRAY(span->array->attribs[i], leftClip, n - leftClip);
+ }
+ }
+
+ SHIFT_ARRAY(span->array->mask, leftClip, n - leftClip);
+ SHIFT_ARRAY(span->array->rgba8, leftClip, n - leftClip);
+ SHIFT_ARRAY(span->array->rgba16, leftClip, n - leftClip);
+ SHIFT_ARRAY(span->array->x, leftClip, n - leftClip);
+ SHIFT_ARRAY(span->array->y, leftClip, n - leftClip);
+ SHIFT_ARRAY(span->array->z, leftClip, n - leftClip);
+ SHIFT_ARRAY(span->array->index, leftClip, n - leftClip);
+ for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
+ SHIFT_ARRAY(span->array->lambda[i], leftClip, n - leftClip);
+ }
+ SHIFT_ARRAY(span->array->coverage, leftClip, n - leftClip);
+
+#undef SHIFT_ARRAY
+
+ span->leftClip = leftClip;
+ span->x = xmin;
+ span->end -= leftClip;
+ span->writeAll = GL_FALSE;
+ }
+
+ ASSERT(span->x >= xmin);
+ ASSERT(span->x + span->end <= xmax);
+ ASSERT(span->y >= ymin);
+ ASSERT(span->y < ymax);
+
+ return GL_TRUE; /* some pixels visible */
+ }
+}
+
+
+/**
+ * Add specular colors to primary colors.
+ * Only called during fixed-function operation.
+ * Result is float color array (FRAG_ATTRIB_COL0).
+ */
+static INLINE void
+add_specular(struct gl_context *ctx, SWspan *span)
+{
+ const SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ const GLubyte *mask = span->array->mask;
+ GLfloat (*col0)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
+ GLfloat (*col1)[4] = span->array->attribs[FRAG_ATTRIB_COL1];
+ GLuint i;
+
+ ASSERT(!ctx->FragmentProgram._Current);
+ ASSERT(span->arrayMask & SPAN_RGBA);
+ ASSERT(swrast->_ActiveAttribMask & FRAG_BIT_COL1);
+ (void) swrast; /* silence warning */
+
+ if (span->array->ChanType == GL_FLOAT) {
+ if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
+ interpolate_active_attribs(ctx, span, FRAG_BIT_COL0);
+ }
+ }
+ else {
+ /* need float colors */
+ if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
+ interpolate_float_colors(span);
+ }
+ }
+
+ if ((span->arrayAttribs & FRAG_BIT_COL1) == 0) {
+ /* XXX could avoid this and interpolate COL1 in the loop below */
+ interpolate_active_attribs(ctx, span, FRAG_BIT_COL1);
+ }
+
+ ASSERT(span->arrayAttribs & FRAG_BIT_COL0);
+ ASSERT(span->arrayAttribs & FRAG_BIT_COL1);
+
+ for (i = 0; i < span->end; i++) {
+ if (mask[i]) {
+ col0[i][0] += col1[i][0];
+ col0[i][1] += col1[i][1];
+ col0[i][2] += col1[i][2];
+ }
+ }
+
+ span->array->ChanType = GL_FLOAT;
+}
+
+
+/**
+ * Apply antialiasing coverage value to alpha values.
+ */
+static INLINE void
+apply_aa_coverage(SWspan *span)
+{
+ const GLfloat *coverage = span->array->coverage;
+ GLuint i;
+ if (span->array->ChanType == GL_UNSIGNED_BYTE) {
+ GLubyte (*rgba)[4] = span->array->rgba8;
+ for (i = 0; i < span->end; i++) {
+ const GLfloat a = rgba[i][ACOMP] * coverage[i];
+ rgba[i][ACOMP] = (GLubyte) CLAMP(a, 0.0, 255.0);
+ ASSERT(coverage[i] >= 0.0);
+ ASSERT(coverage[i] <= 1.0);
+ }
+ }
+ else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
+ GLushort (*rgba)[4] = span->array->rgba16;
+ for (i = 0; i < span->end; i++) {
+ const GLfloat a = rgba[i][ACOMP] * coverage[i];
+ rgba[i][ACOMP] = (GLushort) CLAMP(a, 0.0, 65535.0);
+ }
+ }
+ else {
+ GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
+ for (i = 0; i < span->end; i++) {
+ rgba[i][ACOMP] = rgba[i][ACOMP] * coverage[i];
+ /* clamp later */
+ }
+ }
+}
+
+
+/**
+ * Clamp span's float colors to [0,1]
+ */
+static INLINE void
+clamp_colors(SWspan *span)
+{
+ GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
+ GLuint i;
+ ASSERT(span->array->ChanType == GL_FLOAT);
+ for (i = 0; i < span->end; i++) {
+ rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F);
+ rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F);
+ rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F);
+ rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F);
+ }
+}
+
+
+/**
+ * Convert the span's color arrays to the given type.
+ * The only way 'output' can be greater than zero is when we have a fragment
+ * program that writes to gl_FragData[1] or higher.
+ * \param output which fragment program color output is being processed
+ */
+static INLINE void
+convert_color_type(SWspan *span, GLenum newType, GLuint output)
+{
+ GLvoid *src, *dst;
+
+ if (output > 0 || span->array->ChanType == GL_FLOAT) {
+ src = span->array->attribs[FRAG_ATTRIB_COL0 + output];
+ span->array->ChanType = GL_FLOAT;
+ }
+ else if (span->array->ChanType == GL_UNSIGNED_BYTE) {
+ src = span->array->rgba8;
+ }
+ else {
+ ASSERT(span->array->ChanType == GL_UNSIGNED_SHORT);
+ src = span->array->rgba16;
+ }
+
+ if (newType == GL_UNSIGNED_BYTE) {
+ dst = span->array->rgba8;
+ }
+ else if (newType == GL_UNSIGNED_SHORT) {
+ dst = span->array->rgba16;
+ }
+ else {
+ dst = span->array->attribs[FRAG_ATTRIB_COL0];
+ }
+
+ _mesa_convert_colors(span->array->ChanType, src,
+ newType, dst,
+ span->end, span->array->mask);
+
+ span->array->ChanType = newType;
+ span->array->rgba = dst;
+}
+
+
+
+/**
+ * Apply fragment shader, fragment program or normal texturing to span.
+ */
+static INLINE void
+shade_texture_span(struct gl_context *ctx, SWspan *span)
+{
+ GLbitfield inputsRead;
+
+ /* Determine which fragment attributes are actually needed */
+ if (ctx->FragmentProgram._Current) {
+ inputsRead = ctx->FragmentProgram._Current->Base.InputsRead;
+ }
+ else {
+ /* XXX we could be a bit smarter about this */
+ inputsRead = ~0;
+ }
+
+ if (ctx->FragmentProgram._Current ||
+ ctx->ATIFragmentShader._Enabled) {
+ /* programmable shading */
+ if (span->primitive == GL_BITMAP && span->array->ChanType != GL_FLOAT) {
+ convert_color_type(span, GL_FLOAT, 0);
+ }
+ else {
+ span->array->rgba = (void *) span->array->attribs[FRAG_ATTRIB_COL0];
+ }
+
+ if (span->primitive != GL_POINT ||
+ (span->interpMask & SPAN_RGBA) ||
+ ctx->Point.PointSprite) {
+ /* for single-pixel points, we populated the arrays already */
+ interpolate_active_attribs(ctx, span, ~0);
+ }
+ span->array->ChanType = GL_FLOAT;
+
+ if (!(span->arrayMask & SPAN_Z))
+ _swrast_span_interpolate_z (ctx, span);
+
+#if 0
+ if (inputsRead & FRAG_BIT_WPOS)
+#else
+ /* XXX always interpolate wpos so that DDX/DDY work */
+#endif
+ interpolate_wpos(ctx, span);
+
+ /* Run fragment program/shader now */
+ if (ctx->FragmentProgram._Current) {
+ _swrast_exec_fragment_program(ctx, span);
+ }
+ else {
+ ASSERT(ctx->ATIFragmentShader._Enabled);
+ _swrast_exec_fragment_shader(ctx, span);
+ }
+ }
+ else if (ctx->Texture._EnabledCoordUnits) {
+ /* conventional texturing */
+
+#if CHAN_BITS == 32
+ if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
+ interpolate_int_colors(ctx, span);
+ }
+#else
+ if (!(span->arrayMask & SPAN_RGBA))
+ interpolate_int_colors(ctx, span);
+#endif
+ if ((span->arrayAttribs & FRAG_BITS_TEX_ANY) == 0x0)
+ interpolate_texcoords(ctx, span);
+
+ _swrast_texture_span(ctx, span);
+ }
+}
+
+
+
+/**
+ * Apply all the per-fragment operations to a span.
+ * This now includes texturing (_swrast_write_texture_span() is history).
+ * This function may modify any of the array values in the span.
+ * span->interpMask and span->arrayMask may be changed but will be restored
+ * to their original values before returning.
+ */
+void
+_swrast_write_rgba_span( struct gl_context *ctx, SWspan *span)
+{
+ const SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ const GLuint *colorMask = (GLuint *) ctx->Color.ColorMask;
+ const GLbitfield origInterpMask = span->interpMask;
+ const GLbitfield origArrayMask = span->arrayMask;
+ const GLbitfield origArrayAttribs = span->arrayAttribs;
+ const GLenum origChanType = span->array->ChanType;
+ void * const origRgba = span->array->rgba;
+ const GLboolean shader = (ctx->FragmentProgram._Current
+ || ctx->ATIFragmentShader._Enabled);
+ const GLboolean shaderOrTexture = shader || ctx->Texture._EnabledCoordUnits;
+ struct gl_framebuffer *fb = ctx->DrawBuffer;
+
+ /*
+ printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__,
+ span->interpMask, span->arrayMask);
+ */
+
+ ASSERT(span->primitive == GL_POINT ||
+ span->primitive == GL_LINE ||
+ span->primitive == GL_POLYGON ||
+ span->primitive == GL_BITMAP);
+
+ /* Fragment write masks */
+ 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;
+ }
+
+ /* Clip to window/scissor box */
+ if (!clip_span(ctx, span)) {
+ return;
+ }
+
+ ASSERT(span->end <= MAX_WIDTH);
+
+ /* Depth bounds test */
+ if (ctx->Depth.BoundsTest && fb->Visual.depthBits > 0) {
+ if (!_swrast_depth_bounds_test(ctx, span)) {
+ return;
+ }
+ }
+
+#ifdef DEBUG
+ /* Make sure all fragments are within window bounds */
+ if (span->arrayMask & SPAN_XY) {
+ /* array of pixel locations */
+ GLuint i;
+ for (i = 0; i < span->end; i++) {
+ if (span->array->mask[i]) {
+ assert(span->array->x[i] >= fb->_Xmin);
+ assert(span->array->x[i] < fb->_Xmax);
+ assert(span->array->y[i] >= fb->_Ymin);
+ assert(span->array->y[i] < fb->_Ymax);
+ }
+ }
+ }
+#endif
+
+ /* Polygon Stippling */
+ if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
+ stipple_polygon_span(ctx, span);
+ }
+
+ /* This is the normal place to compute the fragment color/Z
+ * from texturing or shading.
+ */
+ if (shaderOrTexture && !swrast->_DeferredTexture) {
+ shade_texture_span(ctx, span);
+ }
+
+ /* Do the alpha test */
+ if (ctx->Color.AlphaEnabled) {
+ if (!_swrast_alpha_test(ctx, span)) {
+ /* all fragments failed test */
+ goto end;
+ }
+ }
+
+ /* Stencil and Z testing */
+ if (ctx->Stencil._Enabled || ctx->Depth.Test) {
+ if (!(span->arrayMask & SPAN_Z))
+ _swrast_span_interpolate_z(ctx, span);
+
+ if (ctx->Transform.DepthClamp)
+ _swrast_depth_clamp_span(ctx, span);
+
+ if (ctx->Stencil._Enabled) {
+ /* Combined Z/stencil tests */
+ if (!_swrast_stencil_and_ztest_span(ctx, span)) {
+ /* all fragments failed test */
+ goto end;
+ }
+ }
+ else if (fb->Visual.depthBits > 0) {
+ /* Just regular depth testing */
+ ASSERT(ctx->Depth.Test);
+ ASSERT(span->arrayMask & SPAN_Z);
+ if (!_swrast_depth_test_span(ctx, span)) {
+ /* all fragments failed test */
+ goto end;
+ }
+ }
+ }
+
+ if (ctx->Query.CurrentOcclusionObject) {
+ /* update count of 'passed' fragments */
+ struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;
+ GLuint i;
+ for (i = 0; i < span->end; i++)
+ q->Result += span->array->mask[i];
+ }
+
+ /* We had to wait until now to check for glColorMask(0,0,0,0) because of
+ * the occlusion test.
+ */
+ if (fb->_NumColorDrawBuffers == 1 && colorMask[0] == 0x0) {
+ /* no colors to write */
+ goto end;
+ }
+
+ /* If we were able to defer fragment color computation to now, there's
+ * a good chance that many fragments will have already been killed by
+ * Z/stencil testing.
+ */
+ if (shaderOrTexture && swrast->_DeferredTexture) {
+ shade_texture_span(ctx, span);
+ }
+
+#if CHAN_BITS == 32
+ if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
+ interpolate_active_attribs(ctx, span, FRAG_BIT_COL0);
+ }
+#else
+ if ((span->arrayMask & SPAN_RGBA) == 0) {
+ interpolate_int_colors(ctx, span);
+ }
+#endif
+
+ ASSERT(span->arrayMask & SPAN_RGBA);
+
+ if (span->primitive == GL_BITMAP || !swrast->SpecularVertexAdd) {
+ /* Add primary and specular (diffuse + specular) colors */
+ if (!shader) {
+ if (ctx->Fog.ColorSumEnabled ||
+ (ctx->Light.Enabled &&
+ ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
+ add_specular(ctx, span);
+ }
+ }
+ }
+
+ /* Fog */
+ if (swrast->_FogEnabled) {
+ _swrast_fog_rgba_span(ctx, span);
+ }
+
+ /* Antialias coverage application */
+ if (span->arrayMask & SPAN_COVERAGE) {
+ apply_aa_coverage(span);
+ }
+
+ /* Clamp color/alpha values over the range [0.0, 1.0] before storage */
+ if (ctx->Color.ClampFragmentColor == GL_TRUE &&
+ span->array->ChanType == GL_FLOAT) {
+ clamp_colors(span);
+ }
+
+ /*
+ * Write to renderbuffers.
+ * Depending on glDrawBuffer() state and the which color outputs are
+ * written by the fragment shader, we may either replicate one color to
+ * all renderbuffers or write a different color to each renderbuffer.
+ * multiFragOutputs=TRUE for the later case.
+ */
+ {
+ const GLuint numBuffers = fb->_NumColorDrawBuffers;
+ const struct gl_fragment_program *fp = ctx->FragmentProgram._Current;
+ const GLboolean multiFragOutputs =
+ (fp && fp->Base.OutputsWritten >= (1 << FRAG_RESULT_DATA0));
+ GLuint buf;
+
+ for (buf = 0; buf < numBuffers; buf++) {
+ struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf];
+
+ /* color[fragOutput] will be written to buffer[buf] */
+
+ if (rb) {
+ GLchan rgbaSave[MAX_WIDTH][4];
+ const GLuint fragOutput = multiFragOutputs ? buf : 0;
+
+ /* set span->array->rgba to colors for render buffer's datatype */
+ if (rb->DataType != span->array->ChanType || fragOutput > 0) {
+ convert_color_type(span, rb->DataType, fragOutput);
+ }
+ else {
+ if (rb->DataType == GL_UNSIGNED_BYTE) {
+ span->array->rgba = span->array->rgba8;
+ }
+ else if (rb->DataType == GL_UNSIGNED_SHORT) {
+ span->array->rgba = (void *) span->array->rgba16;
+ }
+ else {
+ span->array->rgba = (void *)
+ span->array->attribs[FRAG_ATTRIB_COL0];
+ }
+ }
+
+ if (!multiFragOutputs && numBuffers > 1) {
+ /* save colors for second, third renderbuffer writes */
+ memcpy(rgbaSave, span->array->rgba,
+ 4 * span->end * sizeof(GLchan));
+ }
+
+ ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB ||
+ rb->_BaseFormat == GL_ALPHA);
+
+ if (ctx->Color._LogicOpEnabled) {
+ _swrast_logicop_rgba_span(ctx, rb, span);
+ }
+ else if ((ctx->Color.BlendEnabled >> buf) & 1) {
+ _swrast_blend_span(ctx, rb, span);
+ }
+
+ if (colorMask[buf] != 0xffffffff) {
+ _swrast_mask_rgba_span(ctx, rb, span, buf);
+ }
+
+ if (span->arrayMask & SPAN_XY) {
+ /* array of pixel coords */
+ ASSERT(rb->PutValues);
+ rb->PutValues(ctx, rb, span->end,
+ span->array->x, span->array->y,
+ span->array->rgba, span->array->mask);
+ }
+ else {
+ /* horizontal run of pixels */
+ ASSERT(rb->PutRow);
+ rb->PutRow(ctx, rb, span->end, span->x, span->y,
+ span->array->rgba,
+ span->writeAll ? NULL: span->array->mask);
+ }
+
+ if (!multiFragOutputs && numBuffers > 1) {
+ /* restore original span values */
+ memcpy(span->array->rgba, rgbaSave,
+ 4 * span->end * sizeof(GLchan));
+ }
+
+ } /* if rb */
+ } /* for buf */
+ }
+
+end:
+ /* restore these values before returning */
+ span->interpMask = origInterpMask;
+ span->arrayMask = origArrayMask;
+ span->arrayAttribs = origArrayAttribs;
+ span->array->ChanType = origChanType;
+ span->array->rgba = origRgba;
+}
+
+
+/**
+ * Read RGBA pixels from a renderbuffer. Clipping will be done to prevent
+ * reading ouside the buffer's boundaries.
+ * \param dstType datatype for returned colors
+ * \param rgba the returned colors
+ */
+void
+_swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y, GLenum dstType,
+ GLvoid *rgba)
+{
+ const GLint bufWidth = (GLint) rb->Width;
+ const GLint bufHeight = (GLint) rb->Height;
+
+ if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
+ /* completely above, below, or right */
+ /* XXX maybe leave rgba values undefined? */
+ memset(rgba, 0, 4 * n * sizeof(GLchan));
+ }
+ else {
+ GLint skip, length;
+ if (x < 0) {
+ /* left edge clipping */
+ skip = -x;
+ length = (GLint) n - skip;
+ if (length < 0) {
+ /* completely left of window */
+ return;
+ }
+ if (length > bufWidth) {
+ length = bufWidth;
+ }
+ }
+ else if ((GLint) (x + n) > bufWidth) {
+ /* right edge clipping */
+ skip = 0;
+ length = bufWidth - x;
+ if (length < 0) {
+ /* completely to right of window */
+ return;
+ }
+ }
+ else {
+ /* no clipping */
+ skip = 0;
+ length = (GLint) n;
+ }
+
+ ASSERT(rb);
+ ASSERT(rb->GetRow);
+ ASSERT(rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RGBA ||
+ rb->_BaseFormat == GL_ALPHA);
+
+ if (rb->DataType == dstType) {
+ rb->GetRow(ctx, rb, length, x + skip, y,
+ (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(rb->DataType));
+ }
+ else {
+ GLuint temp[MAX_WIDTH * 4];
+ rb->GetRow(ctx, rb, length, x + skip, y, temp);
+ _mesa_convert_colors(rb->DataType, temp,
+ dstType, (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(dstType),
+ length, NULL);
+ }
+ }
+}
+
+
+/**
+ * Wrapper for gl_renderbuffer::GetValues() which does clipping to avoid
+ * reading values outside the buffer bounds.
+ * We can use this for reading any format/type of renderbuffer.
+ * \param valueSize is the size in bytes of each value (pixel) put into the
+ * values array.
+ */
+void
+_swrast_get_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLuint count, const GLint x[], const GLint y[],
+ void *values, GLuint valueSize)
+{
+ GLuint i, inCount = 0, inStart = 0;
+
+ for (i = 0; i < count; i++) {
+ if (x[i] >= 0 && y[i] >= 0 &&
+ x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) {
+ /* inside */
+ if (inCount == 0)
+ inStart = i;
+ inCount++;
+ }
+ else {
+ if (inCount > 0) {
+ /* read [inStart, inStart + inCount) */
+ rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart,
+ (GLubyte *) values + inStart * valueSize);
+ inCount = 0;
+ }
+ }
+ }
+ if (inCount > 0) {
+ /* read last values */
+ rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart,
+ (GLubyte *) values + inStart * valueSize);
+ }
+}
+
+
+/**
+ * Wrapper for gl_renderbuffer::PutRow() which does clipping.
+ * \param valueSize size of each value (pixel) in bytes
+ */
+void
+_swrast_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLuint count, GLint x, GLint y,
+ const GLvoid *values, GLuint valueSize)
+{
+ GLint skip = 0;
+
+ if (y < 0 || y >= (GLint) rb->Height)
+ return; /* above or below */
+
+ if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
+ return; /* entirely left or right */
+
+ if ((GLint) (x + count) > (GLint) rb->Width) {
+ /* right clip */
+ GLint clip = x + count - rb->Width;
+ count -= clip;
+ }
+
+ if (x < 0) {
+ /* left clip */
+ skip = -x;
+ x = 0;
+ count -= skip;
+ }
+
+ rb->PutRow(ctx, rb, count, x, y,
+ (const GLubyte *) values + skip * valueSize, NULL);
+}
+
+
+/**
+ * Wrapper for gl_renderbuffer::GetRow() which does clipping.
+ * \param valueSize size of each value (pixel) in bytes
+ */
+void
+_swrast_get_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLuint count, GLint x, GLint y,
+ GLvoid *values, GLuint valueSize)
+{
+ GLint skip = 0;
+
+ if (y < 0 || y >= (GLint) rb->Height)
+ return; /* above or below */
+
+ if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
+ return; /* entirely left or right */
+
+ if (x + count > rb->Width) {
+ /* right clip */
+ GLint clip = x + count - rb->Width;
+ count -= clip;
+ }
+
+ if (x < 0) {
+ /* left clip */
+ skip = -x;
+ x = 0;
+ count -= skip;
+ }
+
+ rb->GetRow(ctx, rb, count, x, y, (GLubyte *) values + skip * valueSize);
+}
+
+
+/**
+ * Get RGBA pixels from the given renderbuffer.
+ * Used by blending, logicop and masking functions.
+ * \return pointer to the colors we read.
+ */
+void *
+_swrast_get_dest_rgba(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ SWspan *span)
+{
+ const GLuint pixelSize = RGBA_PIXEL_SIZE(span->array->ChanType);
+ void *rbPixels;
+
+ /* Point rbPixels to a temporary space */
+ rbPixels = span->array->attribs[FRAG_ATTRIB_MAX - 1];
+
+ /* Get destination values from renderbuffer */
+ if (span->arrayMask & SPAN_XY) {
+ _swrast_get_values(ctx, rb, span->end, span->array->x, span->array->y,
+ rbPixels, pixelSize);
+ }
+ else {
+ _swrast_get_row(ctx, rb, span->end, span->x, span->y,
+ rbPixels, pixelSize);
+ }
+
+ return rbPixels;
+}
|