glsl2: Support AST-to-IR translation of invariant keyword
authorIan Romanick <ian.d.romanick@intel.com>
Fri, 2 Jul 2010 03:39:08 +0000 (20:39 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Fri, 2 Jul 2010 03:39:08 +0000 (20:39 -0700)
src/glsl/ast_to_hir.cpp

index 3a7fcf16c52539e5d8913159909d9c090e5e1cfc..3bd0bd65913c8b299d6b0aadbc47bec93a2b3749 100644 (file)
@@ -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 = "";