i965/vec4: Simplify opt_reduce_swizzle() using the swizzle utils.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_fs_nir.cpp
index 7b83a35a940779fd601369adc2798bde9d16fe18..69f296ce8c041de12f5e4a9f099e24dea8a11e30 100644 (file)
@@ -25,6 +25,7 @@
 #include "glsl/ir_optimization.h"
 #include "glsl/nir/glsl_to_nir.h"
 #include "brw_fs.h"
+#include "brw_nir.h"
 
 static void
 nir_optimize(nir_shader *nir)
@@ -105,6 +106,12 @@ fs_visitor::emit_nir_code()
    /* Get rid of split copies */
    nir_optimize(nir);
 
+   nir_assign_var_locations_scalar_direct_first(nir, &nir->uniforms,
+                                                &num_direct_uniforms,
+                                                &nir->num_uniforms);
+   nir_assign_var_locations_scalar(&nir->inputs, &nir->num_inputs);
+   nir_assign_var_locations_scalar(&nir->outputs, &nir->num_outputs);
+
    nir_lower_io(nir);
    nir_validate_shader(nir);
 
@@ -149,6 +156,14 @@ fs_visitor::emit_nir_code()
    nir_convert_from_ssa(nir);
    nir_validate_shader(nir);
 
+   /* This is the last pass we run before we start emitting stuff.  It
+    * determines when we need to insert boolean resolves on Gen <= 5.  We
+    * run it last because it stashes data in instr->pass_flags and we don't
+    * want that to be squashed by other NIR passes.
+    */
+   if (brw->gen <= 5)
+      brw_nir_analyze_boolean_resolves(nir);
+
    /* emit the arrays used for inputs and outputs - load/store intrinsics will
     * be converted to reads/writes of these arrays
     */
@@ -164,7 +179,6 @@ fs_visitor::emit_nir_code()
    }
 
    if (nir->num_uniforms > 0) {
-      nir_uniforms = fs_reg(UNIFORM, 0);
       nir_setup_uniforms(nir);
    }
 
@@ -196,21 +210,49 @@ fs_visitor::emit_nir_code()
 void
 fs_visitor::nir_setup_inputs(nir_shader *shader)
 {
-   struct hash_entry *entry;
-   hash_table_foreach(shader->inputs, entry) {
-      nir_variable *var = (nir_variable *) entry->data;
-      fs_reg varying = offset(nir_inputs, var->data.driver_location);
+   foreach_list_typed(nir_variable, var, node, &shader->inputs) {
+      enum brw_reg_type type = brw_type_for_base_type(var->type);
+      fs_reg input = offset(nir_inputs, var->data.driver_location);
 
       fs_reg reg;
-      if (var->data.location == VARYING_SLOT_POS) {
-         reg = *emit_fragcoord_interpolation(var->data.pixel_center_integer,
-                                             var->data.origin_upper_left);
-         emit_percomp(MOV(varying, reg), 0xF);
-      } else {
-         emit_general_interpolation(varying, var->name, var->type,
-                                    (glsl_interp_qualifier) var->data.interpolation,
-                                    var->data.location, var->data.centroid,
-                                    var->data.sample);
+      switch (stage) {
+      case MESA_SHADER_VERTEX: {
+         /* Our ATTR file is indexed by VERT_ATTRIB_*, which is the value
+          * stored in nir_variable::location.
+          *
+          * However, NIR's load_input intrinsics use a different index - an
+          * offset into a single contiguous array containing all inputs.
+          * This index corresponds to the nir_variable::driver_location field.
+          *
+          * So, we need to copy from fs_reg(ATTR, var->location) to
+          * offset(nir_inputs, var->data.driver_location).
+          */
+         unsigned components = var->type->without_array()->components();
+         unsigned array_length = var->type->is_array() ? var->type->length : 1;
+         for (unsigned i = 0; i < array_length; i++) {
+            for (unsigned j = 0; j < components; j++) {
+               emit(MOV(retype(offset(input, components * i + j), type),
+                        offset(fs_reg(ATTR, var->data.location + i, type), j)));
+            }
+         }
+         break;
+      }
+      case MESA_SHADER_GEOMETRY:
+      case MESA_SHADER_COMPUTE:
+         unreachable("fs_visitor not used for these stages yet.");
+         break;
+      case MESA_SHADER_FRAGMENT:
+         if (var->data.location == VARYING_SLOT_POS) {
+            reg = *emit_fragcoord_interpolation(var->data.pixel_center_integer,
+                                                var->data.origin_upper_left);
+            emit_percomp(MOV(input, reg), 0xF);
+         } else {
+            emit_general_interpolation(input, var->name, var->type,
+                                       (glsl_interp_qualifier) var->data.interpolation,
+                                       var->data.location, var->data.centroid,
+                                       var->data.sample);
+         }
+         break;
       }
    }
 }
@@ -220,12 +262,20 @@ fs_visitor::nir_setup_outputs(nir_shader *shader)
 {
    brw_wm_prog_key *key = (brw_wm_prog_key*) this->key;
 
-   struct hash_entry *entry;
-   hash_table_foreach(shader->outputs, entry) {
-      nir_variable *var = (nir_variable *) entry->data;
+   foreach_list_typed(nir_variable, var, node, &shader->outputs) {
       fs_reg reg = offset(nir_outputs, var->data.driver_location);
 
-      if (var->data.index > 0) {
+      int vector_elements =
+         var->type->is_array() ? var->type->fields.array->vector_elements
+                               : var->type->vector_elements;
+
+      if (stage == MESA_SHADER_VERTEX) {
+         for (int i = 0; i < ALIGN(type_size(var->type), 4) / 4; i++) {
+            int output = var->data.location + i;
+            this->outputs[output] = offset(reg, 4 * i);
+            this->output_components[output] = vector_elements;
+         }
+      } else if (var->data.index > 0) {
          assert(var->data.location == FRAG_RESULT_DATA0);
          assert(var->data.index == 1);
          this->dual_src_output = reg;
@@ -245,10 +295,6 @@ fs_visitor::nir_setup_outputs(nir_shader *shader)
          assert(var->data.location >= FRAG_RESULT_DATA0 &&
                 var->data.location < FRAG_RESULT_DATA0 + BRW_MAX_DRAW_BUFFERS);
 
-         int vector_elements =
-            var->type->is_array() ? var->type->fields.array->vector_elements
-                                  : var->type->vector_elements;
-
          /* General color output. */
          for (unsigned int i = 0; i < MAX2(1, var->type->length); i++) {
             int output = var->data.location - FRAG_RESULT_DATA0 + i;
@@ -263,15 +309,18 @@ void
 fs_visitor::nir_setup_uniforms(nir_shader *shader)
 {
    uniforms = shader->num_uniforms;
-   param_size[0] = shader->num_uniforms;
+
+   /* We split the uniform register file in half.  The first half is
+    * entirely direct uniforms.  The second half is indirect.
+    */
+   param_size[0] = num_direct_uniforms;
+   if (shader->num_uniforms > num_direct_uniforms)
+      param_size[num_direct_uniforms] = shader->num_uniforms - num_direct_uniforms;
 
    if (dispatch_width != 8)
       return;
 
-   struct hash_entry *entry;
-   hash_table_foreach(shader->uniforms, entry) {
-      nir_variable *var = (nir_variable *) entry->data;
-
+   foreach_list_typed(nir_variable, var, node, &shader->uniforms) {
       /* UBO's and atomics don't take up space in the uniform file */
 
       if (var->interface_type != NULL || var->type->contains_atomic())
@@ -473,7 +522,7 @@ fs_visitor::nir_emit_if(nir_if *if_stmt)
    /* first, put the condition into f0 */
    fs_inst *inst = emit(MOV(reg_null_d,
                             retype(get_nir_src(if_stmt->condition),
-                                   BRW_REGISTER_TYPE_UD)));
+                                   BRW_REGISTER_TYPE_D)));
    inst->conditional_mod = BRW_CONDITIONAL_NZ;
 
    emit(IF(BRW_PREDICATE_NORMAL));
@@ -549,9 +598,9 @@ static brw_reg_type
 brw_type_for_nir_type(nir_alu_type type)
 {
    switch (type) {
-   case nir_type_bool:
    case nir_type_unsigned:
       return BRW_REGISTER_TYPE_UD;
+   case nir_type_bool:
    case nir_type_int:
       return BRW_REGISTER_TYPE_D;
    case nir_type_float:
@@ -1096,6 +1145,7 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr)
       } else {
          emit(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_L));
          inst = emit(SEL(result, op[0], op[1]));
+         inst->predicate = BRW_PREDICATE_NORMAL;
       }
       inst->saturate = instr->dest.saturate;
       break;
@@ -1109,6 +1159,7 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr)
       } else {
          emit(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_GE));
          inst = emit(SEL(result, op[0], op[1]));
+         inst->predicate = BRW_PREDICATE_NORMAL;
       }
       inst->saturate = instr->dest.saturate;
       break;
@@ -1203,8 +1254,7 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr)
       break;
 
    case nir_op_flrp:
-      /* TODO emulate for gen < 6 */
-      inst = emit(LRP(result, op[2], op[1], op[0]));
+      inst = emit_lrp(result, op[0], op[1], op[2]);
       inst->saturate = instr->dest.saturate;
       break;
 
@@ -1220,6 +1270,17 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr)
    default:
       unreachable("unhandled instruction");
    }
+
+   /* If we need to do a boolean resolve, replace the result with -(x & 1)
+    * to sign extend the low bit to 0/~0
+    */
+   if (brw->gen <= 5 &&
+       (instr->instr.pass_flags & BRW_NIR_BOOLEAN_MASK) == BRW_NIR_BOOLEAN_NEEDS_RESOLVE) {
+      fs_reg masked = vgrf(glsl_type::int_type);
+      emit(AND(masked, result, fs_reg(1)));
+      masked.negate = true;
+      emit(MOV(retype(result, BRW_REGISTER_TYPE_D), masked));
+   }
 }
 
 fs_reg
@@ -1323,18 +1384,8 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr)
       cmp->flag_subreg = 1;
 
       if (brw->gen >= 6) {
-         /* For performance, after a discard, jump to the end of the shader.
-         * Only jump if all relevant channels have been discarded.
-         */
-         fs_inst *discard_jump = emit(FS_OPCODE_DISCARD_JUMP);
-         discard_jump->flag_subreg = 1;
-
-         discard_jump->predicate = (dispatch_width == 8)
-                                 ? BRW_PREDICATE_ALIGN1_ANY8H
-                                 : BRW_PREDICATE_ALIGN1_ANY16H;
-         discard_jump->predicate_inverse = true;
+         emit_discard_jump();
       }
-
       break;
    }
 
@@ -1423,11 +1474,19 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr)
    case nir_intrinsic_load_uniform_indirect:
       has_indirect = true;
    case nir_intrinsic_load_uniform: {
-      unsigned index = 0;
+      unsigned index = instr->const_index[0];
+
+      fs_reg uniform_reg;
+      if (index < num_direct_uniforms) {
+         uniform_reg = fs_reg(UNIFORM, 0);
+      } else {
+         uniform_reg = fs_reg(UNIFORM, num_direct_uniforms);
+         index -= num_direct_uniforms;
+      }
+
       for (int i = 0; i < instr->const_index[1]; i++) {
          for (unsigned j = 0; j < instr->num_components; j++) {
-            fs_reg src = offset(retype(nir_uniforms, dest.type),
-                                instr->const_index[0] + index);
+            fs_reg src = offset(retype(uniform_reg, dest.type), index);
             if (has_indirect)
                src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[0]));
             index++;