summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Romanick <[email protected]>2010-07-01 20:39:08 -0700
committerIan Romanick <[email protected]>2010-07-01 20:39:08 -0700
commit6f0823da09384cc1b557385b9e19a9cc7e901ad7 (patch)
tree7e1d03ad34015d45ab095feb715ebde65c45c3fa
parent3832706f81d7f5310882eda6d7ef0c3e39593b18 (diff)
glsl2: Support AST-to-IR translation of invariant keyword
-rw-r--r--src/glsl/ast_to_hir.cpp84
1 files changed, 70 insertions, 14 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index 3a7fcf16c52..3bd0bd65913 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -1550,29 +1550,73 @@ ast_declarator_list::hir(exec_list *instructions,
ir_rvalue *result = NULL;
YYLTYPE loc = this->get_location();
+ /* From page 46 (page 52 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "To ensure that a particular output variable is invariant, it is
+ * necessary to use the invariant qualifier. It can either be used to
+ * qualify a previously declared variable as being invariant
+ *
+ * invariant gl_Position; // make existing gl_Position be invariant"
+ *
+ * In these cases the parser will set the 'invariant' flag in the declarator
+ * list, and the type will be NULL.
+ */
+ if (this->invariant) {
+ assert(this->type == NULL);
+
+ if (state->current_function != NULL) {
+ _mesa_glsl_error(& loc, state,
+ "All uses of `invariant' keyword must be at global "
+ "scope\n");
+ }
+
+ foreach_list_typed (ast_declaration, decl, link, &this->declarations) {
+ assert(!decl->is_array);
+ assert(decl->array_size == NULL);
+ assert(decl->initializer == NULL);
+
+ ir_variable *const earlier =
+ state->symbols->get_variable(decl->identifier);
+ if (earlier == NULL) {
+ _mesa_glsl_error(& loc, state,
+ "Undeclared variable `%s' cannot be marked "
+ "invariant\n", decl->identifier);
+ } else if ((state->target == vertex_shader)
+ && (earlier->mode != ir_var_out)) {
+ _mesa_glsl_error(& loc, state,
+ "`%s' cannot be marked invariant, vertex shader "
+ "outputs only\n", decl->identifier);
+ } else if ((state->target == fragment_shader)
+ && (earlier->mode != ir_var_in)) {
+ _mesa_glsl_error(& loc, state,
+ "`%s' cannot be marked invariant, fragment shader "
+ "inputs only\n", decl->identifier);
+ } else {
+ earlier->invariant = true;
+ }
+ }
+
+ /* Invariant redeclarations do not have r-values.
+ */
+ return NULL;
+ }
+
+ assert(this->type != NULL);
+ assert(!this->invariant);
+
/* The type specifier may contain a structure definition. Process that
* before any of the variable declarations.
*/
(void) this->type->specifier->hir(instructions, state);
- /* FINISHME: Handle vertex shader "invariant" declarations that do not
- * FINISHME: include a type. These re-declare built-in variables to be
- * FINISHME: invariant.
- */
-
decl_type = this->type->specifier->glsl_type(& type_name, state);
if (this->declarations.is_empty()) {
- /* There are only two valid cases where the declaration list can be
- * empty.
- *
- * 1. The declaration is setting the default precision of a built-in
- * type (e.g., 'precision highp vec4;').
- *
- * 2. Adding 'invariant' to an existing vertex shader output.
+ /* The only valid case where the declaration list can be empty is when
+ * the declaration is setting the default precision of a built-in type
+ * (e.g., 'precision highp vec4;').
*/
- if (this->type->qualifier.invariant) {
- } else if (decl_type != NULL) {
+ if (decl_type != NULL) {
} else {
_mesa_glsl_error(& loc, state, "incomplete declaration");
}
@@ -1636,6 +1680,18 @@ ast_declarator_list::hir(exec_list *instructions,
apply_type_qualifier_to_variable(& this->type->qualifier, var, state,
& loc);
+ if (this->type->qualifier.invariant) {
+ if ((state->target == vertex_shader) && !var->shader_out) {
+ _mesa_glsl_error(& loc, state,
+ "`%s' cannot be marked invariant, vertex shader "
+ "outputs only\n", var->name);
+ } else if ((state->target == fragment_shader) && !var->shader_in) {
+ _mesa_glsl_error(& loc, state,
+ "`%s' cannot be marked invariant, fragment shader "
+ "inputs only\n", var->name);
+ }
+ }
+
if (state->current_function != NULL) {
const char *mode = NULL;
const char *extra = "";