1 /*
2 * Copyright © 2017 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <string.h>
25
26 #include "util/macros.h"
27
28 #include "aubinator_viewer.h"
29
30 void
aub_viewer_decode_ctx_init(struct aub_viewer_decode_ctx * ctx,struct aub_viewer_cfg * cfg,struct aub_viewer_decode_cfg * decode_cfg,const struct gen_device_info * devinfo,struct gen_spec * spec,struct gen_batch_decode_bo (* get_bo)(void *,bool,uint64_t),unsigned (* get_state_size)(void *,uint32_t),void * user_data)31 aub_viewer_decode_ctx_init(struct aub_viewer_decode_ctx *ctx,
32 struct aub_viewer_cfg *cfg,
33 struct aub_viewer_decode_cfg *decode_cfg,
34 const struct gen_device_info *devinfo,
35 struct gen_spec *spec,
36 struct gen_batch_decode_bo (*get_bo)(void *, bool, uint64_t),
37 unsigned (*get_state_size)(void *, uint32_t),
38 void *user_data)
39 {
40 memset(ctx, 0, sizeof(*ctx));
41
42 ctx->get_bo = get_bo;
43 ctx->get_state_size = get_state_size;
44 ctx->user_data = user_data;
45 ctx->devinfo = devinfo;
46 ctx->engine = I915_ENGINE_CLASS_RENDER;
47
48 ctx->cfg = cfg;
49 ctx->decode_cfg = decode_cfg;
50 ctx->spec = spec;
51 }
52
53 static void
aub_viewer_print_group(struct aub_viewer_decode_ctx * ctx,struct gen_group * group,uint64_t address,const void * map)54 aub_viewer_print_group(struct aub_viewer_decode_ctx *ctx,
55 struct gen_group *group,
56 uint64_t address, const void *map)
57 {
58 struct gen_field_iterator iter;
59 int last_dword = -1;
60 const uint32_t *p = (const uint32_t *) map;
61
62 gen_field_iterator_init(&iter, group, p, 0, false);
63 while (gen_field_iterator_next(&iter)) {
64 if (ctx->decode_cfg->show_dwords) {
65 int iter_dword = iter.end_bit / 32;
66 if (last_dword != iter_dword) {
67 for (int i = last_dword + 1; i <= iter_dword; i++) {
68 ImGui::TextColored(ctx->cfg->dwords_color,
69 "0x%012" PRIx64 ": 0x%012x : Dword %d",
70 address + 4 * i, iter.p[i], i);
71 }
72 last_dword = iter_dword;
73 }
74 }
75 if (!gen_field_is_header(iter.field)) {
76 if (ctx->decode_cfg->field_filter.PassFilter(iter.name)) {
77 if (iter.field->type.kind == gen_type::GEN_TYPE_BOOL && iter.raw_value) {
78 ImGui::Text("%s: ", iter.name); ImGui::SameLine();
79 ImGui::TextColored(ctx->cfg->boolean_color, "true");
80 } else {
81 ImGui::Text("%s: %s", iter.name, iter.value);
82 }
83 if (iter.struct_desc) {
84 int struct_dword = iter.start_bit / 32;
85 uint64_t struct_address = address + 4 * struct_dword;
86 aub_viewer_print_group(ctx, iter.struct_desc, struct_address,
87 &p[struct_dword]);
88 }
89 }
90 }
91 }
92 }
93
94 static struct gen_batch_decode_bo
ctx_get_bo(struct aub_viewer_decode_ctx * ctx,bool ppgtt,uint64_t addr)95 ctx_get_bo(struct aub_viewer_decode_ctx *ctx, bool ppgtt, uint64_t addr)
96 {
97 if (gen_spec_get_gen(ctx->spec) >= gen_make_gen(8,0)) {
98 /* On Broadwell and above, we have 48-bit addresses which consume two
99 * dwords. Some packets require that these get stored in a "canonical
100 * form" which means that bit 47 is sign-extended through the upper
101 * bits. In order to correctly handle those aub dumps, we need to mask
102 * off the top 16 bits.
103 */
104 addr &= (~0ull >> 16);
105 }
106
107 struct gen_batch_decode_bo bo = ctx->get_bo(ctx->user_data, ppgtt, addr);
108
109 if (gen_spec_get_gen(ctx->spec) >= gen_make_gen(8,0))
110 bo.addr &= (~0ull >> 16);
111
112 /* We may actually have an offset into the bo */
113 if (bo.map != NULL) {
114 assert(bo.addr <= addr);
115 uint64_t offset = addr - bo.addr;
116 bo.map = (const uint8_t *)bo.map + offset;
117 bo.addr += offset;
118 bo.size -= offset;
119 }
120
121 return bo;
122 }
123
124 static int
update_count(struct aub_viewer_decode_ctx * ctx,uint32_t offset_from_dsba,unsigned element_dwords,unsigned guess)125 update_count(struct aub_viewer_decode_ctx *ctx,
126 uint32_t offset_from_dsba,
127 unsigned element_dwords,
128 unsigned guess)
129 {
130 unsigned size = 0;
131
132 if (ctx->get_state_size)
133 size = ctx->get_state_size(ctx->user_data, offset_from_dsba);
134
135 if (size > 0)
136 return size / (sizeof(uint32_t) * element_dwords);
137
138 /* In the absence of any information, just guess arbitrarily. */
139 return guess;
140 }
141
142 static void
ctx_disassemble_program(struct aub_viewer_decode_ctx * ctx,uint32_t ksp,const char * type)143 ctx_disassemble_program(struct aub_viewer_decode_ctx *ctx,
144 uint32_t ksp, const char *type)
145 {
146 uint64_t addr = ctx->instruction_base + ksp;
147 struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, addr);
148 if (!bo.map) {
149 ImGui::TextColored(ctx->cfg->missing_color,
150 "Shader unavailable addr=0x%012" PRIx64, addr);
151 return;
152 }
153
154 ImGui::PushID(addr);
155 if (ImGui::Button(type) && ctx->display_shader)
156 ctx->display_shader(ctx->user_data, type, addr);
157 ImGui::PopID();
158 }
159
160 static void
handle_state_base_address(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)161 handle_state_base_address(struct aub_viewer_decode_ctx *ctx,
162 struct gen_group *inst,
163 const uint32_t *p)
164 {
165 struct gen_field_iterator iter;
166 gen_field_iterator_init(&iter, inst, p, 0, false);
167
168 uint64_t surface_base = 0, dynamic_base = 0, instruction_base = 0;
169 bool surface_modify = 0, dynamic_modify = 0, instruction_modify = 0;
170
171 while (gen_field_iterator_next(&iter)) {
172 if (strcmp(iter.name, "Surface State Base Address") == 0) {
173 surface_base = iter.raw_value;
174 } else if (strcmp(iter.name, "Dynamic State Base Address") == 0) {
175 dynamic_base = iter.raw_value;
176 } else if (strcmp(iter.name, "Instruction Base Address") == 0) {
177 instruction_base = iter.raw_value;
178 } else if (strcmp(iter.name, "Surface State Base Address Modify Enable") == 0) {
179 surface_modify = iter.raw_value;
180 } else if (strcmp(iter.name, "Dynamic State Base Address Modify Enable") == 0) {
181 dynamic_modify = iter.raw_value;
182 } else if (strcmp(iter.name, "Instruction Base Address Modify Enable") == 0) {
183 instruction_modify = iter.raw_value;
184 }
185 }
186
187 if (dynamic_modify)
188 ctx->dynamic_base = dynamic_base;
189
190 if (surface_modify)
191 ctx->surface_base = surface_base;
192
193 if (instruction_modify)
194 ctx->instruction_base = instruction_base;
195 }
196
197 static void
dump_binding_table(struct aub_viewer_decode_ctx * ctx,uint32_t offset,int count)198 dump_binding_table(struct aub_viewer_decode_ctx *ctx, uint32_t offset, int count)
199 {
200 struct gen_group *strct =
201 gen_spec_find_struct(ctx->spec, "RENDER_SURFACE_STATE");
202 if (strct == NULL) {
203 ImGui::TextColored(ctx->cfg->missing_color, "did not find RENDER_SURFACE_STATE info");
204 return;
205 }
206
207 if (count < 0)
208 count = update_count(ctx, offset, 1, 8);
209
210 if (offset % 32 != 0 || offset >= UINT16_MAX) {
211 ImGui::TextColored(ctx->cfg->missing_color, "invalid binding table pointer");
212 return;
213 }
214
215 struct gen_batch_decode_bo bind_bo =
216 ctx_get_bo(ctx, true, ctx->surface_base + offset);
217
218 if (bind_bo.map == NULL) {
219 ImGui::TextColored(ctx->cfg->missing_color,
220 "binding table unavailable addr=0x%012" PRIx64,
221 ctx->surface_base + offset);
222 return;
223 }
224
225 const uint32_t *pointers = (const uint32_t *) bind_bo.map;
226 for (int i = 0; i < count; i++) {
227 if (pointers[i] == 0)
228 continue;
229
230 uint64_t addr = ctx->surface_base + pointers[i];
231 struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, addr);
232 uint32_t size = strct->dw_length * 4;
233
234 if (pointers[i] % 32 != 0 ||
235 addr < bo.addr || addr + size >= bo.addr + bo.size) {
236 ImGui::TextColored(ctx->cfg->missing_color,
237 "pointer %u: %012x <not valid>", i, pointers[i]);
238 continue;
239 }
240
241 const uint8_t *state = (const uint8_t *) bo.map + (addr - bo.addr);
242 if (ImGui::TreeNodeEx(&pointers[i], ImGuiTreeNodeFlags_Framed,
243 "pointer %u: %012x", i, pointers[i])) {
244 aub_viewer_print_group(ctx, strct, addr, state);
245 ImGui::TreePop();
246 }
247 }
248 }
249
250 static void
dump_samplers(struct aub_viewer_decode_ctx * ctx,uint32_t offset,int count)251 dump_samplers(struct aub_viewer_decode_ctx *ctx, uint32_t offset, int count)
252 {
253 struct gen_group *strct = gen_spec_find_struct(ctx->spec, "SAMPLER_STATE");
254
255 if (count < 0)
256 count = update_count(ctx, offset, strct->dw_length, 4);
257
258 uint64_t state_addr = ctx->dynamic_base + offset;
259 struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, state_addr);
260 const uint8_t *state_map = (const uint8_t *) bo.map;
261
262 if (state_map == NULL) {
263 ImGui::TextColored(ctx->cfg->missing_color,
264 "samplers unavailable addr=0x%012" PRIx64, state_addr);
265 return;
266 }
267
268 if (offset % 32 != 0 || state_addr - bo.addr >= bo.size) {
269 ImGui::TextColored(ctx->cfg->missing_color, "invalid sampler state pointer");
270 return;
271 }
272
273 for (int i = 0; i < count; i++) {
274 if (ImGui::TreeNodeEx(state_map, ImGuiTreeNodeFlags_Framed,
275 "sampler state %d", i)) {
276 aub_viewer_print_group(ctx, strct, state_addr, state_map);
277 ImGui::TreePop();
278 }
279 state_addr += 16;
280 state_map += 16;
281 }
282 }
283
284 static void
handle_media_interface_descriptor_load(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)285 handle_media_interface_descriptor_load(struct aub_viewer_decode_ctx *ctx,
286 struct gen_group *inst,
287 const uint32_t *p)
288 {
289 struct gen_group *desc =
290 gen_spec_find_struct(ctx->spec, "INTERFACE_DESCRIPTOR_DATA");
291
292 struct gen_field_iterator iter;
293 gen_field_iterator_init(&iter, inst, p, 0, false);
294 uint32_t descriptor_offset = 0;
295 int descriptor_count = 0;
296 while (gen_field_iterator_next(&iter)) {
297 if (strcmp(iter.name, "Interface Descriptor Data Start Address") == 0) {
298 descriptor_offset = strtol(iter.value, NULL, 16);
299 } else if (strcmp(iter.name, "Interface Descriptor Total Length") == 0) {
300 descriptor_count =
301 strtol(iter.value, NULL, 16) / (desc->dw_length * 4);
302 }
303 }
304
305 uint64_t desc_addr = ctx->dynamic_base + descriptor_offset;
306 struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, desc_addr);
307 const uint32_t *desc_map = (const uint32_t *) bo.map;
308
309 if (desc_map == NULL) {
310 ImGui::TextColored(ctx->cfg->missing_color,
311 "interface descriptors unavailable addr=0x%012" PRIx64, desc_addr);
312 return;
313 }
314
315 for (int i = 0; i < descriptor_count; i++) {
316 ImGui::Text("descriptor %d: %012x", i, descriptor_offset);
317
318 aub_viewer_print_group(ctx, desc, desc_addr, desc_map);
319
320 gen_field_iterator_init(&iter, desc, desc_map, 0, false);
321 uint64_t ksp = 0;
322 uint32_t sampler_offset = 0, sampler_count = 0;
323 uint32_t binding_table_offset = 0, binding_entry_count = 0;
324 while (gen_field_iterator_next(&iter)) {
325 if (strcmp(iter.name, "Kernel Start Pointer") == 0) {
326 ksp = strtoll(iter.value, NULL, 16);
327 } else if (strcmp(iter.name, "Sampler State Pointer") == 0) {
328 sampler_offset = strtol(iter.value, NULL, 16);
329 } else if (strcmp(iter.name, "Sampler Count") == 0) {
330 sampler_count = strtol(iter.value, NULL, 10);
331 } else if (strcmp(iter.name, "Binding Table Pointer") == 0) {
332 binding_table_offset = strtol(iter.value, NULL, 16);
333 } else if (strcmp(iter.name, "Binding Table Entry Count") == 0) {
334 binding_entry_count = strtol(iter.value, NULL, 10);
335 }
336 }
337
338 ctx_disassemble_program(ctx, ksp, "compute shader");
339
340 dump_samplers(ctx, sampler_offset, sampler_count);
341 dump_binding_table(ctx, binding_table_offset, binding_entry_count);
342
343 desc_map += desc->dw_length;
344 desc_addr += desc->dw_length * 4;
345 }
346 }
347
348 static void
handle_3dstate_vertex_buffers(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)349 handle_3dstate_vertex_buffers(struct aub_viewer_decode_ctx *ctx,
350 struct gen_group *inst,
351 const uint32_t *p)
352 {
353 struct gen_group *vbs = gen_spec_find_struct(ctx->spec, "VERTEX_BUFFER_STATE");
354
355 struct gen_batch_decode_bo vb = {};
356 uint32_t vb_size = 0;
357 int index = -1;
358 int pitch = -1;
359 bool ready = false;
360
361 struct gen_field_iterator iter;
362 gen_field_iterator_init(&iter, inst, p, 0, false);
363 while (gen_field_iterator_next(&iter)) {
364 if (iter.struct_desc != vbs)
365 continue;
366
367 uint64_t buffer_addr = 0;
368
369 struct gen_field_iterator vbs_iter;
370 gen_field_iterator_init(&vbs_iter, vbs, &iter.p[iter.start_bit / 32], 0, false);
371 while (gen_field_iterator_next(&vbs_iter)) {
372 if (strcmp(vbs_iter.name, "Vertex Buffer Index") == 0) {
373 index = vbs_iter.raw_value;
374 } else if (strcmp(vbs_iter.name, "Buffer Pitch") == 0) {
375 pitch = vbs_iter.raw_value;
376 } else if (strcmp(vbs_iter.name, "Buffer Starting Address") == 0) {
377 buffer_addr = vbs_iter.raw_value;
378 vb = ctx_get_bo(ctx, true, buffer_addr);
379 } else if (strcmp(vbs_iter.name, "Buffer Size") == 0) {
380 vb_size = vbs_iter.raw_value;
381 ready = true;
382 } else if (strcmp(vbs_iter.name, "End Address") == 0) {
383 if (vb.map && vbs_iter.raw_value >= vb.addr)
384 vb_size = vbs_iter.raw_value - vb.addr;
385 else
386 vb_size = 0;
387 ready = true;
388 }
389
390 if (!ready)
391 continue;
392
393 ImGui::Text("vertex buffer %d, size %d, pitch %d", index, vb_size, pitch);
394
395 if (vb.map == NULL) {
396 ImGui::TextColored(ctx->cfg->missing_color,
397 "buffer contents unavailable addr=0x%012" PRIx64, buffer_addr);
398 continue;
399 }
400
401 if (vb.map == 0 || vb_size == 0)
402 continue;
403
404 vb.map = NULL;
405 vb_size = 0;
406 index = -1;
407 pitch = -1;
408 ready = false;
409 }
410 }
411 }
412
413 static void
handle_3dstate_index_buffer(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)414 handle_3dstate_index_buffer(struct aub_viewer_decode_ctx *ctx,
415 struct gen_group *inst,
416 const uint32_t *p)
417 {
418 struct gen_batch_decode_bo ib = {};
419 uint64_t buffer_addr = 0;
420 uint32_t ib_size = 0;
421 uint32_t format = 0;
422
423 struct gen_field_iterator iter;
424 gen_field_iterator_init(&iter, inst, p, 0, false);
425 while (gen_field_iterator_next(&iter)) {
426 if (strcmp(iter.name, "Index Format") == 0) {
427 format = iter.raw_value;
428 } else if (strcmp(iter.name, "Buffer Starting Address") == 0) {
429 buffer_addr = iter.raw_value;
430 ib = ctx_get_bo(ctx, true, buffer_addr);
431 } else if (strcmp(iter.name, "Buffer Size") == 0) {
432 ib_size = iter.raw_value;
433 }
434 }
435
436 if (ib.map == NULL) {
437 ImGui::TextColored(ctx->cfg->missing_color,
438 "buffer contents unavailable addr=0x%012" PRIx64,
439 buffer_addr);
440 return;
441 }
442
443 const uint8_t *m = (const uint8_t *) ib.map;
444 const uint8_t *ib_end = m + MIN2(ib.size, ib_size);
445 for (int i = 0; m < ib_end && i < 10; i++) {
446 switch (format) {
447 case 0:
448 m += 1;
449 break;
450 case 1:
451 m += 2;
452 break;
453 case 2:
454 m += 4;
455 break;
456 }
457 }
458 }
459
460 static void
decode_single_ksp(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)461 decode_single_ksp(struct aub_viewer_decode_ctx *ctx,
462 struct gen_group *inst,
463 const uint32_t *p)
464 {
465 uint64_t ksp = 0;
466 bool is_simd8 = false; /* vertex shaders on Gen8+ only */
467 bool is_enabled = true;
468
469 struct gen_field_iterator iter;
470 gen_field_iterator_init(&iter, inst, p, 0, false);
471 while (gen_field_iterator_next(&iter)) {
472 if (strcmp(iter.name, "Kernel Start Pointer") == 0) {
473 ksp = iter.raw_value;
474 } else if (strcmp(iter.name, "SIMD8 Dispatch Enable") == 0) {
475 is_simd8 = iter.raw_value;
476 } else if (strcmp(iter.name, "Dispatch Mode") == 0) {
477 is_simd8 = strcmp(iter.value, "SIMD8") == 0;
478 } else if (strcmp(iter.name, "Dispatch Enable") == 0) {
479 is_simd8 = strcmp(iter.value, "SIMD8") == 0;
480 } else if (strcmp(iter.name, "Enable") == 0) {
481 is_enabled = iter.raw_value;
482 }
483 }
484
485 const char *type =
486 strcmp(inst->name, "VS_STATE") == 0 ? "vertex shader" :
487 strcmp(inst->name, "GS_STATE") == 0 ? "geometry shader" :
488 strcmp(inst->name, "SF_STATE") == 0 ? "strips and fans shader" :
489 strcmp(inst->name, "CLIP_STATE") == 0 ? "clip shader" :
490 strcmp(inst->name, "3DSTATE_DS") == 0 ? "tessellation evaluation shader" :
491 strcmp(inst->name, "3DSTATE_HS") == 0 ? "tessellation control shader" :
492 strcmp(inst->name, "3DSTATE_VS") == 0 ? (is_simd8 ? "SIMD8 vertex shader" : "vec4 vertex shader") :
493 strcmp(inst->name, "3DSTATE_GS") == 0 ? (is_simd8 ? "SIMD8 geometry shader" : "vec4 geometry shader") :
494 NULL;
495
496 if (is_enabled)
497 ctx_disassemble_program(ctx, ksp, type);
498 }
499
500 static void
decode_ps_kernels(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)501 decode_ps_kernels(struct aub_viewer_decode_ctx *ctx,
502 struct gen_group *inst,
503 const uint32_t *p)
504 {
505 uint64_t ksp[3] = {0, 0, 0};
506 bool enabled[3] = {false, false, false};
507
508 struct gen_field_iterator iter;
509 gen_field_iterator_init(&iter, inst, p, 0, false);
510 while (gen_field_iterator_next(&iter)) {
511 if (strncmp(iter.name, "Kernel Start Pointer ",
512 strlen("Kernel Start Pointer ")) == 0) {
513 int idx = iter.name[strlen("Kernel Start Pointer ")] - '0';
514 ksp[idx] = strtol(iter.value, NULL, 16);
515 } else if (strcmp(iter.name, "8 Pixel Dispatch Enable") == 0) {
516 enabled[0] = strcmp(iter.value, "true") == 0;
517 } else if (strcmp(iter.name, "16 Pixel Dispatch Enable") == 0) {
518 enabled[1] = strcmp(iter.value, "true") == 0;
519 } else if (strcmp(iter.name, "32 Pixel Dispatch Enable") == 0) {
520 enabled[2] = strcmp(iter.value, "true") == 0;
521 }
522 }
523
524 /* Reorder KSPs to be [8, 16, 32] instead of the hardware order. */
525 if (enabled[0] + enabled[1] + enabled[2] == 1) {
526 if (enabled[1]) {
527 ksp[1] = ksp[0];
528 ksp[0] = 0;
529 } else if (enabled[2]) {
530 ksp[2] = ksp[0];
531 ksp[0] = 0;
532 }
533 } else {
534 uint64_t tmp = ksp[1];
535 ksp[1] = ksp[2];
536 ksp[2] = tmp;
537 }
538
539 if (enabled[0])
540 ctx_disassemble_program(ctx, ksp[0], "SIMD8 fragment shader");
541 if (enabled[1])
542 ctx_disassemble_program(ctx, ksp[1], "SIMD16 fragment shader");
543 if (enabled[2])
544 ctx_disassemble_program(ctx, ksp[2], "SIMD32 fragment shader");
545 }
546
547 static void
decode_3dstate_constant(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)548 decode_3dstate_constant(struct aub_viewer_decode_ctx *ctx,
549 struct gen_group *inst,
550 const uint32_t *p)
551 {
552 struct gen_group *body =
553 gen_spec_find_struct(ctx->spec, "3DSTATE_CONSTANT_BODY");
554
555 uint32_t read_length[4] = {0};
556 uint64_t read_addr[4];
557
558 struct gen_field_iterator outer;
559 gen_field_iterator_init(&outer, inst, p, 0, false);
560 while (gen_field_iterator_next(&outer)) {
561 if (outer.struct_desc != body)
562 continue;
563
564 struct gen_field_iterator iter;
565 gen_field_iterator_init(&iter, body, &outer.p[outer.start_bit / 32],
566 0, false);
567
568 while (gen_field_iterator_next(&iter)) {
569 int idx;
570 if (sscanf(iter.name, "Read Length[%d]", &idx) == 1) {
571 read_length[idx] = iter.raw_value;
572 } else if (sscanf(iter.name, "Buffer[%d]", &idx) == 1) {
573 read_addr[idx] = iter.raw_value;
574 }
575 }
576
577 for (int i = 0; i < 4; i++) {
578 if (read_length[i] == 0)
579 continue;
580
581 struct gen_batch_decode_bo buffer = ctx_get_bo(ctx, true, read_addr[i]);
582 if (!buffer.map) {
583 ImGui::TextColored(ctx->cfg->missing_color,
584 "constant buffer %d unavailable addr=0x%012" PRIx64,
585 i, read_addr[i]);
586 continue;
587 }
588
589 unsigned size = read_length[i] * 32;
590 ImGui::Text("constant buffer %d, size %u", i, size);
591
592 if (ctx->edit_address) {
593 if (ImGui::Button("Show/Edit buffer"))
594 ctx->edit_address(ctx->user_data, read_addr[i], size);
595 }
596 }
597 }
598 }
599
600 static void
decode_3dstate_binding_table_pointers(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)601 decode_3dstate_binding_table_pointers(struct aub_viewer_decode_ctx *ctx,
602 struct gen_group *inst,
603 const uint32_t *p)
604 {
605 dump_binding_table(ctx, p[1], -1);
606 }
607
608 static void
decode_3dstate_sampler_state_pointers(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)609 decode_3dstate_sampler_state_pointers(struct aub_viewer_decode_ctx *ctx,
610 struct gen_group *inst,
611 const uint32_t *p)
612 {
613 dump_samplers(ctx, p[1], -1);
614 }
615
616 static void
decode_3dstate_sampler_state_pointers_gen6(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)617 decode_3dstate_sampler_state_pointers_gen6(struct aub_viewer_decode_ctx *ctx,
618 struct gen_group *inst,
619 const uint32_t *p)
620 {
621 dump_samplers(ctx, p[1], -1);
622 dump_samplers(ctx, p[2], -1);
623 dump_samplers(ctx, p[3], -1);
624 }
625
626 static bool
str_ends_with(const char * str,const char * end)627 str_ends_with(const char *str, const char *end)
628 {
629 int offset = strlen(str) - strlen(end);
630 if (offset < 0)
631 return false;
632
633 return strcmp(str + offset, end) == 0;
634 }
635
636 static void
decode_dynamic_state_pointers(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p,const char * struct_type,int count)637 decode_dynamic_state_pointers(struct aub_viewer_decode_ctx *ctx,
638 struct gen_group *inst, const uint32_t *p,
639 const char *struct_type, int count)
640 {
641 uint32_t state_offset = 0;
642
643 struct gen_field_iterator iter;
644 gen_field_iterator_init(&iter, inst, p, 0, false);
645 while (gen_field_iterator_next(&iter)) {
646 if (str_ends_with(iter.name, "Pointer")) {
647 state_offset = iter.raw_value;
648 break;
649 }
650 }
651
652 uint64_t state_addr = ctx->dynamic_base + state_offset;
653 struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, state_addr);
654 const uint8_t *state_map = (const uint8_t *) bo.map;
655
656 if (state_map == NULL) {
657 ImGui::TextColored(ctx->cfg->missing_color,
658 "dynamic %s state unavailable addr=0x%012" PRIx64,
659 struct_type, state_addr);
660 return;
661 }
662
663 struct gen_group *state = gen_spec_find_struct(ctx->spec, struct_type);
664 if (strcmp(struct_type, "BLEND_STATE") == 0) {
665 /* Blend states are different from the others because they have a header
666 * struct called BLEND_STATE which is followed by a variable number of
667 * BLEND_STATE_ENTRY structs.
668 */
669 ImGui::Text("%s", struct_type);
670 aub_viewer_print_group(ctx, state, state_addr, state_map);
671
672 state_addr += state->dw_length * 4;
673 state_map += state->dw_length * 4;
674
675 struct_type = "BLEND_STATE_ENTRY";
676 state = gen_spec_find_struct(ctx->spec, struct_type);
677 }
678
679 for (int i = 0; i < count; i++) {
680 ImGui::Text("%s %d", struct_type, i);
681 aub_viewer_print_group(ctx, state, state_addr, state_map);
682
683 state_addr += state->dw_length * 4;
684 state_map += state->dw_length * 4;
685 }
686 }
687
688 static void
decode_3dstate_viewport_state_pointers_cc(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)689 decode_3dstate_viewport_state_pointers_cc(struct aub_viewer_decode_ctx *ctx,
690 struct gen_group *inst,
691 const uint32_t *p)
692 {
693 decode_dynamic_state_pointers(ctx, inst, p, "CC_VIEWPORT", 4);
694 }
695
696 static void
decode_3dstate_viewport_state_pointers_sf_clip(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)697 decode_3dstate_viewport_state_pointers_sf_clip(struct aub_viewer_decode_ctx *ctx,
698 struct gen_group *inst,
699 const uint32_t *p)
700 {
701 decode_dynamic_state_pointers(ctx, inst, p, "SF_CLIP_VIEWPORT", 4);
702 }
703
704 static void
decode_3dstate_blend_state_pointers(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)705 decode_3dstate_blend_state_pointers(struct aub_viewer_decode_ctx *ctx,
706 struct gen_group *inst,
707 const uint32_t *p)
708 {
709 decode_dynamic_state_pointers(ctx, inst, p, "BLEND_STATE", 1);
710 }
711
712 static void
decode_3dstate_cc_state_pointers(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)713 decode_3dstate_cc_state_pointers(struct aub_viewer_decode_ctx *ctx,
714 struct gen_group *inst,
715 const uint32_t *p)
716 {
717 decode_dynamic_state_pointers(ctx, inst, p, "COLOR_CALC_STATE", 1);
718 }
719
720 static void
decode_3dstate_scissor_state_pointers(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)721 decode_3dstate_scissor_state_pointers(struct aub_viewer_decode_ctx *ctx,
722 struct gen_group *inst,
723 const uint32_t *p)
724 {
725 decode_dynamic_state_pointers(ctx, inst, p, "SCISSOR_RECT", 1);
726 }
727
728 static void
decode_load_register_imm(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)729 decode_load_register_imm(struct aub_viewer_decode_ctx *ctx,
730 struct gen_group *inst,
731 const uint32_t *p)
732 {
733 struct gen_group *reg = gen_spec_find_register(ctx->spec, p[1]);
734
735 if (reg != NULL &&
736 ImGui::TreeNodeEx(&p[1], ImGuiTreeNodeFlags_Framed,
737 "%s (0x%x) = 0x%x",
738 reg->name, reg->register_offset, p[2])) {
739 aub_viewer_print_group(ctx, reg, reg->register_offset, &p[2]);
740 ImGui::TreePop();
741 }
742 }
743
744 static void
decode_3dprimitive(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)745 decode_3dprimitive(struct aub_viewer_decode_ctx *ctx,
746 struct gen_group *inst,
747 const uint32_t *p)
748 {
749 if (ctx->display_urb) {
750 if (ImGui::Button("Show URB"))
751 ctx->display_urb(ctx->user_data, ctx->urb_stages);
752 }
753 }
754
755 static void
handle_urb(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)756 handle_urb(struct aub_viewer_decode_ctx *ctx,
757 struct gen_group *inst,
758 const uint32_t *p)
759 {
760 struct gen_field_iterator iter;
761 gen_field_iterator_init(&iter, inst, p, 0, false);
762 while (gen_field_iterator_next(&iter)) {
763 if (strstr(iter.name, "URB Starting Address")) {
764 ctx->urb_stages[ctx->stage].start = iter.raw_value * 8192;
765 } else if (strstr(iter.name, "URB Entry Allocation Size")) {
766 ctx->urb_stages[ctx->stage].size = (iter.raw_value + 1) * 64;
767 } else if (strstr(iter.name, "Number of URB Entries")) {
768 ctx->urb_stages[ctx->stage].n_entries = iter.raw_value;
769 }
770 }
771
772 ctx->end_urb_offset = MAX2(ctx->urb_stages[ctx->stage].start +
773 ctx->urb_stages[ctx->stage].n_entries *
774 ctx->urb_stages[ctx->stage].size,
775 ctx->end_urb_offset);
776 }
777
778 static void
handle_urb_read(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)779 handle_urb_read(struct aub_viewer_decode_ctx *ctx,
780 struct gen_group *inst,
781 const uint32_t *p)
782 {
783 struct gen_field_iterator iter;
784 gen_field_iterator_init(&iter, inst, p, 0, false);
785 while (gen_field_iterator_next(&iter)) {
786 /* Workaround the "Force * URB Entry Read Length" fields */
787 if (iter.end_bit - iter.start_bit < 2)
788 continue;
789
790 if (strstr(iter.name, "URB Entry Read Offset")) {
791 ctx->urb_stages[ctx->stage].rd_offset = iter.raw_value * 32;
792 } else if (strstr(iter.name, "URB Entry Read Length")) {
793 ctx->urb_stages[ctx->stage].rd_length = iter.raw_value * 32;
794 } else if (strstr(iter.name, "URB Entry Output Read Offset")) {
795 ctx->urb_stages[ctx->stage].wr_offset = iter.raw_value * 32;
796 } else if (strstr(iter.name, "URB Entry Output Length")) {
797 ctx->urb_stages[ctx->stage].wr_length = iter.raw_value * 32;
798 }
799 }
800 }
801
802 static void
handle_urb_constant(struct aub_viewer_decode_ctx * ctx,struct gen_group * inst,const uint32_t * p)803 handle_urb_constant(struct aub_viewer_decode_ctx *ctx,
804 struct gen_group *inst,
805 const uint32_t *p)
806 {
807 struct gen_group *body =
808 gen_spec_find_struct(ctx->spec, "3DSTATE_CONSTANT_BODY");
809
810 struct gen_field_iterator outer;
811 gen_field_iterator_init(&outer, inst, p, 0, false);
812 while (gen_field_iterator_next(&outer)) {
813 if (outer.struct_desc != body)
814 continue;
815
816 struct gen_field_iterator iter;
817 gen_field_iterator_init(&iter, body, &outer.p[outer.start_bit / 32],
818 0, false);
819
820 ctx->urb_stages[ctx->stage].const_rd_length = 0;
821 while (gen_field_iterator_next(&iter)) {
822 int idx;
823 if (sscanf(iter.name, "Read Length[%d]", &idx) == 1) {
824 ctx->urb_stages[ctx->stage].const_rd_length += iter.raw_value * 32;
825 }
826 }
827 }
828 }
829
830 struct custom_decoder {
831 const char *cmd_name;
832 void (*decode)(struct aub_viewer_decode_ctx *ctx,
833 struct gen_group *inst,
834 const uint32_t *p);
835 enum aub_decode_stage stage;
836 } display_decoders[] = {
837 { "STATE_BASE_ADDRESS", handle_state_base_address },
838 { "MEDIA_INTERFACE_DESCRIPTOR_LOAD", handle_media_interface_descriptor_load },
839 { "3DSTATE_VERTEX_BUFFERS", handle_3dstate_vertex_buffers },
840 { "3DSTATE_INDEX_BUFFER", handle_3dstate_index_buffer },
841 { "3DSTATE_VS", decode_single_ksp, AUB_DECODE_STAGE_VS, },
842 { "3DSTATE_GS", decode_single_ksp, AUB_DECODE_STAGE_GS, },
843 { "3DSTATE_DS", decode_single_ksp, AUB_DECODE_STAGE_DS, },
844 { "3DSTATE_HS", decode_single_ksp, AUB_DECODE_STAGE_HS, },
845 { "3DSTATE_PS", decode_ps_kernels, AUB_DECODE_STAGE_PS, },
846 { "3DSTATE_CONSTANT_VS", decode_3dstate_constant, AUB_DECODE_STAGE_VS, },
847 { "3DSTATE_CONSTANT_GS", decode_3dstate_constant, AUB_DECODE_STAGE_GS, },
848 { "3DSTATE_CONSTANT_DS", decode_3dstate_constant, AUB_DECODE_STAGE_DS, },
849 { "3DSTATE_CONSTANT_HS", decode_3dstate_constant, AUB_DECODE_STAGE_HS, },
850 { "3DSTATE_CONSTANT_PS", decode_3dstate_constant, AUB_DECODE_STAGE_PS, },
851
852 { "3DSTATE_BINDING_TABLE_POINTERS_VS", decode_3dstate_binding_table_pointers, AUB_DECODE_STAGE_VS, },
853 { "3DSTATE_BINDING_TABLE_POINTERS_GS", decode_3dstate_binding_table_pointers, AUB_DECODE_STAGE_GS, },
854 { "3DSTATE_BINDING_TABLE_POINTERS_HS", decode_3dstate_binding_table_pointers, AUB_DECODE_STAGE_HS, },
855 { "3DSTATE_BINDING_TABLE_POINTERS_DS", decode_3dstate_binding_table_pointers, AUB_DECODE_STAGE_DS, },
856 { "3DSTATE_BINDING_TABLE_POINTERS_PS", decode_3dstate_binding_table_pointers, AUB_DECODE_STAGE_PS, },
857
858 { "3DSTATE_SAMPLER_STATE_POINTERS_VS", decode_3dstate_sampler_state_pointers, AUB_DECODE_STAGE_VS, },
859 { "3DSTATE_SAMPLER_STATE_POINTERS_GS", decode_3dstate_sampler_state_pointers, AUB_DECODE_STAGE_GS, },
860 { "3DSTATE_SAMPLER_STATE_POINTERS_DS", decode_3dstate_sampler_state_pointers, AUB_DECODE_STAGE_DS, },
861 { "3DSTATE_SAMPLER_STATE_POINTERS_HS", decode_3dstate_sampler_state_pointers, AUB_DECODE_STAGE_HS, },
862 { "3DSTATE_SAMPLER_STATE_POINTERS_PS", decode_3dstate_sampler_state_pointers, AUB_DECODE_STAGE_PS, },
863 { "3DSTATE_SAMPLER_STATE_POINTERS", decode_3dstate_sampler_state_pointers_gen6 },
864
865 { "3DSTATE_VIEWPORT_STATE_POINTERS_CC", decode_3dstate_viewport_state_pointers_cc },
866 { "3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP", decode_3dstate_viewport_state_pointers_sf_clip },
867 { "3DSTATE_BLEND_STATE_POINTERS", decode_3dstate_blend_state_pointers },
868 { "3DSTATE_CC_STATE_POINTERS", decode_3dstate_cc_state_pointers },
869 { "3DSTATE_SCISSOR_STATE_POINTERS", decode_3dstate_scissor_state_pointers },
870 { "MI_LOAD_REGISTER_IMM", decode_load_register_imm },
871 { "3DPRIMITIVE", decode_3dprimitive },
872 };
873
874 struct custom_decoder info_decoders[] = {
875 { "STATE_BASE_ADDRESS", handle_state_base_address },
876 { "3DSTATE_URB_VS", handle_urb, AUB_DECODE_STAGE_VS, },
877 { "3DSTATE_URB_GS", handle_urb, AUB_DECODE_STAGE_GS, },
878 { "3DSTATE_URB_DS", handle_urb, AUB_DECODE_STAGE_DS, },
879 { "3DSTATE_URB_HS", handle_urb, AUB_DECODE_STAGE_HS, },
880 { "3DSTATE_VS", handle_urb_read, AUB_DECODE_STAGE_VS, },
881 { "3DSTATE_GS", handle_urb_read, AUB_DECODE_STAGE_GS, },
882 { "3DSTATE_DS", handle_urb_read, AUB_DECODE_STAGE_DS, },
883 { "3DSTATE_HS", handle_urb_read, AUB_DECODE_STAGE_HS, },
884 { "3DSTATE_PS", handle_urb_read, AUB_DECODE_STAGE_PS, },
885 { "3DSTATE_CONSTANT_VS", handle_urb_constant, AUB_DECODE_STAGE_VS, },
886 { "3DSTATE_CONSTANT_GS", handle_urb_constant, AUB_DECODE_STAGE_GS, },
887 { "3DSTATE_CONSTANT_DS", handle_urb_constant, AUB_DECODE_STAGE_DS, },
888 { "3DSTATE_CONSTANT_HS", handle_urb_constant, AUB_DECODE_STAGE_HS, },
889 { "3DSTATE_CONSTANT_PS", handle_urb_constant, AUB_DECODE_STAGE_PS, },
890 };
891
892 void
aub_viewer_render_batch(struct aub_viewer_decode_ctx * ctx,const void * _batch,uint32_t batch_size,uint64_t batch_addr,bool from_ring)893 aub_viewer_render_batch(struct aub_viewer_decode_ctx *ctx,
894 const void *_batch, uint32_t batch_size,
895 uint64_t batch_addr, bool from_ring)
896 {
897 struct gen_group *inst;
898 const uint32_t *p, *batch = (const uint32_t *) _batch, *end = batch + batch_size / sizeof(uint32_t);
899 int length;
900
901 if (ctx->n_batch_buffer_start >= 100) {
902 ImGui::TextColored(ctx->cfg->error_color,
903 "0x%08" PRIx64 ": Max batch buffer jumps exceeded", batch_addr);
904 return;
905 }
906
907 ctx->n_batch_buffer_start++;
908
909 for (p = batch; p < end; p += length) {
910 inst = gen_spec_find_instruction(ctx->spec, ctx->engine, p);
911 length = gen_group_get_length(inst, p);
912 assert(inst == NULL || length > 0);
913 length = MAX2(1, length);
914
915 uint64_t offset = batch_addr + ((char *)p - (char *)batch);
916
917 if (inst == NULL) {
918 ImGui::TextColored(ctx->cfg->error_color,
919 "0x%012" PRIx64 ": unknown instruction %012x",
920 offset, p[0]);
921 continue;
922 }
923
924 const char *inst_name = gen_group_get_name(inst);
925
926 for (unsigned i = 0; i < ARRAY_SIZE(info_decoders); i++) {
927 if (strcmp(inst_name, info_decoders[i].cmd_name) == 0) {
928 ctx->stage = info_decoders[i].stage;
929 info_decoders[i].decode(ctx, inst, p);
930 break;
931 }
932 }
933
934 if (ctx->decode_cfg->command_filter.PassFilter(inst->name) &&
935 ImGui::TreeNodeEx(p,
936 ImGuiTreeNodeFlags_Framed,
937 "0x%012" PRIx64 ": %s",
938 offset, inst->name)) {
939 aub_viewer_print_group(ctx, inst, offset, p);
940
941 for (unsigned i = 0; i < ARRAY_SIZE(display_decoders); i++) {
942 if (strcmp(inst_name, display_decoders[i].cmd_name) == 0) {
943 ctx->stage = display_decoders[i].stage;
944 display_decoders[i].decode(ctx, inst, p);
945 break;
946 }
947 }
948
949 if (ctx->edit_address) {
950 if (ImGui::Button("Edit instruction"))
951 ctx->edit_address(ctx->user_data, offset, length * 4);
952 }
953
954 ImGui::TreePop();
955 }
956
957 if (strcmp(inst_name, "MI_BATCH_BUFFER_START") == 0) {
958 uint64_t next_batch_addr = 0xd0d0d0d0;
959 bool ppgtt = false;
960 bool second_level = false;
961 struct gen_field_iterator iter;
962 gen_field_iterator_init(&iter, inst, p, 0, false);
963 while (gen_field_iterator_next(&iter)) {
964 if (strcmp(iter.name, "Batch Buffer Start Address") == 0) {
965 next_batch_addr = iter.raw_value;
966 } else if (strcmp(iter.name, "Second Level Batch Buffer") == 0) {
967 second_level = iter.raw_value;
968 } else if (strcmp(iter.name, "Address Space Indicator") == 0) {
969 ppgtt = iter.raw_value;
970 }
971 }
972
973 struct gen_batch_decode_bo next_batch = ctx_get_bo(ctx, ppgtt, next_batch_addr);
974
975 if (next_batch.map == NULL) {
976 ImGui::TextColored(ctx->cfg->missing_color,
977 "Secondary batch at 0x%012" PRIx64 " unavailable",
978 next_batch_addr);
979 } else {
980 aub_viewer_render_batch(ctx, next_batch.map, next_batch.size,
981 next_batch.addr, false);
982 }
983 if (second_level) {
984 /* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" set acts
985 * like a subroutine call. Commands that come afterwards get
986 * processed once the 2nd level batch buffer returns with
987 * MI_BATCH_BUFFER_END.
988 */
989 continue;
990 } else if (!from_ring) {
991 /* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" unset acts
992 * like a goto. Nothing after it will ever get processed. In
993 * order to prevent the recursion from growing, we just reset the
994 * loop and continue;
995 */
996 break;
997 }
998 } else if (strcmp(inst_name, "MI_BATCH_BUFFER_END") == 0) {
999 break;
1000 }
1001 }
1002
1003 ctx->n_batch_buffer_start--;
1004 }
1005