nir: Use a single list for all shader variables
[mesa.git] / src / gallium / drivers / zink / nir_to_spirv / nir_to_spirv.c
index 8df35a3173896939c1e7608c9d3e54164d401a5c..68a5d00a3506c3233e773cdea859e9f1586b432e 100644 (file)
 #include "util/u_memory.h"
 #include "util/hash_table.h"
 
+/* this consistently maps slots to a zero-indexed value to avoid wasting slots */
+static unsigned slot_pack_map[] = {
+   /* Position is builtin */
+   [VARYING_SLOT_POS] = UINT_MAX,
+   [VARYING_SLOT_COL0] = 0, /* input/output */
+   [VARYING_SLOT_COL1] = 1, /* input/output */
+   [VARYING_SLOT_FOGC] = 2, /* input/output */
+   /* TEX0-7 are deprecated, so we put them at the end of the range and hope nobody uses them all */
+   [VARYING_SLOT_TEX0] = VARYING_SLOT_VAR0 - 1, /* input/output */
+   [VARYING_SLOT_TEX1] = VARYING_SLOT_VAR0 - 2,
+   [VARYING_SLOT_TEX2] = VARYING_SLOT_VAR0 - 3,
+   [VARYING_SLOT_TEX3] = VARYING_SLOT_VAR0 - 4,
+   [VARYING_SLOT_TEX4] = VARYING_SLOT_VAR0 - 5,
+   [VARYING_SLOT_TEX5] = VARYING_SLOT_VAR0 - 6,
+   [VARYING_SLOT_TEX6] = VARYING_SLOT_VAR0 - 7,
+   [VARYING_SLOT_TEX7] = VARYING_SLOT_VAR0 - 8,
+
+   /* PointSize is builtin */
+   [VARYING_SLOT_PSIZ] = UINT_MAX,
+
+   [VARYING_SLOT_BFC0] = 3, /* output only */
+   [VARYING_SLOT_BFC1] = 4, /* output only */
+   [VARYING_SLOT_EDGE] = 5, /* output only */
+   [VARYING_SLOT_CLIP_VERTEX] = 6, /* output only */
+
+   /* ClipDistance is builtin */
+   [VARYING_SLOT_CLIP_DIST0] = UINT_MAX,
+   [VARYING_SLOT_CLIP_DIST1] = UINT_MAX,
+
+   /* CullDistance is builtin */
+   [VARYING_SLOT_CULL_DIST0] = UINT_MAX, /* input/output */
+   [VARYING_SLOT_CULL_DIST1] = UINT_MAX, /* never actually used */
+
+   /* PrimitiveId is builtin */
+   [VARYING_SLOT_PRIMITIVE_ID] = UINT_MAX,
+
+   /* Layer is builtin */
+   [VARYING_SLOT_LAYER] = UINT_MAX, /* input/output */
+
+   /* ViewportIndex is builtin */
+   [VARYING_SLOT_VIEWPORT] =  UINT_MAX, /* input/output */
+
+   /* FrontFacing is builtin */
+   [VARYING_SLOT_FACE] = UINT_MAX,
+
+   /* PointCoord is builtin */
+   [VARYING_SLOT_PNTC] = UINT_MAX, /* input only */
+
+   /* TessLevelOuter is builtin */
+   [VARYING_SLOT_TESS_LEVEL_OUTER] = UINT_MAX,
+   /* TessLevelInner is builtin */
+   [VARYING_SLOT_TESS_LEVEL_INNER] = UINT_MAX,
+
+   [VARYING_SLOT_BOUNDING_BOX0] = 7, /* Only appears as TCS output. */
+   [VARYING_SLOT_BOUNDING_BOX1] = 8, /* Only appears as TCS output. */
+   [VARYING_SLOT_VIEW_INDEX] = 9, /* input/output */
+   [VARYING_SLOT_VIEWPORT_MASK] = 10, /* output only */
+};
+#define NTV_MIN_RESERVED_SLOTS 11
+
 struct ntv_context {
+   void *mem_ctx;
+
    struct spirv_builder builder;
 
    SpvId GLSL_std_450;
@@ -51,6 +113,10 @@ struct ntv_context {
    size_t num_regs;
 
    struct hash_table *vars; /* nir_variable -> SpvId */
+   struct hash_table *so_outputs; /* pipe_stream_output -> SpvId */
+   unsigned outputs[VARYING_SLOT_MAX];
+   const struct glsl_type *so_output_gl_types[VARYING_SLOT_MAX];
+   SpvId so_output_types[VARYING_SLOT_MAX];
 
    const SpvId *block_ids;
    size_t num_blocks;
@@ -58,6 +124,9 @@ struct ntv_context {
    SpvId loop_break, loop_cont;
 
    SpvId front_face_var, instance_id_var, vertex_id_var;
+#ifndef NDEBUG
+   bool seen_texcoord[8]; //whether we've seen a VARYING_SLOT_TEX[n] this pass
+#endif
 };
 
 static SpvId
@@ -140,9 +209,9 @@ get_fvec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_component
 static SpvId
 get_ivec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
 {
-   assert(bit_size == 1 || bit_size == 32); // only 32-bit ints supported so far
+   assert(bit_size == 32); // only 32-bit ints supported so far
 
-   SpvId int_type = spirv_builder_type_int(&ctx->builder, MAX2(bit_size, 32));
+   SpvId int_type = spirv_builder_type_int(&ctx->builder, bit_size);
    if (num_components > 1)
       return spirv_builder_type_vector(&ctx->builder, int_type,
                                        num_components);
@@ -154,9 +223,9 @@ get_ivec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_component
 static SpvId
 get_uvec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
 {
-   assert(bit_size == 1 || bit_size == 32); // only 32-bit uints supported so far
+   assert(bit_size == 32); // only 32-bit uints supported so far
 
-   SpvId uint_type = spirv_builder_type_uint(&ctx->builder, MAX2(bit_size, 32));
+   SpvId uint_type = spirv_builder_type_uint(&ctx->builder, bit_size);
    if (num_components > 1)
       return spirv_builder_type_vector(&ctx->builder, uint_type,
                                        num_components);
@@ -168,8 +237,8 @@ get_uvec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_component
 static SpvId
 get_dest_uvec_type(struct ntv_context *ctx, nir_dest *dest)
 {
-   return get_uvec_type(ctx, nir_dest_bit_size(*dest),
-                             nir_dest_num_components(*dest));
+   unsigned bit_size = MAX2(nir_dest_bit_size(*dest), 32);
+   return get_uvec_type(ctx, bit_size, nir_dest_num_components(*dest));
 }
 
 static SpvId
@@ -220,6 +289,34 @@ get_glsl_type(struct ntv_context *ctx, const struct glsl_type *type)
    unreachable("we shouldn't get here, I think...");
 }
 
+static inline unsigned
+handle_slot(struct ntv_context *ctx, unsigned slot)
+{
+   unsigned orig = slot;
+   if (slot < VARYING_SLOT_VAR0) {
+#ifndef NDEBUG
+      if (slot >= VARYING_SLOT_TEX0 && slot <= VARYING_SLOT_TEX7)
+         ctx->seen_texcoord[slot - VARYING_SLOT_TEX0] = true;
+#endif
+      slot = slot_pack_map[slot];
+      if (slot == UINT_MAX)
+         debug_printf("unhandled varying slot: %s\n", gl_varying_slot_name(orig));
+   } else {
+      slot -= VARYING_SLOT_VAR0 - NTV_MIN_RESERVED_SLOTS;
+      assert(slot <= VARYING_SLOT_VAR0 - 8 ||
+             !ctx->seen_texcoord[VARYING_SLOT_VAR0 - slot - 1]);
+
+   }
+   assert(slot < VARYING_SLOT_VAR0);
+   return slot;
+}
+
+#define HANDLE_EMIT_BUILTIN(SLOT, BUILTIN) \
+      case VARYING_SLOT_##SLOT: \
+         spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltIn##BUILTIN); \
+         break
+
+
 static void
 emit_input(struct ntv_context *ctx, struct nir_variable *var)
 {
@@ -234,31 +331,20 @@ emit_input(struct ntv_context *ctx, struct nir_variable *var)
       spirv_builder_emit_name(&ctx->builder, var_id, var->name);
 
    if (ctx->stage == MESA_SHADER_FRAGMENT) {
-      if (var->data.location >= VARYING_SLOT_VAR0)
-         spirv_builder_emit_location(&ctx->builder, var_id,
-                                     var->data.location -
-                                     VARYING_SLOT_VAR0 +
-                                     VARYING_SLOT_TEX0);
-      else if ((var->data.location >= VARYING_SLOT_COL0 &&
-                var->data.location <= VARYING_SLOT_TEX7) ||
-               var->data.location == VARYING_SLOT_BFC0 ||
-               var->data.location == VARYING_SLOT_BFC1) {
-         spirv_builder_emit_location(&ctx->builder, var_id,
-                                     var->data.location);
-      } else {
-         switch (var->data.location) {
-         case VARYING_SLOT_POS:
-            spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInFragCoord);
-            break;
+      unsigned slot = var->data.location;
+      switch (slot) {
+      HANDLE_EMIT_BUILTIN(POS, FragCoord);
+      HANDLE_EMIT_BUILTIN(PNTC, PointCoord);
+      HANDLE_EMIT_BUILTIN(LAYER, Layer);
+      HANDLE_EMIT_BUILTIN(PRIMITIVE_ID, PrimitiveId);
+      HANDLE_EMIT_BUILTIN(CLIP_DIST0, ClipDistance);
+      HANDLE_EMIT_BUILTIN(CULL_DIST0, CullDistance);
+      HANDLE_EMIT_BUILTIN(VIEWPORT, ViewportIndex);
+      HANDLE_EMIT_BUILTIN(FACE, FrontFacing);
 
-         case VARYING_SLOT_PNTC:
-            spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPointCoord);
-            break;
-
-         default:
-            debug_printf("unknown varying slot: %s\n", gl_varying_slot_name(var->data.location));
-            unreachable("unexpected varying slot");
-         }
+      default:
+         slot = handle_slot(ctx, slot);
+         spirv_builder_emit_location(&ctx->builder, var_id, slot);
       }
    } else {
       spirv_builder_emit_location(&ctx->builder, var_id,
@@ -292,47 +378,42 @@ emit_output(struct ntv_context *ctx, struct nir_variable *var)
 
 
    if (ctx->stage == MESA_SHADER_VERTEX) {
-      if (var->data.location >= VARYING_SLOT_VAR0)
-         spirv_builder_emit_location(&ctx->builder, var_id,
-                                     var->data.location -
-                                     VARYING_SLOT_VAR0 +
-                                     VARYING_SLOT_TEX0);
-      else if ((var->data.location >= VARYING_SLOT_COL0 &&
-                var->data.location <= VARYING_SLOT_TEX7) ||
-               var->data.location == VARYING_SLOT_BFC0 ||
-               var->data.location == VARYING_SLOT_BFC1) {
-         spirv_builder_emit_location(&ctx->builder, var_id,
-                                     var->data.location);
-      } else {
-         switch (var->data.location) {
-         case VARYING_SLOT_POS:
-            spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPosition);
-            break;
-
-         case VARYING_SLOT_PSIZ:
-            spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPointSize);
-            break;
-
-         case VARYING_SLOT_CLIP_DIST0:
-            assert(glsl_type_is_array(var->type));
-            spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInClipDistance);
-            break;
+      unsigned slot = var->data.location;
+      switch (slot) {
+      HANDLE_EMIT_BUILTIN(POS, Position);
+      HANDLE_EMIT_BUILTIN(PSIZ, PointSize);
+      HANDLE_EMIT_BUILTIN(LAYER, Layer);
+      HANDLE_EMIT_BUILTIN(PRIMITIVE_ID, PrimitiveId);
+      HANDLE_EMIT_BUILTIN(CULL_DIST0, CullDistance);
+      HANDLE_EMIT_BUILTIN(VIEWPORT, ViewportIndex);
+      HANDLE_EMIT_BUILTIN(TESS_LEVEL_OUTER, TessLevelOuter);
+      HANDLE_EMIT_BUILTIN(TESS_LEVEL_INNER, TessLevelInner);
+
+      case VARYING_SLOT_CLIP_DIST0:
+         assert(glsl_type_is_array(var->type));
+         spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInClipDistance);
+         /* this can be as large as 2x vec4, which requires 2 slots */
+         ctx->outputs[VARYING_SLOT_CLIP_DIST1] = var_id;
+         ctx->so_output_gl_types[VARYING_SLOT_CLIP_DIST1] = var->type;
+         ctx->so_output_types[VARYING_SLOT_CLIP_DIST1] = var_type;
+         break;
 
-         default:
-            debug_printf("unknown varying slot: %s\n", gl_varying_slot_name(var->data.location));
-            unreachable("unexpected varying slot");
-         }
+      default:
+         slot = handle_slot(ctx, slot);
+         spirv_builder_emit_location(&ctx->builder, var_id, slot);
       }
+      ctx->outputs[var->data.location] = var_id;
+      ctx->so_output_gl_types[var->data.location] = var->type;
+      ctx->so_output_types[var->data.location] = var_type;
    } else if (ctx->stage == MESA_SHADER_FRAGMENT) {
-      if (var->data.location >= FRAG_RESULT_DATA0)
+      if (var->data.location >= FRAG_RESULT_DATA0) {
          spirv_builder_emit_location(&ctx->builder, var_id,
                                      var->data.location - FRAG_RESULT_DATA0);
-      else {
+         spirv_builder_emit_index(&ctx->builder, var_id, var->data.index);
+      } else {
          switch (var->data.location) {
          case FRAG_RESULT_COLOR:
-            spirv_builder_emit_location(&ctx->builder, var_id, 0);
-            spirv_builder_emit_index(&ctx->builder, var_id, var->data.index);
-            break;
+            unreachable("gl_FragColor should be lowered by now");
 
          case FRAG_RESULT_DEPTH:
             spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInFragDepth);
@@ -341,6 +422,7 @@ emit_output(struct ntv_context *ctx, struct nir_variable *var)
          default:
             spirv_builder_emit_location(&ctx->builder, var_id,
                                         var->data.driver_location);
+            spirv_builder_emit_index(&ctx->builder, var_id, var->data.index);
          }
       }
    }
@@ -349,6 +431,23 @@ emit_output(struct ntv_context *ctx, struct nir_variable *var)
       spirv_builder_emit_component(&ctx->builder, var_id,
                                    var->data.location_frac);
 
+   switch (var->data.interpolation) {
+   case INTERP_MODE_NONE:
+   case INTERP_MODE_SMOOTH: /* XXX spirv doesn't seem to have anything for this */
+      break;
+   case INTERP_MODE_FLAT:
+      spirv_builder_emit_decoration(&ctx->builder, var_id, SpvDecorationFlat);
+      break;
+   case INTERP_MODE_EXPLICIT:
+      spirv_builder_emit_decoration(&ctx->builder, var_id, SpvDecorationExplicitInterpAMD);
+      break;
+   case INTERP_MODE_NOPERSPECTIVE:
+      spirv_builder_emit_decoration(&ctx->builder, var_id, SpvDecorationNoPerspective);
+      break;
+   default:
+      unreachable("unknown interpolation value");
+   }
+
    _mesa_hash_table_insert(ctx->vars, var, (void *)(intptr_t)var_id);
 
    assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
@@ -533,6 +632,17 @@ emit_uniform(struct ntv_context *ctx, struct nir_variable *var)
    }
 }
 
+static SpvId
+get_vec_from_bit_size(struct ntv_context *ctx, uint32_t bit_size, uint32_t num_components)
+{
+   if (bit_size == 1)
+      return get_bvec_type(ctx, num_components);
+   if (bit_size == 32)
+      return get_uvec_type(ctx, bit_size, num_components);
+   unreachable("unhandled register bit size");
+   return 0;
+}
+
 static SpvId
 get_src_ssa(struct ntv_context *ctx, const nir_ssa_def *ssa)
 {
@@ -557,7 +667,7 @@ get_src_reg(struct ntv_context *ctx, const nir_reg_src *reg)
    assert(!reg->base_offset);
 
    SpvId var = get_var_from_reg(ctx, reg->reg);
-   SpvId type = get_uvec_type(ctx, reg->reg->bit_size, reg->reg->num_components);
+   SpvId type = get_vec_from_bit_size(ctx, reg->reg->bit_size, reg->reg->num_components);
    return spirv_builder_emit_load(&ctx->builder, type, var);
 }
 
@@ -601,28 +711,33 @@ get_alu_src_raw(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
    int bit_size = nir_src_bit_size(alu->src[src].src);
    assert(bit_size == 1 || bit_size == 32);
 
-   SpvId uint_type = spirv_builder_type_uint(&ctx->builder, MAX2(bit_size, 32));
+   SpvId raw_type = bit_size == 1 ? spirv_builder_type_bool(&ctx->builder) :
+                                    spirv_builder_type_uint(&ctx->builder, bit_size);
+
    if (used_channels == 1) {
       uint32_t indices[] =  { alu->src[src].swizzle[0] };
-      return spirv_builder_emit_composite_extract(&ctx->builder, uint_type,
+      return spirv_builder_emit_composite_extract(&ctx->builder, raw_type,
                                                   def, indices,
                                                   ARRAY_SIZE(indices));
    } else if (live_channels == 1) {
-      SpvId uvec_type = spirv_builder_type_vector(&ctx->builder, uint_type,
-                                                  used_channels);
+      SpvId raw_vec_type = spirv_builder_type_vector(&ctx->builder,
+                                                     raw_type,
+                                                     used_channels);
 
-      SpvId constituents[NIR_MAX_VEC_COMPONENTS];
+      SpvId constituents[NIR_MAX_VEC_COMPONENTS] = {0};
       for (unsigned i = 0; i < used_channels; ++i)
         constituents[i] = def;
 
-      return spirv_builder_emit_composite_construct(&ctx->builder, uvec_type,
+      return spirv_builder_emit_composite_construct(&ctx->builder,
+                                                    raw_vec_type,
                                                     constituents,
                                                     used_channels);
    } else {
-      SpvId uvec_type = spirv_builder_type_vector(&ctx->builder, uint_type,
-                                                  used_channels);
+      SpvId raw_vec_type = spirv_builder_type_vector(&ctx->builder,
+                                                     raw_type,
+                                                     used_channels);
 
-      uint32_t components[NIR_MAX_VEC_COMPONENTS];
+      uint32_t components[NIR_MAX_VEC_COMPONENTS] = {0};
       size_t num_components = 0;
       for (unsigned i = 0; i < NIR_MAX_VEC_COMPONENTS; i++) {
          if (!nir_alu_instr_channel_used(alu, src, i))
@@ -631,8 +746,9 @@ get_alu_src_raw(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
          components[num_components++] = alu->src[src].swizzle[i];
       }
 
-      return spirv_builder_emit_vector_shuffle(&ctx->builder, uvec_type,
-                                        def, def, components, num_components);
+      return spirv_builder_emit_vector_shuffle(&ctx->builder, raw_vec_type,
+                                               def, def, components,
+                                               num_components);
    }
 }
 
@@ -651,15 +767,6 @@ emit_select(struct ntv_context *ctx, SpvId type, SpvId cond,
    return emit_triop(ctx, SpvOpSelect, type, cond, if_true, if_false);
 }
 
-static SpvId
-bvec_to_uvec(struct ntv_context *ctx, SpvId value, unsigned num_components)
-{
-   SpvId otype = get_uvec_type(ctx, 32, num_components);
-   SpvId zero = get_uvec_constant(ctx, 32, num_components, 0);
-   SpvId one = get_uvec_constant(ctx, 32, num_components, UINT32_MAX);
-   return emit_select(ctx, otype, value, one, zero);
-}
-
 static SpvId
 uvec_to_bvec(struct ntv_context *ctx, SpvId value, unsigned num_components)
 {
@@ -715,31 +822,32 @@ store_dest_raw(struct ntv_context *ctx, nir_dest *dest, SpvId result)
       store_reg_def(ctx, &dest->reg, result);
 }
 
-static void
+static SpvId
 store_dest(struct ntv_context *ctx, nir_dest *dest, SpvId result, nir_alu_type type)
 {
    unsigned num_components = nir_dest_num_components(*dest);
    unsigned bit_size = nir_dest_bit_size(*dest);
 
-   switch (nir_alu_type_get_base_type(type)) {
-   case nir_type_bool:
-      assert(bit_size == 1);
-      result = bvec_to_uvec(ctx, result, num_components);
-      break;
+   if (bit_size != 1) {
+      switch (nir_alu_type_get_base_type(type)) {
+      case nir_type_bool:
+         assert("bool should have bit-size 1");
 
-   case nir_type_uint:
-      break; /* nothing to do! */
+      case nir_type_uint:
+         break; /* nothing to do! */
 
-   case nir_type_int:
-   case nir_type_float:
-      result = bitcast_to_uvec(ctx, result, bit_size, num_components);
-      break;
+      case nir_type_int:
+      case nir_type_float:
+         result = bitcast_to_uvec(ctx, result, bit_size, num_components);
+         break;
 
-   default:
-      unreachable("unsupported nir_alu_type");
+      default:
+         unreachable("unsupported nir_alu_type");
+      }
    }
 
    store_dest_raw(ctx, dest, result);
+   return result;
 }
 
 static SpvId
@@ -748,6 +856,153 @@ emit_unop(struct ntv_context *ctx, SpvOp op, SpvId type, SpvId src)
    return spirv_builder_emit_unop(&ctx->builder, op, type, src);
 }
 
+/* return the intended xfb output vec type based on base type and vector size */
+static SpvId
+get_output_type(struct ntv_context *ctx, unsigned register_index, unsigned num_components)
+{
+   const struct glsl_type *out_type = ctx->so_output_gl_types[register_index];
+   enum glsl_base_type base_type = glsl_get_base_type(out_type);
+   if (base_type == GLSL_TYPE_ARRAY)
+      base_type = glsl_get_base_type(glsl_without_array(out_type));
+
+   switch (base_type) {
+   case GLSL_TYPE_BOOL:
+      return get_bvec_type(ctx, num_components);
+
+   case GLSL_TYPE_FLOAT:
+      return get_fvec_type(ctx, 32, num_components);
+
+   case GLSL_TYPE_INT:
+      return get_ivec_type(ctx, 32, num_components);
+
+   case GLSL_TYPE_UINT:
+      return get_uvec_type(ctx, 32, num_components);
+
+   default:
+      break;
+   }
+   unreachable("unknown type");
+   return 0;
+}
+
+/* for streamout create new outputs, as streamout can be done on individual components,
+   from complete outputs, so we just can't use the created packed outputs */
+static void
+emit_so_info(struct ntv_context *ctx, unsigned max_output_location,
+             const struct pipe_stream_output_info *so_info, struct pipe_stream_output_info *local_so_info)
+{
+   for (unsigned i = 0; i < local_so_info->num_outputs; i++) {
+      struct pipe_stream_output so_output = local_so_info->output[i];
+      SpvId out_type = get_output_type(ctx, so_output.register_index, so_output.num_components);
+      SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
+                                                      SpvStorageClassOutput,
+                                                      out_type);
+      SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
+                                            SpvStorageClassOutput);
+      char name[10];
+
+      snprintf(name, 10, "xfb%d", i);
+      spirv_builder_emit_name(&ctx->builder, var_id, name);
+      spirv_builder_emit_offset(&ctx->builder, var_id, (so_output.dst_offset * 4));
+      spirv_builder_emit_xfb_buffer(&ctx->builder, var_id, so_output.output_buffer);
+      spirv_builder_emit_xfb_stride(&ctx->builder, var_id, so_info->stride[so_output.output_buffer] * 4);
+
+      /* output location is incremented by VARYING_SLOT_VAR0 for non-builtins in vtn,
+       * so we need to ensure that the new xfb location slot doesn't conflict with any previously-emitted
+       * outputs.
+       *
+       * if there's no previous outputs that take up user slots (VAR0+) then we can start right after the
+       * glsl builtin reserved slots, otherwise we start just after the adjusted user output slot
+       */
+      uint32_t location = NTV_MIN_RESERVED_SLOTS + i;
+      if (max_output_location >= VARYING_SLOT_VAR0)
+         location = max_output_location - VARYING_SLOT_VAR0 + 1 + i;
+      assert(location < VARYING_SLOT_VAR0);
+      assert(location <= VARYING_SLOT_VAR0 - 8 ||
+             !ctx->seen_texcoord[VARYING_SLOT_VAR0 - location - 1]);
+      spirv_builder_emit_location(&ctx->builder, var_id, location);
+
+      /* note: gl_ClipDistance[4] can the 0-indexed member of VARYING_SLOT_CLIP_DIST1 here,
+       * so this is still the 0 component
+       */
+      if (so_output.start_component)
+         spirv_builder_emit_component(&ctx->builder, var_id, so_output.start_component);
+
+      uint32_t *key = ralloc_size(ctx->mem_ctx, sizeof(uint32_t));
+      *key = (uint32_t)so_output.register_index << 2 | so_output.start_component;
+      _mesa_hash_table_insert(ctx->so_outputs, key, (void *)(intptr_t)var_id);
+
+      assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
+      ctx->entry_ifaces[ctx->num_entry_ifaces++] = var_id;
+   }
+}
+
+static void
+emit_so_outputs(struct ntv_context *ctx,
+                const struct pipe_stream_output_info *so_info, struct pipe_stream_output_info *local_so_info)
+{
+   SpvId loaded_outputs[VARYING_SLOT_MAX] = {};
+   for (unsigned i = 0; i < local_so_info->num_outputs; i++) {
+      uint32_t components[NIR_MAX_VEC_COMPONENTS];
+      struct pipe_stream_output so_output = local_so_info->output[i];
+      uint32_t so_key = (uint32_t) so_output.register_index << 2 | so_output.start_component;
+      struct hash_entry *he = _mesa_hash_table_search(ctx->so_outputs, &so_key);
+      assert(he);
+      SpvId so_output_var_id = (SpvId)(intptr_t)he->data;
+
+      SpvId type = get_output_type(ctx, so_output.register_index, so_output.num_components);
+      SpvId output = ctx->outputs[so_output.register_index];
+      SpvId output_type = ctx->so_output_types[so_output.register_index];
+      const struct glsl_type *out_type = ctx->so_output_gl_types[so_output.register_index];
+
+      if (!loaded_outputs[so_output.register_index])
+         loaded_outputs[so_output.register_index] = spirv_builder_emit_load(&ctx->builder, output_type, output);
+      SpvId src = loaded_outputs[so_output.register_index];
+
+      SpvId result;
+
+      for (unsigned c = 0; c < so_output.num_components; c++) {
+         components[c] = so_output.start_component + c;
+         /* this is the second half of a 2 * vec4 array */
+         if (ctx->stage == MESA_SHADER_VERTEX && so_output.register_index == VARYING_SLOT_CLIP_DIST1)
+            components[c] += 4;
+      }
+
+      /* if we're emitting a scalar or the type we're emitting matches the output's original type and we're
+       * emitting the same number of components, then we can skip any sort of conversion here
+       */
+      if (glsl_type_is_scalar(out_type) || (type == output_type && glsl_get_length(out_type) == so_output.num_components))
+         result = src;
+      else {
+         /* OpCompositeExtract can only extract scalars for our use here */
+         if (so_output.num_components == 1) {
+            result = spirv_builder_emit_composite_extract(&ctx->builder, type, src, components, so_output.num_components);
+         } else if (glsl_type_is_vector(out_type)) {
+            /* OpVectorShuffle can select vector members into a differently-sized vector */
+            result = spirv_builder_emit_vector_shuffle(&ctx->builder, type,
+                                                             src, src,
+                                                             components, so_output.num_components);
+            result = emit_unop(ctx, SpvOpBitcast, type, result);
+         } else {
+             /* for arrays, we need to manually extract each desired member
+              * and re-pack them into the desired output type
+              */
+             for (unsigned c = 0; c < so_output.num_components; c++) {
+                uint32_t member[] = { so_output.start_component + c };
+                SpvId base_type = get_glsl_type(ctx, glsl_without_array(out_type));
+
+                if (ctx->stage == MESA_SHADER_VERTEX && so_output.register_index == VARYING_SLOT_CLIP_DIST1)
+                   member[0] += 4;
+                components[c] = spirv_builder_emit_composite_extract(&ctx->builder, base_type, src, member, 1);
+             }
+             result = spirv_builder_emit_composite_construct(&ctx->builder, type, components, so_output.num_components);
+         }
+      }
+
+      spirv_builder_emit_store(&ctx->builder, so_output_var_id, result);
+   }
+}
+
 static SpvId
 emit_binop(struct ntv_context *ctx, SpvOp op, SpvId type,
            SpvId src0, SpvId src1)
@@ -870,26 +1125,29 @@ get_alu_src(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
    unsigned bit_size = nir_src_bit_size(alu->src[src].src);
    nir_alu_type type = nir_op_infos[alu->op].input_types[src];
 
-   switch (nir_alu_type_get_base_type(type)) {
-   case nir_type_bool:
-      assert(bit_size == 1);
-      return uvec_to_bvec(ctx, raw_value, num_components);
+   if (bit_size == 1)
+      return raw_value;
+   else {
+      switch (nir_alu_type_get_base_type(type)) {
+      case nir_type_bool:
+         unreachable("bool should have bit-size 1");
 
-   case nir_type_int:
-      return bitcast_to_ivec(ctx, raw_value, bit_size, num_components);
+      case nir_type_int:
+         return bitcast_to_ivec(ctx, raw_value, bit_size, num_components);
 
-   case nir_type_uint:
-      return raw_value;
+      case nir_type_uint:
+         return raw_value;
 
-   case nir_type_float:
-      return bitcast_to_fvec(ctx, raw_value, bit_size, num_components);
+      case nir_type_float:
+         return bitcast_to_fvec(ctx, raw_value, bit_size, num_components);
 
-   default:
-      unreachable("unknown nir_alu_type");
+      default:
+         unreachable("unknown nir_alu_type");
+      }
    }
 }
 
-static void
+static SpvId
 store_alu_result(struct ntv_context *ctx, nir_alu_instr *alu, SpvId result)
 {
    assert(!alu->dest.saturate);
@@ -903,9 +1161,12 @@ get_dest_type(struct ntv_context *ctx, nir_dest *dest, nir_alu_type type)
    unsigned num_components = nir_dest_num_components(*dest);
    unsigned bit_size = nir_dest_bit_size(*dest);
 
+   if (bit_size == 1)
+      return get_bvec_type(ctx, num_components);
+
    switch (nir_alu_type_get_base_type(type)) {
    case nir_type_bool:
-      return get_bvec_type(ctx, num_components);
+      unreachable("bool should have bit-size 1");
 
    case nir_type_int:
       return get_ivec_type(ctx, bit_size, num_components);
@@ -925,8 +1186,11 @@ static void
 emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
 {
    SpvId src[nir_op_infos[alu->op].num_inputs];
-   for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++)
+   unsigned in_bit_sizes[nir_op_infos[alu->op].num_inputs];
+   for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) {
       src[i] = get_alu_src(ctx, alu, i);
+      in_bit_sizes[i] = nir_src_bit_size(alu->src[i].src);
+   }
 
    SpvId dest_type = get_dest_type(ctx, &alu->dest.dest,
                                    nir_op_infos[alu->op].output_type);
@@ -958,9 +1222,16 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
    UNOP(nir_op_f2u32, SpvOpConvertFToU)
    UNOP(nir_op_i2f32, SpvOpConvertSToF)
    UNOP(nir_op_u2f32, SpvOpConvertUToF)
-   UNOP(nir_op_inot, SpvOpNot)
+   UNOP(nir_op_bitfield_reverse, SpvOpBitReverse)
 #undef UNOP
 
+   case nir_op_inot:
+      if (bit_size == 1)
+         result = emit_unop(ctx, SpvOpLogicalNot, dest_type, src[0]);
+      else
+         result = emit_unop(ctx, SpvOpNot, dest_type, src[0]);
+      break;
+
    case nir_op_b2i32:
       assert(nir_op_infos[alu->op].num_inputs == 1);
       result = emit_select(ctx, dest_type, src[0],
@@ -993,6 +1264,7 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
    BUILTIN_UNOP(nir_op_ftrunc, GLSLstd450Trunc)
    BUILTIN_UNOP(nir_op_fround_even, GLSLstd450RoundEven)
    BUILTIN_UNOP(nir_op_fsign, GLSLstd450FSign)
+   BUILTIN_UNOP(nir_op_isign, GLSLstd450SSign)
    BUILTIN_UNOP(nir_op_fsin, GLSLstd450Sin)
    BUILTIN_UNOP(nir_op_fcos, GLSLstd450Cos)
 #undef BUILTIN_UNOP
@@ -1011,6 +1283,13 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
                                             nir_src_bit_size(alu->src[0].src),
                                             num_components, 0));
       break;
+   case nir_op_i2b1:
+      assert(nir_op_infos[alu->op].num_inputs == 1);
+      result = emit_binop(ctx, SpvOpINotEqual, dest_type, src[0],
+                          get_ivec_constant(ctx,
+                                            nir_src_bit_size(alu->src[0].src),
+                                            num_components, 0));
+      break;
 
 
 #define BINOP(nir_op, spirv_op) \
@@ -1032,20 +1311,33 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
    BINOP(nir_op_fmod, SpvOpFMod)
    BINOP(nir_op_ilt, SpvOpSLessThan)
    BINOP(nir_op_ige, SpvOpSGreaterThanEqual)
-   BINOP(nir_op_ieq, SpvOpIEqual)
-   BINOP(nir_op_ine, SpvOpINotEqual)
+   BINOP(nir_op_ult, SpvOpULessThan)
    BINOP(nir_op_uge, SpvOpUGreaterThanEqual)
    BINOP(nir_op_flt, SpvOpFOrdLessThan)
    BINOP(nir_op_fge, SpvOpFOrdGreaterThanEqual)
    BINOP(nir_op_feq, SpvOpFOrdEqual)
-   BINOP(nir_op_fne, SpvOpFOrdNotEqual)
+   BINOP(nir_op_fne, SpvOpFUnordNotEqual)
    BINOP(nir_op_ishl, SpvOpShiftLeftLogical)
    BINOP(nir_op_ishr, SpvOpShiftRightArithmetic)
    BINOP(nir_op_ushr, SpvOpShiftRightLogical)
-   BINOP(nir_op_iand, SpvOpBitwiseAnd)
-   BINOP(nir_op_ior, SpvOpBitwiseOr)
+   BINOP(nir_op_ixor, SpvOpBitwiseXor)
 #undef BINOP
 
+#define BINOP_LOG(nir_op, spv_op, spv_log_op) \
+   case nir_op: \
+      assert(nir_op_infos[alu->op].num_inputs == 2); \
+      if (nir_src_bit_size(alu->src[0].src) == 1) \
+         result = emit_binop(ctx, spv_log_op, dest_type, src[0], src[1]); \
+      else \
+         result = emit_binop(ctx, spv_op, dest_type, src[0], src[1]); \
+      break;
+
+   BINOP_LOG(nir_op_iand, SpvOpBitwiseAnd, SpvOpLogicalAnd)
+   BINOP_LOG(nir_op_ior, SpvOpBitwiseOr, SpvOpLogicalOr)
+   BINOP_LOG(nir_op_ieq, SpvOpIEqual, SpvOpLogicalEqual)
+   BINOP_LOG(nir_op_ine, SpvOpINotEqual, SpvOpLogicalNotEqual)
+#undef BINOP_LOG
+
 #define BUILTIN_BINOP(nir_op, spirv_op) \
    case nir_op: \
       assert(nir_op_infos[alu->op].num_inputs == 2); \
@@ -1054,6 +1346,10 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
 
    BUILTIN_BINOP(nir_op_fmin, GLSLstd450FMin)
    BUILTIN_BINOP(nir_op_fmax, GLSLstd450FMax)
+   BUILTIN_BINOP(nir_op_imin, GLSLstd450SMin)
+   BUILTIN_BINOP(nir_op_imax, GLSLstd450SMax)
+   BUILTIN_BINOP(nir_op_umin, GLSLstd450UMin)
+   BUILTIN_BINOP(nir_op_umax, GLSLstd450UMax)
 #undef BUILTIN_BINOP
 
    case nir_op_fdot2:
@@ -1126,51 +1422,67 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
 
    case nir_op_bany_fnequal2:
    case nir_op_bany_fnequal3:
-   case nir_op_bany_fnequal4:
+   case nir_op_bany_fnequal4: {
       assert(nir_op_infos[alu->op].num_inputs == 2);
       assert(alu_instr_src_components(alu, 0) ==
              alu_instr_src_components(alu, 1));
-      result = emit_binop(ctx, SpvOpFOrdNotEqual,
+      assert(in_bit_sizes[0] == in_bit_sizes[1]);
+      /* The type of Operand 1 and Operand 2 must be a scalar or vector of floating-point type. */
+      SpvOp op = in_bit_sizes[0] == 1 ? SpvOpLogicalNotEqual : SpvOpFOrdNotEqual;
+      result = emit_binop(ctx, op,
                           get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
                           src[0], src[1]);
       result = emit_unop(ctx, SpvOpAny, dest_type, result);
       break;
+   }
 
    case nir_op_ball_fequal2:
    case nir_op_ball_fequal3:
-   case nir_op_ball_fequal4:
+   case nir_op_ball_fequal4: {
       assert(nir_op_infos[alu->op].num_inputs == 2);
       assert(alu_instr_src_components(alu, 0) ==
              alu_instr_src_components(alu, 1));
-      result = emit_binop(ctx, SpvOpFOrdEqual,
+      assert(in_bit_sizes[0] == in_bit_sizes[1]);
+      /* The type of Operand 1 and Operand 2 must be a scalar or vector of floating-point type. */
+      SpvOp op = in_bit_sizes[0] == 1 ? SpvOpLogicalEqual : SpvOpFOrdEqual;
+      result = emit_binop(ctx, op,
                           get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
                           src[0], src[1]);
       result = emit_unop(ctx, SpvOpAll, dest_type, result);
       break;
+   }
 
    case nir_op_bany_inequal2:
    case nir_op_bany_inequal3:
-   case nir_op_bany_inequal4:
+   case nir_op_bany_inequal4: {
       assert(nir_op_infos[alu->op].num_inputs == 2);
       assert(alu_instr_src_components(alu, 0) ==
              alu_instr_src_components(alu, 1));
-      result = emit_binop(ctx, SpvOpINotEqual,
+      assert(in_bit_sizes[0] == in_bit_sizes[1]);
+      /* The type of Operand 1 and Operand 2 must be a scalar or vector of integer type. */
+      SpvOp op = in_bit_sizes[0] == 1 ? SpvOpLogicalNotEqual : SpvOpINotEqual;
+      result = emit_binop(ctx, op,
                           get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
                           src[0], src[1]);
       result = emit_unop(ctx, SpvOpAny, dest_type, result);
       break;
+   }
 
    case nir_op_ball_iequal2:
    case nir_op_ball_iequal3:
-   case nir_op_ball_iequal4:
+   case nir_op_ball_iequal4: {
       assert(nir_op_infos[alu->op].num_inputs == 2);
       assert(alu_instr_src_components(alu, 0) ==
              alu_instr_src_components(alu, 1));
-      result = emit_binop(ctx, SpvOpIEqual,
+      assert(in_bit_sizes[0] == in_bit_sizes[1]);
+      /* The type of Operand 1 and Operand 2 must be a scalar or vector of integer type. */
+      SpvOp op = in_bit_sizes[0] == 1 ? SpvOpLogicalEqual : SpvOpIEqual;
+      result = emit_binop(ctx, op,
                           get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
                           src[0], src[1]);
       result = emit_unop(ctx, SpvOpAll, dest_type, result);
       break;
+   }
 
    case nir_op_vec2:
    case nir_op_vec3:
@@ -1202,19 +1514,17 @@ emit_load_const(struct ntv_context *ctx, nir_load_const_instr *load_const)
    SpvId constant;
    if (num_components > 1) {
       SpvId components[num_components];
-      SpvId type;
+      SpvId type = get_vec_from_bit_size(ctx, bit_size, num_components);
       if (bit_size == 1) {
          for (int i = 0; i < num_components; i++)
             components[i] = spirv_builder_const_bool(&ctx->builder,
                                                      load_const->value[i].b);
 
-         type = get_bvec_type(ctx, num_components);
       } else {
          for (int i = 0; i < num_components; i++)
             components[i] = emit_uint_const(ctx, bit_size,
                                             load_const->value[i].u32);
 
-         type = get_uvec_type(ctx, bit_size, num_components);
       }
       constant = spirv_builder_const_composite(&ctx->builder, type,
                                                components, num_components);
@@ -1227,9 +1537,6 @@ emit_load_const(struct ntv_context *ctx, nir_load_const_instr *load_const)
          constant = emit_uint_const(ctx, bit_size, load_const->value[0].u32);
    }
 
-   if (bit_size == 1)
-      constant = bvec_to_uvec(ctx, constant, num_components);
-
    store_ssa_def(ctx, &load_const->def, constant);
 }
 
@@ -1279,6 +1586,9 @@ emit_load_ubo(struct ntv_context *ctx, nir_intrinsic_instr *intr)
                                                          num_components);
       }
 
+      if (nir_dest_bit_size(intr->dest) == 1)
+         result = uvec_to_bvec(ctx, result, num_components);
+
       store_dest(ctx, &intr->dest, result, nir_type_uint);
    } else
       unreachable("uniform-addressing not yet supported");
@@ -1299,9 +1609,8 @@ emit_load_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
 {
    SpvId ptr = get_src(ctx, intr->src);
 
-   nir_variable *var = nir_intrinsic_get_var(intr, 0);
    SpvId result = spirv_builder_emit_load(&ctx->builder,
-                                          get_glsl_type(ctx, var->type),
+                                          get_glsl_type(ctx, nir_src_as_deref(intr->src[0])->type),
                                           ptr);
    unsigned num_components = nir_dest_num_components(intr->dest);
    unsigned bit_size = nir_dest_bit_size(intr->dest);
@@ -1315,8 +1624,7 @@ emit_store_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
    SpvId ptr = get_src(ctx, &intr->src[0]);
    SpvId src = get_src(ctx, &intr->src[1]);
 
-   nir_variable *var = nir_intrinsic_get_var(intr, 0);
-   SpvId type = get_glsl_type(ctx, glsl_without_array(var->type));
+   SpvId type = get_glsl_type(ctx, nir_src_as_deref(intr->src[0])->type);
    SpvId result = emit_bitcast(ctx, type, src);
    spirv_builder_emit_store(&ctx->builder, ptr, result);
 }
@@ -1454,6 +1762,42 @@ get_src_int(struct ntv_context *ctx, nir_src *src)
    return bitcast_to_ivec(ctx, def, bit_size, num_components);
 }
 
+static inline bool
+tex_instr_is_lod_allowed(nir_tex_instr *tex)
+{
+   /* This can only be used with an OpTypeImage that has a Dim operand of 1D, 2D, 3D, or Cube
+    * - SPIR-V: 3.14. Image Operands
+    */
+
+   return (tex->sampler_dim == GLSL_SAMPLER_DIM_1D ||
+           tex->sampler_dim == GLSL_SAMPLER_DIM_2D ||
+           tex->sampler_dim == GLSL_SAMPLER_DIM_3D ||
+           tex->sampler_dim == GLSL_SAMPLER_DIM_CUBE);
+}
+
+static SpvId
+pad_coord_vector(struct ntv_context *ctx, SpvId orig, unsigned old_size, unsigned new_size)
+{
+    SpvId int_type = spirv_builder_type_int(&ctx->builder, 32);
+    SpvId type = get_ivec_type(ctx, 32, new_size);
+    SpvId constituents[NIR_MAX_VEC_COMPONENTS] = {0};
+    SpvId zero = emit_int_const(ctx, 32, 0);
+    assert(new_size < NIR_MAX_VEC_COMPONENTS);
+
+    if (old_size == 1)
+       constituents[0] = orig;
+    else {
+       for (unsigned i = 0; i < old_size; i++)
+          constituents[i] = spirv_builder_emit_vector_extract(&ctx->builder, int_type, orig, i);
+    }
+
+    for (unsigned i = old_size; i < new_size; i++)
+       constituents[i] = zero;
+
+    return spirv_builder_emit_composite_construct(&ctx->builder, type,
+                                                  constituents, new_size);
+}
+
 static void
 emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
 {
@@ -1462,20 +1806,23 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
           tex->op == nir_texop_txl ||
           tex->op == nir_texop_txd ||
           tex->op == nir_texop_txf ||
+          tex->op == nir_texop_txf_ms ||
           tex->op == nir_texop_txs);
    assert(tex->texture_index == tex->sampler_index);
 
    SpvId coord = 0, proj = 0, bias = 0, lod = 0, dref = 0, dx = 0, dy = 0,
-         offset = 0;
-   unsigned coord_components = 0;
+         offset = 0, sample = 0;
+   unsigned coord_components = 0, coord_bitsize = 0, offset_components = 0;
    for (unsigned i = 0; i < tex->num_srcs; i++) {
       switch (tex->src[i].src_type) {
       case nir_tex_src_coord:
-         if (tex->op == nir_texop_txf)
+         if (tex->op == nir_texop_txf ||
+             tex->op == nir_texop_txf_ms)
             coord = get_src_int(ctx, &tex->src[i].src);
          else
             coord = get_src_float(ctx, &tex->src[i].src);
          coord_components = nir_src_num_components(tex->src[i].src);
+         coord_bitsize = nir_src_bit_size(tex->src[i].src);
          break;
 
       case nir_tex_src_projector:
@@ -1486,6 +1833,7 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
 
       case nir_tex_src_offset:
          offset = get_src_int(ctx, &tex->src[i].src);
+         offset_components = nir_src_num_components(tex->src[i].src);
          break;
 
       case nir_tex_src_bias:
@@ -1497,6 +1845,7 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
       case nir_tex_src_lod:
          assert(nir_src_num_components(tex->src[i].src) == 1);
          if (tex->op == nir_texop_txf ||
+             tex->op == nir_texop_txf_ms ||
              tex->op == nir_texop_txs)
             lod = get_src_int(ctx, &tex->src[i].src);
          else
@@ -1504,6 +1853,11 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
          assert(lod != 0);
          break;
 
+      case nir_tex_src_ms_index:
+         assert(nir_src_num_components(tex->src[i].src) == 1);
+         sample = get_src_int(ctx, &tex->src[i].src);
+         break;
+
       case nir_tex_src_comparator:
          assert(nir_src_num_components(tex->src[i].src) == 1);
          dref = get_src_float(ctx, &tex->src[i].src);
@@ -1541,6 +1895,8 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
 
    SpvId dest_type = get_dest_type(ctx, &tex->dest, tex->dest_type);
 
+   if (!tex_instr_is_lod_allowed(tex))
+      lod = 0;
    if (tex->op == nir_texop_txs) {
       SpvId image = spirv_builder_emit_image(&ctx->builder, image_type, load);
       SpvId result = spirv_builder_emit_image_query_size(&ctx->builder,
@@ -1578,10 +1934,24 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
       actual_dest_type = spirv_builder_type_float(&ctx->builder, 32);
 
    SpvId result;
-   if (tex->op == nir_texop_txf) {
+   if (tex->op == nir_texop_txf ||
+       tex->op == nir_texop_txf_ms) {
       SpvId image = spirv_builder_emit_image(&ctx->builder, image_type, load);
+      if (offset) {
+         /* SPIRV requires matched length vectors for OpIAdd, so if a shader
+          * uses vecs of differing sizes we need to make a new vec padded with zeroes
+          * to mimic how GLSL does this implicitly
+          */
+         if (offset_components > coord_components)
+            coord = pad_coord_vector(ctx, coord, coord_components, offset_components);
+         else if (coord_components > offset_components)
+            offset = pad_coord_vector(ctx, offset, offset_components, coord_components);
+         coord = emit_binop(ctx, SpvOpIAdd,
+                            get_ivec_type(ctx, coord_bitsize, coord_components),
+                            coord, offset);
+      }
       result = spirv_builder_emit_image_fetch(&ctx->builder, dest_type,
-                                              image, coord, lod);
+                                              image, coord, lod, sample);
    } else {
       result = spirv_builder_emit_image_sample(&ctx->builder,
                                                actual_dest_type, load,
@@ -1662,8 +2032,7 @@ emit_deref_var(struct ntv_context *ctx, nir_deref_instr *deref)
    struct hash_entry *he = _mesa_hash_table_search(ctx->vars, deref->var);
    assert(he);
    SpvId result = (SpvId)(intptr_t)he->data;
-   /* uint is a bit of a lie here, it's really just an opaque type */
-   store_dest(ctx, &deref->dest, result, nir_type_uint);
+   store_dest_raw(ctx, &deref->dest, result);
 }
 
 static void
@@ -1763,10 +2132,8 @@ emit_cf_list(struct ntv_context *ctx, struct exec_list *list);
 static SpvId
 get_src_bool(struct ntv_context *ctx, nir_src *src)
 {
-   SpvId def = get_src(ctx, src);
    assert(nir_src_bit_size(*src) == 1);
-   unsigned num_components = nir_src_num_components(*src);
-   return uvec_to_bvec(ctx, def, num_components);
+   return get_src(ctx, src);
 }
 
 static void
@@ -1826,7 +2193,9 @@ emit_loop(struct ntv_context *ctx, nir_loop *loop)
    ctx->loop_break = save_break;
    ctx->loop_cont = save_cont;
 
-   branch(ctx, cont_id);
+   /* loop->body may have already ended our block */
+   if (ctx->block_started)
+      branch(ctx, cont_id);
    start_block(ctx, cont_id);
    branch(ctx, header_id);
 
@@ -1858,11 +2227,13 @@ emit_cf_list(struct ntv_context *ctx, struct exec_list *list)
 }
 
 struct spirv_shader *
-nir_to_spirv(struct nir_shader *s)
+nir_to_spirv(struct nir_shader *s, const struct pipe_stream_output_info *so_info, struct pipe_stream_output_info *local_so_info)
 {
    struct spirv_shader *ret = NULL;
 
    struct ntv_context ctx = {};
+   ctx.mem_ctx = ralloc_context(NULL);
+   ctx.builder.mem_ctx = ctx.mem_ctx;
 
    switch (s->info.stage) {
    case MESA_SHADER_VERTEX:
@@ -1928,16 +2299,23 @@ nir_to_spirv(struct nir_shader *s)
    SpvId entry_point = spirv_builder_new_id(&ctx.builder);
    spirv_builder_emit_name(&ctx.builder, entry_point, "main");
 
-   ctx.vars = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+   ctx.vars = _mesa_hash_table_create(ctx.mem_ctx, _mesa_hash_pointer,
                                       _mesa_key_pointer_equal);
 
-   nir_foreach_variable(var, &s->inputs)
+   ctx.so_outputs = _mesa_hash_table_create(ctx.mem_ctx, _mesa_hash_u32,
+                                            _mesa_key_u32_equal);
+
+   nir_foreach_shader_in_variable(var, s)
       emit_input(&ctx, var);
 
-   nir_foreach_variable(var, &s->outputs)
+   nir_foreach_shader_out_variable(var, s)
       emit_output(&ctx, var);
 
-   nir_foreach_variable(var, &s->uniforms)
+   if (so_info)
+      emit_so_info(&ctx, util_last_bit64(s->info.outputs_written), so_info, local_so_info);
+   nir_foreach_variable_with_modes(var, s, nir_var_uniform |
+                                           nir_var_mem_ubo |
+                                           nir_var_mem_ssbo)
       emit_uniform(&ctx, var);
 
    if (s->info.stage == MESA_SHADER_FRAGMENT) {
@@ -1948,6 +2326,11 @@ nir_to_spirv(struct nir_shader *s)
                                       SpvExecutionModeDepthReplacing);
    }
 
+   if (so_info && so_info->num_outputs) {
+      spirv_builder_emit_cap(&ctx.builder, SpvCapabilityTransformFeedback);
+      spirv_builder_emit_exec_mode(&ctx.builder, entry_point,
+                                   SpvExecutionModeXfb);
+   }
 
    spirv_builder_function(&ctx.builder, entry_point, type_void,
                                             SpvFunctionControlMaskNone,
@@ -1956,18 +2339,21 @@ nir_to_spirv(struct nir_shader *s)
    nir_function_impl *entry = nir_shader_get_entrypoint(s);
    nir_metadata_require(entry, nir_metadata_block_index);
 
-   ctx.defs = (SpvId *)malloc(sizeof(SpvId) * entry->ssa_alloc);
+   ctx.defs = ralloc_array_size(ctx.mem_ctx,
+                                sizeof(SpvId), entry->ssa_alloc);
    if (!ctx.defs)
       goto fail;
    ctx.num_defs = entry->ssa_alloc;
 
    nir_index_local_regs(entry);
-   ctx.regs = malloc(sizeof(SpvId) * entry->reg_alloc);
+   ctx.regs = ralloc_array_size(ctx.mem_ctx,
+                                sizeof(SpvId), entry->reg_alloc);
    if (!ctx.regs)
       goto fail;
    ctx.num_regs = entry->reg_alloc;
 
-   SpvId *block_ids = (SpvId *)malloc(sizeof(SpvId) * entry->num_blocks);
+   SpvId *block_ids = ralloc_array_size(ctx.mem_ctx,
+                                        sizeof(SpvId), entry->num_blocks);
    if (!block_ids)
       goto fail;
 
@@ -1980,7 +2366,7 @@ nir_to_spirv(struct nir_shader *s)
    /* emit a block only for the variable declarations */
    start_block(&ctx, spirv_builder_new_id(&ctx.builder));
    foreach_list_typed(nir_register, reg, node, &entry->registers) {
-      SpvId type = get_uvec_type(&ctx, reg->bit_size, reg->num_components);
+      SpvId type = get_vec_from_bit_size(&ctx, reg->bit_size, reg->num_components);
       SpvId pointer_type = spirv_builder_type_pointer(&ctx.builder,
                                                       SpvStorageClassFunction,
                                                       type);
@@ -1992,7 +2378,8 @@ nir_to_spirv(struct nir_shader *s)
 
    emit_cf_list(&ctx, &entry->body);
 
-   free(ctx.defs);
+   if (so_info)
+      emit_so_outputs(&ctx, so_info, local_so_info);
 
    spirv_builder_return(&ctx.builder); // doesn't belong here, but whatevz
    spirv_builder_function_end(&ctx.builder);
@@ -2014,16 +2401,16 @@ nir_to_spirv(struct nir_shader *s)
    ret->num_words = spirv_builder_get_words(&ctx.builder, ret->words, num_words);
    assert(ret->num_words == num_words);
 
+   ralloc_free(ctx.mem_ctx);
+
    return ret;
 
 fail:
+   ralloc_free(ctx.mem_ctx);
 
    if (ret)
       spirv_shader_delete(ret);
 
-   if (ctx.vars)
-      _mesa_hash_table_destroy(ctx.vars, NULL);
-
    return NULL;
 }