[Mesa-dev] [PATCH] mesa: Fix querying location of nth element of an array variable
Anuj Phogat
anuj.phogat at gmail.com
Thu Apr 3 16:13:02 PDT 2014
This patch changes the behavior of glGetAttribLocation(),
glGetFragDataLocation() and glGetFragDataIndex() functions.
Code changes handle the cases described in following example:
vertex shader:
layout(location = 1)in vec4[4] a;
void main()
{
}
fragment shader:
layout (location = 1) out vec4[4] c;
void main()
{
}
Currently glGetAttribLocation("a") and glGetFragDataLocation("c") returns
1. glGetAttribLocation("a[i]") and glGetFragDataLocation("c[i]"), where
i = {0, 1, 2, 3}, returns -1. But expected locations for array indices
are: 1, 2, 3 and 4 respectively.
OpenGL spec doesn't say anything specific about getting the location
of an array element. But it looks sensible to allow such query.
Fixes failures in Khronos OpenGL CTS tests:
explicit_attrib_location_room
draw_instanced_max_vertex_attribs
Proprietary linux drivers of AMD and NVIDIA matches current output on
Mesa (i.e. returns -1).
Cc: <mesa-stable at lists.freedesktop.org>
Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
---
src/mesa/main/shader_query.cpp | 76 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 75 insertions(+), 1 deletion(-)
diff --git a/src/mesa/main/shader_query.cpp b/src/mesa/main/shader_query.cpp
index e1afe53..2256482 100644
--- a/src/mesa/main/shader_query.cpp
+++ b/src/mesa/main/shader_query.cpp
@@ -131,6 +131,59 @@ _mesa_GetActiveAttrib(GLhandleARB program, GLuint desired_index,
_mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
}
+/* This function checks if the 'name' matches with var->name appended with
+ * valid array index for the variable. For example the var->name = "color"
+ * is declared as an array in shader program:
+ * in vec4[4] color;
+ *
+ * Match the queried 'name' with "color[0]", "color[1]", "color[2]" and
+ * "color[3]" to return the matched index of array.
+ */
+int static inline
+get_matching_array_index(const ir_variable *const var,
+ const char *name,
+ const char *gl_func_name) {
+ /* Allowed array length for an input attribute or fragment shader output
+ * is not exceeding 100 anytime soon.
+ */
+ assert(var->type->length >= 0 && var->type->length <= 100);
+ GET_CURRENT_CONTEXT(ctx);
+
+ const char *str1 = var->name;
+ const char *str2 = "[0]";
+ int len1 = strlen(str1);
+ int len2 = strlen(str2);
+ char *result = (char*) malloc(len1 + len2
+ + 1 /* space for extra digit */
+ + 1 /* space for null char */);
+ if (result == NULL) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, gl_func_name);
+ return -1;
+ }
+ memcpy(result, str1, len1);
+ memcpy(result + len1, str2, len2 + 1);
+ int len = strlen(result);
+
+ for (unsigned i = 0; i < var->type->length; i++) {
+ /* Increment the array index */
+ if (i < 10)
+ result[len - 2] = (char)(((int)'0') + i);
+ else {
+ /* We allocated extra spaces to handle double digit indices */
+ result[len - 2] = (char)(((int)'0') + i / 10);
+ result[len - 1] = (char)(((int)'0') + i % 10);
+ result[len] = ']';
+ result[len + 1] = '\0';
+ }
+ if (strcmp(result, name) == 0) {
+ free(result);
+ return i;
+ }
+ }
+ free(result);
+ return -1;
+}
+
GLint GLAPIENTRY
_mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name)
{
@@ -176,6 +229,14 @@ _mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name)
if (strcmp(var->name, name) == 0)
return var->data.location - VERT_ATTRIB_GENERIC0;
+
+ if (var->type->length > 0) {
+ int index = get_matching_array_index(var,
+ (const char *) name,
+ "glGetAttribLocation()");
+ if (index >= 0)
+ return var->data.location + index - VERT_ATTRIB_GENERIC0;
+ }
}
return -1;
@@ -338,8 +399,13 @@ _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
|| var->data.location < FRAG_RESULT_DATA0)
continue;
- if (strcmp(var->name, name) == 0)
+ if (strcmp(var->name, name) == 0
+ || (var->type->length > 0
+ && get_matching_array_index(var,
+ (const char *) name,
+ "glGetFragDataIndex()") >= 0)) {
return var->data.index;
+ }
}
return -1;
@@ -396,6 +462,14 @@ _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
if (strcmp(var->name, name) == 0)
return var->data.location - FRAG_RESULT_DATA0;
+
+ if (var->type->length > 0) {
+ int index = get_matching_array_index(var,
+ (const char *) name,
+ "glGetFragDataLocation()");
+ if (index >= 0)
+ return var->data.location + index - FRAG_RESULT_DATA0;
+ }
}
return -1;
--
1.8.3.1
More information about the mesa-dev
mailing list