mesa: return INVALID_VALUE from VertexAttribDivisor if index out of range
[mesa.git] / src / mesa / main / uniform_query.cpp
index 991df7896b41fad6567a3c823a094144d30ccc09..c71577c6ed165f688dba16d818b026fb199b2409 100644 (file)
@@ -38,7 +38,7 @@
 
 
 extern "C" void GLAPIENTRY
-_mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
+_mesa_GetActiveUniform(GLhandleARB program, GLuint index,
                           GLsizei maxLength, GLsizei *length, GLint *size,
                           GLenum *type, GLcharARB *nameOut)
 {
@@ -46,6 +46,8 @@ _mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
    struct gl_shader_program *shProg =
       _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
 
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
    if (!shProg)
       return;
 
@@ -72,6 +74,79 @@ _mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
    }
 }
 
+extern "C" void GLAPIENTRY
+_mesa_GetActiveUniformsiv(GLuint program,
+                         GLsizei uniformCount,
+                         const GLuint *uniformIndices,
+                         GLenum pname,
+                         GLint *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_shader_program *shProg;
+   GLsizei i;
+
+   shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
+   if (!shProg)
+      return;
+
+   if (uniformCount < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                 "glGetUniformIndices(uniformCount < 0)");
+      return;
+   }
+
+   for (i = 0; i < uniformCount; i++) {
+      GLuint index = uniformIndices[i];
+      const struct gl_uniform_storage *uni = &shProg->UniformStorage[index];
+
+      if (index >= shProg->NumUserUniformStorage) {
+        _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)");
+        return;
+      }
+
+      switch (pname) {
+      case GL_UNIFORM_TYPE:
+        params[i] = uni->type->gl_type;
+        break;
+
+      case GL_UNIFORM_SIZE:
+        /* array_elements is zero for non-arrays, but the API requires that 1 be
+         * returned.
+         */
+        params[i] = MAX2(1, uni->array_elements);
+        break;
+
+      case GL_UNIFORM_NAME_LENGTH:
+        params[i] = strlen(uni->name) + 1;
+        break;
+
+      case GL_UNIFORM_BLOCK_INDEX:
+        params[i] = uni->block_index;
+        break;
+
+      case GL_UNIFORM_OFFSET:
+        params[i] = uni->offset;
+        break;
+
+      case GL_UNIFORM_ARRAY_STRIDE:
+        params[i] = uni->array_stride;
+        break;
+
+      case GL_UNIFORM_MATRIX_STRIDE:
+        params[i] = uni->matrix_stride;
+        break;
+
+      case GL_UNIFORM_IS_ROW_MAJOR:
+        params[i] = uni->row_major;
+        break;
+
+      default:
+        _mesa_error(ctx, GL_INVALID_ENUM, "glGetActiveUniformsiv(pname)");
+        return;
+      }
+   }
+}
+
 static bool
 validate_uniform_parameters(struct gl_context *ctx,
                            struct gl_shader_program *shProg,
@@ -734,7 +809,8 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
                   sizeof(shProg->SamplerUnits));
 
            _mesa_update_shader_textures_used(shProg, prog);
-           (void) ctx->Driver.ProgramStringNotify(ctx, prog->Target, prog);
+            if (ctx->Driver.SamplerUniformChange)
+              ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog);
         }
       }
    }
@@ -782,6 +858,16 @@ _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
       return;
    }
 
+   /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE.
+    * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml */
+   if (ctx->API == API_OPENGLES || ctx->API == API_OPENGLES2) {
+      if (transpose) {
+        _mesa_error(ctx, GL_INVALID_VALUE,
+                    "glUniformMatrix(matrix transpose is not GL_FALSE)");
+        return;
+      }
+   }
+
    if (ctx->Shader.Flags & GLSL_UNIFORMS) {
       log_uniform(values, GLSL_TYPE_FLOAT, components, vectors, count,
                  bool(transpose), shProg, location, uni);
@@ -840,13 +926,17 @@ _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
 /**
  * Called via glGetUniformLocation().
  *
- * The return value will encode two values, the uniform location and an
- * offset (used for arrays, structs).
+ * Returns the uniform index into UniformStorage (also the
+ * glGetActiveUniformsiv uniform index), and stores the referenced
+ * array offset in *offset, or GL_INVALID_INDEX (-1).  Those two
+ * return values can be encoded into a uniform location for
+ * glUniform* using _mesa_uniform_merge_location_offset(index, offset).
  */
-extern "C" GLint
+extern "C" unsigned
 _mesa_get_uniform_location(struct gl_context *ctx,
                            struct gl_shader_program *shProg,
-                          const GLchar *name)
+                           const GLchar *name,
+                           unsigned *out_offset)
 {
    const size_t len = strlen(name);
    long offset;
@@ -889,13 +979,13 @@ _mesa_get_uniform_location(struct gl_context *ctx,
        * (or other non-digit characters) before the opening '['.
        */
       if ((i == 0) || name[i-1] != '[')
-        return -1;
+        return GL_INVALID_INDEX;
 
       /* Return an error if there are no digits between the opening '[' to
        * match the closing ']'.
        */
       if (i == (len - 1))
-        return -1;
+        return GL_INVALID_INDEX;
 
       /* Make a new string that is a copy of the old string up to (but not
        * including) the '[' character.
@@ -905,8 +995,10 @@ _mesa_get_uniform_location(struct gl_context *ctx,
       name_copy[i-1] = '\0';
 
       offset = strtol(&name[i], NULL, 10);
-      if (offset < 0)
-        return -1;
+      if (offset < 0) {
+        free(name_copy);
+        return GL_INVALID_INDEX;
+      }
 
       array_lookup = true;
    } else {
@@ -927,16 +1019,17 @@ _mesa_get_uniform_location(struct gl_context *ctx,
       free(name_copy);
 
    if (!found)
-      return -1;
+      return GL_INVALID_INDEX;
 
    /* 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 GL_INVALID_INDEX;
    }
 
-   return _mesa_uniform_merge_location_offset(location, offset);
+   *out_offset = offset;
+   return location;
 }
 
 extern "C" bool