#include "glsl/ir_optimization.h"
#include "glsl/nir/glsl_to_nir.h"
#include "brw_fs.h"
+#include "brw_nir.h"
static void
nir_optimize(nir_shader *nir)
/* 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_convert_from_ssa(nir);
nir_validate_shader(nir);
+ /* This is the last pass we run before we start emitting stuff. It
+ * determines when we need to insert boolean resolves on Gen <= 5. We
+ * run it last because it stashes data in instr->pass_flags and we don't
+ * want that to be squashed by other NIR passes.
+ */
+ if (brw->gen <= 5)
+ brw_nir_analyze_boolean_resolves(nir);
+
/* emit the arrays used for inputs and outputs - load/store intrinsics will
* be converted to reads/writes of these arrays
*/
}
if (nir->num_uniforms > 0) {
- nir_uniforms = fs_reg(UNIFORM, 0);
nir_setup_uniforms(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);
+ foreach_list_typed(nir_variable, var, node, &shader->inputs) {
+ enum brw_reg_type type = brw_type_for_base_type(var->type);
+ fs_reg input = offset(nir_inputs, var->data.driver_location);
fs_reg reg;
- if (var->data.location == VARYING_SLOT_POS) {
- reg = *emit_fragcoord_interpolation(var->data.pixel_center_integer,
- var->data.origin_upper_left);
- emit_percomp(MOV(varying, reg), 0xF);
- } else {
- emit_general_interpolation(varying, var->name, var->type,
- (glsl_interp_qualifier) var->data.interpolation,
- var->data.location, var->data.centroid,
- var->data.sample);
+ switch (stage) {
+ case MESA_SHADER_VERTEX: {
+ /* Our ATTR file is indexed by VERT_ATTRIB_*, which is the value
+ * stored in nir_variable::location.
+ *
+ * However, NIR's load_input intrinsics use a different index - an
+ * offset into a single contiguous array containing all inputs.
+ * This index corresponds to the nir_variable::driver_location field.
+ *
+ * So, we need to copy from fs_reg(ATTR, var->location) to
+ * offset(nir_inputs, var->data.driver_location).
+ */
+ unsigned components = var->type->without_array()->components();
+ unsigned array_length = var->type->is_array() ? var->type->length : 1;
+ for (unsigned i = 0; i < array_length; i++) {
+ for (unsigned j = 0; j < components; j++) {
+ emit(MOV(retype(offset(input, components * i + j), type),
+ offset(fs_reg(ATTR, var->data.location + i, type), j)));
+ }
+ }
+ break;
+ }
+ case MESA_SHADER_GEOMETRY:
+ case MESA_SHADER_COMPUTE:
+ unreachable("fs_visitor not used for these stages yet.");
+ break;
+ case MESA_SHADER_FRAGMENT:
+ if (var->data.location == VARYING_SLOT_POS) {
+ reg = *emit_fragcoord_interpolation(var->data.pixel_center_integer,
+ var->data.origin_upper_left);
+ emit_percomp(MOV(input, reg), 0xF);
+ } else {
+ emit_general_interpolation(input, var->name, var->type,
+ (glsl_interp_qualifier) var->data.interpolation,
+ var->data.location, var->data.centroid,
+ var->data.sample);
+ }
+ break;
}
}
}
{
brw_wm_prog_key *key = (brw_wm_prog_key*) this->key;
- struct hash_entry *entry;
- hash_table_foreach(shader->outputs, entry) {
- nir_variable *var = (nir_variable *) entry->data;
+ foreach_list_typed(nir_variable, var, node, &shader->outputs) {
fs_reg reg = offset(nir_outputs, var->data.driver_location);
- if (var->data.index > 0) {
+ int vector_elements =
+ var->type->is_array() ? var->type->fields.array->vector_elements
+ : var->type->vector_elements;
+
+ if (stage == MESA_SHADER_VERTEX) {
+ for (int i = 0; i < ALIGN(type_size(var->type), 4) / 4; i++) {
+ int output = var->data.location + i;
+ this->outputs[output] = offset(reg, 4 * i);
+ this->output_components[output] = vector_elements;
+ }
+ } else if (var->data.index > 0) {
assert(var->data.location == FRAG_RESULT_DATA0);
assert(var->data.index == 1);
this->dual_src_output = reg;
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;
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())
/* first, put the condition into f0 */
fs_inst *inst = emit(MOV(reg_null_d,
retype(get_nir_src(if_stmt->condition),
- BRW_REGISTER_TYPE_UD)));
+ BRW_REGISTER_TYPE_D)));
inst->conditional_mod = BRW_CONDITIONAL_NZ;
emit(IF(BRW_PREDICATE_NORMAL));
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:
} else {
emit(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_L));
inst = emit(SEL(result, op[0], op[1]));
+ inst->predicate = BRW_PREDICATE_NORMAL;
}
inst->saturate = instr->dest.saturate;
break;
} else {
emit(CMP(reg_null_d, op[0], op[1], BRW_CONDITIONAL_GE));
inst = emit(SEL(result, op[0], op[1]));
+ inst->predicate = BRW_PREDICATE_NORMAL;
}
inst->saturate = instr->dest.saturate;
break;
break;
case nir_op_flrp:
- /* TODO emulate for gen < 6 */
- inst = emit(LRP(result, op[2], op[1], op[0]));
+ inst = emit_lrp(result, op[0], op[1], op[2]);
inst->saturate = instr->dest.saturate;
break;
default:
unreachable("unhandled instruction");
}
+
+ /* If we need to do a boolean resolve, replace the result with -(x & 1)
+ * to sign extend the low bit to 0/~0
+ */
+ if (brw->gen <= 5 &&
+ (instr->instr.pass_flags & BRW_NIR_BOOLEAN_MASK) == BRW_NIR_BOOLEAN_NEEDS_RESOLVE) {
+ fs_reg masked = vgrf(glsl_type::int_type);
+ emit(AND(masked, result, fs_reg(1)));
+ masked.negate = true;
+ emit(MOV(retype(result, BRW_REGISTER_TYPE_D), masked));
+ }
}
fs_reg
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_load_uniform_indirect:
has_indirect = true;
case nir_intrinsic_load_uniform: {
- unsigned index = 0;
+ unsigned index = instr->const_index[0];
+
+ fs_reg uniform_reg;
+ if (index < num_direct_uniforms) {
+ uniform_reg = fs_reg(UNIFORM, 0);
+ } else {
+ uniform_reg = fs_reg(UNIFORM, num_direct_uniforms);
+ index -= num_direct_uniforms;
+ }
+
for (int i = 0; i < instr->const_index[1]; i++) {
for (unsigned j = 0; j < instr->num_components; j++) {
- fs_reg src = offset(retype(nir_uniforms, dest.type),
- instr->const_index[0] + index);
+ fs_reg src = offset(retype(uniform_reg, dest.type), index);
if (has_indirect)
src.reladdr = new(mem_ctx) fs_reg(get_nir_src(instr->src[0]));
index++;