summaryrefslogtreecommitdiffstats
path: root/src/mesa/shader/shader_api.c
diff options
context:
space:
mode:
authorBrian Paul <[email protected]>2008-05-14 16:09:46 -0600
committerBrian Paul <[email protected]>2008-05-14 16:09:46 -0600
commitade508312c701ce89d3c2cd717994dbbabb4f207 (patch)
tree7c7a35935143d90c99820025a8887c5606041db6 /src/mesa/shader/shader_api.c
parentc807c1a23fc918591e9d2f6f26c4e071a725bced (diff)
Updated GLSL uniform/sampler handling from gallium-0.1 branch
Previously, the shader linker combined the uniforms used by the vertex and fragment shaders into a combined set of uniforms. This made the implementation of glUniform*() simple, but was rather inefficient otherwise. Now each shader gets its own set of uniforms (no more modelview matrix showing up in the fragment shader uniforms, for example). cherry-picked by hand from gallium-0.1 branch
Diffstat (limited to 'src/mesa/shader/shader_api.c')
-rw-r--r--src/mesa/shader/shader_api.c423
1 files changed, 211 insertions, 212 deletions
diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c
index 65a8c6cc54a..11450db6448 100644
--- a/src/mesa/shader/shader_api.c
+++ b/src/mesa/shader/shader_api.c
@@ -43,6 +43,7 @@
#include "prog_parameter.h"
#include "prog_print.h"
#include "prog_statevars.h"
+#include "prog_uniform.h"
#include "shader/shader_api.h"
#include "shader/slang/slang_compile.h"
#include "shader/slang/slang_link.h"
@@ -75,23 +76,23 @@ _mesa_clear_shader_program_data(GLcontext *ctx,
struct gl_shader_program *shProg)
{
if (shProg->VertexProgram) {
- if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) {
- /* to prevent a double-free in the next call */
- shProg->VertexProgram->Base.Parameters = NULL;
- }
+ /* Set ptr to NULL since the param list is shared with the
+ * original/unlinked program.
+ */
+ shProg->VertexProgram->Base.Parameters = NULL;
_mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
}
if (shProg->FragmentProgram) {
- if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) {
- /* to prevent a double-free in the next call */
- shProg->FragmentProgram->Base.Parameters = NULL;
- }
+ /* Set ptr to NULL since the param list is shared with the
+ * original/unlinked program.
+ */
+ shProg->FragmentProgram->Base.Parameters = NULL;
_mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
}
if (shProg->Uniforms) {
- _mesa_free_parameter_list(shProg->Uniforms);
+ _mesa_free_uniform_list(shProg->Uniforms);
shProg->Uniforms = NULL;
}
@@ -680,9 +681,9 @@ _mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
shProg->Attributes->Parameters[index].Name);
sz = shProg->Attributes->Parameters[index].Size;
if (size)
- *size = 1; /* attributes may not be arrays */
- if (type && sz > 0 && sz <= 4) /* XXX this is a temporary hack */
- *type = vec_types[sz - 1];
+ *size = sz;
+ if (type)
+ *type = vec_types[sz]; /* XXX this is a temporary hack */
}
@@ -696,41 +697,41 @@ _mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
{
struct gl_shader_program *shProg
= _mesa_lookup_shader_program(ctx, program);
- GLuint ind, j;
+ const struct gl_program *prog;
+ GLint progPos;
if (!shProg) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
return;
}
- if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
+ if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
return;
}
- ind = 0;
- for (j = 0; j < shProg->Uniforms->NumParameters; j++) {
- if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
- shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
- if (ind == index) {
- GLuint uSize = shProg->Uniforms->Parameters[j].Size;
- GLenum uType = shProg->Uniforms->Parameters[j].DataType;
- /* found it */
- copy_string(nameOut, maxLength, length,
- shProg->Uniforms->Parameters[j].Name);
- if (size) {
- /* convert from floats to 'type' (eg: sizeof(mat4x4)=1) */
- *size = uSize / sizeof_glsl_type(uType);
- }
- if (type)
- *type = uType;
- return;
- }
- ind++;
+ progPos = shProg->Uniforms->Uniforms[index].VertPos;
+ if (progPos >= 0) {
+ prog = &shProg->VertexProgram->Base;
+ }
+ else {
+ progPos = shProg->Uniforms->Uniforms[index].FragPos;
+ if (progPos >= 0) {
+ prog = &shProg->FragmentProgram->Base;
}
}
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
+ if (!prog || progPos < 0)
+ return; /* should never happen */
+
+ if (nameOut)
+ copy_string(nameOut, maxLength, length,
+ prog->Parameters->Parameters[progPos].Name);
+ if (size)
+ *size = prog->Parameters->Parameters[progPos].Size;
+
+ if (type)
+ *type = prog->Parameters->Parameters[progPos].DataType;
}
@@ -848,14 +849,10 @@ _mesa_get_programiv(GLcontext *ctx, GLuint program,
PROGRAM_INPUT) + 1;
break;
case GL_ACTIVE_UNIFORMS:
- *params
- = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM)
- + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER);
+ *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
break;
case GL_ACTIVE_UNIFORM_MAX_LENGTH:
- *params = MAX2(
- _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM),
- _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER));
+ *params = _mesa_longest_uniform_name(shProg->Uniforms);
if (*params > 0)
(*params)++; /* add one for terminating zero */
break;
@@ -952,42 +949,24 @@ _mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
struct gl_shader_program *shProg
= _mesa_lookup_shader_program(ctx, program);
if (shProg) {
- GLint i;
- if (location >= 0 && location < shProg->Uniforms->NumParameters) {
- GLuint uSize;
- GLenum uType;
- GLint rows = 0;
- uType = shProg->Uniforms->Parameters[location].DataType;
- uSize = sizeof_glsl_type(uType);
- /* Matrix types need special handling, because they span several
- * parameters, and may also not be fully packed.
- */
- switch (shProg->Uniforms->Parameters[location].DataType) {
- case GL_FLOAT_MAT2:
- case GL_FLOAT_MAT3x2:
- case GL_FLOAT_MAT4x2:
- rows = 2;
- break;
- case GL_FLOAT_MAT2x3:
- case GL_FLOAT_MAT3:
- case GL_FLOAT_MAT4x3:
- rows = 3;
- break;
- case GL_FLOAT_MAT2x4:
- case GL_FLOAT_MAT3x4:
- case GL_FLOAT_MAT4:
- rows = 4;
- }
- if (rows != 0) {
- GLint r, c;
- for (c = 0, i = 0; c * 4 < uSize; c++)
- for (r = 0; r < rows; r++, i++)
- params[i] = shProg->Uniforms->ParameterValues[location + c][r];
+ if (location < shProg->Uniforms->NumUniforms) {
+ GLint progPos, i;
+ const struct gl_program *prog;
+
+ progPos = shProg->Uniforms->Uniforms[location].VertPos;
+ if (progPos >= 0) {
+ prog = &shProg->VertexProgram->Base;
}
- else
- for (i = 0; i < uSize; i++) {
- params[i] = shProg->Uniforms->ParameterValues[location][i];
+ else {
+ progPos = shProg->Uniforms->Uniforms[location].FragPos;
+ if (progPos >= 0) {
+ prog = &shProg->FragmentProgram->Base;
}
+ }
+
+ for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
+ params[i] = prog->Parameters->ParameterValues[progPos][i];
+ }
}
else {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
@@ -1007,23 +986,10 @@ _mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
{
struct gl_shader_program *shProg
= _mesa_lookup_shader_program(ctx, program);
- if (shProg) {
- GLuint loc;
- for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
- const struct gl_program_parameter *u
- = shProg->Uniforms->Parameters + loc;
- /* XXX this is a temporary simplification / short-cut.
- * We need to handle things like "e.c[0].b" as seen in the
- * GLSL orange book, page 189.
- */
- if ((u->Type == PROGRAM_UNIFORM ||
- u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
- return loc;
- }
- }
- }
- return -1;
+ if (!shProg)
+ return -1;
+ return _mesa_lookup_uniform(shProg->Uniforms, name);
}
@@ -1134,55 +1100,121 @@ _mesa_use_program(GLcontext *ctx, GLuint program)
}
+
/**
- * Called via ctx->Driver.Uniform().
+ * Update the vertex and fragment program's TexturesUsed arrays.
*/
-void
-_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
- const GLvoid *values, GLenum type)
+static void
+update_textures_used(struct gl_program *prog)
{
- struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
- GLint elems, i, k;
- GLenum uType;
- GLsizei maxCount;
+ GLuint s;
- if (!shProg || !shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
- return;
- }
+ memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
- if (location == -1)
- return; /* The standard specifies this as a no-op */
-
- /* The spec says this is GL_INVALID_OPERATION, although it seems like it
- * ought to be GL_INVALID_VALUE
- */
- if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
- return;
+ for (s = 0; s < MAX_SAMPLERS; s++) {
+ if (prog->SamplersUsed & (1 << s)) {
+ GLuint u = prog->SamplerUnits[s];
+ GLuint t = prog->SamplerTargets[s];
+ assert(u < MAX_TEXTURE_IMAGE_UNITS);
+ prog->TexturesUsed[u] |= (1 << t);
+ }
}
+}
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- uType = shProg->Uniforms->Parameters[location].DataType;
- /*
- * If we're setting a sampler, we must use glUniformi1()!
- */
- if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
- GLint unit;
+/**
+ * Set the value of a program's uniform variable.
+ * \param program the program whose uniform to update
+ * \param location the location/index of the uniform
+ * \param type the datatype of the uniform
+ * \param count the number of uniforms to set
+ * \param elems number of elements per uniform
+ * \param values the new values
+ */
+static void
+set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
+ GLenum type, GLint count, GLint elems, const void *values)
+{
+ if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
+ /* This controls which texture unit which is used by a sampler */
+ GLuint texUnit, sampler;
+
+ /* data type for setting samplers must be int */
if (type != GL_INT || count != 1) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glUniform(only glUniform1i can be used "
"to set sampler uniforms)");
return;
}
+
+ sampler = (GLuint) program->Parameters->ParameterValues[location][0];
+ texUnit = ((GLuint *) values)[0];
+
/* check that the sampler (tex unit index) is legal */
- unit = ((GLint *) values)[0];
- if (unit >= ctx->Const.MaxTextureImageUnits) {
+ if (texUnit >= ctx->Const.MaxTextureImageUnits) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glUniform1(invalid sampler/tex unit index)");
return;
}
+
+ /* This maps a sampler to a texture unit: */
+ program->SamplerUnits[sampler] = texUnit;
+ update_textures_used(program);
+
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ }
+ else {
+ /* ordinary uniform variable */
+ GLint k, i;
+
+ if (count * elems > program->Parameters->Parameters[location].Size) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
+ return;
+ }
+
+ for (k = 0; k < count; k++) {
+ GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
+ if (type == GL_INT ||
+ type == GL_INT_VEC2 ||
+ type == GL_INT_VEC3 ||
+ type == GL_INT_VEC4) {
+ const GLint *iValues = ((const GLint *) values) + k * elems;
+ for (i = 0; i < elems; i++) {
+ uniformVal[i] = (GLfloat) iValues[i];
+ }
+ }
+ else {
+ const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
+ for (i = 0; i < elems; i++) {
+ uniformVal[i] = fValues[i];
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Called via ctx->Driver.Uniform().
+ */
+void
+_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
+ const GLvoid *values, GLenum type)
+{
+ struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
+ GLint elems;
+
+ if (!shProg || !shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
+ return;
+ }
+
+ if (location == -1)
+ return; /* The standard specifies this as a no-op */
+
+ if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
+ return;
}
if (count < 0) {
@@ -1212,69 +1244,56 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
return;
}
- /* OpenGL requires types to match exactly, except that one can convert
- * float or int array to boolean array.
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ /* A uniform var may be used by both a vertex shader and a fragment
+ * shader. We may need to update one or both shader's uniform here:
*/
- switch (uType)
- {
- case GL_BOOL:
- case GL_BOOL_VEC2:
- case GL_BOOL_VEC3:
- case GL_BOOL_VEC4:
- if (elems != sizeof_glsl_type(uType)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count mismatch)");
- }
- break;
- case PROGRAM_SAMPLER:
- break;
- default:
- if (shProg->Uniforms->Parameters[location].Type != PROGRAM_SAMPLER
- && uType != type) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
- }
- break;
+ if (shProg->VertexProgram) {
+ GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
+ if (loc >= 0) {
+ set_program_uniform(ctx, &shProg->VertexProgram->Base,
+ loc, type, count, elems, values);
+ }
+ }
+
+ if (shProg->FragmentProgram) {
+ GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
+ if (loc >= 0) {
+ set_program_uniform(ctx, &shProg->FragmentProgram->Base,
+ loc, type, count, elems, values);
+ }
}
+}
- /* XXX if this is a base type, then count must equal 1. However, we
- * don't have enough information from the compiler to distinguish a
- * base type from a 1-element array of that type. The standard allows
- * count to overrun an array, in which case the overflow is ignored.
+
+static void
+set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
+ GLuint location, GLuint rows, GLuint cols,
+ GLboolean transpose, const GLfloat *values)
+{
+ /*
+ * Note: the _columns_ of a matrix are stored in program registers, not
+ * the rows.
*/
- maxCount = shProg->Uniforms->Parameters[location].Size / elems;
- if (count > maxCount) count = maxCount;
-
- for (k = 0; k < count; k++) {
- GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
- if (type == GL_INT ||
- type == GL_INT_VEC2 ||
- type == GL_INT_VEC3 ||
- type == GL_INT_VEC4) {
- const GLint *iValues = ((const GLint *) values) + k * elems;
- for (i = 0; i < elems; i++) {
- uniformVal[i] = (GLfloat) iValues[i];
+ /* XXXX need to test 3x3 and 2x2 matrices... */
+ if (transpose) {
+ GLuint row, col;
+ for (col = 0; col < cols; col++) {
+ GLfloat *v = program->Parameters->ParameterValues[location + col];
+ for (row = 0; row < rows; row++) {
+ v[row] = values[row * cols + col];
}
}
- else {
- const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
- for (i = 0; i < elems; i++) {
- uniformVal[i] = fValues[i];
+ }
+ else {
+ GLuint row, col;
+ for (col = 0; col < cols; col++) {
+ GLfloat *v = program->Parameters->ParameterValues[location + col];
+ for (row = 0; row < rows; row++) {
+ v[row] = values[col * rows + row];
}
}
- if (uType == GL_BOOL ||
- uType == GL_BOOL_VEC2 ||
- uType == GL_BOOL_VEC3 ||
- uType == GL_BOOL_VEC4) {
- for (i = 0; i < elems; i++)
- uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
- }
- }
-
- if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
- if (shProg->VertexProgram)
- _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
- if (shProg->FragmentProgram)
- _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
}
}
@@ -1287,62 +1306,42 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
GLenum matrixType, GLint location, GLsizei count,
GLboolean transpose, const GLfloat *values)
{
- GLsizei maxCount, i;
struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
+
if (!shProg || !shProg->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glUniformMatrix(program not linked)");
return;
}
+
if (location == -1)
return; /* The standard specifies this as a no-op */
- /* The spec says this is GL_INVALID_OPERATION, although it seems like it
- * ought to be GL_INVALID_VALUE
- */
- if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
+
+ if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
return;
}
if (values == NULL) {
_mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
return;
}
- if (count < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(count < 0)");
- return;
- }
FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- /*
- * Note: the _columns_ of a matrix are stored in program registers, not
- * the rows.
- */
- /* XXXX need to test 3x3 and 2x2 matrices... */
- maxCount = shProg->Uniforms->Parameters[location].Size / (4 * cols);
- if (count > maxCount)
- count = maxCount;
- for (i = 0; i < count; i++) {
- if (transpose) {
- GLuint row, col;
- for (col = 0; col < cols; col++) {
- GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
- for (row = 0; row < rows; row++) {
- v[row] = values[row * cols + col];
- }
- }
+ if (shProg->VertexProgram) {
+ GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
+ if (loc >= 0) {
+ set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
+ loc, rows, cols, transpose, values);
}
- else {
- GLuint row, col;
- for (col = 0; col < cols; col++) {
- GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
- for (row = 0; row < rows; row++) {
- v[row] = values[col * rows + row];
- }
- }
+ }
+
+ if (shProg->FragmentProgram) {
+ GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
+ if (loc >= 0) {
+ set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
+ loc, rows, cols, transpose, values);
}
- location += cols;
- values += rows * cols;
}
}