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