X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fdri%2Fi965%2Fbrw_fs_nir.cpp;h=9cb7b0db3f6b6bf3b6ee000dacb01f51fe22bf40;hb=59006d3ad3ed5d29e84afa5931f425344e2ef658;hp=e88c71bc0e87cc3bf8002880b7fc6325707c96b4;hpb=112d738b91aac44c2509aafe68bdbf9ab74bb3c1;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 e88c71bc0e8..9cb7b0db3f6 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp @@ -24,189 +24,92 @@ #include "glsl/ir.h" #include "glsl/ir_optimization.h" #include "glsl/nir/glsl_to_nir.h" +#include "program/prog_to_nir.h" #include "brw_fs.h" +#include "brw_fs_surface_builder.h" +#include "brw_nir.h" -static void -nir_optimize(nir_shader *nir) -{ - 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); - } 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; -} +using namespace brw; void fs_visitor::emit_nir_code() { - /* first, lower the GLSL IR shader to NIR */ - lower_output_reads(shader->base.ir); - nir_shader *nir = glsl_to_nir(shader->base.ir, NULL, true); - nir_validate_shader(nir); - - nir_lower_global_vars_to_local(nir); - nir_validate_shader(nir); - - 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); - - nir_lower_io(nir); - nir_validate_shader(nir); - - nir_lower_locals_to_regs(nir); - nir_validate_shader(nir); - - nir_remove_dead_variables(nir); - nir_validate_shader(nir); - - nir_lower_samplers(nir, shader_prog, shader->base.Program); - nir_validate_shader(nir); - - nir_lower_system_values(nir); - nir_validate_shader(nir); - - nir_lower_atomics(nir); - nir_validate_shader(nir); - - nir_optimize(nir); - - nir_lower_to_source_mods(nir); - nir_validate_shader(nir); - nir_copy_prop(nir); - nir_validate_shader(nir); - - if (INTEL_DEBUG & DEBUG_WM) { - fprintf(stderr, "NIR (SSA form) for fragment shader:\n"); - 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, - "FS NIR shader: %d inst\n", - count_nir_instrs(nir)); - } - - nir_convert_from_ssa(nir); - nir_validate_shader(nir); - nir_lower_vec_to_movs(nir); - nir_validate_shader(nir); + nir_shader *nir = prog->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 = vgrf(nir->num_inputs); - nir_setup_inputs(nir); - } - - if (nir->num_outputs > 0) { - 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_inputs(nir); + nir_setup_outputs(nir); + nir_setup_uniforms(nir); 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) { assert(strcmp(overload->function->name, "main") == 0); assert(overload->impl); nir_emit_impl(overload->impl); } - - if (INTEL_DEBUG & DEBUG_WM) { - fprintf(stderr, "NIR (final form) for fragment shader:\n"); - nir_print_shader(nir, stderr); - } - - ralloc_free(nir); } 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); + nir_inputs = bld.vgrf(BRW_REGISTER_TYPE_F, shader->num_inputs); + + 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, bld, 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 { - 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). + */ + const glsl_type *const t = var->type->without_array(); + const unsigned components = t->components(); + const unsigned cols = t->matrix_columns; + const unsigned elts = t->vector_elements; + unsigned array_length = var->type->is_array() ? var->type->length : 1; + for (unsigned i = 0; i < array_length; i++) { + for (unsigned j = 0; j < cols; j++) { + for (unsigned k = 0; k < elts; k++) { + bld.MOV(offset(retype(input, type), bld, + components * i + elts * j + k), + offset(fs_reg(ATTR, var->data.location + i, type), + bld, 4 * j + k)); + } + } + } + break; + } + case MESA_SHADER_GEOMETRY: + case MESA_SHADER_COMPUTE: + case MESA_SHADER_TESS_CTRL: + case MESA_SHADER_TESS_EVAL: + 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(bld, fs_inst(BRW_OPCODE_MOV, bld.dispatch_width(), + 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; } } } @@ -216,41 +119,54 @@ 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; - fs_reg reg = offset(nir_outputs, var->data.driver_location); - - if (var->data.index > 0) { - assert(var->data.location == FRAG_RESULT_DATA0); - assert(var->data.index == 1); - this->dual_src_output = reg; - this->do_dual_src = true; - } else if (var->data.location == FRAG_RESULT_COLOR) { - /* Writing gl_FragColor outputs to all color regions. */ - for (unsigned int i = 0; i < MAX2(key->nr_color_regions, 1); i++) { - this->outputs[i] = reg; - this->output_components[i] = 4; - } - } else if (var->data.location == FRAG_RESULT_DEPTH) { - this->frag_depth = reg; - } else if (var->data.location == FRAG_RESULT_SAMPLE_MASK) { - this->sample_mask = reg; - } else { - /* gl_FragData or a user-defined FS output */ - 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] = offset(reg, vector_elements * i); + nir_outputs = bld.vgrf(BRW_REGISTER_TYPE_F, shader->num_outputs); + + foreach_list_typed(nir_variable, var, node, &shader->outputs) { + fs_reg reg = offset(nir_outputs, bld, var->data.driver_location); + + int vector_elements = + var->type->is_array() ? var->type->fields.array->vector_elements + : var->type->vector_elements; + + switch (stage) { + case 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, bld, 4 * i); this->output_components[output] = vector_elements; } + break; + case MESA_SHADER_FRAGMENT: + if (var->data.index > 0) { + assert(var->data.location == FRAG_RESULT_DATA0); + assert(var->data.index == 1); + this->dual_src_output = reg; + this->do_dual_src = true; + } else if (var->data.location == FRAG_RESULT_COLOR) { + /* Writing gl_FragColor outputs to all color regions. */ + for (unsigned int i = 0; i < MAX2(key->nr_color_regions, 1); i++) { + this->outputs[i] = reg; + this->output_components[i] = 4; + } + } else if (var->data.location == FRAG_RESULT_DEPTH) { + this->frag_depth = reg; + } else if (var->data.location == FRAG_RESULT_SAMPLE_MASK) { + this->sample_mask = reg; + } else { + /* gl_FragData or a user-defined FS output */ + assert(var->data.location >= FRAG_RESULT_DATA0 && + var->data.location < FRAG_RESULT_DATA0+BRW_MAX_DRAW_BUFFERS); + + /* 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] = offset(reg, bld, vector_elements * i); + this->output_components[output] = vector_elements; + } + } + break; + default: + unreachable("unhandled shader stage"); } } } @@ -258,25 +174,40 @@ fs_visitor::nir_setup_outputs(nir_shader *shader) void fs_visitor::nir_setup_uniforms(nir_shader *shader) { - uniforms = shader->num_uniforms; - param_size[0] = shader->num_uniforms; + num_direct_uniforms = shader->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; + /* We split the uniform register file in half. The first half is + * entirely direct uniforms. The second half is indirect. + */ + if (num_direct_uniforms > 0) + param_size[0] = num_direct_uniforms; + if (shader->num_uniforms > num_direct_uniforms) + param_size[num_direct_uniforms] = shader->num_uniforms - num_direct_uniforms; - /* UBO's and atomics don't take up space in the uniform file */ + uniforms = shader->num_uniforms; - if (var->interface_type != NULL || var->type->contains_atomic()) - continue; + if (shader_prog) { + 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()) + continue; - if (strncmp(var->name, "gl_", 3) == 0) - nir_setup_builtin_uniform(var); - else - nir_setup_uniform(var); + if (strncmp(var->name, "gl_", 3) == 0) + nir_setup_builtin_uniform(var); + else + nir_setup_uniform(var); + } + } else { + /* prog_to_nir doesn't create uniform variables; set param up directly. */ + for (unsigned p = 0; p < prog->Parameters->NumParameters; p++) { + for (unsigned int i = 0; i < 4; i++) { + stage_prog_data->param[4 * p + i] = + &prog->Parameters->ParameterValues[p][i]; + } + } } } @@ -293,9 +224,12 @@ fs_visitor::nir_setup_uniform(nir_variable *var) * our name. */ unsigned index = var->data.driver_location; - for (unsigned u = 0; u < shader_prog->NumUserUniformStorage; u++) { + for (unsigned u = 0; u < shader_prog->NumUniformStorage; u++) { struct gl_uniform_storage *storage = &shader_prog->UniformStorage[u]; + if (storage->builtin) + continue; + if (strncmp(var->name, storage->name, namelen) != 0 || (storage->name[namelen] != 0 && storage->name[namelen] != '.' && @@ -359,6 +293,30 @@ emit_system_values_block(nir_block *block, void *void_visitor) 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]; @@ -375,7 +333,7 @@ emit_system_values_block(nir_block *block, void *void_visitor) case nir_intrinsic_load_sample_mask_in: assert(v->stage == MESA_SHADER_FRAGMENT); - assert(v->brw->gen >= 7); + assert(v->devinfo->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), @@ -409,15 +367,19 @@ fs_visitor::nir_emit_impl(nir_function_impl *impl) 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_locals[reg->index] = bld.vgrf(BRW_REGISTER_TYPE_F, size); } + nir_ssa_values = reralloc(mem_ctx, nir_ssa_values, fs_reg, + impl->ssa_alloc); + 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: @@ -442,39 +404,33 @@ void fs_visitor::nir_emit_if(nir_if *if_stmt) { /* first, put the condition into f0 */ - fs_inst *inst = emit(MOV(reg_null_d, + fs_inst *inst = bld.MOV(bld.null_reg_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)); + bld.IF(BRW_PREDICATE_NORMAL); nir_emit_cf_list(&if_stmt->then_list); /* note: if the else is empty, dead CF elimination will remove it */ - emit(BRW_OPCODE_ELSE); + bld.emit(BRW_OPCODE_ELSE); nir_emit_cf_list(&if_stmt->else_list); - emit(BRW_OPCODE_ENDIF); + bld.emit(BRW_OPCODE_ENDIF); - if (!try_replace_with_sel() && brw->gen < 6) { - no16("Can't support (non-uniform) control flow on SIMD16\n"); - } + try_replace_with_sel(); } void fs_visitor::nir_emit_loop(nir_loop *loop) { - if (brw->gen < 6) { - no16("Can't support (non-uniform) control flow on SIMD16\n"); - } - - emit(BRW_OPCODE_DO); + bld.emit(BRW_OPCODE_DO); nir_emit_cf_list(&loop->body); - emit(BRW_OPCODE_WHILE); + bld.emit(BRW_OPCODE_WHILE); } void @@ -488,27 +444,31 @@ fs_visitor::nir_emit_block(nir_block *block) void fs_visitor::nir_emit_instr(nir_instr *instr) { + const fs_builder abld = bld.annotate(NULL, instr); + switch (instr->type) { case nir_instr_type_alu: - nir_emit_alu(nir_instr_as_alu(instr)); + nir_emit_alu(abld, nir_instr_as_alu(instr)); break; case nir_instr_type_intrinsic: - nir_emit_intrinsic(nir_instr_as_intrinsic(instr)); + nir_emit_intrinsic(abld, nir_instr_as_intrinsic(instr)); break; case nir_instr_type_tex: - nir_emit_texture(nir_instr_as_tex(instr)); + nir_emit_texture(abld, nir_instr_as_tex(instr)); break; case nir_instr_type_load_const: - /* We can hit these, but we do nothing now and use them as - * immediates later. - */ + nir_emit_load_const(abld, nir_instr_as_load_const(instr)); + break; + + case nir_instr_type_ssa_undef: + nir_emit_undef(abld, nir_instr_as_ssa_undef(instr)); break; case nir_instr_type_jump: - nir_emit_jump(nir_instr_as_jump(instr)); + nir_emit_jump(abld, nir_instr_as_jump(instr)); break; default: @@ -520,9 +480,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: @@ -534,43 +494,185 @@ 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.ssa->parent_instr->type != nir_instr_type_intrinsic) + return false; + + nir_intrinsic_instr *src0 = + nir_instr_as_intrinsic(instr->src[0].src.ssa->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 (devinfo->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 = bld.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; + } + + bld.OR(tmp, g1_6, fs_reg(0x3f800000)); + } + bld.AND(retype(result, BRW_REGISTER_TYPE_D), tmp, fs_reg(0xbf800000)); + + return true; +} + void -fs_visitor::nir_emit_alu(nir_alu_instr *instr) +fs_visitor::nir_emit_alu(const fs_builder &bld, 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 result = get_nir_dest(instr->dest.dest); result.type = brw_type_for_nir_type(nir_op_infos[instr->op].output_type); - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) - op[i] = get_nir_alu_src(instr, i); + 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 = bld.vgrf(result.type, 4); + 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 = bld.MOV(offset(temp, bld, i), + offset(op[0], bld, instr->src[0].swizzle[i])); + } else { + inst = bld.MOV(offset(temp, bld, i), + offset(op[i], bld, 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; + bld.MOV(offset(result, bld, i), offset(temp, bld, 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) { - /* We've already scalarized, so we know that we only have one - * channel. The only question is which channel. + /* 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); - unsigned off = ffs(instr->dest.write_mask) - 1; - result = offset(result, off); + channel = ffs(instr->dest.write_mask) - 1; + + result = offset(result, bld, channel); + } - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) - op[i] = offset(op[i], off); + for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { + assert(nir_op_infos[instr->op].input_sizes[i] < 2); + op[i] = offset(op[i], bld, instr->src[i].swizzle[channel]); } switch (instr->op) { - case nir_op_fmov: case nir_op_i2f: case nir_op_u2f: - inst = emit(MOV(result, op[0])); + inst = bld.MOV(result, op[0]); inst->saturate = instr->dest.saturate; break; - case nir_op_imov: case nir_op_f2i: case nir_op_f2u: - emit(MOV(result, op[0])); + bld.MOV(result, op[0]); break; case nir_op_fsign: { @@ -579,17 +681,17 @@ 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(CMP(reg_null_f, op[0], fs_reg(0.0f), BRW_CONDITIONAL_NZ)); + bld.CMP(bld.null_reg_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(AND(result_int, op[0], fs_reg(0x80000000u))); + bld.AND(result_int, op[0], fs_reg(0x80000000u)); - inst = emit(OR(result_int, result_int, fs_reg(0x3f800000u))); + inst = bld.OR(result_int, result_int, fs_reg(0x3f800000u)); inst->predicate = BRW_PREDICATE_NORMAL; if (instr->dest.saturate) { - inst = emit(MOV(result, result)); + inst = bld.MOV(result, result); inst->saturate = true; } break; @@ -600,183 +702,186 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) * -> 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))); + bld.CMP(bld.null_reg_d(), op[0], fs_reg(0), BRW_CONDITIONAL_G); + bld.ASR(result, op[0], fs_reg(31)); + inst = bld.OR(result, result, fs_reg(1)); inst->predicate = BRW_PREDICATE_NORMAL; break; case nir_op_frcp: - inst = emit_math(SHADER_OPCODE_RCP, result, op[0]); + inst = bld.emit(SHADER_OPCODE_RCP, result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_fexp2: - inst = emit_math(SHADER_OPCODE_EXP2, result, op[0]); + inst = bld.emit(SHADER_OPCODE_EXP2, result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_flog2: - inst = emit_math(SHADER_OPCODE_LOG2, result, op[0]); + inst = bld.emit(SHADER_OPCODE_LOG2, result, op[0]); inst->saturate = instr->dest.saturate; break; - case nir_op_fexp: - case nir_op_flog: - unreachable("not reached: should be handled by ir_explog_to_explog2"); - case nir_op_fsin: - case nir_op_fsin_reduced: - inst = emit_math(SHADER_OPCODE_SIN, result, op[0]); + inst = bld.emit(SHADER_OPCODE_SIN, result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_fcos: - case nir_op_fcos_reduced: - inst = emit_math(SHADER_OPCODE_COS, result, op[0]); + inst = bld.emit(SHADER_OPCODE_COS, result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_fddx: if (fs_key->high_quality_derivatives) { - inst = emit(FS_OPCODE_DDX_FINE, result, op[0]); + inst = bld.emit(FS_OPCODE_DDX_FINE, result, op[0]); } else { - inst = emit(FS_OPCODE_DDX_COARSE, result, op[0]); + inst = bld.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 = bld.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 = bld.emit(FS_OPCODE_DDX_COARSE, result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_fddy: if (fs_key->high_quality_derivatives) { - inst = emit(FS_OPCODE_DDY_FINE, result, op[0], - fs_reg(fs_key->render_to_fbo)); + inst = bld.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 = bld.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 = bld.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 = bld.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: - inst = emit(ADD(result, op[0], op[1])); + inst = bld.ADD(result, op[0], op[1]); inst->saturate = instr->dest.saturate; break; case nir_op_fmul: - inst = emit(MUL(result, op[0], op[1])); + inst = bld.MUL(result, op[0], op[1]); inst->saturate = instr->dest.saturate; break; - case nir_op_imul: { - /* TODO put in the 16-bit constant optimization once we have SSA */ - - if (brw->gen >= 7) - no16("SIMD16 explicit accumulator operands unsupported\n"); - - struct brw_reg acc = retype(brw_acc_reg(dispatch_width), result.type); - - emit(MUL(acc, op[0], op[1])); - emit(MACH(reg_null_d, op[0], op[1])); - emit(MOV(result, fs_reg(acc))); + case nir_op_imul: + bld.MUL(result, op[0], op[1]); break; - } case nir_op_imul_high: case nir_op_umul_high: { - if (brw->gen >= 7) + if (devinfo->gen >= 7) no16("SIMD16 explicit accumulator operands unsupported\n"); struct brw_reg acc = retype(brw_acc_reg(dispatch_width), result.type); - emit(MUL(acc, op[0], op[1])); - emit(MACH(result, op[0], op[1])); + fs_inst *mul = bld.MUL(acc, op[0], op[1]); + bld.MACH(result, op[0], op[1]); + + /* Until Gen8, integer multiplies read 32-bits from one source, and + * 16-bits from the other, and relying on the MACH instruction to + * generate the high bits of the result. + * + * On Gen8, the multiply instruction does a full 32x32-bit multiply, + * but in order to do a 64x64-bit multiply we have to simulate the + * previous behavior and then use a MACH instruction. + * + * FINISHME: Don't use source modifiers on src1. + */ + if (devinfo->gen >= 8) { + assert(mul->src[1].type == BRW_REGISTER_TYPE_D || + mul->src[1].type == BRW_REGISTER_TYPE_UD); + if (mul->src[1].type == BRW_REGISTER_TYPE_D) { + mul->src[1].type = BRW_REGISTER_TYPE_W; + mul->src[1].stride = 2; + } else { + mul->src[1].type = BRW_REGISTER_TYPE_UW; + mul->src[1].stride = 2; + } + } break; } case nir_op_idiv: case nir_op_udiv: - emit_math(SHADER_OPCODE_INT_QUOTIENT, result, op[0], op[1]); + bld.emit(SHADER_OPCODE_INT_QUOTIENT, result, op[0], op[1]); break; - case nir_op_uadd_carry: { - if (brw->gen >= 7) - no16("SIMD16 explicit accumulator operands unsupported\n"); - - struct brw_reg acc = retype(brw_acc_reg(dispatch_width), - BRW_REGISTER_TYPE_UD); - - emit(ADDC(reg_null_ud, op[0], op[1])); - emit(MOV(result, fs_reg(acc))); - break; - } - - case nir_op_usub_borrow: { - if (brw->gen >= 7) - no16("SIMD16 explicit accumulator operands unsupported\n"); - - struct brw_reg acc = retype(brw_acc_reg(dispatch_width), - BRW_REGISTER_TYPE_UD); + case nir_op_uadd_carry: + unreachable("Should have been lowered by carry_to_arith()."); - emit(SUBB(reg_null_ud, op[0], op[1])); - emit(MOV(result, fs_reg(acc))); - break; - } + case nir_op_usub_borrow: + unreachable("Should have been lowered by borrow_to_arith()."); case nir_op_umod: - emit_math(SHADER_OPCODE_INT_REMAINDER, result, op[0], op[1]); + bld.emit(SHADER_OPCODE_INT_REMAINDER, result, op[0], op[1]); break; case nir_op_flt: case nir_op_ilt: case nir_op_ult: - emit(CMP(result, op[0], op[1], BRW_CONDITIONAL_L)); + bld.CMP(result, op[0], op[1], BRW_CONDITIONAL_L); break; case nir_op_fge: case nir_op_ige: case nir_op_uge: - emit(CMP(result, op[0], op[1], BRW_CONDITIONAL_GE)); + bld.CMP(result, op[0], op[1], BRW_CONDITIONAL_GE); break; case nir_op_feq: case nir_op_ieq: - emit(CMP(result, op[0], op[1], BRW_CONDITIONAL_Z)); + bld.CMP(result, op[0], op[1], BRW_CONDITIONAL_Z); break; case nir_op_fne: case nir_op_ine: - emit(CMP(result, op[0], op[1], BRW_CONDITIONAL_NZ)); + bld.CMP(result, op[0], op[1], BRW_CONDITIONAL_NZ); break; case nir_op_inot: - emit(NOT(result, op[0])); + if (devinfo->gen >= 8) { + resolve_source_modifiers(&op[0]); + } + bld.NOT(result, op[0]); break; case nir_op_ixor: - emit(XOR(result, op[0], op[1])); + if (devinfo->gen >= 8) { + resolve_source_modifiers(&op[0]); + resolve_source_modifiers(&op[1]); + } + bld.XOR(result, op[0], op[1]); break; case nir_op_ior: - emit(OR(result, op[0], op[1])); + if (devinfo->gen >= 8) { + resolve_source_modifiers(&op[0]); + resolve_source_modifiers(&op[1]); + } + bld.OR(result, op[0], op[1]); break; case nir_op_iand: - emit(AND(result, op[0], op[1])); + if (devinfo->gen >= 8) { + resolve_source_modifiers(&op[0]); + resolve_source_modifiers(&op[1]); + } + bld.AND(result, op[0], op[1]); break; case nir_op_fdot2: @@ -820,74 +925,68 @@ 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: - inst = emit_math(SHADER_OPCODE_SQRT, result, op[0]); + inst = bld.emit(SHADER_OPCODE_SQRT, result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_frsq: - inst = emit_math(SHADER_OPCODE_RSQ, result, op[0]); + inst = bld.emit(SHADER_OPCODE_RSQ, result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_b2i: - emit(AND(result, op[0], fs_reg(1))); - break; case nir_op_b2f: - emit(AND(retype(result, BRW_REGISTER_TYPE_UD), op[0], fs_reg(0x3f800000u))); + bld.MOV(result, negate(op[0])); break; case nir_op_f2b: - emit(CMP(result, op[0], fs_reg(0.0f), BRW_CONDITIONAL_NZ)); + bld.CMP(result, op[0], fs_reg(0.0f), BRW_CONDITIONAL_NZ); break; case nir_op_i2b: - emit(CMP(result, op[0], fs_reg(0), BRW_CONDITIONAL_NZ)); + bld.CMP(result, op[0], fs_reg(0), BRW_CONDITIONAL_NZ); break; case nir_op_ftrunc: - inst = emit(RNDZ(result, op[0])); + inst = bld.RNDZ(result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_fceil: { op[0].negate = !op[0].negate; fs_reg temp = vgrf(glsl_type::float_type); - emit(RNDD(temp, op[0])); + bld.RNDD(temp, op[0]); temp.negate = true; - inst = emit(MOV(result, temp)); + inst = bld.MOV(result, temp); inst->saturate = instr->dest.saturate; break; } case nir_op_ffloor: - inst = emit(RNDD(result, op[0])); + inst = bld.RNDD(result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_ffract: - inst = emit(FRC(result, op[0])); + inst = bld.FRC(result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_fround_even: - inst = emit(RNDE(result, op[0])); + inst = bld.RNDE(result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_fmin: case nir_op_imin: case nir_op_umin: - if (brw->gen >= 6) { - inst = emit(BRW_OPCODE_SEL, result, op[0], op[1]); + if (devinfo->gen >= 6) { + inst = bld.emit(BRW_OPCODE_SEL, result, op[0], op[1]); inst->conditional_mod = BRW_CONDITIONAL_L; } else { - emit(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_L)); - inst = emit(SEL(result, op[0], op[1])); + bld.CMP(bld.null_reg_d(), op[0], op[1], BRW_CONDITIONAL_L); + inst = bld.SEL(result, op[0], op[1]); + inst->predicate = BRW_PREDICATE_NORMAL; } inst->saturate = instr->dest.saturate; break; @@ -895,12 +994,13 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) case nir_op_fmax: case nir_op_imax: case nir_op_umax: - if (brw->gen >= 6) { - inst = emit(BRW_OPCODE_SEL, result, op[0], op[1]); + if (devinfo->gen >= 6) { + inst = bld.emit(BRW_OPCODE_SEL, result, op[0], op[1]); inst->conditional_mod = BRW_CONDITIONAL_GE; } else { - emit(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_GE)); - inst = emit(SEL(result, op[0], op[1])); + bld.CMP(bld.null_reg_d(), op[0], op[1], BRW_CONDITIONAL_GE); + inst = bld.SEL(result, op[0], op[1]); + inst->predicate = BRW_PREDICATE_NORMAL; } inst->saturate = instr->dest.saturate; break; @@ -918,57 +1018,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: - inst = emit(FS_OPCODE_UNPACK_HALF_2x16_SPLIT_X, result, op[0]); + inst = bld.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: - inst = emit(FS_OPCODE_UNPACK_HALF_2x16_SPLIT_Y, result, op[0]); + inst = bld.emit(FS_OPCODE_UNPACK_HALF_2x16_SPLIT_Y, result, op[0]); inst->saturate = instr->dest.saturate; break; case nir_op_fpow: - inst = emit(SHADER_OPCODE_POW, result, op[0], op[1]); + inst = bld.emit(SHADER_OPCODE_POW, result, op[0], op[1]); inst->saturate = instr->dest.saturate; break; case nir_op_bitfield_reverse: - emit(BFREV(result, op[0])); + bld.BFREV(result, op[0]); break; case nir_op_bit_count: - emit(CBIT(result, op[0])); + bld.CBIT(result, op[0]); break; case nir_op_ufind_msb: case nir_op_ifind_msb: { - emit(FBH(retype(result, BRW_REGISTER_TYPE_UD), op[0])); + bld.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(CMP(reg_null_d, result, fs_reg(-1), BRW_CONDITIONAL_NZ)); + bld.CMP(bld.null_reg_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 = bld.ADD(result, neg_result, fs_reg(31)); inst->predicate = BRW_PREDICATE_NORMAL; break; } case nir_op_find_lsb: - emit(FBL(result, op[0])); + bld.FBL(result, op[0]); break; case nir_op_ubitfield_extract: case nir_op_ibitfield_extract: - emit(BFE(result, op[2], op[1], op[0])); + bld.BFE(result, op[2], op[1], op[0]); break; case nir_op_bfm: - emit(BFI1(result, op[0], op[1])); + bld.BFI1(result, op[0], op[1]); break; case nir_op_bfi: - emit(BFI2(result, op[0], op[1], op[2])); + bld.BFI2(result, op[0], op[1], op[2]); break; case nir_op_bitfield_insert: @@ -976,152 +1076,146 @@ fs_visitor::nir_emit_alu(nir_alu_instr *instr) "lower_instructions::bitfield_insert_to_bfm_bfi"); case nir_op_ishl: - emit(SHL(result, op[0], op[1])); + bld.SHL(result, op[0], op[1]); break; case nir_op_ishr: - emit(ASR(result, op[0], op[1])); + bld.ASR(result, op[0], op[1]); break; case nir_op_ushr: - emit(SHR(result, op[0], op[1])); + bld.SHR(result, op[0], op[1]); break; case nir_op_pack_half_2x16_split: - emit(FS_OPCODE_PACK_HALF_2x16_SPLIT, result, op[0], op[1]); + bld.emit(FS_OPCODE_PACK_HALF_2x16_SPLIT, result, op[0], op[1]); break; case nir_op_ffma: - emit(MAD(result, op[2], op[1], op[0])); + inst = bld.MAD(result, op[2], op[1], op[0]); + inst->saturate = instr->dest.saturate; break; case nir_op_flrp: - /* TODO emulate for gen < 6 */ - emit(LRP(result, op[2], op[1], op[0])); + inst = bld.LRP(result, op[0], op[1], op[2]); + inst->saturate = instr->dest.saturate; break; case nir_op_bcsel: - emit(CMP(reg_null_d, op[0], fs_reg(0), BRW_CONDITIONAL_NZ)); - inst = emit(SEL(result, op[1], op[2])); + if (optimize_frontfacing_ternary(instr, result)) + return; + + bld.CMP(bld.null_reg_d(), op[0], fs_reg(0), BRW_CONDITIONAL_NZ); + inst = bld.SEL(result, op[1], op[2]); inst->predicate = BRW_PREDICATE_NORMAL; break; 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 (devinfo->gen <= 5 && + (instr->instr.pass_flags & BRW_NIR_BOOLEAN_MASK) == BRW_NIR_BOOLEAN_NEEDS_RESOLVE) { + fs_reg masked = vgrf(glsl_type::int_type); + bld.AND(masked, result, fs_reg(1)); + masked.negate = true; + bld.MOV(retype(result, BRW_REGISTER_TYPE_D), masked); + } } -fs_reg -fs_visitor::get_nir_src(nir_src src) +void +fs_visitor::nir_emit_load_const(const fs_builder &bld, + nir_load_const_instr *instr) { - 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; + fs_reg reg = bld.vgrf(BRW_REGISTER_TYPE_D, instr->def.num_components); - for (unsigned i = 0; i < src.ssa->num_components; ++i) - emit(MOV(offset(reg, i), fs_reg(load->value.i[i]))); + for (unsigned i = 0; i < instr->def.num_components; i++) + bld.MOV(offset(reg, bld, i), fs_reg(instr->value.i[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]; - - /* 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); - } + nir_ssa_values[instr->def.index] = reg; +} - return reg; - } +void +fs_visitor::nir_emit_undef(const fs_builder &bld, nir_ssa_undef_instr *instr) +{ + nir_ssa_values[instr->def.index] = bld.vgrf(BRW_REGISTER_TYPE_D, + instr->def.num_components); } -fs_reg -fs_visitor::get_nir_alu_src(nir_alu_instr *instr, unsigned src) +static fs_reg +fs_reg_for_nir_reg(fs_visitor *v, nir_register *nir_reg, + unsigned base_offset, nir_src *indirect) { - fs_reg reg = get_nir_src(instr->src[src].src); + fs_reg reg; - reg.type = brw_type_for_nir_type(nir_op_infos[instr->op].input_types[src]); - reg.abs = instr->src[src].abs; - reg.negate = instr->src[src].negate; + assert(!nir_reg->is_global); - 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; + reg = v->nir_locals[nir_reg->index]; - if (instr->src[src].swizzle[i] != i) - needs_swizzle = true; + reg = offset(reg, v->bld, base_offset * nir_reg->num_components); + if (indirect) { + int multiplier = nir_reg->num_components * (v->dispatch_width / 8); - num_components = i + 1; + reg.reladdr = new(v->mem_ctx) fs_reg(v->vgrf(glsl_type::int_type)); + v->bld.MUL(*reg.reladdr, v->get_nir_src(*indirect), + fs_reg(multiplier)); } - if (needs_swizzle) { - /* resolve the swizzle through MOV's */ - fs_reg new_reg = vgrf(num_components); - new_reg.type = reg.type; - - for (unsigned i = 0; i < 4; i++) { - if (!nir_alu_instr_channel_used(instr, src, i)) - continue; - - emit(MOV(offset(new_reg, i), - offset(reg, instr->src[src].swizzle[i]))); - } + return reg; +} - return new_reg; +fs_reg +fs_visitor::get_nir_src(nir_src src) +{ + fs_reg reg; + if (src.is_ssa) { + reg = nir_ssa_values[src.ssa->index]; + } else { + reg = fs_reg_for_nir_reg(this, src.reg.reg, src.reg.base_offset, + src.reg.indirect); } - return reg; + /* 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 + */ + return retype(reg, BRW_REGISTER_TYPE_D); } fs_reg fs_visitor::get_nir_dest(nir_dest dest) { - 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), - BRW_REGISTER_TYPE_D); + if (dest.is_ssa) { + nir_ssa_values[dest.ssa.index] = bld.vgrf(BRW_REGISTER_TYPE_F, + dest.ssa.num_components); + return nir_ssa_values[dest.ssa.index]; } - return reg; + return fs_reg_for_nir_reg(this, dest.reg.reg, dest.reg.base_offset, + dest.reg.indirect); } void -fs_visitor::emit_percomp(fs_inst *inst, unsigned wr_mask) +fs_visitor::emit_percomp(const fs_builder &bld, const fs_inst &inst, + unsigned wr_mask) { for (unsigned i = 0; i < 4; i++) { if (!((wr_mask >> i) & 1)) continue; - fs_inst *new_inst = new(mem_ctx) fs_inst(*inst); - new_inst->dst = offset(new_inst->dst, i); + fs_inst *new_inst = new(mem_ctx) fs_inst(inst); + new_inst->dst = offset(new_inst->dst, bld, i); for (unsigned j = 0; j < new_inst->sources; j++) - if (inst->src[j].file == GRF) - new_inst->src[j] = offset(new_inst->src[j], i); + if (new_inst->src[j].file == GRF) + new_inst->src[j] = offset(new_inst->src[j], bld, i); - emit(new_inst); + bld.emit(new_inst); } } void -fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) +fs_visitor::nir_emit_intrinsic(const fs_builder &bld, nir_intrinsic_instr *instr) { fs_reg dest; if (nir_intrinsic_infos[instr->intrinsic].has_dest) @@ -1130,68 +1224,114 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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 = bld.CMP(bld.null_reg_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 = bld.CMP(bld.null_reg_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; + if (devinfo->gen >= 6) { + emit_discard_jump(); } - break; } case nir_intrinsic_atomic_counter_inc: case nir_intrinsic_atomic_counter_dec: 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])); + using namespace surface_access; + /* Get the arguments of the atomic intrinsic. */ + const fs_reg offset = get_nir_src(instr->src[0]); + const unsigned surface = (stage_prog_data->binding_table.abo_start + + instr->const_index[0]); + fs_reg tmp; + + /* Emit a surface read or atomic op. */ 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"); + case nir_intrinsic_atomic_counter_read: + tmp = emit_untyped_read(bld, fs_reg(surface), offset, 1, 1); + break; + + case nir_intrinsic_atomic_counter_inc: + tmp = emit_untyped_atomic(bld, fs_reg(surface), offset, fs_reg(), + fs_reg(), 1, 1, BRW_AOP_INC); + break; + + case nir_intrinsic_atomic_counter_dec: + tmp = emit_untyped_atomic(bld, fs_reg(surface), offset, fs_reg(), + fs_reg(), 1, 1, BRW_AOP_PREDEC); + break; + + default: + unreachable("Unreachable"); } + + /* Assign the result. */ + bld.MOV(retype(dest, BRW_REGISTER_TYPE_UD), tmp); + + /* Mark the surface as used. */ + brw_mark_surface_used(stage_prog_data, surface); + break; + } + + case nir_intrinsic_memory_barrier: { + const fs_reg tmp = bld.vgrf(BRW_REGISTER_TYPE_UD, 16 / dispatch_width); + bld.emit(SHADER_OPCODE_MEMORY_FENCE, tmp) + ->regs_written = 2; break; } case nir_intrinsic_load_front_face: - assert(!"TODO"); + bld.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; + bld.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; + bld.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; + bld.MOV(dest, instance_id); + break; + } case nir_intrinsic_load_sample_mask_in: { 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)); + bld.MOV(dest, sample_mask_in); break; } @@ -1199,8 +1339,8 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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))); + bld.MOV(dest, sample_pos); + bld.MOV(offset(dest, bld, 1), offset(sample_pos, bld, 1)); break; } @@ -1208,31 +1348,39 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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)); + bld.MOV(dest, sample_id); break; } case nir_intrinsic_load_uniform_indirect: has_indirect = true; + /* fallthrough */ case nir_intrinsic_load_uniform: { - unsigned index = 0; - 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); - if (has_indirect) - src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[0])); - index++; - - emit(MOV(dest, src)); - dest = offset(dest, 1); - } + 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 (unsigned j = 0; j < instr->num_components; j++) { + fs_reg src = offset(retype(uniform_reg, dest.type), bld, index); + if (has_indirect) + src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[0])); + index++; + + bld.MOV(dest, src); + dest = offset(dest, bld, 1); } break; } 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; @@ -1242,13 +1390,13 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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. + * per-channel and add the base UBO index; we have to 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; + bld.ADD(surf_index, get_nir_src(instr->src[0]), + fs_reg(stage_prog_data->binding_table.ubo_start)); + surf_index = bld.emit_uniformize(surf_index); /* Assume this may touch any UBO. It would be nice to provide * a tighter bound, but the array information is already lowered away. @@ -1261,21 +1409,21 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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))); + bld.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)); + VARYING_PULL_CONSTANT_LOAD(bld, offset(dest, bld, i), surf_index, + base_offset, vec4_offset + i); } else { fs_reg packed_consts = vgrf(glsl_type::float_type); packed_consts.type = dest.type; 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); + bld.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); @@ -1285,8 +1433,8 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) */ assert(packed_consts.subreg_offset < 32); - emit(MOV(dest, packed_consts)); - dest = offset(dest, 1); + bld.MOV(dest, packed_consts); + dest = offset(dest, bld, 1); } } break; @@ -1294,19 +1442,18 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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 < 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++; - - emit(MOV(dest, src)); - dest = offset(dest, 1); - } + for (unsigned j = 0; j < instr->num_components; j++) { + fs_reg src = offset(retype(nir_inputs, dest.type), bld, + instr->const_index[0] + index); + if (has_indirect) + src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[0])); + index++; + + bld.MOV(dest, src); + dest = offset(dest, bld, 1); } break; } @@ -1332,14 +1479,11 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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."); + assert(stage == MESA_SHADER_FRAGMENT); + + ((struct brw_wm_prog_data *) prog_data)->pulls_bary = true; - fs_reg dst_x = vgrf(2); - fs_reg dst_y = offset(dst_x, 1); + fs_reg dst_xy = bld.vgrf(BRW_REGISTER_TYPE_F, 2); /* 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 @@ -1351,7 +1495,8 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) switch (instr->intrinsic) { case nir_intrinsic_interp_var_at_centroid: - inst = emit(FS_OPCODE_INTERPOLATE_AT_CENTROID, dst_x, src, fs_reg(0u)); + inst = bld.emit(FS_OPCODE_INTERPOLATE_AT_CENTROID, + dst_xy, src, fs_reg(0u)); break; case nir_intrinsic_interp_var_at_sample: { @@ -1359,8 +1504,8 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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)); + inst = bld.emit(FS_OPCODE_INTERPOLATE_AT_SAMPLE, dst_xy, src, + fs_reg(msg_data)); break; } @@ -1371,17 +1516,17 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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))); + inst = bld.emit(FS_OPCODE_INTERPOLATE_AT_SHARED_OFFSET, dst_xy, 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))); + bld.MUL(temp, offset(offset_src, bld, i), fs_reg(16.0f)); fs_reg itemp = vgrf(glsl_type::int_type); - emit(MOV(itemp, temp)); /* float to int */ + bld.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 @@ -1398,14 +1543,13 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) * 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) */ + set_condmod(BRW_CONDITIONAL_L, + bld.SEL(offset(src, bld, i), itemp, fs_reg(7))); } - mlen = 2; - inst = emit(FS_OPCODE_INTERPOLATE_AT_PER_SLOT_OFFSET, dst_x, src, - fs_reg(0u)); + mlen = 2 * dispatch_width / 8; + inst = bld.emit(FS_OPCODE_INTERPOLATE_AT_PER_SLOT_OFFSET, dst_xy, src, + fs_reg(0u)); } break; } @@ -1415,7 +1559,8 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) } inst->mlen = mlen; - inst->regs_written = 2; /* 2 floats per slot returned */ + /* 2 floats per slot returned */ + inst->regs_written = 2 * dispatch_width / 8; inst->pi_noperspective = instr->variables[0]->var->data.interpolation == INTERP_QUALIFIER_NOPERSPECTIVE; @@ -1423,40 +1568,42 @@ fs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr) 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); + bld.emit(FS_OPCODE_LINTERP, dest, dst_xy, src); + dest = offset(dest, bld, 1); } break; } case nir_intrinsic_store_output_indirect: has_indirect = true; + /* fallthrough */ case nir_intrinsic_store_output: { 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 < 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++; - emit(MOV(new_dest, src)); - src = offset(src, 1); - } + for (unsigned j = 0; j < instr->num_components; j++) { + fs_reg new_dest = offset(retype(nir_outputs, src.type), bld, + instr->const_index[0] + index); + if (has_indirect) + src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[1])); + index++; + bld.MOV(new_dest, src); + src = offset(src, bld, 1); } break; } + case nir_intrinsic_barrier: + emit_barrier(); + break; + default: unreachable("unknown intrinsic"); } } void -fs_visitor::nir_emit_texture(nir_tex_instr *instr) +fs_visitor::nir_emit_texture(const fs_builder &bld, 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); @@ -1473,9 +1620,10 @@ 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; + int UNUSED offset_components = 0; - fs_reg coordinate, shadow_comparitor, lod, lod2, sample_index, mcs, offset; + fs_reg coordinate, shadow_comparitor, lod, lod2, sample_index, mcs, tex_offset; for (unsigned i = 0; i < instr->num_srcs; i++) { fs_reg src = get_nir_src(instr->src[i].src); @@ -1521,7 +1669,7 @@ fs_visitor::nir_emit_texture(nir_tex_instr *instr) sample_index = retype(src, BRW_REGISTER_TYPE_UD); break; case nir_tex_src_offset: - offset = retype(src, BRW_REGISTER_TYPE_D); + tex_offset = retype(src, BRW_REGISTER_TYPE_D); if (instr->is_array) offset_components = instr->coord_components - 1; else @@ -1533,7 +1681,7 @@ fs_visitor::nir_emit_texture(nir_tex_instr *instr) 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) { + if (instr->op == nir_texop_tg4 && devinfo->gen < 8) { max_used += stage_prog_data->binding_table.gather_texture_start; } else { max_used += stage_prog_data->binding_table.texture_start; @@ -1542,8 +1690,8 @@ fs_visitor::nir_emit_texture(nir_tex_instr *instr) /* 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; + bld.ADD(sampler_reg, src, fs_reg(sampler)); + sampler_reg = bld.emit_uniformize(sampler_reg); break; } @@ -1553,16 +1701,18 @@ fs_visitor::nir_emit_texture(nir_tex_instr *instr) } if (instr->op == nir_texop_txf_ms) { - if (brw->gen >= 7 && key->tex.compressed_multisample_layout_mask & (1<gen >= 7 && + key_tex->compressed_multisample_layout_mask & (1 << sampler)) { mcs = emit_mcs_fetch(coordinate, instr->coord_components, sampler_reg); - else + } else { mcs = fs_reg(0u); + } } for (unsigned i = 0; i < 3; i++) { if (instr->const_offset[i] != 0) { assert(offset_components == 0); - offset = fs_reg(brw_texture_offset(ctx, instr->const_offset, 3)); + tex_offset = fs_reg(brw_texture_offset(instr->const_offset, 3)); break; } } @@ -1604,24 +1754,26 @@ 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, + tex_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; unsigned num_components = nir_tex_instr_dest_size(instr); - emit_percomp(MOV(dest, this->result), (1 << num_components) - 1); + emit_percomp(bld, fs_inst(BRW_OPCODE_MOV, bld.dispatch_width(), + dest, this->result), + (1 << num_components) - 1); } void -fs_visitor::nir_emit_jump(nir_jump_instr *instr) +fs_visitor::nir_emit_jump(const fs_builder &bld, nir_jump_instr *instr) { switch (instr->type) { case nir_jump_break: - emit(BRW_OPCODE_BREAK); + bld.emit(BRW_OPCODE_BREAK); break; case nir_jump_continue: - emit(BRW_OPCODE_CONTINUE); + bld.emit(BRW_OPCODE_CONTINUE); break; case nir_jump_return: default: