diff --git a/src/panfrost/vulkan/csf/panvk_vX_utrace.c b/src/panfrost/vulkan/csf/panvk_vX_utrace.c index 93fe84adb63..59c768a2064 100644 --- a/src/panfrost/vulkan/csf/panvk_vX_utrace.c +++ b/src/panfrost/vulkan/csf/panvk_vX_utrace.c @@ -16,7 +16,10 @@ static void cmd_write_timestamp(const struct panvk_device *dev, struct cs_builder *b, uint64_t addr, struct cs_async_op ts_async_op) { - const struct cs_index addr_reg = cs_scratch_reg64(b, 0); + /* Unless we dedicate a register, this will potentially overwrite something + * during begin/end. */ + const struct cs_index addr_reg = + cs_scratch_reg64(b, CS_REG_SCRATCH_COUNT - 2); /* Overwrite the signal_slot. Note that this has no effect in case of * synchronous or indirect syncs. */ @@ -74,6 +77,44 @@ cmd_copy_data(struct cs_builder *b, uint64_t dst_addr, uint64_t src_addr, } } +static void +cmd_store_regs(struct cs_builder *b, uint64_t dst_addr, uint64_t src_addr, + uint32_t size, bool wait_for_timestamp) +{ + assert((dst_addr | size) % sizeof(uint32_t) == 0); + uint32_t num_regs = size / sizeof(uint32_t); + assert(num_regs <= CS_MAX_REG_TUPLE_SIZE); + assert(src_addr + num_regs <= PANVK_CS_REG_SCRATCH_END); + + if (wait_for_timestamp) + cs_wait_slot(b, SB_ID(DEFERRED_SYNC)); + + bool valid_dst_regs = false; + struct cs_index dst_addr_reg; + /* Unless we dedicate a register, this will potentially overwrite + * something during indirect capture. For now, we only ensure we don't + * corrupt the registers we're capturing. */ + for (uint32_t dst_scratch_base = PANVK_CS_REG_SCRATCH_END - 1; + dst_scratch_base >= PANVK_CS_REG_SCRATCH_START; dst_scratch_base -= 2) { + if (src_addr + num_regs <= dst_scratch_base || + dst_scratch_base + 2 <= src_addr) { + dst_addr_reg = + cs_scratch_reg64(b, dst_scratch_base - PANVK_CS_REG_SCRATCH_START); + valid_dst_regs = true; + break; + } + } + + if (!valid_dst_regs) { + assert(!"No unused scratch registers found"); + return; + } + + const struct cs_index src_addr_reg = cs_reg_tuple(b, src_addr, num_regs); + cs_move64_to(b, dst_addr_reg, dst_addr); + cs_store(b, src_addr_reg, dst_addr_reg, BITFIELD_MASK(num_regs), 0); +} + static struct cs_builder * get_builder(struct panvk_cmd_buffer *cmdbuf, struct u_trace *ut) { @@ -112,11 +153,16 @@ panvk_utrace_capture_data(struct u_trace *ut, void *cs, void *dst_buffer, const uint64_t dst_addr = dst_bo->addr.dev + dst_offset_B; const uint64_t src_addr = src_offset_B; - /* src_offset_B is absolute */ - assert(!src_buffer); + /* src_offset_B is absolute, src_buffer is used to indicate register capture */ + assert(!src_buffer || + (uintptr_t)src_buffer == PANVK_UTRACE_CAPTURE_REGISTERS); - cmd_copy_data(b, dst_addr, src_addr, size_B, - cs_info->capture_data_wait_for_ts); + if ((uintptr_t)src_buffer == PANVK_UTRACE_CAPTURE_REGISTERS) + cmd_store_regs(b, dst_addr, src_addr, size_B, + cs_info->capture_data_wait_for_ts); + else + cmd_copy_data(b, dst_addr, src_addr, size_B, + cs_info->capture_data_wait_for_ts); } void diff --git a/src/panfrost/vulkan/panvk_utrace.h b/src/panfrost/vulkan/panvk_utrace.h index 13d1f1384af..a0783fabc8c 100644 --- a/src/panfrost/vulkan/panvk_utrace.h +++ b/src/panfrost/vulkan/panvk_utrace.h @@ -49,6 +49,10 @@ struct panvk_utrace_cs_info { bool capture_data_wait_for_ts; }; +/* Special value indicating that an indirect capture should be of registers + * rather than an address. */ +#define PANVK_UTRACE_CAPTURE_REGISTERS 0x1 + void panvk_per_arch(utrace_context_init)(struct panvk_device *dev); void panvk_per_arch(utrace_context_fini)(struct panvk_device *dev);