[Mesa-dev] [PATCH] linker: Assign locations for fragment shader output

Ian Romanick idr at freedesktop.org
Tue Jun 28 13:41:34 PDT 2011


From: Ian Romanick <ian.d.romanick at intel.com>

Fixes an assertion failure in the piglib out-01.frag
ARB_explicit_attrib_location test.  The locations set via the layout
qualifier in fragment shader were not being applied to the shader
outputs.  As a result all of these variables still had a location of
-1 set.

This may need some more work for pre-3.0 contexts.  The problem is
dealing with generic outputs that lack a layout qualifier.  There is
no way for the application to specify a location
(glBindFragDataLocation is not supported) or query the location
assigned by the linker (glGetFragDataLocation is not supported).

NOTE: This is a candidate for the 7.10 and 7.11 branches.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=38624
Cc: Eric Anholt <eric at anholt.net>
Cc: Kenneth Graunke <kenneth at whitecape.org>
Cc: Vinson Lee <vlee at vmware.com>
---
 src/glsl/linker.cpp |   98 +++++++++++++++++++++++++++++++++++---------------
 1 files changed, 68 insertions(+), 30 deletions(-)

diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index b6479e7..12299b3 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -1194,16 +1194,43 @@ find_available_slots(unsigned used_mask, unsigned needed_count)
 }
 
 
+/**
+ * Assign locations for either VS inputs for FS outputs
+ *
+ * \param prog          Shader program whose variables need locations assigned
+ * \param target_index  Selector for the program target to receive location
+ *                      assignmnets.  Must be either \c MESA_SHADER_VERTEX or
+ *                      \c MESA_SHADER_FRAGMENT.
+ * \param max_index     Maximum number of generic locations.  This corresponds
+ *                      to either the maximum number of draw buffers or the
+ *                      maximum number of generic attributes.
+ *
+ * \return
+ * If locations are successfully assigned, true is returned.  Otherwise an
+ * error is emitted to the shader link log and false is returned.
+ *
+ * \bug
+ * Locations set via \c glBindFragDataLocation are not currently supported.
+ * Only locations assigned automatically by the linker, explicitly set by a
+ * layout qualifier, or explicitly set by a built-in variable (e.g., \c
+ * gl_FragColor) are supported for fragment shaders.
+ */
 bool
-assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index)
+assign_attribute_or_color_locations(gl_shader_program *prog,
+				    unsigned target_index,
+				    unsigned max_index)
 {
-   /* Mark invalid attribute locations as being used.
+   /* Mark invalid locations as being used.
     */
-   unsigned used_locations = (max_attribute_index >= 32)
-      ? ~0 : ~((1 << max_attribute_index) - 1);
+   unsigned used_locations = (max_index >= 32)
+      ? ~0 : ~((1 << max_index) - 1);
 
-   gl_shader *const sh = prog->_LinkedShaders[0];
-   assert(sh->Type == GL_VERTEX_SHADER);
+   assert((target_index == MESA_SHADER_VERTEX)
+	  || (target_index == MESA_SHADER_FRAGMENT));
+
+   gl_shader *const sh = prog->_LinkedShaders[target_index];
+   if (sh == NULL)
+      return true;
 
    /* Operate in a total of four passes.
     *
@@ -1220,9 +1247,12 @@ assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index
     * 4. Assign locations to any inputs without assigned locations.
     */
 
-   invalidate_variable_locations(sh, ir_var_in, VERT_ATTRIB_GENERIC0);
+   const int generic_base = (target_index == MESA_SHADER_VERTEX)
+     ? VERT_ATTRIB_GENERIC0 : FRAG_RESULT_DATA0;
+
+   invalidate_variable_locations(sh, ir_var_in, generic_base);
 
-   if (prog->Attributes != NULL) {
+   if ((target_index == MESA_SHADER_VERTEX) && (prog->Attributes != NULL)) {
       for (unsigned i = 0; i < prog->Attributes->NumParameters; i++) {
 	 ir_variable *const var =
 	    sh->symbols->get_variable(prog->Attributes->Parameters[i].Name);
@@ -1306,18 +1336,21 @@ assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index
 
    unsigned num_attr = 0;
 
+   const enum ir_variable_mode direction =
+      (target_index == MESA_SHADER_VERTEX) ? ir_var_in : ir_var_out;
+
    foreach_list(node, sh->ir) {
       ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
-      if ((var == NULL) || (var->mode != ir_var_in))
+      if ((var == NULL) || (var->mode != direction))
 	 continue;
 
       if (var->explicit_location) {
 	 const unsigned slots = count_attribute_slots(var->type);
 	 const unsigned use_mask = (1 << slots) - 1;
-	 const int attr = var->location - VERT_ATTRIB_GENERIC0;
+	 const int attr = var->location - generic_base;
 
-	 if ((var->location >= (int)(max_attribute_index + VERT_ATTRIB_GENERIC0))
+	 if ((var->location >= (int)(max_index + generic_base))
 	     || (var->location < 0)) {
 	    linker_error_printf(prog,
 				"invalid explicit location %d specified for "
@@ -1325,7 +1358,7 @@ assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index
 				(var->location < 0) ? var->location : attr,
 				var->name);
 	    return false;
-	 } else if (var->location >= VERT_ATTRIB_GENERIC0) {
+	 } else if (var->location >= generic_base) {
 	    used_locations |= (use_mask << attr);
 	 }
       }
@@ -1349,14 +1382,16 @@ assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index
 
    qsort(to_assign, num_attr, sizeof(to_assign[0]), temp_attr::compare);
 
-   /* VERT_ATTRIB_GENERIC0 is a pseudo-alias for VERT_ATTRIB_POS.  It can only
-    * be explicitly assigned by via glBindAttribLocation.  Mark it as reserved
-    * to prevent it from being automatically allocated below.
-    */
-   find_deref_visitor find("gl_Vertex");
-   find.run(sh->ir);
-   if (find.variable_found())
-      used_locations |= (1 << 0);
+   if (target_index == MESA_SHADER_VERTEX) {
+      /* VERT_ATTRIB_GENERIC0 is a pseudo-alias for VERT_ATTRIB_POS.  It can
+       * only be explicitly assigned by via glBindAttribLocation.  Mark it as
+       * reserved to prevent it from being automatically allocated below.
+       */
+      find_deref_visitor find("gl_Vertex");
+      find.run(sh->ir);
+      if (find.variable_found())
+	 used_locations |= (1 << 0);
+   }
 
    for (unsigned i = 0; i < num_attr; i++) {
       /* Mask representing the contiguous slots that will be used by this
@@ -1671,16 +1706,19 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 
    assign_uniform_locations(prog);
 
-   if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) {
-      /* FINISHME: The value of the max_attribute_index parameter is
-       * FINISHME: implementation dependent based on the value of
-       * FINISHME: GL_MAX_VERTEX_ATTRIBS.  GL_MAX_VERTEX_ATTRIBS must be
-       * FINISHME: at least 16, so hardcode 16 for now.
-       */
-      if (!assign_attribute_locations(prog, 16)) {
-	 prog->LinkStatus = false;
-	 goto done;
-      }
+   /* FINISHME: The value of the max_attribute_index parameter is
+    * FINISHME: implementation dependent based on the value of
+    * FINISHME: GL_MAX_VERTEX_ATTRIBS.  GL_MAX_VERTEX_ATTRIBS must be
+    * FINISHME: at least 16, so hardcode 16 for now.
+    */
+   if (!assign_attribute_or_color_locations(prog, MESA_SHADER_VERTEX, 16)) {
+      prog->LinkStatus = false;
+      goto done;
+   }
+
+   if (!assign_attribute_or_color_locations(prog, MESA_SHADER_FRAGMENT, ctx->Const.MaxDrawBuffers)) {
+      prog->LinkStatus = false;
+      goto done;
    }
 
    unsigned prev;
-- 
1.7.4.4



More information about the mesa-dev mailing list