mesa: Use shared code for converting shader targets to short strings.
[mesa.git] / src / glsl / linker.cpp
index 70f3d5bedf799cec8d0c7c3fa64463d14084b1d0..c168e47e0c81ffc061336929ca9ec4f0031f5ddf 100644 (file)
@@ -66,6 +66,7 @@
 
 #include "main/core.h"
 #include "glsl_symbol_table.h"
+#include "glsl_parser_extras.h"
 #include "ir.h"
 #include "program.h"
 #include "program/hash_table.h"
@@ -107,8 +108,8 @@ public:
         ir_rvalue *param_rval = (ir_rvalue *)iter.get();
         ir_variable *sig_param = (ir_variable *)sig_iter.get();
 
-        if (sig_param->mode == ir_var_out ||
-            sig_param->mode == ir_var_inout) {
+        if (sig_param->mode == ir_var_function_out ||
+            sig_param->mode == ir_var_function_inout) {
            ir_variable *var = param_rval->variable_referenced();
            if (var && strcmp(name, var->name) == 0) {
               found = true;
@@ -200,6 +201,65 @@ linker_warning(gl_shader_program *prog, const char *fmt, ...)
 }
 
 
+/**
+ * Given a string identifying a program resource, break it into a base name
+ * and an optional array index in square brackets.
+ *
+ * If an array index is present, \c out_base_name_end is set to point to the
+ * "[" that precedes the array index, and the array index itself is returned
+ * as a long.
+ *
+ * If no array index is present (or if the array index is negative or
+ * mal-formed), \c out_base_name_end, is set to point to the null terminator
+ * at the end of the input string, and -1 is returned.
+ *
+ * Only the final array index is parsed; if the string contains other array
+ * indices (or structure field accesses), they are left in the base name.
+ *
+ * No attempt is made to check that the base name is properly formed;
+ * typically the caller will look up the base name in a hash table, so
+ * ill-formed base names simply turn into hash table lookup failures.
+ */
+long
+parse_program_resource_name(const GLchar *name,
+                            const GLchar **out_base_name_end)
+{
+   /* Section 7.3.1 ("Program Interfaces") of the OpenGL 4.3 spec says:
+    *
+    *     "When an integer array element or block instance number is part of
+    *     the name string, it will be specified in decimal form without a "+"
+    *     or "-" sign or any extra leading zeroes. Additionally, the name
+    *     string will not include white space anywhere in the string."
+    */
+
+   const size_t len = strlen(name);
+   *out_base_name_end = name + len;
+
+   if (len == 0 || name[len-1] != ']')
+      return -1;
+
+   /* Walk backwards over the string looking for a non-digit character.  This
+    * had better be the opening bracket for an array index.
+    *
+    * Initially, i specifies the location of the ']'.  Since the string may
+    * contain only the ']' charcater, walk backwards very carefully.
+    */
+   unsigned i;
+   for (i = len - 1; (i > 0) && isdigit(name[i-1]); --i)
+      /* empty */ ;
+
+   if ((i == 0) || name[i-1] != '[')
+      return -1;
+
+   long array_index = strtol(&name[i], NULL, 10);
+   if (array_index < 0)
+      return -1;
+
+   *out_base_name_end = name + (i - 1);
+   return array_index;
+}
+
+
 void
 link_invalidate_variable_locations(gl_shader *sh, int input_base,
                                    int output_base)
@@ -212,10 +272,10 @@ link_invalidate_variable_locations(gl_shader *sh, int input_base,
 
       int base;
       switch (var->mode) {
-      case ir_var_in:
+      case ir_var_shader_in:
          base = input_base;
          break;
-      case ir_var_out:
+      case ir_var_shader_out:
          base = output_base;
          break;
       default:
@@ -393,10 +453,9 @@ mode_string(const ir_variable *var)
    case ir_var_auto:
       return (var->read_only) ? "global constant" : "global variable";
 
-   case ir_var_uniform: return "uniform";
-   case ir_var_in:      return "shader input";
-   case ir_var_out:     return "shader output";
-   case ir_var_inout:   return "shader inout";
+   case ir_var_uniform:    return "uniform";
+   case ir_var_shader_in:  return "shader input";
+   case ir_var_shader_out: return "shader output";
 
    case ir_var_const_in:
    case ir_var_temporary:
@@ -874,31 +933,24 @@ link_intrastage_shaders(void *mem_ctx,
                        unsigned num_shaders)
 {
    struct gl_uniform_block *uniform_blocks = NULL;
-   unsigned num_uniform_blocks = 0;
 
    /* Check that global variables defined in multiple shaders are consistent.
     */
    if (!cross_validate_globals(prog, shader_list, num_shaders, false))
       return NULL;
 
-   /* Check that uniform blocks between shaders for a stage agree. */
-   for (unsigned i = 0; i < num_shaders; i++) {
-      struct gl_shader *sh = shader_list[i];
-
-      for (unsigned j = 0; j < shader_list[i]->NumUniformBlocks; j++) {
-        link_assign_uniform_block_offsets(shader_list[i]);
+   /* Check that interface blocks defined in multiple shaders are consistent.
+    */
+   if (!validate_intrastage_interface_blocks((const gl_shader **)shader_list,
+                                             num_shaders))
+      return NULL;
 
-        int index = link_cross_validate_uniform_block(mem_ctx,
-                                                      &uniform_blocks,
-                                                      &num_uniform_blocks,
-                                                      &sh->UniformBlocks[j]);
-        if (index == -1) {
-           linker_error(prog, "uniform block `%s' has mismatching definitions",
-                        sh->UniformBlocks[j].Name);
-           return NULL;
-        }
-      }
-   }
+   /* Check that uniform blocks between shaders for a stage agree. */
+   const int num_uniform_blocks =
+      link_uniform_blocks(mem_ctx, prog, shader_list, num_shaders,
+                          &uniform_blocks);
+   if (num_uniform_blocks < 0)
+      return NULL;
 
    /* Check that there is only a single definition of each function signature
     * across all shaders.
@@ -958,8 +1010,7 @@ link_intrastage_shaders(void *mem_ctx,
 
    if (main == NULL) {
       linker_error(prog, "%s shader lacks `main'\n",
-                  (shader_list[0]->Type == GL_VERTEX_SHADER)
-                  ? "vertex" : "fragment");
+                  _mesa_glsl_shader_target_name(shader_list[0]->Type));
       return NULL;
    }
 
@@ -1022,13 +1073,11 @@ link_intrastage_shaders(void *mem_ctx,
 
    free(linking_shaders);
 
-#ifdef DEBUG
    /* At this point linked should contain all of the linked IR, so
     * validate it to make sure nothing went wrong.
     */
    if (linked)
       validate_ir_tree(linked->ir);
-#endif
 
    /* Make a pass over all variable declarations to ensure that arrays with
     * unspecified sizes have a size specified.  The size is inferred from the
@@ -1069,8 +1118,8 @@ update_array_sizes(struct gl_shader_program *prog)
         ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
         if ((var == NULL) || (var->mode != ir_var_uniform &&
-                              var->mode != ir_var_in &&
-                              var->mode != ir_var_out) ||
+                              var->mode != ir_var_shader_in &&
+                              var->mode != ir_var_shader_out) ||
             !var->type->is_array())
            continue;
 
@@ -1078,7 +1127,7 @@ update_array_sizes(struct gl_shader_program *prog)
          * will not be eliminated.  Since we always do std140, just
          * don't resize arrays in UBOs.
          */
-        if (var->uniform_block != -1)
+        if (var->is_in_uniform_block())
            continue;
 
         unsigned int size = var->max_array_access;
@@ -1206,7 +1255,8 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
       ? (int) VERT_ATTRIB_GENERIC0 : (int) FRAG_RESULT_DATA0;
 
    const enum ir_variable_mode direction =
-      (target_index == MESA_SHADER_VERTEX) ? ir_var_in : ir_var_out;
+      (target_index == MESA_SHADER_VERTEX)
+      ? ir_var_shader_in : ir_var_shader_out;
 
 
    /* Temporary storage for the set of attributes that need locations assigned.
@@ -1428,7 +1478,7 @@ store_fragdepth_layout(struct gl_shader_program *prog)
    foreach_list(node, ir) {
       ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
-      if (var == NULL || var->mode != ir_var_out) {
+      if (var == NULL || var->mode != ir_var_shader_out) {
          continue;
       }
 
@@ -1468,15 +1518,21 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog)
    };
 
    const unsigned max_samplers[MESA_SHADER_TYPES] = {
-      ctx->Const.MaxVertexTextureImageUnits,
-      ctx->Const.MaxTextureImageUnits,
-      ctx->Const.MaxGeometryTextureImageUnits
+      ctx->Const.VertexProgram.MaxTextureImageUnits,
+      ctx->Const.FragmentProgram.MaxTextureImageUnits,
+      ctx->Const.GeometryProgram.MaxTextureImageUnits
    };
 
-   const unsigned max_uniform_components[MESA_SHADER_TYPES] = {
+   const unsigned max_default_uniform_components[MESA_SHADER_TYPES] = {
       ctx->Const.VertexProgram.MaxUniformComponents,
       ctx->Const.FragmentProgram.MaxUniformComponents,
-      0          /* FINISHME: Geometry shaders. */
+      ctx->Const.GeometryProgram.MaxUniformComponents
+   };
+
+   const unsigned max_combined_uniform_components[MESA_SHADER_TYPES] = {
+      ctx->Const.VertexProgram.MaxCombinedUniformComponents,
+      ctx->Const.FragmentProgram.MaxCombinedUniformComponents,
+      ctx->Const.GeometryProgram.MaxCombinedUniformComponents
    };
 
    const unsigned max_uniform_blocks[MESA_SHADER_TYPES] = {
@@ -1496,7 +1552,22 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog)
                      shader_names[i]);
       }
 
-      if (sh->num_uniform_components > max_uniform_components[i]) {
+      if (sh->num_uniform_components > max_default_uniform_components[i]) {
+         if (ctx->Const.GLSLSkipStrictMaxUniformLimitCheck) {
+            linker_warning(prog, "Too many %s shader default uniform block "
+                           "components, but the driver will try to optimize "
+                           "them out; this is non-portable out-of-spec "
+                          "behavior\n",
+                           shader_names[i]);
+         } else {
+            linker_error(prog, "Too many %s shader default uniform block "
+                        "components",
+                         shader_names[i]);
+         }
+      }
+
+      if (sh->num_combined_uniform_components >
+         max_combined_uniform_components[i]) {
          if (ctx->Const.GLSLSkipStrictMaxUniformLimitCheck) {
             linker_warning(prog, "Too many %s shader uniform components, "
                            "but the driver will try to optimize them out; "
@@ -1678,6 +1749,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
         if (prog->_LinkedShaders[i] == NULL)
            continue;
 
+         if (!validate_interstage_interface_blocks(prog->_LinkedShaders[prev],
+                                                   prog->_LinkedShaders[i])) {
+            linker_error(prog, "interface block mismatch between shader stages\n");
+            goto done;
+         }
+
         if (!cross_validate_outputs_to_inputs(prog,
                                               prog->_LinkedShaders[prev],
                                               prog->_LinkedShaders[i]))
@@ -1689,6 +1766,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
       prog->LinkStatus = true;
    }
 
+
+   for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
+      if (prog->_LinkedShaders[i] != NULL)
+         lower_named_interface_blocks(mem_ctx, prog->_LinkedShaders[i]);
+   }
+
    /* Implement the GLSL 1.30+ rule for discard vs infinite loops Do
     * it before optimization because we want most of the checks to get
     * dropped thanks to constant propagation.
@@ -1723,7 +1806,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 
       unsigned max_unroll = ctx->ShaderCompilerOptions[i].MaxUnrollIterations;
 
-      while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, max_unroll))
+      while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, max_unroll, &ctx->ShaderCompilerOptions[i]))
         ;
    }
 
@@ -1731,13 +1814,13 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
    if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) {
       link_invalidate_variable_locations(
             prog->_LinkedShaders[MESA_SHADER_VERTEX],
-            VERT_ATTRIB_GENERIC0, VERT_RESULT_VAR0);
+            VERT_ATTRIB_GENERIC0, VARYING_SLOT_VAR0);
    }
    /* FINISHME: Geometry shaders not implemented yet */
    if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL) {
       link_invalidate_variable_locations(
             prog->_LinkedShaders[MESA_SHADER_FRAGMENT],
-            FRAG_ATTRIB_VAR0, FRAG_RESULT_DATA0);
+            VARYING_SLOT_VAR0, FRAG_RESULT_DATA0);
    }
 
    /* FINISHME: The value of the max_attribute_index parameter is
@@ -1809,7 +1892,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 
    if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) {
       demote_shader_inputs_and_outputs(prog->_LinkedShaders[MESA_SHADER_VERTEX],
-                                      ir_var_out);
+                                      ir_var_shader_out);
 
       /* Eliminate code that is now dead due to unused vertex outputs being
        * demoted.
@@ -1821,9 +1904,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
    if (prog->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) {
       gl_shader *const sh = prog->_LinkedShaders[MESA_SHADER_GEOMETRY];
 
-      demote_shader_inputs_and_outputs(sh, ir_var_in);
-      demote_shader_inputs_and_outputs(sh, ir_var_inout);
-      demote_shader_inputs_and_outputs(sh, ir_var_out);
+      demote_shader_inputs_and_outputs(sh, ir_var_shader_in);
+      demote_shader_inputs_and_outputs(sh, ir_var_shader_out);
 
       /* Eliminate code that is now dead due to unused geometry outputs being
        * demoted.
@@ -1835,7 +1917,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
    if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL) {
       gl_shader *const sh = prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
 
-      demote_shader_inputs_and_outputs(sh, ir_var_in);
+      demote_shader_inputs_and_outputs(sh, ir_var_shader_in);
 
       /* Eliminate code that is now dead due to unused fragment inputs being
        * demoted.  This shouldn't actually do anything other than remove