#include "brw_vec4_gs_visitor.h"
#include "brw_cfg.h"
#include "brw_dead_control_flow.h"
-#include "common/gen_debug.h"
+#include "dev/gen_debug.h"
#include "compiler/glsl_types.h"
#include "compiler/nir/nir_builder.h"
#include "program/prog_parameter.h"
{
switch (opcode) {
case SHADER_OPCODE_SEND:
- case FS_OPCODE_VARYING_PULL_CONSTANT_LOAD_GEN7:
case SHADER_OPCODE_SHADER_TIME_ADD:
case FS_OPCODE_INTERPOLATE_AT_SAMPLE:
case FS_OPCODE_INTERPOLATE_AT_SHARED_OFFSET:
case FS_OPCODE_INTERPOLATE_AT_PER_SLOT_OFFSET:
- case SHADER_OPCODE_UNTYPED_ATOMIC:
- case SHADER_OPCODE_UNTYPED_ATOMIC_FLOAT:
- case SHADER_OPCODE_UNTYPED_SURFACE_READ:
- case SHADER_OPCODE_UNTYPED_SURFACE_WRITE:
- case SHADER_OPCODE_BYTE_SCATTERED_WRITE:
- case SHADER_OPCODE_BYTE_SCATTERED_READ:
- case SHADER_OPCODE_TYPED_ATOMIC:
- case SHADER_OPCODE_TYPED_SURFACE_READ:
- case SHADER_OPCODE_TYPED_SURFACE_WRITE:
- case SHADER_OPCODE_IMAGE_SIZE:
case SHADER_OPCODE_URB_WRITE_SIMD8:
case SHADER_OPCODE_URB_WRITE_SIMD8_PER_SLOT:
case SHADER_OPCODE_URB_WRITE_SIMD8_MASKED:
}
}
+bool
+fs_inst::is_control_source(unsigned arg) const
+{
+ switch (opcode) {
+ case FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD:
+ case FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD_GEN7:
+ case FS_OPCODE_VARYING_PULL_CONSTANT_LOAD_GEN4:
+ return arg == 0;
+
+ case SHADER_OPCODE_BROADCAST:
+ case SHADER_OPCODE_SHUFFLE:
+ case SHADER_OPCODE_QUAD_SWIZZLE:
+ case FS_OPCODE_INTERPOLATE_AT_SAMPLE:
+ case FS_OPCODE_INTERPOLATE_AT_SHARED_OFFSET:
+ case FS_OPCODE_INTERPOLATE_AT_PER_SLOT_OFFSET:
+ case SHADER_OPCODE_GET_BUFFER_SIZE:
+ return arg == 1;
+
+ case SHADER_OPCODE_MOV_INDIRECT:
+ case SHADER_OPCODE_CLUSTER_BROADCAST:
+ case SHADER_OPCODE_TEX:
+ case FS_OPCODE_TXB:
+ case SHADER_OPCODE_TXD:
+ case SHADER_OPCODE_TXF:
+ case SHADER_OPCODE_TXF_LZ:
+ case SHADER_OPCODE_TXF_CMS:
+ case SHADER_OPCODE_TXF_CMS_W:
+ case SHADER_OPCODE_TXF_UMS:
+ case SHADER_OPCODE_TXF_MCS:
+ case SHADER_OPCODE_TXL:
+ case SHADER_OPCODE_TXL_LZ:
+ case SHADER_OPCODE_TXS:
+ case SHADER_OPCODE_LOD:
+ case SHADER_OPCODE_TG4:
+ case SHADER_OPCODE_TG4_OFFSET:
+ case SHADER_OPCODE_SAMPLEINFO:
+ return arg == 1 || arg == 2;
+
+ case SHADER_OPCODE_SEND:
+ return arg == 0 || arg == 1;
+
+ default:
+ return false;
+ }
+}
+
/**
* Returns true if this instruction's sources and destinations cannot
* safely be the same register.
}
extern "C" int
-type_size_scalar(const struct glsl_type *type)
+type_size_scalar(const struct glsl_type *type, bool bindless)
{
unsigned int size, i;
case GLSL_TYPE_INT64:
return type->components() * 2;
case GLSL_TYPE_ARRAY:
- return type_size_scalar(type->fields.array) * type->length;
+ return type_size_scalar(type->fields.array, bindless) * type->length;
case GLSL_TYPE_STRUCT:
+ case GLSL_TYPE_INTERFACE:
size = 0;
for (i = 0; i < type->length; i++) {
- size += type_size_scalar(type->fields.structure[i].type);
+ size += type_size_scalar(type->fields.structure[i].type, bindless);
}
return size;
case GLSL_TYPE_SAMPLER:
- case GLSL_TYPE_ATOMIC_UINT:
case GLSL_TYPE_IMAGE:
+ if (bindless)
+ return type->components() * 2;
+ case GLSL_TYPE_ATOMIC_UINT:
/* Samplers, atomics, and images take up no register space, since
* they're baked in at link time.
*/
return 1;
case GLSL_TYPE_VOID:
case GLSL_TYPE_ERROR:
- case GLSL_TYPE_INTERFACE:
case GLSL_TYPE_FUNCTION:
unreachable("not reached");
}
case SHADER_OPCODE_UNTYPED_SURFACE_READ_LOGICAL:
case SHADER_OPCODE_TYPED_SURFACE_READ_LOGICAL:
- assert(src[3].file == IMM);
+ assert(src[SURFACE_LOGICAL_SRC_IMM_DIMS].file == IMM);
/* Surface coordinates. */
- if (i == 0)
- return src[3].ud;
+ if (i == SURFACE_LOGICAL_SRC_ADDRESS)
+ return src[SURFACE_LOGICAL_SRC_IMM_DIMS].ud;
/* Surface operation source (ignored for reads). */
- else if (i == 1)
+ else if (i == SURFACE_LOGICAL_SRC_DATA)
return 0;
else
return 1;
case SHADER_OPCODE_UNTYPED_SURFACE_WRITE_LOGICAL:
case SHADER_OPCODE_TYPED_SURFACE_WRITE_LOGICAL:
- assert(src[3].file == IMM &&
- src[4].file == IMM);
+ assert(src[SURFACE_LOGICAL_SRC_IMM_DIMS].file == IMM &&
+ src[SURFACE_LOGICAL_SRC_IMM_ARG].file == IMM);
/* Surface coordinates. */
- if (i == 0)
- return src[3].ud;
+ if (i == SURFACE_LOGICAL_SRC_ADDRESS)
+ return src[SURFACE_LOGICAL_SRC_IMM_DIMS].ud;
/* Surface operation source. */
- else if (i == 1)
- return src[4].ud;
+ else if (i == SURFACE_LOGICAL_SRC_DATA)
+ return src[SURFACE_LOGICAL_SRC_IMM_ARG].ud;
else
return 1;
+ case SHADER_OPCODE_A64_UNTYPED_READ_LOGICAL:
+ assert(src[2].file == IMM);
+ return 1;
+
+ case SHADER_OPCODE_A64_UNTYPED_WRITE_LOGICAL:
+ assert(src[2].file == IMM);
+ return i == 1 ? src[2].ud : 1;
+
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_LOGICAL:
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_INT64_LOGICAL:
+ assert(src[2].file == IMM);
+ if (i == 1) {
+ /* Data source */
+ const unsigned op = src[2].ud;
+ switch (op) {
+ case BRW_AOP_INC:
+ case BRW_AOP_DEC:
+ case BRW_AOP_PREDEC:
+ return 0;
+ case BRW_AOP_CMPWR:
+ return 2;
+ default:
+ return 1;
+ }
+ } else {
+ return 1;
+ }
+
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_FLOAT_LOGICAL:
+ assert(src[2].file == IMM);
+ if (i == 1) {
+ /* Data source */
+ const unsigned op = src[2].ud;
+ return op == BRW_AOP_FCMPWR ? 2 : 1;
+ } else {
+ return 1;
+ }
+
case SHADER_OPCODE_BYTE_SCATTERED_READ_LOGICAL:
/* Scattered logical opcodes use the following params:
* src[0] Surface coordinates
* src[3] IMM with always 1 dimension.
* src[4] IMM with arg bitsize for scattered read/write 8, 16, 32
*/
- assert(src[3].file == IMM &&
- src[4].file == IMM);
- return i == 1 ? 0 : 1;
+ assert(src[SURFACE_LOGICAL_SRC_IMM_DIMS].file == IMM &&
+ src[SURFACE_LOGICAL_SRC_IMM_ARG].file == IMM);
+ return i == SURFACE_LOGICAL_SRC_DATA ? 0 : 1;
case SHADER_OPCODE_BYTE_SCATTERED_WRITE_LOGICAL:
- assert(src[3].file == IMM &&
- src[4].file == IMM);
+ assert(src[SURFACE_LOGICAL_SRC_IMM_DIMS].file == IMM &&
+ src[SURFACE_LOGICAL_SRC_IMM_ARG].file == IMM);
return 1;
case SHADER_OPCODE_UNTYPED_ATOMIC_LOGICAL:
case SHADER_OPCODE_TYPED_ATOMIC_LOGICAL: {
- assert(src[3].file == IMM &&
- src[4].file == IMM);
- const unsigned op = src[4].ud;
+ assert(src[SURFACE_LOGICAL_SRC_IMM_DIMS].file == IMM &&
+ src[SURFACE_LOGICAL_SRC_IMM_ARG].file == IMM);
+ const unsigned op = src[SURFACE_LOGICAL_SRC_IMM_ARG].ud;
/* Surface coordinates. */
- if (i == 0)
- return src[3].ud;
+ if (i == SURFACE_LOGICAL_SRC_ADDRESS)
+ return src[SURFACE_LOGICAL_SRC_IMM_DIMS].ud;
/* Surface operation source. */
- else if (i == 1 && op == BRW_AOP_CMPWR)
+ else if (i == SURFACE_LOGICAL_SRC_DATA && op == BRW_AOP_CMPWR)
return 2;
- else if (i == 1 && (op == BRW_AOP_INC || op == BRW_AOP_DEC ||
- op == BRW_AOP_PREDEC))
+ else if (i == SURFACE_LOGICAL_SRC_DATA &&
+ (op == BRW_AOP_INC || op == BRW_AOP_DEC || op == BRW_AOP_PREDEC))
return 0;
else
return 1;
return (i == 0 ? 2 : 1);
case SHADER_OPCODE_UNTYPED_ATOMIC_FLOAT_LOGICAL: {
- assert(src[3].file == IMM &&
- src[4].file == IMM);
- const unsigned op = src[4].ud;
+ assert(src[SURFACE_LOGICAL_SRC_IMM_DIMS].file == IMM &&
+ src[SURFACE_LOGICAL_SRC_IMM_ARG].file == IMM);
+ const unsigned op = src[SURFACE_LOGICAL_SRC_IMM_ARG].ud;
/* Surface coordinates. */
- if (i == 0)
- return src[3].ud;
+ if (i == SURFACE_LOGICAL_SRC_ADDRESS)
+ return src[SURFACE_LOGICAL_SRC_IMM_DIMS].ud;
/* Surface operation source. */
- else if (i == 1 && op == BRW_AOP_FCMPWR)
+ else if (i == SURFACE_LOGICAL_SRC_DATA && op == BRW_AOP_FCMPWR)
return 2;
else
return 1;
case SHADER_OPCODE_URB_WRITE_SIMD8_MASKED_PER_SLOT:
case SHADER_OPCODE_URB_READ_SIMD8:
case SHADER_OPCODE_URB_READ_SIMD8_PER_SLOT:
- case SHADER_OPCODE_UNTYPED_ATOMIC:
- case SHADER_OPCODE_UNTYPED_ATOMIC_FLOAT:
- case SHADER_OPCODE_UNTYPED_SURFACE_READ:
- case SHADER_OPCODE_UNTYPED_SURFACE_WRITE:
- case SHADER_OPCODE_TYPED_ATOMIC:
- case SHADER_OPCODE_TYPED_SURFACE_READ:
- case SHADER_OPCODE_TYPED_SURFACE_WRITE:
- case SHADER_OPCODE_IMAGE_SIZE:
case FS_OPCODE_INTERPOLATE_AT_SAMPLE:
case FS_OPCODE_INTERPOLATE_AT_SHARED_OFFSET:
- case SHADER_OPCODE_BYTE_SCATTERED_WRITE:
- case SHADER_OPCODE_BYTE_SCATTERED_READ:
if (arg == 0)
return mlen * REG_SIZE;
break;
fs_visitor::vgrf(const glsl_type *const type)
{
int reg_width = dispatch_width / 8;
- return fs_reg(VGRF, alloc.allocate(type_size_scalar(type) * reg_width),
+ return fs_reg(VGRF,
+ alloc.allocate(type_size_scalar(type, false) * reg_width),
brw_type_for_base_type(type));
}
} else {
bld.emit(FS_OPCODE_LINTERP, wpos,
this->delta_xy[BRW_BARYCENTRIC_PERSPECTIVE_PIXEL],
- component(interp_reg(VARYING_SLOT_POS, 2), 0));
+ interp_reg(VARYING_SLOT_POS, 2));
}
wpos = offset(wpos, bld, 1);
break;
}
- /* a * 0.0 = 0.0 */
- if (inst->src[1].is_zero()) {
- inst->opcode = BRW_OPCODE_MOV;
- inst->src[0] = inst->src[1];
- inst->src[1] = reg_undef;
- progress = true;
- break;
- }
-
if (inst->src[0].file == IMM) {
assert(inst->src[0].type == BRW_REGISTER_TYPE_F);
inst->opcode = BRW_OPCODE_MOV;
if (inst->src[1].file != IMM)
continue;
- /* a + 0.0 = a */
- if (inst->src[1].is_zero()) {
- inst->opcode = BRW_OPCODE_MOV;
- inst->src[1] = reg_undef;
- progress = true;
- break;
- }
-
if (inst->src[0].file == IMM) {
assert(inst->src[0].type == BRW_REGISTER_TYPE_F);
inst->opcode = BRW_OPCODE_MOV;
case BRW_OPCODE_OR:
if (inst->src[0].equals(inst->src[1]) ||
inst->src[1].is_zero()) {
- inst->opcode = BRW_OPCODE_MOV;
- inst->src[1] = reg_undef;
- progress = true;
- break;
- }
- break;
- case BRW_OPCODE_LRP:
- if (inst->src[1].equals(inst->src[2])) {
- inst->opcode = BRW_OPCODE_MOV;
- inst->src[0] = inst->src[1];
+ /* On Gen8+, the OR instruction can have a source modifier that
+ * performs logical not on the operand. Cases of 'OR r0, ~r1, 0'
+ * or 'OR r0, ~r1, ~r1' should become a NOT instead of a MOV.
+ */
+ if (inst->src[0].negate) {
+ inst->opcode = BRW_OPCODE_NOT;
+ inst->src[0].negate = false;
+ } else {
+ inst->opcode = BRW_OPCODE_MOV;
+ }
inst->src[1] = reg_undef;
- inst->src[2] = reg_undef;
progress = true;
break;
}
}
break;
case BRW_OPCODE_MAD:
- if (inst->src[1].is_zero() || inst->src[2].is_zero()) {
- inst->opcode = BRW_OPCODE_MOV;
- inst->src[1] = reg_undef;
- inst->src[2] = reg_undef;
- progress = true;
- } else if (inst->src[0].is_zero()) {
- inst->opcode = BRW_OPCODE_MUL;
- inst->src[0] = inst->src[2];
- inst->src[2] = reg_undef;
- progress = true;
- } else if (inst->src[1].is_one()) {
+ if (inst->src[0].type != BRW_REGISTER_TYPE_F ||
+ inst->src[1].type != BRW_REGISTER_TYPE_F ||
+ inst->src[2].type != BRW_REGISTER_TYPE_F)
+ break;
+ if (inst->src[1].is_one()) {
inst->opcode = BRW_OPCODE_ADD;
inst->src[1] = inst->src[2];
inst->src[2] = reg_undef;
inst->opcode = BRW_OPCODE_ADD;
inst->src[2] = reg_undef;
progress = true;
- } else if (inst->src[1].file == IMM && inst->src[2].file == IMM) {
- inst->opcode = BRW_OPCODE_ADD;
- inst->src[1].f *= inst->src[2].f;
- inst->src[2] = reg_undef;
- progress = true;
}
break;
case SHADER_OPCODE_BROADCAST:
if (csel_inst != NULL) {
progress = true;
+ csel_inst->saturate = inst->saturate;
inst->remove(block);
}
}
for (uint8_t i = inst->header_size; i < inst->sources; i++) {
- if (inst->src[i].file != BAD_FILE)
- ibld.MOV(retype(dst, inst->src[i].type), inst->src[i]);
+ if (inst->src[i].file != BAD_FILE) {
+ dst.type = inst->src[i].type;
+ ibld.MOV(dst, inst->src[i]);
+ } else {
+ dst.type = BRW_REGISTER_TYPE_UD;
+ }
dst = offset(dst, ibld, 1);
}
return progress;
}
+bool
+fs_visitor::lower_linterp()
+{
+ bool progress = false;
+
+ if (devinfo->gen < 11)
+ return false;
+
+ foreach_block_and_inst_safe(block, fs_inst, inst, cfg) {
+ const fs_builder ibld(this, block, inst);
+
+ if (inst->opcode != FS_OPCODE_LINTERP)
+ continue;
+
+ fs_reg dwP = component(inst->src[1], 0);
+ fs_reg dwQ = component(inst->src[1], 1);
+ fs_reg dwR = component(inst->src[1], 3);
+ for (unsigned i = 0; i < DIV_ROUND_UP(dispatch_width, 8); i++) {
+ const fs_builder hbld(ibld.half(i));
+ fs_reg dst = half(inst->dst, i);
+ fs_reg delta_xy = offset(inst->src[0], ibld, i);
+ hbld.MAD(dst, dwR, half(delta_xy, 0), dwP);
+ fs_inst *mad = hbld.MAD(dst, dst, half(delta_xy, 1), dwQ);
+
+ /* Propagate conditional mod and saturate from the original
+ * instruction to the second MAD instruction.
+ */
+ set_saturate(inst->saturate, mad);
+ set_condmod(inst->conditional_mod, mad);
+ }
+
+ inst->remove(block);
+ progress = true;
+ }
+
+ if (progress)
+ invalidate_live_intervals();
+
+ return progress;
+}
+
bool
fs_visitor::lower_integer_multiplication()
{
bool needs_mov = false;
fs_reg orig_dst = inst->dst;
+
+ /* Get a new VGRF for the "low" 32x16-bit multiplication result if
+ * reusing the original destination is impossible due to hardware
+ * restrictions, source/destination overlap, or it being the null
+ * register.
+ */
fs_reg low = inst->dst;
if (orig_dst.is_null() || orig_dst.file == MRF ||
regions_overlap(inst->dst, inst->size_written,
inst->src[0], inst->size_read(0)) ||
regions_overlap(inst->dst, inst->size_written,
- inst->src[1], inst->size_read(1))) {
+ inst->src[1], inst->size_read(1)) ||
+ inst->dst.stride >= 4) {
needs_mov = true;
- /* Get a new VGRF but keep the same stride as inst->dst */
low = fs_reg(VGRF, alloc.allocate(regs_written(inst)),
inst->dst.type);
- low.stride = inst->dst.stride;
- low.offset = inst->dst.offset % REG_SIZE;
}
/* Get a new VGRF but keep the same stride as inst->dst */
/* Set "Source0 Alpha Present to RenderTarget" bit in message
* header.
*/
- if (inst->target > 0 && key->replicate_alpha)
+ if (inst->target > 0 && prog_data->replicate_alpha)
g00_bits |= 1 << 11;
/* Set computes stencil to render target */
length++;
}
+ if (src0_alpha.file != BAD_FILE) {
+ for (unsigned i = 0; i < bld.dispatch_width() / 8; i++) {
+ const fs_builder &ubld = bld.exec_all().group(8, i)
+ .annotate("FB write src0 alpha");
+ const fs_reg tmp = ubld.vgrf(BRW_REGISTER_TYPE_F);
+ ubld.MOV(tmp, horiz_offset(src0_alpha, i * 8));
+ setup_color_payload(ubld, key, &sources[length], tmp, 1);
+ length++;
+ }
+ } else if (prog_data->replicate_alpha && inst->target != 0) {
+ /* Handle the case when fragment shader doesn't write to draw buffer
+ * zero. No need to call setup_color_payload() for src0_alpha because
+ * alpha value will be undefined.
+ */
+ length += bld.dispatch_width() / 8;
+ }
+
if (sample_mask.file != BAD_FILE) {
sources[length] = fs_reg(VGRF, bld.shader->alloc.allocate(1),
BRW_REGISTER_TYPE_UD);
payload_header_size = length;
- if (src0_alpha.file != BAD_FILE) {
- /* FIXME: This is being passed at the wrong location in the payload and
- * doesn't work when gl_SampleMask and MRTs are used simultaneously.
- * It's supposed to be immediately before oMask but there seems to be no
- * reasonable way to pass them in the correct order because LOAD_PAYLOAD
- * requires header sources to form a contiguous segment at the beginning
- * of the message and src0_alpha has per-channel semantics.
- */
- setup_color_payload(bld, key, &sources[length], src0_alpha, 1);
- length++;
- } else if (key->replicate_alpha && inst->target != 0) {
- /* Handle the case when fragment shader doesn't write to draw buffer
- * zero. No need to call setup_color_payload() for src0_alpha because
- * alpha value will be undefined.
- */
- length++;
- }
-
setup_color_payload(bld, key, &sources[length], color0, components);
length += 4;
return sampler.file != IMM || sampler.ud >= 16;
}
+static unsigned
+sampler_msg_type(const gen_device_info *devinfo,
+ opcode opcode, bool shadow_compare)
+{
+ assert(devinfo->gen >= 5);
+ switch (opcode) {
+ case SHADER_OPCODE_TEX:
+ return shadow_compare ? GEN5_SAMPLER_MESSAGE_SAMPLE_COMPARE :
+ GEN5_SAMPLER_MESSAGE_SAMPLE;
+ case FS_OPCODE_TXB:
+ return shadow_compare ? GEN5_SAMPLER_MESSAGE_SAMPLE_BIAS_COMPARE :
+ GEN5_SAMPLER_MESSAGE_SAMPLE_BIAS;
+ case SHADER_OPCODE_TXL:
+ return shadow_compare ? GEN5_SAMPLER_MESSAGE_SAMPLE_LOD_COMPARE :
+ GEN5_SAMPLER_MESSAGE_SAMPLE_LOD;
+ case SHADER_OPCODE_TXL_LZ:
+ return shadow_compare ? GEN9_SAMPLER_MESSAGE_SAMPLE_C_LZ :
+ GEN9_SAMPLER_MESSAGE_SAMPLE_LZ;
+ case SHADER_OPCODE_TXS:
+ case SHADER_OPCODE_IMAGE_SIZE_LOGICAL:
+ return GEN5_SAMPLER_MESSAGE_SAMPLE_RESINFO;
+ case SHADER_OPCODE_TXD:
+ assert(!shadow_compare || devinfo->gen >= 8 || devinfo->is_haswell);
+ return shadow_compare ? HSW_SAMPLER_MESSAGE_SAMPLE_DERIV_COMPARE :
+ GEN5_SAMPLER_MESSAGE_SAMPLE_DERIVS;
+ case SHADER_OPCODE_TXF:
+ return GEN5_SAMPLER_MESSAGE_SAMPLE_LD;
+ case SHADER_OPCODE_TXF_LZ:
+ assert(devinfo->gen >= 9);
+ return GEN9_SAMPLER_MESSAGE_SAMPLE_LD_LZ;
+ case SHADER_OPCODE_TXF_CMS_W:
+ assert(devinfo->gen >= 9);
+ return GEN9_SAMPLER_MESSAGE_SAMPLE_LD2DMS_W;
+ case SHADER_OPCODE_TXF_CMS:
+ return devinfo->gen >= 7 ? GEN7_SAMPLER_MESSAGE_SAMPLE_LD2DMS :
+ GEN5_SAMPLER_MESSAGE_SAMPLE_LD;
+ case SHADER_OPCODE_TXF_UMS:
+ assert(devinfo->gen >= 7);
+ return GEN7_SAMPLER_MESSAGE_SAMPLE_LD2DSS;
+ case SHADER_OPCODE_TXF_MCS:
+ assert(devinfo->gen >= 7);
+ return GEN7_SAMPLER_MESSAGE_SAMPLE_LD_MCS;
+ case SHADER_OPCODE_LOD:
+ return GEN5_SAMPLER_MESSAGE_LOD;
+ case SHADER_OPCODE_TG4:
+ assert(devinfo->gen >= 7);
+ return shadow_compare ? GEN7_SAMPLER_MESSAGE_SAMPLE_GATHER4_C :
+ GEN7_SAMPLER_MESSAGE_SAMPLE_GATHER4;
+ break;
+ case SHADER_OPCODE_TG4_OFFSET:
+ assert(devinfo->gen >= 7);
+ return shadow_compare ? GEN7_SAMPLER_MESSAGE_SAMPLE_GATHER4_PO_C :
+ GEN7_SAMPLER_MESSAGE_SAMPLE_GATHER4_PO;
+ case SHADER_OPCODE_SAMPLEINFO:
+ return GEN6_SAMPLER_MESSAGE_SAMPLE_SAMPLEINFO;
+ default:
+ unreachable("not reached");
+ }
+}
+
static void
lower_sampler_logical_send_gen7(const fs_builder &bld, fs_inst *inst, opcode op,
const fs_reg &coordinate,
const fs_reg &mcs,
const fs_reg &surface,
const fs_reg &sampler,
+ const fs_reg &surface_handle,
+ const fs_reg &sampler_handle,
const fs_reg &tg4_offset,
unsigned coord_components,
unsigned grad_components)
{
const gen_device_info *devinfo = bld.shader->devinfo;
+ const brw_stage_prog_data *prog_data = bld.shader->stage_prog_data;
unsigned reg_width = bld.dispatch_width() / 8;
unsigned header_size = 0, length = 0;
fs_reg sources[MAX_SAMPLER_MESSAGE_SIZE];
for (unsigned i = 0; i < ARRAY_SIZE(sources); i++)
sources[i] = bld.vgrf(BRW_REGISTER_TYPE_F);
+ /* We must have exactly one of surface/sampler and surface/sampler_handle */
+ assert((surface.file == BAD_FILE) != (surface_handle.file == BAD_FILE));
+ assert((sampler.file == BAD_FILE) != (sampler_handle.file == BAD_FILE));
+
if (op == SHADER_OPCODE_TG4 || op == SHADER_OPCODE_TG4_OFFSET ||
inst->offset != 0 || inst->eot ||
op == SHADER_OPCODE_SAMPLEINFO ||
+ sampler_handle.file != BAD_FILE ||
is_high_sampler(devinfo, sampler)) {
/* For general texture offsets (no txf workaround), we need a header to
* put them in.
ubld1.MOV(component(header, 2), brw_imm_ud(0));
}
- if (is_high_sampler(devinfo, sampler)) {
+ if (sampler_handle.file != BAD_FILE) {
+ /* Bindless sampler handles aren't relative to the sampler state
+ * pointer passed into the shader through SAMPLER_STATE_POINTERS_*.
+ * Instead, it's an absolute pointer relative to dynamic state base
+ * address.
+ *
+ * Sampler states are 16 bytes each and the pointer we give here has
+ * to be 32-byte aligned. In order to avoid more indirect messages
+ * than required, we assume that all bindless sampler states are
+ * 32-byte aligned. This sacrifices a bit of general state base
+ * address space but means we can do something more efficient in the
+ * shader.
+ */
+ ubld1.MOV(component(header, 3), sampler_handle);
+ } else if (is_high_sampler(devinfo, sampler)) {
if (sampler.file == BRW_IMMEDIATE_VALUE) {
assert(sampler.ud >= 16);
const int sampler_state_size = 16; /* 16 bytes */
bld.MOV(retype(sources[length], BRW_REGISTER_TYPE_UD), lod);
length++;
break;
- case SHADER_OPCODE_IMAGE_SIZE:
+ case SHADER_OPCODE_IMAGE_SIZE_LOGICAL:
/* We need an LOD; just use 0 */
bld.MOV(retype(sources[length], BRW_REGISTER_TYPE_UD), brw_imm_ud(0));
length++;
bld.LOAD_PAYLOAD(src_payload, sources, length, header_size);
/* Generate the SEND. */
- inst->opcode = op;
- inst->src[0] = src_payload;
- inst->src[1] = surface;
- inst->src[2] = sampler;
- inst->resize_sources(3);
+ inst->opcode = SHADER_OPCODE_SEND;
inst->mlen = mlen;
inst->header_size = header_size;
+ const unsigned msg_type =
+ sampler_msg_type(devinfo, op, inst->shadow_compare);
+ const unsigned simd_mode =
+ inst->exec_size <= 8 ? BRW_SAMPLER_SIMD_MODE_SIMD8 :
+ BRW_SAMPLER_SIMD_MODE_SIMD16;
+
+ uint32_t base_binding_table_index;
+ switch (op) {
+ case SHADER_OPCODE_TG4:
+ case SHADER_OPCODE_TG4_OFFSET:
+ base_binding_table_index = prog_data->binding_table.gather_texture_start;
+ break;
+ case SHADER_OPCODE_IMAGE_SIZE_LOGICAL:
+ base_binding_table_index = prog_data->binding_table.image_start;
+ break;
+ default:
+ base_binding_table_index = prog_data->binding_table.texture_start;
+ break;
+ }
+
+ inst->sfid = BRW_SFID_SAMPLER;
+ if (surface.file == IMM &&
+ (sampler.file == IMM || sampler_handle.file != BAD_FILE)) {
+ inst->desc = brw_sampler_desc(devinfo,
+ surface.ud + base_binding_table_index,
+ sampler.file == IMM ? sampler.ud % 16 : 0,
+ msg_type,
+ simd_mode,
+ 0 /* return_format unused on gen7+ */);
+ inst->src[0] = brw_imm_ud(0);
+ inst->src[1] = brw_imm_ud(0); /* ex_desc */
+ } else if (surface_handle.file != BAD_FILE) {
+ /* Bindless surface */
+ assert(devinfo->gen >= 9);
+ inst->desc = brw_sampler_desc(devinfo,
+ GEN9_BTI_BINDLESS,
+ sampler.file == IMM ? sampler.ud % 16 : 0,
+ msg_type,
+ simd_mode,
+ 0 /* return_format unused on gen7+ */);
+
+ /* For bindless samplers, the entire address is included in the message
+ * header so we can leave the portion in the message descriptor 0.
+ */
+ if (sampler_handle.file != BAD_FILE || sampler.file == IMM) {
+ inst->src[0] = brw_imm_ud(0);
+ } else {
+ const fs_builder ubld = bld.group(1, 0).exec_all();
+ fs_reg desc = ubld.vgrf(BRW_REGISTER_TYPE_UD);
+ ubld.SHL(desc, sampler, brw_imm_ud(8));
+ inst->src[0] = desc;
+ }
+
+ /* We assume that the driver provided the handle in the top 20 bits so
+ * we can use the surface handle directly as the extended descriptor.
+ */
+ inst->src[1] = retype(surface_handle, BRW_REGISTER_TYPE_UD);
+ } else {
+ /* Immediate portion of the descriptor */
+ inst->desc = brw_sampler_desc(devinfo,
+ 0, /* surface */
+ 0, /* sampler */
+ msg_type,
+ simd_mode,
+ 0 /* return_format unused on gen7+ */);
+ const fs_builder ubld = bld.group(1, 0).exec_all();
+ fs_reg desc = ubld.vgrf(BRW_REGISTER_TYPE_UD);
+ if (surface.equals(sampler)) {
+ /* This case is common in GL */
+ ubld.MUL(desc, surface, brw_imm_ud(0x101));
+ } else {
+ if (sampler_handle.file != BAD_FILE) {
+ ubld.MOV(desc, surface);
+ } else if (sampler.file == IMM) {
+ ubld.OR(desc, surface, brw_imm_ud(sampler.ud << 8));
+ } else {
+ ubld.SHL(desc, sampler, brw_imm_ud(8));
+ ubld.OR(desc, desc, surface);
+ }
+ }
+ if (base_binding_table_index)
+ ubld.ADD(desc, desc, brw_imm_ud(base_binding_table_index));
+ ubld.AND(desc, desc, brw_imm_ud(0xfff));
+
+ inst->src[0] = component(desc, 0);
+ inst->src[1] = brw_imm_ud(0); /* ex_desc */
+ }
+
+ inst->src[2] = src_payload;
+ inst->resize_sources(3);
+
+ if (inst->eot) {
+ /* EOT sampler messages don't make sense to split because it would
+ * involve ending half of the thread early.
+ */
+ assert(inst->group == 0);
+ /* We need to use SENDC for EOT sampler messages */
+ inst->check_tdr = true;
+ inst->send_has_side_effects = true;
+ }
+
/* Message length > MAX_SAMPLER_MESSAGE_SIZE disallowed by hardware. */
assert(inst->mlen <= MAX_SAMPLER_MESSAGE_SIZE);
}
const fs_reg &mcs = inst->src[TEX_LOGICAL_SRC_MCS];
const fs_reg &surface = inst->src[TEX_LOGICAL_SRC_SURFACE];
const fs_reg &sampler = inst->src[TEX_LOGICAL_SRC_SAMPLER];
+ const fs_reg &surface_handle = inst->src[TEX_LOGICAL_SRC_SURFACE_HANDLE];
+ const fs_reg &sampler_handle = inst->src[TEX_LOGICAL_SRC_SAMPLER_HANDLE];
const fs_reg &tg4_offset = inst->src[TEX_LOGICAL_SRC_TG4_OFFSET];
assert(inst->src[TEX_LOGICAL_SRC_COORD_COMPONENTS].file == IMM);
const unsigned coord_components = inst->src[TEX_LOGICAL_SRC_COORD_COMPONENTS].ud;
lower_sampler_logical_send_gen7(bld, inst, op, coordinate,
shadow_c, lod, lod2, min_lod,
sample_index,
- mcs, surface, sampler, tg4_offset,
+ mcs, surface, sampler,
+ surface_handle, sampler_handle,
+ tg4_offset,
coord_components, grad_components);
} else if (devinfo->gen >= 5) {
lower_sampler_logical_send_gen5(bld, inst, op, coordinate,
const gen_device_info *devinfo = bld.shader->devinfo;
/* Get the logical send arguments. */
- const fs_reg &addr = inst->src[0];
- const fs_reg &src = inst->src[1];
- const fs_reg &surface = inst->src[2];
- const UNUSED fs_reg &dims = inst->src[3];
- const fs_reg &arg = inst->src[4];
+ const fs_reg &addr = inst->src[SURFACE_LOGICAL_SRC_ADDRESS];
+ const fs_reg &src = inst->src[SURFACE_LOGICAL_SRC_DATA];
+ const fs_reg &surface = inst->src[SURFACE_LOGICAL_SRC_SURFACE];
+ const fs_reg &surface_handle = inst->src[SURFACE_LOGICAL_SRC_SURFACE_HANDLE];
+ const UNUSED fs_reg &dims = inst->src[SURFACE_LOGICAL_SRC_IMM_DIMS];
+ const fs_reg &arg = inst->src[SURFACE_LOGICAL_SRC_IMM_ARG];
assert(arg.file == IMM);
+ /* We must have exactly one of surface and surface_handle */
+ assert((surface.file == BAD_FILE) != (surface_handle.file == BAD_FILE));
+
/* Calculate the total number of components of the payload. */
- const unsigned addr_sz = inst->components_read(0);
- const unsigned src_sz = inst->components_read(1);
+ const unsigned addr_sz = inst->components_read(SURFACE_LOGICAL_SRC_ADDRESS);
+ const unsigned src_sz = inst->components_read(SURFACE_LOGICAL_SRC_DATA);
const bool is_typed_access =
inst->opcode == SHADER_OPCODE_TYPED_SURFACE_READ_LOGICAL ||
* Gen11+ the header has been removed so we can only use predication.
*/
const unsigned header_sz = devinfo->gen < 9 && is_typed_access ? 1 : 0;
- const unsigned sz = header_sz + addr_sz + src_sz;
-
- /* Allocate space for the payload. */
- fs_reg *const components = new fs_reg[sz];
- const fs_reg payload = bld.vgrf(BRW_REGISTER_TYPE_UD, sz);
- unsigned n = 0;
const bool has_side_effects = inst->has_side_effects();
fs_reg sample_mask = has_side_effects ? bld.sample_mask_reg() :
fs_reg(brw_imm_d(0xffff));
- /* Construct the payload. */
- if (header_sz)
- components[n++] = emit_surface_header(bld, sample_mask);
+ fs_reg payload, payload2;
+ unsigned mlen, ex_mlen = 0;
+ if (devinfo->gen >= 9) {
+ /* We have split sends on gen9 and above */
+ assert(header_sz == 0);
+ payload = bld.move_to_vgrf(addr, addr_sz);
+ payload2 = bld.move_to_vgrf(src, src_sz);
+ mlen = addr_sz * (inst->exec_size / 8);
+ ex_mlen = src_sz * (inst->exec_size / 8);
+ } else {
+ /* Allocate space for the payload. */
+ const unsigned sz = header_sz + addr_sz + src_sz;
+ payload = bld.vgrf(BRW_REGISTER_TYPE_UD, sz);
+ fs_reg *const components = new fs_reg[sz];
+ unsigned n = 0;
+
+ /* Construct the payload. */
+ if (header_sz)
+ components[n++] = emit_surface_header(bld, sample_mask);
+
+ for (unsigned i = 0; i < addr_sz; i++)
+ components[n++] = offset(addr, bld, i);
- for (unsigned i = 0; i < addr_sz; i++)
- components[n++] = offset(addr, bld, i);
+ for (unsigned i = 0; i < src_sz; i++)
+ components[n++] = offset(src, bld, i);
- for (unsigned i = 0; i < src_sz; i++)
- components[n++] = offset(src, bld, i);
+ bld.LOAD_PAYLOAD(payload, components, sz, header_sz);
+ mlen = header_sz + (addr_sz + src_sz) * inst->exec_size / 8;
- bld.LOAD_PAYLOAD(payload, components, sz, header_sz);
+ delete[] components;
+ }
/* Predicate the instruction on the sample mask if no header is
* provided.
/* Update the original instruction. */
inst->opcode = SHADER_OPCODE_SEND;
- inst->mlen = header_sz + (addr_sz + src_sz) * inst->exec_size / 8;
+ inst->mlen = mlen;
+ inst->ex_mlen = ex_mlen;
inst->header_size = header_sz;
inst->send_has_side_effects = has_side_effects;
inst->send_is_volatile = !has_side_effects;
if (surface.file == IMM) {
inst->desc |= surface.ud & 0xff;
inst->src[0] = brw_imm_ud(0);
+ inst->src[1] = brw_imm_ud(0); /* ex_desc */
+ } else if (surface_handle.file != BAD_FILE) {
+ /* Bindless surface */
+ assert(devinfo->gen >= 9);
+ inst->desc |= GEN9_BTI_BINDLESS;
+ inst->src[0] = brw_imm_ud(0);
+
+ /* We assume that the driver provided the handle in the top 20 bits so
+ * we can use the surface handle directly as the extended descriptor.
+ */
+ inst->src[1] = retype(surface_handle, BRW_REGISTER_TYPE_UD);
} else {
const fs_builder ubld = bld.exec_all().group(1, 0);
fs_reg tmp = ubld.vgrf(BRW_REGISTER_TYPE_UD);
ubld.AND(tmp, surface, brw_imm_ud(0xff));
inst->src[0] = component(tmp, 0);
+ inst->src[1] = brw_imm_ud(0); /* ex_desc */
}
- inst->src[1] = brw_imm_ud(0); /* ex_desc */
/* Finally, the payload */
inst->src[2] = payload;
+ inst->src[3] = payload2;
- inst->resize_sources(3);
+ inst->resize_sources(4);
+}
+
+static void
+lower_a64_logical_send(const fs_builder &bld, fs_inst *inst)
+{
+ const gen_device_info *devinfo = bld.shader->devinfo;
+
+ const fs_reg &addr = inst->src[0];
+ const fs_reg &src = inst->src[1];
+ const unsigned src_comps = inst->components_read(1);
+ assert(inst->src[2].file == IMM);
+ const unsigned arg = inst->src[2].ud;
+ const bool has_side_effects = inst->has_side_effects();
+
+ /* If the surface message has side effects and we're a fragment shader, we
+ * have to predicate with the sample mask to avoid helper invocations.
+ */
+ if (has_side_effects && bld.shader->stage == MESA_SHADER_FRAGMENT) {
+ inst->flag_subreg = 2;
+ inst->predicate = BRW_PREDICATE_NORMAL;
+ inst->predicate_inverse = false;
+
+ fs_reg sample_mask = bld.sample_mask_reg();
+ const fs_builder ubld = bld.group(1, 0).exec_all();
+ ubld.MOV(retype(brw_flag_subreg(inst->flag_subreg), sample_mask.type),
+ sample_mask);
+ }
+
+ fs_reg payload, payload2;
+ unsigned mlen, ex_mlen = 0;
+ if (devinfo->gen >= 9) {
+ /* On Skylake and above, we have SENDS */
+ mlen = 2 * (inst->exec_size / 8);
+ ex_mlen = src_comps * type_sz(src.type) * inst->exec_size / REG_SIZE;
+ payload = retype(bld.move_to_vgrf(addr, 1), BRW_REGISTER_TYPE_UD);
+ payload2 = retype(bld.move_to_vgrf(src, src_comps),
+ BRW_REGISTER_TYPE_UD);
+ } else {
+ /* Add two because the address is 64-bit */
+ const unsigned dwords = 2 + src_comps;
+ mlen = dwords * (inst->exec_size / 8);
+
+ fs_reg sources[5];
+
+ sources[0] = addr;
+
+ for (unsigned i = 0; i < src_comps; i++)
+ sources[1 + i] = offset(src, bld, i);
+
+ payload = bld.vgrf(BRW_REGISTER_TYPE_UD, dwords);
+ bld.LOAD_PAYLOAD(payload, sources, 1 + src_comps, 0);
+ }
+
+ uint32_t desc;
+ switch (inst->opcode) {
+ case SHADER_OPCODE_A64_UNTYPED_READ_LOGICAL:
+ desc = brw_dp_a64_untyped_surface_rw_desc(devinfo, inst->exec_size,
+ arg, /* num_channels */
+ false /* write */);
+ break;
+
+ case SHADER_OPCODE_A64_UNTYPED_WRITE_LOGICAL:
+ desc = brw_dp_a64_untyped_surface_rw_desc(devinfo, inst->exec_size,
+ arg, /* num_channels */
+ true /* write */);
+ break;
+
+ case SHADER_OPCODE_A64_BYTE_SCATTERED_READ_LOGICAL:
+ desc = brw_dp_a64_byte_scattered_rw_desc(devinfo, inst->exec_size,
+ arg, /* bit_size */
+ false /* write */);
+ break;
+
+ case SHADER_OPCODE_A64_BYTE_SCATTERED_WRITE_LOGICAL:
+ desc = brw_dp_a64_byte_scattered_rw_desc(devinfo, inst->exec_size,
+ arg, /* bit_size */
+ true /* write */);
+ break;
+
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_LOGICAL:
+ desc = brw_dp_a64_untyped_atomic_desc(devinfo, inst->exec_size, 32,
+ arg, /* atomic_op */
+ !inst->dst.is_null());
+ break;
+
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_INT64_LOGICAL:
+ desc = brw_dp_a64_untyped_atomic_desc(devinfo, inst->exec_size, 64,
+ arg, /* atomic_op */
+ !inst->dst.is_null());
+ break;
- delete[] components;
+
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_FLOAT_LOGICAL:
+ desc = brw_dp_a64_untyped_atomic_float_desc(devinfo, inst->exec_size,
+ arg, /* atomic_op */
+ !inst->dst.is_null());
+ break;
+
+ default:
+ unreachable("Unknown A64 logical instruction");
+ }
+
+ /* Update the original instruction. */
+ inst->opcode = SHADER_OPCODE_SEND;
+ inst->mlen = mlen;
+ inst->ex_mlen = ex_mlen;
+ inst->header_size = 0;
+ inst->send_has_side_effects = has_side_effects;
+ inst->send_is_volatile = !has_side_effects;
+
+ /* Set up SFID and descriptors */
+ inst->sfid = HSW_SFID_DATAPORT_DATA_CACHE_1;
+ inst->desc = desc;
+ inst->resize_sources(4);
+ inst->src[0] = brw_imm_ud(0); /* desc */
+ inst->src[1] = brw_imm_ud(0); /* ex_desc */
+ inst->src[2] = payload;
+ inst->src[3] = payload2;
}
static void
const gen_device_info *devinfo = bld.shader->devinfo;
if (devinfo->gen >= 7) {
+ fs_reg index = inst->src[0];
/* We are switching the instruction from an ALU-like instruction to a
* send-from-grf instruction. Since sends can't handle strides or
* source modifiers, we have to make a copy of the offset source.
*/
- fs_reg tmp = bld.vgrf(BRW_REGISTER_TYPE_UD);
- bld.MOV(tmp, inst->src[1]);
- inst->src[1] = tmp;
+ fs_reg offset = bld.vgrf(BRW_REGISTER_TYPE_UD);
+ bld.MOV(offset, inst->src[1]);
+
+ const unsigned simd_mode =
+ inst->exec_size <= 8 ? BRW_SAMPLER_SIMD_MODE_SIMD8 :
+ BRW_SAMPLER_SIMD_MODE_SIMD16;
- inst->opcode = FS_OPCODE_VARYING_PULL_CONSTANT_LOAD_GEN7;
+ inst->opcode = SHADER_OPCODE_SEND;
inst->mlen = inst->exec_size / 8;
+ inst->resize_sources(3);
+
+ inst->sfid = BRW_SFID_SAMPLER;
+ inst->desc = brw_sampler_desc(devinfo, 0, 0,
+ GEN5_SAMPLER_MESSAGE_SAMPLE_LD,
+ simd_mode, 0);
+ if (index.file == IMM) {
+ inst->desc |= index.ud & 0xff;
+ inst->src[0] = brw_imm_ud(0);
+ } else {
+ const fs_builder ubld = bld.exec_all().group(1, 0);
+ fs_reg tmp = ubld.vgrf(BRW_REGISTER_TYPE_UD);
+ ubld.AND(tmp, index, brw_imm_ud(0xff));
+ inst->src[0] = component(tmp, 0);
+ }
+ inst->src[1] = brw_imm_ud(0); /* ex_desc */
+ inst->src[2] = offset; /* payload */
} else {
const fs_reg payload(MRF, FIRST_PULL_LOAD_MRF(devinfo->gen),
BRW_REGISTER_TYPE_UD);
break;
case SHADER_OPCODE_IMAGE_SIZE_LOGICAL:
- lower_sampler_logical_send(ibld, inst, SHADER_OPCODE_IMAGE_SIZE);
+ lower_sampler_logical_send(ibld, inst,
+ SHADER_OPCODE_IMAGE_SIZE_LOGICAL);
break;
case FS_OPCODE_TXB_LOGICAL:
lower_surface_logical_send(ibld, inst);
break;
+ case SHADER_OPCODE_A64_UNTYPED_WRITE_LOGICAL:
+ case SHADER_OPCODE_A64_UNTYPED_READ_LOGICAL:
+ case SHADER_OPCODE_A64_BYTE_SCATTERED_WRITE_LOGICAL:
+ case SHADER_OPCODE_A64_BYTE_SCATTERED_READ_LOGICAL:
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_LOGICAL:
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_INT64_LOGICAL:
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_FLOAT_LOGICAL:
+ lower_a64_logical_send(ibld, inst);
+ break;
+
case FS_OPCODE_VARYING_PULL_CONSTANT_LOAD_LOGICAL:
lower_varying_pull_constant_logical_send(ibld, inst);
break;
return progress;
}
+static bool
+is_mixed_float_with_fp32_dst(const fs_inst *inst)
+{
+ /* This opcode sometimes uses :W type on the source even if the operand is
+ * a :HF, because in gen7 there is no support for :HF, and thus it uses :W.
+ */
+ if (inst->opcode == BRW_OPCODE_F16TO32)
+ return true;
+
+ if (inst->dst.type != BRW_REGISTER_TYPE_F)
+ return false;
+
+ for (int i = 0; i < inst->sources; i++) {
+ if (inst->src[i].type == BRW_REGISTER_TYPE_HF)
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+is_mixed_float_with_packed_fp16_dst(const fs_inst *inst)
+{
+ /* This opcode sometimes uses :W type on the destination even if the
+ * destination is a :HF, because in gen7 there is no support for :HF, and
+ * thus it uses :W.
+ */
+ if (inst->opcode == BRW_OPCODE_F32TO16 &&
+ inst->dst.stride == 1)
+ return true;
+
+ if (inst->dst.type != BRW_REGISTER_TYPE_HF ||
+ inst->dst.stride != 1)
+ return false;
+
+ for (int i = 0; i < inst->sources; i++) {
+ if (inst->src[i].type == BRW_REGISTER_TYPE_F)
+ return true;
+ }
+
+ return false;
+}
+
/**
* Get the closest allowed SIMD width for instruction \p inst accounting for
* some common regioning and execution control restrictions that apply to FPU
max_width = MIN2(max_width, 4);
}
+ /* From the SKL PRM, Special Restrictions for Handling Mixed Mode
+ * Float Operations:
+ *
+ * "No SIMD16 in mixed mode when destination is f32. Instruction
+ * execution size must be no more than 8."
+ *
+ * FIXME: the simulator doesn't seem to complain if we don't do this and
+ * empirical testing with existing CTS tests show that they pass just fine
+ * without implementing this, however, since our interpretation of the PRM
+ * is that conversion MOVs between HF and F are still mixed-float
+ * instructions (and therefore subject to this restriction) we decided to
+ * split them to be safe. Might be useful to do additional investigation to
+ * lift the restriction if we can ensure that it is safe though, since these
+ * conversions are common when half-float types are involved since many
+ * instructions do not support HF types and conversions from/to F are
+ * required.
+ */
+ if (is_mixed_float_with_fp32_dst(inst))
+ max_width = MIN2(max_width, 8);
+
+ /* From the SKL PRM, Special Restrictions for Handling Mixed Mode
+ * Float Operations:
+ *
+ * "No SIMD16 in mixed mode when destination is packed f16 for both
+ * Align1 and Align16."
+ */
+ if (is_mixed_float_with_packed_fp16_dst(inst))
+ max_width = MIN2(max_width, 8);
+
/* Only power-of-two execution sizes are representable in the instruction
* control fields.
*/
case SHADER_OPCODE_EXP2:
case SHADER_OPCODE_LOG2:
case SHADER_OPCODE_SIN:
- case SHADER_OPCODE_COS:
+ case SHADER_OPCODE_COS: {
/* Unary extended math instructions are limited to SIMD8 on Gen4 and
- * Gen6.
+ * Gen6. Extended Math Function is limited to SIMD8 with half-float.
*/
- return (devinfo->gen >= 7 ? MIN2(16, inst->exec_size) :
- devinfo->gen == 5 || devinfo->is_g4x ? MIN2(16, inst->exec_size) :
- MIN2(8, inst->exec_size));
+ if (devinfo->gen == 6 || (devinfo->gen == 4 && !devinfo->is_g4x))
+ return MIN2(8, inst->exec_size);
+ if (inst->dst.type == BRW_REGISTER_TYPE_HF)
+ return MIN2(8, inst->exec_size);
+ return MIN2(16, inst->exec_size);
+ }
- case SHADER_OPCODE_POW:
- /* SIMD16 is only allowed on Gen7+. */
- return (devinfo->gen >= 7 ? MIN2(16, inst->exec_size) :
- MIN2(8, inst->exec_size));
+ case SHADER_OPCODE_POW: {
+ /* SIMD16 is only allowed on Gen7+. Extended Math Function is limited
+ * to SIMD8 with half-float
+ */
+ if (devinfo->gen < 7)
+ return MIN2(8, inst->exec_size);
+ if (inst->dst.type == BRW_REGISTER_TYPE_HF)
+ return MIN2(8, inst->exec_size);
+ return MIN2(16, inst->exec_size);
+ }
case SHADER_OPCODE_INT_QUOTIENT:
case SHADER_OPCODE_INT_REMAINDER:
case FS_OPCODE_DDX_FINE:
case FS_OPCODE_DDY_COARSE:
case FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD:
- case FS_OPCODE_VARYING_PULL_CONSTANT_LOAD_GEN7:
case FS_OPCODE_PACK_HALF_2x16_SPLIT:
case FS_OPCODE_INTERPOLATE_AT_SAMPLE:
case FS_OPCODE_INTERPOLATE_AT_SHARED_OFFSET:
case SHADER_OPCODE_BYTE_SCATTERED_READ_LOGICAL:
return MIN2(16, inst->exec_size);
+ case SHADER_OPCODE_A64_UNTYPED_WRITE_LOGICAL:
+ case SHADER_OPCODE_A64_UNTYPED_READ_LOGICAL:
+ case SHADER_OPCODE_A64_BYTE_SCATTERED_WRITE_LOGICAL:
+ case SHADER_OPCODE_A64_BYTE_SCATTERED_READ_LOGICAL:
+ return devinfo->gen <= 8 ? 8 : MIN2(16, inst->exec_size);
+
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_LOGICAL:
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_INT64_LOGICAL:
+ case SHADER_OPCODE_A64_UNTYPED_ATOMIC_FLOAT_LOGICAL:
+ return 8;
+
case SHADER_OPCODE_URB_READ_SIMD8:
case SHADER_OPCODE_URB_READ_SIMD8_PER_SLOT:
case SHADER_OPCODE_URB_WRITE_SIMD8:
int iteration = 0;
int pass_num = 0;
+ /* Before anything else, eliminate dead code. The results of some NIR
+ * instructions may effectively be calculated twice. Once when the
+ * instruction is encountered, and again when the user of that result is
+ * encountered. Wipe those away before algebraic optimizations and
+ * especially copy propagation can mix things up.
+ */
+ OPT(dead_code_eliminate);
+
OPT(remove_extra_rounding_modes);
do {
OPT(compact_virtual_grfs);
} while (progress);
+ if (OPT(lower_linterp)) {
+ OPT(opt_copy_propagation);
+ OPT(dead_code_eliminate);
+ }
+
/* Do this after cmod propagation has had every possible opportunity to
* propagate results into SEL instructions.
*/
OPT(lower_simd_width);
}
+ OPT(fixup_sends_duplicate_payload);
+
lower_uniform_pull_constant_loads();
validate();
}
+/**
+ * From the Skylake PRM Vol. 2a docs for sends:
+ *
+ * "It is required that the second block of GRFs does not overlap with the
+ * first block."
+ *
+ * There are plenty of cases where we may accidentally violate this due to
+ * having, for instance, both sources be the constant 0. This little pass
+ * just adds a new vgrf for the second payload and copies it over.
+ */
+bool
+fs_visitor::fixup_sends_duplicate_payload()
+{
+ bool progress = false;
+
+ foreach_block_and_inst_safe (block, fs_inst, inst, cfg) {
+ if (inst->opcode == SHADER_OPCODE_SEND && inst->ex_mlen > 0 &&
+ regions_overlap(inst->src[2], inst->mlen * REG_SIZE,
+ inst->src[3], inst->ex_mlen * REG_SIZE)) {
+ fs_reg tmp = fs_reg(VGRF, alloc.allocate(inst->ex_mlen),
+ BRW_REGISTER_TYPE_UD);
+ /* Sadly, we've lost all notion of channels and bit sizes at this
+ * point. Just WE_all it.
+ */
+ const fs_builder ibld = bld.at(block, inst).exec_all().group(16, 0);
+ fs_reg copy_src = retype(inst->src[3], BRW_REGISTER_TYPE_UD);
+ fs_reg copy_dst = tmp;
+ for (unsigned i = 0; i < inst->ex_mlen; i += 2) {
+ if (inst->ex_mlen == i + 1) {
+ /* Only one register left; do SIMD8 */
+ ibld.group(8, 0).MOV(copy_dst, copy_src);
+ } else {
+ ibld.MOV(copy_dst, copy_src);
+ }
+ copy_src = offset(copy_src, ibld, 1);
+ copy_dst = offset(copy_dst, ibld, 1);
+ }
+ inst->src[3] = tmp;
+ progress = true;
+ }
+ }
+
+ if (progress)
+ invalidate_live_intervals();
+
+ return progress;
+}
+
/**
* Three source instruction must have a GRF/MRF destination register.
* ARF NULL is not allowed. Fix that up by allocating a temporary GRF.
brw_nir_lower_fs_inputs(shader, devinfo, key);
brw_nir_lower_fs_outputs(shader);
- if (devinfo->gen < 6) {
- brw_setup_vue_interpolation(vue_map, shader, prog_data, devinfo);
- }
+ if (devinfo->gen < 6)
+ brw_setup_vue_interpolation(vue_map, shader, prog_data);
if (!key->multisample_fbo)
NIR_PASS_V(shader, demote_sample_qualifiers);
{
nir_shader *shader = nir_shader_clone(mem_ctx, src_shader);
shader = brw_nir_apply_sampler_key(shader, compiler, &key->tex, true);
- brw_nir_lower_cs_intrinsics(shader, dispatch_width);
+
+ NIR_PASS_V(shader, brw_nir_lower_cs_intrinsics, dispatch_width);
+
+ /* Clean up after the local index and ID calculations. */
+ NIR_PASS_V(shader, nir_opt_constant_folding);
+ NIR_PASS_V(shader, nir_opt_dce);
+
return brw_postprocess_nir(shader, compiler, true);
}