mesa: add/update comments in _mesa_copy_buffer_subdata()
[mesa.git] / src / mesa / drivers / dri / i965 / brw_vec4_visitor.cpp
index 680bd7d0520e49de7d99405477c8e4ff09a8b4e1..20da487399f74e84bc439f5d77dce18f749b45d9 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;
@@ -209,6 +213,9 @@ vec4_visitor::CMP(dst_reg dst, src_reg src0, src_reg src1, uint32_t condition)
         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;
 
@@ -496,9 +503,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);
@@ -559,18 +564,29 @@ 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 < MAX_CLIP_PLANES; ++i) {
-      if (c->key.userclip_planes_enabled & (1 << i)) {
-         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;
+   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;
    }
 }
 
@@ -632,6 +648,8 @@ vec4_visitor::emit_bool_to_cond_code(ir_rvalue *ir, uint32_t *predicate)
       for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
         expr->operands[i]->accept(this);
         op[i] = this->result;
+
+        resolve_ud_negate(&op[i]);
       }
 
       switch (expr->operation) {
@@ -707,6 +725,8 @@ vec4_visitor::emit_bool_to_cond_code(ir_rvalue *ir, uint32_t *predicate)
 
    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)));
@@ -823,6 +843,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)));
       }
@@ -834,7 +855,8 @@ 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;
@@ -859,6 +881,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");
    }
@@ -954,7 +997,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();
@@ -1538,7 +1581,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;
@@ -1712,13 +1756,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.
-    */
-   this->result = src_reg(this, glsl_type::vec4_type);
+   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
@@ -1807,7 +2016,7 @@ vec4_visitor::emit_psiz_and_flags(struct brw_reg reg)
       }
 
       current_annotation = "Clipping flags";
-      for (i = 0; i < c->key.nr_userclip_planes; i++) {
+      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]),
@@ -1883,7 +2092,8 @@ vec4_visitor::emit_clip_distances(struct brw_reg reg, int offset)
       clip_vertex = VERT_RESULT_HPOS;
    }
 
-   for (int i = 0; i + offset < c->key.nr_userclip_planes && i < 4; ++i) {
+   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])));
@@ -1894,6 +2104,7 @@ void
 vec4_visitor::emit_generic_urb_slot(dst_reg reg, int vert_result)
 {
    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,
@@ -2316,6 +2527,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)
@@ -2335,7 +2558,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,