summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian <[email protected]>2007-01-09 17:49:24 -0700
committerBrian <[email protected]>2007-01-09 17:49:24 -0700
commit3209c3ed0d82c158eed1020759aacf51ba1c1ad5 (patch)
treea2dad53d32547ef01b36fd9296dc4f68e52292f8
parent5e75db12d7b17f0295e8099bd357220df97d5013 (diff)
Implement vertex attribute binding.
Users can set explicit binding with glBindAttribLocation(), otherwise the linker will allocate generic attribute slots.
-rw-r--r--src/mesa/main/mtypes.h12
-rw-r--r--src/mesa/shader/prog_parameter.c28
-rw-r--r--src/mesa/shader/prog_parameter.h4
-rw-r--r--src/mesa/shader/prog_statevars.h2
-rw-r--r--src/mesa/shader/program.c2
-rw-r--r--src/mesa/shader/shader_api.c39
-rw-r--r--src/mesa/shader/slang/slang_codegen.c24
-rw-r--r--src/mesa/shader/slang/slang_compile.c1
-rw-r--r--src/mesa/shader/slang/slang_link.h3
-rw-r--r--src/mesa/shader/slang/slang_link2.c138
10 files changed, 209 insertions, 44 deletions
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index b6c72055e16..cbb1fd47eb2 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -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 */
/*@{*/
diff --git a/src/mesa/shader/prog_parameter.c b/src/mesa/shader/prog_parameter.c
index d09cc659376..e543871ab79 100644
--- a/src/mesa/shader/prog_parameter.c
+++ b/src/mesa/shader/prog_parameter.c
@@ -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 */
diff --git a/src/mesa/shader/prog_parameter.h b/src/mesa/shader/prog_parameter.h
index 0db2bcd314f..ab4d7300188 100644
--- a/src/mesa/shader/prog_parameter.h
+++ b/src/mesa/shader/prog_parameter.h
@@ -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);
diff --git a/src/mesa/shader/prog_statevars.h b/src/mesa/shader/prog_statevars.h
index 17e38054bb3..da672c9ec88 100644
--- a/src/mesa/shader/prog_statevars.h
+++ b/src/mesa/shader/prog_statevars.h
@@ -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;
diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c
index 1b26b6c9321..7a319496730 100644
--- a/src/mesa/shader/program.c
+++ b/src/mesa/shader/program.c
@@ -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;
diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c
index bd258f8737b..d1b0e21b949 100644
--- a/src/mesa/shader/shader_api.c
+++ b/src/mesa/shader/shader_api.c
@@ -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);
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index 79261ee29a6..cc70d1de2a2 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -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) {
diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c
index efb23255f94..314c32f7077 100644
--- a/src/mesa/shader/slang/slang_compile.c
+++ b/src/mesa/shader/slang/slang_compile.c
@@ -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);
diff --git a/src/mesa/shader/slang/slang_link.h b/src/mesa/shader/slang/slang_link.h
index 2fc5525000f..d9819289cac 100644
--- a/src/mesa/shader/slang/slang_link.h
+++ b/src/mesa/shader/slang/slang_link.h
@@ -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
}
diff --git a/src/mesa/shader/slang/slang_link2.c b/src/mesa/shader/slang/slang_link2.c
index 3a5bce00995..0965f3e4c4e 100644
--- a/src/mesa/shader/slang/slang_link2.c
+++ b/src/mesa/shader/slang/slang_link2.c
@@ -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);