GLint GLAPIENTRY _mesa_GetUniformLocation(GLuint programObj, const GLcharARB *name) { struct gl_shader_program *shProg; GLuint index, offset; GET_CURRENT_CONTEXT(ctx); shProg = _mesa_lookup_shader_program_err(ctx, programObj, "glGetUniformLocation"); if (!shProg) return -1; /* Page 80 (page 94 of the PDF) of the OpenGL 2.1 spec says: * * "If program has not been successfully linked, the error * INVALID_OPERATION is generated." */ if (shProg->LinkStatus == GL_FALSE) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformLocation(program not linked)"); return -1; } index = _mesa_get_uniform_location(ctx, shProg, name, &offset); if (index == GL_INVALID_INDEX) return -1; /* From the GL_ARB_uniform_buffer_object spec: * * "The value -1 will be returned if <name> does not correspond to an * active uniform variable name in <program>, if <name> is associated * with a named uniform block, or if <name> starts with the reserved * prefix "gl_"." */ if (shProg->UniformStorage[index].block_index != -1 || shProg->UniformStorage[index].atomic_buffer_index != -1) return -1; return _mesa_uniform_merge_location_offset(shProg, index, offset); }
/** * Called via glGetUniformLocation(). * * The return value will encode two values, the uniform location and an * offset (used for arrays, structs). */ extern "C" GLint _mesa_get_uniform_location(struct gl_context *ctx, struct gl_shader_program *shProg, const GLchar *name) { const size_t len = strlen(name); long offset; bool array_lookup; char *name_copy; /* If the name ends with a ']', assume that it refers to some element of an * array. Malformed array references will fail the hash table look up * below, so it doesn't matter that they are not caught here. This code * only wants to catch the "leaf" array references so that arrays of * structures containing arrays will be handled correctly. */ if (name[len-1] == ']') { unsigned i; /* Walk backwards over the string looking for a non-digit character. * This had better be the opening bracket for an array index. * * Initially, i specifies the location of the ']'. Since the string may * contain only the ']' charcater, walk backwards very carefully. */ for (i = len - 1; (i > 0) && isdigit(name[i-1]); --i) /* empty */ ; /* Page 80 (page 94 of the PDF) of the OpenGL 2.1 spec says: * * "The first element of a uniform array is identified using the * name of the uniform array appended with "[0]". Except if the last * part of the string name indicates a uniform array, then the * location of the first element of that array can be retrieved by * either using the name of the uniform array, or the name of the * uniform array appended with "[0]"." * * Page 79 (page 93 of the PDF) of the OpenGL 2.1 spec says: * * "name must be a null terminated string, without white space." * * Return an error if there is no opening '[' to match the closing ']'. * An error will also be returned if there is intervening white space * (or other non-digit characters) before the opening '['. */ if ((i == 0) || name[i-1] != '[') return -1; /* Return an error if there are no digits between the opening '[' to * match the closing ']'. */ if (i == (len - 1)) return -1; /* Make a new string that is a copy of the old string up to (but not * including) the '[' character. */ name_copy = (char *) malloc(i); memcpy(name_copy, name, i - 1); name_copy[i-1] = '\0'; offset = strtol(&name[i], NULL, 10); if (offset < 0) return -1; array_lookup = true; } else { name_copy = (char *) name; offset = 0; array_lookup = false; } unsigned location = 0; const bool found = shProg->UniformHash->get(location, name_copy); assert(!found || strcmp(name_copy, shProg->UniformStorage[location].name) == 0); /* Free the temporary buffer *before* possibly returning an error. */ if (name_copy != name) free(name_copy); if (!found) return -1; /* Since array_elements is 0 for non-arrays, this causes look-ups of 'a[0]' * to (correctly) fail if 'a' is not an array. */ if (array_lookup && shProg->UniformStorage[location].array_elements == 0) { return -1; } return _mesa_uniform_merge_location_offset(location, offset); }