s_fragprog.c revision de2afd8688ceb45013d15be7c6e0995199b80e5a
1762bb9d0ad20320b9f97a841dce57ba5e8e48b07Richard Smith/* 2523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * Mesa 3-D graphics library 3523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * Version: 7.0.3 4523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * 5523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * 7523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * Permission is hereby granted, free of charge, to any person obtaining a 8523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * copy of this software and associated documentation files (the "Software"), 9523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * to deal in the Software without restriction, including without limitation 10523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * and/or sell copies of the Software, and to permit persons to whom the 12523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * Software is furnished to do so, subject to the following conditions: 13523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * 14523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * The above copyright notice and this permission notice shall be included 15523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * in all copies or substantial portions of the Software. 16523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * 17523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor */ 24523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor 25523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor#include "main/glheader.h" 26523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor#include "main/colormac.h" 27523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor#include "main/context.h" 28523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor#include "main/texstate.h" 29523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor#include "shader/prog_instruction.h" 302559a7045a74679c80376305397a5953d038e1d0Douglas Gregor 31523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor#include "s_fragprog.h" 32523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor#include "s_span.h" 33523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor 34523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor 35523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor/** 36523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * Apply texture object's swizzle (X/Y/Z/W/0/1) to incoming 'texel' 37523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor * and return results in 'colorOut'. 38523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor */ 39523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregorstatic INLINE void 40523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregorswizzle_texel(const GLfloat texel[4], GLfloat colorOut[4], GLuint swizzle) 41523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor{ 42523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor if (swizzle == SWIZZLE_NOOP) { 43523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor COPY_4V(colorOut, texel); 44523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor } 45523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor else { 46523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor GLfloat vector[6]; 47523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor vector[SWIZZLE_X] = texel[0]; 48523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor vector[SWIZZLE_Y] = texel[1]; 49523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor vector[SWIZZLE_Z] = texel[2]; 50523d46af407f32fc53861e6f068e8076d4fe84a8Douglas Gregor vector[SWIZZLE_W] = texel[3]; 5157d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin vector[SWIZZLE_ZERO] = 0.0F; 5257d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin vector[SWIZZLE_ONE] = 1.0F; 5357d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin colorOut[0] = vector[GET_SWZ(swizzle, 0)]; 5457d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin colorOut[1] = vector[GET_SWZ(swizzle, 1)]; 5557d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin colorOut[2] = vector[GET_SWZ(swizzle, 2)]; 5657d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin colorOut[3] = vector[GET_SWZ(swizzle, 3)]; 5757d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin } 5857d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin} 5957d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin 6057d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin 6157d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin/** 6257d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin * Fetch a texel with given lod. 6357d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin * Called via machine->FetchTexelLod() 6457d12fd4a2bc739c4a4d62a364b7f08cd483c59eJeffrey Yasskin */ 65static void 66fetch_texel_lod( GLcontext *ctx, const GLfloat texcoord[4], GLfloat lambda, 67 GLuint unit, GLfloat color[4] ) 68{ 69 const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; 70 71 if (texObj) { 72 SWcontext *swrast = SWRAST_CONTEXT(ctx); 73 GLfloat rgba[4]; 74 75 lambda = CLAMP(lambda, texObj->MinLod, texObj->MaxLod); 76 77 /* XXX use a float-valued TextureSample routine here!!! */ 78 swrast->TextureSample[unit](ctx, texObj, 1, 79 (const GLfloat (*)[4]) texcoord, 80 &lambda, &rgba); 81 swizzle_texel(rgba, color, texObj->_Swizzle); 82 } 83 else { 84 ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F); 85 } 86} 87 88 89/** 90 * Fetch a texel with the given partial derivatives to compute a level 91 * of detail in the mipmap. 92 * Called via machine->FetchTexelDeriv() 93 */ 94static void 95fetch_texel_deriv( GLcontext *ctx, const GLfloat texcoord[4], 96 const GLfloat texdx[4], const GLfloat texdy[4], 97 GLfloat lodBias, GLuint unit, GLfloat color[4] ) 98{ 99 SWcontext *swrast = SWRAST_CONTEXT(ctx); 100 const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; 101 102 if (texObj) { 103 const struct gl_texture_image *texImg = 104 texObj->Image[0][texObj->BaseLevel]; 105 const GLfloat texW = (GLfloat) texImg->WidthScale; 106 const GLfloat texH = (GLfloat) texImg->HeightScale; 107 GLfloat lambda; 108 GLfloat rgba[4]; 109 110 lambda = _swrast_compute_lambda(texdx[0], texdy[0], /* ds/dx, ds/dy */ 111 texdx[1], texdy[1], /* dt/dx, dt/dy */ 112 texdx[3], texdy[2], /* dq/dx, dq/dy */ 113 texW, texH, 114 texcoord[0], texcoord[1], texcoord[3], 115 1.0F / texcoord[3]) + lodBias; 116 117 lambda = CLAMP(lambda, texObj->MinLod, texObj->MaxLod); 118 119 /* XXX use a float-valued TextureSample routine here!!! */ 120 swrast->TextureSample[unit](ctx, texObj, 1, 121 (const GLfloat (*)[4]) texcoord, 122 &lambda, &rgba); 123 swizzle_texel(rgba, color, texObj->_Swizzle); 124 } 125 else { 126 ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F); 127 } 128} 129 130 131/** 132 * Initialize the virtual fragment program machine state prior to running 133 * fragment program on a fragment. This involves initializing the input 134 * registers, condition codes, etc. 135 * \param machine the virtual machine state to init 136 * \param program the fragment program we're about to run 137 * \param span the span of pixels we'll operate on 138 * \param col which element (column) of the span we'll operate on 139 */ 140static void 141init_machine(GLcontext *ctx, struct gl_program_machine *machine, 142 const struct gl_fragment_program *program, 143 const SWspan *span, GLuint col) 144{ 145 if (program->Base.Target == GL_FRAGMENT_PROGRAM_NV) { 146 /* Clear temporary registers (undefined for ARB_f_p) */ 147 _mesa_bzero(machine->Temporaries, 148 MAX_PROGRAM_TEMPS * 4 * sizeof(GLfloat)); 149 } 150 151 /* Setup pointer to input attributes */ 152 machine->Attribs = span->array->attribs; 153 154 machine->DerivX = (GLfloat (*)[4]) span->attrStepX; 155 machine->DerivY = (GLfloat (*)[4]) span->attrStepY; 156 machine->NumDeriv = FRAG_ATTRIB_MAX; 157 158 machine->Samplers = program->Base.SamplerUnits; 159 160 /* if running a GLSL program (not ARB_fragment_program) */ 161 if (ctx->Shader.CurrentProgram) { 162 /* Store front/back facing value in register FOGC.Y */ 163 machine->Attribs[FRAG_ATTRIB_FOGC][col][1] = 1.0 - span->facing; 164 /* Note FOGC.ZW is gl_PointCoord if drawing a sprite */ 165 } 166 167 machine->CurElement = col; 168 169 /* init condition codes */ 170 machine->CondCodes[0] = COND_EQ; 171 machine->CondCodes[1] = COND_EQ; 172 machine->CondCodes[2] = COND_EQ; 173 machine->CondCodes[3] = COND_EQ; 174 175 /* init call stack */ 176 machine->StackDepth = 0; 177 178 machine->FetchTexelLod = fetch_texel_lod; 179 machine->FetchTexelDeriv = fetch_texel_deriv; 180} 181 182 183/** 184 * Run fragment program on the pixels in span from 'start' to 'end' - 1. 185 */ 186static void 187run_program(GLcontext *ctx, SWspan *span, GLuint start, GLuint end) 188{ 189 SWcontext *swrast = SWRAST_CONTEXT(ctx); 190 const struct gl_fragment_program *program = ctx->FragmentProgram._Current; 191 const GLbitfield outputsWritten = program->Base.OutputsWritten; 192 struct gl_program_machine *machine = &swrast->FragProgMachine; 193 GLuint i; 194 195 for (i = start; i < end; i++) { 196 if (span->array->mask[i]) { 197 init_machine(ctx, machine, program, span, i); 198 199 if (_mesa_execute_program(ctx, &program->Base, machine)) { 200 201 /* Store result color */ 202 if (outputsWritten & (1 << FRAG_RESULT_COLOR)) { 203 COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0][i], 204 machine->Outputs[FRAG_RESULT_COLOR]); 205 } 206 else { 207 /* Multiple drawbuffers / render targets 208 * Note that colors beyond 0 and 1 will overwrite other 209 * attributes, such as FOGC, TEX0, TEX1, etc. That's OK. 210 */ 211 GLuint buf; 212 for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) { 213 if (outputsWritten & (1 << (FRAG_RESULT_DATA0 + buf))) { 214 COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0 + buf][i], 215 machine->Outputs[FRAG_RESULT_DATA0 + buf]); 216 } 217 } 218 } 219 220 /* Store result depth/z */ 221 if (outputsWritten & (1 << FRAG_RESULT_DEPTH)) { 222 const GLfloat depth = machine->Outputs[FRAG_RESULT_DEPTH][2]; 223 if (depth <= 0.0) 224 span->array->z[i] = 0; 225 else if (depth >= 1.0) 226 span->array->z[i] = ctx->DrawBuffer->_DepthMax; 227 else 228 span->array->z[i] = IROUND(depth * ctx->DrawBuffer->_DepthMaxF); 229 } 230 } 231 else { 232 /* killed fragment */ 233 span->array->mask[i] = GL_FALSE; 234 span->writeAll = GL_FALSE; 235 } 236 } 237 } 238} 239 240 241/** 242 * Execute the current fragment program for all the fragments 243 * in the given span. 244 */ 245void 246_swrast_exec_fragment_program( GLcontext *ctx, SWspan *span ) 247{ 248 const struct gl_fragment_program *program = ctx->FragmentProgram._Current; 249 250 /* incoming colors should be floats */ 251 if (program->Base.InputsRead & FRAG_BIT_COL0) { 252 ASSERT(span->array->ChanType == GL_FLOAT); 253 } 254 255 run_program(ctx, span, 0, span->end); 256 257 if (program->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR)) { 258 span->interpMask &= ~SPAN_RGBA; 259 span->arrayMask |= SPAN_RGBA; 260 } 261 262 if (program->Base.OutputsWritten & (1 << FRAG_RESULT_DEPTH)) { 263 span->interpMask &= ~SPAN_Z; 264 span->arrayMask |= SPAN_Z; 265 } 266} 267 268