glsl2: Move gl_program->InputsRead/OutputsWritten setting to an ir pass.
authorEric Anholt <eric@anholt.net>
Fri, 6 Aug 2010 20:07:25 +0000 (13:07 -0700)
committerEric Anholt <eric@anholt.net>
Fri, 6 Aug 2010 20:22:31 +0000 (13:22 -0700)
This lets us handle arrays much better than trying to work backwards
from assembly.

Fixes fbo-drawbuffers-maxtargets on swrast (i965 needs loop unrolling)

src/glsl/Makefile
src/glsl/ir.h
src/glsl/ir_set_program_inouts.cpp [new file with mode: 0644]
src/mesa/program/ir_to_mesa.cpp

index 752e60a79f6423f3bbfe6ee33c3d23ed10a9f01f..0f8b290b654d836d8ca7bf7089d980dadc0c5927 100644 (file)
@@ -56,6 +56,7 @@ CXX_SOURCES = \
        ir_mod_to_fract.cpp \
        ir_print_visitor.cpp \
        ir_reader.cpp \
+       ir_set_program_inouts.cpp \
        ir_structure_splitting.cpp \
        ir_swizzle_swizzle.cpp \
        ir_tree_grafting.cpp \
index 5dc3c6b918606651df32c3ab8ea6bc49aca486fb..d852a6a93bfaef51fc3e581bf2368ef5ea2b5968 100644 (file)
@@ -1392,4 +1392,7 @@ import_prototypes(const exec_list *source, exec_list *dest,
 extern bool
 ir_has_call(ir_instruction *ir);
 
+extern void
+do_set_program_inouts(exec_list *instructions, struct gl_program *prog);
+
 #endif /* IR_H */
diff --git a/src/glsl/ir_set_program_inouts.cpp b/src/glsl/ir_set_program_inouts.cpp
new file mode 100644 (file)
index 0000000..6586377
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_set_program_inouts.cpp
+ *
+ * Sets the InputsRead and OutputsWritten of Mesa programs.
+ *
+ * Mesa programs (gl_program, not gl_shader_program) have a set of
+ * flags indicating which varyings are read and written.  Computing
+ * which are actually read from some sort of backend code can be
+ * tricky when variable array indexing involved.  So this pass
+ * provides support for setting InputsRead and OutputsWritten right
+ * from the GLSL IR.
+ */
+
+extern "C" {
+#include "main/mtypes.h"
+#include "program/hash_table.h"
+}
+#include "ir.h"
+#include "ir_visitor.h"
+#include "glsl_types.h"
+
+class ir_set_program_inouts_visitor : public ir_hierarchical_visitor {
+public:
+   ir_set_program_inouts_visitor(struct gl_program *prog)
+   {
+      this->prog = prog;
+      this->ht = hash_table_ctor(0,
+                                hash_table_pointer_hash,
+                                hash_table_pointer_compare);
+   }
+   ir_set_program_inouts_visitor()
+   {
+      hash_table_dtor(this->ht);
+   }
+
+   virtual ir_visitor_status visit_enter(ir_dereference_array *);
+   virtual ir_visitor_status visit_enter(ir_function_signature *);
+   virtual ir_visitor_status visit(ir_dereference_variable *);
+   virtual ir_visitor_status visit(ir_variable *);
+
+   struct gl_program *prog;
+   struct hash_table *ht;
+};
+
+static void
+mark(struct gl_program *prog, ir_variable *var, int index)
+{
+   /* As of GLSL 1.20, varyings can only be floats, floating-point
+    * vectors or matrices, or arrays of them.  For Mesa programs using
+    * InputsRead/OutputsWritten, everything but matrices uses one
+    * slot, while matrices use a slot per column.  Presumably
+    * something doing a more clever packing would use something other
+    * than InputsRead/OutputsWritten.
+    */
+   const glsl_type *element_type;
+   int element_size;
+
+   if (var->type->is_array())
+      element_type = var->type->fields.array;
+   else
+      element_type = var->type;
+
+   if (element_type->is_matrix())
+      element_size = element_type->matrix_columns;
+   else
+      element_size = 1;
+
+   index *= element_size;
+   for (int i = 0; i < element_size; i++) {
+      if (var->mode == ir_var_in)
+        prog->InputsRead |= BITFIELD64_BIT(var->location + index + i);
+      else
+        prog->OutputsWritten |= BITFIELD64_BIT(var->location + index + i);
+   }
+}
+
+/* Default handler: Mark all the locations in the variable as used. */
+ir_visitor_status
+ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
+{
+   if (hash_table_find(this->ht, ir->var) == NULL)
+      return visit_continue;
+
+   if (ir->type->is_array()) {
+      for (unsigned int i = 0; i < ir->type->length; i++) {
+        mark(this->prog, ir->var, i);
+      }
+   } else {
+      mark(this->prog, ir->var, 0);
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
+{
+   ir_dereference_variable *deref_var;
+   ir_constant *index = ir->array_index->as_constant();
+   deref_var = ir->array->as_dereference_variable();
+   ir_variable *var = NULL;
+
+   /* Check that we're dereferencing a shader in or out */
+   if (deref_var)
+      var = (ir_variable *)hash_table_find(this->ht, deref_var->var);
+
+   if (index && var) {
+      mark(this->prog, var, index->value.i[0]);
+      return visit_continue_with_parent;
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_set_program_inouts_visitor::visit(ir_variable *ir)
+{
+   if (ir->mode == ir_var_in ||
+       ir->mode == ir_var_out) {
+      hash_table_insert(this->ht, ir, ir);
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
+{
+   /* We don't want to descend into the function parameters and
+    * consider them as shader inputs or outputs.
+    */
+   visit_list_elements(this, &ir->body);
+   return visit_continue_with_parent;
+}
+
+void
+do_set_program_inouts(exec_list *instructions, struct gl_program *prog)
+{
+   ir_set_program_inouts_visitor v(prog);
+
+   prog->InputsRead = 0;
+   prog->OutputsWritten = 0;
+   visit_list_elements(&v, instructions);
+}
index d8a13220ae2d107c956505ff499a537785efba33..c6856eb5a407b0d8835d147922cf6c398466d6c9 100644 (file)
@@ -2323,81 +2323,15 @@ print_program(struct prog_instruction *mesa_instructions,
    }
 }
 
-static void
-mark_input(struct gl_program *prog,
-          int index,
-          GLboolean reladdr)
-{
-   prog->InputsRead |= BITFIELD64_BIT(index);
-   int i;
-
-   if (reladdr) {
-      if (index >= FRAG_ATTRIB_TEX0 && index <= FRAG_ATTRIB_TEX7) {
-        for (i = 0; i < 8; i++) {
-           prog->InputsRead |= BITFIELD64_BIT(FRAG_ATTRIB_TEX0 + i);
-        }
-      } else {
-        assert(!"FINISHME: Mark InputsRead for varying arrays");
-      }
-   }
-}
-
-static void
-mark_output(struct gl_program *prog,
-          int index,
-          GLboolean reladdr)
-{
-   prog->OutputsWritten |= BITFIELD64_BIT(index);
-   int i;
-
-   if (reladdr) {
-      if (index >= VERT_RESULT_TEX0 && index <= VERT_RESULT_TEX7) {
-        for (i = 0; i < 8; i++) {
-           prog->OutputsWritten |= BITFIELD64_BIT(FRAG_ATTRIB_TEX0 + i);
-        }
-      } else {
-        assert(!"FINISHME: Mark OutputsWritten for varying arrays");
-      }
-   }
-}
-
 static void
 count_resources(struct gl_program *prog)
 {
    unsigned int i;
 
-   prog->InputsRead = 0;
-   prog->OutputsWritten = 0;
    prog->SamplersUsed = 0;
 
    for (i = 0; i < prog->NumInstructions; i++) {
       struct prog_instruction *inst = &prog->Instructions[i];
-      unsigned int reg;
-
-      switch (inst->DstReg.File) {
-      case PROGRAM_OUTPUT:
-        mark_output(prog, inst->DstReg.Index, inst->DstReg.RelAddr);
-        break;
-      case PROGRAM_INPUT:
-        mark_input(prog, inst->DstReg.Index, inst->DstReg.RelAddr);
-        break;
-      default:
-        break;
-      }
-
-      for (reg = 0; reg < _mesa_num_inst_src_regs(inst->Opcode); reg++) {
-        switch (inst->SrcReg[reg].File) {
-        case PROGRAM_OUTPUT:
-           mark_output(prog, inst->SrcReg[reg].Index,
-                       inst->SrcReg[reg].RelAddr);
-           break;
-        case PROGRAM_INPUT:
-           mark_input(prog, inst->SrcReg[reg].Index, inst->SrcReg[reg].RelAddr);
-           break;
-        default:
-           break;
-        }
-      }
 
       /* Instead of just using the uniform's value to map to a
        * sampler, Mesa first allocates a separate number for the
@@ -2578,6 +2512,7 @@ get_mesa_program(GLcontext *ctx, struct gl_shader_program *shader_program,
    }
 
    set_branchtargets(&v, mesa_instructions, num_instructions);
+
    if (ctx->Shader.Flags & GLSL_DUMP) {
       printf("\n");
       printf("GLSL IR for linked %s program %d:\n", target_string,
@@ -2594,6 +2529,9 @@ get_mesa_program(GLcontext *ctx, struct gl_shader_program *shader_program,
    prog->Instructions = mesa_instructions;
    prog->NumInstructions = num_instructions;
 
+   do_set_program_inouts(shader->ir, prog);
+   count_resources(prog);
+
    _mesa_reference_program(ctx, &shader->Program, prog);
 
    if ((ctx->Shader.Flags & GLSL_NO_OPT) == 0) {
@@ -2731,7 +2669,6 @@ _mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog)
 
         linked_prog = get_mesa_program(ctx, prog,
                                        prog->_LinkedShaders[i]);
-        count_resources(linked_prog);
 
         link_uniforms_to_shared_uniform_list(prog->Uniforms, linked_prog);