-#include "program/prog_parameter.h"
-#include "program/prog_statevars.h"
-#include "program/prog_uniform.h"
-
-
-
-static GLenum
-base_uniform_type(GLenum type)
-{
- switch (type) {
-#if 0 /* not needed, for now */
- case GL_BOOL:
- case GL_BOOL_VEC2:
- case GL_BOOL_VEC3:
- case GL_BOOL_VEC4:
- return GL_BOOL;
-#endif
- case GL_FLOAT:
- case GL_FLOAT_VEC2:
- case GL_FLOAT_VEC3:
- case GL_FLOAT_VEC4:
- return GL_FLOAT;
- case GL_UNSIGNED_INT:
- case GL_UNSIGNED_INT_VEC2:
- case GL_UNSIGNED_INT_VEC3:
- case GL_UNSIGNED_INT_VEC4:
- return GL_UNSIGNED_INT;
- case GL_INT:
- case GL_INT_VEC2:
- case GL_INT_VEC3:
- case GL_INT_VEC4:
- return GL_INT;
- default:
- _mesa_problem(NULL, "Invalid type in base_uniform_type()");
- return GL_FLOAT;
- }
-}
-
-
-static GLboolean
-is_boolean_type(GLenum type)
-{
- switch (type) {
- case GL_BOOL:
- case GL_BOOL_VEC2:
- case GL_BOOL_VEC3:
- case GL_BOOL_VEC4:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-static GLboolean
-is_sampler_type(GLenum type)
-{
- switch (type) {
- case GL_SAMPLER_1D:
- case GL_SAMPLER_2D:
- case GL_SAMPLER_3D:
- case GL_SAMPLER_CUBE:
- case GL_SAMPLER_1D_SHADOW:
- case GL_SAMPLER_2D_SHADOW:
- case GL_SAMPLER_2D_RECT_ARB:
- case GL_SAMPLER_2D_RECT_SHADOW_ARB:
- case GL_SAMPLER_1D_ARRAY_EXT:
- case GL_SAMPLER_2D_ARRAY_EXT:
- case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-static struct gl_program_parameter *
-get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
-{
- const struct gl_program *prog = NULL;
- GLint progPos;
-
- 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;
- } else {
- progPos = shProg->Uniforms->Uniforms[index].GeomPos;
- if (progPos >= 0) {
- prog = &shProg->GeometryProgram->Base;
- }
- }
- }
-
- if (!prog || progPos < 0)
- return NULL; /* should never happen */
-
- return &prog->Parameters->Parameters[progPos];
-}
-
-
-/**
- * Called by glGetActiveUniform().
- */
-static void
-_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
- GLsizei maxLength, GLsizei *length, GLint *size,
- GLenum *type, GLchar *nameOut)
-{
- const struct gl_shader_program *shProg;
- const struct gl_program *prog = NULL;
- const struct gl_program_parameter *param;
- GLint progPos;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
- if (!shProg)
- return;
-
- if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
- return;
- }
-
- 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;
- } else {
- progPos = shProg->Uniforms->Uniforms[index].GeomPos;
- if (progPos >= 0) {
- prog = &shProg->GeometryProgram->Base;
- }
- }
- }
-
- if (!prog || progPos < 0)
- return; /* should never happen */
-
- ASSERT(progPos < prog->Parameters->NumParameters);
- param = &prog->Parameters->Parameters[progPos];
-
- if (nameOut) {
- _mesa_copy_string(nameOut, maxLength, length, param->Name);
- }
-
- if (size) {
- GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
- if ((GLint) param->Size > typeSize) {
- /* This is an array.
- * Array elements are placed on vector[4] boundaries so they're
- * a multiple of four floats. We round typeSize up to next multiple
- * of four to get the right size below.
- */
- typeSize = (typeSize + 3) & ~3;
- }
- /* Note that the returned size is in units of the <type>, not bytes */
- *size = param->Size / typeSize;
- }
-
- if (type) {
- *type = param->DataType;
- }
-}
-
-
-
-static void
-get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
-{
- switch (type) {
- case GL_FLOAT_MAT2:
- *rows = *cols = 2;
- break;
- case GL_FLOAT_MAT2x3:
- *rows = 3;
- *cols = 2;
- break;
- case GL_FLOAT_MAT2x4:
- *rows = 4;
- *cols = 2;
- break;
- case GL_FLOAT_MAT3:
- *rows = 3;
- *cols = 3;
- break;
- case GL_FLOAT_MAT3x2:
- *rows = 2;
- *cols = 3;
- break;
- case GL_FLOAT_MAT3x4:
- *rows = 4;
- *cols = 3;
- break;
- case GL_FLOAT_MAT4:
- *rows = 4;
- *cols = 4;
- break;
- case GL_FLOAT_MAT4x2:
- *rows = 2;
- *cols = 4;
- break;
- case GL_FLOAT_MAT4x3:
- *rows = 3;
- *cols = 4;
- break;
- default:
- *rows = *cols = 0;
- }
-}
-
-
-/**
- * Determine the number of rows and columns occupied by a uniform
- * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
- * the number of rows = 1 and cols = number of elements in the vector.
- */
-static void
-get_uniform_rows_cols(const struct gl_program_parameter *p,
- GLint *rows, GLint *cols)
-{
- get_matrix_dims(p->DataType, rows, cols);
- if (*rows == 0 && *cols == 0) {
- /* not a matrix type, probably a float or vector */
- if (p->Size <= 4) {
- *rows = 1;
- *cols = p->Size;
- }
- else {
- *rows = p->Size / 4 + 1;
- if (p->Size % 4 == 0)
- *cols = 4;
- else
- *cols = p->Size % 4;
- }
- }
-}
-
-
-/**
- * Helper for get_uniform[fi]v() functions.
- * Given a shader program name and uniform location, return a pointer
- * to the shader program and return the program parameter position.
- */
-static void
-lookup_uniform_parameter(GLcontext *ctx, GLuint program, GLint location,
- struct gl_program **progOut, GLint *paramPosOut)
-{
- struct gl_shader_program *shProg
- = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
- struct gl_program *prog = NULL;
- GLint progPos = -1;
-
- /* if shProg is NULL, we'll have already recorded an error */
-
- if (shProg) {
- if (!shProg->Uniforms ||
- location < 0 ||
- location >= (GLint) shProg->Uniforms->NumUniforms) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
- }
- else {
- /* OK, find the gl_program and program parameter location */
- progPos = shProg->Uniforms->Uniforms[location].VertPos;
- if (progPos >= 0) {
- prog = &shProg->VertexProgram->Base;
- }
- else {
- progPos = shProg->Uniforms->Uniforms[location].FragPos;
- if (progPos >= 0) {
- prog = &shProg->FragmentProgram->Base;
- } else {
- progPos = shProg->Uniforms->Uniforms[location].GeomPos;
- if (progPos >= 0) {
- prog = &shProg->GeometryProgram->Base;
- }
- }
- }
- }
- }
-
- *progOut = prog;
- *paramPosOut = progPos;
-}
-
-
-/**
- * GLGL uniform arrays and structs require special handling.
- *
- * The GL_ARB_shader_objects spec says that if you use
- * glGetUniformLocation to get the location of an array, you CANNOT
- * access other elements of the array by adding an offset to the
- * returned location. For example, you must call
- * glGetUniformLocation("foo[16]") if you want to set the 16th element
- * of the array with glUniform().
- *
- * HOWEVER, some other OpenGL drivers allow accessing array elements
- * by adding an offset to the returned array location. And some apps
- * seem to depend on that behaviour.
- *
- * Mesa's gl_uniform_list doesn't directly support this since each
- * entry in the list describes one uniform variable, not one uniform
- * element. We could insert dummy entries in the list for each array
- * element after [0] but that causes complications elsewhere.
- *
- * We solve this problem by encoding two values in the location that's
- * returned by glGetUniformLocation():
- * a) index into gl_uniform_list::Uniforms[] for the uniform
- * b) an array/field offset (0 for simple types)
- *
- * These two values are encoded in the high and low halves of a GLint.
- * By putting the uniform number in the high part and the offset in the
- * low part, we can support the unofficial ability to index into arrays
- * by adding offsets to the location value.
- */
-static void
-merge_location_offset(GLint *location, GLint offset)
-{
- *location = (*location << 16) | offset;
-}
-
-
-/**
- * Separate the uniform location and parameter offset. See above.
- */
-static void
-split_location_offset(GLint *location, GLint *offset)
-{
- *offset = *location & 0xffff;
- *location = *location >> 16;
-}
-
-
-
-/**
- * Called via glGetUniformfv().
- */
-static void
-_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
- GLfloat *params)
-{
- struct gl_program *prog;
- GLint paramPos;
- GLint offset;
-
- split_location_offset(&location, &offset);
-
- lookup_uniform_parameter(ctx, program, location, &prog, ¶mPos);
-
- if (prog) {
- const struct gl_program_parameter *p =
- &prog->Parameters->Parameters[paramPos];
- GLint rows, cols, i, j, k;
-
- get_uniform_rows_cols(p, &rows, &cols);
-
- k = 0;
- for (i = 0; i < rows; i++) {
- for (j = 0; j < cols; j++ ) {
- params[k++] = prog->Parameters->ParameterValues[paramPos+i][j];
- }
- }
- }
-}
-
-
-/**
- * Called via glGetUniformiv().
- * \sa _mesa_get_uniformfv, only difference is a cast.
- */
-static void
-_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
- GLint *params)
-{
- struct gl_program *prog;
- GLint paramPos;
- GLint offset;
-
- split_location_offset(&location, &offset);
-
- lookup_uniform_parameter(ctx, program, location, &prog, ¶mPos);
-
- if (prog) {
- const struct gl_program_parameter *p =
- &prog->Parameters->Parameters[paramPos];
- GLint rows, cols, i, j, k;
-
- get_uniform_rows_cols(p, &rows, &cols);
-
- k = 0;
- for (i = 0; i < rows; i++) {
- for (j = 0; j < cols; j++ ) {
- params[k++] = (GLint) prog->Parameters->ParameterValues[paramPos+i][j];
- }
- }
- }
-}
-
-
-/**
- * Called via glGetUniformLocation().
- *
- * The return value will encode two values, the uniform location and an
- * offset (used for arrays, structs).
- */
-GLint
-_mesa_get_uniform_location(GLcontext *ctx, struct gl_shader_program *shProg,
- const GLchar *name)
-{
- GLint offset = 0, location = -1;
-
- if (shProg->LinkStatus == GL_FALSE) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
- return -1;
- }
-
- /* XXX we should return -1 if the uniform was declared, but not
- * actually used.
- */
-
- /* XXX we need to be able to parse uniform names for structs and arrays
- * such as:
- * mymatrix[1]
- * mystruct.field1
- */
-
- {
- /* handle 1-dimension arrays here... */
- char *c = strchr(name, '[');
- if (c) {
- /* truncate name at [ */
- const GLint len = c - name;
- GLchar *newName = malloc(len + 1);
- if (!newName)
- return -1; /* out of mem */
- memcpy(newName, name, len);
- newName[len] = 0;
-
- location = _mesa_lookup_uniform(shProg->Uniforms, newName);
- if (location >= 0) {
- const GLint element = atoi(c + 1);
- if (element > 0) {
- /* get type of the uniform array element */
- struct gl_program_parameter *p;
- p = get_uniform_parameter(shProg, location);
- if (p) {
- GLint rows, cols;
- get_matrix_dims(p->DataType, &rows, &cols);
- if (rows < 1)
- rows = 1;
- offset = element * rows;
- }
- }
- }
-
- free(newName);
- }
- }
-
- if (location < 0) {
- location = _mesa_lookup_uniform(shProg->Uniforms, name);
- }
-
- if (location >= 0) {
- merge_location_offset(&location, offset);
- }
-
- return location;
-}
-
-