panfrost: Simplify blend lowering pass

Combine depth/stencil writeout redundancy. This simplifies the code and
will allow us to add dual source blend handling without duplicating even
more code.

Signed-off-by: Alyssa Rosenzweig <alyssa@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13714>
This commit is contained in:
Alyssa Rosenzweig 2021-10-29 09:02:37 -04:00 committed by Marge Bot
parent 5c168f09eb
commit e42133aa2f

View file

@ -33,22 +33,62 @@
* +ZS_EMIT with respect to +ATEST and +BLEND, as well as combining
* depth/stencil stores into a single +ZS_EMIT op.
*/
/*
* Get the type to report for a piece of a combined store, given the store it
* is combining from. If there is no store to render target #0, a dummy <0.0,
* 0.0, 0.0, 0.0> write is used, so report a matching float32 type.
*/
static nir_alu_type
pan_nir_rt_store_type(nir_intrinsic_instr *store)
{
return store ? nir_intrinsic_src_type(store) : nir_type_float32;
}
static void
pan_nir_emit_combined_store(nir_builder *b,
nir_intrinsic_instr *rt0_store,
unsigned writeout,
nir_intrinsic_instr **stores)
{
nir_intrinsic_instr *intr = nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_combined_output_pan);
intr->num_components = rt0_store ? rt0_store->src[0].ssa->num_components : 4;
nir_intrinsic_set_src_type(intr, pan_nir_rt_store_type(rt0_store));
nir_intrinsic_set_component(intr, writeout);
nir_ssa_def *zero = nir_imm_int(b, 0);
nir_ssa_def *zero4 = nir_imm_ivec4(b, 0, 0, 0, 0);
nir_ssa_def *src[] = {
rt0_store ? rt0_store->src[0].ssa : zero4,
rt0_store ? rt0_store->src[1].ssa : zero,
stores[0] ? stores[0]->src[0].ssa : zero,
stores[1] ? stores[1]->src[0].ssa : zero,
};
for (int i = 0; i < ARRAY_SIZE(src); ++i)
intr->src[i] = nir_src_for_ssa(src[i]);
nir_builder_instr_insert(b, &intr->instr);
}
bool
pan_nir_lower_zs_store(nir_shader *nir)
{
if (nir->info.stage != MESA_SHADER_FRAGMENT)
return false;
nir_variable *z_var = NULL, *s_var = NULL;
nir_variable *vars[2] = { NULL };
nir_foreach_shader_out_variable(var, nir) {
if (var->data.location == FRAG_RESULT_DEPTH)
z_var = var;
vars[0] = var;
else if (var->data.location == FRAG_RESULT_STENCIL)
s_var = var;
vars[1] = var;
}
if (!z_var && !s_var)
if (!vars[0] && !vars[1])
return false;
bool progress = false;
@ -56,7 +96,7 @@ pan_nir_lower_zs_store(nir_shader *nir)
nir_foreach_function(function, nir) {
if (!function->impl) continue;
nir_intrinsic_instr *z_store = NULL, *s_store = NULL;
nir_intrinsic_instr *stores[2] = { NULL };
nir_foreach_block(block, function->impl) {
nir_foreach_instr_safe(instr, block) {
@ -67,19 +107,37 @@ pan_nir_lower_zs_store(nir_shader *nir)
if (intr->intrinsic != nir_intrinsic_store_output)
continue;
if (z_var && nir_intrinsic_base(intr) == z_var->data.driver_location) {
assert(!z_store);
z_store = intr;
}
if (s_var && nir_intrinsic_base(intr) == s_var->data.driver_location) {
assert(!s_store);
s_store = intr;
for (unsigned i = 0; i < ARRAY_SIZE(vars); ++i) {
if (vars[i] && nir_intrinsic_base(intr) == vars[i]->data.driver_location) {
assert(!stores[i]);
stores[i] = intr;
}
}
}
}
if (!z_store && !s_store) continue;
if (!stores[0] && !stores[1]) continue;
nir_block *common_block = NULL;
/* Ensure all stores are in the same block */
for (unsigned i = 0; i < ARRAY_SIZE(stores); ++i) {
if (!stores[i])
continue;
nir_block *block = stores[i]->instr.block;
if (common_block)
assert(common_block == block);
else
common_block = block;
}
unsigned writeout = 0;
if (stores[0])
writeout |= PAN_WRITEOUT_Z;
if (stores[1])
writeout |= PAN_WRITEOUT_S;
bool replaced = false;
@ -105,39 +163,9 @@ pan_nir_lower_zs_store(nir_shader *nir)
nir_builder b;
nir_builder_init(&b, function->impl);
assert(!z_store || z_store->instr.block == instr->block);
assert(!s_store || s_store->instr.block == instr->block);
b.cursor = nir_after_block_before_jump(instr->block);
nir_intrinsic_instr *combined_store;
combined_store = nir_intrinsic_instr_create(b.shader, nir_intrinsic_store_combined_output_pan);
combined_store->num_components = intr->src[0].ssa->num_components;
nir_intrinsic_set_src_type(combined_store, nir_intrinsic_src_type(intr));
unsigned writeout = PAN_WRITEOUT_C;
if (z_store)
writeout |= PAN_WRITEOUT_Z;
if (s_store)
writeout |= PAN_WRITEOUT_S;
nir_intrinsic_set_component(combined_store, writeout);
struct nir_ssa_def *zero = nir_imm_int(&b, 0);
struct nir_ssa_def *src[4] = {
intr->src[0].ssa,
intr->src[1].ssa,
z_store ? z_store->src[0].ssa : zero,
s_store ? s_store->src[0].ssa : zero,
};
for (int i = 0; i < 4; ++i)
combined_store->src[i] = nir_src_for_ssa(src[i]);
nir_builder_instr_insert(&b, &combined_store->instr);
pan_nir_emit_combined_store(&b, intr, writeout | PAN_WRITEOUT_C, stores);
nir_instr_remove(instr);
@ -149,53 +177,15 @@ pan_nir_lower_zs_store(nir_shader *nir)
if (!replaced) {
nir_builder b;
nir_builder_init(&b, function->impl);
b.cursor = nir_after_block_before_jump(common_block);
nir_block *block = NULL;
if (z_store && s_store)
assert(z_store->instr.block == s_store->instr.block);
if (z_store)
block = z_store->instr.block;
else
block = s_store->instr.block;
b.cursor = nir_after_block_before_jump(block);
nir_intrinsic_instr *combined_store;
combined_store = nir_intrinsic_instr_create(b.shader, nir_intrinsic_store_combined_output_pan);
combined_store->num_components = 4;
nir_intrinsic_set_src_type(combined_store, nir_type_float32);
unsigned writeout = 0;
if (z_store)
writeout |= PAN_WRITEOUT_Z;
if (s_store)
writeout |= PAN_WRITEOUT_S;
nir_intrinsic_set_component(combined_store, writeout);
struct nir_ssa_def *zero = nir_imm_int(&b, 0);
struct nir_ssa_def *src[4] = {
nir_imm_vec4(&b, 0, 0, 0, 0),
zero,
z_store ? z_store->src[0].ssa : zero,
s_store ? s_store->src[0].ssa : zero,
};
for (int i = 0; i < 4; ++i)
combined_store->src[i] = nir_src_for_ssa(src[i]);
nir_builder_instr_insert(&b, &combined_store->instr);
pan_nir_emit_combined_store(&b, NULL, writeout, stores);
}
if (z_store)
nir_instr_remove(&z_store->instr);
if (s_store)
nir_instr_remove(&s_store->instr);
for (unsigned i = 0; i < ARRAY_SIZE(stores); ++i) {
if (stores[i])
nir_instr_remove(&stores[i]->instr);
}
nir_metadata_preserve(function->impl, nir_metadata_block_index | nir_metadata_dominance);
progress = true;