glsl: move predefined shader input/output info/code to slang_builtin.c
[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_INVERSE },
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 /* texture_matrix[index1][index2] */
115 tokens[1] = index1 >= 0 ? index1 : 0; /* which texture matrix */
116 index1 = index2; /* move matrix row value to index1 */
117 }
118 if (index1 < 0) {
119 /* index1 is unused: prevent extra addition at end of function */
120 index1 = 0;
121 }
122 }
123 else if (strcmp(var, "gl_DepthRange") == 0) {
124 tokens[0] = STATE_DEPTH_RANGE;
125 if (strcmp(field, "near") == 0) {
126 *swizzleOut = SWIZZLE_XXXX;
127 }
128 else if (strcmp(field, "far") == 0) {
129 *swizzleOut = SWIZZLE_YYYY;
130 }
131 else if (strcmp(field, "diff") == 0) {
132 *swizzleOut = SWIZZLE_ZZZZ;
133 }
134 else {
135 return -1;
136 }
137 }
138 else if (strcmp(var, "gl_ClipPlane") == 0) {
139 if (index1 < 0)
140 return -1;
141 tokens[0] = STATE_CLIPPLANE;
142 tokens[1] = index1;
143 }
144 else if (strcmp(var, "gl_Point") == 0) {
145 if (strcmp(field, "size") == 0) {
146 tokens[0] = STATE_POINT_SIZE;
147 *swizzleOut = SWIZZLE_XXXX;
148 }
149 else if (strcmp(field, "sizeMin") == 0) {
150 tokens[0] = STATE_POINT_SIZE;
151 *swizzleOut = SWIZZLE_YYYY;
152 }
153 else if (strcmp(field, "sizeMax") == 0) {
154 tokens[0] = STATE_POINT_SIZE;
155 *swizzleOut = SWIZZLE_ZZZZ;
156 }
157 else if (strcmp(field, "fadeThresholdSize") == 0) {
158 tokens[0] = STATE_POINT_SIZE;
159 *swizzleOut = SWIZZLE_WWWW;
160 }
161 else if (strcmp(field, "distanceConstantAttenuation") == 0) {
162 tokens[0] = STATE_POINT_ATTENUATION;
163 *swizzleOut = SWIZZLE_XXXX;
164 }
165 else if (strcmp(field, "distanceLinearAttenuation") == 0) {
166 tokens[0] = STATE_POINT_ATTENUATION;
167 *swizzleOut = SWIZZLE_YYYY;
168 }
169 else if (strcmp(field, "distanceQuadraticAttenuation") == 0) {
170 tokens[0] = STATE_POINT_ATTENUATION;
171 *swizzleOut = SWIZZLE_ZZZZ;
172 }
173 else {
174 return -1;
175 }
176 }
177 else if (strcmp(var, "gl_FrontMaterial") == 0 ||
178 strcmp(var, "gl_BackMaterial") == 0) {
179 tokens[0] = STATE_MATERIAL;
180 if (strcmp(var, "gl_FrontMaterial") == 0)
181 tokens[1] = 0;
182 else
183 tokens[1] = 1;
184 if (strcmp(field, "emission") == 0) {
185 tokens[2] = STATE_EMISSION;
186 }
187 else if (strcmp(field, "ambient") == 0) {
188 tokens[2] = STATE_AMBIENT;
189 }
190 else if (strcmp(field, "diffuse") == 0) {
191 tokens[2] = STATE_DIFFUSE;
192 }
193 else if (strcmp(field, "specular") == 0) {
194 tokens[2] = STATE_SPECULAR;
195 }
196 else if (strcmp(field, "shininess") == 0) {
197 tokens[2] = STATE_SHININESS;
198 *swizzleOut = SWIZZLE_XXXX;
199 }
200 else {
201 return -1;
202 }
203 }
204 else if (strcmp(var, "gl_LightSource") == 0) {
205 if (!field || index1 < 0)
206 return -1;
207
208 tokens[0] = STATE_LIGHT;
209 tokens[1] = index1;
210
211 if (strcmp(field, "ambient") == 0) {
212 tokens[2] = STATE_AMBIENT;
213 }
214 else if (strcmp(field, "diffuse") == 0) {
215 tokens[2] = STATE_DIFFUSE;
216 }
217 else if (strcmp(field, "specular") == 0) {
218 tokens[2] = STATE_SPECULAR;
219 }
220 else if (strcmp(field, "position") == 0) {
221 tokens[2] = STATE_POSITION;
222 }
223 else if (strcmp(field, "halfVector") == 0) {
224 tokens[2] = STATE_HALF_VECTOR;
225 }
226 else if (strcmp(field, "spotDirection") == 0) {
227 tokens[2] = STATE_SPOT_DIRECTION;
228 }
229 else if (strcmp(field, "spotCosCutoff") == 0) {
230 tokens[2] = STATE_SPOT_DIRECTION;
231 *swizzleOut = SWIZZLE_WWWW;
232 }
233 else if (strcmp(field, "spotCutoff") == 0) {
234 tokens[2] = STATE_SPOT_CUTOFF;
235 *swizzleOut = SWIZZLE_XXXX;
236 }
237 else if (strcmp(field, "spotExponent") == 0) {
238 tokens[2] = STATE_ATTENUATION;
239 *swizzleOut = SWIZZLE_WWWW;
240 }
241 else if (strcmp(field, "constantAttenuation") == 0) {
242 tokens[2] = STATE_ATTENUATION;
243 *swizzleOut = SWIZZLE_XXXX;
244 }
245 else if (strcmp(field, "linearAttenuation") == 0) {
246 tokens[2] = STATE_ATTENUATION;
247 *swizzleOut = SWIZZLE_YYYY;
248 }
249 else if (strcmp(field, "quadraticAttenuation") == 0) {
250 tokens[2] = STATE_ATTENUATION;
251 *swizzleOut = SWIZZLE_ZZZZ;
252 }
253 else {
254 return -1;
255 }
256 }
257 else if (strcmp(var, "gl_LightModel") == 0) {
258 if (strcmp(field, "ambient") == 0) {
259 tokens[0] = STATE_LIGHTMODEL_AMBIENT;
260 }
261 else {
262 return -1;
263 }
264 }
265 else if (strcmp(var, "gl_FrontLightModelProduct") == 0) {
266 if (strcmp(field, "sceneColor") == 0) {
267 tokens[0] = STATE_LIGHTMODEL_SCENECOLOR;
268 tokens[1] = 0;
269 }
270 else {
271 return -1;
272 }
273 }
274 else if (strcmp(var, "gl_BackLightModelProduct") == 0) {
275 if (strcmp(field, "sceneColor") == 0) {
276 tokens[0] = STATE_LIGHTMODEL_SCENECOLOR;
277 tokens[1] = 1;
278 }
279 else {
280 return -1;
281 }
282 }
283 else if (strcmp(var, "gl_FrontLightProduct") == 0 ||
284 strcmp(var, "gl_BackLightProduct") == 0) {
285 if (index1 < 0 || !field)
286 return -1;
287
288 tokens[0] = STATE_LIGHTPROD;
289 tokens[1] = index1; /* light number */
290 if (strcmp(var, "gl_FrontLightProduct") == 0) {
291 tokens[2] = 0; /* front */
292 }
293 else {
294 tokens[2] = 1; /* back */
295 }
296 if (strcmp(field, "ambient") == 0) {
297 tokens[3] = STATE_AMBIENT;
298 }
299 else if (strcmp(field, "diffuse") == 0) {
300 tokens[3] = STATE_DIFFUSE;
301 }
302 else if (strcmp(field, "specular") == 0) {
303 tokens[3] = STATE_SPECULAR;
304 }
305 else {
306 return -1;
307 }
308 }
309 else if (strcmp(var, "gl_TextureEnvColor") == 0) {
310 if (index1 < 0)
311 return -1;
312 tokens[0] = STATE_TEXENV_COLOR;
313 tokens[1] = index1;
314 }
315 else if (strcmp(var, "gl_EyePlaneS") == 0) {
316 if (index1 < 0)
317 return -1;
318 tokens[0] = STATE_TEXGEN;
319 tokens[1] = index1; /* tex unit */
320 tokens[2] = STATE_TEXGEN_EYE_S;
321 }
322 else if (strcmp(var, "gl_EyePlaneT") == 0) {
323 if (index1 < 0)
324 return -1;
325 tokens[0] = STATE_TEXGEN;
326 tokens[1] = index1; /* tex unit */
327 tokens[2] = STATE_TEXGEN_EYE_T;
328 }
329 else if (strcmp(var, "gl_EyePlaneR") == 0) {
330 if (index1 < 0)
331 return -1;
332 tokens[0] = STATE_TEXGEN;
333 tokens[1] = index1; /* tex unit */
334 tokens[2] = STATE_TEXGEN_EYE_R;
335 }
336 else if (strcmp(var, "gl_EyePlaneQ") == 0) {
337 if (index1 < 0)
338 return -1;
339 tokens[0] = STATE_TEXGEN;
340 tokens[1] = index1; /* tex unit */
341 tokens[2] = STATE_TEXGEN_EYE_Q;
342 }
343 else if (strcmp(var, "gl_ObjectPlaneS") == 0) {
344 if (index1 < 0)
345 return -1;
346 tokens[0] = STATE_TEXGEN;
347 tokens[1] = index1; /* tex unit */
348 tokens[2] = STATE_TEXGEN_OBJECT_S;
349 }
350 else if (strcmp(var, "gl_ObjectPlaneT") == 0) {
351 if (index1 < 0)
352 return -1;
353 tokens[0] = STATE_TEXGEN;
354 tokens[1] = index1; /* tex unit */
355 tokens[2] = STATE_TEXGEN_OBJECT_T;
356 }
357 else if (strcmp(var, "gl_ObjectPlaneR") == 0) {
358 if (index1 < 0)
359 return -1;
360 tokens[0] = STATE_TEXGEN;
361 tokens[1] = index1; /* tex unit */
362 tokens[2] = STATE_TEXGEN_OBJECT_R;
363 }
364 else if (strcmp(var, "gl_ObjectPlaneQ") == 0) {
365 if (index1 < 0)
366 return -1;
367 tokens[0] = STATE_TEXGEN;
368 tokens[1] = index1; /* tex unit */
369 tokens[2] = STATE_TEXGEN_OBJECT_Q;
370 }
371 else if (strcmp(var, "gl_Fog") == 0) {
372 if (strcmp(field, "color") == 0) {
373 tokens[0] = STATE_FOG_COLOR;
374 }
375 else if (strcmp(field, "density") == 0) {
376 tokens[0] = STATE_FOG_PARAMS;
377 *swizzleOut = SWIZZLE_XXXX;
378 }
379 else if (strcmp(field, "start") == 0) {
380 tokens[0] = STATE_FOG_PARAMS;
381 *swizzleOut = SWIZZLE_YYYY;
382 }
383 else if (strcmp(field, "end") == 0) {
384 tokens[0] = STATE_FOG_PARAMS;
385 *swizzleOut = SWIZZLE_ZZZZ;
386 }
387 else if (strcmp(field, "scale") == 0) {
388 tokens[0] = STATE_FOG_PARAMS;
389 *swizzleOut = SWIZZLE_WWWW;
390 }
391 else {
392 return -1;
393 }
394 }
395 else {
396 return -1;
397 }
398
399 if (isMatrix) {
400 /* load all four columns of matrix */
401 GLint pos[4];
402 GLuint j;
403 for (j = 0; j < 4; j++) {
404 tokens[2] = tokens[3] = j; /* jth row of matrix */
405 pos[j] = _mesa_add_state_reference(paramList, tokens);
406 assert(pos[j] >= 0);
407 ASSERT(pos[j] >= 0);
408 }
409 return pos[0] + index1;
410 }
411 else {
412 /* allocate a single register */
413 GLint pos = _mesa_add_state_reference(paramList, tokens);
414 ASSERT(pos >= 0);
415 return pos;
416 }
417 }
418
419
420
421 /**
422 * Given a variable name and datatype, emit uniform/constant buffer
423 * entries which will store that state variable.
424 * For example, if name="gl_LightSource" we'll emit 64 state variable
425 * vectors/references and return position where that data starts. This will
426 * allow run-time array indexing into the light source array.
427 *
428 * Note that this is a recursive function.
429 *
430 * \return -1 if error, else index of start of data in the program parameter list
431 */
432 static GLint
433 emit_statevars(const char *name, int array_len,
434 const slang_type_specifier *type,
435 gl_state_index tokens[STATE_LENGTH],
436 struct gl_program_parameter_list *paramList)
437 {
438 if (type->type == SLANG_SPEC_ARRAY) {
439 GLint i, pos;
440 assert(array_len > 0);
441 if (strcmp(name, "gl_ClipPlane") == 0) {
442 tokens[0] = STATE_CLIPPLANE;
443 }
444 else if (strcmp(name, "gl_LightSource") == 0) {
445 tokens[0] = STATE_LIGHT;
446 }
447 else if (strcmp(name, "gl_FrontLightProduct") == 0) {
448 tokens[0] = STATE_LIGHTPROD;
449 tokens[2] = 0; /* front */
450 }
451 else if (strcmp(name, "gl_BackLightProduct") == 0) {
452 tokens[0] = STATE_LIGHTPROD;
453 tokens[2] = 1; /* back */
454 }
455 else if (strcmp(name, "gl_TextureEnvColor") == 0) {
456 tokens[0] = STATE_TEXENV_COLOR;
457 }
458 else if (strcmp(name, "gl_EyePlaneS") == 0) {
459 tokens[0] = STATE_TEXGEN;
460 tokens[2] = STATE_TEXGEN_EYE_S;
461 }
462 else if (strcmp(name, "gl_EyePlaneT") == 0) {
463 tokens[0] = STATE_TEXGEN;
464 tokens[2] = STATE_TEXGEN_EYE_T;
465 }
466 else if (strcmp(name, "gl_EyePlaneR") == 0) {
467 tokens[0] = STATE_TEXGEN;
468 tokens[2] = STATE_TEXGEN_EYE_R;
469 }
470 else if (strcmp(name, "gl_EyePlaneQ") == 0) {
471 tokens[0] = STATE_TEXGEN;
472 tokens[2] = STATE_TEXGEN_EYE_Q;
473 }
474 else if (strcmp(name, "gl_ObjectPlaneS") == 0) {
475 tokens[0] = STATE_TEXGEN;
476 tokens[2] = STATE_TEXGEN_OBJECT_S;
477 }
478 else if (strcmp(name, "gl_ObjectPlaneT") == 0) {
479 tokens[0] = STATE_TEXGEN;
480 tokens[2] = STATE_TEXGEN_OBJECT_T;
481 }
482 else if (strcmp(name, "gl_ObjectPlaneR") == 0) {
483 tokens[0] = STATE_TEXGEN;
484 tokens[2] = STATE_TEXGEN_OBJECT_R;
485 }
486 else if (strcmp(name, "gl_ObjectPlaneQ") == 0) {
487 tokens[0] = STATE_TEXGEN;
488 tokens[2] = STATE_TEXGEN_OBJECT_Q;
489 }
490 else {
491 return -1; /* invalid array name */
492 }
493 for (i = 0; i < array_len; i++) {
494 GLint p;
495 tokens[1] = i;
496 p = emit_statevars(NULL, 0, type->_array, tokens, paramList);
497 if (i == 0)
498 pos = p;
499 }
500 return pos;
501 }
502 else if (type->type == SLANG_SPEC_STRUCT) {
503 const slang_variable_scope *fields = type->_struct->fields;
504 GLuint i, pos = 0;
505 for (i = 0; i < fields->num_variables; i++) {
506 const slang_variable *var = fields->variables[i];
507 GLint p = emit_statevars(var->a_name, 0, &var->type.specifier,
508 tokens, paramList);
509 if (i == 0)
510 pos = p;
511 }
512 return pos;
513 }
514 else {
515 GLint pos;
516 assert(type->type == SLANG_SPEC_VEC4 ||
517 type->type == SLANG_SPEC_VEC3 ||
518 type->type == SLANG_SPEC_VEC2 ||
519 type->type == SLANG_SPEC_FLOAT ||
520 type->type == SLANG_SPEC_IVEC4 ||
521 type->type == SLANG_SPEC_IVEC3 ||
522 type->type == SLANG_SPEC_IVEC2 ||
523 type->type == SLANG_SPEC_INT);
524 if (name) {
525 GLint t;
526
527 if (tokens[0] == STATE_LIGHT)
528 t = 2;
529 else if (tokens[0] == STATE_LIGHTPROD)
530 t = 3;
531 else
532 return -1; /* invalid array name */
533
534 if (strcmp(name, "ambient") == 0) {
535 tokens[t] = STATE_AMBIENT;
536 }
537 else if (strcmp(name, "diffuse") == 0) {
538 tokens[t] = STATE_DIFFUSE;
539 }
540 else if (strcmp(name, "specular") == 0) {
541 tokens[t] = STATE_SPECULAR;
542 }
543 else if (strcmp(name, "position") == 0) {
544 tokens[t] = STATE_POSITION;
545 }
546 else if (strcmp(name, "halfVector") == 0) {
547 tokens[t] = STATE_HALF_VECTOR;
548 }
549 else if (strcmp(name, "spotDirection") == 0) {
550 tokens[t] = STATE_SPOT_DIRECTION; /* xyz components */
551 }
552 else if (strcmp(name, "spotCosCutoff") == 0) {
553 tokens[t] = STATE_SPOT_DIRECTION; /* w component */
554 }
555
556 else if (strcmp(name, "constantAttenuation") == 0) {
557 tokens[t] = STATE_ATTENUATION; /* x component */
558 }
559 else if (strcmp(name, "linearAttenuation") == 0) {
560 tokens[t] = STATE_ATTENUATION; /* y component */
561 }
562 else if (strcmp(name, "quadraticAttenuation") == 0) {
563 tokens[t] = STATE_ATTENUATION; /* z component */
564 }
565 else if (strcmp(name, "spotExponent") == 0) {
566 tokens[t] = STATE_ATTENUATION; /* w = spot exponent */
567 }
568
569 else if (strcmp(name, "spotCutoff") == 0) {
570 tokens[t] = STATE_SPOT_CUTOFF; /* x component */
571 }
572
573 else {
574 return -1; /* invalid field name */
575 }
576 }
577
578 pos = _mesa_add_state_reference(paramList, tokens);
579 return pos;
580 }
581
582 return 1;
583 }
584
585
586 /**
587 * Unroll the named built-in uniform variable into a sequence of state
588 * vars in the given parameter list.
589 */
590 static GLint
591 alloc_state_var_array(const slang_variable *var,
592 struct gl_program_parameter_list *paramList)
593 {
594 gl_state_index tokens[STATE_LENGTH];
595 GLuint i;
596 GLint pos;
597
598 /* Initialize the state tokens array. This is very important.
599 * When we call _mesa_add_state_reference() it'll searches the parameter
600 * list to see if the given statevar token sequence is already present.
601 * This is normally a good thing since it prevents redundant values in the
602 * constant buffer.
603 *
604 * But when we're building arrays of state this can be bad. For example,
605 * consider this fragment of GLSL code:
606 * foo = gl_LightSource[3].diffuse;
607 * ...
608 * bar = gl_LightSource[i].diffuse;
609 *
610 * When we unroll the gl_LightSource array (for "bar") we want to re-emit
611 * gl_LightSource[3].diffuse and not re-use the first instance (from "foo")
612 * since that would upset the array layout. We handle this situation by
613 * setting the last token in the state var token array to the special
614 * value STATE_ARRAY.
615 * This token will only be set for array state. We can hijack the last
616 * element in the array for this since it's never used for light, clipplane
617 * or texture env array state.
618 */
619 for (i = 0; i < STATE_LENGTH; i++)
620 tokens[i] = 0;
621 tokens[STATE_LENGTH - 1] = STATE_ARRAY;
622
623 pos = emit_statevars(var->a_name, var->array_len, &var->type.specifier,
624 tokens, paramList);
625
626 return pos;
627 }
628
629
630
631 /**
632 * Allocate storage for a pre-defined uniform (a GL state variable).
633 * As a memory-saving optimization, we try to only allocate storage for
634 * state vars that are actually used.
635 *
636 * Arrays such as gl_LightSource are handled specially. For an expression
637 * like "gl_LightSource[2].diffuse", we can allocate a single uniform/constant
638 * slot and return the index. In this case, we return direct=TRUE.
639 *
640 * Buf for something like "gl_LightSource[i].diffuse" we don't know the value
641 * of 'i' at compile time so we need to "unroll" the gl_LightSource array
642 * into a consecutive sequence of uniform/constant slots so it can be indexed
643 * at runtime. In this case, we return direct=FALSE.
644 *
645 * Currently, all pre-defined uniforms are in one of these forms:
646 * var
647 * var[i]
648 * var.field
649 * var[i].field
650 * var[i][j]
651 *
652 * \return -1 upon error, else position in paramList of the state variable/data
653 */
654 GLint
655 _slang_alloc_statevar(slang_ir_node *n,
656 struct gl_program_parameter_list *paramList,
657 GLboolean *direct)
658 {
659 slang_ir_node *n0 = n;
660 const char *field = NULL;
661 GLint index1 = -1, index2 = -1;
662 GLuint swizzle;
663
664 *direct = GL_TRUE;
665
666 if (n->Opcode == IR_FIELD) {
667 field = n->Field;
668 n = n->Children[0];
669 }
670
671 if (n->Opcode == IR_ELEMENT) {
672 if (n->Children[1]->Opcode == IR_FLOAT) {
673 index1 = (GLint) n->Children[1]->Value[0];
674 }
675 else {
676 *direct = GL_FALSE;
677 }
678 n = n->Children[0];
679 }
680
681 if (n->Opcode == IR_ELEMENT) {
682 /* XXX can only handle constant indexes for now */
683 if (n->Children[1]->Opcode == IR_FLOAT) {
684 /* two-dimensional array index: mat[i][j] */
685 index2 = index1;
686 index1 = (GLint) n->Children[1]->Value[0];
687 }
688 else {
689 *direct = GL_FALSE;
690 }
691 n = n->Children[0];
692 }
693
694 assert(n->Opcode == IR_VAR);
695
696 if (*direct) {
697 const char *var = (const char *) n->Var->a_name;
698 GLint pos =
699 lookup_statevar(var, index1, index2, field, &swizzle, paramList);
700 if (pos >= 0) {
701 /* newly resolved storage for the statevar/constant/uniform */
702 n0->Store->File = PROGRAM_STATE_VAR;
703 n0->Store->Index = pos;
704 n0->Store->Swizzle = swizzle;
705 n0->Store->Parent = NULL;
706 return pos;
707 }
708 }
709
710 *direct = GL_FALSE;
711 return alloc_state_var_array(n->Var, paramList);
712 }
713
714
715
716
717 #define SWIZZLE_ZWWW MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W)
718
719
720 /** Predefined shader inputs */
721 struct input_info
722 {
723 const char *Name;
724 GLuint Attrib;
725 GLenum Type;
726 GLuint Swizzle;
727 };
728
729 /** Predefined vertex shader inputs/attributes */
730 static const struct input_info vertInputs[] = {
731 { "gl_Vertex", VERT_ATTRIB_POS, GL_FLOAT_VEC4, SWIZZLE_NOOP },
732 { "gl_Normal", VERT_ATTRIB_NORMAL, GL_FLOAT_VEC3, SWIZZLE_NOOP },
733 { "gl_Color", VERT_ATTRIB_COLOR0, GL_FLOAT_VEC4, SWIZZLE_NOOP },
734 { "gl_SecondaryColor", VERT_ATTRIB_COLOR1, GL_FLOAT_VEC4, SWIZZLE_NOOP },
735 { "gl_FogCoord", VERT_ATTRIB_FOG, GL_FLOAT, SWIZZLE_XXXX },
736 { "gl_MultiTexCoord0", VERT_ATTRIB_TEX0, GL_FLOAT_VEC4, SWIZZLE_NOOP },
737 { "gl_MultiTexCoord1", VERT_ATTRIB_TEX1, GL_FLOAT_VEC4, SWIZZLE_NOOP },
738 { "gl_MultiTexCoord2", VERT_ATTRIB_TEX2, GL_FLOAT_VEC4, SWIZZLE_NOOP },
739 { "gl_MultiTexCoord3", VERT_ATTRIB_TEX3, GL_FLOAT_VEC4, SWIZZLE_NOOP },
740 { "gl_MultiTexCoord4", VERT_ATTRIB_TEX4, GL_FLOAT_VEC4, SWIZZLE_NOOP },
741 { "gl_MultiTexCoord5", VERT_ATTRIB_TEX5, GL_FLOAT_VEC4, SWIZZLE_NOOP },
742 { "gl_MultiTexCoord6", VERT_ATTRIB_TEX6, GL_FLOAT_VEC4, SWIZZLE_NOOP },
743 { "gl_MultiTexCoord7", VERT_ATTRIB_TEX7, GL_FLOAT_VEC4, SWIZZLE_NOOP },
744 { NULL, 0, SWIZZLE_NOOP }
745 };
746
747 /** Predefined fragment shader inputs */
748 static const struct input_info fragInputs[] = {
749 { "gl_FragCoord", FRAG_ATTRIB_WPOS, GL_FLOAT_VEC4, SWIZZLE_NOOP },
750 { "gl_Color", FRAG_ATTRIB_COL0, GL_FLOAT_VEC4, SWIZZLE_NOOP },
751 { "gl_SecondaryColor", FRAG_ATTRIB_COL1, GL_FLOAT_VEC4, SWIZZLE_NOOP },
752 { "gl_TexCoord", FRAG_ATTRIB_TEX0, GL_FLOAT_VEC4, SWIZZLE_NOOP },
753 /* note: we're packing several quantities into the fogcoord vector */
754 { "gl_FogFragCoord", FRAG_ATTRIB_FOGC, GL_FLOAT, SWIZZLE_XXXX },
755 { "gl_FrontFacing", FRAG_ATTRIB_FOGC, GL_BOOL, SWIZZLE_YYYY }, /*XXX*/
756 { "gl_PointCoord", FRAG_ATTRIB_FOGC, GL_FLOAT_VEC2, SWIZZLE_ZWWW },
757 { NULL, 0, SWIZZLE_NOOP }
758 };
759
760
761 /**
762 * Return the VERT_ATTRIB_* or FRAG_ATTRIB_* value that corresponds to
763 * a vertex or fragment program input variable. Return -1 if the input
764 * name is invalid.
765 * XXX return size too
766 */
767 GLint
768 _slang_input_index(const char *name, GLenum target, GLuint *swizzleOut)
769 {
770 const struct input_info *inputs;
771 GLuint i;
772
773 switch (target) {
774 case GL_VERTEX_PROGRAM_ARB:
775 inputs = vertInputs;
776 break;
777 case GL_FRAGMENT_PROGRAM_ARB:
778 inputs = fragInputs;
779 break;
780 /* XXX geom program */
781 default:
782 _mesa_problem(NULL, "bad target in _slang_input_index");
783 return -1;
784 }
785
786 ASSERT(MAX_TEXTURE_COORD_UNITS == 8); /* if this fails, fix vertInputs above */
787
788 for (i = 0; inputs[i].Name; i++) {
789 if (strcmp(inputs[i].Name, name) == 0) {
790 /* found */
791 *swizzleOut = inputs[i].Swizzle;
792 return inputs[i].Attrib;
793 }
794 }
795 return -1;
796 }
797
798
799 /**
800 * Return name of the given vertex attribute (VERT_ATTRIB_x).
801 */
802 const char *
803 _slang_vert_attrib_name(GLuint attrib)
804 {
805 GLuint i;
806 assert(attrib < VERT_ATTRIB_GENERIC0);
807 for (i = 0; vertInputs[i].Name; i++) {
808 if (vertInputs[i].Attrib == attrib)
809 return vertInputs[i].Name;
810 }
811 return NULL;
812 }
813
814
815 /**
816 * Return type (GL_FLOAT, GL_FLOAT_VEC2, etc) of the given vertex
817 * attribute (VERT_ATTRIB_x).
818 */
819 GLenum
820 _slang_vert_attrib_type(GLuint attrib)
821 {
822 GLuint i;
823 assert(attrib < VERT_ATTRIB_GENERIC0);
824 for (i = 0; vertInputs[i].Name; i++) {
825 if (vertInputs[i].Attrib == attrib)
826 return vertInputs[i].Type;
827 }
828 return GL_NONE;
829 }
830
831
832
833
834
835 /** Predefined shader output info */
836 struct output_info
837 {
838 const char *Name;
839 GLuint Attrib;
840 };
841
842 /** Predefined vertex shader outputs */
843 static const struct output_info vertOutputs[] = {
844 { "gl_Position", VERT_RESULT_HPOS },
845 { "gl_FrontColor", VERT_RESULT_COL0 },
846 { "gl_BackColor", VERT_RESULT_BFC0 },
847 { "gl_FrontSecondaryColor", VERT_RESULT_COL1 },
848 { "gl_BackSecondaryColor", VERT_RESULT_BFC1 },
849 { "gl_TexCoord", VERT_RESULT_TEX0 },
850 { "gl_FogFragCoord", VERT_RESULT_FOGC },
851 { "gl_PointSize", VERT_RESULT_PSIZ },
852 { NULL, 0 }
853 };
854
855 /** Predefined fragment shader outputs */
856 static const struct output_info fragOutputs[] = {
857 { "gl_FragColor", FRAG_RESULT_COLOR },
858 { "gl_FragDepth", FRAG_RESULT_DEPTH },
859 { "gl_FragData", FRAG_RESULT_DATA0 },
860 { NULL, 0 }
861 };
862
863
864 /**
865 * Return the VERT_RESULT_* or FRAG_RESULT_* value that corresponds to
866 * a vertex or fragment program output variable. Return -1 for an invalid
867 * output name.
868 */
869 GLint
870 _slang_output_index(const char *name, GLenum target)
871 {
872 const struct output_info *outputs;
873 GLuint i;
874
875 switch (target) {
876 case GL_VERTEX_PROGRAM_ARB:
877 outputs = vertOutputs;
878 break;
879 case GL_FRAGMENT_PROGRAM_ARB:
880 outputs = fragOutputs;
881 break;
882 /* XXX geom program */
883 default:
884 _mesa_problem(NULL, "bad target in _slang_output_index");
885 return -1;
886 }
887
888 for (i = 0; outputs[i].Name; i++) {
889 if (strcmp(outputs[i].Name, name) == 0) {
890 /* found */
891 return outputs[i].Attrib;
892 }
893 }
894 return -1;
895 }