1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5848b8605Smrg * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 6848b8605Smrg * 7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 8848b8605Smrg * copy of this software and associated documentation files (the "Software"), 9848b8605Smrg * to deal in the Software without restriction, including without limitation 10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 12848b8605Smrg * Software is furnished to do so, subject to the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice shall be included 15848b8605Smrg * in all copies or substantial portions of the Software. 16848b8605Smrg * 17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 24848b8605Smrg */ 25848b8605Smrg 26848b8605Smrg 27848b8605Smrg/** 28848b8605Smrg * \file swrast/s_span.c 29848b8605Smrg * \brief Span processing functions used by all rasterization functions. 30848b8605Smrg * This is where all the per-fragment tests are performed 31848b8605Smrg * \author Brian Paul 32848b8605Smrg */ 33848b8605Smrg 34b8e80941Smrg#include "c99_math.h" 35b8e80941Smrg#include "main/errors.h" 36848b8605Smrg#include "main/glheader.h" 37848b8605Smrg#include "main/format_pack.h" 38848b8605Smrg#include "main/format_unpack.h" 39848b8605Smrg#include "main/macros.h" 40848b8605Smrg#include "main/imports.h" 41848b8605Smrg#include "main/image.h" 42848b8605Smrg#include "main/samplerobj.h" 43b8e80941Smrg#include "main/state.h" 44b8e80941Smrg#include "main/stencil.h" 45b8e80941Smrg#include "main/teximage.h" 46848b8605Smrg 47848b8605Smrg#include "s_atifragshader.h" 48848b8605Smrg#include "s_alpha.h" 49848b8605Smrg#include "s_blend.h" 50848b8605Smrg#include "s_context.h" 51848b8605Smrg#include "s_depth.h" 52848b8605Smrg#include "s_fog.h" 53848b8605Smrg#include "s_logic.h" 54848b8605Smrg#include "s_masking.h" 55848b8605Smrg#include "s_fragprog.h" 56848b8605Smrg#include "s_span.h" 57848b8605Smrg#include "s_stencil.h" 58848b8605Smrg#include "s_texcombine.h" 59848b8605Smrg 60848b8605Smrg#include <stdbool.h> 61848b8605Smrg 62848b8605Smrg/** 63848b8605Smrg * Set default fragment attributes for the span using the 64848b8605Smrg * current raster values. Used prior to glDraw/CopyPixels 65848b8605Smrg * and glBitmap. 66848b8605Smrg */ 67848b8605Smrgvoid 68848b8605Smrg_swrast_span_default_attribs(struct gl_context *ctx, SWspan *span) 69848b8605Smrg{ 70848b8605Smrg GLchan r, g, b, a; 71848b8605Smrg /* Z*/ 72848b8605Smrg { 73848b8605Smrg const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF; 74848b8605Smrg if (ctx->DrawBuffer->Visual.depthBits <= 16) 75848b8605Smrg span->z = FloatToFixed(ctx->Current.RasterPos[2] * depthMax + 0.5F); 76848b8605Smrg else { 77848b8605Smrg GLfloat tmpf = ctx->Current.RasterPos[2] * depthMax; 78848b8605Smrg tmpf = MIN2(tmpf, depthMax); 79848b8605Smrg span->z = (GLint)tmpf; 80848b8605Smrg } 81848b8605Smrg span->zStep = 0; 82848b8605Smrg span->interpMask |= SPAN_Z; 83848b8605Smrg } 84848b8605Smrg 85848b8605Smrg /* W (for perspective correction) */ 86848b8605Smrg span->attrStart[VARYING_SLOT_POS][3] = 1.0; 87848b8605Smrg span->attrStepX[VARYING_SLOT_POS][3] = 0.0; 88848b8605Smrg span->attrStepY[VARYING_SLOT_POS][3] = 0.0; 89848b8605Smrg 90848b8605Smrg /* primary color, or color index */ 91848b8605Smrg UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]); 92848b8605Smrg UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]); 93848b8605Smrg UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]); 94848b8605Smrg UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]); 95848b8605Smrg#if CHAN_TYPE == GL_FLOAT 96848b8605Smrg span->red = r; 97848b8605Smrg span->green = g; 98848b8605Smrg span->blue = b; 99848b8605Smrg span->alpha = a; 100848b8605Smrg#else 101848b8605Smrg span->red = IntToFixed(r); 102848b8605Smrg span->green = IntToFixed(g); 103848b8605Smrg span->blue = IntToFixed(b); 104848b8605Smrg span->alpha = IntToFixed(a); 105848b8605Smrg#endif 106848b8605Smrg span->redStep = 0; 107848b8605Smrg span->greenStep = 0; 108848b8605Smrg span->blueStep = 0; 109848b8605Smrg span->alphaStep = 0; 110848b8605Smrg span->interpMask |= SPAN_RGBA; 111848b8605Smrg 112848b8605Smrg COPY_4V(span->attrStart[VARYING_SLOT_COL0], ctx->Current.RasterColor); 113848b8605Smrg ASSIGN_4V(span->attrStepX[VARYING_SLOT_COL0], 0.0, 0.0, 0.0, 0.0); 114848b8605Smrg ASSIGN_4V(span->attrStepY[VARYING_SLOT_COL0], 0.0, 0.0, 0.0, 0.0); 115848b8605Smrg 116848b8605Smrg /* Secondary color */ 117848b8605Smrg if (ctx->Light.Enabled || ctx->Fog.ColorSumEnabled) 118848b8605Smrg { 119848b8605Smrg COPY_4V(span->attrStart[VARYING_SLOT_COL1], ctx->Current.RasterSecondaryColor); 120848b8605Smrg ASSIGN_4V(span->attrStepX[VARYING_SLOT_COL1], 0.0, 0.0, 0.0, 0.0); 121848b8605Smrg ASSIGN_4V(span->attrStepY[VARYING_SLOT_COL1], 0.0, 0.0, 0.0, 0.0); 122848b8605Smrg } 123848b8605Smrg 124848b8605Smrg /* fog */ 125848b8605Smrg { 126848b8605Smrg const SWcontext *swrast = SWRAST_CONTEXT(ctx); 127848b8605Smrg GLfloat fogVal; /* a coord or a blend factor */ 128848b8605Smrg if (swrast->_PreferPixelFog) { 129848b8605Smrg /* fog blend factors will be computed from fog coordinates per pixel */ 130848b8605Smrg fogVal = ctx->Current.RasterDistance; 131848b8605Smrg } 132848b8605Smrg else { 133848b8605Smrg /* fog blend factor should be computed from fogcoord now */ 134848b8605Smrg fogVal = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance); 135848b8605Smrg } 136848b8605Smrg span->attrStart[VARYING_SLOT_FOGC][0] = fogVal; 137848b8605Smrg span->attrStepX[VARYING_SLOT_FOGC][0] = 0.0; 138848b8605Smrg span->attrStepY[VARYING_SLOT_FOGC][0] = 0.0; 139848b8605Smrg } 140848b8605Smrg 141848b8605Smrg /* texcoords */ 142848b8605Smrg { 143848b8605Smrg GLuint i; 144848b8605Smrg for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { 145848b8605Smrg const GLuint attr = VARYING_SLOT_TEX0 + i; 146848b8605Smrg const GLfloat *tc = ctx->Current.RasterTexCoords[i]; 147848b8605Smrg if (_swrast_use_fragment_program(ctx) || 148b8e80941Smrg _mesa_ati_fragment_shader_enabled(ctx)) { 149848b8605Smrg COPY_4V(span->attrStart[attr], tc); 150848b8605Smrg } 151848b8605Smrg else if (tc[3] > 0.0F) { 152848b8605Smrg /* use (s/q, t/q, r/q, 1) */ 153848b8605Smrg span->attrStart[attr][0] = tc[0] / tc[3]; 154848b8605Smrg span->attrStart[attr][1] = tc[1] / tc[3]; 155848b8605Smrg span->attrStart[attr][2] = tc[2] / tc[3]; 156848b8605Smrg span->attrStart[attr][3] = 1.0; 157848b8605Smrg } 158848b8605Smrg else { 159848b8605Smrg ASSIGN_4V(span->attrStart[attr], 0.0F, 0.0F, 0.0F, 1.0F); 160848b8605Smrg } 161848b8605Smrg ASSIGN_4V(span->attrStepX[attr], 0.0F, 0.0F, 0.0F, 0.0F); 162848b8605Smrg ASSIGN_4V(span->attrStepY[attr], 0.0F, 0.0F, 0.0F, 0.0F); 163848b8605Smrg } 164848b8605Smrg } 165848b8605Smrg} 166848b8605Smrg 167848b8605Smrg 168848b8605Smrg/** 169848b8605Smrg * Interpolate the active attributes (and'd with attrMask) to 170848b8605Smrg * fill in span->array->attribs[]. 171848b8605Smrg * Perspective correction will be done. The point/line/triangle function 172848b8605Smrg * should have computed attrStart/Step values for VARYING_SLOT_POS[3]! 173848b8605Smrg */ 174848b8605Smrgstatic inline void 175848b8605Smrginterpolate_active_attribs(struct gl_context *ctx, SWspan *span, 176848b8605Smrg GLbitfield64 attrMask) 177848b8605Smrg{ 178848b8605Smrg const SWcontext *swrast = SWRAST_CONTEXT(ctx); 179848b8605Smrg 180848b8605Smrg /* 181848b8605Smrg * Don't overwrite existing array values, such as colors that may have 182848b8605Smrg * been produced by glDraw/CopyPixels. 183848b8605Smrg */ 184848b8605Smrg attrMask &= ~span->arrayAttribs; 185848b8605Smrg 186848b8605Smrg ATTRIB_LOOP_BEGIN 187848b8605Smrg if (attrMask & BITFIELD64_BIT(attr)) { 188848b8605Smrg const GLfloat dwdx = span->attrStepX[VARYING_SLOT_POS][3]; 189848b8605Smrg GLfloat w = span->attrStart[VARYING_SLOT_POS][3]; 190848b8605Smrg const GLfloat dv0dx = span->attrStepX[attr][0]; 191848b8605Smrg const GLfloat dv1dx = span->attrStepX[attr][1]; 192848b8605Smrg const GLfloat dv2dx = span->attrStepX[attr][2]; 193848b8605Smrg const GLfloat dv3dx = span->attrStepX[attr][3]; 194848b8605Smrg GLfloat v0 = span->attrStart[attr][0] + span->leftClip * dv0dx; 195848b8605Smrg GLfloat v1 = span->attrStart[attr][1] + span->leftClip * dv1dx; 196848b8605Smrg GLfloat v2 = span->attrStart[attr][2] + span->leftClip * dv2dx; 197848b8605Smrg GLfloat v3 = span->attrStart[attr][3] + span->leftClip * dv3dx; 198848b8605Smrg GLuint k; 199848b8605Smrg for (k = 0; k < span->end; k++) { 200848b8605Smrg const GLfloat invW = 1.0f / w; 201848b8605Smrg span->array->attribs[attr][k][0] = v0 * invW; 202848b8605Smrg span->array->attribs[attr][k][1] = v1 * invW; 203848b8605Smrg span->array->attribs[attr][k][2] = v2 * invW; 204848b8605Smrg span->array->attribs[attr][k][3] = v3 * invW; 205848b8605Smrg v0 += dv0dx; 206848b8605Smrg v1 += dv1dx; 207848b8605Smrg v2 += dv2dx; 208848b8605Smrg v3 += dv3dx; 209848b8605Smrg w += dwdx; 210848b8605Smrg } 211b8e80941Smrg assert((span->arrayAttribs & BITFIELD64_BIT(attr)) == 0); 212848b8605Smrg span->arrayAttribs |= BITFIELD64_BIT(attr); 213848b8605Smrg } 214848b8605Smrg ATTRIB_LOOP_END 215848b8605Smrg} 216848b8605Smrg 217848b8605Smrg 218848b8605Smrg/** 219848b8605Smrg * Interpolate primary colors to fill in the span->array->rgba8 (or rgb16) 220848b8605Smrg * color array. 221848b8605Smrg */ 222848b8605Smrgstatic inline void 223848b8605Smrginterpolate_int_colors(struct gl_context *ctx, SWspan *span) 224848b8605Smrg{ 225848b8605Smrg#if CHAN_BITS != 32 226848b8605Smrg const GLuint n = span->end; 227848b8605Smrg GLuint i; 228848b8605Smrg 229b8e80941Smrg assert(!(span->arrayMask & SPAN_RGBA)); 230848b8605Smrg#endif 231848b8605Smrg 232848b8605Smrg switch (span->array->ChanType) { 233848b8605Smrg#if CHAN_BITS != 32 234848b8605Smrg case GL_UNSIGNED_BYTE: 235848b8605Smrg { 236848b8605Smrg GLubyte (*rgba)[4] = span->array->rgba8; 237848b8605Smrg if (span->interpMask & SPAN_FLAT) { 238848b8605Smrg GLubyte color[4]; 239848b8605Smrg color[RCOMP] = FixedToInt(span->red); 240848b8605Smrg color[GCOMP] = FixedToInt(span->green); 241848b8605Smrg color[BCOMP] = FixedToInt(span->blue); 242848b8605Smrg color[ACOMP] = FixedToInt(span->alpha); 243848b8605Smrg for (i = 0; i < n; i++) { 244848b8605Smrg COPY_4UBV(rgba[i], color); 245848b8605Smrg } 246848b8605Smrg } 247848b8605Smrg else { 248848b8605Smrg GLfixed r = span->red; 249848b8605Smrg GLfixed g = span->green; 250848b8605Smrg GLfixed b = span->blue; 251848b8605Smrg GLfixed a = span->alpha; 252848b8605Smrg GLint dr = span->redStep; 253848b8605Smrg GLint dg = span->greenStep; 254848b8605Smrg GLint db = span->blueStep; 255848b8605Smrg GLint da = span->alphaStep; 256848b8605Smrg for (i = 0; i < n; i++) { 257848b8605Smrg rgba[i][RCOMP] = FixedToChan(r); 258848b8605Smrg rgba[i][GCOMP] = FixedToChan(g); 259848b8605Smrg rgba[i][BCOMP] = FixedToChan(b); 260848b8605Smrg rgba[i][ACOMP] = FixedToChan(a); 261848b8605Smrg r += dr; 262848b8605Smrg g += dg; 263848b8605Smrg b += db; 264848b8605Smrg a += da; 265848b8605Smrg } 266848b8605Smrg } 267848b8605Smrg } 268848b8605Smrg break; 269848b8605Smrg case GL_UNSIGNED_SHORT: 270848b8605Smrg { 271848b8605Smrg GLushort (*rgba)[4] = span->array->rgba16; 272848b8605Smrg if (span->interpMask & SPAN_FLAT) { 273848b8605Smrg GLushort color[4]; 274848b8605Smrg color[RCOMP] = FixedToInt(span->red); 275848b8605Smrg color[GCOMP] = FixedToInt(span->green); 276848b8605Smrg color[BCOMP] = FixedToInt(span->blue); 277848b8605Smrg color[ACOMP] = FixedToInt(span->alpha); 278848b8605Smrg for (i = 0; i < n; i++) { 279848b8605Smrg COPY_4V(rgba[i], color); 280848b8605Smrg } 281848b8605Smrg } 282848b8605Smrg else { 283848b8605Smrg GLushort (*rgba)[4] = span->array->rgba16; 284848b8605Smrg GLfixed r, g, b, a; 285848b8605Smrg GLint dr, dg, db, da; 286848b8605Smrg r = span->red; 287848b8605Smrg g = span->green; 288848b8605Smrg b = span->blue; 289848b8605Smrg a = span->alpha; 290848b8605Smrg dr = span->redStep; 291848b8605Smrg dg = span->greenStep; 292848b8605Smrg db = span->blueStep; 293848b8605Smrg da = span->alphaStep; 294848b8605Smrg for (i = 0; i < n; i++) { 295848b8605Smrg rgba[i][RCOMP] = FixedToChan(r); 296848b8605Smrg rgba[i][GCOMP] = FixedToChan(g); 297848b8605Smrg rgba[i][BCOMP] = FixedToChan(b); 298848b8605Smrg rgba[i][ACOMP] = FixedToChan(a); 299848b8605Smrg r += dr; 300848b8605Smrg g += dg; 301848b8605Smrg b += db; 302848b8605Smrg a += da; 303848b8605Smrg } 304848b8605Smrg } 305848b8605Smrg } 306848b8605Smrg break; 307848b8605Smrg#endif 308848b8605Smrg case GL_FLOAT: 309848b8605Smrg interpolate_active_attribs(ctx, span, VARYING_BIT_COL0); 310848b8605Smrg break; 311848b8605Smrg default: 312848b8605Smrg _mesa_problem(ctx, "bad datatype 0x%x in interpolate_int_colors", 313848b8605Smrg span->array->ChanType); 314848b8605Smrg } 315848b8605Smrg span->arrayMask |= SPAN_RGBA; 316848b8605Smrg} 317848b8605Smrg 318848b8605Smrg 319848b8605Smrg/** 320848b8605Smrg * Populate the VARYING_SLOT_COL0 array. 321848b8605Smrg */ 322848b8605Smrgstatic inline void 323848b8605Smrginterpolate_float_colors(SWspan *span) 324848b8605Smrg{ 325848b8605Smrg GLfloat (*col0)[4] = span->array->attribs[VARYING_SLOT_COL0]; 326848b8605Smrg const GLuint n = span->end; 327848b8605Smrg GLuint i; 328848b8605Smrg 329848b8605Smrg assert(!(span->arrayAttribs & VARYING_BIT_COL0)); 330848b8605Smrg 331848b8605Smrg if (span->arrayMask & SPAN_RGBA) { 332848b8605Smrg /* convert array of int colors */ 333848b8605Smrg for (i = 0; i < n; i++) { 334848b8605Smrg col0[i][0] = UBYTE_TO_FLOAT(span->array->rgba8[i][0]); 335848b8605Smrg col0[i][1] = UBYTE_TO_FLOAT(span->array->rgba8[i][1]); 336848b8605Smrg col0[i][2] = UBYTE_TO_FLOAT(span->array->rgba8[i][2]); 337848b8605Smrg col0[i][3] = UBYTE_TO_FLOAT(span->array->rgba8[i][3]); 338848b8605Smrg } 339848b8605Smrg } 340848b8605Smrg else { 341848b8605Smrg /* interpolate red/green/blue/alpha to get float colors */ 342b8e80941Smrg assert(span->interpMask & SPAN_RGBA); 343848b8605Smrg if (span->interpMask & SPAN_FLAT) { 344848b8605Smrg GLfloat r = FixedToFloat(span->red); 345848b8605Smrg GLfloat g = FixedToFloat(span->green); 346848b8605Smrg GLfloat b = FixedToFloat(span->blue); 347848b8605Smrg GLfloat a = FixedToFloat(span->alpha); 348848b8605Smrg for (i = 0; i < n; i++) { 349848b8605Smrg ASSIGN_4V(col0[i], r, g, b, a); 350848b8605Smrg } 351848b8605Smrg } 352848b8605Smrg else { 353848b8605Smrg GLfloat r = FixedToFloat(span->red); 354848b8605Smrg GLfloat g = FixedToFloat(span->green); 355848b8605Smrg GLfloat b = FixedToFloat(span->blue); 356848b8605Smrg GLfloat a = FixedToFloat(span->alpha); 357848b8605Smrg GLfloat dr = FixedToFloat(span->redStep); 358848b8605Smrg GLfloat dg = FixedToFloat(span->greenStep); 359848b8605Smrg GLfloat db = FixedToFloat(span->blueStep); 360848b8605Smrg GLfloat da = FixedToFloat(span->alphaStep); 361848b8605Smrg for (i = 0; i < n; i++) { 362848b8605Smrg col0[i][0] = r; 363848b8605Smrg col0[i][1] = g; 364848b8605Smrg col0[i][2] = b; 365848b8605Smrg col0[i][3] = a; 366848b8605Smrg r += dr; 367848b8605Smrg g += dg; 368848b8605Smrg b += db; 369848b8605Smrg a += da; 370848b8605Smrg } 371848b8605Smrg } 372848b8605Smrg } 373848b8605Smrg 374848b8605Smrg span->arrayAttribs |= VARYING_BIT_COL0; 375848b8605Smrg span->array->ChanType = GL_FLOAT; 376848b8605Smrg} 377848b8605Smrg 378848b8605Smrg 379848b8605Smrg 380848b8605Smrg/** 381848b8605Smrg * Fill in the span.zArray array from the span->z, zStep values. 382848b8605Smrg */ 383848b8605Smrgvoid 384848b8605Smrg_swrast_span_interpolate_z( const struct gl_context *ctx, SWspan *span ) 385848b8605Smrg{ 386848b8605Smrg const GLuint n = span->end; 387848b8605Smrg GLuint i; 388848b8605Smrg 389b8e80941Smrg assert(!(span->arrayMask & SPAN_Z)); 390848b8605Smrg 391848b8605Smrg if (ctx->DrawBuffer->Visual.depthBits <= 16) { 392848b8605Smrg GLfixed zval = span->z; 393848b8605Smrg GLuint *z = span->array->z; 394848b8605Smrg for (i = 0; i < n; i++) { 395848b8605Smrg z[i] = FixedToInt(zval); 396848b8605Smrg zval += span->zStep; 397848b8605Smrg } 398848b8605Smrg } 399848b8605Smrg else { 400848b8605Smrg /* Deep Z buffer, no fixed->int shift */ 401848b8605Smrg GLuint zval = span->z; 402848b8605Smrg GLuint *z = span->array->z; 403848b8605Smrg for (i = 0; i < n; i++) { 404848b8605Smrg z[i] = zval; 405848b8605Smrg zval += span->zStep; 406848b8605Smrg } 407848b8605Smrg } 408848b8605Smrg span->interpMask &= ~SPAN_Z; 409848b8605Smrg span->arrayMask |= SPAN_Z; 410848b8605Smrg} 411848b8605Smrg 412848b8605Smrg 413848b8605Smrg/** 414848b8605Smrg * Compute mipmap LOD from partial derivatives. 415848b8605Smrg * This the ideal solution, as given in the OpenGL spec. 416848b8605Smrg */ 417848b8605SmrgGLfloat 418848b8605Smrg_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy, 419848b8605Smrg GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH, 420848b8605Smrg GLfloat s, GLfloat t, GLfloat q, GLfloat invQ) 421848b8605Smrg{ 422848b8605Smrg GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ); 423848b8605Smrg GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ); 424848b8605Smrg GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ); 425848b8605Smrg GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ); 426848b8605Smrg GLfloat x = sqrtf(dudx * dudx + dvdx * dvdx); 427848b8605Smrg GLfloat y = sqrtf(dudy * dudy + dvdy * dvdy); 428848b8605Smrg GLfloat rho = MAX2(x, y); 429848b8605Smrg GLfloat lambda = LOG2(rho); 430848b8605Smrg return lambda; 431848b8605Smrg} 432848b8605Smrg 433848b8605Smrg 434848b8605Smrg/** 435848b8605Smrg * Compute mipmap LOD from partial derivatives. 436848b8605Smrg * This is a faster approximation than above function. 437848b8605Smrg */ 438848b8605Smrg#if 0 439848b8605SmrgGLfloat 440848b8605Smrg_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy, 441848b8605Smrg GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH, 442848b8605Smrg GLfloat s, GLfloat t, GLfloat q, GLfloat invQ) 443848b8605Smrg{ 444848b8605Smrg GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ; 445848b8605Smrg GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ; 446848b8605Smrg GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ; 447848b8605Smrg GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ; 448848b8605Smrg GLfloat maxU, maxV, rho, lambda; 449b8e80941Smrg dsdx2 = fabsf(dsdx2); 450b8e80941Smrg dsdy2 = fabsf(dsdy2); 451b8e80941Smrg dtdx2 = fabsf(dtdx2); 452b8e80941Smrg dtdy2 = fabsf(dtdy2); 453848b8605Smrg maxU = MAX2(dsdx2, dsdy2) * texW; 454848b8605Smrg maxV = MAX2(dtdx2, dtdy2) * texH; 455848b8605Smrg rho = MAX2(maxU, maxV); 456848b8605Smrg lambda = LOG2(rho); 457848b8605Smrg return lambda; 458848b8605Smrg} 459848b8605Smrg#endif 460848b8605Smrg 461848b8605Smrg 462848b8605Smrg/** 463848b8605Smrg * Fill in the span.array->attrib[VARYING_SLOT_TEXn] arrays from the 464848b8605Smrg * using the attrStart/Step values. 465848b8605Smrg * 466848b8605Smrg * This function only used during fixed-function fragment processing. 467848b8605Smrg * 468848b8605Smrg * Note: in the places where we divide by Q (or mult by invQ) we're 469848b8605Smrg * really doing two things: perspective correction and texcoord 470848b8605Smrg * projection. Remember, for texcoord (s,t,r,q) we need to index 471848b8605Smrg * texels with (s/q, t/q, r/q). 472848b8605Smrg */ 473848b8605Smrgstatic void 474848b8605Smrginterpolate_texcoords(struct gl_context *ctx, SWspan *span) 475848b8605Smrg{ 476848b8605Smrg const GLuint maxUnit 477848b8605Smrg = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1; 478848b8605Smrg GLuint u; 479848b8605Smrg 480848b8605Smrg /* XXX CoordUnits vs. ImageUnits */ 481848b8605Smrg for (u = 0; u < maxUnit; u++) { 482848b8605Smrg if (ctx->Texture._EnabledCoordUnits & (1 << u)) { 483848b8605Smrg const GLuint attr = VARYING_SLOT_TEX0 + u; 484848b8605Smrg const struct gl_texture_object *obj = ctx->Texture.Unit[u]._Current; 485848b8605Smrg GLfloat texW, texH; 486848b8605Smrg GLboolean needLambda; 487848b8605Smrg GLfloat (*texcoord)[4] = span->array->attribs[attr]; 488848b8605Smrg GLfloat *lambda = span->array->lambda[u]; 489848b8605Smrg const GLfloat dsdx = span->attrStepX[attr][0]; 490848b8605Smrg const GLfloat dsdy = span->attrStepY[attr][0]; 491848b8605Smrg const GLfloat dtdx = span->attrStepX[attr][1]; 492848b8605Smrg const GLfloat dtdy = span->attrStepY[attr][1]; 493848b8605Smrg const GLfloat drdx = span->attrStepX[attr][2]; 494848b8605Smrg const GLfloat dqdx = span->attrStepX[attr][3]; 495848b8605Smrg const GLfloat dqdy = span->attrStepY[attr][3]; 496848b8605Smrg GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx; 497848b8605Smrg GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx; 498848b8605Smrg GLfloat r = span->attrStart[attr][2] + span->leftClip * drdx; 499848b8605Smrg GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx; 500848b8605Smrg 501848b8605Smrg if (obj) { 502b8e80941Smrg const struct gl_texture_image *img = _mesa_base_tex_image(obj); 503848b8605Smrg const struct swrast_texture_image *swImg = 504848b8605Smrg swrast_texture_image_const(img); 505848b8605Smrg const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, u); 506848b8605Smrg 507848b8605Smrg needLambda = (samp->MinFilter != samp->MagFilter) 508848b8605Smrg || _swrast_use_fragment_program(ctx); 509848b8605Smrg /* LOD is calculated directly in the ansiotropic filter, we can 510848b8605Smrg * skip the normal lambda function as the result is ignored. 511848b8605Smrg */ 512b8e80941Smrg if (samp->MaxAnisotropy > 1.0F && 513848b8605Smrg samp->MinFilter == GL_LINEAR_MIPMAP_LINEAR) { 514848b8605Smrg needLambda = GL_FALSE; 515848b8605Smrg } 516848b8605Smrg texW = swImg->WidthScale; 517848b8605Smrg texH = swImg->HeightScale; 518848b8605Smrg } 519848b8605Smrg else { 520848b8605Smrg /* using a fragment program */ 521848b8605Smrg texW = 1.0; 522848b8605Smrg texH = 1.0; 523848b8605Smrg needLambda = GL_FALSE; 524848b8605Smrg } 525848b8605Smrg 526848b8605Smrg if (needLambda) { 527848b8605Smrg GLuint i; 528848b8605Smrg if (_swrast_use_fragment_program(ctx) 529b8e80941Smrg || _mesa_ati_fragment_shader_enabled(ctx)) { 530848b8605Smrg /* do perspective correction but don't divide s, t, r by q */ 531848b8605Smrg const GLfloat dwdx = span->attrStepX[VARYING_SLOT_POS][3]; 532848b8605Smrg GLfloat w = span->attrStart[VARYING_SLOT_POS][3] + span->leftClip * dwdx; 533848b8605Smrg for (i = 0; i < span->end; i++) { 534848b8605Smrg const GLfloat invW = 1.0F / w; 535848b8605Smrg texcoord[i][0] = s * invW; 536848b8605Smrg texcoord[i][1] = t * invW; 537848b8605Smrg texcoord[i][2] = r * invW; 538848b8605Smrg texcoord[i][3] = q * invW; 539848b8605Smrg lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy, 540848b8605Smrg dqdx, dqdy, texW, texH, 541848b8605Smrg s, t, q, invW); 542848b8605Smrg s += dsdx; 543848b8605Smrg t += dtdx; 544848b8605Smrg r += drdx; 545848b8605Smrg q += dqdx; 546848b8605Smrg w += dwdx; 547848b8605Smrg } 548848b8605Smrg } 549848b8605Smrg else { 550848b8605Smrg for (i = 0; i < span->end; i++) { 551848b8605Smrg const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); 552848b8605Smrg texcoord[i][0] = s * invQ; 553848b8605Smrg texcoord[i][1] = t * invQ; 554848b8605Smrg texcoord[i][2] = r * invQ; 555848b8605Smrg texcoord[i][3] = q; 556848b8605Smrg lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy, 557848b8605Smrg dqdx, dqdy, texW, texH, 558848b8605Smrg s, t, q, invQ); 559848b8605Smrg s += dsdx; 560848b8605Smrg t += dtdx; 561848b8605Smrg r += drdx; 562848b8605Smrg q += dqdx; 563848b8605Smrg } 564848b8605Smrg } 565848b8605Smrg span->arrayMask |= SPAN_LAMBDA; 566848b8605Smrg } 567848b8605Smrg else { 568848b8605Smrg GLuint i; 569848b8605Smrg if (_swrast_use_fragment_program(ctx) || 570b8e80941Smrg _mesa_ati_fragment_shader_enabled(ctx)) { 571848b8605Smrg /* do perspective correction but don't divide s, t, r by q */ 572848b8605Smrg const GLfloat dwdx = span->attrStepX[VARYING_SLOT_POS][3]; 573848b8605Smrg GLfloat w = span->attrStart[VARYING_SLOT_POS][3] + span->leftClip * dwdx; 574848b8605Smrg for (i = 0; i < span->end; i++) { 575848b8605Smrg const GLfloat invW = 1.0F / w; 576848b8605Smrg texcoord[i][0] = s * invW; 577848b8605Smrg texcoord[i][1] = t * invW; 578848b8605Smrg texcoord[i][2] = r * invW; 579848b8605Smrg texcoord[i][3] = q * invW; 580848b8605Smrg lambda[i] = 0.0; 581848b8605Smrg s += dsdx; 582848b8605Smrg t += dtdx; 583848b8605Smrg r += drdx; 584848b8605Smrg q += dqdx; 585848b8605Smrg w += dwdx; 586848b8605Smrg } 587848b8605Smrg } 588848b8605Smrg else if (dqdx == 0.0F) { 589848b8605Smrg /* Ortho projection or polygon's parallel to window X axis */ 590848b8605Smrg const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); 591848b8605Smrg for (i = 0; i < span->end; i++) { 592848b8605Smrg texcoord[i][0] = s * invQ; 593848b8605Smrg texcoord[i][1] = t * invQ; 594848b8605Smrg texcoord[i][2] = r * invQ; 595848b8605Smrg texcoord[i][3] = q; 596848b8605Smrg lambda[i] = 0.0; 597848b8605Smrg s += dsdx; 598848b8605Smrg t += dtdx; 599848b8605Smrg r += drdx; 600848b8605Smrg } 601848b8605Smrg } 602848b8605Smrg else { 603848b8605Smrg for (i = 0; i < span->end; i++) { 604848b8605Smrg const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); 605848b8605Smrg texcoord[i][0] = s * invQ; 606848b8605Smrg texcoord[i][1] = t * invQ; 607848b8605Smrg texcoord[i][2] = r * invQ; 608848b8605Smrg texcoord[i][3] = q; 609848b8605Smrg lambda[i] = 0.0; 610848b8605Smrg s += dsdx; 611848b8605Smrg t += dtdx; 612848b8605Smrg r += drdx; 613848b8605Smrg q += dqdx; 614848b8605Smrg } 615848b8605Smrg } 616848b8605Smrg } /* lambda */ 617848b8605Smrg } /* if */ 618848b8605Smrg } /* for */ 619848b8605Smrg} 620848b8605Smrg 621848b8605Smrg 622848b8605Smrg/** 623848b8605Smrg * Fill in the arrays->attribs[VARYING_SLOT_POS] array. 624848b8605Smrg */ 625848b8605Smrgstatic inline void 626848b8605Smrginterpolate_wpos(struct gl_context *ctx, SWspan *span) 627848b8605Smrg{ 628848b8605Smrg GLfloat (*wpos)[4] = span->array->attribs[VARYING_SLOT_POS]; 629848b8605Smrg GLuint i; 630848b8605Smrg const GLfloat zScale = 1.0F / ctx->DrawBuffer->_DepthMaxF; 631848b8605Smrg GLfloat w, dw; 632848b8605Smrg 633848b8605Smrg if (span->arrayMask & SPAN_XY) { 634848b8605Smrg for (i = 0; i < span->end; i++) { 635848b8605Smrg wpos[i][0] = (GLfloat) span->array->x[i]; 636848b8605Smrg wpos[i][1] = (GLfloat) span->array->y[i]; 637848b8605Smrg } 638848b8605Smrg } 639848b8605Smrg else { 640848b8605Smrg for (i = 0; i < span->end; i++) { 641848b8605Smrg wpos[i][0] = (GLfloat) span->x + i; 642848b8605Smrg wpos[i][1] = (GLfloat) span->y; 643848b8605Smrg } 644848b8605Smrg } 645848b8605Smrg 646848b8605Smrg dw = span->attrStepX[VARYING_SLOT_POS][3]; 647848b8605Smrg w = span->attrStart[VARYING_SLOT_POS][3] + span->leftClip * dw; 648848b8605Smrg for (i = 0; i < span->end; i++) { 649848b8605Smrg wpos[i][2] = (GLfloat) span->array->z[i] * zScale; 650848b8605Smrg wpos[i][3] = w; 651848b8605Smrg w += dw; 652848b8605Smrg } 653848b8605Smrg} 654848b8605Smrg 655848b8605Smrg 656848b8605Smrg/** 657848b8605Smrg * Apply the current polygon stipple pattern to a span of pixels. 658848b8605Smrg */ 659848b8605Smrgstatic inline void 660848b8605Smrgstipple_polygon_span(struct gl_context *ctx, SWspan *span) 661848b8605Smrg{ 662848b8605Smrg GLubyte *mask = span->array->mask; 663848b8605Smrg 664b8e80941Smrg assert(ctx->Polygon.StippleFlag); 665848b8605Smrg 666848b8605Smrg if (span->arrayMask & SPAN_XY) { 667848b8605Smrg /* arrays of x/y pixel coords */ 668848b8605Smrg GLuint i; 669848b8605Smrg for (i = 0; i < span->end; i++) { 670848b8605Smrg const GLint col = span->array->x[i] % 32; 671848b8605Smrg const GLint row = span->array->y[i] % 32; 672848b8605Smrg const GLuint stipple = ctx->PolygonStipple[row]; 673848b8605Smrg if (((1 << col) & stipple) == 0) { 674848b8605Smrg mask[i] = 0; 675848b8605Smrg } 676848b8605Smrg } 677848b8605Smrg } 678848b8605Smrg else { 679848b8605Smrg /* horizontal span of pixels */ 680848b8605Smrg const GLuint highBit = 1 << 31; 681848b8605Smrg const GLuint stipple = ctx->PolygonStipple[span->y % 32]; 682848b8605Smrg GLuint i, m = highBit >> (GLuint) (span->x % 32); 683848b8605Smrg for (i = 0; i < span->end; i++) { 684848b8605Smrg if ((m & stipple) == 0) { 685848b8605Smrg mask[i] = 0; 686848b8605Smrg } 687848b8605Smrg m = m >> 1; 688848b8605Smrg if (m == 0) { 689848b8605Smrg m = highBit; 690848b8605Smrg } 691848b8605Smrg } 692848b8605Smrg } 693848b8605Smrg span->writeAll = GL_FALSE; 694848b8605Smrg} 695848b8605Smrg 696848b8605Smrg 697848b8605Smrg/** 698848b8605Smrg * Clip a pixel span to the current buffer/window boundaries: 699848b8605Smrg * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax. This will accomplish 700848b8605Smrg * window clipping and scissoring. 701848b8605Smrg * Return: GL_TRUE some pixels still visible 702848b8605Smrg * GL_FALSE nothing visible 703848b8605Smrg */ 704848b8605Smrgstatic inline GLuint 705848b8605Smrgclip_span( struct gl_context *ctx, SWspan *span ) 706848b8605Smrg{ 707848b8605Smrg const GLint xmin = ctx->DrawBuffer->_Xmin; 708848b8605Smrg const GLint xmax = ctx->DrawBuffer->_Xmax; 709848b8605Smrg const GLint ymin = ctx->DrawBuffer->_Ymin; 710848b8605Smrg const GLint ymax = ctx->DrawBuffer->_Ymax; 711848b8605Smrg 712848b8605Smrg span->leftClip = 0; 713848b8605Smrg 714848b8605Smrg if (span->arrayMask & SPAN_XY) { 715848b8605Smrg /* arrays of x/y pixel coords */ 716848b8605Smrg const GLint *x = span->array->x; 717848b8605Smrg const GLint *y = span->array->y; 718848b8605Smrg const GLint n = span->end; 719848b8605Smrg GLubyte *mask = span->array->mask; 720848b8605Smrg GLint i; 721848b8605Smrg GLuint passed = 0; 722848b8605Smrg if (span->arrayMask & SPAN_MASK) { 723848b8605Smrg /* note: using & intead of && to reduce branches */ 724848b8605Smrg for (i = 0; i < n; i++) { 725848b8605Smrg mask[i] &= (x[i] >= xmin) & (x[i] < xmax) 726848b8605Smrg & (y[i] >= ymin) & (y[i] < ymax); 727848b8605Smrg passed += mask[i]; 728848b8605Smrg } 729848b8605Smrg } 730848b8605Smrg else { 731848b8605Smrg /* note: using & intead of && to reduce branches */ 732848b8605Smrg for (i = 0; i < n; i++) { 733848b8605Smrg mask[i] = (x[i] >= xmin) & (x[i] < xmax) 734848b8605Smrg & (y[i] >= ymin) & (y[i] < ymax); 735848b8605Smrg passed += mask[i]; 736848b8605Smrg } 737848b8605Smrg } 738848b8605Smrg return passed > 0; 739848b8605Smrg } 740848b8605Smrg else { 741848b8605Smrg /* horizontal span of pixels */ 742848b8605Smrg const GLint x = span->x; 743848b8605Smrg const GLint y = span->y; 744848b8605Smrg GLint n = span->end; 745848b8605Smrg 746848b8605Smrg /* Trivial rejection tests */ 747848b8605Smrg if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) { 748848b8605Smrg span->end = 0; 749848b8605Smrg return GL_FALSE; /* all pixels clipped */ 750848b8605Smrg } 751848b8605Smrg 752848b8605Smrg /* Clip to right */ 753848b8605Smrg if (x + n > xmax) { 754b8e80941Smrg assert(x < xmax); 755848b8605Smrg n = span->end = xmax - x; 756848b8605Smrg } 757848b8605Smrg 758848b8605Smrg /* Clip to the left */ 759848b8605Smrg if (x < xmin) { 760848b8605Smrg const GLint leftClip = xmin - x; 761848b8605Smrg GLuint i; 762848b8605Smrg 763b8e80941Smrg assert(leftClip > 0); 764b8e80941Smrg assert(x + n > xmin); 765848b8605Smrg 766848b8605Smrg /* Clip 'leftClip' pixels from the left side. 767848b8605Smrg * The span->leftClip field will be applied when we interpolate 768848b8605Smrg * fragment attributes. 769848b8605Smrg * For arrays of values, shift them left. 770848b8605Smrg */ 771848b8605Smrg for (i = 0; i < VARYING_SLOT_MAX; i++) { 772b8e80941Smrg if (span->interpMask & (1u << i)) { 773848b8605Smrg GLuint j; 774848b8605Smrg for (j = 0; j < 4; j++) { 775848b8605Smrg span->attrStart[i][j] += leftClip * span->attrStepX[i][j]; 776848b8605Smrg } 777848b8605Smrg } 778848b8605Smrg } 779848b8605Smrg 780848b8605Smrg span->red += leftClip * span->redStep; 781848b8605Smrg span->green += leftClip * span->greenStep; 782848b8605Smrg span->blue += leftClip * span->blueStep; 783848b8605Smrg span->alpha += leftClip * span->alphaStep; 784848b8605Smrg span->index += leftClip * span->indexStep; 785848b8605Smrg span->z += leftClip * span->zStep; 786848b8605Smrg span->intTex[0] += leftClip * span->intTexStep[0]; 787848b8605Smrg span->intTex[1] += leftClip * span->intTexStep[1]; 788848b8605Smrg 789848b8605Smrg#define SHIFT_ARRAY(ARRAY, SHIFT, LEN) \ 790848b8605Smrg memmove(ARRAY, ARRAY + (SHIFT), (LEN) * sizeof(ARRAY[0])) 791848b8605Smrg 792848b8605Smrg for (i = 0; i < VARYING_SLOT_MAX; i++) { 793b8e80941Smrg if (span->arrayAttribs & BITFIELD64_BIT(i)) { 794848b8605Smrg /* shift array elements left by 'leftClip' */ 795848b8605Smrg SHIFT_ARRAY(span->array->attribs[i], leftClip, n - leftClip); 796848b8605Smrg } 797848b8605Smrg } 798848b8605Smrg 799848b8605Smrg SHIFT_ARRAY(span->array->mask, leftClip, n - leftClip); 800848b8605Smrg SHIFT_ARRAY(span->array->rgba8, leftClip, n - leftClip); 801848b8605Smrg SHIFT_ARRAY(span->array->rgba16, leftClip, n - leftClip); 802848b8605Smrg SHIFT_ARRAY(span->array->x, leftClip, n - leftClip); 803848b8605Smrg SHIFT_ARRAY(span->array->y, leftClip, n - leftClip); 804848b8605Smrg SHIFT_ARRAY(span->array->z, leftClip, n - leftClip); 805848b8605Smrg SHIFT_ARRAY(span->array->index, leftClip, n - leftClip); 806848b8605Smrg for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { 807848b8605Smrg SHIFT_ARRAY(span->array->lambda[i], leftClip, n - leftClip); 808848b8605Smrg } 809848b8605Smrg SHIFT_ARRAY(span->array->coverage, leftClip, n - leftClip); 810848b8605Smrg 811848b8605Smrg#undef SHIFT_ARRAY 812848b8605Smrg 813848b8605Smrg span->leftClip = leftClip; 814848b8605Smrg span->x = xmin; 815848b8605Smrg span->end -= leftClip; 816848b8605Smrg span->writeAll = GL_FALSE; 817848b8605Smrg } 818848b8605Smrg 819b8e80941Smrg assert(span->x >= xmin); 820b8e80941Smrg assert(span->x + span->end <= xmax); 821b8e80941Smrg assert(span->y >= ymin); 822b8e80941Smrg assert(span->y < ymax); 823848b8605Smrg 824848b8605Smrg return GL_TRUE; /* some pixels visible */ 825848b8605Smrg } 826848b8605Smrg} 827848b8605Smrg 828848b8605Smrg 829848b8605Smrg/** 830848b8605Smrg * Add specular colors to primary colors. 831848b8605Smrg * Only called during fixed-function operation. 832848b8605Smrg * Result is float color array (VARYING_SLOT_COL0). 833848b8605Smrg */ 834848b8605Smrgstatic inline void 835848b8605Smrgadd_specular(struct gl_context *ctx, SWspan *span) 836848b8605Smrg{ 837848b8605Smrg const SWcontext *swrast = SWRAST_CONTEXT(ctx); 838848b8605Smrg const GLubyte *mask = span->array->mask; 839848b8605Smrg GLfloat (*col0)[4] = span->array->attribs[VARYING_SLOT_COL0]; 840848b8605Smrg GLfloat (*col1)[4] = span->array->attribs[VARYING_SLOT_COL1]; 841848b8605Smrg GLuint i; 842848b8605Smrg 843b8e80941Smrg assert(!_swrast_use_fragment_program(ctx)); 844b8e80941Smrg assert(span->arrayMask & SPAN_RGBA); 845b8e80941Smrg assert(swrast->_ActiveAttribMask & VARYING_BIT_COL1); 846848b8605Smrg (void) swrast; /* silence warning */ 847848b8605Smrg 848848b8605Smrg if (span->array->ChanType == GL_FLOAT) { 849848b8605Smrg if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) { 850848b8605Smrg interpolate_active_attribs(ctx, span, VARYING_BIT_COL0); 851848b8605Smrg } 852848b8605Smrg } 853848b8605Smrg else { 854848b8605Smrg /* need float colors */ 855848b8605Smrg if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) { 856848b8605Smrg interpolate_float_colors(span); 857848b8605Smrg } 858848b8605Smrg } 859848b8605Smrg 860848b8605Smrg if ((span->arrayAttribs & VARYING_BIT_COL1) == 0) { 861848b8605Smrg /* XXX could avoid this and interpolate COL1 in the loop below */ 862848b8605Smrg interpolate_active_attribs(ctx, span, VARYING_BIT_COL1); 863848b8605Smrg } 864848b8605Smrg 865b8e80941Smrg assert(span->arrayAttribs & VARYING_BIT_COL0); 866b8e80941Smrg assert(span->arrayAttribs & VARYING_BIT_COL1); 867848b8605Smrg 868848b8605Smrg for (i = 0; i < span->end; i++) { 869848b8605Smrg if (mask[i]) { 870848b8605Smrg col0[i][0] += col1[i][0]; 871848b8605Smrg col0[i][1] += col1[i][1]; 872848b8605Smrg col0[i][2] += col1[i][2]; 873848b8605Smrg } 874848b8605Smrg } 875848b8605Smrg 876848b8605Smrg span->array->ChanType = GL_FLOAT; 877848b8605Smrg} 878848b8605Smrg 879848b8605Smrg 880848b8605Smrg/** 881848b8605Smrg * Apply antialiasing coverage value to alpha values. 882848b8605Smrg */ 883848b8605Smrgstatic inline void 884848b8605Smrgapply_aa_coverage(SWspan *span) 885848b8605Smrg{ 886848b8605Smrg const GLfloat *coverage = span->array->coverage; 887848b8605Smrg GLuint i; 888848b8605Smrg if (span->array->ChanType == GL_UNSIGNED_BYTE) { 889848b8605Smrg GLubyte (*rgba)[4] = span->array->rgba8; 890848b8605Smrg for (i = 0; i < span->end; i++) { 891848b8605Smrg const GLfloat a = rgba[i][ACOMP] * coverage[i]; 892b8e80941Smrg rgba[i][ACOMP] = (GLubyte) CLAMP(a, 0.0F, 255.0F); 893b8e80941Smrg assert(coverage[i] >= 0.0F); 894b8e80941Smrg assert(coverage[i] <= 1.0F); 895848b8605Smrg } 896848b8605Smrg } 897848b8605Smrg else if (span->array->ChanType == GL_UNSIGNED_SHORT) { 898848b8605Smrg GLushort (*rgba)[4] = span->array->rgba16; 899848b8605Smrg for (i = 0; i < span->end; i++) { 900848b8605Smrg const GLfloat a = rgba[i][ACOMP] * coverage[i]; 901b8e80941Smrg rgba[i][ACOMP] = (GLushort) CLAMP(a, 0.0F, 65535.0F); 902848b8605Smrg } 903848b8605Smrg } 904848b8605Smrg else { 905848b8605Smrg GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0]; 906848b8605Smrg for (i = 0; i < span->end; i++) { 907848b8605Smrg rgba[i][ACOMP] = rgba[i][ACOMP] * coverage[i]; 908848b8605Smrg /* clamp later */ 909848b8605Smrg } 910848b8605Smrg } 911848b8605Smrg} 912848b8605Smrg 913848b8605Smrg 914848b8605Smrg/** 915848b8605Smrg * Clamp span's float colors to [0,1] 916848b8605Smrg */ 917848b8605Smrgstatic inline void 918848b8605Smrgclamp_colors(SWspan *span) 919848b8605Smrg{ 920848b8605Smrg GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0]; 921848b8605Smrg GLuint i; 922b8e80941Smrg assert(span->array->ChanType == GL_FLOAT); 923848b8605Smrg for (i = 0; i < span->end; i++) { 924848b8605Smrg rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F); 925848b8605Smrg rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F); 926848b8605Smrg rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F); 927848b8605Smrg rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F); 928848b8605Smrg } 929848b8605Smrg} 930848b8605Smrg 931848b8605Smrg 932848b8605Smrg/** 933848b8605Smrg * Convert the span's color arrays to the given type. 934848b8605Smrg * The only way 'output' can be greater than zero is when we have a fragment 935848b8605Smrg * program that writes to gl_FragData[1] or higher. 936848b8605Smrg * \param output which fragment program color output is being processed 937848b8605Smrg */ 938848b8605Smrgstatic inline void 939b8e80941Smrgconvert_color_type(SWspan *span, GLenum srcType, GLenum newType, GLuint output) 940848b8605Smrg{ 941848b8605Smrg GLvoid *src, *dst; 942848b8605Smrg 943b8e80941Smrg if (output > 0 || srcType == GL_FLOAT) { 944848b8605Smrg src = span->array->attribs[VARYING_SLOT_COL0 + output]; 945848b8605Smrg span->array->ChanType = GL_FLOAT; 946848b8605Smrg } 947b8e80941Smrg else if (srcType == GL_UNSIGNED_BYTE) { 948848b8605Smrg src = span->array->rgba8; 949848b8605Smrg } 950848b8605Smrg else { 951b8e80941Smrg assert(srcType == GL_UNSIGNED_SHORT); 952848b8605Smrg src = span->array->rgba16; 953848b8605Smrg } 954848b8605Smrg 955848b8605Smrg if (newType == GL_UNSIGNED_BYTE) { 956848b8605Smrg dst = span->array->rgba8; 957848b8605Smrg } 958848b8605Smrg else if (newType == GL_UNSIGNED_SHORT) { 959848b8605Smrg dst = span->array->rgba16; 960848b8605Smrg } 961848b8605Smrg else { 962848b8605Smrg dst = span->array->attribs[VARYING_SLOT_COL0]; 963848b8605Smrg } 964848b8605Smrg 965848b8605Smrg _mesa_convert_colors(span->array->ChanType, src, 966848b8605Smrg newType, dst, 967848b8605Smrg span->end, span->array->mask); 968848b8605Smrg 969848b8605Smrg span->array->ChanType = newType; 970848b8605Smrg span->array->rgba = dst; 971848b8605Smrg} 972848b8605Smrg 973848b8605Smrg 974848b8605Smrg 975848b8605Smrg/** 976848b8605Smrg * Apply fragment shader, fragment program or normal texturing to span. 977848b8605Smrg */ 978848b8605Smrgstatic inline void 979848b8605Smrgshade_texture_span(struct gl_context *ctx, SWspan *span) 980848b8605Smrg{ 981848b8605Smrg if (_swrast_use_fragment_program(ctx) || 982b8e80941Smrg _mesa_ati_fragment_shader_enabled(ctx)) { 983848b8605Smrg /* programmable shading */ 984848b8605Smrg if (span->primitive == GL_BITMAP && span->array->ChanType != GL_FLOAT) { 985b8e80941Smrg convert_color_type(span, span->array->ChanType, GL_FLOAT, 0); 986848b8605Smrg } 987848b8605Smrg else { 988848b8605Smrg span->array->rgba = (void *) span->array->attribs[VARYING_SLOT_COL0]; 989848b8605Smrg } 990848b8605Smrg 991848b8605Smrg if (span->primitive != GL_POINT || 992848b8605Smrg (span->interpMask & SPAN_RGBA) || 993848b8605Smrg ctx->Point.PointSprite) { 994848b8605Smrg /* for single-pixel points, we populated the arrays already */ 995848b8605Smrg interpolate_active_attribs(ctx, span, ~0); 996848b8605Smrg } 997848b8605Smrg span->array->ChanType = GL_FLOAT; 998848b8605Smrg 999848b8605Smrg if (!(span->arrayMask & SPAN_Z)) 1000848b8605Smrg _swrast_span_interpolate_z (ctx, span); 1001848b8605Smrg 1002848b8605Smrg#if 0 1003848b8605Smrg if (inputsRead & VARYING_BIT_POS) 1004848b8605Smrg#else 1005848b8605Smrg /* XXX always interpolate wpos so that DDX/DDY work */ 1006848b8605Smrg#endif 1007848b8605Smrg interpolate_wpos(ctx, span); 1008848b8605Smrg 1009848b8605Smrg /* Run fragment program/shader now */ 1010848b8605Smrg if (_swrast_use_fragment_program(ctx)) { 1011848b8605Smrg _swrast_exec_fragment_program(ctx, span); 1012848b8605Smrg } 1013848b8605Smrg else { 1014b8e80941Smrg assert(_mesa_ati_fragment_shader_enabled(ctx)); 1015848b8605Smrg _swrast_exec_fragment_shader(ctx, span); 1016848b8605Smrg } 1017848b8605Smrg } 1018848b8605Smrg else if (ctx->Texture._EnabledCoordUnits) { 1019848b8605Smrg /* conventional texturing */ 1020848b8605Smrg 1021848b8605Smrg#if CHAN_BITS == 32 1022848b8605Smrg if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) { 1023848b8605Smrg interpolate_int_colors(ctx, span); 1024848b8605Smrg } 1025848b8605Smrg#else 1026848b8605Smrg if (!(span->arrayMask & SPAN_RGBA)) 1027848b8605Smrg interpolate_int_colors(ctx, span); 1028848b8605Smrg#endif 1029848b8605Smrg if ((span->arrayAttribs & VARYING_BITS_TEX_ANY) == 0x0) 1030848b8605Smrg interpolate_texcoords(ctx, span); 1031848b8605Smrg 1032848b8605Smrg _swrast_texture_span(ctx, span); 1033848b8605Smrg } 1034848b8605Smrg} 1035848b8605Smrg 1036848b8605Smrg 1037848b8605Smrg/** Put colors at x/y locations into a renderbuffer */ 1038848b8605Smrgstatic void 1039848b8605Smrgput_values(struct gl_context *ctx, struct gl_renderbuffer *rb, 1040848b8605Smrg GLenum datatype, 1041848b8605Smrg GLuint count, const GLint x[], const GLint y[], 1042848b8605Smrg const void *values, const GLubyte *mask) 1043848b8605Smrg{ 1044848b8605Smrg gl_pack_ubyte_rgba_func pack_ubyte = NULL; 1045848b8605Smrg gl_pack_float_rgba_func pack_float = NULL; 1046848b8605Smrg GLuint i; 1047848b8605Smrg 1048848b8605Smrg if (datatype == GL_UNSIGNED_BYTE) 1049848b8605Smrg pack_ubyte = _mesa_get_pack_ubyte_rgba_function(rb->Format); 1050848b8605Smrg else 1051848b8605Smrg pack_float = _mesa_get_pack_float_rgba_function(rb->Format); 1052848b8605Smrg 1053848b8605Smrg for (i = 0; i < count; i++) { 1054848b8605Smrg if (mask[i]) { 1055848b8605Smrg GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]); 1056848b8605Smrg 1057848b8605Smrg if (datatype == GL_UNSIGNED_BYTE) { 1058848b8605Smrg pack_ubyte((const GLubyte *) values + 4 * i, dst); 1059848b8605Smrg } 1060848b8605Smrg else { 1061848b8605Smrg assert(datatype == GL_FLOAT); 1062848b8605Smrg pack_float((const GLfloat *) values + 4 * i, dst); 1063848b8605Smrg } 1064848b8605Smrg } 1065848b8605Smrg } 1066848b8605Smrg} 1067848b8605Smrg 1068848b8605Smrg 1069848b8605Smrg/** Put row of colors into renderbuffer */ 1070848b8605Smrgvoid 1071848b8605Smrg_swrast_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb, 1072848b8605Smrg GLenum datatype, 1073848b8605Smrg GLuint count, GLint x, GLint y, 1074848b8605Smrg const void *values, const GLubyte *mask) 1075848b8605Smrg{ 1076848b8605Smrg GLubyte *dst = _swrast_pixel_address(rb, x, y); 1077848b8605Smrg 1078848b8605Smrg if (!mask) { 1079848b8605Smrg if (datatype == GL_UNSIGNED_BYTE) { 1080848b8605Smrg _mesa_pack_ubyte_rgba_row(rb->Format, count, 1081848b8605Smrg (const GLubyte (*)[4]) values, dst); 1082848b8605Smrg } 1083848b8605Smrg else { 1084848b8605Smrg assert(datatype == GL_FLOAT); 1085848b8605Smrg _mesa_pack_float_rgba_row(rb->Format, count, 1086848b8605Smrg (const GLfloat (*)[4]) values, dst); 1087848b8605Smrg } 1088848b8605Smrg } 1089848b8605Smrg else { 1090848b8605Smrg const GLuint bpp = _mesa_get_format_bytes(rb->Format); 1091848b8605Smrg GLuint i, runLen, runStart; 1092848b8605Smrg /* We can't pass a 'mask' array to the _mesa_pack_rgba_row() functions 1093848b8605Smrg * so look for runs where mask=1... 1094848b8605Smrg */ 1095848b8605Smrg runLen = runStart = 0; 1096848b8605Smrg for (i = 0; i < count; i++) { 1097848b8605Smrg if (mask[i]) { 1098848b8605Smrg if (runLen == 0) 1099848b8605Smrg runStart = i; 1100848b8605Smrg runLen++; 1101848b8605Smrg } 1102848b8605Smrg 1103848b8605Smrg if (!mask[i] || i == count - 1) { 1104848b8605Smrg /* might be the end of a run of pixels */ 1105848b8605Smrg if (runLen > 0) { 1106848b8605Smrg if (datatype == GL_UNSIGNED_BYTE) { 1107848b8605Smrg _mesa_pack_ubyte_rgba_row(rb->Format, runLen, 1108848b8605Smrg (const GLubyte (*)[4]) values + runStart, 1109848b8605Smrg dst + runStart * bpp); 1110848b8605Smrg } 1111848b8605Smrg else { 1112848b8605Smrg assert(datatype == GL_FLOAT); 1113848b8605Smrg _mesa_pack_float_rgba_row(rb->Format, runLen, 1114848b8605Smrg (const GLfloat (*)[4]) values + runStart, 1115848b8605Smrg dst + runStart * bpp); 1116848b8605Smrg } 1117848b8605Smrg runLen = 0; 1118848b8605Smrg } 1119848b8605Smrg } 1120848b8605Smrg } 1121848b8605Smrg } 1122848b8605Smrg} 1123848b8605Smrg 1124848b8605Smrg 1125848b8605Smrg 1126848b8605Smrg/** 1127848b8605Smrg * Apply all the per-fragment operations to a span. 1128848b8605Smrg * This now includes texturing (_swrast_write_texture_span() is history). 1129848b8605Smrg * This function may modify any of the array values in the span. 1130848b8605Smrg * span->interpMask and span->arrayMask may be changed but will be restored 1131848b8605Smrg * to their original values before returning. 1132848b8605Smrg */ 1133848b8605Smrgvoid 1134848b8605Smrg_swrast_write_rgba_span( struct gl_context *ctx, SWspan *span) 1135848b8605Smrg{ 1136848b8605Smrg const SWcontext *swrast = SWRAST_CONTEXT(ctx); 1137848b8605Smrg const GLbitfield origInterpMask = span->interpMask; 1138848b8605Smrg const GLbitfield origArrayMask = span->arrayMask; 1139848b8605Smrg const GLbitfield64 origArrayAttribs = span->arrayAttribs; 1140848b8605Smrg const GLenum origChanType = span->array->ChanType; 1141848b8605Smrg void * const origRgba = span->array->rgba; 1142848b8605Smrg const GLboolean shader = (_swrast_use_fragment_program(ctx) 1143b8e80941Smrg || _mesa_ati_fragment_shader_enabled(ctx)); 1144848b8605Smrg const GLboolean shaderOrTexture = shader || ctx->Texture._EnabledCoordUnits; 1145848b8605Smrg struct gl_framebuffer *fb = ctx->DrawBuffer; 1146848b8605Smrg 1147848b8605Smrg /* 1148b8e80941Smrg printf("%s() interp 0x%x array 0x%x\n", __func__, 1149848b8605Smrg span->interpMask, span->arrayMask); 1150848b8605Smrg */ 1151848b8605Smrg 1152b8e80941Smrg assert(span->primitive == GL_POINT || 1153848b8605Smrg span->primitive == GL_LINE || 1154848b8605Smrg span->primitive == GL_POLYGON || 1155848b8605Smrg span->primitive == GL_BITMAP); 1156848b8605Smrg 1157848b8605Smrg /* Fragment write masks */ 1158848b8605Smrg if (span->arrayMask & SPAN_MASK) { 1159848b8605Smrg /* mask was initialized by caller, probably glBitmap */ 1160848b8605Smrg span->writeAll = GL_FALSE; 1161848b8605Smrg } 1162848b8605Smrg else { 1163848b8605Smrg memset(span->array->mask, 1, span->end); 1164848b8605Smrg span->writeAll = GL_TRUE; 1165848b8605Smrg } 1166848b8605Smrg 1167848b8605Smrg /* Clip to window/scissor box */ 1168848b8605Smrg if (!clip_span(ctx, span)) { 1169848b8605Smrg return; 1170848b8605Smrg } 1171848b8605Smrg 1172b8e80941Smrg assert(span->end <= SWRAST_MAX_WIDTH); 1173848b8605Smrg 1174848b8605Smrg /* Depth bounds test */ 1175848b8605Smrg if (ctx->Depth.BoundsTest && fb->Visual.depthBits > 0) { 1176848b8605Smrg if (!_swrast_depth_bounds_test(ctx, span)) { 1177848b8605Smrg return; 1178848b8605Smrg } 1179848b8605Smrg } 1180848b8605Smrg 1181848b8605Smrg#ifdef DEBUG 1182848b8605Smrg /* Make sure all fragments are within window bounds */ 1183848b8605Smrg if (span->arrayMask & SPAN_XY) { 1184848b8605Smrg /* array of pixel locations */ 1185848b8605Smrg GLuint i; 1186848b8605Smrg for (i = 0; i < span->end; i++) { 1187848b8605Smrg if (span->array->mask[i]) { 1188848b8605Smrg assert(span->array->x[i] >= fb->_Xmin); 1189848b8605Smrg assert(span->array->x[i] < fb->_Xmax); 1190848b8605Smrg assert(span->array->y[i] >= fb->_Ymin); 1191848b8605Smrg assert(span->array->y[i] < fb->_Ymax); 1192848b8605Smrg } 1193848b8605Smrg } 1194848b8605Smrg } 1195848b8605Smrg#endif 1196848b8605Smrg 1197848b8605Smrg /* Polygon Stippling */ 1198848b8605Smrg if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) { 1199848b8605Smrg stipple_polygon_span(ctx, span); 1200848b8605Smrg } 1201848b8605Smrg 1202848b8605Smrg /* This is the normal place to compute the fragment color/Z 1203848b8605Smrg * from texturing or shading. 1204848b8605Smrg */ 1205848b8605Smrg if (shaderOrTexture && !swrast->_DeferredTexture) { 1206848b8605Smrg shade_texture_span(ctx, span); 1207848b8605Smrg } 1208848b8605Smrg 1209848b8605Smrg /* Do the alpha test */ 1210848b8605Smrg if (ctx->Color.AlphaEnabled) { 1211848b8605Smrg if (!_swrast_alpha_test(ctx, span)) { 1212848b8605Smrg /* all fragments failed test */ 1213848b8605Smrg goto end; 1214848b8605Smrg } 1215848b8605Smrg } 1216848b8605Smrg 1217848b8605Smrg /* Stencil and Z testing */ 1218b8e80941Smrg if (_mesa_stencil_is_enabled(ctx) || ctx->Depth.Test) { 1219848b8605Smrg if (!(span->arrayMask & SPAN_Z)) 1220848b8605Smrg _swrast_span_interpolate_z(ctx, span); 1221848b8605Smrg 1222b8e80941Smrg if (ctx->Transform.DepthClampNear && ctx->Transform.DepthClampFar) 1223848b8605Smrg _swrast_depth_clamp_span(ctx, span); 1224848b8605Smrg 1225b8e80941Smrg if (_mesa_stencil_is_enabled(ctx)) { 1226848b8605Smrg /* Combined Z/stencil tests */ 1227848b8605Smrg if (!_swrast_stencil_and_ztest_span(ctx, span)) { 1228848b8605Smrg /* all fragments failed test */ 1229848b8605Smrg goto end; 1230848b8605Smrg } 1231848b8605Smrg } 1232848b8605Smrg else if (fb->Visual.depthBits > 0) { 1233848b8605Smrg /* Just regular depth testing */ 1234b8e80941Smrg assert(ctx->Depth.Test); 1235b8e80941Smrg assert(span->arrayMask & SPAN_Z); 1236848b8605Smrg if (!_swrast_depth_test_span(ctx, span)) { 1237848b8605Smrg /* all fragments failed test */ 1238848b8605Smrg goto end; 1239848b8605Smrg } 1240848b8605Smrg } 1241848b8605Smrg } 1242848b8605Smrg 1243848b8605Smrg if (ctx->Query.CurrentOcclusionObject) { 1244848b8605Smrg /* update count of 'passed' fragments */ 1245848b8605Smrg struct gl_query_object *q = ctx->Query.CurrentOcclusionObject; 1246848b8605Smrg GLuint i; 1247848b8605Smrg for (i = 0; i < span->end; i++) 1248848b8605Smrg q->Result += span->array->mask[i]; 1249848b8605Smrg } 1250848b8605Smrg 1251848b8605Smrg /* We had to wait until now to check for glColorMask(0,0,0,0) because of 1252848b8605Smrg * the occlusion test. 1253848b8605Smrg */ 1254b8e80941Smrg if (fb->_NumColorDrawBuffers == 1 && 1255b8e80941Smrg !GET_COLORMASK(ctx->Color.ColorMask, 0)) { 1256848b8605Smrg /* no colors to write */ 1257848b8605Smrg goto end; 1258848b8605Smrg } 1259848b8605Smrg 1260848b8605Smrg /* If we were able to defer fragment color computation to now, there's 1261848b8605Smrg * a good chance that many fragments will have already been killed by 1262848b8605Smrg * Z/stencil testing. 1263848b8605Smrg */ 1264848b8605Smrg if (shaderOrTexture && swrast->_DeferredTexture) { 1265848b8605Smrg shade_texture_span(ctx, span); 1266848b8605Smrg } 1267848b8605Smrg 1268848b8605Smrg#if CHAN_BITS == 32 1269848b8605Smrg if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) { 1270848b8605Smrg interpolate_active_attribs(ctx, span, VARYING_BIT_COL0); 1271848b8605Smrg } 1272848b8605Smrg#else 1273848b8605Smrg if ((span->arrayMask & SPAN_RGBA) == 0) { 1274848b8605Smrg interpolate_int_colors(ctx, span); 1275848b8605Smrg } 1276848b8605Smrg#endif 1277848b8605Smrg 1278b8e80941Smrg assert(span->arrayMask & SPAN_RGBA); 1279848b8605Smrg 1280848b8605Smrg if (span->primitive == GL_BITMAP || !swrast->SpecularVertexAdd) { 1281848b8605Smrg /* Add primary and specular (diffuse + specular) colors */ 1282848b8605Smrg if (!shader) { 1283848b8605Smrg if (ctx->Fog.ColorSumEnabled || 1284848b8605Smrg (ctx->Light.Enabled && 1285848b8605Smrg ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) { 1286848b8605Smrg add_specular(ctx, span); 1287848b8605Smrg } 1288848b8605Smrg } 1289848b8605Smrg } 1290848b8605Smrg 1291848b8605Smrg /* Fog */ 1292848b8605Smrg if (swrast->_FogEnabled) { 1293848b8605Smrg _swrast_fog_rgba_span(ctx, span); 1294848b8605Smrg } 1295848b8605Smrg 1296848b8605Smrg /* Antialias coverage application */ 1297848b8605Smrg if (span->arrayMask & SPAN_COVERAGE) { 1298848b8605Smrg apply_aa_coverage(span); 1299848b8605Smrg } 1300848b8605Smrg 1301848b8605Smrg /* Clamp color/alpha values over the range [0.0, 1.0] before storage */ 1302848b8605Smrg if (ctx->Color.ClampFragmentColor == GL_TRUE && 1303848b8605Smrg span->array->ChanType == GL_FLOAT) { 1304848b8605Smrg clamp_colors(span); 1305848b8605Smrg } 1306848b8605Smrg 1307848b8605Smrg /* 1308848b8605Smrg * Write to renderbuffers. 1309848b8605Smrg * Depending on glDrawBuffer() state and the which color outputs are 1310848b8605Smrg * written by the fragment shader, we may either replicate one color to 1311848b8605Smrg * all renderbuffers or write a different color to each renderbuffer. 1312848b8605Smrg * multiFragOutputs=TRUE for the later case. 1313848b8605Smrg */ 1314848b8605Smrg { 1315848b8605Smrg const GLuint numBuffers = fb->_NumColorDrawBuffers; 1316b8e80941Smrg const struct gl_program *fp = ctx->FragmentProgram._Current; 1317848b8605Smrg const GLboolean multiFragOutputs = 1318848b8605Smrg _swrast_use_fragment_program(ctx) 1319b8e80941Smrg && fp->info.outputs_written >= (1 << FRAG_RESULT_DATA0); 1320b8e80941Smrg /* Save srcColorType because convert_color_type() can change it */ 1321b8e80941Smrg const GLenum srcColorType = span->array->ChanType; 1322848b8605Smrg GLuint buf; 1323848b8605Smrg 1324848b8605Smrg for (buf = 0; buf < numBuffers; buf++) { 1325848b8605Smrg struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf]; 1326848b8605Smrg 1327848b8605Smrg /* color[fragOutput] will be written to buffer[buf] */ 1328848b8605Smrg 1329848b8605Smrg if (rb) { 1330848b8605Smrg /* re-use one of the attribute array buffers for rgbaSave */ 1331848b8605Smrg GLchan (*rgbaSave)[4] = (GLchan (*)[4]) span->array->attribs[0]; 1332848b8605Smrg struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 1333b8e80941Smrg const GLenum dstColorType = srb->ColorType; 1334848b8605Smrg 1335b8e80941Smrg assert(dstColorType == GL_UNSIGNED_BYTE || 1336b8e80941Smrg dstColorType == GL_FLOAT); 1337848b8605Smrg 1338848b8605Smrg /* set span->array->rgba to colors for renderbuffer's datatype */ 1339b8e80941Smrg if (srcColorType != dstColorType) { 1340b8e80941Smrg convert_color_type(span, srcColorType, dstColorType, 1341b8e80941Smrg multiFragOutputs ? buf : 0); 1342848b8605Smrg } 1343848b8605Smrg else { 1344b8e80941Smrg if (srcColorType == GL_UNSIGNED_BYTE) { 1345848b8605Smrg span->array->rgba = span->array->rgba8; 1346848b8605Smrg } 1347848b8605Smrg else { 1348848b8605Smrg span->array->rgba = (void *) 1349848b8605Smrg span->array->attribs[VARYING_SLOT_COL0]; 1350848b8605Smrg } 1351848b8605Smrg } 1352848b8605Smrg 1353848b8605Smrg if (!multiFragOutputs && numBuffers > 1) { 1354848b8605Smrg /* save colors for second, third renderbuffer writes */ 1355848b8605Smrg memcpy(rgbaSave, span->array->rgba, 1356848b8605Smrg 4 * span->end * sizeof(GLchan)); 1357848b8605Smrg } 1358848b8605Smrg 1359b8e80941Smrg assert(rb->_BaseFormat == GL_RGBA || 1360848b8605Smrg rb->_BaseFormat == GL_RGB || 1361848b8605Smrg rb->_BaseFormat == GL_RED || 1362848b8605Smrg rb->_BaseFormat == GL_RG || 1363848b8605Smrg rb->_BaseFormat == GL_ALPHA); 1364848b8605Smrg 1365848b8605Smrg if (ctx->Color.ColorLogicOpEnabled) { 1366848b8605Smrg _swrast_logicop_rgba_span(ctx, rb, span); 1367848b8605Smrg } 1368848b8605Smrg else if ((ctx->Color.BlendEnabled >> buf) & 1) { 1369848b8605Smrg _swrast_blend_span(ctx, rb, span); 1370848b8605Smrg } 1371848b8605Smrg 1372b8e80941Smrg if (GET_COLORMASK(ctx->Color.ColorMask, buf) != 0xf) { 1373848b8605Smrg _swrast_mask_rgba_span(ctx, rb, span, buf); 1374848b8605Smrg } 1375848b8605Smrg 1376848b8605Smrg if (span->arrayMask & SPAN_XY) { 1377848b8605Smrg /* array of pixel coords */ 1378848b8605Smrg put_values(ctx, rb, 1379848b8605Smrg span->array->ChanType, span->end, 1380848b8605Smrg span->array->x, span->array->y, 1381848b8605Smrg span->array->rgba, span->array->mask); 1382848b8605Smrg } 1383848b8605Smrg else { 1384848b8605Smrg /* horizontal run of pixels */ 1385848b8605Smrg _swrast_put_row(ctx, rb, 1386848b8605Smrg span->array->ChanType, 1387848b8605Smrg span->end, span->x, span->y, 1388848b8605Smrg span->array->rgba, 1389848b8605Smrg span->writeAll ? NULL: span->array->mask); 1390848b8605Smrg } 1391848b8605Smrg 1392848b8605Smrg if (!multiFragOutputs && numBuffers > 1) { 1393848b8605Smrg /* restore original span values */ 1394848b8605Smrg memcpy(span->array->rgba, rgbaSave, 1395848b8605Smrg 4 * span->end * sizeof(GLchan)); 1396848b8605Smrg } 1397848b8605Smrg 1398848b8605Smrg } /* if rb */ 1399848b8605Smrg } /* for buf */ 1400848b8605Smrg } 1401848b8605Smrg 1402848b8605Smrgend: 1403848b8605Smrg /* restore these values before returning */ 1404848b8605Smrg span->interpMask = origInterpMask; 1405848b8605Smrg span->arrayMask = origArrayMask; 1406848b8605Smrg span->arrayAttribs = origArrayAttribs; 1407848b8605Smrg span->array->ChanType = origChanType; 1408848b8605Smrg span->array->rgba = origRgba; 1409848b8605Smrg} 1410848b8605Smrg 1411848b8605Smrg 1412848b8605Smrg/** 1413848b8605Smrg * Read float RGBA pixels from a renderbuffer. Clipping will be done to 1414848b8605Smrg * prevent reading ouside the buffer's boundaries. 1415848b8605Smrg * \param rgba the returned colors 1416848b8605Smrg */ 1417848b8605Smrgvoid 1418848b8605Smrg_swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb, 1419848b8605Smrg GLuint n, GLint x, GLint y, 1420848b8605Smrg GLvoid *rgba) 1421848b8605Smrg{ 1422848b8605Smrg struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 1423848b8605Smrg GLenum dstType = GL_FLOAT; 1424848b8605Smrg const GLint bufWidth = (GLint) rb->Width; 1425848b8605Smrg const GLint bufHeight = (GLint) rb->Height; 1426848b8605Smrg 1427848b8605Smrg if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) { 1428848b8605Smrg /* completely above, below, or right */ 1429848b8605Smrg /* XXX maybe leave rgba values undefined? */ 1430848b8605Smrg memset(rgba, 0, 4 * n * sizeof(GLchan)); 1431848b8605Smrg } 1432848b8605Smrg else { 1433848b8605Smrg GLint skip, length; 1434848b8605Smrg GLubyte *src; 1435848b8605Smrg 1436848b8605Smrg if (x < 0) { 1437848b8605Smrg /* left edge clipping */ 1438848b8605Smrg skip = -x; 1439848b8605Smrg length = (GLint) n - skip; 1440848b8605Smrg if (length < 0) { 1441848b8605Smrg /* completely left of window */ 1442848b8605Smrg return; 1443848b8605Smrg } 1444848b8605Smrg if (length > bufWidth) { 1445848b8605Smrg length = bufWidth; 1446848b8605Smrg } 1447848b8605Smrg } 1448848b8605Smrg else if ((GLint) (x + n) > bufWidth) { 1449848b8605Smrg /* right edge clipping */ 1450848b8605Smrg skip = 0; 1451848b8605Smrg length = bufWidth - x; 1452848b8605Smrg if (length < 0) { 1453848b8605Smrg /* completely to right of window */ 1454848b8605Smrg return; 1455848b8605Smrg } 1456848b8605Smrg } 1457848b8605Smrg else { 1458848b8605Smrg /* no clipping */ 1459848b8605Smrg skip = 0; 1460848b8605Smrg length = (GLint) n; 1461848b8605Smrg } 1462848b8605Smrg 1463b8e80941Smrg assert(rb); 1464b8e80941Smrg assert(rb->_BaseFormat == GL_RGBA || 1465848b8605Smrg rb->_BaseFormat == GL_RGB || 1466848b8605Smrg rb->_BaseFormat == GL_RG || 1467848b8605Smrg rb->_BaseFormat == GL_RED || 1468848b8605Smrg rb->_BaseFormat == GL_LUMINANCE || 1469848b8605Smrg rb->_BaseFormat == GL_INTENSITY || 1470848b8605Smrg rb->_BaseFormat == GL_LUMINANCE_ALPHA || 1471848b8605Smrg rb->_BaseFormat == GL_ALPHA); 1472848b8605Smrg 1473848b8605Smrg assert(srb->Map); 1474b8e80941Smrg (void) srb; /* silence unused var warning */ 1475848b8605Smrg 1476848b8605Smrg src = _swrast_pixel_address(rb, x + skip, y); 1477848b8605Smrg 1478848b8605Smrg if (dstType == GL_UNSIGNED_BYTE) { 1479848b8605Smrg _mesa_unpack_ubyte_rgba_row(rb->Format, length, src, 1480848b8605Smrg (GLubyte (*)[4]) rgba + skip); 1481848b8605Smrg } 1482848b8605Smrg else if (dstType == GL_FLOAT) { 1483848b8605Smrg _mesa_unpack_rgba_row(rb->Format, length, src, 1484848b8605Smrg (GLfloat (*)[4]) rgba + skip); 1485848b8605Smrg } 1486848b8605Smrg else { 1487848b8605Smrg _mesa_problem(ctx, "unexpected type in _swrast_read_rgba_span()"); 1488848b8605Smrg } 1489848b8605Smrg } 1490848b8605Smrg} 1491848b8605Smrg 1492848b8605Smrg 1493848b8605Smrg/** 1494848b8605Smrg * Get colors at x/y positions with clipping. 1495848b8605Smrg * \param type type of values to return 1496848b8605Smrg */ 1497848b8605Smrgstatic void 1498848b8605Smrgget_values(struct gl_context *ctx, struct gl_renderbuffer *rb, 1499848b8605Smrg GLuint count, const GLint x[], const GLint y[], 1500848b8605Smrg void *values, GLenum type) 1501848b8605Smrg{ 1502848b8605Smrg GLuint i; 1503848b8605Smrg 1504848b8605Smrg for (i = 0; i < count; i++) { 1505848b8605Smrg if (x[i] >= 0 && y[i] >= 0 && 1506848b8605Smrg x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) { 1507848b8605Smrg /* inside */ 1508848b8605Smrg const GLubyte *src = _swrast_pixel_address(rb, x[i], y[i]); 1509848b8605Smrg 1510848b8605Smrg if (type == GL_UNSIGNED_BYTE) { 1511848b8605Smrg _mesa_unpack_ubyte_rgba_row(rb->Format, 1, src, 1512848b8605Smrg (GLubyte (*)[4]) values + i); 1513848b8605Smrg } 1514848b8605Smrg else if (type == GL_FLOAT) { 1515848b8605Smrg _mesa_unpack_rgba_row(rb->Format, 1, src, 1516848b8605Smrg (GLfloat (*)[4]) values + i); 1517848b8605Smrg } 1518848b8605Smrg else { 1519848b8605Smrg _mesa_problem(ctx, "unexpected type in get_values()"); 1520848b8605Smrg } 1521848b8605Smrg } 1522848b8605Smrg } 1523848b8605Smrg} 1524848b8605Smrg 1525848b8605Smrg 1526848b8605Smrg/** 1527848b8605Smrg * Get row of colors with clipping. 1528848b8605Smrg * \param type type of values to return 1529848b8605Smrg */ 1530848b8605Smrgstatic void 1531848b8605Smrgget_row(struct gl_context *ctx, struct gl_renderbuffer *rb, 1532848b8605Smrg GLuint count, GLint x, GLint y, 1533848b8605Smrg GLvoid *values, GLenum type) 1534848b8605Smrg{ 1535848b8605Smrg GLint skip = 0; 1536848b8605Smrg GLubyte *src; 1537848b8605Smrg 1538848b8605Smrg if (y < 0 || y >= (GLint) rb->Height) 1539848b8605Smrg return; /* above or below */ 1540848b8605Smrg 1541848b8605Smrg if (x + (GLint) count <= 0 || x >= (GLint) rb->Width) 1542848b8605Smrg return; /* entirely left or right */ 1543848b8605Smrg 1544848b8605Smrg if (x + count > rb->Width) { 1545848b8605Smrg /* right clip */ 1546848b8605Smrg GLint clip = x + count - rb->Width; 1547848b8605Smrg count -= clip; 1548848b8605Smrg } 1549848b8605Smrg 1550848b8605Smrg if (x < 0) { 1551848b8605Smrg /* left clip */ 1552848b8605Smrg skip = -x; 1553848b8605Smrg x = 0; 1554848b8605Smrg count -= skip; 1555848b8605Smrg } 1556848b8605Smrg 1557848b8605Smrg src = _swrast_pixel_address(rb, x, y); 1558848b8605Smrg 1559848b8605Smrg if (type == GL_UNSIGNED_BYTE) { 1560848b8605Smrg _mesa_unpack_ubyte_rgba_row(rb->Format, count, src, 1561848b8605Smrg (GLubyte (*)[4]) values + skip); 1562848b8605Smrg } 1563848b8605Smrg else if (type == GL_FLOAT) { 1564848b8605Smrg _mesa_unpack_rgba_row(rb->Format, count, src, 1565848b8605Smrg (GLfloat (*)[4]) values + skip); 1566848b8605Smrg } 1567848b8605Smrg else { 1568848b8605Smrg _mesa_problem(ctx, "unexpected type in get_row()"); 1569848b8605Smrg } 1570848b8605Smrg} 1571848b8605Smrg 1572848b8605Smrg 1573848b8605Smrg/** 1574848b8605Smrg * Get RGBA pixels from the given renderbuffer. 1575848b8605Smrg * Used by blending, logicop and masking functions. 1576848b8605Smrg * \return pointer to the colors we read. 1577848b8605Smrg */ 1578848b8605Smrgvoid * 1579848b8605Smrg_swrast_get_dest_rgba(struct gl_context *ctx, struct gl_renderbuffer *rb, 1580848b8605Smrg SWspan *span) 1581848b8605Smrg{ 1582848b8605Smrg void *rbPixels; 1583848b8605Smrg 1584848b8605Smrg /* Point rbPixels to a temporary space */ 1585848b8605Smrg rbPixels = span->array->attribs[VARYING_SLOT_MAX - 1]; 1586848b8605Smrg 1587848b8605Smrg /* Get destination values from renderbuffer */ 1588848b8605Smrg if (span->arrayMask & SPAN_XY) { 1589848b8605Smrg get_values(ctx, rb, span->end, span->array->x, span->array->y, 1590848b8605Smrg rbPixels, span->array->ChanType); 1591848b8605Smrg } 1592848b8605Smrg else { 1593848b8605Smrg get_row(ctx, rb, span->end, span->x, span->y, 1594848b8605Smrg rbPixels, span->array->ChanType); 1595848b8605Smrg } 1596848b8605Smrg 1597848b8605Smrg return rbPixels; 1598848b8605Smrg} 1599