pan/decode: handle more than one panfrost_device

Before this commit, if an application tried to create more than one
panfrost_device, such as piglit's "ext_image_dma_buf_import" tests,
it would result in a crash when running with PAN_MESA_DEBUG=sync or
PAN_MESA_DEBUG=trace.

This commit fixes that by introducing a pandecode_context, which
encapsulates all the information that is being tracked, and thus
avoiding memory conflicts.

Signed-off-by: Italo Nicola <italonicola@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24144>
This commit is contained in:
Italo Nicola 2023-07-13 12:13:19 +00:00 committed by Marge Bot
parent cea0cc5b16
commit 56be9a55be
14 changed files with 732 additions and 630 deletions

View file

@ -114,7 +114,7 @@ panfrost_flush(struct pipe_context *pipe, struct pipe_fence_handle **fence,
} }
if (dev->debug & PAN_DBG_TRACE) if (dev->debug & PAN_DBG_TRACE)
pandecode_next_frame(); pandecode_next_frame(dev->decode_ctx);
} }
static void static void

View file

@ -685,14 +685,14 @@ panfrost_batch_submit_ioctl(struct panfrost_batch *batch,
drmSyncobjWait(dev->fd, &out_sync, 1, INT64_MAX, 0, NULL); drmSyncobjWait(dev->fd, &out_sync, 1, INT64_MAX, 0, NULL);
if (dev->debug & PAN_DBG_TRACE) if (dev->debug & PAN_DBG_TRACE)
pandecode_jc(submit.jc, dev->gpu_id); pandecode_jc(dev->decode_ctx, submit.jc, dev->gpu_id);
if (dev->debug & PAN_DBG_DUMP) if (dev->debug & PAN_DBG_DUMP)
pandecode_dump_mappings(); pandecode_dump_mappings(dev->decode_ctx);
/* Jobs won't be complete if blackhole rendering, that's ok */ /* Jobs won't be complete if blackhole rendering, that's ok */
if (!ctx->is_noop && dev->debug & PAN_DBG_SYNC) if (!ctx->is_noop && dev->debug & PAN_DBG_SYNC)
pandecode_abort_on_fault(submit.jc, dev->gpu_id); pandecode_abort_on_fault(dev->decode_ctx, submit.jc, dev->gpu_id);
} }
return 0; return 0;

View file

@ -1004,7 +1004,8 @@ panfrost_ptr_map(struct pipe_context *pctx, struct pipe_resource *resource,
panfrost_bo_mmap(bo); panfrost_bo_mmap(bo);
if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC)) if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC))
pandecode_inject_mmap(bo->ptr.gpu, bo->ptr.cpu, bo->size, NULL); pandecode_inject_mmap(dev->decode_ctx, bo->ptr.gpu, bo->ptr.cpu, bo->size,
NULL);
/* Upgrade writes to uninitialized ranges to UNSYNCHRONIZED */ /* Upgrade writes to uninitialized ranges to UNSYNCHRONIZED */
if ((usage & PIPE_MAP_WRITE) && resource->target == PIPE_BUFFER && if ((usage & PIPE_MAP_WRITE) && resource->target == PIPE_BUFFER &&

View file

@ -45,11 +45,12 @@
* larger FBD */ * larger FBD */
static void static void
pandecode_midgard_tiler_descriptor(const struct mali_tiler_context_packed *tp, pandecode_midgard_tiler_descriptor(struct pandecode_context *ctx,
const struct mali_tiler_context_packed *tp,
const struct mali_tiler_weights_packed *wp) const struct mali_tiler_weights_packed *wp)
{ {
pan_unpack(tp, TILER_CONTEXT, t); pan_unpack(tp, TILER_CONTEXT, t);
DUMP_UNPACKED(TILER_CONTEXT, t, "Tiler:\n"); DUMP_UNPACKED(ctx, TILER_CONTEXT, t, "Tiler:\n");
/* We've never seen weights used in practice, but they exist */ /* We've never seen weights used in practice, but they exist */
pan_unpack(wp, TILER_WEIGHTS, w); pan_unpack(wp, TILER_WEIGHTS, w);
@ -65,55 +66,58 @@ pandecode_midgard_tiler_descriptor(const struct mali_tiler_context_packed *tp,
nonzero_weights |= w.weight7 != 0x0; nonzero_weights |= w.weight7 != 0x0;
if (nonzero_weights) if (nonzero_weights)
DUMP_UNPACKED(TILER_WEIGHTS, w, "Tiler Weights:\n"); DUMP_UNPACKED(ctx, TILER_WEIGHTS, w, "Tiler Weights:\n");
} }
#endif #endif
#if PAN_ARCH >= 5 #if PAN_ARCH >= 5
static void static void
pandecode_render_target(uint64_t gpu_va, unsigned gpu_id, pandecode_render_target(struct pandecode_context *ctx, uint64_t gpu_va,
unsigned gpu_id,
const struct MALI_FRAMEBUFFER_PARAMETERS *fb) const struct MALI_FRAMEBUFFER_PARAMETERS *fb)
{ {
pandecode_log("Color Render Targets @%" PRIx64 ":\n", gpu_va); pandecode_log(ctx, "Color Render Targets @%" PRIx64 ":\n", gpu_va);
pandecode_indent++; ctx->indent++;
for (int i = 0; i < (fb->render_target_count); i++) { for (int i = 0; i < (fb->render_target_count); i++) {
mali_ptr rt_va = gpu_va + i * pan_size(RENDER_TARGET); mali_ptr rt_va = gpu_va + i * pan_size(RENDER_TARGET);
const struct mali_render_target_packed *PANDECODE_PTR_VAR( const struct mali_render_target_packed *PANDECODE_PTR_VAR(
rtp, (mali_ptr)rt_va); ctx, rtp, (mali_ptr)rt_va);
DUMP_CL(RENDER_TARGET, rtp, "Color Render Target %d:\n", i); DUMP_CL(ctx, RENDER_TARGET, rtp, "Color Render Target %d:\n", i);
} }
pandecode_indent--; ctx->indent--;
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
#endif #endif
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
static void static void
pandecode_sample_locations(const void *fb) pandecode_sample_locations(struct pandecode_context *ctx, const void *fb)
{ {
pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, params); pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, params);
const u16 *PANDECODE_PTR_VAR(samples, params.sample_locations); const u16 *PANDECODE_PTR_VAR(ctx, samples, params.sample_locations);
pandecode_log("Sample locations @%" PRIx64 ":\n", params.sample_locations); pandecode_log(ctx, "Sample locations @%" PRIx64 ":\n",
params.sample_locations);
for (int i = 0; i < 33; i++) { for (int i = 0; i < 33; i++) {
pandecode_log(" (%d, %d),\n", samples[2 * i] - 128, pandecode_log(ctx, " (%d, %d),\n", samples[2 * i] - 128,
samples[2 * i + 1] - 128); samples[2 * i + 1] - 128);
} }
} }
#endif #endif
struct pandecode_fbd struct pandecode_fbd
GENX(pandecode_fbd)(uint64_t gpu_va, bool is_fragment, unsigned gpu_id) GENX(pandecode_fbd)(struct pandecode_context *ctx, uint64_t gpu_va,
bool is_fragment, unsigned gpu_id)
{ {
const void *PANDECODE_PTR_VAR(fb, (mali_ptr)gpu_va); const void *PANDECODE_PTR_VAR(ctx, fb, (mali_ptr)gpu_va);
pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, params); pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, params);
DUMP_UNPACKED(FRAMEBUFFER_PARAMETERS, params, "Parameters:\n"); DUMP_UNPACKED(ctx, FRAMEBUFFER_PARAMETERS, params, "Parameters:\n");
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
pandecode_sample_locations(fb); pandecode_sample_locations(ctx, fb);
unsigned dcd_size = pan_size(DRAW); unsigned dcd_size = pan_size(DRAW);
unsigned job_type_param = 0; unsigned job_type_param = 0;
@ -123,64 +127,64 @@ GENX(pandecode_fbd)(uint64_t gpu_va, bool is_fragment, unsigned gpu_id)
#endif #endif
if (params.pre_frame_0 != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) { if (params.pre_frame_0 != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) {
const void *PANDECODE_PTR_VAR(dcd, const void *PANDECODE_PTR_VAR(ctx, dcd,
params.frame_shader_dcds + (0 * dcd_size)); params.frame_shader_dcds + (0 * dcd_size));
pan_unpack(dcd, DRAW, draw); pan_unpack(dcd, DRAW, draw);
pandecode_log("Pre frame 0 @%" PRIx64 " (mode=%d):\n", pandecode_log(ctx, "Pre frame 0 @%" PRIx64 " (mode=%d):\n",
params.frame_shader_dcds, params.pre_frame_0); params.frame_shader_dcds, params.pre_frame_0);
GENX(pandecode_dcd)(&draw, job_type_param, gpu_id); GENX(pandecode_dcd)(ctx, &draw, job_type_param, gpu_id);
} }
if (params.pre_frame_1 != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) { if (params.pre_frame_1 != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) {
const void *PANDECODE_PTR_VAR(dcd, const void *PANDECODE_PTR_VAR(ctx, dcd,
params.frame_shader_dcds + (1 * dcd_size)); params.frame_shader_dcds + (1 * dcd_size));
pan_unpack(dcd, DRAW, draw); pan_unpack(dcd, DRAW, draw);
pandecode_log("Pre frame 1 @%" PRIx64 ":\n", pandecode_log(ctx, "Pre frame 1 @%" PRIx64 ":\n",
params.frame_shader_dcds + (1 * dcd_size)); params.frame_shader_dcds + (1 * dcd_size));
GENX(pandecode_dcd)(&draw, job_type_param, gpu_id); GENX(pandecode_dcd)(ctx, &draw, job_type_param, gpu_id);
} }
if (params.post_frame != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) { if (params.post_frame != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) {
const void *PANDECODE_PTR_VAR(dcd, const void *PANDECODE_PTR_VAR(ctx, dcd,
params.frame_shader_dcds + (2 * dcd_size)); params.frame_shader_dcds + (2 * dcd_size));
pan_unpack(dcd, DRAW, draw); pan_unpack(dcd, DRAW, draw);
pandecode_log("Post frame:\n"); pandecode_log(ctx, "Post frame:\n");
GENX(pandecode_dcd)(&draw, job_type_param, gpu_id); GENX(pandecode_dcd)(ctx, &draw, job_type_param, gpu_id);
} }
#else #else
DUMP_SECTION(FRAMEBUFFER, LOCAL_STORAGE, fb, "Local Storage:\n"); DUMP_SECTION(ctx, FRAMEBUFFER, LOCAL_STORAGE, fb, "Local Storage:\n");
const void *t = pan_section_ptr(fb, FRAMEBUFFER, TILER); const void *t = pan_section_ptr(fb, FRAMEBUFFER, TILER);
const void *w = pan_section_ptr(fb, FRAMEBUFFER, TILER_WEIGHTS); const void *w = pan_section_ptr(fb, FRAMEBUFFER, TILER_WEIGHTS);
pandecode_midgard_tiler_descriptor(t, w); pandecode_midgard_tiler_descriptor(ctx, t, w);
#endif #endif
pandecode_log("Framebuffer @%" PRIx64 ":\n", gpu_va); pandecode_log(ctx, "Framebuffer @%" PRIx64 ":\n", gpu_va);
pandecode_indent++; ctx->indent++;
DUMP_UNPACKED(FRAMEBUFFER_PARAMETERS, params, "Parameters:\n"); DUMP_UNPACKED(ctx, FRAMEBUFFER_PARAMETERS, params, "Parameters:\n");
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
if (params.tiler) if (params.tiler)
GENX(pandecode_tiler)(params.tiler, gpu_id); GENX(pandecode_tiler)(ctx, params.tiler, gpu_id);
#endif #endif
pandecode_indent--; ctx->indent--;
pandecode_log("\n"); pandecode_log(ctx, "\n");
#if PAN_ARCH >= 5 #if PAN_ARCH >= 5
gpu_va += pan_size(FRAMEBUFFER); gpu_va += pan_size(FRAMEBUFFER);
if (params.has_zs_crc_extension) { if (params.has_zs_crc_extension) {
const struct mali_zs_crc_extension_packed *PANDECODE_PTR_VAR( const struct mali_zs_crc_extension_packed *PANDECODE_PTR_VAR(
zs_crc, (mali_ptr)gpu_va); ctx, zs_crc, (mali_ptr)gpu_va);
DUMP_CL(ZS_CRC_EXTENSION, zs_crc, "ZS CRC Extension:\n"); DUMP_CL(ctx, ZS_CRC_EXTENSION, zs_crc, "ZS CRC Extension:\n");
pandecode_log("\n"); pandecode_log(ctx, "\n");
gpu_va += pan_size(ZS_CRC_EXTENSION); gpu_va += pan_size(ZS_CRC_EXTENSION);
} }
if (is_fragment) if (is_fragment)
pandecode_render_target(gpu_va, gpu_id, &params); pandecode_render_target(ctx, gpu_va, gpu_id, &params);
return (struct pandecode_fbd){ return (struct pandecode_fbd){
.rt_count = params.render_target_count, .rt_count = params.render_target_count,
@ -201,10 +205,11 @@ GENX(pandecode_fbd)(uint64_t gpu_va, bool is_fragment, unsigned gpu_id)
#if PAN_ARCH >= 5 #if PAN_ARCH >= 5
mali_ptr mali_ptr
GENX(pandecode_blend)(void *descs, int rt_no, mali_ptr frag_shader) GENX(pandecode_blend)(struct pandecode_context *ctx, void *descs, int rt_no,
mali_ptr frag_shader)
{ {
pan_unpack(descs + (rt_no * pan_size(BLEND)), BLEND, b); pan_unpack(descs + (rt_no * pan_size(BLEND)), BLEND, b);
DUMP_UNPACKED(BLEND, b, "Blend RT %d:\n", rt_no); DUMP_UNPACKED(ctx, BLEND, b, "Blend RT %d:\n", rt_no);
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
if (b.internal.mode != MALI_BLEND_MODE_SHADER) if (b.internal.mode != MALI_BLEND_MODE_SHADER)
return 0; return 0;
@ -231,7 +236,8 @@ panfrost_is_yuv_format(uint32_t packed)
} }
static void static void
pandecode_texture_payload(mali_ptr payload, const struct MALI_TEXTURE *tex) pandecode_texture_payload(struct pandecode_context *ctx, mali_ptr payload,
const struct MALI_TEXTURE *tex)
{ {
unsigned nr_samples = unsigned nr_samples =
tex->dimension == MALI_TEXTURE_DIMENSION_3D ? 1 : tex->sample_count; tex->dimension == MALI_TEXTURE_DIMENSION_3D ? 1 : tex->sample_count;
@ -257,8 +263,8 @@ pandecode_texture_payload(mali_ptr payload, const struct MALI_TEXTURE *tex)
#define PANDECODE_EMIT_TEX_PAYLOAD_DESC(T, msg) \ #define PANDECODE_EMIT_TEX_PAYLOAD_DESC(T, msg) \
for (int i = 0; i < bitmap_count; ++i) { \ for (int i = 0; i < bitmap_count; ++i) { \
uint64_t addr = payload + pan_size(T) * i; \ uint64_t addr = payload + pan_size(T) * i; \
pan_unpack(PANDECODE_PTR(addr, void), T, s); \ pan_unpack(PANDECODE_PTR(ctx, addr, void), T, s); \
DUMP_UNPACKED(T, s, msg " @%" PRIx64 ":\n", addr) \ DUMP_UNPACKED(ctx, T, s, msg " @%" PRIx64 ":\n", addr) \
} }
#if PAN_ARCH <= 5 #if PAN_ARCH <= 5
@ -277,7 +283,7 @@ pandecode_texture_payload(mali_ptr payload, const struct MALI_TEXTURE *tex)
"Surface With Stride"); "Surface With Stride");
break; break;
default: default:
fprintf(pandecode_dump_stream, "Unknown surface descriptor type %X\n", fprintf(ctx->dump_stream, "Unknown surface descriptor type %X\n",
tex->surface_type); tex->surface_type);
break; break;
} }
@ -299,25 +305,26 @@ pandecode_texture_payload(mali_ptr payload, const struct MALI_TEXTURE *tex)
#if PAN_ARCH <= 5 #if PAN_ARCH <= 5
void void
GENX(pandecode_texture)(mali_ptr u, unsigned tex) GENX(pandecode_texture)(struct pandecode_context *ctx, mali_ptr u, unsigned tex)
{ {
const uint8_t *cl = pandecode_fetch_gpu_mem(u, pan_size(TEXTURE)); const uint8_t *cl = pandecode_fetch_gpu_mem(ctx, u, pan_size(TEXTURE));
pan_unpack(cl, TEXTURE, temp); pan_unpack(cl, TEXTURE, temp);
DUMP_UNPACKED(TEXTURE, temp, "Texture:\n") DUMP_UNPACKED(ctx, TEXTURE, temp, "Texture:\n")
pandecode_indent++; ctx->indent++;
pandecode_texture_payload(u + pan_size(TEXTURE), &temp); pandecode_texture_payload(ctx, u + pan_size(TEXTURE), &temp);
pandecode_indent--; ctx->indent--;
} }
#else #else
void void
GENX(pandecode_texture)(const void *cl, unsigned tex) GENX(pandecode_texture)(struct pandecode_context *ctx, const void *cl,
unsigned tex)
{ {
pan_unpack(cl, TEXTURE, temp); pan_unpack(cl, TEXTURE, temp);
DUMP_UNPACKED(TEXTURE, temp, "Texture:\n") DUMP_UNPACKED(ctx, TEXTURE, temp, "Texture:\n")
pandecode_indent++; ctx->indent++;
#if PAN_ARCH >= 9 #if PAN_ARCH >= 9
int plane_count = temp.levels * temp.array_size; int plane_count = temp.levels * temp.array_size;
@ -327,66 +334,70 @@ GENX(pandecode_texture)(const void *cl, unsigned tex)
plane_count *= 6; plane_count *= 6;
for (unsigned i = 0; i < plane_count; ++i) for (unsigned i = 0; i < plane_count; ++i)
DUMP_ADDR(PLANE, temp.surfaces + i * pan_size(PLANE), "Plane %u:\n", i); DUMP_ADDR(ctx, PLANE, temp.surfaces + i * pan_size(PLANE), "Plane %u:\n",
i);
#else #else
pandecode_texture_payload(temp.surfaces, &temp); pandecode_texture_payload(ctx, temp.surfaces, &temp);
#endif #endif
pandecode_indent--; ctx->indent--;
} }
#endif #endif
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
void void
GENX(pandecode_tiler)(mali_ptr gpu_va, unsigned gpu_id) GENX(pandecode_tiler)(struct pandecode_context *ctx, mali_ptr gpu_va,
unsigned gpu_id)
{ {
pan_unpack(PANDECODE_PTR(gpu_va, void), TILER_CONTEXT, t); pan_unpack(PANDECODE_PTR(ctx, gpu_va, void), TILER_CONTEXT, t);
if (t.heap) { if (t.heap) {
pan_unpack(PANDECODE_PTR(t.heap, void), TILER_HEAP, h); pan_unpack(PANDECODE_PTR(ctx, t.heap, void), TILER_HEAP, h);
DUMP_UNPACKED(TILER_HEAP, h, "Tiler Heap:\n"); DUMP_UNPACKED(ctx, TILER_HEAP, h, "Tiler Heap:\n");
} }
DUMP_UNPACKED(TILER_CONTEXT, t, "Tiler Context @%" PRIx64 ":\n", gpu_va); DUMP_UNPACKED(ctx, TILER_CONTEXT, t, "Tiler Context @%" PRIx64 ":\n",
gpu_va);
} }
#endif #endif
#if PAN_ARCH >= 9 #if PAN_ARCH >= 9
void void
GENX(pandecode_fau)(mali_ptr addr, unsigned count, const char *name) GENX(pandecode_fau)(struct pandecode_context *ctx, mali_ptr addr,
unsigned count, const char *name)
{ {
if (count == 0) if (count == 0)
return; return;
const uint32_t *PANDECODE_PTR_VAR(raw, addr); const uint32_t *PANDECODE_PTR_VAR(ctx, raw, addr);
pandecode_validate_buffer(addr, count * 8); pandecode_validate_buffer(ctx, addr, count * 8);
fprintf(pandecode_dump_stream, "%s @%" PRIx64 ":\n", name, addr); fprintf(ctx->dump_stream, "%s @%" PRIx64 ":\n", name, addr);
for (unsigned i = 0; i < count; ++i) { for (unsigned i = 0; i < count; ++i) {
fprintf(pandecode_dump_stream, " %08X %08X\n", raw[2 * i], fprintf(ctx->dump_stream, " %08X %08X\n", raw[2 * i], raw[2 * i + 1]);
raw[2 * i + 1]);
} }
fprintf(pandecode_dump_stream, "\n"); fprintf(ctx->dump_stream, "\n");
} }
mali_ptr mali_ptr
GENX(pandecode_shader)(mali_ptr addr, const char *label, unsigned gpu_id) GENX(pandecode_shader)(struct pandecode_context *ctx, mali_ptr addr,
const char *label, unsigned gpu_id)
{ {
MAP_ADDR(SHADER_PROGRAM, addr, cl); MAP_ADDR(ctx, SHADER_PROGRAM, addr, cl);
pan_unpack(cl, SHADER_PROGRAM, desc); pan_unpack(cl, SHADER_PROGRAM, desc);
assert(desc.type == 8); assert(desc.type == 8);
DUMP_UNPACKED(SHADER_PROGRAM, desc, "%s Shader @%" PRIx64 ":\n", label, DUMP_UNPACKED(ctx, SHADER_PROGRAM, desc, "%s Shader @%" PRIx64 ":\n", label,
addr); addr);
pandecode_shader_disassemble(desc.binary, gpu_id); pandecode_shader_disassemble(ctx, desc.binary, gpu_id);
return desc.binary; return desc.binary;
} }
static void static void
pandecode_resources(mali_ptr addr, unsigned size) pandecode_resources(struct pandecode_context *ctx, mali_ptr addr, unsigned size)
{ {
const uint8_t *cl = pandecode_fetch_gpu_mem(addr, size); const uint8_t *cl = pandecode_fetch_gpu_mem(ctx, addr, size);
assert((size % 0x20) == 0); assert((size % 0x20) == 0);
for (unsigned i = 0; i < size; i += 0x20) { for (unsigned i = 0; i < size; i += 0x20) {
@ -394,96 +405,101 @@ pandecode_resources(mali_ptr addr, unsigned size)
switch (type) { switch (type) {
case MALI_DESCRIPTOR_TYPE_SAMPLER: case MALI_DESCRIPTOR_TYPE_SAMPLER:
DUMP_CL(SAMPLER, cl + i, "Sampler @%" PRIx64 ":\n", addr + i); DUMP_CL(ctx, SAMPLER, cl + i, "Sampler @%" PRIx64 ":\n", addr + i);
break; break;
case MALI_DESCRIPTOR_TYPE_TEXTURE: case MALI_DESCRIPTOR_TYPE_TEXTURE:
pandecode_log("Texture @%" PRIx64 "\n", addr + i); pandecode_log(ctx, "Texture @%" PRIx64 "\n", addr + i);
GENX(pandecode_texture)(cl + i, i); GENX(pandecode_texture)(ctx, cl + i, i);
break; break;
case MALI_DESCRIPTOR_TYPE_ATTRIBUTE: case MALI_DESCRIPTOR_TYPE_ATTRIBUTE:
DUMP_CL(ATTRIBUTE, cl + i, "Attribute @%" PRIx64 ":\n", addr + i); DUMP_CL(ctx, ATTRIBUTE, cl + i, "Attribute @%" PRIx64 ":\n", addr + i);
break; break;
case MALI_DESCRIPTOR_TYPE_BUFFER: case MALI_DESCRIPTOR_TYPE_BUFFER:
DUMP_CL(BUFFER, cl + i, "Buffer @%" PRIx64 ":\n", addr + i); DUMP_CL(ctx, BUFFER, cl + i, "Buffer @%" PRIx64 ":\n", addr + i);
break; break;
default: default:
fprintf(pandecode_dump_stream, "Unknown descriptor type %X\n", type); fprintf(ctx->dump_stream, "Unknown descriptor type %X\n", type);
break; break;
} }
} }
} }
void void
GENX(pandecode_resource_tables)(mali_ptr addr, const char *label) GENX(pandecode_resource_tables)(struct pandecode_context *ctx, mali_ptr addr,
const char *label)
{ {
unsigned count = addr & 0x3F; unsigned count = addr & 0x3F;
addr = addr & ~0x3F; addr = addr & ~0x3F;
const uint8_t *cl = const uint8_t *cl =
pandecode_fetch_gpu_mem(addr, MALI_RESOURCE_LENGTH * count); pandecode_fetch_gpu_mem(ctx, addr, MALI_RESOURCE_LENGTH * count);
for (unsigned i = 0; i < count; ++i) { for (unsigned i = 0; i < count; ++i) {
pan_unpack(cl + i * MALI_RESOURCE_LENGTH, RESOURCE, entry); pan_unpack(cl + i * MALI_RESOURCE_LENGTH, RESOURCE, entry);
DUMP_UNPACKED(RESOURCE, entry, "Entry %u @%" PRIx64 ":\n", i, DUMP_UNPACKED(ctx, RESOURCE, entry, "Entry %u @%" PRIx64 ":\n", i,
addr + i * MALI_RESOURCE_LENGTH); addr + i * MALI_RESOURCE_LENGTH);
pandecode_indent += 2; ctx->indent += 2;
if (entry.address) if (entry.address)
pandecode_resources(entry.address, entry.size); pandecode_resources(ctx, entry.address, entry.size);
pandecode_indent -= 2; ctx->indent -= 2;
} }
} }
void void
GENX(pandecode_depth_stencil)(mali_ptr addr) GENX(pandecode_depth_stencil)(struct pandecode_context *ctx, mali_ptr addr)
{ {
MAP_ADDR(DEPTH_STENCIL, addr, cl); MAP_ADDR(ctx, DEPTH_STENCIL, addr, cl);
pan_unpack(cl, DEPTH_STENCIL, desc); pan_unpack(cl, DEPTH_STENCIL, desc);
DUMP_UNPACKED(DEPTH_STENCIL, desc, "Depth/stencil"); DUMP_UNPACKED(ctx, DEPTH_STENCIL, desc, "Depth/stencil");
} }
void void
GENX(pandecode_shader_environment)(const struct MALI_SHADER_ENVIRONMENT *p, GENX(pandecode_shader_environment)(struct pandecode_context *ctx,
const struct MALI_SHADER_ENVIRONMENT *p,
unsigned gpu_id) unsigned gpu_id)
{ {
if (p->shader) if (p->shader)
GENX(pandecode_shader)(p->shader, "Shader", gpu_id); GENX(pandecode_shader)(ctx, p->shader, "Shader", gpu_id);
if (p->resources) if (p->resources)
GENX(pandecode_resource_tables)(p->resources, "Resources"); GENX(pandecode_resource_tables)(ctx, p->resources, "Resources");
if (p->thread_storage) if (p->thread_storage)
DUMP_ADDR(LOCAL_STORAGE, p->thread_storage, "Local Storage:\n"); DUMP_ADDR(ctx, LOCAL_STORAGE, p->thread_storage, "Local Storage:\n");
if (p->fau) if (p->fau)
GENX(pandecode_fau)(p->fau, p->fau_count, "FAU"); GENX(pandecode_fau)(ctx, p->fau, p->fau_count, "FAU");
} }
void void
GENX(pandecode_blend_descs)(mali_ptr blend, unsigned count, GENX(pandecode_blend_descs)(struct pandecode_context *ctx, mali_ptr blend,
mali_ptr frag_shader, unsigned gpu_id) unsigned count, mali_ptr frag_shader,
unsigned gpu_id)
{ {
for (unsigned i = 0; i < count; ++i) { for (unsigned i = 0; i < count; ++i) {
struct mali_blend_packed *PANDECODE_PTR_VAR(blend_descs, blend); struct mali_blend_packed *PANDECODE_PTR_VAR(ctx, blend_descs, blend);
mali_ptr blend_shader = mali_ptr blend_shader =
GENX(pandecode_blend)(blend_descs, i, frag_shader); GENX(pandecode_blend)(ctx, blend_descs, i, frag_shader);
if (blend_shader) { if (blend_shader) {
fprintf(pandecode_dump_stream, "Blend shader %u @%" PRIx64 "", i, fprintf(ctx->dump_stream, "Blend shader %u @%" PRIx64 "", i,
blend_shader); blend_shader);
pandecode_shader_disassemble(blend_shader, gpu_id); pandecode_shader_disassemble(ctx, blend_shader, gpu_id);
} }
} }
} }
void void
GENX(pandecode_dcd)(const struct MALI_DRAW *p, unsigned unused, unsigned gpu_id) GENX(pandecode_dcd)(struct pandecode_context *ctx, const struct MALI_DRAW *p,
unsigned unused, unsigned gpu_id)
{ {
mali_ptr frag_shader = 0; mali_ptr frag_shader = 0;
GENX(pandecode_depth_stencil)(p->depth_stencil); GENX(pandecode_depth_stencil)(ctx, p->depth_stencil);
GENX(pandecode_blend_descs)(p->blend, p->blend_count, frag_shader, gpu_id); GENX(pandecode_blend_descs)
GENX(pandecode_shader_environment)(&p->shader, gpu_id); (ctx, p->blend, p->blend_count, frag_shader, gpu_id);
DUMP_UNPACKED(DRAW, *p, "Draw:\n"); GENX(pandecode_shader_environment)(ctx, &p->shader, gpu_id);
DUMP_UNPACKED(ctx, DRAW, *p, "Draw:\n");
} }
#endif #endif

View file

@ -28,13 +28,22 @@
#include "genxml/gen_macros.h" #include "genxml/gen_macros.h"
#include "util/rb_tree.h" #include "util/rb_tree.h"
#include "util/simple_mtx.h"
#include "util/u_dynarray.h"
#include "wrap.h" #include "wrap.h"
extern FILE *pandecode_dump_stream; struct pandecode_context {
extern unsigned pandecode_indent; int id; /* only used for the filename */
FILE *dump_stream;
unsigned indent;
struct rb_tree mmap_tree;
struct util_dynarray ro_mappings;
int dump_frame_count;
simple_mtx_t lock;
};
void pandecode_dump_file_open(void); void pandecode_dump_file_open(struct pandecode_context *ctx);
struct pandecode_mapped_memory { struct pandecode_mapped_memory {
struct rb_node node; struct rb_node node;
@ -45,21 +54,22 @@ struct pandecode_mapped_memory {
char name[32]; char name[32];
}; };
char *pointer_as_memory_reference(uint64_t ptr); char *pointer_as_memory_reference(struct pandecode_context *ctx, uint64_t ptr);
struct pandecode_mapped_memory * struct pandecode_mapped_memory *
pandecode_find_mapped_gpu_mem_containing(uint64_t addr); pandecode_find_mapped_gpu_mem_containing(struct pandecode_context *ctx,
uint64_t addr);
void pandecode_map_read_write(void); void pandecode_map_read_write(struct pandecode_context *ctx);
void pandecode_dump_mappings(void); void pandecode_dump_mappings(struct pandecode_context *ctx);
static inline void * static inline void *
__pandecode_fetch_gpu_mem(uint64_t gpu_va, size_t size, int line, __pandecode_fetch_gpu_mem(struct pandecode_context *ctx, uint64_t gpu_va,
const char *filename) size_t size, int line, const char *filename)
{ {
const struct pandecode_mapped_memory *mem = const struct pandecode_mapped_memory *mem =
pandecode_find_mapped_gpu_mem_containing(gpu_va); pandecode_find_mapped_gpu_mem_containing(ctx, gpu_va);
if (!mem) { if (!mem) {
fprintf(stderr, "Access to unknown memory %" PRIx64 " in %s:%d\n", gpu_va, fprintf(stderr, "Access to unknown memory %" PRIx64 " in %s:%d\n", gpu_va,
@ -72,97 +82,110 @@ __pandecode_fetch_gpu_mem(uint64_t gpu_va, size_t size, int line,
return mem->addr + gpu_va - mem->gpu_va; return mem->addr + gpu_va - mem->gpu_va;
} }
#define pandecode_fetch_gpu_mem(gpu_va, size) \ #define pandecode_fetch_gpu_mem(ctx, gpu_va, size) \
__pandecode_fetch_gpu_mem(gpu_va, size, __LINE__, __FILE__) __pandecode_fetch_gpu_mem(ctx, gpu_va, size, __LINE__, __FILE__)
/* Returns a validated pointer to mapped GPU memory with the given pointer type, /* Returns a validated pointer to mapped GPU memory with the given pointer type,
* size automatically determined from the pointer type * size automatically determined from the pointer type
*/ */
#define PANDECODE_PTR(gpu_va, type) \ #define PANDECODE_PTR(ctx, gpu_va, type) \
((type *)(__pandecode_fetch_gpu_mem(gpu_va, sizeof(type), __LINE__, \ ((type *)(__pandecode_fetch_gpu_mem(ctx, gpu_va, sizeof(type), __LINE__, \
__FILE__))) __FILE__)))
/* Usage: <variable type> PANDECODE_PTR_VAR(name, gpu_va) */ /* Usage: <variable type> PANDECODE_PTR_VAR(name, gpu_va) */
#define PANDECODE_PTR_VAR(name, gpu_va) \ #define PANDECODE_PTR_VAR(ctx, name, gpu_va) \
name = __pandecode_fetch_gpu_mem(gpu_va, sizeof(*name), __LINE__, __FILE__) name = __pandecode_fetch_gpu_mem(ctx, gpu_va, sizeof(*name), __LINE__, \
__FILE__)
void pandecode_validate_buffer(mali_ptr addr, size_t sz); void pandecode_validate_buffer(struct pandecode_context *ctx, mali_ptr addr,
size_t sz);
/* Forward declare for all supported gens to permit thunking */ /* Forward declare for all supported gens to permit thunking */
void pandecode_jc_v4(mali_ptr jc_gpu_va, unsigned gpu_id); void pandecode_jc_v4(struct pandecode_context *ctx, mali_ptr jc_gpu_va,
void pandecode_jc_v5(mali_ptr jc_gpu_va, unsigned gpu_id); unsigned gpu_id);
void pandecode_jc_v6(mali_ptr jc_gpu_va, unsigned gpu_id); void pandecode_jc_v5(struct pandecode_context *ctx, mali_ptr jc_gpu_va,
void pandecode_jc_v7(mali_ptr jc_gpu_va, unsigned gpu_id); unsigned gpu_id);
void pandecode_jc_v9(mali_ptr jc_gpu_va, unsigned gpu_id); void pandecode_jc_v6(struct pandecode_context *ctx, mali_ptr jc_gpu_va,
unsigned gpu_id);
void pandecode_jc_v7(struct pandecode_context *ctx, mali_ptr jc_gpu_va,
unsigned gpu_id);
void pandecode_jc_v9(struct pandecode_context *ctx, mali_ptr jc_gpu_va,
unsigned gpu_id);
void pandecode_abort_on_fault_v4(mali_ptr jc_gpu_va); void pandecode_abort_on_fault_v4(struct pandecode_context *ctx,
void pandecode_abort_on_fault_v5(mali_ptr jc_gpu_va); mali_ptr jc_gpu_va);
void pandecode_abort_on_fault_v6(mali_ptr jc_gpu_va); void pandecode_abort_on_fault_v5(struct pandecode_context *ctx,
void pandecode_abort_on_fault_v7(mali_ptr jc_gpu_va); mali_ptr jc_gpu_va);
void pandecode_abort_on_fault_v9(mali_ptr jc_gpu_va); void pandecode_abort_on_fault_v6(struct pandecode_context *ctx,
mali_ptr jc_gpu_va);
void pandecode_abort_on_fault_v7(struct pandecode_context *ctx,
mali_ptr jc_gpu_va);
void pandecode_abort_on_fault_v9(struct pandecode_context *ctx,
mali_ptr jc_gpu_va);
void pandecode_cs_v10(mali_ptr queue, uint32_t size, unsigned gpu_id, void pandecode_cs_v10(struct pandecode_context *ctx, mali_ptr queue,
uint32_t *regs); uint32_t size, unsigned gpu_id, uint32_t *regs);
/* Logging infrastructure */ /* Logging infrastructure */
static void static void
pandecode_make_indent(void) pandecode_make_indent(struct pandecode_context *ctx)
{ {
for (unsigned i = 0; i < pandecode_indent; ++i) for (unsigned i = 0; i < ctx->indent; ++i)
fprintf(pandecode_dump_stream, " "); fprintf(ctx->dump_stream, " ");
} }
static inline void PRINTFLIKE(1, 2) pandecode_log(const char *format, ...) static inline void PRINTFLIKE(2, 3)
pandecode_log(struct pandecode_context *ctx, const char *format, ...)
{ {
va_list ap; va_list ap;
pandecode_make_indent(); pandecode_make_indent(ctx);
va_start(ap, format); va_start(ap, format);
vfprintf(pandecode_dump_stream, format, ap); vfprintf(ctx->dump_stream, format, ap);
va_end(ap); va_end(ap);
} }
static inline void static inline void
pandecode_log_cont(const char *format, ...) pandecode_log_cont(struct pandecode_context *ctx, const char *format, ...)
{ {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
vfprintf(pandecode_dump_stream, format, ap); vfprintf(ctx->dump_stream, format, ap);
va_end(ap); va_end(ap);
} }
/* Convenience methods */ /* Convenience methods */
#define DUMP_UNPACKED(T, var, ...) \ #define DUMP_UNPACKED(ctx, T, var, ...) \
{ \ { \
pandecode_log(__VA_ARGS__); \ pandecode_log(ctx, __VA_ARGS__); \
pan_print(pandecode_dump_stream, T, var, (pandecode_indent + 1) * 2); \ pan_print(ctx->dump_stream, T, var, (ctx->indent + 1) * 2); \
} }
#define DUMP_CL(T, cl, ...) \ #define DUMP_CL(ctx, T, cl, ...) \
{ \ { \
pan_unpack(cl, T, temp); \ pan_unpack(cl, T, temp); \
DUMP_UNPACKED(T, temp, __VA_ARGS__); \ DUMP_UNPACKED(ctx, T, temp, __VA_ARGS__); \
} }
#define DUMP_SECTION(A, S, cl, ...) \ #define DUMP_SECTION(ctx, A, S, cl, ...) \
{ \ { \
pan_section_unpack(cl, A, S, temp); \ pan_section_unpack(cl, A, S, temp); \
pandecode_log(__VA_ARGS__); \ pandecode_log(ctx, __VA_ARGS__); \
pan_section_print(pandecode_dump_stream, A, S, temp, \ pan_section_print(ctx->dump_stream, A, S, temp, (ctx->indent + 1) * 2); \
(pandecode_indent + 1) * 2); \
} }
#define MAP_ADDR(T, addr, cl) \ #define MAP_ADDR(ctx, T, addr, cl) \
const uint8_t *cl = pandecode_fetch_gpu_mem(addr, pan_size(T)); const uint8_t *cl = pandecode_fetch_gpu_mem(ctx, addr, pan_size(T));
#define DUMP_ADDR(T, addr, ...) \ #define DUMP_ADDR(ctx, T, addr, ...) \
{ \ { \
MAP_ADDR(T, addr, cl) \ MAP_ADDR(ctx, T, addr, cl) \
DUMP_CL(T, cl, __VA_ARGS__); \ DUMP_CL(ctx, T, cl, __VA_ARGS__); \
} }
void pandecode_shader_disassemble(mali_ptr shader_ptr, unsigned gpu_id); void pandecode_shader_disassemble(struct pandecode_context *ctx,
mali_ptr shader_ptr, unsigned gpu_id);
#ifdef PAN_ARCH #ifdef PAN_ARCH
@ -172,46 +195,58 @@ struct pandecode_fbd {
bool has_extra; bool has_extra;
}; };
struct pandecode_fbd GENX(pandecode_fbd)(uint64_t gpu_va, bool is_fragment, struct pandecode_fbd GENX(pandecode_fbd)(struct pandecode_context *ctx,
uint64_t gpu_va, bool is_fragment,
unsigned gpu_id); unsigned gpu_id);
#if PAN_ARCH >= 9 #if PAN_ARCH >= 9
void GENX(pandecode_dcd)(const struct MALI_DRAW *p, unsigned unused, void GENX(pandecode_dcd)(struct pandecode_context *ctx,
const struct MALI_DRAW *p, unsigned unused,
unsigned gpu_id); unsigned gpu_id);
#else #else
void GENX(pandecode_dcd)(const struct MALI_DRAW *p, enum mali_job_type job_type, void GENX(pandecode_dcd)(struct pandecode_context *ctx,
const struct MALI_DRAW *p, enum mali_job_type job_type,
unsigned gpu_id); unsigned gpu_id);
#endif #endif
#if PAN_ARCH <= 5 #if PAN_ARCH <= 5
void GENX(pandecode_texture)(mali_ptr u, unsigned tex); void GENX(pandecode_texture)(struct pandecode_context *ctx, mali_ptr u,
unsigned tex);
#else #else
void GENX(pandecode_texture)(const void *cl, unsigned tex); void GENX(pandecode_texture)(struct pandecode_context *ctx, const void *cl,
unsigned tex);
#endif #endif
#if PAN_ARCH >= 5 #if PAN_ARCH >= 5
mali_ptr GENX(pandecode_blend)(void *descs, int rt_no, mali_ptr frag_shader); mali_ptr GENX(pandecode_blend)(struct pandecode_context *ctx, void *descs,
int rt_no, mali_ptr frag_shader);
#endif #endif
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
void GENX(pandecode_tiler)(mali_ptr gpu_va, unsigned gpu_id); void GENX(pandecode_tiler)(struct pandecode_context *ctx, mali_ptr gpu_va,
unsigned gpu_id);
#endif #endif
#if PAN_ARCH >= 9 #if PAN_ARCH >= 9
void GENX(pandecode_shader_environment)(const struct MALI_SHADER_ENVIRONMENT *p, void GENX(pandecode_shader_environment)(struct pandecode_context *ctx,
const struct MALI_SHADER_ENVIRONMENT *p,
unsigned gpu_id); unsigned gpu_id);
void GENX(pandecode_resource_tables)(mali_ptr addr, const char *label); void GENX(pandecode_resource_tables)(struct pandecode_context *ctx,
mali_ptr addr, const char *label);
void GENX(pandecode_fau)(mali_ptr addr, unsigned count, const char *name); void GENX(pandecode_fau)(struct pandecode_context *ctx, mali_ptr addr,
unsigned count, const char *name);
mali_ptr GENX(pandecode_shader)(mali_ptr addr, const char *label, mali_ptr GENX(pandecode_shader)(struct pandecode_context *ctx, mali_ptr addr,
unsigned gpu_id); const char *label, unsigned gpu_id);
void GENX(pandecode_blend_descs)(mali_ptr blend, unsigned count, void GENX(pandecode_blend_descs)(struct pandecode_context *ctx, mali_ptr blend,
mali_ptr frag_shader, unsigned gpu_id); unsigned count, mali_ptr frag_shader,
unsigned gpu_id);
void GENX(pandecode_depth_stencil)(mali_ptr addr); void GENX(pandecode_depth_stencil)(struct pandecode_context *ctx,
mali_ptr addr);
#endif #endif
#endif #endif

View file

@ -31,9 +31,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include "util/macros.h" #include "util/macros.h"
#include "util/simple_mtx.h"
#include "util/u_debug.h" #include "util/u_debug.h"
#include "util/u_dynarray.h"
#include "util/u_hexdump.h" #include "util/u_hexdump.h"
#include "decode.h" #include "decode.h"
@ -41,17 +39,9 @@
#include "compiler/valhall/disassemble.h" #include "compiler/valhall/disassemble.h"
#include "midgard/disassemble.h" #include "midgard/disassemble.h"
FILE *pandecode_dump_stream; /* Used to distiguish dumped files, otherwise we would have to print the ctx
* pointer, which is annoying for the user since it changes with every run */
unsigned pandecode_indent; static int num_ctxs = 0;
/* Memory handling */
static struct rb_tree mmap_tree;
static struct util_dynarray ro_mappings;
static simple_mtx_t pandecode_lock = SIMPLE_MTX_INITIALIZER;
#define to_mapped_memory(x) \ #define to_mapped_memory(x) \
rb_node_data(struct pandecode_mapped_memory, x, node) rb_node_data(struct pandecode_mapped_memory, x, node)
@ -80,27 +70,31 @@ pandecode_cmp(const struct rb_node *lhs, const struct rb_node *rhs)
} }
static struct pandecode_mapped_memory * static struct pandecode_mapped_memory *
pandecode_find_mapped_gpu_mem_containing_rw(uint64_t addr) pandecode_find_mapped_gpu_mem_containing_rw(struct pandecode_context *ctx,
uint64_t addr)
{ {
simple_mtx_assert_locked(&pandecode_lock); simple_mtx_assert_locked(&ctx->lock);
struct rb_node *node = rb_tree_search(&mmap_tree, &addr, pandecode_cmp_key); struct rb_node *node =
rb_tree_search(&ctx->mmap_tree, &addr, pandecode_cmp_key);
return to_mapped_memory(node); return to_mapped_memory(node);
} }
struct pandecode_mapped_memory * struct pandecode_mapped_memory *
pandecode_find_mapped_gpu_mem_containing(uint64_t addr) pandecode_find_mapped_gpu_mem_containing(struct pandecode_context *ctx,
uint64_t addr)
{ {
simple_mtx_assert_locked(&pandecode_lock); simple_mtx_assert_locked(&ctx->lock);
struct pandecode_mapped_memory *mem = struct pandecode_mapped_memory *mem =
pandecode_find_mapped_gpu_mem_containing_rw(addr); pandecode_find_mapped_gpu_mem_containing_rw(ctx, addr);
if (mem && mem->addr && !mem->ro) { if (mem && mem->addr && !mem->ro) {
mprotect(mem->addr, mem->length, PROT_READ); mprotect(mem->addr, mem->length, PROT_READ);
mem->ro = true; mem->ro = true;
util_dynarray_append(&ro_mappings, struct pandecode_mapped_memory *, mem); util_dynarray_append(&ctx->ro_mappings, struct pandecode_mapped_memory *,
mem);
} }
return mem; return mem;
@ -112,20 +106,21 @@ pandecode_find_mapped_gpu_mem_containing(uint64_t addr)
* detect GPU-side memory bugs by validating pointers. * detect GPU-side memory bugs by validating pointers.
*/ */
void void
pandecode_validate_buffer(mali_ptr addr, size_t sz) pandecode_validate_buffer(struct pandecode_context *ctx, mali_ptr addr,
size_t sz)
{ {
if (!addr) { if (!addr) {
pandecode_log("// XXX: null pointer deref\n"); pandecode_log(ctx, "// XXX: null pointer deref\n");
return; return;
} }
/* Find a BO */ /* Find a BO */
struct pandecode_mapped_memory *bo = struct pandecode_mapped_memory *bo =
pandecode_find_mapped_gpu_mem_containing(addr); pandecode_find_mapped_gpu_mem_containing(ctx, addr);
if (!bo) { if (!bo) {
pandecode_log("// XXX: invalid memory dereference\n"); pandecode_log(ctx, "// XXX: invalid memory dereference\n");
return; return;
} }
@ -135,7 +130,8 @@ pandecode_validate_buffer(mali_ptr addr, size_t sz)
unsigned total = offset + sz; unsigned total = offset + sz;
if (total > bo->length) { if (total > bo->length) {
pandecode_log("// XXX: buffer overrun. " pandecode_log(ctx,
"// XXX: buffer overrun. "
"Chunk of size %zu at offset %d in buffer of size %zu. " "Chunk of size %zu at offset %d in buffer of size %zu. "
"Overrun by %zu bytes. \n", "Overrun by %zu bytes. \n",
sz, offset, bo->length, total - bo->length); sz, offset, bo->length, total - bo->length);
@ -144,22 +140,24 @@ pandecode_validate_buffer(mali_ptr addr, size_t sz)
} }
void void
pandecode_map_read_write(void) pandecode_map_read_write(struct pandecode_context *ctx)
{ {
simple_mtx_assert_locked(&pandecode_lock); simple_mtx_assert_locked(&ctx->lock);
util_dynarray_foreach(&ro_mappings, struct pandecode_mapped_memory *, mem) { util_dynarray_foreach(&ctx->ro_mappings, struct pandecode_mapped_memory *,
mem) {
(*mem)->ro = false; (*mem)->ro = false;
mprotect((*mem)->addr, (*mem)->length, PROT_READ | PROT_WRITE); mprotect((*mem)->addr, (*mem)->length, PROT_READ | PROT_WRITE);
} }
util_dynarray_clear(&ro_mappings); util_dynarray_clear(&ctx->ro_mappings);
} }
static void static void
pandecode_add_name(struct pandecode_mapped_memory *mem, uint64_t gpu_va, pandecode_add_name(struct pandecode_context *ctx,
struct pandecode_mapped_memory *mem, uint64_t gpu_va,
const char *name) const char *name)
{ {
simple_mtx_assert_locked(&pandecode_lock); simple_mtx_assert_locked(&ctx->lock);
if (!name) { if (!name) {
/* If we don't have a name, assign one */ /* If we don't have a name, assign one */
@ -172,19 +170,20 @@ pandecode_add_name(struct pandecode_mapped_memory *mem, uint64_t gpu_va,
} }
void void
pandecode_inject_mmap(uint64_t gpu_va, void *cpu, unsigned sz, const char *name) pandecode_inject_mmap(struct pandecode_context *ctx, uint64_t gpu_va, void *cpu,
unsigned sz, const char *name)
{ {
simple_mtx_lock(&pandecode_lock); simple_mtx_lock(&ctx->lock);
/* First, search if we already mapped this and are just updating an address */ /* First, search if we already mapped this and are just updating an address */
struct pandecode_mapped_memory *existing = struct pandecode_mapped_memory *existing =
pandecode_find_mapped_gpu_mem_containing_rw(gpu_va); pandecode_find_mapped_gpu_mem_containing_rw(ctx, gpu_va);
if (existing && existing->gpu_va == gpu_va) { if (existing && existing->gpu_va == gpu_va) {
existing->length = sz; existing->length = sz;
existing->addr = cpu; existing->addr = cpu;
pandecode_add_name(existing, gpu_va, name); pandecode_add_name(ctx, existing, gpu_va, name);
} else { } else {
/* Otherwise, add a fresh mapping */ /* Otherwise, add a fresh mapping */
struct pandecode_mapped_memory *mapped_mem = NULL; struct pandecode_mapped_memory *mapped_mem = NULL;
@ -193,45 +192,46 @@ pandecode_inject_mmap(uint64_t gpu_va, void *cpu, unsigned sz, const char *name)
mapped_mem->gpu_va = gpu_va; mapped_mem->gpu_va = gpu_va;
mapped_mem->length = sz; mapped_mem->length = sz;
mapped_mem->addr = cpu; mapped_mem->addr = cpu;
pandecode_add_name(mapped_mem, gpu_va, name); pandecode_add_name(ctx, mapped_mem, gpu_va, name);
/* Add it to the tree */ /* Add it to the tree */
rb_tree_insert(&mmap_tree, &mapped_mem->node, pandecode_cmp); rb_tree_insert(&ctx->mmap_tree, &mapped_mem->node, pandecode_cmp);
} }
simple_mtx_unlock(&pandecode_lock); simple_mtx_unlock(&ctx->lock);
} }
void void
pandecode_inject_free(uint64_t gpu_va, unsigned sz) pandecode_inject_free(struct pandecode_context *ctx, uint64_t gpu_va,
unsigned sz)
{ {
simple_mtx_lock(&pandecode_lock); simple_mtx_lock(&ctx->lock);
struct pandecode_mapped_memory *mem = struct pandecode_mapped_memory *mem =
pandecode_find_mapped_gpu_mem_containing_rw(gpu_va); pandecode_find_mapped_gpu_mem_containing_rw(ctx, gpu_va);
if (mem) { if (mem) {
assert(mem->gpu_va == gpu_va); assert(mem->gpu_va == gpu_va);
assert(mem->length == sz); assert(mem->length == sz);
rb_tree_remove(&mmap_tree, &mem->node); rb_tree_remove(&ctx->mmap_tree, &mem->node);
free(mem); free(mem);
} }
simple_mtx_unlock(&pandecode_lock); simple_mtx_unlock(&ctx->lock);
} }
char * char *
pointer_as_memory_reference(uint64_t ptr) pointer_as_memory_reference(struct pandecode_context *ctx, uint64_t ptr)
{ {
simple_mtx_assert_locked(&pandecode_lock); simple_mtx_assert_locked(&ctx->lock);
struct pandecode_mapped_memory *mapped; struct pandecode_mapped_memory *mapped;
char *out = malloc(128); char *out = malloc(128);
/* Try to find the corresponding mapped zone */ /* Try to find the corresponding mapped zone */
mapped = pandecode_find_mapped_gpu_mem_containing_rw(ptr); mapped = pandecode_find_mapped_gpu_mem_containing_rw(ctx, ptr);
if (mapped) { if (mapped) {
snprintf(out, 128, "%s + %d", mapped->name, (int)(ptr - mapped->gpu_va)); snprintf(out, 128, "%s + %d", mapped->name, (int)(ptr - mapped->gpu_va));
@ -244,32 +244,25 @@ pointer_as_memory_reference(uint64_t ptr)
return out; return out;
} }
static int pandecode_dump_frame_count = 0;
static bool force_stderr = false;
void void
pandecode_dump_file_open(void) pandecode_dump_file_open(struct pandecode_context *ctx)
{ {
simple_mtx_assert_locked(&pandecode_lock); simple_mtx_assert_locked(&ctx->lock);
if (pandecode_dump_stream)
return;
/* This does a getenv every frame, so it is possible to use /* This does a getenv every frame, so it is possible to use
* setenv to change the base at runtime. * setenv to change the base at runtime.
*/ */
const char *dump_file_base = const char *dump_file_base =
debug_get_option("PANDECODE_DUMP_FILE", "pandecode.dump"); debug_get_option("PANDECODE_DUMP_FILE", "pandecode.dump");
if (force_stderr || !strcmp(dump_file_base, "stderr")) if (!strcmp(dump_file_base, "stderr"))
pandecode_dump_stream = stdout; // stderr; ctx->dump_stream = stderr;
else { else if (!ctx->dump_stream) {
char buffer[1024]; char buffer[1024];
snprintf(buffer, sizeof(buffer), "%s.%04d", dump_file_base, snprintf(buffer, sizeof(buffer), "%s.ctx-%d.%04d", dump_file_base,
pandecode_dump_frame_count); ctx->id, ctx->dump_frame_count);
printf("pandecode: dump command stream to file %s\n", buffer); printf("pandecode: dump command stream to file %s\n", buffer);
pandecode_dump_stream = fopen(buffer, "w"); ctx->dump_stream = fopen(buffer, "w");
if (!pandecode_dump_stream) if (!ctx->dump_stream)
fprintf(stderr, fprintf(stderr,
"pandecode: failed to open command stream log file %s\n", "pandecode: failed to open command stream log file %s\n",
buffer); buffer);
@ -277,171 +270,191 @@ pandecode_dump_file_open(void)
} }
static void static void
pandecode_dump_file_close(void) pandecode_dump_file_close(struct pandecode_context *ctx)
{ {
simple_mtx_assert_locked(&pandecode_lock); simple_mtx_assert_locked(&ctx->lock);
if (pandecode_dump_stream && pandecode_dump_stream != stderr) { if (ctx->dump_stream && ctx->dump_stream != stderr) {
if (fclose(pandecode_dump_stream)) if (fclose(ctx->dump_stream))
perror("pandecode: dump file"); perror("pandecode: dump file");
pandecode_dump_stream = NULL; ctx->dump_stream = NULL;
} }
} }
void struct pandecode_context *
pandecode_initialize(bool to_stderr) pandecode_create_context(bool to_stderr)
{ {
force_stderr = to_stderr; struct pandecode_context *ctx = calloc(1, sizeof(*ctx));
rb_tree_init(&mmap_tree);
util_dynarray_init(&ro_mappings, NULL); /* Not thread safe, but we shouldn't ever hit this, and even if we do, the
* worst that could happen is having the files dumped with their filenames
* in a different order. */
ctx->id = num_ctxs++;
/* This will be initialized later and can be changed at run time through
* the PANDECODE_DUMP_FILE environment variable.
*/
ctx->dump_stream = to_stderr ? stderr : NULL;
rb_tree_init(&ctx->mmap_tree);
util_dynarray_init(&ctx->ro_mappings, NULL);
simple_mtx_t mtx_init = SIMPLE_MTX_INITIALIZER;
memcpy(&ctx->lock, &mtx_init, sizeof(simple_mtx_t));
return ctx;
} }
void void
pandecode_next_frame(void) pandecode_next_frame(struct pandecode_context *ctx)
{ {
simple_mtx_lock(&pandecode_lock); simple_mtx_lock(&ctx->lock);
pandecode_dump_file_close(); pandecode_dump_file_close(ctx);
pandecode_dump_frame_count++; ctx->dump_frame_count++;
simple_mtx_unlock(&pandecode_lock); simple_mtx_unlock(&ctx->lock);
} }
void void
pandecode_close(void) pandecode_destroy_context(struct pandecode_context *ctx)
{ {
simple_mtx_lock(&pandecode_lock); simple_mtx_lock(&ctx->lock);
rb_tree_foreach_safe(struct pandecode_mapped_memory, it, &mmap_tree, node) { rb_tree_foreach_safe(struct pandecode_mapped_memory, it, &ctx->mmap_tree,
rb_tree_remove(&mmap_tree, &it->node); node) {
rb_tree_remove(&ctx->mmap_tree, &it->node);
free(it); free(it);
} }
util_dynarray_fini(&ro_mappings); util_dynarray_fini(&ctx->ro_mappings);
pandecode_dump_file_close(); pandecode_dump_file_close(ctx);
simple_mtx_unlock(&pandecode_lock); simple_mtx_unlock(&ctx->lock);
free(ctx);
} }
void void
pandecode_dump_mappings(void) pandecode_dump_mappings(struct pandecode_context *ctx)
{ {
simple_mtx_lock(&pandecode_lock); simple_mtx_lock(&ctx->lock);
pandecode_dump_file_open(); pandecode_dump_file_open(ctx);
rb_tree_foreach(struct pandecode_mapped_memory, it, &mmap_tree, node) { rb_tree_foreach(struct pandecode_mapped_memory, it, &ctx->mmap_tree, node) {
if (!it->addr || !it->length) if (!it->addr || !it->length)
continue; continue;
fprintf(pandecode_dump_stream, "Buffer: %s gpu %" PRIx64 "\n\n", it->name, fprintf(ctx->dump_stream, "Buffer: %s gpu %" PRIx64 "\n\n", it->name,
it->gpu_va); it->gpu_va);
u_hexdump(pandecode_dump_stream, it->addr, it->length, false); u_hexdump(ctx->dump_stream, it->addr, it->length, false);
fprintf(pandecode_dump_stream, "\n"); fprintf(ctx->dump_stream, "\n");
} }
fflush(pandecode_dump_stream); fflush(ctx->dump_stream);
simple_mtx_unlock(&pandecode_lock); simple_mtx_unlock(&ctx->lock);
} }
void void
pandecode_abort_on_fault(mali_ptr jc_gpu_va, unsigned gpu_id) pandecode_abort_on_fault(struct pandecode_context *ctx, mali_ptr jc_gpu_va,
unsigned gpu_id)
{ {
simple_mtx_lock(&pandecode_lock); simple_mtx_lock(&ctx->lock);
switch (pan_arch(gpu_id)) { switch (pan_arch(gpu_id)) {
case 4: case 4:
pandecode_abort_on_fault_v4(jc_gpu_va); pandecode_abort_on_fault_v4(ctx, jc_gpu_va);
break; break;
case 5: case 5:
pandecode_abort_on_fault_v5(jc_gpu_va); pandecode_abort_on_fault_v5(ctx, jc_gpu_va);
break; break;
case 6: case 6:
pandecode_abort_on_fault_v6(jc_gpu_va); pandecode_abort_on_fault_v6(ctx, jc_gpu_va);
break; break;
case 7: case 7:
pandecode_abort_on_fault_v7(jc_gpu_va); pandecode_abort_on_fault_v7(ctx, jc_gpu_va);
break; break;
case 9: case 9:
pandecode_abort_on_fault_v9(jc_gpu_va); pandecode_abort_on_fault_v9(ctx, jc_gpu_va);
break; break;
default: default:
unreachable("Unsupported architecture"); unreachable("Unsupported architecture");
} }
simple_mtx_unlock(&pandecode_lock); simple_mtx_unlock(&ctx->lock);
} }
void void
pandecode_jc(mali_ptr jc_gpu_va, unsigned gpu_id) pandecode_jc(struct pandecode_context *ctx, mali_ptr jc_gpu_va, unsigned gpu_id)
{ {
simple_mtx_lock(&pandecode_lock); simple_mtx_lock(&ctx->lock);
switch (pan_arch(gpu_id)) { switch (pan_arch(gpu_id)) {
case 4: case 4:
pandecode_jc_v4(jc_gpu_va, gpu_id); pandecode_jc_v4(ctx, jc_gpu_va, gpu_id);
break; break;
case 5: case 5:
pandecode_jc_v5(jc_gpu_va, gpu_id); pandecode_jc_v5(ctx, jc_gpu_va, gpu_id);
break; break;
case 6: case 6:
pandecode_jc_v6(jc_gpu_va, gpu_id); pandecode_jc_v6(ctx, jc_gpu_va, gpu_id);
break; break;
case 7: case 7:
pandecode_jc_v7(jc_gpu_va, gpu_id); pandecode_jc_v7(ctx, jc_gpu_va, gpu_id);
break; break;
case 9: case 9:
pandecode_jc_v9(jc_gpu_va, gpu_id); pandecode_jc_v9(ctx, jc_gpu_va, gpu_id);
break; break;
default: default:
unreachable("Unsupported architecture"); unreachable("Unsupported architecture");
} }
simple_mtx_unlock(&pandecode_lock); simple_mtx_unlock(&ctx->lock);
} }
void void
pandecode_cs(mali_ptr queue_gpu_va, uint32_t size, unsigned gpu_id, pandecode_cs(struct pandecode_context *ctx, mali_ptr queue_gpu_va,
uint32_t *regs) uint32_t size, unsigned gpu_id, uint32_t *regs)
{ {
simple_mtx_lock(&pandecode_lock); simple_mtx_lock(&ctx->lock);
switch (pan_arch(gpu_id)) { switch (pan_arch(gpu_id)) {
case 10: case 10:
pandecode_cs_v10(queue_gpu_va, size, gpu_id, regs); pandecode_cs_v10(ctx, queue_gpu_va, size, gpu_id, regs);
break; break;
default: default:
unreachable("Unsupported architecture"); unreachable("Unsupported architecture");
} }
simple_mtx_unlock(&pandecode_lock); simple_mtx_unlock(&ctx->lock);
} }
void void
pandecode_shader_disassemble(mali_ptr shader_ptr, unsigned gpu_id) pandecode_shader_disassemble(struct pandecode_context *ctx, mali_ptr shader_ptr,
unsigned gpu_id)
{ {
uint8_t *PANDECODE_PTR_VAR(code, shader_ptr); uint8_t *PANDECODE_PTR_VAR(ctx, code, shader_ptr);
/* Compute maximum possible size */ /* Compute maximum possible size */
struct pandecode_mapped_memory *mem = struct pandecode_mapped_memory *mem =
pandecode_find_mapped_gpu_mem_containing(shader_ptr); pandecode_find_mapped_gpu_mem_containing(ctx, shader_ptr);
size_t sz = mem->length - (shader_ptr - mem->gpu_va); size_t sz = mem->length - (shader_ptr - mem->gpu_va);
/* Print some boilerplate to clearly denote the assembly (which doesn't /* Print some boilerplate to clearly denote the assembly (which doesn't
* obey indentation rules), and actually do the disassembly! */ * obey indentation rules), and actually do the disassembly! */
pandecode_log_cont("\nShader %p (GPU VA %" PRIx64 ") sz %" PRId64 "\n", code, pandecode_log_cont(ctx, "\nShader %p (GPU VA %" PRIx64 ") sz %" PRId64 "\n",
shader_ptr, sz); code, shader_ptr, sz);
if (pan_arch(gpu_id) >= 9) { if (pan_arch(gpu_id) >= 9) {
disassemble_valhall(pandecode_dump_stream, (const uint64_t *)code, sz, disassemble_valhall(ctx->dump_stream, (const uint64_t *)code, sz, true);
true);
} else if (pan_arch(gpu_id) >= 6) } else if (pan_arch(gpu_id) >= 6)
disassemble_bifrost(pandecode_dump_stream, code, sz, false); disassemble_bifrost(ctx->dump_stream, code, sz, false);
else else
disassemble_midgard(pandecode_dump_stream, code, sz, gpu_id, true); disassemble_midgard(ctx->dump_stream, code, sz, gpu_id, true);
pandecode_log_cont("\n\n"); pandecode_log_cont(ctx, "\n\n");
} }

View file

@ -55,21 +55,21 @@ struct queue_ctx {
}; };
static uint32_t static uint32_t
cs_get_u32(struct queue_ctx *ctx, uint8_t reg) cs_get_u32(struct queue_ctx *qctx, uint8_t reg)
{ {
assert(reg < ctx->nr_regs); assert(reg < qctx->nr_regs);
return ctx->regs[reg]; return qctx->regs[reg];
} }
static uint64_t static uint64_t
cs_get_u64(struct queue_ctx *ctx, uint8_t reg) cs_get_u64(struct queue_ctx *qctx, uint8_t reg)
{ {
return (((uint64_t)cs_get_u32(ctx, reg + 1)) << 32) | cs_get_u32(ctx, reg); return (((uint64_t)cs_get_u32(qctx, reg + 1)) << 32) | cs_get_u32(qctx, reg);
} }
static void static void
pandecode_run_compute(FILE *fp, struct queue_ctx *ctx, pandecode_run_compute(struct pandecode_context *ctx, FILE *fp,
struct MALI_CEU_RUN_COMPUTE *I) struct queue_ctx *qctx, struct MALI_CEU_RUN_COMPUTE *I)
{ {
const char *axes[4] = {"x_axis", "y_axis", "z_axis"}; const char *axes[4] = {"x_axis", "y_axis", "z_axis"};
@ -78,39 +78,41 @@ pandecode_run_compute(FILE *fp, struct queue_ctx *ctx,
*/ */
fprintf(fp, "RUN_COMPUTE.%s #%u\n", axes[I->task_axis], I->task_increment); fprintf(fp, "RUN_COMPUTE.%s #%u\n", axes[I->task_axis], I->task_increment);
pandecode_indent++; ctx->indent++;
unsigned reg_srt = 0 + (I->srt_select * 2); unsigned reg_srt = 0 + (I->srt_select * 2);
unsigned reg_fau = 8 + (I->fau_select * 2); unsigned reg_fau = 8 + (I->fau_select * 2);
unsigned reg_spd = 16 + (I->spd_select * 2); unsigned reg_spd = 16 + (I->spd_select * 2);
unsigned reg_tsd = 24 + (I->tsd_select * 2); unsigned reg_tsd = 24 + (I->tsd_select * 2);
GENX(pandecode_resource_tables)(cs_get_u64(ctx, reg_srt), "Resources"); GENX(pandecode_resource_tables)(ctx, cs_get_u64(qctx, reg_srt), "Resources");
mali_ptr fau = cs_get_u64(ctx, reg_fau); mali_ptr fau = cs_get_u64(qctx, reg_fau);
if (fau) if (fau)
GENX(pandecode_fau)(fau & BITFIELD64_MASK(48), fau >> 56, "FAU"); GENX(pandecode_fau)(ctx, fau & BITFIELD64_MASK(48), fau >> 56, "FAU");
GENX(pandecode_shader)(cs_get_u64(ctx, reg_spd), "Shader", ctx->gpu_id); GENX(pandecode_shader)
(ctx, cs_get_u64(qctx, reg_spd), "Shader", qctx->gpu_id);
DUMP_ADDR(LOCAL_STORAGE, cs_get_u64(ctx, reg_tsd), DUMP_ADDR(ctx, LOCAL_STORAGE, cs_get_u64(qctx, reg_tsd),
"Local Storage @%" PRIx64 ":\n", cs_get_u64(ctx, reg_tsd)); "Local Storage @%" PRIx64 ":\n", cs_get_u64(qctx, reg_tsd));
pandecode_log("Global attribute offset: %u\n", cs_get_u32(ctx, 32)); pandecode_log(ctx, "Global attribute offset: %u\n", cs_get_u32(qctx, 32));
DUMP_CL(COMPUTE_SIZE_WORKGROUP, &ctx->regs[33], "Workgroup size\n"); DUMP_CL(ctx, COMPUTE_SIZE_WORKGROUP, &qctx->regs[33], "Workgroup size\n");
pandecode_log("Job offset X: %u\n", cs_get_u32(ctx, 34)); pandecode_log(ctx, "Job offset X: %u\n", cs_get_u32(qctx, 34));
pandecode_log("Job offset Y: %u\n", cs_get_u32(ctx, 35)); pandecode_log(ctx, "Job offset Y: %u\n", cs_get_u32(qctx, 35));
pandecode_log("Job offset Z: %u\n", cs_get_u32(ctx, 36)); pandecode_log(ctx, "Job offset Z: %u\n", cs_get_u32(qctx, 36));
pandecode_log("Job size X: %u\n", cs_get_u32(ctx, 37)); pandecode_log(ctx, "Job size X: %u\n", cs_get_u32(qctx, 37));
pandecode_log("Job size Y: %u\n", cs_get_u32(ctx, 38)); pandecode_log(ctx, "Job size Y: %u\n", cs_get_u32(qctx, 38));
pandecode_log("Job size Z: %u\n", cs_get_u32(ctx, 39)); pandecode_log(ctx, "Job size Z: %u\n", cs_get_u32(qctx, 39));
pandecode_indent--; ctx->indent--;
} }
static void static void
pandecode_run_idvs(FILE *fp, struct queue_ctx *ctx, struct MALI_CEU_RUN_IDVS *I) pandecode_run_idvs(struct pandecode_context *ctx, FILE *fp,
struct queue_ctx *qctx, struct MALI_CEU_RUN_IDVS *I)
{ {
/* Print the instruction. Ignore the selects and the flags override /* Print the instruction. Ignore the selects and the flags override
* since we'll print them implicitly later. * since we'll print them implicitly later.
@ -122,10 +124,10 @@ pandecode_run_idvs(FILE *fp, struct queue_ctx *ctx, struct MALI_CEU_RUN_IDVS *I)
fprintf(fp, "\n"); fprintf(fp, "\n");
pandecode_indent++; ctx->indent++;
/* Merge flag overrides with the register flags */ /* Merge flag overrides with the register flags */
uint32_t tiler_flags_raw = cs_get_u64(ctx, 56); uint32_t tiler_flags_raw = cs_get_u64(qctx, 56);
tiler_flags_raw |= I->flags_override; tiler_flags_raw |= I->flags_override;
pan_unpack(&tiler_flags_raw, PRIMITIVE_FLAGS, tiler_flags); pan_unpack(&tiler_flags_raw, PRIMITIVE_FLAGS, tiler_flags);
@ -141,110 +143,113 @@ pandecode_run_idvs(FILE *fp, struct queue_ctx *ctx, struct MALI_CEU_RUN_IDVS *I)
unsigned reg_frag_fau = 12; unsigned reg_frag_fau = 12;
unsigned reg_frag_tsd = I->fragment_tsd_select ? 28 : 24; unsigned reg_frag_tsd = I->fragment_tsd_select ? 28 : 24;
uint64_t position_srt = cs_get_u64(ctx, reg_position_srt); uint64_t position_srt = cs_get_u64(qctx, reg_position_srt);
uint64_t vary_srt = cs_get_u64(ctx, reg_vary_srt); uint64_t vary_srt = cs_get_u64(qctx, reg_vary_srt);
uint64_t frag_srt = cs_get_u64(ctx, reg_frag_srt); uint64_t frag_srt = cs_get_u64(qctx, reg_frag_srt);
GENX(pandecode_resource_tables)(position_srt, "Position resources"); GENX(pandecode_resource_tables)(ctx, position_srt, "Position resources");
GENX(pandecode_resource_tables)(vary_srt, "Varying resources"); GENX(pandecode_resource_tables)(ctx, vary_srt, "Varying resources");
GENX(pandecode_resource_tables)(frag_srt, "Fragment resources"); GENX(pandecode_resource_tables)(ctx, frag_srt, "Fragment resources");
mali_ptr position_fau = cs_get_u64(ctx, reg_position_fau); mali_ptr position_fau = cs_get_u64(qctx, reg_position_fau);
mali_ptr vary_fau = cs_get_u64(ctx, reg_vary_fau); mali_ptr vary_fau = cs_get_u64(qctx, reg_vary_fau);
mali_ptr fragment_fau = cs_get_u64(ctx, reg_frag_fau); mali_ptr fragment_fau = cs_get_u64(qctx, reg_frag_fau);
if (position_fau) { if (position_fau) {
uint64_t lo = position_fau & BITFIELD64_MASK(48); uint64_t lo = position_fau & BITFIELD64_MASK(48);
uint64_t hi = position_fau >> 56; uint64_t hi = position_fau >> 56;
GENX(pandecode_fau)(lo, hi, "Position FAU"); GENX(pandecode_fau)(ctx, lo, hi, "Position FAU");
} }
if (vary_fau) { if (vary_fau) {
uint64_t lo = vary_fau & BITFIELD64_MASK(48); uint64_t lo = vary_fau & BITFIELD64_MASK(48);
uint64_t hi = vary_fau >> 56; uint64_t hi = vary_fau >> 56;
GENX(pandecode_fau)(lo, hi, "Varying FAU"); GENX(pandecode_fau)(ctx, lo, hi, "Varying FAU");
} }
if (fragment_fau) { if (fragment_fau) {
uint64_t lo = fragment_fau & BITFIELD64_MASK(48); uint64_t lo = fragment_fau & BITFIELD64_MASK(48);
uint64_t hi = fragment_fau >> 56; uint64_t hi = fragment_fau >> 56;
GENX(pandecode_fau)(lo, hi, "Fragment FAU"); GENX(pandecode_fau)(ctx, lo, hi, "Fragment FAU");
} }
GENX(pandecode_shader)(cs_get_u64(ctx, 16), "Position shader", ctx->gpu_id); GENX(pandecode_shader)
(ctx, cs_get_u64(qctx, 16), "Position shader", qctx->gpu_id);
if (tiler_flags.secondary_shader) { if (tiler_flags.secondary_shader) {
uint64_t ptr = cs_get_u64(ctx, 18); uint64_t ptr = cs_get_u64(qctx, 18);
GENX(pandecode_shader)(ptr, "Varying shader", ctx->gpu_id); GENX(pandecode_shader)(ctx, ptr, "Varying shader", qctx->gpu_id);
} }
GENX(pandecode_shader)(cs_get_u64(ctx, 20), "Fragment shader", ctx->gpu_id); GENX(pandecode_shader)
(ctx, cs_get_u64(qctx, 20), "Fragment shader", qctx->gpu_id);
DUMP_ADDR(LOCAL_STORAGE, cs_get_u64(ctx, 24), DUMP_ADDR(ctx, LOCAL_STORAGE, cs_get_u64(qctx, 24),
"Position Local Storage @%" PRIx64 ":\n", "Position Local Storage @%" PRIx64 ":\n",
cs_get_u64(ctx, reg_position_tsd)); cs_get_u64(qctx, reg_position_tsd));
DUMP_ADDR(LOCAL_STORAGE, cs_get_u64(ctx, 24), DUMP_ADDR(ctx, LOCAL_STORAGE, cs_get_u64(qctx, 24),
"Varying Local Storage @%" PRIx64 ":\n", "Varying Local Storage @%" PRIx64 ":\n",
cs_get_u64(ctx, reg_vary_tsd)); cs_get_u64(qctx, reg_vary_tsd));
DUMP_ADDR(LOCAL_STORAGE, cs_get_u64(ctx, 30), DUMP_ADDR(ctx, LOCAL_STORAGE, cs_get_u64(qctx, 30),
"Fragment Local Storage @%" PRIx64 ":\n", "Fragment Local Storage @%" PRIx64 ":\n",
cs_get_u64(ctx, reg_frag_tsd)); cs_get_u64(qctx, reg_frag_tsd));
pandecode_log("Global attribute offset: %u\n", cs_get_u32(ctx, 32)); pandecode_log(ctx, "Global attribute offset: %u\n", cs_get_u32(qctx, 32));
pandecode_log("Index count: %u\n", cs_get_u32(ctx, 33)); pandecode_log(ctx, "Index count: %u\n", cs_get_u32(qctx, 33));
pandecode_log("Instance count: %u\n", cs_get_u32(ctx, 34)); pandecode_log(ctx, "Instance count: %u\n", cs_get_u32(qctx, 34));
if (tiler_flags.index_type) if (tiler_flags.index_type)
pandecode_log("Index offset: %u\n", cs_get_u32(ctx, 35)); pandecode_log(ctx, "Index offset: %u\n", cs_get_u32(qctx, 35));
pandecode_log("Vertex offset: %d\n", cs_get_u32(ctx, 36)); pandecode_log(ctx, "Vertex offset: %d\n", cs_get_u32(qctx, 36));
pandecode_log("Instance offset: %u\n", cs_get_u32(ctx, 37)); pandecode_log(ctx, "Instance offset: %u\n", cs_get_u32(qctx, 37));
pandecode_log("Tiler DCD flags2: %X\n", cs_get_u32(ctx, 38)); pandecode_log(ctx, "Tiler DCD flags2: %X\n", cs_get_u32(qctx, 38));
if (tiler_flags.index_type) if (tiler_flags.index_type)
pandecode_log("Index array size: %u\n", cs_get_u32(ctx, 39)); pandecode_log(ctx, "Index array size: %u\n", cs_get_u32(qctx, 39));
GENX(pandecode_tiler)(cs_get_u64(ctx, 40), ctx->gpu_id); GENX(pandecode_tiler)(ctx, cs_get_u64(qctx, 40), qctx->gpu_id);
DUMP_CL(SCISSOR, &ctx->regs[42], "Scissor\n"); DUMP_CL(ctx, SCISSOR, &qctx->regs[42], "Scissor\n");
pandecode_log("Low depth clamp: %f\n", uif(cs_get_u32(ctx, 44))); pandecode_log(ctx, "Low depth clamp: %f\n", uif(cs_get_u32(qctx, 44)));
pandecode_log("High depth clamp: %f\n", uif(cs_get_u32(ctx, 45))); pandecode_log(ctx, "High depth clamp: %f\n", uif(cs_get_u32(qctx, 45)));
pandecode_log("Occlusion: %" PRIx64 "\n", cs_get_u64(ctx, 46)); pandecode_log(ctx, "Occlusion: %" PRIx64 "\n", cs_get_u64(qctx, 46));
if (tiler_flags.secondary_shader) if (tiler_flags.secondary_shader)
pandecode_log("Varying allocation: %u\n", cs_get_u32(ctx, 48)); pandecode_log(ctx, "Varying allocation: %u\n", cs_get_u32(qctx, 48));
mali_ptr blend = cs_get_u64(ctx, 50); mali_ptr blend = cs_get_u64(qctx, 50);
GENX(pandecode_blend_descs)(blend & ~7, blend & 7, 0, ctx->gpu_id); GENX(pandecode_blend_descs)(ctx, blend & ~7, blend & 7, 0, qctx->gpu_id);
DUMP_ADDR(DEPTH_STENCIL, cs_get_u64(ctx, 52), "Depth/stencil"); DUMP_ADDR(ctx, DEPTH_STENCIL, cs_get_u64(qctx, 52), "Depth/stencil");
if (tiler_flags.index_type) if (tiler_flags.index_type)
pandecode_log("Indices: %" PRIx64 "\n", cs_get_u64(ctx, 54)); pandecode_log(ctx, "Indices: %" PRIx64 "\n", cs_get_u64(qctx, 54));
DUMP_UNPACKED(PRIMITIVE_FLAGS, tiler_flags, "Primitive flags\n"); DUMP_UNPACKED(ctx, PRIMITIVE_FLAGS, tiler_flags, "Primitive flags\n");
DUMP_CL(DCD_FLAGS_0, &ctx->regs[57], "DCD Flags 0\n"); DUMP_CL(ctx, DCD_FLAGS_0, &qctx->regs[57], "DCD Flags 0\n");
DUMP_CL(DCD_FLAGS_1, &ctx->regs[58], "DCD Flags 1\n"); DUMP_CL(ctx, DCD_FLAGS_1, &qctx->regs[58], "DCD Flags 1\n");
DUMP_CL(PRIMITIVE_SIZE, &ctx->regs[60], "Primitive size\n"); DUMP_CL(ctx, PRIMITIVE_SIZE, &qctx->regs[60], "Primitive size\n");
pandecode_indent--; ctx->indent--;
} }
static void static void
pandecode_run_fragment(struct queue_ctx *ctx, struct MALI_CEU_RUN_FRAGMENT *I) pandecode_run_fragment(struct pandecode_context *ctx, struct queue_ctx *qctx,
struct MALI_CEU_RUN_FRAGMENT *I)
{ {
pandecode_indent++; ctx->indent++;
DUMP_CL(SCISSOR, &ctx->regs[42], "Scissor\n"); DUMP_CL(ctx, SCISSOR, &qctx->regs[42], "Scissor\n");
/* TODO: Tile enable map */ /* TODO: Tile enable map */
GENX(pandecode_fbd)(cs_get_u64(ctx, 40), true, ctx->gpu_id); GENX(pandecode_fbd)(ctx, cs_get_u64(qctx, 40), true, qctx->gpu_id);
pandecode_indent--; ctx->indent--;
} }
static void static void
@ -271,8 +276,9 @@ print_reg_tuple(unsigned base, uint16_t mask, FILE *fp)
} }
static void static void
disassemble_ceu_instr(uint64_t dword, unsigned indent, bool verbose, FILE *fp, disassemble_ceu_instr(struct pandecode_context *ctx, uint64_t dword,
struct queue_ctx *ctx) unsigned indent, bool verbose, FILE *fp,
struct queue_ctx *qctx)
{ {
if (verbose) { if (verbose) {
fprintf(fp, " "); fprintf(fp, " ");
@ -327,13 +333,13 @@ disassemble_ceu_instr(uint64_t dword, unsigned indent, bool verbose, FILE *fp,
case MALI_CEU_OPCODE_RUN_COMPUTE: { case MALI_CEU_OPCODE_RUN_COMPUTE: {
pan_unpack(bytes, CEU_RUN_COMPUTE, I); pan_unpack(bytes, CEU_RUN_COMPUTE, I);
pandecode_run_compute(fp, ctx, &I); pandecode_run_compute(ctx, fp, qctx, &I);
break; break;
} }
case MALI_CEU_OPCODE_RUN_IDVS: { case MALI_CEU_OPCODE_RUN_IDVS: {
pan_unpack(bytes, CEU_RUN_IDVS, I); pan_unpack(bytes, CEU_RUN_IDVS, I);
pandecode_run_idvs(fp, ctx, &I); pandecode_run_idvs(ctx, fp, qctx, &I);
break; break;
} }
@ -341,7 +347,7 @@ disassemble_ceu_instr(uint64_t dword, unsigned indent, bool verbose, FILE *fp,
pan_unpack(bytes, CEU_RUN_FRAGMENT, I); pan_unpack(bytes, CEU_RUN_FRAGMENT, I);
fprintf(fp, "RUN_FRAGMENT%s\n", fprintf(fp, "RUN_FRAGMENT%s\n",
I.enable_tem ? ".tile_enable_map_enable" : ""); I.enable_tem ? ".tile_enable_map_enable" : "");
pandecode_run_fragment(ctx, &I); pandecode_run_fragment(ctx, qctx, &I);
break; break;
} }
@ -593,12 +599,12 @@ disassemble_ceu_instr(uint64_t dword, unsigned indent, bool verbose, FILE *fp,
} }
static bool static bool
interpret_ceu_jump(struct queue_ctx *ctx, uint64_t reg_address, interpret_ceu_jump(struct pandecode_context *ctx, struct queue_ctx *qctx,
uint32_t reg_length) uint64_t reg_address, uint32_t reg_length)
{ {
uint32_t address_lo = ctx->regs[reg_address]; uint32_t address_lo = qctx->regs[reg_address];
uint32_t address_hi = ctx->regs[reg_address + 1]; uint32_t address_hi = qctx->regs[reg_address + 1];
uint32_t length = ctx->regs[reg_length]; uint32_t length = qctx->regs[reg_length];
if (length % 8) { if (length % 8) {
fprintf(stderr, "CS call alignment error\n"); fprintf(stderr, "CS call alignment error\n");
@ -607,10 +613,10 @@ interpret_ceu_jump(struct queue_ctx *ctx, uint64_t reg_address,
/* Map the entire subqueue now */ /* Map the entire subqueue now */
uint64_t address = ((uint64_t)address_hi << 32) | address_lo; uint64_t address = ((uint64_t)address_hi << 32) | address_lo;
uint64_t *cs = pandecode_fetch_gpu_mem(address, length); uint64_t *cs = pandecode_fetch_gpu_mem(ctx, address, length);
ctx->ip = cs; qctx->ip = cs;
ctx->end = cs + (length / 8); qctx->end = cs + (length / 8);
/* Skip the usual IP update */ /* Skip the usual IP update */
return true; return true;
@ -624,34 +630,34 @@ interpret_ceu_jump(struct queue_ctx *ctx, uint64_t reg_address,
* Returns true if execution should continue. * Returns true if execution should continue.
*/ */
static bool static bool
interpret_ceu_instr(struct queue_ctx *ctx) interpret_ceu_instr(struct pandecode_context *ctx, struct queue_ctx *qctx)
{ {
/* Unpack the base so we get the opcode */ /* Unpack the base so we get the opcode */
uint8_t *bytes = (uint8_t *)ctx->ip; uint8_t *bytes = (uint8_t *)qctx->ip;
pan_unpack(bytes, CEU_BASE, base); pan_unpack(bytes, CEU_BASE, base);
assert(ctx->ip < ctx->end); assert(qctx->ip < qctx->end);
switch (base.opcode) { switch (base.opcode) {
case MALI_CEU_OPCODE_MOVE: { case MALI_CEU_OPCODE_MOVE: {
pan_unpack(bytes, CEU_MOVE, I); pan_unpack(bytes, CEU_MOVE, I);
ctx->regs[I.destination + 0] = (uint32_t)I.immediate; qctx->regs[I.destination + 0] = (uint32_t)I.immediate;
ctx->regs[I.destination + 1] = (uint32_t)(I.immediate >> 32); qctx->regs[I.destination + 1] = (uint32_t)(I.immediate >> 32);
break; break;
} }
case MALI_CEU_OPCODE_MOVE32: { case MALI_CEU_OPCODE_MOVE32: {
pan_unpack(bytes, CEU_MOVE32, I); pan_unpack(bytes, CEU_MOVE32, I);
ctx->regs[I.destination] = I.immediate; qctx->regs[I.destination] = I.immediate;
break; break;
} }
case MALI_CEU_OPCODE_ADD_IMMEDIATE32: { case MALI_CEU_OPCODE_ADD_IMMEDIATE32: {
pan_unpack(bytes, CEU_ADD_IMMEDIATE32, I); pan_unpack(bytes, CEU_ADD_IMMEDIATE32, I);
ctx->regs[I.destination] = ctx->regs[I.source] + I.immediate; qctx->regs[I.destination] = qctx->regs[I.source] + I.immediate;
break; break;
} }
@ -659,46 +665,46 @@ interpret_ceu_instr(struct queue_ctx *ctx)
pan_unpack(bytes, CEU_ADD_IMMEDIATE64, I); pan_unpack(bytes, CEU_ADD_IMMEDIATE64, I);
int64_t value = int64_t value =
(ctx->regs[I.source] | ((int64_t)ctx->regs[I.source + 1] << 32)) + (qctx->regs[I.source] | ((int64_t)qctx->regs[I.source + 1] << 32)) +
I.immediate; I.immediate;
ctx->regs[I.destination] = value; qctx->regs[I.destination] = value;
ctx->regs[I.destination + 1] = value >> 32; qctx->regs[I.destination + 1] = value >> 32;
break; break;
} }
case MALI_CEU_OPCODE_CALL: { case MALI_CEU_OPCODE_CALL: {
pan_unpack(bytes, CEU_CALL, I); pan_unpack(bytes, CEU_CALL, I);
if (ctx->call_stack_depth == MAX_CALL_STACK_DEPTH) { if (qctx->call_stack_depth == MAX_CALL_STACK_DEPTH) {
fprintf(stderr, "CS call stack overflow\n"); fprintf(stderr, "CS call stack overflow\n");
return false; return false;
} }
assert(ctx->call_stack_depth < MAX_CALL_STACK_DEPTH); assert(qctx->call_stack_depth < MAX_CALL_STACK_DEPTH);
ctx->ip++; qctx->ip++;
/* Note: tail calls are not optimized in the hardware. */ /* Note: tail calls are not optimized in the hardware. */
assert(ctx->ip <= ctx->end); assert(qctx->ip <= qctx->end);
unsigned depth = ctx->call_stack_depth++; unsigned depth = qctx->call_stack_depth++;
ctx->call_stack[depth].lr = ctx->ip; qctx->call_stack[depth].lr = qctx->ip;
ctx->call_stack[depth].end = ctx->end; qctx->call_stack[depth].end = qctx->end;
return interpret_ceu_jump(ctx, I.address, I.length); return interpret_ceu_jump(ctx, qctx, I.address, I.length);
} }
case MALI_CEU_OPCODE_JUMP: { case MALI_CEU_OPCODE_JUMP: {
pan_unpack(bytes, CEU_CALL, I); pan_unpack(bytes, CEU_CALL, I);
if (ctx->call_stack_depth == 0) { if (qctx->call_stack_depth == 0) {
fprintf(stderr, "Cannot jump from the entrypoint\n"); fprintf(stderr, "Cannot jump from the entrypoint\n");
return false; return false;
} }
return interpret_ceu_jump(ctx, I.address, I.length); return interpret_ceu_jump(ctx, qctx, I.address, I.length);
} }
default: default:
@ -708,35 +714,35 @@ interpret_ceu_instr(struct queue_ctx *ctx)
/* Update IP first to point to the next instruction, so call doesn't /* Update IP first to point to the next instruction, so call doesn't
* require special handling (even for tail calls). * require special handling (even for tail calls).
*/ */
ctx->ip++; qctx->ip++;
while (ctx->ip == ctx->end) { while (qctx->ip == qctx->end) {
/* Graceful termination */ /* Graceful termination */
if (ctx->call_stack_depth == 0) if (qctx->call_stack_depth == 0)
return false; return false;
/* Pop off the call stack */ /* Pop off the call stack */
unsigned old_depth = --ctx->call_stack_depth; unsigned old_depth = --qctx->call_stack_depth;
ctx->ip = ctx->call_stack[old_depth].lr; qctx->ip = qctx->call_stack[old_depth].lr;
ctx->end = ctx->call_stack[old_depth].end; qctx->end = qctx->call_stack[old_depth].end;
} }
return true; return true;
} }
void void
GENX(pandecode_cs)(mali_ptr queue, uint32_t size, unsigned gpu_id, GENX(pandecode_cs)(struct pandecode_context *ctx, mali_ptr queue, uint32_t size,
uint32_t *regs) unsigned gpu_id, uint32_t *regs)
{ {
pandecode_dump_file_open(); pandecode_dump_file_open(ctx);
uint64_t *cs = pandecode_fetch_gpu_mem(queue, size); uint64_t *cs = pandecode_fetch_gpu_mem(ctx, queue, size);
/* Mali-G610 has 96 registers. Other devices not yet supported, we can make /* Mali-G610 has 96 registers. Other devices not yet supported, we can make
* this configurable later when we encounter new Malis. * this configurable later when we encounter new Malis.
*/ */
struct queue_ctx ctx = { struct queue_ctx qctx = {
.nr_regs = 96, .nr_regs = 96,
.regs = regs, .regs = regs,
.ip = cs, .ip = cs,
@ -746,12 +752,12 @@ GENX(pandecode_cs)(mali_ptr queue, uint32_t size, unsigned gpu_id,
if (size) { if (size) {
do { do {
disassemble_ceu_instr(*(ctx.ip), 1 + ctx.call_stack_depth, true, disassemble_ceu_instr(ctx, *(qctx.ip), 1 + qctx.call_stack_depth, true,
pandecode_dump_stream, &ctx); ctx->dump_stream, &qctx);
} while (interpret_ceu_instr(&ctx)); } while (interpret_ceu_instr(ctx, &qctx));
} }
fflush(pandecode_dump_stream); fflush(ctx->dump_stream);
pandecode_map_read_write(); pandecode_map_read_write(ctx);
} }
#endif #endif

View file

@ -30,10 +30,10 @@
#if PAN_ARCH <= 9 #if PAN_ARCH <= 9
static void static void
pandecode_primitive(const void *p) pandecode_primitive(struct pandecode_context *ctx, const void *p)
{ {
pan_unpack(p, PRIMITIVE, primitive); pan_unpack(p, PRIMITIVE, primitive);
DUMP_UNPACKED(PRIMITIVE, primitive, "Primitive:\n"); DUMP_UNPACKED(ctx, PRIMITIVE, primitive, "Primitive:\n");
#if PAN_ARCH <= 7 #if PAN_ARCH <= 7
/* Validate an index buffer is present if we need one. TODO: verify /* Validate an index buffer is present if we need one. TODO: verify
@ -50,41 +50,41 @@ pandecode_primitive(const void *p)
* size */ * size */
if (!size) if (!size)
pandecode_log("// XXX: index size missing\n"); pandecode_log(ctx, "// XXX: index size missing\n");
else else
pandecode_validate_buffer(primitive.indices, pandecode_validate_buffer(ctx, primitive.indices,
primitive.index_count * size); primitive.index_count * size);
} else if (primitive.index_type) } else if (primitive.index_type)
pandecode_log("// XXX: unexpected index size\n"); pandecode_log(ctx, "// XXX: unexpected index size\n");
#endif #endif
} }
#if PAN_ARCH <= 7 #if PAN_ARCH <= 7
static void static void
pandecode_attributes(mali_ptr addr, int count, bool varying, pandecode_attributes(struct pandecode_context *ctx, mali_ptr addr, int count,
enum mali_job_type job_type) bool varying, enum mali_job_type job_type)
{ {
char *prefix = varying ? "Varying" : "Attribute"; char *prefix = varying ? "Varying" : "Attribute";
assert(addr); assert(addr);
if (!count) { if (!count) {
pandecode_log("// warn: No %s records\n", prefix); pandecode_log(ctx, "// warn: No %s records\n", prefix);
return; return;
} }
MAP_ADDR(ATTRIBUTE_BUFFER, addr, cl); MAP_ADDR(ctx, ATTRIBUTE_BUFFER, addr, cl);
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
pan_unpack(cl + i * pan_size(ATTRIBUTE_BUFFER), ATTRIBUTE_BUFFER, temp); pan_unpack(cl + i * pan_size(ATTRIBUTE_BUFFER), ATTRIBUTE_BUFFER, temp);
DUMP_UNPACKED(ATTRIBUTE_BUFFER, temp, "%s:\n", prefix); DUMP_UNPACKED(ctx, ATTRIBUTE_BUFFER, temp, "%s:\n", prefix);
switch (temp.type) { switch (temp.type) {
case MALI_ATTRIBUTE_TYPE_1D_NPOT_DIVISOR_WRITE_REDUCTION: case MALI_ATTRIBUTE_TYPE_1D_NPOT_DIVISOR_WRITE_REDUCTION:
case MALI_ATTRIBUTE_TYPE_1D_NPOT_DIVISOR: { case MALI_ATTRIBUTE_TYPE_1D_NPOT_DIVISOR: {
pan_unpack(cl + (i + 1) * pan_size(ATTRIBUTE_BUFFER), pan_unpack(cl + (i + 1) * pan_size(ATTRIBUTE_BUFFER),
ATTRIBUTE_BUFFER_CONTINUATION_NPOT, temp2); ATTRIBUTE_BUFFER_CONTINUATION_NPOT, temp2);
pan_print(pandecode_dump_stream, ATTRIBUTE_BUFFER_CONTINUATION_NPOT, pan_print(ctx->dump_stream, ATTRIBUTE_BUFFER_CONTINUATION_NPOT, temp2,
temp2, (pandecode_indent + 1) * 2); (ctx->indent + 1) * 2);
i++; i++;
break; break;
} }
@ -92,8 +92,8 @@ pandecode_attributes(mali_ptr addr, int count, bool varying,
case MALI_ATTRIBUTE_TYPE_3D_INTERLEAVED: { case MALI_ATTRIBUTE_TYPE_3D_INTERLEAVED: {
pan_unpack(cl + (i + 1) * pan_size(ATTRIBUTE_BUFFER_CONTINUATION_3D), pan_unpack(cl + (i + 1) * pan_size(ATTRIBUTE_BUFFER_CONTINUATION_3D),
ATTRIBUTE_BUFFER_CONTINUATION_3D, temp2); ATTRIBUTE_BUFFER_CONTINUATION_3D, temp2);
pan_print(pandecode_dump_stream, ATTRIBUTE_BUFFER_CONTINUATION_3D, pan_print(ctx->dump_stream, ATTRIBUTE_BUFFER_CONTINUATION_3D, temp2,
temp2, (pandecode_indent + 1) * 2); (ctx->indent + 1) * 2);
i++; i++;
break; break;
} }
@ -101,22 +101,24 @@ pandecode_attributes(mali_ptr addr, int count, bool varying,
break; break;
} }
} }
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
static unsigned static unsigned
pandecode_attribute_meta(int count, mali_ptr attribute, bool varying) pandecode_attribute_meta(struct pandecode_context *ctx, int count,
mali_ptr attribute, bool varying)
{ {
unsigned max = 0; unsigned max = 0;
for (int i = 0; i < count; ++i, attribute += pan_size(ATTRIBUTE)) { for (int i = 0; i < count; ++i, attribute += pan_size(ATTRIBUTE)) {
MAP_ADDR(ATTRIBUTE, attribute, cl); MAP_ADDR(ctx, ATTRIBUTE, attribute, cl);
pan_unpack(cl, ATTRIBUTE, a); pan_unpack(cl, ATTRIBUTE, a);
DUMP_UNPACKED(ATTRIBUTE, a, "%s:\n", varying ? "Varying" : "Attribute"); DUMP_UNPACKED(ctx, ATTRIBUTE, a, "%s:\n",
varying ? "Varying" : "Attribute");
max = MAX2(max, a.buffer_index); max = MAX2(max, a.buffer_index);
} }
pandecode_log("\n"); pandecode_log(ctx, "\n");
return MIN2(max + 1, 256); return MIN2(max + 1, 256);
} }
@ -134,7 +136,7 @@ bits(u32 word, u32 lo, u32 hi)
} }
static void static void
pandecode_invocation(const void *i) pandecode_invocation(struct pandecode_context *ctx, const void *i)
{ {
/* Decode invocation_count. See the comment before the definition of /* Decode invocation_count. See the comment before the definition of
* invocation_count for an explanation. * invocation_count for an explanation.
@ -161,94 +163,98 @@ pandecode_invocation(const void *i)
unsigned groups_z = unsigned groups_z =
bits(invocation.invocations, invocation.workgroups_z_shift, 32) + 1; bits(invocation.invocations, invocation.workgroups_z_shift, 32) + 1;
pandecode_log("Invocation (%d, %d, %d) x (%d, %d, %d)\n", size_x, size_y, pandecode_log(ctx, "Invocation (%d, %d, %d) x (%d, %d, %d)\n", size_x,
size_z, groups_x, groups_y, groups_z); size_y, size_z, groups_x, groups_y, groups_z);
DUMP_UNPACKED(INVOCATION, invocation, "Invocation:\n") DUMP_UNPACKED(ctx, INVOCATION, invocation, "Invocation:\n")
} }
static void static void
pandecode_textures(mali_ptr textures, unsigned texture_count) pandecode_textures(struct pandecode_context *ctx, mali_ptr textures,
unsigned texture_count)
{ {
if (!textures) if (!textures)
return; return;
pandecode_log("Textures %" PRIx64 ":\n", textures); pandecode_log(ctx, "Textures %" PRIx64 ":\n", textures);
pandecode_indent++; ctx->indent++;
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
const void *cl = const void *cl =
pandecode_fetch_gpu_mem(textures, pan_size(TEXTURE) * texture_count); pandecode_fetch_gpu_mem(ctx, textures, pan_size(TEXTURE) * texture_count);
for (unsigned tex = 0; tex < texture_count; ++tex) for (unsigned tex = 0; tex < texture_count; ++tex)
GENX(pandecode_texture)(cl + pan_size(TEXTURE) * tex, tex); GENX(pandecode_texture)(ctx, cl + pan_size(TEXTURE) * tex, tex);
#else #else
mali_ptr *PANDECODE_PTR_VAR(u, textures); mali_ptr *PANDECODE_PTR_VAR(ctx, u, textures);
for (int tex = 0; tex < texture_count; ++tex) { for (int tex = 0; tex < texture_count; ++tex) {
mali_ptr *PANDECODE_PTR_VAR(u, textures + tex * sizeof(mali_ptr)); mali_ptr *PANDECODE_PTR_VAR(ctx, u, textures + tex * sizeof(mali_ptr));
char *a = pointer_as_memory_reference(*u); char *a = pointer_as_memory_reference(ctx, *u);
pandecode_log("%s,\n", a); pandecode_log(ctx, "%s,\n", a);
free(a); free(a);
} }
/* Now, finally, descend down into the texture descriptor */ /* Now, finally, descend down into the texture descriptor */
for (unsigned tex = 0; tex < texture_count; ++tex) { for (unsigned tex = 0; tex < texture_count; ++tex) {
mali_ptr *PANDECODE_PTR_VAR(u, textures + tex * sizeof(mali_ptr)); mali_ptr *PANDECODE_PTR_VAR(ctx, u, textures + tex * sizeof(mali_ptr));
GENX(pandecode_texture)(*u, tex); GENX(pandecode_texture)(ctx, *u, tex);
} }
#endif #endif
pandecode_indent--; ctx->indent--;
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
static void static void
pandecode_samplers(mali_ptr samplers, unsigned sampler_count) pandecode_samplers(struct pandecode_context *ctx, mali_ptr samplers,
unsigned sampler_count)
{ {
pandecode_log("Samplers %" PRIx64 ":\n", samplers); pandecode_log(ctx, "Samplers %" PRIx64 ":\n", samplers);
pandecode_indent++; ctx->indent++;
for (int i = 0; i < sampler_count; ++i) for (int i = 0; i < sampler_count; ++i)
DUMP_ADDR(SAMPLER, samplers + (pan_size(SAMPLER) * i), "Sampler %d:\n", DUMP_ADDR(ctx, SAMPLER, samplers + (pan_size(SAMPLER) * i),
i); "Sampler %d:\n", i);
pandecode_indent--; ctx->indent--;
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
static void static void
pandecode_uniform_buffers(mali_ptr pubufs, int ubufs_count) pandecode_uniform_buffers(struct pandecode_context *ctx, mali_ptr pubufs,
int ubufs_count)
{ {
uint64_t *PANDECODE_PTR_VAR(ubufs, pubufs); uint64_t *PANDECODE_PTR_VAR(ctx, ubufs, pubufs);
for (int i = 0; i < ubufs_count; i++) { for (int i = 0; i < ubufs_count; i++) {
mali_ptr addr = (ubufs[i] >> 10) << 2; mali_ptr addr = (ubufs[i] >> 10) << 2;
unsigned size = addr ? (((ubufs[i] & ((1 << 10) - 1)) + 1) * 16) : 0; unsigned size = addr ? (((ubufs[i] & ((1 << 10) - 1)) + 1) * 16) : 0;
pandecode_validate_buffer(addr, size); pandecode_validate_buffer(ctx, addr, size);
char *ptr = pointer_as_memory_reference(addr); char *ptr = pointer_as_memory_reference(ctx, addr);
pandecode_log("ubuf_%d[%u] = %s;\n", i, size, ptr); pandecode_log(ctx, "ubuf_%d[%u] = %s;\n", i, size, ptr);
free(ptr); free(ptr);
} }
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
static void static void
pandecode_uniforms(mali_ptr uniforms, unsigned uniform_count) pandecode_uniforms(struct pandecode_context *ctx, mali_ptr uniforms,
unsigned uniform_count)
{ {
pandecode_validate_buffer(uniforms, uniform_count * 16); pandecode_validate_buffer(ctx, uniforms, uniform_count * 16);
char *ptr = pointer_as_memory_reference(uniforms); char *ptr = pointer_as_memory_reference(ctx, uniforms);
pandecode_log("vec4 uniforms[%u] = %s;\n", uniform_count, ptr); pandecode_log(ctx, "vec4 uniforms[%u] = %s;\n", uniform_count, ptr);
free(ptr); free(ptr);
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
void void
GENX(pandecode_dcd)(const struct MALI_DRAW *p, enum mali_job_type job_type, GENX(pandecode_dcd)(struct pandecode_context *ctx, const struct MALI_DRAW *p,
unsigned gpu_id) enum mali_job_type job_type, unsigned gpu_id)
{ {
#if PAN_ARCH >= 5 #if PAN_ARCH >= 5
struct pandecode_fbd fbd_info = {.rt_count = 1}; struct pandecode_fbd fbd_info = {.rt_count = 1};
@ -256,7 +262,7 @@ GENX(pandecode_dcd)(const struct MALI_DRAW *p, enum mali_job_type job_type,
if (PAN_ARCH >= 6 || (PAN_ARCH == 5 && job_type != MALI_JOB_TYPE_TILER)) { if (PAN_ARCH >= 6 || (PAN_ARCH == 5 && job_type != MALI_JOB_TYPE_TILER)) {
#if PAN_ARCH >= 5 #if PAN_ARCH >= 5
DUMP_ADDR(LOCAL_STORAGE, p->thread_storage & ~1, "Local Storage:\n"); DUMP_ADDR(ctx, LOCAL_STORAGE, p->thread_storage & ~1, "Local Storage:\n");
#endif #endif
} else { } else {
#if PAN_ARCH == 5 #if PAN_ARCH == 5
@ -268,13 +274,12 @@ GENX(pandecode_dcd)(const struct MALI_DRAW *p, enum mali_job_type job_type,
if (!ptr.type || ptr.zs_crc_extension_present || if (!ptr.type || ptr.zs_crc_extension_present ||
ptr.render_target_count != 1) { ptr.render_target_count != 1) {
fprintf(pandecode_dump_stream, fprintf(ctx->dump_stream, "Unexpected framebuffer pointer settings");
"Unexpected framebuffer pointer settings");
} }
GENX(pandecode_fbd)(ptr.pointer, false, gpu_id); GENX(pandecode_fbd)(ctx, ptr.pointer, false, gpu_id);
#elif PAN_ARCH == 4 #elif PAN_ARCH == 4
GENX(pandecode_fbd)(p->fbd, false, gpu_id); GENX(pandecode_fbd)(ctx, p->fbd, false, gpu_id);
#endif #endif
} }
@ -284,21 +289,21 @@ GENX(pandecode_dcd)(const struct MALI_DRAW *p, enum mali_job_type job_type,
if (p->state) { if (p->state) {
uint32_t *cl = uint32_t *cl =
pandecode_fetch_gpu_mem(p->state, pan_size(RENDERER_STATE)); pandecode_fetch_gpu_mem(ctx, p->state, pan_size(RENDERER_STATE));
pan_unpack(cl, RENDERER_STATE, state); pan_unpack(cl, RENDERER_STATE, state);
if (state.shader.shader & ~0xF) if (state.shader.shader & ~0xF)
pandecode_shader_disassemble(state.shader.shader & ~0xF, gpu_id); pandecode_shader_disassemble(ctx, state.shader.shader & ~0xF, gpu_id);
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
bool idvs = (job_type == MALI_JOB_TYPE_INDEXED_VERTEX); bool idvs = (job_type == MALI_JOB_TYPE_INDEXED_VERTEX);
if (idvs && state.secondary_shader) if (idvs && state.secondary_shader)
pandecode_shader_disassemble(state.secondary_shader, gpu_id); pandecode_shader_disassemble(ctx, state.secondary_shader, gpu_id);
#endif #endif
DUMP_UNPACKED(RENDERER_STATE, state, "State:\n"); DUMP_UNPACKED(ctx, RENDERER_STATE, state, "State:\n");
pandecode_indent++; ctx->indent++;
/* Save for dumps */ /* Save for dumps */
attribute_count = state.shader.attribute_count; attribute_count = state.shader.attribute_count;
@ -316,10 +321,10 @@ GENX(pandecode_dcd)(const struct MALI_DRAW *p, enum mali_job_type job_type,
#if PAN_ARCH == 4 #if PAN_ARCH == 4
mali_ptr shader = state.blend_shader & ~0xF; mali_ptr shader = state.blend_shader & ~0xF;
if (state.multisample_misc.blend_shader && shader) if (state.multisample_misc.blend_shader && shader)
pandecode_shader_disassemble(shader, gpu_id); pandecode_shader_disassemble(ctx, shader, gpu_id);
#endif #endif
pandecode_indent--; ctx->indent--;
pandecode_log("\n"); pandecode_log(ctx, "\n");
/* MRT blend fields are used on v5+. Technically, they are optional on v5 /* MRT blend fields are used on v5+. Technically, they are optional on v5
* for backwards compatibility but we don't care about that. * for backwards compatibility but we don't care about that.
@ -332,141 +337,146 @@ GENX(pandecode_dcd)(const struct MALI_DRAW *p, enum mali_job_type job_type,
for (unsigned i = 0; i < fbd_info.rt_count; i++) { for (unsigned i = 0; i < fbd_info.rt_count; i++) {
mali_ptr shader = mali_ptr shader =
GENX(pandecode_blend)(blend_base, i, state.shader.shader); GENX(pandecode_blend)(ctx, blend_base, i, state.shader.shader);
if (shader & ~0xF) if (shader & ~0xF)
pandecode_shader_disassemble(shader, gpu_id); pandecode_shader_disassemble(ctx, shader, gpu_id);
} }
} }
#endif #endif
} else } else
pandecode_log("// XXX: missing shader descriptor\n"); pandecode_log(ctx, "// XXX: missing shader descriptor\n");
if (p->viewport) { if (p->viewport) {
DUMP_ADDR(VIEWPORT, p->viewport, "Viewport:\n"); DUMP_ADDR(ctx, VIEWPORT, p->viewport, "Viewport:\n");
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
unsigned max_attr_index = 0; unsigned max_attr_index = 0;
if (p->attributes) if (p->attributes)
max_attr_index = max_attr_index =
pandecode_attribute_meta(attribute_count, p->attributes, false); pandecode_attribute_meta(ctx, attribute_count, p->attributes, false);
if (p->attribute_buffers) if (p->attribute_buffers)
pandecode_attributes(p->attribute_buffers, max_attr_index, false, pandecode_attributes(ctx, p->attribute_buffers, max_attr_index, false,
job_type); job_type);
if (p->varyings) { if (p->varyings) {
varying_count = varying_count =
pandecode_attribute_meta(varying_count, p->varyings, true); pandecode_attribute_meta(ctx, varying_count, p->varyings, true);
} }
if (p->varying_buffers) if (p->varying_buffers)
pandecode_attributes(p->varying_buffers, varying_count, true, job_type); pandecode_attributes(ctx, p->varying_buffers, varying_count, true,
job_type);
if (p->uniform_buffers) { if (p->uniform_buffers) {
if (uniform_buffer_count) if (uniform_buffer_count)
pandecode_uniform_buffers(p->uniform_buffers, uniform_buffer_count); pandecode_uniform_buffers(ctx, p->uniform_buffers,
uniform_buffer_count);
else else
pandecode_log("// warn: UBOs specified but not referenced\n"); pandecode_log(ctx, "// warn: UBOs specified but not referenced\n");
} else if (uniform_buffer_count) } else if (uniform_buffer_count)
pandecode_log("// XXX: UBOs referenced but not specified\n"); pandecode_log(ctx, "// XXX: UBOs referenced but not specified\n");
/* We don't want to actually dump uniforms, but we do need to validate /* We don't want to actually dump uniforms, but we do need to validate
* that the counts we were given are sane */ * that the counts we were given are sane */
if (p->push_uniforms) { if (p->push_uniforms) {
if (uniform_count) if (uniform_count)
pandecode_uniforms(p->push_uniforms, uniform_count); pandecode_uniforms(ctx, p->push_uniforms, uniform_count);
else else
pandecode_log("// warn: Uniforms specified but not referenced\n"); pandecode_log(ctx, "// warn: Uniforms specified but not referenced\n");
} else if (uniform_count) } else if (uniform_count)
pandecode_log("// XXX: Uniforms referenced but not specified\n"); pandecode_log(ctx, "// XXX: Uniforms referenced but not specified\n");
if (p->textures) if (p->textures)
pandecode_textures(p->textures, texture_count); pandecode_textures(ctx, p->textures, texture_count);
if (p->samplers) if (p->samplers)
pandecode_samplers(p->samplers, sampler_count); pandecode_samplers(ctx, p->samplers, sampler_count);
} }
static void static void
pandecode_vertex_compute_geometry_job(const struct MALI_JOB_HEADER *h, pandecode_vertex_compute_geometry_job(struct pandecode_context *ctx,
const struct MALI_JOB_HEADER *h,
mali_ptr job, unsigned gpu_id) mali_ptr job, unsigned gpu_id)
{ {
struct mali_compute_job_packed *PANDECODE_PTR_VAR(p, job); struct mali_compute_job_packed *PANDECODE_PTR_VAR(ctx, p, job);
pan_section_unpack(p, COMPUTE_JOB, DRAW, draw); pan_section_unpack(p, COMPUTE_JOB, DRAW, draw);
GENX(pandecode_dcd)(&draw, h->type, gpu_id); GENX(pandecode_dcd)(ctx, &draw, h->type, gpu_id);
pandecode_log("Vertex Job Payload:\n"); pandecode_log(ctx, "Vertex Job Payload:\n");
pandecode_indent++; ctx->indent++;
pandecode_invocation(pan_section_ptr(p, COMPUTE_JOB, INVOCATION)); pandecode_invocation(ctx, pan_section_ptr(p, COMPUTE_JOB, INVOCATION));
DUMP_SECTION(COMPUTE_JOB, PARAMETERS, p, "Vertex Job Parameters:\n"); DUMP_SECTION(ctx, COMPUTE_JOB, PARAMETERS, p, "Vertex Job Parameters:\n");
DUMP_UNPACKED(DRAW, draw, "Draw:\n"); DUMP_UNPACKED(ctx, DRAW, draw, "Draw:\n");
pandecode_indent--; ctx->indent--;
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
#endif #endif
static void static void
pandecode_write_value_job(mali_ptr job) pandecode_write_value_job(struct pandecode_context *ctx, mali_ptr job)
{ {
struct mali_write_value_job_packed *PANDECODE_PTR_VAR(p, job); struct mali_write_value_job_packed *PANDECODE_PTR_VAR(ctx, p, job);
pan_section_unpack(p, WRITE_VALUE_JOB, PAYLOAD, u); pan_section_unpack(p, WRITE_VALUE_JOB, PAYLOAD, u);
DUMP_SECTION(WRITE_VALUE_JOB, PAYLOAD, p, "Write Value Payload:\n"); DUMP_SECTION(ctx, WRITE_VALUE_JOB, PAYLOAD, p, "Write Value Payload:\n");
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
static void static void
pandecode_cache_flush_job(mali_ptr job) pandecode_cache_flush_job(struct pandecode_context *ctx, mali_ptr job)
{ {
struct mali_cache_flush_job_packed *PANDECODE_PTR_VAR(p, job); struct mali_cache_flush_job_packed *PANDECODE_PTR_VAR(ctx, p, job);
pan_section_unpack(p, CACHE_FLUSH_JOB, PAYLOAD, u); pan_section_unpack(p, CACHE_FLUSH_JOB, PAYLOAD, u);
DUMP_SECTION(CACHE_FLUSH_JOB, PAYLOAD, p, "Cache Flush Payload:\n"); DUMP_SECTION(ctx, CACHE_FLUSH_JOB, PAYLOAD, p, "Cache Flush Payload:\n");
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
static void static void
pandecode_tiler_job(const struct MALI_JOB_HEADER *h, mali_ptr job, pandecode_tiler_job(struct pandecode_context *ctx,
const struct MALI_JOB_HEADER *h, mali_ptr job,
unsigned gpu_id) unsigned gpu_id)
{ {
struct mali_tiler_job_packed *PANDECODE_PTR_VAR(p, job); struct mali_tiler_job_packed *PANDECODE_PTR_VAR(ctx, p, job);
pan_section_unpack(p, TILER_JOB, DRAW, draw); pan_section_unpack(p, TILER_JOB, DRAW, draw);
GENX(pandecode_dcd)(&draw, h->type, gpu_id); GENX(pandecode_dcd)(ctx, &draw, h->type, gpu_id);
pandecode_log("Tiler Job Payload:\n"); pandecode_log(ctx, "Tiler Job Payload:\n");
pandecode_indent++; ctx->indent++;
#if PAN_ARCH <= 7 #if PAN_ARCH <= 7
pandecode_invocation(pan_section_ptr(p, TILER_JOB, INVOCATION)); pandecode_invocation(ctx, pan_section_ptr(p, TILER_JOB, INVOCATION));
#endif #endif
pandecode_primitive(pan_section_ptr(p, TILER_JOB, PRIMITIVE)); pandecode_primitive(ctx, pan_section_ptr(p, TILER_JOB, PRIMITIVE));
DUMP_UNPACKED(DRAW, draw, "Draw:\n"); DUMP_UNPACKED(ctx, DRAW, draw, "Draw:\n");
DUMP_SECTION(TILER_JOB, PRIMITIVE_SIZE, p, "Primitive Size:\n"); DUMP_SECTION(ctx, TILER_JOB, PRIMITIVE_SIZE, p, "Primitive Size:\n");
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
pan_section_unpack(p, TILER_JOB, TILER, tiler_ptr); pan_section_unpack(p, TILER_JOB, TILER, tiler_ptr);
GENX(pandecode_tiler)(tiler_ptr.address, gpu_id); GENX(pandecode_tiler)(ctx, tiler_ptr.address, gpu_id);
#if PAN_ARCH >= 9 #if PAN_ARCH >= 9
DUMP_SECTION(TILER_JOB, INSTANCE_COUNT, p, "Instance count:\n"); DUMP_SECTION(ctx, TILER_JOB, INSTANCE_COUNT, p, "Instance count:\n");
DUMP_SECTION(TILER_JOB, VERTEX_COUNT, p, "Vertex count:\n"); DUMP_SECTION(ctx, TILER_JOB, VERTEX_COUNT, p, "Vertex count:\n");
DUMP_SECTION(TILER_JOB, SCISSOR, p, "Scissor:\n"); DUMP_SECTION(ctx, TILER_JOB, SCISSOR, p, "Scissor:\n");
DUMP_SECTION(TILER_JOB, INDICES, p, "Indices:\n"); DUMP_SECTION(ctx, TILER_JOB, INDICES, p, "Indices:\n");
#else #else
pan_section_unpack(p, TILER_JOB, PADDING, padding); pan_section_unpack(p, TILER_JOB, PADDING, padding);
#endif #endif
#endif #endif
pandecode_indent--; ctx->indent--;
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
static void static void
pandecode_fragment_job(mali_ptr job, unsigned gpu_id) pandecode_fragment_job(struct pandecode_context *ctx, mali_ptr job,
unsigned gpu_id)
{ {
struct mali_fragment_job_packed *PANDECODE_PTR_VAR(p, job); struct mali_fragment_job_packed *PANDECODE_PTR_VAR(ctx, p, job);
pan_section_unpack(p, FRAGMENT_JOB, PAYLOAD, s); pan_section_unpack(p, FRAGMENT_JOB, PAYLOAD, s);
uint64_t fbd_pointer; uint64_t fbd_pointer;
@ -483,47 +493,50 @@ pandecode_fragment_job(mali_ptr job, unsigned gpu_id)
#endif #endif
UNUSED struct pandecode_fbd info = UNUSED struct pandecode_fbd info =
GENX(pandecode_fbd)(fbd_pointer, true, gpu_id); GENX(pandecode_fbd)(ctx, fbd_pointer, true, gpu_id);
#if PAN_ARCH >= 5 #if PAN_ARCH >= 5
if (!ptr.type || ptr.zs_crc_extension_present != info.has_extra || if (!ptr.type || ptr.zs_crc_extension_present != info.has_extra ||
ptr.render_target_count != info.rt_count) { ptr.render_target_count != info.rt_count) {
pandecode_log("invalid FBD tag\n"); pandecode_log(ctx, "invalid FBD tag\n");
} }
#endif #endif
DUMP_UNPACKED(FRAGMENT_JOB_PAYLOAD, s, "Fragment Job Payload:\n"); DUMP_UNPACKED(ctx, FRAGMENT_JOB_PAYLOAD, s, "Fragment Job Payload:\n");
pandecode_log("\n"); pandecode_log(ctx, "\n");
} }
#if PAN_ARCH == 6 || PAN_ARCH == 7 #if PAN_ARCH == 6 || PAN_ARCH == 7
static void static void
pandecode_indexed_vertex_job(const struct MALI_JOB_HEADER *h, mali_ptr job, pandecode_indexed_vertex_job(struct pandecode_context *ctx,
const struct MALI_JOB_HEADER *h, mali_ptr job,
unsigned gpu_id) unsigned gpu_id)
{ {
struct mali_indexed_vertex_job_packed *PANDECODE_PTR_VAR(p, job); struct mali_indexed_vertex_job_packed *PANDECODE_PTR_VAR(ctx, p, job);
pandecode_log("Vertex:\n"); pandecode_log(ctx, "Vertex:\n");
pan_section_unpack(p, INDEXED_VERTEX_JOB, VERTEX_DRAW, vert_draw); pan_section_unpack(p, INDEXED_VERTEX_JOB, VERTEX_DRAW, vert_draw);
GENX(pandecode_dcd)(&vert_draw, h->type, gpu_id); GENX(pandecode_dcd)(ctx, &vert_draw, h->type, gpu_id);
DUMP_UNPACKED(DRAW, vert_draw, "Vertex Draw:\n"); DUMP_UNPACKED(ctx, DRAW, vert_draw, "Vertex Draw:\n");
pandecode_log("Fragment:\n"); pandecode_log(ctx, "Fragment:\n");
pan_section_unpack(p, INDEXED_VERTEX_JOB, FRAGMENT_DRAW, frag_draw); pan_section_unpack(p, INDEXED_VERTEX_JOB, FRAGMENT_DRAW, frag_draw);
GENX(pandecode_dcd)(&frag_draw, MALI_JOB_TYPE_FRAGMENT, gpu_id); GENX(pandecode_dcd)(ctx, &frag_draw, MALI_JOB_TYPE_FRAGMENT, gpu_id);
DUMP_UNPACKED(DRAW, frag_draw, "Fragment Draw:\n"); DUMP_UNPACKED(ctx, DRAW, frag_draw, "Fragment Draw:\n");
pan_section_unpack(p, INDEXED_VERTEX_JOB, TILER, tiler_ptr); pan_section_unpack(p, INDEXED_VERTEX_JOB, TILER, tiler_ptr);
pandecode_log("Tiler Job Payload:\n"); pandecode_log(ctx, "Tiler Job Payload:\n");
pandecode_indent++; ctx->indent++;
GENX(pandecode_tiler)(tiler_ptr.address, gpu_id); GENX(pandecode_tiler)(ctx, tiler_ptr.address, gpu_id);
pandecode_indent--; ctx->indent--;
pandecode_invocation(pan_section_ptr(p, INDEXED_VERTEX_JOB, INVOCATION)); pandecode_invocation(ctx,
pandecode_primitive(pan_section_ptr(p, INDEXED_VERTEX_JOB, PRIMITIVE)); pan_section_ptr(p, INDEXED_VERTEX_JOB, INVOCATION));
pandecode_primitive(ctx, pan_section_ptr(p, INDEXED_VERTEX_JOB, PRIMITIVE));
DUMP_SECTION(INDEXED_VERTEX_JOB, PRIMITIVE_SIZE, p, "Primitive Size:\n"); DUMP_SECTION(ctx, INDEXED_VERTEX_JOB, PRIMITIVE_SIZE, p,
"Primitive Size:\n");
pan_section_unpack(p, INDEXED_VERTEX_JOB, PADDING, padding); pan_section_unpack(p, INDEXED_VERTEX_JOB, PADDING, padding);
} }
@ -531,45 +544,47 @@ pandecode_indexed_vertex_job(const struct MALI_JOB_HEADER *h, mali_ptr job,
#if PAN_ARCH == 9 #if PAN_ARCH == 9
static void static void
pandecode_malloc_vertex_job(mali_ptr job, unsigned gpu_id) pandecode_malloc_vertex_job(struct pandecode_context *ctx, mali_ptr job,
unsigned gpu_id)
{ {
struct mali_malloc_vertex_job_packed *PANDECODE_PTR_VAR(p, job); struct mali_malloc_vertex_job_packed *PANDECODE_PTR_VAR(ctx, p, job);
DUMP_SECTION(MALLOC_VERTEX_JOB, PRIMITIVE, p, "Primitive:\n"); DUMP_SECTION(ctx, MALLOC_VERTEX_JOB, PRIMITIVE, p, "Primitive:\n");
DUMP_SECTION(MALLOC_VERTEX_JOB, INSTANCE_COUNT, p, "Instance count:\n"); DUMP_SECTION(ctx, MALLOC_VERTEX_JOB, INSTANCE_COUNT, p, "Instance count:\n");
DUMP_SECTION(MALLOC_VERTEX_JOB, ALLOCATION, p, "Allocation:\n"); DUMP_SECTION(ctx, MALLOC_VERTEX_JOB, ALLOCATION, p, "Allocation:\n");
DUMP_SECTION(MALLOC_VERTEX_JOB, TILER, p, "Tiler:\n"); DUMP_SECTION(ctx, MALLOC_VERTEX_JOB, TILER, p, "Tiler:\n");
DUMP_SECTION(MALLOC_VERTEX_JOB, SCISSOR, p, "Scissor:\n"); DUMP_SECTION(ctx, MALLOC_VERTEX_JOB, SCISSOR, p, "Scissor:\n");
DUMP_SECTION(MALLOC_VERTEX_JOB, PRIMITIVE_SIZE, p, "Primitive Size:\n"); DUMP_SECTION(ctx, MALLOC_VERTEX_JOB, PRIMITIVE_SIZE, p, "Primitive Size:\n");
DUMP_SECTION(MALLOC_VERTEX_JOB, INDICES, p, "Indices:\n"); DUMP_SECTION(ctx, MALLOC_VERTEX_JOB, INDICES, p, "Indices:\n");
pan_section_unpack(p, MALLOC_VERTEX_JOB, DRAW, dcd); pan_section_unpack(p, MALLOC_VERTEX_JOB, DRAW, dcd);
pan_section_unpack(p, MALLOC_VERTEX_JOB, TILER, tiler_ptr); pan_section_unpack(p, MALLOC_VERTEX_JOB, TILER, tiler_ptr);
pandecode_log("Tiler Job Payload:\n"); pandecode_log(ctx, "Tiler Job Payload:\n");
pandecode_indent++; ctx->indent++;
if (tiler_ptr.address) if (tiler_ptr.address)
GENX(pandecode_tiler)(tiler_ptr.address, gpu_id); GENX(pandecode_tiler)(ctx, tiler_ptr.address, gpu_id);
else else
pandecode_log("<omitted>\n"); pandecode_log(ctx, "<omitted>\n");
pandecode_indent--; ctx->indent--;
GENX(pandecode_dcd)(&dcd, 0, gpu_id); GENX(pandecode_dcd)(ctx, &dcd, 0, gpu_id);
pan_section_unpack(p, MALLOC_VERTEX_JOB, POSITION, position); pan_section_unpack(p, MALLOC_VERTEX_JOB, POSITION, position);
pan_section_unpack(p, MALLOC_VERTEX_JOB, VARYING, varying); pan_section_unpack(p, MALLOC_VERTEX_JOB, VARYING, varying);
GENX(pandecode_shader_environment)(&position, gpu_id); GENX(pandecode_shader_environment)(ctx, &position, gpu_id);
GENX(pandecode_shader_environment)(&varying, gpu_id); GENX(pandecode_shader_environment)(ctx, &varying, gpu_id);
} }
static void static void
pandecode_compute_job(mali_ptr job, unsigned gpu_id) pandecode_compute_job(struct pandecode_context *ctx, mali_ptr job,
unsigned gpu_id)
{ {
struct mali_compute_job_packed *PANDECODE_PTR_VAR(p, job); struct mali_compute_job_packed *PANDECODE_PTR_VAR(ctx, p, job);
pan_section_unpack(p, COMPUTE_JOB, PAYLOAD, payload); pan_section_unpack(p, COMPUTE_JOB, PAYLOAD, payload);
GENX(pandecode_shader_environment)(&payload.compute, gpu_id); GENX(pandecode_shader_environment)(ctx, &payload.compute, gpu_id);
DUMP_SECTION(COMPUTE_JOB, PAYLOAD, p, "Compute"); DUMP_SECTION(ctx, COMPUTE_JOB, PAYLOAD, p, "Compute");
} }
#endif #endif
@ -578,9 +593,10 @@ pandecode_compute_job(mali_ptr job, unsigned gpu_id)
* GPU using the job manager. * GPU using the job manager.
*/ */
void void
GENX(pandecode_jc)(mali_ptr jc_gpu_va, unsigned gpu_id) GENX(pandecode_jc)(struct pandecode_context *ctx, mali_ptr jc_gpu_va,
unsigned gpu_id)
{ {
pandecode_dump_file_open(); pandecode_dump_file_open(ctx);
struct set *va_set = _mesa_pointer_set_create(NULL); struct set *va_set = _mesa_pointer_set_create(NULL);
struct set_entry *entry = NULL; struct set_entry *entry = NULL;
@ -589,7 +605,7 @@ GENX(pandecode_jc)(mali_ptr jc_gpu_va, unsigned gpu_id)
do { do {
struct mali_job_header_packed *hdr = struct mali_job_header_packed *hdr =
PANDECODE_PTR(jc_gpu_va, struct mali_job_header_packed); PANDECODE_PTR(ctx, jc_gpu_va, struct mali_job_header_packed);
entry = _mesa_set_search(va_set, hdr); entry = _mesa_set_search(va_set, hdr);
if (entry != NULL) { if (entry != NULL) {
@ -600,45 +616,46 @@ GENX(pandecode_jc)(mali_ptr jc_gpu_va, unsigned gpu_id)
pan_unpack(hdr, JOB_HEADER, h); pan_unpack(hdr, JOB_HEADER, h);
next_job = h.next; next_job = h.next;
DUMP_UNPACKED(JOB_HEADER, h, "Job Header (%" PRIx64 "):\n", jc_gpu_va); DUMP_UNPACKED(ctx, JOB_HEADER, h, "Job Header (%" PRIx64 "):\n",
pandecode_log("\n"); jc_gpu_va);
pandecode_log(ctx, "\n");
switch (h.type) { switch (h.type) {
case MALI_JOB_TYPE_WRITE_VALUE: case MALI_JOB_TYPE_WRITE_VALUE:
pandecode_write_value_job(jc_gpu_va); pandecode_write_value_job(ctx, jc_gpu_va);
break; break;
case MALI_JOB_TYPE_CACHE_FLUSH: case MALI_JOB_TYPE_CACHE_FLUSH:
pandecode_cache_flush_job(jc_gpu_va); pandecode_cache_flush_job(ctx, jc_gpu_va);
break; break;
case MALI_JOB_TYPE_TILER: case MALI_JOB_TYPE_TILER:
pandecode_tiler_job(&h, jc_gpu_va, gpu_id); pandecode_tiler_job(ctx, &h, jc_gpu_va, gpu_id);
break; break;
#if PAN_ARCH <= 7 #if PAN_ARCH <= 7
case MALI_JOB_TYPE_VERTEX: case MALI_JOB_TYPE_VERTEX:
case MALI_JOB_TYPE_COMPUTE: case MALI_JOB_TYPE_COMPUTE:
pandecode_vertex_compute_geometry_job(&h, jc_gpu_va, gpu_id); pandecode_vertex_compute_geometry_job(ctx, &h, jc_gpu_va, gpu_id);
break; break;
#if PAN_ARCH >= 6 #if PAN_ARCH >= 6
case MALI_JOB_TYPE_INDEXED_VERTEX: case MALI_JOB_TYPE_INDEXED_VERTEX:
pandecode_indexed_vertex_job(&h, jc_gpu_va, gpu_id); pandecode_indexed_vertex_job(ctx, &h, jc_gpu_va, gpu_id);
break; break;
#endif #endif
#else #else
case MALI_JOB_TYPE_COMPUTE: case MALI_JOB_TYPE_COMPUTE:
pandecode_compute_job(jc_gpu_va, gpu_id); pandecode_compute_job(ctx, jc_gpu_va, gpu_id);
break; break;
case MALI_JOB_TYPE_MALLOC_VERTEX: case MALI_JOB_TYPE_MALLOC_VERTEX:
pandecode_malloc_vertex_job(jc_gpu_va, gpu_id); pandecode_malloc_vertex_job(ctx, jc_gpu_va, gpu_id);
break; break;
#endif #endif
case MALI_JOB_TYPE_FRAGMENT: case MALI_JOB_TYPE_FRAGMENT:
pandecode_fragment_job(jc_gpu_va, gpu_id); pandecode_fragment_job(ctx, jc_gpu_va, gpu_id);
break; break;
default: default:
@ -651,17 +668,18 @@ GENX(pandecode_jc)(mali_ptr jc_gpu_va, unsigned gpu_id)
_mesa_set_destroy(va_set, NULL); _mesa_set_destroy(va_set, NULL);
fflush(pandecode_dump_stream); fflush(ctx->dump_stream);
pandecode_map_read_write(); pandecode_map_read_write(ctx);
} }
void void
GENX(pandecode_abort_on_fault)(mali_ptr jc_gpu_va) GENX(pandecode_abort_on_fault)(struct pandecode_context *ctx,
mali_ptr jc_gpu_va)
{ {
mali_ptr next_job = 0; mali_ptr next_job = 0;
do { do {
pan_unpack(PANDECODE_PTR(jc_gpu_va, struct mali_job_header_packed), pan_unpack(PANDECODE_PTR(ctx, jc_gpu_va, struct mali_job_header_packed),
JOB_HEADER, h); JOB_HEADER, h);
next_job = h.next; next_job = h.next;
@ -673,7 +691,7 @@ GENX(pandecode_abort_on_fault)(mali_ptr jc_gpu_va)
} }
} while ((jc_gpu_va = next_job)); } while ((jc_gpu_va = next_job));
pandecode_map_read_write(); pandecode_map_read_write(ctx);
} }
#endif #endif

View file

@ -405,9 +405,11 @@ panfrost_bo_create(struct panfrost_device *dev, size_t size, uint32_t flags,
if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC)) { if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC)) {
if (flags & PAN_BO_INVISIBLE) if (flags & PAN_BO_INVISIBLE)
pandecode_inject_mmap(bo->ptr.gpu, NULL, bo->size, NULL); pandecode_inject_mmap(dev->decode_ctx, bo->ptr.gpu, NULL, bo->size,
NULL);
else if (!(flags & PAN_BO_DELAY_MMAP)) else if (!(flags & PAN_BO_DELAY_MMAP))
pandecode_inject_mmap(bo->ptr.gpu, bo->ptr.cpu, bo->size, NULL); pandecode_inject_mmap(dev->decode_ctx, bo->ptr.gpu, bo->ptr.cpu,
bo->size, NULL);
} }
return bo; return bo;
@ -444,7 +446,7 @@ panfrost_bo_unreference(struct panfrost_bo *bo)
panfrost_bo_munmap(bo); panfrost_bo_munmap(bo);
if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC)) if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC))
pandecode_inject_free(bo->ptr.gpu, bo->size); pandecode_inject_free(dev->decode_ctx, bo->ptr.gpu, bo->size);
/* Rather than freeing the BO now, we'll cache the BO for later /* Rather than freeing the BO now, we'll cache the BO for later
* allocations if we're allowed to. * allocations if we're allowed to.

View file

@ -130,6 +130,9 @@ struct panfrost_device {
int fd; int fd;
/* For pandecode */
struct pandecode_context *decode_ctx;
/* Properties of the GPU in use */ /* Properties of the GPU in use */
unsigned arch; unsigned arch;
unsigned gpu_id; unsigned gpu_id;

View file

@ -286,7 +286,7 @@ panfrost_open_device(void *memctx, int fd, struct panfrost_device *dev)
/* Initialize pandecode before we start allocating */ /* Initialize pandecode before we start allocating */
if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC)) if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC))
pandecode_initialize(!(dev->debug & PAN_DBG_TRACE)); dev->decode_ctx = pandecode_create_context(!(dev->debug & PAN_DBG_TRACE));
/* Tiler heap is internally required by the tiler, which can only be /* Tiler heap is internally required by the tiler, which can only be
* active for a single job chain at once, so a single heap can be * active for a single job chain at once, so a single heap can be

View file

@ -42,22 +42,29 @@
* included in-tree. * included in-tree.
*/ */
void pandecode_initialize(bool to_stderr); // TODO: update panwrap
void pandecode_next_frame(void); struct pandecode_context;
void pandecode_close(void); struct pandecode_context *pandecode_create_context(bool to_stderr);
void pandecode_inject_mmap(uint64_t gpu_va, void *cpu, unsigned sz, void pandecode_next_frame(struct pandecode_context *ctx);
const char *name);
void pandecode_inject_free(uint64_t gpu_va, unsigned sz); void pandecode_destroy_context(struct pandecode_context *ctx);
void pandecode_jc(uint64_t jc_gpu_va, unsigned gpu_id); void pandecode_inject_mmap(struct pandecode_context *ctx, uint64_t gpu_va,
void *cpu, unsigned sz, const char *name);
void pandecode_cs(mali_ptr queue_gpu_va, uint32_t size, unsigned gpu_id, void pandecode_inject_free(struct pandecode_context *ctx, uint64_t gpu_va,
uint32_t *regs); unsigned sz);
void pandecode_abort_on_fault(uint64_t jc_gpu_va, unsigned gpu_id); void pandecode_jc(struct pandecode_context *ctx, uint64_t jc_gpu_va,
unsigned gpu_id);
void pandecode_cs(struct pandecode_context *ctx, mali_ptr queue_gpu_va,
uint32_t size, unsigned gpu_id, uint32_t *regs);
void pandecode_abort_on_fault(struct pandecode_context *ctx, uint64_t jc_gpu_va,
unsigned gpu_id);
#endif /* __MMAP_TRACE_H__ */ #endif /* __MMAP_TRACE_H__ */

View file

@ -254,7 +254,7 @@ main(int argc, char *argv[])
i = j = k = 0; i = j = k = 0;
atexit(cleanup); atexit(cleanup);
pandecode_initialize(false); struct pandecode_context *ctx = pandecode_create_context(false);
hdr_fp = fopen(argv[optind], "r"); hdr_fp = fopen(argv[optind], "r");
if (!hdr_fp) { if (!hdr_fp) {
@ -374,7 +374,7 @@ main(int argc, char *argv[])
fclose(bodump); fclose(bodump);
pandecode_inject_mmap(doh.bomap.iova, bos[j], doh.file_size, pandecode_inject_mmap(ctx, doh.bomap.iova, bos[j], doh.file_size,
NULL); NULL);
} else { } else {
@ -397,8 +397,8 @@ main(int argc, char *argv[])
if (doh.type != PANFROSTDUMP_BUF_TRAILER) if (doh.type != PANFROSTDUMP_BUF_TRAILER)
fprintf(stderr, "Trailing header isn't right\n"); fprintf(stderr, "Trailing header isn't right\n");
pandecode_jc(jc, gpu_id); pandecode_jc(ctx, jc, gpu_id);
pandecode_close(); pandecode_destroy_context(ctx);
fclose(data_fp); fclose(data_fp);
fclose(hdr_fp); fclose(hdr_fp);

View file

@ -77,10 +77,11 @@ panvk_queue_submit_batch(struct panvk_queue *queue, struct panvk_batch *batch,
} }
if (debug & PANVK_DEBUG_TRACE) if (debug & PANVK_DEBUG_TRACE)
pandecode_jc(batch->scoreboard.first_job, pdev->gpu_id); pandecode_jc(pdev->decode_ctx, batch->scoreboard.first_job,
pdev->gpu_id);
if (debug & PANVK_DEBUG_DUMP) if (debug & PANVK_DEBUG_DUMP)
pandecode_dump_mappings(); pandecode_dump_mappings(pdev->decode_ctx);
} }
if (batch->fragment_job) { if (batch->fragment_job) {
@ -109,14 +110,14 @@ panvk_queue_submit_batch(struct panvk_queue *queue, struct panvk_batch *batch,
} }
if (debug & PANVK_DEBUG_TRACE) if (debug & PANVK_DEBUG_TRACE)
pandecode_jc(batch->fragment_job, pdev->gpu_id); pandecode_jc(pdev->decode_ctx, batch->fragment_job, pdev->gpu_id);
if (debug & PANVK_DEBUG_DUMP) if (debug & PANVK_DEBUG_DUMP)
pandecode_dump_mappings(); pandecode_dump_mappings(pdev->decode_ctx);
} }
if (debug & PANVK_DEBUG_TRACE) if (debug & PANVK_DEBUG_TRACE)
pandecode_next_frame(); pandecode_next_frame(0);
batch->issued = true; batch->issued = true;
} }