-/*\r
- * Mesa 3-D graphics library\r
- * Version: 6.5\r
- *\r
- * Copyright (C) 2006 Brian Paul All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a\r
- * copy of this software and associated documentation files (the "Software"),\r
- * to deal in the Software without restriction, including without limitation\r
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
- * and/or sell copies of the Software, and to permit persons to whom the\r
- * Software is furnished to do so, subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included\r
- * in all copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN\r
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- */\r
-\r
-/**\r
- * \file slang_link.c\r
- * slang linker\r
- * \author Michal Krol\r
- */\r
-\r
-#include "imports.h"\r
-#include "slang_link.h"\r
-\r
-/*\r
- * slang_uniform_bindings\r
- */\r
-\r
-static GLvoid slang_uniform_bindings_ctr (slang_uniform_bindings *self)\r
-{\r
- self->table = NULL;\r
- self->count = 0;\r
-}\r
-\r
-static GLvoid slang_uniform_bindings_dtr (slang_uniform_bindings *self)\r
-{\r
- GLuint i;\r
-\r
- for (i = 0; i < self->count; i++)\r
- slang_alloc_free (self->table[i].name);\r
- slang_alloc_free (self->table);\r
-}\r
-\r
-static GLboolean slang_uniform_bindings_add (slang_uniform_bindings *self, slang_export_data_quant *q,\r
- const char *name, GLuint index, GLuint address)\r
-{\r
- const GLuint n = self->count;\r
- GLuint i;\r
-\r
- for (i = 0; i < n; i++)\r
- if (slang_string_compare (self->table[i].name, name) == 0)\r
- {\r
- self->table[i].address[index] = address;\r
- return GL_TRUE;\r
- }\r
-\r
- self->table = (slang_uniform_binding *) slang_alloc_realloc (self->table,\r
- n * sizeof (slang_uniform_binding), (n + 1) * sizeof (slang_uniform_binding));\r
- if (self->table == NULL)\r
- return GL_FALSE;\r
- self->table[n].quant = q;\r
- self->table[n].name = slang_string_duplicate (name);\r
- for (i = 0; i < SLANG_UNIFORM_BINDING_MAX; i++)\r
- self->table[n].address[i] = ~0;\r
- self->table[n].address[index] = address;\r
- if (self->table[n].name == NULL)\r
- return GL_FALSE;\r
- self->count++;\r
- return GL_TRUE;\r
-}\r
-\r
-static GLboolean insert_binding (slang_uniform_bindings *bind, slang_export_data_quant *q,\r
- char *name, slang_atom_pool *atoms, GLuint index, GLuint addr)\r
-{\r
- GLuint count, i;\r
-\r
- slang_string_concat (name, slang_atom_pool_id (atoms, q->name));\r
-\r
- if (q->array_len == 0)\r
- count = 1;\r
- else\r
- count = q->array_len;\r
-\r
- for (i = 0; i < count; i++)\r
- {\r
- GLuint save;\r
-\r
- save = slang_string_length (name);\r
- if (q->array_len != 0)\r
- _mesa_sprintf (name + slang_string_length (name), "[%d]", i);\r
-\r
- if (q->structure != NULL)\r
- {\r
- GLuint save, i;\r
-\r
- slang_string_concat (name, ".");\r
- save = slang_string_length (name);\r
-\r
- for (i = 0; i < q->u.field_count; i++)\r
- {\r
- if (!insert_binding (bind, &q->structure[i], name, atoms, index, addr))\r
- return GL_FALSE;\r
- name[save] = '\0';\r
- addr += q->structure[i].size;\r
- }\r
- }\r
- else\r
- {\r
- if (!slang_uniform_bindings_add (bind, q, name, index, addr))\r
- return GL_FALSE;\r
- addr += q->size;\r
- }\r
- name[save] = '\0';\r
- }\r
-\r
- return GL_TRUE;\r
-}\r
-\r
-static GLboolean gather_uniform_bindings (slang_uniform_bindings *bind, slang_export_data_table *tbl,\r
- GLuint index)\r
-{\r
- GLuint i;\r
-\r
- for (i = 0; i < tbl->count; i++)\r
- if (tbl->entries[i].access == slang_exp_uniform)\r
- {\r
- char name[1024] = "";\r
-\r
- if (!insert_binding (bind, &tbl->entries[i].quant, name, tbl->atoms, index,\r
- tbl->entries[i].address))\r
- return GL_FALSE;\r
- }\r
-\r
- return GL_TRUE;\r
-}\r
-\r
-/*\r
- * slang_active_uniforms\r
- */\r
-\r
-static GLvoid slang_active_uniforms_ctr (slang_active_uniforms *self)\r
-{\r
- self->table = NULL;\r
- self->count = 0;\r
-}\r
-\r
-static GLvoid slang_active_uniforms_dtr (slang_active_uniforms *self)\r
-{\r
- GLuint i;\r
-\r
- for (i = 0; i < self->count; i++)\r
- slang_alloc_free (self->table[i].name);\r
- slang_alloc_free (self->table);\r
-}\r
-\r
-static GLboolean slang_active_uniforms_add (slang_active_uniforms *self, slang_export_data_quant *q,\r
- const char *name)\r
-{\r
- const GLuint n = self->count;\r
-\r
- self->table = (slang_active_uniform *) slang_alloc_realloc (self->table,\r
- n * sizeof (slang_active_uniform), (n + 1) * sizeof (slang_active_uniform));\r
- if (self->table == NULL)\r
- return GL_FALSE;\r
- self->table[n].quant = q;\r
- self->table[n].name = slang_string_duplicate (name);\r
- if (self->table[n].name == NULL)\r
- return GL_FALSE;\r
- self->count++;\r
- return GL_TRUE;\r
-}\r
-\r
-static GLboolean insert_uniform (slang_active_uniforms *u, slang_export_data_quant *q, char *name,\r
- slang_atom_pool *atoms)\r
-{\r
- slang_string_concat (name, slang_atom_pool_id (atoms, q->name));\r
- if (q->array_len != 0)\r
- slang_string_concat (name, "[0]");\r
-\r
- if (q->structure != NULL)\r
- {\r
- GLuint save, i;\r
-\r
- slang_string_concat (name, ".");\r
- save = slang_string_length (name);\r
-\r
- for (i = 0; i < q->u.field_count; i++)\r
- {\r
- if (!insert_uniform (u, &q->structure[i], name, atoms))\r
- return GL_FALSE;\r
- name[save] = '\0';\r
- }\r
-\r
- return GL_TRUE;\r
- }\r
-\r
- return slang_active_uniforms_add (u, q, name);\r
-}\r
-\r
-static GLboolean gather_active_uniforms (slang_active_uniforms *u, slang_export_data_table *tbl)\r
-{\r
- GLuint i;\r
-\r
- for (i = 0; i < tbl->count; i++)\r
- if (tbl->entries[i].access == slang_exp_uniform)\r
- {\r
- char name[1024] = "";\r
-\r
- if (!insert_uniform (u, &tbl->entries[i].quant, name, tbl->atoms))\r
- return GL_FALSE;\r
- }\r
-\r
- return GL_TRUE;\r
-}\r
-\r
-/*\r
- * slang_program\r
- */\r
-\r
-GLvoid slang_program_ctr (slang_program *self)\r
-{\r
- GLuint i;\r
-\r
- slang_uniform_bindings_ctr (&self->uniforms);\r
- slang_active_uniforms_ctr (&self->active_uniforms);\r
- for (i = 0; i < SLANG_UNIFORM_BINDING_MAX; i++)\r
- {\r
- GLuint j;\r
-\r
- for (j = 0; j < SLANG_COMMON_FIXED_MAX; j++)\r
- self->common_fixed_entries[i][j] = ~0;\r
- self->code[i] = ~0;\r
- self->machines[i] = NULL;\r
- self->assemblies[i] = NULL;\r
- }\r
- for (i = 0; i < SLANG_VERTEX_FIXED_MAX; i++)\r
- self->vertex_fixed_entries[i] = ~0;\r
- for (i = 0; i < SLANG_FRAGMENT_FIXED_MAX; i++)\r
- self->fragment_fixed_entries[i] = ~0;\r
-}\r
-\r
-GLvoid slang_program_dtr (slang_program *self)\r
-{\r
- slang_uniform_bindings_dtr (&self->uniforms);\r
- slang_active_uniforms_dtr (&self->active_uniforms);\r
-}\r
-\r
-/*\r
- * _slang_link()\r
- */\r
-\r
-static GLuint gd (slang_export_data_table *tbl, const char *name)\r
-{\r
- slang_atom atom;\r
- GLuint i;\r
-\r
- atom = slang_atom_pool_atom (tbl->atoms, name);\r
- if (atom == SLANG_ATOM_NULL)\r
- return ~0;\r
-\r
- for (i = 0; i < tbl->count; i++)\r
- if (atom == tbl->entries[i].quant.name)\r
- return tbl->entries[i].address;\r
- return ~0;\r
-}\r
-\r
-static GLvoid fill_common_fixed_entries (GLuint e[], slang_export_data_table *tbl)\r
-{\r
- e[SLANG_COMMON_FIXED_MODELVIEWMATRIX] = gd (tbl, "gl_ModelViewMatrix");\r
- e[SLANG_COMMON_FIXED_PROJECTIONMATRIX] = gd (tbl, "gl_ProjectionMatrix");\r
- e[SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIX] = gd (tbl, "gl_ModelViewProjectionMatrix");\r
- e[SLANG_COMMON_FIXED_TEXTUREMATRIX] = gd (tbl, "gl_TextureMatrix");\r
- e[SLANG_COMMON_FIXED_NORMALMATRIX] = gd (tbl, "gl_NormalMatrix");\r
- e[SLANG_COMMON_FIXED_MODELVIEWMATRIXINVERSE] = gd (tbl, "gl_ModelViewMatrixInverse");\r
- e[SLANG_COMMON_FIXED_PROJECTIONMATRIXINVERSE] = gd (tbl, "gl_ProjectionMatrixInverse");\r
- e[SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXINVERSE] =\r
- gd (tbl, "gl_ModelViewProjectionMatrixInverse");\r
- e[SLANG_COMMON_FIXED_TEXTUREMATRIXINVERSE] = gd (tbl, "gl_TextureMatrixInverse");\r
- e[SLANG_COMMON_FIXED_MODELVIEWMATRIXTRANSPOSE] = gd (tbl, "gl_ModelViewMatrixTranspose");\r
- e[SLANG_COMMON_FIXED_PROJECTIONMATRIXTRANSPOSE] = gd (tbl, "gl_ProjectionMatrixTranspose");\r
- e[SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXTRANSPOSE] =\r
- gd (tbl, "gl_ModelViewProjectionMatrixTranspose");\r
- e[SLANG_COMMON_FIXED_TEXTUREMATRIXTRANSPOSE] = gd (tbl, "gl_TextureMatrixTranspose");\r
- e[SLANG_COMMON_FIXED_MODELVIEWMATRIXINVERSETRANSPOSE] =\r
- gd (tbl, "gl_ModelViewMatrixInverseTranspose");\r
- e[SLANG_COMMON_FIXED_PROJECTIONMATRIXINVERSETRANSPOSE] =\r
- gd (tbl, "gl_ProjectionMatrixInverseTranspose");\r
- e[SLANG_COMMON_FIXED_MODELVIEWPROJECTIONMATRIXINVERSETRANSPOSE] =\r
- gd (tbl, "gl_ModelViewProjectionMatrixInverseTranspose");\r
- e[SLANG_COMMON_FIXED_TEXTUREMATRIXINVERSETRANSPOSE] =\r
- gd (tbl, "gl_TextureMatrixInverseTranspose");\r
- e[SLANG_COMMON_FIXED_NORMALSCALE] = gd (tbl, "gl_NormalScale");\r
- e[SLANG_COMMON_FIXED_DEPTHRANGE] = gd (tbl, "gl_DepthRange");\r
- e[SLANG_COMMON_FIXED_CLIPPLANE] = gd (tbl, "gl_ClipPlane");\r
- e[SLANG_COMMON_FIXED_POINT] = gd (tbl, "gl_Point");\r
- e[SLANG_COMMON_FIXED_FRONTMATERIAL] = gd (tbl, "gl_FrontMaterial");\r
- e[SLANG_COMMON_FIXED_BACKMATERIAL] = gd (tbl, "gl_BackMaterial");\r
- e[SLANG_COMMON_FIXED_LIGHTSOURCE] = gd (tbl, "gl_LightSource");\r
- e[SLANG_COMMON_FIXED_LIGHTMODEL] = gd (tbl, "gl_LightModel");\r
- e[SLANG_COMMON_FIXED_FRONTLIGHTMODELPRODUCT] = gd (tbl, "gl_FrontLightModelProduct");\r
- e[SLANG_COMMON_FIXED_BACKLIGHTMODELPRODUCT] = gd (tbl, "gl_BackLightModelProduct");\r
- e[SLANG_COMMON_FIXED_FRONTLIGHTPRODUCT] = gd (tbl, "gl_FrontLightProduct");\r
- e[SLANG_COMMON_FIXED_BACKLIGHTPRODUCT] = gd (tbl, "gl_BackLightProduct");\r
- e[SLANG_COMMON_FIXED_TEXTUREENVCOLOR] = gd (tbl, "gl_TextureEnvColor");\r
- e[SLANG_COMMON_FIXED_EYEPLANES] = gd (tbl, "gl_EyePlaneS");\r
- e[SLANG_COMMON_FIXED_EYEPLANET] = gd (tbl, "gl_EyePlaneT");\r
- e[SLANG_COMMON_FIXED_EYEPLANER] = gd (tbl, "gl_EyePlaneR");\r
- e[SLANG_COMMON_FIXED_EYEPLANEQ] = gd (tbl, "gl_EyePlaneQ");\r
- e[SLANG_COMMON_FIXED_OBJECTPLANES] = gd (tbl, "gl_ObjectPlaneS");\r
- e[SLANG_COMMON_FIXED_OBJECTPLANET] = gd (tbl, "gl_ObjectPlaneT");\r
- e[SLANG_COMMON_FIXED_OBJECTPLANER] = gd (tbl, "gl_ObjectPlaneR");\r
- e[SLANG_COMMON_FIXED_OBJECTPLANEQ] = gd (tbl, "gl_ObjectPlaneQ");\r
- e[SLANG_COMMON_FIXED_FOG] = gd (tbl, "gl_Fog");\r
-}\r
-\r
-static GLvoid fill_vertex_fixed_entries (GLuint e[], slang_export_data_table *tbl)\r
-{\r
- e[SLANG_VERTEX_FIXED_POSITION] = gd (tbl, "gl_Position");\r
- e[SLANG_VERTEX_FIXED_POINTSIZE] = gd (tbl, "gl_PointSize");\r
- e[SLANG_VERTEX_FIXED_CLIPVERTEX] = gd (tbl, "gl_ClipVertex");\r
- e[SLANG_VERTEX_FIXED_COLOR] = gd (tbl, "gl_Color");\r
- e[SLANG_VERTEX_FIXED_SECONDARYCOLOR] = gd (tbl, "gl_SecondaryColor");\r
- e[SLANG_VERTEX_FIXED_NORMAL] = gd (tbl, "gl_Normal");\r
- e[SLANG_VERTEX_FIXED_VERTEX] = gd (tbl, "gl_Vertex");\r
- e[SLANG_VERTEX_FIXED_MULTITEXCOORD0] = gd (tbl, "gl_MultiTexCoord0");\r
- e[SLANG_VERTEX_FIXED_MULTITEXCOORD1] = gd (tbl, "gl_MultiTexCoord1");\r
- e[SLANG_VERTEX_FIXED_MULTITEXCOORD2] = gd (tbl, "gl_MultiTexCoord2");\r
- e[SLANG_VERTEX_FIXED_MULTITEXCOORD3] = gd (tbl, "gl_MultiTexCoord3");\r
- e[SLANG_VERTEX_FIXED_MULTITEXCOORD4] = gd (tbl, "gl_MultiTexCoord4");\r
- e[SLANG_VERTEX_FIXED_MULTITEXCOORD5] = gd (tbl, "gl_MultiTexCoord5");\r
- e[SLANG_VERTEX_FIXED_MULTITEXCOORD6] = gd (tbl, "gl_MultiTexCoord6");\r
- e[SLANG_VERTEX_FIXED_MULTITEXCOORD7] = gd (tbl, "gl_MultiTexCoord7");\r
- e[SLANG_VERTEX_FIXED_FOGCOORD] = gd (tbl, "gl_FogCoord");\r
- e[SLANG_VERTEX_FIXED_FRONTCOLOR] = gd (tbl, "gl_FrontColor");\r
- e[SLANG_VERTEX_FIXED_BACKCOLOR] = gd (tbl, "gl_BackColor");\r
- e[SLANG_VERTEX_FIXED_FRONTSECONDARYCOLOR] = gd (tbl, "gl_FrontSecondaryColor");\r
- e[SLANG_VERTEX_FIXED_BACKSECONDARYCOLOR] = gd (tbl, "gl_BackSecondaryColor");\r
- e[SLANG_VERTEX_FIXED_TEXCOORD] = gd (tbl, "gl_TexCoord");\r
- e[SLANG_VERTEX_FIXED_FOGFRAGCOORD] = gd (tbl, "gl_FogFragCoord");\r
-}\r
-\r
-static GLvoid fill_fragment_fixed_entries (GLuint e[], slang_export_data_table *tbl)\r
-{\r
- e[SLANG_FRAGMENT_FIXED_FRAGCOORD] = gd (tbl, "gl_FragCoord");\r
- e[SLANG_FRAGMENT_FIXED_FRONTFACING] = gd (tbl, "gl_FrontFacing");\r
- e[SLANG_FRAGMENT_FIXED_FRAGCOLOR] = gd (tbl, "gl_FragColor");\r
- e[SLANG_FRAGMENT_FIXED_FRAGDATA] = gd (tbl, "gl_FragData");\r
- e[SLANG_FRAGMENT_FIXED_FRAGDEPTH] = gd (tbl, "gl_FragDepth");\r
- e[SLANG_FRAGMENT_FIXED_COLOR] = gd (tbl, "gl_Color");\r
- e[SLANG_FRAGMENT_FIXED_SECONDARYCOLOR] = gd (tbl, "gl_SecondaryColor");\r
- e[SLANG_FRAGMENT_FIXED_TEXCOORD] = gd (tbl, "gl_TexCoord");\r
- e[SLANG_FRAGMENT_FIXED_FOGFRAGCOORD] = gd (tbl, "gl_FogFragCoord");\r
-}\r
-\r
-static GLuint gc (slang_export_code_table *tbl, const char *name)\r
-{\r
- slang_atom atom;\r
- GLuint i;\r
-\r
- atom = slang_atom_pool_atom (tbl->atoms, name);\r
- if (atom == SLANG_ATOM_NULL)\r
- return ~0;\r
-\r
- for (i = 0; i < tbl->count; i++)\r
- if (atom == tbl->entries[i].name)\r
- return tbl->entries[i].address;\r
- return ~0;\r
-}\r
-\r
-static GLvoid resolve_code (GLuint code[], slang_export_code_table *tbl)\r
-{\r
- code[0] = gc (tbl, "@main");\r
-}\r
-\r
-GLboolean _slang_link (slang_program *prog, slang_translation_unit **units, GLuint count)\r
-{\r
- GLuint i;\r
-\r
- for (i = 0; i < count; i++)\r
- {\r
- GLuint index;\r
-\r
- if (units[i]->type == slang_unit_fragment_shader)\r
- {\r
- index = SLANG_UNIFORM_BINDING_FRAGMENT;\r
- fill_fragment_fixed_entries (prog->fragment_fixed_entries, &units[i]->exp_data);\r
- }\r
- else\r
- {\r
- index = SLANG_UNIFORM_BINDING_VERTEX;\r
- fill_vertex_fixed_entries (prog->vertex_fixed_entries, &units[i]->exp_data);\r
- }\r
-\r
- if (!gather_uniform_bindings (&prog->uniforms, &units[i]->exp_data, index))\r
- return GL_FALSE;\r
- if (!gather_active_uniforms (&prog->active_uniforms, &units[i]->exp_data))\r
- return GL_FALSE;\r
- fill_common_fixed_entries (prog->common_fixed_entries[index], &units[i]->exp_data);\r
- resolve_code (&prog->code[index], &units[i]->exp_code);\r
- prog->machines[index] = units[i]->machine;\r
- prog->assemblies[index] = units[i]->assembly;\r
- }\r
-\r
- return GL_TRUE;\r
-}\r
-\r
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.2
+ *
+ * Copyright (C) 2008 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file slang_link.c
+ * GLSL linker
+ * \author Brian Paul
+ */
+
+#include "main/imports.h"
+#include "main/context.h"
+#include "main/hash.h"
+#include "main/macros.h"
+#include "shader/program.h"
+#include "shader/prog_instruction.h"
+#include "shader/prog_parameter.h"
+#include "shader/prog_print.h"
+#include "shader/prog_statevars.h"
+#include "shader/prog_uniform.h"
+#include "shader/shader_api.h"
+#include "slang_link.h"
+
+
+/** cast wrapper */
+static struct gl_vertex_program *
+vertex_program(struct gl_program *prog)
+{
+ assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
+ return (struct gl_vertex_program *) prog;
+}
+
+
+/** cast wrapper */
+static struct gl_fragment_program *
+fragment_program(struct gl_program *prog)
+{
+ assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB);
+ return (struct gl_fragment_program *) prog;
+}
+
+
+/**
+ * Record a linking error.
+ */
+static void
+link_error(struct gl_shader_program *shProg, const char *msg)
+{
+ if (shProg->InfoLog) {
+ _mesa_free(shProg->InfoLog);
+ }
+ shProg->InfoLog = _mesa_strdup(msg);
+ shProg->LinkStatus = GL_FALSE;
+}
+
+
+
+/**
+ * Linking varying vars involves rearranging varying vars so that the
+ * vertex program's output varyings matches the order of the fragment
+ * program's input varyings.
+ */
+static GLboolean
+link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog)
+{
+ GLuint *map, i, firstVarying, newFile;
+
+ map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint));
+ if (!map)
+ return GL_FALSE;
+
+ for (i = 0; i < prog->Varying->NumParameters; i++) {
+ /* see if this varying is in the linked varying list */
+ const struct gl_program_parameter *var = prog->Varying->Parameters + i;
+ GLint j = _mesa_lookup_parameter_index(shProg->Varying, -1, var->Name);
+ if (j >= 0) {
+ /* already in list, check size */
+ if (var->Size != shProg->Varying->Parameters[j].Size) {
+ /* error */
+ link_error(shProg, "mismatched varying variable types");
+ return GL_FALSE;
+ }
+ }
+ else {
+ /* not already in linked list */
+ j = _mesa_add_varying(shProg->Varying, var->Name, var->Size);
+ }
+
+ /* map varying[i] to varying[j].
+ * Note: the loop here takes care of arrays or large (sz>4) vars.
+ */
+ {
+ GLint sz = var->Size;
+ while (sz > 0) {
+ /*printf("Link varying from %d to %d\n", i, j);*/
+ map[i++] = j++;
+ sz -= 4;
+ }
+ i--; /* go back one */
+ }
+ }
+
+
+ /* Varying variables are treated like other vertex program outputs
+ * (and like other fragment program inputs). The position of the
+ * first varying differs for vertex/fragment programs...
+ * Also, replace File=PROGRAM_VARYING with File=PROGRAM_INPUT/OUTPUT.
+ */
+ if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
+ firstVarying = VERT_RESULT_VAR0;
+ newFile = PROGRAM_OUTPUT;
+ }
+ else {
+ assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB);
+ firstVarying = FRAG_ATTRIB_VAR0;
+ newFile = PROGRAM_INPUT;
+ }
+
+ /* OK, now scan the program/shader instructions looking for varying vars,
+ * replacing the old index with the new index.
+ */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ GLuint j;
+
+ if (inst->DstReg.File == PROGRAM_VARYING) {
+ inst->DstReg.File = newFile;
+ inst->DstReg.Index = map[ inst->DstReg.Index ] + firstVarying;
+ }
+
+ for (j = 0; j < 3; j++) {
+ if (inst->SrcReg[j].File == PROGRAM_VARYING) {
+ inst->SrcReg[j].File = newFile;
+ inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ] + firstVarying;
+ }
+ }
+ }
+
+ free(map);
+
+ /* these will get recomputed before linking is completed */
+ prog->InputsRead = 0x0;
+ prog->OutputsWritten = 0x0;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Build the shProg->Uniforms list.
+ * This is basically a list/index of all uniforms found in either/both of
+ * the vertex and fragment shaders.
+ */
+static void
+link_uniform_vars(struct gl_shader_program *shProg,
+ struct gl_program *prog,
+ GLuint *numSamplers)
+{
+ GLuint samplerMap[MAX_SAMPLERS];
+ GLuint i;
+
+ for (i = 0; i < prog->Parameters->NumParameters; i++) {
+ const struct gl_program_parameter *p = prog->Parameters->Parameters + i;
+
+ /*
+ * XXX FIX NEEDED HERE
+ * We should also be adding a uniform if p->Type == PROGRAM_STATE_VAR.
+ * For example, modelview matrix, light pos, etc.
+ * Also, we need to update the state-var name-generator code to
+ * generate GLSL-style names, like "gl_LightSource[0].position".
+ * Furthermore, we'll need to fix the state-var's size/datatype info.
+ */
+
+ if ((p->Type == PROGRAM_UNIFORM && p->Used) ||
+ p->Type == PROGRAM_SAMPLER) {
+ struct gl_uniform *uniform =
+ _mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i);
+ if (uniform)
+ uniform->Initialized = p->Initialized;
+ }
+
+ if (p->Type == PROGRAM_SAMPLER) {
+ /* Allocate a new sampler index */
+ GLuint sampNum = *numSamplers;
+ GLuint oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0];
+ assert(oldSampNum < MAX_SAMPLERS);
+ samplerMap[oldSampNum] = sampNum;
+ (*numSamplers)++;
+ }
+ }
+
+
+ /* OK, now scan the program/shader instructions looking for sampler vars,
+ * replacing the old index with the new index.
+ */
+ prog->SamplersUsed = 0x0;
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (_mesa_is_tex_instruction(inst->Opcode)) {
+ /*
+ printf("====== remap sampler from %d to %d\n",
+ inst->Sampler, map[ inst->Sampler ]);
+ */
+ /* here, texUnit is really samplerUnit */
+ assert(inst->TexSrcUnit < MAX_SAMPLERS);
+ inst->TexSrcUnit = samplerMap[inst->TexSrcUnit];
+ prog->SamplerTargets[inst->TexSrcUnit] = inst->TexSrcTarget;
+ prog->SamplersUsed |= (1 << inst->TexSrcUnit);
+ }
+ }
+
+}
+
+
+/**
+ * Resolve binding of generic vertex attributes.
+ * For example, if the vertex shader declared "attribute vec4 foobar" we'll
+ * allocate a generic vertex attribute for "foobar" and plug that value into
+ * the vertex program instructions.
+ * But if the user called glBindAttributeLocation(), those bindings will
+ * have priority.
+ */
+static GLboolean
+_slang_resolve_attributes(struct gl_shader_program *shProg,
+ const struct gl_program *origProg,
+ struct gl_program *linkedProg)
+{
+ GLint attribMap[MAX_VERTEX_ATTRIBS];
+ GLuint i, j;
+ GLbitfield usedAttributes;
+
+ assert(origProg != linkedProg);
+ assert(origProg->Target == GL_VERTEX_PROGRAM_ARB);
+ assert(linkedProg->Target == GL_VERTEX_PROGRAM_ARB);
+
+ if (!shProg->Attributes)
+ shProg->Attributes = _mesa_new_parameter_list();
+
+ if (linkedProg->Attributes) {
+ _mesa_free_parameter_list(linkedProg->Attributes);
+ }
+ linkedProg->Attributes = _mesa_new_parameter_list();
+
+
+ /* Build a bitmask indicating which attribute indexes have been
+ * explicitly bound by the user with glBindAttributeLocation().
+ */
+ usedAttributes = 0x0;
+ for (i = 0; i < shProg->Attributes->NumParameters; i++) {
+ GLint attr = shProg->Attributes->Parameters[i].StateIndexes[0];
+ usedAttributes |= (1 << attr);
+ }
+
+ /* initialize the generic attribute map entries to -1 */
+ for (i = 0; i < MAX_VERTEX_ATTRIBS; i++) {
+ attribMap[i] = -1;
+ }
+
+ /*
+ * Scan program for generic attribute references
+ */
+ for (i = 0; i < linkedProg->NumInstructions; i++) {
+ struct prog_instruction *inst = linkedProg->Instructions + i;
+ for (j = 0; j < 3; j++) {
+ if (inst->SrcReg[j].File == PROGRAM_INPUT &&
+ inst->SrcReg[j].Index >= VERT_ATTRIB_GENERIC0) {
+ /*
+ * OK, we've found a generic vertex attribute reference.
+ */
+ const GLint k = inst->SrcReg[j].Index - VERT_ATTRIB_GENERIC0;
+
+ GLint attr = attribMap[k];
+
+ if (attr < 0) {
+ /* Need to figure out attribute mapping now.
+ */
+ const char *name = origProg->Attributes->Parameters[k].Name;
+ const GLint size = origProg->Attributes->Parameters[k].Size;
+ const GLenum type =origProg->Attributes->Parameters[k].DataType;
+ GLint index;
+
+ /* See if there's a user-defined attribute binding for
+ * this name.
+ */
+ index = _mesa_lookup_parameter_index(shProg->Attributes,
+ -1, name);
+ if (index >= 0) {
+ /* Found a user-defined binding */
+ attr = shProg->Attributes->Parameters[index].StateIndexes[0];
+ }
+ else {
+ /* No user-defined binding, choose our own attribute number.
+ * Start at 1 since generic attribute 0 always aliases
+ * glVertex/position.
+ */
+ for (attr = 1; attr < MAX_VERTEX_ATTRIBS; attr++) {
+ if (((1 << attr) & usedAttributes) == 0)
+ break;
+ }
+ if (attr == MAX_VERTEX_ATTRIBS) {
+ link_error(shProg, "Too many vertex attributes");
+ return GL_FALSE;
+ }
+
+ /* mark this attribute as used */
+ usedAttributes |= (1 << attr);
+ }
+
+ attribMap[k] = attr;
+
+ /* Save the final name->attrib binding so it can be queried
+ * with glGetAttributeLocation().
+ */
+ _mesa_add_attribute(linkedProg->Attributes, name,
+ size, type, attr);
+ }
+
+ assert(attr >= 0);
+
+ /* update the instruction's src reg */
+ inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr;
+ }
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Scan program instructions to update the program's NumTemporaries field.
+ * Note: this implemenation relies on the code generator allocating
+ * temps in increasing order (0, 1, 2, ... ).
+ */
+static void
+_slang_count_temporaries(struct gl_program *prog)
+{
+ GLuint i, j;
+ GLint maxIndex = -1;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
+ for (j = 0; j < numSrc; j++) {
+ if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
+ if (maxIndex < inst->SrcReg[j].Index)
+ maxIndex = inst->SrcReg[j].Index;
+ }
+ if (inst->DstReg.File == PROGRAM_TEMPORARY) {
+ if (maxIndex < (GLint) inst->DstReg.Index)
+ maxIndex = inst->DstReg.Index;
+ }
+ }
+ }
+
+ prog->NumTemporaries = (GLuint) (maxIndex + 1);
+}
+
+
+/**
+ * Scan program instructions to update the program's InputsRead and
+ * OutputsWritten fields.
+ */
+static void
+_slang_update_inputs_outputs(struct gl_program *prog)
+{
+ GLuint i, j;
+ GLuint maxAddrReg = 0;
+
+ prog->InputsRead = 0x0;
+ prog->OutputsWritten = 0x0;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
+ for (j = 0; j < numSrc; j++) {
+ if (inst->SrcReg[j].File == PROGRAM_INPUT) {
+ prog->InputsRead |= 1 << inst->SrcReg[j].Index;
+ if (prog->Target == GL_FRAGMENT_PROGRAM_ARB &&
+ inst->SrcReg[j].Index == FRAG_ATTRIB_FOGC) {
+ /* The fragment shader FOGC input is used for fog,
+ * front-facing and sprite/point coord.
+ */
+ struct gl_fragment_program *fp = fragment_program(prog);
+ const GLint swz = GET_SWZ(inst->SrcReg[j].Swizzle, 0);
+ if (swz == SWIZZLE_X)
+ fp->UsesFogFragCoord = GL_TRUE;
+ else if (swz == SWIZZLE_Y)
+ fp->UsesFrontFacing = GL_TRUE;
+ else if (swz == SWIZZLE_Z || swz == SWIZZLE_W)
+ fp->UsesPointCoord = GL_TRUE;
+ }
+ }
+ else if (inst->SrcReg[j].File == PROGRAM_ADDRESS) {
+ maxAddrReg = MAX2(maxAddrReg, (GLuint) (inst->SrcReg[j].Index + 1));
+ }
+ }
+ if (inst->DstReg.File == PROGRAM_OUTPUT) {
+ prog->OutputsWritten |= 1 << inst->DstReg.Index;
+ }
+ else if (inst->DstReg.File == PROGRAM_ADDRESS) {
+ maxAddrReg = MAX2(maxAddrReg, inst->DstReg.Index + 1);
+ }
+ }
+
+ prog->NumAddressRegs = maxAddrReg;
+}
+
+
+/**
+ * Shader linker. Currently:
+ *
+ * 1. The last attached vertex shader and fragment shader are linked.
+ * 2. Varying vars in the two shaders are combined so their locations
+ * agree between the vertex and fragment stages. They're treated as
+ * vertex program output attribs and as fragment program input attribs.
+ * 3. The vertex and fragment programs are cloned and modified to update
+ * src/dst register references so they use the new, linked varying
+ * storage locations.
+ */
+void
+_slang_link(GLcontext *ctx,
+ GLhandleARB programObj,
+ struct gl_shader_program *shProg)
+{
+ const struct gl_vertex_program *vertProg;
+ const struct gl_fragment_program *fragProg;
+ GLuint numSamplers = 0;
+ GLuint i;
+
+ _mesa_clear_shader_program_data(ctx, shProg);
+
+ /* check that all programs compiled successfully */
+ for (i = 0; i < shProg->NumShaders; i++) {
+ if (!shProg->Shaders[i]->CompileStatus) {
+ link_error(shProg, "linking with uncompiled shader\n");
+ return;
+ }
+ }
+
+ shProg->Uniforms = _mesa_new_uniform_list();
+ shProg->Varying = _mesa_new_parameter_list();
+
+ /**
+ * Find attached vertex, fragment shaders defining main()
+ */
+ vertProg = NULL;
+ fragProg = NULL;
+ for (i = 0; i < shProg->NumShaders; i++) {
+ struct gl_shader *shader = shProg->Shaders[i];
+ if (shader->Type == GL_VERTEX_SHADER) {
+ if (shader->Main)
+ vertProg = vertex_program(shader->Program);
+ }
+ else if (shader->Type == GL_FRAGMENT_SHADER) {
+ if (shader->Main)
+ fragProg = fragment_program(shader->Program);
+ }
+ else {
+ _mesa_problem(ctx, "unexpected shader target in slang_link()");
+ }
+ }
+
+#if FEATURE_es2_glsl
+ /* must have both a vertex and fragment program for ES2 */
+ if (!vertProg) {
+ link_error(shProg, "missing vertex shader\n");
+ return;
+ }
+ if (!fragProg) {
+ link_error(shProg, "missing fragment shader\n");
+ return;
+ }
+#endif
+
+ /*
+ * Make copies of the vertex/fragment programs now since we'll be
+ * changing src/dst registers after merging the uniforms and varying vars.
+ */
+ _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
+ if (vertProg) {
+ struct gl_vertex_program *linked_vprog =
+ vertex_program(_mesa_clone_program(ctx, &vertProg->Base));
+ shProg->VertexProgram = linked_vprog; /* refcount OK */
+ ASSERT(shProg->VertexProgram->Base.RefCount == 1);
+ }
+
+ _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
+ if (fragProg) {
+ struct gl_fragment_program *linked_fprog =
+ fragment_program(_mesa_clone_program(ctx, &fragProg->Base));
+ shProg->FragmentProgram = linked_fprog; /* refcount OK */
+ ASSERT(shProg->FragmentProgram->Base.RefCount == 1);
+ }
+
+ /* link varying vars */
+ if (shProg->VertexProgram) {
+ if (!link_varying_vars(shProg, &shProg->VertexProgram->Base))
+ return;
+ }
+ if (shProg->FragmentProgram) {
+ if (!link_varying_vars(shProg, &shProg->FragmentProgram->Base))
+ return;
+ }
+
+ /* link uniform vars */
+ if (shProg->VertexProgram)
+ link_uniform_vars(shProg, &shProg->VertexProgram->Base, &numSamplers);
+ if (shProg->FragmentProgram)
+ link_uniform_vars(shProg, &shProg->FragmentProgram->Base, &numSamplers);
+
+ /*_mesa_print_uniforms(shProg->Uniforms);*/
+
+ if (shProg->VertexProgram) {
+ if (!_slang_resolve_attributes(shProg, &vertProg->Base,
+ &shProg->VertexProgram->Base)) {
+ return;
+ }
+ }
+
+ if (shProg->VertexProgram) {
+ _slang_update_inputs_outputs(&shProg->VertexProgram->Base);
+ _slang_count_temporaries(&shProg->VertexProgram->Base);
+ if (!(shProg->VertexProgram->Base.OutputsWritten & (1 << VERT_RESULT_HPOS))) {
+ /* the vertex program did not compute a vertex position */
+ link_error(shProg,
+ "gl_Position was not written by vertex shader\n");
+ return;
+ }
+ }
+ if (shProg->FragmentProgram) {
+ _slang_count_temporaries(&shProg->FragmentProgram->Base);
+ _slang_update_inputs_outputs(&shProg->FragmentProgram->Base);
+ }
+
+ /* Check that all the varying vars needed by the fragment shader are
+ * actually produced by the vertex shader.
+ */
+ if (shProg->FragmentProgram) {
+ const GLbitfield varyingRead
+ = shProg->FragmentProgram->Base.InputsRead >> FRAG_ATTRIB_VAR0;
+ const GLbitfield varyingWritten = shProg->VertexProgram ?
+ shProg->VertexProgram->Base.OutputsWritten >> VERT_RESULT_VAR0 : 0x0;
+ if ((varyingRead & varyingWritten) != varyingRead) {
+ link_error(shProg,
+ "Fragment program using varying vars not written by vertex shader\n");
+ return;
+ }
+ }
+
+
+ if (fragProg && shProg->FragmentProgram) {
+ /* Compute initial program's TexturesUsed info */
+ _mesa_update_shader_textures_used(&shProg->FragmentProgram->Base);
+
+ /* notify driver that a new fragment program has been compiled/linked */
+ ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB,
+ &shProg->FragmentProgram->Base);
+ if (MESA_VERBOSE & VERBOSE_GLSL_DUMP) {
+ printf("Mesa original fragment program:\n");
+ _mesa_print_program(&fragProg->Base);
+ _mesa_print_program_parameters(ctx, &fragProg->Base);
+
+ printf("Mesa post-link fragment program:\n");
+ _mesa_print_program(&shProg->FragmentProgram->Base);
+ _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base);
+ }
+ }
+
+ if (vertProg && shProg->VertexProgram) {
+ /* Compute initial program's TexturesUsed info */
+ _mesa_update_shader_textures_used(&shProg->VertexProgram->Base);
+
+ /* notify driver that a new vertex program has been compiled/linked */
+ ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB,
+ &shProg->VertexProgram->Base);
+ if (MESA_VERBOSE & VERBOSE_GLSL_DUMP) {
+ printf("Mesa original vertex program:\n");
+ _mesa_print_program(&vertProg->Base);
+ _mesa_print_program_parameters(ctx, &vertProg->Base);
+
+ printf("Mesa post-link vertex program:\n");
+ _mesa_print_program(&shProg->VertexProgram->Base);
+ _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base);
+ }
+ }
+
+ shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram);
+}
+