[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