panfrost/midgard: Implement indirect loads of varyings/UBOs

This adds preliminary support for indirect loads of varying arrays and
uniform arrays, bringing a few new tests in shader.indexing.* to
passing, although there remains a number of cases still missing.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
Alyssa Rosenzweig
2019-04-20 23:52:42 +00:00
parent 1f7b3884c9
commit 6a466c0a06
2 changed files with 76 additions and 16 deletions
@@ -991,6 +991,34 @@ emit_condition(compiler_context *ctx, nir_src *src, bool for_branch)
emit_mir_instruction(ctx, ins);
}
/* Likewise, indirect offsets are put in r27.w. TODO: Allow componentwise
* pinning to eliminate this move in all known cases */
static void
emit_indirect_offset(compiler_context *ctx, nir_src *src)
{
int offset = nir_src_index(ctx, src);
midgard_instruction ins = {
.type = TAG_ALU_4,
.ssa_args = {
.src0 = SSA_UNUSED_1,
.src1 = offset,
.dest = SSA_FIXED_REGISTER(REGISTER_OFFSET),
},
.alu = {
.op = midgard_alu_op_imov,
.reg_mode = midgard_reg_mode_full,
.dest_override = midgard_dest_override_none,
.mask = (0x3 << 6), /* w */
.src1 = vector_alu_srco_unsigned(zero_alu_src),
.src2 = vector_alu_srco_unsigned(blank_alu_src_xxxx)
},
};
emit_mir_instruction(ctx, ins);
}
#define ALU_CASE(nir, _op) \
case nir_op_##nir: \
op = midgard_alu_op_##_op; \
@@ -1260,23 +1288,22 @@ emit_alu(compiler_context *ctx, nir_alu_instr *instr)
#undef ALU_CASE
static void
emit_uniform_read(compiler_context *ctx, unsigned dest, unsigned offset)
emit_uniform_read(compiler_context *ctx, unsigned dest, unsigned offset, nir_src *indirect_offset)
{
/* TODO: half-floats */
if (offset < ctx->uniform_cutoff) {
/* Fast path: For the first 16 uniform,
* accesses are 0-cycle, since they're
* just a register fetch in the usual
* case. So, we alias the registers
* while we're still in SSA-space */
if (!indirect_offset && offset < ctx->uniform_cutoff) {
/* Fast path: For the first 16 uniforms, direct accesses are
* 0-cycle, since they're just a register fetch in the usual
* case. So, we alias the registers while we're still in
* SSA-space */
int reg_slot = 23 - offset;
alias_ssa(ctx, dest, SSA_FIXED_REGISTER(reg_slot));
} else {
/* Otherwise, read from the 'special'
* UBO to access higher-indexed
* uniforms, at a performance cost */
/* Otherwise, read from the 'special' UBO to access
* higher-indexed uniforms, at a performance cost. More
* generally, we're emitting a UBO read instruction. */
midgard_instruction ins = m_load_uniform_32(dest, offset);
@@ -1284,7 +1311,13 @@ emit_uniform_read(compiler_context *ctx, unsigned dest, unsigned offset)
ins.load_store.varying_parameters = (offset & 7) << 7;
ins.load_store.address = offset >> 3;
ins.load_store.unknown = 0x1E00; /* xxx: what is this? */
if (indirect_offset) {
emit_indirect_offset(ctx, indirect_offset);
ins.load_store.unknown = 0x8700; /* xxx: what is this? */
} else {
ins.load_store.unknown = 0x1E00; /* xxx: what is this? */
}
emit_mir_instruction(ctx, ins);
}
}
@@ -1302,7 +1335,8 @@ emit_sysval_read(compiler_context *ctx, nir_intrinsic_instr *instr)
/* Sysvals are prefix uniforms */
unsigned uniform = ((uintptr_t) val) - 1;
emit_uniform_read(ctx, dest, uniform);
/* Emit the read itself -- this is never indirect */
emit_uniform_read(ctx, dest, uniform, NULL);
}
static void
@@ -1328,14 +1362,18 @@ emit_intrinsic(compiler_context *ctx, nir_intrinsic_instr *instr)
case nir_intrinsic_load_uniform:
case nir_intrinsic_load_input:
assert(nir_src_is_const(instr->src[0]) && "no indirect inputs");
offset = nir_intrinsic_base(instr);
offset = nir_intrinsic_base(instr) + nir_src_as_uint(instr->src[0]);
bool direct = nir_src_is_const(instr->src[0]);
if (direct) {
offset += nir_src_as_uint(instr->src[0]);
}
reg = nir_dest_index(ctx, &instr->dest);
if (instr->intrinsic == nir_intrinsic_load_uniform && !ctx->is_blend) {
emit_uniform_read(ctx, reg, ctx->sysval_count + offset);
emit_uniform_read(ctx, reg, ctx->sysval_count + offset, !direct ? &instr->src[0] : NULL);
} else if (ctx->stage == MESA_SHADER_FRAGMENT && !ctx->is_blend) {
/* XXX: Half-floats? */
/* TODO: swizzle, mask */
@@ -1352,7 +1390,16 @@ emit_intrinsic(compiler_context *ctx, nir_intrinsic_instr *instr)
memcpy(&u, &p, sizeof(p));
ins.load_store.varying_parameters = u;
ins.load_store.unknown = 0x1e9e; /* xxx: what is this? */
if (direct) {
/* We have the offset totally ready */
ins.load_store.unknown = 0x1e9e; /* xxx: what is this? */
} else {
/* We have it partially ready, but we need to
* add in the dynamic index, moved to r27.w */
emit_indirect_offset(ctx, &instr->src[0]);
ins.load_store.unknown = 0x79e; /* xxx: what is this? */
}
emit_mir_instruction(ctx, ins);
} else if (ctx->is_blend && instr->intrinsic == nir_intrinsic_load_uniform) {
/* Constant encoded as a pinned constant */
@@ -2978,8 +3025,19 @@ midgard_pair_load_store(compiler_context *ctx, midgard_block *block)
if (c->type != TAG_LOAD_STORE_4) continue;
/* Stores cannot be reordered, since they have
* dependencies. For the same reason, indirect
* loads cannot be reordered as their index is
* loaded in r27.w */
if (OP_IS_STORE(c->load_store.op)) continue;
/* It appears the 0x800 bit is set whenever a
* load is direct, unset when it is indirect.
* Skip indirect loads. */
if (!(c->load_store.unknown & 0x800)) continue;
/* We found one! Move it up to pair and remove it from the old location */
mir_insert_instruction_before(ins, *c);
@@ -321,6 +321,8 @@ panfrost_get_shader_param(struct pipe_screen *screen,
case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR:
case PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR:
return 1;
case PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR:
return 0;