101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2016 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg#include <stdio.h>
2501e04c3fSmrg#include <stdlib.h>
2601e04c3fSmrg#include <stdint.h>
2701e04c3fSmrg#include <getopt.h>
2801e04c3fSmrg#include <unistd.h>
2901e04c3fSmrg#include <fcntl.h>
3001e04c3fSmrg#include <string.h>
3101e04c3fSmrg#include <errno.h>
3201e04c3fSmrg#include <sys/stat.h>
3301e04c3fSmrg#include <sys/mman.h>
3401e04c3fSmrg#include <sys/types.h>
3501e04c3fSmrg#include <ctype.h>
3601e04c3fSmrg
3701e04c3fSmrg#include "util/macros.h"
3801e04c3fSmrg
3901e04c3fSmrg#include "aub_read.h"
4001e04c3fSmrg#include "aub_mem.h"
4101e04c3fSmrg
427ec681f3Smrg#include "common/intel_disasm.h"
4301e04c3fSmrg
4401e04c3fSmrg#define xtzalloc(name) ((decltype(&name)) calloc(1, sizeof(name)))
4501e04c3fSmrg#define xtalloc(name) ((decltype(&name)) malloc(sizeof(name)))
4601e04c3fSmrg
4701e04c3fSmrgstruct aub_file {
4801e04c3fSmrg   uint8_t *map, *end, *cursor;
4901e04c3fSmrg
5001e04c3fSmrg   uint16_t pci_id;
5101e04c3fSmrg   char app_name[33];
5201e04c3fSmrg
5301e04c3fSmrg   /* List of batch buffers to process */
5401e04c3fSmrg   struct {
5501e04c3fSmrg      const uint8_t *start;
5601e04c3fSmrg      const uint8_t *end;
5701e04c3fSmrg   } *execs;
5801e04c3fSmrg   int n_execs;
5901e04c3fSmrg   int n_allocated_execs;
6001e04c3fSmrg
6101e04c3fSmrg   uint32_t idx_reg_write;
6201e04c3fSmrg
6301e04c3fSmrg   /* Device state */
647ec681f3Smrg   struct intel_device_info devinfo;
657ec681f3Smrg   struct intel_spec *spec;
6601e04c3fSmrg};
6701e04c3fSmrg
6801e04c3fSmrgstatic void
6901e04c3fSmrgstore_exec_begin(struct aub_file *file)
7001e04c3fSmrg{
7101e04c3fSmrg   if (unlikely(file->n_execs >= file->n_allocated_execs)) {
7201e04c3fSmrg      file->n_allocated_execs = MAX2(2U * file->n_allocated_execs,
7301e04c3fSmrg                                     4096 / sizeof(file->execs[0]));
7401e04c3fSmrg      file->execs = (decltype(file->execs))
7501e04c3fSmrg         realloc(static_cast<void *>(file->execs),
7601e04c3fSmrg                 file->n_allocated_execs * sizeof(file->execs[0]));
7701e04c3fSmrg   }
7801e04c3fSmrg
7901e04c3fSmrg   file->execs[file->n_execs++].start = file->cursor;
8001e04c3fSmrg}
8101e04c3fSmrg
8201e04c3fSmrgstatic void
8301e04c3fSmrgstore_exec_end(struct aub_file *file)
8401e04c3fSmrg{
8501e04c3fSmrg   if (file->n_execs > 0 && file->execs[file->n_execs - 1].end == NULL)
8601e04c3fSmrg      file->execs[file->n_execs - 1].end = file->cursor;
8701e04c3fSmrg}
8801e04c3fSmrg
8901e04c3fSmrgstatic void
9001e04c3fSmrghandle_mem_write(void *user_data, uint64_t phys_addr,
9101e04c3fSmrg                 const void *data, uint32_t data_len)
9201e04c3fSmrg{
9301e04c3fSmrg   struct aub_file *file = (struct aub_file *) user_data;
9401e04c3fSmrg   file->idx_reg_write = 0;
9501e04c3fSmrg   store_exec_end(file);
9601e04c3fSmrg}
9701e04c3fSmrg
9801e04c3fSmrgstatic void
999f464c52Smayahandle_ring_write(void *user_data, enum drm_i915_gem_engine_class engine,
10001e04c3fSmrg                  const void *ring_data, uint32_t ring_data_len)
10101e04c3fSmrg{
10201e04c3fSmrg   struct aub_file *file = (struct aub_file *) user_data;
10301e04c3fSmrg   file->idx_reg_write = 0;
10401e04c3fSmrg   store_exec_begin(file);
10501e04c3fSmrg}
10601e04c3fSmrg
10701e04c3fSmrgstatic void
10801e04c3fSmrghandle_reg_write(void *user_data, uint32_t reg_offset, uint32_t reg_value)
10901e04c3fSmrg{
11001e04c3fSmrg   struct aub_file *file = (struct aub_file *) user_data;
11101e04c3fSmrg
11201e04c3fSmrg   /* Only store the first register write of a series (execlist writes take
11301e04c3fSmrg    * involve 2 dwords).
11401e04c3fSmrg    */
11501e04c3fSmrg   if (file->idx_reg_write++ == 0)
11601e04c3fSmrg      store_exec_begin(file);
11701e04c3fSmrg}
11801e04c3fSmrg
11901e04c3fSmrgstatic void
12001e04c3fSmrghandle_info(void *user_data, int pci_id, const char *app_name)
12101e04c3fSmrg{
12201e04c3fSmrg   struct aub_file *file = (struct aub_file *) user_data;
12301e04c3fSmrg   store_exec_end(file);
12401e04c3fSmrg
12501e04c3fSmrg   file->pci_id = pci_id;
12601e04c3fSmrg   snprintf(file->app_name, sizeof(app_name), "%s", app_name);
12701e04c3fSmrg
1287ec681f3Smrg   if (!intel_get_device_info_from_pci_id(file->pci_id, &file->devinfo)) {
12901e04c3fSmrg      fprintf(stderr, "can't find device information: pci_id=0x%x\n", file->pci_id);
13001e04c3fSmrg      exit(EXIT_FAILURE);
13101e04c3fSmrg   }
1327ec681f3Smrg   file->spec = intel_spec_load(&file->devinfo);
13301e04c3fSmrg}
13401e04c3fSmrg
13501e04c3fSmrgstatic void
13601e04c3fSmrghandle_error(void *user_data, const void *aub_data, const char *msg)
13701e04c3fSmrg{
1387ec681f3Smrg   fprintf(stderr, "ERROR: %s", msg);
13901e04c3fSmrg}
14001e04c3fSmrg
14101e04c3fSmrgstatic struct aub_file *
14201e04c3fSmrgaub_file_open(const char *filename)
14301e04c3fSmrg{
14401e04c3fSmrg   struct aub_file *file;
14501e04c3fSmrg   struct stat sb;
14601e04c3fSmrg   int fd;
14701e04c3fSmrg
14801e04c3fSmrg   file = xtzalloc(*file);
14901e04c3fSmrg   fd = open(filename, O_RDWR);
15001e04c3fSmrg   if (fd == -1) {
15101e04c3fSmrg      fprintf(stderr, "open %s failed: %s\n", filename, strerror(errno));
15201e04c3fSmrg      exit(EXIT_FAILURE);
15301e04c3fSmrg   }
15401e04c3fSmrg
15501e04c3fSmrg   if (fstat(fd, &sb) == -1) {
15601e04c3fSmrg      fprintf(stderr, "stat failed: %s\n", strerror(errno));
15701e04c3fSmrg      exit(EXIT_FAILURE);
15801e04c3fSmrg   }
15901e04c3fSmrg
16001e04c3fSmrg   file->map = (uint8_t *) mmap(NULL, sb.st_size,
16101e04c3fSmrg                                PROT_READ, MAP_SHARED, fd, 0);
16201e04c3fSmrg   if (file->map == MAP_FAILED) {
16301e04c3fSmrg      fprintf(stderr, "mmap failed: %s\n", strerror(errno));
16401e04c3fSmrg      exit(EXIT_FAILURE);
16501e04c3fSmrg   }
16601e04c3fSmrg
16701e04c3fSmrg   close(fd);
16801e04c3fSmrg
16901e04c3fSmrg   file->cursor = file->map;
17001e04c3fSmrg   file->end = file->map + sb.st_size;
17101e04c3fSmrg
17201e04c3fSmrg   struct aub_read aub_read = {};
17301e04c3fSmrg   aub_read.user_data = file;
17401e04c3fSmrg   aub_read.info = handle_info;
17501e04c3fSmrg   aub_read.error = handle_error;
17601e04c3fSmrg   aub_read.reg_write = handle_reg_write;
17701e04c3fSmrg   aub_read.ring_write = handle_ring_write;
17801e04c3fSmrg   aub_read.local_write = handle_mem_write;
17901e04c3fSmrg   aub_read.phys_write = handle_mem_write;
18001e04c3fSmrg   aub_read.ggtt_write = handle_mem_write;
18101e04c3fSmrg   aub_read.ggtt_entry_write = handle_mem_write;
18201e04c3fSmrg
18301e04c3fSmrg   int consumed;
18401e04c3fSmrg   while (file->cursor < file->end &&
18501e04c3fSmrg          (consumed = aub_read_command(&aub_read, file->cursor,
18601e04c3fSmrg                                       file->end - file->cursor)) > 0) {
18701e04c3fSmrg      file->cursor += consumed;
18801e04c3fSmrg   }
18901e04c3fSmrg
19001e04c3fSmrg   /* Ensure we have an end on the last register write. */
19101e04c3fSmrg   if (file->n_execs > 0 && file->execs[file->n_execs - 1].end == NULL)
19201e04c3fSmrg      file->execs[file->n_execs - 1].end = file->end;
19301e04c3fSmrg
19401e04c3fSmrg   return file;
19501e04c3fSmrg}
19601e04c3fSmrg
19701e04c3fSmrg/**/
19801e04c3fSmrg
19901e04c3fSmrgstatic void
20001e04c3fSmrgupdate_mem_for_exec(struct aub_mem *mem, struct aub_file *file, int exec_idx)
20101e04c3fSmrg{
20201e04c3fSmrg   struct aub_read read = {};
20301e04c3fSmrg   read.user_data = mem;
20401e04c3fSmrg   read.local_write = aub_mem_local_write;
20501e04c3fSmrg   read.phys_write = aub_mem_phys_write;
20601e04c3fSmrg   read.ggtt_write = aub_mem_ggtt_write;
20701e04c3fSmrg   read.ggtt_entry_write = aub_mem_ggtt_entry_write;
20801e04c3fSmrg
20901e04c3fSmrg   /* Replay the aub file from the beginning up to just before the
21001e04c3fSmrg    * commands we want to read. where the context setup happens.
21101e04c3fSmrg    */
21201e04c3fSmrg   const uint8_t *iter = file->map;
21301e04c3fSmrg   while (iter < file->execs[exec_idx].start) {
21401e04c3fSmrg      iter += aub_read_command(&read, iter, file->execs[exec_idx].start - iter);
21501e04c3fSmrg   }
21601e04c3fSmrg}
21701e04c3fSmrg
21801e04c3fSmrg/* UI */
21901e04c3fSmrg
22001e04c3fSmrg#include <epoxy/gl.h>
22101e04c3fSmrg
2229f464c52Smaya#include "imgui/imgui.h"
2239f464c52Smaya#include "imgui/imgui_memory_editor.h"
22401e04c3fSmrg#include "imgui_impl_gtk3.h"
22501e04c3fSmrg#include "imgui_impl_opengl3.h"
22601e04c3fSmrg
22701e04c3fSmrg#include "aubinator_viewer.h"
22801e04c3fSmrg#include "aubinator_viewer_urb.h"
22901e04c3fSmrg
23001e04c3fSmrgstruct window {
23101e04c3fSmrg   struct list_head link; /* link in the global list of windows */
23201e04c3fSmrg   struct list_head parent_link; /* link in parent window list of children */
23301e04c3fSmrg
23401e04c3fSmrg   struct list_head children_windows; /* list of children windows */
23501e04c3fSmrg
23601e04c3fSmrg   char name[128];
23701e04c3fSmrg   bool opened;
23801e04c3fSmrg
23901e04c3fSmrg   ImVec2 position;
24001e04c3fSmrg   ImVec2 size;
24101e04c3fSmrg
24201e04c3fSmrg   void (*display)(struct window*);
24301e04c3fSmrg   void (*destroy)(struct window*);
24401e04c3fSmrg};
24501e04c3fSmrg
24601e04c3fSmrgstruct edit_window {
24701e04c3fSmrg   struct window base;
24801e04c3fSmrg
24901e04c3fSmrg   struct aub_mem *mem;
25001e04c3fSmrg   uint64_t address;
25101e04c3fSmrg   uint32_t len;
25201e04c3fSmrg
2537ec681f3Smrg   struct intel_batch_decode_bo aub_bo;
25401e04c3fSmrg   uint64_t aub_offset;
25501e04c3fSmrg
2567ec681f3Smrg   struct intel_batch_decode_bo gtt_bo;
25701e04c3fSmrg   uint64_t gtt_offset;
25801e04c3fSmrg
25901e04c3fSmrg   struct MemoryEditor editor;
26001e04c3fSmrg};
26101e04c3fSmrg
26201e04c3fSmrgstruct pml4_window {
26301e04c3fSmrg   struct window base;
26401e04c3fSmrg
26501e04c3fSmrg   struct aub_mem *mem;
26601e04c3fSmrg};
26701e04c3fSmrg
26801e04c3fSmrgstruct shader_window {
26901e04c3fSmrg   struct window base;
27001e04c3fSmrg
27101e04c3fSmrg   uint64_t address;
27201e04c3fSmrg   char *shader;
27301e04c3fSmrg   size_t shader_size;
27401e04c3fSmrg};
27501e04c3fSmrg
27601e04c3fSmrgstruct urb_window {
27701e04c3fSmrg   struct window base;
27801e04c3fSmrg
27901e04c3fSmrg   uint32_t end_urb_offset;
28001e04c3fSmrg   struct aub_decode_urb_stage_state urb_stages[AUB_DECODE_N_STAGE];
28101e04c3fSmrg
28201e04c3fSmrg   AubinatorViewerUrb urb_view;
28301e04c3fSmrg};
28401e04c3fSmrg
28501e04c3fSmrgstruct batch_window {
28601e04c3fSmrg   struct window base;
28701e04c3fSmrg
28801e04c3fSmrg   struct aub_mem mem;
28901e04c3fSmrg   struct aub_read read;
29001e04c3fSmrg
29101e04c3fSmrg   bool uses_ppgtt;
29201e04c3fSmrg
29301e04c3fSmrg   bool collapsed;
29401e04c3fSmrg   int exec_idx;
29501e04c3fSmrg
29601e04c3fSmrg   struct aub_viewer_decode_cfg decode_cfg;
29701e04c3fSmrg   struct aub_viewer_decode_ctx decode_ctx;
29801e04c3fSmrg
29901e04c3fSmrg   struct pml4_window pml4_window;
30001e04c3fSmrg
30101e04c3fSmrg   char edit_address[20];
30201e04c3fSmrg};
30301e04c3fSmrg
30401e04c3fSmrgstatic struct Context {
30501e04c3fSmrg   struct aub_file *file;
30601e04c3fSmrg   char *input_file;
30701e04c3fSmrg   char *xml_path;
30801e04c3fSmrg
30901e04c3fSmrg   GtkWidget *gtk_window;
31001e04c3fSmrg
31101e04c3fSmrg   /* UI state*/
31201e04c3fSmrg   bool show_commands_window;
31301e04c3fSmrg   bool show_registers_window;
31401e04c3fSmrg
31501e04c3fSmrg   struct aub_viewer_cfg cfg;
31601e04c3fSmrg
31701e04c3fSmrg   struct list_head windows;
31801e04c3fSmrg
31901e04c3fSmrg   struct window file_window;
32001e04c3fSmrg   struct window commands_window;
32101e04c3fSmrg   struct window registers_window;
32201e04c3fSmrg} context;
32301e04c3fSmrg
3249f464c52Smayathread_local ImGuiContext* __MesaImGui;
3259f464c52Smaya
32601e04c3fSmrgstatic int
32701e04c3fSmrgmap_key(int k)
32801e04c3fSmrg{
32901e04c3fSmrg   return ImGuiKey_COUNT + k;
33001e04c3fSmrg}
33101e04c3fSmrg
33201e04c3fSmrgstatic bool
33301e04c3fSmrghas_ctrl_key(int key)
33401e04c3fSmrg{
33501e04c3fSmrg   return ImGui::GetIO().KeyCtrl && ImGui::IsKeyPressed(map_key(key));
33601e04c3fSmrg}
33701e04c3fSmrg
33801e04c3fSmrgstatic bool
33901e04c3fSmrgwindow_has_ctrl_key(int key)
34001e04c3fSmrg{
34101e04c3fSmrg   return ImGui::IsRootWindowOrAnyChildFocused() && has_ctrl_key(key);
34201e04c3fSmrg}
34301e04c3fSmrg
34401e04c3fSmrgstatic void
34501e04c3fSmrgdestroy_window_noop(struct window *win)
34601e04c3fSmrg{
34701e04c3fSmrg}
34801e04c3fSmrg
34901e04c3fSmrg/* Shader windows */
35001e04c3fSmrg
35101e04c3fSmrgstatic void
35201e04c3fSmrgdisplay_shader_window(struct window *win)
35301e04c3fSmrg{
35401e04c3fSmrg   struct shader_window *window = (struct shader_window *) win;
35501e04c3fSmrg
35601e04c3fSmrg   if (window->shader) {
35701e04c3fSmrg      ImGui::InputTextMultiline("Assembly",
35801e04c3fSmrg                                window->shader, window->shader_size,
35901e04c3fSmrg                                ImGui::GetContentRegionAvail(),
36001e04c3fSmrg                                ImGuiInputTextFlags_ReadOnly);
36101e04c3fSmrg   } else {
36201e04c3fSmrg      ImGui::Text("Shader not available");
36301e04c3fSmrg   }
36401e04c3fSmrg}
36501e04c3fSmrg
36601e04c3fSmrgstatic void
36701e04c3fSmrgdestroy_shader_window(struct window *win)
36801e04c3fSmrg{
36901e04c3fSmrg   struct shader_window *window = (struct shader_window *) win;
37001e04c3fSmrg
37101e04c3fSmrg   free(window->shader);
37201e04c3fSmrg   free(window);
37301e04c3fSmrg}
37401e04c3fSmrg
37501e04c3fSmrgstatic struct shader_window *
37601e04c3fSmrgnew_shader_window(struct aub_mem *mem, uint64_t address, const char *desc)
37701e04c3fSmrg{
37801e04c3fSmrg   struct shader_window *window = xtzalloc(*window);
37901e04c3fSmrg
38001e04c3fSmrg   snprintf(window->base.name, sizeof(window->base.name),
3817ec681f3Smrg            "%s (0x%" PRIx64 ")##%p", desc, address, window);
38201e04c3fSmrg
38301e04c3fSmrg   list_inithead(&window->base.parent_link);
38401e04c3fSmrg   window->base.position = ImVec2(-1, -1);
38501e04c3fSmrg   window->base.size = ImVec2(700, 300);
38601e04c3fSmrg   window->base.opened = true;
38701e04c3fSmrg   window->base.display = display_shader_window;
38801e04c3fSmrg   window->base.destroy = destroy_shader_window;
38901e04c3fSmrg
3907ec681f3Smrg   struct intel_batch_decode_bo shader_bo =
3919f464c52Smaya      aub_mem_get_ppgtt_bo(mem, address);
39201e04c3fSmrg   if (shader_bo.map) {
39301e04c3fSmrg      FILE *f = open_memstream(&window->shader, &window->shader_size);
39401e04c3fSmrg      if (f) {
3957ec681f3Smrg         intel_disassemble(&context.file->devinfo,
3967ec681f3Smrg                           (const uint8_t *) shader_bo.map +
3977ec681f3Smrg                           (address - shader_bo.addr), 0, f);
39801e04c3fSmrg         fclose(f);
39901e04c3fSmrg      }
40001e04c3fSmrg   }
40101e04c3fSmrg
40201e04c3fSmrg   list_addtail(&window->base.link, &context.windows);
40301e04c3fSmrg
40401e04c3fSmrg   return window;
40501e04c3fSmrg}
40601e04c3fSmrg
40701e04c3fSmrg/* URB windows */
40801e04c3fSmrg
40901e04c3fSmrgstatic void
41001e04c3fSmrgdisplay_urb_window(struct window *win)
41101e04c3fSmrg{
41201e04c3fSmrg   struct urb_window *window = (struct urb_window *) win;
41301e04c3fSmrg   static const char *stages[] = {
41401e04c3fSmrg      [AUB_DECODE_STAGE_VS] = "VS",
41501e04c3fSmrg      [AUB_DECODE_STAGE_HS] = "HS",
41601e04c3fSmrg      [AUB_DECODE_STAGE_DS] = "DS",
41701e04c3fSmrg      [AUB_DECODE_STAGE_GS] = "GS",
41801e04c3fSmrg      [AUB_DECODE_STAGE_PS] = "PS",
41901e04c3fSmrg      [AUB_DECODE_STAGE_CS] = "CS",
42001e04c3fSmrg   };
42101e04c3fSmrg
42201e04c3fSmrg   ImGui::Text("URB allocation:");
42301e04c3fSmrg   window->urb_view.DrawAllocation("##urb",
42401e04c3fSmrg                                   ARRAY_SIZE(window->urb_stages),
42501e04c3fSmrg                                   window->end_urb_offset,
42601e04c3fSmrg                                   stages,
42701e04c3fSmrg                                   &window->urb_stages[0]);
42801e04c3fSmrg}
42901e04c3fSmrg
43001e04c3fSmrgstatic void
43101e04c3fSmrgdestroy_urb_window(struct window *win)
43201e04c3fSmrg{
43301e04c3fSmrg   struct urb_window *window = (struct urb_window *) win;
43401e04c3fSmrg
43501e04c3fSmrg   free(window);
43601e04c3fSmrg}
43701e04c3fSmrg
43801e04c3fSmrgstatic struct urb_window *
43901e04c3fSmrgnew_urb_window(struct aub_viewer_decode_ctx *decode_ctx, uint64_t address)
44001e04c3fSmrg{
44101e04c3fSmrg   struct urb_window *window = xtzalloc(*window);
44201e04c3fSmrg
44301e04c3fSmrg   snprintf(window->base.name, sizeof(window->base.name),
4447ec681f3Smrg            "URB view (0x%" PRIx64 ")##%p", address, window);
44501e04c3fSmrg
44601e04c3fSmrg   list_inithead(&window->base.parent_link);
44701e04c3fSmrg   window->base.position = ImVec2(-1, -1);
44801e04c3fSmrg   window->base.size = ImVec2(700, 300);
44901e04c3fSmrg   window->base.opened = true;
45001e04c3fSmrg   window->base.display = display_urb_window;
45101e04c3fSmrg   window->base.destroy = destroy_urb_window;
45201e04c3fSmrg
45301e04c3fSmrg   window->end_urb_offset = decode_ctx->end_urb_offset;
45401e04c3fSmrg   memcpy(window->urb_stages, decode_ctx->urb_stages, sizeof(window->urb_stages));
45501e04c3fSmrg   window->urb_view = AubinatorViewerUrb();
45601e04c3fSmrg
45701e04c3fSmrg   list_addtail(&window->base.link, &context.windows);
45801e04c3fSmrg
45901e04c3fSmrg   return window;
46001e04c3fSmrg}
46101e04c3fSmrg
46201e04c3fSmrg/* Memory editor windows */
46301e04c3fSmrg
46401e04c3fSmrgstatic uint8_t
46501e04c3fSmrgread_edit_window(const uint8_t *data, size_t off)
46601e04c3fSmrg{
46701e04c3fSmrg   struct edit_window *window = (struct edit_window *) data;
46801e04c3fSmrg
46901e04c3fSmrg   return *((const uint8_t *) window->gtt_bo.map + window->gtt_offset + off);
47001e04c3fSmrg}
47101e04c3fSmrg
47201e04c3fSmrgstatic void
47301e04c3fSmrgwrite_edit_window(uint8_t *data, size_t off, uint8_t d)
47401e04c3fSmrg{
47501e04c3fSmrg   struct edit_window *window = (struct edit_window *) data;
47601e04c3fSmrg   uint8_t *gtt = (uint8_t *) window->gtt_bo.map + window->gtt_offset + off;
47701e04c3fSmrg   uint8_t *aub = (uint8_t *) window->aub_bo.map + window->aub_offset + off;
47801e04c3fSmrg
47901e04c3fSmrg   *gtt = *aub = d;
48001e04c3fSmrg}
48101e04c3fSmrg
48201e04c3fSmrgstatic void
48301e04c3fSmrgdisplay_edit_window(struct window *win)
48401e04c3fSmrg{
48501e04c3fSmrg   struct edit_window *window = (struct edit_window *) win;
48601e04c3fSmrg
48701e04c3fSmrg   if (window->aub_bo.map && window->gtt_bo.map) {
48801e04c3fSmrg      ImGui::BeginChild(ImGui::GetID("##block"));
48901e04c3fSmrg      window->editor.DrawContents((uint8_t *) window,
49001e04c3fSmrg                                  MIN3(window->len,
49101e04c3fSmrg                                       window->gtt_bo.size - window->gtt_offset,
49201e04c3fSmrg                                       window->aub_bo.size - window->aub_offset),
49301e04c3fSmrg                                  window->address);
49401e04c3fSmrg      ImGui::EndChild();
49501e04c3fSmrg   } else {
4967ec681f3Smrg      ImGui::Text("Memory view at 0x%" PRIx64 " not available", window->address);
49701e04c3fSmrg   }
49801e04c3fSmrg}
49901e04c3fSmrg
50001e04c3fSmrgstatic void
50101e04c3fSmrgdestroy_edit_window(struct window *win)
50201e04c3fSmrg{
50301e04c3fSmrg   struct edit_window *window = (struct edit_window *) win;
50401e04c3fSmrg
50501e04c3fSmrg   if (window->aub_bo.map)
50601e04c3fSmrg      mprotect((void *) window->aub_bo.map, 4096, PROT_READ);
50701e04c3fSmrg   free(window);
50801e04c3fSmrg}
50901e04c3fSmrg
51001e04c3fSmrgstatic struct edit_window *
51101e04c3fSmrgnew_edit_window(struct aub_mem *mem, uint64_t address, uint32_t len)
51201e04c3fSmrg{
51301e04c3fSmrg   struct edit_window *window = xtzalloc(*window);
51401e04c3fSmrg
51501e04c3fSmrg   snprintf(window->base.name, sizeof(window->base.name),
5167ec681f3Smrg            "Editing aub at 0x%" PRIx64 "##%p", address, window);
51701e04c3fSmrg
51801e04c3fSmrg   list_inithead(&window->base.parent_link);
51901e04c3fSmrg   window->base.position = ImVec2(-1, -1);
52001e04c3fSmrg   window->base.size = ImVec2(500, 600);
52101e04c3fSmrg   window->base.opened = true;
52201e04c3fSmrg   window->base.display = display_edit_window;
52301e04c3fSmrg   window->base.destroy = destroy_edit_window;
52401e04c3fSmrg
52501e04c3fSmrg   window->mem = mem;
52601e04c3fSmrg   window->address = address;
52701e04c3fSmrg   window->aub_bo = aub_mem_get_ppgtt_addr_aub_data(mem, address);
52801e04c3fSmrg   window->gtt_bo = aub_mem_get_ppgtt_addr_data(mem, address);
52901e04c3fSmrg   window->len = len;
53001e04c3fSmrg   window->editor = MemoryEditor();
53101e04c3fSmrg   window->editor.OptShowDataPreview = true;
53201e04c3fSmrg   window->editor.OptShowAscii = false;
53301e04c3fSmrg   window->editor.ReadFn = read_edit_window;
53401e04c3fSmrg   window->editor.WriteFn = write_edit_window;
53501e04c3fSmrg
53601e04c3fSmrg   if (window->aub_bo.map) {
53701e04c3fSmrg      uint64_t unaligned_map = (uint64_t) window->aub_bo.map;
53801e04c3fSmrg      window->aub_bo.map = (const void *)(unaligned_map & ~0xffful);
53901e04c3fSmrg      window->aub_offset = unaligned_map - (uint64_t) window->aub_bo.map;
54001e04c3fSmrg
54101e04c3fSmrg      if (mprotect((void *) window->aub_bo.map, window->aub_bo.size, PROT_READ | PROT_WRITE) != 0) {
54201e04c3fSmrg         window->aub_bo.map = NULL;
54301e04c3fSmrg      }
54401e04c3fSmrg   }
54501e04c3fSmrg
54601e04c3fSmrg   window->gtt_offset = address - window->gtt_bo.addr;
54701e04c3fSmrg
54801e04c3fSmrg   list_addtail(&window->base.link, &context.windows);
54901e04c3fSmrg
55001e04c3fSmrg   return window;
55101e04c3fSmrg}
55201e04c3fSmrg
55301e04c3fSmrg/* 4 level page table walk windows */
55401e04c3fSmrg
55501e04c3fSmrgstatic void
55601e04c3fSmrgdisplay_pml4_level(struct aub_mem *mem, uint64_t table_addr, uint64_t table_virt_addr, int level)
55701e04c3fSmrg{
55801e04c3fSmrg   if (level == 0)
55901e04c3fSmrg      return;
56001e04c3fSmrg
5617ec681f3Smrg   struct intel_batch_decode_bo table_bo =
56201e04c3fSmrg      aub_mem_get_phys_addr_data(mem, table_addr);
56301e04c3fSmrg   const uint64_t *table = (const uint64_t *) ((const uint8_t *) table_bo.map +
56401e04c3fSmrg                                               table_addr - table_bo.addr);
56501e04c3fSmrg   if (!table) {
56601e04c3fSmrg      ImGui::TextColored(context.cfg.missing_color, "Page not available");
56701e04c3fSmrg      return;
56801e04c3fSmrg   }
56901e04c3fSmrg
57001e04c3fSmrg   uint64_t addr_increment = 1ULL << (12 + 9 * (level - 1));
57101e04c3fSmrg
57201e04c3fSmrg   if (level == 1) {
57301e04c3fSmrg      for (int e = 0; e < 512; e++) {
57401e04c3fSmrg         bool available = (table[e] & 1) != 0;
57501e04c3fSmrg         uint64_t entry_virt_addr = table_virt_addr + e * addr_increment;
57601e04c3fSmrg         if (!available)
57701e04c3fSmrg            continue;
5787ec681f3Smrg         ImGui::Text("Entry%03i - phys_addr=0x%" PRIx64 " - virt_addr=0x%" PRIx64,
57901e04c3fSmrg                     e, table[e], entry_virt_addr);
58001e04c3fSmrg      }
58101e04c3fSmrg   } else {
58201e04c3fSmrg      for (int e = 0; e < 512; e++) {
58301e04c3fSmrg         bool available = (table[e] & 1) != 0;
58401e04c3fSmrg         uint64_t entry_virt_addr = table_virt_addr + e * addr_increment;
58501e04c3fSmrg         if (available &&
58601e04c3fSmrg             ImGui::TreeNodeEx(&table[e],
58701e04c3fSmrg                               available ? ImGuiTreeNodeFlags_Framed : 0,
5887ec681f3Smrg                               "Entry%03i - phys_addr=0x%" PRIx64 " - virt_addr=0x%" PRIx64,
58901e04c3fSmrg                               e, table[e], entry_virt_addr)) {
59001e04c3fSmrg            display_pml4_level(mem, table[e] & ~0xffful, entry_virt_addr, level -1);
59101e04c3fSmrg            ImGui::TreePop();
59201e04c3fSmrg         }
59301e04c3fSmrg      }
59401e04c3fSmrg   }
59501e04c3fSmrg}
59601e04c3fSmrg
59701e04c3fSmrgstatic void
59801e04c3fSmrgdisplay_pml4_window(struct window *win)
59901e04c3fSmrg{
60001e04c3fSmrg   struct pml4_window *window = (struct pml4_window *) win;
60101e04c3fSmrg
6027ec681f3Smrg   ImGui::Text("pml4: %" PRIx64, window->mem->pml4);
60301e04c3fSmrg   ImGui::BeginChild(ImGui::GetID("##block"));
60401e04c3fSmrg   display_pml4_level(window->mem, window->mem->pml4, 0, 4);
60501e04c3fSmrg   ImGui::EndChild();
60601e04c3fSmrg}
60701e04c3fSmrg
60801e04c3fSmrgstatic void
60901e04c3fSmrgshow_pml4_window(struct pml4_window *window, struct aub_mem *mem)
61001e04c3fSmrg{
61101e04c3fSmrg   if (window->base.opened) {
61201e04c3fSmrg      window->base.opened = false;
61301e04c3fSmrg      return;
61401e04c3fSmrg   }
61501e04c3fSmrg
61601e04c3fSmrg   snprintf(window->base.name, sizeof(window->base.name),
61701e04c3fSmrg            "4-Level page tables##%p", window);
61801e04c3fSmrg
61901e04c3fSmrg   list_inithead(&window->base.parent_link);
62001e04c3fSmrg   window->base.position = ImVec2(-1, -1);
62101e04c3fSmrg   window->base.size = ImVec2(500, 600);
62201e04c3fSmrg   window->base.opened = true;
62301e04c3fSmrg   window->base.display = display_pml4_window;
62401e04c3fSmrg   window->base.destroy = destroy_window_noop;
62501e04c3fSmrg
62601e04c3fSmrg   window->mem = mem;
62701e04c3fSmrg
62801e04c3fSmrg   list_addtail(&window->base.link, &context.windows);
62901e04c3fSmrg}
63001e04c3fSmrg
63101e04c3fSmrg/* Batch decoding windows */
63201e04c3fSmrg
63301e04c3fSmrgstatic void
63401e04c3fSmrgdisplay_decode_options(struct aub_viewer_decode_cfg *cfg)
63501e04c3fSmrg{
63601e04c3fSmrg   char name[40];
63701e04c3fSmrg   snprintf(name, sizeof(name), "command filter##%p", &cfg->command_filter);
63801e04c3fSmrg   cfg->command_filter.Draw(name); ImGui::SameLine();
63901e04c3fSmrg   snprintf(name, sizeof(name), "field filter##%p", &cfg->field_filter);
64001e04c3fSmrg   cfg->field_filter.Draw(name); ImGui::SameLine();
64101e04c3fSmrg   if (ImGui::Button("Dwords")) cfg->show_dwords ^= 1;
64201e04c3fSmrg}
64301e04c3fSmrg
64401e04c3fSmrgstatic void
64501e04c3fSmrgbatch_display_shader(void *user_data, const char *shader_desc, uint64_t address)
64601e04c3fSmrg{
64701e04c3fSmrg   struct batch_window *window = (struct batch_window *) user_data;
64801e04c3fSmrg   struct shader_window *shader_window =
64901e04c3fSmrg      new_shader_window(&window->mem, address, shader_desc);
65001e04c3fSmrg
65101e04c3fSmrg   list_add(&shader_window->base.parent_link, &window->base.children_windows);
65201e04c3fSmrg}
65301e04c3fSmrg
65401e04c3fSmrgstatic void
65501e04c3fSmrgbatch_display_urb(void *user_data, const struct aub_decode_urb_stage_state *stages)
65601e04c3fSmrg{
65701e04c3fSmrg   struct batch_window *window = (struct batch_window *) user_data;
65801e04c3fSmrg   struct urb_window *urb_window = new_urb_window(&window->decode_ctx, 0);
65901e04c3fSmrg
66001e04c3fSmrg   list_add(&urb_window->base.parent_link, &window->base.children_windows);
66101e04c3fSmrg}
66201e04c3fSmrg
66301e04c3fSmrgstatic void
66401e04c3fSmrgbatch_edit_address(void *user_data, uint64_t address, uint32_t len)
66501e04c3fSmrg{
66601e04c3fSmrg   struct batch_window *window = (struct batch_window *) user_data;
66701e04c3fSmrg   struct edit_window *edit_window =
66801e04c3fSmrg      new_edit_window(&window->mem, address, len);
66901e04c3fSmrg
67001e04c3fSmrg   list_add(&edit_window->base.parent_link, &window->base.children_windows);
67101e04c3fSmrg}
67201e04c3fSmrg
6737ec681f3Smrgstatic struct intel_batch_decode_bo
6749f464c52Smayabatch_get_bo(void *user_data, bool ppgtt, uint64_t address)
67501e04c3fSmrg{
67601e04c3fSmrg   struct batch_window *window = (struct batch_window *) user_data;
67701e04c3fSmrg
6789f464c52Smaya   if (window->uses_ppgtt && ppgtt)
67901e04c3fSmrg      return aub_mem_get_ppgtt_bo(&window->mem, address);
68001e04c3fSmrg   else
68101e04c3fSmrg      return aub_mem_get_ggtt_bo(&window->mem, address);
68201e04c3fSmrg}
68301e04c3fSmrg
68401e04c3fSmrgstatic void
68501e04c3fSmrgupdate_batch_window(struct batch_window *window, bool reset, int exec_idx)
68601e04c3fSmrg{
68701e04c3fSmrg   if (reset)
68801e04c3fSmrg      aub_mem_fini(&window->mem);
68901e04c3fSmrg   aub_mem_init(&window->mem);
69001e04c3fSmrg
69101e04c3fSmrg   window->exec_idx = MAX2(MIN2(context.file->n_execs - 1, exec_idx), 0);
69201e04c3fSmrg   update_mem_for_exec(&window->mem, context.file, window->exec_idx);
69301e04c3fSmrg}
69401e04c3fSmrg
69501e04c3fSmrgstatic void
6969f464c52Smayadisplay_batch_ring_write(void *user_data, enum drm_i915_gem_engine_class engine,
69701e04c3fSmrg                         const void *data, uint32_t data_len)
69801e04c3fSmrg{
69901e04c3fSmrg   struct batch_window *window = (struct batch_window *) user_data;
70001e04c3fSmrg
70101e04c3fSmrg   window->uses_ppgtt = false;
70201e04c3fSmrg
7039f464c52Smaya   aub_viewer_render_batch(&window->decode_ctx, data, data_len, 0, false);
70401e04c3fSmrg}
70501e04c3fSmrg
70601e04c3fSmrgstatic void
7079f464c52Smayadisplay_batch_execlist_write(void *user_data,
7089f464c52Smaya                             enum drm_i915_gem_engine_class engine,
70901e04c3fSmrg                             uint64_t context_descriptor)
71001e04c3fSmrg{
71101e04c3fSmrg   struct batch_window *window = (struct batch_window *) user_data;
71201e04c3fSmrg
71301e04c3fSmrg   const uint32_t pphwsp_size = 4096;
71401e04c3fSmrg   uint32_t pphwsp_addr = context_descriptor & 0xfffff000;
7157ec681f3Smrg   struct intel_batch_decode_bo pphwsp_bo =
71601e04c3fSmrg      aub_mem_get_ggtt_bo(&window->mem, pphwsp_addr);
71701e04c3fSmrg   uint32_t *context_img = (uint32_t *)((uint8_t *)pphwsp_bo.map +
71801e04c3fSmrg                                        (pphwsp_addr - pphwsp_bo.addr) +
71901e04c3fSmrg                                        pphwsp_size);
72001e04c3fSmrg
72101e04c3fSmrg   uint32_t ring_buffer_head = context_img[5];
72201e04c3fSmrg   uint32_t ring_buffer_tail = context_img[7];
72301e04c3fSmrg   uint32_t ring_buffer_start = context_img[9];
7249f464c52Smaya   uint32_t ring_buffer_length = (context_img[11] & 0x1ff000) + 4096;
72501e04c3fSmrg
72601e04c3fSmrg   window->mem.pml4 = (uint64_t)context_img[49] << 32 | context_img[51];
72701e04c3fSmrg
7287ec681f3Smrg   struct intel_batch_decode_bo ring_bo =
72901e04c3fSmrg      aub_mem_get_ggtt_bo(&window->mem, ring_buffer_start);
73001e04c3fSmrg   assert(ring_bo.size > 0);
7319f464c52Smaya   void *commands = (uint8_t *)ring_bo.map + (ring_buffer_start - ring_bo.addr) + ring_buffer_head;
73201e04c3fSmrg
73301e04c3fSmrg   window->uses_ppgtt = true;
73401e04c3fSmrg
7359f464c52Smaya   window->decode_ctx.engine = engine;
73601e04c3fSmrg   aub_viewer_render_batch(&window->decode_ctx, commands,
7379f464c52Smaya                           MIN2(ring_buffer_tail - ring_buffer_head, ring_buffer_length),
7389f464c52Smaya                           ring_buffer_start + ring_buffer_head, true);
73901e04c3fSmrg}
74001e04c3fSmrg
74101e04c3fSmrgstatic void
74201e04c3fSmrgdisplay_batch_window(struct window *win)
74301e04c3fSmrg{
74401e04c3fSmrg   struct batch_window *window = (struct batch_window *) win;
74501e04c3fSmrg
74601e04c3fSmrg   ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() / (2 * 2));
74701e04c3fSmrg   if (window_has_ctrl_key('f')) ImGui::SetKeyboardFocusHere();
74801e04c3fSmrg   display_decode_options(&window->decode_cfg);
74901e04c3fSmrg   ImGui::PopItemWidth();
75001e04c3fSmrg
75101e04c3fSmrg   if (ImGui::InputInt("Execbuf", &window->exec_idx))
75201e04c3fSmrg      update_batch_window(window, true, window->exec_idx);
75301e04c3fSmrg
75401e04c3fSmrg   if (window_has_ctrl_key('p'))
75501e04c3fSmrg      update_batch_window(window, true, window->exec_idx - 1);
75601e04c3fSmrg   if (window_has_ctrl_key('n'))
75701e04c3fSmrg      update_batch_window(window, true, window->exec_idx + 1);
75801e04c3fSmrg
75901e04c3fSmrg   ImGui::Text("execbuf %i", window->exec_idx);
76001e04c3fSmrg   if (ImGui::Button("Show PPGTT")) { show_pml4_window(&window->pml4_window, &window->mem); }
76101e04c3fSmrg
76201e04c3fSmrg   ImGui::BeginChild(ImGui::GetID("##block"));
76301e04c3fSmrg
76401e04c3fSmrg   struct aub_read read = {};
76501e04c3fSmrg   read.user_data = window;
76601e04c3fSmrg   read.ring_write = display_batch_ring_write;
76701e04c3fSmrg   read.execlist_write = display_batch_execlist_write;
76801e04c3fSmrg
76901e04c3fSmrg   const uint8_t *iter = context.file->execs[window->exec_idx].start;
77001e04c3fSmrg   while (iter < context.file->execs[window->exec_idx].end) {
77101e04c3fSmrg      iter += aub_read_command(&read, iter,
77201e04c3fSmrg                               context.file->execs[window->exec_idx].end - iter);
77301e04c3fSmrg   }
77401e04c3fSmrg
77501e04c3fSmrg   ImGui::EndChild();
77601e04c3fSmrg}
77701e04c3fSmrg
77801e04c3fSmrgstatic void
77901e04c3fSmrgdestroy_batch_window(struct window *win)
78001e04c3fSmrg{
78101e04c3fSmrg   struct batch_window *window = (struct batch_window *) win;
78201e04c3fSmrg
78301e04c3fSmrg   aub_mem_fini(&window->mem);
78401e04c3fSmrg
78501e04c3fSmrg   /* This works because children windows are inserted at the back of the
78601e04c3fSmrg    * list, ensuring the deletion loop goes through the children after calling
78701e04c3fSmrg    * this function.
78801e04c3fSmrg    */
78901e04c3fSmrg   list_for_each_entry(struct window, child_window,
79001e04c3fSmrg                       &window->base.children_windows, parent_link)
79101e04c3fSmrg      child_window->opened = false;
79201e04c3fSmrg   window->pml4_window.base.opened = false;
79301e04c3fSmrg
79401e04c3fSmrg   free(window);
79501e04c3fSmrg}
79601e04c3fSmrg
79701e04c3fSmrgstatic void
79801e04c3fSmrgnew_batch_window(int exec_idx)
79901e04c3fSmrg{
80001e04c3fSmrg   struct batch_window *window = xtzalloc(*window);
80101e04c3fSmrg
80201e04c3fSmrg   snprintf(window->base.name, sizeof(window->base.name),
80301e04c3fSmrg            "Batch view##%p", window);
80401e04c3fSmrg
80501e04c3fSmrg   list_inithead(&window->base.parent_link);
80601e04c3fSmrg   list_inithead(&window->base.children_windows);
80701e04c3fSmrg   window->base.position = ImVec2(-1, -1);
80801e04c3fSmrg   window->base.size = ImVec2(600, 700);
80901e04c3fSmrg   window->base.opened = true;
81001e04c3fSmrg   window->base.display = display_batch_window;
81101e04c3fSmrg   window->base.destroy = destroy_batch_window;
81201e04c3fSmrg
81301e04c3fSmrg   window->collapsed = true;
81401e04c3fSmrg   window->decode_cfg = aub_viewer_decode_cfg();
81501e04c3fSmrg
81601e04c3fSmrg   aub_viewer_decode_ctx_init(&window->decode_ctx,
81701e04c3fSmrg                              &context.cfg,
81801e04c3fSmrg                              &window->decode_cfg,
8197ec681f3Smrg                              &context.file->devinfo,
82001e04c3fSmrg                              context.file->spec,
82101e04c3fSmrg                              batch_get_bo,
82201e04c3fSmrg                              NULL,
82301e04c3fSmrg                              window);
82401e04c3fSmrg   window->decode_ctx.display_shader = batch_display_shader;
82501e04c3fSmrg   window->decode_ctx.display_urb = batch_display_urb;
82601e04c3fSmrg   window->decode_ctx.edit_address = batch_edit_address;
82701e04c3fSmrg
82801e04c3fSmrg   update_batch_window(window, false, exec_idx);
82901e04c3fSmrg
83001e04c3fSmrg   list_addtail(&window->base.link, &context.windows);
83101e04c3fSmrg}
83201e04c3fSmrg
83301e04c3fSmrg/**/
83401e04c3fSmrg
83501e04c3fSmrgstatic void
83601e04c3fSmrgdisplay_registers_window(struct window *win)
83701e04c3fSmrg{
83801e04c3fSmrg   static struct ImGuiTextFilter filter;
83901e04c3fSmrg   if (window_has_ctrl_key('f')) ImGui::SetKeyboardFocusHere();
84001e04c3fSmrg   filter.Draw();
84101e04c3fSmrg
84201e04c3fSmrg   ImGui::BeginChild(ImGui::GetID("##block"));
84301e04c3fSmrg   hash_table_foreach(context.file->spec->registers_by_name, entry) {
8447ec681f3Smrg      struct intel_group *reg = (struct intel_group *) entry->data;
84501e04c3fSmrg      if (filter.PassFilter(reg->name) &&
84601e04c3fSmrg          ImGui::CollapsingHeader(reg->name)) {
8477ec681f3Smrg         const struct intel_field *field = reg->fields;
84801e04c3fSmrg         while (field) {
84901e04c3fSmrg            ImGui::Text("%s : %i -> %i\n", field->name, field->start, field->end);
85001e04c3fSmrg            field = field->next;
85101e04c3fSmrg         }
85201e04c3fSmrg      }
85301e04c3fSmrg   }
85401e04c3fSmrg   ImGui::EndChild();
85501e04c3fSmrg}
85601e04c3fSmrg
85701e04c3fSmrgstatic void
85801e04c3fSmrgshow_register_window(void)
85901e04c3fSmrg{
86001e04c3fSmrg   struct window *window = &context.registers_window;
86101e04c3fSmrg
86201e04c3fSmrg   if (window->opened) {
86301e04c3fSmrg      window->opened = false;
86401e04c3fSmrg      return;
86501e04c3fSmrg   }
86601e04c3fSmrg
86701e04c3fSmrg   snprintf(window->name, sizeof(window->name), "Registers");
86801e04c3fSmrg
86901e04c3fSmrg   list_inithead(&window->parent_link);
87001e04c3fSmrg   window->position = ImVec2(-1, -1);
87101e04c3fSmrg   window->size = ImVec2(200, 400);
87201e04c3fSmrg   window->opened = true;
87301e04c3fSmrg   window->display = display_registers_window;
87401e04c3fSmrg   window->destroy = destroy_window_noop;
87501e04c3fSmrg
87601e04c3fSmrg   list_addtail(&window->link, &context.windows);
87701e04c3fSmrg}
87801e04c3fSmrg
87901e04c3fSmrgstatic void
88001e04c3fSmrgdisplay_commands_window(struct window *win)
88101e04c3fSmrg{
88201e04c3fSmrg   static struct ImGuiTextFilter cmd_filter;
88301e04c3fSmrg   if (window_has_ctrl_key('f')) ImGui::SetKeyboardFocusHere();
88401e04c3fSmrg   cmd_filter.Draw("name filter");
88501e04c3fSmrg   static struct ImGuiTextFilter field_filter;
88601e04c3fSmrg   field_filter.Draw("field filter");
88701e04c3fSmrg
88801e04c3fSmrg   static char opcode_str[9] = { 0, };
88901e04c3fSmrg   ImGui::InputText("opcode filter", opcode_str, sizeof(opcode_str),
89001e04c3fSmrg                    ImGuiInputTextFlags_CharsHexadecimal);
89101e04c3fSmrg   size_t opcode_len = strlen(opcode_str);
89201e04c3fSmrg   uint64_t opcode = strtol(opcode_str, NULL, 16);
89301e04c3fSmrg
89401e04c3fSmrg   static bool show_dwords = true;
89501e04c3fSmrg   if (ImGui::Button("Dwords")) show_dwords ^= 1;
89601e04c3fSmrg
89701e04c3fSmrg   ImGui::BeginChild(ImGui::GetID("##block"));
89801e04c3fSmrg   hash_table_foreach(context.file->spec->commands, entry) {
8997ec681f3Smrg      struct intel_group *cmd = (struct intel_group *) entry->data;
90001e04c3fSmrg      if ((cmd_filter.PassFilter(cmd->name) &&
90101e04c3fSmrg           (opcode_len == 0 || (opcode & cmd->opcode_mask) == cmd->opcode)) &&
90201e04c3fSmrg          ImGui::CollapsingHeader(cmd->name)) {
9037ec681f3Smrg         const struct intel_field *field = cmd->fields;
90401e04c3fSmrg         int32_t last_dword = -1;
90501e04c3fSmrg         while (field) {
90601e04c3fSmrg            if (show_dwords && field->start / 32 != last_dword) {
90701e04c3fSmrg               for (last_dword = MAX2(0, last_dword + 1);
90801e04c3fSmrg                    last_dword < field->start / 32; last_dword++) {
90901e04c3fSmrg                  ImGui::TextColored(context.cfg.dwords_color,
91001e04c3fSmrg                                     "Dword %d", last_dword);
91101e04c3fSmrg               }
91201e04c3fSmrg               ImGui::TextColored(context.cfg.dwords_color, "Dword %d", last_dword);
91301e04c3fSmrg            }
91401e04c3fSmrg            if (field_filter.PassFilter(field->name))
91501e04c3fSmrg               ImGui::Text("%s : %i -> %i\n", field->name, field->start, field->end);
91601e04c3fSmrg            field = field->next;
91701e04c3fSmrg         }
91801e04c3fSmrg      }
91901e04c3fSmrg   }
92001e04c3fSmrg   hash_table_foreach(context.file->spec->structs, entry) {
9217ec681f3Smrg      struct intel_group *cmd = (struct intel_group *) entry->data;
92201e04c3fSmrg      if (cmd_filter.PassFilter(cmd->name) && opcode_len == 0 &&
92301e04c3fSmrg          ImGui::CollapsingHeader(cmd->name)) {
9247ec681f3Smrg         const struct intel_field *field = cmd->fields;
92501e04c3fSmrg         int32_t last_dword = -1;
92601e04c3fSmrg         while (field) {
92701e04c3fSmrg            if (show_dwords && field->start / 32 != last_dword) {
92801e04c3fSmrg               last_dword = field->start / 32;
92901e04c3fSmrg               ImGui::TextColored(context.cfg.dwords_color,
93001e04c3fSmrg                                  "Dword %d", last_dword);
93101e04c3fSmrg            }
93201e04c3fSmrg            if (field_filter.PassFilter(field->name))
93301e04c3fSmrg               ImGui::Text("%s : %i -> %i\n", field->name, field->start, field->end);
93401e04c3fSmrg            field = field->next;
93501e04c3fSmrg         }
93601e04c3fSmrg      }
93701e04c3fSmrg   }
93801e04c3fSmrg   ImGui::EndChild();
93901e04c3fSmrg}
94001e04c3fSmrg
94101e04c3fSmrgstatic void
94201e04c3fSmrgshow_commands_window(void)
94301e04c3fSmrg{
94401e04c3fSmrg   struct window *window = &context.commands_window;
94501e04c3fSmrg
94601e04c3fSmrg   if (window->opened) {
94701e04c3fSmrg      window->opened = false;
94801e04c3fSmrg      return;
94901e04c3fSmrg   }
95001e04c3fSmrg
95101e04c3fSmrg   snprintf(window->name, sizeof(window->name), "Commands & structs");
95201e04c3fSmrg
95301e04c3fSmrg   list_inithead(&window->parent_link);
95401e04c3fSmrg   window->position = ImVec2(-1, -1);
95501e04c3fSmrg   window->size = ImVec2(300, 400);
95601e04c3fSmrg   window->opened = true;
95701e04c3fSmrg   window->display = display_commands_window;
95801e04c3fSmrg   window->destroy = destroy_window_noop;
95901e04c3fSmrg
96001e04c3fSmrg   list_addtail(&window->link, &context.windows);
96101e04c3fSmrg}
96201e04c3fSmrg
96301e04c3fSmrg/* Main window */
96401e04c3fSmrg
96501e04c3fSmrgstatic const char *
96601e04c3fSmrghuman_size(size_t size)
96701e04c3fSmrg{
96801e04c3fSmrg   unsigned divisions = 0;
96901e04c3fSmrg   double v = size;
97001e04c3fSmrg   double divider = 1024;
97101e04c3fSmrg   while (v >= divider) {
97201e04c3fSmrg      v /= divider;
97301e04c3fSmrg      divisions++;
97401e04c3fSmrg   }
97501e04c3fSmrg
97601e04c3fSmrg   static const char *units[] = { "Bytes", "Kilobytes", "Megabytes", "Gigabytes" };
97701e04c3fSmrg   static char result[20];
97801e04c3fSmrg   snprintf(result, sizeof(result), "%.2f %s",
97901e04c3fSmrg            v, divisions >= ARRAY_SIZE(units) ? "Too much!" : units[divisions]);
98001e04c3fSmrg   return result;
98101e04c3fSmrg}
98201e04c3fSmrg
98301e04c3fSmrgstatic void
98401e04c3fSmrgdisplay_aubfile_window(struct window *win)
98501e04c3fSmrg{
98601e04c3fSmrg   ImGuiColorEditFlags cflags = (ImGuiColorEditFlags_NoAlpha |
98701e04c3fSmrg                                 ImGuiColorEditFlags_NoLabel |
98801e04c3fSmrg                                 ImGuiColorEditFlags_NoInputs);
98901e04c3fSmrg   struct aub_viewer_cfg *cfg = &context.cfg;
99001e04c3fSmrg
99101e04c3fSmrg   ImGui::ColorEdit3("background", (float *)&cfg->clear_color, cflags); ImGui::SameLine();
99201e04c3fSmrg   ImGui::ColorEdit3("missing", (float *)&cfg->missing_color, cflags); ImGui::SameLine();
99301e04c3fSmrg   ImGui::ColorEdit3("error", (float *)&cfg->error_color, cflags); ImGui::SameLine();
99401e04c3fSmrg   ImGui::ColorEdit3("highlight", (float *)&cfg->highlight_color, cflags); ImGui::SameLine();
99501e04c3fSmrg   ImGui::ColorEdit3("dwords", (float *)&cfg->dwords_color, cflags); ImGui::SameLine();
9969f464c52Smaya   ImGui::ColorEdit3("booleans", (float *)&cfg->boolean_color, cflags); ImGui::SameLine();
99701e04c3fSmrg
99801e04c3fSmrg   if (ImGui::Button("Commands list") || has_ctrl_key('c')) { show_commands_window(); } ImGui::SameLine();
99901e04c3fSmrg   if (ImGui::Button("Registers list") || has_ctrl_key('r')) { show_register_window(); } ImGui::SameLine();
100001e04c3fSmrg   if (ImGui::Button("Help") || has_ctrl_key('h')) { ImGui::OpenPopup("Help"); }
100101e04c3fSmrg
100201e04c3fSmrg   if (ImGui::Button("New batch window") || has_ctrl_key('b')) { new_batch_window(0); }
100301e04c3fSmrg
100401e04c3fSmrg   ImGui::Text("File name:        %s", context.input_file);
100501e04c3fSmrg   ImGui::Text("File size:        %s", human_size(context.file->end - context.file->map));
100601e04c3fSmrg   ImGui::Text("Execbufs          %u", context.file->n_execs);
100701e04c3fSmrg   ImGui::Text("PCI ID:           0x%x", context.file->pci_id);
100801e04c3fSmrg   ImGui::Text("Application name: %s", context.file->app_name);
10097ec681f3Smrg   ImGui::Text("%s", context.file->devinfo.name);
101001e04c3fSmrg
101101e04c3fSmrg   ImGui::SetNextWindowContentWidth(500);
101201e04c3fSmrg   if (ImGui::BeginPopupModal("Help", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
101301e04c3fSmrg      ImGui::Text("Some global keybindings:");
101401e04c3fSmrg      ImGui::Separator();
101501e04c3fSmrg
101601e04c3fSmrg      static const char *texts[] = {
101701e04c3fSmrg         "Ctrl-h",          "show this screen",
101801e04c3fSmrg         "Ctrl-c",          "show commands list",
101901e04c3fSmrg         "Ctrl-r",          "show registers list",
102001e04c3fSmrg         "Ctrl-b",          "new batch window",
102101e04c3fSmrg         "Ctrl-p/n",        "switch to previous/next batch buffer",
102201e04c3fSmrg         "Ctrl-Tab",        "switch focus between window",
102301e04c3fSmrg         "Ctrl-left/right", "align window to the side of the screen",
102401e04c3fSmrg      };
102501e04c3fSmrg      float align = 0.0f;
102601e04c3fSmrg      for (uint32_t i = 0; i < ARRAY_SIZE(texts); i += 2)
102701e04c3fSmrg         align = MAX2(align, ImGui::CalcTextSize(texts[i]).x);
102801e04c3fSmrg      align += ImGui::GetStyle().WindowPadding.x + 10;
102901e04c3fSmrg
103001e04c3fSmrg      for (uint32_t i = 0; i < ARRAY_SIZE(texts); i += 2) {
10319f464c52Smaya         ImGui::Text("%s", texts[i]); ImGui::SameLine(align); ImGui::Text("%s", texts[i + 1]);
103201e04c3fSmrg      }
103301e04c3fSmrg
103401e04c3fSmrg      if (ImGui::Button("Done") || ImGui::IsKeyPressed(ImGuiKey_Escape))
103501e04c3fSmrg         ImGui::CloseCurrentPopup();
103601e04c3fSmrg      ImGui::EndPopup();
103701e04c3fSmrg   }
103801e04c3fSmrg}
103901e04c3fSmrg
104001e04c3fSmrgstatic void
104101e04c3fSmrgshow_aubfile_window(void)
104201e04c3fSmrg{
104301e04c3fSmrg   struct window *window = &context.file_window;
104401e04c3fSmrg
104501e04c3fSmrg   if (window->opened)
104601e04c3fSmrg      return;
104701e04c3fSmrg
104801e04c3fSmrg   snprintf(window->name, sizeof(window->name),
104901e04c3fSmrg            "Aubinator Viewer: Intel AUB file decoder/editor");
105001e04c3fSmrg
105101e04c3fSmrg   list_inithead(&window->parent_link);
105201e04c3fSmrg   window->size = ImVec2(-1, 250);
105301e04c3fSmrg   window->position = ImVec2(0, 0);
105401e04c3fSmrg   window->opened = true;
105501e04c3fSmrg   window->display = display_aubfile_window;
105601e04c3fSmrg   window->destroy = NULL;
105701e04c3fSmrg
105801e04c3fSmrg   list_addtail(&window->link, &context.windows);
105901e04c3fSmrg}
106001e04c3fSmrg
106101e04c3fSmrg/* Main redrawing */
106201e04c3fSmrg
106301e04c3fSmrgstatic void
106401e04c3fSmrgdisplay_windows(void)
106501e04c3fSmrg{
106601e04c3fSmrg   /* Start by disposing closed windows, we don't want to destroy windows that
106701e04c3fSmrg    * have already been scheduled to be painted. So destroy always happens on
106801e04c3fSmrg    * the next draw cycle, prior to any drawing.
106901e04c3fSmrg    */
107001e04c3fSmrg   list_for_each_entry_safe(struct window, window, &context.windows, link) {
107101e04c3fSmrg      if (window->opened)
107201e04c3fSmrg         continue;
107301e04c3fSmrg
107401e04c3fSmrg      /* Can't close this one. */
107501e04c3fSmrg      if (window == &context.file_window) {
107601e04c3fSmrg         window->opened = true;
107701e04c3fSmrg         continue;
107801e04c3fSmrg      }
107901e04c3fSmrg
108001e04c3fSmrg      list_del(&window->link);
108101e04c3fSmrg      list_del(&window->parent_link);
108201e04c3fSmrg      if (window->destroy)
108301e04c3fSmrg         window->destroy(window);
108401e04c3fSmrg   }
108501e04c3fSmrg
10867ec681f3Smrg   list_for_each_entry_safe(struct window, window, &context.windows, link) {
108701e04c3fSmrg      ImGui::SetNextWindowPos(window->position, ImGuiCond_FirstUseEver);
108801e04c3fSmrg      ImGui::SetNextWindowSize(window->size, ImGuiCond_FirstUseEver);
108901e04c3fSmrg      if (ImGui::Begin(window->name, &window->opened)) {
109001e04c3fSmrg         window->display(window);
109101e04c3fSmrg         window->position = ImGui::GetWindowPos();
109201e04c3fSmrg         window->size = ImGui::GetWindowSize();
109301e04c3fSmrg      }
109401e04c3fSmrg      if (window_has_ctrl_key('w'))
109501e04c3fSmrg         window->opened = false;
109601e04c3fSmrg      ImGui::End();
109701e04c3fSmrg   }
109801e04c3fSmrg}
109901e04c3fSmrg
110001e04c3fSmrgstatic void
110101e04c3fSmrgrepaint_area(GtkGLArea *area, GdkGLContext *gdk_gl_context)
110201e04c3fSmrg{
110301e04c3fSmrg   ImGui_ImplOpenGL3_NewFrame();
110401e04c3fSmrg   ImGui_ImplGtk3_NewFrame();
110501e04c3fSmrg   ImGui::NewFrame();
110601e04c3fSmrg
110701e04c3fSmrg   display_windows();
110801e04c3fSmrg
110901e04c3fSmrg   ImGui::EndFrame();
111001e04c3fSmrg   ImGui::Render();
111101e04c3fSmrg
111201e04c3fSmrg   glClearColor(context.cfg.clear_color.Value.x,
111301e04c3fSmrg                context.cfg.clear_color.Value.y,
111401e04c3fSmrg                context.cfg.clear_color.Value.z, 1.0);
111501e04c3fSmrg   glClear(GL_COLOR_BUFFER_BIT);
111601e04c3fSmrg   ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
111701e04c3fSmrg}
111801e04c3fSmrg
111901e04c3fSmrgstatic void
112001e04c3fSmrgrealize_area(GtkGLArea *area)
112101e04c3fSmrg{
112201e04c3fSmrg   ImGui::CreateContext();
112301e04c3fSmrg   ImGui_ImplGtk3_Init(GTK_WIDGET(area), true);
112401e04c3fSmrg   ImGui_ImplOpenGL3_Init("#version 130");
112501e04c3fSmrg
112601e04c3fSmrg   list_inithead(&context.windows);
112701e04c3fSmrg
112801e04c3fSmrg   ImGui::StyleColorsDark();
112901e04c3fSmrg   context.cfg = aub_viewer_cfg();
113001e04c3fSmrg
113101e04c3fSmrg   ImGuiIO& io = ImGui::GetIO();
113201e04c3fSmrg   io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
113301e04c3fSmrg}
113401e04c3fSmrg
113501e04c3fSmrgstatic void
113601e04c3fSmrgunrealize_area(GtkGLArea *area)
113701e04c3fSmrg{
113801e04c3fSmrg   gtk_gl_area_make_current(area);
113901e04c3fSmrg
114001e04c3fSmrg   ImGui_ImplOpenGL3_Shutdown();
114101e04c3fSmrg   ImGui_ImplGtk3_Shutdown();
114201e04c3fSmrg   ImGui::DestroyContext();
114301e04c3fSmrg}
114401e04c3fSmrg
114501e04c3fSmrgstatic void
114601e04c3fSmrgsize_allocate_area(GtkGLArea *area,
114701e04c3fSmrg                   GdkRectangle *allocation,
114801e04c3fSmrg                   gpointer user_data)
114901e04c3fSmrg{
115001e04c3fSmrg   if (!gtk_widget_get_realized(GTK_WIDGET(area)))
115101e04c3fSmrg      return;
115201e04c3fSmrg
115301e04c3fSmrg   /* We want to catch only initial size allocate. */
115401e04c3fSmrg   g_signal_handlers_disconnect_by_func(area,
115501e04c3fSmrg                                        (gpointer) size_allocate_area,
115601e04c3fSmrg                                        user_data);
115701e04c3fSmrg   show_aubfile_window();
115801e04c3fSmrg}
115901e04c3fSmrg
116001e04c3fSmrgstatic void
116101e04c3fSmrgprint_help(const char *progname, FILE *file)
116201e04c3fSmrg{
116301e04c3fSmrg   fprintf(file,
116401e04c3fSmrg           "Usage: %s [OPTION]... FILE\n"
116501e04c3fSmrg           "Decode aub file contents from FILE.\n\n"
116601e04c3fSmrg           "      --help             display this help and exit\n"
116701e04c3fSmrg           "  -x, --xml=DIR          load hardware xml description from directory DIR\n",
116801e04c3fSmrg           progname);
116901e04c3fSmrg}
117001e04c3fSmrg
117101e04c3fSmrgint main(int argc, char *argv[])
117201e04c3fSmrg{
117301e04c3fSmrg   int c, i;
117401e04c3fSmrg   bool help = false;
117501e04c3fSmrg   const struct option aubinator_opts[] = {
117601e04c3fSmrg      { "help",          no_argument,       (int *) &help,                 true },
117701e04c3fSmrg      { "xml",           required_argument, NULL,                          'x' },
117801e04c3fSmrg      { NULL,            0,                 NULL,                          0 }
117901e04c3fSmrg   };
118001e04c3fSmrg
118101e04c3fSmrg   memset(&context, 0, sizeof(context));
118201e04c3fSmrg
118301e04c3fSmrg   i = 0;
118401e04c3fSmrg   while ((c = getopt_long(argc, argv, "x:s:", aubinator_opts, &i)) != -1) {
118501e04c3fSmrg      switch (c) {
118601e04c3fSmrg      case 'x':
118701e04c3fSmrg         context.xml_path = strdup(optarg);
118801e04c3fSmrg         break;
118901e04c3fSmrg      default:
119001e04c3fSmrg         break;
119101e04c3fSmrg      }
119201e04c3fSmrg   }
119301e04c3fSmrg
119401e04c3fSmrg   if (optind < argc)
119501e04c3fSmrg      context.input_file = argv[optind];
119601e04c3fSmrg
119701e04c3fSmrg   if (help || !context.input_file) {
119801e04c3fSmrg      print_help(argv[0], stderr);
119901e04c3fSmrg      exit(0);
120001e04c3fSmrg   }
120101e04c3fSmrg
120201e04c3fSmrg   context.file = aub_file_open(context.input_file);
120301e04c3fSmrg
120401e04c3fSmrg   gtk_init(NULL, NULL);
120501e04c3fSmrg
120601e04c3fSmrg   context.gtk_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
120701e04c3fSmrg   gtk_window_set_title(GTK_WINDOW(context.gtk_window), "Aubinator Viewer");
120801e04c3fSmrg   g_signal_connect(context.gtk_window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
120901e04c3fSmrg   gtk_window_resize(GTK_WINDOW(context.gtk_window), 1280, 720);
121001e04c3fSmrg
121101e04c3fSmrg   GtkWidget* gl_area = gtk_gl_area_new();
121201e04c3fSmrg   g_signal_connect(gl_area, "render", G_CALLBACK(repaint_area), NULL);
121301e04c3fSmrg   g_signal_connect(gl_area, "realize", G_CALLBACK(realize_area), NULL);
121401e04c3fSmrg   g_signal_connect(gl_area, "unrealize", G_CALLBACK(unrealize_area), NULL);
121501e04c3fSmrg   g_signal_connect(gl_area, "size_allocate", G_CALLBACK(size_allocate_area), NULL);
121601e04c3fSmrg   gtk_container_add(GTK_CONTAINER(context.gtk_window), gl_area);
121701e04c3fSmrg
121801e04c3fSmrg   gtk_widget_show_all(context.gtk_window);
121901e04c3fSmrg
122001e04c3fSmrg   gtk_main();
122101e04c3fSmrg
122201e04c3fSmrg   free(context.xml_path);
122301e04c3fSmrg
122401e04c3fSmrg   return EXIT_SUCCESS;
122501e04c3fSmrg}
1226