diff --git a/src/asahi/lib/agx_bo.c b/src/asahi/lib/agx_bo.c index dec4256bacd..c51319efcab 100644 --- a/src/asahi/lib/agx_bo.c +++ b/src/asahi/lib/agx_bo.c @@ -192,7 +192,7 @@ agx_bo_unreference(struct agx_bo *bo) assert(!p_atomic_read_relaxed(&bo->writer_syncobj)); if (dev->debug & AGX_DBG_TRACE) - agxdecode_track_free(bo); + agxdecode_track_free(dev->agxdecode, bo); if (!agx_bo_cache_put(bo)) agx_bo_free(dev, bo); @@ -242,7 +242,7 @@ agx_bo_create_aligned(struct agx_device *dev, unsigned size, unsigned align, p_atomic_set(&bo->refcnt, 1); if (dev->debug & AGX_DBG_TRACE) - agxdecode_track_alloc(bo); + agxdecode_track_alloc(dev->agxdecode, bo); return bo; } diff --git a/src/asahi/lib/agx_device.c b/src/asahi/lib/agx_device.c index e5e8f7e9ea0..7caedd5d6c5 100644 --- a/src/asahi/lib/agx_device.c +++ b/src/asahi/lib/agx_device.c @@ -338,6 +338,8 @@ agx_open_device(void *memctx, struct agx_device *dev) dev->debug = debug_get_flags_option("ASAHI_MESA_DEBUG", agx_debug_options, 0); + dev->agxdecode = agxdecode_new_context(); + ssize_t params_size = -1; /* TODO: Linux UAPI */ @@ -391,6 +393,7 @@ agx_close_device(struct agx_device *dev) agx_bo_unreference(dev->helper); agx_bo_cache_evict_all(dev); util_sparse_array_finish(&dev->bo_map); + agxdecode_destroy_context(dev->agxdecode); util_vma_heap_finish(&dev->main_heap); util_vma_heap_finish(&dev->usc_heap); diff --git a/src/asahi/lib/agx_device.h b/src/asahi/lib/agx_device.h index 6de83be68c6..65cb918a793 100644 --- a/src/asahi/lib/agx_device.h +++ b/src/asahi/lib/agx_device.h @@ -11,6 +11,7 @@ #include "util/vma.h" #include "agx_bo.h" #include "agx_formats.h" +#include "decode.h" enum agx_dbg { AGX_DBG_TRACE = BITFIELD_BIT(0), @@ -121,6 +122,8 @@ struct agx_device { } bo_cache; struct agx_bo *helper; + + struct agxdecode_ctx *agxdecode; }; bool agx_open_device(void *memctx, struct agx_device *dev); diff --git a/src/asahi/lib/decode.c b/src/asahi/lib/decode.c index 11e12d2f964..f8230fa7b92 100644 --- a/src/asahi/lib/decode.c +++ b/src/asahi/lib/decode.c @@ -11,6 +11,8 @@ #include #include #include +#include "util/u_dynarray.h" +#include "util/u_math.h" #include #include @@ -43,35 +45,46 @@ FILE *agxdecode_dump_stream; #define MAX_MAPPINGS 4096 -struct agx_bo mmap_array[MAX_MAPPINGS]; -unsigned mmap_count = 0; +struct agxdecode_ctx { + struct util_dynarray mmap_array; + struct util_dynarray ro_mappings; +}; -struct agx_bo *ro_mappings[MAX_MAPPINGS]; -unsigned ro_mapping_count = 0; +struct agxdecode_ctx * +agxdecode_new_context(void) +{ + return calloc(1, sizeof(struct agxdecode_ctx)); +} + +void +agxdecode_destroy_context(struct agxdecode_ctx *ctx) +{ + free(ctx); +} static struct agx_bo * -agxdecode_find_mapped_gpu_mem_containing_rw(uint64_t addr) +agxdecode_find_mapped_gpu_mem_containing_rw(struct agxdecode_ctx *ctx, + uint64_t addr) { - for (unsigned i = 0; i < mmap_count; ++i) { - if (mmap_array[i].type == AGX_ALLOC_REGULAR && - addr >= mmap_array[i].ptr.gpu && - (addr - mmap_array[i].ptr.gpu) < mmap_array[i].size) - return mmap_array + i; + util_dynarray_foreach(&ctx->mmap_array, struct agx_bo, it) { + if (it->type == AGX_ALLOC_REGULAR && addr >= it->ptr.gpu && + (addr - it->ptr.gpu) < it->size) + return it; } return NULL; } static struct agx_bo * -agxdecode_find_mapped_gpu_mem_containing(uint64_t addr) +agxdecode_find_mapped_gpu_mem_containing(struct agxdecode_ctx *ctx, + uint64_t addr) { - struct agx_bo *mem = agxdecode_find_mapped_gpu_mem_containing_rw(addr); + struct agx_bo *mem = agxdecode_find_mapped_gpu_mem_containing_rw(ctx, addr); if (mem && mem->ptr.cpu && !mem->ro) { mprotect(mem->ptr.cpu, mem->size, PROT_READ); mem->ro = true; - ro_mappings[ro_mapping_count++] = mem; - assert(ro_mapping_count < MAX_MAPPINGS); + util_dynarray_append(&ctx->ro_mappings, struct agx_bo *, mem); } if (mem && !mem->mapped) { @@ -85,25 +98,25 @@ agxdecode_find_mapped_gpu_mem_containing(uint64_t addr) } static struct agx_bo * -agxdecode_find_handle(unsigned handle, unsigned type) +agxdecode_find_handle(struct agxdecode_ctx *ctx, unsigned handle, unsigned type) { - for (unsigned i = 0; i < mmap_count; ++i) { - if (mmap_array[i].type != type) + util_dynarray_foreach(&ctx->mmap_array, struct agx_bo, it) { + if (it->type != type) continue; - if (mmap_array[i].handle != handle) + if (it->handle != handle) continue; - return &mmap_array[i]; + return it; } return NULL; } static void -agxdecode_mark_mapped(unsigned handle) +agxdecode_mark_mapped(struct agxdecode_ctx *ctx, unsigned handle) { - struct agx_bo *bo = agxdecode_find_handle(handle, AGX_ALLOC_REGULAR); + struct agx_bo *bo = agxdecode_find_handle(ctx, handle, AGX_ALLOC_REGULAR); if (!bo) { fprintf(stderr, "ERROR - unknown BO mapped with handle %u\n", handle); @@ -117,13 +130,14 @@ agxdecode_mark_mapped(unsigned handle) #ifdef __APPLE__ static void -agxdecode_decode_segment_list(void *segment_list) +agxdecode_decode_segment_list(struct agxdecode_ctx *ctx, void *segment_list) { unsigned nr_handles = 0; /* First, mark everything unmapped */ - for (unsigned i = 0; i < mmap_count; ++i) - mmap_array[i].mapped = false; + util_dynarray_foreach(&ctx->mmap_array, struct agx_bo, it) { + it->mapped = false; + } /* Check the header */ struct agx_map_header *hdr = segment_list; @@ -211,15 +225,15 @@ agxdecode_decode_segment_list(void *segment_list) #endif static size_t -__agxdecode_fetch_gpu_mem(const struct agx_bo *mem, uint64_t gpu_va, - size_t size, void *buf, int line, +__agxdecode_fetch_gpu_mem(struct agxdecode_ctx *ctx, const struct agx_bo *mem, + uint64_t gpu_va, size_t size, void *buf, int line, const char *filename) { if (lib_config.read_gpu_mem) return lib_config.read_gpu_mem(gpu_va, size, buf); if (!mem) - mem = agxdecode_find_mapped_gpu_mem_containing(gpu_va); + mem = agxdecode_find_mapped_gpu_mem_containing(ctx, gpu_va); if (!mem) { fprintf(stderr, "Access to unknown memory %" PRIx64 " in %s:%d\n", gpu_va, @@ -245,22 +259,21 @@ __agxdecode_fetch_gpu_mem(const struct agx_bo *mem, uint64_t gpu_va, return size; } -#define agxdecode_fetch_gpu_mem(gpu_va, size, buf) \ - __agxdecode_fetch_gpu_mem(NULL, gpu_va, size, buf, __LINE__, __FILE__) +#define agxdecode_fetch_gpu_mem(ctx, gpu_va, size, buf) \ + __agxdecode_fetch_gpu_mem(ctx, NULL, gpu_va, size, buf, __LINE__, __FILE__) -#define agxdecode_fetch_gpu_array(gpu_va, buf) \ - agxdecode_fetch_gpu_mem(gpu_va, sizeof(buf), buf) +#define agxdecode_fetch_gpu_array(ctx, gpu_va, buf) \ + agxdecode_fetch_gpu_mem(ctx, gpu_va, sizeof(buf), buf) static void -agxdecode_map_read_write(void) +agxdecode_map_read_write(struct agxdecode_ctx *ctx) { - for (unsigned i = 0; i < ro_mapping_count; ++i) { - ro_mappings[i]->ro = false; - mprotect(ro_mappings[i]->ptr.cpu, ro_mappings[i]->size, - PROT_READ | PROT_WRITE); + util_dynarray_foreach(&ctx->ro_mappings, struct agx_bo *, it) { + (*it)->ro = false; + mprotect((*it)->ptr.cpu, (*it)->size, PROT_READ | PROT_WRITE); } - ro_mapping_count = 0; + util_dynarray_clear(&ctx->ro_mappings); } /* Helpers for parsing the cmdstream */ @@ -268,7 +281,7 @@ agxdecode_map_read_write(void) #define DUMP_UNPACKED(T, var, str) \ { \ agxdecode_log(str); \ - agx_print(agxdecode_dump_stream, T, var, (agxdecode_indent + 1) * 2); \ + agx_print(agxdecode_dump_stream, T, var, 2); \ } #define DUMP_CL(T, cl, str) \ @@ -280,12 +293,11 @@ agxdecode_map_read_write(void) #define agxdecode_log(str) fputs(str, agxdecode_dump_stream) #define agxdecode_msg(str) fprintf(agxdecode_dump_stream, "// %s", str) -unsigned agxdecode_indent = 0; - typedef struct drm_asahi_params_global decoder_params; /* Abstraction for command stream parsing */ -typedef unsigned (*decode_cmd)(const uint8_t *map, uint64_t *link, bool verbose, +typedef unsigned (*decode_cmd)(struct agxdecode_ctx *ctx, const uint8_t *map, + uint64_t *link, bool verbose, decoder_params *params, void *data); #define STATE_DONE (0xFFFFFFFFu) @@ -294,8 +306,9 @@ typedef unsigned (*decode_cmd)(const uint8_t *map, uint64_t *link, bool verbose, #define STATE_RET (0xFFFFFFFCu) static void -agxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder, - bool verbose, decoder_params *params, void *data) +agxdecode_stateful(struct agxdecode_ctx *ctx, uint64_t va, const char *label, + decode_cmd decoder, bool verbose, decoder_params *params, + void *data) { uint64_t stack[16]; unsigned sp = 0; @@ -303,7 +316,7 @@ agxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder, uint8_t buf[1024]; size_t size = sizeof(buf); if (!lib_config.read_gpu_mem) { - struct agx_bo *alloc = agxdecode_find_mapped_gpu_mem_containing(va); + struct agx_bo *alloc = agxdecode_find_mapped_gpu_mem_containing(ctx, va); assert(alloc != NULL && "nonexistent object"); fprintf(agxdecode_dump_stream, "%s (%" PRIx64 ", handle %u)\n", label, va, alloc->handle); @@ -313,7 +326,7 @@ agxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder, } fflush(agxdecode_dump_stream); - int len = agxdecode_fetch_gpu_mem(va, size, buf); + int len = agxdecode_fetch_gpu_mem(ctx, va, size, buf); int left = len; uint8_t *map = buf; @@ -328,7 +341,7 @@ agxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder, return; } - unsigned count = decoder(map, &link, verbose, params, data); + unsigned count = decoder(ctx, map, &link, verbose, params, data); /* If we fail to decode, default to a hexdump (don't hang) */ if (count == 0) { @@ -342,7 +355,7 @@ agxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder, } else if (count == STATE_LINK) { fprintf(agxdecode_dump_stream, "Linking to 0x%" PRIx64 "\n\n", link); va = link; - left = len = agxdecode_fetch_gpu_array(va, buf); + left = len = agxdecode_fetch_gpu_array(ctx, va, buf); map = buf; } else if (count == STATE_CALL) { fprintf(agxdecode_dump_stream, @@ -351,13 +364,13 @@ agxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder, assert(sp < ARRAY_SIZE(stack)); stack[sp++] = va + 8; va = link; - left = len = agxdecode_fetch_gpu_array(va, buf); + left = len = agxdecode_fetch_gpu_array(ctx, va, buf); map = buf; } else if (count == STATE_RET) { assert(sp > 0); va = stack[--sp]; fprintf(agxdecode_dump_stream, "Returning to 0x%" PRIx64 "\n\n", va); - left = len = agxdecode_fetch_gpu_array(va, buf); + left = len = agxdecode_fetch_gpu_array(ctx, va, buf); map = buf; } else { va += count; @@ -365,15 +378,45 @@ agxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder, left -= count; if (left < 512 && len == sizeof(buf)) { - left = len = agxdecode_fetch_gpu_array(va, buf); + left = len = agxdecode_fetch_gpu_array(ctx, va, buf); map = buf; } } } } +static void +agxdecode_texture_pbe(struct agxdecode_ctx *ctx, const void *map) +{ + struct AGX_TEXTURE tex; + struct AGX_PBE pbe; + + bool valid_texture = AGX_TEXTURE_unpack(NULL, map, &tex); + bool valid_pbe = AGX_PBE_unpack(NULL, map, &pbe); + + /* Try to guess if it's texture or PBE */ + valid_texture &= + tex.swizzle_r <= AGX_CHANNEL_0 && tex.swizzle_g <= AGX_CHANNEL_0 && + tex.swizzle_b <= AGX_CHANNEL_0 && tex.swizzle_a <= AGX_CHANNEL_0; + + if (valid_texture && !valid_pbe) { + DUMP_CL(TEXTURE, map, "Texture"); + } else if (valid_pbe && !valid_texture) { + DUMP_CL(PBE, map, "PBE"); + } else { + if (!valid_texture) { + assert(!valid_pbe); + fprintf(agxdecode_dump_stream, "XXX: invalid texture/PBE\n"); + } + + DUMP_CL(TEXTURE, map, "Texture"); + DUMP_CL(PBE, map, "PBE"); + } +} + static unsigned -agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose, +agxdecode_usc(struct agxdecode_ctx *ctx, const uint8_t *map, + UNUSED uint64_t *link, UNUSED bool verbose, decoder_params *params, UNUSED void *data) { enum agx_sampler_states *sampler_states = data; @@ -401,7 +444,7 @@ agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose, agx_unpack(agxdecode_dump_stream, map, USC_PRESHADER, ctrl); DUMP_UNPACKED(USC_PRESHADER, ctrl, "Preshader\n"); - agx_disassemble(buf, agxdecode_fetch_gpu_array(ctrl.code, buf), + agx_disassemble(buf, agxdecode_fetch_gpu_array(ctx, ctrl.code, buf), agxdecode_dump_stream); return STATE_DONE; @@ -412,7 +455,7 @@ agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose, DUMP_UNPACKED(USC_SHADER, ctrl, "Shader\n"); agxdecode_log("\n"); - agx_disassemble(buf, agxdecode_fetch_gpu_array(ctrl.code, buf), + agx_disassemble(buf, agxdecode_fetch_gpu_array(ctx, ctrl.code, buf), agxdecode_dump_stream); agxdecode_log("\n"); @@ -427,7 +470,7 @@ agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose, AGX_SAMPLER_LENGTH + (extended_samplers ? AGX_BORDER_LENGTH : 0); uint8_t *samp = alloca(stride * temp.count); - agxdecode_fetch_gpu_mem(temp.buffer, stride * temp.count, samp); + agxdecode_fetch_gpu_mem(ctx, temp.buffer, stride * temp.count, samp); for (unsigned i = 0; i < temp.count; ++i) { DUMP_CL(SAMPLER, samp, "Sampler"); @@ -449,13 +492,12 @@ agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose, uint8_t buf[AGX_TEXTURE_LENGTH * temp.count]; uint8_t *tex = buf; - agxdecode_fetch_gpu_array(temp.buffer, buf); + agxdecode_fetch_gpu_array(ctx, temp.buffer, buf); /* Note: samplers only need 8 byte alignment? */ for (unsigned i = 0; i < temp.count; ++i) { - agx_unpack(agxdecode_dump_stream, tex, TEXTURE, t); - DUMP_CL(TEXTURE, tex, "Texture"); - DUMP_CL(PBE, tex, "PBE"); + fprintf(agxdecode_dump_stream, "ts%u: \n", temp.start + i); + agxdecode_texture_pbe(ctx, tex); tex += AGX_TEXTURE_LENGTH; } @@ -468,7 +510,7 @@ agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose, DUMP_UNPACKED(USC_UNIFORM, temp, "Uniform\n"); uint8_t buf[2 * temp.size_halfs]; - agxdecode_fetch_gpu_array(temp.buffer, buf); + agxdecode_fetch_gpu_array(ctx, temp.buffer, buf); u_hexdump(agxdecode_dump_stream, buf, 2 * temp.size_halfs, false); return AGX_USC_UNIFORM_LENGTH; @@ -479,7 +521,7 @@ agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose, DUMP_UNPACKED(USC_UNIFORM_HIGH, temp, "Uniform (high)\n"); uint8_t buf[2 * temp.size_halfs]; - agxdecode_fetch_gpu_array(temp.buffer, buf); + agxdecode_fetch_gpu_array(ctx, temp.buffer, buf); u_hexdump(agxdecode_dump_stream, buf, 2 * temp.size_halfs, false); return AGX_USC_UNIFORM_HIGH_LENGTH; @@ -510,13 +552,14 @@ agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose, } static void -agxdecode_record(uint64_t va, size_t size, bool verbose, decoder_params *params) +agxdecode_record(struct agxdecode_ctx *ctx, uint64_t va, size_t size, + bool verbose, decoder_params *params) { uint8_t buf[size]; uint8_t *base = buf; uint8_t *map = base; - agxdecode_fetch_gpu_array(va, buf); + agxdecode_fetch_gpu_array(ctx, va, buf); agx_unpack(agxdecode_dump_stream, map, PPP_HEADER, hdr); map += AGX_PPP_HEADER_LENGTH; @@ -571,14 +614,14 @@ agxdecode_record(uint64_t va, size_t size, bool verbose, decoder_params *params) if (hdr.fragment_shader) { agx_unpack(agxdecode_dump_stream, map, FRAGMENT_SHADER, frag); - agxdecode_stateful(frag.pipeline, "Fragment pipeline", agxdecode_usc, + agxdecode_stateful(ctx, frag.pipeline, "Fragment pipeline", agxdecode_usc, verbose, params, &frag.sampler_state_register_count); if (frag.cf_bindings) { uint8_t buf[128]; uint8_t *cf = buf; - agxdecode_fetch_gpu_array(frag.cf_bindings, buf); + agxdecode_fetch_gpu_array(ctx, frag.cf_bindings, buf); u_hexdump(agxdecode_dump_stream, cf, 128, false); DUMP_CL(CF_BINDING_HEADER, cf, "Coefficient binding header:"); @@ -606,8 +649,8 @@ agxdecode_record(uint64_t va, size_t size, bool verbose, decoder_params *params) } static unsigned -agxdecode_cdm(const uint8_t *map, uint64_t *link, bool verbose, - decoder_params *params, UNUSED void *data) +agxdecode_cdm(struct agxdecode_ctx *ctx, const uint8_t *map, uint64_t *link, + bool verbose, decoder_params *params, UNUSED void *data) { /* Bits 29-31 contain the block type */ enum agx_cdm_block_type block_type = (map[3] >> 5); @@ -624,7 +667,7 @@ agxdecode_cdm(const uint8_t *map, uint64_t *link, bool verbose, } while (0); agx_unpack(agxdecode_dump_stream, map, CDM_LAUNCH, hdr); - agxdecode_stateful(hdr.pipeline, "Pipeline", agxdecode_usc, verbose, + agxdecode_stateful(ctx, hdr.pipeline, "Pipeline", agxdecode_usc, verbose, params, &hdr.sampler_state_register_count); DUMP_UNPACKED(CDM_LAUNCH, hdr, "Compute\n"); map += AGX_CDM_LAUNCH_LENGTH; @@ -679,8 +722,8 @@ agxdecode_cdm(const uint8_t *map, uint64_t *link, bool verbose, } static unsigned -agxdecode_vdm(const uint8_t *map, uint64_t *link, bool verbose, - decoder_params *params, UNUSED void *data) +agxdecode_vdm(struct agxdecode_ctx *ctx, const uint8_t *map, uint64_t *link, + bool verbose, decoder_params *params, UNUSED void *data) { /* Bits 29-31 contain the block type */ enum agx_vdm_block_type block_type = (map[3] >> 5); @@ -698,7 +741,8 @@ agxdecode_vdm(const uint8_t *map, uint64_t *link, bool verbose, uint64_t address = (((uint64_t)cmd.pointer_hi) << 32) | cmd.pointer_lo; if (!lib_config.read_gpu_mem) { - struct agx_bo *mem = agxdecode_find_mapped_gpu_mem_containing(address); + struct agx_bo *mem = + agxdecode_find_mapped_gpu_mem_containing(ctx, address); if (!mem) { DUMP_UNPACKED(PPP_STATE, cmd, "Non-existent record (XXX)\n"); @@ -706,7 +750,7 @@ agxdecode_vdm(const uint8_t *map, uint64_t *link, bool verbose, } } - agxdecode_record(address, cmd.size_words * 4, verbose, params); + agxdecode_record(ctx, address, cmd.size_words * 4, verbose, params); return AGX_PPP_STATE_LENGTH; } @@ -741,8 +785,8 @@ agxdecode_vdm(const uint8_t *map, uint64_t *link, bool verbose, word_1); fprintf(agxdecode_dump_stream, "Pipeline %X\n", (uint32_t)word_1.pipeline); - agxdecode_stateful(word_1.pipeline, "Pipeline", agxdecode_usc, verbose, - params, &sampler_states); + agxdecode_stateful(ctx, word_1.pipeline, "Pipeline", agxdecode_usc, + verbose, params, &sampler_states); } VDM_PRINT(vertex_shader_word_1, VERTEX_SHADER_WORD_1, @@ -827,54 +871,110 @@ agxdecode_vdm(const uint8_t *map, uint64_t *link, bool verbose, } static void -agxdecode_cs(uint32_t *cmdbuf, uint64_t encoder, bool verbose, - decoder_params *params) +agxdecode_cs(struct agxdecode_ctx *ctx, uint32_t *cmdbuf, uint64_t encoder, + bool verbose, decoder_params *params) { agx_unpack(agxdecode_dump_stream, cmdbuf + 16, IOGPU_COMPUTE, cs); DUMP_UNPACKED(IOGPU_COMPUTE, cs, "Compute\n"); - agxdecode_stateful(encoder, "Encoder", agxdecode_cdm, verbose, params, NULL); + agxdecode_stateful(ctx, encoder, "Encoder", agxdecode_cdm, verbose, params, + NULL); fprintf(agxdecode_dump_stream, "Context switch program:\n"); uint8_t buf[1024]; - agx_disassemble(buf, - agxdecode_fetch_gpu_array(cs.context_switch_program, buf), - agxdecode_dump_stream); + agx_disassemble( + buf, agxdecode_fetch_gpu_array(ctx, cs.context_switch_program, buf), + agxdecode_dump_stream); } static void -agxdecode_gfx(uint32_t *cmdbuf, uint64_t encoder, bool verbose, - decoder_params *params) +agxdecode_gfx(struct agxdecode_ctx *ctx, uint32_t *cmdbuf, uint64_t encoder, + bool verbose, decoder_params *params) { agx_unpack(agxdecode_dump_stream, cmdbuf + 16, IOGPU_GRAPHICS, gfx); DUMP_UNPACKED(IOGPU_GRAPHICS, gfx, "Graphics\n"); - agxdecode_stateful(encoder, "Encoder", agxdecode_vdm, verbose, params, NULL); + agxdecode_stateful(ctx, encoder, "Encoder", agxdecode_vdm, verbose, params, + NULL); if (gfx.clear_pipeline_unk) { fprintf(agxdecode_dump_stream, "Unk: %X\n", gfx.clear_pipeline_unk); - agxdecode_stateful(gfx.clear_pipeline, "Clear pipeline", agxdecode_usc, - verbose, params, NULL); + agxdecode_stateful(ctx, gfx.clear_pipeline, "Clear pipeline", + agxdecode_usc, verbose, params, NULL); } if (gfx.store_pipeline_unk) { assert(gfx.store_pipeline_unk == 0x4); - agxdecode_stateful(gfx.store_pipeline, "Store pipeline", agxdecode_usc, - verbose, params, NULL); + agxdecode_stateful(ctx, gfx.store_pipeline, "Store pipeline", + agxdecode_usc, verbose, params, NULL); } assert((gfx.partial_reload_pipeline_unk & 0xF) == 0x4); if (gfx.partial_reload_pipeline) { - agxdecode_stateful(gfx.partial_reload_pipeline, "Partial reload pipeline", - agxdecode_usc, verbose, params, NULL); + agxdecode_stateful(ctx, gfx.partial_reload_pipeline, + "Partial reload pipeline", agxdecode_usc, verbose, + params, NULL); } if (gfx.partial_store_pipeline) { - agxdecode_stateful(gfx.partial_store_pipeline, "Partial store pipeline", - agxdecode_usc, verbose, params, NULL); + agxdecode_stateful(ctx, gfx.partial_store_pipeline, + "Partial store pipeline", agxdecode_usc, verbose, + params, NULL); } } +static void +agxdecode_sampler_heap(struct agxdecode_ctx *ctx, uint64_t heap, unsigned count) +{ + if (!heap) + return; + + struct agx_sampler_packed samp[1024]; + agxdecode_fetch_gpu_array(ctx, heap, samp); + + for (unsigned i = 0; i < count; ++i) { + bool nonzero = false; + for (unsigned j = 0; j < ARRAY_SIZE(samp[i].opaque); ++j) { + nonzero |= samp[i].opaque[j] != 0; + } + + if (nonzero) { + fprintf(agxdecode_dump_stream, "Heap sampler %u\n", i); + + agx_unpack(agxdecode_dump_stream, samp + i, SAMPLER, temp); + agx_print(agxdecode_dump_stream, SAMPLER, temp, 2); + } + } +} + +void +agxdecode_image_heap(struct agxdecode_ctx *ctx, uint64_t heap, + unsigned nr_entries) +{ + agxdecode_dump_file_open(); + + fprintf(agxdecode_dump_stream, "Image heap:\n"); + struct agx_texture_packed *map = calloc(nr_entries, AGX_TEXTURE_LENGTH); + agxdecode_fetch_gpu_mem(ctx, heap, AGX_TEXTURE_LENGTH * nr_entries, map); + + for (unsigned i = 0; i < nr_entries; ++i) { + bool nonzero = false; + for (unsigned j = 0; j < ARRAY_SIZE(map[i].opaque); ++j) { + nonzero |= map[i].opaque[j] != 0; + } + + if (nonzero) { + fprintf(agxdecode_dump_stream, "%u: \n", i); + agxdecode_texture_pbe(ctx, map + i); + fprintf(agxdecode_dump_stream, "\n"); + } + } + + free(map); + + agxdecode_map_read_write(ctx); +} + static void chip_id_to_params(decoder_params *params, uint32_t chip_id) { @@ -918,7 +1018,8 @@ chip_id_to_params(decoder_params *params, uint32_t chip_id) #ifdef __APPLE__ void -agxdecode_cmdstream(unsigned cmdbuf_handle, unsigned map_handle, bool verbose) +agxdecode_cmdstream(struct agxdecode_ctx *ctx, unsigned cmdbuf_handle, + unsigned map_handle, bool verbose) { agxdecode_dump_file_open(); @@ -960,7 +1061,7 @@ agxdecode_cmdstream(unsigned cmdbuf_handle, unsigned map_handle, bool verbose) } void -agxdecode_dump_mappings(unsigned map_handle) +agxdecode_dump_mappings(struct agxdecode_ctx *ctx, unsigned map_handle) { agxdecode_dump_file_open(); @@ -968,20 +1069,17 @@ agxdecode_dump_mappings(unsigned map_handle) assert(map != NULL && "nonexistent mapping"); agxdecode_decode_segment_list(map->ptr.cpu); - for (unsigned i = 0; i < mmap_count; ++i) { - if (!mmap_array[i].ptr.cpu || !mmap_array[i].size || - !mmap_array[i].mapped) + util_dynarray_foreach(&ctx->mmap_array, struct agx_bo, it) { + if (!it->ptr.cpu || !it->size || !it->mapped) continue; - assert(mmap_array[i].type < AGX_NUM_ALLOC); + assert(it->type < AGX_NUM_ALLOC); fprintf(agxdecode_dump_stream, "Buffer: type %s, gpu %" PRIx64 ", handle %u.bin:\n\n", - agx_alloc_types[mmap_array[i].type], mmap_array[i].ptr.gpu, - mmap_array[i].handle); + agx_alloc_types[it->type], it->ptr.gpu, it->handle); - u_hexdump(agxdecode_dump_stream, mmap_array[i].ptr.cpu, - mmap_array[i].size, false); + u_hexdump(agxdecode_dump_stream, it->ptr.cpu, it->size, false); fprintf(agxdecode_dump_stream, "\n"); } } @@ -989,32 +1087,28 @@ agxdecode_dump_mappings(unsigned map_handle) #endif void -agxdecode_track_alloc(struct agx_bo *alloc) +agxdecode_track_alloc(struct agxdecode_ctx *ctx, struct agx_bo *alloc) { - assert((mmap_count + 1) < MAX_MAPPINGS); - - for (unsigned i = 0; i < mmap_count; ++i) { - struct agx_bo *bo = &mmap_array[i]; - bool match = (bo->handle == alloc->handle && bo->type == alloc->type); + util_dynarray_foreach(&ctx->mmap_array, struct agx_bo, it) { + bool match = (it->handle == alloc->handle && it->type == alloc->type); assert(!match && "tried to alloc already allocated BO"); } - mmap_array[mmap_count++] = *alloc; + util_dynarray_append(&ctx->mmap_array, struct agx_bo, *alloc); } void -agxdecode_track_free(struct agx_bo *bo) +agxdecode_track_free(struct agxdecode_ctx *ctx, struct agx_bo *bo) { bool found = false; - for (unsigned i = 0; i < mmap_count; ++i) { - if (mmap_array[i].handle == bo->handle && - (mmap_array[i].type == AGX_ALLOC_REGULAR) == - (bo->type == AGX_ALLOC_REGULAR)) { + util_dynarray_foreach(&ctx->mmap_array, struct agx_bo, it) { + if (it->handle == bo->handle && + (it->type == AGX_ALLOC_REGULAR) == (bo->type == AGX_ALLOC_REGULAR)) { assert(!found && "mapped multiple times!"); found = true; - memset(&mmap_array[i], 0, sizeof(mmap_array[i])); + memset(it, 0, sizeof(*it)); } } @@ -1099,20 +1193,26 @@ libagxdecode_init(struct libagxdecode_config *config) } void -libagxdecode_vdm(uint64_t addr, const char *label, bool verbose) +libagxdecode_vdm(struct agxdecode_ctx *ctx, uint64_t addr, const char *label, + bool verbose) { - agxdecode_stateful(addr, label, agxdecode_vdm, verbose, &lib_params, NULL); + agxdecode_stateful(ctx, addr, label, agxdecode_vdm, verbose, &lib_params, + NULL); } void -libagxdecode_cdm(uint64_t addr, const char *label, bool verbose) +libagxdecode_cdm(struct agxdecode_ctx *ctx, uint64_t addr, const char *label, + bool verbose) { - agxdecode_stateful(addr, label, agxdecode_cdm, verbose, &lib_params, NULL); + agxdecode_stateful(ctx, addr, label, agxdecode_cdm, verbose, &lib_params, + NULL); } void -libagxdecode_usc(uint64_t addr, const char *label, bool verbose) +libagxdecode_usc(struct agxdecode_ctx *ctx, uint64_t addr, const char *label, + bool verbose) { - agxdecode_stateful(addr, label, agxdecode_usc, verbose, &lib_params, NULL); + agxdecode_stateful(ctx, addr, label, agxdecode_usc, verbose, &lib_params, + NULL); } void libagxdecode_shutdown(void) diff --git a/src/asahi/lib/decode.h b/src/asahi/lib/decode.h index 8f7152f62f3..6ae6d8ec5d3 100644 --- a/src/asahi/lib/decode.h +++ b/src/asahi/lib/decode.h @@ -10,20 +10,29 @@ #include #include "agx_bo.h" +struct agxdecode_ctx; + +struct agxdecode_ctx *agxdecode_new_context(void); + +void agxdecode_destroy_context(struct agxdecode_ctx *ctx); + void agxdecode_next_frame(void); void agxdecode_close(void); -void agxdecode_cmdstream(unsigned cmdbuf_index, unsigned map_index, - bool verbose); +void agxdecode_cmdstream(struct agxdecode_ctx *ctx, unsigned cmdbuf_index, + unsigned map_index, bool verbose); + +void agxdecode_image_heap(struct agxdecode_ctx *ctx, uint64_t heap, + unsigned nr_entries); void agxdecode_dump_file_open(void); -void agxdecode_track_alloc(struct agx_bo *alloc); +void agxdecode_track_alloc(struct agxdecode_ctx *ctx, struct agx_bo *alloc); -void agxdecode_dump_mappings(unsigned map_index); +void agxdecode_dump_mappings(struct agxdecode_ctx *ctx, unsigned map_index); -void agxdecode_track_free(struct agx_bo *bo); +void agxdecode_track_free(struct agxdecode_ctx *ctx, struct agx_bo *bo); struct libagxdecode_config { uint32_t chip_id; @@ -32,7 +41,10 @@ struct libagxdecode_config { }; void libagxdecode_init(struct libagxdecode_config *config); -void libagxdecode_vdm(uint64_t addr, const char *label, bool verbose); -void libagxdecode_cdm(uint64_t addr, const char *label, bool verbose); -void libagxdecode_usc(uint64_t addr, const char *label, bool verbose); +void libagxdecode_vdm(struct agxdecode_ctx *ctx, uint64_t addr, + const char *label, bool verbose); +void libagxdecode_cdm(struct agxdecode_ctx *ctx, uint64_t addr, + const char *label, bool verbose); +void libagxdecode_usc(struct agxdecode_ctx *ctx, uint64_t addr, + const char *label, bool verbose); void libagxdecode_shutdown(void);