mesa: Expose GLSL interpolation qualifiers in gl_fragment_program.
authorPaul Berry <stereotype441@gmail.com>
Wed, 26 Oct 2011 01:06:37 +0000 (18:06 -0700)
committerPaul Berry <stereotype441@gmail.com>
Thu, 27 Oct 2011 22:30:58 +0000 (15:30 -0700)
This patch makes GLSL interpolation qualifiers visible to drivers via
the array InterpQualifier[] in gl_fragment_program, so that they can
easily be used by driver back-ends to select the correct interpolation
mode.

Previous to this patch, the GLSL compiler was using the enum
ir_variable_interpolation to represent interpolation types.  Rather
than make a duplicate enum in core mesa to represent the same thing, I
moved the enum into mtypes.h and renamed it to be more consistent with
the other enums defined there.

Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
src/glsl/ast_to_hir.cpp
src/glsl/ir.cpp
src/glsl/ir.h
src/glsl/ir_reader.cpp
src/glsl/ir_set_program_inouts.cpp
src/mesa/main/mtypes.h
src/mesa/program/ir_to_mesa.cpp
src/mesa/state_tracker/st_glsl_to_tgsi.cpp

index 70afb67dfc195bb2a1411fe964737966b7f2fcbe..d090d311da8827212e2a443b05cd3ac4ba724f56 100644 (file)
@@ -1962,11 +1962,11 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
    }
 
    if (qual->flags.q.flat)
-      var->interpolation = ir_var_flat;
+      var->interpolation = INTERP_QUALIFIER_FLAT;
    else if (qual->flags.q.noperspective)
-      var->interpolation = ir_var_noperspective;
+      var->interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
    else
-      var->interpolation = ir_var_smooth;
+      var->interpolation = INTERP_QUALIFIER_SMOOTH;
 
    var->pixel_center_integer = qual->flags.q.pixel_center_integer;
    var->origin_upper_left = qual->flags.q.origin_upper_left;
@@ -2630,7 +2630,7 @@ ast_declarator_list::hir(exec_list *instructions,
           && state->current_function == NULL
           && var->type->is_integer()
           && var->mode == ir_var_out
-          && var->interpolation != ir_var_flat) {
+          && var->interpolation != INTERP_QUALIFIER_FLAT) {
 
          _mesa_glsl_error(&loc, state, "If a vertex output is an integer, "
                           "then it must be qualified with 'flat'");
index d968890a2c99bbe4f31685e0107a31fe7ea41f8c..046ce25f90c767d5e33297d7e890fb90da9ddee1 100644 (file)
@@ -1320,7 +1320,7 @@ ir_swizzle::variable_referenced() const
 ir_variable::ir_variable(const struct glsl_type *type, const char *name,
                         ir_variable_mode mode)
    : max_array_access(0), read_only(false), centroid(false), invariant(false),
-     mode(mode), interpolation(ir_var_smooth)
+     mode(mode), interpolation(INTERP_QUALIFIER_SMOOTH)
 {
    this->ir_type = ir_type_variable;
    this->type = type;
@@ -1343,9 +1343,9 @@ const char *
 ir_variable::interpolation_string() const
 {
    switch (this->interpolation) {
-   case ir_var_smooth:        return "smooth";
-   case ir_var_flat:          return "flat";
-   case ir_var_noperspective: return "noperspective";
+   case INTERP_QUALIFIER_SMOOTH:        return "smooth";
+   case INTERP_QUALIFIER_FLAT:          return "flat";
+   case INTERP_QUALIFIER_NOPERSPECTIVE: return "noperspective";
    }
 
    assert(!"Should not get here.");
index b707634ea5ab0bb64516fd1802bc88c46e935ab1..4ea8764b68f125acf009653ffbb876e24876e7b9 100644 (file)
@@ -34,6 +34,7 @@
 #include "list.h"
 #include "ir_visitor.h"
 #include "ir_hierarchical_visitor.h"
+#include "main/mtypes.h"
 
 /**
  * \defgroup IR Intermediate representation nodes
@@ -227,12 +228,6 @@ enum ir_variable_mode {
    ir_var_temporary    /**< Temporary variable generated during compilation. */
 };
 
-enum ir_variable_interpolation {
-   ir_var_smooth = 0,
-   ir_var_flat,
-   ir_var_noperspective
-};
-
 /**
  * \brief Layout qualifiers for gl_FragDepth.
  *
@@ -1679,7 +1674,8 @@ extern bool
 ir_has_call(ir_instruction *ir);
 
 extern void
-do_set_program_inouts(exec_list *instructions, struct gl_program *prog);
+do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
+                      bool is_fragment_shader);
 
 extern char *
 prototype_string(const glsl_type *return_type, const char *name,
index afb06b3beff530e90ad45f8b6d74e01462d34edf..e3a3ed97d3a6dde1c9a0a123af2533fb36b4dd70 100644 (file)
@@ -405,11 +405,11 @@ ir_reader::read_declaration(s_expression *expr)
       } else if (strcmp(qualifier->value(), "inout") == 0) {
         var->mode = ir_var_inout;
       } else if (strcmp(qualifier->value(), "smooth") == 0) {
-        var->interpolation = ir_var_smooth;
+        var->interpolation = INTERP_QUALIFIER_SMOOTH;
       } else if (strcmp(qualifier->value(), "flat") == 0) {
-        var->interpolation = ir_var_flat;
+        var->interpolation = INTERP_QUALIFIER_FLAT;
       } else if (strcmp(qualifier->value(), "noperspective") == 0) {
-        var->interpolation = ir_var_noperspective;
+        var->interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
       } else {
         ir_read_error(expr, "unknown qualifier: %s", qualifier->value());
         return NULL;
index ae3ef74c75e0fd25ef4e20cb00b2f66ad3c383a3..8c2bc30d614a96f3192d571717b14b30e746f257 100644 (file)
@@ -26,6 +26,8 @@
  *
  * Sets the InputsRead and OutputsWritten of Mesa programs.
  *
+ * Additionally, for fragment shaders, sets the InterpQualifier array.
+ *
  * 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
 
 class ir_set_program_inouts_visitor : public ir_hierarchical_visitor {
 public:
-   ir_set_program_inouts_visitor(struct gl_program *prog)
+   ir_set_program_inouts_visitor(struct gl_program *prog,
+                                 bool is_fragment_shader)
    {
       this->prog = prog;
+      this->is_fragment_shader = is_fragment_shader;
       this->ht = hash_table_ctor(0,
                                 hash_table_pointer_hash,
                                 hash_table_pointer_compare);
@@ -61,10 +65,12 @@ public:
 
    struct gl_program *prog;
    struct hash_table *ht;
+   bool is_fragment_shader;
 };
 
 static void
-mark(struct gl_program *prog, ir_variable *var, int offset, int len)
+mark(struct gl_program *prog, ir_variable *var, int offset, int len,
+     bool is_fragment_shader)
 {
    /* As of GLSL 1.20, varyings can only be floats, floating-point
     * vectors or matrices, or arrays of them.  For Mesa programs using
@@ -75,12 +81,19 @@ mark(struct gl_program *prog, ir_variable *var, int offset, int len)
     */
 
    for (int i = 0; i < len; i++) {
-      if (var->mode == ir_var_in)
-        prog->InputsRead |= BITFIELD64_BIT(var->location + offset + i);
-      else if (var->mode == ir_var_system_value)
-         prog->SystemValuesRead |= (1 << (var->location + offset + i));
-      else
-        prog->OutputsWritten |= BITFIELD64_BIT(var->location + offset + i);
+      GLbitfield64 bitfield = BITFIELD64_BIT(var->location + offset + i);
+      if (var->mode == ir_var_in) {
+        prog->InputsRead |= bitfield;
+         if (is_fragment_shader) {
+            gl_fragment_program *fprog = (gl_fragment_program *) prog;
+            fprog->InterpQualifier[var->location + offset + i] =
+               (glsl_interp_qualifier) var->interpolation;
+         }
+      } else if (var->mode == ir_var_system_value) {
+         prog->SystemValuesRead |= bitfield;
+      } else {
+        prog->OutputsWritten |= bitfield;
+      }
    }
 }
 
@@ -93,9 +106,11 @@ ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
 
    if (ir->type->is_array()) {
       mark(this->prog, ir->var, 0,
-          ir->type->length * ir->type->fields.array->matrix_columns);
+          ir->type->length * ir->type->fields.array->matrix_columns,
+           this->is_fragment_shader);
    } else {
-      mark(this->prog, ir->var, 0, ir->type->matrix_columns);
+      mark(this->prog, ir->var, 0, ir->type->matrix_columns,
+           this->is_fragment_shader);
    }
 
    return visit_continue;
@@ -121,7 +136,8 @@ ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
         width = deref_var->type->fields.array->matrix_columns;
       }
 
-      mark(this->prog, var, index->value.i[0] * width, width);
+      mark(this->prog, var, index->value.i[0] * width, width,
+           this->is_fragment_shader);
       return visit_continue_with_parent;
    }
 
@@ -151,12 +167,17 @@ ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
 }
 
 void
-do_set_program_inouts(exec_list *instructions, struct gl_program *prog)
+do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
+                      bool is_fragment_shader)
 {
-   ir_set_program_inouts_visitor v(prog);
+   ir_set_program_inouts_visitor v(prog, is_fragment_shader);
 
    prog->InputsRead = 0;
    prog->OutputsWritten = 0;
    prog->SystemValuesRead = 0;
+   if (is_fragment_shader) {
+      memset(((gl_fragment_program *) prog)->InterpQualifier, 0,
+             sizeof(((gl_fragment_program *) prog)->InterpQualifier));
+   }
    visit_list_elements(&v, instructions);
 }
index 4117686414ea201e6e83d0b9f5d18d2e5aa7f2ac..9410e3ff67a39ad2784b04b5287de14fa71f9e04 100644 (file)
@@ -1790,6 +1790,18 @@ typedef enum
 } gl_system_value;
 
 
+/**
+ * The possible interpolation qualifiers that can be applied to a fragment
+ * shader input in GLSL.
+ */
+enum glsl_interp_qualifier
+{
+   INTERP_QUALIFIER_SMOOTH,
+   INTERP_QUALIFIER_FLAT,
+   INTERP_QUALIFIER_NOPERSPECTIVE
+};
+
+
 /** Vertex and fragment instructions */
 struct prog_instruction;
 struct gl_program_parameter_list;
@@ -1890,6 +1902,13 @@ struct gl_fragment_program
    GLboolean OriginUpperLeft;
    GLboolean PixelCenterInteger;
    enum gl_frag_depth_layout FragDepthLayout;
+
+   /**
+    * GLSL interpolation qualifier associated with each fragment shader input.
+    * For inputs that do not have an interpolation qualifier specified in
+    * GLSL, the value is INTERP_QUALIFIER_SMOOTH.
+    */
+   enum glsl_interp_qualifier InterpQualifier[FRAG_ATTRIB_MAX];
 };
 
 
index bdbb6b93838a6f1a2b87ca7f5db11ac7f087e7cf..93563bdaa5b270fae15fe0c934c13a3335fdd21c 100644 (file)
@@ -3191,7 +3191,7 @@ get_mesa_program(struct gl_context *ctx,
    prog->Instructions = mesa_instructions;
    prog->NumInstructions = num_instructions;
 
-   do_set_program_inouts(shader->ir, prog);
+   do_set_program_inouts(shader->ir, prog, shader->Type == GL_FRAGMENT_SHADER);
    count_resources(prog);
 
    check_resources(ctx, shader_program, prog);
index 145bd7dcd0c8b96b7227987a3eb6d9d3433fcef5..67a1b513bda09196f7ba27b234c58988823e07e6 100644 (file)
@@ -4966,7 +4966,7 @@ get_mesa_program(struct gl_context *ctx,
    prog->Instructions = NULL;
    prog->NumInstructions = 0;
 
-   do_set_program_inouts(shader->ir, prog);
+   do_set_program_inouts(shader->ir, prog, shader->Type == GL_FRAGMENT_SHADER);
    count_resources(v, prog);
 
    check_resources(ctx, shader_program, v, prog);