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