1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2017-2019 Alyssa Rosenzweig 3bf215546Sopenharmony_ci * Copyright (C) 2017-2019 Connor Abbott 4bf215546Sopenharmony_ci * Copyright (C) 2019 Collabora, Ltd. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 9bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 11bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 12bf215546Sopenharmony_ci * 13bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 14bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 15bf215546Sopenharmony_ci * Software. 16bf215546Sopenharmony_ci * 17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23bf215546Sopenharmony_ci * SOFTWARE. 24bf215546Sopenharmony_ci */ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include <agx_pack.h> 27bf215546Sopenharmony_ci#include <stdio.h> 28bf215546Sopenharmony_ci#include <stdlib.h> 29bf215546Sopenharmony_ci#include <memory.h> 30bf215546Sopenharmony_ci#include <stdbool.h> 31bf215546Sopenharmony_ci#include <stdarg.h> 32bf215546Sopenharmony_ci#include <ctype.h> 33bf215546Sopenharmony_ci#include <sys/mman.h> 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include "decode.h" 36bf215546Sopenharmony_ci#include "io.h" 37bf215546Sopenharmony_ci#include "hexdump.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_cistatic const char *agx_alloc_types[AGX_NUM_ALLOC] = { "mem", "map", "cmd" }; 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_cistatic void 42bf215546Sopenharmony_ciagx_disassemble(void *_code, size_t maxlen, FILE *fp) 43bf215546Sopenharmony_ci{ 44bf215546Sopenharmony_ci /* stub */ 45bf215546Sopenharmony_ci} 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ciFILE *agxdecode_dump_stream; 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci#define MAX_MAPPINGS 4096 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_cistruct agx_bo mmap_array[MAX_MAPPINGS]; 52bf215546Sopenharmony_ciunsigned mmap_count = 0; 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistruct agx_bo *ro_mappings[MAX_MAPPINGS]; 55bf215546Sopenharmony_ciunsigned ro_mapping_count = 0; 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_cistatic struct agx_bo * 58bf215546Sopenharmony_ciagxdecode_find_mapped_gpu_mem_containing_rw(uint64_t addr) 59bf215546Sopenharmony_ci{ 60bf215546Sopenharmony_ci for (unsigned i = 0; i < mmap_count; ++i) { 61bf215546Sopenharmony_ci if (mmap_array[i].type == AGX_ALLOC_REGULAR && addr >= mmap_array[i].ptr.gpu && (addr - mmap_array[i].ptr.gpu) < mmap_array[i].size) 62bf215546Sopenharmony_ci return mmap_array + i; 63bf215546Sopenharmony_ci } 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci return NULL; 66bf215546Sopenharmony_ci} 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_cistatic struct agx_bo * 69bf215546Sopenharmony_ciagxdecode_find_mapped_gpu_mem_containing(uint64_t addr) 70bf215546Sopenharmony_ci{ 71bf215546Sopenharmony_ci struct agx_bo *mem = agxdecode_find_mapped_gpu_mem_containing_rw(addr); 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci if (mem && mem->ptr.cpu && !mem->ro) { 74bf215546Sopenharmony_ci mprotect(mem->ptr.cpu, mem->size, PROT_READ); 75bf215546Sopenharmony_ci mem->ro = true; 76bf215546Sopenharmony_ci ro_mappings[ro_mapping_count++] = mem; 77bf215546Sopenharmony_ci assert(ro_mapping_count < MAX_MAPPINGS); 78bf215546Sopenharmony_ci } 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci if (mem && !mem->mapped) { 81bf215546Sopenharmony_ci fprintf(stderr, "[ERROR] access to memory not mapped (GPU %" PRIx64 ", handle %u)\n", mem->ptr.gpu, mem->handle); 82bf215546Sopenharmony_ci } 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci return mem; 85bf215546Sopenharmony_ci} 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_cistatic struct agx_bo * 88bf215546Sopenharmony_ciagxdecode_find_handle(unsigned handle, unsigned type) 89bf215546Sopenharmony_ci{ 90bf215546Sopenharmony_ci for (unsigned i = 0; i < mmap_count; ++i) { 91bf215546Sopenharmony_ci if (mmap_array[i].type != type) 92bf215546Sopenharmony_ci continue; 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci if (mmap_array[i].handle != handle) 95bf215546Sopenharmony_ci continue; 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci return &mmap_array[i]; 98bf215546Sopenharmony_ci } 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci return NULL; 101bf215546Sopenharmony_ci} 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_cistatic void 104bf215546Sopenharmony_ciagxdecode_mark_mapped(unsigned handle) 105bf215546Sopenharmony_ci{ 106bf215546Sopenharmony_ci struct agx_bo *bo = agxdecode_find_handle(handle, AGX_ALLOC_REGULAR); 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci if (!bo) { 109bf215546Sopenharmony_ci fprintf(stderr, "ERROR - unknown BO mapped with handle %u\n", handle); 110bf215546Sopenharmony_ci return; 111bf215546Sopenharmony_ci } 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci /* Mark mapped for future consumption */ 114bf215546Sopenharmony_ci bo->mapped = true; 115bf215546Sopenharmony_ci} 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_cistatic void 118bf215546Sopenharmony_ciagxdecode_decode_segment_list(void *segment_list) 119bf215546Sopenharmony_ci{ 120bf215546Sopenharmony_ci unsigned nr_handles = 0; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci /* First, mark everything unmapped */ 123bf215546Sopenharmony_ci for (unsigned i = 0; i < mmap_count; ++i) 124bf215546Sopenharmony_ci mmap_array[i].mapped = false; 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci /* Check the header */ 127bf215546Sopenharmony_ci struct agx_map_header *hdr = segment_list; 128bf215546Sopenharmony_ci if (hdr->resource_group_count == 0) { 129bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "ERROR - empty map\n"); 130bf215546Sopenharmony_ci return; 131bf215546Sopenharmony_ci } 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci if (hdr->segment_count != 1) { 134bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "ERROR - can't handle segment count %u\n", 135bf215546Sopenharmony_ci hdr->segment_count); 136bf215546Sopenharmony_ci } 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "Segment list:\n"); 139bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, " Command buffer shmem ID: %" PRIx64 "\n", hdr->cmdbuf_id); 140bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, " Encoder ID: %" PRIx64 "\n", hdr->encoder_id); 141bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, " Kernel commands start offset: %u\n", 142bf215546Sopenharmony_ci hdr->kernel_commands_start_offset); 143bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, " Kernel commands end offset: %u\n", 144bf215546Sopenharmony_ci hdr->kernel_commands_end_offset); 145bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, " Unknown: 0x%X\n", hdr->unk); 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci /* Expected structure: header followed by resource groups */ 148bf215546Sopenharmony_ci size_t length = sizeof(struct agx_map_header); 149bf215546Sopenharmony_ci length += sizeof(struct agx_map_entry) * hdr->resource_group_count; 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci if (length != hdr->length) { 152bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "ERROR: expected length %zu, got %u\n", 153bf215546Sopenharmony_ci length, hdr->length); 154bf215546Sopenharmony_ci } 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci if (hdr->padding[0] || hdr->padding[1]) 157bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "ERROR - padding tripped\n"); 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci /* Check the entries */ 160bf215546Sopenharmony_ci struct agx_map_entry *groups = ((void *) hdr) + sizeof(*hdr); 161bf215546Sopenharmony_ci for (unsigned i = 0; i < hdr->resource_group_count; ++i) { 162bf215546Sopenharmony_ci struct agx_map_entry group = groups[i]; 163bf215546Sopenharmony_ci unsigned count = group.resource_count; 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci STATIC_ASSERT(ARRAY_SIZE(group.resource_id) == 6); 166bf215546Sopenharmony_ci STATIC_ASSERT(ARRAY_SIZE(group.resource_unk) == 6); 167bf215546Sopenharmony_ci STATIC_ASSERT(ARRAY_SIZE(group.resource_flags) == 6); 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci if ((count < 1) || (count > 6)) { 170bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "ERROR - invalid count %u\n", count); 171bf215546Sopenharmony_ci continue; 172bf215546Sopenharmony_ci } 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci for (unsigned j = 0; j < count; ++j) { 175bf215546Sopenharmony_ci unsigned handle = group.resource_id[j]; 176bf215546Sopenharmony_ci unsigned unk = group.resource_unk[j]; 177bf215546Sopenharmony_ci unsigned flags = group.resource_flags[j]; 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci if (!handle) { 180bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "ERROR - invalid handle %u\n", handle); 181bf215546Sopenharmony_ci continue; 182bf215546Sopenharmony_ci } 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci agxdecode_mark_mapped(handle); 185bf215546Sopenharmony_ci nr_handles++; 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "%u (0x%X, 0x%X)\n", handle, unk, flags); 188bf215546Sopenharmony_ci } 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci if (group.unka) 191bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "ERROR - unknown 0x%X\n", group.unka); 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci /* Visual separator for resource groups */ 194bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "\n"); 195bf215546Sopenharmony_ci } 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci /* Check the handle count */ 198bf215546Sopenharmony_ci if (nr_handles != hdr->total_resources) { 199bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "ERROR - wrong handle count, got %u, expected %u (%u entries)\n", 200bf215546Sopenharmony_ci nr_handles, hdr->total_resources, hdr->resource_group_count); 201bf215546Sopenharmony_ci } 202bf215546Sopenharmony_ci} 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_cistatic inline void * 205bf215546Sopenharmony_ci__agxdecode_fetch_gpu_mem(const struct agx_bo *mem, 206bf215546Sopenharmony_ci uint64_t gpu_va, size_t size, 207bf215546Sopenharmony_ci int line, const char *filename) 208bf215546Sopenharmony_ci{ 209bf215546Sopenharmony_ci if (!mem) 210bf215546Sopenharmony_ci mem = agxdecode_find_mapped_gpu_mem_containing(gpu_va); 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci if (!mem) { 213bf215546Sopenharmony_ci fprintf(stderr, "Access to unknown memory %" PRIx64 " in %s:%d\n", 214bf215546Sopenharmony_ci gpu_va, filename, line); 215bf215546Sopenharmony_ci fflush(agxdecode_dump_stream); 216bf215546Sopenharmony_ci assert(0); 217bf215546Sopenharmony_ci } 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci assert(mem); 220bf215546Sopenharmony_ci assert(size + (gpu_va - mem->ptr.gpu) <= mem->size); 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci return mem->ptr.cpu + gpu_va - mem->ptr.gpu; 223bf215546Sopenharmony_ci} 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci#define agxdecode_fetch_gpu_mem(gpu_va, size) \ 226bf215546Sopenharmony_ci __agxdecode_fetch_gpu_mem(NULL, gpu_va, size, __LINE__, __FILE__) 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_cistatic void 229bf215546Sopenharmony_ciagxdecode_map_read_write(void) 230bf215546Sopenharmony_ci{ 231bf215546Sopenharmony_ci for (unsigned i = 0; i < ro_mapping_count; ++i) { 232bf215546Sopenharmony_ci ro_mappings[i]->ro = false; 233bf215546Sopenharmony_ci mprotect(ro_mappings[i]->ptr.cpu, ro_mappings[i]->size, 234bf215546Sopenharmony_ci PROT_READ | PROT_WRITE); 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci ro_mapping_count = 0; 238bf215546Sopenharmony_ci} 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci/* Helpers for parsing the cmdstream */ 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci#define DUMP_UNPACKED(T, var, str) { \ 243bf215546Sopenharmony_ci agxdecode_log(str); \ 244bf215546Sopenharmony_ci agx_print(agxdecode_dump_stream, T, var, (agxdecode_indent + 1) * 2); \ 245bf215546Sopenharmony_ci} 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci#define DUMP_CL(T, cl, str) {\ 248bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, cl, T, temp); \ 249bf215546Sopenharmony_ci DUMP_UNPACKED(T, temp, str "\n"); \ 250bf215546Sopenharmony_ci} 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci#define agxdecode_log(str) fputs(str, agxdecode_dump_stream) 253bf215546Sopenharmony_ci#define agxdecode_msg(str) fprintf(agxdecode_dump_stream, "// %s", str) 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ciunsigned agxdecode_indent = 0; 256bf215546Sopenharmony_ciuint64_t pipeline_base = 0; 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_cistatic void 259bf215546Sopenharmony_ciagxdecode_dump_bo(struct agx_bo *bo, const char *name) 260bf215546Sopenharmony_ci{ 261bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "%s %s (%u)\n", name, bo->name ?: "", bo->handle); 262bf215546Sopenharmony_ci hexdump(agxdecode_dump_stream, bo->ptr.cpu, bo->size, false); 263bf215546Sopenharmony_ci} 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci/* Abstraction for command stream parsing */ 266bf215546Sopenharmony_citypedef unsigned (*decode_cmd)(const uint8_t *map, bool verbose); 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci#define STATE_DONE (0xFFFFFFFFu) 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_cistatic void 271bf215546Sopenharmony_ciagxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder, bool verbose) 272bf215546Sopenharmony_ci{ 273bf215546Sopenharmony_ci struct agx_bo *alloc = agxdecode_find_mapped_gpu_mem_containing(va); 274bf215546Sopenharmony_ci assert(alloc != NULL && "nonexistant object"); 275bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "%s (%" PRIx64 ", handle %u)\n", label, va, alloc->handle); 276bf215546Sopenharmony_ci fflush(agxdecode_dump_stream); 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci uint8_t *map = agxdecode_fetch_gpu_mem(va, 64); 279bf215546Sopenharmony_ci uint8_t *end = (uint8_t *) alloc->ptr.cpu + alloc->size; 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci if (verbose) 282bf215546Sopenharmony_ci agxdecode_dump_bo(alloc, label); 283bf215546Sopenharmony_ci fflush(agxdecode_dump_stream); 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci while (map < end) { 286bf215546Sopenharmony_ci unsigned count = decoder(map, verbose); 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci /* If we fail to decode, default to a hexdump (don't hang) */ 289bf215546Sopenharmony_ci if (count == 0) { 290bf215546Sopenharmony_ci hexdump(agxdecode_dump_stream, map, 8, false); 291bf215546Sopenharmony_ci count = 8; 292bf215546Sopenharmony_ci } 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci map += count; 295bf215546Sopenharmony_ci fflush(agxdecode_dump_stream); 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci if (count == STATE_DONE) 298bf215546Sopenharmony_ci break; 299bf215546Sopenharmony_ci } 300bf215546Sopenharmony_ci} 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ciunsigned COUNTER = 0; 303bf215546Sopenharmony_cistatic unsigned 304bf215546Sopenharmony_ciagxdecode_pipeline(const uint8_t *map, UNUSED bool verbose) 305bf215546Sopenharmony_ci{ 306bf215546Sopenharmony_ci uint8_t zeroes[16] = { 0 }; 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci if (map[0] == 0x4D && map[1] == 0xbd) { 309bf215546Sopenharmony_ci /* TODO: Disambiguation for extended is a guess */ 310bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, map, SET_SHADER_EXTENDED, cmd); 311bf215546Sopenharmony_ci DUMP_UNPACKED(SET_SHADER_EXTENDED, cmd, "Set shader\n"); 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci if (cmd.preshader_mode == AGX_PRESHADER_MODE_PRESHADER) { 314bf215546Sopenharmony_ci agxdecode_log("Preshader\n"); 315bf215546Sopenharmony_ci agx_disassemble(agxdecode_fetch_gpu_mem(cmd.preshader_code, 2048), 316bf215546Sopenharmony_ci 2048, agxdecode_dump_stream); 317bf215546Sopenharmony_ci agxdecode_log("\n---\n"); 318bf215546Sopenharmony_ci } 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci agxdecode_log("\n"); 321bf215546Sopenharmony_ci agx_disassemble(agxdecode_fetch_gpu_mem(cmd.code, 2048), 322bf215546Sopenharmony_ci 2048, agxdecode_dump_stream); 323bf215546Sopenharmony_ci agxdecode_log("\n"); 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_ci char *name; 326bf215546Sopenharmony_ci asprintf(&name, "file%u.bin", COUNTER++); 327bf215546Sopenharmony_ci FILE *fp = fopen(name, "wb"); 328bf215546Sopenharmony_ci fwrite(agxdecode_fetch_gpu_mem(cmd.code, 2048), 1, 2048, fp); 329bf215546Sopenharmony_ci fclose(fp); 330bf215546Sopenharmony_ci free(name); 331bf215546Sopenharmony_ci agxdecode_log("\n"); 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci return AGX_SET_SHADER_EXTENDED_LENGTH; 334bf215546Sopenharmony_ci } else if (map[0] == 0x4D) { 335bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, map, SET_SHADER, cmd); 336bf215546Sopenharmony_ci DUMP_UNPACKED(SET_SHADER, cmd, "Set shader\n"); 337bf215546Sopenharmony_ci fflush(agxdecode_dump_stream); 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci if (cmd.preshader_mode == AGX_PRESHADER_MODE_PRESHADER) { 340bf215546Sopenharmony_ci agxdecode_log("Preshader\n"); 341bf215546Sopenharmony_ci agx_disassemble(agxdecode_fetch_gpu_mem(cmd.preshader_code, 2048), 342bf215546Sopenharmony_ci 2048, agxdecode_dump_stream); 343bf215546Sopenharmony_ci agxdecode_log("\n---\n"); 344bf215546Sopenharmony_ci } 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci agxdecode_log("\n"); 347bf215546Sopenharmony_ci agx_disassemble(agxdecode_fetch_gpu_mem(cmd.code, 2048), 348bf215546Sopenharmony_ci 2048, agxdecode_dump_stream); 349bf215546Sopenharmony_ci char *name; 350bf215546Sopenharmony_ci asprintf(&name, "file%u.bin", COUNTER++); 351bf215546Sopenharmony_ci FILE *fp = fopen(name, "wb"); 352bf215546Sopenharmony_ci fwrite(agxdecode_fetch_gpu_mem(cmd.code, 2048), 1, 2048, fp); 353bf215546Sopenharmony_ci fclose(fp); 354bf215546Sopenharmony_ci free(name); 355bf215546Sopenharmony_ci agxdecode_log("\n"); 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci return AGX_SET_SHADER_LENGTH; 358bf215546Sopenharmony_ci } else if (map[0] == 0xDD) { 359bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, map, BIND_TEXTURE, temp); 360bf215546Sopenharmony_ci DUMP_UNPACKED(BIND_TEXTURE, temp, "Bind texture\n"); 361bf215546Sopenharmony_ci 362bf215546Sopenharmony_ci uint8_t *tex = agxdecode_fetch_gpu_mem(temp.buffer, 64); 363bf215546Sopenharmony_ci /* Texture length seen to be <= 0x18 bytes, samplers only need 8 byte 364bf215546Sopenharmony_ci * alignment */ 365bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, tex, TEXTURE, t); 366bf215546Sopenharmony_ci DUMP_CL(TEXTURE, tex, "Texture"); 367bf215546Sopenharmony_ci DUMP_CL(RENDER_TARGET, tex, "Render target"); 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ci return AGX_BIND_TEXTURE_LENGTH; 370bf215546Sopenharmony_ci } else if (map[0] == 0x9D) { 371bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, map, BIND_SAMPLER, temp); 372bf215546Sopenharmony_ci DUMP_UNPACKED(BIND_SAMPLER, temp, "Bind sampler\n"); 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_ci uint8_t *samp = agxdecode_fetch_gpu_mem(temp.buffer, 64); 375bf215546Sopenharmony_ci DUMP_CL(SAMPLER, samp, "Sampler"); 376bf215546Sopenharmony_ci hexdump(agxdecode_dump_stream, samp + AGX_SAMPLER_LENGTH, 64 - AGX_SAMPLER_LENGTH, false); 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci return AGX_BIND_SAMPLER_LENGTH; 379bf215546Sopenharmony_ci } else if (map[0] == 0x1D) { 380bf215546Sopenharmony_ci DUMP_CL(BIND_UNIFORM, map, "Bind uniform"); 381bf215546Sopenharmony_ci return AGX_BIND_UNIFORM_LENGTH; 382bf215546Sopenharmony_ci } else if (memcmp(map, zeroes, 16) == 0) { 383bf215546Sopenharmony_ci /* TODO: Termination */ 384bf215546Sopenharmony_ci return STATE_DONE; 385bf215546Sopenharmony_ci } else { 386bf215546Sopenharmony_ci return 0; 387bf215546Sopenharmony_ci } 388bf215546Sopenharmony_ci} 389bf215546Sopenharmony_ci 390bf215546Sopenharmony_cistatic void 391bf215546Sopenharmony_ciagxdecode_record(uint64_t va, size_t size, bool verbose) 392bf215546Sopenharmony_ci{ 393bf215546Sopenharmony_ci uint8_t *map = agxdecode_fetch_gpu_mem(va, size); 394bf215546Sopenharmony_ci uint32_t tag = 0; 395bf215546Sopenharmony_ci memcpy(&tag, map, 4); 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_ci if (tag == 0x00000C00) { 398bf215546Sopenharmony_ci assert(size == AGX_VIEWPORT_LENGTH); 399bf215546Sopenharmony_ci DUMP_CL(VIEWPORT, map, "Viewport"); 400bf215546Sopenharmony_ci } else if (tag == 0x0C020000) { 401bf215546Sopenharmony_ci assert(size == AGX_LINKAGE_LENGTH); 402bf215546Sopenharmony_ci DUMP_CL(LINKAGE, map, "Linkage"); 403bf215546Sopenharmony_ci } else if (tag == 0x200004a) { 404bf215546Sopenharmony_ci assert(size == AGX_UNKNOWN_4A_LENGTH); 405bf215546Sopenharmony_ci DUMP_CL(UNKNOWN_4A, map, "Unknown 4a"); 406bf215546Sopenharmony_ci } else if (tag == 0x10000b5) { 407bf215546Sopenharmony_ci assert(size == AGX_RASTERIZER_LENGTH); 408bf215546Sopenharmony_ci DUMP_CL(RASTERIZER, map, "Rasterizer"); 409bf215546Sopenharmony_ci } else if (tag == 0x200000) { 410bf215546Sopenharmony_ci assert(size == AGX_CULL_LENGTH); 411bf215546Sopenharmony_ci DUMP_CL(CULL, map, "Cull"); 412bf215546Sopenharmony_ci } else if (tag == 0x000100) { 413bf215546Sopenharmony_ci assert(size == AGX_SET_INDEX_LENGTH); 414bf215546Sopenharmony_ci DUMP_CL(SET_INDEX, map, "Set index"); 415bf215546Sopenharmony_ci } else if (tag == 0x800000) { 416bf215546Sopenharmony_ci assert(size == (AGX_BIND_PIPELINE_LENGTH - 4)); 417bf215546Sopenharmony_ci 418bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, map, BIND_PIPELINE, cmd); 419bf215546Sopenharmony_ci agxdecode_stateful(cmd.pipeline, "Pipeline", agxdecode_pipeline, verbose); 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci /* TODO: parse */ 422bf215546Sopenharmony_ci if (cmd.fs_varyings) { 423bf215546Sopenharmony_ci uint8_t *map = agxdecode_fetch_gpu_mem(cmd.fs_varyings, 128); 424bf215546Sopenharmony_ci hexdump(agxdecode_dump_stream, map, 128, false); 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci DUMP_CL(VARYING_HEADER, map, "Varying header:"); 427bf215546Sopenharmony_ci map += AGX_VARYING_HEADER_LENGTH; 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci for (unsigned i = 0; i < cmd.input_count; ++i) { 430bf215546Sopenharmony_ci DUMP_CL(VARYING, map, "Varying:"); 431bf215546Sopenharmony_ci map += AGX_VARYING_LENGTH; 432bf215546Sopenharmony_ci } 433bf215546Sopenharmony_ci } 434bf215546Sopenharmony_ci 435bf215546Sopenharmony_ci DUMP_UNPACKED(BIND_PIPELINE, cmd, "Bind fragment pipeline\n"); 436bf215546Sopenharmony_ci } else if (size == 0) { 437bf215546Sopenharmony_ci pipeline_base = va; 438bf215546Sopenharmony_ci } else { 439bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "Record %" PRIx64 "\n", va); 440bf215546Sopenharmony_ci hexdump(agxdecode_dump_stream, map, size, false); 441bf215546Sopenharmony_ci } 442bf215546Sopenharmony_ci} 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_cistatic unsigned 445bf215546Sopenharmony_ciagxdecode_cmd(const uint8_t *map, bool verbose) 446bf215546Sopenharmony_ci{ 447bf215546Sopenharmony_ci if (map[0] == 0x02 && map[1] == 0x10 && map[2] == 0x00 && map[3] == 0x00) { 448bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, map, LAUNCH, cmd); 449bf215546Sopenharmony_ci agxdecode_stateful(cmd.pipeline, "Pipeline", agxdecode_pipeline, verbose); 450bf215546Sopenharmony_ci DUMP_UNPACKED(LAUNCH, cmd, "Launch\n"); 451bf215546Sopenharmony_ci return AGX_LAUNCH_LENGTH; 452bf215546Sopenharmony_ci } else if (map[0] == 0x2E && map[1] == 0x00 && map[2] == 0x00 && map[3] == 0x40) { 453bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, map, BIND_PIPELINE, cmd); 454bf215546Sopenharmony_ci agxdecode_stateful(cmd.pipeline, "Pipeline", agxdecode_pipeline, verbose); 455bf215546Sopenharmony_ci DUMP_UNPACKED(BIND_PIPELINE, cmd, "Bind vertex pipeline\n"); 456bf215546Sopenharmony_ci return AGX_BIND_PIPELINE_LENGTH; 457bf215546Sopenharmony_ci } else if (map[3] == 0x61) { 458bf215546Sopenharmony_ci DUMP_CL(DRAW, map, "Draw"); 459bf215546Sopenharmony_ci return AGX_DRAW_LENGTH; 460bf215546Sopenharmony_ci } else if (map[2] == 0x00 && map[3] == 0x00) { 461bf215546Sopenharmony_ci /* No need to explicitly dump the record */ 462bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, map, RECORD, cmd); 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci uint64_t address = (((uint64_t) cmd.pointer_hi) << 32) | cmd.pointer_lo; 465bf215546Sopenharmony_ci struct agx_bo *mem = agxdecode_find_mapped_gpu_mem_containing(address); 466bf215546Sopenharmony_ci 467bf215546Sopenharmony_ci if (mem) 468bf215546Sopenharmony_ci agxdecode_record(address, cmd.size_words * 4, verbose); 469bf215546Sopenharmony_ci else 470bf215546Sopenharmony_ci DUMP_UNPACKED(RECORD, cmd, "Non-existant record (XXX)\n"); 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_ci return AGX_RECORD_LENGTH; 473bf215546Sopenharmony_ci } else if (map[1] == 0 && map[2] == 0 && map[3] == 0xC0 && map[4] == 0x00) { 474bf215546Sopenharmony_ci ASSERTED unsigned zero[4] = { 0 }; 475bf215546Sopenharmony_ci assert(memcmp(map + 4, zero, sizeof(zero)) == 0); 476bf215546Sopenharmony_ci return STATE_DONE; 477bf215546Sopenharmony_ci } else { 478bf215546Sopenharmony_ci return 0; 479bf215546Sopenharmony_ci } 480bf215546Sopenharmony_ci} 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_civoid 483bf215546Sopenharmony_ciagxdecode_cmdstream(unsigned cmdbuf_handle, unsigned map_handle, bool verbose) 484bf215546Sopenharmony_ci{ 485bf215546Sopenharmony_ci agxdecode_dump_file_open(); 486bf215546Sopenharmony_ci 487bf215546Sopenharmony_ci struct agx_bo *cmdbuf = agxdecode_find_handle(cmdbuf_handle, AGX_ALLOC_CMDBUF); 488bf215546Sopenharmony_ci struct agx_bo *map = agxdecode_find_handle(map_handle, AGX_ALLOC_MEMMAP); 489bf215546Sopenharmony_ci assert(cmdbuf != NULL && "nonexistant command buffer"); 490bf215546Sopenharmony_ci assert(map != NULL && "nonexistant mapping"); 491bf215546Sopenharmony_ci 492bf215546Sopenharmony_ci /* Before decoding anything, validate the map. Set bo->mapped fields */ 493bf215546Sopenharmony_ci agxdecode_decode_segment_list(map->ptr.cpu); 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci /* Print the IOGPU stuff */ 496bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, cmdbuf->ptr.cpu, IOGPU_HEADER, cmd); 497bf215546Sopenharmony_ci DUMP_UNPACKED(IOGPU_HEADER, cmd, "IOGPU Header\n"); 498bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, ((uint32_t *) cmdbuf->ptr.cpu) + 160, 499bf215546Sopenharmony_ci IOGPU_INTERNAL_PIPELINES, pip); 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci DUMP_CL(IOGPU_INTERNAL_PIPELINES, ((uint32_t *) cmdbuf->ptr.cpu) + 160, "Internal pipelines"); 502bf215546Sopenharmony_ci DUMP_CL(IOGPU_AUX_FRAMEBUFFER, ((uint32_t *) cmdbuf->ptr.cpu) + 228, "Aux Framebuffer"); 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci agx_unpack(agxdecode_dump_stream, ((uint32_t *) cmdbuf->ptr.cpu) + 292, 505bf215546Sopenharmony_ci IOGPU_CLEAR_Z_S, clearzs); 506bf215546Sopenharmony_ci DUMP_UNPACKED(IOGPU_CLEAR_Z_S, clearzs, "Clear Z/S"); 507bf215546Sopenharmony_ci 508bf215546Sopenharmony_ci /* Guard against changes */ 509bf215546Sopenharmony_ci uint32_t zeroes[356 - 344] = { 0 }; 510bf215546Sopenharmony_ci assert(memcmp(((uint32_t *) cmdbuf->ptr.cpu) + 344, zeroes, 4 * (356 - 344)) == 0); 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci DUMP_CL(IOGPU_MISC, ((uint32_t *) cmdbuf->ptr.cpu) + 356, "Misc"); 513bf215546Sopenharmony_ci 514bf215546Sopenharmony_ci /* Should be unused, we think */ 515bf215546Sopenharmony_ci for (unsigned i = (0x6B0 / 4); i < (cmd.attachment_offset / 4); ++i) { 516bf215546Sopenharmony_ci assert(((uint32_t *) cmdbuf->ptr.cpu)[i] == 0); 517bf215546Sopenharmony_ci } 518bf215546Sopenharmony_ci 519bf215546Sopenharmony_ci DUMP_CL(IOGPU_ATTACHMENT_COUNT, ((uint8_t *) cmdbuf->ptr.cpu + 520bf215546Sopenharmony_ci cmd.attachment_offset), "Attachment count"); 521bf215546Sopenharmony_ci 522bf215546Sopenharmony_ci uint32_t *attachments = (uint32_t *) ((uint8_t *) cmdbuf->ptr.cpu + cmd.attachment_offset); 523bf215546Sopenharmony_ci unsigned attachment_count = attachments[3]; 524bf215546Sopenharmony_ci for (unsigned i = 0; i < attachment_count; ++i) { 525bf215546Sopenharmony_ci uint32_t *ptr = attachments + 4 + (i * AGX_IOGPU_ATTACHMENT_LENGTH / 4); 526bf215546Sopenharmony_ci DUMP_CL(IOGPU_ATTACHMENT, ptr, "Attachment"); 527bf215546Sopenharmony_ci } 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci uint64_t *encoder = ((uint64_t *) cmdbuf->ptr.cpu) + 7; 530bf215546Sopenharmony_ci agxdecode_stateful(*encoder, "Encoder", agxdecode_cmd, verbose); 531bf215546Sopenharmony_ci 532bf215546Sopenharmony_ci if (pip.clear_pipeline_unk) { 533bf215546Sopenharmony_ci assert(pip.clear_pipeline_unk == 0x4); 534bf215546Sopenharmony_ci agxdecode_stateful(pip.clear_pipeline, "Clear pipeline", 535bf215546Sopenharmony_ci agxdecode_pipeline, verbose); 536bf215546Sopenharmony_ci } 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci if (pip.store_pipeline_unk) { 539bf215546Sopenharmony_ci assert(pip.store_pipeline_unk == 0x4); 540bf215546Sopenharmony_ci agxdecode_stateful(pip.store_pipeline, "Store pipeline", 541bf215546Sopenharmony_ci agxdecode_pipeline, verbose); 542bf215546Sopenharmony_ci } 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci assert((clearzs.partial_reload_pipeline_unk & 0xF) == 0x4); 545bf215546Sopenharmony_ci if (clearzs.partial_reload_pipeline) { 546bf215546Sopenharmony_ci agxdecode_stateful(clearzs.partial_reload_pipeline, 547bf215546Sopenharmony_ci "Partial reload pipeline", agxdecode_pipeline, verbose); 548bf215546Sopenharmony_ci } 549bf215546Sopenharmony_ci 550bf215546Sopenharmony_ci if (clearzs.partial_store_pipeline) { 551bf215546Sopenharmony_ci agxdecode_stateful(clearzs.partial_store_pipeline, 552bf215546Sopenharmony_ci "Partial store pipeline", agxdecode_pipeline, verbose); 553bf215546Sopenharmony_ci } 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_ci agxdecode_map_read_write(); 556bf215546Sopenharmony_ci} 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_civoid 559bf215546Sopenharmony_ciagxdecode_dump_mappings(unsigned map_handle) 560bf215546Sopenharmony_ci{ 561bf215546Sopenharmony_ci agxdecode_dump_file_open(); 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_ci struct agx_bo *map = agxdecode_find_handle(map_handle, AGX_ALLOC_MEMMAP); 564bf215546Sopenharmony_ci assert(map != NULL && "nonexistant mapping"); 565bf215546Sopenharmony_ci agxdecode_decode_segment_list(map->ptr.cpu); 566bf215546Sopenharmony_ci 567bf215546Sopenharmony_ci for (unsigned i = 0; i < mmap_count; ++i) { 568bf215546Sopenharmony_ci if (!mmap_array[i].ptr.cpu || !mmap_array[i].size || !mmap_array[i].mapped) 569bf215546Sopenharmony_ci continue; 570bf215546Sopenharmony_ci 571bf215546Sopenharmony_ci assert(mmap_array[i].type < AGX_NUM_ALLOC); 572bf215546Sopenharmony_ci 573bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "Buffer: type %s, gpu %" PRIx64 ", handle %u.bin:\n\n", 574bf215546Sopenharmony_ci agx_alloc_types[mmap_array[i].type], 575bf215546Sopenharmony_ci mmap_array[i].ptr.gpu, mmap_array[i].handle); 576bf215546Sopenharmony_ci 577bf215546Sopenharmony_ci hexdump(agxdecode_dump_stream, mmap_array[i].ptr.cpu, mmap_array[i].size, false); 578bf215546Sopenharmony_ci fprintf(agxdecode_dump_stream, "\n"); 579bf215546Sopenharmony_ci } 580bf215546Sopenharmony_ci} 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_civoid 583bf215546Sopenharmony_ciagxdecode_track_alloc(struct agx_bo *alloc) 584bf215546Sopenharmony_ci{ 585bf215546Sopenharmony_ci assert((mmap_count + 1) < MAX_MAPPINGS); 586bf215546Sopenharmony_ci 587bf215546Sopenharmony_ci for (unsigned i = 0; i < mmap_count; ++i) { 588bf215546Sopenharmony_ci struct agx_bo *bo = &mmap_array[i]; 589bf215546Sopenharmony_ci bool match = (bo->handle == alloc->handle && bo->type == alloc->type); 590bf215546Sopenharmony_ci assert(!match && "tried to alloc already allocated BO"); 591bf215546Sopenharmony_ci } 592bf215546Sopenharmony_ci 593bf215546Sopenharmony_ci mmap_array[mmap_count++] = *alloc; 594bf215546Sopenharmony_ci} 595bf215546Sopenharmony_ci 596bf215546Sopenharmony_civoid 597bf215546Sopenharmony_ciagxdecode_track_free(struct agx_bo *bo) 598bf215546Sopenharmony_ci{ 599bf215546Sopenharmony_ci bool found = false; 600bf215546Sopenharmony_ci 601bf215546Sopenharmony_ci for (unsigned i = 0; i < mmap_count; ++i) { 602bf215546Sopenharmony_ci if (mmap_array[i].handle == bo->handle && mmap_array[i].type == bo->type) { 603bf215546Sopenharmony_ci assert(!found && "mapped multiple times!"); 604bf215546Sopenharmony_ci found = true; 605bf215546Sopenharmony_ci 606bf215546Sopenharmony_ci memset(&mmap_array[i], 0, sizeof(mmap_array[i])); 607bf215546Sopenharmony_ci } 608bf215546Sopenharmony_ci } 609bf215546Sopenharmony_ci 610bf215546Sopenharmony_ci assert(found && "freed unmapped memory"); 611bf215546Sopenharmony_ci} 612bf215546Sopenharmony_ci 613bf215546Sopenharmony_cistatic int agxdecode_dump_frame_count = 0; 614bf215546Sopenharmony_ci 615bf215546Sopenharmony_civoid 616bf215546Sopenharmony_ciagxdecode_dump_file_open(void) 617bf215546Sopenharmony_ci{ 618bf215546Sopenharmony_ci if (agxdecode_dump_stream) 619bf215546Sopenharmony_ci return; 620bf215546Sopenharmony_ci 621bf215546Sopenharmony_ci /* This does a getenv every frame, so it is possible to use 622bf215546Sopenharmony_ci * setenv to change the base at runtime. 623bf215546Sopenharmony_ci */ 624bf215546Sopenharmony_ci const char *dump_file_base = getenv("AGXDECODE_DUMP_FILE") ?: "agxdecode.dump"; 625bf215546Sopenharmony_ci if (!strcmp(dump_file_base, "stderr")) 626bf215546Sopenharmony_ci agxdecode_dump_stream = stderr; 627bf215546Sopenharmony_ci else { 628bf215546Sopenharmony_ci char buffer[1024]; 629bf215546Sopenharmony_ci snprintf(buffer, sizeof(buffer), "%s.%04d", dump_file_base, agxdecode_dump_frame_count); 630bf215546Sopenharmony_ci printf("agxdecode: dump command stream to file %s\n", buffer); 631bf215546Sopenharmony_ci agxdecode_dump_stream = fopen(buffer, "w"); 632bf215546Sopenharmony_ci if (!agxdecode_dump_stream) 633bf215546Sopenharmony_ci fprintf(stderr, 634bf215546Sopenharmony_ci "agxdecode: failed to open command stream log file %s\n", 635bf215546Sopenharmony_ci buffer); 636bf215546Sopenharmony_ci } 637bf215546Sopenharmony_ci} 638bf215546Sopenharmony_ci 639bf215546Sopenharmony_cistatic void 640bf215546Sopenharmony_ciagxdecode_dump_file_close(void) 641bf215546Sopenharmony_ci{ 642bf215546Sopenharmony_ci if (agxdecode_dump_stream && agxdecode_dump_stream != stderr) { 643bf215546Sopenharmony_ci fclose(agxdecode_dump_stream); 644bf215546Sopenharmony_ci agxdecode_dump_stream = NULL; 645bf215546Sopenharmony_ci } 646bf215546Sopenharmony_ci} 647bf215546Sopenharmony_ci 648bf215546Sopenharmony_civoid 649bf215546Sopenharmony_ciagxdecode_next_frame(void) 650bf215546Sopenharmony_ci{ 651bf215546Sopenharmony_ci agxdecode_dump_file_close(); 652bf215546Sopenharmony_ci agxdecode_dump_frame_count++; 653bf215546Sopenharmony_ci} 654bf215546Sopenharmony_ci 655bf215546Sopenharmony_civoid 656bf215546Sopenharmony_ciagxdecode_close(void) 657bf215546Sopenharmony_ci{ 658bf215546Sopenharmony_ci agxdecode_dump_file_close(); 659bf215546Sopenharmony_ci} 660