tu: avoid memory polling in occlusion query endings using ZPASS_DONE

On newer hardware where ZPASS_DONE events are used for sample count writes
the memory polling in occlusion query endings can be wholly avoided. A WFI
is still required, but the performance gain is still in the range of 10% on
the trivial occlusionquery demo.

Signed-off-by: Zan Dobersek <zdobersek@igalia.com>
Tested-by: Mike Lothian <mike@fireburn.co.uk>
Reviewed-by: Connor Abbott <cwabbott0@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29403>
This commit is contained in:
Zan Dobersek
2024-06-17 18:03:04 +02:00
committed by Marge Bot
parent 5653c52151
commit 9845e99960
+27 -24
View File
@@ -1189,11 +1189,14 @@ emit_end_occlusion_query(struct tu_cmd_buffer *cmdbuf,
uint64_t begin_iova = occlusion_query_iova(pool, query, begin);
uint64_t result_iova = occlusion_query_iova(pool, query, result);
uint64_t end_iova = occlusion_query_iova(pool, query, end);
tu_cs_emit_pkt7(cs, CP_MEM_WRITE, 4);
tu_cs_emit_qw(cs, end_iova);
tu_cs_emit_qw(cs, 0xffffffffffffffffull);
tu_cs_emit_pkt7(cs, CP_WAIT_MEM_WRITES, 0);
if (!cmdbuf->device->physical_device->info->a7xx.has_event_write_sample_count) {
tu_cs_emit_pkt7(cs, CP_MEM_WRITE, 4);
tu_cs_emit_qw(cs, end_iova);
tu_cs_emit_qw(cs, 0xffffffffffffffffull);
tu_cs_emit_pkt7(cs, CP_WAIT_MEM_WRITES, 0);
}
tu_cs_emit_regs(cs,
A6XX_RB_SAMPLE_COUNT_CONTROL(.copy = true));
@@ -1208,6 +1211,24 @@ emit_end_occlusion_query(struct tu_cmd_buffer *cmdbuf,
tu_cs_emit_pkt7(cs, CP_EVENT_WRITE, 1);
tu_cs_emit(cs, CCU_CLEAN_DEPTH);
}
tu_cs_emit_pkt7(cs, CP_WAIT_REG_MEM, 6);
tu_cs_emit(cs, CP_WAIT_REG_MEM_0_FUNCTION(WRITE_NE) |
CP_WAIT_REG_MEM_0_POLL(POLL_MEMORY));
tu_cs_emit_qw(cs, end_iova);
tu_cs_emit(cs, CP_WAIT_REG_MEM_3_REF(0xffffffff));
tu_cs_emit(cs, CP_WAIT_REG_MEM_4_MASK(~0));
tu_cs_emit(cs, CP_WAIT_REG_MEM_5_DELAY_LOOP_CYCLES(16));
/* result (dst) = result (srcA) + end (srcB) - begin (srcC) */
tu_cs_emit_pkt7(cs, CP_MEM_TO_MEM, 9);
tu_cs_emit(cs, CP_MEM_TO_MEM_0_DOUBLE | CP_MEM_TO_MEM_0_NEG_C);
tu_cs_emit_qw(cs, result_iova);
tu_cs_emit_qw(cs, result_iova);
tu_cs_emit_qw(cs, end_iova);
tu_cs_emit_qw(cs, begin_iova);
tu_cs_emit_pkt7(cs, CP_WAIT_MEM_WRITES, 0);
} else {
/* When outside of renderpass, potential autotuner activity can cause
* interference between ZPASS_DONE event pairs. In that case, like at the
@@ -1229,28 +1250,10 @@ emit_end_occlusion_query(struct tu_cmd_buffer *cmdbuf,
.sample_count_end_offset = true,
.write_accum_sample_count_diff = true).value);
tu_cs_emit_qw(cs, begin_iova);
tu_cs_emit_wfi(cs);
}
tu_cs_emit_pkt7(cs, CP_WAIT_REG_MEM, 6);
tu_cs_emit(cs, CP_WAIT_REG_MEM_0_FUNCTION(WRITE_NE) |
CP_WAIT_REG_MEM_0_POLL(POLL_MEMORY));
tu_cs_emit_qw(cs, end_iova);
tu_cs_emit(cs, CP_WAIT_REG_MEM_3_REF(0xffffffff));
tu_cs_emit(cs, CP_WAIT_REG_MEM_4_MASK(~0));
tu_cs_emit(cs, CP_WAIT_REG_MEM_5_DELAY_LOOP_CYCLES(16));
if (!cmdbuf->device->physical_device->info->a7xx.has_event_write_sample_count) {
/* result (dst) = result (srcA) + end (srcB) - begin (srcC) */
tu_cs_emit_pkt7(cs, CP_MEM_TO_MEM, 9);
tu_cs_emit(cs, CP_MEM_TO_MEM_0_DOUBLE | CP_MEM_TO_MEM_0_NEG_C);
tu_cs_emit_qw(cs, result_iova);
tu_cs_emit_qw(cs, result_iova);
tu_cs_emit_qw(cs, end_iova);
tu_cs_emit_qw(cs, begin_iova);
}
tu_cs_emit_pkt7(cs, CP_WAIT_MEM_WRITES, 0);
if (pass)
/* Technically, queries should be tracked per-subpass, but here we track
* at the render pass level to simply the code a bit. This is safe