glsl: new MESA_GLSL env var for GLSL debugging features
[mesa.git] / src / mesa / shader / slang / slang_link.c
index 9d61a29e9128e24006e579f55b9928463d48c488..848a64f932af4e56fdc67372b9ab1f996f3f1983 100644 (file)
-/*\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
-#include "slang_analyse.h"\r
-\r
-static GLboolean entry_has_gl_prefix (slang_atom name, slang_atom_pool *atoms)\r
-{\r
-       const char *str = slang_atom_pool_id (atoms, name);\r
-       return str[0] == 'g' && str[1] == 'l' && str[2] == '_';\r
-}\r
-\r
-/*\r
- * slang_active_variables\r
- */\r
-\r
-static GLvoid slang_active_variables_ctr (slang_active_variables *self)\r
-{\r
-       self->table = NULL;\r
-       self->count = 0;\r
-}\r
-\r
-static GLvoid slang_active_variables_dtr (slang_active_variables *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 add_simple_variable (slang_active_variables *self, slang_export_data_quant *q,\r
-       const char *name)\r
-{\r
-       const GLuint n = self->count;\r
-\r
-       self->table = (slang_active_variable *) slang_alloc_realloc (self->table,\r
-               n * sizeof (slang_active_variable), (n + 1) * sizeof (slang_active_variable));\r
-       if (self->table == NULL)\r
-               return GL_FALSE;\r
-\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
-\r
-       return GL_TRUE;\r
-}\r
-\r
-static GLboolean add_complex_variable (slang_active_variables *self, slang_export_data_quant *q,\r
-       char *name, slang_atom_pool *atoms)\r
-{\r
-       slang_string_concat (name, slang_atom_pool_id (atoms, q->name));\r
-       if (slang_export_data_quant_array (q))\r
-               slang_string_concat (name, "[0]");\r
-\r
-       if (slang_export_data_quant_struct (q))\r
-       {\r
-               GLuint dot_pos, i;\r
-               const GLuint fields = slang_export_data_quant_fields (q);\r
-\r
-               slang_string_concat (name, ".");\r
-               dot_pos = slang_string_length (name);\r
-\r
-               for (i = 0; i < fields; i++)\r
-               {\r
-                       if (!add_complex_variable (self, &q->structure[i], name, atoms))\r
-                               return GL_FALSE;\r
-\r
-                       name[dot_pos] = '\0';\r
-               }\r
-\r
-               return GL_TRUE;\r
-       }\r
-\r
-       return add_simple_variable (self, q, name);\r
-}\r
-\r
-static GLboolean gather_active_variables (slang_active_variables *self,\r
-       slang_export_data_table *tbl, slang_export_data_access access)\r
-{\r
-       GLuint i;\r
-\r
-       for (i = 0; i < tbl->count; i++)\r
-               if (tbl->entries[i].access == access)\r
-               {\r
-                       char name[1024] = "";\r
-\r
-                       if (!add_complex_variable (self, &tbl->entries[i].quant, name, tbl->atoms))\r
-                               return GL_FALSE;\r
-               }\r
-\r
-       return GL_TRUE;\r
-}\r
-\r
-/*\r
- * slang_attrib_overrides\r
- */\r
-\r
-static GLvoid slang_attrib_overrides_ctr (slang_attrib_overrides *self)\r
-{\r
-       self->table = NULL;\r
-       self->count = 0;\r
-}\r
-\r
-static GLvoid slang_attrib_overrides_dtr (slang_attrib_overrides *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
-GLboolean slang_attrib_overrides_add (slang_attrib_overrides *self, GLuint index, const GLchar *name)\r
-{\r
-       const GLuint n = self->count;\r
-       GLuint i;\r
-\r
-       for (i = 0; i < n; i++)\r
-               if (slang_string_compare (name, self->table[i].name) == 0)\r
-               {\r
-                       self->table[i].index = index;\r
-                       return GL_TRUE;\r
-               }\r
-\r
-       self->table = (slang_attrib_override *) slang_alloc_realloc (self->table,\r
-               n * sizeof (slang_attrib_override), (n + 1) * sizeof (slang_attrib_override));\r
-       if (self->table == NULL)\r
-               return GL_FALSE;\r
-\r
-       self->table[n].index = index;\r
-       self->table[n].name = slang_string_duplicate (name);\r
-       if (self->table[n].name == NULL)\r
-               return GL_FALSE;\r
-       self->count++;\r
-\r
-       return GL_TRUE;\r
-}\r
-\r
-static GLuint lookup_attrib_override (slang_attrib_overrides *self, const GLchar *name)\r
-{\r
-       GLuint i;\r
-\r
-       for (i = 0; self->count; i++)\r
-               if (slang_string_compare (name, self->table[i].name) == 0)\r
-                       return self->table[i].index;\r
-       return MAX_VERTEX_ATTRIBS;\r
-}\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 add_simple_uniform_binding (slang_uniform_bindings *self,\r
-       slang_export_data_quant *q, const char *name, GLuint index, GLuint addr)\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] = addr;\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
-\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
-       for (i = 0; i < SLANG_SHADER_MAX; i++)\r
-               self->table[n].address[i] = ~0;\r
-       self->table[n].address[index] = addr;\r
-       self->count++;\r
-\r
-       return GL_TRUE;\r
-}\r
-\r
-static GLboolean add_complex_uniform_binding (slang_uniform_bindings *self,\r
-       slang_export_data_quant *q, 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
-       count = slang_export_data_quant_elements (q);\r
-       for (i = 0; i < count; i++)\r
-       {\r
-               GLuint bracket_pos;\r
-\r
-               bracket_pos = slang_string_length (name);\r
-               if (slang_export_data_quant_array (q))\r
-                       _mesa_sprintf (name + slang_string_length (name), "[%d]", i);\r
-\r
-               if (slang_export_data_quant_struct (q))\r
-               {\r
-                       GLuint dot_pos, i;\r
-                       const GLuint fields = slang_export_data_quant_fields (q);\r
-\r
-                       slang_string_concat (name, ".");\r
-                       dot_pos = slang_string_length (name);\r
-\r
-                       for (i = 0; i < fields; i++)\r
-                       {\r
-                               if (!add_complex_uniform_binding (self, &q->structure[i], name, atoms, index, addr))\r
-                                       return GL_FALSE;\r
-\r
-                               name[dot_pos] = '\0';\r
-                               addr += slang_export_data_quant_size (&q->structure[i]);\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       if (!add_simple_uniform_binding (self, q, name, index, addr))\r
-                               return GL_FALSE;\r
-\r
-                       addr += slang_export_data_quant_size (q);\r
-               }\r
-\r
-               name[bracket_pos] = '\0';\r
-       }\r
-\r
-       return GL_TRUE;\r
-}\r
-\r
-static GLboolean gather_uniform_bindings (slang_uniform_bindings *self,\r
-       slang_export_data_table *tbl, 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 (!add_complex_uniform_binding (self, &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_attrib_bindings\r
- */\r
-\r
-static GLvoid slang_attrib_bindings_ctr (slang_attrib_bindings *self)\r
-{\r
-       GLuint i;\r
-\r
-       self->binding_count = 0;\r
-       for (i = 0; i < MAX_VERTEX_ATTRIBS; i++)\r
-               self->slots[i].addr = ~0;\r
-}\r
-\r
-static GLvoid slang_attrib_bindings_dtr (slang_attrib_bindings *self)\r
-{\r
-       GLuint i;\r
-\r
-       for (i = 0; i < self->binding_count; i++)\r
-               slang_alloc_free (self->bindings[i].name);\r
-}\r
-\r
-static GLuint can_allocate_attrib_slots (slang_attrib_bindings *self, GLuint index, GLuint count)\r
-{\r
-       GLuint i;\r
-\r
-       for (i = 0; i < count; i++)\r
-               if (self->slots[index + i].addr != ~0)\r
-                       break;\r
-       return i;\r
-}\r
-\r
-static GLuint allocate_attrib_slots (slang_attrib_bindings *self, GLuint count)\r
-{\r
-       GLuint i;\r
-\r
-       for (i = 0; i <= MAX_VERTEX_ATTRIBS - count; i++)\r
-       {\r
-               GLuint size;\r
-               \r
-               size = can_allocate_attrib_slots (self, i, count);\r
-               if (size == count)\r
-                       return i;\r
-\r
-               /* speed-up the search a bit */\r
-               i += count;\r
-       }\r
-       return MAX_VERTEX_ATTRIBS;\r
-}\r
-\r
-static GLboolean add_attrib_binding (slang_attrib_bindings *self, slang_export_data_quant *q,\r
-       const char *name, GLuint addr, GLuint index_override)\r
-{\r
-       const GLuint n = self->binding_count;\r
-       GLuint slot_span, slot_index;\r
-       GLuint i;\r
-\r
-       assert (slang_export_data_quant_simple (q));\r
-\r
-       switch (slang_export_data_quant_type (q))\r
-       {\r
-       case GL_FLOAT:\r
-       case GL_FLOAT_VEC2:\r
-       case GL_FLOAT_VEC3:\r
-       case GL_FLOAT_VEC4:\r
-               slot_span = 1;\r
-               break;\r
-       case GL_FLOAT_MAT2:\r
-               slot_span = 2;\r
-               break;\r
-       case GL_FLOAT_MAT3:\r
-               slot_span = 3;\r
-               break;\r
-       case GL_FLOAT_MAT4:\r
-               slot_span = 4;\r
-               break;\r
-       default:\r
-               assert (0);\r
-       }\r
-\r
-       if (index_override == MAX_VERTEX_ATTRIBS)\r
-               slot_index = allocate_attrib_slots (self, slot_span);\r
-       else if (can_allocate_attrib_slots (self, index_override, slot_span) == slot_span)\r
-               slot_index = index_override;\r
-       else\r
-               slot_index = MAX_VERTEX_ATTRIBS;\r
-                       \r
-       if (slot_index == MAX_VERTEX_ATTRIBS)\r
-       {\r
-               /* TODO: info log: error: MAX_VERTEX_ATTRIBS exceeded */\r
-               return GL_FALSE;\r
-       }\r
-\r
-       self->bindings[n].quant = q;\r
-       self->bindings[n].name = slang_string_duplicate (name);\r
-       if (self->bindings[n].name == NULL)\r
-               return GL_FALSE;\r
-       self->bindings[n].first_slot_index = slot_index;\r
-       self->binding_count++;\r
-\r
-       for (i = 0; i < slot_span; i++)\r
-               self->slots[self->bindings[n].first_slot_index + i].addr = addr + i * 4;\r
-\r
-       return GL_TRUE;\r
-}\r
-\r
-static GLboolean gather_attrib_bindings (slang_attrib_bindings *self, slang_export_data_table *tbl,\r
-       slang_attrib_overrides *ovr)\r
-{\r
-       GLuint i;\r
-\r
-       /* First pass. Gather attribs that have overriden index slots. */\r
-       for (i = 0; i < tbl->count; i++)\r
-               if (tbl->entries[i].access == slang_exp_attribute &&\r
-                       !entry_has_gl_prefix (tbl->entries[i].quant.name, tbl->atoms))\r
-               {\r
-                       slang_export_data_quant *quant = &tbl->entries[i].quant;\r
-                       const GLchar *id = slang_atom_pool_id (tbl->atoms, quant->name);\r
-                       GLuint index = lookup_attrib_override (ovr, id);\r
-\r
-                       if (index != MAX_VERTEX_ATTRIBS)\r
-                       {\r
-                               if (!add_attrib_binding (self, quant, id, tbl->entries[i].address, index))\r
-                                       return GL_FALSE;\r
-                       }\r
-               }\r
-\r
-       /* Second pass. Gather attribs that have *NOT* overriden index slots. */\r
-       for (i = 0; i < tbl->count; i++)\r
-               if (tbl->entries[i].access == slang_exp_attribute &&\r
-                       !entry_has_gl_prefix (tbl->entries[i].quant.name, tbl->atoms))\r
-               {\r
-                       slang_export_data_quant *quant = &tbl->entries[i].quant;\r
-                       const GLchar *id = slang_atom_pool_id (tbl->atoms, quant->name);\r
-                       GLuint index = lookup_attrib_override (ovr, id);\r
-\r
-                       if (index == MAX_VERTEX_ATTRIBS)\r
-                       {\r
-                               if (!add_attrib_binding (self, quant, id, tbl->entries[i].address, index))\r
-                                       return GL_FALSE;\r
-                       }\r
-               }\r
-\r
-       return GL_TRUE;\r
-}\r
-\r
-/*\r
- * slang_varying_bindings\r
- */\r
-\r
-static GLvoid slang_varying_bindings_ctr (slang_varying_bindings *self)\r
-{\r
-       self->binding_count = 0;\r
-       self->slot_count = 0;\r
-}\r
-\r
-static GLvoid slang_varying_bindings_dtr (slang_varying_bindings *self)\r
-{\r
-       GLuint i;\r
-\r
-       for (i = 0; i < self->binding_count; i++)\r
-               slang_alloc_free (self->bindings[i].name);\r
-}\r
-\r
-static GLvoid update_varying_slots (slang_varying_slot *slots, GLuint count, GLboolean is_vert,\r
-       GLuint addr, GLuint do_offset)\r
-{\r
-       GLuint i;\r
-\r
-       for (i = 0; i < count; i++)\r
-               *(is_vert ? &slots[i].vert_addr : &slots[i].frag_addr) = addr + i * 4 * do_offset;\r
-}\r
-\r
-static GLboolean add_varying_binding (slang_varying_bindings *self,\r
-       slang_export_data_quant *q, const char *name, GLboolean is_vert, GLuint addr)\r
-{\r
-       const GLuint n = self->binding_count;\r
-       const GLuint slot_span =\r
-               slang_export_data_quant_components (q) * slang_export_data_quant_elements (q);\r
-       GLuint i;\r
-\r
-       for (i = 0; i < n; i++)\r
-               if (slang_string_compare (self->bindings[i].name, name) == 0)\r
-               {\r
-                       /* TODO: data quantities must match, or else link fails */\r
-                       update_varying_slots (&self->slots[self->bindings[i].first_slot_index], slot_span,\r
-                               is_vert, addr, 1);\r
-                       return GL_TRUE;\r
-               }\r
-\r
-       if (self->slot_count + slot_span > MAX_VARYING_FLOATS)\r
-       {\r
-               /* TODO: info log: error: MAX_VARYING_FLOATS exceeded */\r
-               return GL_FALSE;\r
-       }\r
-\r
-       self->bindings[n].quant = q;\r
-       self->bindings[n].name = slang_string_duplicate (name);\r
-       if (self->bindings[n].name == NULL)\r
-               return GL_FALSE;\r
-       self->bindings[n].first_slot_index = self->slot_count;\r
-       self->binding_count++;\r
-\r
-       update_varying_slots (&self->slots[self->bindings[n].first_slot_index], slot_span, is_vert,\r
-               addr, 1);\r
-       update_varying_slots (&self->slots[self->bindings[n].first_slot_index], slot_span, !is_vert,\r
-               ~0, 0);\r
-       self->slot_count += slot_span;\r
-\r
-       return GL_TRUE;\r
-}\r
-\r
-static GLboolean gather_varying_bindings (slang_varying_bindings *self,\r
-       slang_export_data_table *tbl, GLboolean is_vert)\r
-{\r
-       GLuint i;\r
-\r
-       for (i = 0; i < tbl->count; i++)\r
-               if (tbl->entries[i].access == slang_exp_varying &&\r
-                       !entry_has_gl_prefix (tbl->entries[i].quant.name, tbl->atoms))\r
-               {\r
-                       if (!add_varying_binding (self, &tbl->entries[i].quant, slang_atom_pool_id (tbl->atoms,\r
-                               tbl->entries[i].quant.name), is_vert, tbl->entries[i].address))\r
-                               return GL_FALSE;\r
-               }\r
-\r
-       return GL_TRUE;\r
-}\r
-\r
-/*\r
- * slang_texture_bindings\r
- */\r
-\r
-GLvoid slang_texture_usages_ctr (slang_texture_usages *self)\r
-{\r
-       self->table = NULL;\r
-       self->count = 0;\r
-}\r
-\r
-GLvoid slang_texture_usages_dtr (slang_texture_usages *self)\r
-{\r
-       slang_alloc_free (self->table);\r
-}\r
-\r
-/*\r
- * slang_program\r
- */\r
-\r
-GLvoid slang_program_ctr (slang_program *self)\r
-{\r
-       GLuint i;\r
-\r
-       slang_active_variables_ctr (&self->active_uniforms);\r
-       slang_active_variables_ctr (&self->active_attribs);\r
-       slang_attrib_overrides_ctr (&self->attrib_overrides);\r
-       slang_uniform_bindings_ctr (&self->uniforms);\r
-       slang_attrib_bindings_ctr (&self->attribs);\r
-       slang_varying_bindings_ctr (&self->varyings);\r
-       slang_texture_usages_ctr (&self->texture_usage);\r
-       for (i = 0; i < SLANG_SHADER_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
-               for (j = 0; j < SLANG_COMMON_CODE_MAX; j++)\r
-                       self->code[i][j] = ~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_active_variables_dtr (&self->active_uniforms);\r
-       slang_active_variables_dtr (&self->active_attribs);\r
-       slang_attrib_overrides_dtr (&self->attrib_overrides);\r
-       slang_uniform_bindings_dtr (&self->uniforms);\r
-       slang_attrib_bindings_dtr (&self->attribs);\r
-       slang_varying_bindings_dtr (&self->varyings);\r
-       slang_texture_usages_dtr (&self->texture_usage);\r
-}\r
-\r
-static GLvoid slang_program_rst (slang_program *self)\r
-{\r
-       GLuint i;\r
-\r
-       slang_active_variables_dtr (&self->active_uniforms);\r
-       slang_active_variables_dtr (&self->active_attribs);\r
-       slang_uniform_bindings_dtr (&self->uniforms);\r
-       slang_attrib_bindings_dtr (&self->attribs);\r
-       slang_varying_bindings_dtr (&self->varyings);\r
-       slang_texture_usages_dtr (&self->texture_usage);\r
-\r
-       slang_active_variables_ctr (&self->active_uniforms);\r
-       slang_active_variables_ctr (&self->active_attribs);\r
-       slang_uniform_bindings_ctr (&self->uniforms);\r
-       slang_attrib_bindings_ctr (&self->attribs);\r
-       slang_varying_bindings_ctr (&self->varyings);\r
-       slang_texture_usages_ctr (&self->texture_usage);\r
-       for (i = 0; i < SLANG_SHADER_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
-               for (j = 0; j < SLANG_COMMON_CODE_MAX; j++)\r
-                       self->code[i][j] = ~0;\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
-/*\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 resolve_common_fixed (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 resolve_vertex_fixed (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 resolve_fragment_fixed (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_common_code (GLuint code[], slang_export_code_table *tbl)\r
-{\r
-       code[SLANG_COMMON_CODE_MAIN] = gc (tbl, "@main");\r
-}\r
-\r
-GLboolean _slang_link (slang_program *prog, slang_translation_unit **units, GLuint count)\r
-{\r
-       GLuint i;\r
-\r
-       slang_program_rst (prog);\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_SHADER_FRAGMENT;\r
-                       resolve_fragment_fixed (prog->fragment_fixed_entries, &units[i]->exp_data);\r
-               }\r
-               else\r
-               {\r
-                       index = SLANG_SHADER_VERTEX;\r
-                       resolve_vertex_fixed (prog->vertex_fixed_entries, &units[i]->exp_data);\r
-                       if (!gather_attrib_bindings (&prog->attribs, &units[i]->exp_data,\r
-                               &prog->attrib_overrides))\r
-                               return GL_FALSE;\r
-               }\r
-\r
-               if (!gather_active_variables (&prog->active_uniforms, &units[i]->exp_data,\r
-                       slang_exp_uniform))\r
-                       return GL_FALSE;\r
-               if (!gather_active_variables (&prog->active_attribs, &units[i]->exp_data,\r
-                       slang_exp_attribute))\r
-                       return GL_FALSE;\r
-               if (!gather_uniform_bindings (&prog->uniforms, &units[i]->exp_data, index))\r
-                       return GL_FALSE;\r
-               if (!gather_varying_bindings (&prog->varyings, &units[i]->exp_data,\r
-                       index == SLANG_SHADER_VERTEX))\r
-                       return GL_FALSE;\r
-               resolve_common_fixed (prog->common_fixed_entries[index], &units[i]->exp_data);\r
-               resolve_common_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
-       /* TODO: all varyings read by fragment shader must be written by vertex shader */\r
-\r
-       if (!_slang_analyse_texture_usage (prog))\r
-               return GL_FALSE;\r
-\r
-       return GL_TRUE;\r
-}\r
-\r
+/*
+ * Mesa 3-D graphics library
+ * Version:  7.3
+ *
+ * Copyright (C) 2008  Brian Paul   All Rights Reserved.
+ * Copyright (C) 2009  VMware, Inc.  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;
+}
+
+
+
+/**
+ * Check if the given bit is either set or clear in both bitfields.
+ */
+static GLboolean
+bits_agree(GLbitfield flags1, GLbitfield flags2, GLbitfield bit)
+{
+   return (flags1 & bit) == (flags2 & bit);
+}
+
+
+/**
+ * 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.
+ * We'll then rewrite instructions to replace PROGRAM_VARYING with either
+ * PROGRAM_INPUT or PROGRAM_OUTPUT depending on whether it's a vertex or
+ * fragment shader.
+ * This is also where we set program Input/OutputFlags to indicate
+ * which inputs are centroid-sampled, invariant, etc.
+ */
+static GLboolean
+link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog)
+{
+   GLuint *map, i, firstVarying, newFile;
+   GLbitfield *inOutFlags;
+
+   map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint));
+   if (!map)
+      return GL_FALSE;
+
+   /* 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;
+      inOutFlags = prog->OutputFlags;
+   }
+   else {
+      assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB);
+      firstVarying = FRAG_ATTRIB_VAR0;
+      newFile = PROGRAM_INPUT;
+      inOutFlags = prog->InputFlags;
+   }
+
+   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) {
+         /* varying is already in list, do some error checking */
+         const struct gl_program_parameter *v =
+            &shProg->Varying->Parameters[j];
+         if (var->Size != v->Size) {
+            link_error(shProg, "mismatched varying variable types");
+            return GL_FALSE;
+         }
+         if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_CENTROID)) {
+            char msg[100];
+            _mesa_snprintf(msg, sizeof(msg),
+                           "centroid modifier mismatch for '%s'", var->Name);
+            link_error(shProg, msg);
+            return GL_FALSE;
+         }
+         if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_INVARIANT)) {
+            char msg[100];
+            _mesa_snprintf(msg, sizeof(msg),
+                           "invariant modifier mismatch for '%s'", var->Name);
+            link_error(shProg, msg);
+            return GL_FALSE;
+         }
+      }
+      else {
+         /* not already in linked list */
+         j = _mesa_add_varying(shProg->Varying, var->Name, var->Size,
+                               var->Flags);
+      }
+
+      /* Map varying[i] to varying[j].
+       * Plus, set prog->Input/OutputFlags[] as described above.
+       * Note: the loop here takes care of arrays or large (sz>4) vars.
+       */
+      {
+         GLint sz = var->Size;
+         while (sz > 0) {
+            inOutFlags[firstVarying + j] = var->Flags;
+            /*printf("Link varying from %d to %d\n", i, j);*/
+            map[i++] = j++;
+            sz -= 4;
+         }
+         i--; /* go back one */
+      }
+   }
+
+
+   /* 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.
+ *
+ * About uniforms:
+ * Each uniform has two indexes, one that points into the vertex
+ * program's parameter array and another that points into the fragment
+ * program's parameter array.  When the user changes a uniform's value
+ * we have to change the value in the vertex and/or fragment program's
+ * parameter array.
+ *
+ * This function will be called twice to set up the two uniform->parameter
+ * mappings.
+ *
+ * If a uniform is only present in the vertex program OR fragment program
+ * then the fragment/vertex parameter index, respectively, will be -1.
+ */
+static GLboolean
+link_uniform_vars(GLcontext *ctx,
+                  struct gl_shader_program *shProg,
+                  struct gl_program *prog,
+                  GLuint *numSamplers)
+{
+   GLuint samplerMap[200]; /* max number of samplers declared, not used */
+   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->Type == PROGRAM_SAMPLER)
+          && p->Used) {
+         /* add this uniform, indexing into the target's Parameters list */
+         struct gl_uniform *uniform =
+            _mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i);
+         if (uniform)
+            uniform->Initialized = p->Initialized;
+      }
+
+      /* The samplerMap[] table we build here is used to remap/re-index
+       * sampler references by TEX instructions.
+       */
+      if (p->Type == PROGRAM_SAMPLER && p->Used) {
+         /* Allocate a new sampler index */
+         GLuint oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0];
+         GLuint newSampNum = *numSamplers;
+         if (newSampNum >= ctx->Const.MaxTextureImageUnits) {
+            char s[100];
+            _mesa_sprintf(s, "Too many texture samplers (%u, max is %u)",
+                          newSampNum, ctx->Const.MaxTextureImageUnits);
+            link_error(shProg, s);
+            return GL_FALSE;
+         }
+         /* save old->new mapping in the table */
+         if (oldSampNum < Elements(samplerMap))
+            samplerMap[oldSampNum] = newSampNum;
+         /* update parameter's sampler index */
+         prog->Parameters->ParameterValues[i][0] = (GLfloat) newSampNum;
+         (*numSamplers)++;
+      }
+   }
+
+   /* OK, now scan the program/shader instructions looking for texture
+    * instructions using sampler vars.  Replace old sampler indexes with
+    * new ones.
+    */
+   prog->SamplersUsed = 0x0;
+   for (i = 0; i < prog->NumInstructions; i++) {
+      struct prog_instruction *inst = prog->Instructions + i;
+      if (_mesa_is_tex_instruction(inst->Opcode)) {
+         const GLint oldSampNum = inst->TexSrcUnit;
+
+#if 0
+         printf("====== remap sampler from %d to %d\n",
+                inst->TexSrcUnit, samplerMap[ inst->TexSrcUnit ]);
+#endif
+
+         /* here, texUnit is really samplerUnit */
+         if (oldSampNum < Elements(samplerMap)) {
+            const GLuint newSampNum = samplerMap[oldSampNum];
+            inst->TexSrcUnit = newSampNum;
+            prog->SamplerTargets[newSampNum] = inst->TexSrcTarget;
+            prog->SamplersUsed |= (1 << newSampNum);
+         }
+      }
+   }
+
+   return GL_TRUE;
+}
+
+
+/**
+ * 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; /* generics only, not legacy attributes */
+
+   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);
+   }
+
+   /* If gl_Vertex is used, that actually counts against the limit
+    * on generic vertex attributes.  This avoids the ambiguity of
+    * whether glVertexAttrib4fv(0, v) sets legacy attribute 0 (vert pos)
+    * or generic attribute[0].  If gl_Vertex is used, we want the former.
+    */
+   if (origProg->InputsRead & VERT_BIT_POS) {
+      usedAttributes |= 0x1;
+   }
+
+   /* 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 = 0; 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) {
+      if (!link_uniform_vars(ctx, shProg, &shProg->VertexProgram->Base,
+                             &numSamplers)) {
+         return;
+      }
+   }
+   if (shProg->FragmentProgram) {
+      if (!link_uniform_vars(ctx, shProg, &shProg->FragmentProgram->Base,
+                             &numSamplers)) {
+         return;
+      }
+   }
+
+   /*_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;
+      }         
+   }
+
+   /* check that gl_FragColor and gl_FragData are not both written to */
+   if (shProg->FragmentProgram) {
+      GLbitfield outputsWritten = shProg->FragmentProgram->Base.OutputsWritten;
+      if ((outputsWritten & ((1 << FRAG_RESULT_COLR))) &&
+          (outputsWritten >= (1 << FRAG_RESULT_DATA0))) {
+         link_error(shProg, "Fragment program cannot write both gl_FragColor"
+                    " and gl_FragData[].\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 (ctx->Shader.Flags & GLSL_DUMP) {
+         _mesa_printf("Mesa pre-link fragment program:\n");
+         _mesa_print_program(&fragProg->Base);
+         _mesa_print_program_parameters(ctx, &fragProg->Base);
+
+         _mesa_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 (ctx->Shader.Flags & GLSL_DUMP) {
+         _mesa_printf("Mesa pre-link vertex program:\n");
+         _mesa_print_program(&vertProg->Base);
+         _mesa_print_program_parameters(ctx, &vertProg->Base);
+
+         _mesa_printf("Mesa post-link vertex program:\n");
+         _mesa_print_program(&shProg->VertexProgram->Base);
+         _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base);
+      }
+   }
+
+   if (ctx->Shader.Flags & GLSL_DUMP) {
+      _mesa_printf("Varying vars:\n");
+      _mesa_print_parameter_list(shProg->Varying);
+      if (shProg->InfoLog) {
+         _mesa_printf("Info Log: %s\n", shProg->InfoLog);
+      }
+   }
+
+   shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram);
+}
+