remove stray tab
[mesa.git] / src / mesa / shader / slang / slang_link2.c
index 81a1875548166127c47f800877dd899d4d26bf7c..0a517aecc5f5f741f4d1dd4352300fe4eb89d627 100644 (file)
@@ -36,6 +36,7 @@
 #include "prog_instruction.h"
 #include "prog_parameter.h"
 #include "prog_print.h"
+#include "prog_statevars.h"
 #include "shader_api.h"
 #include "slang_link.h"
 
@@ -138,6 +139,7 @@ is_uniform(enum register_file file)
            file == PROGRAM_STATE_VAR ||
            file == PROGRAM_NAMED_PARAM ||
            file == PROGRAM_CONSTANT ||
+           file == PROGRAM_SAMPLER ||
            file == PROGRAM_UNIFORM);
 }
 
@@ -148,7 +150,8 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
    GLuint *map, i;
 
 #if 0
-      _mesa_print_parameter_list(prog->Parameters);
+   printf("================ pre link uniforms ===============\n");
+   _mesa_print_parameter_list(shProg->Uniforms);
 #endif
 
    map = (GLuint *) malloc(prog->Parameters->NumParameters * sizeof(GLuint));
@@ -201,6 +204,9 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
          case PROGRAM_UNIFORM:
             j = _mesa_add_uniform(shProg->Uniforms, p->Name, p->Size);
             break;
+         case PROGRAM_SAMPLER:
+            j = _mesa_add_sampler(shProg->Uniforms, p->Name);
+            break;
          default:
             abort();
          }
@@ -218,6 +224,11 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
 
    }
 
+#if 0
+   printf("================ post link uniforms ===============\n");
+   _mesa_print_parameter_list(shProg->Uniforms);
+#endif
+
 #if 0
    {
       GLuint i;
@@ -244,7 +255,16 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
             inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ];
          }
       }
-      /* XXX update program OutputsWritten, InputsRead */
+
+      if (inst->Opcode == OPCODE_TEX ||
+          inst->Opcode == OPCODE_TXB ||
+          inst->Opcode == OPCODE_TXP) {
+         /*
+         printf("====== remap sampler from %d to %d\n",
+                inst->Sampler, map[ inst->Sampler ]);
+         */
+         inst->Sampler = map[ inst->Sampler ];
+      }
    }
 
    free(map);
@@ -257,7 +277,7 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
  * XXX Temporary
  */
 static void
-slang_resolve_branches(struct gl_program *prog)
+_slang_resolve_branches(struct gl_program *prog)
 {
    struct target {
       const char *Name;
@@ -293,6 +313,166 @@ slang_resolve_branches(struct gl_program *prog)
 }
 
 
+/**
+ * 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.
+ */
+static GLboolean
+_slang_resolve_attributes(struct gl_shader_program *shProg,
+                          struct gl_program *prog)
+{
+   GLuint i, j;
+   GLbitfield usedAttributes;
+   GLint size = 4; /* XXX fix */
+
+   assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
+
+   /* 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 |= attr;
+   }
+
+   if (!shProg->Attributes)
+      shProg->Attributes = _mesa_new_parameter_list();
+
+   /*
+    * Scan program for generic attribute references
+    */
+   for (i = 0; i < prog->NumInstructions; i++) {
+      struct prog_instruction *inst = prog->Instructions + i;
+      for (j = 0; j < 3; j++) {
+         if (inst->SrcReg[j].File == PROGRAM_INPUT &&
+             inst->SrcReg[j].Index >= VERT_ATTRIB_GENERIC0) {
+            /* this is a generic attrib */
+            const GLint k = inst->SrcReg[j].Index - VERT_ATTRIB_GENERIC0;
+            const char *name = prog->Attributes->Parameters[k].Name;
+            /* See if this attrib name is in the program's attribute list
+             * (i.e. was bound by the user).
+             */
+            GLint index = _mesa_lookup_parameter_index(shProg->Attributes,
+                                                          -1, name);
+            GLint attr;
+            if (index >= 0) {
+               /* found, user must have specified a binding */
+               attr = shProg->Attributes->Parameters[index].StateIndexes[0];
+            }
+            else {
+               /* Not found, 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) {
+                  /* too many!  XXX record error log */
+                  return GL_FALSE;
+               }
+               _mesa_add_attribute(shProg->Attributes, name, size, attr);
+            }
+
+            inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr;
+         }
+      }
+   }
+   return GL_TRUE;
+}
+
+
+/**
+ * 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;
+
+   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 (inst->DstReg.File == PROGRAM_OUTPUT) {
+         prog->OutputsWritten |= 1 << inst->DstReg.Index;
+      }
+   }
+}
+
+
+/**
+ * Scan a vertex program looking for instances of
+ * (PROGRAM_INPUT, VERT_ATTRIB_GENERIC0 + oldAttrib) and replace with
+ * (PROGRAM_INPUT, VERT_ATTRIB_GENERIC0 + newAttrib).
+ * This is used when the user calls glBindAttribLocation on an already linked
+ * shader program.
+ */
+void
+_slang_remap_attribute(struct gl_program *prog, GLuint oldAttrib, GLuint newAttrib)
+{
+   GLuint i, j;
+
+   assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
+
+   for (i = 0; i < prog->NumInstructions; i++) {
+      struct prog_instruction *inst = prog->Instructions + i;
+      for (j = 0; j < 3; j++) {
+         if (inst->SrcReg[j].File == PROGRAM_INPUT) {
+            if (inst->SrcReg[j].Index == VERT_ATTRIB_GENERIC0 + oldAttrib) {
+               inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + newAttrib;
+            }
+         }
+      }
+   }
+
+   _slang_update_inputs_outputs(prog);
+}
+
+
+
+/**
+ * Scan program for texture instructions, lookup sampler/uniform's value
+ * to determine which texture unit to use.
+ * Also, update the program's TexturesUsed[] array.
+ */
+void
+_slang_resolve_samplers(struct gl_shader_program *shProg,
+                        struct gl_program *prog)
+{
+   GLuint i;
+
+   for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
+      prog->TexturesUsed[i] = 0;
+
+   for (i = 0; i < prog->NumInstructions; i++) {
+      struct prog_instruction *inst = prog->Instructions + i;
+      if (inst->Opcode == OPCODE_TEX ||
+          inst->Opcode == OPCODE_TXB ||
+          inst->Opcode == OPCODE_TXP) {
+         GLint sampleUnit = (GLint) shProg->Uniforms->ParameterValues[inst->Sampler][0];
+         assert(sampleUnit < MAX_TEXTURE_IMAGE_UNITS);
+         inst->TexSrcUnit = sampleUnit;
+
+         prog->TexturesUsed[inst->TexSrcUnit] |= (1 << inst->TexSrcTarget);
+      }
+   }
+}
+
+
+
 /** cast wrapper */
 static struct gl_vertex_program *
 vertex_program(struct gl_program *prog)
@@ -387,8 +567,18 @@ _slang_link2(GLcontext *ctx,
    shProg->VertexProgram->Base.Parameters = shProg->Uniforms;
    shProg->FragmentProgram->Base.Parameters = shProg->Uniforms;
 
-   slang_resolve_branches(&shProg->VertexProgram->Base);
-   slang_resolve_branches(&shProg->FragmentProgram->Base);
+   _slang_resolve_branches(&shProg->VertexProgram->Base);
+   _slang_resolve_branches(&shProg->FragmentProgram->Base);
+
+   _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
+   _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
+
+   if (!_slang_resolve_attributes(shProg, &shProg->VertexProgram->Base)) {
+      /*goto cleanup;*/
+   }
+
+   _slang_update_inputs_outputs(&shProg->VertexProgram->Base);
+   _slang_update_inputs_outputs(&shProg->FragmentProgram->Base);
 
 #if 1
    printf("************** original fragment program\n");