zink/spirv: implement bcsel
[mesa.git] / src / gallium / drivers / zink / nir_to_spirv / nir_to_spirv.c
index 5b6a3191add415910b22321d4d44d809a205c166..a78a26b4bb327cd2f60194e7331a5896481c34af 100644 (file)
@@ -27,6 +27,7 @@
 #include "nir.h"
 #include "pipe/p_state.h"
 #include "util/u_memory.h"
+#include "util/hash_table.h"
 
 struct ntv_context {
    struct spirv_builder builder;
@@ -34,10 +35,6 @@ struct ntv_context {
    SpvId GLSL_std_450;
 
    gl_shader_stage stage;
-   SpvId inputs[PIPE_MAX_SHADER_INPUTS][4];
-   SpvId input_types[PIPE_MAX_SHADER_INPUTS][4];
-   SpvId outputs[PIPE_MAX_SHADER_OUTPUTS][4];
-   SpvId output_types[PIPE_MAX_SHADER_OUTPUTS][4];
    int var_location;
 
    SpvId ubos[128];
@@ -50,8 +47,10 @@ struct ntv_context {
    SpvId *defs;
    size_t num_defs;
 
-   SpvId *vars;
-   size_t num_vars;
+   SpvId *regs;
+   size_t num_regs;
+
+   struct hash_table *vars; /* nir_variable -> SpvId */
 
    const SpvId *block_ids;
    size_t num_blocks;
@@ -177,16 +176,27 @@ get_glsl_type(struct ntv_context *ctx, const struct glsl_type *type)
          get_glsl_basetype(ctx, glsl_get_base_type(type)),
          glsl_get_vector_elements(type));
 
+   if (glsl_type_is_array(type)) {
+      SpvId ret = spirv_builder_type_array(&ctx->builder,
+         get_glsl_type(ctx, glsl_get_array_element(type)),
+         spirv_builder_const_uint(&ctx->builder, 32, glsl_get_length(type)));
+      uint32_t stride = glsl_get_explicit_stride(type);
+      if (stride)
+         spirv_builder_emit_array_stride(&ctx->builder, ret, stride);
+      return ret;
+   }
+
+
    unreachable("we shouldn't get here, I think...");
 }
 
 static void
 emit_input(struct ntv_context *ctx, struct nir_variable *var)
 {
-   SpvId vec_type = get_glsl_type(ctx, var->type);
+   SpvId var_type = get_glsl_type(ctx, var->type);
    SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
                                                    SpvStorageClassInput,
-                                                   vec_type);
+                                                   var_type);
    SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
                                          SpvStorageClassInput);
 
@@ -210,7 +220,8 @@ emit_input(struct ntv_context *ctx, struct nir_variable *var)
             break;
 
          default:
-            unreachable("unknown varying slot");
+            debug_printf("unknown varying slot: %s\n", gl_varying_slot_name(var->data.location));
+            unreachable("unexpected varying slot");
          }
       }
    } else {
@@ -225,11 +236,7 @@ emit_input(struct ntv_context *ctx, struct nir_variable *var)
    if (var->data.interpolation == INTERP_MODE_FLAT)
       spirv_builder_emit_decoration(&ctx->builder, var_id, SpvDecorationFlat);
 
-   assert(var->data.driver_location < PIPE_MAX_SHADER_INPUTS);
-   assert(var->data.location_frac < 4);
-   assert(ctx->inputs[var->data.driver_location][var->data.location_frac] == 0);
-   ctx->inputs[var->data.driver_location][var->data.location_frac] = var_id;
-   ctx->input_types[var->data.driver_location][var->data.location_frac] = vec_type;
+   _mesa_hash_table_insert(ctx->vars, var, (void *)(intptr_t)var_id);
 
    assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
    ctx->entry_ifaces[ctx->num_entry_ifaces++] = var_id;
@@ -238,10 +245,10 @@ emit_input(struct ntv_context *ctx, struct nir_variable *var)
 static void
 emit_output(struct ntv_context *ctx, struct nir_variable *var)
 {
-   SpvId vec_type = get_glsl_type(ctx, var->type);
+   SpvId var_type = get_glsl_type(ctx, var->type);
    SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
                                                    SpvStorageClassOutput,
-                                                   vec_type);
+                                                   var_type);
    SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
                                          SpvStorageClassOutput);
    if (var->name)
@@ -264,19 +271,34 @@ emit_output(struct ntv_context *ctx, struct nir_variable *var)
             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;
+
          default:
-            unreachable("unknown varying slot");
+            debug_printf("unknown varying slot: %s\n", gl_varying_slot_name(var->data.location));
+            unreachable("unexpected varying slot");
          }
       }
    } else if (ctx->stage == MESA_SHADER_FRAGMENT) {
-      switch (var->data.location) {
-      case FRAG_RESULT_DEPTH:
-         spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInFragDepth);
-         break;
-
-      default:
+      if (var->data.location >= FRAG_RESULT_DATA0)
          spirv_builder_emit_location(&ctx->builder, var_id,
-                                     var->data.driver_location);
+                                     var->data.location - FRAG_RESULT_DATA0);
+      else {
+         switch (var->data.location) {
+         case FRAG_RESULT_COLOR:
+            spirv_builder_emit_location(&ctx->builder, var_id, 0);
+            break;
+
+         case FRAG_RESULT_DEPTH:
+            spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInFragDepth);
+            break;
+
+         default:
+            spirv_builder_emit_location(&ctx->builder, var_id,
+                                        var->data.driver_location);
+         }
       }
    }
 
@@ -284,11 +306,7 @@ emit_output(struct ntv_context *ctx, struct nir_variable *var)
       spirv_builder_emit_component(&ctx->builder, var_id,
                                    var->data.location_frac);
 
-   assert(var->data.driver_location < PIPE_MAX_SHADER_INPUTS);
-   assert(var->data.location_frac < 4);
-   assert(ctx->outputs[var->data.driver_location][var->data.location_frac] == 0);
-   ctx->outputs[var->data.driver_location][var->data.location_frac] = var_id;
-   ctx->output_types[var->data.driver_location][var->data.location_frac] = vec_type;
+   _mesa_hash_table_insert(ctx->vars, var, (void *)(intptr_t)var_id);
 
    assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
    ctx->entry_ifaces[ctx->num_entry_ifaces++] = var_id;
@@ -391,10 +409,13 @@ emit_ubo(struct ntv_context *ctx, struct nir_variable *var)
 static void
 emit_uniform(struct ntv_context *ctx, struct nir_variable *var)
 {
-   if (glsl_type_is_sampler(var->type))
-      emit_sampler(ctx, var);
-   else if (var->interface_type)
+   if (var->data.mode == nir_var_mem_ubo)
       emit_ubo(ctx, var);
+   else {
+      assert(var->data.mode == nir_var_uniform);
+      if (glsl_type_is_sampler(var->type))
+         emit_sampler(ctx, var);
+   }
 }
 
 static SpvId
@@ -408,9 +429,9 @@ get_src_uint_ssa(struct ntv_context *ctx, const nir_ssa_def *ssa)
 static SpvId
 get_var_from_reg(struct ntv_context *ctx, nir_register *reg)
 {
-   assert(reg->index < ctx->num_vars);
-   assert(ctx->vars[reg->index] != 0);
-   return ctx->vars[reg->index];
+   assert(reg->index < ctx->num_regs);
+   assert(ctx->regs[reg->index] != 0);
+   return ctx->regs[reg->index];
 }
 
 static SpvId
@@ -463,6 +484,7 @@ get_alu_src_uint(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
       return def;
 
    int bit_size = nir_src_bit_size(alu->src[src].src);
+   assert(bit_size == 32);
 
    SpvId uint_type = spirv_builder_type_uint(&ctx->builder, bit_size);
    if (used_channels == 1) {
@@ -773,16 +795,22 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
       result = emit_unop(ctx, spirv_op, dest_type, src[0]); \
       break;
 
+   UNOP(nir_op_ineg, SpvOpSNegate)
+   UNOP(nir_op_fneg, SpvOpFNegate)
+   UNOP(nir_op_fddx, SpvOpDPdx)
+   UNOP(nir_op_fddy, SpvOpDPdy)
+   UNOP(nir_op_f2i32, SpvOpConvertFToS)
+   UNOP(nir_op_f2u32, SpvOpConvertFToU)
+   UNOP(nir_op_i2f32, SpvOpConvertSToF)
+   UNOP(nir_op_u2f32, SpvOpConvertUToF)
+#undef UNOP
+
 #define BUILTIN_UNOP(nir_op, spirv_op) \
    case nir_op: \
       assert(nir_op_infos[alu->op].num_inputs == 1); \
       result = emit_builtin_unop(ctx, spirv_op, dest_type, src[0]); \
       break;
 
-   UNOP(nir_op_fneg, SpvOpFNegate)
-   UNOP(nir_op_fddx, SpvOpDPdx)
-   UNOP(nir_op_fddy, SpvOpDPdy)
-
    BUILTIN_UNOP(nir_op_fabs, GLSLstd450FAbs)
    BUILTIN_UNOP(nir_op_fsqrt, GLSLstd450Sqrt)
    BUILTIN_UNOP(nir_op_frsq, GLSLstd450InverseSqrt)
@@ -796,6 +824,7 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
    BUILTIN_UNOP(nir_op_fsign, GLSLstd450FSign)
    BUILTIN_UNOP(nir_op_fsin, GLSLstd450Sin)
    BUILTIN_UNOP(nir_op_fcos, GLSLstd450Cos)
+#undef BUILTIN_UNOP
 
    case nir_op_frcp: {
       assert(nir_op_infos[alu->op].num_inputs == 1);
@@ -806,8 +835,14 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
       }
       break;
 
-#undef UNOP
-#undef BUILTIN_UNOP
+   case nir_op_f2b1: {
+      assert(nir_op_infos[alu->op].num_inputs == 1);
+      float values[NIR_MAX_VEC_COMPONENTS] = { 0 };
+      SpvId zero = get_fvec_constant(ctx, nir_src_bit_size(alu->src[0].src),
+                                     num_components, values);
+      result = emit_binop(ctx, SpvOpFOrdNotEqual, dest_type, src[0], zero);
+      } break;
+
 
 #define BINOP(nir_op, spirv_op) \
    case nir_op: \
@@ -815,26 +850,37 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
       result = emit_binop(ctx, spirv_op, dest_type, src[0], src[1]); \
       break;
 
-#define BUILTIN_BINOP(nir_op, spirv_op) \
-   case nir_op: \
-      assert(nir_op_infos[alu->op].num_inputs == 2); \
-      result = emit_builtin_binop(ctx, spirv_op, dest_type, src[0], src[1]); \
-      break;
-
    BINOP(nir_op_iadd, SpvOpIAdd)
    BINOP(nir_op_isub, SpvOpISub)
    BINOP(nir_op_imul, SpvOpIMul)
+   BINOP(nir_op_idiv, SpvOpSDiv)
+   BINOP(nir_op_udiv, SpvOpUDiv)
    BINOP(nir_op_fadd, SpvOpFAdd)
    BINOP(nir_op_fsub, SpvOpFSub)
    BINOP(nir_op_fmul, SpvOpFMul)
+   BINOP(nir_op_fdiv, SpvOpFDiv)
    BINOP(nir_op_fmod, SpvOpFMod)
-   BINOP(nir_op_flt, SpvOpFUnordLessThan)
-   BINOP(nir_op_fge, SpvOpFUnordGreaterThanEqual)
+   BINOP(nir_op_ilt, SpvOpSLessThan)
+   BINOP(nir_op_ige, SpvOpSGreaterThanEqual)
+   BINOP(nir_op_ieq, SpvOpIEqual)
+   BINOP(nir_op_ine, SpvOpINotEqual)
+   BINOP(nir_op_flt, SpvOpFOrdLessThan)
+   BINOP(nir_op_fge, SpvOpFOrdGreaterThanEqual)
+   BINOP(nir_op_feq, SpvOpFOrdEqual)
+   BINOP(nir_op_fne, SpvOpFOrdNotEqual)
+   BINOP(nir_op_ishl, SpvOpShiftLeftLogical)
+   BINOP(nir_op_ishr, SpvOpShiftRightArithmetic)
+   BINOP(nir_op_ushr, SpvOpShiftRightLogical)
+#undef BINOP
+
+#define BUILTIN_BINOP(nir_op, spirv_op) \
+   case nir_op: \
+      assert(nir_op_infos[alu->op].num_inputs == 2); \
+      result = emit_builtin_binop(ctx, spirv_op, dest_type, src[0], src[1]); \
+      break;
 
    BUILTIN_BINOP(nir_op_fmin, GLSLstd450FMin)
    BUILTIN_BINOP(nir_op_fmax, GLSLstd450FMax)
-
-#undef BINOP
 #undef BUILTIN_BINOP
 
    case nir_op_fdot2:
@@ -895,6 +941,11 @@ emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
       }
       break;
 
+   case nir_op_bcsel:
+      assert(nir_op_infos[alu->op].num_inputs == 3);
+      result = emit_triop(ctx, SpvOpSelect, dest_type, src[0], src[1], src[2]);
+      break;
+
    case nir_op_vec2:
    case nir_op_vec3:
    case nir_op_vec4: {
@@ -929,31 +980,6 @@ emit_load_const(struct ntv_context *ctx, nir_load_const_instr *load_const)
    store_ssa_def_uint(ctx, &load_const->def, constant);
 }
 
-static void
-emit_load_input(struct ntv_context *ctx, nir_intrinsic_instr *intr)
-{
-   nir_const_value *const_offset = nir_src_as_const_value(intr->src[0]);
-   if (const_offset) {
-      int driver_location = (int)nir_intrinsic_base(intr) + const_offset->u32;
-      assert(driver_location < PIPE_MAX_SHADER_INPUTS);
-      int location_frac = nir_intrinsic_component(intr);
-      assert(location_frac < 4);
-
-      SpvId ptr = ctx->inputs[driver_location][location_frac];
-      SpvId type = ctx->input_types[driver_location][location_frac];
-      assert(ptr && type);
-
-      SpvId result = spirv_builder_emit_load(&ctx->builder, type, ptr);
-
-      unsigned num_components = nir_dest_num_components(intr->dest);
-      unsigned bit_size = nir_dest_bit_size(intr->dest);
-      result = bitcast_to_uvec(ctx, result, bit_size, num_components);
-
-      store_dest_uint(ctx, &intr->dest, result);
-   } else
-      unreachable("input-addressing not yet supported");
-}
-
 static void
 emit_load_ubo(struct ntv_context *ctx, nir_intrinsic_instr *intr)
 {
@@ -1005,27 +1031,6 @@ emit_load_ubo(struct ntv_context *ctx, nir_intrinsic_instr *intr)
       unreachable("uniform-addressing not yet supported");
 }
 
-static void
-emit_store_output(struct ntv_context *ctx, nir_intrinsic_instr *intr)
-{
-   nir_const_value *const_offset = nir_src_as_const_value(intr->src[1]);
-   if (const_offset) {
-      int driver_location = (int)nir_intrinsic_base(intr) + const_offset->u32;
-      assert(driver_location < PIPE_MAX_SHADER_OUTPUTS);
-      int location_frac = nir_intrinsic_component(intr);
-      assert(location_frac < 4);
-
-      SpvId ptr = ctx->outputs[driver_location][location_frac];
-      assert(ptr > 0);
-
-      SpvId src = get_src_uint(ctx, &intr->src[0]);
-      SpvId spirv_type = ctx->output_types[driver_location][location_frac];
-      SpvId result = emit_unop(ctx, SpvOpBitcast, spirv_type, src);
-      spirv_builder_emit_store(&ctx->builder, ptr, result);
-   } else
-      unreachable("output-addressing not yet supported");
-}
-
 static void
 emit_discard(struct ntv_context *ctx, nir_intrinsic_instr *intr)
 {
@@ -1036,26 +1041,56 @@ emit_discard(struct ntv_context *ctx, nir_intrinsic_instr *intr)
    spirv_builder_label(&ctx->builder, spirv_builder_new_id(&ctx->builder));
 }
 
+static void
+emit_load_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
+{
+   /* uint is a bit of a lie here; it's really just a pointer */
+   SpvId ptr = get_src_uint(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),
+                                          ptr);
+   unsigned num_components = nir_dest_num_components(intr->dest);
+   unsigned bit_size = nir_dest_bit_size(intr->dest);
+   result = bitcast_to_uvec(ctx, result, bit_size, num_components);
+   store_dest_uint(ctx, &intr->dest, result);
+}
+
+static void
+emit_store_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
+{
+   /* uint is a bit of a lie here; it's really just a pointer */
+   SpvId ptr = get_src_uint(ctx, &intr->src[0]);
+   SpvId src = get_src_uint(ctx, &intr->src[1]);
+
+   nir_variable *var = nir_intrinsic_get_var(intr, 0);
+   SpvId result = emit_unop(ctx, SpvOpBitcast,
+                            get_glsl_type(ctx, glsl_without_array(var->type)),
+                            src);
+   spirv_builder_emit_store(&ctx->builder, ptr, result);
+}
+
 static void
 emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr)
 {
    switch (intr->intrinsic) {
-   case nir_intrinsic_load_input:
-      emit_load_input(ctx, intr);
-      break;
-
    case nir_intrinsic_load_ubo:
       emit_load_ubo(ctx, intr);
       break;
 
-   case nir_intrinsic_store_output:
-      emit_store_output(ctx, intr);
-      break;
-
    case nir_intrinsic_discard:
       emit_discard(ctx, intr);
       break;
 
+   case nir_intrinsic_load_deref:
+      emit_load_deref(ctx, intr);
+      break;
+
+   case nir_intrinsic_store_deref:
+      emit_store_deref(ctx, intr);
+      break;
+
    default:
       fprintf(stderr, "emit_intrinsic: not implemented (%s)\n",
               nir_intrinsic_infos[intr->intrinsic].name);
@@ -1085,12 +1120,13 @@ get_src_float(struct ntv_context *ctx, nir_src *src)
 static void
 emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
 {
-   assert(tex->op == nir_texop_tex);
+   assert(tex->op == nir_texop_tex ||
+          tex->op == nir_texop_txb ||
+          tex->op == nir_texop_txl);
    assert(nir_alu_type_get_base_type(tex->dest_type) == nir_type_float);
    assert(tex->texture_index == tex->sampler_index);
 
-   bool has_proj = false, has_lod = false;
-   SpvId coord = 0, proj, lod;
+   SpvId coord = 0, proj = 0, bias = 0, lod = 0, dref = 0;
    unsigned coord_components;
    for (unsigned i = 0; i < tex->num_srcs; i++) {
       switch (tex->src[i].src_type) {
@@ -1100,15 +1136,27 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
          break;
 
       case nir_tex_src_projector:
-         has_proj = true;
-         proj = get_src_float(ctx, &tex->src[i].src);
          assert(nir_src_num_components(tex->src[i].src) == 1);
+         proj = get_src_float(ctx, &tex->src[i].src);
+         assert(proj != 0);
+         break;
+
+      case nir_tex_src_bias:
+         assert(tex->op == nir_texop_txb);
+         bias = get_src_float(ctx, &tex->src[i].src);
+         assert(bias != 0);
          break;
 
       case nir_tex_src_lod:
-         has_lod = true;
+         assert(nir_src_num_components(tex->src[i].src) == 1);
          lod = get_src_float(ctx, &tex->src[i].src);
+         assert(lod != 0);
+         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);
+         assert(dref != 0);
          break;
 
       default:
@@ -1117,9 +1165,9 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
       }
    }
 
-   if (!has_lod && ctx->stage != MESA_SHADER_FRAGMENT) {
-      has_lod = true;
+   if (lod == 0 && ctx->stage != MESA_SHADER_FRAGMENT) {
       lod = spirv_builder_const_float(&ctx->builder, 32, 0);
+      assert(lod != 0);
    }
 
    bool is_ms;
@@ -1137,50 +1185,49 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
 
    SpvId dest_type = get_dest_type(ctx, &tex->dest, tex->dest_type);
 
-   SpvId result;
-   if (has_proj) {
+   if (proj) {
       SpvId constituents[coord_components + 1];
-      SpvId float_type = spirv_builder_type_float(&ctx->builder, 32);
-      for (uint32_t i = 0; i < coord_components; ++i)
-         constituents[i] = spirv_builder_emit_composite_extract(&ctx->builder,
-                                              float_type,
-                                              coord,
-                                              &i, 1);
+      if (coord_components == 1)
+         constituents[0] = coord;
+      else {
+         assert(coord_components > 1);
+         SpvId float_type = spirv_builder_type_float(&ctx->builder, 32);
+         for (uint32_t i = 0; i < coord_components; ++i)
+            constituents[i] = spirv_builder_emit_composite_extract(&ctx->builder,
+                                                 float_type,
+                                                 coord,
+                                                 &i, 1);
+      }
 
       constituents[coord_components++] = proj;
 
       SpvId vec_type = get_fvec_type(ctx, 32, coord_components);
-      SpvId merged = spirv_builder_emit_composite_construct(&ctx->builder,
+      coord = spirv_builder_emit_composite_construct(&ctx->builder,
                                                             vec_type,
                                                             constituents,
                                                             coord_components);
-
-      if (has_lod)
-         result = spirv_builder_emit_image_sample_proj_explicit_lod(&ctx->builder,
-                                                                    dest_type,
-                                                                    load,
-                                                                    merged,
-                                                                    lod);
-      else
-         result = spirv_builder_emit_image_sample_proj_implicit_lod(&ctx->builder,
-                                                                    dest_type,
-                                                                    load,
-                                                                    merged);
-   } else {
-      if (has_lod)
-         result = spirv_builder_emit_image_sample_explicit_lod(&ctx->builder,
-                                                               dest_type,
-                                                               load,
-                                                               coord, lod);
-      else
-         result = spirv_builder_emit_image_sample_implicit_lod(&ctx->builder,
-                                                               dest_type,
-                                                               load,
-                                                               coord);
    }
+
+   SpvId actual_dest_type = dest_type;
+   if (dref)
+      actual_dest_type = float_type;
+
+   SpvId result = spirv_builder_emit_image_sample(&ctx->builder,
+                                                  actual_dest_type, load,
+                                                  coord,
+                                                  proj != 0,
+                                                  lod, bias, dref);
    spirv_builder_emit_decoration(&ctx->builder, result,
                                  SpvDecorationRelaxedPrecision);
 
+   if (dref) {
+      SpvId components[4] = { result, result, result, result };
+      result = spirv_builder_emit_composite_construct(&ctx->builder,
+                                                      dest_type,
+                                                      components,
+                                                      4);
+   }
+
    store_dest(ctx, &tex->dest, result, tex->dest_type);
 }
 
@@ -1233,6 +1280,69 @@ emit_jump(struct ntv_context *ctx, nir_jump_instr *jump)
    }
 }
 
+static void
+emit_deref_var(struct ntv_context *ctx, nir_deref_instr *deref)
+{
+   assert(deref->deref_type == nir_deref_type_var);
+
+   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_uint(ctx, &deref->dest, result);
+}
+
+static void
+emit_deref_array(struct ntv_context *ctx, nir_deref_instr *deref)
+{
+   assert(deref->deref_type == nir_deref_type_array);
+   nir_variable *var = nir_deref_instr_get_variable(deref);
+
+   SpvStorageClass storage_class;
+   switch (var->data.mode) {
+   case nir_var_shader_in:
+      storage_class = SpvStorageClassInput;
+      break;
+
+   case nir_var_shader_out:
+      storage_class = SpvStorageClassOutput;
+      break;
+
+   default:
+      unreachable("Unsupported nir_variable_mode\n");
+   }
+
+   SpvId index = get_src_uint(ctx, &deref->arr.index);
+
+   SpvId ptr_type = spirv_builder_type_pointer(&ctx->builder,
+                                               storage_class,
+                                               get_glsl_type(ctx, deref->type));
+
+   SpvId result = spirv_builder_emit_access_chain(&ctx->builder,
+                                                  ptr_type,
+                                                  get_src_uint(ctx, &deref->parent),
+                                                  &index, 1);
+   /* uint is a bit of a lie here, it's really just an opaque type */
+   store_dest_uint(ctx, &deref->dest, result);
+}
+
+static void
+emit_deref(struct ntv_context *ctx, nir_deref_instr *deref)
+{
+   switch (deref->deref_type) {
+   case nir_deref_type_var:
+      emit_deref_var(ctx, deref);
+      break;
+
+   case nir_deref_type_array:
+      emit_deref_array(ctx, deref);
+      break;
+
+   default:
+      unreachable("unexpected deref_type");
+   }
+}
+
 static void
 emit_block(struct ntv_context *ctx, struct nir_block *block)
 {
@@ -1267,7 +1377,7 @@ emit_block(struct ntv_context *ctx, struct nir_block *block)
          unreachable("nir_instr_type_parallel_copy not supported");
          break;
       case nir_instr_type_deref:
-         unreachable("nir_instr_type_deref not supported");
+         emit_deref(ctx, nir_instr_as_deref(instr));
          break;
       }
    }
@@ -1400,6 +1510,10 @@ nir_to_spirv(struct nir_shader *s)
       unreachable("invalid stage");
    }
 
+   // TODO: only enable when needed
+   if (s->info.stage == MESA_SHADER_FRAGMENT)
+      spirv_builder_emit_cap(&ctx.builder, SpvCapabilitySampled1D);
+
    ctx.stage = s->info.stage;
    ctx.GLSL_std_450 = spirv_builder_import(&ctx.builder, "GLSL.std.450");
    spirv_builder_emit_source(&ctx.builder, SpvSourceLanguageGLSL, 450);
@@ -1437,6 +1551,9 @@ 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,
+                                      _mesa_key_pointer_equal);
+
    nir_foreach_variable(var, &s->inputs)
       emit_input(&ctx, var);
 
@@ -1449,9 +1566,13 @@ nir_to_spirv(struct nir_shader *s)
    spirv_builder_emit_entry_point(&ctx.builder, exec_model, entry_point,
                                   "main", ctx.entry_ifaces,
                                   ctx.num_entry_ifaces);
-   if (s->info.stage == MESA_SHADER_FRAGMENT)
+   if (s->info.stage == MESA_SHADER_FRAGMENT) {
       spirv_builder_emit_exec_mode(&ctx.builder, entry_point,
                                    SpvExecutionModeOriginUpperLeft);
+      if (s->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH))
+         spirv_builder_emit_exec_mode(&ctx.builder, entry_point,
+                                      SpvExecutionModeDepthReplacing);
+   }
 
 
    spirv_builder_function(&ctx.builder, entry_point, type_void,
@@ -1467,10 +1588,10 @@ nir_to_spirv(struct nir_shader *s)
    ctx.num_defs = entry->ssa_alloc;
 
    nir_index_local_regs(entry);
-   ctx.vars = malloc(sizeof(SpvId) * entry->reg_alloc);
-   if (!ctx.vars)
+   ctx.regs = malloc(sizeof(SpvId) * entry->reg_alloc);
+   if (!ctx.regs)
       goto fail;
-   ctx.num_vars = entry->reg_alloc;
+   ctx.num_regs = entry->reg_alloc;
 
    SpvId *block_ids = (SpvId *)malloc(sizeof(SpvId) * entry->num_blocks);
    if (!block_ids)
@@ -1492,7 +1613,7 @@ nir_to_spirv(struct nir_shader *s)
       SpvId var = spirv_builder_emit_var(&ctx.builder, pointer_type,
                                          SpvStorageClassFunction);
 
-      ctx.vars[reg->index] = var;
+      ctx.regs[reg->index] = var;
    }
 
    emit_cf_list(&ctx, &entry->body);
@@ -1522,6 +1643,9 @@ fail:
    if (ret)
       spirv_shader_delete(ret);
 
+   if (ctx.vars)
+      _mesa_hash_table_destroy(ctx.vars, NULL);
+
    return NULL;
 }