i965: Make the userclip flag for the VUE map come from VS prog data.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_vec4_visitor.cpp
index 71d8b395d556ed804913bc6713a1837f202bf821..5dfe1c1354c49adb52ce7dfcae45dbdfdc91804b 100644 (file)
@@ -25,6 +25,7 @@
 extern "C" {
 #include "main/macros.h"
 #include "program/prog_parameter.h"
+#include "program/sampler.h"
 }
 
 namespace brw {
@@ -182,6 +183,9 @@ vec4_visitor::IF(src_reg src0, src_reg src1, uint32_t condition)
 
    vec4_instruction *inst;
 
+   resolve_ud_negate(&src0);
+   resolve_ud_negate(&src1);
+
    inst = new(mem_ctx) vec4_instruction(this, BRW_OPCODE_IF, dst_null_d(),
                                        src0, src1);
    inst->conditional_mod = condition;
@@ -203,8 +207,14 @@ vec4_visitor::CMP(dst_reg dst, src_reg src0, src_reg src1, uint32_t condition)
     * before before comparison, producing garbage results for floating
     * point comparisons.
     */
-   if (intel->gen == 4)
+   if (intel->gen == 4) {
       dst.type = src0.type;
+      if (dst.file == HW_REG)
+        dst.fixed_hw_reg.type = dst.type;
+   }
+
+   resolve_ud_negate(&src0);
+   resolve_ud_negate(&src1);
 
    inst = new(mem_ctx) vec4_instruction(this, BRW_OPCODE_CMP, dst, src0, src1);
    inst->conditional_mod = condition;
@@ -303,7 +313,9 @@ vec4_visitor::emit_math(opcode opcode, dst_reg dst, src_reg src)
       return;
    }
 
-   if (intel->gen >= 6) {
+   if (intel->gen >= 7) {
+      emit(opcode, dst, src);
+   } else if (intel->gen == 6) {
       return emit_math1_gen6(opcode, dst, src);
    } else {
       return emit_math1_gen4(opcode, dst, src);
@@ -323,10 +335,12 @@ vec4_visitor::emit_math2_gen6(enum opcode opcode,
     */
 
    expanded = src_reg(this, glsl_type::vec4_type);
+   expanded.type = src0.type;
    emit(MOV(dst_reg(expanded), src0));
    src0 = expanded;
 
    expanded = src_reg(this, glsl_type::vec4_type);
+   expanded.type = src1.type;
    emit(MOV(dst_reg(expanded), src1));
    src1 = expanded;
 
@@ -335,6 +349,7 @@ vec4_visitor::emit_math2_gen6(enum opcode opcode,
        * writemasks.
        */
       dst_reg temp_dst = dst_reg(this, glsl_type::vec4_type);
+      temp_dst.type = dst.type;
 
       emit(opcode, temp_dst, src0, src1);
 
@@ -357,9 +372,19 @@ void
 vec4_visitor::emit_math(enum opcode opcode,
                        dst_reg dst, src_reg src0, src_reg src1)
 {
-   assert(opcode == SHADER_OPCODE_POW);
+   switch (opcode) {
+   case SHADER_OPCODE_POW:
+   case SHADER_OPCODE_INT_QUOTIENT:
+   case SHADER_OPCODE_INT_REMAINDER:
+      break;
+   default:
+      assert(!"not reached: unsupported binary math opcode");
+      return;
+   }
 
-   if (intel->gen >= 6) {
+   if (intel->gen >= 7) {
+      emit(opcode, dst, src0, src1);
+   } else if (intel->gen == 6) {
       return emit_math2_gen6(opcode, dst, src0, src1);
    } else {
       return emit_math2_gen4(opcode, dst, src0, src1);
@@ -429,7 +454,11 @@ vec4_visitor::virtual_grf_alloc(int size)
         virtual_grf_array_size *= 2;
       virtual_grf_sizes = reralloc(mem_ctx, virtual_grf_sizes, int,
                                   virtual_grf_array_size);
+      virtual_grf_reg_map = reralloc(mem_ctx, virtual_grf_reg_map, int,
+                                    virtual_grf_array_size);
    }
+   virtual_grf_reg_map[virtual_grf_count] = virtual_grf_reg_count;
+   virtual_grf_reg_count += size;
    virtual_grf_sizes[virtual_grf_count] = size;
    return virtual_grf_count++;
 }
@@ -478,9 +507,7 @@ vec4_visitor::setup_uniform_values(int loc, const glsl_type *type)
    float *values = &this->vp->Base.Parameters->ParameterValues[loc][0].f;
 
    if (type->is_matrix()) {
-      const glsl_type *column = glsl_type::get_instance(GLSL_TYPE_FLOAT,
-                                                       type->vector_elements,
-                                                       1);
+      const glsl_type *column = type->column_type();
 
       for (unsigned int i = 0; i < type->matrix_columns; i++) {
         offset += setup_uniform_values(loc + offset, column);
@@ -536,6 +563,37 @@ vec4_visitor::setup_uniform_values(int loc, const glsl_type *type)
    }
 }
 
+void
+vec4_visitor::setup_uniform_clipplane_values()
+{
+   gl_clip_plane *clip_planes = brw_select_clip_planes(ctx);
+
+   /* Pre-Gen6, we compact clip planes.  For example, if the user
+    * enables just clip planes 0, 1, and 3, we will enable clip planes
+    * 0, 1, and 2 in the hardware, and we'll move clip plane 3 to clip
+    * plane 2.  This simplifies the implementation of the Gen6 clip
+    * thread.
+    *
+    * In Gen6 and later, we don't compact clip planes, because this
+    * simplifies the implementation of gl_ClipDistance.
+    */
+   int compacted_clipplane_index = 0;
+   for (int i = 0; i < c->key.nr_userclip_plane_consts; ++i) {
+      if (intel->gen < 6 &&
+          !(c->key.userclip_planes_enabled_gen_4_5 & (1 << i))) {
+         continue;
+      }
+      this->uniform_vector_size[this->uniforms] = 4;
+      this->userplane[compacted_clipplane_index] = dst_reg(UNIFORM, this->uniforms);
+      this->userplane[compacted_clipplane_index].type = BRW_REGISTER_TYPE_F;
+      for (int j = 0; j < 4; ++j) {
+         c->prog_data.param[this->uniforms * 4 + j] = &clip_planes[i][j];
+      }
+      ++compacted_clipplane_index;
+      ++this->uniforms;
+   }
+}
+
 /* Our support for builtin uniforms is even scarier than non-builtin.
  * It sits on top of the PROG_STATE_VAR parameters that are
  * automatically updated from GL context state.
@@ -580,20 +638,22 @@ vec4_visitor::variable_storage(ir_variable *var)
 }
 
 void
-vec4_visitor::emit_bool_to_cond_code(ir_rvalue *ir)
+vec4_visitor::emit_bool_to_cond_code(ir_rvalue *ir, uint32_t *predicate)
 {
    ir_expression *expr = ir->as_expression();
 
+   *predicate = BRW_PREDICATE_NORMAL;
+
    if (expr) {
       src_reg op[2];
       vec4_instruction *inst;
 
       assert(expr->get_num_operands() <= 2);
       for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
-        assert(expr->operands[i]->type->is_scalar());
-
         expr->operands[i]->accept(this);
         op[i] = this->result;
+
+        resolve_ud_negate(&op[i]);
       }
 
       switch (expr->operation) {
@@ -635,14 +695,27 @@ vec4_visitor::emit_bool_to_cond_code(ir_rvalue *ir)
         }
         break;
 
+      case ir_binop_all_equal:
+        inst = emit(CMP(dst_null_d(), op[0], op[1], BRW_CONDITIONAL_Z));
+        *predicate = BRW_PREDICATE_ALIGN16_ALL4H;
+        break;
+
+      case ir_binop_any_nequal:
+        inst = emit(CMP(dst_null_d(), op[0], op[1], BRW_CONDITIONAL_NZ));
+        *predicate = BRW_PREDICATE_ALIGN16_ANY4H;
+        break;
+
+      case ir_unop_any:
+        inst = emit(CMP(dst_null_d(), op[0], src_reg(0), BRW_CONDITIONAL_NZ));
+        *predicate = BRW_PREDICATE_ALIGN16_ANY4H;
+        break;
+
       case ir_binop_greater:
       case ir_binop_gequal:
       case ir_binop_less:
       case ir_binop_lequal:
       case ir_binop_equal:
-      case ir_binop_all_equal:
       case ir_binop_nequal:
-      case ir_binop_any_nequal:
         emit(CMP(dst_null_d(), op[0], op[1],
                  brw_conditional_for_comparison(expr->operation)));
         break;
@@ -656,6 +729,8 @@ vec4_visitor::emit_bool_to_cond_code(ir_rvalue *ir)
 
    ir->accept(this);
 
+   resolve_ud_negate(&this->result);
+
    if (intel->gen >= 6) {
       vec4_instruction *inst = emit(AND(dst_null_d(),
                                        this->result, src_reg(1)));
@@ -772,6 +847,7 @@ vec4_visitor::visit(ir_variable *ir)
            continue;
 
         dst_reg dst = *reg;
+         dst.type = brw_type_for_base_type(ir->type);
         dst.writemask = (1 << c->key.gl_fixed_input_size[i]) - 1;
         emit(MUL(dst, src_reg(dst), src_reg(1.0f / 65536.0f)));
       }
@@ -783,7 +859,9 @@ vec4_visitor::visit(ir_variable *ir)
       for (int i = 0; i < type_size(ir->type); i++) {
         output_reg[ir->location + i] = *reg;
         output_reg[ir->location + i].reg_offset = i;
-        output_reg[ir->location + i].type = BRW_REGISTER_TYPE_F;
+        output_reg[ir->location + i].type =
+            brw_type_for_base_type(ir->type->get_scalar_type());
+        output_reg_annotation[ir->location + i] = ir->name;
       }
       break;
 
@@ -807,6 +885,27 @@ vec4_visitor::visit(ir_variable *ir)
       }
       break;
 
+   case ir_var_system_value:
+      /* VertexID is stored by the VF as the last vertex element, but
+       * we don't represent it with a flag in inputs_read, so we call
+       * it VERT_ATTRIB_MAX, which setup_attributes() picks up on.
+       */
+      reg = new(mem_ctx) dst_reg(ATTR, VERT_ATTRIB_MAX);
+      prog_data->uses_vertexid = true;
+
+      switch (ir->location) {
+      case SYSTEM_VALUE_VERTEX_ID:
+        reg->writemask = WRITEMASK_X;
+        break;
+      case SYSTEM_VALUE_INSTANCE_ID:
+        reg->writemask = WRITEMASK_Y;
+        break;
+      default:
+        assert(!"not reached");
+        break;
+      }
+      break;
+
    default:
       assert(!"not reached");
    }
@@ -902,7 +1001,7 @@ vec4_visitor::visit(ir_function *ir)
    }
 }
 
-GLboolean
+bool
 vec4_visitor::try_emit_sat(ir_expression *ir)
 {
    ir_rvalue *sat_src = ir->as_rvalue_to_saturate();
@@ -1073,9 +1172,14 @@ vec4_visitor::visit(ir_expression *ir)
       }
       break;
    case ir_binop_div:
-      assert(!"not reached: should be handled by ir_div_to_mul_rcp");
+      /* Floating point should be lowered by DIV_TO_MUL_RCP in the compiler. */
+      assert(ir->type->is_integer());
+      emit_math(SHADER_OPCODE_INT_QUOTIENT, result_dst, op[0], op[1]);
+      break;
    case ir_binop_mod:
-      assert(!"ir_binop_mod should have been converted to b * fract(a/b)");
+      /* Floating point should be lowered by MOD_TO_FRACT in the compiler. */
+      assert(ir->type->is_integer());
+      emit_math(SHADER_OPCODE_INT_REMAINDER, result_dst, op[0], op[1]);
       break;
 
    case ir_binop_less:
@@ -1185,16 +1289,26 @@ vec4_visitor::visit(ir_expression *ir)
       break;
 
    case ir_binop_min:
-      emit(CMP(result_dst, op[0], op[1], BRW_CONDITIONAL_L));
+      if (intel->gen >= 6) {
+        inst = emit(BRW_OPCODE_SEL, result_dst, op[0], op[1]);
+        inst->conditional_mod = BRW_CONDITIONAL_L;
+      } else {
+        emit(CMP(result_dst, op[0], op[1], BRW_CONDITIONAL_L));
 
-      inst = emit(BRW_OPCODE_SEL, result_dst, op[0], op[1]);
-      inst->predicate = BRW_PREDICATE_NORMAL;
+        inst = emit(BRW_OPCODE_SEL, result_dst, op[0], op[1]);
+        inst->predicate = BRW_PREDICATE_NORMAL;
+      }
       break;
    case ir_binop_max:
-      emit(CMP(result_dst, op[0], op[1], BRW_CONDITIONAL_G));
+      if (intel->gen >= 6) {
+        inst = emit(BRW_OPCODE_SEL, result_dst, op[0], op[1]);
+        inst->conditional_mod = BRW_CONDITIONAL_G;
+      } else {
+        emit(CMP(result_dst, op[0], op[1], BRW_CONDITIONAL_G));
 
-      inst = emit(BRW_OPCODE_SEL, result_dst, op[0], op[1]);
-      inst->predicate = BRW_PREDICATE_NORMAL;
+        inst = emit(BRW_OPCODE_SEL, result_dst, op[0], op[1]);
+        inst->predicate = BRW_PREDICATE_NORMAL;
+      }
       break;
 
    case ir_binop_pow:
@@ -1215,8 +1329,14 @@ vec4_visitor::visit(ir_expression *ir)
       break;
 
    case ir_binop_lshift:
+      inst = emit(BRW_OPCODE_SHL, result_dst, op[0], op[1]);
+      break;
+
    case ir_binop_rshift:
-      assert(!"GLSL 1.30 features unsupported");
+      if (ir->type->base_type == GLSL_TYPE_INT)
+        inst = emit(BRW_OPCODE_ASR, result_dst, op[0], op[1]);
+      else
+        inst = emit(BRW_OPCODE_SHR, result_dst, op[0], op[1]);
       break;
 
    case ir_quadop_vector:
@@ -1391,18 +1511,18 @@ get_assignment_lhs(ir_dereference *ir, vec4_visitor *v)
 
 void
 vec4_visitor::emit_block_move(dst_reg *dst, src_reg *src,
-                             const struct glsl_type *type, bool predicated)
+                             const struct glsl_type *type, uint32_t predicate)
 {
    if (type->base_type == GLSL_TYPE_STRUCT) {
       for (unsigned int i = 0; i < type->length; i++) {
-        emit_block_move(dst, src, type->fields.structure[i].type, predicated);
+        emit_block_move(dst, src, type->fields.structure[i].type, predicate);
       }
       return;
    }
 
    if (type->is_array()) {
       for (unsigned int i = 0; i < type->length; i++) {
-        emit_block_move(dst, src, type->fields.array, predicated);
+        emit_block_move(dst, src, type->fields.array, predicate);
       }
       return;
    }
@@ -1414,7 +1534,7 @@ vec4_visitor::emit_block_move(dst_reg *dst, src_reg *src,
                                         type->vector_elements, 1);
 
       for (int i = 0; i < type->matrix_columns; i++) {
-        emit_block_move(dst, src, vec_type, predicated);
+        emit_block_move(dst, src, vec_type, predicate);
       }
       return;
    }
@@ -1426,13 +1546,10 @@ vec4_visitor::emit_block_move(dst_reg *dst, src_reg *src,
 
    dst->writemask = (1 << type->vector_elements) - 1;
 
-   /* Do we need to worry about swizzling a swizzle? */
-   assert(src->swizzle = BRW_SWIZZLE_NOOP);
    src->swizzle = swizzle_for_size(type->vector_elements);
 
    vec4_instruction *inst = emit(MOV(*dst, *src));
-   if (predicated)
-      inst->predicate = BRW_PREDICATE_NORMAL;
+   inst->predicate = predicate;
 
    dst->reg_offset++;
    src->reg_offset++;
@@ -1475,7 +1592,8 @@ vec4_visitor::try_rewrite_rhs_to_dst(ir_assignment *ir,
     * potentially reswizzle the operands of many instructions so that
     * we could handle out of order channels, but don't yet.
     */
-   for (int i = 0; i < 4; i++) {
+
+   for (unsigned i = 0; i < 4; i++) {
       if (dst.writemask & (1 << i)) {
         if (!(last_rhs_inst->dst.writemask & (1 << i)))
            return false;
@@ -1499,6 +1617,7 @@ void
 vec4_visitor::visit(ir_assignment *ir)
 {
    dst_reg dst = get_assignment_lhs(ir->lhs, this);
+   uint32_t predicate = BRW_PREDICATE_NONE;
 
    if (!ir->lhs->type->is_scalar() &&
        !ir->lhs->type->is_vector()) {
@@ -1506,10 +1625,19 @@ vec4_visitor::visit(ir_assignment *ir)
       src_reg src = this->result;
 
       if (ir->condition) {
-        emit_bool_to_cond_code(ir->condition);
+        emit_bool_to_cond_code(ir->condition, &predicate);
       }
 
-      emit_block_move(&dst, &src, ir->rhs->type, ir->condition != NULL);
+      /* emit_block_move doesn't account for swizzles in the source register.
+       * This should be ok, since the source register is a structure or an
+       * array, and those can't be swizzled.  But double-check to be sure.
+       */
+      assert(src.swizzle ==
+             (ir->rhs->type->is_matrix()
+              ? swizzle_for_size(ir->rhs->type->vector_elements)
+              : BRW_SWIZZLE_NOOP));
+
+      emit_block_move(&dst, &src, ir->rhs->type, predicate);
       return;
    }
 
@@ -1560,14 +1688,12 @@ vec4_visitor::visit(ir_assignment *ir)
    }
 
    if (ir->condition) {
-      emit_bool_to_cond_code(ir->condition);
+      emit_bool_to_cond_code(ir->condition, &predicate);
    }
 
    for (i = 0; i < type_size(ir->lhs->type); i++) {
       vec4_instruction *inst = emit(MOV(dst, src));
-
-      if (ir->condition)
-        inst->predicate = BRW_PREDICATE_NORMAL;
+      inst->predicate = predicate;
 
       dst.reg_offset++;
       src.reg_offset++;
@@ -1595,22 +1721,45 @@ vec4_visitor::emit_constant_values(dst_reg *dst, ir_constant *ir)
 
    if (ir->type->is_matrix()) {
       for (int i = 0; i < ir->type->matrix_columns; i++) {
+        float *vec = &ir->value.f[i * ir->type->vector_elements];
+
         for (int j = 0; j < ir->type->vector_elements; j++) {
            dst->writemask = 1 << j;
            dst->type = BRW_REGISTER_TYPE_F;
 
-           emit(MOV(*dst,
-                    src_reg(ir->value.f[i * ir->type->vector_elements + j])));
+           emit(MOV(*dst, src_reg(vec[j])));
         }
         dst->reg_offset++;
       }
       return;
    }
 
+   int remaining_writemask = (1 << ir->type->vector_elements) - 1;
+
    for (int i = 0; i < ir->type->vector_elements; i++) {
+      if (!(remaining_writemask & (1 << i)))
+        continue;
+
       dst->writemask = 1 << i;
       dst->type = brw_type_for_base_type(ir->type);
 
+      /* Find other components that match the one we're about to
+       * write.  Emits fewer instructions for things like vec4(0.5,
+       * 1.5, 1.5, 1.5).
+       */
+      for (int j = i + 1; j < ir->type->vector_elements; j++) {
+        if (ir->type->base_type == GLSL_TYPE_BOOL) {
+           if (ir->value.b[i] == ir->value.b[j])
+              dst->writemask |= (1 << j);
+        } else {
+           /* u, i, and f storage all line up, so no need for a
+            * switch case for comparing each type.
+            */
+           if (ir->value.u[i] == ir->value.u[j])
+              dst->writemask |= (1 << j);
+        }
+      }
+
       switch (ir->type->base_type) {
       case GLSL_TYPE_FLOAT:
         emit(MOV(*dst, src_reg(ir->value.f[i])));
@@ -1628,6 +1777,8 @@ vec4_visitor::emit_constant_values(dst_reg *dst, ir_constant *ir)
         assert(!"Non-float/uint/int/bool constant");
         break;
       }
+
+      remaining_writemask &= ~dst->writemask;
    }
    dst->reg_offset++;
 }
@@ -1650,12 +1801,178 @@ vec4_visitor::visit(ir_call *ir)
 void
 vec4_visitor::visit(ir_texture *ir)
 {
-   /* FINISHME: Implement vertex texturing.
-    *
-    * With 0 vertex samplers available, the linker will reject
-    * programs that do vertex texturing, but after our visitor has
-    * run.
-    */
+   int sampler = _mesa_get_sampler_uniform_value(ir->sampler, prog, &vp->Base);
+   sampler = vp->Base.SamplerUnits[sampler];
+
+   /* Should be lowered by do_lower_texture_projection */
+   assert(!ir->projector);
+
+   vec4_instruction *inst = NULL;
+   switch (ir->op) {
+   case ir_tex:
+   case ir_txl:
+      inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXL);
+      break;
+   case ir_txd:
+      inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXD);
+      break;
+   case ir_txf:
+      inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXF);
+      break;
+   case ir_txs:
+      inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXS);
+      break;
+   case ir_txb:
+      assert(!"TXB is not valid for vertex shaders.");
+   }
+
+   /* Texel offsets go in the message header; Gen4 also requires headers. */
+   inst->header_present = ir->offset || intel->gen < 5;
+   inst->base_mrf = 2;
+   inst->mlen = inst->header_present + 1; /* always at least one */
+   inst->sampler = sampler;
+   inst->dst = dst_reg(this, ir->type);
+   inst->shadow_compare = ir->shadow_comparitor != NULL;
+
+   if (ir->offset != NULL)
+      inst->texture_offset = brw_texture_offset(ir->offset->as_constant());
+
+   /* MRF for the first parameter */
+   int param_base = inst->base_mrf + inst->header_present;
+
+   if (ir->op == ir_txs) {
+      ir->lod_info.lod->accept(this);
+      int writemask = intel->gen == 4 ? WRITEMASK_W : WRITEMASK_X;
+      emit(MOV(dst_reg(MRF, param_base, ir->lod_info.lod->type, writemask),
+          this->result));
+   } else {
+      int i, coord_mask = 0, zero_mask = 0;
+      /* Load the coordinate */
+      /* FINISHME: gl_clamp_mask and saturate */
+      for (i = 0; i < ir->coordinate->type->vector_elements; i++)
+        coord_mask |= (1 << i);
+      for (; i < 4; i++)
+        zero_mask |= (1 << i);
+
+      ir->coordinate->accept(this);
+      emit(MOV(dst_reg(MRF, param_base, ir->coordinate->type, coord_mask),
+              this->result));
+      emit(MOV(dst_reg(MRF, param_base, ir->coordinate->type, zero_mask),
+              src_reg(0)));
+      /* Load the shadow comparitor */
+      if (ir->shadow_comparitor) {
+        ir->shadow_comparitor->accept(this);
+        emit(MOV(dst_reg(MRF, param_base + 1, ir->shadow_comparitor->type,
+                         WRITEMASK_X),
+                 this->result));
+        inst->mlen++;
+      }
+
+      /* Load the LOD info */
+      if (ir->op == ir_txl) {
+        int mrf, writemask;
+        if (intel->gen >= 5) {
+           mrf = param_base + 1;
+           if (ir->shadow_comparitor) {
+              writemask = WRITEMASK_Y;
+              /* mlen already incremented */
+           } else {
+              writemask = WRITEMASK_X;
+              inst->mlen++;
+           }
+        } else /* intel->gen == 4 */ {
+           mrf = param_base;
+           writemask = WRITEMASK_Z;
+        }
+        ir->lod_info.lod->accept(this);
+        emit(MOV(dst_reg(MRF, mrf, ir->lod_info.lod->type, writemask),
+                 this->result));
+      } else if (ir->op == ir_txf) {
+        ir->lod_info.lod->accept(this);
+        emit(MOV(dst_reg(MRF, param_base, ir->lod_info.lod->type, WRITEMASK_W),
+                 this->result));
+      } else if (ir->op == ir_txd) {
+        const glsl_type *type = ir->lod_info.grad.dPdx->type;
+
+        ir->lod_info.grad.dPdx->accept(this);
+        src_reg dPdx = this->result;
+        ir->lod_info.grad.dPdy->accept(this);
+        src_reg dPdy = this->result;
+
+        if (intel->gen >= 5) {
+           dPdx.swizzle = BRW_SWIZZLE4(SWIZZLE_X,SWIZZLE_X,SWIZZLE_Y,SWIZZLE_Y);
+           dPdy.swizzle = BRW_SWIZZLE4(SWIZZLE_X,SWIZZLE_X,SWIZZLE_Y,SWIZZLE_Y);
+           emit(MOV(dst_reg(MRF, param_base + 1, type, WRITEMASK_XZ), dPdx));
+           emit(MOV(dst_reg(MRF, param_base + 1, type, WRITEMASK_YW), dPdy));
+           inst->mlen++;
+
+           if (ir->type->vector_elements == 3) {
+              dPdx.swizzle = BRW_SWIZZLE_ZZZZ;
+              dPdy.swizzle = BRW_SWIZZLE_ZZZZ;
+              emit(MOV(dst_reg(MRF, param_base + 2, type, WRITEMASK_X), dPdx));
+              emit(MOV(dst_reg(MRF, param_base + 2, type, WRITEMASK_Y), dPdy));
+              inst->mlen++;
+           }
+        } else /* intel->gen == 4 */ {
+           emit(MOV(dst_reg(MRF, param_base + 1, type, WRITEMASK_XYZ), dPdx));
+           emit(MOV(dst_reg(MRF, param_base + 2, type, WRITEMASK_XYZ), dPdy));
+           inst->mlen += 2;
+        }
+      }
+   }
+
+   emit(inst);
+
+   swizzle_result(ir, src_reg(inst->dst), sampler);
+}
+
+void
+vec4_visitor::swizzle_result(ir_texture *ir, src_reg orig_val, int sampler)
+{
+   this->result = orig_val;
+
+   int s = c->key.tex.swizzles[sampler];
+
+   if (ir->op == ir_txs || ir->type == glsl_type::float_type
+                       || s == SWIZZLE_NOOP)
+      return;
+
+   int zero_mask = 0, one_mask = 0, copy_mask = 0;
+   int swizzle[4];
+
+   for (int i = 0; i < 4; i++) {
+      switch (GET_SWZ(s, i)) {
+      case SWIZZLE_ZERO:
+        zero_mask |= (1 << i);
+        break;
+      case SWIZZLE_ONE:
+        one_mask |= (1 << i);
+        break;
+      default:
+        copy_mask |= (1 << i);
+        swizzle[i] = GET_SWZ(s, i);
+        break;
+      }
+   }
+
+   this->result = src_reg(this, ir->type);
+   dst_reg swizzled_result(this->result);
+
+   if (copy_mask) {
+      orig_val.swizzle = BRW_SWIZZLE4(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
+      swizzled_result.writemask = copy_mask;
+      emit(MOV(swizzled_result, orig_val));
+   }
+
+   if (zero_mask) {
+      swizzled_result.writemask = zero_mask;
+      emit(MOV(swizzled_result, src_reg(0.0f)));
+   }
+
+   if (one_mask) {
+      swizzled_result.writemask = one_mask;
+      emit(MOV(swizzled_result, src_reg(1.0f)));
+   }
 }
 
 void
@@ -1681,8 +1998,9 @@ vec4_visitor::visit(ir_if *ir)
    if (intel->gen == 6) {
       emit_if_gen6(ir);
    } else {
-      emit_bool_to_cond_code(ir->condition);
-      emit(IF(BRW_PREDICATE_NORMAL));
+      uint32_t predicate;
+      emit_bool_to_cond_code(ir->condition, &predicate);
+      emit(IF(predicate));
    }
 
    visit_instructions(&ir->then_instructions);
@@ -1698,8 +2016,8 @@ vec4_visitor::visit(ir_if *ir)
    emit(BRW_OPCODE_ENDIF);
 }
 
-int
-vec4_visitor::emit_vue_header_gen4(int header_mrf)
+void
+vec4_visitor::emit_ndc_computation()
 {
    /* Get the position */
    src_reg pos = src_reg(output_reg[VERT_RESULT_HPOS]);
@@ -1719,31 +2037,38 @@ vec4_visitor::emit_vue_header_gen4(int header_mrf)
    ndc_xyz.writemask = WRITEMASK_XYZ;
 
    emit(MUL(ndc_xyz, pos, src_reg(ndc_w)));
+}
 
-   if ((c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) ||
-       c->key.nr_userclip || brw->has_negative_rhw_bug) {
+void
+vec4_visitor::emit_psiz_and_flags(struct brw_reg reg)
+{
+   if (intel->gen < 6 &&
+       ((c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) ||
+        c->key.userclip_active || brw->has_negative_rhw_bug)) {
       dst_reg header1 = dst_reg(this, glsl_type::uvec4_type);
+      dst_reg header1_w = header1;
+      header1_w.writemask = WRITEMASK_W;
       GLuint i;
 
       emit(MOV(header1, 0u));
 
       if (c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) {
-        assert(!"finishme: psiz");
-        src_reg psiz;
+        src_reg psiz = src_reg(output_reg[VERT_RESULT_PSIZ]);
 
-        header1.writemask = WRITEMASK_W;
-        emit(MUL(header1, psiz, 1u << 11));
-        emit(AND(header1, src_reg(header1), 0x7ff << 8));
+        current_annotation = "Point size";
+        emit(MUL(header1_w, psiz, src_reg((float)(1 << 11))));
+        emit(AND(header1_w, src_reg(header1_w), 0x7ff << 8));
       }
 
-      for (i = 0; i < c->key.nr_userclip; i++) {
+      current_annotation = "Clipping flags";
+      for (i = 0; i < c->key.nr_userclip_plane_consts; i++) {
         vec4_instruction *inst;
 
         inst = emit(DP4(dst_null_f(), src_reg(output_reg[VERT_RESULT_HPOS]),
-                         src_reg(c->userplane[i])));
+                         src_reg(this->userplane[i])));
         inst->conditional_mod = BRW_CONDITIONAL_L;
 
-        emit(OR(header1, src_reg(header1), 1u << i));
+        inst = emit(OR(header1_w, src_reg(header1_w), 1u << i));
         inst->predicate = BRW_PREDICATE_NORMAL;
       }
 
@@ -1771,99 +2096,111 @@ vec4_visitor::emit_vue_header_gen4(int header_mrf)
 #endif
       }
 
-      header1.writemask = WRITEMASK_XYZW;
-      emit(MOV(brw_message_reg(header_mrf++), src_reg(header1)));
+      emit(MOV(retype(reg, BRW_REGISTER_TYPE_UD), src_reg(header1)));
+   } else if (intel->gen < 6) {
+      emit(MOV(retype(reg, BRW_REGISTER_TYPE_UD), 0u));
    } else {
-      emit(MOV(retype(brw_message_reg(header_mrf++),
-                     BRW_REGISTER_TYPE_UD), 0u));
-   }
-
-   if (intel->gen == 5) {
-      /* There are 20 DWs (D0-D19) in VUE header on Ironlake:
-       * dword 0-3 (m1) of the header is indices, point width, clip flags.
-       * dword 4-7 (m2) is the ndc position (set above)
-       * dword 8-11 (m3) of the vertex header is the 4D space position
-       * dword 12-19 (m4,m5) of the vertex header is the user clip distance.
-       * m6 is a pad so that the vertex element data is aligned
-       * m7 is the first vertex data we fill.
-       */
-      current_annotation = "NDC";
-      emit(MOV(brw_message_reg(header_mrf++),
-               src_reg(output_reg[BRW_VERT_RESULT_NDC])));
-
-      current_annotation = "gl_Position";
-      emit(MOV(brw_message_reg(header_mrf++),
-               src_reg(output_reg[VERT_RESULT_HPOS])));
-
-      /* user clip distance. */
-      header_mrf += 2;
+      emit(MOV(retype(reg, BRW_REGISTER_TYPE_D), src_reg(0)));
+      if (c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) {
+         emit(MOV(brw_writemask(reg, WRITEMASK_W),
+                  src_reg(output_reg[VERT_RESULT_PSIZ])));
+      }
+   }
+}
 
-      /* Pad so that vertex element data is aligned. */
-      header_mrf++;
-   } else {
-      /* There are 8 dwords in VUE header pre-Ironlake:
-       * dword 0-3 (m1) is indices, point width, clip flags.
-       * dword 4-7 (m2) is ndc position (set above)
-       *
-       * dword 8-11 (m3) is the first vertex data.
+void
+vec4_visitor::emit_clip_distances(struct brw_reg reg, int offset)
+{
+   if (intel->gen < 6) {
+      /* Clip distance slots are set aside in gen5, but they are not used.  It
+       * is not clear whether we actually need to set aside space for them,
+       * but the performance cost is negligible.
        */
-      current_annotation = "NDC";
-      emit(MOV(brw_message_reg(header_mrf++),
-               src_reg(output_reg[BRW_VERT_RESULT_NDC])));
+      return;
+   }
 
-      current_annotation = "gl_Position";
-      emit(MOV(brw_message_reg(header_mrf++),
-               src_reg(output_reg[VERT_RESULT_HPOS])));
+   /* From the GLSL 1.30 spec, section 7.1 (Vertex Shader Special Variables):
+    *
+    *     "If a linked set of shaders forming the vertex stage contains no
+    *     static write to gl_ClipVertex or gl_ClipDistance, but the
+    *     application has requested clipping against user clip planes through
+    *     the API, then the coordinate written to gl_Position is used for
+    *     comparison against the user clip planes."
+    *
+    * This function is only called if the shader didn't write to
+    * gl_ClipDistance.  Accordingly, we use gl_ClipVertex to perform clipping
+    * if the user wrote to it; otherwise we use gl_Position.
+    */
+   gl_vert_result clip_vertex = VERT_RESULT_CLIP_VERTEX;
+   if (!(c->prog_data.outputs_written
+         & BITFIELD64_BIT(VERT_RESULT_CLIP_VERTEX))) {
+      clip_vertex = VERT_RESULT_HPOS;
    }
 
-   return header_mrf;
+   for (int i = 0; i + offset < c->key.nr_userclip_plane_consts && i < 4;
+        ++i) {
+      emit(DP4(dst_reg(brw_writemask(reg, 1 << i)),
+               src_reg(output_reg[clip_vertex]),
+               src_reg(this->userplane[i + offset])));
+   }
 }
 
-int
-vec4_visitor::emit_vue_header_gen6(int header_mrf)
+void
+vec4_visitor::emit_generic_urb_slot(dst_reg reg, int vert_result)
 {
-   struct brw_reg reg;
+   assert (vert_result < VERT_RESULT_MAX);
+   reg.type = output_reg[vert_result].type;
+   current_annotation = output_reg_annotation[vert_result];
+   /* Copy the register, saturating if necessary */
+   vec4_instruction *inst = emit(MOV(reg,
+                                     src_reg(output_reg[vert_result])));
+   if ((vert_result == VERT_RESULT_COL0 ||
+        vert_result == VERT_RESULT_COL1 ||
+        vert_result == VERT_RESULT_BFC0 ||
+        vert_result == VERT_RESULT_BFC1) &&
+       c->key.clamp_vertex_color) {
+      inst->saturate = true;
+   }
+}
 
-   /* There are 8 or 16 DWs (D0-D15) in VUE header on Sandybridge:
-    * dword 0-3 (m2) of the header is indices, point width, clip flags.
-    * dword 4-7 (m3) is the 4D space position
-    * dword 8-15 (m4,m5) of the vertex header is the user clip distance if
-    * enabled.
-    *
-    * m4 or 6 is the first vertex element data we fill.
-    */
+void
+vec4_visitor::emit_urb_slot(int mrf, int vert_result)
+{
+   struct brw_reg hw_reg = brw_message_reg(mrf);
+   dst_reg reg = dst_reg(MRF, mrf);
+   reg.type = BRW_REGISTER_TYPE_F;
 
-   current_annotation = "indices, point width, clip flags";
-   reg = brw_message_reg(header_mrf++);
-   emit(MOV(retype(reg, BRW_REGISTER_TYPE_D), src_reg(0)));
-   if (c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) {
-      emit(MOV(brw_writemask(reg, WRITEMASK_W),
-              src_reg(output_reg[VERT_RESULT_PSIZ])));
-   }
-
-   current_annotation = "gl_Position";
-   emit(MOV(brw_message_reg(header_mrf++),
-           src_reg(output_reg[VERT_RESULT_HPOS])));
-
-   current_annotation = "user clip distances";
-   if (c->key.nr_userclip) {
-      for (int i = 0; i < c->key.nr_userclip; i++) {
-        struct brw_reg m;
-        if (i < 4)
-           m = brw_message_reg(header_mrf);
-        else
-           m = brw_message_reg(header_mrf + 1);
-
-        emit(DP4(dst_reg(brw_writemask(m, 1 << (i & 3))),
-                 src_reg(output_reg[VERT_RESULT_HPOS]),
-                 src_reg(c->userplane[i])));
+   switch (vert_result) {
+   case VERT_RESULT_PSIZ:
+      /* PSIZ is always in slot 0, and is coupled with other flags. */
+      current_annotation = "indices, point width, clip flags";
+      emit_psiz_and_flags(hw_reg);
+      break;
+   case BRW_VERT_RESULT_NDC:
+      current_annotation = "NDC";
+      emit(MOV(reg, src_reg(output_reg[BRW_VERT_RESULT_NDC])));
+      break;
+   case BRW_VERT_RESULT_HPOS_DUPLICATE:
+   case VERT_RESULT_HPOS:
+      current_annotation = "gl_Position";
+      emit(MOV(reg, src_reg(output_reg[VERT_RESULT_HPOS])));
+      break;
+   case VERT_RESULT_CLIP_DIST0:
+   case VERT_RESULT_CLIP_DIST1:
+      if (this->c->key.uses_clip_distance) {
+         emit_generic_urb_slot(reg, vert_result);
+      } else {
+         current_annotation = "user clip distances";
+         emit_clip_distances(hw_reg, (vert_result - VERT_RESULT_CLIP_DIST0) * 4);
       }
-      header_mrf += 2;
+      break;
+   case BRW_VERT_RESULT_PAD:
+      /* No need to write to this slot */
+      break;
+   default:
+      emit_generic_urb_slot(reg, vert_result);
+      break;
    }
-
-   current_annotation = NULL;
-
-   return header_mrf;
 }
 
 static int
@@ -1901,87 +2238,62 @@ vec4_visitor::emit_urb_writes()
     */
    int base_mrf = 1;
    int mrf = base_mrf;
-   int urb_entry_size;
-   uint64_t outputs_remaining = c->prog_data.outputs_written;
    /* In the process of generating our URB write message contents, we
     * may need to unspill a register or load from an array.  Those
     * reads would use MRFs 14-15.
     */
    int max_usable_mrf = 13;
 
+   /* The following assertion verifies that max_usable_mrf causes an
+    * even-numbered amount of URB write data, which will meet gen6's
+    * requirements for length alignment.
+    */
+   assert ((max_usable_mrf - base_mrf) % 2 == 0);
+
    /* FINISHME: edgeflag */
 
+   brw_compute_vue_map(&c->vue_map, intel, &c->prog_data);
+
    /* First mrf is the g0-based message header containing URB handles and such,
     * which is implied in VS_OPCODE_URB_WRITE.
     */
    mrf++;
 
-   if (intel->gen >= 6) {
-      mrf = emit_vue_header_gen6(mrf);
-   } else {
-      mrf = emit_vue_header_gen4(mrf);
+   if (intel->gen < 6) {
+      emit_ndc_computation();
    }
 
    /* Set up the VUE data for the first URB write */
-   int attr;
-   for (attr = 0; attr < VERT_RESULT_MAX; attr++) {
-      if (!(c->prog_data.outputs_written & BITFIELD64_BIT(attr)))
-        continue;
-
-      outputs_remaining &= ~BITFIELD64_BIT(attr);
+   int slot;
+   for (slot = 0; slot < c->vue_map.num_slots; ++slot) {
+      emit_urb_slot(mrf++, c->vue_map.slot_to_vert_result[slot]);
 
-      /* This is set up in the VUE header. */
-      if (attr == VERT_RESULT_HPOS)
-        continue;
-
-      /* This is loaded into the VUE header, and thus doesn't occupy
-       * an attribute slot.
-       */
-      if (attr == VERT_RESULT_PSIZ)
-        continue;
-
-      vec4_instruction *inst = emit(MOV(brw_message_reg(mrf++),
-                                       src_reg(output_reg[attr])));
-
-      if ((attr == VERT_RESULT_COL0 ||
-          attr == VERT_RESULT_COL1 ||
-          attr == VERT_RESULT_BFC0 ||
-          attr == VERT_RESULT_BFC1) &&
-         c->key.clamp_vertex_color) {
-        inst->saturate = true;
-      }
-
-      /* If this was MRF 15, we can't fit anything more into this URB
-       * WRITE.  Note that base_mrf of 1 means that MRF 15 is an
-       * even-numbered amount of URB write data, which will meet
-       * gen6's requirements for length alignment.
+      /* If this was max_usable_mrf, we can't fit anything more into this URB
+       * WRITE.
        */
       if (mrf > max_usable_mrf) {
-        attr++;
+        slot++;
         break;
       }
    }
 
+   current_annotation = "URB write";
    vec4_instruction *inst = emit(VS_OPCODE_URB_WRITE);
    inst->base_mrf = base_mrf;
    inst->mlen = align_interleaved_urb_mlen(brw, mrf - base_mrf);
-   inst->eot = !outputs_remaining;
-
-   urb_entry_size = mrf - base_mrf;
+   inst->eot = (slot >= c->vue_map.num_slots);
 
    /* Optional second URB write */
-   if (outputs_remaining) {
+   if (!inst->eot) {
       mrf = base_mrf + 1;
 
-      for (; attr < VERT_RESULT_MAX; attr++) {
-        if (!(c->prog_data.outputs_written & BITFIELD64_BIT(attr)))
-           continue;
-
+      for (; slot < c->vue_map.num_slots; ++slot) {
         assert(mrf < max_usable_mrf);
 
-        emit(MOV(brw_message_reg(mrf++), src_reg(output_reg[attr])));
+         emit_urb_slot(mrf++, c->vue_map.slot_to_vert_result[slot]);
       }
 
+      current_annotation = "URB write";
       inst = emit(VS_OPCODE_URB_WRITE);
       inst->base_mrf = base_mrf;
       inst->mlen = align_interleaved_urb_mlen(brw, mrf - base_mrf);
@@ -1992,14 +2304,7 @@ vec4_visitor::emit_urb_writes()
        * those, since we're doing interleaved writes.
        */
       inst->offset = (max_usable_mrf - base_mrf) / 2;
-
-      urb_entry_size += mrf - base_mrf;
    }
-
-   if (intel->gen == 6)
-      c->prog_data.urb_entry_size = ALIGN(urb_entry_size, 8) / 8;
-   else
-      c->prog_data.urb_entry_size = ALIGN(urb_entry_size, 4) / 4;
 }
 
 src_reg
@@ -2230,7 +2535,7 @@ vec4_visitor::move_uniform_array_access_to_pull_constants()
         if (pull_constant_loc[uniform] == -1) {
            const float **values = &prog_data->param[uniform * 4];
 
-           pull_constant_loc[uniform] = prog_data->nr_pull_params;
+           pull_constant_loc[uniform] = prog_data->nr_pull_params / 4;
 
            for (int j = 0; j < uniform_size[uniform] * 4; j++) {
               prog_data->pull_param[prog_data->nr_pull_params++] = values[j];
@@ -2261,6 +2566,18 @@ vec4_visitor::move_uniform_array_access_to_pull_constants()
    split_uniform_registers();
 }
 
+void
+vec4_visitor::resolve_ud_negate(src_reg *reg)
+{
+   if (reg->type != BRW_REGISTER_TYPE_UD ||
+       !reg->negate)
+      return;
+
+   src_reg temp = src_reg(this, glsl_type::uvec4_type);
+   emit(BRW_OPCODE_MOV, dst_reg(temp), *reg);
+   *reg = temp;
+}
+
 vec4_visitor::vec4_visitor(struct brw_vs_compile *c,
                           struct gl_shader_program *prog,
                           struct brw_shader *shader)
@@ -2280,7 +2597,8 @@ vec4_visitor::vec4_visitor(struct brw_vs_compile *c,
    this->current_annotation = NULL;
 
    this->c = c;
-   this->vp = prog->VertexProgram;
+   this->vp = (struct gl_vertex_program *)
+     prog->_LinkedShaders[MESA_SHADER_VERTEX]->Program;
    this->prog_data = &c->prog_data;
 
    this->variable_ht = hash_table_ctor(0,
@@ -2291,14 +2609,14 @@ vec4_visitor::vec4_visitor(struct brw_vs_compile *c,
    this->virtual_grf_use = NULL;
    this->virtual_grf_sizes = NULL;
    this->virtual_grf_count = 0;
+   this->virtual_grf_reg_map = NULL;
+   this->virtual_grf_reg_count = 0;
    this->virtual_grf_array_size = 0;
    this->live_intervals_valid = false;
 
-   this->uniforms = 0;
+   this->max_grf = intel->gen >= 7 ? GEN7_MRF_HACK_START : BRW_MAX_GRF;
 
-   this->variable_ht = hash_table_ctor(0,
-                                      hash_table_pointer_hash,
-                                      hash_table_pointer_compare);
+   this->uniforms = 0;
 }
 
 vec4_visitor::~vec4_visitor()