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