Merge commit 'origin/master' into gallium-0.2
[mesa.git] / src / mesa / shader / slang / slang_builtin.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.3
4 *
5 * Copyright (C) 2005-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 /**
26 * \file slang_builtin.c
27 * Resolve built-in uniform vars.
28 * \author Brian Paul
29 */
30
31 #include "main/imports.h"
32 #include "main/mtypes.h"
33 #include "shader/program.h"
34 #include "shader/prog_instruction.h"
35 #include "shader/prog_parameter.h"
36 #include "shader/prog_statevars.h"
37 #include "shader/slang/slang_ir.h"
38 #include "shader/slang/slang_emit.h"
39 #include "shader/slang/slang_builtin.h"
40
41
42 /**
43 * Lookup GL state given a variable name, 0, 1 or 2 indexes and a field.
44 * Allocate room for the state in the given param list and return position
45 * in the list.
46 * Yes, this is kind of ugly, but it works.
47 */
48 static GLint
49 lookup_statevar(const char *var, GLint index1, GLint index2, const char *field,
50 GLuint *swizzleOut,
51 struct gl_program_parameter_list *paramList)
52 {
53 /*
54 * NOTE: The ARB_vertex_program extension specified that matrices get
55 * loaded in registers in row-major order. With GLSL, we want column-
56 * major order. So, we need to transpose all matrices here...
57 */
58 static const struct {
59 const char *name;
60 gl_state_index matrix;
61 gl_state_index modifier;
62 } matrices[] = {
63 { "gl_ModelViewMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE },
64 { "gl_ModelViewMatrixInverse", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVTRANS },
65 { "gl_ModelViewMatrixTranspose", STATE_MODELVIEW_MATRIX, 0 },
66 { "gl_ModelViewMatrixInverseTranspose", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE },
67
68 { "gl_ProjectionMatrix", STATE_PROJECTION_MATRIX, STATE_MATRIX_TRANSPOSE },
69 { "gl_ProjectionMatrixInverse", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVTRANS },
70 { "gl_ProjectionMatrixTranspose", STATE_PROJECTION_MATRIX, 0 },
71 { "gl_ProjectionMatrixInverseTranspose", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVERSE },
72
73 { "gl_ModelViewProjectionMatrix", STATE_MVP_MATRIX, STATE_MATRIX_TRANSPOSE },
74 { "gl_ModelViewProjectionMatrixInverse", STATE_MVP_MATRIX, STATE_MATRIX_INVTRANS },
75 { "gl_ModelViewProjectionMatrixTranspose", STATE_MVP_MATRIX, 0 },
76 { "gl_ModelViewProjectionMatrixInverseTranspose", STATE_MVP_MATRIX, STATE_MATRIX_INVERSE },
77
78 { "gl_TextureMatrix", STATE_TEXTURE_MATRIX, STATE_MATRIX_TRANSPOSE },
79 { "gl_TextureMatrixInverse", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVTRANS },
80 { "gl_TextureMatrixTranspose", STATE_TEXTURE_MATRIX, 0 },
81 { "gl_TextureMatrixInverseTranspose", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE },
82
83 { "gl_NormalMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE },
84
85 { NULL, 0, 0 }
86 };
87 gl_state_index tokens[STATE_LENGTH];
88 GLuint i;
89 GLboolean isMatrix = GL_FALSE;
90
91 for (i = 0; i < STATE_LENGTH; i++) {
92 tokens[i] = 0;
93 }
94 *swizzleOut = SWIZZLE_NOOP;
95
96 /* first, look if var is a pre-defined matrix */
97 for (i = 0; matrices[i].name; i++) {
98 if (strcmp(var, matrices[i].name) == 0) {
99 tokens[0] = matrices[i].matrix;
100 /* tokens[1], [2] and [3] filled below */
101 tokens[4] = matrices[i].modifier;
102 isMatrix = GL_TRUE;
103 break;
104 }
105 }
106
107 if (isMatrix) {
108 if (tokens[0] == STATE_TEXTURE_MATRIX) {
109 if (index1 >= 0) {
110 tokens[1] = index1; /* which texture matrix */
111 index1 = 0; /* prevent extra addition at end of function */
112 }
113 }
114 if (index1 < 0) {
115 /* index1 is unused: prevent extra addition at end of function */
116 index1 = 0;
117 }
118 }
119 else if (strcmp(var, "gl_DepthRange") == 0) {
120 tokens[0] = STATE_DEPTH_RANGE;
121 if (strcmp(field, "near") == 0) {
122 *swizzleOut = SWIZZLE_XXXX;
123 }
124 else if (strcmp(field, "far") == 0) {
125 *swizzleOut = SWIZZLE_YYYY;
126 }
127 else if (strcmp(field, "diff") == 0) {
128 *swizzleOut = SWIZZLE_ZZZZ;
129 }
130 else {
131 return -1;
132 }
133 }
134 else if (strcmp(var, "gl_ClipPlane") == 0) {
135 tokens[0] = STATE_CLIPPLANE;
136 tokens[1] = index1;
137 }
138 else if (strcmp(var, "gl_Point") == 0) {
139 if (strcmp(field, "size") == 0) {
140 tokens[0] = STATE_POINT_SIZE;
141 *swizzleOut = SWIZZLE_XXXX;
142 }
143 else if (strcmp(field, "sizeMin") == 0) {
144 tokens[0] = STATE_POINT_SIZE;
145 *swizzleOut = SWIZZLE_YYYY;
146 }
147 else if (strcmp(field, "sizeMax") == 0) {
148 tokens[0] = STATE_POINT_SIZE;
149 *swizzleOut = SWIZZLE_ZZZZ;
150 }
151 else if (strcmp(field, "fadeThresholdSize") == 0) {
152 tokens[0] = STATE_POINT_SIZE;
153 *swizzleOut = SWIZZLE_WWWW;
154 }
155 else if (strcmp(field, "distanceConstantAttenuation") == 0) {
156 tokens[0] = STATE_POINT_ATTENUATION;
157 *swizzleOut = SWIZZLE_XXXX;
158 }
159 else if (strcmp(field, "distanceLinearAttenuation") == 0) {
160 tokens[0] = STATE_POINT_ATTENUATION;
161 *swizzleOut = SWIZZLE_YYYY;
162 }
163 else if (strcmp(field, "distanceQuadraticAttenuation") == 0) {
164 tokens[0] = STATE_POINT_ATTENUATION;
165 *swizzleOut = SWIZZLE_ZZZZ;
166 }
167 else {
168 return -1;
169 }
170 }
171 else if (strcmp(var, "gl_FrontMaterial") == 0 ||
172 strcmp(var, "gl_BackMaterial") == 0) {
173 tokens[0] = STATE_MATERIAL;
174 if (strcmp(var, "gl_FrontMaterial") == 0)
175 tokens[1] = 0;
176 else
177 tokens[1] = 1;
178 if (strcmp(field, "emission") == 0) {
179 tokens[2] = STATE_EMISSION;
180 }
181 else if (strcmp(field, "ambient") == 0) {
182 tokens[2] = STATE_AMBIENT;
183 }
184 else if (strcmp(field, "diffuse") == 0) {
185 tokens[2] = STATE_DIFFUSE;
186 }
187 else if (strcmp(field, "specular") == 0) {
188 tokens[2] = STATE_SPECULAR;
189 }
190 else if (strcmp(field, "shininess") == 0) {
191 tokens[2] = STATE_SHININESS;
192 *swizzleOut = SWIZZLE_XXXX;
193 }
194 else {
195 return -1;
196 }
197 }
198 else if (strcmp(var, "gl_LightSource") == 0) {
199 tokens[0] = STATE_LIGHT;
200 tokens[1] = index1;
201 if (strcmp(field, "ambient") == 0) {
202 tokens[2] = STATE_AMBIENT;
203 }
204 else if (strcmp(field, "diffuse") == 0) {
205 tokens[2] = STATE_DIFFUSE;
206 }
207 else if (strcmp(field, "specular") == 0) {
208 tokens[2] = STATE_SPECULAR;
209 }
210 else if (strcmp(field, "position") == 0) {
211 tokens[2] = STATE_POSITION;
212 }
213 else if (strcmp(field, "halfVector") == 0) {
214 tokens[2] = STATE_HALF_VECTOR;
215 }
216 else if (strcmp(field, "spotDirection") == 0) {
217 tokens[2] = STATE_SPOT_DIRECTION;
218 }
219 else if (strcmp(field, "spotCosCutoff") == 0) {
220 tokens[2] = STATE_SPOT_DIRECTION;
221 *swizzleOut = SWIZZLE_WWWW;
222 }
223 else if (strcmp(field, "spotCutoff") == 0) {
224 tokens[2] = STATE_SPOT_CUTOFF;
225 *swizzleOut = SWIZZLE_XXXX;
226 }
227 else if (strcmp(field, "spotExponent") == 0) {
228 tokens[2] = STATE_ATTENUATION;
229 *swizzleOut = SWIZZLE_WWWW;
230 }
231 else if (strcmp(field, "constantAttenuation") == 0) {
232 tokens[2] = STATE_ATTENUATION;
233 *swizzleOut = SWIZZLE_XXXX;
234 }
235 else if (strcmp(field, "linearAttenuation") == 0) {
236 tokens[2] = STATE_ATTENUATION;
237 *swizzleOut = SWIZZLE_YYYY;
238 }
239 else if (strcmp(field, "quadraticAttenuation") == 0) {
240 tokens[2] = STATE_ATTENUATION;
241 *swizzleOut = SWIZZLE_ZZZZ;
242 }
243 else {
244 return -1;
245 }
246 }
247 else if (strcmp(var, "gl_LightModel") == 0) {
248 if (strcmp(field, "ambient") == 0) {
249 tokens[0] = STATE_LIGHTMODEL_AMBIENT;
250 }
251 else {
252 return -1;
253 }
254 }
255 else if (strcmp(var, "gl_FrontLightModelProduct") == 0) {
256 if (strcmp(field, "sceneColor") == 0) {
257 tokens[0] = STATE_LIGHTMODEL_SCENECOLOR;
258 tokens[1] = 0;
259 }
260 else {
261 return -1;
262 }
263 }
264 else if (strcmp(var, "gl_BackLightModelProduct") == 0) {
265 if (strcmp(field, "sceneColor") == 0) {
266 tokens[0] = STATE_LIGHTMODEL_SCENECOLOR;
267 tokens[1] = 1;
268 }
269 else {
270 return -1;
271 }
272 }
273 else if (strcmp(var, "gl_FrontLightProduct") == 0 ||
274 strcmp(var, "gl_BackLightProduct") == 0) {
275 tokens[0] = STATE_LIGHTPROD;
276 tokens[1] = index1; /* light number */
277 if (strcmp(var, "gl_FrontLightProduct") == 0) {
278 tokens[2] = 0; /* front */
279 }
280 else {
281 tokens[2] = 1; /* back */
282 }
283 if (strcmp(field, "ambient") == 0) {
284 tokens[3] = STATE_AMBIENT;
285 }
286 else if (strcmp(field, "diffuse") == 0) {
287 tokens[3] = STATE_DIFFUSE;
288 }
289 else if (strcmp(field, "specular") == 0) {
290 tokens[3] = STATE_SPECULAR;
291 }
292 else {
293 return -1;
294 }
295 }
296 else if (strcmp(var, "gl_TextureEnvColor") == 0) {
297 tokens[0] = STATE_TEXENV_COLOR;
298 tokens[1] = index1;
299 }
300 else if (strcmp(var, "gl_EyePlaneS") == 0) {
301 tokens[0] = STATE_TEXGEN;
302 tokens[1] = index1; /* tex unit */
303 tokens[2] = STATE_TEXGEN_EYE_S;
304 }
305 else if (strcmp(var, "gl_EyePlaneT") == 0) {
306 tokens[0] = STATE_TEXGEN;
307 tokens[1] = index1; /* tex unit */
308 tokens[2] = STATE_TEXGEN_EYE_T;
309 }
310 else if (strcmp(var, "gl_EyePlaneR") == 0) {
311 tokens[0] = STATE_TEXGEN;
312 tokens[1] = index1; /* tex unit */
313 tokens[2] = STATE_TEXGEN_EYE_R;
314 }
315 else if (strcmp(var, "gl_EyePlaneQ") == 0) {
316 tokens[0] = STATE_TEXGEN;
317 tokens[1] = index1; /* tex unit */
318 tokens[2] = STATE_TEXGEN_EYE_Q;
319 }
320 else if (strcmp(var, "gl_ObjectPlaneS") == 0) {
321 tokens[0] = STATE_TEXGEN;
322 tokens[1] = index1; /* tex unit */
323 tokens[2] = STATE_TEXGEN_OBJECT_S;
324 }
325 else if (strcmp(var, "gl_ObjectPlaneT") == 0) {
326 tokens[0] = STATE_TEXGEN;
327 tokens[1] = index1; /* tex unit */
328 tokens[2] = STATE_TEXGEN_OBJECT_T;
329 }
330 else if (strcmp(var, "gl_ObjectPlaneR") == 0) {
331 tokens[0] = STATE_TEXGEN;
332 tokens[1] = index1; /* tex unit */
333 tokens[2] = STATE_TEXGEN_OBJECT_R;
334 }
335 else if (strcmp(var, "gl_ObjectPlaneQ") == 0) {
336 tokens[0] = STATE_TEXGEN;
337 tokens[1] = index1; /* tex unit */
338 tokens[2] = STATE_TEXGEN_OBJECT_Q;
339 }
340 else if (strcmp(var, "gl_Fog") == 0) {
341 if (strcmp(field, "color") == 0) {
342 tokens[0] = STATE_FOG_COLOR;
343 }
344 else if (strcmp(field, "density") == 0) {
345 tokens[0] = STATE_FOG_PARAMS;
346 *swizzleOut = SWIZZLE_XXXX;
347 }
348 else if (strcmp(field, "start") == 0) {
349 tokens[0] = STATE_FOG_PARAMS;
350 *swizzleOut = SWIZZLE_YYYY;
351 }
352 else if (strcmp(field, "end") == 0) {
353 tokens[0] = STATE_FOG_PARAMS;
354 *swizzleOut = SWIZZLE_ZZZZ;
355 }
356 else if (strcmp(field, "scale") == 0) {
357 tokens[0] = STATE_FOG_PARAMS;
358 *swizzleOut = SWIZZLE_WWWW;
359 }
360 else {
361 return -1;
362 }
363 }
364 else {
365 return -1;
366 }
367
368 if (isMatrix) {
369 /* load all four columns of matrix */
370 GLint pos[4];
371 GLuint j;
372 for (j = 0; j < 4; j++) {
373 tokens[2] = tokens[3] = j; /* jth row of matrix */
374 pos[j] = _mesa_add_state_reference(paramList, tokens);
375 assert(pos[j] >= 0);
376 ASSERT(pos[j] >= 0);
377 }
378 return pos[0] + index1;
379 }
380 else {
381 /* allocate a single register */
382 GLint pos = _mesa_add_state_reference(paramList, tokens);
383 ASSERT(pos >= 0);
384 return pos;
385 }
386 }
387
388
389 /**
390 * Allocate storage for a pre-defined uniform (a GL state variable).
391 * As a memory-saving optimization, we try to only allocate storage for
392 * state vars that are actually used.
393 * For example, the "gl_LightSource" uniform is huge. If we only use
394 * a handful of gl_LightSource fields, we don't want to allocate storage
395 * for all of gl_LightSource.
396 *
397 * Currently, all pre-defined uniforms are in one of these forms:
398 * var
399 * var[i]
400 * var.field
401 * var[i].field
402 * var[i][j]
403 *
404 * \return -1 upon error, else position in paramList of the state var/data
405 */
406 GLint
407 _slang_alloc_statevar(slang_ir_node *n,
408 struct gl_program_parameter_list *paramList)
409 {
410 slang_ir_node *n0 = n;
411 const char *field = NULL, *var;
412 GLint index1 = -1, index2 = -1, pos;
413 GLuint swizzle;
414
415 if (n->Opcode == IR_FIELD) {
416 field = n->Field;
417 n = n->Children[0];
418 }
419
420 if (n->Opcode == IR_ELEMENT) {
421 /* XXX can only handle constant indexes for now */
422 if (n->Children[1]->Opcode == IR_FLOAT) {
423 index1 = (GLint) n->Children[1]->Value[0];
424 n = n->Children[0];
425 }
426 else {
427 return -1;
428 }
429 }
430
431 if (n->Opcode == IR_ELEMENT) {
432 /* XXX can only handle constant indexes for now */
433 assert(n->Children[1]->Opcode == IR_FLOAT);
434 index2 = (GLint) n->Children[1]->Value[0];
435 n = n->Children[0];
436 }
437
438 assert(n->Opcode == IR_VAR);
439 var = (char *) n->Var->a_name;
440
441 pos = lookup_statevar(var, index1, index2, field, &swizzle, paramList);
442 assert(pos >= 0);
443 if (pos >= 0) {
444 /* newly resolved storage for the statevar/constant/uniform */
445 n0->Store->File = PROGRAM_STATE_VAR;
446 n0->Store->Index = pos;
447 n0->Store->Swizzle = swizzle;
448 n0->Store->Parent = NULL;
449 }
450 return pos;
451 }
452