mesa: implement grammar/parsing for precision/invariant syntax
authorBrian Paul <brian.paul@tungstengraphics.com>
Wed, 16 Jul 2008 20:27:50 +0000 (14:27 -0600)
committerBrian Paul <brian.paul@tungstengraphics.com>
Wed, 16 Jul 2008 22:11:38 +0000 (16:11 -0600)
Plus, fix some issues with pre-defined preprocessor symbols and version checking.

src/mesa/shader/slang/library/slang_shader.syn
src/mesa/shader/slang/library/slang_shader_syn.h
src/mesa/shader/slang/slang_compile.c
src/mesa/shader/slang/slang_preprocess.c

index 1764d1ae6898b370ddab8e640901243549d0b2fc..52a792ad1792afb187f0f5af33f2452b9979ea74 100644 (file)
 /* revision number - increment after each change affecting emitted output */
 .emtcode REVISION                                   3
 
-/* external declaration */
+/* external declaration (or precision or invariant stmt) */
 .emtcode EXTERNAL_NULL                              0
 .emtcode EXTERNAL_FUNCTION_DEFINITION               1
 .emtcode EXTERNAL_DECLARATION                       2
+.emtcode DEFAULT_PRECISION                          3
+.emtcode INVARIANT_STMT                             4
+
+/* precision */
+.emtcode PRECISION_LOW                              0
+.emtcode PRECISION_MEDIUM                           1
+.emtcode PRECISION_HIGH                             2
 
 /* declaration */
 .emtcode DECLARATION_FUNCTION_PROTOTYPE             1
 .errtext LBRACE_EXPECTED                            "2003: '{' expected but '$err_token$' found."
 .errtext LPAREN_EXPECTED                            "2004: '(' expected but '$err_token$' found."
 .errtext RPAREN_EXPECTED                            "2005: ')' expected but '$err_token$' found."
+.errtext INVALID_PRECISION                          "2006: Invalid precision specifier '$err_token$'."
+.errtext INVALID_PRECISION_TYPE                     "2007: Invalid precision type '$err_token$'."
+
 
 /* tells whether the shader that is being parsed is a built-in shader or not */
 /*   0 - normal behaviour */
@@ -1226,23 +1236,70 @@ asm_argument
 var_with_field
     variable_identifier .and dot .and field_selection .emit OP_FIELD;
 
+
 /*
   <translation_unit>                  ::= <external_declaration>
                                         | <translation_unit> <external_declaration>
-*/
*  <translation_unit>                  ::= <external_declaration>
*                                        | <translation_unit> <external_declaration>
+ */
 translation_unit
     optional_space .emit REVISION .and external_declaration .error INVALID_EXTERNAL_DECLARATION .and
     .loop external_declaration .and optional_space .and
     '\0' .error INVALID_EXTERNAL_DECLARATION .emit EXTERNAL_NULL;
 
+
 /*
   <external_declaration>              ::= <function_definition>
                                         | <declaration>
-*/
*  <external_declaration>              ::= <function_definition>
*                                        | <declaration>
+ */
 external_declaration
+    precision_stmt .emit DEFAULT_PRECISION .or
+    invariant_stmt .emit INVARIANT_STMT .or
     function_definition .emit EXTERNAL_FUNCTION_DEFINITION .or
     declaration .emit EXTERNAL_DECLARATION;
 
+
+/*
+ * <precision_stmt>    ::= "precision" <precision> <prectype>
+ */
+precision_stmt
+    "precision" .and space .and precision .error INVALID_PRECISION .and space .and prectype .error INVALID_PRECISION_TYPE .and semicolon;
+
+/*
+ * <precision>           ::= "lowp"
+ *                         | "mediump"
+ *                         | "highp"
+ */
+precision
+    "lowp" .emit PRECISION_LOW .or
+    "mediump" .emit PRECISION_MEDIUM .or
+    "highp" .emit PRECISION_HIGH;
+
+/*
+ * <prectype> ::= "int"
+ *              | "float"
+ *              | "a sampler type"
+ */
+prectype
+    "int" .emit TYPE_SPECIFIER_INT .or
+    "float" .emit TYPE_SPECIFIER_FLOAT .or
+    "sampler1D" .emit TYPE_SPECIFIER_SAMPLER1D .or
+    "sampler2D" .emit TYPE_SPECIFIER_SAMPLER2D .or
+    "sampler3D" .emit TYPE_SPECIFIER_SAMPLER3D .or
+    "samplerCube" .emit TYPE_SPECIFIER_SAMPLERCUBE .or
+    "sampler1DShadow" .emit TYPE_SPECIFIER_SAMPLER1DSHADOW .or
+    "sampler2DShadow" .emit TYPE_SPECIFIER_SAMPLER2DSHADOW .or
+    "sampler2DRect" .emit TYPE_SPECIFIER_SAMPLER2DRECT .or
+    "sampler2DRectShadow" .emit TYPE_SPECIFIER_SAMPLER2DRECTSHADOW;
+
+
+/*
+ * <invariant_stmt>    ::= "invariant" identifier;
+ */
+invariant_stmt
+    "invariant" .and space .and identifier .and semicolon;
+
+
+
 /*
     <function_definition>               :: <function_prototype> <compound_statement_no_new_scope>
 */
index fe37adcac4a4c52f23d3e65ceb9a1dda507e40e6..c0fef6e4e3d6f8f74aea830c6c8daccf51ba66ea 100644 (file)
@@ -6,6 +6,11 @@
 ".emtcode EXTERNAL_NULL 0\n"
 ".emtcode EXTERNAL_FUNCTION_DEFINITION 1\n"
 ".emtcode EXTERNAL_DECLARATION 2\n"
+".emtcode DEFAULT_PRECISION 3\n"
+".emtcode INVARIANT_STMT 4\n"
+".emtcode PRECISION_LOW 0\n"
+".emtcode PRECISION_MEDIUM 1\n"
+".emtcode PRECISION_HIGH 2\n"
 ".emtcode DECLARATION_FUNCTION_PROTOTYPE 1\n"
 ".emtcode DECLARATION_INIT_DECLARATOR_LIST 2\n"
 ".emtcode FUNCTION_ORDINARY 0\n"
@@ -41,6 +46,7 @@
 ".emtcode TYPE_QUALIFIER_UNIFORM 4\n"
 ".emtcode TYPE_QUALIFIER_FIXEDOUTPUT 5\n"
 ".emtcode TYPE_QUALIFIER_FIXEDINPUT 6\n"
+".emtcode TYPE_QUALIFIER_INVARIANT_VARYING 7\n"
 ".emtcode TYPE_SPECIFIER_VOID 0\n"
 ".emtcode TYPE_SPECIFIER_BOOL 1\n"
 ".emtcode TYPE_SPECIFIER_BVEC2 2\n"
 ".errtext LBRACE_EXPECTED \"2003: '{' expected but '$err_token$' found.\"\n"
 ".errtext LPAREN_EXPECTED \"2004: '(' expected but '$err_token$' found.\"\n"
 ".errtext RPAREN_EXPECTED \"2005: ')' expected but '$err_token$' found.\"\n"
+".errtext INVALID_PRECISION \"2006: Invalid precision specifier '$err_token$'.\"\n"
+".errtext INVALID_PRECISION_TYPE \"2007: Invalid precision type '$err_token$'.\"\n"
 ".regbyte parsing_builtin 0\n"
 ".regbyte shader_type 0\n"
 "variable_identifier\n"
 " .loop external_declaration .and optional_space .and\n"
 " '\\0' .error INVALID_EXTERNAL_DECLARATION .emit EXTERNAL_NULL;\n"
 "external_declaration\n"
+" precision_stmt .emit DEFAULT_PRECISION .or\n"
+" invariant_stmt .emit INVARIANT_STMT .or\n"
 " function_definition .emit EXTERNAL_FUNCTION_DEFINITION .or\n"
 " declaration .emit EXTERNAL_DECLARATION;\n"
+"precision_stmt\n"
+" \"precision\" .and space .and precision .error INVALID_PRECISION .and space .and prectype .error INVALID_PRECISION_TYPE .and semicolon;\n"
+"precision\n"
+" \"lowp\" .emit PRECISION_LOW .or\n"
+" \"mediump\" .emit PRECISION_MEDIUM .or\n"
+" \"highp\" .emit PRECISION_HIGH;\n"
+"prectype\n"
+" \"int\" .emit TYPE_SPECIFIER_INT .or\n"
+" \"float\" .emit TYPE_SPECIFIER_FLOAT .or\n"
+" \"sampler1D\" .emit TYPE_SPECIFIER_SAMPLER1D .or\n"
+" \"sampler2D\" .emit TYPE_SPECIFIER_SAMPLER2D .or\n"
+" \"sampler3D\" .emit TYPE_SPECIFIER_SAMPLER3D .or\n"
+" \"samplerCube\" .emit TYPE_SPECIFIER_SAMPLERCUBE .or\n"
+" \"sampler1DShadow\" .emit TYPE_SPECIFIER_SAMPLER1DSHADOW .or\n"
+" \"sampler2DShadow\" .emit TYPE_SPECIFIER_SAMPLER2DSHADOW .or\n"
+" \"sampler2DRect\" .emit TYPE_SPECIFIER_SAMPLER2DRECT .or\n"
+" \"sampler2DRectShadow\" .emit TYPE_SPECIFIER_SAMPLER2DRECTSHADOW;\n"
+"invariant_stmt\n"
+" \"invariant\" .and space .and identifier .and semicolon;\n"
 "function_definition\n"
 " function_prototype .and compound_statement_no_new_scope;\n"
 "digit_oct\n"
index 29c5ca2f4b2dad03c163d53682e36e04cd7288a4..fd5d4afacb67007328720579705cb22a51ed41c1 100644 (file)
@@ -56,6 +56,9 @@
  */
 
 
+/** re-defined below, should be the same though */
+#define TYPE_SPECIFIER_COUNT 32
+
 
 /**
  * Allocate storage for a variable of 'size' bytes from given pool.
@@ -129,6 +132,7 @@ typedef struct slang_parse_ctx_
    GLboolean global_scope;   /**< Is object being declared a global? */
    slang_atom_pool *atoms;
    slang_unit_type type;     /**< Vertex vs. Fragment */
+   GLuint version;           /**< user-specified (or default) #version */
 } slang_parse_ctx;
 
 /* slang_output_ctx */
@@ -141,6 +145,7 @@ typedef struct slang_output_ctx_
    slang_var_pool *global_pool;
    struct gl_program *program;
    slang_var_table *vartable;
+   GLuint default_precision[TYPE_SPECIFIER_COUNT];
 } slang_output_ctx;
 
 /* _slang_compile() */
@@ -525,7 +530,7 @@ parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual)
 #define TYPE_SPECIFIER_MAT42 29
 #define TYPE_SPECIFIER_MAT34 30
 #define TYPE_SPECIFIER_MAT43 31
-
+#define TYPE_SPECIFIER_COUNT 32
 
 static int
 parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O,
@@ -1817,10 +1822,111 @@ parse_declaration(slang_parse_ctx * C, slang_output_ctx * O)
    return 1;
 }
 
-/* external declaration */
+
+#define PRECISION_LOW    0
+#define PRECISION_MEDIUM 1
+#define PRECISION_HIGH   2
+
+static int
+parse_default_precision(slang_parse_ctx * C, slang_output_ctx * O)
+{
+#if FEATURE_es2_glsl
+   int precision, type;
+
+   precision = *C->I++;
+   switch (precision) {
+   case PRECISION_LOW:
+   case PRECISION_MEDIUM:
+   case PRECISION_HIGH:
+      /* OK */
+      break;
+   default:
+      _mesa_problem(NULL, "unexpected precision %d at %s:%d\n",
+                    precision, __FILE__, __LINE__);
+      return 0;
+   }
+
+   type = *C->I++;
+   switch (type) {
+   case TYPE_SPECIFIER_FLOAT:
+   case TYPE_SPECIFIER_INT:
+   case TYPE_SPECIFIER_SAMPLER1D:
+   case TYPE_SPECIFIER_SAMPLER2D:
+   case TYPE_SPECIFIER_SAMPLER3D:
+   case TYPE_SPECIFIER_SAMPLERCUBE:
+   case TYPE_SPECIFIER_SAMPLER1DSHADOW:
+   case TYPE_SPECIFIER_SAMPLER2DSHADOW:
+   case TYPE_SPECIFIER_SAMPLER2DRECT:
+   case TYPE_SPECIFIER_SAMPLER2DRECTSHADOW:
+      /* OK */
+      break;
+   default:
+      _mesa_problem(NULL, "unexpected type %d at %s:%d\n",
+                    type, __FILE__, __LINE__);
+      return 0;
+   }
+
+   assert(type < TYPE_SPECIFIER_COUNT);
+   O->default_precision[type] = precision;
+
+   return 1;
+#else
+   slang_info_log_error(C->L, "syntax error at \"precision\"");
+   return 0;
+#endif
+}
+
+
+/**
+ * Initialize the default precision for all types.
+ * XXX this info isn't used yet.
+ */
+static void
+init_default_precision(slang_output_ctx *O, slang_unit_type type)
+{
+   GLuint i;
+   for (i = 0; i < TYPE_SPECIFIER_COUNT; i++) {
+#if FEATURE_es2_glsl
+      O->default_precision[i] = PRECISION_LOW;
+#else
+      O->default_precision[i] = PRECISION_HIGH;
+#endif
+   }
+#if FEATURE_es2_glsl
+   if (type == SLANG_UNIT_VERTEX_SHADER) {
+      O->default_precision[TYPE_SPECIFIER_FLOAT] = PRECISION_HIGH;
+      O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_HIGH;
+   }
+   else {
+      O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_MEDIUM;
+   }
+#endif
+}
+
+
+static int
+parse_invariant(slang_parse_ctx * C, slang_output_ctx * O)
+{
+   if (C->version >= 120 || FEATURE_es2_glsl) {
+      slang_atom *a = parse_identifier(C);
+      /* XXX not doing anything with this var yet */
+      /*printf("ID: %s\n", (char*) a);*/
+      return a ? 1 : 0;
+   }
+   else {
+      slang_info_log_error(C->L, "syntax error at \"invariant\"");
+      return 0;
+   }
+}
+      
+
+/* external declaration or default precision specifier */
 #define EXTERNAL_NULL 0
 #define EXTERNAL_FUNCTION_DEFINITION 1
 #define EXTERNAL_DECLARATION 2
+#define DEFAULT_PRECISION 3
+#define INVARIANT_STMT 4
+
 
 static GLboolean
 parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit,
@@ -1843,6 +1949,7 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit,
    }
 
    /* setup output context */
+   init_default_precision(&o, unit->type);
    o.funs = &unit->funs;
    o.structs = &unit->structs;
    o.vars = &unit->vars;
@@ -1868,6 +1975,12 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit,
       case EXTERNAL_DECLARATION:
          success = parse_declaration(C, &o);
          break;
+      case DEFAULT_PRECISION:
+         success = parse_default_precision(C, &o);
+         break;
+      case INVARIANT_STMT:
+         success = parse_invariant(C, &o);
+         break;
       default:
          success = GL_FALSE;
       }
@@ -1904,6 +2017,7 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit,
 
 static GLboolean
 compile_binary(const byte * prod, slang_code_unit * unit,
+               GLuint version,
                slang_unit_type type, slang_info_log * infolog,
                slang_code_unit * builtin, slang_code_unit * downlink,
                struct gl_program *program)
@@ -1919,6 +2033,7 @@ compile_binary(const byte * prod, slang_code_unit * unit,
    C.global_scope = GL_TRUE;
    C.atoms = &unit->object->atompool;
    C.type = type;
+   C.version = version;
 
    if (!check_revision(&C))
       return GL_FALSE;
@@ -1946,6 +2061,8 @@ compile_with_grammar(grammar id, const char *source, slang_code_unit * unit,
 
 #if FEATURE_ARB_shading_language_120
    maxVersion = 120;
+#elif FEATURE_es2_glsl
+   maxVersion = 100;
 #else
    maxVersion = 110;
 #endif
@@ -1995,7 +2112,7 @@ compile_with_grammar(grammar id, const char *source, slang_code_unit * unit,
    slang_string_free(&preprocessed);
 
    /* Syntax is okay - translate it to internal representation. */
-   if (!compile_binary(prod, unit, type, infolog, builtin,
+   if (!compile_binary(prod, unit, version, type, infolog, builtin,
                        &builtin[SLANG_BUILTIN_TOTAL - 1],
                        program)) {
       grammar_alloc_free(prod);
@@ -2039,6 +2156,7 @@ compile_object(grammar * id, const char *source, slang_code_object * object,
                struct gl_program *program)
 {
    slang_code_unit *builtins = NULL;
+   GLuint base_version = 110;
 
    /* load GLSL grammar */
    *id = grammar_load_from_text((const byte *) (slang_shader_syn));
@@ -2066,6 +2184,7 @@ compile_object(grammar * id, const char *source, slang_code_object * object,
       /* compile core functionality first */
       if (!compile_binary(slang_core_gc,
                           &object->builtin[SLANG_BUILTIN_CORE],
+                          base_version,
                           SLANG_UNIT_FRAGMENT_BUILTIN, infolog,
                           NULL, NULL, NULL))
          return GL_FALSE;
@@ -2073,6 +2192,7 @@ compile_object(grammar * id, const char *source, slang_code_object * object,
 #if FEATURE_ARB_shading_language_120
       if (!compile_binary(slang_120_core_gc,
                           &object->builtin[SLANG_BUILTIN_120_CORE],
+                          120,
                           SLANG_UNIT_FRAGMENT_BUILTIN, infolog,
                           NULL, &object->builtin[SLANG_BUILTIN_CORE], NULL))
          return GL_FALSE;
@@ -2081,6 +2201,11 @@ compile_object(grammar * id, const char *source, slang_code_object * object,
       /* compile common functions and variables, link to core */
       if (!compile_binary(slang_common_builtin_gc,
                           &object->builtin[SLANG_BUILTIN_COMMON],
+#if FEATURE_ARB_shading_language_120
+                          120,
+#else
+                          base_version,
+#endif
                           SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL,
 #if FEATURE_ARB_shading_language_120
                           &object->builtin[SLANG_BUILTIN_120_CORE],
@@ -2094,12 +2219,14 @@ compile_object(grammar * id, const char *source, slang_code_object * object,
       if (type == SLANG_UNIT_FRAGMENT_SHADER) {
          if (!compile_binary(slang_fragment_builtin_gc,
                              &object->builtin[SLANG_BUILTIN_TARGET],
+                             base_version,
                              SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL,
                              &object->builtin[SLANG_BUILTIN_COMMON], NULL))
             return GL_FALSE;
 #if FEATURE_ARB_shading_language_120
          if (!compile_binary(slang_120_fragment_gc,
                              &object->builtin[SLANG_BUILTIN_TARGET],
+                             120,
                              SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL,
                              &object->builtin[SLANG_BUILTIN_COMMON], NULL))
             return GL_FALSE;
@@ -2108,6 +2235,7 @@ compile_object(grammar * id, const char *source, slang_code_object * object,
       else if (type == SLANG_UNIT_VERTEX_SHADER) {
          if (!compile_binary(slang_vertex_builtin_gc,
                              &object->builtin[SLANG_BUILTIN_TARGET],
+                             base_version,
                              SLANG_UNIT_VERTEX_BUILTIN, infolog, NULL,
                              &object->builtin[SLANG_BUILTIN_COMMON], NULL))
             return GL_FALSE;
index 1645afcc18f9a2ea8c606188a249298589831faf..d3f412c211e977f6ed1e48013173104a1a89382a 100644 (file)
@@ -729,6 +729,14 @@ expand (expand_state *e, pp_symbols *symbols)
             slang_string_pushi (e->output, e->state->version);
             slang_string_pushc (e->output, ' ');
          }
+#if FEATURE_es2_glsl
+         else if (_mesa_strcmp (id, "GL_ES") == 0 ||
+                  _mesa_strcmp (id, "GL_FRAGMENT_PRECISION_HIGH") == 0) {
+            slang_string_pushc (e->output, ' ');
+            slang_string_pushi (e->output, '1');
+            slang_string_pushc (e->output, ' ');
+         }
+#endif
          else {
             pp_symbol *symbol;
 
@@ -829,6 +837,16 @@ static GLboolean
 preprocess_source (slang_string *output, const char *source, grammar pid, grammar eid,
                    slang_info_log *elog)
 {
+   static const char *predefined[] = {
+      "__FILE__",
+      "__LINE__",
+      "__VERSION__",
+#if FEATURE_es2_glsl
+      "GL_ES",
+      "GL_FRAGMENT_PRECISION_HIGH",
+#endif
+      NULL
+   };
    byte *prod;
    GLuint size, i;
    pp_state state;
@@ -840,6 +858,15 @@ preprocess_source (slang_string *output, const char *source, grammar pid, gramma
 
    pp_state_init (&state, elog);
 
+   /* add the predefined symbols to the symbol table */
+   for (i = 0; predefined[i]; i++) {
+      pp_symbol *symbol = NULL;
+      symbol = pp_symbols_push(&state.symbols);
+      assert(symbol);
+      slang_string_pushs(&symbol->name,
+                         predefined[i], _mesa_strlen(predefined[i]));
+   }
+
    i = 0;
    while (i < size) {
       if (prod[i] != ESCAPE_TOKEN) {