Merge branch 'radeon-rewrite' of git+ssh://agd5f@git.freedesktop.org/git/mesa/mesa...
[mesa.git] / src / mesa / shader / slang / slang_builtin.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.3
4 *
5 * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
6 * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26 /**
27 * \file slang_builtin.c
28 * Resolve built-in uniform vars.
29 * \author Brian Paul
30 */
31
32 #include "main/imports.h"
33 #include "main/mtypes.h"
34 #include "shader/program.h"
35 #include "shader/prog_instruction.h"
36 #include "shader/prog_parameter.h"
37 #include "shader/prog_statevars.h"
38 #include "shader/slang/slang_ir.h"
39 #include "shader/slang/slang_emit.h"
40 #include "shader/slang/slang_builtin.h"
41
42
43 /** special state token (see below) */
44 #define STATE_ARRAY ((gl_state_index) 0xfffff)
45
46
47 /**
48 * Lookup GL state given a variable name, 0, 1 or 2 indexes and a field.
49 * Allocate room for the state in the given param list and return position
50 * in the list.
51 * Yes, this is kind of ugly, but it works.
52 */
53 static GLint
54 lookup_statevar(const char *var, GLint index1, GLint index2, const char *field,
55 GLuint *swizzleOut,
56 struct gl_program_parameter_list *paramList)
57 {
58 /*
59 * NOTE: The ARB_vertex_program extension specified that matrices get
60 * loaded in registers in row-major order. With GLSL, we want column-
61 * major order. So, we need to transpose all matrices here...
62 */
63 static const struct {
64 const char *name;
65 gl_state_index matrix;
66 gl_state_index modifier;
67 } matrices[] = {
68 { "gl_ModelViewMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE },
69 { "gl_ModelViewMatrixInverse", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVTRANS },
70 { "gl_ModelViewMatrixTranspose", STATE_MODELVIEW_MATRIX, 0 },
71 { "gl_ModelViewMatrixInverseTranspose", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE },
72
73 { "gl_ProjectionMatrix", STATE_PROJECTION_MATRIX, STATE_MATRIX_TRANSPOSE },
74 { "gl_ProjectionMatrixInverse", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVTRANS },
75 { "gl_ProjectionMatrixTranspose", STATE_PROJECTION_MATRIX, 0 },
76 { "gl_ProjectionMatrixInverseTranspose", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVERSE },
77
78 { "gl_ModelViewProjectionMatrix", STATE_MVP_MATRIX, STATE_MATRIX_TRANSPOSE },
79 { "gl_ModelViewProjectionMatrixInverse", STATE_MVP_MATRIX, STATE_MATRIX_INVTRANS },
80 { "gl_ModelViewProjectionMatrixTranspose", STATE_MVP_MATRIX, 0 },
81 { "gl_ModelViewProjectionMatrixInverseTranspose", STATE_MVP_MATRIX, STATE_MATRIX_INVERSE },
82
83 { "gl_TextureMatrix", STATE_TEXTURE_MATRIX, STATE_MATRIX_TRANSPOSE },
84 { "gl_TextureMatrixInverse", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVTRANS },
85 { "gl_TextureMatrixTranspose", STATE_TEXTURE_MATRIX, 0 },
86 { "gl_TextureMatrixInverseTranspose", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE },
87
88 { "gl_NormalMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE },
89
90 { NULL, 0, 0 }
91 };
92 gl_state_index tokens[STATE_LENGTH];
93 GLuint i;
94 GLboolean isMatrix = GL_FALSE;
95
96 for (i = 0; i < STATE_LENGTH; i++) {
97 tokens[i] = 0;
98 }
99 *swizzleOut = SWIZZLE_NOOP;
100
101 /* first, look if var is a pre-defined matrix */
102 for (i = 0; matrices[i].name; i++) {
103 if (strcmp(var, matrices[i].name) == 0) {
104 tokens[0] = matrices[i].matrix;
105 /* tokens[1], [2] and [3] filled below */
106 tokens[4] = matrices[i].modifier;
107 isMatrix = GL_TRUE;
108 break;
109 }
110 }
111
112 if (isMatrix) {
113 if (tokens[0] == STATE_TEXTURE_MATRIX) {
114 if (index1 >= 0) {
115 tokens[1] = index1; /* which texture matrix */
116 index1 = 0; /* prevent extra addition at end of function */
117 }
118 }
119 if (index1 < 0) {
120 /* index1 is unused: prevent extra addition at end of function */
121 index1 = 0;
122 }
123 }
124 else if (strcmp(var, "gl_DepthRange") == 0) {
125 tokens[0] = STATE_DEPTH_RANGE;
126 if (strcmp(field, "near") == 0) {
127 *swizzleOut = SWIZZLE_XXXX;
128 }
129 else if (strcmp(field, "far") == 0) {
130 *swizzleOut = SWIZZLE_YYYY;
131 }
132 else if (strcmp(field, "diff") == 0) {
133 *swizzleOut = SWIZZLE_ZZZZ;
134 }
135 else {
136 return -1;
137 }
138 }
139 else if (strcmp(var, "gl_ClipPlane") == 0) {
140 if (index1 < 0)
141 return -1;
142 tokens[0] = STATE_CLIPPLANE;
143 tokens[1] = index1;
144 }
145 else if (strcmp(var, "gl_Point") == 0) {
146 if (strcmp(field, "size") == 0) {
147 tokens[0] = STATE_POINT_SIZE;
148 *swizzleOut = SWIZZLE_XXXX;
149 }
150 else if (strcmp(field, "sizeMin") == 0) {
151 tokens[0] = STATE_POINT_SIZE;
152 *swizzleOut = SWIZZLE_YYYY;
153 }
154 else if (strcmp(field, "sizeMax") == 0) {
155 tokens[0] = STATE_POINT_SIZE;
156 *swizzleOut = SWIZZLE_ZZZZ;
157 }
158 else if (strcmp(field, "fadeThresholdSize") == 0) {
159 tokens[0] = STATE_POINT_SIZE;
160 *swizzleOut = SWIZZLE_WWWW;
161 }
162 else if (strcmp(field, "distanceConstantAttenuation") == 0) {
163 tokens[0] = STATE_POINT_ATTENUATION;
164 *swizzleOut = SWIZZLE_XXXX;
165 }
166 else if (strcmp(field, "distanceLinearAttenuation") == 0) {
167 tokens[0] = STATE_POINT_ATTENUATION;
168 *swizzleOut = SWIZZLE_YYYY;
169 }
170 else if (strcmp(field, "distanceQuadraticAttenuation") == 0) {
171 tokens[0] = STATE_POINT_ATTENUATION;
172 *swizzleOut = SWIZZLE_ZZZZ;
173 }
174 else {
175 return -1;
176 }
177 }
178 else if (strcmp(var, "gl_FrontMaterial") == 0 ||
179 strcmp(var, "gl_BackMaterial") == 0) {
180 tokens[0] = STATE_MATERIAL;
181 if (strcmp(var, "gl_FrontMaterial") == 0)
182 tokens[1] = 0;
183 else
184 tokens[1] = 1;
185 if (strcmp(field, "emission") == 0) {
186 tokens[2] = STATE_EMISSION;
187 }
188 else if (strcmp(field, "ambient") == 0) {
189 tokens[2] = STATE_AMBIENT;
190 }
191 else if (strcmp(field, "diffuse") == 0) {
192 tokens[2] = STATE_DIFFUSE;
193 }
194 else if (strcmp(field, "specular") == 0) {
195 tokens[2] = STATE_SPECULAR;
196 }
197 else if (strcmp(field, "shininess") == 0) {
198 tokens[2] = STATE_SHININESS;
199 *swizzleOut = SWIZZLE_XXXX;
200 }
201 else {
202 return -1;
203 }
204 }
205 else if (strcmp(var, "gl_LightSource") == 0) {
206 if (!field || index1 < 0)
207 return -1;
208
209 tokens[0] = STATE_LIGHT;
210 tokens[1] = index1;
211
212 if (strcmp(field, "ambient") == 0) {
213 tokens[2] = STATE_AMBIENT;
214 }
215 else if (strcmp(field, "diffuse") == 0) {
216 tokens[2] = STATE_DIFFUSE;
217 }
218 else if (strcmp(field, "specular") == 0) {
219 tokens[2] = STATE_SPECULAR;
220 }
221 else if (strcmp(field, "position") == 0) {
222 tokens[2] = STATE_POSITION;
223 }
224 else if (strcmp(field, "halfVector") == 0) {
225 tokens[2] = STATE_HALF_VECTOR;
226 }
227 else if (strcmp(field, "spotDirection") == 0) {
228 tokens[2] = STATE_SPOT_DIRECTION;
229 }
230 else if (strcmp(field, "spotCosCutoff") == 0) {
231 tokens[2] = STATE_SPOT_DIRECTION;
232 *swizzleOut = SWIZZLE_WWWW;
233 }
234 else if (strcmp(field, "spotCutoff") == 0) {
235 tokens[2] = STATE_SPOT_CUTOFF;
236 *swizzleOut = SWIZZLE_XXXX;
237 }
238 else if (strcmp(field, "spotExponent") == 0) {
239 tokens[2] = STATE_ATTENUATION;
240 *swizzleOut = SWIZZLE_WWWW;
241 }
242 else if (strcmp(field, "constantAttenuation") == 0) {
243 tokens[2] = STATE_ATTENUATION;
244 *swizzleOut = SWIZZLE_XXXX;
245 }
246 else if (strcmp(field, "linearAttenuation") == 0) {
247 tokens[2] = STATE_ATTENUATION;
248 *swizzleOut = SWIZZLE_YYYY;
249 }
250 else if (strcmp(field, "quadraticAttenuation") == 0) {
251 tokens[2] = STATE_ATTENUATION;
252 *swizzleOut = SWIZZLE_ZZZZ;
253 }
254 else {
255 return -1;
256 }
257 }
258 else if (strcmp(var, "gl_LightModel") == 0) {
259 if (strcmp(field, "ambient") == 0) {
260 tokens[0] = STATE_LIGHTMODEL_AMBIENT;
261 }
262 else {
263 return -1;
264 }
265 }
266 else if (strcmp(var, "gl_FrontLightModelProduct") == 0) {
267 if (strcmp(field, "sceneColor") == 0) {
268 tokens[0] = STATE_LIGHTMODEL_SCENECOLOR;
269 tokens[1] = 0;
270 }
271 else {
272 return -1;
273 }
274 }
275 else if (strcmp(var, "gl_BackLightModelProduct") == 0) {
276 if (strcmp(field, "sceneColor") == 0) {
277 tokens[0] = STATE_LIGHTMODEL_SCENECOLOR;
278 tokens[1] = 1;
279 }
280 else {
281 return -1;
282 }
283 }
284 else if (strcmp(var, "gl_FrontLightProduct") == 0 ||
285 strcmp(var, "gl_BackLightProduct") == 0) {
286 if (index1 < 0 || !field)
287 return -1;
288
289 tokens[0] = STATE_LIGHTPROD;
290 tokens[1] = index1; /* light number */
291 if (strcmp(var, "gl_FrontLightProduct") == 0) {
292 tokens[2] = 0; /* front */
293 }
294 else {
295 tokens[2] = 1; /* back */
296 }
297 if (strcmp(field, "ambient") == 0) {
298 tokens[3] = STATE_AMBIENT;
299 }
300 else if (strcmp(field, "diffuse") == 0) {
301 tokens[3] = STATE_DIFFUSE;
302 }
303 else if (strcmp(field, "specular") == 0) {
304 tokens[3] = STATE_SPECULAR;
305 }
306 else {
307 return -1;
308 }
309 }
310 else if (strcmp(var, "gl_TextureEnvColor") == 0) {
311 if (index1 < 0)
312 return -1;
313 tokens[0] = STATE_TEXENV_COLOR;
314 tokens[1] = index1;
315 }
316 else if (strcmp(var, "gl_EyePlaneS") == 0) {
317 if (index1 < 0)
318 return -1;
319 tokens[0] = STATE_TEXGEN;
320 tokens[1] = index1; /* tex unit */
321 tokens[2] = STATE_TEXGEN_EYE_S;
322 }
323 else if (strcmp(var, "gl_EyePlaneT") == 0) {
324 if (index1 < 0)
325 return -1;
326 tokens[0] = STATE_TEXGEN;
327 tokens[1] = index1; /* tex unit */
328 tokens[2] = STATE_TEXGEN_EYE_T;
329 }
330 else if (strcmp(var, "gl_EyePlaneR") == 0) {
331 if (index1 < 0)
332 return -1;
333 tokens[0] = STATE_TEXGEN;
334 tokens[1] = index1; /* tex unit */
335 tokens[2] = STATE_TEXGEN_EYE_R;
336 }
337 else if (strcmp(var, "gl_EyePlaneQ") == 0) {
338 if (index1 < 0)
339 return -1;
340 tokens[0] = STATE_TEXGEN;
341 tokens[1] = index1; /* tex unit */
342 tokens[2] = STATE_TEXGEN_EYE_Q;
343 }
344 else if (strcmp(var, "gl_ObjectPlaneS") == 0) {
345 if (index1 < 0)
346 return -1;
347 tokens[0] = STATE_TEXGEN;
348 tokens[1] = index1; /* tex unit */
349 tokens[2] = STATE_TEXGEN_OBJECT_S;
350 }
351 else if (strcmp(var, "gl_ObjectPlaneT") == 0) {
352 if (index1 < 0)
353 return -1;
354 tokens[0] = STATE_TEXGEN;
355 tokens[1] = index1; /* tex unit */
356 tokens[2] = STATE_TEXGEN_OBJECT_T;
357 }
358 else if (strcmp(var, "gl_ObjectPlaneR") == 0) {
359 if (index1 < 0)
360 return -1;
361 tokens[0] = STATE_TEXGEN;
362 tokens[1] = index1; /* tex unit */
363 tokens[2] = STATE_TEXGEN_OBJECT_R;
364 }
365 else if (strcmp(var, "gl_ObjectPlaneQ") == 0) {
366 if (index1 < 0)
367 return -1;
368 tokens[0] = STATE_TEXGEN;
369 tokens[1] = index1; /* tex unit */
370 tokens[2] = STATE_TEXGEN_OBJECT_Q;
371 }
372 else if (strcmp(var, "gl_Fog") == 0) {
373 if (strcmp(field, "color") == 0) {
374 tokens[0] = STATE_FOG_COLOR;
375 }
376 else if (strcmp(field, "density") == 0) {
377 tokens[0] = STATE_FOG_PARAMS;
378 *swizzleOut = SWIZZLE_XXXX;
379 }
380 else if (strcmp(field, "start") == 0) {
381 tokens[0] = STATE_FOG_PARAMS;
382 *swizzleOut = SWIZZLE_YYYY;
383 }
384 else if (strcmp(field, "end") == 0) {
385 tokens[0] = STATE_FOG_PARAMS;
386 *swizzleOut = SWIZZLE_ZZZZ;
387 }
388 else if (strcmp(field, "scale") == 0) {
389 tokens[0] = STATE_FOG_PARAMS;
390 *swizzleOut = SWIZZLE_WWWW;
391 }
392 else {
393 return -1;
394 }
395 }
396 else {
397 return -1;
398 }
399
400 if (isMatrix) {
401 /* load all four columns of matrix */
402 GLint pos[4];
403 GLuint j;
404 for (j = 0; j < 4; j++) {
405 tokens[2] = tokens[3] = j; /* jth row of matrix */
406 pos[j] = _mesa_add_state_reference(paramList, tokens);
407 assert(pos[j] >= 0);
408 ASSERT(pos[j] >= 0);
409 }
410 return pos[0] + index1;
411 }
412 else {
413 /* allocate a single register */
414 GLint pos = _mesa_add_state_reference(paramList, tokens);
415 ASSERT(pos >= 0);
416 return pos;
417 }
418 }
419
420
421
422 /**
423 * Given a variable name and datatype, emit uniform/constant buffer
424 * entries which will store that state variable.
425 * For example, if name="gl_LightSource" we'll emit 64 state variable
426 * vectors/references and return position where that data starts. This will
427 * allow run-time array indexing into the light source array.
428 *
429 * Note that this is a recursive function.
430 *
431 * \return -1 if error, else index of start of data in the program parameter list
432 */
433 static GLint
434 emit_statevars(const char *name, int array_len,
435 const slang_type_specifier *type,
436 gl_state_index tokens[STATE_LENGTH],
437 struct gl_program_parameter_list *paramList)
438 {
439 if (type->type == SLANG_SPEC_ARRAY) {
440 GLint i, pos;
441 assert(array_len > 0);
442 if (strcmp(name, "gl_ClipPlane") == 0) {
443 tokens[0] = STATE_CLIPPLANE;
444 }
445 else if (strcmp(name, "gl_LightSource") == 0) {
446 tokens[0] = STATE_LIGHT;
447 }
448 else if (strcmp(name, "gl_FrontLightProduct") == 0) {
449 tokens[0] = STATE_LIGHTPROD;
450 tokens[2] = 0; /* front */
451 }
452 else if (strcmp(name, "gl_BackLightProduct") == 0) {
453 tokens[0] = STATE_LIGHTPROD;
454 tokens[2] = 1; /* back */
455 }
456 else if (strcmp(name, "gl_TextureEnvColor") == 0) {
457 tokens[0] = STATE_TEXENV_COLOR;
458 }
459 else if (strcmp(name, "gl_EyePlaneS") == 0) {
460 tokens[0] = STATE_TEXGEN;
461 tokens[2] = STATE_TEXGEN_EYE_S;
462 }
463 else if (strcmp(name, "gl_EyePlaneT") == 0) {
464 tokens[0] = STATE_TEXGEN;
465 tokens[2] = STATE_TEXGEN_EYE_T;
466 }
467 else if (strcmp(name, "gl_EyePlaneR") == 0) {
468 tokens[0] = STATE_TEXGEN;
469 tokens[2] = STATE_TEXGEN_EYE_R;
470 }
471 else if (strcmp(name, "gl_EyePlaneQ") == 0) {
472 tokens[0] = STATE_TEXGEN;
473 tokens[2] = STATE_TEXGEN_EYE_Q;
474 }
475 else if (strcmp(name, "gl_ObjectPlaneS") == 0) {
476 tokens[0] = STATE_TEXGEN;
477 tokens[2] = STATE_TEXGEN_OBJECT_S;
478 }
479 else if (strcmp(name, "gl_ObjectPlaneT") == 0) {
480 tokens[0] = STATE_TEXGEN;
481 tokens[2] = STATE_TEXGEN_OBJECT_T;
482 }
483 else if (strcmp(name, "gl_ObjectPlaneR") == 0) {
484 tokens[0] = STATE_TEXGEN;
485 tokens[2] = STATE_TEXGEN_OBJECT_R;
486 }
487 else if (strcmp(name, "gl_ObjectPlaneQ") == 0) {
488 tokens[0] = STATE_TEXGEN;
489 tokens[2] = STATE_TEXGEN_OBJECT_Q;
490 }
491 else {
492 return -1; /* invalid array name */
493 }
494 for (i = 0; i < array_len; i++) {
495 GLint p;
496 tokens[1] = i;
497 p = emit_statevars(NULL, 0, type->_array, tokens, paramList);
498 if (i == 0)
499 pos = p;
500 }
501 return pos;
502 }
503 else if (type->type == SLANG_SPEC_STRUCT) {
504 const slang_variable_scope *fields = type->_struct->fields;
505 GLuint i, pos = 0;
506 for (i = 0; i < fields->num_variables; i++) {
507 const slang_variable *var = fields->variables[i];
508 GLint p = emit_statevars(var->a_name, 0, &var->type.specifier,
509 tokens, paramList);
510 if (i == 0)
511 pos = p;
512 }
513 return pos;
514 }
515 else {
516 GLint pos;
517 assert(type->type == SLANG_SPEC_VEC4 ||
518 type->type == SLANG_SPEC_VEC3 ||
519 type->type == SLANG_SPEC_VEC2 ||
520 type->type == SLANG_SPEC_FLOAT ||
521 type->type == SLANG_SPEC_IVEC4 ||
522 type->type == SLANG_SPEC_IVEC3 ||
523 type->type == SLANG_SPEC_IVEC2 ||
524 type->type == SLANG_SPEC_INT);
525 if (name) {
526 GLint t;
527
528 if (tokens[0] == STATE_LIGHT)
529 t = 2;
530 else if (tokens[0] == STATE_LIGHTPROD)
531 t = 3;
532 else
533 return -1; /* invalid array name */
534
535 if (strcmp(name, "ambient") == 0) {
536 tokens[t] = STATE_AMBIENT;
537 }
538 else if (strcmp(name, "diffuse") == 0) {
539 tokens[t] = STATE_DIFFUSE;
540 }
541 else if (strcmp(name, "specular") == 0) {
542 tokens[t] = STATE_SPECULAR;
543 }
544 else if (strcmp(name, "position") == 0) {
545 tokens[t] = STATE_POSITION;
546 }
547 else if (strcmp(name, "halfVector") == 0) {
548 tokens[t] = STATE_HALF_VECTOR;
549 }
550 else if (strcmp(name, "spotDirection") == 0) {
551 tokens[t] = STATE_SPOT_DIRECTION; /* xyz components */
552 }
553 else if (strcmp(name, "spotCosCutoff") == 0) {
554 tokens[t] = STATE_SPOT_DIRECTION; /* w component */
555 }
556
557 else if (strcmp(name, "constantAttenuation") == 0) {
558 tokens[t] = STATE_ATTENUATION; /* x component */
559 }
560 else if (strcmp(name, "linearAttenuation") == 0) {
561 tokens[t] = STATE_ATTENUATION; /* y component */
562 }
563 else if (strcmp(name, "quadraticAttenuation") == 0) {
564 tokens[t] = STATE_ATTENUATION; /* z component */
565 }
566 else if (strcmp(name, "spotExponent") == 0) {
567 tokens[t] = STATE_ATTENUATION; /* w = spot exponent */
568 }
569
570 else if (strcmp(name, "spotCutoff") == 0) {
571 tokens[t] = STATE_SPOT_CUTOFF; /* x component */
572 }
573
574 else {
575 return -1; /* invalid field name */
576 }
577 }
578
579 pos = _mesa_add_state_reference(paramList, tokens);
580 return pos;
581 }
582
583 return 1;
584 }
585
586
587 /**
588 * Unroll the named built-in uniform variable into a sequence of state
589 * vars in the given parameter list.
590 */
591 static GLint
592 alloc_state_var_array(const slang_variable *var,
593 struct gl_program_parameter_list *paramList)
594 {
595 gl_state_index tokens[STATE_LENGTH];
596 GLuint i;
597 GLint pos;
598
599 /* Initialize the state tokens array. This is very important.
600 * When we call _mesa_add_state_reference() it'll searches the parameter
601 * list to see if the given statevar token sequence is already present.
602 * This is normally a good thing since it prevents redundant values in the
603 * constant buffer.
604 *
605 * But when we're building arrays of state this can be bad. For example,
606 * consider this fragment of GLSL code:
607 * foo = gl_LightSource[3].diffuse;
608 * ...
609 * bar = gl_LightSource[i].diffuse;
610 *
611 * When we unroll the gl_LightSource array (for "bar") we want to re-emit
612 * gl_LightSource[3].diffuse and not re-use the first instance (from "foo")
613 * since that would upset the array layout. We handle this situation by
614 * setting the last token in the state var token array to the special
615 * value STATE_ARRAY.
616 * This token will only be set for array state. We can hijack the last
617 * element in the array for this since it's never used for light, clipplane
618 * or texture env array state.
619 */
620 for (i = 0; i < STATE_LENGTH; i++)
621 tokens[i] = 0;
622 tokens[STATE_LENGTH - 1] = STATE_ARRAY;
623
624 pos = emit_statevars(var->a_name, var->array_len, &var->type.specifier,
625 tokens, paramList);
626
627 return pos;
628 }
629
630
631
632 /**
633 * Allocate storage for a pre-defined uniform (a GL state variable).
634 * As a memory-saving optimization, we try to only allocate storage for
635 * state vars that are actually used.
636 *
637 * Arrays such as gl_LightSource are handled specially. For an expression
638 * like "gl_LightSource[2].diffuse", we can allocate a single uniform/constant
639 * slot and return the index. In this case, we return direct=TRUE.
640 *
641 * Buf for something like "gl_LightSource[i].diffuse" we don't know the value
642 * of 'i' at compile time so we need to "unroll" the gl_LightSource array
643 * into a consecutive sequence of uniform/constant slots so it can be indexed
644 * at runtime. In this case, we return direct=FALSE.
645 *
646 * Currently, all pre-defined uniforms are in one of these forms:
647 * var
648 * var[i]
649 * var.field
650 * var[i].field
651 * var[i][j]
652 *
653 * \return -1 upon error, else position in paramList of the state variable/data
654 */
655 GLint
656 _slang_alloc_statevar(slang_ir_node *n,
657 struct gl_program_parameter_list *paramList,
658 GLboolean *direct)
659 {
660 slang_ir_node *n0 = n;
661 const char *field = NULL;
662 GLint index1 = -1, index2 = -1;
663 GLuint swizzle;
664
665 *direct = GL_TRUE;
666
667 if (n->Opcode == IR_FIELD) {
668 field = n->Field;
669 n = n->Children[0];
670 }
671
672 if (n->Opcode == IR_ELEMENT) {
673 if (n->Children[1]->Opcode == IR_FLOAT) {
674 index1 = (GLint) n->Children[1]->Value[0];
675 }
676 else {
677 *direct = GL_FALSE;
678 }
679 n = n->Children[0];
680 }
681
682 if (n->Opcode == IR_ELEMENT) {
683 /* XXX can only handle constant indexes for now */
684 if (n->Children[1]->Opcode == IR_FLOAT) {
685 index2 = (GLint) n->Children[1]->Value[0];
686 }
687 else {
688 *direct = GL_FALSE;
689 }
690 n = n->Children[0];
691 }
692
693 assert(n->Opcode == IR_VAR);
694
695 if (*direct) {
696 const char *var = (const char *) n->Var->a_name;
697 GLint pos =
698 lookup_statevar(var, index1, index2, field, &swizzle, paramList);
699 if (pos >= 0) {
700 /* newly resolved storage for the statevar/constant/uniform */
701 n0->Store->File = PROGRAM_STATE_VAR;
702 n0->Store->Index = pos;
703 n0->Store->Swizzle = swizzle;
704 n0->Store->Parent = NULL;
705 return pos;
706 }
707 }
708
709 *direct = GL_FALSE;
710 return alloc_state_var_array(n->Var, paramList);
711 }