diff options
| author | Ian Romanick <ian.d.romanick@intel.com> | 2010-10-07 17:21:22 -0700 | 
|---|---|---|
| committer | Ian Romanick <ian.d.romanick@intel.com> | 2010-10-08 14:21:23 -0700 | 
| commit | 68a4fc9d5a9dd3b61472451d659275531253b67d (patch) | |
| tree | 2458cf332f819c61cbdc589e637cc0f171328892 | |
| parent | eee68d3631813580a14fa51fda6f0c959279256c (diff) | |
glsl: Add linker support for explicit attribute locations
| -rw-r--r-- | src/glsl/ast_to_hir.cpp | 18 | ||||
| -rw-r--r-- | src/glsl/ir_variable.cpp | 1 | ||||
| -rw-r--r-- | src/glsl/linker.cpp | 33 | 
3 files changed, 48 insertions, 4 deletions
| diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index 47fe7a32c3..6e8a1fd1da 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -1668,9 +1668,21 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,  			  string);        } else {  	 var->explicit_location = true; -	 var->location = (state->target == vertex_shader) -	    ? (qual->location + VERT_ATTRIB_GENERIC0) -	    : (qual->location + FRAG_RESULT_DATA0); + +	 /* This bit of silliness is needed because invalid explicit locations +	  * are supposed to be flagged during linking.  Small negative values +	  * biased by VERT_ATTRIB_GENERIC0 or FRAG_RESULT_DATA0 could alias +	  * built-in values (e.g., -16+VERT_ATTRIB_GENERIC0 = VERT_ATTRIB_POS). +	  * The linker needs to be able to differentiate these cases.  This +	  * ensures that negative values stay negative. +	  */ +	 if (qual->location >= 0) { +	    var->location = (state->target == vertex_shader) +	       ? (qual->location + VERT_ATTRIB_GENERIC0) +	       : (qual->location + FRAG_RESULT_DATA0); +	 } else { +	    var->location = qual->location; +	 }        }     } diff --git a/src/glsl/ir_variable.cpp b/src/glsl/ir_variable.cpp index 1eff740ef9..ddc3bb0b9f 100644 --- a/src/glsl/ir_variable.cpp +++ b/src/glsl/ir_variable.cpp @@ -52,6 +52,7 @@ add_variable(const char *name, enum ir_variable_mode mode, int slot,     }     var->location = slot; +   var->explicit_location = (slot >= 0);     /* Once the variable is created an initialized, add it to the symbol table      * and add the declaration to the IR stream. diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index bddf8788b4..c612fe5466 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -191,7 +191,7 @@ invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode,        /* Only assign locations for generic attributes / varyings / etc.         */ -      if (var->location >= generic_base) +      if ((var->location >= generic_base) && !var->explicit_location)  	  var->location = -1;     }  } @@ -365,6 +365,19 @@ cross_validate_globals(struct gl_shader_program *prog,  	       }  	    } +	    if (var->explicit_location) { +	       if (existing->explicit_location +		   && (var->location != existing->location)) { +		     linker_error_printf(prog, "explicit locations for %s " +					 "`%s' have differing values\n", +					 mode_string(var), var->name); +		     return false; +	       } + +	       existing->location = var->location; +	       existing->explicit_location = true; +	    } +  	    /* FINISHME: Handle non-constant initializers.  	     */  	    if (var->constant_value != NULL) { @@ -1186,6 +1199,24 @@ assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index        if ((var == NULL) || (var->mode != ir_var_in))  	 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; + +	 if ((var->location >= (int)(max_attribute_index + VERT_ATTRIB_GENERIC0)) +	     || (var->location < 0)) { +	    linker_error_printf(prog, +				"invalid explicit location %d specified for " +				"`%s'\n", +				(var->location < 0) ? var->location : attr, +				var->name); +	    return false; +	 } else if (var->location >= VERT_ATTRIB_GENERIC0) { +	    used_locations |= (use_mask << attr); +	 } +      } +        /* The location was explicitly assigned, nothing to do here.         */        if (var->location != -1) | 
