Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/freedreno/decode/cffdump.c
4565 views
1
/*
2
* Copyright (c) 2012 Rob Clark <[email protected]>
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 <errno.h>
28
#include <fcntl.h>
29
#include <getopt.h>
30
#include <signal.h>
31
#include <stdarg.h>
32
#include <stdbool.h>
33
#include <stdint.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <unistd.h>
38
#include <sys/stat.h>
39
#include <sys/types.h>
40
#include <sys/wait.h>
41
42
#include "buffers.h"
43
#include "cffdec.h"
44
#include "disasm.h"
45
#include "io.h"
46
#include "pager.h"
47
#include "redump.h"
48
#include "rnnutil.h"
49
#include "script.h"
50
51
static struct cffdec_options options = {
52
.gpu_id = 220,
53
};
54
55
static bool needs_wfi = false;
56
static bool is_blob = false;
57
static int show_comp = false;
58
static int interactive;
59
static int vertices;
60
static const char *exename;
61
62
static int handle_file(const char *filename, int start, int end, int draw);
63
64
static void
65
print_usage(const char *name)
66
{
67
/* clang-format off */
68
fprintf(stderr, "Usage:\n\n"
69
"\t%s [OPTSIONS]... FILE...\n\n"
70
"Options:\n"
71
"\t-v, --verbose - more verbose disassembly\n"
72
"\t--dump-shaders - dump each shader to a raw file\n"
73
"\t--no-color - disable colorized output (default for non-console\n"
74
"\t output)\n"
75
"\t--color - enable colorized output (default for tty output)\n"
76
"\t--no-pager - disable pager (default for non-console output)\n"
77
"\t--pager - enable pager (default for tty output)\n"
78
"\t-s, --summary - don't show individual register writes, but just\n"
79
"\t register values on draws\n"
80
"\t-a, --allregs - show all registers (including ones not written\n"
81
"\t since previous draw) on each draw\n"
82
"\t-S, --start=N - start decoding from frame N\n"
83
"\t-E, --end=N - stop decoding after frame N\n"
84
"\t-F, --frame=N - decode only frame N\n"
85
"\t-D, --draw=N - decode only draw N\n"
86
"\t-e, --exe=NAME - only decode cmdstream from named process\n"
87
"\t--textures - dump texture contents (if possible)\n"
88
"\t-L, --script=LUA - run specified lua script to analyze state\n"
89
"\t-q, --query=REG - query mode, dump only specified query registers on\n"
90
"\t each draw; multiple --query/-q args can be given to\n"
91
"\t dump multiple registers; register can be specified\n"
92
"\t either by name or numeric offset\n"
93
"\t--query-all - in query mode, show all queried regs on each draw\n"
94
"\t (default query mode)\n"
95
"\t--query-written - in query mode, show queried regs on draws if any of\n"
96
"\t them have been written since previous draw\n"
97
"\t--query-delta - in query mode, show queried regs on draws if any of\n"
98
"\t them have changed since previous draw\n"
99
"\t--query-compare - dump registers for BINNING vs GMEM/BYPASS per draw;\n"
100
"\t only applicable for regs set via SDS group (a6xx+),\n"
101
"\t implies --once, can be combined with --query-all,\n"
102
"\t --query-written, or --query-delta\n"
103
"\t--once - decode cmdstream only once (per draw mode); if same\n"
104
"\t cmdstream is executed for each tile, this will decode\n"
105
"\t it only for the first tile and skip the remainder,\n"
106
"\t which can be useful when looking at state that does\n"
107
"\t not change per tile\n"
108
"\t--not-once - decode cmdstream for each IB (default)\n"
109
"\t-h, --help - show this message\n"
110
, name);
111
/* clang-format on */
112
exit(2);
113
}
114
115
/* clang-format off */
116
static const struct option opts[] = {
117
/* Long opts that simply set a flag (no corresponding short alias: */
118
{ "dump-shaders", no_argument, &options.dump_shaders, 1 },
119
{ "no-color", no_argument, &options.color, 0 },
120
{ "color", no_argument, &options.color, 1 },
121
{ "no-pager", no_argument, &interactive, 0 },
122
{ "pager", no_argument, &interactive, 1 },
123
{ "textures", no_argument, &options.dump_textures, 1 },
124
{ "show-compositor", no_argument, &show_comp, 1 },
125
{ "query-all", no_argument, &options.query_mode, QUERY_ALL },
126
{ "query-written", no_argument, &options.query_mode, QUERY_WRITTEN },
127
{ "query-delta", no_argument, &options.query_mode, QUERY_DELTA },
128
{ "query-compare", no_argument, &options.query_compare, 1 },
129
{ "once", no_argument, &options.once, 1 },
130
{ "not-once", no_argument, &options.once, 0 },
131
132
/* Long opts with short alias: */
133
{ "verbose", no_argument, 0, 'v' },
134
{ "summary", no_argument, 0, 's' },
135
{ "allregs", no_argument, 0, 'a' },
136
{ "start", required_argument, 0, 'S' },
137
{ "end", required_argument, 0, 'E' },
138
{ "frame", required_argument, 0, 'F' },
139
{ "draw", required_argument, 0, 'D' },
140
{ "exe", required_argument, 0, 'e' },
141
{ "script", required_argument, 0, 'L' },
142
{ "query", required_argument, 0, 'q' },
143
{ "help", no_argument, 0, 'h' },
144
};
145
/* clang-format on */
146
147
int
148
main(int argc, char **argv)
149
{
150
enum debug_t debug = PRINT_RAW | PRINT_STATS;
151
int ret = -1;
152
int start = 0, end = 0x7ffffff, draw = -1;
153
int c;
154
155
interactive = isatty(STDOUT_FILENO);
156
157
options.color = interactive;
158
159
while ((c = getopt_long(argc, argv, "vsaS:E:F:D:e:L:q:h", opts, NULL)) !=
160
-1) {
161
switch (c) {
162
case 0:
163
/* option that set a flag, nothing to do */
164
break;
165
case 'v':
166
debug |= (PRINT_RAW | EXPAND_REPEAT | PRINT_VERBOSE);
167
break;
168
case 's':
169
options.summary = true;
170
break;
171
case 'a':
172
options.allregs = true;
173
break;
174
case 'S':
175
start = atoi(optarg);
176
break;
177
case 'E':
178
end = atoi(optarg);
179
break;
180
case 'F':
181
start = end = atoi(optarg);
182
break;
183
case 'D':
184
draw = atoi(optarg);
185
break;
186
case 'e':
187
exename = optarg;
188
break;
189
case 'L':
190
options.script = optarg;
191
if (script_load(options.script)) {
192
errx(-1, "error loading %s\n", options.script);
193
}
194
break;
195
case 'q':
196
options.querystrs =
197
realloc(options.querystrs,
198
(options.nquery + 1) * sizeof(*options.querystrs));
199
options.querystrs[options.nquery] = optarg;
200
options.nquery++;
201
interactive = 0;
202
break;
203
case 'h':
204
default:
205
print_usage(argv[0]);
206
}
207
}
208
209
disasm_a2xx_set_debug(debug);
210
disasm_a3xx_set_debug(debug);
211
212
if (interactive) {
213
pager_open();
214
}
215
216
while (optind < argc) {
217
ret = handle_file(argv[optind], start, end, draw);
218
if (ret) {
219
fprintf(stderr, "error reading: %s\n", argv[optind]);
220
fprintf(stderr, "continuing..\n");
221
}
222
optind++;
223
}
224
225
if (ret)
226
print_usage(argv[0]);
227
228
if ((options.query_mode || options.query_compare) && !options.nquery) {
229
fprintf(stderr, "query options only valid in query mode!\n");
230
print_usage(argv[0]);
231
}
232
233
script_finish();
234
235
if (interactive) {
236
pager_close();
237
}
238
239
return ret;
240
}
241
242
static void
243
parse_addr(uint32_t *buf, int sz, unsigned int *len, uint64_t *gpuaddr)
244
{
245
*gpuaddr = buf[0];
246
*len = buf[1];
247
if (sz > 8)
248
*gpuaddr |= ((uint64_t)(buf[2])) << 32;
249
}
250
251
static int
252
handle_file(const char *filename, int start, int end, int draw)
253
{
254
enum rd_sect_type type = RD_NONE;
255
void *buf = NULL;
256
struct io *io;
257
int submit = 0, got_gpu_id = 0;
258
int sz, ret = 0;
259
bool needs_reset = false;
260
bool skip = false;
261
262
options.draw_filter = draw;
263
264
cffdec_init(&options);
265
266
printf("Reading %s...\n", filename);
267
268
script_start_cmdstream(filename);
269
270
if (!strcmp(filename, "-"))
271
io = io_openfd(0);
272
else
273
io = io_open(filename);
274
275
if (!io) {
276
fprintf(stderr, "could not open: %s\n", filename);
277
return -1;
278
}
279
280
struct {
281
unsigned int len;
282
uint64_t gpuaddr;
283
} gpuaddr = {0};
284
285
while (true) {
286
uint32_t arr[2];
287
288
ret = io_readn(io, arr, 8);
289
if (ret <= 0)
290
goto end;
291
292
while ((arr[0] == 0xffffffff) && (arr[1] == 0xffffffff)) {
293
ret = io_readn(io, arr, 8);
294
if (ret <= 0)
295
goto end;
296
}
297
298
type = arr[0];
299
sz = arr[1];
300
301
if (sz < 0) {
302
ret = -1;
303
goto end;
304
}
305
306
free(buf);
307
308
needs_wfi = false;
309
310
buf = malloc(sz + 1);
311
((char *)buf)[sz] = '\0';
312
ret = io_readn(io, buf, sz);
313
if (ret < 0)
314
goto end;
315
316
switch (type) {
317
case RD_TEST:
318
printl(1, "test: %s\n", (char *)buf);
319
break;
320
case RD_CMD:
321
is_blob = true;
322
printl(2, "cmd: %s\n", (char *)buf);
323
skip = false;
324
if (exename) {
325
skip |= (strstr(buf, exename) != buf);
326
} else if (!show_comp) {
327
skip |= (strstr(buf, "fdperf") == buf);
328
skip |= (strstr(buf, "chrome") == buf);
329
skip |= (strstr(buf, "surfaceflinger") == buf);
330
skip |= ((char *)buf)[0] == 'X';
331
}
332
break;
333
case RD_VERT_SHADER:
334
printl(2, "vertex shader:\n%s\n", (char *)buf);
335
break;
336
case RD_FRAG_SHADER:
337
printl(2, "fragment shader:\n%s\n", (char *)buf);
338
break;
339
case RD_GPUADDR:
340
if (needs_reset) {
341
reset_buffers();
342
needs_reset = false;
343
}
344
parse_addr(buf, sz, &gpuaddr.len, &gpuaddr.gpuaddr);
345
break;
346
case RD_BUFFER_CONTENTS:
347
add_buffer(gpuaddr.gpuaddr, gpuaddr.len, buf);
348
buf = NULL;
349
break;
350
case RD_CMDSTREAM_ADDR:
351
if ((start <= submit) && (submit <= end)) {
352
unsigned int sizedwords;
353
uint64_t gpuaddr;
354
parse_addr(buf, sz, &sizedwords, &gpuaddr);
355
printl(2, "############################################################\n");
356
printl(2, "cmdstream: %d dwords\n", sizedwords);
357
if (!skip) {
358
script_start_submit();
359
dump_commands(hostptr(gpuaddr), sizedwords, 0);
360
script_end_submit();
361
}
362
printl(2, "############################################################\n");
363
printl(2, "vertices: %d\n", vertices);
364
}
365
needs_reset = true;
366
submit++;
367
break;
368
case RD_GPU_ID:
369
if (!got_gpu_id) {
370
options.gpu_id = *((unsigned int *)buf);
371
printl(2, "gpu_id: %d\n", options.gpu_id);
372
cffdec_init(&options);
373
got_gpu_id = 1;
374
}
375
break;
376
default:
377
break;
378
}
379
}
380
381
end:
382
script_end_cmdstream();
383
384
io_close(io);
385
fflush(stdout);
386
387
if (ret < 0) {
388
printf("corrupt file\n");
389
}
390
return 0;
391
}
392
393