diff options
Diffstat (limited to 'mesalib/src/mesa/swrast')
-rw-r--r-- | mesalib/src/mesa/swrast/s_fragprog.c | 554 | ||||
-rw-r--r-- | mesalib/src/mesa/swrast/s_span.c | 3006 | ||||
-rw-r--r-- | mesalib/src/mesa/swrast/s_texcombine.c | 22 | ||||
-rw-r--r-- | mesalib/src/mesa/swrast/s_texfilter.c | 255 | ||||
-rw-r--r-- | mesalib/src/mesa/swrast/s_triangle.c | 2286 |
5 files changed, 3063 insertions, 3060 deletions
diff --git a/mesalib/src/mesa/swrast/s_fragprog.c b/mesalib/src/mesa/swrast/s_fragprog.c index 2608d5373..b6bfeaed4 100644 --- a/mesalib/src/mesa/swrast/s_fragprog.c +++ b/mesalib/src/mesa/swrast/s_fragprog.c @@ -1,277 +1,277 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.0.3
- *
- * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * 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.
- */
-
-#include "main/glheader.h"
-#include "main/colormac.h"
-#include "program/prog_instruction.h"
-
-#include "s_context.h"
-#include "s_fragprog.h"
-#include "s_span.h"
-
-
-/**
- * Apply texture object's swizzle (X/Y/Z/W/0/1) to incoming 'texel'
- * and return results in 'colorOut'.
- */
-static INLINE void
-swizzle_texel(const GLfloat texel[4], GLfloat colorOut[4], GLuint swizzle)
-{
- if (swizzle == SWIZZLE_NOOP) {
- COPY_4V(colorOut, texel);
- }
- else {
- GLfloat vector[6];
- vector[SWIZZLE_X] = texel[0];
- vector[SWIZZLE_Y] = texel[1];
- vector[SWIZZLE_Z] = texel[2];
- vector[SWIZZLE_W] = texel[3];
- vector[SWIZZLE_ZERO] = 0.0F;
- vector[SWIZZLE_ONE] = 1.0F;
- colorOut[0] = vector[GET_SWZ(swizzle, 0)];
- colorOut[1] = vector[GET_SWZ(swizzle, 1)];
- colorOut[2] = vector[GET_SWZ(swizzle, 2)];
- colorOut[3] = vector[GET_SWZ(swizzle, 3)];
- }
-}
-
-
-/**
- * Fetch a texel with given lod.
- * Called via machine->FetchTexelLod()
- */
-static void
-fetch_texel_lod( struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda,
- GLuint unit, GLfloat color[4] )
-{
- const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
-
- if (texObj) {
- SWcontext *swrast = SWRAST_CONTEXT(ctx);
- GLfloat rgba[4];
-
- lambda = CLAMP(lambda, texObj->MinLod, texObj->MaxLod);
-
- swrast->TextureSample[unit](ctx, texObj, 1,
- (const GLfloat (*)[4]) texcoord,
- &lambda, &rgba);
- swizzle_texel(rgba, color, texObj->_Swizzle);
- }
- else {
- ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F);
- }
-}
-
-
-/**
- * Fetch a texel with the given partial derivatives to compute a level
- * of detail in the mipmap.
- * Called via machine->FetchTexelDeriv()
- * \param lodBias the lod bias which may be specified by a TXB instruction,
- * otherwise zero.
- */
-static void
-fetch_texel_deriv( struct gl_context *ctx, const GLfloat texcoord[4],
- const GLfloat texdx[4], const GLfloat texdy[4],
- GLfloat lodBias, GLuint unit, GLfloat color[4] )
-{
- SWcontext *swrast = SWRAST_CONTEXT(ctx);
- const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
- const struct gl_texture_object *texObj = texUnit->_Current;
-
- if (texObj) {
- const struct gl_texture_image *texImg =
- texObj->Image[0][texObj->BaseLevel];
- const GLfloat texW = (GLfloat) texImg->WidthScale;
- const GLfloat texH = (GLfloat) texImg->HeightScale;
- GLfloat lambda;
- GLfloat rgba[4];
-
- lambda = _swrast_compute_lambda(texdx[0], texdy[0], /* ds/dx, ds/dy */
- texdx[1], texdy[1], /* dt/dx, dt/dy */
- texdx[3], texdy[3], /* dq/dx, dq/dy */
- texW, texH,
- texcoord[0], texcoord[1], texcoord[3],
- 1.0F / texcoord[3]);
-
- lambda += lodBias + texUnit->LodBias + texObj->LodBias;
-
- lambda = CLAMP(lambda, texObj->MinLod, texObj->MaxLod);
-
- swrast->TextureSample[unit](ctx, texObj, 1,
- (const GLfloat (*)[4]) texcoord,
- &lambda, &rgba);
- swizzle_texel(rgba, color, texObj->_Swizzle);
- }
- else {
- ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F);
- }
-}
-
-
-/**
- * Initialize the virtual fragment program machine state prior to running
- * fragment program on a fragment. This involves initializing the input
- * registers, condition codes, etc.
- * \param machine the virtual machine state to init
- * \param program the fragment program we're about to run
- * \param span the span of pixels we'll operate on
- * \param col which element (column) of the span we'll operate on
- */
-static void
-init_machine(struct gl_context *ctx, struct gl_program_machine *machine,
- const struct gl_fragment_program *program,
- const SWspan *span, GLuint col)
-{
- GLfloat *wpos = span->array->attribs[FRAG_ATTRIB_WPOS][col];
-
- if (program->Base.Target == GL_FRAGMENT_PROGRAM_NV) {
- /* Clear temporary registers (undefined for ARB_f_p) */
- memset(machine->Temporaries, 0, MAX_PROGRAM_TEMPS * 4 * sizeof(GLfloat));
- }
-
- /* ARB_fragment_coord_conventions */
- if (program->OriginUpperLeft)
- wpos[1] = ctx->DrawBuffer->Height - 1 - wpos[1];
- if (!program->PixelCenterInteger) {
- wpos[0] += 0.5F;
- wpos[1] += 0.5F;
- }
-
- /* Setup pointer to input attributes */
- machine->Attribs = span->array->attribs;
-
- machine->DerivX = (GLfloat (*)[4]) span->attrStepX;
- machine->DerivY = (GLfloat (*)[4]) span->attrStepY;
- machine->NumDeriv = FRAG_ATTRIB_MAX;
-
- machine->Samplers = program->Base.SamplerUnits;
-
- /* if running a GLSL program (not ARB_fragment_program) */
- if (ctx->Shader.CurrentFragmentProgram) {
- /* Store front/back facing value */
- machine->Attribs[FRAG_ATTRIB_FACE][col][0] = 1.0F - span->facing;
- }
-
- machine->CurElement = col;
-
- /* init condition codes */
- machine->CondCodes[0] = COND_EQ;
- machine->CondCodes[1] = COND_EQ;
- machine->CondCodes[2] = COND_EQ;
- machine->CondCodes[3] = COND_EQ;
-
- /* init call stack */
- machine->StackDepth = 0;
-
- machine->FetchTexelLod = fetch_texel_lod;
- machine->FetchTexelDeriv = fetch_texel_deriv;
-}
-
-
-/**
- * Run fragment program on the pixels in span from 'start' to 'end' - 1.
- */
-static void
-run_program(struct gl_context *ctx, SWspan *span, GLuint start, GLuint end)
-{
- SWcontext *swrast = SWRAST_CONTEXT(ctx);
- const struct gl_fragment_program *program = ctx->FragmentProgram._Current;
- const GLbitfield64 outputsWritten = program->Base.OutputsWritten;
- struct gl_program_machine *machine = &swrast->FragProgMachine;
- GLuint i;
-
- for (i = start; i < end; i++) {
- if (span->array->mask[i]) {
- init_machine(ctx, machine, program, span, i);
-
- if (_mesa_execute_program(ctx, &program->Base, machine)) {
-
- /* Store result color */
- if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) {
- COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0][i],
- machine->Outputs[FRAG_RESULT_COLOR]);
- }
- else {
- /* Multiple drawbuffers / render targets
- * Note that colors beyond 0 and 1 will overwrite other
- * attributes, such as FOGC, TEX0, TEX1, etc. That's OK.
- */
- GLuint buf;
- for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
- if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DATA0 + buf)) {
- COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0 + buf][i],
- machine->Outputs[FRAG_RESULT_DATA0 + buf]);
- }
- }
- }
-
- /* Store result depth/z */
- if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
- const GLfloat depth = machine->Outputs[FRAG_RESULT_DEPTH][2];
- if (depth <= 0.0)
- span->array->z[i] = 0;
- else if (depth >= 1.0)
- span->array->z[i] = ctx->DrawBuffer->_DepthMax;
- else
- span->array->z[i] = IROUND(depth * ctx->DrawBuffer->_DepthMaxF);
- }
- }
- else {
- /* killed fragment */
- span->array->mask[i] = GL_FALSE;
- span->writeAll = GL_FALSE;
- }
- }
- }
-}
-
-
-/**
- * Execute the current fragment program for all the fragments
- * in the given span.
- */
-void
-_swrast_exec_fragment_program( struct gl_context *ctx, SWspan *span )
-{
- const struct gl_fragment_program *program = ctx->FragmentProgram._Current;
-
- /* incoming colors should be floats */
- if (program->Base.InputsRead & FRAG_BIT_COL0) {
- ASSERT(span->array->ChanType == GL_FLOAT);
- }
-
- run_program(ctx, span, 0, span->end);
-
- if (program->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) {
- span->interpMask &= ~SPAN_RGBA;
- span->arrayMask |= SPAN_RGBA;
- }
-
- if (program->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
- span->interpMask &= ~SPAN_Z;
- span->arrayMask |= SPAN_Z;
- }
-}
-
+/* + * Mesa 3-D graphics library + * Version: 7.0.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * 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. + */ + +#include "main/glheader.h" +#include "main/colormac.h" +#include "program/prog_instruction.h" + +#include "s_context.h" +#include "s_fragprog.h" +#include "s_span.h" + + +/** + * Apply texture object's swizzle (X/Y/Z/W/0/1) to incoming 'texel' + * and return results in 'colorOut'. + */ +static INLINE void +swizzle_texel(const GLfloat texel[4], GLfloat colorOut[4], GLuint swizzle) +{ + if (swizzle == SWIZZLE_NOOP) { + COPY_4V(colorOut, texel); + } + else { + GLfloat vector[6]; + vector[SWIZZLE_X] = texel[0]; + vector[SWIZZLE_Y] = texel[1]; + vector[SWIZZLE_Z] = texel[2]; + vector[SWIZZLE_W] = texel[3]; + vector[SWIZZLE_ZERO] = 0.0F; + vector[SWIZZLE_ONE] = 1.0F; + colorOut[0] = vector[GET_SWZ(swizzle, 0)]; + colorOut[1] = vector[GET_SWZ(swizzle, 1)]; + colorOut[2] = vector[GET_SWZ(swizzle, 2)]; + colorOut[3] = vector[GET_SWZ(swizzle, 3)]; + } +} + + +/** + * Fetch a texel with given lod. + * Called via machine->FetchTexelLod() + */ +static void +fetch_texel_lod( struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda, + GLuint unit, GLfloat color[4] ) +{ + const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; + + if (texObj) { + SWcontext *swrast = SWRAST_CONTEXT(ctx); + GLfloat rgba[4]; + + lambda = CLAMP(lambda, texObj->Sampler.MinLod, texObj->Sampler.MaxLod); + + swrast->TextureSample[unit](ctx, texObj, 1, + (const GLfloat (*)[4]) texcoord, + &lambda, &rgba); + swizzle_texel(rgba, color, texObj->_Swizzle); + } + else { + ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F); + } +} + + +/** + * Fetch a texel with the given partial derivatives to compute a level + * of detail in the mipmap. + * Called via machine->FetchTexelDeriv() + * \param lodBias the lod bias which may be specified by a TXB instruction, + * otherwise zero. + */ +static void +fetch_texel_deriv( struct gl_context *ctx, const GLfloat texcoord[4], + const GLfloat texdx[4], const GLfloat texdy[4], + GLfloat lodBias, GLuint unit, GLfloat color[4] ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + const struct gl_texture_object *texObj = texUnit->_Current; + + if (texObj) { + const struct gl_texture_image *texImg = + texObj->Image[0][texObj->BaseLevel]; + const GLfloat texW = (GLfloat) texImg->WidthScale; + const GLfloat texH = (GLfloat) texImg->HeightScale; + GLfloat lambda; + GLfloat rgba[4]; + + lambda = _swrast_compute_lambda(texdx[0], texdy[0], /* ds/dx, ds/dy */ + texdx[1], texdy[1], /* dt/dx, dt/dy */ + texdx[3], texdy[3], /* dq/dx, dq/dy */ + texW, texH, + texcoord[0], texcoord[1], texcoord[3], + 1.0F / texcoord[3]); + + lambda += lodBias + texUnit->LodBias + texObj->Sampler.LodBias; + + lambda = CLAMP(lambda, texObj->Sampler.MinLod, texObj->Sampler.MaxLod); + + swrast->TextureSample[unit](ctx, texObj, 1, + (const GLfloat (*)[4]) texcoord, + &lambda, &rgba); + swizzle_texel(rgba, color, texObj->_Swizzle); + } + else { + ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F); + } +} + + +/** + * Initialize the virtual fragment program machine state prior to running + * fragment program on a fragment. This involves initializing the input + * registers, condition codes, etc. + * \param machine the virtual machine state to init + * \param program the fragment program we're about to run + * \param span the span of pixels we'll operate on + * \param col which element (column) of the span we'll operate on + */ +static void +init_machine(struct gl_context *ctx, struct gl_program_machine *machine, + const struct gl_fragment_program *program, + const SWspan *span, GLuint col) +{ + GLfloat *wpos = span->array->attribs[FRAG_ATTRIB_WPOS][col]; + + if (program->Base.Target == GL_FRAGMENT_PROGRAM_NV) { + /* Clear temporary registers (undefined for ARB_f_p) */ + memset(machine->Temporaries, 0, MAX_PROGRAM_TEMPS * 4 * sizeof(GLfloat)); + } + + /* ARB_fragment_coord_conventions */ + if (program->OriginUpperLeft) + wpos[1] = ctx->DrawBuffer->Height - 1 - wpos[1]; + if (!program->PixelCenterInteger) { + wpos[0] += 0.5F; + wpos[1] += 0.5F; + } + + /* Setup pointer to input attributes */ + machine->Attribs = span->array->attribs; + + machine->DerivX = (GLfloat (*)[4]) span->attrStepX; + machine->DerivY = (GLfloat (*)[4]) span->attrStepY; + machine->NumDeriv = FRAG_ATTRIB_MAX; + + machine->Samplers = program->Base.SamplerUnits; + + /* if running a GLSL program (not ARB_fragment_program) */ + if (ctx->Shader.CurrentFragmentProgram) { + /* Store front/back facing value */ + machine->Attribs[FRAG_ATTRIB_FACE][col][0] = 1.0F - span->facing; + } + + machine->CurElement = col; + + /* init condition codes */ + machine->CondCodes[0] = COND_EQ; + machine->CondCodes[1] = COND_EQ; + machine->CondCodes[2] = COND_EQ; + machine->CondCodes[3] = COND_EQ; + + /* init call stack */ + machine->StackDepth = 0; + + machine->FetchTexelLod = fetch_texel_lod; + machine->FetchTexelDeriv = fetch_texel_deriv; +} + + +/** + * Run fragment program on the pixels in span from 'start' to 'end' - 1. + */ +static void +run_program(struct gl_context *ctx, SWspan *span, GLuint start, GLuint end) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + const struct gl_fragment_program *program = ctx->FragmentProgram._Current; + const GLbitfield64 outputsWritten = program->Base.OutputsWritten; + struct gl_program_machine *machine = &swrast->FragProgMachine; + GLuint i; + + for (i = start; i < end; i++) { + if (span->array->mask[i]) { + init_machine(ctx, machine, program, span, i); + + if (_mesa_execute_program(ctx, &program->Base, machine)) { + + /* Store result color */ + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) { + COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0][i], + machine->Outputs[FRAG_RESULT_COLOR]); + } + else { + /* Multiple drawbuffers / render targets + * Note that colors beyond 0 and 1 will overwrite other + * attributes, such as FOGC, TEX0, TEX1, etc. That's OK. + */ + GLuint buf; + for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) { + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DATA0 + buf)) { + COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0 + buf][i], + machine->Outputs[FRAG_RESULT_DATA0 + buf]); + } + } + } + + /* Store result depth/z */ + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { + const GLfloat depth = machine->Outputs[FRAG_RESULT_DEPTH][2]; + if (depth <= 0.0) + span->array->z[i] = 0; + else if (depth >= 1.0) + span->array->z[i] = ctx->DrawBuffer->_DepthMax; + else + span->array->z[i] = IROUND(depth * ctx->DrawBuffer->_DepthMaxF); + } + } + else { + /* killed fragment */ + span->array->mask[i] = GL_FALSE; + span->writeAll = GL_FALSE; + } + } + } +} + + +/** + * Execute the current fragment program for all the fragments + * in the given span. + */ +void +_swrast_exec_fragment_program( struct gl_context *ctx, SWspan *span ) +{ + const struct gl_fragment_program *program = ctx->FragmentProgram._Current; + + /* incoming colors should be floats */ + if (program->Base.InputsRead & FRAG_BIT_COL0) { + ASSERT(span->array->ChanType == GL_FLOAT); + } + + run_program(ctx, span, 0, span->end); + + if (program->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) { + span->interpMask &= ~SPAN_RGBA; + span->arrayMask |= SPAN_RGBA; + } + + if (program->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { + span->interpMask &= ~SPAN_Z; + span->arrayMask |= SPAN_Z; + } +} + diff --git a/mesalib/src/mesa/swrast/s_span.c b/mesalib/src/mesa/swrast/s_span.c index 75e3c53a1..9cfecc9e3 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->MinFilter != obj->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; +} diff --git a/mesalib/src/mesa/swrast/s_texcombine.c b/mesalib/src/mesa/swrast/s_texcombine.c index 0c8cc9ff3..7f49b6ffa 100644 --- a/mesalib/src/mesa/swrast/s_texcombine.c +++ b/mesalib/src/mesa/swrast/s_texcombine.c @@ -631,9 +631,9 @@ _swrast_texture_span( struct gl_context *ctx, SWspan *span ) /* adjust texture lod (lambda) */ if (span->arrayMask & SPAN_LAMBDA) { - if (texUnit->LodBias + curObj->LodBias != 0.0F) { + if (texUnit->LodBias + curObj->Sampler.LodBias != 0.0F) { /* apply LOD bias, but don't clamp yet */ - const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias, + const GLfloat bias = CLAMP(texUnit->LodBias + curObj->Sampler.LodBias, -ctx->Const.MaxTextureLodBias, ctx->Const.MaxTextureLodBias); GLuint i; @@ -642,10 +642,11 @@ _swrast_texture_span( struct gl_context *ctx, SWspan *span ) } } - if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) { + if (curObj->Sampler.MinLod != -1000.0 || + curObj->Sampler.MaxLod != 1000.0) { /* apply LOD clamping to lambda */ - const GLfloat min = curObj->MinLod; - const GLfloat max = curObj->MaxLod; + const GLfloat min = curObj->Sampler.MinLod; + const GLfloat max = curObj->Sampler.MaxLod; GLuint i; for (i = 0; i < span->end; i++) { GLfloat l = lambda[i]; @@ -686,9 +687,9 @@ _swrast_texture_span( struct gl_context *ctx, SWspan *span ) /* adjust texture lod (lambda) */ if (span->arrayMask & SPAN_LAMBDA) { - if (texUnit->LodBias + curObj->LodBias != 0.0F) { + if (texUnit->LodBias + curObj->Sampler.LodBias != 0.0F) { /* apply LOD bias, but don't clamp yet */ - const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias, + const GLfloat bias = CLAMP(texUnit->LodBias + curObj->Sampler.LodBias, -ctx->Const.MaxTextureLodBias, ctx->Const.MaxTextureLodBias); GLuint i; @@ -697,10 +698,11 @@ _swrast_texture_span( struct gl_context *ctx, SWspan *span ) } } - if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) { + if (curObj->Sampler.MinLod != -1000.0 || + curObj->Sampler.MaxLod != 1000.0) { /* apply LOD clamping to lambda */ - const GLfloat min = curObj->MinLod; - const GLfloat max = curObj->MaxLod; + const GLfloat min = curObj->Sampler.MinLod; + const GLfloat max = curObj->Sampler.MaxLod; GLuint i; for (i = 0; i < span->end; i++) { GLfloat l = lambda[i]; diff --git a/mesalib/src/mesa/swrast/s_texfilter.c b/mesalib/src/mesa/swrast/s_texfilter.c index 42785400c..106f8b75f 100644 --- a/mesalib/src/mesa/swrast/s_texfilter.c +++ b/mesalib/src/mesa/swrast/s_texfilter.c @@ -505,28 +505,28 @@ nearest_texcoord(const struct gl_texture_object *texObj, switch (texObj->Target) { case GL_TEXTURE_RECTANGLE_ARB: - *i = clamp_rect_coord_nearest(texObj->WrapS, texcoord[0], width); - *j = clamp_rect_coord_nearest(texObj->WrapT, texcoord[1], height); + *i = clamp_rect_coord_nearest(texObj->Sampler.WrapS, texcoord[0], width); + *j = clamp_rect_coord_nearest(texObj->Sampler.WrapT, texcoord[1], height); *k = 0; break; case GL_TEXTURE_1D: - *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); + *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); *j = 0; *k = 0; break; case GL_TEXTURE_2D: - *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); - *j = nearest_texel_location(texObj->WrapT, img, height, texcoord[1]); + *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); + *j = nearest_texel_location(texObj->Sampler.WrapT, img, height, texcoord[1]); *k = 0; break; case GL_TEXTURE_1D_ARRAY_EXT: - *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); + *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); *j = tex_array_slice(texcoord[1], height); *k = 0; break; case GL_TEXTURE_2D_ARRAY_EXT: - *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); - *j = nearest_texel_location(texObj->WrapT, img, height, texcoord[1]); + *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); + *j = nearest_texel_location(texObj->Sampler.WrapT, img, height, texcoord[1]); *k = tex_array_slice(texcoord[2], depth); break; default: @@ -553,24 +553,24 @@ linear_texcoord(const struct gl_texture_object *texObj, switch (texObj->Target) { case GL_TEXTURE_RECTANGLE_ARB: - clamp_rect_coord_linear(texObj->WrapS, texcoord[0], + clamp_rect_coord_linear(texObj->Sampler.WrapS, texcoord[0], width, i0, i1, wi); - clamp_rect_coord_linear(texObj->WrapT, texcoord[1], + clamp_rect_coord_linear(texObj->Sampler.WrapT, texcoord[1], height, j0, j1, wj); *slice = 0; break; case GL_TEXTURE_1D: case GL_TEXTURE_2D: - linear_texel_locations(texObj->WrapS, img, width, + linear_texel_locations(texObj->Sampler.WrapS, img, width, texcoord[0], i0, i1, wi); - linear_texel_locations(texObj->WrapT, img, height, + linear_texel_locations(texObj->Sampler.WrapT, img, height, texcoord[1], j0, j1, wj); *slice = 0; break; case GL_TEXTURE_1D_ARRAY_EXT: - linear_texel_locations(texObj->WrapS, img, width, + linear_texel_locations(texObj->Sampler.WrapS, img, width, texcoord[0], i0, i1, wi); *j0 = tex_array_slice(texcoord[1], height); *j1 = *j0; @@ -578,9 +578,9 @@ linear_texcoord(const struct gl_texture_object *texObj, break; case GL_TEXTURE_2D_ARRAY_EXT: - linear_texel_locations(texObj->WrapS, img, width, + linear_texel_locations(texObj->Sampler.WrapS, img, width, texcoord[0], i0, i1, wi); - linear_texel_locations(texObj->WrapT, img, height, + linear_texel_locations(texObj->Sampler.WrapT, img, height, texcoord[1], j0, j1, wj); *slice = tex_array_slice(texcoord[2], depth); break; @@ -656,12 +656,12 @@ compute_min_mag_ranges(const struct gl_texture_object *tObj, GLfloat minMagThresh; /* we shouldn't be here if minfilter == magfilter */ - ASSERT(tObj->MinFilter != tObj->MagFilter); + ASSERT(tObj->Sampler.MinFilter != tObj->Sampler.MagFilter); /* This bit comes from the OpenGL spec: */ - if (tObj->MagFilter == GL_LINEAR - && (tObj->MinFilter == GL_NEAREST_MIPMAP_NEAREST || - tObj->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) { + if (tObj->Sampler.MagFilter == GL_LINEAR + && (tObj->Sampler.MinFilter == GL_NEAREST_MIPMAP_NEAREST || + tObj->Sampler.MinFilter == GL_NEAREST_MIPMAP_LINEAR)) { minMagThresh = 0.5F; } else { @@ -763,28 +763,28 @@ get_border_color(const struct gl_texture_object *tObj, { switch (img->_BaseFormat) { case GL_RGB: - rgba[0] = tObj->BorderColor.f[0]; - rgba[1] = tObj->BorderColor.f[1]; - rgba[2] = tObj->BorderColor.f[2]; + rgba[0] = tObj->Sampler.BorderColor.f[0]; + rgba[1] = tObj->Sampler.BorderColor.f[1]; + rgba[2] = tObj->Sampler.BorderColor.f[2]; rgba[3] = 1.0F; break; case GL_ALPHA: rgba[0] = rgba[1] = rgba[2] = 0.0; - rgba[3] = tObj->BorderColor.f[3]; + rgba[3] = tObj->Sampler.BorderColor.f[3]; break; case GL_LUMINANCE: - rgba[0] = rgba[1] = rgba[2] = tObj->BorderColor.f[0]; + rgba[0] = rgba[1] = rgba[2] = tObj->Sampler.BorderColor.f[0]; rgba[3] = 1.0; break; case GL_LUMINANCE_ALPHA: - rgba[0] = rgba[1] = rgba[2] = tObj->BorderColor.f[0]; - rgba[3] = tObj->BorderColor.f[3]; + rgba[0] = rgba[1] = rgba[2] = tObj->Sampler.BorderColor.f[0]; + rgba[3] = tObj->Sampler.BorderColor.f[3]; break; case GL_INTENSITY: - rgba[0] = rgba[1] = rgba[2] = rgba[3] = tObj->BorderColor.f[0]; + rgba[0] = rgba[1] = rgba[2] = rgba[3] = tObj->Sampler.BorderColor.f[0]; break; default: - COPY_4V(rgba, tObj->BorderColor.f); + COPY_4V(rgba, tObj->Sampler.BorderColor.f); } } @@ -804,7 +804,7 @@ sample_1d_nearest(struct gl_context *ctx, { const GLint width = img->Width2; /* without border, power of two */ GLint i; - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); /* skip over the border, if any */ i += img->Border; if (i < 0 || i >= (GLint) img->Width) { @@ -832,7 +832,7 @@ sample_1d_linear(struct gl_context *ctx, GLfloat a; GLfloat t0[4], t1[4]; /* texels */ - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); if (img->Border) { i0 += img->Border; @@ -991,7 +991,7 @@ sample_lambda_1d( struct gl_context *ctx, if (minStart < minEnd) { /* do the minified texels */ const GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { + switch (tObj->Sampler.MinFilter) { case GL_NEAREST: for (i = minStart; i < minEnd; i++) sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], @@ -1026,7 +1026,7 @@ sample_lambda_1d( struct gl_context *ctx, if (magStart < magEnd) { /* do the magnified texels */ - switch (tObj->MagFilter) { + switch (tObj->Sampler.MagFilter) { case GL_NEAREST: for (i = magStart; i < magEnd; i++) sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], @@ -1065,8 +1065,8 @@ sample_2d_nearest(struct gl_context *ctx, GLint i, j; (void) ctx; - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); - j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]); + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); + j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]); /* skip over the border, if any */ i += img->Border; @@ -1100,8 +1100,8 @@ sample_2d_linear(struct gl_context *ctx, GLfloat a, b; GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); - linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b); + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b); if (img->Border) { i0 += img->Border; @@ -1165,8 +1165,8 @@ sample_2d_linear_repeat(struct gl_context *ctx, (void) ctx; - ASSERT(tObj->WrapS == GL_REPEAT); - ASSERT(tObj->WrapT == GL_REPEAT); + ASSERT(tObj->Sampler.WrapS == GL_REPEAT); + ASSERT(tObj->Sampler.WrapT == GL_REPEAT); ASSERT(img->Border == 0); ASSERT(img->_BaseFormat != GL_COLOR_INDEX); ASSERT(img->_IsPowerOfTwo); @@ -1270,8 +1270,8 @@ sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx, { GLuint i; ASSERT(lambda != NULL); - ASSERT(tObj->WrapS == GL_REPEAT); - ASSERT(tObj->WrapT == GL_REPEAT); + ASSERT(tObj->Sampler.WrapS == GL_REPEAT); + ASSERT(tObj->Sampler.WrapT == GL_REPEAT); for (i = 0; i < n; i++) { GLint level = linear_mipmap_level(tObj, lambda[i]); if (level >= tObj->_MaxLevel) { @@ -1317,8 +1317,8 @@ sample_linear_2d(struct gl_context *ctx, GLuint i; struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; (void) lambda; - if (tObj->WrapS == GL_REPEAT && - tObj->WrapT == GL_REPEAT && + if (tObj->Sampler.WrapS == GL_REPEAT && + tObj->Sampler.WrapT == GL_REPEAT && image->_IsPowerOfTwo && image->Border == 0) { for (i = 0; i < n; i++) { @@ -1356,8 +1356,8 @@ opt_sample_rgb_2d(struct gl_context *ctx, GLuint k; (void) ctx; (void) lambda; - ASSERT(tObj->WrapS==GL_REPEAT); - ASSERT(tObj->WrapT==GL_REPEAT); + ASSERT(tObj->Sampler.WrapS==GL_REPEAT); + ASSERT(tObj->Sampler.WrapT==GL_REPEAT); ASSERT(img->Border==0); ASSERT(img->TexFormat == MESA_FORMAT_RGB888); ASSERT(img->_IsPowerOfTwo); @@ -1398,8 +1398,8 @@ opt_sample_rgba_2d(struct gl_context *ctx, GLuint i; (void) ctx; (void) lambda; - ASSERT(tObj->WrapS==GL_REPEAT); - ASSERT(tObj->WrapT==GL_REPEAT); + ASSERT(tObj->Sampler.WrapS==GL_REPEAT); + ASSERT(tObj->Sampler.WrapT==GL_REPEAT); ASSERT(img->Border==0); ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888); ASSERT(img->_IsPowerOfTwo); @@ -1428,8 +1428,8 @@ sample_lambda_2d(struct gl_context *ctx, GLuint minStart, minEnd; /* texels with minification */ GLuint magStart, magEnd; /* texels with magnification */ - const GLboolean repeatNoBorderPOT = (tObj->WrapS == GL_REPEAT) - && (tObj->WrapT == GL_REPEAT) + const GLboolean repeatNoBorderPOT = (tObj->Sampler.WrapS == GL_REPEAT) + && (tObj->Sampler.WrapT == GL_REPEAT) && (tImg->Border == 0 && (tImg->Width == tImg->RowStride)) && (tImg->_BaseFormat != GL_COLOR_INDEX) && tImg->_IsPowerOfTwo; @@ -1441,7 +1441,7 @@ sample_lambda_2d(struct gl_context *ctx, if (minStart < minEnd) { /* do the minified texels */ const GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { + switch (tObj->Sampler.MinFilter) { case GL_NEAREST: if (repeatNoBorderPOT) { switch (tImg->TexFormat) { @@ -1498,7 +1498,7 @@ sample_lambda_2d(struct gl_context *ctx, /* do the magnified texels */ const GLuint m = magEnd - magStart; - switch (tObj->MagFilter) { + switch (tObj->Sampler.MagFilter) { case GL_NEAREST: if (repeatNoBorderPOT) { switch (tImg->TexFormat) { @@ -1552,9 +1552,9 @@ sample_3d_nearest(struct gl_context *ctx, GLint i, j, k; (void) ctx; - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); - j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]); - k = nearest_texel_location(tObj->WrapR, img, depth, texcoord[2]); + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); + j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]); + k = nearest_texel_location(tObj->Sampler.WrapR, img, depth, texcoord[2]); if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height || @@ -1587,9 +1587,9 @@ sample_3d_linear(struct gl_context *ctx, GLfloat t000[4], t010[4], t001[4], t011[4]; GLfloat t100[4], t110[4], t101[4], t111[4]; - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); - linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b); - linear_texel_locations(tObj->WrapR, img, depth, texcoord[2], &k0, &k1, &c); + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b); + linear_texel_locations(tObj->Sampler.WrapR, img, depth, texcoord[2], &k0, &k1, &c); if (img->Border) { i0 += img->Border; @@ -1794,7 +1794,7 @@ sample_lambda_3d(struct gl_context *ctx, if (minStart < minEnd) { /* do the minified texels */ GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { + switch (tObj->Sampler.MinFilter) { case GL_NEAREST: for (i = minStart; i < minEnd; i++) sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], @@ -1829,7 +1829,7 @@ sample_lambda_3d(struct gl_context *ctx, if (magStart < magEnd) { /* do the magnified texels */ - switch (tObj->MagFilter) { + switch (tObj->Sampler.MagFilter) { case GL_NEAREST: for (i = magStart; i < magEnd; i++) sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], @@ -2091,7 +2091,7 @@ sample_lambda_cube(struct gl_context *ctx, if (minStart < minEnd) { /* do the minified texels */ const GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { + switch (tObj->Sampler.MinFilter) { case GL_NEAREST: sample_nearest_cube(ctx, tObj, m, texcoords + minStart, lambda + minStart, rgba + minStart); @@ -2128,7 +2128,7 @@ sample_lambda_cube(struct gl_context *ctx, if (magStart < magEnd) { /* do the magnified texels */ const GLuint m = magEnd - magStart; - switch (tObj->MagFilter) { + switch (tObj->Sampler.MagFilter) { case GL_NEAREST: sample_nearest_cube(ctx, tObj, m, texcoords + magStart, lambda + magStart, rgba + magStart); @@ -2163,18 +2163,18 @@ sample_nearest_rect(struct gl_context *ctx, (void) ctx; (void) lambda; - ASSERT(tObj->WrapS == GL_CLAMP || - tObj->WrapS == GL_CLAMP_TO_EDGE || - tObj->WrapS == GL_CLAMP_TO_BORDER); - ASSERT(tObj->WrapT == GL_CLAMP || - tObj->WrapT == GL_CLAMP_TO_EDGE || - tObj->WrapT == GL_CLAMP_TO_BORDER); + ASSERT(tObj->Sampler.WrapS == GL_CLAMP || + tObj->Sampler.WrapS == GL_CLAMP_TO_EDGE || + tObj->Sampler.WrapS == GL_CLAMP_TO_BORDER); + ASSERT(tObj->Sampler.WrapT == GL_CLAMP || + tObj->Sampler.WrapT == GL_CLAMP_TO_EDGE || + tObj->Sampler.WrapT == GL_CLAMP_TO_BORDER); ASSERT(img->_BaseFormat != GL_COLOR_INDEX); for (i = 0; i < n; i++) { GLint row, col; - col = clamp_rect_coord_nearest(tObj->WrapS, texcoords[i][0], width); - row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height); + col = clamp_rect_coord_nearest(tObj->Sampler.WrapS, texcoords[i][0], width); + row = clamp_rect_coord_nearest(tObj->Sampler.WrapT, texcoords[i][1], height); if (col < 0 || col >= width || row < 0 || row >= height) get_border_color(tObj, img, rgba[i]); else @@ -2197,12 +2197,12 @@ sample_linear_rect(struct gl_context *ctx, (void) ctx; (void) lambda; - ASSERT(tObj->WrapS == GL_CLAMP || - tObj->WrapS == GL_CLAMP_TO_EDGE || - tObj->WrapS == GL_CLAMP_TO_BORDER); - ASSERT(tObj->WrapT == GL_CLAMP || - tObj->WrapT == GL_CLAMP_TO_EDGE || - tObj->WrapT == GL_CLAMP_TO_BORDER); + ASSERT(tObj->Sampler.WrapS == GL_CLAMP || + tObj->Sampler.WrapS == GL_CLAMP_TO_EDGE || + tObj->Sampler.WrapS == GL_CLAMP_TO_BORDER); + ASSERT(tObj->Sampler.WrapT == GL_CLAMP || + tObj->Sampler.WrapT == GL_CLAMP_TO_EDGE || + tObj->Sampler.WrapT == GL_CLAMP_TO_BORDER); ASSERT(img->_BaseFormat != GL_COLOR_INDEX); for (i = 0; i < n; i++) { @@ -2211,9 +2211,9 @@ sample_linear_rect(struct gl_context *ctx, GLfloat a, b; GLbitfield useBorderColor = 0x0; - clamp_rect_coord_linear(tObj->WrapS, texcoords[i][0], width, + clamp_rect_coord_linear(tObj->Sampler.WrapS, texcoords[i][0], width, &i0, &i1, &a); - clamp_rect_coord_linear(tObj->WrapT, texcoords[i][1], height, + clamp_rect_coord_linear(tObj->Sampler.WrapT, texcoords[i][1], height, &j0, &j1, &b); /* compute integer rows/columns */ @@ -2264,7 +2264,7 @@ sample_lambda_rect(struct gl_context *ctx, &minStart, &minEnd, &magStart, &magEnd); if (minStart < minEnd) { - if (tObj->MinFilter == GL_NEAREST) { + if (tObj->Sampler.MinFilter == GL_NEAREST) { sample_nearest_rect(ctx, tObj, minEnd - minStart, texcoords + minStart, NULL, rgba + minStart); } @@ -2274,7 +2274,7 @@ sample_lambda_rect(struct gl_context *ctx, } } if (magStart < magEnd) { - if (tObj->MagFilter == GL_NEAREST) { + if (tObj->Sampler.MagFilter == GL_NEAREST) { sample_nearest_rect(ctx, tObj, magEnd - magStart, texcoords + magStart, NULL, rgba + magStart); } @@ -2307,8 +2307,8 @@ sample_2d_array_nearest(struct gl_context *ctx, GLint array; (void) ctx; - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); - j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]); + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); + j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]); array = tex_array_slice(texcoord[2], depth); if (i < 0 || i >= (GLint) img->Width || @@ -2342,12 +2342,12 @@ sample_2d_array_linear(struct gl_context *ctx, GLfloat a, b; GLfloat t00[4], t01[4], t10[4], t11[4]; - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); - linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b); + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b); array = tex_array_slice(texcoord[2], depth); if (array < 0 || array >= depth) { - COPY_4V(rgba, tObj->BorderColor.f); + COPY_4V(rgba, tObj->Sampler.BorderColor.f); } else { if (img->Border) { @@ -2532,7 +2532,7 @@ sample_lambda_2d_array(struct gl_context *ctx, if (minStart < minEnd) { /* do the minified texels */ GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { + switch (tObj->Sampler.MinFilter) { case GL_NEAREST: for (i = minStart; i < minEnd; i++) sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], @@ -2575,7 +2575,7 @@ sample_lambda_2d_array(struct gl_context *ctx, if (magStart < magEnd) { /* do the magnified texels */ - switch (tObj->MagFilter) { + switch (tObj->Sampler.MagFilter) { case GL_NEAREST: for (i = magStart; i < magEnd; i++) sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], @@ -2616,7 +2616,7 @@ sample_1d_array_nearest(struct gl_context *ctx, GLint array; (void) ctx; - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); array = tex_array_slice(texcoord[1], height); if (i < 0 || i >= (GLint) img->Width || @@ -2648,7 +2648,7 @@ sample_1d_array_linear(struct gl_context *ctx, GLfloat a; GLfloat t0[4], t1[4]; - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); array = tex_array_slice(texcoord[1], height); if (img->Border) { @@ -2813,7 +2813,7 @@ sample_lambda_1d_array(struct gl_context *ctx, if (minStart < minEnd) { /* do the minified texels */ GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { + switch (tObj->Sampler.MinFilter) { case GL_NEAREST: for (i = minStart; i < minEnd; i++) sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], @@ -2852,7 +2852,7 @@ sample_lambda_1d_array(struct gl_context *ctx, if (magStart < magEnd) { /* do the magnified texels */ - switch (tObj->MagFilter) { + switch (tObj->Sampler.MagFilter) { case GL_NEAREST: for (i = magStart; i < magEnd; i++) sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], @@ -2975,13 +2975,13 @@ choose_depth_texture_level(const struct gl_texture_object *tObj, GLfloat lambda) { GLint level; - if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { + if (tObj->Sampler.MinFilter == GL_NEAREST || tObj->Sampler.MinFilter == GL_LINEAR) { /* no mipmapping - use base level */ level = tObj->BaseLevel; } else { /* choose mipmap level */ - lambda = CLAMP(lambda, tObj->MinLod, tObj->MaxLod); + lambda = CLAMP(lambda, tObj->Sampler.MinLod, tObj->Sampler.MaxLod); level = (GLint) lambda; level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel); } @@ -3020,14 +3020,14 @@ sample_depth_texture( struct gl_context *ctx, tObj->Target == GL_TEXTURE_1D_ARRAY_EXT || tObj->Target == GL_TEXTURE_2D_ARRAY_EXT); - ambient = tObj->CompareFailValue; + ambient = tObj->Sampler.CompareFailValue; - /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */ + /* XXXX if tObj->Sampler.MinFilter != tObj->Sampler.MagFilter, we're ignoring lambda */ - function = (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ? - tObj->CompareFunc : GL_NONE; + function = (tObj->Sampler.CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ? + tObj->Sampler.CompareFunc : GL_NONE; - if (tObj->MagFilter == GL_NEAREST) { + if (tObj->Sampler.MagFilter == GL_NEAREST) { GLuint i; for (i = 0; i < n; i++) { GLfloat depthSample, depthRef; @@ -3040,14 +3040,14 @@ sample_depth_texture( struct gl_context *ctx, img->FetchTexelf(img, col, row, slice, &depthSample); } else { - depthSample = tObj->BorderColor.f[0]; + depthSample = tObj->Sampler.BorderColor.f[0]; } depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F); result = shadow_compare(function, depthRef, depthSample, ambient); - switch (tObj->DepthMode) { + switch (tObj->Sampler.DepthMode) { case GL_LUMINANCE: ASSIGN_4V(texel[i], result, result, result, 1.0F); break; @@ -3067,7 +3067,7 @@ sample_depth_texture( struct gl_context *ctx, } else { GLuint i; - ASSERT(tObj->MagFilter == GL_LINEAR); + ASSERT(tObj->Sampler.MagFilter == GL_LINEAR); for (i = 0; i < n; i++) { GLfloat depth00, depth01, depth10, depth11, depthRef; GLint i0, i1, j0, j1; @@ -3095,21 +3095,21 @@ sample_depth_texture( struct gl_context *ctx, } if (slice < 0 || slice >= (GLint) depth) { - depth00 = tObj->BorderColor.f[0]; - depth01 = tObj->BorderColor.f[0]; - depth10 = tObj->BorderColor.f[0]; - depth11 = tObj->BorderColor.f[0]; + depth00 = tObj->Sampler.BorderColor.f[0]; + depth01 = tObj->Sampler.BorderColor.f[0]; + depth10 = tObj->Sampler.BorderColor.f[0]; + depth11 = tObj->Sampler.BorderColor.f[0]; } else { /* get four depth samples from the texture */ if (useBorderTexel & (I0BIT | J0BIT)) { - depth00 = tObj->BorderColor.f[0]; + depth00 = tObj->Sampler.BorderColor.f[0]; } else { img->FetchTexelf(img, i0, j0, slice, &depth00); } if (useBorderTexel & (I1BIT | J0BIT)) { - depth10 = tObj->BorderColor.f[0]; + depth10 = tObj->Sampler.BorderColor.f[0]; } else { img->FetchTexelf(img, i1, j0, slice, &depth10); @@ -3117,13 +3117,13 @@ sample_depth_texture( struct gl_context *ctx, if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { if (useBorderTexel & (I0BIT | J1BIT)) { - depth01 = tObj->BorderColor.f[0]; + depth01 = tObj->Sampler.BorderColor.f[0]; } else { img->FetchTexelf(img, i0, j1, slice, &depth01); } if (useBorderTexel & (I1BIT | J1BIT)) { - depth11 = tObj->BorderColor.f[0]; + depth11 = tObj->Sampler.BorderColor.f[0]; } else { img->FetchTexelf(img, i1, j1, slice, &depth11); @@ -3141,7 +3141,7 @@ sample_depth_texture( struct gl_context *ctx, depth00, depth01, depth10, depth11, ambient, wi, wj); - switch (tObj->DepthMode) { + switch (tObj->Sampler.DepthMode) { case GL_LUMINANCE: ASSIGN_4V(texel[i], result, result, result, 1.0F); break; @@ -3197,7 +3197,8 @@ _swrast_choose_texture_sample_func( struct gl_context *ctx, return &null_sample_func; } else { - const GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter); + const GLboolean needLambda = + (GLboolean) (t->Sampler.MinFilter != t->Sampler.MagFilter); const GLenum format = t->Image[0][t->BaseLevel]->_BaseFormat; switch (t->Target) { @@ -3208,11 +3209,11 @@ _swrast_choose_texture_sample_func( struct gl_context *ctx, else if (needLambda) { return &sample_lambda_1d; } - else if (t->MinFilter == GL_LINEAR) { + else if (t->Sampler.MinFilter == GL_LINEAR) { return &sample_linear_1d; } else { - ASSERT(t->MinFilter == GL_NEAREST); + ASSERT(t->Sampler.MinFilter == GL_NEAREST); return &sample_nearest_1d; } case GL_TEXTURE_2D: @@ -3222,22 +3223,22 @@ _swrast_choose_texture_sample_func( struct gl_context *ctx, else if (needLambda) { return &sample_lambda_2d; } - else if (t->MinFilter == GL_LINEAR) { + else if (t->Sampler.MinFilter == GL_LINEAR) { return &sample_linear_2d; } else { /* check for a few optimized cases */ const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; - ASSERT(t->MinFilter == GL_NEAREST); - if (t->WrapS == GL_REPEAT && - t->WrapT == GL_REPEAT && + ASSERT(t->Sampler.MinFilter == GL_NEAREST); + if (t->Sampler.WrapS == GL_REPEAT && + t->Sampler.WrapT == GL_REPEAT && img->_IsPowerOfTwo && img->Border == 0 && img->TexFormat == MESA_FORMAT_RGB888) { return &opt_sample_rgb_2d; } - else if (t->WrapS == GL_REPEAT && - t->WrapT == GL_REPEAT && + else if (t->Sampler.WrapS == GL_REPEAT && + t->Sampler.WrapT == GL_REPEAT && img->_IsPowerOfTwo && img->Border == 0 && img->TexFormat == MESA_FORMAT_RGBA8888) { @@ -3251,22 +3252,22 @@ _swrast_choose_texture_sample_func( struct gl_context *ctx, if (needLambda) { return &sample_lambda_3d; } - else if (t->MinFilter == GL_LINEAR) { + else if (t->Sampler.MinFilter == GL_LINEAR) { return &sample_linear_3d; } else { - ASSERT(t->MinFilter == GL_NEAREST); + ASSERT(t->Sampler.MinFilter == GL_NEAREST); return &sample_nearest_3d; } case GL_TEXTURE_CUBE_MAP: if (needLambda) { return &sample_lambda_cube; } - else if (t->MinFilter == GL_LINEAR) { + else if (t->Sampler.MinFilter == GL_LINEAR) { return &sample_linear_cube; } else { - ASSERT(t->MinFilter == GL_NEAREST); + ASSERT(t->Sampler.MinFilter == GL_NEAREST); return &sample_nearest_cube; } case GL_TEXTURE_RECTANGLE_NV: @@ -3276,33 +3277,33 @@ _swrast_choose_texture_sample_func( struct gl_context *ctx, else if (needLambda) { return &sample_lambda_rect; } - else if (t->MinFilter == GL_LINEAR) { + else if (t->Sampler.MinFilter == GL_LINEAR) { return &sample_linear_rect; } else { - ASSERT(t->MinFilter == GL_NEAREST); + ASSERT(t->Sampler.MinFilter == GL_NEAREST); return &sample_nearest_rect; } case GL_TEXTURE_1D_ARRAY_EXT: if (needLambda) { return &sample_lambda_1d_array; } - else if (t->MinFilter == GL_LINEAR) { + else if (t->Sampler.MinFilter == GL_LINEAR) { return &sample_linear_1d_array; } else { - ASSERT(t->MinFilter == GL_NEAREST); + ASSERT(t->Sampler.MinFilter == GL_NEAREST); return &sample_nearest_1d_array; } case GL_TEXTURE_2D_ARRAY_EXT: if (needLambda) { return &sample_lambda_2d_array; } - else if (t->MinFilter == GL_LINEAR) { + else if (t->Sampler.MinFilter == GL_LINEAR) { return &sample_linear_2d_array; } else { - ASSERT(t->MinFilter == GL_NEAREST); + ASSERT(t->Sampler.MinFilter == GL_NEAREST); return &sample_nearest_2d_array; } default: diff --git a/mesalib/src/mesa/swrast/s_triangle.c b/mesalib/src/mesa/swrast/s_triangle.c index c2c1ce221..8a9671aa0 100644 --- a/mesalib/src/mesa/swrast/s_triangle.c +++ b/mesalib/src/mesa/swrast/s_triangle.c @@ -1,1143 +1,1143 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * 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.
- */
-
-
-/*
- * When the device driver doesn't implement triangle rasterization it
- * can hook in _swrast_Triangle, which eventually calls one of these
- * functions to draw triangles.
- */
-
-#include "main/glheader.h"
-#include "main/context.h"
-#include "main/colormac.h"
-#include "main/imports.h"
-#include "main/macros.h"
-#include "main/mtypes.h"
-#include "main/state.h"
-#include "program/prog_instruction.h"
-
-#include "s_aatriangle.h"
-#include "s_context.h"
-#include "s_feedback.h"
-#include "s_span.h"
-#include "s_triangle.h"
-
-
-/**
- * Test if a triangle should be culled. Used for feedback and selection mode.
- * \return GL_TRUE if the triangle is to be culled, GL_FALSE otherwise.
- */
-GLboolean
-_swrast_culltriangle( struct gl_context *ctx,
- const SWvertex *v0,
- const SWvertex *v1,
- const SWvertex *v2 )
-{
- SWcontext *swrast = SWRAST_CONTEXT(ctx);
- GLfloat ex = v1->attrib[FRAG_ATTRIB_WPOS][0] - v0->attrib[FRAG_ATTRIB_WPOS][0];
- GLfloat ey = v1->attrib[FRAG_ATTRIB_WPOS][1] - v0->attrib[FRAG_ATTRIB_WPOS][1];
- GLfloat fx = v2->attrib[FRAG_ATTRIB_WPOS][0] - v0->attrib[FRAG_ATTRIB_WPOS][0];
- GLfloat fy = v2->attrib[FRAG_ATTRIB_WPOS][1] - v0->attrib[FRAG_ATTRIB_WPOS][1];
- GLfloat c = ex*fy-ey*fx;
-
- if (c * swrast->_BackfaceSign * swrast->_BackfaceCullSign <= 0.0F)
- return GL_FALSE;
-
- return GL_TRUE;
-}
-
-
-
-/*
- * Render a flat-shaded RGBA triangle.
- */
-#define NAME flat_rgba_triangle
-#define INTERP_Z 1
-#define SETUP_CODE \
- ASSERT(ctx->Texture._EnabledCoordUnits == 0);\
- ASSERT(ctx->Light.ShadeModel==GL_FLAT); \
- span.interpMask |= SPAN_RGBA; \
- span.red = ChanToFixed(v2->color[0]); \
- span.green = ChanToFixed(v2->color[1]); \
- span.blue = ChanToFixed(v2->color[2]); \
- span.alpha = ChanToFixed(v2->color[3]); \
- span.redStep = 0; \
- span.greenStep = 0; \
- span.blueStep = 0; \
- span.alphaStep = 0;
-#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span);
-#include "s_tritemp.h"
-
-
-
-/*
- * Render a smooth-shaded RGBA triangle.
- */
-#define NAME smooth_rgba_triangle
-#define INTERP_Z 1
-#define INTERP_RGB 1
-#define INTERP_ALPHA 1
-#define SETUP_CODE \
- { \
- /* texturing must be off */ \
- ASSERT(ctx->Texture._EnabledCoordUnits == 0); \
- ASSERT(ctx->Light.ShadeModel==GL_SMOOTH); \
- }
-#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span);
-#include "s_tritemp.h"
-
-
-
-/*
- * Render an RGB, GL_DECAL, textured triangle.
- * Interpolate S,T only w/out mipmapping or perspective correction.
- *
- * No fog. No depth testing.
- */
-#define NAME simple_textured_triangle
-#define INTERP_INT_TEX 1
-#define S_SCALE twidth
-#define T_SCALE theight
-
-#define SETUP_CODE \
- struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; \
- const struct gl_texture_object *obj = \
- ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \
- const struct gl_texture_image *texImg = \
- obj->Image[0][obj->BaseLevel]; \
- const GLfloat twidth = (GLfloat) texImg->Width; \
- const GLfloat theight = (GLfloat) texImg->Height; \
- const GLint twidth_log2 = texImg->WidthLog2; \
- const GLubyte *texture = (const GLubyte *) texImg->Data; \
- const GLint smask = texImg->Width - 1; \
- const GLint tmask = texImg->Height - 1; \
- ASSERT(texImg->TexFormat == MESA_FORMAT_RGB888); \
- if (!rb || !texture) { \
- return; \
- }
-
-#define RENDER_SPAN( span ) \
- GLuint i; \
- GLubyte rgb[MAX_WIDTH][3]; \
- span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \
- span.intTex[1] -= FIXED_HALF; \
- for (i = 0; i < span.end; i++) { \
- GLint s = FixedToInt(span.intTex[0]) & smask; \
- GLint t = FixedToInt(span.intTex[1]) & tmask; \
- GLint pos = (t << twidth_log2) + s; \
- pos = pos + pos + pos; /* multiply by 3 */ \
- rgb[i][RCOMP] = texture[pos+2]; \
- rgb[i][GCOMP] = texture[pos+1]; \
- rgb[i][BCOMP] = texture[pos+0]; \
- span.intTex[0] += span.intTexStep[0]; \
- span.intTex[1] += span.intTexStep[1]; \
- } \
- rb->PutRowRGB(ctx, rb, span.end, span.x, span.y, rgb, NULL);
-
-#include "s_tritemp.h"
-
-
-
-/*
- * Render an RGB, GL_DECAL, textured triangle.
- * Interpolate S,T, GL_LESS depth test, w/out mipmapping or
- * perspective correction.
- * Depth buffer bits must be <= sizeof(DEFAULT_SOFTWARE_DEPTH_TYPE)
- *
- * No fog.
- */
-#define NAME simple_z_textured_triangle
-#define INTERP_Z 1
-#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
-#define INTERP_INT_TEX 1
-#define S_SCALE twidth
-#define T_SCALE theight
-
-#define SETUP_CODE \
- struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; \
- const struct gl_texture_object *obj = \
- ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \
- const struct gl_texture_image *texImg = \
- obj->Image[0][obj->BaseLevel]; \
- const GLfloat twidth = (GLfloat) texImg->Width; \
- const GLfloat theight = (GLfloat) texImg->Height; \
- const GLint twidth_log2 = texImg->WidthLog2; \
- const GLubyte *texture = (const GLubyte *) texImg->Data; \
- const GLint smask = texImg->Width - 1; \
- const GLint tmask = texImg->Height - 1; \
- ASSERT(texImg->TexFormat == MESA_FORMAT_RGB888); \
- if (!rb || !texture) { \
- return; \
- }
-
-#define RENDER_SPAN( span ) \
- GLuint i; \
- GLubyte rgb[MAX_WIDTH][3]; \
- span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \
- span.intTex[1] -= FIXED_HALF; \
- for (i = 0; i < span.end; i++) { \
- const GLuint z = FixedToDepth(span.z); \
- if (z < zRow[i]) { \
- GLint s = FixedToInt(span.intTex[0]) & smask; \
- GLint t = FixedToInt(span.intTex[1]) & tmask; \
- GLint pos = (t << twidth_log2) + s; \
- pos = pos + pos + pos; /* multiply by 3 */ \
- rgb[i][RCOMP] = texture[pos+2]; \
- rgb[i][GCOMP] = texture[pos+1]; \
- rgb[i][BCOMP] = texture[pos+0]; \
- zRow[i] = z; \
- span.array->mask[i] = 1; \
- } \
- else { \
- span.array->mask[i] = 0; \
- } \
- span.intTex[0] += span.intTexStep[0]; \
- span.intTex[1] += span.intTexStep[1]; \
- span.z += span.zStep; \
- } \
- rb->PutRowRGB(ctx, rb, span.end, span.x, span.y, rgb, span.array->mask);
-
-#include "s_tritemp.h"
-
-
-#if CHAN_TYPE != GL_FLOAT
-
-struct affine_info
-{
- GLenum filter;
- GLenum format;
- GLenum envmode;
- GLint smask, tmask;
- GLint twidth_log2;
- const GLchan *texture;
- GLfixed er, eg, eb, ea;
- GLint tbytesline, tsize;
-};
-
-
-static INLINE GLint
-ilerp(GLint t, GLint a, GLint b)
-{
- return a + ((t * (b - a)) >> FIXED_SHIFT);
-}
-
-static INLINE GLint
-ilerp_2d(GLint ia, GLint ib, GLint v00, GLint v10, GLint v01, GLint v11)
-{
- const GLint temp0 = ilerp(ia, v00, v10);
- const GLint temp1 = ilerp(ia, v01, v11);
- return ilerp(ib, temp0, temp1);
-}
-
-
-/* This function can handle GL_NEAREST or GL_LINEAR sampling of 2D RGB or RGBA
- * textures with GL_REPLACE, GL_MODULATE, GL_BLEND, GL_DECAL or GL_ADD
- * texture env modes.
- */
-static INLINE void
-affine_span(struct gl_context *ctx, SWspan *span,
- struct affine_info *info)
-{
- GLchan sample[4]; /* the filtered texture sample */
- const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits;
-
- /* Instead of defining a function for each mode, a test is done
- * between the outer and inner loops. This is to reduce code size
- * and complexity. Observe that an optimizing compiler kills
- * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
- */
-
-#define NEAREST_RGB \
- sample[RCOMP] = tex00[2]; \
- sample[GCOMP] = tex00[1]; \
- sample[BCOMP] = tex00[0]; \
- sample[ACOMP] = CHAN_MAX;
-
-#define LINEAR_RGB \
- sample[RCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\
- sample[GCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\
- sample[BCOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0]);\
- sample[ACOMP] = CHAN_MAX;
-
-#define NEAREST_RGBA \
- sample[RCOMP] = tex00[3]; \
- sample[GCOMP] = tex00[2]; \
- sample[BCOMP] = tex00[1]; \
- sample[ACOMP] = tex00[0];
-
-#define LINEAR_RGBA \
- sample[RCOMP] = ilerp_2d(sf, tf, tex00[3], tex01[3], tex10[3], tex11[3]);\
- sample[GCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\
- sample[BCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\
- sample[ACOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0])
-
-#define MODULATE \
- dest[RCOMP] = span->red * (sample[RCOMP] + 1u) >> (FIXED_SHIFT + 8); \
- dest[GCOMP] = span->green * (sample[GCOMP] + 1u) >> (FIXED_SHIFT + 8); \
- dest[BCOMP] = span->blue * (sample[BCOMP] + 1u) >> (FIXED_SHIFT + 8); \
- dest[ACOMP] = span->alpha * (sample[ACOMP] + 1u) >> (FIXED_SHIFT + 8)
-
-#define DECAL \
- dest[RCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->red + \
- ((sample[ACOMP] + 1) * sample[RCOMP] << FIXED_SHIFT)) \
- >> (FIXED_SHIFT + 8); \
- dest[GCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->green + \
- ((sample[ACOMP] + 1) * sample[GCOMP] << FIXED_SHIFT)) \
- >> (FIXED_SHIFT + 8); \
- dest[BCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->blue + \
- ((sample[ACOMP] + 1) * sample[BCOMP] << FIXED_SHIFT)) \
- >> (FIXED_SHIFT + 8); \
- dest[ACOMP] = FixedToInt(span->alpha)
-
-#define BLEND \
- dest[RCOMP] = ((CHAN_MAX - sample[RCOMP]) * span->red \
- + (sample[RCOMP] + 1) * info->er) >> (FIXED_SHIFT + 8); \
- dest[GCOMP] = ((CHAN_MAX - sample[GCOMP]) * span->green \
- + (sample[GCOMP] + 1) * info->eg) >> (FIXED_SHIFT + 8); \
- dest[BCOMP] = ((CHAN_MAX - sample[BCOMP]) * span->blue \
- + (sample[BCOMP] + 1) * info->eb) >> (FIXED_SHIFT + 8); \
- dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8)
-
-#define REPLACE COPY_CHAN4(dest, sample)
-
-#define ADD \
- { \
- GLint rSum = FixedToInt(span->red) + (GLint) sample[RCOMP]; \
- GLint gSum = FixedToInt(span->green) + (GLint) sample[GCOMP]; \
- GLint bSum = FixedToInt(span->blue) + (GLint) sample[BCOMP]; \
- dest[RCOMP] = MIN2(rSum, CHAN_MAX); \
- dest[GCOMP] = MIN2(gSum, CHAN_MAX); \
- dest[BCOMP] = MIN2(bSum, CHAN_MAX); \
- dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8); \
- }
-
-/* shortcuts */
-
-#define NEAREST_RGB_REPLACE \
- NEAREST_RGB; \
- dest[0] = sample[0]; \
- dest[1] = sample[1]; \
- dest[2] = sample[2]; \
- dest[3] = FixedToInt(span->alpha);
-
-#define NEAREST_RGBA_REPLACE \
- dest[RCOMP] = tex00[3]; \
- dest[GCOMP] = tex00[2]; \
- dest[BCOMP] = tex00[1]; \
- dest[ACOMP] = tex00[0]
-
-#define SPAN_NEAREST(DO_TEX, COMPS) \
- for (i = 0; i < span->end; i++) { \
- /* Isn't it necessary to use FixedFloor below?? */ \
- GLint s = FixedToInt(span->intTex[0]) & info->smask; \
- GLint t = FixedToInt(span->intTex[1]) & info->tmask; \
- GLint pos = (t << info->twidth_log2) + s; \
- const GLchan *tex00 = info->texture + COMPS * pos; \
- DO_TEX; \
- span->red += span->redStep; \
- span->green += span->greenStep; \
- span->blue += span->blueStep; \
- span->alpha += span->alphaStep; \
- span->intTex[0] += span->intTexStep[0]; \
- span->intTex[1] += span->intTexStep[1]; \
- dest += 4; \
- }
-
-#define SPAN_LINEAR(DO_TEX, COMPS) \
- for (i = 0; i < span->end; i++) { \
- /* Isn't it necessary to use FixedFloor below?? */ \
- const GLint s = FixedToInt(span->intTex[0]) & info->smask; \
- const GLint t = FixedToInt(span->intTex[1]) & info->tmask; \
- const GLfixed sf = span->intTex[0] & FIXED_FRAC_MASK; \
- const GLfixed tf = span->intTex[1] & FIXED_FRAC_MASK; \
- const GLint pos = (t << info->twidth_log2) + s; \
- const GLchan *tex00 = info->texture + COMPS * pos; \
- const GLchan *tex10 = tex00 + info->tbytesline; \
- const GLchan *tex01 = tex00 + COMPS; \
- const GLchan *tex11 = tex10 + COMPS; \
- if (t == info->tmask) { \
- tex10 -= info->tsize; \
- tex11 -= info->tsize; \
- } \
- if (s == info->smask) { \
- tex01 -= info->tbytesline; \
- tex11 -= info->tbytesline; \
- } \
- DO_TEX; \
- span->red += span->redStep; \
- span->green += span->greenStep; \
- span->blue += span->blueStep; \
- span->alpha += span->alphaStep; \
- span->intTex[0] += span->intTexStep[0]; \
- span->intTex[1] += span->intTexStep[1]; \
- dest += 4; \
- }
-
-
- GLuint i;
- GLchan *dest = span->array->rgba[0];
-
- /* Disable tex units so they're not re-applied in swrast_write_rgba_span */
- ctx->Texture._EnabledCoordUnits = 0x0;
-
- span->intTex[0] -= FIXED_HALF;
- span->intTex[1] -= FIXED_HALF;
- switch (info->filter) {
- case GL_NEAREST:
- switch (info->format) {
- case MESA_FORMAT_RGB888:
- switch (info->envmode) {
- case GL_MODULATE:
- SPAN_NEAREST(NEAREST_RGB;MODULATE,3);
- break;
- case GL_DECAL:
- case GL_REPLACE:
- SPAN_NEAREST(NEAREST_RGB_REPLACE,3);
- break;
- case GL_BLEND:
- SPAN_NEAREST(NEAREST_RGB;BLEND,3);
- break;
- case GL_ADD:
- SPAN_NEAREST(NEAREST_RGB;ADD,3);
- break;
- default:
- _mesa_problem(ctx, "bad tex env mode in SPAN_LINEAR");
- return;
- }
- break;
- case MESA_FORMAT_RGBA8888:
- switch(info->envmode) {
- case GL_MODULATE:
- SPAN_NEAREST(NEAREST_RGBA;MODULATE,4);
- break;
- case GL_DECAL:
- SPAN_NEAREST(NEAREST_RGBA;DECAL,4);
- break;
- case GL_BLEND:
- SPAN_NEAREST(NEAREST_RGBA;BLEND,4);
- break;
- case GL_ADD:
- SPAN_NEAREST(NEAREST_RGBA;ADD,4);
- break;
- case GL_REPLACE:
- SPAN_NEAREST(NEAREST_RGBA_REPLACE,4);
- break;
- default:
- _mesa_problem(ctx, "bad tex env mode (2) in SPAN_LINEAR");
- return;
- }
- break;
- }
- break;
-
- case GL_LINEAR:
- span->intTex[0] -= FIXED_HALF;
- span->intTex[1] -= FIXED_HALF;
- switch (info->format) {
- case MESA_FORMAT_RGB888:
- switch (info->envmode) {
- case GL_MODULATE:
- SPAN_LINEAR(LINEAR_RGB;MODULATE,3);
- break;
- case GL_DECAL:
- case GL_REPLACE:
- SPAN_LINEAR(LINEAR_RGB;REPLACE,3);
- break;
- case GL_BLEND:
- SPAN_LINEAR(LINEAR_RGB;BLEND,3);
- break;
- case GL_ADD:
- SPAN_LINEAR(LINEAR_RGB;ADD,3);
- break;
- default:
- _mesa_problem(ctx, "bad tex env mode (3) in SPAN_LINEAR");
- return;
- }
- break;
- case MESA_FORMAT_RGBA8888:
- switch (info->envmode) {
- case GL_MODULATE:
- SPAN_LINEAR(LINEAR_RGBA;MODULATE,4);
- break;
- case GL_DECAL:
- SPAN_LINEAR(LINEAR_RGBA;DECAL,4);
- break;
- case GL_BLEND:
- SPAN_LINEAR(LINEAR_RGBA;BLEND,4);
- break;
- case GL_ADD:
- SPAN_LINEAR(LINEAR_RGBA;ADD,4);
- break;
- case GL_REPLACE:
- SPAN_LINEAR(LINEAR_RGBA;REPLACE,4);
- break;
- default:
- _mesa_problem(ctx, "bad tex env mode (4) in SPAN_LINEAR");
- return;
- }
- break;
- }
- break;
- }
- span->interpMask &= ~SPAN_RGBA;
- ASSERT(span->arrayMask & SPAN_RGBA);
-
- _swrast_write_rgba_span(ctx, span);
-
- /* re-enable texture units */
- ctx->Texture._EnabledCoordUnits = texEnableSave;
-
-#undef SPAN_NEAREST
-#undef SPAN_LINEAR
-}
-
-
-
-/*
- * Render an RGB/RGBA textured triangle without perspective correction.
- */
-#define NAME affine_textured_triangle
-#define INTERP_Z 1
-#define INTERP_RGB 1
-#define INTERP_ALPHA 1
-#define INTERP_INT_TEX 1
-#define S_SCALE twidth
-#define T_SCALE theight
-
-#define SETUP_CODE \
- struct affine_info info; \
- struct gl_texture_unit *unit = ctx->Texture.Unit+0; \
- const struct gl_texture_object *obj = \
- ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \
- const struct gl_texture_image *texImg = \
- obj->Image[0][obj->BaseLevel]; \
- const GLfloat twidth = (GLfloat) texImg->Width; \
- const GLfloat theight = (GLfloat) texImg->Height; \
- info.texture = (const GLchan *) texImg->Data; \
- info.twidth_log2 = texImg->WidthLog2; \
- info.smask = texImg->Width - 1; \
- info.tmask = texImg->Height - 1; \
- info.format = texImg->TexFormat; \
- info.filter = obj->MinFilter; \
- info.envmode = unit->EnvMode; \
- info.er = 0; \
- info.eg = 0; \
- info.eb = 0; \
- span.arrayMask |= SPAN_RGBA; \
- \
- if (info.envmode == GL_BLEND) { \
- /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \
- info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \
- info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \
- info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \
- info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \
- } \
- if (!info.texture) { \
- /* this shouldn't happen */ \
- return; \
- } \
- \
- switch (info.format) { \
- case MESA_FORMAT_RGB888: \
- info.tbytesline = texImg->Width * 3; \
- break; \
- case MESA_FORMAT_RGBA8888: \
- info.tbytesline = texImg->Width * 4; \
- break; \
- default: \
- _mesa_problem(NULL, "Bad texture format in affine_texture_triangle");\
- return; \
- } \
- info.tsize = texImg->Height * info.tbytesline;
-
-#define RENDER_SPAN( span ) affine_span(ctx, &span, &info);
-
-#include "s_tritemp.h"
-
-
-
-struct persp_info
-{
- GLenum filter;
- GLenum format;
- GLenum envmode;
- GLint smask, tmask;
- GLint twidth_log2;
- const GLchan *texture;
- GLfixed er, eg, eb, ea; /* texture env color */
- GLint tbytesline, tsize;
-};
-
-
-static INLINE void
-fast_persp_span(struct gl_context *ctx, SWspan *span,
- struct persp_info *info)
-{
- GLchan sample[4]; /* the filtered texture sample */
-
- /* Instead of defining a function for each mode, a test is done
- * between the outer and inner loops. This is to reduce code size
- * and complexity. Observe that an optimizing compiler kills
- * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
- */
-#define SPAN_NEAREST(DO_TEX,COMP) \
- for (i = 0; i < span->end; i++) { \
- GLdouble invQ = tex_coord[2] ? \
- (1.0 / tex_coord[2]) : 1.0; \
- GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \
- GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \
- GLint s = IFLOOR(s_tmp) & info->smask; \
- GLint t = IFLOOR(t_tmp) & info->tmask; \
- GLint pos = (t << info->twidth_log2) + s; \
- const GLchan *tex00 = info->texture + COMP * pos; \
- DO_TEX; \
- span->red += span->redStep; \
- span->green += span->greenStep; \
- span->blue += span->blueStep; \
- span->alpha += span->alphaStep; \
- tex_coord[0] += tex_step[0]; \
- tex_coord[1] += tex_step[1]; \
- tex_coord[2] += tex_step[2]; \
- dest += 4; \
- }
-
-#define SPAN_LINEAR(DO_TEX,COMP) \
- for (i = 0; i < span->end; i++) { \
- GLdouble invQ = tex_coord[2] ? \
- (1.0 / tex_coord[2]) : 1.0; \
- const GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \
- const GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \
- const GLfixed s_fix = FloatToFixed(s_tmp) - FIXED_HALF; \
- const GLfixed t_fix = FloatToFixed(t_tmp) - FIXED_HALF; \
- const GLint s = FixedToInt(FixedFloor(s_fix)) & info->smask; \
- const GLint t = FixedToInt(FixedFloor(t_fix)) & info->tmask; \
- const GLfixed sf = s_fix & FIXED_FRAC_MASK; \
- const GLfixed tf = t_fix & FIXED_FRAC_MASK; \
- const GLint pos = (t << info->twidth_log2) + s; \
- const GLchan *tex00 = info->texture + COMP * pos; \
- const GLchan *tex10 = tex00 + info->tbytesline; \
- const GLchan *tex01 = tex00 + COMP; \
- const GLchan *tex11 = tex10 + COMP; \
- if (t == info->tmask) { \
- tex10 -= info->tsize; \
- tex11 -= info->tsize; \
- } \
- if (s == info->smask) { \
- tex01 -= info->tbytesline; \
- tex11 -= info->tbytesline; \
- } \
- DO_TEX; \
- span->red += span->redStep; \
- span->green += span->greenStep; \
- span->blue += span->blueStep; \
- span->alpha += span->alphaStep; \
- tex_coord[0] += tex_step[0]; \
- tex_coord[1] += tex_step[1]; \
- tex_coord[2] += tex_step[2]; \
- dest += 4; \
- }
-
- GLuint i;
- GLfloat tex_coord[3], tex_step[3];
- GLchan *dest = span->array->rgba[0];
-
- const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits;
- ctx->Texture._EnabledCoordUnits = 0;
-
- tex_coord[0] = span->attrStart[FRAG_ATTRIB_TEX0][0] * (info->smask + 1);
- tex_step[0] = span->attrStepX[FRAG_ATTRIB_TEX0][0] * (info->smask + 1);
- tex_coord[1] = span->attrStart[FRAG_ATTRIB_TEX0][1] * (info->tmask + 1);
- tex_step[1] = span->attrStepX[FRAG_ATTRIB_TEX0][1] * (info->tmask + 1);
- /* span->attrStart[FRAG_ATTRIB_TEX0][2] only if 3D-texturing, here only 2D */
- tex_coord[2] = span->attrStart[FRAG_ATTRIB_TEX0][3];
- tex_step[2] = span->attrStepX[FRAG_ATTRIB_TEX0][3];
-
- switch (info->filter) {
- case GL_NEAREST:
- switch (info->format) {
- case MESA_FORMAT_RGB888:
- switch (info->envmode) {
- case GL_MODULATE:
- SPAN_NEAREST(NEAREST_RGB;MODULATE,3);
- break;
- case GL_DECAL:
- case GL_REPLACE:
- SPAN_NEAREST(NEAREST_RGB_REPLACE,3);
- break;
- case GL_BLEND:
- SPAN_NEAREST(NEAREST_RGB;BLEND,3);
- break;
- case GL_ADD:
- SPAN_NEAREST(NEAREST_RGB;ADD,3);
- break;
- default:
- _mesa_problem(ctx, "bad tex env mode (5) in SPAN_LINEAR");
- return;
- }
- break;
- case MESA_FORMAT_RGBA8888:
- switch(info->envmode) {
- case GL_MODULATE:
- SPAN_NEAREST(NEAREST_RGBA;MODULATE,4);
- break;
- case GL_DECAL:
- SPAN_NEAREST(NEAREST_RGBA;DECAL,4);
- break;
- case GL_BLEND:
- SPAN_NEAREST(NEAREST_RGBA;BLEND,4);
- break;
- case GL_ADD:
- SPAN_NEAREST(NEAREST_RGBA;ADD,4);
- break;
- case GL_REPLACE:
- SPAN_NEAREST(NEAREST_RGBA_REPLACE,4);
- break;
- default:
- _mesa_problem(ctx, "bad tex env mode (6) in SPAN_LINEAR");
- return;
- }
- break;
- }
- break;
-
- case GL_LINEAR:
- switch (info->format) {
- case MESA_FORMAT_RGB888:
- switch (info->envmode) {
- case GL_MODULATE:
- SPAN_LINEAR(LINEAR_RGB;MODULATE,3);
- break;
- case GL_DECAL:
- case GL_REPLACE:
- SPAN_LINEAR(LINEAR_RGB;REPLACE,3);
- break;
- case GL_BLEND:
- SPAN_LINEAR(LINEAR_RGB;BLEND,3);
- break;
- case GL_ADD:
- SPAN_LINEAR(LINEAR_RGB;ADD,3);
- break;
- default:
- _mesa_problem(ctx, "bad tex env mode (7) in SPAN_LINEAR");
- return;
- }
- break;
- case MESA_FORMAT_RGBA8888:
- switch (info->envmode) {
- case GL_MODULATE:
- SPAN_LINEAR(LINEAR_RGBA;MODULATE,4);
- break;
- case GL_DECAL:
- SPAN_LINEAR(LINEAR_RGBA;DECAL,4);
- break;
- case GL_BLEND:
- SPAN_LINEAR(LINEAR_RGBA;BLEND,4);
- break;
- case GL_ADD:
- SPAN_LINEAR(LINEAR_RGBA;ADD,4);
- break;
- case GL_REPLACE:
- SPAN_LINEAR(LINEAR_RGBA;REPLACE,4);
- break;
- default:
- _mesa_problem(ctx, "bad tex env mode (8) in SPAN_LINEAR");
- return;
- }
- break;
- }
- break;
- }
-
- ASSERT(span->arrayMask & SPAN_RGBA);
- _swrast_write_rgba_span(ctx, span);
-
-#undef SPAN_NEAREST
-#undef SPAN_LINEAR
-
- /* restore state */
- ctx->Texture._EnabledCoordUnits = texEnableSave;
-}
-
-
-/*
- * Render an perspective corrected RGB/RGBA textured triangle.
- * The Q (aka V in Mesa) coordinate must be zero such that the divide
- * by interpolated Q/W comes out right.
- *
- */
-#define NAME persp_textured_triangle
-#define INTERP_Z 1
-#define INTERP_RGB 1
-#define INTERP_ALPHA 1
-#define INTERP_ATTRIBS 1
-
-#define SETUP_CODE \
- struct persp_info info; \
- const struct gl_texture_unit *unit = ctx->Texture.Unit+0; \
- const struct gl_texture_object *obj = \
- ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \
- const struct gl_texture_image *texImg = \
- obj->Image[0][obj->BaseLevel]; \
- info.texture = (const GLchan *) texImg->Data; \
- info.twidth_log2 = texImg->WidthLog2; \
- info.smask = texImg->Width - 1; \
- info.tmask = texImg->Height - 1; \
- info.format = texImg->TexFormat; \
- info.filter = obj->MinFilter; \
- info.envmode = unit->EnvMode; \
- info.er = 0; \
- info.eg = 0; \
- info.eb = 0; \
- \
- if (info.envmode == GL_BLEND) { \
- /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \
- info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \
- info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \
- info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \
- info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \
- } \
- if (!info.texture) { \
- /* this shouldn't happen */ \
- return; \
- } \
- \
- switch (info.format) { \
- case MESA_FORMAT_RGB888: \
- info.tbytesline = texImg->Width * 3; \
- break; \
- case MESA_FORMAT_RGBA8888: \
- info.tbytesline = texImg->Width * 4; \
- break; \
- default: \
- _mesa_problem(NULL, "Bad texture format in persp_textured_triangle");\
- return; \
- } \
- info.tsize = texImg->Height * info.tbytesline;
-
-#define RENDER_SPAN( span ) \
- span.interpMask &= ~SPAN_RGBA; \
- span.arrayMask |= SPAN_RGBA; \
- fast_persp_span(ctx, &span, &info);
-
-#include "s_tritemp.h"
-
-#endif /*CHAN_TYPE != GL_FLOAT*/
-
-
-
-/*
- * Render an RGBA triangle with arbitrary attributes.
- */
-#define NAME general_triangle
-#define INTERP_Z 1
-#define INTERP_RGB 1
-#define INTERP_ALPHA 1
-#define INTERP_ATTRIBS 1
-#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span);
-#include "s_tritemp.h"
-
-
-
-
-/*
- * Special tri function for occlusion testing
- */
-#define NAME occlusion_zless_triangle
-#define INTERP_Z 1
-#define SETUP_CODE \
- struct gl_renderbuffer *rb = ctx->DrawBuffer->_DepthBuffer; \
- struct gl_query_object *q = ctx->Query.CurrentOcclusionObject; \
- ASSERT(ctx->Depth.Test); \
- ASSERT(!ctx->Depth.Mask); \
- ASSERT(ctx->Depth.Func == GL_LESS); \
- if (!q) { \
- return; \
- }
-#define RENDER_SPAN( span ) \
- if (rb->Format == MESA_FORMAT_Z16) { \
- GLuint i; \
- const GLushort *zRow = (const GLushort *) \
- rb->GetPointer(ctx, rb, span.x, span.y); \
- for (i = 0; i < span.end; i++) { \
- GLuint z = FixedToDepth(span.z); \
- if (z < zRow[i]) { \
- q->Result++; \
- } \
- span.z += span.zStep; \
- } \
- } \
- else { \
- GLuint i; \
- const GLuint *zRow = (const GLuint *) \
- rb->GetPointer(ctx, rb, span.x, span.y); \
- for (i = 0; i < span.end; i++) { \
- if ((GLuint)span.z < zRow[i]) { \
- q->Result++; \
- } \
- span.z += span.zStep; \
- } \
- }
-#include "s_tritemp.h"
-
-
-
-static void
-nodraw_triangle( struct gl_context *ctx,
- const SWvertex *v0,
- const SWvertex *v1,
- const SWvertex *v2 )
-{
- (void) (ctx && v0 && v1 && v2);
-}
-
-
-/*
- * This is used when separate specular color is enabled, but not
- * texturing. We add the specular color to the primary color,
- * draw the triangle, then restore the original primary color.
- * Inefficient, but seldom needed.
- */
-void
-_swrast_add_spec_terms_triangle(struct gl_context *ctx, const SWvertex *v0,
- const SWvertex *v1, const SWvertex *v2)
-{
- SWvertex *ncv0 = (SWvertex *)v0; /* drop const qualifier */
- SWvertex *ncv1 = (SWvertex *)v1;
- SWvertex *ncv2 = (SWvertex *)v2;
- GLfloat rSum, gSum, bSum;
- GLchan cSave[3][4];
-
- /* save original colors */
- COPY_CHAN4( cSave[0], ncv0->color );
- COPY_CHAN4( cSave[1], ncv1->color );
- COPY_CHAN4( cSave[2], ncv2->color );
- /* sum v0 */
- rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0];
- gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1];
- bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2];
- UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
- UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
- UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
- /* sum v1 */
- rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[FRAG_ATTRIB_COL1][0];
- gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[FRAG_ATTRIB_COL1][1];
- bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[FRAG_ATTRIB_COL1][2];
- UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum);
- UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum);
- UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum);
- /* sum v2 */
- rSum = CHAN_TO_FLOAT(ncv2->color[0]) + ncv2->attrib[FRAG_ATTRIB_COL1][0];
- gSum = CHAN_TO_FLOAT(ncv2->color[1]) + ncv2->attrib[FRAG_ATTRIB_COL1][1];
- bSum = CHAN_TO_FLOAT(ncv2->color[2]) + ncv2->attrib[FRAG_ATTRIB_COL1][2];
- UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[0], rSum);
- UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[1], gSum);
- UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[2], bSum);
- /* draw */
- SWRAST_CONTEXT(ctx)->SpecTriangle( ctx, ncv0, ncv1, ncv2 );
- /* restore original colors */
- COPY_CHAN4( ncv0->color, cSave[0] );
- COPY_CHAN4( ncv1->color, cSave[1] );
- COPY_CHAN4( ncv2->color, cSave[2] );
-}
-
-
-
-#ifdef DEBUG
-
-/* record the current triangle function name */
-const char *_mesa_triFuncName = NULL;
-
-#define USE(triFunc) \
-do { \
- _mesa_triFuncName = #triFunc; \
- /*printf("%s\n", _mesa_triFuncName);*/ \
- swrast->Triangle = triFunc; \
-} while (0)
-
-#else
-
-#define USE(triFunc) swrast->Triangle = triFunc;
-
-#endif
-
-
-
-
-/*
- * Determine which triangle rendering function to use given the current
- * rendering context.
- *
- * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or
- * remove tests to this code.
- */
-void
-_swrast_choose_triangle( struct gl_context *ctx )
-{
- SWcontext *swrast = SWRAST_CONTEXT(ctx);
-
- if (ctx->Polygon.CullFlag &&
- ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) {
- USE(nodraw_triangle);
- return;
- }
-
- if (ctx->RenderMode==GL_RENDER) {
-
- if (ctx->Polygon.SmoothFlag) {
- _swrast_set_aa_triangle_function(ctx);
- ASSERT(swrast->Triangle);
- return;
- }
-
- /* special case for occlusion testing */
- if (ctx->Query.CurrentOcclusionObject &&
- ctx->Depth.Test &&
- ctx->Depth.Mask == GL_FALSE &&
- ctx->Depth.Func == GL_LESS &&
- !ctx->Stencil._Enabled) {
- if (ctx->Color.ColorMask[0][0] == 0 &&
- ctx->Color.ColorMask[0][1] == 0 &&
- ctx->Color.ColorMask[0][2] == 0 &&
- ctx->Color.ColorMask[0][3] == 0) {
- USE(occlusion_zless_triangle);
- return;
- }
- }
-
- /*
- * XXX should examine swrast->_ActiveAttribMask to determine what
- * needs to be interpolated.
- */
- if (ctx->Texture._EnabledCoordUnits ||
- ctx->FragmentProgram._Current ||
- ctx->ATIFragmentShader._Enabled ||
- _mesa_need_secondary_color(ctx) ||
- swrast->_FogEnabled) {
- /* Ugh, we do a _lot_ of tests to pick the best textured tri func */
- const struct gl_texture_object *texObj2D;
- const struct gl_texture_image *texImg;
- GLenum minFilter, magFilter, envMode;
- gl_format format;
- texObj2D = ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX];
-
- texImg = texObj2D ? texObj2D->Image[0][texObj2D->BaseLevel] : NULL;
- format = texImg ? texImg->TexFormat : MESA_FORMAT_NONE;
- minFilter = texObj2D ? texObj2D->MinFilter : GL_NONE;
- magFilter = texObj2D ? texObj2D->MagFilter : GL_NONE;
- envMode = ctx->Texture.Unit[0].EnvMode;
-
- /* First see if we can use an optimized 2-D texture function */
- if (ctx->Texture._EnabledCoordUnits == 0x1
- && !ctx->FragmentProgram._Current
- && !ctx->ATIFragmentShader._Enabled
- && ctx->Texture._EnabledUnits == 0x1
- && ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT
- && texObj2D->WrapS == GL_REPEAT
- && texObj2D->WrapT == GL_REPEAT
- && texObj2D->_Swizzle == SWIZZLE_NOOP
- && texImg->_IsPowerOfTwo
- && texImg->Border == 0
- && texImg->Width == texImg->RowStride
- && (format == MESA_FORMAT_RGB888 || format == MESA_FORMAT_RGBA8888)
- && minFilter == magFilter
- && ctx->Light.Model.ColorControl == GL_SINGLE_COLOR
- && !swrast->_FogEnabled
- && ctx->Texture.Unit[0].EnvMode != GL_COMBINE_EXT
- && ctx->Texture.Unit[0].EnvMode != GL_COMBINE4_NV) {
- if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) {
- if (minFilter == GL_NEAREST
- && format == MESA_FORMAT_RGB888
- && (envMode == GL_REPLACE || envMode == GL_DECAL)
- && ((swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)
- && ctx->Depth.Func == GL_LESS
- && ctx->Depth.Mask == GL_TRUE)
- || swrast->_RasterMask == TEXTURE_BIT)
- && ctx->Polygon.StippleFlag == GL_FALSE
- && ctx->DrawBuffer->Visual.depthBits <= 16) {
- if (swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)) {
- USE(simple_z_textured_triangle);
- }
- else {
- USE(simple_textured_triangle);
- }
- }
- else {
-#if CHAN_BITS != 8
- USE(general_triangle);
-#else
- if (format == MESA_FORMAT_RGBA8888 && !_mesa_little_endian()) {
- /* We only handle RGBA8888 correctly on little endian
- * in the optimized code above.
- */
- USE(general_triangle);
- }
- else {
- USE(affine_textured_triangle);
- }
-#endif
- }
- }
- else {
-#if CHAN_BITS != 8
- USE(general_triangle);
-#else
- USE(persp_textured_triangle);
-#endif
- }
- }
- else {
- /* general case textured triangles */
- USE(general_triangle);
- }
- }
- else {
- ASSERT(!swrast->_FogEnabled);
- ASSERT(!_mesa_need_secondary_color(ctx));
- if (ctx->Light.ShadeModel==GL_SMOOTH) {
- /* smooth shaded, no texturing, stippled or some raster ops */
-#if CHAN_BITS != 8
- USE(general_triangle);
-#else
- USE(smooth_rgba_triangle);
-#endif
- }
- else {
- /* flat shaded, no texturing, stippled or some raster ops */
-#if CHAN_BITS != 8
- USE(general_triangle);
-#else
- USE(flat_rgba_triangle);
-#endif
- }
- }
- }
- else if (ctx->RenderMode==GL_FEEDBACK) {
- USE(_swrast_feedback_triangle);
- }
- else {
- /* GL_SELECT mode */
- USE(_swrast_select_triangle);
- }
-}
+/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * 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. + */ + + +/* + * When the device driver doesn't implement triangle rasterization it + * can hook in _swrast_Triangle, which eventually calls one of these + * functions to draw triangles. + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/colormac.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/mtypes.h" +#include "main/state.h" +#include "program/prog_instruction.h" + +#include "s_aatriangle.h" +#include "s_context.h" +#include "s_feedback.h" +#include "s_span.h" +#include "s_triangle.h" + + +/** + * Test if a triangle should be culled. Used for feedback and selection mode. + * \return GL_TRUE if the triangle is to be culled, GL_FALSE otherwise. + */ +GLboolean +_swrast_culltriangle( struct gl_context *ctx, + const SWvertex *v0, + const SWvertex *v1, + const SWvertex *v2 ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + GLfloat ex = v1->attrib[FRAG_ATTRIB_WPOS][0] - v0->attrib[FRAG_ATTRIB_WPOS][0]; + GLfloat ey = v1->attrib[FRAG_ATTRIB_WPOS][1] - v0->attrib[FRAG_ATTRIB_WPOS][1]; + GLfloat fx = v2->attrib[FRAG_ATTRIB_WPOS][0] - v0->attrib[FRAG_ATTRIB_WPOS][0]; + GLfloat fy = v2->attrib[FRAG_ATTRIB_WPOS][1] - v0->attrib[FRAG_ATTRIB_WPOS][1]; + GLfloat c = ex*fy-ey*fx; + + if (c * swrast->_BackfaceSign * swrast->_BackfaceCullSign <= 0.0F) + return GL_FALSE; + + return GL_TRUE; +} + + + +/* + * Render a flat-shaded RGBA triangle. + */ +#define NAME flat_rgba_triangle +#define INTERP_Z 1 +#define SETUP_CODE \ + ASSERT(ctx->Texture._EnabledCoordUnits == 0);\ + ASSERT(ctx->Light.ShadeModel==GL_FLAT); \ + span.interpMask |= SPAN_RGBA; \ + span.red = ChanToFixed(v2->color[0]); \ + span.green = ChanToFixed(v2->color[1]); \ + span.blue = ChanToFixed(v2->color[2]); \ + span.alpha = ChanToFixed(v2->color[3]); \ + span.redStep = 0; \ + span.greenStep = 0; \ + span.blueStep = 0; \ + span.alphaStep = 0; +#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); +#include "s_tritemp.h" + + + +/* + * Render a smooth-shaded RGBA triangle. + */ +#define NAME smooth_rgba_triangle +#define INTERP_Z 1 +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define SETUP_CODE \ + { \ + /* texturing must be off */ \ + ASSERT(ctx->Texture._EnabledCoordUnits == 0); \ + ASSERT(ctx->Light.ShadeModel==GL_SMOOTH); \ + } +#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); +#include "s_tritemp.h" + + + +/* + * Render an RGB, GL_DECAL, textured triangle. + * Interpolate S,T only w/out mipmapping or perspective correction. + * + * No fog. No depth testing. + */ +#define NAME simple_textured_triangle +#define INTERP_INT_TEX 1 +#define S_SCALE twidth +#define T_SCALE theight + +#define SETUP_CODE \ + struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; \ + const struct gl_texture_object *obj = \ + ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \ + const struct gl_texture_image *texImg = \ + obj->Image[0][obj->BaseLevel]; \ + const GLfloat twidth = (GLfloat) texImg->Width; \ + const GLfloat theight = (GLfloat) texImg->Height; \ + const GLint twidth_log2 = texImg->WidthLog2; \ + const GLubyte *texture = (const GLubyte *) texImg->Data; \ + const GLint smask = texImg->Width - 1; \ + const GLint tmask = texImg->Height - 1; \ + ASSERT(texImg->TexFormat == MESA_FORMAT_RGB888); \ + if (!rb || !texture) { \ + return; \ + } + +#define RENDER_SPAN( span ) \ + GLuint i; \ + GLubyte rgb[MAX_WIDTH][3]; \ + span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \ + span.intTex[1] -= FIXED_HALF; \ + for (i = 0; i < span.end; i++) { \ + GLint s = FixedToInt(span.intTex[0]) & smask; \ + GLint t = FixedToInt(span.intTex[1]) & tmask; \ + GLint pos = (t << twidth_log2) + s; \ + pos = pos + pos + pos; /* multiply by 3 */ \ + rgb[i][RCOMP] = texture[pos+2]; \ + rgb[i][GCOMP] = texture[pos+1]; \ + rgb[i][BCOMP] = texture[pos+0]; \ + span.intTex[0] += span.intTexStep[0]; \ + span.intTex[1] += span.intTexStep[1]; \ + } \ + rb->PutRowRGB(ctx, rb, span.end, span.x, span.y, rgb, NULL); + +#include "s_tritemp.h" + + + +/* + * Render an RGB, GL_DECAL, textured triangle. + * Interpolate S,T, GL_LESS depth test, w/out mipmapping or + * perspective correction. + * Depth buffer bits must be <= sizeof(DEFAULT_SOFTWARE_DEPTH_TYPE) + * + * No fog. + */ +#define NAME simple_z_textured_triangle +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_INT_TEX 1 +#define S_SCALE twidth +#define T_SCALE theight + +#define SETUP_CODE \ + struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; \ + const struct gl_texture_object *obj = \ + ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \ + const struct gl_texture_image *texImg = \ + obj->Image[0][obj->BaseLevel]; \ + const GLfloat twidth = (GLfloat) texImg->Width; \ + const GLfloat theight = (GLfloat) texImg->Height; \ + const GLint twidth_log2 = texImg->WidthLog2; \ + const GLubyte *texture = (const GLubyte *) texImg->Data; \ + const GLint smask = texImg->Width - 1; \ + const GLint tmask = texImg->Height - 1; \ + ASSERT(texImg->TexFormat == MESA_FORMAT_RGB888); \ + if (!rb || !texture) { \ + return; \ + } + +#define RENDER_SPAN( span ) \ + GLuint i; \ + GLubyte rgb[MAX_WIDTH][3]; \ + span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \ + span.intTex[1] -= FIXED_HALF; \ + for (i = 0; i < span.end; i++) { \ + const GLuint z = FixedToDepth(span.z); \ + if (z < zRow[i]) { \ + GLint s = FixedToInt(span.intTex[0]) & smask; \ + GLint t = FixedToInt(span.intTex[1]) & tmask; \ + GLint pos = (t << twidth_log2) + s; \ + pos = pos + pos + pos; /* multiply by 3 */ \ + rgb[i][RCOMP] = texture[pos+2]; \ + rgb[i][GCOMP] = texture[pos+1]; \ + rgb[i][BCOMP] = texture[pos+0]; \ + zRow[i] = z; \ + span.array->mask[i] = 1; \ + } \ + else { \ + span.array->mask[i] = 0; \ + } \ + span.intTex[0] += span.intTexStep[0]; \ + span.intTex[1] += span.intTexStep[1]; \ + span.z += span.zStep; \ + } \ + rb->PutRowRGB(ctx, rb, span.end, span.x, span.y, rgb, span.array->mask); + +#include "s_tritemp.h" + + +#if CHAN_TYPE != GL_FLOAT + +struct affine_info +{ + GLenum filter; + GLenum format; + GLenum envmode; + GLint smask, tmask; + GLint twidth_log2; + const GLchan *texture; + GLfixed er, eg, eb, ea; + GLint tbytesline, tsize; +}; + + +static INLINE GLint +ilerp(GLint t, GLint a, GLint b) +{ + return a + ((t * (b - a)) >> FIXED_SHIFT); +} + +static INLINE GLint +ilerp_2d(GLint ia, GLint ib, GLint v00, GLint v10, GLint v01, GLint v11) +{ + const GLint temp0 = ilerp(ia, v00, v10); + const GLint temp1 = ilerp(ia, v01, v11); + return ilerp(ib, temp0, temp1); +} + + +/* This function can handle GL_NEAREST or GL_LINEAR sampling of 2D RGB or RGBA + * textures with GL_REPLACE, GL_MODULATE, GL_BLEND, GL_DECAL or GL_ADD + * texture env modes. + */ +static INLINE void +affine_span(struct gl_context *ctx, SWspan *span, + struct affine_info *info) +{ + GLchan sample[4]; /* the filtered texture sample */ + const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits; + + /* Instead of defining a function for each mode, a test is done + * between the outer and inner loops. This is to reduce code size + * and complexity. Observe that an optimizing compiler kills + * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST). + */ + +#define NEAREST_RGB \ + sample[RCOMP] = tex00[2]; \ + sample[GCOMP] = tex00[1]; \ + sample[BCOMP] = tex00[0]; \ + sample[ACOMP] = CHAN_MAX; + +#define LINEAR_RGB \ + sample[RCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\ + sample[GCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\ + sample[BCOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0]);\ + sample[ACOMP] = CHAN_MAX; + +#define NEAREST_RGBA \ + sample[RCOMP] = tex00[3]; \ + sample[GCOMP] = tex00[2]; \ + sample[BCOMP] = tex00[1]; \ + sample[ACOMP] = tex00[0]; + +#define LINEAR_RGBA \ + sample[RCOMP] = ilerp_2d(sf, tf, tex00[3], tex01[3], tex10[3], tex11[3]);\ + sample[GCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\ + sample[BCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\ + sample[ACOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0]) + +#define MODULATE \ + dest[RCOMP] = span->red * (sample[RCOMP] + 1u) >> (FIXED_SHIFT + 8); \ + dest[GCOMP] = span->green * (sample[GCOMP] + 1u) >> (FIXED_SHIFT + 8); \ + dest[BCOMP] = span->blue * (sample[BCOMP] + 1u) >> (FIXED_SHIFT + 8); \ + dest[ACOMP] = span->alpha * (sample[ACOMP] + 1u) >> (FIXED_SHIFT + 8) + +#define DECAL \ + dest[RCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->red + \ + ((sample[ACOMP] + 1) * sample[RCOMP] << FIXED_SHIFT)) \ + >> (FIXED_SHIFT + 8); \ + dest[GCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->green + \ + ((sample[ACOMP] + 1) * sample[GCOMP] << FIXED_SHIFT)) \ + >> (FIXED_SHIFT + 8); \ + dest[BCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->blue + \ + ((sample[ACOMP] + 1) * sample[BCOMP] << FIXED_SHIFT)) \ + >> (FIXED_SHIFT + 8); \ + dest[ACOMP] = FixedToInt(span->alpha) + +#define BLEND \ + dest[RCOMP] = ((CHAN_MAX - sample[RCOMP]) * span->red \ + + (sample[RCOMP] + 1) * info->er) >> (FIXED_SHIFT + 8); \ + dest[GCOMP] = ((CHAN_MAX - sample[GCOMP]) * span->green \ + + (sample[GCOMP] + 1) * info->eg) >> (FIXED_SHIFT + 8); \ + dest[BCOMP] = ((CHAN_MAX - sample[BCOMP]) * span->blue \ + + (sample[BCOMP] + 1) * info->eb) >> (FIXED_SHIFT + 8); \ + dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8) + +#define REPLACE COPY_CHAN4(dest, sample) + +#define ADD \ + { \ + GLint rSum = FixedToInt(span->red) + (GLint) sample[RCOMP]; \ + GLint gSum = FixedToInt(span->green) + (GLint) sample[GCOMP]; \ + GLint bSum = FixedToInt(span->blue) + (GLint) sample[BCOMP]; \ + dest[RCOMP] = MIN2(rSum, CHAN_MAX); \ + dest[GCOMP] = MIN2(gSum, CHAN_MAX); \ + dest[BCOMP] = MIN2(bSum, CHAN_MAX); \ + dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8); \ + } + +/* shortcuts */ + +#define NEAREST_RGB_REPLACE \ + NEAREST_RGB; \ + dest[0] = sample[0]; \ + dest[1] = sample[1]; \ + dest[2] = sample[2]; \ + dest[3] = FixedToInt(span->alpha); + +#define NEAREST_RGBA_REPLACE \ + dest[RCOMP] = tex00[3]; \ + dest[GCOMP] = tex00[2]; \ + dest[BCOMP] = tex00[1]; \ + dest[ACOMP] = tex00[0] + +#define SPAN_NEAREST(DO_TEX, COMPS) \ + for (i = 0; i < span->end; i++) { \ + /* Isn't it necessary to use FixedFloor below?? */ \ + GLint s = FixedToInt(span->intTex[0]) & info->smask; \ + GLint t = FixedToInt(span->intTex[1]) & info->tmask; \ + GLint pos = (t << info->twidth_log2) + s; \ + const GLchan *tex00 = info->texture + COMPS * pos; \ + DO_TEX; \ + span->red += span->redStep; \ + span->green += span->greenStep; \ + span->blue += span->blueStep; \ + span->alpha += span->alphaStep; \ + span->intTex[0] += span->intTexStep[0]; \ + span->intTex[1] += span->intTexStep[1]; \ + dest += 4; \ + } + +#define SPAN_LINEAR(DO_TEX, COMPS) \ + for (i = 0; i < span->end; i++) { \ + /* Isn't it necessary to use FixedFloor below?? */ \ + const GLint s = FixedToInt(span->intTex[0]) & info->smask; \ + const GLint t = FixedToInt(span->intTex[1]) & info->tmask; \ + const GLfixed sf = span->intTex[0] & FIXED_FRAC_MASK; \ + const GLfixed tf = span->intTex[1] & FIXED_FRAC_MASK; \ + const GLint pos = (t << info->twidth_log2) + s; \ + const GLchan *tex00 = info->texture + COMPS * pos; \ + const GLchan *tex10 = tex00 + info->tbytesline; \ + const GLchan *tex01 = tex00 + COMPS; \ + const GLchan *tex11 = tex10 + COMPS; \ + if (t == info->tmask) { \ + tex10 -= info->tsize; \ + tex11 -= info->tsize; \ + } \ + if (s == info->smask) { \ + tex01 -= info->tbytesline; \ + tex11 -= info->tbytesline; \ + } \ + DO_TEX; \ + span->red += span->redStep; \ + span->green += span->greenStep; \ + span->blue += span->blueStep; \ + span->alpha += span->alphaStep; \ + span->intTex[0] += span->intTexStep[0]; \ + span->intTex[1] += span->intTexStep[1]; \ + dest += 4; \ + } + + + GLuint i; + GLchan *dest = span->array->rgba[0]; + + /* Disable tex units so they're not re-applied in swrast_write_rgba_span */ + ctx->Texture._EnabledCoordUnits = 0x0; + + span->intTex[0] -= FIXED_HALF; + span->intTex[1] -= FIXED_HALF; + switch (info->filter) { + case GL_NEAREST: + switch (info->format) { + case MESA_FORMAT_RGB888: + switch (info->envmode) { + case GL_MODULATE: + SPAN_NEAREST(NEAREST_RGB;MODULATE,3); + break; + case GL_DECAL: + case GL_REPLACE: + SPAN_NEAREST(NEAREST_RGB_REPLACE,3); + break; + case GL_BLEND: + SPAN_NEAREST(NEAREST_RGB;BLEND,3); + break; + case GL_ADD: + SPAN_NEAREST(NEAREST_RGB;ADD,3); + break; + default: + _mesa_problem(ctx, "bad tex env mode in SPAN_LINEAR"); + return; + } + break; + case MESA_FORMAT_RGBA8888: + switch(info->envmode) { + case GL_MODULATE: + SPAN_NEAREST(NEAREST_RGBA;MODULATE,4); + break; + case GL_DECAL: + SPAN_NEAREST(NEAREST_RGBA;DECAL,4); + break; + case GL_BLEND: + SPAN_NEAREST(NEAREST_RGBA;BLEND,4); + break; + case GL_ADD: + SPAN_NEAREST(NEAREST_RGBA;ADD,4); + break; + case GL_REPLACE: + SPAN_NEAREST(NEAREST_RGBA_REPLACE,4); + break; + default: + _mesa_problem(ctx, "bad tex env mode (2) in SPAN_LINEAR"); + return; + } + break; + } + break; + + case GL_LINEAR: + span->intTex[0] -= FIXED_HALF; + span->intTex[1] -= FIXED_HALF; + switch (info->format) { + case MESA_FORMAT_RGB888: + switch (info->envmode) { + case GL_MODULATE: + SPAN_LINEAR(LINEAR_RGB;MODULATE,3); + break; + case GL_DECAL: + case GL_REPLACE: + SPAN_LINEAR(LINEAR_RGB;REPLACE,3); + break; + case GL_BLEND: + SPAN_LINEAR(LINEAR_RGB;BLEND,3); + break; + case GL_ADD: + SPAN_LINEAR(LINEAR_RGB;ADD,3); + break; + default: + _mesa_problem(ctx, "bad tex env mode (3) in SPAN_LINEAR"); + return; + } + break; + case MESA_FORMAT_RGBA8888: + switch (info->envmode) { + case GL_MODULATE: + SPAN_LINEAR(LINEAR_RGBA;MODULATE,4); + break; + case GL_DECAL: + SPAN_LINEAR(LINEAR_RGBA;DECAL,4); + break; + case GL_BLEND: + SPAN_LINEAR(LINEAR_RGBA;BLEND,4); + break; + case GL_ADD: + SPAN_LINEAR(LINEAR_RGBA;ADD,4); + break; + case GL_REPLACE: + SPAN_LINEAR(LINEAR_RGBA;REPLACE,4); + break; + default: + _mesa_problem(ctx, "bad tex env mode (4) in SPAN_LINEAR"); + return; + } + break; + } + break; + } + span->interpMask &= ~SPAN_RGBA; + ASSERT(span->arrayMask & SPAN_RGBA); + + _swrast_write_rgba_span(ctx, span); + + /* re-enable texture units */ + ctx->Texture._EnabledCoordUnits = texEnableSave; + +#undef SPAN_NEAREST +#undef SPAN_LINEAR +} + + + +/* + * Render an RGB/RGBA textured triangle without perspective correction. + */ +#define NAME affine_textured_triangle +#define INTERP_Z 1 +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define INTERP_INT_TEX 1 +#define S_SCALE twidth +#define T_SCALE theight + +#define SETUP_CODE \ + struct affine_info info; \ + struct gl_texture_unit *unit = ctx->Texture.Unit+0; \ + const struct gl_texture_object *obj = \ + ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \ + const struct gl_texture_image *texImg = \ + obj->Image[0][obj->BaseLevel]; \ + const GLfloat twidth = (GLfloat) texImg->Width; \ + const GLfloat theight = (GLfloat) texImg->Height; \ + info.texture = (const GLchan *) texImg->Data; \ + info.twidth_log2 = texImg->WidthLog2; \ + info.smask = texImg->Width - 1; \ + info.tmask = texImg->Height - 1; \ + info.format = texImg->TexFormat; \ + info.filter = obj->Sampler.MinFilter; \ + info.envmode = unit->EnvMode; \ + info.er = 0; \ + info.eg = 0; \ + info.eb = 0; \ + span.arrayMask |= SPAN_RGBA; \ + \ + if (info.envmode == GL_BLEND) { \ + /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \ + info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \ + info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \ + info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \ + info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \ + } \ + if (!info.texture) { \ + /* this shouldn't happen */ \ + return; \ + } \ + \ + switch (info.format) { \ + case MESA_FORMAT_RGB888: \ + info.tbytesline = texImg->Width * 3; \ + break; \ + case MESA_FORMAT_RGBA8888: \ + info.tbytesline = texImg->Width * 4; \ + break; \ + default: \ + _mesa_problem(NULL, "Bad texture format in affine_texture_triangle");\ + return; \ + } \ + info.tsize = texImg->Height * info.tbytesline; + +#define RENDER_SPAN( span ) affine_span(ctx, &span, &info); + +#include "s_tritemp.h" + + + +struct persp_info +{ + GLenum filter; + GLenum format; + GLenum envmode; + GLint smask, tmask; + GLint twidth_log2; + const GLchan *texture; + GLfixed er, eg, eb, ea; /* texture env color */ + GLint tbytesline, tsize; +}; + + +static INLINE void +fast_persp_span(struct gl_context *ctx, SWspan *span, + struct persp_info *info) +{ + GLchan sample[4]; /* the filtered texture sample */ + + /* Instead of defining a function for each mode, a test is done + * between the outer and inner loops. This is to reduce code size + * and complexity. Observe that an optimizing compiler kills + * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST). + */ +#define SPAN_NEAREST(DO_TEX,COMP) \ + for (i = 0; i < span->end; i++) { \ + GLdouble invQ = tex_coord[2] ? \ + (1.0 / tex_coord[2]) : 1.0; \ + GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \ + GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \ + GLint s = IFLOOR(s_tmp) & info->smask; \ + GLint t = IFLOOR(t_tmp) & info->tmask; \ + GLint pos = (t << info->twidth_log2) + s; \ + const GLchan *tex00 = info->texture + COMP * pos; \ + DO_TEX; \ + span->red += span->redStep; \ + span->green += span->greenStep; \ + span->blue += span->blueStep; \ + span->alpha += span->alphaStep; \ + tex_coord[0] += tex_step[0]; \ + tex_coord[1] += tex_step[1]; \ + tex_coord[2] += tex_step[2]; \ + dest += 4; \ + } + +#define SPAN_LINEAR(DO_TEX,COMP) \ + for (i = 0; i < span->end; i++) { \ + GLdouble invQ = tex_coord[2] ? \ + (1.0 / tex_coord[2]) : 1.0; \ + const GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \ + const GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \ + const GLfixed s_fix = FloatToFixed(s_tmp) - FIXED_HALF; \ + const GLfixed t_fix = FloatToFixed(t_tmp) - FIXED_HALF; \ + const GLint s = FixedToInt(FixedFloor(s_fix)) & info->smask; \ + const GLint t = FixedToInt(FixedFloor(t_fix)) & info->tmask; \ + const GLfixed sf = s_fix & FIXED_FRAC_MASK; \ + const GLfixed tf = t_fix & FIXED_FRAC_MASK; \ + const GLint pos = (t << info->twidth_log2) + s; \ + const GLchan *tex00 = info->texture + COMP * pos; \ + const GLchan *tex10 = tex00 + info->tbytesline; \ + const GLchan *tex01 = tex00 + COMP; \ + const GLchan *tex11 = tex10 + COMP; \ + if (t == info->tmask) { \ + tex10 -= info->tsize; \ + tex11 -= info->tsize; \ + } \ + if (s == info->smask) { \ + tex01 -= info->tbytesline; \ + tex11 -= info->tbytesline; \ + } \ + DO_TEX; \ + span->red += span->redStep; \ + span->green += span->greenStep; \ + span->blue += span->blueStep; \ + span->alpha += span->alphaStep; \ + tex_coord[0] += tex_step[0]; \ + tex_coord[1] += tex_step[1]; \ + tex_coord[2] += tex_step[2]; \ + dest += 4; \ + } + + GLuint i; + GLfloat tex_coord[3], tex_step[3]; + GLchan *dest = span->array->rgba[0]; + + const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits; + ctx->Texture._EnabledCoordUnits = 0; + + tex_coord[0] = span->attrStart[FRAG_ATTRIB_TEX0][0] * (info->smask + 1); + tex_step[0] = span->attrStepX[FRAG_ATTRIB_TEX0][0] * (info->smask + 1); + tex_coord[1] = span->attrStart[FRAG_ATTRIB_TEX0][1] * (info->tmask + 1); + tex_step[1] = span->attrStepX[FRAG_ATTRIB_TEX0][1] * (info->tmask + 1); + /* span->attrStart[FRAG_ATTRIB_TEX0][2] only if 3D-texturing, here only 2D */ + tex_coord[2] = span->attrStart[FRAG_ATTRIB_TEX0][3]; + tex_step[2] = span->attrStepX[FRAG_ATTRIB_TEX0][3]; + + switch (info->filter) { + case GL_NEAREST: + switch (info->format) { + case MESA_FORMAT_RGB888: + switch (info->envmode) { + case GL_MODULATE: + SPAN_NEAREST(NEAREST_RGB;MODULATE,3); + break; + case GL_DECAL: + case GL_REPLACE: + SPAN_NEAREST(NEAREST_RGB_REPLACE,3); + break; + case GL_BLEND: + SPAN_NEAREST(NEAREST_RGB;BLEND,3); + break; + case GL_ADD: + SPAN_NEAREST(NEAREST_RGB;ADD,3); + break; + default: + _mesa_problem(ctx, "bad tex env mode (5) in SPAN_LINEAR"); + return; + } + break; + case MESA_FORMAT_RGBA8888: + switch(info->envmode) { + case GL_MODULATE: + SPAN_NEAREST(NEAREST_RGBA;MODULATE,4); + break; + case GL_DECAL: + SPAN_NEAREST(NEAREST_RGBA;DECAL,4); + break; + case GL_BLEND: + SPAN_NEAREST(NEAREST_RGBA;BLEND,4); + break; + case GL_ADD: + SPAN_NEAREST(NEAREST_RGBA;ADD,4); + break; + case GL_REPLACE: + SPAN_NEAREST(NEAREST_RGBA_REPLACE,4); + break; + default: + _mesa_problem(ctx, "bad tex env mode (6) in SPAN_LINEAR"); + return; + } + break; + } + break; + + case GL_LINEAR: + switch (info->format) { + case MESA_FORMAT_RGB888: + switch (info->envmode) { + case GL_MODULATE: + SPAN_LINEAR(LINEAR_RGB;MODULATE,3); + break; + case GL_DECAL: + case GL_REPLACE: + SPAN_LINEAR(LINEAR_RGB;REPLACE,3); + break; + case GL_BLEND: + SPAN_LINEAR(LINEAR_RGB;BLEND,3); + break; + case GL_ADD: + SPAN_LINEAR(LINEAR_RGB;ADD,3); + break; + default: + _mesa_problem(ctx, "bad tex env mode (7) in SPAN_LINEAR"); + return; + } + break; + case MESA_FORMAT_RGBA8888: + switch (info->envmode) { + case GL_MODULATE: + SPAN_LINEAR(LINEAR_RGBA;MODULATE,4); + break; + case GL_DECAL: + SPAN_LINEAR(LINEAR_RGBA;DECAL,4); + break; + case GL_BLEND: + SPAN_LINEAR(LINEAR_RGBA;BLEND,4); + break; + case GL_ADD: + SPAN_LINEAR(LINEAR_RGBA;ADD,4); + break; + case GL_REPLACE: + SPAN_LINEAR(LINEAR_RGBA;REPLACE,4); + break; + default: + _mesa_problem(ctx, "bad tex env mode (8) in SPAN_LINEAR"); + return; + } + break; + } + break; + } + + ASSERT(span->arrayMask & SPAN_RGBA); + _swrast_write_rgba_span(ctx, span); + +#undef SPAN_NEAREST +#undef SPAN_LINEAR + + /* restore state */ + ctx->Texture._EnabledCoordUnits = texEnableSave; +} + + +/* + * Render an perspective corrected RGB/RGBA textured triangle. + * The Q (aka V in Mesa) coordinate must be zero such that the divide + * by interpolated Q/W comes out right. + * + */ +#define NAME persp_textured_triangle +#define INTERP_Z 1 +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define INTERP_ATTRIBS 1 + +#define SETUP_CODE \ + struct persp_info info; \ + const struct gl_texture_unit *unit = ctx->Texture.Unit+0; \ + const struct gl_texture_object *obj = \ + ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \ + const struct gl_texture_image *texImg = \ + obj->Image[0][obj->BaseLevel]; \ + info.texture = (const GLchan *) texImg->Data; \ + info.twidth_log2 = texImg->WidthLog2; \ + info.smask = texImg->Width - 1; \ + info.tmask = texImg->Height - 1; \ + info.format = texImg->TexFormat; \ + info.filter = obj->Sampler.MinFilter; \ + info.envmode = unit->EnvMode; \ + info.er = 0; \ + info.eg = 0; \ + info.eb = 0; \ + \ + if (info.envmode == GL_BLEND) { \ + /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \ + info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \ + info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \ + info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \ + info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \ + } \ + if (!info.texture) { \ + /* this shouldn't happen */ \ + return; \ + } \ + \ + switch (info.format) { \ + case MESA_FORMAT_RGB888: \ + info.tbytesline = texImg->Width * 3; \ + break; \ + case MESA_FORMAT_RGBA8888: \ + info.tbytesline = texImg->Width * 4; \ + break; \ + default: \ + _mesa_problem(NULL, "Bad texture format in persp_textured_triangle");\ + return; \ + } \ + info.tsize = texImg->Height * info.tbytesline; + +#define RENDER_SPAN( span ) \ + span.interpMask &= ~SPAN_RGBA; \ + span.arrayMask |= SPAN_RGBA; \ + fast_persp_span(ctx, &span, &info); + +#include "s_tritemp.h" + +#endif /*CHAN_TYPE != GL_FLOAT*/ + + + +/* + * Render an RGBA triangle with arbitrary attributes. + */ +#define NAME general_triangle +#define INTERP_Z 1 +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define INTERP_ATTRIBS 1 +#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); +#include "s_tritemp.h" + + + + +/* + * Special tri function for occlusion testing + */ +#define NAME occlusion_zless_triangle +#define INTERP_Z 1 +#define SETUP_CODE \ + struct gl_renderbuffer *rb = ctx->DrawBuffer->_DepthBuffer; \ + struct gl_query_object *q = ctx->Query.CurrentOcclusionObject; \ + ASSERT(ctx->Depth.Test); \ + ASSERT(!ctx->Depth.Mask); \ + ASSERT(ctx->Depth.Func == GL_LESS); \ + if (!q) { \ + return; \ + } +#define RENDER_SPAN( span ) \ + if (rb->Format == MESA_FORMAT_Z16) { \ + GLuint i; \ + const GLushort *zRow = (const GLushort *) \ + rb->GetPointer(ctx, rb, span.x, span.y); \ + for (i = 0; i < span.end; i++) { \ + GLuint z = FixedToDepth(span.z); \ + if (z < zRow[i]) { \ + q->Result++; \ + } \ + span.z += span.zStep; \ + } \ + } \ + else { \ + GLuint i; \ + const GLuint *zRow = (const GLuint *) \ + rb->GetPointer(ctx, rb, span.x, span.y); \ + for (i = 0; i < span.end; i++) { \ + if ((GLuint)span.z < zRow[i]) { \ + q->Result++; \ + } \ + span.z += span.zStep; \ + } \ + } +#include "s_tritemp.h" + + + +static void +nodraw_triangle( struct gl_context *ctx, + const SWvertex *v0, + const SWvertex *v1, + const SWvertex *v2 ) +{ + (void) (ctx && v0 && v1 && v2); +} + + +/* + * This is used when separate specular color is enabled, but not + * texturing. We add the specular color to the primary color, + * draw the triangle, then restore the original primary color. + * Inefficient, but seldom needed. + */ +void +_swrast_add_spec_terms_triangle(struct gl_context *ctx, const SWvertex *v0, + const SWvertex *v1, const SWvertex *v2) +{ + SWvertex *ncv0 = (SWvertex *)v0; /* drop const qualifier */ + SWvertex *ncv1 = (SWvertex *)v1; + SWvertex *ncv2 = (SWvertex *)v2; + GLfloat rSum, gSum, bSum; + GLchan cSave[3][4]; + + /* save original colors */ + COPY_CHAN4( cSave[0], ncv0->color ); + COPY_CHAN4( cSave[1], ncv1->color ); + COPY_CHAN4( cSave[2], ncv2->color ); + /* sum v0 */ + rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0]; + gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1]; + bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2]; + UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum); + UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum); + UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum); + /* sum v1 */ + rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[FRAG_ATTRIB_COL1][0]; + gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[FRAG_ATTRIB_COL1][1]; + bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[FRAG_ATTRIB_COL1][2]; + UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum); + UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum); + UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum); + /* sum v2 */ + rSum = CHAN_TO_FLOAT(ncv2->color[0]) + ncv2->attrib[FRAG_ATTRIB_COL1][0]; + gSum = CHAN_TO_FLOAT(ncv2->color[1]) + ncv2->attrib[FRAG_ATTRIB_COL1][1]; + bSum = CHAN_TO_FLOAT(ncv2->color[2]) + ncv2->attrib[FRAG_ATTRIB_COL1][2]; + UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[0], rSum); + UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[1], gSum); + UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[2], bSum); + /* draw */ + SWRAST_CONTEXT(ctx)->SpecTriangle( ctx, ncv0, ncv1, ncv2 ); + /* restore original colors */ + COPY_CHAN4( ncv0->color, cSave[0] ); + COPY_CHAN4( ncv1->color, cSave[1] ); + COPY_CHAN4( ncv2->color, cSave[2] ); +} + + + +#ifdef DEBUG + +/* record the current triangle function name */ +const char *_mesa_triFuncName = NULL; + +#define USE(triFunc) \ +do { \ + _mesa_triFuncName = #triFunc; \ + /*printf("%s\n", _mesa_triFuncName);*/ \ + swrast->Triangle = triFunc; \ +} while (0) + +#else + +#define USE(triFunc) swrast->Triangle = triFunc; + +#endif + + + + +/* + * Determine which triangle rendering function to use given the current + * rendering context. + * + * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or + * remove tests to this code. + */ +void +_swrast_choose_triangle( struct gl_context *ctx ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + + if (ctx->Polygon.CullFlag && + ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) { + USE(nodraw_triangle); + return; + } + + if (ctx->RenderMode==GL_RENDER) { + + if (ctx->Polygon.SmoothFlag) { + _swrast_set_aa_triangle_function(ctx); + ASSERT(swrast->Triangle); + return; + } + + /* special case for occlusion testing */ + if (ctx->Query.CurrentOcclusionObject && + ctx->Depth.Test && + ctx->Depth.Mask == GL_FALSE && + ctx->Depth.Func == GL_LESS && + !ctx->Stencil._Enabled) { + if (ctx->Color.ColorMask[0][0] == 0 && + ctx->Color.ColorMask[0][1] == 0 && + ctx->Color.ColorMask[0][2] == 0 && + ctx->Color.ColorMask[0][3] == 0) { + USE(occlusion_zless_triangle); + return; + } + } + + /* + * XXX should examine swrast->_ActiveAttribMask to determine what + * needs to be interpolated. + */ + if (ctx->Texture._EnabledCoordUnits || + ctx->FragmentProgram._Current || + ctx->ATIFragmentShader._Enabled || + _mesa_need_secondary_color(ctx) || + swrast->_FogEnabled) { + /* Ugh, we do a _lot_ of tests to pick the best textured tri func */ + const struct gl_texture_object *texObj2D; + const struct gl_texture_image *texImg; + GLenum minFilter, magFilter, envMode; + gl_format format; + texObj2D = ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; + + texImg = texObj2D ? texObj2D->Image[0][texObj2D->BaseLevel] : NULL; + format = texImg ? texImg->TexFormat : MESA_FORMAT_NONE; + minFilter = texObj2D ? texObj2D->Sampler.MinFilter : GL_NONE; + magFilter = texObj2D ? texObj2D->Sampler.MagFilter : GL_NONE; + envMode = ctx->Texture.Unit[0].EnvMode; + + /* First see if we can use an optimized 2-D texture function */ + if (ctx->Texture._EnabledCoordUnits == 0x1 + && !ctx->FragmentProgram._Current + && !ctx->ATIFragmentShader._Enabled + && ctx->Texture._EnabledUnits == 0x1 + && ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT + && texObj2D->Sampler.WrapS == GL_REPEAT + && texObj2D->Sampler.WrapT == GL_REPEAT + && texObj2D->_Swizzle == SWIZZLE_NOOP + && texImg->_IsPowerOfTwo + && texImg->Border == 0 + && texImg->Width == texImg->RowStride + && (format == MESA_FORMAT_RGB888 || format == MESA_FORMAT_RGBA8888) + && minFilter == magFilter + && ctx->Light.Model.ColorControl == GL_SINGLE_COLOR + && !swrast->_FogEnabled + && ctx->Texture.Unit[0].EnvMode != GL_COMBINE_EXT + && ctx->Texture.Unit[0].EnvMode != GL_COMBINE4_NV) { + if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) { + if (minFilter == GL_NEAREST + && format == MESA_FORMAT_RGB888 + && (envMode == GL_REPLACE || envMode == GL_DECAL) + && ((swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT) + && ctx->Depth.Func == GL_LESS + && ctx->Depth.Mask == GL_TRUE) + || swrast->_RasterMask == TEXTURE_BIT) + && ctx->Polygon.StippleFlag == GL_FALSE + && ctx->DrawBuffer->Visual.depthBits <= 16) { + if (swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)) { + USE(simple_z_textured_triangle); + } + else { + USE(simple_textured_triangle); + } + } + else { +#if CHAN_BITS != 8 + USE(general_triangle); +#else + if (format == MESA_FORMAT_RGBA8888 && !_mesa_little_endian()) { + /* We only handle RGBA8888 correctly on little endian + * in the optimized code above. + */ + USE(general_triangle); + } + else { + USE(affine_textured_triangle); + } +#endif + } + } + else { +#if CHAN_BITS != 8 + USE(general_triangle); +#else + USE(persp_textured_triangle); +#endif + } + } + else { + /* general case textured triangles */ + USE(general_triangle); + } + } + else { + ASSERT(!swrast->_FogEnabled); + ASSERT(!_mesa_need_secondary_color(ctx)); + if (ctx->Light.ShadeModel==GL_SMOOTH) { + /* smooth shaded, no texturing, stippled or some raster ops */ +#if CHAN_BITS != 8 + USE(general_triangle); +#else + USE(smooth_rgba_triangle); +#endif + } + else { + /* flat shaded, no texturing, stippled or some raster ops */ +#if CHAN_BITS != 8 + USE(general_triangle); +#else + USE(flat_rgba_triangle); +#endif + } + } + } + else if (ctx->RenderMode==GL_FEEDBACK) { + USE(_swrast_feedback_triangle); + } + else { + /* GL_SELECT mode */ + USE(_swrast_select_triangle); + } +} |