tgsi/ureg: remove index parameter from ureg_DECL_system_value
[mesa.git] / src / gallium / auxiliary / tgsi / tgsi_ureg.c
index f928f5730997bb9287a75098a4642e6657f5d6f8..964272386b31211080b05b43dfc5f0dc26d98b6a 100644 (file)
@@ -26,6 +26,7 @@
  **************************************************************************/
 
 
+#include "pipe/p_screen.h"
 #include "pipe/p_context.h"
 #include "pipe/p_state.h"
 #include "tgsi/tgsi_ureg.h"
@@ -34,6 +35,7 @@
 #include "tgsi/tgsi_dump.h"
 #include "tgsi/tgsi_sanity.h"
 #include "util/u_debug.h"
+#include "util/u_inlines.h"
 #include "util/u_memory.h"
 #include "util/u_math.h"
 #include "util/u_bitmask.h"
@@ -73,12 +75,12 @@ struct ureg_tokens {
    unsigned count;
 };
 
-#define UREG_MAX_INPUT PIPE_MAX_ATTRIBS
+#define UREG_MAX_INPUT PIPE_MAX_SHADER_INPUTS
 #define UREG_MAX_SYSTEM_VALUE PIPE_MAX_ATTRIBS
 #define UREG_MAX_OUTPUT PIPE_MAX_SHADER_OUTPUTS
 #define UREG_MAX_CONSTANT_RANGE 32
 #define UREG_MAX_IMMEDIATE 4096
-#define UREG_MAX_ADDR 2
+#define UREG_MAX_ADDR 3
 #define UREG_MAX_PRED 1
 #define UREG_MAX_ARRAY_TEMPS 256
 
@@ -96,28 +98,23 @@ struct const_decl {
 struct ureg_program
 {
    unsigned processor;
-   struct pipe_context *pipe;
+   bool supports_any_inout_decl_range;
 
    struct {
       unsigned semantic_name;
       unsigned semantic_index;
       unsigned interp;
       unsigned char cylindrical_wrap;
-      unsigned char centroid;
-   } fs_input[UREG_MAX_INPUT];
-   unsigned nr_fs_inputs;
-
-   unsigned vs_inputs[UREG_MAX_INPUT/32];
+      unsigned interp_location;
+      unsigned first;
+      unsigned last;
+      unsigned array_id;
+   } input[UREG_MAX_INPUT];
+   unsigned nr_inputs, nr_input_regs;
 
-   struct {
-      unsigned index;
-      unsigned semantic_name;
-      unsigned semantic_index;
-   } gs_input[UREG_MAX_INPUT];
-   unsigned nr_gs_inputs;
+   unsigned vs_inputs[PIPE_MAX_ATTRIBS/32];
 
    struct {
-      unsigned index;
       unsigned semantic_name;
       unsigned semantic_index;
    } system_value[UREG_MAX_SYSTEM_VALUE];
@@ -127,8 +124,11 @@ struct ureg_program
       unsigned semantic_name;
       unsigned semantic_index;
       unsigned usage_mask; /* = TGSI_WRITEMASK_* */
+      unsigned first;
+      unsigned last;
+      unsigned array_id;
    } output[UREG_MAX_OUTPUT];
-   unsigned nr_outputs;
+   unsigned nr_outputs, nr_output_regs;
 
    struct {
       union {
@@ -165,13 +165,7 @@ struct ureg_program
    struct const_decl const_decls;
    struct const_decl const_decls2D[PIPE_MAX_CONSTANT_BUFFERS];
 
-   unsigned property_gs_input_prim;
-   unsigned property_gs_output_prim;
-   unsigned property_gs_max_vertices;
-   unsigned char property_fs_coord_origin; /* = TGSI_FS_COORD_ORIGIN_* */
-   unsigned char property_fs_coord_pixel_center; /* = TGSI_FS_COORD_PIXEL_CENTER_* */
-   unsigned char property_fs_color0_writes_all_cbufs; /* = TGSI_FS_COLOR0_WRITES_ALL_CBUFS * */
-   unsigned char property_fs_depth_layout; /* TGSI_FS_DEPTH_LAYOUT */
+   unsigned properties[TGSI_PROPERTY_COUNT];
 
    unsigned nr_addrs;
    unsigned nr_preds;
@@ -247,81 +241,11 @@ static union tgsi_any_token *retrieve_token( struct ureg_program *ureg,
    return &ureg->domain[domain].tokens[nr];
 }
 
-
-
-static INLINE struct ureg_dst
-ureg_dst_register( unsigned file,
-                   unsigned index )
-{
-   struct ureg_dst dst;
-
-   dst.File      = file;
-   dst.WriteMask = TGSI_WRITEMASK_XYZW;
-   dst.Indirect  = 0;
-   dst.IndirectFile = TGSI_FILE_NULL;
-   dst.IndirectIndex = 0;
-   dst.IndirectSwizzle = 0;
-   dst.Saturate  = 0;
-   dst.Predicate = 0;
-   dst.PredNegate = 0;
-   dst.PredSwizzleX = TGSI_SWIZZLE_X;
-   dst.PredSwizzleY = TGSI_SWIZZLE_Y;
-   dst.PredSwizzleZ = TGSI_SWIZZLE_Z;
-   dst.PredSwizzleW = TGSI_SWIZZLE_W;
-   dst.Index     = index;
-   dst.ArrayID = 0;
-
-   return dst;
-}
-
-
-void
-ureg_property_gs_input_prim(struct ureg_program *ureg,
-                            unsigned input_prim)
-{
-   ureg->property_gs_input_prim = input_prim;
-}
-
 void
-ureg_property_gs_output_prim(struct ureg_program *ureg,
-                             unsigned output_prim)
+ureg_property(struct ureg_program *ureg, unsigned name, unsigned value)
 {
-   ureg->property_gs_output_prim = output_prim;
-}
-
-void
-ureg_property_gs_max_vertices(struct ureg_program *ureg,
-                              unsigned max_vertices)
-{
-   ureg->property_gs_max_vertices = max_vertices;
-}
-
-void
-ureg_property_fs_coord_origin(struct ureg_program *ureg,
-                            unsigned fs_coord_origin)
-{
-   ureg->property_fs_coord_origin = fs_coord_origin;
-}
-
-void
-ureg_property_fs_coord_pixel_center(struct ureg_program *ureg,
-                            unsigned fs_coord_pixel_center)
-{
-   ureg->property_fs_coord_pixel_center = fs_coord_pixel_center;
-}
-
-void
-ureg_property_fs_color0_writes_all_cbufs(struct ureg_program *ureg,
-                            unsigned fs_color0_writes_all_cbufs)
-{
-   ureg->property_fs_color0_writes_all_cbufs = fs_color0_writes_all_cbufs;
-}
-
-void
-ureg_property_fs_depth_layout(struct ureg_program *ureg,
-                              unsigned fs_depth_layout)
-{
-   ureg->property_fs_depth_layout = fs_depth_layout;
+   assert(name < Elements(ureg->properties));
+   ureg->properties[name] = value;
 }
 
 struct ureg_src
@@ -330,30 +254,42 @@ ureg_DECL_fs_input_cyl_centroid(struct ureg_program *ureg,
                        unsigned semantic_index,
                        unsigned interp_mode,
                        unsigned cylindrical_wrap,
-                       unsigned centroid)
+                       unsigned interp_location,
+                       unsigned array_id,
+                       unsigned array_size)
 {
    unsigned i;
 
-   for (i = 0; i < ureg->nr_fs_inputs; i++) {
-      if (ureg->fs_input[i].semantic_name == semantic_name &&
-          ureg->fs_input[i].semantic_index == semantic_index) {
+   for (i = 0; i < ureg->nr_inputs; i++) {
+      if (ureg->input[i].semantic_name == semantic_name &&
+          ureg->input[i].semantic_index == semantic_index) {
+         assert(ureg->input[i].interp == interp_mode);
+         assert(ureg->input[i].cylindrical_wrap == cylindrical_wrap);
+         assert(ureg->input[i].interp_location == interp_location);
+         assert(ureg->input[i].array_id == array_id);
          goto out;
       }
    }
 
-   if (ureg->nr_fs_inputs < UREG_MAX_INPUT) {
-      ureg->fs_input[i].semantic_name = semantic_name;
-      ureg->fs_input[i].semantic_index = semantic_index;
-      ureg->fs_input[i].interp = interp_mode;
-      ureg->fs_input[i].cylindrical_wrap = cylindrical_wrap;
-      ureg->fs_input[i].centroid = centroid;
-      ureg->nr_fs_inputs++;
+   if (ureg->nr_inputs < UREG_MAX_INPUT) {
+      assert(array_size >= 1);
+      ureg->input[i].semantic_name = semantic_name;
+      ureg->input[i].semantic_index = semantic_index;
+      ureg->input[i].interp = interp_mode;
+      ureg->input[i].cylindrical_wrap = cylindrical_wrap;
+      ureg->input[i].interp_location = interp_location;
+      ureg->input[i].first = ureg->nr_input_regs;
+      ureg->input[i].last = ureg->nr_input_regs + array_size - 1;
+      ureg->input[i].array_id = array_id;
+      ureg->nr_input_regs += array_size;
+      ureg->nr_inputs++;
    } else {
       set_bad(ureg);
    }
 
 out:
-   return ureg_src_register(TGSI_FILE_INPUT, i);
+   return ureg_src_array_register(TGSI_FILE_INPUT, ureg->input[i].first,
+                                  array_id);
 }
 
 
@@ -362,56 +298,52 @@ ureg_DECL_vs_input( struct ureg_program *ureg,
                     unsigned index )
 {
    assert(ureg->processor == TGSI_PROCESSOR_VERTEX);
-   
+   assert(index / 32 < ARRAY_SIZE(ureg->vs_inputs));
+
    ureg->vs_inputs[index/32] |= 1 << (index % 32);
    return ureg_src_register( TGSI_FILE_INPUT, index );
 }
 
 
 struct ureg_src
-ureg_DECL_gs_input(struct ureg_program *ureg,
-                   unsigned index,
-                   unsigned semantic_name,
-                   unsigned semantic_index)
+ureg_DECL_input(struct ureg_program *ureg,
+                unsigned semantic_name,
+                unsigned semantic_index,
+                unsigned array_id,
+                unsigned array_size)
 {
-   if (ureg->nr_gs_inputs < UREG_MAX_INPUT) {
-      ureg->gs_input[ureg->nr_gs_inputs].index = index;
-      ureg->gs_input[ureg->nr_gs_inputs].semantic_name = semantic_name;
-      ureg->gs_input[ureg->nr_gs_inputs].semantic_index = semantic_index;
-      ureg->nr_gs_inputs++;
-   } else {
-      set_bad(ureg);
-   }
-
-   /* XXX: Add suport for true 2D input registers. */
-   return ureg_src_register(TGSI_FILE_INPUT, index);
+   return ureg_DECL_fs_input_cyl_centroid(ureg, semantic_name, semantic_index,
+                                          0, 0, 0, array_id, array_size);
 }
 
 
 struct ureg_src
 ureg_DECL_system_value(struct ureg_program *ureg,
-                       unsigned index,
                        unsigned semantic_name,
                        unsigned semantic_index)
 {
+   unsigned i = 0;
+
    if (ureg->nr_system_values < UREG_MAX_SYSTEM_VALUE) {
-      ureg->system_value[ureg->nr_system_values].index = index;
       ureg->system_value[ureg->nr_system_values].semantic_name = semantic_name;
       ureg->system_value[ureg->nr_system_values].semantic_index = semantic_index;
+      i = ureg->nr_system_values;
       ureg->nr_system_values++;
    } else {
       set_bad(ureg);
    }
 
-   return ureg_src_register(TGSI_FILE_SYSTEM_VALUE, index);
+   return ureg_src_register(TGSI_FILE_SYSTEM_VALUE, i);
 }
 
 
 struct ureg_dst 
-ureg_DECL_output_masked( struct ureg_program *ureg,
-                         unsigned name,
-                         unsigned index,
-                         unsigned usage_mask )
+ureg_DECL_output_masked(struct ureg_program *ureg,
+                        unsigned name,
+                        unsigned index,
+                        unsigned usage_mask,
+                        unsigned array_id,
+                        unsigned array_size)
 {
    unsigned i;
 
@@ -419,7 +351,8 @@ ureg_DECL_output_masked( struct ureg_program *ureg,
 
    for (i = 0; i < ureg->nr_outputs; i++) {
       if (ureg->output[i].semantic_name == name &&
-          ureg->output[i].semantic_index == index) { 
+          ureg->output[i].semantic_index == index) {
+         assert(ureg->output[i].array_id == array_id);
          ureg->output[i].usage_mask |= usage_mask;
          goto out;
       }
@@ -429,6 +362,10 @@ ureg_DECL_output_masked( struct ureg_program *ureg,
       ureg->output[i].semantic_name = name;
       ureg->output[i].semantic_index = index;
       ureg->output[i].usage_mask = usage_mask;
+      ureg->output[i].first = ureg->nr_output_regs;
+      ureg->output[i].last = ureg->nr_output_regs + array_size - 1;
+      ureg->output[i].array_id = array_id;
+      ureg->nr_output_regs += array_size;
       ureg->nr_outputs++;
    }
    else {
@@ -436,16 +373,30 @@ ureg_DECL_output_masked( struct ureg_program *ureg,
    }
 
 out:
-   return ureg_dst_register( TGSI_FILE_OUTPUT, i );
+   return ureg_dst_array_register(TGSI_FILE_OUTPUT, ureg->output[i].first,
+                                  array_id);
 }
 
 
 struct ureg_dst 
-ureg_DECL_output( struct ureg_program *ureg,
-                  unsigned name,
-                  unsigned index )
+ureg_DECL_output(struct ureg_program *ureg,
+                 unsigned name,
+                 unsigned index)
 {
-   return ureg_DECL_output_masked(ureg, name, index, TGSI_WRITEMASK_XYZW);
+   return ureg_DECL_output_masked(ureg, name, index, TGSI_WRITEMASK_XYZW,
+                                  0, 1);
+}
+
+struct ureg_dst
+ureg_DECL_output_array(struct ureg_program *ureg,
+                       unsigned semantic_name,
+                       unsigned semantic_index,
+                       unsigned array_id,
+                       unsigned array_size)
+{
+   return ureg_DECL_output_masked(ureg, semantic_name, semantic_index,
+                                  TGSI_WRITEMASK_XYZW,
+                                  array_id, array_size);
 }
 
 
@@ -697,8 +648,49 @@ ureg_DECL_sampler_view(struct ureg_program *ureg,
    return reg;
 }
 
+static int
+match_or_expand_immediate64( const unsigned *v,
+                             int type,
+                             unsigned nr,
+                             unsigned *v2,
+                             unsigned *pnr2,
+                             unsigned *swizzle )
+{
+   unsigned nr2 = *pnr2;
+   unsigned i, j;
+   *swizzle = 0;
+
+   for (i = 0; i < nr; i += 2) {
+      boolean found = FALSE;
+
+      for (j = 0; j < nr2 && !found; j += 2) {
+         if (v[i] == v2[j] && v[i + 1] == v2[j + 1]) {
+            *swizzle |= (j << (i * 2)) | ((j + 1) << ((i + 1) * 2));
+            found = TRUE;
+         }
+      }
+      if (!found) {
+         if ((nr2) >= 4) {
+            return FALSE;
+         }
+
+         v2[nr2] = v[i];
+         v2[nr2 + 1] = v[i + 1];
+
+         *swizzle |= (nr2 << (i * 2)) | ((nr2 + 1) << ((i + 1) * 2));
+         nr2 += 2;
+      }
+   }
+
+   /* Actually expand immediate only when fully succeeded.
+    */
+   *pnr2 = nr2;
+   return TRUE;
+}
+
 static int
 match_or_expand_immediate( const unsigned *v,
+                           int type,
                            unsigned nr,
                            unsigned *v2,
                            unsigned *pnr2,
@@ -707,6 +699,9 @@ match_or_expand_immediate( const unsigned *v,
    unsigned nr2 = *pnr2;
    unsigned i, j;
 
+   if (type == TGSI_IMM_FLOAT64)
+      return match_or_expand_immediate64(v, type, nr, v2, pnr2, swizzle);
+
    *swizzle = 0;
 
    for (i = 0; i < nr; i++) {
@@ -755,6 +750,7 @@ decl_immediate( struct ureg_program *ureg,
          continue;
       }
       if (match_or_expand_immediate(v,
+                                    type,
                                     nr,
                                     ureg->immediate[i].value.u,
                                     &ureg->immediate[i].nr,
@@ -767,6 +763,7 @@ decl_immediate( struct ureg_program *ureg,
       i = ureg->nr_immediates++;
       ureg->immediate[i].type = type;
       if (match_or_expand_immediate(v,
+                                    type,
                                     nr,
                                     ureg->immediate[i].value.u,
                                     &ureg->immediate[i].nr,
@@ -781,10 +778,15 @@ out:
    /* Make sure that all referenced elements are from this immediate.
     * Has the effect of making size-one immediates into scalars.
     */
-   for (j = nr; j < 4; j++) {
-      swizzle |= (swizzle & 0x3) << (j * 2);
+   if (type == TGSI_IMM_FLOAT64) {
+      for (j = nr; j < 4; j+=2) {
+         swizzle |= (swizzle & 0xf) << (j * 2);
+      }
+   } else {
+      for (j = nr; j < 4; j++) {
+         swizzle |= (swizzle & 0x3) << (j * 2);
+      }
    }
-
    return ureg_swizzle(ureg_src_register(TGSI_FILE_IMMEDIATE, i),
                        (swizzle >> 0) & 0x3,
                        (swizzle >> 2) & 0x3,
@@ -811,6 +813,24 @@ ureg_DECL_immediate( struct ureg_program *ureg,
    return decl_immediate(ureg, fu.u, nr, TGSI_IMM_FLOAT32);
 }
 
+struct ureg_src
+ureg_DECL_immediate_f64( struct ureg_program *ureg,
+                         const double *v,
+                         unsigned nr )
+{
+   union {
+      unsigned u[4];
+      double d[2];
+   } fu;
+   unsigned int i;
+
+   assert((nr / 2) < 3);
+   for (i = 0; i < nr / 2; i++) {
+      fu.d[i] = v[i];
+   }
+
+   return decl_immediate(ureg, fu.u, nr, TGSI_IMM_FLOAT64);
+}
 
 struct ureg_src
 ureg_DECL_immediate_uint( struct ureg_program *ureg,
@@ -889,7 +909,11 @@ ureg_emit_src( struct ureg_program *ureg,
       out[n].ind.File = src.IndirectFile;
       out[n].ind.Swizzle = src.IndirectSwizzle;
       out[n].ind.Index = src.IndirectIndex;
-      out[n].ind.ArrayID = src.ArrayID;
+      if (!ureg->supports_any_inout_decl_range &&
+          (src.File == TGSI_FILE_INPUT || src.File == TGSI_FILE_OUTPUT))
+         out[n].ind.ArrayID = 0;
+      else
+         out[n].ind.ArrayID = src.ArrayID;
       n++;
    }
 
@@ -905,7 +929,11 @@ ureg_emit_src( struct ureg_program *ureg,
          out[n].ind.File = src.DimIndFile;
          out[n].ind.Swizzle = src.DimIndSwizzle;
          out[n].ind.Index = src.DimIndIndex;
-         out[n].ind.ArrayID = src.ArrayID;
+         if (!ureg->supports_any_inout_decl_range &&
+             (src.File == TGSI_FILE_INPUT || src.File == TGSI_FILE_OUTPUT))
+            out[n].ind.ArrayID = 0;
+         else
+            out[n].ind.ArrayID = src.ArrayID;
       } else {
          out[n].dim.Indirect = 0;
          out[n].dim.Index = src.DimensionIndex;
@@ -921,8 +949,8 @@ void
 ureg_emit_dst( struct ureg_program *ureg,
                struct ureg_dst dst )
 {
-   unsigned size = (1 + 
-                    (dst.Indirect ? 1 : 0));
+   unsigned size = 1 + (dst.Indirect ? 1 : 0) +
+                   (dst.Dimension ? (dst.DimIndirect ? 2 : 1) : 0);
 
    union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size );
    unsigned n = 0;
@@ -947,7 +975,35 @@ ureg_emit_dst( struct ureg_program *ureg,
       out[n].ind.File = dst.IndirectFile;
       out[n].ind.Swizzle = dst.IndirectSwizzle;
       out[n].ind.Index = dst.IndirectIndex;
-      out[n].ind.ArrayID = dst.ArrayID;
+      if (!ureg->supports_any_inout_decl_range &&
+          (dst.File == TGSI_FILE_INPUT || dst.File == TGSI_FILE_OUTPUT))
+         out[n].ind.ArrayID = 0;
+      else
+         out[n].ind.ArrayID = dst.ArrayID;
+      n++;
+   }
+
+   if (dst.Dimension) {
+      out[0].dst.Dimension = 1;
+      out[n].dim.Dimension = 0;
+      out[n].dim.Padding = 0;
+      if (dst.DimIndirect) {
+         out[n].dim.Indirect = 1;
+         out[n].dim.Index = dst.DimensionIndex;
+         n++;
+         out[n].value = 0;
+         out[n].ind.File = dst.DimIndFile;
+         out[n].ind.Swizzle = dst.DimIndSwizzle;
+         out[n].ind.Index = dst.DimIndIndex;
+         if (!ureg->supports_any_inout_decl_range &&
+             (dst.File == TGSI_FILE_INPUT || dst.File == TGSI_FILE_OUTPUT))
+            out[n].ind.ArrayID = 0;
+         else
+            out[n].ind.ArrayID = dst.ArrayID;
+      } else {
+         out[n].dim.Indirect = 0;
+         out[n].dim.Index = dst.DimensionIndex;
+      }
       n++;
    }
 
@@ -962,7 +1018,7 @@ static void validate( unsigned opcode,
 #ifdef DEBUG
    const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode );
    assert(info);
-   if(info) {
+   if (info) {
       assert(nr_dst == info->num_dst);
       assert(nr_src == info->num_src);
    }
@@ -1014,6 +1070,12 @@ ureg_emit_insn(struct ureg_program *ureg,
 }
 
 
+/**
+ * Emit a label token.
+ * \param label_token returns a token number indicating where the label
+ * needs to be patched later.  Later, this value should be passed to the
+ * ureg_fixup_label() function.
+ */
 void
 ureg_emit_label(struct ureg_program *ureg,
                 unsigned extended_token,
@@ -1021,7 +1083,7 @@ ureg_emit_label(struct ureg_program *ureg,
 {
    union tgsi_any_token *out, *insn;
 
-   if(!label_token)
+   if (!label_token)
       return;
 
    out = get_tokens( ureg, DOMAIN_INSN, 1 );
@@ -1241,12 +1303,14 @@ ureg_label_insn(struct ureg_program *ureg,
 static void
 emit_decl_semantic(struct ureg_program *ureg,
                    unsigned file,
-                   unsigned index,
+                   unsigned first,
+                   unsigned last,
                    unsigned semantic_name,
                    unsigned semantic_index,
-                   unsigned usage_mask)
+                   unsigned usage_mask,
+                   unsigned array_id)
 {
-   union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 3);
+   union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, array_id ? 4 : 3);
 
    out[0].value = 0;
    out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION;
@@ -1254,28 +1318,37 @@ emit_decl_semantic(struct ureg_program *ureg,
    out[0].decl.File = file;
    out[0].decl.UsageMask = usage_mask;
    out[0].decl.Semantic = 1;
+   out[0].decl.Array = array_id != 0;
 
    out[1].value = 0;
-   out[1].decl_range.First = index;
-   out[1].decl_range.Last = index;
+   out[1].decl_range.First = first;
+   out[1].decl_range.Last = last;
 
    out[2].value = 0;
    out[2].decl_semantic.Name = semantic_name;
    out[2].decl_semantic.Index = semantic_index;
+
+   if (array_id) {
+      out[3].value = 0;
+      out[3].array.ArrayID = array_id;
+   }
 }
 
 
 static void
 emit_decl_fs(struct ureg_program *ureg,
              unsigned file,
-             unsigned index,
+             unsigned first,
+             unsigned last,
              unsigned semantic_name,
              unsigned semantic_index,
              unsigned interpolate,
              unsigned cylindrical_wrap,
-             unsigned centroid)
+             unsigned interpolate_location,
+             unsigned array_id)
 {
-   union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 4);
+   union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL,
+                                          array_id ? 5 : 4);
 
    out[0].value = 0;
    out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION;
@@ -1284,19 +1357,25 @@ emit_decl_fs(struct ureg_program *ureg,
    out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */
    out[0].decl.Interpolate = 1;
    out[0].decl.Semantic = 1;
+   out[0].decl.Array = array_id != 0;
 
    out[1].value = 0;
-   out[1].decl_range.First = index;
-   out[1].decl_range.Last = index;
+   out[1].decl_range.First = first;
+   out[1].decl_range.Last = last;
 
    out[2].value = 0;
    out[2].decl_interp.Interpolate = interpolate;
    out[2].decl_interp.CylindricalWrap = cylindrical_wrap;
-   out[2].decl_interp.Centroid = centroid;
+   out[2].decl_interp.Location = interpolate_location;
 
    out[3].value = 0;
    out[3].decl_semantic.Name = semantic_name;
    out[3].decl_semantic.Index = semantic_index;
+
+   if (array_id) {
+      out[4].value = 0;
+      out[4].array.ArrayID = array_id;
+   }
 }
 
 static void
@@ -1435,108 +1514,110 @@ emit_property(struct ureg_program *ureg,
 
 static void emit_decls( struct ureg_program *ureg )
 {
-   unsigned i;
-
-   if (ureg->property_gs_input_prim != ~0) {
-      assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY);
-
-      emit_property(ureg,
-                    TGSI_PROPERTY_GS_INPUT_PRIM,
-                    ureg->property_gs_input_prim);
-   }
-
-   if (ureg->property_gs_output_prim != ~0) {
-      assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY);
-
-      emit_property(ureg,
-                    TGSI_PROPERTY_GS_OUTPUT_PRIM,
-                    ureg->property_gs_output_prim);
-   }
-
-   if (ureg->property_gs_max_vertices != ~0) {
-      assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY);
-
-      emit_property(ureg,
-                    TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES,
-                    ureg->property_gs_max_vertices);
-   }
-
-   if (ureg->property_fs_coord_origin) {
-      assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT);
-
-      emit_property(ureg,
-                    TGSI_PROPERTY_FS_COORD_ORIGIN,
-                    ureg->property_fs_coord_origin);
-   }
-
-   if (ureg->property_fs_coord_pixel_center) {
-      assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT);
-
-      emit_property(ureg,
-                    TGSI_PROPERTY_FS_COORD_PIXEL_CENTER,
-                    ureg->property_fs_coord_pixel_center);
-   }
-
-   if (ureg->property_fs_color0_writes_all_cbufs) {
-      assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT);
+   unsigned i,j;
 
-      emit_property(ureg,
-                    TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS,
-                    ureg->property_fs_color0_writes_all_cbufs);
-   }
-
-   if (ureg->property_fs_depth_layout) {
-      assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT);
-
-      emit_property(ureg,
-                    TGSI_PROPERTY_FS_DEPTH_LAYOUT,
-                    ureg->property_fs_depth_layout);
-   }
+   for (i = 0; i < Elements(ureg->properties); i++)
+      if (ureg->properties[i] != ~0)
+         emit_property(ureg, i, ureg->properties[i]);
 
    if (ureg->processor == TGSI_PROCESSOR_VERTEX) {
-      for (i = 0; i < UREG_MAX_INPUT; i++) {
+      for (i = 0; i < PIPE_MAX_ATTRIBS; i++) {
          if (ureg->vs_inputs[i/32] & (1 << (i%32))) {
             emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 );
          }
       }
    } else if (ureg->processor == TGSI_PROCESSOR_FRAGMENT) {
-      for (i = 0; i < ureg->nr_fs_inputs; i++) {
-         emit_decl_fs(ureg,
-                      TGSI_FILE_INPUT,
-                      i,
-                      ureg->fs_input[i].semantic_name,
-                      ureg->fs_input[i].semantic_index,
-                      ureg->fs_input[i].interp,
-                      ureg->fs_input[i].cylindrical_wrap,
-                      ureg->fs_input[i].centroid);
+      if (ureg->supports_any_inout_decl_range) {
+         for (i = 0; i < ureg->nr_inputs; i++) {
+            emit_decl_fs(ureg,
+                         TGSI_FILE_INPUT,
+                         ureg->input[i].first,
+                         ureg->input[i].last,
+                         ureg->input[i].semantic_name,
+                         ureg->input[i].semantic_index,
+                         ureg->input[i].interp,
+                         ureg->input[i].cylindrical_wrap,
+                         ureg->input[i].interp_location,
+                         ureg->input[i].array_id);
+         }
       }
-   } else {
-      for (i = 0; i < ureg->nr_gs_inputs; i++) {
-         emit_decl_semantic(ureg,
+      else {
+         for (i = 0; i < ureg->nr_inputs; i++) {
+            for (j = ureg->input[i].first; j <= ureg->input[i].last; j++) {
+               emit_decl_fs(ureg,
                             TGSI_FILE_INPUT,
-                            ureg->gs_input[i].index,
-                            ureg->gs_input[i].semantic_name,
-                            ureg->gs_input[i].semantic_index,
-                            TGSI_WRITEMASK_XYZW);
+                            j, j,
+                            ureg->input[i].semantic_name,
+                            ureg->input[i].semantic_index +
+                            (j - ureg->input[i].first),
+                            ureg->input[i].interp,
+                            ureg->input[i].cylindrical_wrap,
+                            ureg->input[i].interp_location, 0);
+            }
+         }
+      }
+   } else {
+      if (ureg->supports_any_inout_decl_range) {
+         for (i = 0; i < ureg->nr_inputs; i++) {
+            emit_decl_semantic(ureg,
+                               TGSI_FILE_INPUT,
+                               ureg->input[i].first,
+                               ureg->input[i].last,
+                               ureg->input[i].semantic_name,
+                               ureg->input[i].semantic_index,
+                               TGSI_WRITEMASK_XYZW,
+                               ureg->input[i].array_id);
+         }
+      }
+      else {
+         for (i = 0; i < ureg->nr_inputs; i++) {
+            for (j = ureg->input[i].first; j <= ureg->input[i].last; j++) {
+               emit_decl_semantic(ureg,
+                                  TGSI_FILE_INPUT,
+                                  j, j,
+                                  ureg->input[i].semantic_name,
+                                  ureg->input[i].semantic_index +
+                                  (j - ureg->input[i].first),
+                                  TGSI_WRITEMASK_XYZW, 0);
+            }
+         }
       }
    }
 
    for (i = 0; i < ureg->nr_system_values; i++) {
       emit_decl_semantic(ureg,
                          TGSI_FILE_SYSTEM_VALUE,
-                         ureg->system_value[i].index,
+                         i,
+                         i,
                          ureg->system_value[i].semantic_name,
                          ureg->system_value[i].semantic_index,
-                         TGSI_WRITEMASK_XYZW);
+                         TGSI_WRITEMASK_XYZW, 0);
    }
 
-   for (i = 0; i < ureg->nr_outputs; i++) {
-      emit_decl_semantic(ureg,
-                         TGSI_FILE_OUTPUT,
-                         i,
-                         ureg->output[i].semantic_name,
-                         ureg->output[i].semantic_index,
-                         ureg->output[i].usage_mask);
+   if (ureg->supports_any_inout_decl_range) {
+      for (i = 0; i < ureg->nr_outputs; i++) {
+         emit_decl_semantic(ureg,
+                            TGSI_FILE_OUTPUT,
+                            ureg->output[i].first,
+                            ureg->output[i].last,
+                            ureg->output[i].semantic_name,
+                            ureg->output[i].semantic_index,
+                            ureg->output[i].usage_mask,
+                            ureg->output[i].array_id);
+      }
+   }
+   else {
+      for (i = 0; i < ureg->nr_outputs; i++) {
+         for (j = ureg->output[i].first; j <= ureg->output[i].last; j++) {
+            emit_decl_semantic(ureg,
+                               TGSI_FILE_OUTPUT,
+                               j, j,
+                               ureg->output[i].semantic_name,
+                               ureg->output[i].semantic_index +
+                               (j - ureg->output[i].first),
+                               ureg->output[i].usage_mask, 0);
+         }
+      }
    }
 
    for (i = 0; i < ureg->nr_samplers; i++) {
@@ -1706,10 +1787,20 @@ void *ureg_create_shader( struct ureg_program *ureg,
    else
       memset(&state.stream_output, 0, sizeof(state.stream_output));
 
-   if (ureg->processor == TGSI_PROCESSOR_VERTEX)
-      return pipe->create_vs_state( pipe, &state );
-   else
-      return pipe->create_fs_state( pipe, &state );
+   switch (ureg->processor) {
+   case TGSI_PROCESSOR_VERTEX:
+      return pipe->create_vs_state(pipe, &state);
+   case TGSI_PROCESSOR_TESS_CTRL:
+      return pipe->create_tcs_state(pipe, &state);
+   case TGSI_PROCESSOR_TESS_EVAL:
+      return pipe->create_tes_state(pipe, &state);
+   case TGSI_PROCESSOR_GEOMETRY:
+      return pipe->create_gs_state(pipe, &state);
+   case TGSI_PROCESSOR_FRAGMENT:
+      return pipe->create_fs_state(pipe, &state);
+   default:
+      return NULL;
+   }
 }
 
 
@@ -1740,16 +1831,30 @@ void ureg_free_tokens( const struct tgsi_token *tokens )
 }
 
 
-struct ureg_program *ureg_create( unsigned processor )
+struct ureg_program *
+ureg_create(unsigned processor)
 {
+   return ureg_create_with_screen(processor, NULL);
+}
+
+
+struct ureg_program *
+ureg_create_with_screen(unsigned processor, struct pipe_screen *screen)
+{
+   int i;
    struct ureg_program *ureg = CALLOC_STRUCT( ureg_program );
-   if (ureg == NULL)
+   if (!ureg)
       goto no_ureg;
 
    ureg->processor = processor;
-   ureg->property_gs_input_prim = ~0;
-   ureg->property_gs_output_prim = ~0;
-   ureg->property_gs_max_vertices = ~0;
+   ureg->supports_any_inout_decl_range =
+      screen &&
+      screen->get_shader_param(screen,
+                               util_pipe_shader_from_tgsi_processor(processor),
+                               PIPE_SHADER_CAP_TGSI_ANY_INOUT_DECL_RANGE) != 0;
+
+   for (i = 0; i < Elements(ureg->properties); i++)
+      ureg->properties[i] = ~0;
 
    ureg->free_temps = util_bitmask_create();
    if (ureg->free_temps == NULL)
@@ -1776,7 +1881,7 @@ no_ureg:
 }
 
 
-const unsigned
+unsigned
 ureg_get_nr_outputs( const struct ureg_program *ureg )
 {
    if (!ureg)