mesa: Use shared code for converting shader targets to short strings.
[mesa.git] / src / glsl / linker.cpp
index 63ce178f44c48c53ac7f528c8ef404ed8a0b2954..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"
@@ -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)
@@ -879,6 +939,12 @@ link_intrastage_shaders(void *mem_ctx,
    if (!cross_validate_globals(prog, shader_list, num_shaders, false))
       return NULL;
 
+   /* Check that interface blocks defined in multiple shaders are consistent.
+    */
+   if (!validate_intrastage_interface_blocks((const gl_shader **)shader_list,
+                                             num_shaders))
+      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,
@@ -944,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;
    }
 
@@ -1008,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
@@ -1455,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] = {
@@ -1483,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; "
@@ -1665,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]))
@@ -1676,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.
@@ -1710,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]))
         ;
    }
 
@@ -1718,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