mesa/st: Fix NULL access if no fragment shader is bound
[mesa.git] / src / mesa / state_tracker / st_glsl_to_tgsi.cpp
index b8182de0be8b6bae7636d13457c7c6d121d675db..06b4bb41a9b1075ba7767847d55d474b129f08d8 100644 (file)
 
 #include "compiler/glsl/glsl_parser_extras.h"
 #include "compiler/glsl/ir_optimization.h"
+#include "compiler/glsl/program.h"
 
 #include "main/errors.h"
 #include "main/shaderobj.h"
 #include "main/uniforms.h"
 #include "main/shaderapi.h"
+#include "main/shaderimage.h"
 #include "program/prog_instruction.h"
-#include "program/sampler.h"
 
 #include "pipe/p_context.h"
 #include "pipe/p_screen.h"
@@ -50,6 +51,7 @@
 #include "util/u_memory.h"
 #include "st_program.h"
 #include "st_mesa_to_tgsi.h"
+#include "st_format.h"
 
 
 #define PROGRAM_ANY_CONST ((1 << PROGRAM_STATE_VAR) |    \
@@ -164,7 +166,6 @@ public:
       this->index = index;
       this->index2D = 0;
       this->writemask = writemask;
-      this->cond_mask = COND_TR;
       this->reladdr = NULL;
       this->reladdr2 = NULL;
       this->has_index2 = false;
@@ -178,7 +179,6 @@ public:
       this->index = 0;
       this->index2D = 0;
       this->writemask = writemask;
-      this->cond_mask = COND_TR;
       this->reladdr = NULL;
       this->reladdr2 = NULL;
       this->has_index2 = false;
@@ -193,7 +193,6 @@ public:
       this->index = 0;
       this->index2D = 0;
       this->writemask = 0;
-      this->cond_mask = COND_TR;
       this->reladdr = NULL;
       this->reladdr2 = NULL;
       this->has_index2 = false;
@@ -206,7 +205,6 @@ public:
    int index; /**< temporary index, VERT_ATTRIB_*, VARYING_SLOT_*, etc. */
    int index2D;
    int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
-   GLuint cond_mask:4;
    int type; /** GLSL_TYPE_* from GLSL IR (enum glsl_base_type) */
    /** Register index should be offset by the integer in this reg. */
    st_src_reg *reladdr;
@@ -237,7 +235,6 @@ st_dst_reg::st_dst_reg(st_src_reg reg)
    this->file = reg.file;
    this->index = reg.index;
    this->writemask = WRITEMASK_XYZW;
-   this->cond_mask = COND_TR;
    this->reladdr = reg.reladdr;
    this->index2D = reg.index2D;
    this->reladdr2 = reg.reladdr2;
@@ -257,10 +254,12 @@ public:
    GLboolean cond_update;
    bool saturate;
    st_src_reg sampler; /**< sampler register */
+   int sampler_base;
    int sampler_array_size; /**< 1-based size of sampler array, 1 if not array */
    int tex_target; /**< One of TEXTURE_*_INDEX */
    glsl_base_type tex_type;
    GLboolean tex_shadow;
+   unsigned image_format;
 
    st_src_reg tex_offsets[MAX_GLSL_TEXTURE_OFFSET];
    unsigned tex_offset_num_offset;
@@ -394,6 +393,9 @@ public:
    glsl_base_type sampler_types[PIPE_MAX_SAMPLERS];
    int sampler_targets[PIPE_MAX_SAMPLERS];   /**< One of TGSI_TEXTURE_* */
    int buffers_used;
+   int images_used;
+   int image_targets[PIPE_MAX_SHADER_IMAGES];
+   unsigned image_formats[PIPE_MAX_SHADER_IMAGES];
    bool indirect_addr_consts;
    int wpos_transform_const;
 
@@ -401,6 +403,7 @@ public:
    bool native_integers;
    bool have_sqrt;
    bool have_fma;
+   bool use_shared_memory;
 
    variable_storage *find_variable_storage(ir_variable *var);
 
@@ -450,6 +453,8 @@ public:
    void visit_atomic_counter_intrinsic(ir_call *);
    void visit_ssbo_intrinsic(ir_call *);
    void visit_membar_intrinsic(ir_call *);
+   void visit_shared_intrinsic(ir_call *);
+   void visit_image_intrinsic(ir_call *);
 
    st_src_reg result;
 
@@ -502,6 +507,19 @@ public:
 
    void emit_arl(ir_instruction *ir, st_dst_reg dst, st_src_reg src0);
 
+   void get_deref_offsets(ir_dereference *ir,
+                          unsigned *array_size,
+                          unsigned *base,
+                          unsigned *index,
+                          st_src_reg *reladdr);
+  void calc_deref_offsets(ir_dereference *head,
+                          ir_dereference *tail,
+                          unsigned *array_elements,
+                          unsigned *base,
+                          unsigned *index,
+                          st_src_reg *indirect,
+                          unsigned *location);
+
    bool try_emit_mad(ir_expression *ir,
               int mul_operand);
    bool try_emit_mad_for_and_not(ir_expression *ir,
@@ -1200,6 +1218,7 @@ attrib_type_size(const struct glsl_type *type, bool is_vs_input)
    case GLSL_TYPE_INTERFACE:
    case GLSL_TYPE_VOID:
    case GLSL_TYPE_ERROR:
+   case GLSL_TYPE_FUNCTION:
       assert(!"Invalid type in type_size");
       break;
    }
@@ -1955,6 +1974,7 @@ glsl_to_tgsi_visitor::visit(ir_expression *ir)
    case ir_unop_u2i:
       /* Converting between signed and unsigned integers is a no-op. */
       result_src = op[0];
+      result_src.type = result_dst.type;
       break;
    case ir_unop_b2i:
       if (native_integers) {
@@ -2350,7 +2370,7 @@ glsl_to_tgsi_visitor::visit(ir_dereference_variable *ir)
       switch (var->data.mode) {
       case ir_var_uniform:
          entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM,
-                                               var->data.location);
+                                               var->data.param_index);
          this->variables.push_tail(entry);
          break;
       case ir_var_shader_in:
@@ -3138,8 +3158,8 @@ void
 glsl_to_tgsi_visitor::visit_atomic_counter_intrinsic(ir_call *ir)
 {
    const char *callee = ir->callee->function_name();
-   ir_dereference *deref = static_cast<ir_dereference *>(
-      ir->actual_parameters.get_head());
+   exec_node *param = ir->actual_parameters.get_head();
+   ir_dereference *deref = static_cast<ir_dereference *>(param);
    ir_variable *location = deref->variable_referenced();
 
    st_src_reg buffer(
@@ -3147,19 +3167,17 @@ glsl_to_tgsi_visitor::visit_atomic_counter_intrinsic(ir_call *ir)
 
    /* Calculate the surface offset */
    st_src_reg offset;
-   ir_dereference_array *deref_array = deref->as_dereference_array();
-
-   if (deref_array) {
-      offset = get_temp(glsl_type::uint_type);
+   unsigned array_size = 0, base = 0, index = 0;
 
-      deref_array->array_index->accept(this);
+   get_deref_offsets(deref, &array_size, &base, &index, &offset);
 
+   if (offset.file != PROGRAM_UNDEFINED) {
       emit_asm(ir, TGSI_OPCODE_MUL, st_dst_reg(offset),
-               this->result, st_src_reg_for_int(ATOMIC_COUNTER_SIZE));
+               offset, st_src_reg_for_int(ATOMIC_COUNTER_SIZE));
       emit_asm(ir, TGSI_OPCODE_ADD, st_dst_reg(offset),
-               offset, st_src_reg_for_int(location->data.offset));
+               offset, st_src_reg_for_int(location->data.offset + index * ATOMIC_COUNTER_SIZE));
    } else {
-      offset = st_src_reg_for_int(location->data.offset);
+      offset = st_src_reg_for_int(location->data.offset + index * ATOMIC_COUNTER_SIZE);
    }
 
    ir->return_deref->accept(this);
@@ -3170,17 +3188,56 @@ glsl_to_tgsi_visitor::visit_atomic_counter_intrinsic(ir_call *ir)
 
    if (!strcmp("__intrinsic_atomic_read", callee)) {
       inst = emit_asm(ir, TGSI_OPCODE_LOAD, dst, offset);
-      inst->buffer = buffer;
    } else if (!strcmp("__intrinsic_atomic_increment", callee)) {
       inst = emit_asm(ir, TGSI_OPCODE_ATOMUADD, dst, offset,
                       st_src_reg_for_int(1));
-      inst->buffer = buffer;
    } else if (!strcmp("__intrinsic_atomic_predecrement", callee)) {
       inst = emit_asm(ir, TGSI_OPCODE_ATOMUADD, dst, offset,
                       st_src_reg_for_int(-1));
-      inst->buffer = buffer;
       emit_asm(ir, TGSI_OPCODE_ADD, dst, this->result, st_src_reg_for_int(-1));
+   } else {
+      param = param->get_next();
+      ir_rvalue *val = ((ir_instruction *)param)->as_rvalue();
+      val->accept(this);
+
+      st_src_reg data = this->result, data2 = undef_src;
+      unsigned opcode;
+      if (!strcmp("__intrinsic_atomic_add", callee))
+         opcode = TGSI_OPCODE_ATOMUADD;
+      else if (!strcmp("__intrinsic_atomic_min", callee))
+         opcode = TGSI_OPCODE_ATOMIMIN;
+      else if (!strcmp("__intrinsic_atomic_max", callee))
+         opcode = TGSI_OPCODE_ATOMIMAX;
+      else if (!strcmp("__intrinsic_atomic_and", callee))
+         opcode = TGSI_OPCODE_ATOMAND;
+      else if (!strcmp("__intrinsic_atomic_or", callee))
+         opcode = TGSI_OPCODE_ATOMOR;
+      else if (!strcmp("__intrinsic_atomic_xor", callee))
+         opcode = TGSI_OPCODE_ATOMXOR;
+      else if (!strcmp("__intrinsic_atomic_exchange", callee))
+         opcode = TGSI_OPCODE_ATOMXCHG;
+      else if (!strcmp("__intrinsic_atomic_comp_swap", callee)) {
+         opcode = TGSI_OPCODE_ATOMCAS;
+         param = param->get_next();
+         val = ((ir_instruction *)param)->as_rvalue();
+         val->accept(this);
+         data2 = this->result;
+      } else if (!strcmp("__intrinsic_atomic_sub", callee)) {
+         opcode = TGSI_OPCODE_ATOMUADD;
+         st_src_reg res = get_temp(glsl_type::uvec4_type);
+         st_dst_reg dstres = st_dst_reg(res);
+         dstres.writemask = dst.writemask;
+         emit_asm(ir, TGSI_OPCODE_INEG, dstres, data);
+         data = res;
+      } else {
+         assert(!"Unexpected intrinsic");
+         return;
+      }
+
+      inst = emit_asm(ir, opcode, dst, offset, data, data2);
    }
+
+   inst->buffer = buffer;
 }
 
 void
@@ -3328,6 +3385,246 @@ glsl_to_tgsi_visitor::visit_membar_intrinsic(ir_call *ir)
       assert(!"Unexpected memory barrier intrinsic");
 }
 
+void
+glsl_to_tgsi_visitor::visit_shared_intrinsic(ir_call *ir)
+{
+   const char *callee = ir->callee->function_name();
+   exec_node *param = ir->actual_parameters.get_head();
+
+   ir_rvalue *offset = ((ir_instruction *)param)->as_rvalue();
+
+   st_src_reg buffer(PROGRAM_MEMORY, 0, GLSL_TYPE_UINT);
+
+   /* Calculate the surface offset */
+   offset->accept(this);
+   st_src_reg off = this->result;
+
+   st_dst_reg dst = undef_dst;
+   if (ir->return_deref) {
+      ir->return_deref->accept(this);
+      dst = st_dst_reg(this->result);
+      dst.writemask = (1 << ir->return_deref->type->vector_elements) - 1;
+   }
+
+   glsl_to_tgsi_instruction *inst;
+
+   if (!strcmp("__intrinsic_load_shared", callee)) {
+      inst = emit_asm(ir, TGSI_OPCODE_LOAD, dst, off);
+      inst->buffer = buffer;
+   } else if (!strcmp("__intrinsic_store_shared", callee)) {
+      param = param->get_next();
+      ir_rvalue *val = ((ir_instruction *)param)->as_rvalue();
+      val->accept(this);
+
+      param = param->get_next();
+      ir_constant *write_mask = ((ir_instruction *)param)->as_constant();
+      assert(write_mask);
+      dst.writemask = write_mask->value.u[0];
+
+      dst.type = this->result.type;
+      inst = emit_asm(ir, TGSI_OPCODE_STORE, dst, off, this->result);
+      inst->buffer = buffer;
+   } else {
+      param = param->get_next();
+      ir_rvalue *val = ((ir_instruction *)param)->as_rvalue();
+      val->accept(this);
+
+      st_src_reg data = this->result, data2 = undef_src;
+      unsigned opcode;
+      if (!strcmp("__intrinsic_atomic_add_shared", callee))
+         opcode = TGSI_OPCODE_ATOMUADD;
+      else if (!strcmp("__intrinsic_atomic_min_shared", callee))
+         opcode = TGSI_OPCODE_ATOMIMIN;
+      else if (!strcmp("__intrinsic_atomic_max_shared", callee))
+         opcode = TGSI_OPCODE_ATOMIMAX;
+      else if (!strcmp("__intrinsic_atomic_and_shared", callee))
+         opcode = TGSI_OPCODE_ATOMAND;
+      else if (!strcmp("__intrinsic_atomic_or_shared", callee))
+         opcode = TGSI_OPCODE_ATOMOR;
+      else if (!strcmp("__intrinsic_atomic_xor_shared", callee))
+         opcode = TGSI_OPCODE_ATOMXOR;
+      else if (!strcmp("__intrinsic_atomic_exchange_shared", callee))
+         opcode = TGSI_OPCODE_ATOMXCHG;
+      else if (!strcmp("__intrinsic_atomic_comp_swap_shared", callee)) {
+         opcode = TGSI_OPCODE_ATOMCAS;
+         param = param->get_next();
+         val = ((ir_instruction *)param)->as_rvalue();
+         val->accept(this);
+         data2 = this->result;
+      } else {
+         assert(!"Unexpected intrinsic");
+         return;
+      }
+
+      inst = emit_asm(ir, opcode, dst, off, data, data2);
+      inst->buffer = buffer;
+   }
+}
+
+void
+glsl_to_tgsi_visitor::visit_image_intrinsic(ir_call *ir)
+{
+   const char *callee = ir->callee->function_name();
+   exec_node *param = ir->actual_parameters.get_head();
+
+   ir_dereference *img = (ir_dereference *)param;
+   const ir_variable *imgvar = img->variable_referenced();
+   const glsl_type *type = imgvar->type->without_array();
+   unsigned sampler_array_size = 1, sampler_base = 0;
+
+   st_src_reg reladdr;
+   st_src_reg image(PROGRAM_IMAGE, 0, GLSL_TYPE_UINT);
+
+   get_deref_offsets(img, &sampler_array_size, &sampler_base,
+                     (unsigned int *)&image.index, &reladdr);
+   if (reladdr.file != PROGRAM_UNDEFINED) {
+      emit_arl(ir, sampler_reladdr, reladdr);
+      image.reladdr = ralloc(mem_ctx, st_src_reg);
+      memcpy(image.reladdr, &sampler_reladdr, sizeof(reladdr));
+   }
+
+   st_dst_reg dst = undef_dst;
+   if (ir->return_deref) {
+      ir->return_deref->accept(this);
+      dst = st_dst_reg(this->result);
+      dst.writemask = (1 << ir->return_deref->type->vector_elements) - 1;
+   }
+
+   glsl_to_tgsi_instruction *inst;
+
+   if (!strcmp("__intrinsic_image_size", callee)) {
+      dst.writemask = WRITEMASK_XYZ;
+      inst = emit_asm(ir, TGSI_OPCODE_RESQ, dst);
+   } else if (!strcmp("__intrinsic_image_samples", callee)) {
+      st_src_reg res = get_temp(glsl_type::ivec4_type);
+      st_dst_reg dstres = st_dst_reg(res);
+      dstres.writemask = WRITEMASK_W;
+      emit_asm(ir, TGSI_OPCODE_RESQ, dstres);
+      res.swizzle = SWIZZLE_WWWW;
+      inst = emit_asm(ir, TGSI_OPCODE_MOV, dst, res);
+   } else {
+      st_src_reg arg1 = undef_src, arg2 = undef_src;
+      st_src_reg coord;
+      st_dst_reg coord_dst;
+      coord = get_temp(glsl_type::ivec4_type);
+      coord_dst = st_dst_reg(coord);
+      coord_dst.writemask = (1 << type->coordinate_components()) - 1;
+      param = param->get_next();
+      ((ir_dereference *)param)->accept(this);
+      emit_asm(ir, TGSI_OPCODE_MOV, coord_dst, this->result);
+      coord.swizzle = SWIZZLE_XXXX;
+      switch (type->coordinate_components()) {
+      case 4: assert(!"unexpected coord count");
+      /* fallthrough */
+      case 3: coord.swizzle |= SWIZZLE_Z << 6;
+      /* fallthrough */
+      case 2: coord.swizzle |= SWIZZLE_Y << 3;
+      }
+
+      if (type->sampler_dimensionality == GLSL_SAMPLER_DIM_MS) {
+         param = param->get_next();
+         ((ir_dereference *)param)->accept(this);
+         st_src_reg sample = this->result;
+         sample.swizzle = SWIZZLE_XXXX;
+         coord_dst.writemask = WRITEMASK_W;
+         emit_asm(ir, TGSI_OPCODE_MOV, coord_dst, sample);
+         coord.swizzle |= SWIZZLE_W << 9;
+      }
+
+      param = param->get_next();
+      if (!param->is_tail_sentinel()) {
+         ((ir_dereference *)param)->accept(this);
+         arg1 = this->result;
+         param = param->get_next();
+      }
+
+      if (!param->is_tail_sentinel()) {
+         ((ir_dereference *)param)->accept(this);
+         arg2 = this->result;
+         param = param->get_next();
+      }
+
+      assert(param->is_tail_sentinel());
+
+      unsigned opcode;
+      if (!strcmp("__intrinsic_image_load", callee))
+         opcode = TGSI_OPCODE_LOAD;
+      else if (!strcmp("__intrinsic_image_store", callee))
+         opcode = TGSI_OPCODE_STORE;
+      else if (!strcmp("__intrinsic_image_atomic_add", callee))
+         opcode = TGSI_OPCODE_ATOMUADD;
+      else if (!strcmp("__intrinsic_image_atomic_min", callee))
+         opcode = TGSI_OPCODE_ATOMIMIN;
+      else if (!strcmp("__intrinsic_image_atomic_max", callee))
+         opcode = TGSI_OPCODE_ATOMIMAX;
+      else if (!strcmp("__intrinsic_image_atomic_and", callee))
+         opcode = TGSI_OPCODE_ATOMAND;
+      else if (!strcmp("__intrinsic_image_atomic_or", callee))
+         opcode = TGSI_OPCODE_ATOMOR;
+      else if (!strcmp("__intrinsic_image_atomic_xor", callee))
+         opcode = TGSI_OPCODE_ATOMXOR;
+      else if (!strcmp("__intrinsic_image_atomic_exchange", callee))
+         opcode = TGSI_OPCODE_ATOMXCHG;
+      else if (!strcmp("__intrinsic_image_atomic_comp_swap", callee))
+         opcode = TGSI_OPCODE_ATOMCAS;
+      else {
+         assert(!"Unexpected intrinsic");
+         return;
+      }
+
+      inst = emit_asm(ir, opcode, dst, coord, arg1, arg2);
+      if (opcode == TGSI_OPCODE_STORE)
+         inst->dst[0].writemask = WRITEMASK_XYZW;
+   }
+
+   inst->buffer = image;
+   inst->sampler_array_size = sampler_array_size;
+   inst->sampler_base = sampler_base;
+
+   switch (type->sampler_dimensionality) {
+   case GLSL_SAMPLER_DIM_1D:
+      inst->tex_target = (type->sampler_array)
+         ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX;
+      break;
+   case GLSL_SAMPLER_DIM_2D:
+      inst->tex_target = (type->sampler_array)
+         ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX;
+      break;
+   case GLSL_SAMPLER_DIM_3D:
+      inst->tex_target = TEXTURE_3D_INDEX;
+      break;
+   case GLSL_SAMPLER_DIM_CUBE:
+      inst->tex_target = (type->sampler_array)
+         ? TEXTURE_CUBE_ARRAY_INDEX : TEXTURE_CUBE_INDEX;
+      break;
+   case GLSL_SAMPLER_DIM_RECT:
+      inst->tex_target = TEXTURE_RECT_INDEX;
+      break;
+   case GLSL_SAMPLER_DIM_BUF:
+      inst->tex_target = TEXTURE_BUFFER_INDEX;
+      break;
+   case GLSL_SAMPLER_DIM_EXTERNAL:
+      inst->tex_target = TEXTURE_EXTERNAL_INDEX;
+      break;
+   case GLSL_SAMPLER_DIM_MS:
+      inst->tex_target = (type->sampler_array)
+         ? TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX : TEXTURE_2D_MULTISAMPLE_INDEX;
+      break;
+   default:
+      assert(!"Should not get here.");
+   }
+
+   inst->image_format = st_mesa_format_to_pipe_format(st_context(ctx),
+         _mesa_get_shader_image_format(imgvar->data.image_format));
+
+   if (imgvar->data.image_coherent)
+      inst->buffer_access |= TGSI_MEMORY_COHERENT;
+   if (imgvar->data.image_restrict)
+      inst->buffer_access |= TGSI_MEMORY_RESTRICT;
+   if (imgvar->data.image_volatile)
+      inst->buffer_access |= TGSI_MEMORY_VOLATILE;
+}
+
 void
 glsl_to_tgsi_visitor::visit(ir_call *ir)
 {
@@ -3340,7 +3637,16 @@ glsl_to_tgsi_visitor::visit(ir_call *ir)
    /* Filter out intrinsics */
    if (!strcmp("__intrinsic_atomic_read", callee) ||
        !strcmp("__intrinsic_atomic_increment", callee) ||
-       !strcmp("__intrinsic_atomic_predecrement", callee)) {
+       !strcmp("__intrinsic_atomic_predecrement", callee) ||
+       !strcmp("__intrinsic_atomic_add", callee) ||
+       !strcmp("__intrinsic_atomic_sub", callee) ||
+       !strcmp("__intrinsic_atomic_min", callee) ||
+       !strcmp("__intrinsic_atomic_max", callee) ||
+       !strcmp("__intrinsic_atomic_and", callee) ||
+       !strcmp("__intrinsic_atomic_or", callee) ||
+       !strcmp("__intrinsic_atomic_xor", callee) ||
+       !strcmp("__intrinsic_atomic_exchange", callee) ||
+       !strcmp("__intrinsic_atomic_comp_swap", callee)) {
       visit_atomic_counter_intrinsic(ir);
       return;
    }
@@ -3369,6 +3675,36 @@ glsl_to_tgsi_visitor::visit(ir_call *ir)
       return;
    }
 
+   if (!strcmp("__intrinsic_load_shared", callee) ||
+       !strcmp("__intrinsic_store_shared", callee) ||
+       !strcmp("__intrinsic_atomic_add_shared", callee) ||
+       !strcmp("__intrinsic_atomic_min_shared", callee) ||
+       !strcmp("__intrinsic_atomic_max_shared", callee) ||
+       !strcmp("__intrinsic_atomic_and_shared", callee) ||
+       !strcmp("__intrinsic_atomic_or_shared", callee) ||
+       !strcmp("__intrinsic_atomic_xor_shared", callee) ||
+       !strcmp("__intrinsic_atomic_exchange_shared", callee) ||
+       !strcmp("__intrinsic_atomic_comp_swap_shared", callee)) {
+      visit_shared_intrinsic(ir);
+      return;
+   }
+
+   if (!strcmp("__intrinsic_image_load", callee) ||
+       !strcmp("__intrinsic_image_store", callee) ||
+       !strcmp("__intrinsic_image_atomic_add", callee) ||
+       !strcmp("__intrinsic_image_atomic_min", callee) ||
+       !strcmp("__intrinsic_image_atomic_max", callee) ||
+       !strcmp("__intrinsic_image_atomic_and", callee) ||
+       !strcmp("__intrinsic_image_atomic_or", callee) ||
+       !strcmp("__intrinsic_image_atomic_xor", callee) ||
+       !strcmp("__intrinsic_image_atomic_exchange", callee) ||
+       !strcmp("__intrinsic_image_atomic_comp_swap", callee) ||
+       !strcmp("__intrinsic_image_size", callee) ||
+       !strcmp("__intrinsic_image_samples", callee)) {
+      visit_image_intrinsic(ir);
+      return;
+   }
+
    entry = get_function_signature(sig);
    /* Process in parameters. */
    foreach_two_lists(formal_node, &sig->parameters,
@@ -3389,7 +3725,6 @@ glsl_to_tgsi_visitor::visit(ir_call *ir)
          l.index = storage->index;
          l.reladdr = NULL;
          l.writemask = WRITEMASK_XYZW;
-         l.cond_mask = COND_TR;
 
          for (i = 0; i < type_size(param->type); i++) {
             emit_asm(ir, TGSI_OPCODE_MOV, l, r);
@@ -3436,18 +3771,113 @@ glsl_to_tgsi_visitor::visit(ir_call *ir)
    this->result = entry->return_reg;
 }
 
+void
+glsl_to_tgsi_visitor::calc_deref_offsets(ir_dereference *head,
+                                         ir_dereference *tail,
+                                         unsigned *array_elements,
+                                         unsigned *base,
+                                         unsigned *index,
+                                         st_src_reg *indirect,
+                                         unsigned *location)
+{
+   switch (tail->ir_type) {
+   case ir_type_dereference_record: {
+      ir_dereference_record *deref_record = tail->as_dereference_record();
+      const glsl_type *struct_type = deref_record->record->type;
+      int field_index = deref_record->record->type->field_index(deref_record->field);
+
+      calc_deref_offsets(head, deref_record->record->as_dereference(), array_elements, base, index, indirect, location);
+
+      assert(field_index >= 0);
+      *location += struct_type->record_location_offset(field_index);
+      break;
+   }
+
+   case ir_type_dereference_array: {
+      ir_dereference_array *deref_arr = tail->as_dereference_array();
+      ir_constant *array_index = deref_arr->array_index->constant_expression_value();
+
+      if (!array_index) {
+         st_src_reg temp_reg;
+         st_dst_reg temp_dst;
+
+         temp_reg = get_temp(glsl_type::uint_type);
+         temp_dst = st_dst_reg(temp_reg);
+         temp_dst.writemask = 1;
+
+         deref_arr->array_index->accept(this);
+         if (*array_elements != 1)
+            emit_asm(NULL, TGSI_OPCODE_MUL, temp_dst, this->result, st_src_reg_for_int(*array_elements));
+         else
+            emit_asm(NULL, TGSI_OPCODE_MOV, temp_dst, this->result);
+
+         if (indirect->file == PROGRAM_UNDEFINED)
+            *indirect = temp_reg;
+         else {
+            temp_dst = st_dst_reg(*indirect);
+            temp_dst.writemask = 1;
+            emit_asm(NULL, TGSI_OPCODE_ADD, temp_dst, *indirect, temp_reg);
+         }
+      } else
+         *index += array_index->value.u[0] * *array_elements;
+
+      *array_elements *= deref_arr->array->type->length;
+
+      calc_deref_offsets(head, deref_arr->array->as_dereference(), array_elements, base, index, indirect, location);
+      break;
+   }
+   default:
+      break;
+   }
+}
+
+void
+glsl_to_tgsi_visitor::get_deref_offsets(ir_dereference *ir,
+                                        unsigned *array_size,
+                                        unsigned *base,
+                                        unsigned *index,
+                                        st_src_reg *reladdr)
+{
+   GLuint shader = _mesa_program_enum_to_shader_stage(this->prog->Target);
+   unsigned location = 0;
+   ir_variable *var = ir->variable_referenced();
+
+   memset(reladdr, 0, sizeof(*reladdr));
+   reladdr->file = PROGRAM_UNDEFINED;
+
+   *base = 0;
+   *array_size = 1;
+
+   assert(var);
+   location = var->data.location;
+   calc_deref_offsets(ir, ir, array_size, base, index, reladdr, &location);
+
+   /*
+    * If we end up with no indirect then adjust the base to the index,
+    * and set the array size to 1.
+    */
+   if (reladdr->file == PROGRAM_UNDEFINED) {
+      *base = *index;
+      *array_size = 1;
+   }
+
+   if (location != 0xffffffff) {
+      *base += this->shader_program->UniformStorage[location].opaque[shader].index;
+      *index += this->shader_program->UniformStorage[location].opaque[shader].index;
+   }
+}
+
 void
 glsl_to_tgsi_visitor::visit(ir_texture *ir)
 {
    st_src_reg result_src, coord, cube_sc, lod_info, projector, dx, dy;
    st_src_reg offset[MAX_GLSL_TEXTURE_OFFSET], sample_index, component;
-   st_src_reg levels_src;
+   st_src_reg levels_src, reladdr;
    st_dst_reg result_dst, coord_dst, cube_sc_dst;
    glsl_to_tgsi_instruction *inst = NULL;
    unsigned opcode = TGSI_OPCODE_NOP;
    const glsl_type *sampler_type = ir->sampler->type;
-   ir_rvalue *sampler_index =
-      _mesa_get_sampler_array_nonconst_index(ir->sampler);
+   unsigned sampler_array_size = 1, sampler_index = 0, sampler_base = 0;
    bool is_cube_array = false;
    unsigned i;
 
@@ -3669,10 +4099,10 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir)
       coord_dst.writemask = WRITEMASK_XYZW;
    }
 
-   if (sampler_index) {
-      sampler_index->accept(this);
-      emit_arl(ir, sampler_reladdr, this->result);
-   }
+   get_deref_offsets(ir->sampler, &sampler_array_size, &sampler_base,
+                     &sampler_index, &reladdr);
+   if (reladdr.file != PROGRAM_UNDEFINED)
+      emit_arl(ir, sampler_reladdr, reladdr);
 
    if (opcode == TGSI_OPCODE_TXD)
       inst = emit_asm(ir, opcode, result_dst, coord, dx, dy);
@@ -3705,16 +4135,13 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir)
    if (ir->shadow_comparitor)
       inst->tex_shadow = GL_TRUE;
 
-   inst->sampler.index = _mesa_get_sampler_uniform_value(ir->sampler,
-                                                         this->shader_program,
-                                                         this->prog);
-   if (sampler_index) {
+   inst->sampler.index = sampler_index;
+   inst->sampler_array_size = sampler_array_size;
+   inst->sampler_base = sampler_base;
+
+   if (reladdr.file != PROGRAM_UNDEFINED) {
       inst->sampler.reladdr = ralloc(mem_ctx, st_src_reg);
-      memcpy(inst->sampler.reladdr, &sampler_reladdr, sizeof(sampler_reladdr));
-      inst->sampler_array_size =
-         ir->sampler->as_dereference_array()->array->type->array_size();
-   } else {
-      inst->sampler_array_size = 1;
+      memcpy(inst->sampler.reladdr, &reladdr, sizeof(reladdr));
    }
 
    if (ir->offset) {
@@ -3876,6 +4303,7 @@ glsl_to_tgsi_visitor::glsl_to_tgsi_visitor()
    num_address_regs = 0;
    samplers_used = 0;
    buffers_used = 0;
+   images_used = 0;
    indirect_addr_consts = false;
    wpos_transform_const = -1;
    glsl_version = 0;
@@ -3888,6 +4316,7 @@ glsl_to_tgsi_visitor::glsl_to_tgsi_visitor()
    options = NULL;
    have_sqrt = false;
    have_fma = false;
+   use_shared_memory = false;
 }
 
 glsl_to_tgsi_visitor::~glsl_to_tgsi_visitor()
@@ -3911,11 +4340,12 @@ count_resources(glsl_to_tgsi_visitor *v, gl_program *prog)
 {
    v->samplers_used = 0;
    v->buffers_used = 0;
+   v->images_used = 0;
 
    foreach_in_list(glsl_to_tgsi_instruction, inst, &v->instructions) {
       if (inst->info->is_tex) {
          for (int i = 0; i < inst->sampler_array_size; i++) {
-            unsigned idx = inst->sampler.index + i;
+            unsigned idx = inst->sampler_base + i;
             v->samplers_used |= 1 << idx;
 
             debug_assert(idx < (int)ARRAY_SIZE(v->sampler_types));
@@ -3931,8 +4361,20 @@ count_resources(glsl_to_tgsi_visitor *v, gl_program *prog)
       if (inst->buffer.file != PROGRAM_UNDEFINED && (
                 is_resource_instruction(inst->op) ||
                 inst->op == TGSI_OPCODE_STORE)) {
-         if (inst->buffer.file == PROGRAM_BUFFER)
+         if (inst->buffer.file == PROGRAM_BUFFER) {
             v->buffers_used |= 1 << inst->buffer.index;
+         } else if (inst->buffer.file == PROGRAM_MEMORY) {
+            v->use_shared_memory = true;
+         } else {
+            assert(inst->buffer.file == PROGRAM_IMAGE);
+            for (int i = 0; i < inst->sampler_array_size; i++) {
+               unsigned idx = inst->sampler_base + i;
+               v->images_used |= 1 << idx;
+               v->image_targets[idx] =
+                  st_translate_texture_target(inst->tex_target, false);
+               v->image_formats[idx] = inst->image_format;
+            }
+         }
       }
    }
    prog->SamplersUsed = v->samplers_used;
@@ -4715,7 +5157,9 @@ struct st_translate {
    struct ureg_dst address[3];
    struct ureg_src samplers[PIPE_MAX_SAMPLERS];
    struct ureg_src buffers[PIPE_MAX_SHADER_BUFFERS];
+   struct ureg_src images[PIPE_MAX_SHADER_IMAGES];
    struct ureg_src systemValues[SYSTEM_VALUE_MAX];
+   struct ureg_src shared_memory;
    struct tgsi_texture_offset tex_offsets[MAX_GLSL_TEXTURE_OFFSET];
    unsigned *array_sizes;
    struct array_decl *input_arrays;
@@ -4776,6 +5220,12 @@ const unsigned _mesa_sysval_to_semantic[SYSTEM_VALUE_MAX] = {
    TGSI_SEMANTIC_PRIMID,
    TGSI_SEMANTIC_TESSOUTER,
    TGSI_SEMANTIC_TESSINNER,
+
+   /* Compute shaders
+    */
+   TGSI_SEMANTIC_THREAD_ID,
+   TGSI_SEMANTIC_BLOCK_ID,
+   TGSI_SEMANTIC_GRID_SIZE,
 };
 
 /**
@@ -5129,7 +5579,7 @@ compile_tgsi_instruction(struct st_translate *t,
 
    int num_dst;
    int num_src;
-   unsigned tex_target;
+   unsigned tex_target = 0;
 
    num_dst = num_inst_dst_regs(inst);
    num_src = num_inst_src_regs(inst);
@@ -5204,21 +5654,38 @@ compile_tgsi_instruction(struct st_translate *t,
       for (i = num_src - 1; i >= 0; i--)
          src[i + 1] = src[i];
       num_src++;
-      src[0] = t->buffers[inst->buffer.index];
+      if (inst->buffer.file == PROGRAM_MEMORY) {
+         src[0] = t->shared_memory;
+      } else if (inst->buffer.file == PROGRAM_BUFFER) {
+         src[0] = t->buffers[inst->buffer.index];
+      } else {
+         src[0] = t->images[inst->buffer.index];
+         tex_target = st_translate_texture_target(inst->tex_target, inst->tex_shadow);
+      }
       if (inst->buffer.reladdr)
          src[0] = ureg_src_indirect(src[0], ureg_src(t->address[2]));
       assert(src[0].File != TGSI_FILE_NULL);
       ureg_memory_insn(ureg, inst->op, dst, num_dst, src, num_src,
-                       inst->buffer_access);
+                       inst->buffer_access,
+                       tex_target, inst->image_format);
       break;
 
    case TGSI_OPCODE_STORE:
-      dst[0] = ureg_writemask(ureg_dst(t->buffers[inst->buffer.index]), inst->dst[0].writemask);
+      if (inst->buffer.file == PROGRAM_MEMORY) {
+         dst[0] = ureg_dst(t->shared_memory);
+      } else if (inst->buffer.file == PROGRAM_BUFFER) {
+         dst[0] = ureg_dst(t->buffers[inst->buffer.index]);
+      } else {
+         dst[0] = ureg_dst(t->images[inst->buffer.index]);
+         tex_target = st_translate_texture_target(inst->tex_target, inst->tex_shadow);
+      }
+      dst[0] = ureg_writemask(dst[0], inst->dst[0].writemask);
       if (inst->buffer.reladdr)
          dst[0] = ureg_dst_indirect(dst[0], ureg_src(t->address[2]));
       assert(dst[0].File != TGSI_FILE_NULL);
       ureg_memory_insn(ureg, inst->op, dst, num_dst, src, num_src,
-                       inst->buffer_access);
+                       inst->buffer_access,
+                       tex_target, inst->image_format);
       break;
 
    case TGSI_OPCODE_SCS:
@@ -5539,6 +6006,12 @@ st_translate_program(
           TGSI_SEMANTIC_TESSCOORD);
    assert(_mesa_sysval_to_semantic[SYSTEM_VALUE_HELPER_INVOCATION] ==
           TGSI_SEMANTIC_HELPER_INVOCATION);
+   assert(_mesa_sysval_to_semantic[SYSTEM_VALUE_LOCAL_INVOCATION_ID] ==
+          TGSI_SEMANTIC_THREAD_ID);
+   assert(_mesa_sysval_to_semantic[SYSTEM_VALUE_WORK_GROUP_ID] ==
+          TGSI_SEMANTIC_BLOCK_ID);
+   assert(_mesa_sysval_to_semantic[SYSTEM_VALUE_NUM_WORK_GROUPS] ==
+          TGSI_SEMANTIC_GRID_SIZE);
 
    t = CALLOC_STRUCT(st_translate);
    if (!t) {
@@ -5606,6 +6079,8 @@ st_translate_program(
          t->inputs[i] = ureg_DECL_vs_input(ureg, i);
       }
       break;
+   case TGSI_PROCESSOR_COMPUTE:
+      break;
    default:
       assert(0);
    }
@@ -5615,6 +6090,7 @@ st_translate_program(
     */
    switch (procType) {
    case TGSI_PROCESSOR_FRAGMENT:
+   case TGSI_PROCESSOR_COMPUTE:
       break;
    case TGSI_PROCESSOR_GEOMETRY:
    case TGSI_PROCESSOR_TESS_EVAL:
@@ -5645,6 +6121,9 @@ st_translate_program(
    }
 
    if (procType == TGSI_PROCESSOR_FRAGMENT) {
+      if (program->shader->EarlyFragmentTests)
+         ureg_property(ureg, TGSI_PROPERTY_FS_EARLY_DEPTH_STENCIL, 1);
+
       if (proginfo->InputsRead & VARYING_BIT_POS) {
           /* Must do this after setting up t->inputs. */
           emit_wpos(st_context(ctx), t, proginfo, ureg,
@@ -5865,7 +6344,17 @@ st_translate_program(
       }
    }
 
+   if (program->use_shared_memory)
+      t->shared_memory = ureg_DECL_memory(ureg, TGSI_MEMORY_TYPE_SHARED);
 
+   for (i = 0; i < program->shader->NumImages; i++) {
+      if (program->images_used & (1 << i)) {
+         t->images[i] = ureg_DECL_image(ureg, i,
+                                        program->image_targets[i],
+                                        program->image_formats[i],
+                                        true, false);
+      }
+   }
 
    /* Emit each instruction in turn:
     */
@@ -5881,6 +6370,42 @@ st_translate_program(
                        t->insn[t->labels[i].branch_target]);
    }
 
+   /* Set the next shader stage hint for VS and TES. */
+   switch (procType) {
+   case TGSI_PROCESSOR_VERTEX:
+   case TGSI_PROCESSOR_TESS_EVAL:
+      if (program->shader_program->SeparateShader)
+         break;
+
+      for (i = program->shader->Stage+1; i <= MESA_SHADER_FRAGMENT; i++) {
+         if (program->shader_program->_LinkedShaders[i]) {
+            unsigned next;
+
+            switch (i) {
+            case MESA_SHADER_TESS_CTRL:
+               next = TGSI_PROCESSOR_TESS_CTRL;
+               break;
+            case MESA_SHADER_TESS_EVAL:
+               next = TGSI_PROCESSOR_TESS_EVAL;
+               break;
+            case MESA_SHADER_GEOMETRY:
+               next = TGSI_PROCESSOR_GEOMETRY;
+               break;
+            case MESA_SHADER_FRAGMENT:
+               next = TGSI_PROCESSOR_FRAGMENT;
+               break;
+            default:
+               assert(0);
+               continue;
+            }
+
+            ureg_set_next_shader_processor(ureg, next);
+            break;
+         }
+      }
+      break;
+   }
+
 out:
    if (t) {
       free(t->arrays);
@@ -6045,6 +6570,10 @@ get_mesa_program(struct gl_context *ctx,
                              prog->OutputsWritten, 0ULL, prog->PatchOutputsWritten);
    count_resources(v, prog);
 
+   /* The GLSL IR won't be needed anymore. */
+   ralloc_free(shader->ir);
+   shader->ir = NULL;
+
    /* This must be done before the uniform storage is associated. */
    if (shader->Type == GL_FRAGMENT_SHADER &&
        (prog->InputsRead & VARYING_BIT_POS ||
@@ -6080,6 +6609,7 @@ get_mesa_program(struct gl_context *ctx,
    struct st_geometry_program *stgp;
    struct st_tessctrl_program *sttcp;
    struct st_tesseval_program *sttep;
+   struct st_compute_program *stcp;
 
    switch (shader->Type) {
    case GL_VERTEX_SHADER:
@@ -6102,6 +6632,10 @@ get_mesa_program(struct gl_context *ctx,
       sttep = (struct st_tesseval_program *)prog;
       sttep->glsl_to_tgsi = v;
       break;
+   case GL_COMPUTE_SHADER:
+      stcp = (struct st_compute_program *)prog;
+      stcp->glsl_to_tgsi = v;
+      break;
    default:
       assert(!"should not be reached");
       return NULL;
@@ -6277,6 +6811,8 @@ st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
       validate_ir_tree(ir);
    }
 
+   build_program_resource_list(prog);
+
    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       struct gl_program *linked_prog;