Implement vertex attribute binding.
authorBrian <brian@yutani.localnet.net>
Wed, 10 Jan 2007 00:49:24 +0000 (17:49 -0700)
committerBrian <brian@yutani.localnet.net>
Wed, 10 Jan 2007 00:49:24 +0000 (17:49 -0700)
Users can set explicit binding with glBindAttribLocation(), otherwise the
linker will allocate generic attribute slots.

src/mesa/main/mtypes.h
src/mesa/shader/prog_parameter.c
src/mesa/shader/prog_parameter.h
src/mesa/shader/prog_statevars.h
src/mesa/shader/program.c
src/mesa/shader/shader_api.c
src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_compile.c
src/mesa/shader/slang/slang_link.h
src/mesa/shader/slang/slang_link2.c

index b6c7205..cbb1fd4 100644 (file)
@@ -1844,16 +1844,16 @@ struct gl_program_parameter_list;
 struct gl_program
 {
    GLuint Id;
-   GLubyte *String;          /**< Null-terminated program text */
+   GLubyte *String;  /**< Null-terminated program text */
    GLint RefCount;
-   GLenum Target;
-   GLenum Format;            /**< String encoding format */
+   GLenum Target;    /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB, GL_FRAGMENT_PROGRAM_NV */
+   GLenum Format;    /**< String encoding format */
    GLboolean Resident;
 
    struct prog_instruction *Instructions;
 
-   GLbitfield InputsRead;     /* Bitmask of which input regs are read */
-   GLbitfield OutputsWritten; /* Bitmask of which output regs are written to */
+   GLbitfield InputsRead;     /**< Bitmask of which input regs are read */
+   GLbitfield OutputsWritten; /**< Bitmask of which output regs are written to */
    GLbitfield TexturesUsed[MAX_TEXTURE_IMAGE_UNITS];  /**< TEXTURE_x_BIT bitmask */
 
    /** Named parameters, constants, etc. from program text */
@@ -1863,6 +1863,8 @@ struct gl_program
 
    /** Vertex/fragment shader varying vars */
    struct gl_program_parameter_list *Varying;
+   /** Vertex program user-defined attributes */
+   struct gl_program_parameter_list *Attributes;
 
    /** Logical counts */
    /*@{*/
index d09cc65..e543871 100644 (file)
@@ -239,6 +239,9 @@ _mesa_add_sampler(struct gl_program_parameter_list *paramList,
 }
 
 
+/**
+ * Add parameter representing a varying variable.
+ */
 GLint
 _mesa_add_varying(struct gl_program_parameter_list *paramList,
                   const char *name, GLuint size)
@@ -256,6 +259,31 @@ _mesa_add_varying(struct gl_program_parameter_list *paramList,
 }
 
 
+/**
+ * Add parameter representing a vertex program attribute.
+ */
+GLint
+_mesa_add_attribute(struct gl_program_parameter_list *paramList,
+                    const char *name, GLint attrib)
+{
+   GLint size = 4; /* XXX ok? */
+   GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
+   if (i >= 0) {
+      /* replace */
+      ASSERT(paramList->Parameters[i].StateIndexes[0] == STATE_USER_ATTRIB);
+      paramList->Parameters[i].StateIndexes[1] = attrib;
+   }
+   else {
+      /* add */
+      i = _mesa_add_parameter(paramList, name, NULL, size, PROGRAM_INPUT);
+      if (i >= 0) {
+         paramList->Parameters[i].StateIndexes[0] = STATE_USER_ATTRIB;
+         paramList->Parameters[i].StateIndexes[1] = attrib;
+      }
+   }
+   return i;
+}
+
 
 
 #if 0 /* not used yet */
index 0db2bcd..ab4d730 100644 (file)
@@ -108,6 +108,10 @@ _mesa_add_varying(struct gl_program_parameter_list *paramList,
                   const char *name, GLuint size);
 
 extern GLint
+_mesa_add_attribute(struct gl_program_parameter_list *paramList,
+                    const char *name, GLint attrib);
+
+extern GLint
 _mesa_add_state_reference(struct gl_program_parameter_list *paramList,
                           const GLint *stateTokens);
 
index 17e3805..da672c9 100644 (file)
@@ -96,6 +96,8 @@ typedef enum gl_state_index_ {
    STATE_NORMAL_SCALE,
    STATE_TEXRECT_SCALE,
    STATE_POSITION_NORMALIZED,   /* normalized light position */
+   STATE_USER_ATTRIB,           /** shader vertex attrib: user-specified */
+   STATE_AUTO_ATTRIB,           /** shader vertex attrib: linker-specified */
    STATE_INTERNAL_DRIVER       /* first available state index for drivers (must be last) */
 } gl_state_index;
 
index 1b26b6c..7a31949 100644 (file)
@@ -365,6 +365,8 @@ _mesa_clone_program(GLcontext *ctx, const struct gl_program *prog)
    memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
    if (prog->Varying)
       clone->Varying = _mesa_clone_parameter_list(prog->Varying);
+   if (prog->Attributes)
+      clone->Attributes = _mesa_clone_parameter_list(prog->Attributes);
    memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
    clone->NumInstructions = prog->NumInstructions;
    clone->NumTemporaries = prog->NumTemporaries;
index bd258f8..d1b0e21 100644 (file)
@@ -40,6 +40,8 @@
 #include "hash.h"
 #include "program.h"
 #include "prog_parameter.h"
+#include "prog_print.h"
+#include "prog_statevars.h"
 #include "shader_api.h"
 
 #include "slang_compile.h"
@@ -59,6 +61,7 @@ _mesa_new_shader_program(GLcontext *ctx, GLuint name)
       shProg->Type = GL_SHADER_PROGRAM;
       shProg->Name = name;
       shProg->RefCount = 1;
+      shProg->Attributes = _mesa_new_parameter_list();
    }
    return shProg;
 }
@@ -275,6 +278,8 @@ _mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
 {
    struct gl_shader_program *shProg
       = _mesa_lookup_shader_program(ctx, program);
+   GLint i;
+   GLint oldIndex;
 
    if (!shProg) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
@@ -290,15 +295,21 @@ _mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
       return;
    }
 
-#if 0 /* XXXX */
-   if (name == NULL || index >= MAX_VERTEX_ATTRIBS)
-      _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocationARB");
-   else if (IS_NAME_WITH_GL_PREFIX(name))
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glBindAttribLocationARB");
-   else
-      (**pro).OverrideAttribBinding(pro, index, name);
-   RELEASE_PROGRAM(pro);
-#endif
+   oldIndex = _mesa_get_attrib_location(ctx, program, name);
+
+   /* this will replace the current value if it's already in the list */
+   i = _mesa_add_attribute(shProg->Attributes, name, index);
+   if (i < 0) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
+   }
+
+   if (shProg->VertexProgram && oldIndex >= 0) {
+      _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
+   }
+
+   printf("===== post BindAttrib:\n");
+   _mesa_print_program(&shProg->VertexProgram->Base);
+
 }
 
 
@@ -541,11 +552,9 @@ _mesa_get_attrib_location(GLcontext *ctx, GLuint program,
       return -1;
 
    if (shProg->Attributes) {
-      GLuint i;
-      for (i = 0; i < shProg->Attributes->NumParameters; i++) {
-         if (!strcmp(shProg->Attributes->Parameters[i].Name, name)) {
-            return i;
-         }
+      GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
+      if (i >= 0) {
+         return shProg->Attributes->Parameters[i].StateIndexes[1];
       }
    }
    return -1;
@@ -605,7 +614,7 @@ _mesa_get_programiv(GLcontext *ctx, GLuint program,
       *params = shProg->NumShaders;
       break;
    case GL_ACTIVE_ATTRIBUTES:
-      *params = shProg->Uniforms ? shProg->Uniforms->NumParameters : 0;
+      *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
       break;
    case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
       *params = _mesa_parameter_longest_name(shProg->Attributes);
index 79261ee..cc70d1d 100644 (file)
@@ -540,7 +540,8 @@ _slang_codegen_global_variable(slang_variable *var, struct gl_program *prog,
    }
    else if (var->type.qualifier == slang_qual_const) {
       if (prog) {
-         abort();
+         /* user-defined constant */
+         abort(); /* XXX fix */
       }
       else {
          /* pre-defined global constant, like gl_MaxLights */
@@ -550,11 +551,22 @@ _slang_codegen_global_variable(slang_variable *var, struct gl_program *prog,
       if (dbg) printf("CONST ");
    }
    else if (var->type.qualifier == slang_qual_attribute) {
-      /* Vertex attribute */
-      GLint index = _slang_input_index(varName, GL_VERTEX_PROGRAM_ARB);
-      GLint size = 4; /* XXX? */
-      assert(index >= 0);
-      store = _slang_new_ir_storage(PROGRAM_INPUT, index, size);
+      if (prog) {
+         /* user-defined vertex attribute */
+         const GLint size = _slang_sizeof_type_specifier(&var->type.specifier);
+         GLint index = _mesa_add_parameter(prog->Attributes, varName,
+                                           NULL, size, PROGRAM_INPUT);
+         assert(index >= 0);
+         store = _slang_new_ir_storage(PROGRAM_INPUT,
+                                       VERT_ATTRIB_GENERIC0 + index, size);
+      }
+      else {
+         /* pre-defined vertex attrib */
+         GLint index = _slang_input_index(varName, GL_VERTEX_PROGRAM_ARB);
+         GLint size = 4; /* XXX? */
+         assert(index >= 0);
+         store = _slang_new_ir_storage(PROGRAM_INPUT, index, size);
+      }
       if (dbg) printf("ATTRIB ");
    }
    else if (var->type.qualifier == slang_qual_fixedinput) {
index efb2325..314c32f 100644 (file)
@@ -2260,6 +2260,7 @@ _slang_compile(GLcontext *ctx, struct gl_shader *shader)
 
       shader->Programs[0]->Parameters = _mesa_new_parameter_list();
       shader->Programs[0]->Varying = _mesa_new_parameter_list();
+      shader->Programs[0]->Attributes = _mesa_new_parameter_list();
    }
 
    slang_info_log_construct(&info_log);
index 2fc5525..d981928 100644 (file)
@@ -357,6 +357,9 @@ extern void
 _slang_resolve_samplers(struct gl_shader_program *shProg,
                         struct gl_program *prog);
 
+extern void
+_slang_remap_attribute(struct gl_program *prog, GLuint oldAttrib, GLuint newAttrib);
+
 
 #ifdef __cplusplus
 }
index 3a5bce0..0965f3e 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"
 
@@ -311,31 +312,71 @@ _slang_resolve_branches(struct gl_program *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.
+ * 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.
  */
-void
-_slang_resolve_samplers(struct gl_shader_program *shProg,
-                        struct gl_program *prog)
+static GLboolean
+_slang_resolve_attributes(struct gl_shader_program *shProg,
+                          struct gl_program *prog)
 {
-   GLuint i;
+   GLuint i, j;
+   GLbitfield usedAttributes;
 
-   for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
-      prog->TexturesUsed[i] = 0;
+   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[1];
+      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;
-      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;
+      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[1];
+            }
+            else {
+               /* not found, choose our own attribute number */
+               for (attr = 0; 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, attr);
+            }
 
-         prog->TexturesUsed[inst->TexSrcUnit] |= (1 << inst->TexSrcTarget);
+            inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr;
+         }
       }
    }
+   return GL_TRUE;
 }
 
 
@@ -366,6 +407,65 @@ _slang_update_inputs_outputs(struct gl_program *prog)
 }
 
 
+/**
+ * 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 *
@@ -463,10 +563,12 @@ _slang_link2(GLcontext *ctx,
 
    _slang_resolve_branches(&shProg->VertexProgram->Base);
    _slang_resolve_branches(&shProg->FragmentProgram->Base);
-#if 1
+
    _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
    _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
-#endif
+
+   _slang_resolve_attributes(shProg, &shProg->VertexProgram->Base);
+
    _slang_update_inputs_outputs(&shProg->VertexProgram->Base);
    _slang_update_inputs_outputs(&shProg->FragmentProgram->Base);