* makes it easier to do backend-specific optimizations than doing so
* in the GLSL IR or in the native code.
*/
-extern "C" {
-
#include <sys/types.h>
#include "main/macros.h"
#include "brw_context.h"
#include "brw_eu.h"
#include "brw_wm.h"
-}
+#include "brw_cs.h"
#include "brw_vec4.h"
#include "brw_fs.h"
#include "main/uniforms.h"
fs_reg *
-fs_visitor::emit_vs_system_value(enum brw_reg_type type, int location)
+fs_visitor::emit_vs_system_value(int location)
{
fs_reg *reg = new(this->mem_ctx)
- fs_reg(ATTR, VERT_ATTRIB_MAX, type);
+ fs_reg(ATTR, VERT_ATTRIB_MAX, BRW_REGISTER_TYPE_D);
brw_vs_prog_data *vs_prog_data = (brw_vs_prog_data *) prog_data;
switch (location) {
reg = new(this->mem_ctx)
fs_reg(ATTR, ir->data.location,
brw_type_for_base_type(ir->type->get_scalar_type()));
- } else if (!strcmp(ir->name, "gl_FragCoord")) {
+ } else if (ir->data.location == VARYING_SLOT_POS) {
reg = emit_fragcoord_interpolation(ir->data.pixel_center_integer,
ir->data.origin_upper_left);
- } else if (!strcmp(ir->name, "gl_FrontFacing")) {
+ } else if (ir->data.location == VARYING_SLOT_FACE) {
reg = emit_frontfacing_interpolation();
} else {
reg = new(this->mem_ctx) fs_reg(vgrf(ir->type));
case SYSTEM_VALUE_VERTEX_ID:
case SYSTEM_VALUE_VERTEX_ID_ZERO_BASE:
case SYSTEM_VALUE_INSTANCE_ID:
- reg = emit_vs_system_value(brw_type_for_base_type(ir->type),
- ir->data.location);
+ reg = emit_vs_system_value(ir->data.location);
break;
case SYSTEM_VALUE_SAMPLE_POS:
reg = emit_samplepos_setup();
reg = emit_sampleid_setup();
break;
case SYSTEM_VALUE_SAMPLE_MASK_IN:
- assert(brw->gen >= 7);
+ assert(devinfo->gen >= 7);
reg = new(mem_ctx)
fs_reg(retype(brw_vec8_grf(payload.sample_mask_in_reg, 0),
BRW_REGISTER_TYPE_D));
this->result = src;
}
-void
+fs_inst *
fs_visitor::emit_lrp(const fs_reg &dst, const fs_reg &x, const fs_reg &y,
const fs_reg &a)
{
- if (brw->gen < 6) {
+ if (devinfo->gen < 6) {
/* We can't use the LRP instruction. Emit x*(1-a) + y*a. */
fs_reg y_times_a = vgrf(glsl_type::float_type);
fs_reg one_minus_a = vgrf(glsl_type::float_type);
emit(ADD(one_minus_a, negative_a, fs_reg(1.0f)));
emit(MUL(x_times_one_minus_a, x, one_minus_a));
- emit(ADD(dst, x_times_one_minus_a, y_times_a));
+ return emit(ADD(dst, x_times_one_minus_a, y_times_a));
} else {
/* The LRP instruction actually does op1 * op0 + op2 * (1 - op0), so
* we need to reorder the operands.
*/
- emit(LRP(dst, a, y, x));
+ return emit(LRP(dst, a, y, x));
}
}
fs_visitor::emit_minmax(enum brw_conditional_mod conditionalmod, const fs_reg &dst,
const fs_reg &src0, const fs_reg &src1)
{
+ assert(conditionalmod == BRW_CONDITIONAL_GE ||
+ conditionalmod == BRW_CONDITIONAL_L);
+
fs_inst *inst;
- if (brw->gen >= 6) {
+ if (devinfo->gen >= 6) {
inst = emit(BRW_OPCODE_SEL, dst, src0, src1);
inst->conditional_mod = conditionalmod;
} else {
}
}
+void
+fs_visitor::emit_uniformize(const fs_reg &dst, const fs_reg &src)
+{
+ const fs_reg chan_index = vgrf(glsl_type::uint_type);
+
+ emit(SHADER_OPCODE_FIND_LIVE_CHANNEL, component(chan_index, 0))
+ ->force_writemask_all = true;
+ emit(SHADER_OPCODE_BROADCAST, component(dst, 0),
+ src, component(chan_index, 0))
+ ->force_writemask_all = true;
+}
+
bool
fs_visitor::try_emit_saturate(ir_expression *ir)
{
fs_visitor::try_emit_mad(ir_expression *ir)
{
/* 3-src instructions were introduced in gen6. */
- if (brw->gen < 6)
+ if (devinfo->gen < 6)
return false;
/* MAD can only handle floating-point data. */
if (ir->type != glsl_type::float_type)
return false;
- ir_rvalue *nonmul = ir->operands[1];
- ir_expression *mul = ir->operands[0]->as_expression();
+ ir_rvalue *nonmul;
+ ir_expression *mul;
+ bool mul_negate, mul_abs;
- bool mul_negate = false, mul_abs = false;
- if (mul && mul->operation == ir_unop_abs) {
- mul = mul->operands[0]->as_expression();
- mul_abs = true;
- } else if (mul && mul->operation == ir_unop_neg) {
- mul = mul->operands[0]->as_expression();
- mul_negate = true;
- }
+ for (int i = 0; i < 2; i++) {
+ mul_negate = false;
+ mul_abs = false;
- if (!mul || mul->operation != ir_binop_mul) {
- nonmul = ir->operands[0];
- mul = ir->operands[1]->as_expression();
+ mul = ir->operands[i]->as_expression();
+ nonmul = ir->operands[1 - i];
if (mul && mul->operation == ir_unop_abs) {
mul = mul->operands[0]->as_expression();
mul_negate = true;
}
- if (!mul || mul->operation != ir_binop_mul)
- return false;
+ if (mul && mul->operation == ir_binop_mul)
+ break;
}
- if (nonmul->as_constant() ||
- mul->operands[0]->as_constant() ||
- mul->operands[1]->as_constant())
+ if (!mul || mul->operation != ir_binop_mul)
return false;
nonmul->accept(this);
return true;
}
+bool
+fs_visitor::try_emit_b2f_of_comparison(ir_expression *ir)
+{
+ /* On platforms that do not natively generate 0u and ~0u for Boolean
+ * results, b2f expressions that look like
+ *
+ * f = b2f(expr cmp 0)
+ *
+ * will generate better code by pretending the expression is
+ *
+ * f = ir_triop_csel(0.0, 1.0, expr cmp 0)
+ *
+ * This is because the last instruction of "expr" can generate the
+ * condition code for the "cmp 0". This avoids having to do the "-(b & 1)"
+ * trick to generate 0u or ~0u for the Boolean result. This means code like
+ *
+ * mov(16) g16<1>F 1F
+ * mul.ge.f0(16) null g6<8,8,1>F g14<8,8,1>F
+ * (+f0) sel(16) m6<1>F g16<8,8,1>F 0F
+ *
+ * will be generated instead of
+ *
+ * mul(16) g2<1>F g12<8,8,1>F g4<8,8,1>F
+ * cmp.ge.f0(16) g2<1>D g4<8,8,1>F 0F
+ * and(16) g4<1>D g2<8,8,1>D 1D
+ * and(16) m6<1>D -g4<8,8,1>D 0x3f800000UD
+ *
+ * When the comparison is != 0.0 using the knowledge that the false case
+ * already results in zero would allow better code generation by possibly
+ * avoiding a load-immediate instruction.
+ */
+ ir_expression *cmp = ir->operands[0]->as_expression();
+ if (cmp == NULL)
+ return false;
+
+ if (cmp->operation == ir_binop_nequal) {
+ for (unsigned i = 0; i < 2; i++) {
+ ir_constant *c = cmp->operands[i]->as_constant();
+ if (c == NULL || !c->is_zero())
+ continue;
+
+ ir_expression *expr = cmp->operands[i ^ 1]->as_expression();
+ if (expr != NULL) {
+ fs_reg op[2];
+
+ for (unsigned j = 0; j < 2; j++) {
+ cmp->operands[j]->accept(this);
+ op[j] = this->result;
+
+ resolve_ud_negate(&op[j]);
+ }
+
+ emit_bool_to_cond_code_of_reg(cmp, op);
+
+ /* In this case we know when the condition is true, op[i ^ 1]
+ * contains zero. Invert the predicate, use op[i ^ 1] as src0,
+ * and immediate 1.0f as src1.
+ */
+ this->result = vgrf(ir->type);
+ op[i ^ 1].type = BRW_REGISTER_TYPE_F;
+
+ fs_inst *inst = emit(SEL(this->result, op[i ^ 1], fs_reg(1.0f)));
+ inst->predicate = BRW_PREDICATE_NORMAL;
+ inst->predicate_inverse = true;
+ return true;
+ }
+ }
+ }
+
+ emit_bool_to_cond_code(cmp);
+
+ fs_reg temp = vgrf(ir->type);
+ emit(MOV(temp, fs_reg(1.0f)));
+
+ this->result = vgrf(ir->type);
+ fs_inst *inst = emit(SEL(this->result, temp, fs_reg(0.0f)));
+ inst->predicate = BRW_PREDICATE_NORMAL;
+
+ return true;
+}
+
static int
pack_pixel_offset(float x)
{
/* 1. collect interpolation factors */
- fs_reg dst_x = vgrf(glsl_type::get_instance(ir->type->base_type, 2, 1));
- fs_reg dst_y = offset(dst_x, 1);
+ fs_reg dst_xy = vgrf(glsl_type::get_instance(ir->type->base_type, 2, 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
switch (ir->operation) {
case ir_unop_interpolate_at_centroid:
- inst = emit(FS_OPCODE_INTERPOLATE_AT_CENTROID, dst_x, src, fs_reg(0u));
+ inst = emit(FS_OPCODE_INTERPOLATE_AT_CENTROID, dst_xy, src, fs_reg(0u));
break;
case ir_binop_interpolate_at_sample: {
assert(sample_num || !"nonconstant sample number should have been lowered.");
unsigned msg_data = sample_num->value.i[0] << 4;
- inst = emit(FS_OPCODE_INTERPOLATE_AT_SAMPLE, dst_x, src, fs_reg(msg_data));
+ inst = emit(FS_OPCODE_INTERPOLATE_AT_SAMPLE, dst_xy, src, fs_reg(msg_data));
break;
}
if (const_offset) {
unsigned msg_data = pack_pixel_offset(const_offset->value.f[0]) |
(pack_pixel_offset(const_offset->value.f[1]) << 4);
- inst = emit(FS_OPCODE_INTERPOLATE_AT_SHARED_OFFSET, dst_x, src,
+ inst = emit(FS_OPCODE_INTERPOLATE_AT_SHARED_OFFSET, dst_xy, src,
fs_reg(msg_data));
} else {
/* pack the operands: hw wants offsets as 4 bit signed ints */
}
mlen = 2 * reg_width;
- inst = emit(FS_OPCODE_INTERPOLATE_AT_PER_SLOT_OFFSET, dst_x, src,
+ inst = emit(FS_OPCODE_INTERPOLATE_AT_PER_SLOT_OFFSET, dst_xy, src,
fs_reg(0u));
}
break;
for (int i = 0; i < ir->type->vector_elements; i++) {
int ch = swiz ? ((*(int *)&swiz->mask) >> 2*i) & 3 : i;
- emit(FS_OPCODE_LINTERP, res,
- dst_x, dst_y,
+ emit(FS_OPCODE_LINTERP, res, dst_xy,
fs_reg(interp_reg(var->data.location, ch)));
res = offset(res, 1);
}
/* Deal with the real oddball stuff first */
switch (ir->operation) {
case ir_binop_add:
- if (brw->gen <= 5 && try_emit_line(ir))
+ if (devinfo->gen <= 5 && try_emit_line(ir))
return;
if (try_emit_mad(ir))
return;
inst->predicate = BRW_PREDICATE_NORMAL;
return;
+ case ir_unop_b2f:
+ if (devinfo->gen <= 5 && try_emit_b2f_of_comparison(ir))
+ return;
+ break;
+
case ir_unop_interpolate_at_centroid:
case ir_binop_interpolate_at_offset:
case ir_binop_interpolate_at_sample:
case ir_unop_log:
unreachable("not reached: should be handled by ir_explog_to_explog2");
case ir_unop_sin:
- case ir_unop_sin_reduced:
emit_math(SHADER_OPCODE_SIN, this->result, op[0]);
break;
case ir_unop_cos:
- case ir_unop_cos_reduced:
emit_math(SHADER_OPCODE_COS, this->result, op[0]);
break;
unreachable("not reached: should be handled by ir_sub_to_add_neg");
case ir_binop_mul:
- if (brw->gen < 8 && ir->type->is_integer()) {
+ if (devinfo->gen < 8 && ir->type->is_integer()) {
/* For integer multiplication, the MUL uses the low 16 bits
* of one of the operands (src0 on gen6, src1 on gen7). The
* MACH accumulates in the contribution of the upper 16 bits
* of that operand.
*/
if (ir->operands[0]->is_uint16_constant()) {
- if (brw->gen < 7)
+ if (devinfo->gen < 7)
emit(MUL(this->result, op[0], op[1]));
else
emit(MUL(this->result, op[1], op[0]));
} else if (ir->operands[1]->is_uint16_constant()) {
- if (brw->gen < 7)
+ if (devinfo->gen < 7)
emit(MUL(this->result, op[1], op[0]));
else
emit(MUL(this->result, op[0], op[1]));
} else {
- 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),
}
break;
case ir_binop_imul_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),
*
* FINISHME: Don't use source modifiers on src1.
*/
- if (brw->gen >= 8) {
+ 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;
}
}
emit_math(SHADER_OPCODE_INT_QUOTIENT, this->result, op[0], op[1]);
break;
case ir_binop_carry: {
- 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),
break;
}
case ir_binop_borrow: {
- 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),
case ir_binop_all_equal:
case ir_binop_nequal:
case ir_binop_any_nequal:
- if (brw->gen <= 5) {
+ if (devinfo->gen <= 5) {
resolve_bool_comparison(ir->operands[0], &op[0]);
resolve_bool_comparison(ir->operands[1], &op[1]);
}
emit(AND(this->result, op[0], fs_reg(1)));
break;
case ir_unop_b2f:
- if (brw->gen <= 5) {
+ if (devinfo->gen <= 5) {
resolve_bool_comparison(ir->operands[0], &op[0]);
}
op[0].type = BRW_REGISTER_TYPE_D;
const_uniform_block->value.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, op[0],
- fs_reg(stage_prog_data->binding_table.ubo_start)))
- ->force_writemask_all = true;
+ fs_reg(stage_prog_data->binding_table.ubo_start)));
+ emit_uniformize(surf_index, 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.
case ir_binop_interpolate_at_sample:
unreachable("already handled above");
break;
+
+ case ir_unop_d2f:
+ case ir_unop_f2d:
+ case ir_unop_d2i:
+ case ir_unop_i2d:
+ case ir_unop_d2u:
+ case ir_unop_u2d:
+ case ir_unop_d2b:
+ case ir_unop_pack_double_2x32:
+ case ir_unop_unpack_double_2x32:
+ case ir_unop_frexp_sig:
+ case ir_unop_frexp_exp:
+ unreachable("fp64 todo");
+ break;
}
}
case GLSL_TYPE_ATOMIC_UINT:
break;
+ case GLSL_TYPE_DOUBLE:
case GLSL_TYPE_VOID:
case GLSL_TYPE_ERROR:
case GLSL_TYPE_INTERFACE:
return inst;
}
+fs_inst *
+fs_visitor::emit_texture_gen4_simd16(ir_texture_opcode op, fs_reg dst,
+ fs_reg coordinate, int vector_elements,
+ fs_reg shadow_c, fs_reg lod,
+ uint32_t sampler)
+{
+ fs_reg message(MRF, 2, BRW_REGISTER_TYPE_F, dispatch_width);
+ bool has_lod = op == ir_txl || op == ir_txb || op == ir_txf;
+
+ if (has_lod && shadow_c.file != BAD_FILE)
+ no16("TXB and TXL with shadow comparison unsupported in SIMD16.");
+
+ if (op == ir_txd)
+ no16("textureGrad unsupported in SIMD16.");
+
+ /* Copy the coordinates. */
+ for (int i = 0; i < vector_elements; i++) {
+ emit(MOV(retype(offset(message, i), coordinate.type), coordinate));
+ coordinate = offset(coordinate, 1);
+ }
+
+ fs_reg msg_end = offset(message, vector_elements);
+
+ /* Messages other than sample and ld require all three components */
+ if (has_lod || shadow_c.file != BAD_FILE) {
+ for (int i = vector_elements; i < 3; i++) {
+ emit(MOV(offset(message, i), fs_reg(0.0f)));
+ }
+ }
+
+ if (has_lod) {
+ fs_reg msg_lod = retype(offset(message, 3), op == ir_txf ?
+ BRW_REGISTER_TYPE_UD : BRW_REGISTER_TYPE_F);
+ emit(MOV(msg_lod, lod));
+ msg_end = offset(msg_lod, 1);
+ }
+
+ if (shadow_c.file != BAD_FILE) {
+ fs_reg msg_ref = offset(message, 3 + has_lod);
+ emit(MOV(msg_ref, shadow_c));
+ msg_end = offset(msg_ref, 1);
+ }
+
+ enum opcode opcode;
+ switch (op) {
+ case ir_tex: opcode = SHADER_OPCODE_TEX; break;
+ case ir_txb: opcode = FS_OPCODE_TXB; break;
+ case ir_txd: opcode = SHADER_OPCODE_TXD; break;
+ case ir_txl: opcode = SHADER_OPCODE_TXL; break;
+ case ir_txs: opcode = SHADER_OPCODE_TXS; break;
+ case ir_txf: opcode = SHADER_OPCODE_TXF; break;
+ default: unreachable("not reached");
+ }
+
+ fs_inst *inst = emit(opcode, dst, reg_undef, fs_reg(sampler));
+ inst->base_mrf = message.reg - 1;
+ inst->mlen = msg_end.reg - inst->base_mrf;
+ inst->header_present = true;
+ inst->regs_written = 8;
+
+ return inst;
+}
+
/* gen5's sampler has slots for u, v, r, array index, then optional
* parameters like shadow comparitor or LOD bias. If optional
* parameters aren't present, those base slots are optional and don't
}
static bool
-is_high_sampler(struct brw_context *brw, fs_reg sampler)
+is_high_sampler(const struct brw_device_info *devinfo, fs_reg sampler)
{
- if (brw->gen < 8 && !brw->is_haswell)
+ if (devinfo->gen < 8 && !devinfo->is_haswell)
return false;
return sampler.file != IMM || sampler.fixed_hw_reg.dw1.ud >= 16;
int length = 0;
if (op == ir_tg4 || offset_value.file != BAD_FILE ||
- is_high_sampler(brw, sampler)) {
+ is_high_sampler(devinfo, sampler)) {
/* For general texture offsets (no txf workaround), we need a header to
* put them in. Note that for SIMD16 we're making space for two actual
* hardware registers here, so the emit will have to fix up for this.
offset_value.file != BAD_FILE && offset_value.file != IMM;
bool coordinate_done = false;
+ /* The sampler can only meaningfully compute LOD for fragment shader
+ * messages. For all other stages, we change the opcode to ir_txl and
+ * hardcode the LOD to 0.
+ */
+ if (stage != MESA_SHADER_FRAGMENT && op == ir_tex) {
+ op = ir_txl;
+ lod = fs_reg(0.0f);
+ }
+
/* Set up the LOD info */
switch (op) {
case ir_tex:
length++;
break;
case ir_txf:
- /* Unfortunately, the parameters for LD are intermixed: u, lod, v, r. */
+ /* Unfortunately, the parameters for LD are intermixed: u, lod, v, r.
+ * On Gen9 they are u, v, lod, r
+ */
+
emit(MOV(retype(sources[length], BRW_REGISTER_TYPE_D), coordinate));
coordinate = offset(coordinate, 1);
length++;
+ if (devinfo->gen >= 9) {
+ if (coord_components >= 2) {
+ emit(MOV(retype(sources[length], BRW_REGISTER_TYPE_D), coordinate));
+ coordinate = offset(coordinate, 1);
+ }
+ length++;
+ }
+
emit(MOV(retype(sources[length], BRW_REGISTER_TYPE_D), lod));
length++;
- for (int i = 1; i < coord_components; i++) {
+ for (int i = devinfo->gen >= 9 ? 2 : 1; i < coord_components; i++) {
emit(MOV(retype(sources[length], BRW_REGISTER_TYPE_D), coordinate));
coordinate = offset(coordinate, 1);
length++;
return inst;
}
-static struct brw_sampler_prog_key_data *
-get_tex(gl_shader_stage stage, const void *key)
-{
- switch (stage) {
- case MESA_SHADER_FRAGMENT:
- return &((brw_wm_prog_key*) key)->tex;
- case MESA_SHADER_VERTEX:
- return &((brw_vue_prog_key*) key)->tex;
- default:
- unreachable("unhandled shader stage");
- }
-}
-
fs_reg
fs_visitor::rescale_texcoord(fs_reg coordinate, int coord_components,
bool is_rect, uint32_t sampler, int texunit)
fs_inst *inst = NULL;
bool needs_gl_clamp = true;
fs_reg scale_x, scale_y;
- struct brw_sampler_prog_key_data *tex = get_tex(stage, this->key);
/* The 965 requires the EU to do the normalization of GL rectangle
* texture coordinates. We use the program parameter state
* tracking to get the scaling factor.
*/
if (is_rect &&
- (brw->gen < 6 ||
- (brw->gen >= 6 && (tex->gl_clamp_mask[0] & (1 << sampler) ||
- tex->gl_clamp_mask[1] & (1 << sampler))))) {
+ (devinfo->gen < 6 ||
+ (devinfo->gen >= 6 && (key_tex->gl_clamp_mask[0] & (1 << sampler) ||
+ key_tex->gl_clamp_mask[1] & (1 << sampler))))) {
struct gl_program_parameter_list *params = prog->Parameters;
int tokens[STATE_LENGTH] = {
STATE_INTERNAL,
* texture coordinates. We use the program parameter state
* tracking to get the scaling factor.
*/
- if (brw->gen < 6 && is_rect) {
+ if (devinfo->gen < 6 && is_rect) {
fs_reg dst = fs_reg(GRF, alloc.allocate(coord_components));
fs_reg src = coordinate;
coordinate = dst;
needs_gl_clamp = false;
for (int i = 0; i < 2; i++) {
- if (tex->gl_clamp_mask[i] & (1 << sampler)) {
+ if (key_tex->gl_clamp_mask[i] & (1 << sampler)) {
fs_reg chan = coordinate;
chan = offset(chan, i);
inst = emit(BRW_OPCODE_SEL, chan, chan, fs_reg(0.0f));
- inst->conditional_mod = BRW_CONDITIONAL_G;
+ inst->conditional_mod = BRW_CONDITIONAL_GE;
/* Our parameter comes in as 1.0/width or 1.0/height,
* because that's what people normally want for doing
if (coord_components > 0 && needs_gl_clamp) {
for (int i = 0; i < MIN2(coord_components, 3); i++) {
- if (tex->gl_clamp_mask[i] & (1 << sampler)) {
+ if (key_tex->gl_clamp_mask[i] & (1 << sampler)) {
fs_reg chan = coordinate;
chan = offset(chan, i);
fs_reg shadow_c,
fs_reg lod, fs_reg lod2, int grad_components,
fs_reg sample_index,
- fs_reg offset_value, unsigned offset_components,
+ fs_reg offset_value,
fs_reg mcs,
int gather_component,
bool is_cube_array,
uint32_t sampler,
fs_reg sampler_reg, int texunit)
{
- struct brw_sampler_prog_key_data *tex = get_tex(stage, this->key);
fs_inst *inst = NULL;
if (op == ir_tg4) {
/* When tg4 is used with the degenerate ZERO/ONE swizzles, don't bother
* emitting anything other than setting up the constant result.
*/
- int swiz = GET_SWZ(tex->swizzles[sampler], gather_component);
+ int swiz = GET_SWZ(key_tex->swizzles[sampler], gather_component);
if (swiz == SWIZZLE_ZERO || swiz == SWIZZLE_ONE) {
fs_reg res = vgrf(glsl_type::vec4_type);
*/
fs_reg dst = vgrf(glsl_type::get_instance(dest_type->base_type, 4, 1));
- if (brw->gen >= 7) {
+ if (devinfo->gen >= 7) {
inst = emit_texture_gen7(op, dst, coordinate, coord_components,
shadow_c, lod, lod2, grad_components,
sample_index, mcs, sampler_reg,
offset_value);
- } else if (brw->gen >= 5) {
+ } else if (devinfo->gen >= 5) {
inst = emit_texture_gen5(op, dst, coordinate, coord_components,
shadow_c, lod, lod2, grad_components,
sample_index, sampler,
offset_value.file != BAD_FILE);
+ } else if (dispatch_width == 16) {
+ inst = emit_texture_gen4_simd16(op, dst, coordinate, coord_components,
+ shadow_c, lod, sampler);
} else {
inst = emit_texture_gen4(op, dst, coordinate, coord_components,
shadow_c, lod, lod2, grad_components,
inst->offset |=
gather_channel(gather_component, sampler) << 16; /* M0.2:16-17 */
- if (brw->gen == 6)
- emit_gen6_gather_wa(tex->gen6_gather_wa[sampler], dst);
+ if (devinfo->gen == 6)
+ emit_gen6_gather_wa(key_tex->gen6_gather_wa[sampler], dst);
}
/* fixup #layers for cube map arrays */
void
fs_visitor::visit(ir_texture *ir)
{
- const struct brw_sampler_prog_key_data *tex = get_tex(stage, this->key);
uint32_t sampler =
_mesa_get_sampler_uniform_value(ir->sampler, shader_prog, prog);
->array->type->array_size();
uint32_t max_used = sampler + array_size - 1;
- if (ir->op == ir_tg4 && brw->gen < 8) {
+ if (ir->op == ir_tg4 && devinfo->gen < 8) {
max_used += stage_prog_data->binding_table.gather_texture_start;
} else {
max_used += stage_prog_data->binding_table.texture_start;
}
fs_reg offset_value;
- int offset_components = 0;
if (ir->offset) {
ir_constant *const_offset = ir->offset->as_constant();
if (const_offset) {
* offset, and a non-constant offset.
*/
offset_value =
- fs_reg(brw_texture_offset(ctx, const_offset->value.i,
+ fs_reg(brw_texture_offset(const_offset->value.i,
const_offset->type->vector_elements));
} else {
ir->offset->accept(this);
offset_value = this->result;
}
- offset_components = ir->offset->type->vector_elements;
}
fs_reg lod, lod2, sample_index, mcs;
ir->lod_info.sample_index->accept(this);
sample_index = this->result;
- if (brw->gen >= 7 && tex->compressed_multisample_layout_mask & (1<<sampler))
+ if (devinfo->gen >= 7 &&
+ key_tex->compressed_multisample_layout_mask & (1 << sampler)) {
mcs = emit_mcs_fetch(coordinate, ir->coordinate->type->vector_elements,
sampler_reg);
- else
+ } else {
mcs = fs_reg(0u);
+ }
break;
default:
unreachable("Unrecognized texture opcode");
emit_texture(ir->op, ir->type, coordinate, coord_components,
shadow_comparitor, lod, lod2, grad_components,
- sample_index, offset_value, offset_components, mcs,
+ sample_index, offset_value, mcs,
gather_component, is_cube_array, is_rect, sampler,
sampler_reg, texunit);
}
uint32_t
fs_visitor::gather_channel(int orig_chan, uint32_t sampler)
{
- struct brw_sampler_prog_key_data *tex = get_tex(stage, this->key);
- int swiz = GET_SWZ(tex->swizzles[sampler], orig_chan);
+ int swiz = GET_SWZ(key_tex->swizzles[sampler], orig_chan);
switch (swiz) {
case SWIZZLE_X: return 0;
case SWIZZLE_Y:
/* gather4 sampler is broken for green channel on RG32F --
* we must ask for blue instead.
*/
- if (tex->gather_channel_quirk_mask & (1<<sampler))
+ if (key_tex->gather_channel_quirk_mask & (1 << sampler))
return 2;
return 1;
case SWIZZLE_Z: return 2;
if (op == ir_txs || op == ir_lod || op == ir_tg4)
return;
- struct brw_sampler_prog_key_data *tex = get_tex(stage, this->key);
-
if (dest_components == 1) {
/* Ignore DEPTH_TEXTURE_MODE swizzling. */
- } else if (tex->swizzles[sampler] != SWIZZLE_NOOP) {
+ } else if (key_tex->swizzles[sampler] != SWIZZLE_NOOP) {
fs_reg swizzled_result = vgrf(glsl_type::vec4_type);
swizzled_result.type = orig_val.type;
for (int i = 0; i < 4; i++) {
- int swiz = GET_SWZ(tex->swizzles[sampler], i);
+ int swiz = GET_SWZ(key_tex->swizzles[sampler], i);
fs_reg l = swizzled_result;
l = offset(l, i);
emit(MOV(l, fs_reg(1.0f)));
} else {
emit(MOV(l, offset(orig_val,
- GET_SWZ(tex->swizzles[sampler], i))));
+ GET_SWZ(key_tex->swizzles[sampler], i))));
}
}
this->result = swizzled_result;
void
fs_visitor::visit(ir_discard *ir)
{
- assert(ir->condition == NULL); /* FINISHME */
-
/* 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 (ir->condition) {
+ emit_bool_to_cond_code(ir->condition);
+ cmp = (fs_inst *) this->instructions.get_tail();
+ cmp->conditional_mod = brw_negate_cmod(cmp->conditional_mod);
+ } 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;
+ if (devinfo->gen >= 6) {
+ emit_discard_jump();
}
}
emit(MOV(dst_reg, fs_reg(ir->value.i[i])));
break;
case GLSL_TYPE_BOOL:
- emit(MOV(dst_reg,
- fs_reg(ir->value.b[i] != 0 ? (int)ctx->Const.UniformBooleanTrue
- : 0)));
+ emit(MOV(dst_reg, fs_reg(ir->value.b[i] != 0 ? ~0 : 0)));
break;
default:
unreachable("Non-float/uint/int/bool constant");
}
fs_reg op[3];
- fs_inst *inst;
assert(expr->get_num_operands() <= 3);
for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
resolve_ud_negate(&op[i]);
}
+ emit_bool_to_cond_code_of_reg(expr, op);
+}
+
+void
+fs_visitor::emit_bool_to_cond_code_of_reg(ir_expression *expr, fs_reg op[3])
+{
+ fs_inst *inst;
+
switch (expr->operation) {
case ir_unop_logic_not:
inst = emit(AND(reg_null_d, op[0], fs_reg(1)));
break;
case ir_binop_logic_xor:
- if (brw->gen <= 5) {
- fs_reg temp = vgrf(ir->type);
+ if (devinfo->gen <= 5) {
+ fs_reg temp = vgrf(expr->type);
emit(XOR(temp, op[0], op[1]));
inst = emit(AND(reg_null_d, temp, fs_reg(1)));
} else {
break;
case ir_binop_logic_or:
- if (brw->gen <= 5) {
- fs_reg temp = vgrf(ir->type);
+ if (devinfo->gen <= 5) {
+ fs_reg temp = vgrf(expr->type);
emit(OR(temp, op[0], op[1]));
inst = emit(AND(reg_null_d, temp, fs_reg(1)));
} else {
break;
case ir_binop_logic_and:
- if (brw->gen <= 5) {
- fs_reg temp = vgrf(ir->type);
+ if (devinfo->gen <= 5) {
+ fs_reg temp = vgrf(expr->type);
emit(AND(temp, op[0], op[1]));
inst = emit(AND(reg_null_d, temp, fs_reg(1)));
} else {
break;
case ir_unop_f2b:
- if (brw->gen >= 6) {
+ if (devinfo->gen >= 6) {
emit(CMP(reg_null_d, op[0], fs_reg(0.0f), BRW_CONDITIONAL_NZ));
} else {
inst = emit(MOV(reg_null_f, op[0]));
break;
case ir_unop_i2b:
- if (brw->gen >= 6) {
+ if (devinfo->gen >= 6) {
emit(CMP(reg_null_d, op[0], fs_reg(0), BRW_CONDITIONAL_NZ));
} else {
inst = emit(MOV(reg_null_d, op[0]));
case ir_binop_all_equal:
case ir_binop_nequal:
case ir_binop_any_nequal:
- if (brw->gen <= 5) {
+ if (devinfo->gen <= 5) {
resolve_bool_comparison(expr->operands[0], &op[0]);
resolve_bool_comparison(expr->operands[1], &op[1]);
}
case ir_binop_all_equal:
case ir_binop_nequal:
case ir_binop_any_nequal:
- if (brw->gen <= 5) {
+ if (devinfo->gen <= 5) {
resolve_bool_comparison(expr->operands[0], &op[0]);
resolve_bool_comparison(expr->operands[1], &op[1]);
}
emit(IF(this->result, fs_reg(0), BRW_CONDITIONAL_NZ));
}
+bool
+fs_visitor::try_opt_frontfacing_ternary(ir_if *ir)
+{
+ ir_dereference_variable *deref = ir->condition->as_dereference_variable();
+ if (!deref || strcmp(deref->var->name, "gl_FrontFacing") != 0)
+ return false;
+
+ if (ir->then_instructions.length() != 1 ||
+ ir->else_instructions.length() != 1)
+ return false;
+
+ ir_assignment *then_assign =
+ ((ir_instruction *)ir->then_instructions.head)->as_assignment();
+ ir_assignment *else_assign =
+ ((ir_instruction *)ir->else_instructions.head)->as_assignment();
+
+ if (!then_assign || then_assign->condition ||
+ !else_assign || else_assign->condition ||
+ then_assign->write_mask != else_assign->write_mask ||
+ !then_assign->lhs->equals(else_assign->lhs))
+ return false;
+
+ ir_constant *then_rhs = then_assign->rhs->as_constant();
+ ir_constant *else_rhs = else_assign->rhs->as_constant();
+
+ if (!then_rhs || !else_rhs)
+ return false;
+
+ if (then_rhs->type->base_type != GLSL_TYPE_FLOAT)
+ return false;
+
+ if ((then_rhs->is_one() && else_rhs->is_negative_one()) ||
+ (else_rhs->is_one() && then_rhs->is_negative_one())) {
+ then_assign->lhs->accept(this);
+ fs_reg dst = this->result;
+ dst.type = BRW_REGISTER_TYPE_D;
+ 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).
+ */
+
+ if (then_rhs->is_negative_one()) {
+ assert(else_rhs->is_one());
+ 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).
+ */
+
+ if (then_rhs->is_negative_one()) {
+ assert(else_rhs->is_one());
+ g1_6.negate = true;
+ }
+
+ emit(OR(tmp, g1_6, fs_reg(0x3f800000)));
+ }
+ emit(AND(dst, tmp, fs_reg(0xbf800000)));
+ return true;
+ }
+
+ return false;
+}
+
/**
* Try to replace IF/MOV/ELSE/MOV/ENDIF with SEL.
*
void
fs_visitor::visit(ir_if *ir)
{
+ if (try_opt_frontfacing_ternary(ir))
+ return;
+
/* Don't point the annotation at the if statement, because then it plus
* the then and else blocks get printed.
*/
this->base_ir = ir->condition;
- if (brw->gen == 6) {
+ if (devinfo->gen == 6) {
emit_if_gen6(ir);
} else {
emit_bool_to_cond_code(ir->condition);
emit(BRW_OPCODE_ENDIF);
- if (!try_replace_with_sel() && brw->gen < 6) {
+ if (!try_replace_with_sel() && devinfo->gen < 6) {
no16("Can't support (non-uniform) control flow on SIMD16\n");
}
}
void
fs_visitor::visit(ir_loop *ir)
{
- if (brw->gen < 6) {
+ if (devinfo->gen < 6) {
no16("Can't support (non-uniform) control flow on SIMD16\n");
}
fs_reg dst, fs_reg offset, fs_reg src0,
fs_reg src1)
{
- bool uses_kill =
- (stage == MESA_SHADER_FRAGMENT) &&
- ((brw_wm_prog_data*) this->prog_data)->uses_kill;
int reg_width = dispatch_width / 8;
int length = 0;
emit(MOV(sources[0], fs_reg(0u)))
->force_writemask_all = true;
- if (uses_kill) {
- emit(MOV(component(sources[0], 7), brw_flag_reg(0, 1)))
- ->force_writemask_all = true;
+ if (stage == MESA_SHADER_FRAGMENT) {
+ if (((brw_wm_prog_data*)this->prog_data)->uses_kill) {
+ emit(MOV(component(sources[0], 7), brw_flag_reg(0, 1)))
+ ->force_writemask_all = true;
+ } else {
+ emit(MOV(component(sources[0], 7),
+ retype(brw_vec1_grf(1, 7), BRW_REGISTER_TYPE_UD)))
+ ->force_writemask_all = true;
+ }
} else {
+ /* The execution mask is part of the side-band information sent together with
+ * the message payload to the data port. It's implicitly ANDed with the sample
+ * mask sent in the header to compute the actual set of channels that execute
+ * the atomic operation.
+ */
+ assert(stage == MESA_SHADER_VERTEX || stage == MESA_SHADER_COMPUTE);
emit(MOV(component(sources[0], 7),
- retype(brw_vec1_grf(1, 7), BRW_REGISTER_TYPE_UD)))
- ->force_writemask_all = true;
+ fs_reg(0xffffu)))->force_writemask_all = true;
}
length++;
/* Emit the instruction. */
fs_inst *inst = emit(SHADER_OPCODE_UNTYPED_ATOMIC, dst, src_payload,
- fs_reg(atomic_op), fs_reg(surf_index));
+ fs_reg(surf_index), fs_reg(atomic_op));
inst->mlen = mlen;
}
fs_visitor::emit_untyped_surface_read(unsigned surf_index, fs_reg dst,
fs_reg offset)
{
- bool uses_kill =
- (stage == MESA_SHADER_FRAGMENT) &&
- ((brw_wm_prog_data*) this->prog_data)->uses_kill;
int reg_width = dispatch_width / 8;
fs_reg *sources = ralloc_array(mem_ctx, fs_reg, 2);
emit(MOV(sources[0], fs_reg(0u)))
->force_writemask_all = true;
- if (uses_kill) {
- emit(MOV(component(sources[0], 7), brw_flag_reg(0, 1)))
- ->force_writemask_all = true;
+ if (stage == MESA_SHADER_FRAGMENT) {
+ if (((brw_wm_prog_data*)this->prog_data)->uses_kill) {
+ emit(MOV(component(sources[0], 7), brw_flag_reg(0, 1)))
+ ->force_writemask_all = true;
+ } else {
+ emit(MOV(component(sources[0], 7),
+ retype(brw_vec1_grf(1, 7), BRW_REGISTER_TYPE_UD)))
+ ->force_writemask_all = true;
+ }
} else {
+ /* The execution mask is part of the side-band information sent together with
+ * the message payload to the data port. It's implicitly ANDed with the sample
+ * mask sent in the header to compute the actual set of channels that execute
+ * the atomic operation.
+ */
+ assert(stage == MESA_SHADER_VERTEX || stage == MESA_SHADER_COMPUTE);
emit(MOV(component(sources[0], 7),
- retype(brw_vec1_grf(1, 7), BRW_REGISTER_TYPE_UD)))
- ->force_writemask_all = true;
+ fs_reg(0xffffu)))->force_writemask_all = true;
}
/* Set the surface read offset. */
/* Emit the instruction. */
inst = emit(SHADER_OPCODE_UNTYPED_SURFACE_READ, dst, src_payload,
- fs_reg(surf_index));
+ fs_reg(surf_index), fs_reg(1));
inst->mlen = mlen;
}
fs_inst *write;
write = emit(FS_OPCODE_FB_WRITE);
write->eot = true;
- if (brw->gen >= 6) {
+ if (devinfo->gen >= 6) {
write->base_mrf = 2;
write->mlen = 4 * reg_width;
} else {
* varying to avoid GPU hangs, so set that.
*/
brw_wm_prog_data *wm_prog_data = (brw_wm_prog_data *) this->prog_data;
- wm_prog_data->num_varying_inputs = brw->gen < 6 ? 1 : 0;
+ wm_prog_data->num_varying_inputs = devinfo->gen < 6 ? 1 : 0;
memset(wm_prog_data->urb_setup, -1,
sizeof(wm_prog_data->urb_setup[0]) * VARYING_SLOT_MAX);
void
fs_visitor::emit_interpolation_setup_gen4()
{
+ struct brw_reg g1_uw = retype(brw_vec1_grf(1, 0), BRW_REGISTER_TYPE_UW);
+
this->current_annotation = "compute pixel centers";
this->pixel_x = vgrf(glsl_type::uint_type);
this->pixel_y = vgrf(glsl_type::uint_type);
this->pixel_x.type = BRW_REGISTER_TYPE_UW;
this->pixel_y.type = BRW_REGISTER_TYPE_UW;
-
- emit(FS_OPCODE_PIXEL_X, this->pixel_x);
- emit(FS_OPCODE_PIXEL_Y, this->pixel_y);
+ emit(ADD(this->pixel_x,
+ fs_reg(stride(suboffset(g1_uw, 4), 2, 4, 0)),
+ fs_reg(brw_imm_v(0x10101010))));
+ emit(ADD(this->pixel_y,
+ fs_reg(stride(suboffset(g1_uw, 5), 2, 4, 0)),
+ fs_reg(brw_imm_v(0x11001100))));
this->current_annotation = "compute pixel deltas from v0";
- if (brw->has_pln) {
- this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] =
- vgrf(glsl_type::vec2_type);
- this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] =
- offset(this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC], 1);
+
+ this->delta_xy[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] =
+ vgrf(glsl_type::vec2_type);
+ const fs_reg &delta_xy = this->delta_xy[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC];
+ const fs_reg xstart(negate(brw_vec1_grf(1, 0)));
+ const fs_reg ystart(negate(brw_vec1_grf(1, 1)));
+
+ if (devinfo->has_pln && dispatch_width == 16) {
+ emit(ADD(half(offset(delta_xy, 0), 0), half(this->pixel_x, 0), xstart));
+ emit(ADD(half(offset(delta_xy, 0), 1), half(this->pixel_y, 0), ystart));
+ emit(ADD(half(offset(delta_xy, 1), 0), half(this->pixel_x, 1), xstart))
+ ->force_sechalf = true;
+ emit(ADD(half(offset(delta_xy, 1), 1), half(this->pixel_y, 1), ystart))
+ ->force_sechalf = true;
} else {
- this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] =
- vgrf(glsl_type::float_type);
- this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] =
- vgrf(glsl_type::float_type);
+ emit(ADD(offset(delta_xy, 0), this->pixel_x, xstart));
+ emit(ADD(offset(delta_xy, 1), this->pixel_y, ystart));
}
- emit(ADD(this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
- this->pixel_x, fs_reg(negate(brw_vec1_grf(1, 0)))));
- emit(ADD(this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
- this->pixel_y, fs_reg(negate(brw_vec1_grf(1, 1)))));
this->current_annotation = "compute pos.w and 1/pos.w";
/* Compute wpos.w. It's always in our setup, since it's needed to
* interpolate the other attributes.
*/
this->wpos_w = vgrf(glsl_type::float_type);
- emit(FS_OPCODE_LINTERP, wpos_w,
- this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
- this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
- interp_reg(VARYING_SLOT_POS, 3));
+ emit(FS_OPCODE_LINTERP, wpos_w, delta_xy, interp_reg(VARYING_SLOT_POS, 3));
/* Compute the pixel 1/W value from wpos.w. */
this->pixel_w = vgrf(glsl_type::float_type);
emit_math(SHADER_OPCODE_RCP, this->pixel_w, wpos_w);
{
struct brw_reg g1_uw = retype(brw_vec1_grf(1, 0), BRW_REGISTER_TYPE_UW);
- /* If the pixel centers end up used, the setup is the same as for gen4. */
this->current_annotation = "compute pixel centers";
- fs_reg int_pixel_x = vgrf(glsl_type::uint_type);
- fs_reg int_pixel_y = vgrf(glsl_type::uint_type);
- int_pixel_x.type = BRW_REGISTER_TYPE_UW;
- int_pixel_y.type = BRW_REGISTER_TYPE_UW;
- emit(ADD(int_pixel_x,
- fs_reg(stride(suboffset(g1_uw, 4), 2, 4, 0)),
- fs_reg(brw_imm_v(0x10101010))));
- emit(ADD(int_pixel_y,
- fs_reg(stride(suboffset(g1_uw, 5), 2, 4, 0)),
- fs_reg(brw_imm_v(0x11001100))));
+ if (brw->gen >= 8 || dispatch_width == 8) {
+ /* The "Register Region Restrictions" page says for BDW (and newer,
+ * presumably):
+ *
+ * "When destination spans two registers, the source may be one or
+ * two registers. The destination elements must be evenly split
+ * between the two registers."
+ *
+ * Thus we can do a single add(16) in SIMD8 or an add(32) in SIMD16 to
+ * compute our pixel centers.
+ */
+ fs_reg int_pixel_xy(GRF, alloc.allocate(dispatch_width / 8),
+ BRW_REGISTER_TYPE_UW, dispatch_width * 2);
+ emit(ADD(int_pixel_xy,
+ fs_reg(stride(suboffset(g1_uw, 4), 1, 4, 0)),
+ fs_reg(brw_imm_v(0x11001010))))
+ ->force_writemask_all = true;
- /* As of gen6, we can no longer mix float and int sources. We have
- * to turn the integer pixel centers into floats for their actual
- * use.
- */
- this->pixel_x = vgrf(glsl_type::float_type);
- this->pixel_y = vgrf(glsl_type::float_type);
- emit(MOV(this->pixel_x, int_pixel_x));
- emit(MOV(this->pixel_y, int_pixel_y));
+ this->pixel_x = vgrf(glsl_type::float_type);
+ this->pixel_y = vgrf(glsl_type::float_type);
+ emit(FS_OPCODE_PIXEL_X, this->pixel_x, int_pixel_xy);
+ emit(FS_OPCODE_PIXEL_Y, this->pixel_y, int_pixel_xy);
+ } else {
+ /* The "Register Region Restrictions" page says for SNB, IVB, HSW:
+ *
+ * "When destination spans two registers, the source MUST span two
+ * registers."
+ *
+ * Since the GRF source of the ADD will only read a single register, we
+ * must do two separate ADDs in SIMD16.
+ */
+ fs_reg int_pixel_x = vgrf(glsl_type::uint_type);
+ fs_reg int_pixel_y = vgrf(glsl_type::uint_type);
+ int_pixel_x.type = BRW_REGISTER_TYPE_UW;
+ int_pixel_y.type = BRW_REGISTER_TYPE_UW;
+ emit(ADD(int_pixel_x,
+ fs_reg(stride(suboffset(g1_uw, 4), 2, 4, 0)),
+ fs_reg(brw_imm_v(0x10101010))));
+ emit(ADD(int_pixel_y,
+ fs_reg(stride(suboffset(g1_uw, 5), 2, 4, 0)),
+ fs_reg(brw_imm_v(0x11001100))));
+
+ /* As of gen6, we can no longer mix float and int sources. We have
+ * to turn the integer pixel centers into floats for their actual
+ * use.
+ */
+ this->pixel_x = vgrf(glsl_type::float_type);
+ this->pixel_y = vgrf(glsl_type::float_type);
+ emit(MOV(this->pixel_x, int_pixel_x));
+ emit(MOV(this->pixel_y, int_pixel_y));
+ }
this->current_annotation = "compute pos.w";
this->pixel_w = fs_reg(brw_vec8_grf(payload.source_w_reg, 0));
for (int i = 0; i < BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT; ++i) {
uint8_t reg = payload.barycentric_coord_reg[i];
- this->delta_x[i] = fs_reg(brw_vec8_grf(reg, 0));
- this->delta_y[i] = fs_reg(brw_vec8_grf(reg + 1, 0));
+ this->delta_xy[i] = fs_reg(brw_vec16_grf(reg, 0));
}
this->current_annotation = NULL;
}
int
-fs_visitor::setup_color_payload(fs_reg *dst, fs_reg color, unsigned components)
+fs_visitor::setup_color_payload(fs_reg *dst, fs_reg color, unsigned components,
+ bool use_2nd_half)
{
brw_wm_prog_key *key = (brw_wm_prog_key*) this->key;
fs_inst *inst;
colors_enabled = (1 << components) - 1;
}
- if (dispatch_width == 8 || brw->gen >= 6) {
+ if (dispatch_width == 8 || (devinfo->gen >= 6 && !do_dual_src)) {
/* SIMD8 write looks like:
* m + 0: r0
* m + 1: r1
len++;
}
return len;
+ } else if (devinfo->gen >= 6 && do_dual_src) {
+ /* SIMD16 dual source blending for gen6+.
+ *
+ * From the SNB PRM, volume 4, part 1, page 193:
+ *
+ * "The dual source render target messages only have SIMD8 forms due to
+ * maximum message length limitations. SIMD16 pixel shaders must send two
+ * of these messages to cover all of the pixels. Each message contains
+ * two colors (4 channels each) for each pixel in the message payload."
+ *
+ * So in SIMD16 dual source blending we will send 2 SIMD8 messages,
+ * each one will call this function twice (one for each color involved),
+ * so in each pass we only write 4 registers. Notice that the second
+ * SIMD8 message needs to read color data from the 2nd half of the color
+ * registers, so it needs to call this with use_2nd_half = true.
+ */
+ for (unsigned i = 0; i < 4; ++i) {
+ if (colors_enabled & (1 << i)) {
+ dst[i] = fs_reg(GRF, alloc.allocate(1), color.type);
+ inst = emit(MOV(dst[i], half(offset(color, i),
+ use_2nd_half ? 1 : 0)));
+ inst->saturate = key->clamp_fragment_color;
+ if (use_2nd_half)
+ inst->force_sechalf = true;
+ }
+ }
+ return 4;
} else {
/* pre-gen6 SIMD16 single source DP write looks like:
* m + 0: r0
fs_inst *
fs_visitor::emit_single_fb_write(fs_reg color0, fs_reg color1,
- fs_reg src0_alpha, unsigned components)
+ fs_reg src0_alpha, unsigned components,
+ bool use_2nd_half)
{
assert(stage == MESA_SHADER_FRAGMENT);
brw_wm_prog_data *prog_data = (brw_wm_prog_data*) this->prog_data;
* dispatched. This field is only required for the end-of-
* thread message and on all dual-source messages."
*/
- if (brw->gen >= 6 &&
- (brw->is_haswell || brw->gen >= 8 || !prog_data->uses_kill) &&
+ if (devinfo->gen >= 6 &&
+ (devinfo->is_haswell || devinfo->gen >= 8 || !prog_data->uses_kill) &&
color1.file == BAD_FILE &&
key->nr_color_regions == 1) {
header_present = false;
* alpha out the pipeline to our null renderbuffer to support
* alpha-testing, alpha-to-coverage, and so on.
*/
- length += setup_color_payload(sources + length, this->outputs[0], 0);
+ length += setup_color_payload(sources + length, this->outputs[0], 0,
+ false);
} else if (color1.file == BAD_FILE) {
if (src0_alpha.file != BAD_FILE) {
sources[length] = fs_reg(GRF, alloc.allocate(reg_size),
length++;
}
- length += setup_color_payload(sources + length, color0, components);
+ length += setup_color_payload(sources + length, color0, components,
+ false);
} else {
- length += setup_color_payload(sources + length, color0, components);
- length += setup_color_payload(sources + length, color1, components);
+ length += setup_color_payload(sources + length, color0, components,
+ use_2nd_half);
+ length += setup_color_payload(sources + length, color1, components,
+ use_2nd_half);
}
if (source_depth_to_render_target) {
- if (brw->gen == 6) {
+ if (devinfo->gen == 6) {
/* For outputting oDepth on gen6, SIMD8 writes have to be
* used. This would require SIMD8 moves of each half to
* message regs, kind of like pre-gen5 SIMD16 FB writes.
fs_inst *load;
fs_inst *write;
- if (brw->gen >= 7) {
+ if (devinfo->gen >= 7) {
/* Send from the GRF */
fs_reg payload = fs_reg(GRF, -1, BRW_REGISTER_TYPE_F);
load = emit(LOAD_PAYLOAD(payload, sources, length));
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_inst *inst = NULL;
if (do_dual_src) {
- no16("GL_ARB_blend_func_extended not yet supported in SIMD16.");
- if (dispatch_width == 16)
- do_dual_src = false;
- }
-
- fs_inst *inst;
- if (do_dual_src) {
- if (INTEL_DEBUG & DEBUG_SHADER_TIME)
- emit_shader_time_end();
-
this->current_annotation = ralloc_asprintf(this->mem_ctx,
"FB dual-source write");
inst = emit_single_fb_write(this->outputs[0], this->dual_src_output,
reg_undef, 4);
inst->target = 0;
+
+ /* SIMD16 dual source blending requires to send two SIMD8 dual source
+ * messages, where each message contains color data for 8 pixels. Color
+ * data for the first group of pixels is stored in the "lower" half of
+ * the color registers, so in SIMD16, the previous message did:
+ * m + 0: r0
+ * m + 1: g0
+ * m + 2: b0
+ * m + 3: a0
+ *
+ * Here goes the second message, which packs color data for the
+ * remaining 8 pixels. Color data for these pixels is stored in the
+ * "upper" half of the color registers, so we need to do:
+ * m + 0: r1
+ * m + 1: g1
+ * m + 2: b1
+ * m + 3: a1
+ */
+ if (dispatch_width == 16) {
+ inst = emit_single_fb_write(this->outputs[0], this->dual_src_output,
+ reg_undef, 4, true);
+ inst->target = 0;
+ }
+
prog_data->dual_src_blend = true;
- } else if (key->nr_color_regions > 0) {
+ } else {
for (int target = 0; target < key->nr_color_regions; target++) {
+ /* Skip over outputs that weren't written. */
+ if (this->outputs[target].file == BAD_FILE)
+ continue;
+
this->current_annotation = ralloc_asprintf(this->mem_ctx,
"FB write target %d",
target);
fs_reg src0_alpha;
- if (brw->gen >= 6 && key->replicate_alpha && target != 0)
+ if (devinfo->gen >= 6 && key->replicate_alpha && target != 0)
src0_alpha = offset(outputs[0], 3);
- if (target == key->nr_color_regions - 1 &&
- (INTEL_DEBUG & DEBUG_SHADER_TIME))
- emit_shader_time_end();
-
inst = emit_single_fb_write(this->outputs[target], reg_undef,
src0_alpha,
this->output_components[target]);
inst->target = target;
}
- } else {
- if (INTEL_DEBUG & DEBUG_SHADER_TIME)
- emit_shader_time_end();
+ }
+ if (inst == NULL) {
/* Even if there's no color buffers enabled, we still need to send
* alpha out the pipeline to our null renderbuffer to support
* alpha-testing, alpha-to-coverage, and so on.
if (length == 8 || last)
flush = true;
if (flush) {
- if (last && (INTEL_DEBUG & DEBUG_SHADER_TIME))
- emit_shader_time_end();
-
fs_reg *payload_sources = ralloc_array(mem_ctx, fs_reg, length + 1);
fs_reg payload = fs_reg(GRF, alloc.allocate(length + 1),
BRW_REGISTER_TYPE_F);
*reg = temp;
}
+void
+fs_visitor::emit_cs_terminate()
+{
+ assert(brw->gen >= 7);
+
+ /* We are getting the thread ID from the compute shader header */
+ assert(stage == MESA_SHADER_COMPUTE);
+
+ /* We can't directly send from g0, since sends with EOT have to use
+ * g112-127. So, copy it to a virtual register, The register allocator will
+ * make sure it uses the appropriate register range.
+ */
+ struct brw_reg g0 = retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UD);
+ fs_reg payload = fs_reg(GRF, alloc.allocate(1), BRW_REGISTER_TYPE_UD);
+ fs_inst *inst = emit(MOV(payload, g0));
+ inst->force_writemask_all = true;
+
+ /* Send a message to the thread spawner to terminate the thread. */
+ inst = emit(CS_OPCODE_CS_TERMINATE, reg_undef, payload);
+ inst->eot = true;
+}
+
/**
* Resolve the result of a Gen4-5 CMP instruction to a proper boolean.
*
void
fs_visitor::resolve_bool_comparison(ir_rvalue *rvalue, fs_reg *reg)
{
- assert(brw->gen <= 5);
+ assert(devinfo->gen <= 5);
if (rvalue->type != glsl_type::bool_type)
return;
reg_null_d(retype(brw_null_vec(dispatch_width), BRW_REGISTER_TYPE_D)),
reg_null_ud(retype(brw_null_vec(dispatch_width), BRW_REGISTER_TYPE_UD)),
key(key), prog_data(&prog_data->base),
- dispatch_width(dispatch_width)
+ dispatch_width(dispatch_width), promoted_constants(0)
{
this->mem_ctx = mem_ctx;
init();
reg_null_d(retype(brw_null_vec(dispatch_width), BRW_REGISTER_TYPE_D)),
reg_null_ud(retype(brw_null_vec(dispatch_width), BRW_REGISTER_TYPE_UD)),
key(key), prog_data(&prog_data->base.base),
+ dispatch_width(dispatch_width), promoted_constants(0)
+{
+ this->mem_ctx = mem_ctx;
+ init();
+}
+
+fs_visitor::fs_visitor(struct brw_context *brw,
+ void *mem_ctx,
+ const struct brw_cs_prog_key *key,
+ struct brw_cs_prog_data *prog_data,
+ struct gl_shader_program *shader_prog,
+ struct gl_compute_program *cp,
+ unsigned dispatch_width)
+ : backend_visitor(brw, shader_prog, &cp->Base, &prog_data->base,
+ MESA_SHADER_COMPUTE),
+ reg_null_f(retype(brw_null_vec(dispatch_width), BRW_REGISTER_TYPE_F)),
+ reg_null_d(retype(brw_null_vec(dispatch_width), BRW_REGISTER_TYPE_D)),
+ reg_null_ud(retype(brw_null_vec(dispatch_width), BRW_REGISTER_TYPE_UD)),
+ key(key), prog_data(&prog_data->base),
dispatch_width(dispatch_width)
{
this->mem_ctx = mem_ctx;
void
fs_visitor::init()
{
+ switch (stage) {
+ case MESA_SHADER_FRAGMENT:
+ key_tex = &((const brw_wm_prog_key *) key)->tex;
+ break;
+ case MESA_SHADER_VERTEX:
+ case MESA_SHADER_GEOMETRY:
+ key_tex = &((const brw_vue_prog_key *) key)->tex;
+ break;
+ case MESA_SHADER_COMPUTE:
+ key_tex = &((const brw_cs_prog_key*) key)->tex;
+ break;
+ default:
+ unreachable("unhandled shader stage");
+ }
+
this->failed = false;
this->simd16_unsupported = false;
this->no16_msg = NULL;
this->source_depth_to_render_target = false;
this->runtime_check_aads_emit = false;
this->first_non_payload_grf = 0;
- this->max_grf = brw->gen >= 7 ? GEN7_MRF_HACK_START : BRW_MAX_GRF;
+ this->max_grf = devinfo->gen >= 7 ? GEN7_MRF_HACK_START : BRW_MAX_GRF;
this->current_annotation = NULL;
this->base_ir = NULL;