~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/freedreno/decode/cffdump.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 <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--unit-test      - make reproducible output for unit testing\n"
110
 
           "\t-h, --help       - show this message\n"
111
 
           , name);
112
 
   /* clang-format on */
113
 
   exit(2);
114
 
}
115
 
 
116
 
/* clang-format off */
117
 
static const struct option opts[] = {
118
 
      /* Long opts that simply set a flag (no corresponding short alias: */
119
 
      { "dump-shaders",    no_argument, &options.dump_shaders,  1 },
120
 
      { "no-color",        no_argument, &options.color,         0 },
121
 
      { "color",           no_argument, &options.color,         1 },
122
 
      { "no-pager",        no_argument, &interactive,           0 },
123
 
      { "pager",           no_argument, &interactive,           1 },
124
 
      { "textures",        no_argument, &options.dump_textures, 1 },
125
 
      { "show-compositor", no_argument, &show_comp,             1 },
126
 
      { "query-all",       no_argument, &options.query_mode,    QUERY_ALL },
127
 
      { "query-written",   no_argument, &options.query_mode,    QUERY_WRITTEN },
128
 
      { "query-delta",     no_argument, &options.query_mode,    QUERY_DELTA },
129
 
      { "query-compare",   no_argument, &options.query_compare, 1 },
130
 
      { "once",            no_argument, &options.once,          1 },
131
 
      { "not-once",        no_argument, &options.once,          0 },
132
 
      { "unit-test",       no_argument, &options.unit_test,     1 },
133
 
 
134
 
      /* Long opts with short alias: */
135
 
      { "verbose",   no_argument,       0, 'v' },
136
 
      { "summary",   no_argument,       0, 's' },
137
 
      { "allregs",   no_argument,       0, 'a' },
138
 
      { "start",     required_argument, 0, 'S' },
139
 
      { "end",       required_argument, 0, 'E' },
140
 
      { "frame",     required_argument, 0, 'F' },
141
 
      { "draw",      required_argument, 0, 'D' },
142
 
      { "exe",       required_argument, 0, 'e' },
143
 
      { "script",    required_argument, 0, 'L' },
144
 
      { "query",     required_argument, 0, 'q' },
145
 
      { "help",      no_argument,       0, 'h' },
146
 
};
147
 
/* clang-format on */
148
 
 
149
 
int
150
 
main(int argc, char **argv)
151
 
{
152
 
   enum debug_t debug = PRINT_RAW | PRINT_STATS;
153
 
   int ret = -1;
154
 
   int start = 0, end = 0x7ffffff, draw = -1;
155
 
   int c;
156
 
 
157
 
   interactive = isatty(STDOUT_FILENO);
158
 
 
159
 
   options.color = interactive;
160
 
 
161
 
   while ((c = getopt_long(argc, argv, "vsaS:E:F:D:e:L:q:h", opts, NULL)) !=
162
 
          -1) {
163
 
      switch (c) {
164
 
      case 0:
165
 
         /* option that set a flag, nothing to do */
166
 
         break;
167
 
      case 'v':
168
 
         debug |= (PRINT_RAW | EXPAND_REPEAT | PRINT_VERBOSE);
169
 
         break;
170
 
      case 's':
171
 
         options.summary = true;
172
 
         break;
173
 
      case 'a':
174
 
         options.allregs = true;
175
 
         break;
176
 
      case 'S':
177
 
         start = atoi(optarg);
178
 
         break;
179
 
      case 'E':
180
 
         end = atoi(optarg);
181
 
         break;
182
 
      case 'F':
183
 
         start = end = atoi(optarg);
184
 
         break;
185
 
      case 'D':
186
 
         draw = atoi(optarg);
187
 
         break;
188
 
      case 'e':
189
 
         exename = optarg;
190
 
         break;
191
 
      case 'L':
192
 
         options.script = optarg;
193
 
         if (script_load(options.script)) {
194
 
            errx(-1, "error loading %s\n", options.script);
195
 
         }
196
 
         break;
197
 
      case 'q':
198
 
         options.querystrs =
199
 
            realloc(options.querystrs,
200
 
                    (options.nquery + 1) * sizeof(*options.querystrs));
201
 
         options.querystrs[options.nquery] = optarg;
202
 
         options.nquery++;
203
 
         interactive = 0;
204
 
         break;
205
 
      case 'h':
206
 
      default:
207
 
         print_usage(argv[0]);
208
 
      }
209
 
   }
210
 
 
211
 
   disasm_a2xx_set_debug(debug);
212
 
   disasm_a3xx_set_debug(debug);
213
 
 
214
 
   if (interactive) {
215
 
      pager_open();
216
 
   }
217
 
 
218
 
   while (optind < argc) {
219
 
      ret = handle_file(argv[optind], start, end, draw);
220
 
      if (ret) {
221
 
         fprintf(stderr, "error reading: %s\n", argv[optind]);
222
 
         fprintf(stderr, "continuing..\n");
223
 
      }
224
 
      optind++;
225
 
   }
226
 
 
227
 
   if (ret)
228
 
      print_usage(argv[0]);
229
 
 
230
 
   if ((options.query_mode || options.query_compare) && !options.nquery) {
231
 
      fprintf(stderr, "query options only valid in query mode!\n");
232
 
      print_usage(argv[0]);
233
 
   }
234
 
 
235
 
   script_finish();
236
 
 
237
 
   if (interactive) {
238
 
      pager_close();
239
 
   }
240
 
 
241
 
   return ret;
242
 
}
243
 
 
244
 
static void
245
 
parse_addr(uint32_t *buf, int sz, unsigned int *len, uint64_t *gpuaddr)
246
 
{
247
 
   *gpuaddr = buf[0];
248
 
   *len = buf[1];
249
 
   if (sz > 8)
250
 
      *gpuaddr |= ((uint64_t)(buf[2])) << 32;
251
 
}
252
 
 
253
 
static int
254
 
handle_file(const char *filename, int start, int end, int draw)
255
 
{
256
 
   enum rd_sect_type type = RD_NONE;
257
 
   void *buf = NULL;
258
 
   struct io *io;
259
 
   int submit = 0, got_gpu_id = 0;
260
 
   int sz, ret = 0;
261
 
   bool needs_reset = false;
262
 
   bool skip = false;
263
 
 
264
 
   options.draw_filter = draw;
265
 
 
266
 
   cffdec_init(&options);
267
 
 
268
 
   if (!options.unit_test)
269
 
      printf("Reading %s...\n", filename);
270
 
 
271
 
   script_start_cmdstream(filename);
272
 
 
273
 
   if (!strcmp(filename, "-"))
274
 
      io = io_openfd(0);
275
 
   else
276
 
      io = io_open(filename);
277
 
 
278
 
   if (!io) {
279
 
      fprintf(stderr, "could not open: %s\n", filename);
280
 
      return -1;
281
 
   }
282
 
 
283
 
   struct {
284
 
      unsigned int len;
285
 
      uint64_t gpuaddr;
286
 
   } gpuaddr = {0};
287
 
 
288
 
   while (true) {
289
 
      uint32_t arr[2];
290
 
 
291
 
      ret = io_readn(io, arr, 8);
292
 
      if (ret <= 0)
293
 
         goto end;
294
 
 
295
 
      while ((arr[0] == 0xffffffff) && (arr[1] == 0xffffffff)) {
296
 
         ret = io_readn(io, arr, 8);
297
 
         if (ret <= 0)
298
 
            goto end;
299
 
      }
300
 
 
301
 
      type = arr[0];
302
 
      sz = arr[1];
303
 
 
304
 
      if (sz < 0) {
305
 
         ret = -1;
306
 
         goto end;
307
 
      }
308
 
 
309
 
      free(buf);
310
 
 
311
 
      needs_wfi = false;
312
 
 
313
 
      buf = malloc(sz + 1);
314
 
      ((char *)buf)[sz] = '\0';
315
 
      ret = io_readn(io, buf, sz);
316
 
      if (ret < 0)
317
 
         goto end;
318
 
 
319
 
      switch (type) {
320
 
      case RD_TEST:
321
 
         printl(1, "test: %s\n", (char *)buf);
322
 
         break;
323
 
      case RD_CMD:
324
 
         is_blob = true;
325
 
         printl(2, "cmd: %s\n", (char *)buf);
326
 
         skip = false;
327
 
         if (exename) {
328
 
            skip |= (strstr(buf, exename) != buf);
329
 
         } else if (!show_comp) {
330
 
            skip |= (strstr(buf, "fdperf") == buf);
331
 
            skip |= (strstr(buf, "chrome") == buf);
332
 
            skip |= (strstr(buf, "surfaceflinger") == buf);
333
 
            skip |= ((char *)buf)[0] == 'X';
334
 
         }
335
 
         break;
336
 
      case RD_VERT_SHADER:
337
 
         printl(2, "vertex shader:\n%s\n", (char *)buf);
338
 
         break;
339
 
      case RD_FRAG_SHADER:
340
 
         printl(2, "fragment shader:\n%s\n", (char *)buf);
341
 
         break;
342
 
      case RD_GPUADDR:
343
 
         if (needs_reset) {
344
 
            reset_buffers();
345
 
            needs_reset = false;
346
 
         }
347
 
         parse_addr(buf, sz, &gpuaddr.len, &gpuaddr.gpuaddr);
348
 
         break;
349
 
      case RD_BUFFER_CONTENTS:
350
 
         add_buffer(gpuaddr.gpuaddr, gpuaddr.len, buf);
351
 
         buf = NULL;
352
 
         break;
353
 
      case RD_CMDSTREAM_ADDR:
354
 
         if ((start <= submit) && (submit <= end)) {
355
 
            unsigned int sizedwords;
356
 
            uint64_t gpuaddr;
357
 
            parse_addr(buf, sz, &sizedwords, &gpuaddr);
358
 
            printl(2, "############################################################\n");
359
 
            printl(2, "cmdstream: %d dwords\n", sizedwords);
360
 
            if (!skip) {
361
 
               script_start_submit();
362
 
               dump_commands(hostptr(gpuaddr), sizedwords, 0);
363
 
               script_end_submit();
364
 
            }
365
 
            printl(2, "############################################################\n");
366
 
            printl(2, "vertices: %d\n", vertices);
367
 
         }
368
 
         needs_reset = true;
369
 
         submit++;
370
 
         break;
371
 
      case RD_GPU_ID:
372
 
         if (!got_gpu_id) {
373
 
            uint32_t gpu_id = *((unsigned int *)buf);
374
 
            if (!gpu_id)
375
 
               break;
376
 
            options.gpu_id = gpu_id;
377
 
            printl(2, "gpu_id: %d\n", options.gpu_id);
378
 
            cffdec_init(&options);
379
 
            got_gpu_id = 1;
380
 
         }
381
 
         break;
382
 
      case RD_CHIP_ID:
383
 
         if (!got_gpu_id) {
384
 
            uint64_t chip_id = *((uint64_t *)buf);
385
 
            options.gpu_id = 100 * ((chip_id >> 24) & 0xff) +
386
 
                  10 * ((chip_id >> 16) & 0xff) +
387
 
                  ((chip_id >> 8) & 0xff);
388
 
            printl(2, "gpu_id: %d\n", options.gpu_id);
389
 
            cffdec_init(&options);
390
 
            got_gpu_id = 1;
391
 
         }
392
 
         break;
393
 
      default:
394
 
         break;
395
 
      }
396
 
   }
397
 
 
398
 
end:
399
 
   script_end_cmdstream();
400
 
 
401
 
   io_close(io);
402
 
   fflush(stdout);
403
 
 
404
 
   if (ret < 0) {
405
 
      printf("corrupt file\n");
406
 
   }
407
 
   return 0;
408
 
}