freedreno: slurp in decode tools
[mesa.git] / src / freedreno / decode / cffdump.c
1 /*
2 * Copyright (c) 2012 Rob Clark <robdclark@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <err.h>
27 #include <getopt.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <stdarg.h>
32 #include <stdbool.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/wait.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <assert.h>
40 #include <signal.h>
41 #include <errno.h>
42
43 #include "redump.h"
44 #include "disasm.h"
45 #include "script.h"
46 #include "io.h"
47 #include "rnnutil.h"
48 #include "pager.h"
49 #include "buffers.h"
50 #include "cffdec.h"
51
52 static struct cffdec_options options = {
53 .gpu_id = 220,
54 };
55
56 static bool needs_wfi = false;
57 static bool is_blob = false;
58 static int show_comp = false;
59 static int interactive;
60 static int vertices;
61
62 static int handle_file(const char *filename, int start, int end, int draw);
63
64 static void print_usage(const char *name)
65 {
66 fprintf(stderr, "Usage:\n\n"
67 "\t%s [OPTSIONS]... FILE...\n\n"
68 "Options:\n"
69 "\t-v, --verbose - more verbose disassembly\n"
70 "\t--dump-shaders - dump each shader to a raw file\n"
71 "\t--no-color - disable colorized output (default for non-console\n"
72 "\t output)\n"
73 "\t--color - enable colorized output (default for tty output)\n"
74 "\t--no-pager - disable pager (default for non-console output)\n"
75 "\t--pager - enable pager (default for tty output)\n"
76 "\t-s, --summary - don't show individual register writes, but just\n"
77 "\t register values on draws\n"
78 "\t-a, --allregs - show all registers (including ones not written\n"
79 "\t since previous draw) on each draw\n"
80 "\t-S, --start=N - start decoding from frame N\n"
81 "\t-E, --end=N - stop decoding after frame N\n"
82 "\t-F, --frame=N - decode only frame N\n"
83 "\t-D, --draw=N - decode only draw N\n"
84 "\t--textures - dump texture contents (if possible)\n"
85 "\t-L, --script=LUA - run specified lua script to analyze state\n"
86 "\t-q, --query=REG - query mode, dump only specified query registers on\n"
87 "\t each draw; multiple --query/-q args can be given to\n"
88 "\t dump multiple registers; register can be specified\n"
89 "\t either by name or numeric offset\n"
90 "\t--query-all - in query mode, show all queried regs on each draw\n"
91 "\t (default query mode)\n"
92 "\t--query-written - in query mode, show queried regs on draws if any of\n"
93 "\t them have been written since previous draw\n"
94 "\t--query-delta - in query mode, show queried regs on draws if any of\n"
95 "\t them have changed since previous draw\n"
96 "\t--query-compare - dump registers for BINNING vs GMEM/BYPASS per draw;\n"
97 "\t only applicable for regs set via SDS group (a6xx+),\n"
98 "\t implies --once, can be combined with --query-all,\n"
99 "\t --query-written, or --query-delta\n"
100 "\t--once - decode cmdstream only once (per draw mode); if same\n"
101 "\t cmdstream is executed for each tile, this will decode\n"
102 "\t it only for the first tile and skip the remainder,\n"
103 "\t which can be useful when looking at state that does\n"
104 "\t not change per tile\n"
105 "\t--not-once - decode cmdstream for each IB (default)\n"
106 "\t-h, --help - show this message\n"
107 , name);
108 exit(2);
109 }
110
111 static const struct option opts[] = {
112 /* Long opts that simply set a flag (no corresponding short alias: */
113 { "dump-shaders", no_argument, &options.dump_shaders, 1 },
114 { "no-color", no_argument, &options.color, 0 },
115 { "color", no_argument, &options.color, 1 },
116 { "no-pager", no_argument, &interactive, 0 },
117 { "pager", no_argument, &interactive, 1 },
118 { "textures", no_argument, &options.dump_textures, 1 },
119 { "show-compositor", no_argument, &show_comp, 1 },
120 { "query-all", no_argument, &options.query_mode, QUERY_ALL },
121 { "query-written", no_argument, &options.query_mode, QUERY_WRITTEN },
122 { "query-delta", no_argument, &options.query_mode, QUERY_DELTA },
123 { "query-compare", no_argument, &options.query_compare, 1 },
124 { "once", no_argument, &options.once, 1 },
125 { "not-once", no_argument, &options.once, 0 },
126
127 /* Long opts with short alias: */
128 { "verbose", no_argument, 0, 'v' },
129 { "summary", no_argument, 0, 's' },
130 { "allregs", no_argument, 0, 'a' },
131 { "start", required_argument, 0, 'S' },
132 { "end", required_argument, 0, 'E' },
133 { "frame", required_argument, 0, 'F' },
134 { "draw", required_argument, 0, 'D' },
135 { "script", required_argument, 0, 'L' },
136 { "query", required_argument, 0, 'q' },
137 { "help", no_argument, 0, 'h' },
138 };
139
140 int main(int argc, char **argv)
141 {
142 int ret = -1;
143 int start = 0, end = 0x7ffffff, draw = -1;
144 int c;
145
146 interactive = isatty(STDOUT_FILENO);
147
148 options.color = interactive;
149
150 while ((c = getopt_long(argc, argv, "vsaS:E:F:D:L:q:h", opts, NULL)) != -1) {
151 switch (c) {
152 case 0:
153 /* option that set a flag, nothing to do */
154 break;
155 case 'v':
156 disasm_set_debug(PRINT_RAW | EXPAND_REPEAT | PRINT_VERBOSE);
157 break;
158 case 's':
159 options.summary = true;
160 break;
161 case 'a':
162 options.allregs = true;
163 break;
164 case 'S':
165 start = atoi(optarg);
166 break;
167 case 'E':
168 end = atoi(optarg);
169 break;
170 case 'F':
171 start = end = atoi(optarg);
172 break;
173 case 'D':
174 draw = atoi(optarg);
175 break;
176 case 'L':
177 options.script = optarg;
178 if (script_load(options.script)) {
179 errx(-1, "error loading %s\n", options.script);
180 }
181 break;
182 case 'q':
183 options.querystrs = realloc(options.querystrs,
184 (options.nquery + 1) * sizeof(*options.querystrs));
185 options.querystrs[options.nquery] = optarg;
186 options.nquery++;
187 interactive = 0;
188 break;
189 case 'h':
190 default:
191 print_usage(argv[0]);
192 }
193 }
194
195 if (interactive) {
196 pager_open();
197 }
198
199 while (optind < argc) {
200 ret = handle_file(argv[optind], start, end, draw);
201 if (ret) {
202 fprintf(stderr, "error reading: %s\n", argv[optind]);
203 fprintf(stderr, "continuing..\n");
204 }
205 optind++;
206 }
207
208 if (ret)
209 print_usage(argv[0]);
210
211 if ((options.query_mode || options.query_compare) && !options.nquery) {
212 fprintf(stderr, "query options only valid in query mode!\n");
213 print_usage(argv[0]);
214 }
215
216 script_finish();
217
218 if (interactive) {
219 pager_close();
220 }
221
222 return ret;
223 }
224
225 static void parse_addr(uint32_t *buf, int sz, unsigned int *len, uint64_t *gpuaddr)
226 {
227 *gpuaddr = buf[0];
228 *len = buf[1];
229 if (sz > 8)
230 *gpuaddr |= ((uint64_t)(buf[2])) << 32;
231 }
232
233 static int handle_file(const char *filename, int start, int end, int draw)
234 {
235 enum rd_sect_type type = RD_NONE;
236 void *buf = NULL;
237 struct io *io;
238 int submit = 0, got_gpu_id = 0;
239 int sz, ret = 0;
240 bool needs_reset = false;
241 bool skip = false;
242
243 options.draw_filter = draw;
244
245 cffdec_init(&options);
246
247 printf("Reading %s...\n", filename);
248
249 script_start_cmdstream(filename);
250
251 if (!strcmp(filename, "-"))
252 io = io_openfd(0);
253 else
254 io = io_open(filename);
255
256 if (!io) {
257 fprintf(stderr, "could not open: %s\n", filename);
258 return -1;
259 }
260
261 struct {
262 unsigned int len;
263 uint64_t gpuaddr;
264 } gpuaddr = {0};
265
266 while (true) {
267 uint32_t arr[2];
268
269 ret = io_readn(io, arr, 8);
270 if (ret <= 0)
271 goto end;
272
273 while ((arr[0] == 0xffffffff) && (arr[1] == 0xffffffff)) {
274 ret = io_readn(io, arr, 8);
275 if (ret <= 0)
276 goto end;
277 }
278
279 type = arr[0];
280 sz = arr[1];
281
282 if (sz < 0) {
283 ret = -1;
284 goto end;
285 }
286
287 free(buf);
288
289 needs_wfi = false;
290
291 buf = malloc(sz + 1);
292 ((char *)buf)[sz] = '\0';
293 ret = io_readn(io, buf, sz);
294 if (ret < 0)
295 goto end;
296
297 switch(type) {
298 case RD_TEST:
299 printl(1, "test: %s\n", (char *)buf);
300 break;
301 case RD_CMD:
302 is_blob = true;
303 printl(2, "cmd: %s\n", (char *)buf);
304 skip = false;
305 if (!show_comp) {
306 skip |= (strstr(buf, "fdperf") == buf);
307 skip |= (strstr(buf, "chrome") == buf);
308 skip |= (strstr(buf, "surfaceflinger") == buf);
309 skip |= ((char *)buf)[0] == 'X';
310 }
311 break;
312 case RD_VERT_SHADER:
313 printl(2, "vertex shader:\n%s\n", (char *)buf);
314 break;
315 case RD_FRAG_SHADER:
316 printl(2, "fragment shader:\n%s\n", (char *)buf);
317 break;
318 case RD_GPUADDR:
319 if (needs_reset) {
320 reset_buffers();
321 needs_reset = false;
322 }
323 parse_addr(buf, sz, &gpuaddr.len, &gpuaddr.gpuaddr);
324 break;
325 case RD_BUFFER_CONTENTS:
326 add_buffer(gpuaddr.gpuaddr, gpuaddr.len, buf);
327 buf = NULL;
328 break;
329 case RD_CMDSTREAM_ADDR:
330 if ((start <= submit) && (submit <= end)) {
331 unsigned int sizedwords;
332 uint64_t gpuaddr;
333 parse_addr(buf, sz, &sizedwords, &gpuaddr);
334 printl(2, "############################################################\n");
335 printl(2, "cmdstream: %d dwords\n", sizedwords);
336 if (!skip) {
337 script_start_submit();
338 dump_commands(hostptr(gpuaddr), sizedwords, 0);
339 script_end_submit();
340 }
341 printl(2, "############################################################\n");
342 printl(2, "vertices: %d\n", vertices);
343 }
344 needs_reset = true;
345 submit++;
346 break;
347 case RD_GPU_ID:
348 if (!got_gpu_id) {
349 options.gpu_id = *((unsigned int *)buf);
350 printl(2, "gpu_id: %d\n", options.gpu_id);
351 cffdec_init(&options);
352 got_gpu_id = 1;
353 }
354 break;
355 default:
356 break;
357 }
358 }
359
360 end:
361 script_end_cmdstream();
362
363 io_close(io);
364 fflush(stdout);
365
366 if (ret < 0) {
367 printf("corrupt file\n");
368 }
369 return 0;
370 }