diff --git a/src/freedreno/decode/cffdec.c b/src/freedreno/decode/cffdec.c index d816d2e7472..e7f7c42f113 100644 --- a/src/freedreno/decode/cffdec.c +++ b/src/freedreno/decode/cffdec.c @@ -1490,6 +1490,67 @@ dump_tex_const(uint32_t *texconst, int num_unit, int level) } } +static void +dump_bindless_descriptors(bool is_compute, int level) +{ + if (!options->dump_bindless) + return; + + printl(2, "%sdraw[%i] bindless descriptors\n", levels[level], draw_count); + + for (unsigned i = 0; i < 128; i++) { + static char reg_name[64]; + if (is_compute) { + sprintf(reg_name, "SP_CS_BINDLESS_BASE[%u].DESCRIPTOR", i); + } else { + sprintf(reg_name, "SP_BINDLESS_BASE[%u].DESCRIPTOR", i); + } + const unsigned base_reg = regbase(reg_name); + if (!base_reg) + break; + + printl(2, "%sset[%u]:\n", levels[level + 1], i); + + uint64_t ext_src_addr; + if (is_64b()) { + const unsigned reg = base_reg + i * 2; + if (!reg_written(reg)) + continue; + + ext_src_addr = reg_val(reg) & 0xfffffffc; + ext_src_addr |= ((uint64_t)reg_val(reg + 1)) << 32; + } else { + const unsigned reg = base_reg + i; + if (!reg_written(reg)) + continue; + + ext_src_addr = reg_val(reg) & 0xfffffffc; + } + + uint32_t *contents = NULL; + if (ext_src_addr) + contents = hostptr(ext_src_addr); + + if (!contents) + continue; + + unsigned length = hostlen(ext_src_addr); + unsigned desc_count = length / (16 * sizeof(uint32_t)); + for (unsigned desc_idx = 0; desc_idx < desc_count; desc_idx++) { + printl(2, "%sUBO[%u]:\n", levels[level + 1], desc_idx); + dump_domain(contents, 2, level + 2, "A6XX_UBO"); + + printl(2, "%sSTORAGE/TEXEL/IMAGE[%u]:\n", levels[level + 1], desc_idx); + dump_tex_const(contents, 1, level); + + printl(2, "%sSAMPLER[%u]:\n", levels[level + 1], desc_idx); + dump_tex_samp(contents, STATE_SRC_BINDLESS, 1, level); + + contents += 16; + } + } +} + static void cp_load_state(uint32_t *dwords, uint32_t sizedwords, int level) { @@ -2027,8 +2088,10 @@ cp_draw_indx(uint32_t *dwords, uint32_t sizedwords, int level) } /* don't bother dumping registers for the dummy draw_indx's.. */ - if (num_indices > 0) + if (num_indices > 0) { + dump_bindless_descriptors(false, level); dump_register_summary(level); + } needs_wfi = true; } @@ -2069,8 +2132,10 @@ cp_draw_indx_2(uint32_t *dwords, uint32_t sizedwords, int level) } /* don't bother dumping registers for the dummy draw_indx's.. */ - if (num_indices > 0) + if (num_indices > 0) { + dump_bindless_descriptors(false, level); dump_register_summary(level); + } } static void @@ -2083,8 +2148,10 @@ cp_draw_indx_offset(uint32_t *dwords, uint32_t sizedwords, int level) print_mode(level); /* don't bother dumping registers for the dummy draw_indx's.. */ - if (num_indices > 0) + if (num_indices > 0) { + dump_bindless_descriptors(false, level); dump_register_summary(level); + } } static void @@ -2108,6 +2175,7 @@ cp_draw_indx_indirect(uint32_t *dwords, uint32_t sizedwords, int level) addr = dwords[3]; dump_gpuaddr_size(addr, level, 0x10, 2); + dump_bindless_descriptors(false, level); dump_register_summary(level); } @@ -2123,6 +2191,7 @@ cp_draw_indirect(uint32_t *dwords, uint32_t sizedwords, int level) addr = (((uint64_t)dwords[2] & 0x1ffff) << 32) | dwords[1]; dump_gpuaddr_size(addr, level, 0x10, 2); + dump_bindless_descriptors(false, level); dump_register_summary(level); } @@ -2182,6 +2251,7 @@ cp_draw_indirect_multi(uint32_t *dwords, uint32_t sizedwords, int level) } } + dump_bindless_descriptors(false, level); dump_register_summary(level); } @@ -2193,6 +2263,7 @@ cp_draw_auto(uint32_t *dwords, uint32_t sizedwords, int level) do_query(rnn_enumname(rnn, "pc_di_primtype", prim_type), 0); print_mode(level); + dump_bindless_descriptors(false, level); dump_register_summary(level); } @@ -2619,6 +2690,7 @@ static void cp_exec_cs(uint32_t *dwords, uint32_t sizedwords, int level) { do_query("compute", 0); + dump_bindless_descriptors(true, level); dump_register_summary(level); } @@ -2637,6 +2709,7 @@ cp_exec_cs_indirect(uint32_t *dwords, uint32_t sizedwords, int level) dump_gpuaddr_size(addr, level, 0x10, 2); do_query("compute", 0); + dump_bindless_descriptors(true, level); dump_register_summary(level); } diff --git a/src/freedreno/decode/cffdec.h b/src/freedreno/decode/cffdec.h index 4a08e2d95d3..95748307cba 100644 --- a/src/freedreno/decode/cffdec.h +++ b/src/freedreno/decode/cffdec.h @@ -35,6 +35,7 @@ struct cffdec_options { int summary; int allregs; int dump_textures; + int dump_bindless; int decode_markers; char *script; diff --git a/src/freedreno/decode/cffdump.c b/src/freedreno/decode/cffdump.c index 64ed7fb357f..030c291a549 100644 --- a/src/freedreno/decode/cffdump.c +++ b/src/freedreno/decode/cffdump.c @@ -67,6 +67,7 @@ print_usage(const char *name) "\t-D, --draw=N - decode only draw N\n" "\t-e, --exe=NAME - only decode cmdstream from named process\n" "\t--textures - dump texture contents (if possible)\n" + "\t--bindless - dump bindless descriptors contents (if possible)\n" "\t-L, --script=LUA - run specified lua script to analyze state\n" "\t-q, --query=REG - query mode, dump only specified query registers on\n" "\t each draw; multiple --query/-q args can be given to\n" @@ -104,6 +105,7 @@ static const struct option opts[] = { { "no-pager", no_argument, &interactive, 0 }, { "pager", no_argument, &interactive, 1 }, { "textures", no_argument, &options.dump_textures, 1 }, + { "bindless", no_argument, &options.dump_bindless, 1 }, { "show-compositor", no_argument, &show_comp, 1 }, { "query-all", no_argument, &options.query_mode, QUERY_ALL }, { "query-written", no_argument, &options.query_mode, QUERY_WRITTEN },