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