~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/intel/tools/aubinator_viewer.cpp

  • 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 © 2016 Intel Corporation
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
20
 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
 
 * IN THE SOFTWARE.
22
 
 */
23
 
 
24
 
#include <stdio.h>
25
 
#include <stdlib.h>
26
 
#include <stdint.h>
27
 
#include <getopt.h>
28
 
#include <unistd.h>
29
 
#include <fcntl.h>
30
 
#include <string.h>
31
 
#include <errno.h>
32
 
#include <sys/stat.h>
33
 
#include <sys/mman.h>
34
 
#include <sys/types.h>
35
 
#include <ctype.h>
36
 
 
37
 
#include "util/macros.h"
38
 
 
39
 
#include "aub_read.h"
40
 
#include "aub_mem.h"
41
 
 
42
 
#include "common/intel_disasm.h"
43
 
 
44
 
#define xtzalloc(name) ((decltype(&name)) calloc(1, sizeof(name)))
45
 
#define xtalloc(name) ((decltype(&name)) malloc(sizeof(name)))
46
 
 
47
 
struct aub_file {
48
 
   uint8_t *map, *end, *cursor;
49
 
 
50
 
   uint16_t pci_id;
51
 
   char app_name[33];
52
 
 
53
 
   /* List of batch buffers to process */
54
 
   struct {
55
 
      const uint8_t *start;
56
 
      const uint8_t *end;
57
 
   } *execs;
58
 
   int n_execs;
59
 
   int n_allocated_execs;
60
 
 
61
 
   uint32_t idx_reg_write;
62
 
 
63
 
   /* Device state */
64
 
   struct intel_device_info devinfo;
65
 
   struct intel_spec *spec;
66
 
};
67
 
 
68
 
static void
69
 
store_exec_begin(struct aub_file *file)
70
 
{
71
 
   if (unlikely(file->n_execs >= file->n_allocated_execs)) {
72
 
      file->n_allocated_execs = MAX2(2U * file->n_allocated_execs,
73
 
                                     4096 / sizeof(file->execs[0]));
74
 
      file->execs = (decltype(file->execs))
75
 
         realloc(static_cast<void *>(file->execs),
76
 
                 file->n_allocated_execs * sizeof(file->execs[0]));
77
 
   }
78
 
 
79
 
   file->execs[file->n_execs++].start = file->cursor;
80
 
}
81
 
 
82
 
static void
83
 
store_exec_end(struct aub_file *file)
84
 
{
85
 
   if (file->n_execs > 0 && file->execs[file->n_execs - 1].end == NULL)
86
 
      file->execs[file->n_execs - 1].end = file->cursor;
87
 
}
88
 
 
89
 
static void
90
 
handle_mem_write(void *user_data, uint64_t phys_addr,
91
 
                 const void *data, uint32_t data_len)
92
 
{
93
 
   struct aub_file *file = (struct aub_file *) user_data;
94
 
   file->idx_reg_write = 0;
95
 
   store_exec_end(file);
96
 
}
97
 
 
98
 
static void
99
 
handle_ring_write(void *user_data, enum drm_i915_gem_engine_class engine,
100
 
                  const void *ring_data, uint32_t ring_data_len)
101
 
{
102
 
   struct aub_file *file = (struct aub_file *) user_data;
103
 
   file->idx_reg_write = 0;
104
 
   store_exec_begin(file);
105
 
}
106
 
 
107
 
static void
108
 
handle_reg_write(void *user_data, uint32_t reg_offset, uint32_t reg_value)
109
 
{
110
 
   struct aub_file *file = (struct aub_file *) user_data;
111
 
 
112
 
   /* Only store the first register write of a series (execlist writes take
113
 
    * involve 2 dwords).
114
 
    */
115
 
   if (file->idx_reg_write++ == 0)
116
 
      store_exec_begin(file);
117
 
}
118
 
 
119
 
static void
120
 
handle_info(void *user_data, int pci_id, const char *app_name)
121
 
{
122
 
   struct aub_file *file = (struct aub_file *) user_data;
123
 
   store_exec_end(file);
124
 
 
125
 
   file->pci_id = pci_id;
126
 
   snprintf(file->app_name, sizeof(app_name), "%s", app_name);
127
 
 
128
 
   if (!intel_get_device_info_from_pci_id(file->pci_id, &file->devinfo)) {
129
 
      fprintf(stderr, "can't find device information: pci_id=0x%x\n", file->pci_id);
130
 
      exit(EXIT_FAILURE);
131
 
   }
132
 
   file->spec = intel_spec_load(&file->devinfo);
133
 
}
134
 
 
135
 
static void
136
 
handle_error(void *user_data, const void *aub_data, const char *msg)
137
 
{
138
 
   fprintf(stderr, "ERROR: %s", msg);
139
 
}
140
 
 
141
 
static struct aub_file *
142
 
aub_file_open(const char *filename)
143
 
{
144
 
   struct aub_file *file;
145
 
   struct stat sb;
146
 
   int fd;
147
 
 
148
 
   file = xtzalloc(*file);
149
 
   fd = open(filename, O_RDWR);
150
 
   if (fd == -1) {
151
 
      fprintf(stderr, "open %s failed: %s\n", filename, strerror(errno));
152
 
      exit(EXIT_FAILURE);
153
 
   }
154
 
 
155
 
   if (fstat(fd, &sb) == -1) {
156
 
      fprintf(stderr, "stat failed: %s\n", strerror(errno));
157
 
      exit(EXIT_FAILURE);
158
 
   }
159
 
 
160
 
   file->map = (uint8_t *) mmap(NULL, sb.st_size,
161
 
                                PROT_READ, MAP_SHARED, fd, 0);
162
 
   if (file->map == MAP_FAILED) {
163
 
      fprintf(stderr, "mmap failed: %s\n", strerror(errno));
164
 
      exit(EXIT_FAILURE);
165
 
   }
166
 
 
167
 
   close(fd);
168
 
 
169
 
   file->cursor = file->map;
170
 
   file->end = file->map + sb.st_size;
171
 
 
172
 
   struct aub_read aub_read = {};
173
 
   aub_read.user_data = file;
174
 
   aub_read.info = handle_info;
175
 
   aub_read.error = handle_error;
176
 
   aub_read.reg_write = handle_reg_write;
177
 
   aub_read.ring_write = handle_ring_write;
178
 
   aub_read.local_write = handle_mem_write;
179
 
   aub_read.phys_write = handle_mem_write;
180
 
   aub_read.ggtt_write = handle_mem_write;
181
 
   aub_read.ggtt_entry_write = handle_mem_write;
182
 
 
183
 
   int consumed;
184
 
   while (file->cursor < file->end &&
185
 
          (consumed = aub_read_command(&aub_read, file->cursor,
186
 
                                       file->end - file->cursor)) > 0) {
187
 
      file->cursor += consumed;
188
 
   }
189
 
 
190
 
   /* Ensure we have an end on the last register write. */
191
 
   if (file->n_execs > 0 && file->execs[file->n_execs - 1].end == NULL)
192
 
      file->execs[file->n_execs - 1].end = file->end;
193
 
 
194
 
   return file;
195
 
}
196
 
 
197
 
/**/
198
 
 
199
 
static void
200
 
update_mem_for_exec(struct aub_mem *mem, struct aub_file *file, int exec_idx)
201
 
{
202
 
   struct aub_read read = {};
203
 
   read.user_data = mem;
204
 
   read.local_write = aub_mem_local_write;
205
 
   read.phys_write = aub_mem_phys_write;
206
 
   read.ggtt_write = aub_mem_ggtt_write;
207
 
   read.ggtt_entry_write = aub_mem_ggtt_entry_write;
208
 
 
209
 
   /* Replay the aub file from the beginning up to just before the
210
 
    * commands we want to read. where the context setup happens.
211
 
    */
212
 
   const uint8_t *iter = file->map;
213
 
   while (iter < file->execs[exec_idx].start) {
214
 
      iter += aub_read_command(&read, iter, file->execs[exec_idx].start - iter);
215
 
   }
216
 
}
217
 
 
218
 
/* UI */
219
 
 
220
 
#include <epoxy/gl.h>
221
 
 
222
 
#include "imgui/imgui.h"
223
 
#include "imgui/imgui_memory_editor.h"
224
 
#include "imgui_impl_gtk3.h"
225
 
#include "imgui_impl_opengl3.h"
226
 
 
227
 
#include "aubinator_viewer.h"
228
 
#include "aubinator_viewer_urb.h"
229
 
 
230
 
struct window {
231
 
   struct list_head link; /* link in the global list of windows */
232
 
   struct list_head parent_link; /* link in parent window list of children */
233
 
 
234
 
   struct list_head children_windows; /* list of children windows */
235
 
 
236
 
   char name[128];
237
 
   bool opened;
238
 
 
239
 
   ImVec2 position;
240
 
   ImVec2 size;
241
 
 
242
 
   void (*display)(struct window*);
243
 
   void (*destroy)(struct window*);
244
 
};
245
 
 
246
 
struct edit_window {
247
 
   struct window base;
248
 
 
249
 
   struct aub_mem *mem;
250
 
   uint64_t address;
251
 
   uint32_t len;
252
 
 
253
 
   struct intel_batch_decode_bo aub_bo;
254
 
   uint64_t aub_offset;
255
 
 
256
 
   struct intel_batch_decode_bo gtt_bo;
257
 
   uint64_t gtt_offset;
258
 
 
259
 
   struct MemoryEditor editor;
260
 
};
261
 
 
262
 
struct pml4_window {
263
 
   struct window base;
264
 
 
265
 
   struct aub_mem *mem;
266
 
};
267
 
 
268
 
struct shader_window {
269
 
   struct window base;
270
 
 
271
 
   uint64_t address;
272
 
   char *shader;
273
 
   size_t shader_size;
274
 
};
275
 
 
276
 
struct urb_window {
277
 
   struct window base;
278
 
 
279
 
   uint32_t end_urb_offset;
280
 
   struct aub_decode_urb_stage_state urb_stages[AUB_DECODE_N_STAGE];
281
 
 
282
 
   AubinatorViewerUrb urb_view;
283
 
};
284
 
 
285
 
struct batch_window {
286
 
   struct window base;
287
 
 
288
 
   struct aub_mem mem;
289
 
   struct aub_read read;
290
 
 
291
 
   bool uses_ppgtt;
292
 
 
293
 
   bool collapsed;
294
 
   int exec_idx;
295
 
 
296
 
   struct aub_viewer_decode_cfg decode_cfg;
297
 
   struct aub_viewer_decode_ctx decode_ctx;
298
 
 
299
 
   struct pml4_window pml4_window;
300
 
 
301
 
   char edit_address[20];
302
 
};
303
 
 
304
 
static struct Context {
305
 
   struct aub_file *file;
306
 
   char *input_file;
307
 
   char *xml_path;
308
 
 
309
 
   GtkWidget *gtk_window;
310
 
 
311
 
   /* UI state*/
312
 
   bool show_commands_window;
313
 
   bool show_registers_window;
314
 
 
315
 
   struct aub_viewer_cfg cfg;
316
 
 
317
 
   struct list_head windows;
318
 
 
319
 
   struct window file_window;
320
 
   struct window commands_window;
321
 
   struct window registers_window;
322
 
} context;
323
 
 
324
 
thread_local ImGuiContext* __MesaImGui;
325
 
 
326
 
static int
327
 
map_key(int k)
328
 
{
329
 
   return ImGuiKey_COUNT + k;
330
 
}
331
 
 
332
 
static bool
333
 
has_ctrl_key(int key)
334
 
{
335
 
   return ImGui::GetIO().KeyCtrl && ImGui::IsKeyPressed(map_key(key));
336
 
}
337
 
 
338
 
static bool
339
 
window_has_ctrl_key(int key)
340
 
{
341
 
   return ImGui::IsRootWindowOrAnyChildFocused() && has_ctrl_key(key);
342
 
}
343
 
 
344
 
static void
345
 
destroy_window_noop(struct window *win)
346
 
{
347
 
}
348
 
 
349
 
/* Shader windows */
350
 
 
351
 
static void
352
 
display_shader_window(struct window *win)
353
 
{
354
 
   struct shader_window *window = (struct shader_window *) win;
355
 
 
356
 
   if (window->shader) {
357
 
      ImGui::InputTextMultiline("Assembly",
358
 
                                window->shader, window->shader_size,
359
 
                                ImGui::GetContentRegionAvail(),
360
 
                                ImGuiInputTextFlags_ReadOnly);
361
 
   } else {
362
 
      ImGui::Text("Shader not available");
363
 
   }
364
 
}
365
 
 
366
 
static void
367
 
destroy_shader_window(struct window *win)
368
 
{
369
 
   struct shader_window *window = (struct shader_window *) win;
370
 
 
371
 
   free(window->shader);
372
 
   free(window);
373
 
}
374
 
 
375
 
static struct shader_window *
376
 
new_shader_window(struct aub_mem *mem, uint64_t address, const char *desc)
377
 
{
378
 
   struct shader_window *window = xtzalloc(*window);
379
 
 
380
 
   snprintf(window->base.name, sizeof(window->base.name),
381
 
            "%s (0x%" PRIx64 ")##%p", desc, address, window);
382
 
 
383
 
   list_inithead(&window->base.parent_link);
384
 
   window->base.position = ImVec2(-1, -1);
385
 
   window->base.size = ImVec2(700, 300);
386
 
   window->base.opened = true;
387
 
   window->base.display = display_shader_window;
388
 
   window->base.destroy = destroy_shader_window;
389
 
 
390
 
   struct intel_batch_decode_bo shader_bo =
391
 
      aub_mem_get_ppgtt_bo(mem, address);
392
 
   if (shader_bo.map) {
393
 
      FILE *f = open_memstream(&window->shader, &window->shader_size);
394
 
      if (f) {
395
 
         intel_disassemble(&context.file->devinfo,
396
 
                           (const uint8_t *) shader_bo.map +
397
 
                           (address - shader_bo.addr), 0, f);
398
 
         fclose(f);
399
 
      }
400
 
   }
401
 
 
402
 
   list_addtail(&window->base.link, &context.windows);
403
 
 
404
 
   return window;
405
 
}
406
 
 
407
 
/* URB windows */
408
 
 
409
 
static void
410
 
display_urb_window(struct window *win)
411
 
{
412
 
   struct urb_window *window = (struct urb_window *) win;
413
 
   static const char *stages[] = {
414
 
      [AUB_DECODE_STAGE_VS] = "VS",
415
 
      [AUB_DECODE_STAGE_HS] = "HS",
416
 
      [AUB_DECODE_STAGE_DS] = "DS",
417
 
      [AUB_DECODE_STAGE_GS] = "GS",
418
 
      [AUB_DECODE_STAGE_PS] = "PS",
419
 
      [AUB_DECODE_STAGE_CS] = "CS",
420
 
   };
421
 
 
422
 
   ImGui::Text("URB allocation:");
423
 
   window->urb_view.DrawAllocation("##urb",
424
 
                                   ARRAY_SIZE(window->urb_stages),
425
 
                                   window->end_urb_offset,
426
 
                                   stages,
427
 
                                   &window->urb_stages[0]);
428
 
}
429
 
 
430
 
static void
431
 
destroy_urb_window(struct window *win)
432
 
{
433
 
   struct urb_window *window = (struct urb_window *) win;
434
 
 
435
 
   free(window);
436
 
}
437
 
 
438
 
static struct urb_window *
439
 
new_urb_window(struct aub_viewer_decode_ctx *decode_ctx, uint64_t address)
440
 
{
441
 
   struct urb_window *window = xtzalloc(*window);
442
 
 
443
 
   snprintf(window->base.name, sizeof(window->base.name),
444
 
            "URB view (0x%" PRIx64 ")##%p", address, window);
445
 
 
446
 
   list_inithead(&window->base.parent_link);
447
 
   window->base.position = ImVec2(-1, -1);
448
 
   window->base.size = ImVec2(700, 300);
449
 
   window->base.opened = true;
450
 
   window->base.display = display_urb_window;
451
 
   window->base.destroy = destroy_urb_window;
452
 
 
453
 
   window->end_urb_offset = decode_ctx->end_urb_offset;
454
 
   memcpy(window->urb_stages, decode_ctx->urb_stages, sizeof(window->urb_stages));
455
 
   window->urb_view = AubinatorViewerUrb();
456
 
 
457
 
   list_addtail(&window->base.link, &context.windows);
458
 
 
459
 
   return window;
460
 
}
461
 
 
462
 
/* Memory editor windows */
463
 
 
464
 
static uint8_t
465
 
read_edit_window(const uint8_t *data, size_t off)
466
 
{
467
 
   struct edit_window *window = (struct edit_window *) data;
468
 
 
469
 
   return *((const uint8_t *) window->gtt_bo.map + window->gtt_offset + off);
470
 
}
471
 
 
472
 
static void
473
 
write_edit_window(uint8_t *data, size_t off, uint8_t d)
474
 
{
475
 
   struct edit_window *window = (struct edit_window *) data;
476
 
   uint8_t *gtt = (uint8_t *) window->gtt_bo.map + window->gtt_offset + off;
477
 
   uint8_t *aub = (uint8_t *) window->aub_bo.map + window->aub_offset + off;
478
 
 
479
 
   *gtt = *aub = d;
480
 
}
481
 
 
482
 
static void
483
 
display_edit_window(struct window *win)
484
 
{
485
 
   struct edit_window *window = (struct edit_window *) win;
486
 
 
487
 
   if (window->aub_bo.map && window->gtt_bo.map) {
488
 
      ImGui::BeginChild(ImGui::GetID("##block"));
489
 
      window->editor.DrawContents((uint8_t *) window,
490
 
                                  MIN3(window->len,
491
 
                                       window->gtt_bo.size - window->gtt_offset,
492
 
                                       window->aub_bo.size - window->aub_offset),
493
 
                                  window->address);
494
 
      ImGui::EndChild();
495
 
   } else {
496
 
      ImGui::Text("Memory view at 0x%" PRIx64 " not available", window->address);
497
 
   }
498
 
}
499
 
 
500
 
static void
501
 
destroy_edit_window(struct window *win)
502
 
{
503
 
   struct edit_window *window = (struct edit_window *) win;
504
 
 
505
 
   if (window->aub_bo.map)
506
 
      mprotect((void *) window->aub_bo.map, 4096, PROT_READ);
507
 
   free(window);
508
 
}
509
 
 
510
 
static struct edit_window *
511
 
new_edit_window(struct aub_mem *mem, uint64_t address, uint32_t len)
512
 
{
513
 
   struct edit_window *window = xtzalloc(*window);
514
 
 
515
 
   snprintf(window->base.name, sizeof(window->base.name),
516
 
            "Editing aub at 0x%" PRIx64 "##%p", address, window);
517
 
 
518
 
   list_inithead(&window->base.parent_link);
519
 
   window->base.position = ImVec2(-1, -1);
520
 
   window->base.size = ImVec2(500, 600);
521
 
   window->base.opened = true;
522
 
   window->base.display = display_edit_window;
523
 
   window->base.destroy = destroy_edit_window;
524
 
 
525
 
   window->mem = mem;
526
 
   window->address = address;
527
 
   window->aub_bo = aub_mem_get_ppgtt_addr_aub_data(mem, address);
528
 
   window->gtt_bo = aub_mem_get_ppgtt_addr_data(mem, address);
529
 
   window->len = len;
530
 
   window->editor = MemoryEditor();
531
 
   window->editor.OptShowDataPreview = true;
532
 
   window->editor.OptShowAscii = false;
533
 
   window->editor.ReadFn = read_edit_window;
534
 
   window->editor.WriteFn = write_edit_window;
535
 
 
536
 
   if (window->aub_bo.map) {
537
 
      uint64_t unaligned_map = (uint64_t) window->aub_bo.map;
538
 
      window->aub_bo.map = (const void *)(unaligned_map & ~0xffful);
539
 
      window->aub_offset = unaligned_map - (uint64_t) window->aub_bo.map;
540
 
 
541
 
      if (mprotect((void *) window->aub_bo.map, window->aub_bo.size, PROT_READ | PROT_WRITE) != 0) {
542
 
         window->aub_bo.map = NULL;
543
 
      }
544
 
   }
545
 
 
546
 
   window->gtt_offset = address - window->gtt_bo.addr;
547
 
 
548
 
   list_addtail(&window->base.link, &context.windows);
549
 
 
550
 
   return window;
551
 
}
552
 
 
553
 
/* 4 level page table walk windows */
554
 
 
555
 
static void
556
 
display_pml4_level(struct aub_mem *mem, uint64_t table_addr, uint64_t table_virt_addr, int level)
557
 
{
558
 
   if (level == 0)
559
 
      return;
560
 
 
561
 
   struct intel_batch_decode_bo table_bo =
562
 
      aub_mem_get_phys_addr_data(mem, table_addr);
563
 
   const uint64_t *table = (const uint64_t *) ((const uint8_t *) table_bo.map +
564
 
                                               table_addr - table_bo.addr);
565
 
   if (!table) {
566
 
      ImGui::TextColored(context.cfg.missing_color, "Page not available");
567
 
      return;
568
 
   }
569
 
 
570
 
   uint64_t addr_increment = 1ULL << (12 + 9 * (level - 1));
571
 
 
572
 
   if (level == 1) {
573
 
      for (int e = 0; e < 512; e++) {
574
 
         bool available = (table[e] & 1) != 0;
575
 
         uint64_t entry_virt_addr = table_virt_addr + e * addr_increment;
576
 
         if (!available)
577
 
            continue;
578
 
         ImGui::Text("Entry%03i - phys_addr=0x%" PRIx64 " - virt_addr=0x%" PRIx64,
579
 
                     e, table[e], entry_virt_addr);
580
 
      }
581
 
   } else {
582
 
      for (int e = 0; e < 512; e++) {
583
 
         bool available = (table[e] & 1) != 0;
584
 
         uint64_t entry_virt_addr = table_virt_addr + e * addr_increment;
585
 
         if (available &&
586
 
             ImGui::TreeNodeEx(&table[e],
587
 
                               available ? ImGuiTreeNodeFlags_Framed : 0,
588
 
                               "Entry%03i - phys_addr=0x%" PRIx64 " - virt_addr=0x%" PRIx64,
589
 
                               e, table[e], entry_virt_addr)) {
590
 
            display_pml4_level(mem, table[e] & ~0xffful, entry_virt_addr, level -1);
591
 
            ImGui::TreePop();
592
 
         }
593
 
      }
594
 
   }
595
 
}
596
 
 
597
 
static void
598
 
display_pml4_window(struct window *win)
599
 
{
600
 
   struct pml4_window *window = (struct pml4_window *) win;
601
 
 
602
 
   ImGui::Text("pml4: %" PRIx64, window->mem->pml4);
603
 
   ImGui::BeginChild(ImGui::GetID("##block"));
604
 
   display_pml4_level(window->mem, window->mem->pml4, 0, 4);
605
 
   ImGui::EndChild();
606
 
}
607
 
 
608
 
static void
609
 
show_pml4_window(struct pml4_window *window, struct aub_mem *mem)
610
 
{
611
 
   if (window->base.opened) {
612
 
      window->base.opened = false;
613
 
      return;
614
 
   }
615
 
 
616
 
   snprintf(window->base.name, sizeof(window->base.name),
617
 
            "4-Level page tables##%p", window);
618
 
 
619
 
   list_inithead(&window->base.parent_link);
620
 
   window->base.position = ImVec2(-1, -1);
621
 
   window->base.size = ImVec2(500, 600);
622
 
   window->base.opened = true;
623
 
   window->base.display = display_pml4_window;
624
 
   window->base.destroy = destroy_window_noop;
625
 
 
626
 
   window->mem = mem;
627
 
 
628
 
   list_addtail(&window->base.link, &context.windows);
629
 
}
630
 
 
631
 
/* Batch decoding windows */
632
 
 
633
 
static void
634
 
display_decode_options(struct aub_viewer_decode_cfg *cfg)
635
 
{
636
 
   char name[40];
637
 
   snprintf(name, sizeof(name), "command filter##%p", &cfg->command_filter);
638
 
   cfg->command_filter.Draw(name); ImGui::SameLine();
639
 
   snprintf(name, sizeof(name), "field filter##%p", &cfg->field_filter);
640
 
   cfg->field_filter.Draw(name); ImGui::SameLine();
641
 
   if (ImGui::Button("Dwords")) cfg->show_dwords ^= 1;
642
 
}
643
 
 
644
 
static void
645
 
batch_display_shader(void *user_data, const char *shader_desc, uint64_t address)
646
 
{
647
 
   struct batch_window *window = (struct batch_window *) user_data;
648
 
   struct shader_window *shader_window =
649
 
      new_shader_window(&window->mem, address, shader_desc);
650
 
 
651
 
   list_add(&shader_window->base.parent_link, &window->base.children_windows);
652
 
}
653
 
 
654
 
static void
655
 
batch_display_urb(void *user_data, const struct aub_decode_urb_stage_state *stages)
656
 
{
657
 
   struct batch_window *window = (struct batch_window *) user_data;
658
 
   struct urb_window *urb_window = new_urb_window(&window->decode_ctx, 0);
659
 
 
660
 
   list_add(&urb_window->base.parent_link, &window->base.children_windows);
661
 
}
662
 
 
663
 
static void
664
 
batch_edit_address(void *user_data, uint64_t address, uint32_t len)
665
 
{
666
 
   struct batch_window *window = (struct batch_window *) user_data;
667
 
   struct edit_window *edit_window =
668
 
      new_edit_window(&window->mem, address, len);
669
 
 
670
 
   list_add(&edit_window->base.parent_link, &window->base.children_windows);
671
 
}
672
 
 
673
 
static struct intel_batch_decode_bo
674
 
batch_get_bo(void *user_data, bool ppgtt, uint64_t address)
675
 
{
676
 
   struct batch_window *window = (struct batch_window *) user_data;
677
 
 
678
 
   if (window->uses_ppgtt && ppgtt)
679
 
      return aub_mem_get_ppgtt_bo(&window->mem, address);
680
 
   else
681
 
      return aub_mem_get_ggtt_bo(&window->mem, address);
682
 
}
683
 
 
684
 
static void
685
 
update_batch_window(struct batch_window *window, bool reset, int exec_idx)
686
 
{
687
 
   if (reset)
688
 
      aub_mem_fini(&window->mem);
689
 
   aub_mem_init(&window->mem);
690
 
 
691
 
   window->exec_idx = MAX2(MIN2(context.file->n_execs - 1, exec_idx), 0);
692
 
   update_mem_for_exec(&window->mem, context.file, window->exec_idx);
693
 
}
694
 
 
695
 
static void
696
 
display_batch_ring_write(void *user_data, enum drm_i915_gem_engine_class engine,
697
 
                         const void *data, uint32_t data_len)
698
 
{
699
 
   struct batch_window *window = (struct batch_window *) user_data;
700
 
 
701
 
   window->uses_ppgtt = false;
702
 
 
703
 
   aub_viewer_render_batch(&window->decode_ctx, data, data_len, 0, false);
704
 
}
705
 
 
706
 
static void
707
 
display_batch_execlist_write(void *user_data,
708
 
                             enum drm_i915_gem_engine_class engine,
709
 
                             uint64_t context_descriptor)
710
 
{
711
 
   struct batch_window *window = (struct batch_window *) user_data;
712
 
 
713
 
   const uint32_t pphwsp_size = 4096;
714
 
   uint32_t pphwsp_addr = context_descriptor & 0xfffff000;
715
 
   struct intel_batch_decode_bo pphwsp_bo =
716
 
      aub_mem_get_ggtt_bo(&window->mem, pphwsp_addr);
717
 
   uint32_t *context_img = (uint32_t *)((uint8_t *)pphwsp_bo.map +
718
 
                                        (pphwsp_addr - pphwsp_bo.addr) +
719
 
                                        pphwsp_size);
720
 
 
721
 
   uint32_t ring_buffer_head = context_img[5];
722
 
   uint32_t ring_buffer_tail = context_img[7];
723
 
   uint32_t ring_buffer_start = context_img[9];
724
 
   uint32_t ring_buffer_length = (context_img[11] & 0x1ff000) + 4096;
725
 
 
726
 
   window->mem.pml4 = (uint64_t)context_img[49] << 32 | context_img[51];
727
 
 
728
 
   struct intel_batch_decode_bo ring_bo =
729
 
      aub_mem_get_ggtt_bo(&window->mem, ring_buffer_start);
730
 
   assert(ring_bo.size > 0);
731
 
   void *commands = (uint8_t *)ring_bo.map + (ring_buffer_start - ring_bo.addr) + ring_buffer_head;
732
 
 
733
 
   window->uses_ppgtt = true;
734
 
 
735
 
   window->decode_ctx.engine = engine;
736
 
   aub_viewer_render_batch(&window->decode_ctx, commands,
737
 
                           MIN2(ring_buffer_tail - ring_buffer_head, ring_buffer_length),
738
 
                           ring_buffer_start + ring_buffer_head, true);
739
 
}
740
 
 
741
 
static void
742
 
display_batch_window(struct window *win)
743
 
{
744
 
   struct batch_window *window = (struct batch_window *) win;
745
 
 
746
 
   ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() / (2 * 2));
747
 
   if (window_has_ctrl_key('f')) ImGui::SetKeyboardFocusHere();
748
 
   display_decode_options(&window->decode_cfg);
749
 
   ImGui::PopItemWidth();
750
 
 
751
 
   if (ImGui::InputInt("Execbuf", &window->exec_idx))
752
 
      update_batch_window(window, true, window->exec_idx);
753
 
 
754
 
   if (window_has_ctrl_key('p'))
755
 
      update_batch_window(window, true, window->exec_idx - 1);
756
 
   if (window_has_ctrl_key('n'))
757
 
      update_batch_window(window, true, window->exec_idx + 1);
758
 
 
759
 
   ImGui::Text("execbuf %i", window->exec_idx);
760
 
   if (ImGui::Button("Show PPGTT")) { show_pml4_window(&window->pml4_window, &window->mem); }
761
 
 
762
 
   ImGui::BeginChild(ImGui::GetID("##block"));
763
 
 
764
 
   struct aub_read read = {};
765
 
   read.user_data = window;
766
 
   read.ring_write = display_batch_ring_write;
767
 
   read.execlist_write = display_batch_execlist_write;
768
 
 
769
 
   const uint8_t *iter = context.file->execs[window->exec_idx].start;
770
 
   while (iter < context.file->execs[window->exec_idx].end) {
771
 
      iter += aub_read_command(&read, iter,
772
 
                               context.file->execs[window->exec_idx].end - iter);
773
 
   }
774
 
 
775
 
   ImGui::EndChild();
776
 
}
777
 
 
778
 
static void
779
 
destroy_batch_window(struct window *win)
780
 
{
781
 
   struct batch_window *window = (struct batch_window *) win;
782
 
 
783
 
   aub_mem_fini(&window->mem);
784
 
 
785
 
   /* This works because children windows are inserted at the back of the
786
 
    * list, ensuring the deletion loop goes through the children after calling
787
 
    * this function.
788
 
    */
789
 
   list_for_each_entry(struct window, child_window,
790
 
                       &window->base.children_windows, parent_link)
791
 
      child_window->opened = false;
792
 
   window->pml4_window.base.opened = false;
793
 
 
794
 
   free(window);
795
 
}
796
 
 
797
 
static void
798
 
new_batch_window(int exec_idx)
799
 
{
800
 
   struct batch_window *window = xtzalloc(*window);
801
 
 
802
 
   snprintf(window->base.name, sizeof(window->base.name),
803
 
            "Batch view##%p", window);
804
 
 
805
 
   list_inithead(&window->base.parent_link);
806
 
   list_inithead(&window->base.children_windows);
807
 
   window->base.position = ImVec2(-1, -1);
808
 
   window->base.size = ImVec2(600, 700);
809
 
   window->base.opened = true;
810
 
   window->base.display = display_batch_window;
811
 
   window->base.destroy = destroy_batch_window;
812
 
 
813
 
   window->collapsed = true;
814
 
   window->decode_cfg = aub_viewer_decode_cfg();
815
 
 
816
 
   aub_viewer_decode_ctx_init(&window->decode_ctx,
817
 
                              &context.cfg,
818
 
                              &window->decode_cfg,
819
 
                              &context.file->devinfo,
820
 
                              context.file->spec,
821
 
                              batch_get_bo,
822
 
                              NULL,
823
 
                              window);
824
 
   window->decode_ctx.display_shader = batch_display_shader;
825
 
   window->decode_ctx.display_urb = batch_display_urb;
826
 
   window->decode_ctx.edit_address = batch_edit_address;
827
 
 
828
 
   update_batch_window(window, false, exec_idx);
829
 
 
830
 
   list_addtail(&window->base.link, &context.windows);
831
 
}
832
 
 
833
 
/**/
834
 
 
835
 
static void
836
 
display_registers_window(struct window *win)
837
 
{
838
 
   static struct ImGuiTextFilter filter;
839
 
   if (window_has_ctrl_key('f')) ImGui::SetKeyboardFocusHere();
840
 
   filter.Draw();
841
 
 
842
 
   ImGui::BeginChild(ImGui::GetID("##block"));
843
 
   hash_table_foreach(context.file->spec->registers_by_name, entry) {
844
 
      struct intel_group *reg = (struct intel_group *) entry->data;
845
 
      if (filter.PassFilter(reg->name) &&
846
 
          ImGui::CollapsingHeader(reg->name)) {
847
 
         const struct intel_field *field = reg->fields;
848
 
         while (field) {
849
 
            ImGui::Text("%s : %i -> %i\n", field->name, field->start, field->end);
850
 
            field = field->next;
851
 
         }
852
 
      }
853
 
   }
854
 
   ImGui::EndChild();
855
 
}
856
 
 
857
 
static void
858
 
show_register_window(void)
859
 
{
860
 
   struct window *window = &context.registers_window;
861
 
 
862
 
   if (window->opened) {
863
 
      window->opened = false;
864
 
      return;
865
 
   }
866
 
 
867
 
   snprintf(window->name, sizeof(window->name), "Registers");
868
 
 
869
 
   list_inithead(&window->parent_link);
870
 
   window->position = ImVec2(-1, -1);
871
 
   window->size = ImVec2(200, 400);
872
 
   window->opened = true;
873
 
   window->display = display_registers_window;
874
 
   window->destroy = destroy_window_noop;
875
 
 
876
 
   list_addtail(&window->link, &context.windows);
877
 
}
878
 
 
879
 
static void
880
 
display_commands_window(struct window *win)
881
 
{
882
 
   static struct ImGuiTextFilter cmd_filter;
883
 
   if (window_has_ctrl_key('f')) ImGui::SetKeyboardFocusHere();
884
 
   cmd_filter.Draw("name filter");
885
 
   static struct ImGuiTextFilter field_filter;
886
 
   field_filter.Draw("field filter");
887
 
 
888
 
   static char opcode_str[9] = { 0, };
889
 
   ImGui::InputText("opcode filter", opcode_str, sizeof(opcode_str),
890
 
                    ImGuiInputTextFlags_CharsHexadecimal);
891
 
   size_t opcode_len = strlen(opcode_str);
892
 
   uint64_t opcode = strtol(opcode_str, NULL, 16);
893
 
 
894
 
   static bool show_dwords = true;
895
 
   if (ImGui::Button("Dwords")) show_dwords ^= 1;
896
 
 
897
 
   ImGui::BeginChild(ImGui::GetID("##block"));
898
 
   hash_table_foreach(context.file->spec->commands, entry) {
899
 
      struct intel_group *cmd = (struct intel_group *) entry->data;
900
 
      if ((cmd_filter.PassFilter(cmd->name) &&
901
 
           (opcode_len == 0 || (opcode & cmd->opcode_mask) == cmd->opcode)) &&
902
 
          ImGui::CollapsingHeader(cmd->name)) {
903
 
         const struct intel_field *field = cmd->fields;
904
 
         int32_t last_dword = -1;
905
 
         while (field) {
906
 
            if (show_dwords && field->start / 32 != last_dword) {
907
 
               for (last_dword = MAX2(0, last_dword + 1);
908
 
                    last_dword < field->start / 32; last_dword++) {
909
 
                  ImGui::TextColored(context.cfg.dwords_color,
910
 
                                     "Dword %d", last_dword);
911
 
               }
912
 
               ImGui::TextColored(context.cfg.dwords_color, "Dword %d", last_dword);
913
 
            }
914
 
            if (field_filter.PassFilter(field->name))
915
 
               ImGui::Text("%s : %i -> %i\n", field->name, field->start, field->end);
916
 
            field = field->next;
917
 
         }
918
 
      }
919
 
   }
920
 
   hash_table_foreach(context.file->spec->structs, entry) {
921
 
      struct intel_group *cmd = (struct intel_group *) entry->data;
922
 
      if (cmd_filter.PassFilter(cmd->name) && opcode_len == 0 &&
923
 
          ImGui::CollapsingHeader(cmd->name)) {
924
 
         const struct intel_field *field = cmd->fields;
925
 
         int32_t last_dword = -1;
926
 
         while (field) {
927
 
            if (show_dwords && field->start / 32 != last_dword) {
928
 
               last_dword = field->start / 32;
929
 
               ImGui::TextColored(context.cfg.dwords_color,
930
 
                                  "Dword %d", last_dword);
931
 
            }
932
 
            if (field_filter.PassFilter(field->name))
933
 
               ImGui::Text("%s : %i -> %i\n", field->name, field->start, field->end);
934
 
            field = field->next;
935
 
         }
936
 
      }
937
 
   }
938
 
   ImGui::EndChild();
939
 
}
940
 
 
941
 
static void
942
 
show_commands_window(void)
943
 
{
944
 
   struct window *window = &context.commands_window;
945
 
 
946
 
   if (window->opened) {
947
 
      window->opened = false;
948
 
      return;
949
 
   }
950
 
 
951
 
   snprintf(window->name, sizeof(window->name), "Commands & structs");
952
 
 
953
 
   list_inithead(&window->parent_link);
954
 
   window->position = ImVec2(-1, -1);
955
 
   window->size = ImVec2(300, 400);
956
 
   window->opened = true;
957
 
   window->display = display_commands_window;
958
 
   window->destroy = destroy_window_noop;
959
 
 
960
 
   list_addtail(&window->link, &context.windows);
961
 
}
962
 
 
963
 
/* Main window */
964
 
 
965
 
static const char *
966
 
human_size(size_t size)
967
 
{
968
 
   unsigned divisions = 0;
969
 
   double v = size;
970
 
   double divider = 1024;
971
 
   while (v >= divider) {
972
 
      v /= divider;
973
 
      divisions++;
974
 
   }
975
 
 
976
 
   static const char *units[] = { "Bytes", "Kilobytes", "Megabytes", "Gigabytes" };
977
 
   static char result[20];
978
 
   snprintf(result, sizeof(result), "%.2f %s",
979
 
            v, divisions >= ARRAY_SIZE(units) ? "Too much!" : units[divisions]);
980
 
   return result;
981
 
}
982
 
 
983
 
static void
984
 
display_aubfile_window(struct window *win)
985
 
{
986
 
   ImGuiColorEditFlags cflags = (ImGuiColorEditFlags_NoAlpha |
987
 
                                 ImGuiColorEditFlags_NoLabel |
988
 
                                 ImGuiColorEditFlags_NoInputs);
989
 
   struct aub_viewer_cfg *cfg = &context.cfg;
990
 
 
991
 
   ImGui::ColorEdit3("background", (float *)&cfg->clear_color, cflags); ImGui::SameLine();
992
 
   ImGui::ColorEdit3("missing", (float *)&cfg->missing_color, cflags); ImGui::SameLine();
993
 
   ImGui::ColorEdit3("error", (float *)&cfg->error_color, cflags); ImGui::SameLine();
994
 
   ImGui::ColorEdit3("highlight", (float *)&cfg->highlight_color, cflags); ImGui::SameLine();
995
 
   ImGui::ColorEdit3("dwords", (float *)&cfg->dwords_color, cflags); ImGui::SameLine();
996
 
   ImGui::ColorEdit3("booleans", (float *)&cfg->boolean_color, cflags); ImGui::SameLine();
997
 
 
998
 
   if (ImGui::Button("Commands list") || has_ctrl_key('c')) { show_commands_window(); } ImGui::SameLine();
999
 
   if (ImGui::Button("Registers list") || has_ctrl_key('r')) { show_register_window(); } ImGui::SameLine();
1000
 
   if (ImGui::Button("Help") || has_ctrl_key('h')) { ImGui::OpenPopup("Help"); }
1001
 
 
1002
 
   if (ImGui::Button("New batch window") || has_ctrl_key('b')) { new_batch_window(0); }
1003
 
 
1004
 
   ImGui::Text("File name:        %s", context.input_file);
1005
 
   ImGui::Text("File size:        %s", human_size(context.file->end - context.file->map));
1006
 
   ImGui::Text("Execbufs          %u", context.file->n_execs);
1007
 
   ImGui::Text("PCI ID:           0x%x", context.file->pci_id);
1008
 
   ImGui::Text("Application name: %s", context.file->app_name);
1009
 
   ImGui::Text("%s", context.file->devinfo.name);
1010
 
 
1011
 
   ImGui::SetNextWindowContentWidth(500);
1012
 
   if (ImGui::BeginPopupModal("Help", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
1013
 
      ImGui::Text("Some global keybindings:");
1014
 
      ImGui::Separator();
1015
 
 
1016
 
      static const char *texts[] = {
1017
 
         "Ctrl-h",          "show this screen",
1018
 
         "Ctrl-c",          "show commands list",
1019
 
         "Ctrl-r",          "show registers list",
1020
 
         "Ctrl-b",          "new batch window",
1021
 
         "Ctrl-p/n",        "switch to previous/next batch buffer",
1022
 
         "Ctrl-Tab",        "switch focus between window",
1023
 
         "Ctrl-left/right", "align window to the side of the screen",
1024
 
      };
1025
 
      float align = 0.0f;
1026
 
      for (uint32_t i = 0; i < ARRAY_SIZE(texts); i += 2)
1027
 
         align = MAX2(align, ImGui::CalcTextSize(texts[i]).x);
1028
 
      align += ImGui::GetStyle().WindowPadding.x + 10;
1029
 
 
1030
 
      for (uint32_t i = 0; i < ARRAY_SIZE(texts); i += 2) {
1031
 
         ImGui::Text("%s", texts[i]); ImGui::SameLine(align); ImGui::Text("%s", texts[i + 1]);
1032
 
      }
1033
 
 
1034
 
      if (ImGui::Button("Done") || ImGui::IsKeyPressed(ImGuiKey_Escape))
1035
 
         ImGui::CloseCurrentPopup();
1036
 
      ImGui::EndPopup();
1037
 
   }
1038
 
}
1039
 
 
1040
 
static void
1041
 
show_aubfile_window(void)
1042
 
{
1043
 
   struct window *window = &context.file_window;
1044
 
 
1045
 
   if (window->opened)
1046
 
      return;
1047
 
 
1048
 
   snprintf(window->name, sizeof(window->name),
1049
 
            "Aubinator Viewer: Intel AUB file decoder/editor");
1050
 
 
1051
 
   list_inithead(&window->parent_link);
1052
 
   window->size = ImVec2(-1, 250);
1053
 
   window->position = ImVec2(0, 0);
1054
 
   window->opened = true;
1055
 
   window->display = display_aubfile_window;
1056
 
   window->destroy = NULL;
1057
 
 
1058
 
   list_addtail(&window->link, &context.windows);
1059
 
}
1060
 
 
1061
 
/* Main redrawing */
1062
 
 
1063
 
static void
1064
 
display_windows(void)
1065
 
{
1066
 
   /* Start by disposing closed windows, we don't want to destroy windows that
1067
 
    * have already been scheduled to be painted. So destroy always happens on
1068
 
    * the next draw cycle, prior to any drawing.
1069
 
    */
1070
 
   list_for_each_entry_safe(struct window, window, &context.windows, link) {
1071
 
      if (window->opened)
1072
 
         continue;
1073
 
 
1074
 
      /* Can't close this one. */
1075
 
      if (window == &context.file_window) {
1076
 
         window->opened = true;
1077
 
         continue;
1078
 
      }
1079
 
 
1080
 
      list_del(&window->link);
1081
 
      list_del(&window->parent_link);
1082
 
      if (window->destroy)
1083
 
         window->destroy(window);
1084
 
   }
1085
 
 
1086
 
   list_for_each_entry_safe(struct window, window, &context.windows, link) {
1087
 
      ImGui::SetNextWindowPos(window->position, ImGuiCond_FirstUseEver);
1088
 
      ImGui::SetNextWindowSize(window->size, ImGuiCond_FirstUseEver);
1089
 
      if (ImGui::Begin(window->name, &window->opened)) {
1090
 
         window->display(window);
1091
 
         window->position = ImGui::GetWindowPos();
1092
 
         window->size = ImGui::GetWindowSize();
1093
 
      }
1094
 
      if (window_has_ctrl_key('w'))
1095
 
         window->opened = false;
1096
 
      ImGui::End();
1097
 
   }
1098
 
}
1099
 
 
1100
 
static void
1101
 
repaint_area(GtkGLArea *area, GdkGLContext *gdk_gl_context)
1102
 
{
1103
 
   ImGui_ImplOpenGL3_NewFrame();
1104
 
   ImGui_ImplGtk3_NewFrame();
1105
 
   ImGui::NewFrame();
1106
 
 
1107
 
   display_windows();
1108
 
 
1109
 
   ImGui::EndFrame();
1110
 
   ImGui::Render();
1111
 
 
1112
 
   glClearColor(context.cfg.clear_color.Value.x,
1113
 
                context.cfg.clear_color.Value.y,
1114
 
                context.cfg.clear_color.Value.z, 1.0);
1115
 
   glClear(GL_COLOR_BUFFER_BIT);
1116
 
   ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
1117
 
}
1118
 
 
1119
 
static void
1120
 
realize_area(GtkGLArea *area)
1121
 
{
1122
 
   ImGui::CreateContext();
1123
 
   ImGui_ImplGtk3_Init(GTK_WIDGET(area), true);
1124
 
   ImGui_ImplOpenGL3_Init("#version 130");
1125
 
 
1126
 
   list_inithead(&context.windows);
1127
 
 
1128
 
   ImGui::StyleColorsDark();
1129
 
   context.cfg = aub_viewer_cfg();
1130
 
 
1131
 
   ImGuiIO& io = ImGui::GetIO();
1132
 
   io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
1133
 
}
1134
 
 
1135
 
static void
1136
 
unrealize_area(GtkGLArea *area)
1137
 
{
1138
 
   gtk_gl_area_make_current(area);
1139
 
 
1140
 
   ImGui_ImplOpenGL3_Shutdown();
1141
 
   ImGui_ImplGtk3_Shutdown();
1142
 
   ImGui::DestroyContext();
1143
 
}
1144
 
 
1145
 
static void
1146
 
size_allocate_area(GtkGLArea *area,
1147
 
                   GdkRectangle *allocation,
1148
 
                   gpointer user_data)
1149
 
{
1150
 
   if (!gtk_widget_get_realized(GTK_WIDGET(area)))
1151
 
      return;
1152
 
 
1153
 
   /* We want to catch only initial size allocate. */
1154
 
   g_signal_handlers_disconnect_by_func(area,
1155
 
                                        (gpointer) size_allocate_area,
1156
 
                                        user_data);
1157
 
   show_aubfile_window();
1158
 
}
1159
 
 
1160
 
static void
1161
 
print_help(const char *progname, FILE *file)
1162
 
{
1163
 
   fprintf(file,
1164
 
           "Usage: %s [OPTION]... FILE\n"
1165
 
           "Decode aub file contents from FILE.\n\n"
1166
 
           "      --help             display this help and exit\n"
1167
 
           "  -x, --xml=DIR          load hardware xml description from directory DIR\n",
1168
 
           progname);
1169
 
}
1170
 
 
1171
 
int main(int argc, char *argv[])
1172
 
{
1173
 
   int c, i;
1174
 
   bool help = false;
1175
 
   const struct option aubinator_opts[] = {
1176
 
      { "help",          no_argument,       (int *) &help,                 true },
1177
 
      { "xml",           required_argument, NULL,                          'x' },
1178
 
      { NULL,            0,                 NULL,                          0 }
1179
 
   };
1180
 
 
1181
 
   memset(&context, 0, sizeof(context));
1182
 
 
1183
 
   i = 0;
1184
 
   while ((c = getopt_long(argc, argv, "x:s:", aubinator_opts, &i)) != -1) {
1185
 
      switch (c) {
1186
 
      case 'x':
1187
 
         context.xml_path = strdup(optarg);
1188
 
         break;
1189
 
      default:
1190
 
         break;
1191
 
      }
1192
 
   }
1193
 
 
1194
 
   if (optind < argc)
1195
 
      context.input_file = argv[optind];
1196
 
 
1197
 
   if (help || !context.input_file) {
1198
 
      print_help(argv[0], stderr);
1199
 
      exit(0);
1200
 
   }
1201
 
 
1202
 
   context.file = aub_file_open(context.input_file);
1203
 
 
1204
 
   gtk_init(NULL, NULL);
1205
 
 
1206
 
   context.gtk_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1207
 
   gtk_window_set_title(GTK_WINDOW(context.gtk_window), "Aubinator Viewer");
1208
 
   g_signal_connect(context.gtk_window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
1209
 
   gtk_window_resize(GTK_WINDOW(context.gtk_window), 1280, 720);
1210
 
 
1211
 
   GtkWidget* gl_area = gtk_gl_area_new();
1212
 
   g_signal_connect(gl_area, "render", G_CALLBACK(repaint_area), NULL);
1213
 
   g_signal_connect(gl_area, "realize", G_CALLBACK(realize_area), NULL);
1214
 
   g_signal_connect(gl_area, "unrealize", G_CALLBACK(unrealize_area), NULL);
1215
 
   g_signal_connect(gl_area, "size_allocate", G_CALLBACK(size_allocate_area), NULL);
1216
 
   gtk_container_add(GTK_CONTAINER(context.gtk_window), gl_area);
1217
 
 
1218
 
   gtk_widget_show_all(context.gtk_window);
1219
 
 
1220
 
   gtk_main();
1221
 
 
1222
 
   free(context.xml_path);
1223
 
 
1224
 
   return EXIT_SUCCESS;
1225
 
}