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