2021-04-24 19:13:29 -04:00
|
|
|
/*
|
asahi: Convert to SPDX headers
Also drop my email address in the copyright lines and fix some "Copyright 208
Alyssa Rosenzweig" lines, I'm not *that* old. Together this drops a lot of
boilerplate without losing any meaningful licensing information. SPDX is already
in use for the MIT-licensed code in turnip, venus, and a few other scattered
parts of the tree, so this should be ok from a Mesa licensing standpoint.
This reduces friction to create new files, by parsing the copy/paste boilerplate
and being short enough you can easily type it out if you want. It makes new
files seem less daunting: 20 lines of header for 30 lines of code is
discouraging, but 2 lines of header for 30 lines of code is reasonable for a
simple compiler pass. This has technical effects, as lowering the barrier to
making new files should encourage people to split code into more modular files
with (hopefully positive) effects on project compile time.
This helps with consistency between files. Across the tree we have at least a
half dozen variants of the MIT license text (probably more), plus code that uses
SPDX headers instead. I've already been using SPDX headers in Asahi manually, so
you can tell old vs new code based on the headers.
Finally, it means less for reviewers to scroll through adding files. Minimal
actual cognitive burden for reviewers thanks to banner blindness, but the big
headers still bloat diffs that add/delete files.
I originally proposed this in December (for much more of the tree) but someone
requested I wait until January to discuss. I've been trying to get in touch with
them since then. It is now almost April and, with still no response, I'd like to
press forward with this. So with a joint sign-off from the major authors of the
code in question, let's do this.
Signed-off-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Acked-by: Emma Anholt <emma@anholt.net>
Acked-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Eric Engestrom <eric@igalia.com>
Acked-by: Kenneth Graunke <kenneth@whitecape.org>
Acked-by: Rose Hudson <rose@krx.sh>
Acked-by: Lyude Paul [over IRC: "yes I'm fine with that"]
Meh'd-by: Rob Clark <robdclark@chromium.org>
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22062>
2023-03-15 17:36:17 -04:00
|
|
|
* Copyright 2017-2019 Alyssa Rosenzweig
|
|
|
|
|
* Copyright 2017-2019 Connor Abbott
|
|
|
|
|
* Copyright 2019 Collabora, Ltd.
|
|
|
|
|
* SPDX-License-Identifier: MIT
|
2021-04-24 19:13:29 -04:00
|
|
|
*/
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
#include <ctype.h>
|
2021-04-24 19:13:29 -04:00
|
|
|
#include <memory.h>
|
|
|
|
|
#include <stdarg.h>
|
2022-12-27 17:36:08 -05:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
2021-04-24 19:13:29 -04:00
|
|
|
#include <sys/mman.h>
|
2022-12-27 17:36:08 -05:00
|
|
|
#include <agx_pack.h>
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2023-05-17 17:29:59 -04:00
|
|
|
#include "util/u_hexdump.h"
|
2021-04-24 19:13:29 -04:00
|
|
|
#include "decode.h"
|
2023-01-11 20:48:29 +09:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
#include "agx_iokit.h"
|
|
|
|
|
#endif
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2023-01-11 20:48:29 +09:00
|
|
|
UNUSED static const char *agx_alloc_types[AGX_NUM_ALLOC] = {"mem", "map",
|
|
|
|
|
"cmd"};
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
agx_disassemble(void *_code, size_t maxlen, FILE *fp)
|
|
|
|
|
{
|
|
|
|
|
/* stub */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FILE *agxdecode_dump_stream;
|
|
|
|
|
|
|
|
|
|
#define MAX_MAPPINGS 4096
|
|
|
|
|
|
|
|
|
|
struct agx_bo mmap_array[MAX_MAPPINGS];
|
|
|
|
|
unsigned mmap_count = 0;
|
|
|
|
|
|
|
|
|
|
struct agx_bo *ro_mappings[MAX_MAPPINGS];
|
|
|
|
|
unsigned ro_mapping_count = 0;
|
|
|
|
|
|
|
|
|
|
static struct agx_bo *
|
|
|
|
|
agxdecode_find_mapped_gpu_mem_containing_rw(uint64_t addr)
|
|
|
|
|
{
|
|
|
|
|
for (unsigned i = 0; i < mmap_count; ++i) {
|
2022-12-27 17:36:08 -05:00
|
|
|
if (mmap_array[i].type == AGX_ALLOC_REGULAR &&
|
|
|
|
|
addr >= mmap_array[i].ptr.gpu &&
|
|
|
|
|
(addr - mmap_array[i].ptr.gpu) < mmap_array[i].size)
|
2021-04-24 19:13:29 -04:00
|
|
|
return mmap_array + i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct agx_bo *
|
|
|
|
|
agxdecode_find_mapped_gpu_mem_containing(uint64_t addr)
|
|
|
|
|
{
|
|
|
|
|
struct agx_bo *mem = agxdecode_find_mapped_gpu_mem_containing_rw(addr);
|
|
|
|
|
|
|
|
|
|
if (mem && mem->ptr.cpu && !mem->ro) {
|
|
|
|
|
mprotect(mem->ptr.cpu, mem->size, PROT_READ);
|
|
|
|
|
mem->ro = true;
|
|
|
|
|
ro_mappings[ro_mapping_count++] = mem;
|
|
|
|
|
assert(ro_mapping_count < MAX_MAPPINGS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mem && !mem->mapped) {
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(stderr,
|
|
|
|
|
"[ERROR] access to memory not mapped (GPU %" PRIx64
|
|
|
|
|
", handle %u)\n",
|
|
|
|
|
mem->ptr.gpu, mem->handle);
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct agx_bo *
|
|
|
|
|
agxdecode_find_handle(unsigned handle, unsigned type)
|
|
|
|
|
{
|
|
|
|
|
for (unsigned i = 0; i < mmap_count; ++i) {
|
|
|
|
|
if (mmap_array[i].type != type)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (mmap_array[i].handle != handle)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
return &mmap_array[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-10 12:05:34 -04:00
|
|
|
static void
|
|
|
|
|
agxdecode_mark_mapped(unsigned handle)
|
|
|
|
|
{
|
|
|
|
|
struct agx_bo *bo = agxdecode_find_handle(handle, AGX_ALLOC_REGULAR);
|
|
|
|
|
|
|
|
|
|
if (!bo) {
|
|
|
|
|
fprintf(stderr, "ERROR - unknown BO mapped with handle %u\n", handle);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mark mapped for future consumption */
|
|
|
|
|
bo->mapped = true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-11 20:48:29 +09:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
static void
|
2022-04-02 22:14:11 -04:00
|
|
|
agxdecode_decode_segment_list(void *segment_list)
|
2021-04-24 19:13:29 -04:00
|
|
|
{
|
2021-07-10 12:05:34 -04:00
|
|
|
unsigned nr_handles = 0;
|
|
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
/* First, mark everything unmapped */
|
|
|
|
|
for (unsigned i = 0; i < mmap_count; ++i)
|
|
|
|
|
mmap_array[i].mapped = false;
|
|
|
|
|
|
|
|
|
|
/* Check the header */
|
2022-04-02 22:14:11 -04:00
|
|
|
struct agx_map_header *hdr = segment_list;
|
2022-04-02 21:55:25 -04:00
|
|
|
if (hdr->resource_group_count == 0) {
|
2022-04-02 22:14:11 -04:00
|
|
|
fprintf(agxdecode_dump_stream, "ERROR - empty map\n");
|
2021-04-24 19:13:29 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-02 22:14:11 -04:00
|
|
|
if (hdr->segment_count != 1) {
|
|
|
|
|
fprintf(agxdecode_dump_stream, "ERROR - can't handle segment count %u\n",
|
2022-12-27 17:36:08 -05:00
|
|
|
hdr->segment_count);
|
2022-04-02 22:14:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(agxdecode_dump_stream, "Segment list:\n");
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(agxdecode_dump_stream, " Command buffer shmem ID: %" PRIx64 "\n",
|
|
|
|
|
hdr->cmdbuf_id);
|
|
|
|
|
fprintf(agxdecode_dump_stream, " Encoder ID: %" PRIx64 "\n",
|
|
|
|
|
hdr->encoder_id);
|
2022-04-02 22:14:11 -04:00
|
|
|
fprintf(agxdecode_dump_stream, " Kernel commands start offset: %u\n",
|
2022-12-27 17:36:08 -05:00
|
|
|
hdr->kernel_commands_start_offset);
|
2022-04-02 22:14:11 -04:00
|
|
|
fprintf(agxdecode_dump_stream, " Kernel commands end offset: %u\n",
|
2022-12-27 17:36:08 -05:00
|
|
|
hdr->kernel_commands_end_offset);
|
2022-04-02 22:18:01 -04:00
|
|
|
fprintf(agxdecode_dump_stream, " Unknown: 0x%X\n", hdr->unk);
|
2022-04-02 22:14:11 -04:00
|
|
|
|
2022-04-02 22:21:15 -04:00
|
|
|
/* Expected structure: header followed by resource groups */
|
|
|
|
|
size_t length = sizeof(struct agx_map_header);
|
|
|
|
|
length += sizeof(struct agx_map_entry) * hdr->resource_group_count;
|
|
|
|
|
|
|
|
|
|
if (length != hdr->length) {
|
|
|
|
|
fprintf(agxdecode_dump_stream, "ERROR: expected length %zu, got %u\n",
|
|
|
|
|
length, hdr->length);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-02 22:14:11 -04:00
|
|
|
if (hdr->padding[0] || hdr->padding[1])
|
|
|
|
|
fprintf(agxdecode_dump_stream, "ERROR - padding tripped\n");
|
|
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
/* Check the entries */
|
2022-12-27 17:36:08 -05:00
|
|
|
struct agx_map_entry *groups = ((void *)hdr) + sizeof(*hdr);
|
2022-04-02 21:55:25 -04:00
|
|
|
for (unsigned i = 0; i < hdr->resource_group_count; ++i) {
|
2022-04-02 22:14:11 -04:00
|
|
|
struct agx_map_entry group = groups[i];
|
|
|
|
|
unsigned count = group.resource_count;
|
|
|
|
|
|
|
|
|
|
STATIC_ASSERT(ARRAY_SIZE(group.resource_id) == 6);
|
|
|
|
|
STATIC_ASSERT(ARRAY_SIZE(group.resource_unk) == 6);
|
|
|
|
|
STATIC_ASSERT(ARRAY_SIZE(group.resource_flags) == 6);
|
|
|
|
|
|
|
|
|
|
if ((count < 1) || (count > 6)) {
|
|
|
|
|
fprintf(agxdecode_dump_stream, "ERROR - invalid count %u\n", count);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-12-27 17:36:08 -05:00
|
|
|
|
2022-04-02 22:14:11 -04:00
|
|
|
for (unsigned j = 0; j < count; ++j) {
|
|
|
|
|
unsigned handle = group.resource_id[j];
|
|
|
|
|
unsigned unk = group.resource_unk[j];
|
|
|
|
|
unsigned flags = group.resource_flags[j];
|
|
|
|
|
|
|
|
|
|
if (!handle) {
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(agxdecode_dump_stream, "ERROR - invalid handle %u\n",
|
|
|
|
|
handle);
|
2022-04-02 22:14:11 -04:00
|
|
|
continue;
|
2021-07-10 12:05:34 -04:00
|
|
|
}
|
2022-04-02 22:14:11 -04:00
|
|
|
|
|
|
|
|
agxdecode_mark_mapped(handle);
|
|
|
|
|
nr_handles++;
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(agxdecode_dump_stream, "%u (0x%X, 0x%X)\n", handle, unk,
|
|
|
|
|
flags);
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
2022-04-02 22:14:11 -04:00
|
|
|
|
|
|
|
|
if (group.unka)
|
|
|
|
|
fprintf(agxdecode_dump_stream, "ERROR - unknown 0x%X\n", group.unka);
|
|
|
|
|
|
|
|
|
|
/* Visual separator for resource groups */
|
|
|
|
|
fprintf(agxdecode_dump_stream, "\n");
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
|
2021-07-10 12:05:34 -04:00
|
|
|
/* Check the handle count */
|
2022-04-02 21:55:25 -04:00
|
|
|
if (nr_handles != hdr->total_resources) {
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(agxdecode_dump_stream,
|
|
|
|
|
"ERROR - wrong handle count, got %u, expected %u (%u entries)\n",
|
|
|
|
|
nr_handles, hdr->total_resources, hdr->resource_group_count);
|
2021-07-10 12:05:34 -04:00
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
|
2023-01-11 20:48:29 +09:00
|
|
|
#endif
|
|
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
static inline void *
|
2022-12-27 17:36:08 -05:00
|
|
|
__agxdecode_fetch_gpu_mem(const struct agx_bo *mem, uint64_t gpu_va,
|
|
|
|
|
size_t size, int line, const char *filename)
|
2021-04-24 19:13:29 -04:00
|
|
|
{
|
|
|
|
|
if (!mem)
|
|
|
|
|
mem = agxdecode_find_mapped_gpu_mem_containing(gpu_va);
|
|
|
|
|
|
|
|
|
|
if (!mem) {
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(stderr, "Access to unknown memory %" PRIx64 " in %s:%d\n", gpu_va,
|
|
|
|
|
filename, line);
|
2021-04-24 19:13:29 -04:00
|
|
|
fflush(agxdecode_dump_stream);
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(mem);
|
|
|
|
|
assert(size + (gpu_va - mem->ptr.gpu) <= mem->size);
|
|
|
|
|
|
|
|
|
|
return mem->ptr.cpu + gpu_va - mem->ptr.gpu;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
#define agxdecode_fetch_gpu_mem(gpu_va, size) \
|
|
|
|
|
__agxdecode_fetch_gpu_mem(NULL, gpu_va, size, __LINE__, __FILE__)
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
agxdecode_map_read_write(void)
|
|
|
|
|
{
|
|
|
|
|
for (unsigned i = 0; i < ro_mapping_count; ++i) {
|
|
|
|
|
ro_mappings[i]->ro = false;
|
|
|
|
|
mprotect(ro_mappings[i]->ptr.cpu, ro_mappings[i]->size,
|
|
|
|
|
PROT_READ | PROT_WRITE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ro_mapping_count = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helpers for parsing the cmdstream */
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
#define DUMP_UNPACKED(T, var, str) \
|
|
|
|
|
{ \
|
|
|
|
|
agxdecode_log(str); \
|
|
|
|
|
agx_print(agxdecode_dump_stream, T, var, (agxdecode_indent + 1) * 2); \
|
|
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
#define DUMP_CL(T, cl, str) \
|
|
|
|
|
{ \
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, cl, T, temp); \
|
|
|
|
|
DUMP_UNPACKED(T, temp, str "\n"); \
|
|
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
#define agxdecode_log(str) fputs(str, agxdecode_dump_stream)
|
|
|
|
|
#define agxdecode_msg(str) fprintf(agxdecode_dump_stream, "// %s", str)
|
|
|
|
|
|
|
|
|
|
unsigned agxdecode_indent = 0;
|
|
|
|
|
|
|
|
|
|
/* Abstraction for command stream parsing */
|
2023-02-02 00:11:36 -05:00
|
|
|
typedef unsigned (*decode_cmd)(const uint8_t *map, uint64_t *link, bool verbose,
|
|
|
|
|
void *data);
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
#define STATE_DONE (0xFFFFFFFFu)
|
2022-09-05 17:43:34 -04:00
|
|
|
#define STATE_LINK (0xFFFFFFFEu)
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
static void
|
2022-12-27 17:36:08 -05:00
|
|
|
agxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder,
|
2023-02-02 00:11:36 -05:00
|
|
|
bool verbose, void *data)
|
2021-04-24 19:13:29 -04:00
|
|
|
{
|
|
|
|
|
struct agx_bo *alloc = agxdecode_find_mapped_gpu_mem_containing(va);
|
2023-03-16 07:51:57 +00:00
|
|
|
assert(alloc != NULL && "nonexistent object");
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(agxdecode_dump_stream, "%s (%" PRIx64 ", handle %u)\n", label, va,
|
|
|
|
|
alloc->handle);
|
2021-04-24 19:13:29 -04:00
|
|
|
fflush(agxdecode_dump_stream);
|
|
|
|
|
|
|
|
|
|
uint8_t *map = agxdecode_fetch_gpu_mem(va, 64);
|
2022-12-27 17:36:08 -05:00
|
|
|
uint8_t *end = (uint8_t *)alloc->ptr.cpu + alloc->size;
|
2022-09-05 17:43:34 -04:00
|
|
|
uint64_t link = 0;
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
fflush(agxdecode_dump_stream);
|
|
|
|
|
|
|
|
|
|
while (map < end) {
|
2023-02-02 00:11:36 -05:00
|
|
|
unsigned count = decoder(map, &link, verbose, data);
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
/* If we fail to decode, default to a hexdump (don't hang) */
|
|
|
|
|
if (count == 0) {
|
2023-05-17 17:29:59 -04:00
|
|
|
u_hexdump(agxdecode_dump_stream, map, 8, false);
|
2021-04-24 19:13:29 -04:00
|
|
|
count = 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
map += count;
|
|
|
|
|
fflush(agxdecode_dump_stream);
|
|
|
|
|
|
2022-09-05 17:43:34 -04:00
|
|
|
if (count == STATE_DONE) {
|
2021-04-24 19:13:29 -04:00
|
|
|
break;
|
2022-09-05 17:43:34 -04:00
|
|
|
} else if (count == STATE_LINK) {
|
|
|
|
|
alloc = agxdecode_find_mapped_gpu_mem_containing(link);
|
|
|
|
|
map = agxdecode_fetch_gpu_mem(link, 64);
|
2022-12-27 17:36:08 -05:00
|
|
|
end = (uint8_t *)alloc->ptr.cpu + alloc->size;
|
2022-09-05 17:43:34 -04:00
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned
|
2023-02-02 00:11:36 -05:00
|
|
|
agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose,
|
|
|
|
|
UNUSED void *data)
|
2021-04-24 19:13:29 -04:00
|
|
|
{
|
2023-02-02 00:24:11 -05:00
|
|
|
enum agx_sampler_states *sampler_states = data;
|
2022-09-17 11:22:01 -04:00
|
|
|
enum agx_usc_control type = map[0];
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2023-02-02 00:24:11 -05:00
|
|
|
bool extended_samplers =
|
|
|
|
|
(sampler_states != NULL) &&
|
|
|
|
|
(((*sampler_states) == AGX_SAMPLER_STATES_8_EXTENDED) ||
|
|
|
|
|
((*sampler_states) == AGX_SAMPLER_STATES_16_EXTENDED));
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
#define USC_CASE(name, human) \
|
|
|
|
|
case AGX_USC_CONTROL_##name: { \
|
|
|
|
|
DUMP_CL(USC_##name, map, human); \
|
|
|
|
|
return AGX_USC_##name##_LENGTH; \
|
2022-09-17 11:22:01 -04:00
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2022-09-17 11:22:01 -04:00
|
|
|
switch (type) {
|
|
|
|
|
case AGX_USC_CONTROL_NO_PRESHADER: {
|
|
|
|
|
DUMP_CL(USC_NO_PRESHADER, map, "No preshader");
|
|
|
|
|
return STATE_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case AGX_USC_CONTROL_PRESHADER: {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, USC_PRESHADER, ctrl);
|
|
|
|
|
DUMP_UNPACKED(USC_PRESHADER, ctrl, "Preshader\n");
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
agx_disassemble(agxdecode_fetch_gpu_mem(ctrl.code, 2048), 8192,
|
|
|
|
|
agxdecode_dump_stream);
|
2022-09-17 11:22:01 -04:00
|
|
|
|
|
|
|
|
return STATE_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case AGX_USC_CONTROL_SHADER: {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, USC_SHADER, ctrl);
|
|
|
|
|
DUMP_UNPACKED(USC_SHADER, ctrl, "Shader\n");
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
agxdecode_log("\n");
|
2022-12-27 17:36:08 -05:00
|
|
|
agx_disassemble(agxdecode_fetch_gpu_mem(ctrl.code, 2048), 8192,
|
|
|
|
|
agxdecode_dump_stream);
|
2021-04-24 19:13:29 -04:00
|
|
|
agxdecode_log("\n");
|
|
|
|
|
|
2022-09-17 11:22:01 -04:00
|
|
|
return AGX_USC_SHADER_LENGTH;
|
|
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2022-09-17 11:22:01 -04:00
|
|
|
case AGX_USC_CONTROL_SAMPLER: {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, USC_SAMPLER, temp);
|
|
|
|
|
DUMP_UNPACKED(USC_SAMPLER, temp, "Sampler state\n");
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
uint8_t *samp =
|
|
|
|
|
agxdecode_fetch_gpu_mem(temp.buffer, AGX_SAMPLER_LENGTH * temp.count);
|
2022-09-17 11:22:01 -04:00
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < temp.count; ++i) {
|
|
|
|
|
DUMP_CL(SAMPLER, samp, "Sampler");
|
|
|
|
|
samp += AGX_SAMPLER_LENGTH;
|
2023-02-02 00:24:11 -05:00
|
|
|
|
|
|
|
|
if (extended_samplers) {
|
|
|
|
|
DUMP_CL(BORDER, samp, "Border");
|
|
|
|
|
samp += AGX_BORDER_LENGTH;
|
|
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-17 11:22:01 -04:00
|
|
|
return AGX_USC_SAMPLER_LENGTH;
|
|
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2022-09-17 11:22:01 -04:00
|
|
|
case AGX_USC_CONTROL_TEXTURE: {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, USC_TEXTURE, temp);
|
|
|
|
|
DUMP_UNPACKED(USC_TEXTURE, temp, "Texture state\n");
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
uint8_t *tex =
|
|
|
|
|
agxdecode_fetch_gpu_mem(temp.buffer, AGX_TEXTURE_LENGTH * temp.count);
|
2022-05-22 23:02:29 -04:00
|
|
|
|
|
|
|
|
/* Note: samplers only need 8 byte alignment? */
|
|
|
|
|
for (unsigned i = 0; i < temp.count; ++i) {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, tex, TEXTURE, t);
|
|
|
|
|
DUMP_CL(TEXTURE, tex, "Texture");
|
2023-05-19 13:05:39 -04:00
|
|
|
DUMP_CL(PBE, tex, "PBE");
|
2022-05-22 23:02:29 -04:00
|
|
|
|
|
|
|
|
tex += AGX_TEXTURE_LENGTH;
|
|
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2022-09-17 11:22:01 -04:00
|
|
|
return AGX_USC_TEXTURE_LENGTH;
|
|
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2022-12-20 14:22:00 -05:00
|
|
|
case AGX_USC_CONTROL_UNIFORM: {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, USC_UNIFORM, temp);
|
|
|
|
|
DUMP_UNPACKED(USC_UNIFORM, temp, "Uniform\n");
|
|
|
|
|
|
|
|
|
|
uint8_t *raw = agxdecode_fetch_gpu_mem(temp.buffer, 2 * temp.size_halfs);
|
2023-05-17 17:29:59 -04:00
|
|
|
u_hexdump(agxdecode_dump_stream, raw, 2 * temp.size_halfs, false);
|
2022-12-20 14:22:00 -05:00
|
|
|
|
|
|
|
|
return AGX_USC_UNIFORM_LENGTH;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
USC_CASE(FRAGMENT_PROPERTIES, "Fragment properties");
|
|
|
|
|
USC_CASE(UNIFORM_HIGH, "Uniform high");
|
|
|
|
|
USC_CASE(SHARED, "Shared");
|
|
|
|
|
USC_CASE(REGISTERS, "Registers");
|
2022-05-22 23:02:29 -04:00
|
|
|
|
2022-09-17 11:22:01 -04:00
|
|
|
default:
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(agxdecode_dump_stream, "Unknown USC control type: %u\n", type);
|
2023-05-17 17:29:59 -04:00
|
|
|
u_hexdump(agxdecode_dump_stream, map, 8, false);
|
2022-09-17 11:22:01 -04:00
|
|
|
return 8;
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
2022-09-17 11:22:01 -04:00
|
|
|
|
|
|
|
|
#undef USC_CASE
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
#define PPP_PRINT(map, header_name, struct_name, human) \
|
|
|
|
|
if (hdr.header_name) { \
|
|
|
|
|
assert(((map + AGX_##struct_name##_LENGTH) <= (base + size)) && \
|
|
|
|
|
"buffer overrun in PPP update"); \
|
|
|
|
|
DUMP_CL(struct_name, map, human); \
|
|
|
|
|
map += AGX_##struct_name##_LENGTH; \
|
asahi: Match PPP data structures with PowerVR
Looking at PowerVR's PPP definitions in tree in Mesa
(src/imagination/csbgen/), we find that AGX's "tagged" data structures
are actually sequences of state items prefixed by a header specifying
which state follows. Rather than hardcoding the sequences in which Apple's
driver chooses to bundle state, we need the XML to be flexible enough to
encode or decode any valid combination of state. That means reworking
the XML. While doing so, we find a number of fields that are identical
between RGX and AGX, and fix the names while at it (for example, the W
Clamp floating point).
Names are from the PowerVR code in Mesa where sensible.
Once we've reworked the XML, we need to rework the decoder. Instead of
reading tags and printing the combined state packets, the decoder now
must unpack the header and print the individual state items specified by
the header, with slightly more complicated bounds checking.
Finally, state emission in the driver becomes much more flexible. To
prove the flexibility actually works, we now emit all PPP state (except for
viewport and scissor state) as a single PPP update. This works. After
this we can move onto more interesting arrangements of state for lower
driver overhead.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
2022-09-04 15:17:22 -04:00
|
|
|
}
|
|
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
static void
|
|
|
|
|
agxdecode_record(uint64_t va, size_t size, bool verbose)
|
|
|
|
|
{
|
asahi: Match PPP data structures with PowerVR
Looking at PowerVR's PPP definitions in tree in Mesa
(src/imagination/csbgen/), we find that AGX's "tagged" data structures
are actually sequences of state items prefixed by a header specifying
which state follows. Rather than hardcoding the sequences in which Apple's
driver chooses to bundle state, we need the XML to be flexible enough to
encode or decode any valid combination of state. That means reworking
the XML. While doing so, we find a number of fields that are identical
between RGX and AGX, and fix the names while at it (for example, the W
Clamp floating point).
Names are from the PowerVR code in Mesa where sensible.
Once we've reworked the XML, we need to rework the decoder. Instead of
reading tags and printing the combined state packets, the decoder now
must unpack the header and print the individual state items specified by
the header, with slightly more complicated bounds checking.
Finally, state emission in the driver becomes much more flexible. To
prove the flexibility actually works, we now emit all PPP state (except for
viewport and scissor state) as a single PPP update. This works. After
this we can move onto more interesting arrangements of state for lower
driver overhead.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
2022-09-04 15:17:22 -04:00
|
|
|
uint8_t *base = agxdecode_fetch_gpu_mem(va, size);
|
|
|
|
|
uint8_t *map = base;
|
|
|
|
|
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, PPP_HEADER, hdr);
|
|
|
|
|
map += AGX_PPP_HEADER_LENGTH;
|
|
|
|
|
|
|
|
|
|
PPP_PRINT(map, fragment_control, FRAGMENT_CONTROL, "Fragment control");
|
2023-01-06 23:22:33 -05:00
|
|
|
PPP_PRINT(map, fragment_control_2, FRAGMENT_CONTROL, "Fragment control 2");
|
asahi: Match PPP data structures with PowerVR
Looking at PowerVR's PPP definitions in tree in Mesa
(src/imagination/csbgen/), we find that AGX's "tagged" data structures
are actually sequences of state items prefixed by a header specifying
which state follows. Rather than hardcoding the sequences in which Apple's
driver chooses to bundle state, we need the XML to be flexible enough to
encode or decode any valid combination of state. That means reworking
the XML. While doing so, we find a number of fields that are identical
between RGX and AGX, and fix the names while at it (for example, the W
Clamp floating point).
Names are from the PowerVR code in Mesa where sensible.
Once we've reworked the XML, we need to rework the decoder. Instead of
reading tags and printing the combined state packets, the decoder now
must unpack the header and print the individual state items specified by
the header, with slightly more complicated bounds checking.
Finally, state emission in the driver becomes much more flexible. To
prove the flexibility actually works, we now emit all PPP state (except for
viewport and scissor state) as a single PPP update. This works. After
this we can move onto more interesting arrangements of state for lower
driver overhead.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
2022-09-04 15:17:22 -04:00
|
|
|
PPP_PRINT(map, fragment_front_face, FRAGMENT_FACE, "Front face");
|
|
|
|
|
PPP_PRINT(map, fragment_front_face_2, FRAGMENT_FACE_2, "Front face 2");
|
|
|
|
|
PPP_PRINT(map, fragment_front_stencil, FRAGMENT_STENCIL, "Front stencil");
|
|
|
|
|
PPP_PRINT(map, fragment_back_face, FRAGMENT_FACE, "Back face");
|
|
|
|
|
PPP_PRINT(map, fragment_back_face_2, FRAGMENT_FACE_2, "Back face 2");
|
|
|
|
|
PPP_PRINT(map, fragment_back_stencil, FRAGMENT_STENCIL, "Back stencil");
|
|
|
|
|
PPP_PRINT(map, depth_bias_scissor, DEPTH_BIAS_SCISSOR, "Depth bias/scissor");
|
|
|
|
|
PPP_PRINT(map, region_clip, REGION_CLIP, "Region clip");
|
|
|
|
|
PPP_PRINT(map, viewport, VIEWPORT, "Viewport");
|
|
|
|
|
PPP_PRINT(map, w_clamp, W_CLAMP, "W clamp");
|
|
|
|
|
PPP_PRINT(map, output_select, OUTPUT_SELECT, "Output select");
|
2023-06-28 17:09:19 +09:00
|
|
|
PPP_PRINT(map, varying_counts_32, VARYING_COUNTS, "Varying counts 32");
|
|
|
|
|
PPP_PRINT(map, varying_counts_16, VARYING_COUNTS, "Varying counts 16");
|
asahi: Match PPP data structures with PowerVR
Looking at PowerVR's PPP definitions in tree in Mesa
(src/imagination/csbgen/), we find that AGX's "tagged" data structures
are actually sequences of state items prefixed by a header specifying
which state follows. Rather than hardcoding the sequences in which Apple's
driver chooses to bundle state, we need the XML to be flexible enough to
encode or decode any valid combination of state. That means reworking
the XML. While doing so, we find a number of fields that are identical
between RGX and AGX, and fix the names while at it (for example, the W
Clamp floating point).
Names are from the PowerVR code in Mesa where sensible.
Once we've reworked the XML, we need to rework the decoder. Instead of
reading tags and printing the combined state packets, the decoder now
must unpack the header and print the individual state items specified by
the header, with slightly more complicated bounds checking.
Finally, state emission in the driver becomes much more flexible. To
prove the flexibility actually works, we now emit all PPP state (except for
viewport and scissor state) as a single PPP update. This works. After
this we can move onto more interesting arrangements of state for lower
driver overhead.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
2022-09-04 15:17:22 -04:00
|
|
|
PPP_PRINT(map, cull, CULL, "Cull");
|
|
|
|
|
PPP_PRINT(map, cull_2, CULL_2, "Cull 2");
|
|
|
|
|
|
|
|
|
|
if (hdr.fragment_shader) {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, FRAGMENT_SHADER, frag);
|
2022-12-27 17:36:08 -05:00
|
|
|
agxdecode_stateful(frag.pipeline, "Fragment pipeline", agxdecode_usc,
|
2023-02-02 00:24:11 -05:00
|
|
|
verbose, &frag.sampler_state_register_count);
|
asahi: Match PPP data structures with PowerVR
Looking at PowerVR's PPP definitions in tree in Mesa
(src/imagination/csbgen/), we find that AGX's "tagged" data structures
are actually sequences of state items prefixed by a header specifying
which state follows. Rather than hardcoding the sequences in which Apple's
driver chooses to bundle state, we need the XML to be flexible enough to
encode or decode any valid combination of state. That means reworking
the XML. While doing so, we find a number of fields that are identical
between RGX and AGX, and fix the names while at it (for example, the W
Clamp floating point).
Names are from the PowerVR code in Mesa where sensible.
Once we've reworked the XML, we need to rework the decoder. Instead of
reading tags and printing the combined state packets, the decoder now
must unpack the header and print the individual state items specified by
the header, with slightly more complicated bounds checking.
Finally, state emission in the driver becomes much more flexible. To
prove the flexibility actually works, we now emit all PPP state (except for
viewport and scissor state) as a single PPP update. This works. After
this we can move onto more interesting arrangements of state for lower
driver overhead.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
2022-09-04 15:17:22 -04:00
|
|
|
|
|
|
|
|
if (frag.cf_bindings) {
|
|
|
|
|
uint8_t *cf = agxdecode_fetch_gpu_mem(frag.cf_bindings, 128);
|
2023-05-17 17:29:59 -04:00
|
|
|
u_hexdump(agxdecode_dump_stream, cf, 128, false);
|
asahi: Match PPP data structures with PowerVR
Looking at PowerVR's PPP definitions in tree in Mesa
(src/imagination/csbgen/), we find that AGX's "tagged" data structures
are actually sequences of state items prefixed by a header specifying
which state follows. Rather than hardcoding the sequences in which Apple's
driver chooses to bundle state, we need the XML to be flexible enough to
encode or decode any valid combination of state. That means reworking
the XML. While doing so, we find a number of fields that are identical
between RGX and AGX, and fix the names while at it (for example, the W
Clamp floating point).
Names are from the PowerVR code in Mesa where sensible.
Once we've reworked the XML, we need to rework the decoder. Instead of
reading tags and printing the combined state packets, the decoder now
must unpack the header and print the individual state items specified by
the header, with slightly more complicated bounds checking.
Finally, state emission in the driver becomes much more flexible. To
prove the flexibility actually works, we now emit all PPP state (except for
viewport and scissor state) as a single PPP update. This works. After
this we can move onto more interesting arrangements of state for lower
driver overhead.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
2022-09-04 15:17:22 -04:00
|
|
|
|
|
|
|
|
DUMP_CL(CF_BINDING_HEADER, cf, "Coefficient binding header:");
|
|
|
|
|
cf += AGX_CF_BINDING_HEADER_LENGTH;
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < frag.cf_binding_count; ++i) {
|
|
|
|
|
DUMP_CL(CF_BINDING, cf, "Coefficient binding:");
|
|
|
|
|
cf += AGX_CF_BINDING_LENGTH;
|
2021-07-11 17:05:03 -04:00
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
|
asahi: Match PPP data structures with PowerVR
Looking at PowerVR's PPP definitions in tree in Mesa
(src/imagination/csbgen/), we find that AGX's "tagged" data structures
are actually sequences of state items prefixed by a header specifying
which state follows. Rather than hardcoding the sequences in which Apple's
driver chooses to bundle state, we need the XML to be flexible enough to
encode or decode any valid combination of state. That means reworking
the XML. While doing so, we find a number of fields that are identical
between RGX and AGX, and fix the names while at it (for example, the W
Clamp floating point).
Names are from the PowerVR code in Mesa where sensible.
Once we've reworked the XML, we need to rework the decoder. Instead of
reading tags and printing the combined state packets, the decoder now
must unpack the header and print the individual state items specified by
the header, with slightly more complicated bounds checking.
Finally, state emission in the driver becomes much more flexible. To
prove the flexibility actually works, we now emit all PPP state (except for
viewport and scissor state) as a single PPP update. This works. After
this we can move onto more interesting arrangements of state for lower
driver overhead.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
2022-09-04 15:17:22 -04:00
|
|
|
DUMP_UNPACKED(FRAGMENT_SHADER, frag, "Fragment shader\n");
|
|
|
|
|
map += AGX_FRAGMENT_SHADER_LENGTH;
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
asahi: Match PPP data structures with PowerVR
Looking at PowerVR's PPP definitions in tree in Mesa
(src/imagination/csbgen/), we find that AGX's "tagged" data structures
are actually sequences of state items prefixed by a header specifying
which state follows. Rather than hardcoding the sequences in which Apple's
driver chooses to bundle state, we need the XML to be flexible enough to
encode or decode any valid combination of state. That means reworking
the XML. While doing so, we find a number of fields that are identical
between RGX and AGX, and fix the names while at it (for example, the W
Clamp floating point).
Names are from the PowerVR code in Mesa where sensible.
Once we've reworked the XML, we need to rework the decoder. Instead of
reading tags and printing the combined state packets, the decoder now
must unpack the header and print the individual state items specified by
the header, with slightly more complicated bounds checking.
Finally, state emission in the driver becomes much more flexible. To
prove the flexibility actually works, we now emit all PPP state (except for
viewport and scissor state) as a single PPP update. This works. After
this we can move onto more interesting arrangements of state for lower
driver overhead.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
2022-09-04 15:17:22 -04:00
|
|
|
|
|
|
|
|
PPP_PRINT(map, occlusion_query, FRAGMENT_OCCLUSION_QUERY, "Occlusion query");
|
2022-12-27 17:36:08 -05:00
|
|
|
PPP_PRINT(map, occlusion_query_2, FRAGMENT_OCCLUSION_QUERY_2,
|
|
|
|
|
"Occlusion query 2");
|
asahi: Match PPP data structures with PowerVR
Looking at PowerVR's PPP definitions in tree in Mesa
(src/imagination/csbgen/), we find that AGX's "tagged" data structures
are actually sequences of state items prefixed by a header specifying
which state follows. Rather than hardcoding the sequences in which Apple's
driver chooses to bundle state, we need the XML to be flexible enough to
encode or decode any valid combination of state. That means reworking
the XML. While doing so, we find a number of fields that are identical
between RGX and AGX, and fix the names while at it (for example, the W
Clamp floating point).
Names are from the PowerVR code in Mesa where sensible.
Once we've reworked the XML, we need to rework the decoder. Instead of
reading tags and printing the combined state packets, the decoder now
must unpack the header and print the individual state items specified by
the header, with slightly more complicated bounds checking.
Finally, state emission in the driver becomes much more flexible. To
prove the flexibility actually works, we now emit all PPP state (except for
viewport and scissor state) as a single PPP update. This works. After
this we can move onto more interesting arrangements of state for lower
driver overhead.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
2022-09-04 15:17:22 -04:00
|
|
|
PPP_PRINT(map, output_unknown, OUTPUT_UNKNOWN, "Output unknown");
|
|
|
|
|
PPP_PRINT(map, output_size, OUTPUT_SIZE, "Output size");
|
|
|
|
|
PPP_PRINT(map, varying_word_2, VARYING_2, "Varying word 2");
|
|
|
|
|
|
|
|
|
|
/* PPP print checks we don't read too much, now check we read enough */
|
|
|
|
|
assert(map == (base + size) && "invalid size of PPP update");
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned
|
2023-02-02 00:11:36 -05:00
|
|
|
agxdecode_cdm(const uint8_t *map, uint64_t *link, bool verbose,
|
|
|
|
|
UNUSED void *data)
|
2021-04-24 19:13:29 -04:00
|
|
|
{
|
2022-09-12 22:34:12 -04:00
|
|
|
/* Bits 29-31 contain the block type */
|
|
|
|
|
enum agx_cdm_block_type block_type = (map[3] >> 5);
|
|
|
|
|
|
|
|
|
|
switch (block_type) {
|
2023-02-11 16:12:04 -05:00
|
|
|
case AGX_CDM_BLOCK_TYPE_HEADER: {
|
|
|
|
|
size_t length = AGX_CDM_HEADER_LENGTH;
|
|
|
|
|
|
|
|
|
|
#define CDM_PRINT(STRUCT_NAME, human) \
|
|
|
|
|
DUMP_CL(CDM_##STRUCT_NAME, map, human); \
|
|
|
|
|
map += AGX_CDM_##STRUCT_NAME##_LENGTH; \
|
|
|
|
|
length += AGX_CDM_##STRUCT_NAME##_LENGTH;
|
|
|
|
|
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, CDM_HEADER, hdr);
|
|
|
|
|
agxdecode_stateful(hdr.pipeline, "Pipeline", agxdecode_usc, verbose,
|
|
|
|
|
&hdr.sampler_state_register_count);
|
|
|
|
|
DUMP_UNPACKED(CDM_HEADER, hdr, "Compute\n");
|
|
|
|
|
map += AGX_CDM_HEADER_LENGTH;
|
|
|
|
|
|
|
|
|
|
switch (hdr.mode) {
|
|
|
|
|
case AGX_CDM_MODE_DIRECT:
|
|
|
|
|
CDM_PRINT(GLOBAL_SIZE, "Global size");
|
|
|
|
|
CDM_PRINT(LOCAL_SIZE, "Local size");
|
|
|
|
|
break;
|
|
|
|
|
case AGX_CDM_MODE_INDIRECT_GLOBAL:
|
|
|
|
|
CDM_PRINT(INDIRECT, "Indirect buffer");
|
|
|
|
|
CDM_PRINT(LOCAL_SIZE, "Local size");
|
|
|
|
|
break;
|
|
|
|
|
case AGX_CDM_MODE_INDIRECT_LOCAL:
|
|
|
|
|
CDM_PRINT(INDIRECT, "Indirect buffer");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(agxdecode_dump_stream, "Unknown CDM mode: %u\n", hdr.mode);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return length;
|
2022-09-05 15:49:39 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-12 22:34:12 -04:00
|
|
|
case AGX_CDM_BLOCK_TYPE_STREAM_LINK: {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, CDM_STREAM_LINK, hdr);
|
|
|
|
|
DUMP_UNPACKED(CDM_STREAM_LINK, hdr, "Stream Link\n");
|
2022-12-27 17:36:08 -05:00
|
|
|
*link = hdr.target_lo | (((uint64_t)hdr.target_hi) << 32);
|
2022-09-12 22:34:12 -04:00
|
|
|
return STATE_LINK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case AGX_CDM_BLOCK_TYPE_STREAM_TERMINATE: {
|
|
|
|
|
DUMP_CL(CDM_STREAM_TERMINATE, map, "Stream Terminate");
|
|
|
|
|
return STATE_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-11 16:12:04 -05:00
|
|
|
case AGX_CDM_BLOCK_TYPE_LAUNCH: {
|
|
|
|
|
DUMP_CL(CDM_LAUNCH, map, "Launch");
|
|
|
|
|
return AGX_CDM_LAUNCH_LENGTH;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-12 22:34:12 -04:00
|
|
|
default:
|
|
|
|
|
fprintf(agxdecode_dump_stream, "Unknown CDM block type: %u\n",
|
|
|
|
|
block_type);
|
2023-05-17 17:29:59 -04:00
|
|
|
u_hexdump(agxdecode_dump_stream, map, 8, false);
|
2022-09-12 22:34:12 -04:00
|
|
|
return 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned
|
2023-02-02 00:11:36 -05:00
|
|
|
agxdecode_vdm(const uint8_t *map, uint64_t *link, bool verbose,
|
|
|
|
|
UNUSED void *data)
|
2022-09-12 22:34:12 -04:00
|
|
|
{
|
2022-09-05 15:49:39 -04:00
|
|
|
/* Bits 29-31 contain the block type */
|
|
|
|
|
enum agx_vdm_block_type block_type = (map[3] >> 5);
|
|
|
|
|
|
|
|
|
|
switch (block_type) {
|
2023-02-25 11:21:37 -05:00
|
|
|
case AGX_VDM_BLOCK_TYPE_BARRIER: {
|
2023-03-18 14:33:10 -04:00
|
|
|
DUMP_CL(VDM_BARRIER, map, "Barrier");
|
2023-02-25 11:21:37 -05:00
|
|
|
return AGX_VDM_BARRIER_LENGTH;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 15:49:39 -04:00
|
|
|
case AGX_VDM_BLOCK_TYPE_PPP_STATE_UPDATE: {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, PPP_STATE, cmd);
|
2021-07-10 12:30:09 -04:00
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
uint64_t address = (((uint64_t)cmd.pointer_hi) << 32) | cmd.pointer_lo;
|
2021-11-13 14:52:52 -05:00
|
|
|
struct agx_bo *mem = agxdecode_find_mapped_gpu_mem_containing(address);
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
if (mem)
|
2021-11-13 14:52:52 -05:00
|
|
|
agxdecode_record(address, cmd.size_words * 4, verbose);
|
2021-04-24 19:13:29 -04:00
|
|
|
else
|
2023-03-16 07:51:57 +00:00
|
|
|
DUMP_UNPACKED(PPP_STATE, cmd, "Non-existent record (XXX)\n");
|
2022-09-05 15:49:39 -04:00
|
|
|
|
|
|
|
|
return AGX_PPP_STATE_LENGTH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case AGX_VDM_BLOCK_TYPE_VDM_STATE_UPDATE: {
|
|
|
|
|
size_t length = AGX_VDM_STATE_LENGTH;
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, VDM_STATE, hdr);
|
|
|
|
|
map += AGX_VDM_STATE_LENGTH;
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
#define VDM_PRINT(header_name, STRUCT_NAME, human) \
|
|
|
|
|
if (hdr.header_name##_present) { \
|
|
|
|
|
DUMP_CL(VDM_STATE_##STRUCT_NAME, map, human); \
|
|
|
|
|
map += AGX_VDM_STATE_##STRUCT_NAME##_LENGTH; \
|
|
|
|
|
length += AGX_VDM_STATE_##STRUCT_NAME##_LENGTH; \
|
|
|
|
|
}
|
2022-09-05 15:49:39 -04:00
|
|
|
|
|
|
|
|
VDM_PRINT(restart_index, RESTART_INDEX, "Restart index");
|
2023-02-02 00:24:11 -05:00
|
|
|
|
|
|
|
|
/* If word 1 is present but word 0 is not, fallback to compact samplers */
|
|
|
|
|
enum agx_sampler_states sampler_states = 0;
|
|
|
|
|
|
|
|
|
|
if (hdr.vertex_shader_word_0_present) {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, VDM_STATE_VERTEX_SHADER_WORD_0,
|
|
|
|
|
word_0);
|
|
|
|
|
sampler_states = word_0.sampler_state_register_count;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
VDM_PRINT(vertex_shader_word_0, VERTEX_SHADER_WORD_0,
|
|
|
|
|
"Vertex shader word 0");
|
2022-09-05 15:49:39 -04:00
|
|
|
|
|
|
|
|
if (hdr.vertex_shader_word_1_present) {
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, VDM_STATE_VERTEX_SHADER_WORD_1,
|
|
|
|
|
word_1);
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(agxdecode_dump_stream, "Pipeline %X\n",
|
|
|
|
|
(uint32_t)word_1.pipeline);
|
2023-02-02 00:11:36 -05:00
|
|
|
agxdecode_stateful(word_1.pipeline, "Pipeline", agxdecode_usc, verbose,
|
2023-02-02 00:24:11 -05:00
|
|
|
&sampler_states);
|
2022-09-05 15:49:39 -04:00
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
VDM_PRINT(vertex_shader_word_1, VERTEX_SHADER_WORD_1,
|
|
|
|
|
"Vertex shader word 1");
|
2022-09-05 15:49:39 -04:00
|
|
|
VDM_PRINT(vertex_outputs, VERTEX_OUTPUTS, "Vertex outputs");
|
|
|
|
|
VDM_PRINT(vertex_unknown, VERTEX_UNKNOWN, "Vertex unknown");
|
|
|
|
|
|
|
|
|
|
#undef VDM_PRINT
|
|
|
|
|
return ALIGN_POT(length, 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case AGX_VDM_BLOCK_TYPE_INDEX_LIST: {
|
|
|
|
|
size_t length = AGX_INDEX_LIST_LENGTH;
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, map, INDEX_LIST, hdr);
|
|
|
|
|
DUMP_UNPACKED(INDEX_LIST, hdr, "Index List\n");
|
|
|
|
|
map += AGX_INDEX_LIST_LENGTH;
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
#define IDX_PRINT(header_name, STRUCT_NAME, human) \
|
|
|
|
|
if (hdr.header_name##_present) { \
|
|
|
|
|
DUMP_CL(INDEX_LIST_##STRUCT_NAME, map, human); \
|
|
|
|
|
map += AGX_INDEX_LIST_##STRUCT_NAME##_LENGTH; \
|
|
|
|
|
length += AGX_INDEX_LIST_##STRUCT_NAME##_LENGTH; \
|
|
|
|
|
}
|
2022-09-05 15:49:39 -04:00
|
|
|
|
|
|
|
|
IDX_PRINT(index_buffer, BUFFER_LO, "Index buffer");
|
|
|
|
|
IDX_PRINT(index_count, COUNT, "Index count");
|
|
|
|
|
IDX_PRINT(instance_count, INSTANCES, "Instance count");
|
|
|
|
|
IDX_PRINT(start, START, "Start");
|
2023-02-11 17:39:37 -05:00
|
|
|
IDX_PRINT(indirect_buffer, INDIRECT_BUFFER, "Indirect buffer");
|
2022-11-08 15:07:24 -05:00
|
|
|
IDX_PRINT(index_buffer_size, BUFFER_SIZE, "Index buffer size");
|
2022-09-05 15:49:39 -04:00
|
|
|
|
|
|
|
|
#undef IDX_PRINT
|
2023-02-11 17:39:37 -05:00
|
|
|
return length;
|
2022-09-05 15:49:39 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-05 17:43:34 -04:00
|
|
|
case AGX_VDM_BLOCK_TYPE_STREAM_LINK: {
|
2022-09-12 22:22:56 -04:00
|
|
|
agx_unpack(agxdecode_dump_stream, map, VDM_STREAM_LINK, hdr);
|
|
|
|
|
DUMP_UNPACKED(VDM_STREAM_LINK, hdr, "Stream Link\n");
|
2022-12-27 17:36:08 -05:00
|
|
|
*link = hdr.target_lo | (((uint64_t)hdr.target_hi) << 32);
|
2022-09-05 17:43:34 -04:00
|
|
|
return STATE_LINK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 15:49:39 -04:00
|
|
|
case AGX_VDM_BLOCK_TYPE_STREAM_TERMINATE: {
|
2022-09-12 22:22:56 -04:00
|
|
|
DUMP_CL(VDM_STREAM_TERMINATE, map, "Stream Terminate");
|
2021-04-24 19:13:29 -04:00
|
|
|
return STATE_DONE;
|
2022-09-05 15:49:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf(agxdecode_dump_stream, "Unknown VDM block type: %u\n",
|
|
|
|
|
block_type);
|
2023-05-17 17:29:59 -04:00
|
|
|
u_hexdump(agxdecode_dump_stream, map, 8, false);
|
2022-09-05 15:49:39 -04:00
|
|
|
return 8;
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-14 20:08:23 -04:00
|
|
|
static void
|
|
|
|
|
agxdecode_cs(uint32_t *cmdbuf, uint64_t encoder, bool verbose)
|
|
|
|
|
{
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, cmdbuf + 16, IOGPU_COMPUTE, cs);
|
|
|
|
|
DUMP_UNPACKED(IOGPU_COMPUTE, cs, "Compute\n");
|
|
|
|
|
|
2023-02-02 00:11:36 -05:00
|
|
|
agxdecode_stateful(encoder, "Encoder", agxdecode_cdm, verbose, NULL);
|
2022-12-03 13:18:03 -05:00
|
|
|
|
|
|
|
|
fprintf(agxdecode_dump_stream, "Context switch program:\n");
|
|
|
|
|
agx_disassemble(agxdecode_fetch_gpu_mem(cs.context_switch_program, 1024),
|
|
|
|
|
1024, agxdecode_dump_stream);
|
2022-09-14 20:08:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
agxdecode_gfx(uint32_t *cmdbuf, uint64_t encoder, bool verbose)
|
|
|
|
|
{
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, cmdbuf + 16, IOGPU_GRAPHICS, gfx);
|
|
|
|
|
DUMP_UNPACKED(IOGPU_GRAPHICS, gfx, "Graphics\n");
|
|
|
|
|
|
2023-02-02 00:11:36 -05:00
|
|
|
agxdecode_stateful(encoder, "Encoder", agxdecode_vdm, verbose, NULL);
|
2022-09-14 20:08:23 -04:00
|
|
|
|
|
|
|
|
if (gfx.clear_pipeline_unk) {
|
|
|
|
|
fprintf(agxdecode_dump_stream, "Unk: %X\n", gfx.clear_pipeline_unk);
|
2022-12-27 17:36:08 -05:00
|
|
|
agxdecode_stateful(gfx.clear_pipeline, "Clear pipeline", agxdecode_usc,
|
2023-02-02 00:11:36 -05:00
|
|
|
verbose, NULL);
|
2022-09-14 20:08:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gfx.store_pipeline_unk) {
|
|
|
|
|
assert(gfx.store_pipeline_unk == 0x4);
|
2022-12-27 17:36:08 -05:00
|
|
|
agxdecode_stateful(gfx.store_pipeline, "Store pipeline", agxdecode_usc,
|
2023-02-02 00:11:36 -05:00
|
|
|
verbose, NULL);
|
2022-09-14 20:08:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert((gfx.partial_reload_pipeline_unk & 0xF) == 0x4);
|
|
|
|
|
if (gfx.partial_reload_pipeline) {
|
2022-12-27 17:36:08 -05:00
|
|
|
agxdecode_stateful(gfx.partial_reload_pipeline, "Partial reload pipeline",
|
2023-02-02 00:11:36 -05:00
|
|
|
agxdecode_usc, verbose, NULL);
|
2022-09-14 20:08:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gfx.partial_store_pipeline) {
|
2022-12-27 17:36:08 -05:00
|
|
|
agxdecode_stateful(gfx.partial_store_pipeline, "Partial store pipeline",
|
2023-02-02 00:11:36 -05:00
|
|
|
agxdecode_usc, verbose, NULL);
|
2022-09-14 20:08:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-11 20:48:29 +09:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
void
|
|
|
|
|
agxdecode_cmdstream(unsigned cmdbuf_handle, unsigned map_handle, bool verbose)
|
|
|
|
|
{
|
|
|
|
|
agxdecode_dump_file_open();
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
struct agx_bo *cmdbuf =
|
|
|
|
|
agxdecode_find_handle(cmdbuf_handle, AGX_ALLOC_CMDBUF);
|
2021-04-24 19:13:29 -04:00
|
|
|
struct agx_bo *map = agxdecode_find_handle(map_handle, AGX_ALLOC_MEMMAP);
|
2023-03-16 07:51:57 +00:00
|
|
|
assert(cmdbuf != NULL && "nonexistent command buffer");
|
|
|
|
|
assert(map != NULL && "nonexistent mapping");
|
2021-04-24 19:13:29 -04:00
|
|
|
|
|
|
|
|
/* Before decoding anything, validate the map. Set bo->mapped fields */
|
2022-04-02 22:14:11 -04:00
|
|
|
agxdecode_decode_segment_list(map->ptr.cpu);
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2021-07-11 14:48:03 -04:00
|
|
|
/* Print the IOGPU stuff */
|
|
|
|
|
agx_unpack(agxdecode_dump_stream, cmdbuf->ptr.cpu, IOGPU_HEADER, cmd);
|
|
|
|
|
DUMP_UNPACKED(IOGPU_HEADER, cmd, "IOGPU Header\n");
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
DUMP_CL(IOGPU_ATTACHMENT_COUNT,
|
|
|
|
|
((uint8_t *)cmdbuf->ptr.cpu + cmd.attachment_offset),
|
|
|
|
|
"Attachment count");
|
2022-04-02 12:35:57 -04:00
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
uint32_t *attachments =
|
|
|
|
|
(uint32_t *)((uint8_t *)cmdbuf->ptr.cpu + cmd.attachment_offset);
|
2021-07-11 14:48:03 -04:00
|
|
|
unsigned attachment_count = attachments[3];
|
|
|
|
|
for (unsigned i = 0; i < attachment_count; ++i) {
|
|
|
|
|
uint32_t *ptr = attachments + 4 + (i * AGX_IOGPU_ATTACHMENT_LENGTH / 4);
|
|
|
|
|
DUMP_CL(IOGPU_ATTACHMENT, ptr, "Attachment");
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-12 22:34:12 -04:00
|
|
|
if (cmd.unk_5 == 3)
|
2022-12-27 17:36:08 -05:00
|
|
|
agxdecode_cs((uint32_t *)cmdbuf->ptr.cpu, cmd.encoder, verbose);
|
2022-09-12 22:34:12 -04:00
|
|
|
else
|
2022-12-27 17:36:08 -05:00
|
|
|
agxdecode_gfx((uint32_t *)cmdbuf->ptr.cpu, cmd.encoder, verbose);
|
2022-04-02 13:22:04 -04:00
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
agxdecode_map_read_write();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2021-07-10 11:04:45 -04:00
|
|
|
agxdecode_dump_mappings(unsigned map_handle)
|
2021-04-24 19:13:29 -04:00
|
|
|
{
|
|
|
|
|
agxdecode_dump_file_open();
|
|
|
|
|
|
2021-07-10 11:04:45 -04:00
|
|
|
struct agx_bo *map = agxdecode_find_handle(map_handle, AGX_ALLOC_MEMMAP);
|
2023-03-16 07:51:57 +00:00
|
|
|
assert(map != NULL && "nonexistent mapping");
|
2022-04-02 22:14:11 -04:00
|
|
|
agxdecode_decode_segment_list(map->ptr.cpu);
|
2021-07-10 11:04:45 -04:00
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
for (unsigned i = 0; i < mmap_count; ++i) {
|
2022-12-27 17:36:08 -05:00
|
|
|
if (!mmap_array[i].ptr.cpu || !mmap_array[i].size ||
|
|
|
|
|
!mmap_array[i].mapped)
|
2021-04-24 19:13:29 -04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
assert(mmap_array[i].type < AGX_NUM_ALLOC);
|
|
|
|
|
|
2022-12-27 17:36:08 -05:00
|
|
|
fprintf(agxdecode_dump_stream,
|
|
|
|
|
"Buffer: type %s, gpu %" PRIx64 ", handle %u.bin:\n\n",
|
|
|
|
|
agx_alloc_types[mmap_array[i].type], mmap_array[i].ptr.gpu,
|
|
|
|
|
mmap_array[i].handle);
|
2021-04-24 19:13:29 -04:00
|
|
|
|
2023-05-17 17:29:59 -04:00
|
|
|
u_hexdump(agxdecode_dump_stream, mmap_array[i].ptr.cpu,
|
|
|
|
|
mmap_array[i].size, false);
|
2021-04-24 19:13:29 -04:00
|
|
|
fprintf(agxdecode_dump_stream, "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-11 20:48:29 +09:00
|
|
|
#endif
|
|
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
void
|
|
|
|
|
agxdecode_track_alloc(struct agx_bo *alloc)
|
|
|
|
|
{
|
|
|
|
|
assert((mmap_count + 1) < MAX_MAPPINGS);
|
2021-07-10 11:16:56 -04:00
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < mmap_count; ++i) {
|
|
|
|
|
struct agx_bo *bo = &mmap_array[i];
|
|
|
|
|
bool match = (bo->handle == alloc->handle && bo->type == alloc->type);
|
|
|
|
|
assert(!match && "tried to alloc already allocated BO");
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
mmap_array[mmap_count++] = *alloc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
agxdecode_track_free(struct agx_bo *bo)
|
|
|
|
|
{
|
2021-07-10 11:16:56 -04:00
|
|
|
bool found = false;
|
|
|
|
|
|
2021-04-24 19:13:29 -04:00
|
|
|
for (unsigned i = 0; i < mmap_count; ++i) {
|
2022-12-27 17:36:08 -05:00
|
|
|
if (mmap_array[i].handle == bo->handle &&
|
|
|
|
|
mmap_array[i].type == bo->type) {
|
2021-07-10 11:16:56 -04:00
|
|
|
assert(!found && "mapped multiple times!");
|
|
|
|
|
found = true;
|
|
|
|
|
|
|
|
|
|
memset(&mmap_array[i], 0, sizeof(mmap_array[i]));
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
}
|
2021-07-10 11:16:56 -04:00
|
|
|
|
|
|
|
|
assert(found && "freed unmapped memory");
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int agxdecode_dump_frame_count = 0;
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
agxdecode_dump_file_open(void)
|
|
|
|
|
{
|
|
|
|
|
if (agxdecode_dump_stream)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* This does a getenv every frame, so it is possible to use
|
|
|
|
|
* setenv to change the base at runtime.
|
|
|
|
|
*/
|
2022-12-27 17:36:08 -05:00
|
|
|
const char *dump_file_base =
|
|
|
|
|
getenv("AGXDECODE_DUMP_FILE") ?: "agxdecode.dump";
|
2021-04-24 19:13:29 -04:00
|
|
|
if (!strcmp(dump_file_base, "stderr"))
|
|
|
|
|
agxdecode_dump_stream = stderr;
|
|
|
|
|
else {
|
|
|
|
|
char buffer[1024];
|
2022-12-27 17:36:08 -05:00
|
|
|
snprintf(buffer, sizeof(buffer), "%s.%04d", dump_file_base,
|
|
|
|
|
agxdecode_dump_frame_count);
|
2021-04-24 19:13:29 -04:00
|
|
|
printf("agxdecode: dump command stream to file %s\n", buffer);
|
|
|
|
|
agxdecode_dump_stream = fopen(buffer, "w");
|
2023-04-05 19:48:12 +09:00
|
|
|
if (!agxdecode_dump_stream) {
|
2021-04-24 19:13:29 -04:00
|
|
|
fprintf(stderr,
|
|
|
|
|
"agxdecode: failed to open command stream log file %s\n",
|
|
|
|
|
buffer);
|
2023-04-05 19:48:12 +09:00
|
|
|
}
|
2021-04-24 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
agxdecode_dump_file_close(void)
|
|
|
|
|
{
|
|
|
|
|
if (agxdecode_dump_stream && agxdecode_dump_stream != stderr) {
|
|
|
|
|
fclose(agxdecode_dump_stream);
|
|
|
|
|
agxdecode_dump_stream = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
agxdecode_next_frame(void)
|
|
|
|
|
{
|
|
|
|
|
agxdecode_dump_file_close();
|
|
|
|
|
agxdecode_dump_frame_count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
agxdecode_close(void)
|
|
|
|
|
{
|
|
|
|
|
agxdecode_dump_file_close();
|
|
|
|
|
}
|