Merge branch 'master' into glsl2
[mesa.git] / src / mesa / swrast / s_fragprog.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.0.3
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "main/glheader.h"
26 #include "main/colormac.h"
27 #include "program/prog_instruction.h"
28
29 #include "s_fragprog.h"
30 #include "s_span.h"
31
32
33 /**
34 * Apply texture object's swizzle (X/Y/Z/W/0/1) to incoming 'texel'
35 * and return results in 'colorOut'.
36 */
37 static INLINE void
38 swizzle_texel(const GLfloat texel[4], GLfloat colorOut[4], GLuint swizzle)
39 {
40 if (swizzle == SWIZZLE_NOOP) {
41 COPY_4V(colorOut, texel);
42 }
43 else {
44 GLfloat vector[6];
45 vector[SWIZZLE_X] = texel[0];
46 vector[SWIZZLE_Y] = texel[1];
47 vector[SWIZZLE_Z] = texel[2];
48 vector[SWIZZLE_W] = texel[3];
49 vector[SWIZZLE_ZERO] = 0.0F;
50 vector[SWIZZLE_ONE] = 1.0F;
51 colorOut[0] = vector[GET_SWZ(swizzle, 0)];
52 colorOut[1] = vector[GET_SWZ(swizzle, 1)];
53 colorOut[2] = vector[GET_SWZ(swizzle, 2)];
54 colorOut[3] = vector[GET_SWZ(swizzle, 3)];
55 }
56 }
57
58
59 /**
60 * Fetch a texel with given lod.
61 * Called via machine->FetchTexelLod()
62 */
63 static void
64 fetch_texel_lod( GLcontext *ctx, const GLfloat texcoord[4], GLfloat lambda,
65 GLuint unit, GLfloat color[4] )
66 {
67 const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
68
69 if (texObj) {
70 SWcontext *swrast = SWRAST_CONTEXT(ctx);
71 GLfloat rgba[4];
72
73 lambda = CLAMP(lambda, texObj->MinLod, texObj->MaxLod);
74
75 swrast->TextureSample[unit](ctx, texObj, 1,
76 (const GLfloat (*)[4]) texcoord,
77 &lambda, &rgba);
78 swizzle_texel(rgba, color, texObj->_Swizzle);
79 }
80 else {
81 ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F);
82 }
83 }
84
85
86 /**
87 * Fetch a texel with the given partial derivatives to compute a level
88 * of detail in the mipmap.
89 * Called via machine->FetchTexelDeriv()
90 * \param lodBias the lod bias which may be specified by a TXB instruction,
91 * otherwise zero.
92 */
93 static void
94 fetch_texel_deriv( GLcontext *ctx, const GLfloat texcoord[4],
95 const GLfloat texdx[4], const GLfloat texdy[4],
96 GLfloat lodBias, GLuint unit, GLfloat color[4] )
97 {
98 SWcontext *swrast = SWRAST_CONTEXT(ctx);
99 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
100 const struct gl_texture_object *texObj = texUnit->_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[3], /* dq/dx, dq/dy */
113 texW, texH,
114 texcoord[0], texcoord[1], texcoord[3],
115 1.0F / texcoord[3]);
116
117 lambda += lodBias + texUnit->LodBias + texObj->LodBias;
118
119 lambda = CLAMP(lambda, texObj->MinLod, texObj->MaxLod);
120
121 swrast->TextureSample[unit](ctx, texObj, 1,
122 (const GLfloat (*)[4]) texcoord,
123 &lambda, &rgba);
124 swizzle_texel(rgba, color, texObj->_Swizzle);
125 }
126 else {
127 ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F);
128 }
129 }
130
131
132 /**
133 * Initialize the virtual fragment program machine state prior to running
134 * fragment program on a fragment. This involves initializing the input
135 * registers, condition codes, etc.
136 * \param machine the virtual machine state to init
137 * \param program the fragment program we're about to run
138 * \param span the span of pixels we'll operate on
139 * \param col which element (column) of the span we'll operate on
140 */
141 static void
142 init_machine(GLcontext *ctx, struct gl_program_machine *machine,
143 const struct gl_fragment_program *program,
144 const SWspan *span, GLuint col)
145 {
146 GLfloat *wpos = span->array->attribs[FRAG_ATTRIB_WPOS][col];
147
148 if (program->Base.Target == GL_FRAGMENT_PROGRAM_NV) {
149 /* Clear temporary registers (undefined for ARB_f_p) */
150 memset(machine->Temporaries, 0, MAX_PROGRAM_TEMPS * 4 * sizeof(GLfloat));
151 }
152
153 /* ARB_fragment_coord_conventions */
154 if (program->OriginUpperLeft)
155 wpos[1] = ctx->DrawBuffer->Height - 1 - wpos[1];
156 if (!program->PixelCenterInteger) {
157 wpos[0] += 0.5F;
158 wpos[1] += 0.5F;
159 }
160
161 /* Setup pointer to input attributes */
162 machine->Attribs = span->array->attribs;
163
164 machine->DerivX = (GLfloat (*)[4]) span->attrStepX;
165 machine->DerivY = (GLfloat (*)[4]) span->attrStepY;
166 machine->NumDeriv = FRAG_ATTRIB_MAX;
167
168 machine->Samplers = program->Base.SamplerUnits;
169
170 /* if running a GLSL program (not ARB_fragment_program) */
171 if (ctx->Shader.CurrentProgram) {
172 /* Store front/back facing value */
173 machine->Attribs[FRAG_ATTRIB_FACE][col][0] = 1.0F - span->facing;
174 }
175
176 machine->CurElement = col;
177
178 /* init condition codes */
179 machine->CondCodes[0] = COND_EQ;
180 machine->CondCodes[1] = COND_EQ;
181 machine->CondCodes[2] = COND_EQ;
182 machine->CondCodes[3] = COND_EQ;
183
184 /* init call stack */
185 machine->StackDepth = 0;
186
187 machine->FetchTexelLod = fetch_texel_lod;
188 machine->FetchTexelDeriv = fetch_texel_deriv;
189 }
190
191
192 /**
193 * Run fragment program on the pixels in span from 'start' to 'end' - 1.
194 */
195 static void
196 run_program(GLcontext *ctx, SWspan *span, GLuint start, GLuint end)
197 {
198 SWcontext *swrast = SWRAST_CONTEXT(ctx);
199 const struct gl_fragment_program *program = ctx->FragmentProgram._Current;
200 const GLbitfield64 outputsWritten = program->Base.OutputsWritten;
201 struct gl_program_machine *machine = &swrast->FragProgMachine;
202 GLuint i;
203
204 for (i = start; i < end; i++) {
205 if (span->array->mask[i]) {
206 init_machine(ctx, machine, program, span, i);
207
208 if (_mesa_execute_program(ctx, &program->Base, machine)) {
209
210 /* Store result color */
211 if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) {
212 COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0][i],
213 machine->Outputs[FRAG_RESULT_COLOR]);
214 }
215 else {
216 /* Multiple drawbuffers / render targets
217 * Note that colors beyond 0 and 1 will overwrite other
218 * attributes, such as FOGC, TEX0, TEX1, etc. That's OK.
219 */
220 GLuint buf;
221 for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
222 if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DATA0 + buf)) {
223 COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0 + buf][i],
224 machine->Outputs[FRAG_RESULT_DATA0 + buf]);
225 }
226 }
227 }
228
229 /* Store result depth/z */
230 if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
231 const GLfloat depth = machine->Outputs[FRAG_RESULT_DEPTH][2];
232 if (depth <= 0.0)
233 span->array->z[i] = 0;
234 else if (depth >= 1.0)
235 span->array->z[i] = ctx->DrawBuffer->_DepthMax;
236 else
237 span->array->z[i] = IROUND(depth * ctx->DrawBuffer->_DepthMaxF);
238 }
239 }
240 else {
241 /* killed fragment */
242 span->array->mask[i] = GL_FALSE;
243 span->writeAll = GL_FALSE;
244 }
245 }
246 }
247 }
248
249
250 /**
251 * Execute the current fragment program for all the fragments
252 * in the given span.
253 */
254 void
255 _swrast_exec_fragment_program( GLcontext *ctx, SWspan *span )
256 {
257 const struct gl_fragment_program *program = ctx->FragmentProgram._Current;
258
259 /* incoming colors should be floats */
260 if (program->Base.InputsRead & FRAG_BIT_COL0) {
261 ASSERT(span->array->ChanType == GL_FLOAT);
262 }
263
264 run_program(ctx, span, 0, span->end);
265
266 if (program->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) {
267 span->interpMask &= ~SPAN_RGBA;
268 span->arrayMask |= SPAN_RGBA;
269 }
270
271 if (program->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
272 span->interpMask &= ~SPAN_Z;
273 span->arrayMask |= SPAN_Z;
274 }
275 }
276