freedreno/registers: install gzip'd register database
[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 enum debug_t debug = PRINT_RAW | PRINT_STATS;
143 int ret = -1;
144 int start = 0, end = 0x7ffffff, draw = -1;
145 int c;
146
147 interactive = isatty(STDOUT_FILENO);
148
149 options.color = interactive;
150
151 while ((c = getopt_long(argc, argv, "vsaS:E:F:D:L:q:h", opts, NULL)) != -1) {
152 switch (c) {
153 case 0:
154 /* option that set a flag, nothing to do */
155 break;
156 case 'v':
157 debug |= (PRINT_RAW | EXPAND_REPEAT | PRINT_VERBOSE);
158 break;
159 case 's':
160 options.summary = true;
161 break;
162 case 'a':
163 options.allregs = true;
164 break;
165 case 'S':
166 start = atoi(optarg);
167 break;
168 case 'E':
169 end = atoi(optarg);
170 break;
171 case 'F':
172 start = end = atoi(optarg);
173 break;
174 case 'D':
175 draw = atoi(optarg);
176 break;
177 case 'L':
178 options.script = optarg;
179 if (script_load(options.script)) {
180 errx(-1, "error loading %s\n", options.script);
181 }
182 break;
183 case 'q':
184 options.querystrs = realloc(options.querystrs,
185 (options.nquery + 1) * sizeof(*options.querystrs));
186 options.querystrs[options.nquery] = optarg;
187 options.nquery++;
188 interactive = 0;
189 break;
190 case 'h':
191 default:
192 print_usage(argv[0]);
193 }
194 }
195
196 disasm_a2xx_set_debug(debug);
197 disasm_a3xx_set_debug(debug);
198
199 if (interactive) {
200 pager_open();
201 }
202
203 while (optind < argc) {
204 ret = handle_file(argv[optind], start, end, draw);
205 if (ret) {
206 fprintf(stderr, "error reading: %s\n", argv[optind]);
207 fprintf(stderr, "continuing..\n");
208 }
209 optind++;
210 }
211
212 if (ret)
213 print_usage(argv[0]);
214
215 if ((options.query_mode || options.query_compare) && !options.nquery) {
216 fprintf(stderr, "query options only valid in query mode!\n");
217 print_usage(argv[0]);
218 }
219
220 script_finish();
221
222 if (interactive) {
223 pager_close();
224 }
225
226 return ret;
227 }
228
229 static void parse_addr(uint32_t *buf, int sz, unsigned int *len, uint64_t *gpuaddr)
230 {
231 *gpuaddr = buf[0];
232 *len = buf[1];
233 if (sz > 8)
234 *gpuaddr |= ((uint64_t)(buf[2])) << 32;
235 }
236
237 static int handle_file(const char *filename, int start, int end, int draw)
238 {
239 enum rd_sect_type type = RD_NONE;
240 void *buf = NULL;
241 struct io *io;
242 int submit = 0, got_gpu_id = 0;
243 int sz, ret = 0;
244 bool needs_reset = false;
245 bool skip = false;
246
247 options.draw_filter = draw;
248
249 cffdec_init(&options);
250
251 printf("Reading %s...\n", filename);
252
253 script_start_cmdstream(filename);
254
255 if (!strcmp(filename, "-"))
256 io = io_openfd(0);
257 else
258 io = io_open(filename);
259
260 if (!io) {
261 fprintf(stderr, "could not open: %s\n", filename);
262 return -1;
263 }
264
265 struct {
266 unsigned int len;
267 uint64_t gpuaddr;
268 } gpuaddr = {0};
269
270 while (true) {
271 uint32_t arr[2];
272
273 ret = io_readn(io, arr, 8);
274 if (ret <= 0)
275 goto end;
276
277 while ((arr[0] == 0xffffffff) && (arr[1] == 0xffffffff)) {
278 ret = io_readn(io, arr, 8);
279 if (ret <= 0)
280 goto end;
281 }
282
283 type = arr[0];
284 sz = arr[1];
285
286 if (sz < 0) {
287 ret = -1;
288 goto end;
289 }
290
291 free(buf);
292
293 needs_wfi = false;
294
295 buf = malloc(sz + 1);
296 ((char *)buf)[sz] = '\0';
297 ret = io_readn(io, buf, sz);
298 if (ret < 0)
299 goto end;
300
301 switch(type) {
302 case RD_TEST:
303 printl(1, "test: %s\n", (char *)buf);
304 break;
305 case RD_CMD:
306 is_blob = true;
307 printl(2, "cmd: %s\n", (char *)buf);
308 skip = false;
309 if (!show_comp) {
310 skip |= (strstr(buf, "fdperf") == buf);
311 skip |= (strstr(buf, "chrome") == buf);
312 skip |= (strstr(buf, "surfaceflinger") == buf);
313 skip |= ((char *)buf)[0] == 'X';
314 }
315 break;
316 case RD_VERT_SHADER:
317 printl(2, "vertex shader:\n%s\n", (char *)buf);
318 break;
319 case RD_FRAG_SHADER:
320 printl(2, "fragment shader:\n%s\n", (char *)buf);
321 break;
322 case RD_GPUADDR:
323 if (needs_reset) {
324 reset_buffers();
325 needs_reset = false;
326 }
327 parse_addr(buf, sz, &gpuaddr.len, &gpuaddr.gpuaddr);
328 break;
329 case RD_BUFFER_CONTENTS:
330 add_buffer(gpuaddr.gpuaddr, gpuaddr.len, buf);
331 buf = NULL;
332 break;
333 case RD_CMDSTREAM_ADDR:
334 if ((start <= submit) && (submit <= end)) {
335 unsigned int sizedwords;
336 uint64_t gpuaddr;
337 parse_addr(buf, sz, &sizedwords, &gpuaddr);
338 printl(2, "############################################################\n");
339 printl(2, "cmdstream: %d dwords\n", sizedwords);
340 if (!skip) {
341 script_start_submit();
342 dump_commands(hostptr(gpuaddr), sizedwords, 0);
343 script_end_submit();
344 }
345 printl(2, "############################################################\n");
346 printl(2, "vertices: %d\n", vertices);
347 }
348 needs_reset = true;
349 submit++;
350 break;
351 case RD_GPU_ID:
352 if (!got_gpu_id) {
353 options.gpu_id = *((unsigned int *)buf);
354 printl(2, "gpu_id: %d\n", options.gpu_id);
355 cffdec_init(&options);
356 got_gpu_id = 1;
357 }
358 break;
359 default:
360 break;
361 }
362 }
363
364 end:
365 script_end_cmdstream();
366
367 io_close(io);
368 fflush(stdout);
369
370 if (ret < 0) {
371 printf("corrupt file\n");
372 }
373 return 0;
374 }