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