X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fdri%2Fi965%2Fbrw_fs_nir.cpp;h=a059dbb6a562e984207dced848be66440de6f527;hb=235c728020af352ee0f4b7d598c951f4a4e83232;hp=aab74298fae0f2e80ee582358a4140925b44a4f5;hpb=4582341ea74a076c981c962f1a01311bfa3bf991;p=mesa.git diff --git a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp index aab74298fae..a059dbb6a56 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp @@ -21,35 +21,100 @@ * IN THE SOFTWARE. */ +#include "glsl/ir.h" +#include "glsl/ir_optimization.h" #include "glsl/nir/glsl_to_nir.h" #include "brw_fs.h" -static glsl_interp_qualifier -determine_interpolation_mode(nir_variable *var, bool flat_shade) +static void +nir_optimize(nir_shader *nir) { - if (var->data.interpolation != INTERP_QUALIFIER_NONE) - return (glsl_interp_qualifier) var->data.interpolation; - int location = var->data.location; - bool is_gl_Color = - location == VARYING_SLOT_COL0 || location == VARYING_SLOT_COL1; - if (flat_shade && is_gl_Color) - return INTERP_QUALIFIER_FLAT; - else - return INTERP_QUALIFIER_SMOOTH; + bool progress; + do { + progress = false; + nir_lower_vars_to_ssa(nir); + nir_validate_shader(nir); + nir_lower_alu_to_scalar(nir); + nir_validate_shader(nir); + progress |= nir_copy_prop(nir); + nir_validate_shader(nir); + nir_lower_phis_to_scalar(nir); + nir_validate_shader(nir); + progress |= nir_copy_prop(nir); + nir_validate_shader(nir); + progress |= nir_opt_dce(nir); + nir_validate_shader(nir); + progress |= nir_opt_cse(nir); + nir_validate_shader(nir); + progress |= nir_opt_peephole_select(nir); + nir_validate_shader(nir); + progress |= nir_opt_algebraic(nir); + nir_validate_shader(nir); + progress |= nir_opt_constant_folding(nir); + nir_validate_shader(nir); + progress |= nir_opt_remove_phis(nir); + nir_validate_shader(nir); + } while (progress); +} + +static bool +count_nir_instrs_in_block(nir_block *block, void *state) +{ + int *count = (int *) state; + nir_foreach_instr(block, instr) { + *count = *count + 1; + } + return true; +} + +static int +count_nir_instrs(nir_shader *nir) +{ + int count = 0; + nir_foreach_overload(nir, overload) { + if (!overload->impl) + continue; + nir_foreach_block(overload->impl, count_nir_instrs_in_block, &count); + } + return count; } void fs_visitor::emit_nir_code() { + const nir_shader_compiler_options *options = + ctx->Const.ShaderCompilerOptions[stage].NirOptions; + /* first, lower the GLSL IR shader to NIR */ - nir_shader *nir = glsl_to_nir(shader->base.ir, NULL, true); + lower_output_reads(shader->base.ir); + nir_shader *nir = glsl_to_nir(&shader->base, options); nir_validate_shader(nir); - /* lower some of the GLSL-isms into NIR-isms - after this point, we no - * longer have to deal with variables inside the shader - */ + nir_lower_global_vars_to_local(nir); + nir_validate_shader(nir); - nir_lower_variables_scalar(nir, true, true, true, true); + nir_split_var_copies(nir); + nir_validate_shader(nir); + + nir_optimize(nir); + + /* Lower a bunch of stuff */ + nir_lower_var_copies(nir); + nir_validate_shader(nir); + + /* 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); + + nir_remove_dead_variables(nir); nir_validate_shader(nir); nir_lower_samplers(nir, shader_prog, shader->base.Program); @@ -61,33 +126,62 @@ fs_visitor::emit_nir_code() nir_lower_atomics(nir); nir_validate_shader(nir); - nir_remove_dead_variables(nir); - nir_opt_global_to_local(nir); + nir_optimize(nir); + + nir_lower_locals_to_regs(nir); + nir_validate_shader(nir); + + nir_lower_to_source_mods(nir); + nir_validate_shader(nir); + nir_copy_prop(nir); nir_validate_shader(nir); - if (1) + if (unlikely(debug_enabled)) { + fprintf(stderr, "NIR (SSA form) for %s shader:\n", stage_name); nir_print_shader(nir, stderr); + } + + if (dispatch_width == 8) { + static GLuint msg_id = 0; + _mesa_gl_debug(&brw->ctx, &msg_id, + MESA_DEBUG_SOURCE_SHADER_COMPILER, + MESA_DEBUG_TYPE_OTHER, + MESA_DEBUG_SEVERITY_NOTIFICATION, + "%s NIR shader: %d inst\n", + stage_abbrev, + count_nir_instrs(nir)); + } + + nir_convert_from_ssa(nir); + nir_validate_shader(nir); /* emit the arrays used for inputs and outputs - load/store intrinsics will * be converted to reads/writes of these arrays */ if (nir->num_inputs > 0) { - nir_inputs = fs_reg(GRF, virtual_grf_alloc(nir->num_inputs)); + nir_inputs = vgrf(nir->num_inputs); nir_setup_inputs(nir); } if (nir->num_outputs > 0) { - nir_outputs = fs_reg(GRF, virtual_grf_alloc(nir->num_outputs)); + nir_outputs = vgrf(nir->num_outputs); nir_setup_outputs(nir); } if (nir->num_uniforms > 0) { - nir_uniforms = fs_reg(UNIFORM, 0); nir_setup_uniforms(nir); } - nir_setup_registers(&nir->registers); + nir_emit_system_values(nir); + + nir_globals = ralloc_array(mem_ctx, fs_reg, nir->reg_alloc); + foreach_list_typed(nir_register, reg, node, &nir->registers) { + unsigned array_elems = + reg->num_array_elems == 0 ? 1 : reg->num_array_elems; + unsigned size = array_elems * reg->num_components; + nir_globals[reg->index] = vgrf(size); + } /* get the main function and emit it */ nir_foreach_overload(nir, overload) { @@ -96,123 +190,60 @@ fs_visitor::emit_nir_code() nir_emit_impl(overload->impl); } + if (unlikely(debug_enabled)) { + fprintf(stderr, "NIR (final form) for %s shader:\n", stage_name); + nir_print_shader(nir, stderr); + } + ralloc_free(nir); } void fs_visitor::nir_setup_inputs(nir_shader *shader) { - fs_reg varying = nir_inputs; - - struct hash_entry *entry; - hash_table_foreach(shader->inputs, entry) { - nir_variable *var = (nir_variable *) entry->data; - varying.reg_offset = 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 (!strcmp(var->name, "gl_FragCoord")) { - reg = *emit_fragcoord_interpolation(var->data.pixel_center_integer, - var->data.origin_upper_left); - emit_percomp(MOV(varying, reg), 0xF); - } else if (!strcmp(var->name, "gl_FrontFacing")) { - reg = *emit_frontfacing_interpolation(); - emit(MOV(retype(varying, BRW_REGISTER_TYPE_UD), reg)); - } else { - nir_emit_interpolation(var, &varying); - } - } -} - -void -fs_visitor::nir_emit_interpolation(nir_variable *var, fs_reg *varying) -{ - brw_wm_prog_data *prog_data = (brw_wm_prog_data*) this->prog_data; - brw_wm_prog_key *key = (brw_wm_prog_key*) this->key; - fs_reg reg = *varying; - reg.type = brw_type_for_base_type(var->type->get_scalar_type()); - - unsigned int array_elements; - const glsl_type *type; - - if (var->type->is_array()) { - array_elements = var->type->length; - if (array_elements == 0) { - fail("dereferenced array '%s' has length 0\n", var->name); - } - type = var->type->fields.array; - } else { - array_elements = 1; - type = var->type; - } - - glsl_interp_qualifier interpolation_mode = - determine_interpolation_mode(var, key->flat_shade); - - int location = var->data.location; - for (unsigned int i = 0; i < array_elements; i++) { - for (unsigned int j = 0; j < type->matrix_columns; j++) { - if (prog_data->urb_setup[location] == -1) { - /* If there's no incoming setup data for this slot, don't - * emit interpolation for it. - */ - reg.reg_offset += type->vector_elements; - location++; - continue; - } - - if (interpolation_mode == INTERP_QUALIFIER_FLAT) { - /* Constant interpolation (flat shading) case. The SF has - * handed us defined values in only the constant offset - * field of the setup reg. - */ - for (unsigned int k = 0; k < type->vector_elements; k++) { - struct brw_reg interp = interp_reg(location, k); - interp = suboffset(interp, 3); - interp.type = reg.type; - emit(FS_OPCODE_CINTERP, reg, fs_reg(interp)); - reg.reg_offset++; + 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 { - /* Smooth/noperspective interpolation case. */ - for (unsigned int k = 0; k < type->vector_elements; k++) { - struct brw_reg interp = interp_reg(location, k); - if (brw->needs_unlit_centroid_workaround && var->data.centroid) { - /* Get the pixel/sample mask into f0 so that we know - * which pixels are lit. Then, for each channel that is - * unlit, replace the centroid data with non-centroid - * data. - */ - emit(FS_OPCODE_MOV_DISPATCH_TO_FLAGS); - - fs_inst *inst; - inst = emit_linterp(reg, fs_reg(interp), interpolation_mode, - false, false); - inst->predicate = BRW_PREDICATE_NORMAL; - inst->predicate_inverse = true; - if (brw->has_pln) - inst->no_dd_clear = true; - - inst = emit_linterp(reg, fs_reg(interp), interpolation_mode, - var->data.centroid && !key->persample_shading, - var->data.sample || key->persample_shading); - inst->predicate = BRW_PREDICATE_NORMAL; - inst->predicate_inverse = false; - if (brw->has_pln) - inst->no_dd_check = true; - - } else { - emit_linterp(reg, fs_reg(interp), interpolation_mode, - var->data.centroid && !key->persample_shading, - var->data.sample || key->persample_shading); - } - if (brw->gen < 6 && interpolation_mode == INTERP_QUALIFIER_SMOOTH) { - emit(BRW_OPCODE_MUL, reg, reg, this->pixel_w); - } - reg.reg_offset++; - } - + emit_general_interpolation(input, var->name, var->type, + (glsl_interp_qualifier) var->data.interpolation, + var->data.location, var->data.centroid, + var->data.sample); } - location++; + break; } } } @@ -221,14 +252,21 @@ void fs_visitor::nir_setup_outputs(nir_shader *shader) { brw_wm_prog_key *key = (brw_wm_prog_key*) this->key; - fs_reg reg = nir_outputs; - struct hash_entry *entry; - hash_table_foreach(shader->outputs, entry) { - nir_variable *var = (nir_variable *) entry->data; - reg.reg_offset = var->data.driver_location; + 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; @@ -248,15 +286,10 @@ 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; - this->outputs[output] = reg; - this->outputs[output].reg_offset += vector_elements * i; + this->outputs[output] = offset(reg, vector_elements * i); this->output_components[output] = vector_elements; } } @@ -267,15 +300,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()) @@ -355,28 +391,102 @@ fs_visitor::nir_setup_builtin_uniform(nir_variable *var) } } +static bool +emit_system_values_block(nir_block *block, void *void_visitor) +{ + fs_visitor *v = (fs_visitor *)void_visitor; + fs_reg *reg; + + nir_foreach_instr(block, instr) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + switch (intrin->intrinsic) { + case nir_intrinsic_load_vertex_id: + unreachable("should be lowered by lower_vertex_id()."); + + case nir_intrinsic_load_vertex_id_zero_base: + assert(v->stage == MESA_SHADER_VERTEX); + reg = &v->nir_system_values[SYSTEM_VALUE_VERTEX_ID_ZERO_BASE]; + if (reg->file == BAD_FILE) + *reg = *v->emit_vs_system_value(SYSTEM_VALUE_VERTEX_ID_ZERO_BASE); + break; + + case nir_intrinsic_load_base_vertex: + assert(v->stage == MESA_SHADER_VERTEX); + reg = &v->nir_system_values[SYSTEM_VALUE_BASE_VERTEX]; + if (reg->file == BAD_FILE) + *reg = *v->emit_vs_system_value(SYSTEM_VALUE_BASE_VERTEX); + break; + + case nir_intrinsic_load_instance_id: + assert(v->stage == MESA_SHADER_VERTEX); + reg = &v->nir_system_values[SYSTEM_VALUE_INSTANCE_ID]; + if (reg->file == BAD_FILE) + *reg = *v->emit_vs_system_value(SYSTEM_VALUE_INSTANCE_ID); + break; + + case nir_intrinsic_load_sample_pos: + assert(v->stage == MESA_SHADER_FRAGMENT); + reg = &v->nir_system_values[SYSTEM_VALUE_SAMPLE_POS]; + if (reg->file == BAD_FILE) + *reg = *v->emit_samplepos_setup(); + break; + + case nir_intrinsic_load_sample_id: + assert(v->stage == MESA_SHADER_FRAGMENT); + reg = &v->nir_system_values[SYSTEM_VALUE_SAMPLE_ID]; + if (reg->file == BAD_FILE) + *reg = *v->emit_sampleid_setup(); + break; + + case nir_intrinsic_load_sample_mask_in: + assert(v->stage == MESA_SHADER_FRAGMENT); + assert(v->brw->gen >= 7); + reg = &v->nir_system_values[SYSTEM_VALUE_SAMPLE_MASK_IN]; + if (reg->file == BAD_FILE) + *reg = fs_reg(retype(brw_vec8_grf(v->payload.sample_mask_in_reg, 0), + BRW_REGISTER_TYPE_D)); + break; + + default: + break; + } + } + + return true; +} + void -fs_visitor::nir_setup_registers(exec_list *list) +fs_visitor::nir_emit_system_values(nir_shader *shader) { - foreach_list_typed(nir_register, nir_reg, node, list) { - unsigned array_elems = - nir_reg->num_array_elems == 0 ? 1 : nir_reg->num_array_elems; - unsigned size = array_elems * nir_reg->num_components; - fs_reg *reg = new(mem_ctx) fs_reg(GRF, virtual_grf_alloc(size)); - _mesa_hash_table_insert(this->nir_reg_ht, nir_reg, reg); + nir_system_values = ralloc_array(mem_ctx, fs_reg, SYSTEM_VALUE_MAX); + nir_foreach_overload(shader, overload) { + assert(strcmp(overload->function->name, "main") == 0); + assert(overload->impl); + nir_foreach_block(overload->impl, emit_system_values_block, this); } } void fs_visitor::nir_emit_impl(nir_function_impl *impl) { - nir_setup_registers(&impl->registers); + nir_locals = reralloc(mem_ctx, nir_locals, fs_reg, impl->reg_alloc); + foreach_list_typed(nir_register, reg, node, &impl->registers) { + unsigned array_elems = + reg->num_array_elems == 0 ? 1 : reg->num_array_elems; + unsigned size = array_elems * reg->num_components; + nir_locals[reg->index] = vgrf(size); + } + nir_emit_cf_list(&impl->body); } void fs_visitor::nir_emit_cf_list(exec_list *list) { + exec_list_validate(list); foreach_list_typed(nir_cf_node, node, node, list) { switch (node->type) { case nir_cf_node_if: @@ -400,10 +510,6 @@ fs_visitor::nir_emit_cf_list(exec_list *list) void fs_visitor::nir_emit_if(nir_if *if_stmt) { - if (brw->gen < 6) { - no16("Can't support (non-uniform) control flow on SIMD16\n"); - } - /* first, put the condition into f0 */ fs_inst *inst = emit(MOV(reg_null_d, retype(get_nir_src(if_stmt->condition), @@ -421,7 +527,9 @@ fs_visitor::nir_emit_if(nir_if *if_stmt) emit(BRW_OPCODE_ENDIF); - try_replace_with_sel(); + if (!try_replace_with_sel() && brw->gen < 6) { + no16("Can't support (non-uniform) control flow on SIMD16\n"); + } } void @@ -458,12 +566,14 @@ fs_visitor::nir_emit_instr(nir_instr *instr) nir_emit_intrinsic(nir_instr_as_intrinsic(instr)); break; - case nir_instr_type_texture: - nir_emit_texture(nir_instr_as_texture(instr)); + case nir_instr_type_tex: + nir_emit_texture(nir_instr_as_tex(instr)); break; case nir_instr_type_load_const: - nir_emit_load_const(nir_instr_as_load_const(instr)); + /* We can hit these, but we do nothing now and use them as + * immediates later. + */ break; case nir_instr_type_jump: @@ -493,43 +603,190 @@ brw_type_for_nir_type(nir_alu_type type) return BRW_REGISTER_TYPE_F; } +bool +fs_visitor::optimize_frontfacing_ternary(nir_alu_instr *instr, + const fs_reg &result) +{ + if (instr->src[0].src.is_ssa || + !instr->src[0].src.reg.reg || + !instr->src[0].src.reg.reg->parent_instr) + return false; + + if (instr->src[0].src.reg.reg->parent_instr->type != + nir_instr_type_intrinsic) + return false; + + nir_intrinsic_instr *src0 = + nir_instr_as_intrinsic(instr->src[0].src.reg.reg->parent_instr); + + if (src0->intrinsic != nir_intrinsic_load_front_face) + return false; + + nir_const_value *value1 = nir_src_as_const_value(instr->src[1].src); + if (!value1 || fabsf(value1->f[0]) != 1.0f) + return false; + + nir_const_value *value2 = nir_src_as_const_value(instr->src[2].src); + if (!value2 || fabsf(value2->f[0]) != 1.0f) + return false; + + fs_reg tmp = vgrf(glsl_type::int_type); + + if (brw->gen >= 6) { + /* Bit 15 of g0.0 is 0 if the polygon is front facing. */ + fs_reg g0 = fs_reg(retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_W)); + + /* For (gl_FrontFacing ? 1.0 : -1.0), emit: + * + * or(8) tmp.1<2>W g0.0<0,1,0>W 0x00003f80W + * and(8) dst<1>D tmp<8,8,1>D 0xbf800000D + * + * and negate g0.0<0,1,0>W for (gl_FrontFacing ? -1.0 : 1.0). + * + * This negation looks like it's safe in practice, because bits 0:4 will + * surely be TRIANGLES + */ + + if (value1->f[0] == -1.0f) { + g0.negate = true; + } + + tmp.type = BRW_REGISTER_TYPE_W; + tmp.subreg_offset = 2; + tmp.stride = 2; + + fs_inst *or_inst = emit(OR(tmp, g0, fs_reg(0x3f80))); + or_inst->src[1].type = BRW_REGISTER_TYPE_UW; + + tmp.type = BRW_REGISTER_TYPE_D; + tmp.subreg_offset = 0; + tmp.stride = 1; + } else { + /* Bit 31 of g1.6 is 0 if the polygon is front facing. */ + fs_reg g1_6 = fs_reg(retype(brw_vec1_grf(1, 6), BRW_REGISTER_TYPE_D)); + + /* For (gl_FrontFacing ? 1.0 : -1.0), emit: + * + * or(8) tmp<1>D g1.6<0,1,0>D 0x3f800000D + * and(8) dst<1>D tmp<8,8,1>D 0xbf800000D + * + * and negate g1.6<0,1,0>D for (gl_FrontFacing ? -1.0 : 1.0). + * + * This negation looks like it's safe in practice, because bits 0:4 will + * surely be TRIANGLES + */ + + if (value1->f[0] == -1.0f) { + g1_6.negate = true; + } + + emit(OR(tmp, g1_6, fs_reg(0x3f800000))); + } + emit(AND(retype(result, BRW_REGISTER_TYPE_D), tmp, fs_reg(0xbf800000))); + + return true; +} + void fs_visitor::nir_emit_alu(nir_alu_instr *instr) { struct brw_wm_prog_key *fs_key = (struct brw_wm_prog_key *) this->key; + fs_inst *inst; - fs_reg op[3]; - fs_reg dest = retype(get_nir_dest(instr->dest.dest), - brw_type_for_nir_type(nir_op_infos[instr->op].output_type)); + fs_reg result = get_nir_dest(instr->dest.dest); + result.type = brw_type_for_nir_type(nir_op_infos[instr->op].output_type); - fs_reg result; - if (instr->has_predicate) { - result = fs_reg(GRF, virtual_grf_alloc(4)); - result.type = dest.type; - } else { - result = dest; + fs_reg op[4]; + for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { + op[i] = get_nir_src(instr->src[i].src); + op[i].type = brw_type_for_nir_type(nir_op_infos[instr->op].input_types[i]); + op[i].abs = instr->src[i].abs; + op[i].negate = instr->src[i].negate; + } + + /* We get a bunch of mov's out of the from_ssa pass and they may still + * be vectorized. We'll handle them as a special-case. We'll also + * handle vecN here because it's basically the same thing. + */ + switch (instr->op) { + case nir_op_imov: + case nir_op_fmov: + case nir_op_vec2: + case nir_op_vec3: + case nir_op_vec4: { + fs_reg temp = result; + bool need_extra_copy = false; + for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { + if (!instr->src[i].src.is_ssa && + instr->dest.dest.reg.reg == instr->src[i].src.reg.reg) { + need_extra_copy = true; + temp = retype(vgrf(4), result.type); + break; + } + } + + for (unsigned i = 0; i < 4; i++) { + if (!(instr->dest.write_mask & (1 << i))) + continue; + + if (instr->op == nir_op_imov || instr->op == nir_op_fmov) { + inst = emit(MOV(offset(temp, i), + offset(op[0], instr->src[0].swizzle[i]))); + } else { + inst = emit(MOV(offset(temp, i), + offset(op[i], instr->src[i].swizzle[0]))); + } + inst->saturate = instr->dest.saturate; + } + + /* In this case the source and destination registers were the same, + * so we need to insert an extra set of moves in order to deal with + * any swizzling. + */ + if (need_extra_copy) { + for (unsigned i = 0; i < 4; i++) { + if (!(instr->dest.write_mask & (1 << i))) + continue; + + emit(MOV(offset(result, i), offset(temp, i))); + } + } + return; + } + default: + break; } + /* At this point, we have dealt with any instruction that operates on + * more than a single channel. Therefore, we can just adjust the source + * and destination registers for that channel and emit the instruction. + */ + unsigned channel = 0; + if (nir_op_infos[instr->op].output_size == 0) { + /* Since NIR is doing the scalarizing for us, we should only ever see + * vectorized operations with a single channel. + */ + assert(_mesa_bitcount(instr->dest.write_mask) == 1); + channel = ffs(instr->dest.write_mask) - 1; + + result = offset(result, channel); + } for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - op[i] = retype(get_nir_alu_src(instr, i), - brw_type_for_nir_type(nir_op_infos[instr->op].input_types[i])); + assert(nir_op_infos[instr->op].input_sizes[i] < 2); + op[i] = offset(op[i], instr->src[i].swizzle[channel]); } switch (instr->op) { - case nir_op_fmov: case nir_op_i2f: - case nir_op_u2f: { - fs_inst *inst = MOV(result, op[0]); + case nir_op_u2f: + inst = emit(MOV(result, op[0])); inst->saturate = instr->dest.saturate; - emit_percomp(inst, instr->dest.write_mask); - } break; - case nir_op_imov: case nir_op_f2i: case nir_op_f2u: - emit_percomp(MOV(result, op[0]), instr->dest.write_mask); + emit(MOV(result, op[0])); break; case nir_op_fsign: { @@ -538,55 +795,46 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) * Predicated OR ORs 1.0 (0x3f800000) with the sign bit if val is not * zero. */ - emit_percomp(CMP(reg_null_f, op[0], fs_reg(0.0f), BRW_CONDITIONAL_NZ), - instr->dest.write_mask); + emit(CMP(reg_null_f, op[0], fs_reg(0.0f), BRW_CONDITIONAL_NZ)); fs_reg result_int = retype(result, BRW_REGISTER_TYPE_UD); op[0].type = BRW_REGISTER_TYPE_UD; result.type = BRW_REGISTER_TYPE_UD; - emit_percomp(AND(result_int, op[0], fs_reg(0x80000000u)), - instr->dest.write_mask); + emit(AND(result_int, op[0], fs_reg(0x80000000u))); - fs_inst *inst = OR(result_int, result_int, fs_reg(0x3f800000u)); + inst = emit(OR(result_int, result_int, fs_reg(0x3f800000u))); inst->predicate = BRW_PREDICATE_NORMAL; - emit_percomp(inst, instr->dest.write_mask); if (instr->dest.saturate) { - fs_inst *inst = MOV(result, result); + inst = emit(MOV(result, result)); inst->saturate = true; - emit_percomp(inst, instr->dest.write_mask); } break; } - case nir_op_isign: { + case nir_op_isign: /* ASR(val, 31) -> negative val generates 0xffffffff (signed -1). - * -> non-negative val generates 0x00000000. - * Predicated OR sets 1 if val is positive. - */ - emit_percomp(CMP(reg_null_d, op[0], fs_reg(0), BRW_CONDITIONAL_G), - instr->dest.write_mask); - - emit_percomp(ASR(result, op[0], fs_reg(31)), instr->dest.write_mask); - - fs_inst *inst = OR(result, result, fs_reg(1)); + * -> non-negative val generates 0x00000000. + * Predicated OR sets 1 if val is positive. + */ + emit(CMP(reg_null_d, op[0], fs_reg(0), BRW_CONDITIONAL_G)); + emit(ASR(result, op[0], fs_reg(31))); + inst = emit(OR(result, result, fs_reg(1))); inst->predicate = BRW_PREDICATE_NORMAL; - emit_percomp(inst, instr->dest.write_mask); break; - } case nir_op_frcp: - emit_math_percomp(SHADER_OPCODE_RCP, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + inst = emit_math(SHADER_OPCODE_RCP, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_fexp2: - emit_math_percomp(SHADER_OPCODE_EXP2, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + inst = emit_math(SHADER_OPCODE_EXP2, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_flog2: - emit_math_percomp(SHADER_OPCODE_LOG2, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + inst = emit_math(SHADER_OPCODE_LOG2, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_fexp: @@ -595,61 +843,97 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) case nir_op_fsin: case nir_op_fsin_reduced: - emit_math_percomp(SHADER_OPCODE_SIN, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + inst = emit_math(SHADER_OPCODE_SIN, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_fcos: case nir_op_fcos_reduced: - emit_math_percomp(SHADER_OPCODE_COS, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + inst = emit_math(SHADER_OPCODE_COS, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_fddx: - if (fs_key->high_quality_derivatives) - emit_percomp(FS_OPCODE_DDX_FINE, result, op[0], - instr->dest.write_mask, instr->dest.saturate); - else - emit_percomp(FS_OPCODE_DDX_COARSE, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + if (fs_key->high_quality_derivatives) { + inst = emit(FS_OPCODE_DDX_FINE, result, op[0]); + } else { + inst = emit(FS_OPCODE_DDX_COARSE, result, op[0]); + } + inst->saturate = instr->dest.saturate; + break; + case nir_op_fddx_fine: + inst = emit(FS_OPCODE_DDX_FINE, result, op[0]); + inst->saturate = instr->dest.saturate; + break; + case nir_op_fddx_coarse: + inst = emit(FS_OPCODE_DDX_COARSE, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_fddy: - if (fs_key->high_quality_derivatives) - emit_percomp(FS_OPCODE_DDY_FINE, result, op[0], - fs_reg(fs_key->render_to_fbo), - instr->dest.write_mask, instr->dest.saturate); - else - emit_percomp(FS_OPCODE_DDY_COARSE, result, op[0], - fs_reg(fs_key->render_to_fbo), - instr->dest.write_mask, instr->dest.saturate); + if (fs_key->high_quality_derivatives) { + inst = emit(FS_OPCODE_DDY_FINE, result, op[0], + fs_reg(fs_key->render_to_fbo)); + } else { + inst = emit(FS_OPCODE_DDY_COARSE, result, op[0], + fs_reg(fs_key->render_to_fbo)); + } + inst->saturate = instr->dest.saturate; + break; + case nir_op_fddy_fine: + inst = emit(FS_OPCODE_DDY_FINE, result, op[0], + fs_reg(fs_key->render_to_fbo)); + inst->saturate = instr->dest.saturate; + break; + case nir_op_fddy_coarse: + inst = emit(FS_OPCODE_DDY_COARSE, result, op[0], + fs_reg(fs_key->render_to_fbo)); + inst->saturate = instr->dest.saturate; break; case nir_op_fadd: - case nir_op_iadd: { - fs_inst *inst = ADD(result, op[0], op[1]); + case nir_op_iadd: + inst = emit(ADD(result, op[0], op[1])); inst->saturate = instr->dest.saturate; - emit_percomp(inst, instr->dest.write_mask); break; - } - case nir_op_fmul: { - fs_inst *inst = MUL(result, op[0], op[1]); + case nir_op_fmul: + inst = emit(MUL(result, op[0], op[1])); inst->saturate = instr->dest.saturate; - emit_percomp(MUL(result, op[0], op[1]), instr->dest.write_mask); break; - } case nir_op_imul: { - /* TODO put in the 16-bit constant optimization once we have SSA */ + if (brw->gen >= 8) { + emit(MUL(result, op[0], op[1])); + break; + } else { + nir_const_value *value0 = nir_src_as_const_value(instr->src[0].src); + nir_const_value *value1 = nir_src_as_const_value(instr->src[1].src); + + if (value0 && value0->u[0] < (1 << 16)) { + if (brw->gen < 7) { + emit(MUL(result, op[0], op[1])); + } else { + emit(MUL(result, op[1], op[0])); + } + break; + } else if (value1 && value1->u[0] < (1 << 16)) { + if (brw->gen < 7) { + emit(MUL(result, op[1], op[0])); + } else { + emit(MUL(result, op[0], op[1])); + } + break; + } + } if (brw->gen >= 7) no16("SIMD16 explicit accumulator operands unsupported\n"); struct brw_reg acc = retype(brw_acc_reg(dispatch_width), result.type); - emit_percomp(MUL(acc, op[0], op[1]), instr->dest.write_mask); - emit_percomp(MACH(reg_null_d, op[0], op[1]), instr->dest.write_mask); - emit_percomp(MOV(result, fs_reg(acc)), instr->dest.write_mask); + emit(MUL(acc, op[0], op[1])); + emit(MACH(reg_null_d, op[0], op[1])); + emit(MOV(result, fs_reg(acc))); break; } @@ -660,15 +944,14 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) struct brw_reg acc = retype(brw_acc_reg(dispatch_width), result.type); - emit_percomp(MUL(acc, op[0], op[1]), instr->dest.write_mask); - emit_percomp(MACH(result, op[0], op[1]), instr->dest.write_mask); + emit(MUL(acc, op[0], op[1])); + emit(MACH(result, op[0], op[1])); break; } case nir_op_idiv: case nir_op_udiv: - emit_math_percomp(SHADER_OPCODE_INT_QUOTIENT, result, op[0], op[1], - instr->dest.write_mask); + emit_math(SHADER_OPCODE_INT_QUOTIENT, result, op[0], op[1]); break; case nir_op_uadd_carry: { @@ -678,8 +961,8 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) struct brw_reg acc = retype(brw_acc_reg(dispatch_width), BRW_REGISTER_TYPE_UD); - emit_percomp(ADDC(reg_null_ud, op[0], op[1]), instr->dest.write_mask); - emit_percomp(MOV(result, fs_reg(acc)), instr->dest.write_mask); + emit(ADDC(reg_null_ud, op[0], op[1])); + emit(MOV(result, fs_reg(acc))); break; } @@ -690,113 +973,87 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) struct brw_reg acc = retype(brw_acc_reg(dispatch_width), BRW_REGISTER_TYPE_UD); - emit_percomp(SUBB(reg_null_ud, op[0], op[1]), instr->dest.write_mask); - emit_percomp(MOV(result, fs_reg(acc)), instr->dest.write_mask); + emit(SUBB(reg_null_ud, op[0], op[1])); + emit(MOV(result, fs_reg(acc))); break; } case nir_op_umod: - emit_math_percomp(SHADER_OPCODE_INT_REMAINDER, result, op[0], - op[1], instr->dest.write_mask); + emit_math(SHADER_OPCODE_INT_REMAINDER, result, op[0], op[1]); break; case nir_op_flt: case nir_op_ilt: case nir_op_ult: - emit_percomp(CMP(result, op[0], op[1], BRW_CONDITIONAL_L), - instr->dest.write_mask); + emit(CMP(result, op[0], op[1], BRW_CONDITIONAL_L)); break; case nir_op_fge: case nir_op_ige: case nir_op_uge: - emit_percomp(CMP(result, op[0], op[1], BRW_CONDITIONAL_GE), - instr->dest.write_mask); + emit(CMP(result, op[0], op[1], BRW_CONDITIONAL_GE)); break; case nir_op_feq: case nir_op_ieq: - emit_percomp(CMP(result, op[0], op[1], BRW_CONDITIONAL_Z), - instr->dest.write_mask); + emit(CMP(result, op[0], op[1], BRW_CONDITIONAL_Z)); break; case nir_op_fne: case nir_op_ine: - emit_percomp(CMP(result, op[0], op[1], BRW_CONDITIONAL_NZ), - instr->dest.write_mask); + emit(CMP(result, op[0], op[1], BRW_CONDITIONAL_NZ)); break; - case nir_op_ball_fequal2: - case nir_op_ball_iequal2: - case nir_op_ball_fequal3: - case nir_op_ball_iequal3: - case nir_op_ball_fequal4: - case nir_op_ball_iequal4: { - unsigned num_components = nir_op_infos[instr->op].input_sizes[0]; - fs_reg temp = fs_reg(GRF, virtual_grf_alloc(num_components)); - emit_percomp(CMP(temp, op[0], op[1], BRW_CONDITIONAL_Z), - (1 << num_components) - 1); - emit_reduction(BRW_OPCODE_AND, result, temp, num_components); - break; - } - - case nir_op_bany_fnequal2: - case nir_op_bany_inequal2: - case nir_op_bany_fnequal3: - case nir_op_bany_inequal3: - case nir_op_bany_fnequal4: - case nir_op_bany_inequal4: { - unsigned num_components = nir_op_infos[instr->op].input_sizes[0]; - fs_reg temp = fs_reg(GRF, virtual_grf_alloc(num_components)); - temp.type = BRW_REGISTER_TYPE_UD; - emit_percomp(CMP(temp, op[0], op[1], BRW_CONDITIONAL_NZ), - (1 << num_components) - 1); - emit_reduction(BRW_OPCODE_OR, result, temp, num_components); - break; - } - case nir_op_inot: - emit_percomp(NOT(result, op[0]), instr->dest.write_mask); + if (brw->gen >= 8) { + resolve_source_modifiers(&op[0]); + } + emit(NOT(result, op[0])); break; case nir_op_ixor: - emit_percomp(XOR(result, op[0], op[1]), instr->dest.write_mask); + if (brw->gen >= 8) { + resolve_source_modifiers(&op[0]); + resolve_source_modifiers(&op[1]); + } + emit(XOR(result, op[0], op[1])); break; case nir_op_ior: - emit_percomp(OR(result, op[0], op[1]), instr->dest.write_mask); + if (brw->gen >= 8) { + resolve_source_modifiers(&op[0]); + resolve_source_modifiers(&op[1]); + } + emit(OR(result, op[0], op[1])); break; case nir_op_iand: - emit_percomp(AND(result, op[0], op[1]), instr->dest.write_mask); + if (brw->gen >= 8) { + resolve_source_modifiers(&op[0]); + resolve_source_modifiers(&op[1]); + } + emit(AND(result, op[0], op[1])); break; case nir_op_fdot2: case nir_op_fdot3: - case nir_op_fdot4: { - unsigned num_components = nir_op_infos[instr->op].input_sizes[0]; - fs_reg temp = fs_reg(GRF, virtual_grf_alloc(num_components)); - emit_percomp(MUL(temp, op[0], op[1]), (1 << num_components) - 1); - emit_reduction(BRW_OPCODE_ADD, result, temp, num_components); - if (instr->dest.saturate) { - fs_inst *inst = emit(MOV(result, result)); - inst->saturate = true; - } - break; - } - + case nir_op_fdot4: case nir_op_bany2: case nir_op_bany3: - case nir_op_bany4: { - unsigned num_components = nir_op_infos[instr->op].input_sizes[0]; - emit_reduction(BRW_OPCODE_OR, result, op[0], num_components); - break; - } - + case nir_op_bany4: case nir_op_ball2: case nir_op_ball3: - case nir_op_ball4: { - unsigned num_components = nir_op_infos[instr->op].input_sizes[0]; - emit_reduction(BRW_OPCODE_AND, result, op[0], num_components); - break; - } + case nir_op_ball4: + case nir_op_ball_fequal2: + case nir_op_ball_iequal2: + case nir_op_ball_fequal3: + case nir_op_ball_iequal3: + case nir_op_ball_fequal4: + case nir_op_ball_iequal4: + case nir_op_bany_fnequal2: + case nir_op_bany_inequal2: + case nir_op_bany_fnequal3: + case nir_op_bany_inequal3: + case nir_op_bany_fnequal4: + case nir_op_bany_inequal4: + unreachable("Lowered by nir_lower_alu_reductions"); case nir_op_fnoise1_1: case nir_op_fnoise1_2: @@ -816,110 +1073,84 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) case nir_op_fnoise4_4: unreachable("not reached: should be handled by lower_noise"); - case nir_op_vec2: - case nir_op_vec3: - case nir_op_vec4: - unreachable("not reached: should be handled by lower_quadop_vector"); - case nir_op_ldexp: unreachable("not reached: should be handled by ldexp_to_arith()"); case nir_op_fsqrt: - emit_math_percomp(SHADER_OPCODE_SQRT, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + inst = emit_math(SHADER_OPCODE_SQRT, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_frsq: - emit_math_percomp(SHADER_OPCODE_RSQ, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + inst = emit_math(SHADER_OPCODE_RSQ, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_b2i: - emit_percomp(AND(result, op[0], fs_reg(1)), instr->dest.write_mask); + emit(AND(result, op[0], fs_reg(1))); break; - case nir_op_b2f: { - emit_percomp(AND(retype(result, BRW_REGISTER_TYPE_UD), op[0], - fs_reg(0x3f800000u)), - instr->dest.write_mask); + case nir_op_b2f: + emit(AND(retype(result, BRW_REGISTER_TYPE_UD), op[0], fs_reg(0x3f800000u))); break; - } case nir_op_f2b: - emit_percomp(CMP(result, op[0], fs_reg(0.0f), BRW_CONDITIONAL_NZ), - instr->dest.write_mask); + emit(CMP(result, op[0], fs_reg(0.0f), BRW_CONDITIONAL_NZ)); break; case nir_op_i2b: - emit_percomp(CMP(result, op[0], fs_reg(0), BRW_CONDITIONAL_NZ), - instr->dest.write_mask); + emit(CMP(result, op[0], fs_reg(0), BRW_CONDITIONAL_NZ)); break; - case nir_op_ftrunc: { - fs_inst *inst = RNDZ(result, op[0]); + case nir_op_ftrunc: + inst = emit(RNDZ(result, op[0])); inst->saturate = instr->dest.saturate; - emit_percomp(inst, instr->dest.write_mask); break; - } + case nir_op_fceil: { op[0].negate = !op[0].negate; - fs_reg temp = fs_reg(this, glsl_type::vec4_type); - emit_percomp(RNDD(temp, op[0]), instr->dest.write_mask); + fs_reg temp = vgrf(glsl_type::float_type); + emit(RNDD(temp, op[0])); temp.negate = true; - fs_inst *inst = MOV(result, temp); + inst = emit(MOV(result, temp)); inst->saturate = instr->dest.saturate; - emit_percomp(inst, instr->dest.write_mask); break; } - case nir_op_ffloor: { - fs_inst *inst = RNDD(result, op[0]); + case nir_op_ffloor: + inst = emit(RNDD(result, op[0])); inst->saturate = instr->dest.saturate; - emit_percomp(inst, instr->dest.write_mask); break; - } - case nir_op_ffract: { - fs_inst *inst = FRC(result, op[0]); + case nir_op_ffract: + inst = emit(FRC(result, op[0])); inst->saturate = instr->dest.saturate; - emit_percomp(inst, instr->dest.write_mask); break; - } - case nir_op_fround_even: { - fs_inst *inst = RNDE(result, op[0]); + case nir_op_fround_even: + inst = emit(RNDE(result, op[0])); inst->saturate = instr->dest.saturate; - emit_percomp(inst, instr->dest.write_mask); break; - } case nir_op_fmin: case nir_op_imin: case nir_op_umin: if (brw->gen >= 6) { - emit_percomp(BRW_OPCODE_SEL, result, op[0], op[1], - instr->dest.write_mask, instr->dest.saturate, - BRW_PREDICATE_NONE, BRW_CONDITIONAL_L); + inst = emit(BRW_OPCODE_SEL, result, op[0], op[1]); + inst->conditional_mod = BRW_CONDITIONAL_L; } else { - emit_percomp(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_L), - instr->dest.write_mask); - - emit_percomp(BRW_OPCODE_SEL, result, op[0], op[1], - instr->dest.write_mask, instr->dest.saturate, - BRW_PREDICATE_NORMAL); + emit(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_L)); + inst = emit(SEL(result, op[0], op[1])); } + inst->saturate = instr->dest.saturate; break; case nir_op_fmax: case nir_op_imax: case nir_op_umax: if (brw->gen >= 6) { - emit_percomp(BRW_OPCODE_SEL, result, op[0], op[1], - instr->dest.write_mask, instr->dest.saturate, - BRW_PREDICATE_NONE, BRW_CONDITIONAL_GE); + inst = emit(BRW_OPCODE_SEL, result, op[0], op[1]); + inst->conditional_mod = BRW_CONDITIONAL_GE; } else { - emit_percomp(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_GE), - instr->dest.write_mask); - - emit_percomp(BRW_OPCODE_SEL, result, op[0], op[1], - instr->dest.write_mask, instr->dest.saturate, - BRW_PREDICATE_NORMAL); + emit(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_GE)); + inst = emit(SEL(result, op[0], op[1])); } + inst->saturate = instr->dest.saturate; break; case nir_op_pack_snorm_2x16: @@ -935,58 +1166,57 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) unreachable("not reached: should be handled by lower_packing_builtins"); case nir_op_unpack_half_2x16_split_x: - emit_percomp(FS_OPCODE_UNPACK_HALF_2x16_SPLIT_X, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + inst = emit(FS_OPCODE_UNPACK_HALF_2x16_SPLIT_X, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_unpack_half_2x16_split_y: - emit_percomp(FS_OPCODE_UNPACK_HALF_2x16_SPLIT_Y, result, op[0], - instr->dest.write_mask, instr->dest.saturate); + inst = emit(FS_OPCODE_UNPACK_HALF_2x16_SPLIT_Y, result, op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_fpow: - emit_percomp(SHADER_OPCODE_POW, result, op[0], op[1], - instr->dest.write_mask, instr->dest.saturate); + inst = emit_math(SHADER_OPCODE_POW, result, op[0], op[1]); + inst->saturate = instr->dest.saturate; break; case nir_op_bitfield_reverse: - emit_percomp(BFREV(result, op[0]), instr->dest.write_mask); + emit(BFREV(result, op[0])); break; case nir_op_bit_count: - emit_percomp(CBIT(result, op[0]), instr->dest.write_mask); + emit(CBIT(result, op[0])); break; - case nir_op_find_msb: { - fs_reg temp = fs_reg(this, glsl_type::uvec4_type); - emit_percomp(FBH(temp, op[0]), instr->dest.write_mask); + case nir_op_ufind_msb: + case nir_op_ifind_msb: { + emit(FBH(retype(result, BRW_REGISTER_TYPE_UD), op[0])); /* FBH counts from the MSB side, while GLSL's findMSB() wants the count * from the LSB side. If FBH didn't return an error (0xFFFFFFFF), then * subtract the result from 31 to convert the MSB count into an LSB count. */ - emit_percomp(CMP(reg_null_d, temp, fs_reg(~0), BRW_CONDITIONAL_NZ), - instr->dest.write_mask); - temp.negate = true; - fs_inst *inst = ADD(result, temp, fs_reg(31)); + emit(CMP(reg_null_d, result, fs_reg(-1), BRW_CONDITIONAL_NZ)); + fs_reg neg_result(result); + neg_result.negate = true; + inst = emit(ADD(result, neg_result, fs_reg(31))); inst->predicate = BRW_PREDICATE_NORMAL; - emit_percomp(inst, instr->dest.write_mask); break; } case nir_op_find_lsb: - emit_percomp(FBL(result, op[0]), instr->dest.write_mask); + emit(FBL(result, op[0])); break; case nir_op_ubitfield_extract: case nir_op_ibitfield_extract: - emit_percomp(BFE(result, op[2], op[1], op[0]), instr->dest.write_mask); + emit(BFE(result, op[2], op[1], op[0])); break; case nir_op_bfm: - emit_percomp(BFI1(result, op[0], op[1]), instr->dest.write_mask); + emit(BFI1(result, op[0], op[1])); break; case nir_op_bfi: - emit_percomp(BFI2(result, op[0], op[1], op[2]), instr->dest.write_mask); + emit(BFI2(result, op[0], op[1], op[2])); break; case nir_op_bitfield_insert: @@ -994,123 +1224,88 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) "lower_instructions::bitfield_insert_to_bfm_bfi"); case nir_op_ishl: - emit_percomp(SHL(result, op[0], op[1]), instr->dest.write_mask); + emit(SHL(result, op[0], op[1])); break; case nir_op_ishr: - emit_percomp(ASR(result, op[0], op[1]), instr->dest.write_mask); + emit(ASR(result, op[0], op[1])); break; case nir_op_ushr: - emit_percomp(SHR(result, op[0], op[1]), instr->dest.write_mask); + emit(SHR(result, op[0], op[1])); break; case nir_op_pack_half_2x16_split: - emit_percomp(FS_OPCODE_PACK_HALF_2x16_SPLIT, result, op[0], op[1], - instr->dest.write_mask); + emit(FS_OPCODE_PACK_HALF_2x16_SPLIT, result, op[0], op[1]); break; case nir_op_ffma: - emit_percomp(MAD(result, op[2], op[1], op[0]), instr->dest.write_mask); + inst = emit(MAD(result, op[2], op[1], op[0])); + inst->saturate = instr->dest.saturate; break; case nir_op_flrp: - /* TODO emulate for gen < 6 */ - emit_percomp(LRP(result, op[2], op[1], op[0]), instr->dest.write_mask); + inst = emit_lrp(result, op[0], op[1], op[2]); + inst->saturate = instr->dest.saturate; break; case nir_op_bcsel: + if (optimize_frontfacing_ternary(instr, result)) + return; + emit(CMP(reg_null_d, op[0], fs_reg(0), BRW_CONDITIONAL_NZ)); - emit_percomp(BRW_OPCODE_SEL, result, op[1], op[2], - instr->dest.write_mask, false, BRW_PREDICATE_NORMAL); + inst = emit(SEL(result, op[1], op[2])); + inst->predicate = BRW_PREDICATE_NORMAL; break; default: unreachable("unhandled instruction"); } - - /* emit a predicated move if there was predication */ - if (instr->has_predicate) { - fs_inst *inst = emit(MOV(reg_null_d, - retype(get_nir_src(instr->predicate), - BRW_REGISTER_TYPE_UD))); - inst->conditional_mod = BRW_CONDITIONAL_NZ; - inst = MOV(dest, result); - inst->predicate = BRW_PREDICATE_NORMAL; - emit_percomp(inst, instr->dest.write_mask); - } } fs_reg fs_visitor::get_nir_src(nir_src src) { - struct hash_entry *entry = - _mesa_hash_table_search(this->nir_reg_ht, src.reg.reg); - fs_reg reg = *((fs_reg *) entry->data); - /* to avoid floating-point denorm flushing problems, set the type by - * default to D - instructions that need floating point semantics will set - * this to F if they need to - */ - reg.type = BRW_REGISTER_TYPE_D; - reg.reg_offset = src.reg.base_offset; - if (src.reg.indirect) { - reg.reladdr = new(mem_ctx) fs_reg(); - *reg.reladdr = retype(get_nir_src(*src.reg.indirect), - BRW_REGISTER_TYPE_D); - } + if (src.is_ssa) { + assert(src.ssa->parent_instr->type == nir_instr_type_load_const); + nir_load_const_instr *load = nir_instr_as_load_const(src.ssa->parent_instr); + fs_reg reg = vgrf(src.ssa->num_components); + reg.type = BRW_REGISTER_TYPE_D; - return reg; -} - -fs_reg -fs_visitor::get_nir_alu_src(nir_alu_instr *instr, unsigned src) -{ - fs_reg reg = get_nir_src(instr->src[src].src); - - reg.abs = instr->src[src].abs; - reg.negate = instr->src[src].negate; - - bool needs_swizzle = false; - unsigned num_components = 0; - for (unsigned i = 0; i < 4; i++) { - if (!nir_alu_instr_channel_used(instr, src, i)) - continue; + for (unsigned i = 0; i < src.ssa->num_components; ++i) + emit(MOV(offset(reg, i), fs_reg(load->value.i[i]))); - if (instr->src[src].swizzle[i] != i) - needs_swizzle = true; - - num_components = i + 1; - } - - if (needs_swizzle) { - /* resolve the swizzle through MOV's */ - fs_reg new_reg = fs_reg(GRF, virtual_grf_alloc(num_components)); - - for (unsigned i = 0; i < 4; i++) { - if (!nir_alu_instr_channel_used(instr, src, i)) - continue; - - fs_reg dest = new_reg; - dest.type = reg.type; - dest.reg_offset = i; - - fs_reg src0 = reg; - src0.reg_offset += instr->src[src].swizzle[i]; + return reg; + } else { + fs_reg reg; + if (src.reg.reg->is_global) + reg = nir_globals[src.reg.reg->index]; + else + reg = nir_locals[src.reg.reg->index]; - emit(MOV(dest, src0)); + /* to avoid floating-point denorm flushing problems, set the type by + * default to D - instructions that need floating point semantics will set + * this to F if they need to + */ + reg = retype(offset(reg, src.reg.base_offset), BRW_REGISTER_TYPE_D); + if (src.reg.indirect) { + reg.reladdr = new(mem_ctx) fs_reg(); + *reg.reladdr = retype(get_nir_src(*src.reg.indirect), + BRW_REGISTER_TYPE_D); } - return new_reg; + return reg; } - - return reg; } fs_reg fs_visitor::get_nir_dest(nir_dest dest) { - struct hash_entry *entry = - _mesa_hash_table_search(this->nir_reg_ht, dest.reg.reg); - fs_reg reg = *((fs_reg *) entry->data); - reg.reg_offset = dest.reg.base_offset; + fs_reg reg; + if (dest.reg.reg->is_global) + reg = nir_globals[dest.reg.reg->index]; + else + reg = nir_locals[dest.reg.reg->index]; + + reg = offset(reg, dest.reg.base_offset); if (dest.reg.indirect) { reg.reladdr = new(mem_ctx) fs_reg(); *reg.reladdr = retype(get_nir_src(*dest.reg.indirect), @@ -1128,415 +1323,373 @@ fs_visitor::emit_percomp(fs_inst *inst, unsigned wr_mask) continue; fs_inst *new_inst = new(mem_ctx) fs_inst(*inst); - new_inst->dst.reg_offset += i; + new_inst->dst = offset(new_inst->dst, i); for (unsigned j = 0; j < new_inst->sources; j++) if (inst->src[j].file == GRF) - new_inst->src[j].reg_offset += i; + new_inst->src[j] = offset(new_inst->src[j], i); emit(new_inst); } } -void -fs_visitor::emit_percomp(enum opcode op, fs_reg dest, fs_reg src0, - unsigned wr_mask, bool saturate, - enum brw_predicate predicate, - enum brw_conditional_mod mod) -{ - for (unsigned i = 0; i < 4; i++) { - if (!((wr_mask >> i) & 1)) - continue; - - fs_inst *new_inst = new(mem_ctx) fs_inst(op, dest, src0); - new_inst->dst.reg_offset += i; - for (unsigned j = 0; j < new_inst->sources; j++) - if (new_inst->src[j].file == GRF) - new_inst->src[j].reg_offset += i; - - new_inst->predicate = predicate; - new_inst->conditional_mod = mod; - new_inst->saturate = saturate; - emit(new_inst); - } -} - -void -fs_visitor::emit_percomp(enum opcode op, fs_reg dest, fs_reg src0, fs_reg src1, - unsigned wr_mask, bool saturate, - enum brw_predicate predicate, - enum brw_conditional_mod mod) -{ - for (unsigned i = 0; i < 4; i++) { - if (!((wr_mask >> i) & 1)) - continue; - - fs_inst *new_inst = new(mem_ctx) fs_inst(op, dest, src0, src1); - new_inst->dst.reg_offset += i; - for (unsigned j = 0; j < new_inst->sources; j++) - if (new_inst->src[j].file == GRF) - new_inst->src[j].reg_offset += i; - - new_inst->predicate = predicate; - new_inst->conditional_mod = mod; - new_inst->saturate = saturate; - emit(new_inst); - } -} - -void -fs_visitor::emit_math_percomp(enum opcode op, fs_reg dest, fs_reg src0, - unsigned wr_mask, bool saturate) -{ - for (unsigned i = 0; i < 4; i++) { - if (!((wr_mask >> i) & 1)) - continue; - - fs_reg new_dest = dest; - new_dest.reg_offset += i; - fs_reg new_src0 = src0; - if (src0.file == GRF) - new_src0.reg_offset += i; - - fs_inst *new_inst = emit_math(op, new_dest, new_src0); - new_inst->saturate = saturate; - } -} - -void -fs_visitor::emit_math_percomp(enum opcode op, fs_reg dest, fs_reg src0, - fs_reg src1, unsigned wr_mask, - bool saturate) -{ - for (unsigned i = 0; i < 4; i++) { - if (!((wr_mask >> i) & 1)) - continue; - - fs_reg new_dest = dest; - new_dest.reg_offset += i; - fs_reg new_src0 = src0; - if (src0.file == GRF) - new_src0.reg_offset += i; - fs_reg new_src1 = src1; - if (src1.file == GRF) - new_src1.reg_offset += i; - - fs_inst *new_inst = emit_math(op, new_dest, new_src0, new_src1); - new_inst->saturate = saturate; - } -} - -void -fs_visitor::emit_reduction(enum opcode op, fs_reg dest, fs_reg src, - unsigned num_components) -{ - fs_reg src0 = src; - fs_reg src1 = src; - src1.reg_offset++; - - if (num_components == 2) { - emit(op, dest, src0, src1); - return; - } - - fs_reg temp1 = fs_reg(GRF, virtual_grf_alloc(1)); - temp1.type = src.type; - emit(op, temp1, src0, src1); - - fs_reg src2 = src; - src2.reg_offset += 2; - - if (num_components == 3) { - emit(op, dest, temp1, src2); - return; - } - - assert(num_components == 4); - - fs_reg src3 = src; - src3.reg_offset += 3; - fs_reg temp2 = fs_reg(GRF, virtual_grf_alloc(1)); - temp2.type = src.type; - - emit(op, temp2, src2, src3); - emit(op, dest, temp1, temp2); -} - void fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) { fs_reg dest; if (nir_intrinsic_infos[instr->intrinsic].has_dest) dest = get_nir_dest(instr->dest); - if (instr->has_predicate) { - fs_inst *inst = emit(MOV(reg_null_d, - retype(get_nir_src(instr->predicate), - BRW_REGISTER_TYPE_UD))); - inst->conditional_mod = BRW_CONDITIONAL_NZ; - } + + bool has_indirect = false; switch (instr->intrinsic) { - case nir_intrinsic_discard: { + case nir_intrinsic_discard: + case nir_intrinsic_discard_if: { /* We track our discarded pixels in f0.1. By predicating on it, we can - * update just the flag bits that aren't yet discarded. By emitting a - * CMP of g0 != g0, all our currently executing channels will get turned - * off. + * update just the flag bits that aren't yet discarded. If there's no + * condition, we emit a CMP of g0 != g0, so all currently executing + * channels will get turned off. */ - fs_reg some_reg = fs_reg(retype(brw_vec8_grf(0, 0), - BRW_REGISTER_TYPE_UW)); - fs_inst *cmp = emit(CMP(reg_null_f, some_reg, some_reg, - BRW_CONDITIONAL_NZ)); + fs_inst *cmp; + if (instr->intrinsic == nir_intrinsic_discard_if) { + cmp = emit(CMP(reg_null_f, get_nir_src(instr->src[0]), + fs_reg(0), BRW_CONDITIONAL_Z)); + } else { + fs_reg some_reg = fs_reg(retype(brw_vec8_grf(0, 0), + BRW_REGISTER_TYPE_UW)); + cmp = emit(CMP(reg_null_f, some_reg, some_reg, BRW_CONDITIONAL_NZ)); + } cmp->predicate = BRW_PREDICATE_NORMAL; 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; } case nir_intrinsic_atomic_counter_inc: case nir_intrinsic_atomic_counter_dec: - case nir_intrinsic_atomic_counter_read: - assert(!"TODO"); - + case nir_intrinsic_atomic_counter_read: { + unsigned surf_index = prog_data->binding_table.abo_start + + (unsigned) instr->const_index[0]; + fs_reg offset = fs_reg(get_nir_src(instr->src[0])); + + switch (instr->intrinsic) { + case nir_intrinsic_atomic_counter_inc: + emit_untyped_atomic(BRW_AOP_INC, surf_index, dest, offset, + fs_reg(), fs_reg()); + break; + case nir_intrinsic_atomic_counter_dec: + emit_untyped_atomic(BRW_AOP_PREDEC, surf_index, dest, offset, + fs_reg(), fs_reg()); + break; + case nir_intrinsic_atomic_counter_read: + emit_untyped_surface_read(surf_index, dest, offset); + break; + default: + unreachable("Unreachable"); + } + break; + } case nir_intrinsic_load_front_face: - assert(!"TODO"); + emit(MOV(retype(dest, BRW_REGISTER_TYPE_D), + *emit_frontfacing_interpolation())); + break; + + case nir_intrinsic_load_vertex_id: + unreachable("should be lowered by lower_vertex_id()"); + + case nir_intrinsic_load_vertex_id_zero_base: { + fs_reg vertex_id = nir_system_values[SYSTEM_VALUE_VERTEX_ID_ZERO_BASE]; + assert(vertex_id.file != BAD_FILE); + dest.type = vertex_id.type; + emit(MOV(dest, vertex_id)); + break; + } + + case nir_intrinsic_load_base_vertex: { + fs_reg base_vertex = nir_system_values[SYSTEM_VALUE_BASE_VERTEX]; + assert(base_vertex.file != BAD_FILE); + dest.type = base_vertex.type; + emit(MOV(dest, base_vertex)); + break; + } + + case nir_intrinsic_load_instance_id: { + fs_reg instance_id = nir_system_values[SYSTEM_VALUE_INSTANCE_ID]; + assert(instance_id.file != BAD_FILE); + dest.type = instance_id.type; + emit(MOV(dest, instance_id)); + break; + } case nir_intrinsic_load_sample_mask_in: { - assert(brw->gen >= 7); - fs_reg reg = fs_reg(retype(brw_vec8_grf(payload.sample_mask_in_reg, 0), - BRW_REGISTER_TYPE_D)); - dest.type = reg.type; - fs_inst *inst = MOV(dest, reg); - if (instr->has_predicate) - inst->predicate = BRW_PREDICATE_NORMAL; - emit(inst); + fs_reg sample_mask_in = nir_system_values[SYSTEM_VALUE_SAMPLE_MASK_IN]; + assert(sample_mask_in.file != BAD_FILE); + dest.type = sample_mask_in.type; + emit(MOV(dest, sample_mask_in)); break; } case nir_intrinsic_load_sample_pos: { - fs_reg *reg = emit_samplepos_setup(); - dest.type = reg->type; - emit(MOV(dest, *reg)); - emit(MOV(offset(dest, 1), offset(*reg, 1))); + fs_reg sample_pos = nir_system_values[SYSTEM_VALUE_SAMPLE_POS]; + assert(sample_pos.file != BAD_FILE); + dest.type = sample_pos.type; + emit(MOV(dest, sample_pos)); + emit(MOV(offset(dest, 1), offset(sample_pos, 1))); break; } case nir_intrinsic_load_sample_id: { - fs_reg *reg = emit_sampleid_setup(); - dest.type = reg->type; - emit(MOV(dest, *reg)); + fs_reg sample_id = nir_system_values[SYSTEM_VALUE_SAMPLE_ID]; + assert(sample_id.file != BAD_FILE); + dest.type = sample_id.type; + emit(MOV(dest, sample_id)); break; } - case nir_intrinsic_load_uniform_vec1: - case nir_intrinsic_load_uniform_vec2: - case nir_intrinsic_load_uniform_vec3: - case nir_intrinsic_load_uniform_vec4: { - unsigned index = 0; - for (int i = 0; i < instr->const_index[1]; i++) { - for (unsigned j = 0; - j < nir_intrinsic_infos[instr->intrinsic].dest_components; j++) { - fs_reg src = nir_uniforms; - src.reg_offset = instr->const_index[0] + index; - src.type = dest.type; - index++; + case nir_intrinsic_load_uniform_indirect: + has_indirect = true; + case nir_intrinsic_load_uniform: { + unsigned index = instr->const_index[0]; - fs_inst *inst = MOV(dest, src); - if (instr->has_predicate) - inst->predicate = BRW_PREDICATE_NORMAL; - emit(inst); - dest.reg_offset++; - } + 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; } - break; - } - case nir_intrinsic_load_uniform_vec1_indirect: - case nir_intrinsic_load_uniform_vec2_indirect: - case nir_intrinsic_load_uniform_vec3_indirect: - case nir_intrinsic_load_uniform_vec4_indirect: { - unsigned index = 0; for (int i = 0; i < instr->const_index[1]; i++) { - for (unsigned j = 0; - j < nir_intrinsic_infos[instr->intrinsic].dest_components; j++) { - fs_reg src = nir_uniforms; - src.reg_offset = instr->const_index[0] + index; - src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[0])); - src.reladdr->type = BRW_REGISTER_TYPE_D; - src.type = dest.type; + for (unsigned j = 0; j < instr->num_components; j++) { + 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++; - fs_inst *inst = MOV(dest, src); - if (instr->has_predicate) - inst->predicate = BRW_PREDICATE_NORMAL; - emit(inst); - dest.reg_offset++; + emit(MOV(dest, src)); + dest = offset(dest, 1); } } break; } - case nir_intrinsic_load_ubo_vec1: - case nir_intrinsic_load_ubo_vec2: - case nir_intrinsic_load_ubo_vec3: - case nir_intrinsic_load_ubo_vec4: { - fs_reg surf_index = fs_reg(prog_data->binding_table.ubo_start + - (unsigned) instr->const_index[0]); - fs_reg packed_consts = fs_reg(this, glsl_type::float_type); - packed_consts.type = dest.type; - - fs_reg const_offset_reg = fs_reg((unsigned) instr->const_index[1] & ~15); - emit(new(mem_ctx) fs_inst(FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD, - packed_consts, surf_index, const_offset_reg)); - - for (unsigned i = 0; - i < nir_intrinsic_infos[instr->intrinsic].dest_components; i++) { - packed_consts.set_smear(instr->const_index[1] % 16 / 4 + i); - - /* The std140 packing rules don't allow vectors to cross 16-byte - * boundaries, and a reg is 32 bytes. - */ - assert(packed_consts.subreg_offset < 32); + case nir_intrinsic_load_ubo_indirect: + has_indirect = true; + /* fallthrough */ + case nir_intrinsic_load_ubo: { + nir_const_value *const_index = nir_src_as_const_value(instr->src[0]); + fs_reg surf_index; - fs_inst *inst = MOV(dest, packed_consts); - if (instr->has_predicate) - inst->predicate = BRW_PREDICATE_NORMAL; - emit(inst); + if (const_index) { + surf_index = fs_reg(stage_prog_data->binding_table.ubo_start + + const_index->u[0]); + } else { + /* The block index is not a constant. Evaluate the index expression + * per-channel and add the base UBO index; the generator will select + * a value from any live channel. + */ + surf_index = vgrf(glsl_type::uint_type); + emit(ADD(surf_index, get_nir_src(instr->src[0]), + fs_reg(stage_prog_data->binding_table.ubo_start))) + ->force_writemask_all = true; - dest.reg_offset++; + /* Assume this may touch any UBO. It would be nice to provide + * a tighter bound, but the array information is already lowered away. + */ + brw_mark_surface_used(prog_data, + stage_prog_data->binding_table.ubo_start + + shader_prog->NumUniformBlocks - 1); } - break; - } - case nir_intrinsic_load_ubo_vec1_indirect: - case nir_intrinsic_load_ubo_vec2_indirect: - case nir_intrinsic_load_ubo_vec3_indirect: - case nir_intrinsic_load_ubo_vec4_indirect: { - fs_reg surf_index = fs_reg(prog_data->binding_table.ubo_start + - instr->const_index[0]); - /* Turn the byte offset into a dword offset. */ - unsigned base_offset = instr->const_index[1] / 4; - fs_reg offset = fs_reg(this, glsl_type::int_type); - emit(SHR(offset, retype(get_nir_src(instr->src[0]), BRW_REGISTER_TYPE_D), - fs_reg(2))); - - for (unsigned i = 0; - i < nir_intrinsic_infos[instr->intrinsic].dest_components; i++) { - exec_list list = VARYING_PULL_CONSTANT_LOAD(dest, surf_index, - offset, base_offset + i); - fs_inst *last_inst = (fs_inst *) list.get_tail(); - if (instr->has_predicate) - last_inst->predicate = BRW_PREDICATE_NORMAL; - emit(list); - - dest.reg_offset++; - } - break; - } + if (has_indirect) { + /* Turn the byte offset into a dword offset. */ + fs_reg base_offset = vgrf(glsl_type::int_type); + emit(SHR(base_offset, retype(get_nir_src(instr->src[1]), + BRW_REGISTER_TYPE_D), + fs_reg(2))); + + unsigned vec4_offset = instr->const_index[0] / 4; + for (int i = 0; i < instr->num_components; i++) + emit(VARYING_PULL_CONSTANT_LOAD(offset(dest, i), surf_index, + base_offset, vec4_offset + i)); + } else { + fs_reg packed_consts = vgrf(glsl_type::float_type); + packed_consts.type = dest.type; - case nir_intrinsic_load_input_vec1: - case nir_intrinsic_load_input_vec2: - case nir_intrinsic_load_input_vec3: - case nir_intrinsic_load_input_vec4: { - unsigned index = 0; - for (int i = 0; i < instr->const_index[1]; i++) { - for (unsigned j = 0; - j < nir_intrinsic_infos[instr->intrinsic].dest_components; j++) { - fs_reg src = nir_inputs; - src.reg_offset = instr->const_index[0] + index; - src.type = dest.type; - index++; + fs_reg const_offset_reg((unsigned) instr->const_index[0] & ~15); + emit(FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD, packed_consts, + surf_index, const_offset_reg); + + for (unsigned i = 0; i < instr->num_components; i++) { + packed_consts.set_smear(instr->const_index[0] % 16 / 4 + i); + + /* The std140 packing rules don't allow vectors to cross 16-byte + * boundaries, and a reg is 32 bytes. + */ + assert(packed_consts.subreg_offset < 32); - fs_inst *inst = MOV(dest, src); - if (instr->has_predicate) - inst->predicate = BRW_PREDICATE_NORMAL; - emit(inst); - dest.reg_offset++; + emit(MOV(dest, packed_consts)); + dest = offset(dest, 1); } } break; } - case nir_intrinsic_load_input_vec1_indirect: - case nir_intrinsic_load_input_vec2_indirect: - case nir_intrinsic_load_input_vec3_indirect: - case nir_intrinsic_load_input_vec4_indirect: { + case nir_intrinsic_load_input_indirect: + has_indirect = true; + /* fallthrough */ + case nir_intrinsic_load_input: { unsigned index = 0; for (int i = 0; i < instr->const_index[1]; i++) { - for (unsigned j = 0; - j < nir_intrinsic_infos[instr->intrinsic].dest_components; j++) { - fs_reg src = nir_inputs; - src.reg_offset = instr->const_index[0] + index; - src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[0])); - src.reladdr->type = BRW_REGISTER_TYPE_D; - src.type = dest.type; + for (unsigned j = 0; j < instr->num_components; j++) { + fs_reg src = offset(retype(nir_inputs, dest.type), + instr->const_index[0] + index); + if (has_indirect) + src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[0])); index++; - fs_inst *inst = MOV(dest, src); - if (instr->has_predicate) - inst->predicate = BRW_PREDICATE_NORMAL; - emit(inst); - dest.reg_offset++; + emit(MOV(dest, src)); + dest = offset(dest, 1); } } break; } - case nir_intrinsic_store_output_vec1: - case nir_intrinsic_store_output_vec2: - case nir_intrinsic_store_output_vec3: - case nir_intrinsic_store_output_vec4: { - fs_reg src = get_nir_src(instr->src[0]); - unsigned index = 0; - for (int i = 0; i < instr->const_index[1]; i++) { - for (unsigned j = 0; - j < nir_intrinsic_infos[instr->intrinsic].src_components[0]; j++) { - fs_reg new_dest = nir_outputs; - new_dest.reg_offset = instr->const_index[0] + index; - new_dest.type = src.type; - index++; - fs_inst *inst = MOV(new_dest, src); - if (instr->has_predicate) - inst->predicate = BRW_PREDICATE_NORMAL; - emit(inst); - src.reg_offset++; + /* Handle ARB_gpu_shader5 interpolation intrinsics + * + * It's worth a quick word of explanation as to why we handle the full + * variable-based interpolation intrinsic rather than a lowered version + * with like we do for other inputs. We have to do that because the way + * we set up inputs doesn't allow us to use the already setup inputs for + * interpolation. At the beginning of the shader, we go through all of + * the input variables and do the initial interpolation and put it in + * the nir_inputs array based on its location as determined in + * nir_lower_io. If the input isn't used, dead code cleans up and + * everything works fine. However, when we get to the ARB_gpu_shader5 + * interpolation intrinsics, we need to reinterpolate the input + * differently. If we used an intrinsic that just had an index it would + * only give us the offset into the nir_inputs array. However, this is + * useless because that value is post-interpolation and we need + * pre-interpolation. In order to get the actual location of the bits + * we get from the vertex fetching hardware, we need the variable. + */ + case nir_intrinsic_interp_var_at_centroid: + case nir_intrinsic_interp_var_at_sample: + case nir_intrinsic_interp_var_at_offset: { + /* in SIMD16 mode, the pixel interpolator returns coords interleaved + * 8 channels at a time, same as the barycentric coords presented in + * the FS payload. this requires a bit of extra work to support. + */ + no16("interpolate_at_* not yet supported in SIMD16 mode."); + + fs_reg dst_x = vgrf(2); + fs_reg dst_y = offset(dst_x, 1); + + /* For most messages, we need one reg of ignored data; the hardware + * requires mlen==1 even when there is no payload. in the per-slot + * offset case, we'll replace this with the proper source data. + */ + fs_reg src = vgrf(glsl_type::float_type); + int mlen = 1; /* one reg unless overriden */ + fs_inst *inst; + + switch (instr->intrinsic) { + case nir_intrinsic_interp_var_at_centroid: + inst = emit(FS_OPCODE_INTERPOLATE_AT_CENTROID, dst_x, src, fs_reg(0u)); + break; + + case nir_intrinsic_interp_var_at_sample: { + /* XXX: We should probably handle non-constant sample id's */ + nir_const_value *const_sample = nir_src_as_const_value(instr->src[0]); + assert(const_sample); + unsigned msg_data = const_sample ? const_sample->i[0] << 4 : 0; + inst = emit(FS_OPCODE_INTERPOLATE_AT_SAMPLE, dst_x, src, + fs_reg(msg_data)); + break; + } + + case nir_intrinsic_interp_var_at_offset: { + nir_const_value *const_offset = nir_src_as_const_value(instr->src[0]); + + if (const_offset) { + unsigned off_x = MIN2((int)(const_offset->f[0] * 16), 7) & 0xf; + unsigned off_y = MIN2((int)(const_offset->f[1] * 16), 7) & 0xf; + + inst = emit(FS_OPCODE_INTERPOLATE_AT_SHARED_OFFSET, dst_x, src, + fs_reg(off_x | (off_y << 4))); + } else { + src = vgrf(glsl_type::ivec2_type); + fs_reg offset_src = retype(get_nir_src(instr->src[0]), + BRW_REGISTER_TYPE_F); + for (int i = 0; i < 2; i++) { + fs_reg temp = vgrf(glsl_type::float_type); + emit(MUL(temp, offset(offset_src, i), fs_reg(16.0f))); + fs_reg itemp = vgrf(glsl_type::int_type); + emit(MOV(itemp, temp)); /* float to int */ + + /* Clamp the upper end of the range to +7/16. + * ARB_gpu_shader5 requires that we support a maximum offset + * of +0.5, which isn't representable in a S0.4 value -- if + * we didn't clamp it, we'd end up with -8/16, which is the + * opposite of what the shader author wanted. + * + * This is legal due to ARB_gpu_shader5's quantization + * rules: + * + * "Not all values of may be supported; x and y + * offsets may be rounded to fixed-point values with the + * number of fraction bits given by the + * implementation-dependent constant + * FRAGMENT_INTERPOLATION_OFFSET_BITS" + */ + + emit(BRW_OPCODE_SEL, offset(src, i), itemp, fs_reg(7)) + ->conditional_mod = BRW_CONDITIONAL_L; /* min(src2, 7) */ + } + + mlen = 2; + inst = emit(FS_OPCODE_INTERPOLATE_AT_PER_SLOT_OFFSET, dst_x, src, + fs_reg(0u)); } + break; + } + + default: + unreachable("Invalid intrinsic"); + } + + inst->mlen = mlen; + inst->regs_written = 2; /* 2 floats per slot returned */ + inst->pi_noperspective = instr->variables[0]->var->data.interpolation == + INTERP_QUALIFIER_NOPERSPECTIVE; + + for (unsigned j = 0; j < instr->num_components; j++) { + fs_reg src = interp_reg(instr->variables[0]->var->data.location, j); + src.type = dest.type; + + emit(FS_OPCODE_LINTERP, dest, dst_x, dst_y, src); + dest = offset(dest, 1); } break; } - case nir_intrinsic_store_output_vec1_indirect: - case nir_intrinsic_store_output_vec2_indirect: - case nir_intrinsic_store_output_vec3_indirect: - case nir_intrinsic_store_output_vec4_indirect: { + case nir_intrinsic_store_output_indirect: + has_indirect = true; + case nir_intrinsic_store_output: { fs_reg src = get_nir_src(instr->src[0]); - fs_reg indirect = get_nir_src(instr->src[1]); unsigned index = 0; for (int i = 0; i < instr->const_index[1]; i++) { - for (unsigned j = 0; - j < nir_intrinsic_infos[instr->intrinsic].src_components[0]; j++) { - fs_reg new_dest = nir_outputs; - new_dest.reg_offset = instr->const_index[0] + index; - new_dest.reladdr = new(mem_ctx) fs_reg(indirect); - new_dest.type = src.type; + for (unsigned j = 0; j < instr->num_components; j++) { + fs_reg new_dest = offset(retype(nir_outputs, src.type), + instr->const_index[0] + index); + if (has_indirect) + src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[1])); index++; - fs_inst *inst = MOV(new_dest, src); - if (instr->has_predicate) - inst->predicate = BRW_PREDICATE_NORMAL; emit(MOV(new_dest, src)); - src.reg_offset++; + src = offset(src, 1); } } break; @@ -1550,8 +1703,8 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) void fs_visitor::nir_emit_texture(nir_tex_instr *instr) { - brw_wm_prog_key *key = (brw_wm_prog_key*) this->key; unsigned sampler = instr->sampler_index; + fs_reg sampler_reg(sampler); /* FINISHME: We're failing to recompile our programs when the sampler is * updated. This only matters for the texture rectangle scale parameters @@ -1566,13 +1719,13 @@ fs_visitor::nir_emit_texture(nir_tex_instr *instr) bool is_cube_array = instr->sampler_dim == GLSL_SAMPLER_DIM_CUBE && instr->is_array; - int lod_components, offset_components = 0; + int lod_components = 0, offset_components = 0; fs_reg coordinate, shadow_comparitor, lod, lod2, sample_index, mcs, offset; for (unsigned i = 0; i < instr->num_srcs; i++) { - fs_reg src = get_nir_src(instr->src[i]); - switch (instr->src_type[i]) { + fs_reg src = get_nir_src(instr->src[i].src); + switch (instr->src[i].src_type) { case nir_tex_src_bias: lod = retype(src, BRW_REGISTER_TYPE_F); break; @@ -1622,18 +1775,36 @@ fs_visitor::nir_emit_texture(nir_tex_instr *instr) break; case nir_tex_src_projector: unreachable("should be lowered"); - case nir_tex_src_sampler_index: - unreachable("not yet supported"); + + case nir_tex_src_sampler_offset: { + /* Figure out the highest possible sampler index and mark it as used */ + uint32_t max_used = sampler + instr->sampler_array_size - 1; + if (instr->op == nir_texop_tg4 && brw->gen < 8) { + max_used += stage_prog_data->binding_table.gather_texture_start; + } else { + max_used += stage_prog_data->binding_table.texture_start; + } + brw_mark_surface_used(prog_data, max_used); + + /* Emit code to evaluate the actual indexing expression */ + sampler_reg = vgrf(glsl_type::uint_type); + emit(ADD(sampler_reg, src, fs_reg(sampler))) + ->force_writemask_all = true; + break; + } + default: unreachable("unknown texture source"); } } if (instr->op == nir_texop_txf_ms) { - if (brw->gen >= 7 && key->tex.compressed_multisample_layout_mask & (1<coord_components, fs_reg(sampler)); - else + if (brw->gen >= 7 && + key_tex->compressed_multisample_layout_mask & (1 << sampler)) { + mcs = emit_mcs_fetch(coordinate, instr->coord_components, sampler_reg); + } else { mcs = fs_reg(0u); + } } for (unsigned i = 0; i < 3; i++) { @@ -1681,8 +1852,8 @@ fs_visitor::nir_emit_texture(nir_tex_instr *instr) emit_texture(op, dest_type, coordinate, instr->coord_components, shadow_comparitor, lod, lod2, lod_components, sample_index, - offset, offset_components, mcs, gather_component, - is_cube_array, is_rect, sampler, fs_reg(sampler), texunit); + offset, mcs, gather_component, + is_cube_array, is_rect, sampler, sampler_reg, texunit); fs_reg dest = get_nir_dest(instr->dest); dest.type = this->result.type; @@ -1690,26 +1861,6 @@ fs_visitor::nir_emit_texture(nir_tex_instr *instr) emit_percomp(MOV(dest, this->result), (1 << num_components) - 1); } -void -fs_visitor::nir_emit_load_const(nir_load_const_instr *instr) -{ - fs_reg dest = get_nir_dest(instr->dest); - dest.type = BRW_REGISTER_TYPE_UD; - if (instr->array_elems == 0) { - for (unsigned i = 0; i < instr->num_components; i++) { - emit(MOV(dest, fs_reg(instr->value.u[i]))); - dest.reg_offset++; - } - } else { - for (unsigned i = 0; i < instr->array_elems; i++) { - for (unsigned j = 0; j < instr->num_components; j++) { - emit(MOV(dest, fs_reg(instr->array[i].u[j]))); - dest.reg_offset++; - } - } - } -} - void fs_visitor::nir_emit_jump(nir_jump_instr *instr) {