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