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