r600g: Add support for RATs in evergreen_cb()
[mesa.git] / src / glsl / linker.cpp
index adedfe6f33ae5be7783a09bd045cba021b94f314..31094475216b3b010a9e64c548816671381e378d 100644 (file)
@@ -101,7 +101,7 @@ public:
 
    virtual ir_visitor_status visit_enter(ir_call *ir)
    {
-      exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+      exec_list_iterator sig_iter = ir->callee->parameters.iterator();
       foreach_iter(exec_list_iterator, iter, *ir) {
         ir_rvalue *param_rval = (ir_rvalue *)iter.get();
         ir_variable *sig_param = (ir_variable *)sig_iter.get();
@@ -117,6 +117,15 @@ public:
         sig_iter.next();
       }
 
+      if (ir->return_deref != NULL) {
+        ir_variable *const var = ir->return_deref->variable_referenced();
+
+        if (strcmp(name, var->name) == 0) {
+           found = true;
+           return visit_stop;
+        }
+      }
+
       return visit_continue_with_parent;
    }
 
@@ -258,11 +267,36 @@ validate_vertex_shader_executable(struct gl_shader_program *prog,
    if (shader == NULL)
       return true;
 
-   find_assignment_visitor find("gl_Position");
-   find.run(shader->ir);
-   if (!find.variable_found()) {
-      linker_error(prog, "vertex shader does not write to `gl_Position'\n");
-      return false;
+   /* From the GLSL 1.10 spec, page 48:
+    *
+    *     "The variable gl_Position is available only in the vertex
+    *      language and is intended for writing the homogeneous vertex
+    *      position. All executions of a well-formed vertex shader
+    *      executable must write a value into this variable. [...] The
+    *      variable gl_Position is available only in the vertex
+    *      language and is intended for writing the homogeneous vertex
+    *      position. All executions of a well-formed vertex shader
+    *      executable must write a value into this variable."
+    *
+    * while in GLSL 1.40 this text is changed to:
+    *
+    *     "The variable gl_Position is available only in the vertex
+    *      language and is intended for writing the homogeneous vertex
+    *      position. It can be written at any time during shader
+    *      execution. It may also be read back by a vertex shader
+    *      after being written. This value will be used by primitive
+    *      assembly, clipping, culling, and other fixed functionality
+    *      operations, if present, that operate on primitives after
+    *      vertex processing has occurred. Its value is undefined if
+    *      the vertex shader executable does not write gl_Position."
+    */
+   if (prog->Version < 140) {
+      find_assignment_visitor find("gl_Position");
+      find.run(shader->ir);
+      if (!find.variable_found()) {
+        linker_error(prog, "vertex shader does not write to `gl_Position'\n");
+        return false;
+      }
    }
 
    prog->Vert.ClipDistanceArraySize = 0;
@@ -805,6 +839,7 @@ move_non_declarations(exec_list *instructions, exec_node *last,
         continue;
 
       assert(inst->as_assignment()
+             || inst->as_call()
             || ((var != NULL) && (var->mode == ir_var_temporary)));
 
       if (make_copies) {
@@ -855,6 +890,27 @@ get_main_function_signature(gl_shader *sh)
 }
 
 
+/**
+ * This class is only used in link_intrastage_shaders() below but declaring
+ * it inside that function leads to compiler warnings with some versions of
+ * gcc.
+ */
+class array_sizing_visitor : public ir_hierarchical_visitor {
+public:
+   virtual ir_visitor_status visit(ir_variable *var)
+   {
+      if (var->type->is_array() && (var->type->length == 0)) {
+         const glsl_type *type =
+            glsl_type::get_array_instance(var->type->fields.array,
+                                          var->max_array_access + 1);
+         assert(type != NULL);
+         var->type = type;
+      }
+      return visit_continue;
+   }
+};
+
+
 /**
  * Combine a group of shaders for a single stage to generate a linked shader
  *
@@ -1005,22 +1061,7 @@ link_intrastage_shaders(void *mem_ctx,
     * max_array_access field.
     */
    if (linked != NULL) {
-      class array_sizing_visitor : public ir_hierarchical_visitor {
-      public:
-        virtual ir_visitor_status visit(ir_variable *var)
-        {
-           if (var->type->is_array() && (var->type->length == 0)) {
-              const glsl_type *type =
-                 glsl_type::get_array_instance(var->type->fields.array,
-                                               var->max_array_access + 1);
-
-              assert(type != NULL);
-              var->type = type;
-           }
-
-           return visit_continue;
-        }
-      } v;
+      array_sizing_visitor v;
 
       v.run(linked->ir);
    }
@@ -1233,10 +1274,15 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
         }
       } else if (target_index == MESA_SHADER_FRAGMENT) {
         unsigned binding;
+        unsigned index;
 
         if (prog->FragDataBindings->get(binding, var->name)) {
            assert(binding >= FRAG_RESULT_DATA0);
            var->location = binding;
+
+           if (prog->FragDataIndexBindings->get(index, var->name)) {
+              var->index = index;
+           }
         }
       }
 
@@ -1247,7 +1293,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
        */
       const unsigned slots = count_attribute_slots(var->type);
       if (var->location != -1) {
-        if (var->location >= generic_base) {
+        if (var->location >= generic_base && var->index < 1) {
            /* From page 61 of the OpenGL 4.0 spec:
             *
             *     "LinkProgram will fail if the attribute bindings assigned
@@ -1288,10 +1334,12 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
             * attribute overlaps any previously allocated bits.
             */
            if ((~(use_mask << attr) & used_locations) != used_locations) {
+              const char *const string = (target_index == MESA_SHADER_VERTEX)
+                 ? "vertex shader input" : "fragment shader output";
               linker_error(prog,
-                           "insufficient contiguous attribute locations "
-                           "available for vertex shader input `%s'",
-                           var->name);
+                           "insufficient contiguous locations "
+                           "available for %s `%s' %d %d %d", string,
+                           var->name, used_locations, use_mask, attr);
               return false;
            }
 
@@ -1339,7 +1387,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
            ? "vertex shader input" : "fragment shader output";
 
         linker_error(prog,
-                     "insufficient contiguous attribute locations "
+                     "insufficient contiguous locations "
                      "available for %s `%s'",
                      string, to_assign[i].var->name);
         return false;
@@ -1388,9 +1436,10 @@ public:
    static bool is_same(const tfeedback_decl &x, const tfeedback_decl &y);
    bool assign_location(struct gl_context *ctx, struct gl_shader_program *prog,
                         ir_variable *output_var);
+   bool accumulate_num_outputs(struct gl_shader_program *prog, unsigned *count);
    bool store(struct gl_context *ctx, struct gl_shader_program *prog,
               struct gl_transform_feedback_info *info, unsigned buffer,
-             unsigned varying) const;
+              unsigned varying, const unsigned max_outputs) const;
 
 
    /**
@@ -1624,16 +1673,9 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
 }
 
 
-/**
- * Update gl_transform_feedback_info to reflect this tfeedback_decl.
- *
- * If an error occurs, the error is reported through linker_error() and false
- * is returned.
- */
 bool
-tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
-                      struct gl_transform_feedback_info *info,
-                      unsigned buffer, unsigned varying) const
+tfeedback_decl::accumulate_num_outputs(struct gl_shader_program *prog,
+                                       unsigned *count)
 {
    if (!this->is_assigned()) {
       /* From GL_EXT_transform_feedback:
@@ -1648,6 +1690,28 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
       return false;
    }
 
+   unsigned translated_size = this->size;
+   if (this->is_clip_distance_mesa)
+      translated_size = (translated_size + 3) / 4;
+
+   *count += translated_size * this->matrix_columns;
+
+   return true;
+}
+
+
+/**
+ * Update gl_transform_feedback_info to reflect this tfeedback_decl.
+ *
+ * If an error occurs, the error is reported through linker_error() and false
+ * is returned.
+ */
+bool
+tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
+                      struct gl_transform_feedback_info *info,
+                      unsigned buffer,
+                      unsigned varying, const unsigned max_outputs) const
+{
    /* From GL_EXT_transform_feedback:
     *   A program will fail to link if:
     *
@@ -1663,19 +1727,6 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
       return false;
    }
 
-   /* Verify that the checks on MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS
-    * and MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS are sufficient to prevent
-    * overflow of info->Outputs[].  In worst case we generate one entry in
-    * Outputs[] per component so a conservative check is to verify that the
-    * size of the array is greater than or equal to both
-    * MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS and
-    * MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS.
-    */
-   assert(Elements(info->Outputs) >=
-          ctx->Const.MaxTransformFeedbackInterleavedComponents);
-   assert(Elements(info->Outputs) >=
-          ctx->Const.MaxTransformFeedbackSeparateComponents);
-
    unsigned translated_size = this->size;
    if (this->is_clip_distance_mesa)
       translated_size = (translated_size + 3) / 4;
@@ -1683,6 +1734,7 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
    for (unsigned index = 0; index < translated_size; ++index) {
       for (unsigned v = 0; v < this->matrix_columns; ++v) {
          unsigned num_components = this->vector_elements;
+         assert(info->NumOutputs < max_outputs);
          info->Outputs[info->NumOutputs].ComponentOffset = 0;
          if (this->is_clip_distance_mesa) {
             if (this->is_subscripted) {
@@ -1806,6 +1858,32 @@ assign_varying_location(ir_variable *input_var, ir_variable *output_var,
 }
 
 
+/**
+ * Is the given variable a varying variable to be counted against the
+ * limit in ctx->Const.MaxVarying?
+ * This includes variables such as texcoords, colors and generic
+ * varyings, but excludes variables such as gl_FrontFacing and gl_FragCoord.
+ */
+static bool
+is_varying_var(GLenum shaderType, const ir_variable *var)
+{
+   /* Only fragment shaders will take a varying variable as an input */
+   if (shaderType == GL_FRAGMENT_SHADER &&
+       var->mode == ir_var_in &&
+       var->explicit_location) {
+      switch (var->location) {
+      case FRAG_ATTRIB_WPOS:
+      case FRAG_ATTRIB_FACE:
+      case FRAG_ATTRIB_PNTC:
+         return false;
+      default:
+         return true;
+      }
+   }
+   return false;
+}
+
+
 /**
  * Assign locations for all variables that are produced in one pipeline stage
  * (the "producer") and consumed in the next stage (the "consumer").
@@ -1914,7 +1992,7 @@ assign_varying_locations(struct gl_context *ctx,
              * value is written by the previous stage.
              */
             var->mode = ir_var_auto;
-         } else {
+         } else if (is_varying_var(consumer->Type, var)) {
             /* The packing rules are used for vertex shader inputs are also
              * used for fragment shader inputs.
              */
@@ -1976,6 +2054,7 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
       prog->TransformFeedback.BufferMode == GL_SEPARATE_ATTRIBS;
 
    ralloc_free(prog->LinkedTransformFeedback.Varyings);
+   ralloc_free(prog->LinkedTransformFeedback.Outputs);
 
    memset(&prog->LinkedTransformFeedback, 0,
           sizeof(prog->LinkedTransformFeedback));
@@ -1988,12 +2067,23 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
                    struct gl_transform_feedback_varying_info,
                    num_tfeedback_decls);
 
+   unsigned num_outputs = 0;
+   for (unsigned i = 0; i < num_tfeedback_decls; ++i)
+      if (!tfeedback_decls[i].accumulate_num_outputs(prog, &num_outputs))
+         return false;
+
+   prog->LinkedTransformFeedback.Outputs =
+      rzalloc_array(prog,
+                    struct gl_transform_feedback_output,
+                    num_outputs);
+
    for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
       unsigned buffer = separate_attribs_mode ? i : 0;
       if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback,
-                                    buffer, i))
+                                    buffer, i, num_outputs))
          return false;
    }
+   assert(prog->LinkedTransformFeedback.NumOutputs == num_outputs);
 
    return true;
 }
@@ -2153,7 +2243,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
     * of all shaders must match.
     */
    assert(min_version >= 100);
-   assert(max_version <= 130);
+   assert(max_version <= 140);
    if ((max_version >= 130 || min_version == 100)
        && min_version != max_version) {
       linker_error(prog, "all shaders must use same shading "
@@ -2232,6 +2322,17 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
       prog->LinkStatus = true;
    }
 
+   /* 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.
+    */
+   if (max_version >= 130) {
+      struct gl_shader *sh = prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
+      if (sh) {
+        lower_discard_flow(sh->ir);
+      }
+   }
+
    /* Do common optimization before assigning storage for attributes,
     * uniforms, and varyings.  Later optimization could possibly make
     * some of that unused.
@@ -2247,7 +2348,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
       if (ctx->ShaderCompilerOptions[i].LowerClipDistance)
          lower_clip_distance(prog->_LinkedShaders[i]->ir);
 
-      while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, 32))
+      unsigned max_unroll = ctx->ShaderCompilerOptions[i].MaxUnrollIterations;
+
+      while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, max_unroll))
         ;
    }
 
@@ -2260,7 +2363,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
       goto done;
    }
 
-   if (!assign_attribute_or_color_locations(prog, MESA_SHADER_FRAGMENT, ctx->Const.MaxDrawBuffers)) {
+   if (!assign_attribute_or_color_locations(prog, MESA_SHADER_FRAGMENT, MAX2(ctx->Const.MaxDrawBuffers, ctx->Const.MaxDualSourceDrawBuffers))) {
       goto done;
    }