diff --git a/src/panfrost/util/pan_lower_writeout.c b/src/panfrost/util/pan_lower_writeout.c index a978d9c3fc7..532c11f4e6c 100644 --- a/src/panfrost/util/pan_lower_writeout.c +++ b/src/panfrost/util/pan_lower_writeout.c @@ -108,6 +108,8 @@ pan_nir_lower_zs_store(nir_shader *nir) nir_foreach_function_impl(impl, nir) { nir_intrinsic_instr *stores[3] = {NULL}; + nir_intrinsic_instr *last_mask_store = NULL; + nir_block *mask_block = NULL; unsigned writeout = 0; nir_foreach_block(block, impl) { @@ -130,14 +132,17 @@ pan_nir_lower_zs_store(nir_shader *nir) assert(!stores[2]); /* there should be only 1 source for dual blending */ stores[2] = intr; writeout |= PAN_WRITEOUT_2; + } else if (sem.location == FRAG_RESULT_SAMPLE_MASK) { + last_mask_store = intr; + mask_block = intr->instr.block; } } } - if (!writeout) + if (!writeout && !last_mask_store) continue; - nir_block *common_block = NULL; + nir_block *common_block = mask_block; /* Ensure all stores are in the same block */ for (unsigned i = 0; i < ARRAY_SIZE(stores); ++i) { @@ -152,6 +157,28 @@ pan_nir_lower_zs_store(nir_shader *nir) common_block = block; } + /* move data stores in the common block to after the last mask store */ + if (last_mask_store) { + nir_cursor insert_point = nir_after_instr(&last_mask_store->instr); + nir_foreach_instr_safe(instr, mask_block) { + if (instr->type != nir_instr_type_intrinsic) + continue; + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + + /* stop when we've reached the last store to mask */ + if (intr == last_mask_store) + break; + if (intr->intrinsic != nir_intrinsic_store_output) + continue; + nir_io_semantics sem = nir_intrinsic_io_semantics(intr); + if (sem.location >= FRAG_RESULT_DATA0 && + sem.location <= FRAG_RESULT_DATA7) { + nir_instr_move(insert_point, instr); + insert_point = nir_after_instr(instr); + } + } + } + bool replaced = false; nir_foreach_block(block, impl) {