glsl: allow linking of tessellation shaders.
[mesa.git] / src / glsl / link_varyings.cpp
index ac38a2f31e2651d03bba7db329d10dd269d30474..9174e9c2f2da510bd5695b28175ff77bbebd597b 100644 (file)
@@ -54,10 +54,16 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog,
    /* Check that the types match between stages.
     */
    const glsl_type *type_to_match = input->type;
-   if (consumer_stage == MESA_SHADER_GEOMETRY) {
-      assert(type_to_match->is_array()); /* Enforced by ast_to_hir */
-      type_to_match = type_to_match->element_type();
+
+   /* VS -> GS, VS -> TCS, VS -> TES, TES -> GS */
+   const bool extra_array_level = (producer_stage == MESA_SHADER_VERTEX &&
+                                   consumer_stage != MESA_SHADER_FRAGMENT) ||
+                                  consumer_stage == MESA_SHADER_GEOMETRY;
+   if (extra_array_level) {
+      assert(type_to_match->is_array());
+      type_to_match = type_to_match->fields.array;
    }
+
    if (type_to_match != output->type) {
       /* There is a bit of a special case for gl_TexCoord.  This
        * built-in is unsized by default.  Applications that variable
@@ -77,8 +83,7 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog,
        *     correspondence between the vertex language and the
        *     fragment language."
        */
-      if (!output->type->is_array()
-          || (strncmp("gl_", output->name, 3) != 0)) {
+      if (!output->type->is_array() || !is_gl_identifier(output->name)) {
          linker_error(prog,
                       "%s shader output `%s' declared as type `%s', "
                       "but %s shader input declared as type `%s'\n",
@@ -117,7 +122,19 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog,
       return;
    }
 
-   if (input->data.invariant != output->data.invariant) {
+   if (input->data.patch != output->data.patch) {
+      linker_error(prog,
+                   "%s shader output `%s' %s patch qualifier, "
+                   "but %s shader input %s patch qualifier\n",
+                   _mesa_shader_stage_to_string(producer_stage),
+                   output->name,
+                   (output->data.patch) ? "has" : "lacks",
+                   _mesa_shader_stage_to_string(consumer_stage),
+                   (input->data.patch) ? "has" : "lacks");
+      return;
+   }
+
+   if (!prog->IsES && input->data.invariant != output->data.invariant) {
       linker_error(prog,
                    "%s shader output `%s' %s invariant qualifier, "
                    "but %s shader input %s invariant qualifier\n",
@@ -129,7 +146,17 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog,
       return;
    }
 
-   if (input->data.interpolation != output->data.interpolation) {
+   /* GLSL >= 4.40 removes text requiring interpolation qualifiers
+    * to match cross stage, they must only match within the same stage.
+    *
+    * From page 84 (page 90 of the PDF) of the GLSL 4.40 spec:
+    *
+    *     "It is a link-time error if, within the same stage, the interpolation
+    *     qualifiers of variables of the same name do not match.
+    *
+    */
+   if (input->data.interpolation != output->data.interpolation &&
+       prog->Version < 440) {
       linker_error(prog,
                    "%s shader output `%s' specifies %s "
                    "interpolation qualifier, "
@@ -176,8 +203,8 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
 
    /* Find all shader outputs in the "producer" stage.
     */
-   foreach_list(node, producer->ir) {
-      ir_variable *const var = ((ir_instruction *) node)->as_variable();
+   foreach_in_list(ir_instruction, node, producer->ir) {
+      ir_variable *const var = node->as_variable();
 
       if ((var == NULL) || (var->data.mode != ir_var_shader_out))
         continue;
@@ -213,8 +240,8 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
     * should be arrays and the type of the array element should match the type
     * of the corresponding producer output.
     */
-   foreach_list(node, consumer->ir) {
-      ir_variable *const input = ((ir_instruction *) node)->as_variable();
+   foreach_in_list(ir_instruction, node, consumer->ir) {
+      ir_variable *const input = node->as_variable();
 
       if ((input == NULL) || (input->data.mode != ir_var_shader_in))
         continue;
@@ -264,6 +291,19 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
          if (output != NULL) {
             cross_validate_types_and_qualifiers(prog, input, output,
                                                 consumer->Stage, producer->Stage);
+         } else {
+            /* Check for input vars with unmatched output vars in prev stage
+             * taking into account that interface blocks could have a matching
+             * output but with different name, so we ignore them.
+             */
+            assert(!input->data.assigned);
+            if (input->data.used && !input->get_interface_type() &&
+                !input->data.explicit_location && !prog->SeparateShader)
+               linker_error(prog,
+                            "%s shader input `%s' "
+                            "has no matching output in the previous stage\n",
+                            _mesa_shader_stage_to_string(consumer->Stage),
+                            input->name);
          }
       }
    }
@@ -292,6 +332,7 @@ tfeedback_decl::init(struct gl_context *ctx, const void *mem_ctx,
    this->skip_components = 0;
    this->next_buffer_separator = false;
    this->matched_candidate = NULL;
+   this->stream_id = 0;
 
    if (ctx->Extensions.ARB_transform_feedback3) {
       /* Parse gl_NextBuffer. */
@@ -318,6 +359,11 @@ tfeedback_decl::init(struct gl_context *ctx, const void *mem_ctx,
    const char *base_name_end;
    long subscript = parse_program_resource_name(input, &base_name_end);
    this->var_name = ralloc_strndup(mem_ctx, input, base_name_end - input);
+   if (this->var_name == NULL) {
+      _mesa_error_no_memory(__func__);
+      return;
+   }
+
    if (subscript >= 0) {
       this->array_subscript = subscript;
       this->is_subscripted = true;
@@ -329,7 +375,7 @@ tfeedback_decl::init(struct gl_context *ctx, const void *mem_ctx,
     * class must behave specially to account for the fact that gl_ClipDistance
     * is converted from a float[8] to a vec4[2].
     */
-   if (ctx->ShaderCompilerOptions[MESA_SHADER_VERTEX].LowerClipDistance &&
+   if (ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].LowerClipDistance &&
        strcmp(this->var_name, "gl_ClipDistance") == 0) {
       this->is_clip_distance_mesa = true;
    }
@@ -356,8 +402,8 @@ tfeedback_decl::is_same(const tfeedback_decl &x, const tfeedback_decl &y)
 
 
 /**
- * Assign a location for this tfeedback_decl object based on the transform
- * feedback candidate found by find_candidate.
+ * Assign a location and stream ID for this tfeedback_decl object based on the
+ * transform feedback candidate found by find_candidate.
  *
  * If an error occurs, the error is reported through linker_error() and false
  * is returned.
@@ -438,6 +484,11 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
       return false;
    }
 
+   /* Only transform feedback varyings can be assigned to non-zero streams,
+    * so assign the stream id here.
+    */
+   this->stream_id = this->matched_candidate->toplevel_var->data.stream;
+
    return true;
 }
 
@@ -496,6 +547,7 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
       info->Outputs[info->NumOutputs].ComponentOffset = location_frac;
       info->Outputs[info->NumOutputs].OutputRegister = location;
       info->Outputs[info->NumOutputs].NumComponents = output_size;
+      info->Outputs[info->NumOutputs].StreamId = stream_id;
       info->Outputs[info->NumOutputs].OutputBuffer = buffer;
       info->Outputs[info->NumOutputs].DstOffset = info->BufferStride[buffer];
       ++info->NumOutputs;
@@ -629,10 +681,27 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
    }
    else {
       /* GL_INVERLEAVED_ATTRIBS */
+      int buffer_stream_id = -1;
       for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
          if (tfeedback_decls[i].is_next_buffer_separator()) {
             num_buffers++;
+            buffer_stream_id = -1;
             continue;
+         } else if (buffer_stream_id == -1)  {
+            /* First varying writing to this buffer: remember its stream */
+            buffer_stream_id = (int) tfeedback_decls[i].get_stream_id();
+         } else if (buffer_stream_id !=
+                    (int) tfeedback_decls[i].get_stream_id()) {
+            /* Varying writes to the same buffer from a different stream */
+            linker_error(prog,
+                         "Transform feedback can't capture varyings belonging "
+                         "to different vertex streams in a single buffer. "
+                         "Varying %s writes to buffer from stream %u, other "
+                         "varyings in the same buffer write from stream %u.",
+                         tfeedback_decls[i].name(),
+                         tfeedback_decls[i].get_stream_id(),
+                         buffer_stream_id);
+            return false;
          }
 
          if (!tfeedback_decls[i].store(ctx, prog,
@@ -807,9 +876,11 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var)
        * regardless of where they appear.  We can trivially satisfy that
        * requirement by changing the interpolation type to flat here.
        */
-      producer_var->data.centroid = false;
-      producer_var->data.sample = false;
-      producer_var->data.interpolation = INTERP_QUALIFIER_FLAT;
+      if (producer_var) {
+         producer_var->data.centroid = false;
+         producer_var->data.sample = false;
+         producer_var->data.interpolation = INTERP_QUALIFIER_FLAT;
+      }
 
       if (consumer_var) {
          consumer_var->data.centroid = false;
@@ -936,7 +1007,8 @@ varying_matches::compute_packing_class(const ir_variable *var)
     *
     * Therefore, the packing class depends only on the interpolation type.
     */
-   unsigned packing_class = var->data.centroid | (var->data.sample << 1);
+   unsigned packing_class = var->data.centroid | (var->data.sample << 1) |
+                            (var->data.patch << 2);
    packing_class *= 4;
    packing_class += var->data.interpolation;
    return packing_class;
@@ -992,7 +1064,7 @@ varying_matches::match_comparator(const void *x_generic, const void *y_generic)
  * varyings, but excludes variables such as gl_FrontFacing and gl_FragCoord.
  */
 static bool
-is_varying_var(gl_shader_stage stage, const ir_variable *var)
+var_counts_against_varying_limit(gl_shader_stage stage, const ir_variable *var)
 {
    /* Only fragment shaders will take a varying variable as an input */
    if (stage == MESA_SHADER_FRAGMENT &&
@@ -1045,10 +1117,8 @@ private:
    virtual void visit_field(const glsl_type *type, const char *name,
                             bool row_major)
    {
-      assert(!type->is_record());
-      assert(!(type->is_array() && type->fields.array->is_record()));
-      assert(!type->is_interface());
-      assert(!(type->is_array() && type->fields.array->is_interface()));
+      assert(!type->without_array()->is_record());
+      assert(!type->without_array()->is_interface());
 
       (void) row_major;
 
@@ -1098,8 +1168,8 @@ populate_consumer_input_sets(void *mem_ctx, exec_list *ir,
           0,
           sizeof(consumer_inputs_with_locations[0]) * VARYING_SLOT_MAX);
 
-   foreach_list(node, ir) {
-      ir_variable *const input_var = ((ir_instruction *) node)->as_variable();
+   foreach_in_list(ir_instruction, node, ir) {
+      ir_variable *const input_var = node->as_variable();
 
       if ((input_var != NULL) && (input_var->data.mode == ir_var_shader_in)) {
          if (input_var->type->is_interface())
@@ -1204,8 +1274,8 @@ canonicalize_shader_io(exec_list *ir, enum ir_variable_mode io_mode)
    ir_variable *var_table[MAX_PROGRAM_OUTPUTS * 4];
    unsigned num_variables = 0;
 
-   foreach_list(node, ir) {
-      ir_variable *const var = ((ir_instruction *) node)->as_variable();
+   foreach_in_list(ir_instruction, node, ir) {
+      ir_variable *const var = node->as_variable();
 
       if (var == NULL || var->data.mode != io_mode)
          continue;
@@ -1316,14 +1386,18 @@ assign_varying_locations(struct gl_context *ctx,
    }
 
    if (producer) {
-      foreach_list(node, producer->ir) {
-         ir_variable *const output_var =
-            ((ir_instruction *) node)->as_variable();
+      foreach_in_list(ir_instruction, node, producer->ir) {
+         ir_variable *const output_var = node->as_variable();
 
          if ((output_var == NULL) ||
              (output_var->data.mode != ir_var_shader_out))
             continue;
 
+         /* Only geometry shaders can use non-zero streams */
+         assert(output_var->data.stream == 0 ||
+                (output_var->data.stream < MAX_VERTEX_STREAMS &&
+                 producer->Stage == MESA_SHADER_GEOMETRY));
+
          tfeedback_candidate_generator g(mem_ctx, tfeedback_candidates);
          g.process(output_var);
 
@@ -1339,6 +1413,14 @@ assign_varying_locations(struct gl_context *ctx,
          if (input_var || (prog->SeparateShader && consumer == NULL)) {
             matches.record(output_var, input_var);
          }
+
+         /* Only stream 0 outputs can be consumed in the next stage */
+         if (input_var && output_var->data.stream != 0) {
+            linker_error(prog, "output %s is assigned to stream=%d but "
+                         "is linked to an input, which requires stream=0",
+                         output_var->name, output_var->data.stream);
+            return false;
+         }
       }
    } else {
       /* If there's no producer stage, then this must be a separable program.
@@ -1347,9 +1429,8 @@ assign_varying_locations(struct gl_context *ctx,
        * geometry) shader program.  This means that locations must be assigned
        * for all the inputs.
        */
-      foreach_list(node, consumer->ir) {
-         ir_variable *const input_var =
-            ((ir_instruction *) node)->as_variable();
+      foreach_in_list(ir_instruction, node, consumer->ir) {
+         ir_variable *const input_var = node->as_variable();
 
          if ((input_var == NULL) ||
              (input_var->data.mode != ir_var_shader_in))
@@ -1414,12 +1495,27 @@ assign_varying_locations(struct gl_context *ctx,
    }
 
    if (consumer && producer) {
-      foreach_list(node, consumer->ir) {
-         ir_variable *const var = ((ir_instruction *) node)->as_variable();
+      foreach_in_list(ir_instruction, node, consumer->ir) {
+         ir_variable *const var = node->as_variable();
 
          if (var && var->data.mode == ir_var_shader_in &&
              var->data.is_unmatched_generic_inout) {
-            if (prog->Version <= 120) {
+            if (prog->IsES) {
+               /*
+                * On Page 91 (Page 97 of the PDF) of the GLSL ES 1.0 spec:
+                *
+                *     If the vertex shader declares but doesn't write to a
+                *     varying and the fragment shader declares and reads it,
+                *     is this an error?
+                *
+                *     RESOLUTION: No.
+                */
+               linker_warning(prog, "%s shader varying %s not written "
+                              "by %s shader\n.",
+                              _mesa_shader_stage_to_string(consumer->Stage),
+                              var->name,
+                              _mesa_shader_stage_to_string(producer->Stage));
+            } else if (prog->Version <= 120) {
                /* On page 25 (page 31 of the PDF) of the GLSL 1.20 spec:
                 *
                 *     Only those varying variables used (i.e. read) in
@@ -1432,7 +1528,6 @@ assign_varying_locations(struct gl_context *ctx,
                 * write the variable for the FS to read it.  See
                 * "glsl1-varying read but not written" in piglit.
                 */
-
                linker_error(prog, "%s shader varying %s not written "
                             "by %s shader\n.",
                             _mesa_shader_stage_to_string(consumer->Stage),
@@ -1458,11 +1553,11 @@ check_against_output_limit(struct gl_context *ctx,
 {
    unsigned output_vectors = 0;
 
-   foreach_list(node, producer->ir) {
-      ir_variable *const var = ((ir_instruction *) node)->as_variable();
+   foreach_in_list(ir_instruction, node, producer->ir) {
+      ir_variable *const var = node->as_variable();
 
       if (var && var->data.mode == ir_var_shader_out &&
-          is_varying_var(producer->Stage, var)) {
+          var_counts_against_varying_limit(producer->Stage, var)) {
          output_vectors += var->type->count_attribute_slots();
       }
    }
@@ -1474,13 +1569,15 @@ check_against_output_limit(struct gl_context *ctx,
    const unsigned output_components = output_vectors * 4;
    if (output_components > max_output_components) {
       if (ctx->API == API_OPENGLES2 || prog->IsES)
-         linker_error(prog, "shader uses too many output vectors "
+         linker_error(prog, "%s shader uses too many output vectors "
                       "(%u > %u)\n",
+                      _mesa_shader_stage_to_string(producer->Stage),
                       output_vectors,
                       max_output_components / 4);
       else
-         linker_error(prog, "shader uses too many output components "
+         linker_error(prog, "%s shader uses too many output components "
                       "(%u > %u)\n",
+                      _mesa_shader_stage_to_string(producer->Stage),
                       output_components,
                       max_output_components);
 
@@ -1497,11 +1594,11 @@ check_against_input_limit(struct gl_context *ctx,
 {
    unsigned input_vectors = 0;
 
-   foreach_list(node, consumer->ir) {
-      ir_variable *const var = ((ir_instruction *) node)->as_variable();
+   foreach_in_list(ir_instruction, node, consumer->ir) {
+      ir_variable *const var = node->as_variable();
 
       if (var && var->data.mode == ir_var_shader_in &&
-          is_varying_var(consumer->Stage, var)) {
+          var_counts_against_varying_limit(consumer->Stage, var)) {
          input_vectors += var->type->count_attribute_slots();
       }
    }
@@ -1513,13 +1610,15 @@ check_against_input_limit(struct gl_context *ctx,
    const unsigned input_components = input_vectors * 4;
    if (input_components > max_input_components) {
       if (ctx->API == API_OPENGLES2 || prog->IsES)
-         linker_error(prog, "shader uses too many input vectors "
+         linker_error(prog, "%s shader uses too many input vectors "
                       "(%u > %u)\n",
+                      _mesa_shader_stage_to_string(consumer->Stage),
                       input_vectors,
                       max_input_components / 4);
       else
-         linker_error(prog, "shader uses too many input components "
+         linker_error(prog, "%s shader uses too many input components "
                       "(%u > %u)\n",
+                      _mesa_shader_stage_to_string(consumer->Stage),
                       input_components,
                       max_input_components);