diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_emit.cc b/src/gallium/drivers/freedreno/a6xx/fd6_emit.cc index 478a5ceaa4c..5e3fb31a022 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_emit.cc +++ b/src/gallium/drivers/freedreno/a6xx/fd6_emit.cc @@ -959,6 +959,25 @@ fd6_emit_restore(struct fd_batch *batch, struct fd_ringbuffer *ring) OUT_PKT4(ring, REG_A6XX_SP_PS_TP_BORDER_COLOR_BASE_ADDR, 2); OUT_RELOC(ring, bcolor_mem, 0, 0, 0); + /* There is an optimization to skip executing draw states for draws with no + * instances. Instead of simply skipping the draw, internally the firmware + * sets a bit in PC_DRAW_INITIATOR that seemingly skips the draw. However + * there is a hardware bug where this bit does not always cause the FS + * early preamble to be skipped. Because the draw states were skipped, + * SP_FS_CTRL_REG0, SP_FS_OBJ_START and so on are never updated and a + * random FS preamble from the last draw is executed. If the last visible + * draw is from the same submit, it shouldn't be a problem because we just + * re-execute the same preamble and preambles don't have side effects, but + * if it's from another process then we could execute a garbage preamble + * leading to hangs and faults. To make sure this doesn't happen, we reset + * SP_FS_CTRL_REG0 here, making sure that the EARLYPREAMBLE bit isn't set + * so any leftover early preamble doesn't get executed. Other stages don't + * seem to be affected. + */ + if (screen->info->a6xx.has_early_preamble) { + WRITE(REG_A6XX_SP_FS_CTRL_REG0, 0); + } + if (!batch->nondraw) { trace_end_state_restore(&batch->trace, ring); }