Example #1
0
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);
}
Example #2
0
/**
 * 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);
}