2 * Copyright © 2017 Intel Corporation
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:
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
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
26 #include "util/macros.h"
28 #include "aubinator_viewer.h"
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),
40 memset(ctx
, 0, sizeof(*ctx
));
43 ctx
->get_state_size
= get_state_size
;
44 ctx
->user_data
= user_data
;
45 ctx
->engine
= I915_ENGINE_CLASS_RENDER
;
48 ctx
->decode_cfg
= decode_cfg
;
54 aub_viewer_print_group(struct aub_viewer_decode_ctx
*ctx
,
55 struct gen_group
*group
,
56 uint64_t address
, const void *map
)
58 struct gen_field_iterator iter
;
60 const uint32_t *p
= (const uint32_t *) map
;
62 gen_field_iterator_init(&iter
, group
, p
, 0, false);
63 while (gen_field_iterator_next(&iter
)) {
64 if (ctx
->decode_cfg
->show_dwords
) {
65 int iter_dword
= iter
.end_bit
/ 32;
66 if (last_dword
!= iter_dword
) {
67 for (int i
= last_dword
+ 1; i
<= iter_dword
; i
++) {
68 ImGui::TextColored(ctx
->cfg
->dwords_color
,
69 "0x%012" PRIx64
": 0x%012x : Dword %d",
70 address
+ 4 * i
, iter
.p
[i
], i
);
72 last_dword
= iter_dword
;
75 if (!gen_field_is_header(iter
.field
)) {
76 if (ctx
->decode_cfg
->field_filter
.PassFilter(iter
.name
)) {
77 if (iter
.field
->type
.kind
== gen_type::GEN_TYPE_BOOL
&& iter
.raw_value
) {
78 ImGui::Text("%s: ", iter
.name
); ImGui::SameLine();
79 ImGui::TextColored(ctx
->cfg
->boolean_color
, "true");
81 ImGui::Text("%s: %s", iter
.name
, iter
.value
);
83 if (iter
.struct_desc
) {
84 int struct_dword
= iter
.start_bit
/ 32;
85 uint64_t struct_address
= address
+ 4 * struct_dword
;
86 aub_viewer_print_group(ctx
, iter
.struct_desc
, struct_address
,
94 static struct gen_batch_decode_bo
95 ctx_get_bo(struct aub_viewer_decode_ctx
*ctx
, uint64_t addr
)
97 if (gen_spec_get_gen(ctx
->spec
) >= gen_make_gen(8,0)) {
98 /* On Broadwell and above, we have 48-bit addresses which consume two
99 * dwords. Some packets require that these get stored in a "canonical
100 * form" which means that bit 47 is sign-extended through the upper
101 * bits. In order to correctly handle those aub dumps, we need to mask
102 * off the top 16 bits.
104 addr
&= (~0ull >> 16);
107 struct gen_batch_decode_bo bo
= ctx
->get_bo(ctx
->user_data
, addr
);
109 if (gen_spec_get_gen(ctx
->spec
) >= gen_make_gen(8,0))
110 bo
.addr
&= (~0ull >> 16);
112 /* We may actually have an offset into the bo */
113 if (bo
.map
!= NULL
) {
114 assert(bo
.addr
<= addr
);
115 uint64_t offset
= addr
- bo
.addr
;
116 bo
.map
= (const uint8_t *)bo
.map
+ offset
;
125 update_count(struct aub_viewer_decode_ctx
*ctx
,
126 uint32_t offset_from_dsba
,
127 unsigned element_dwords
,
132 if (ctx
->get_state_size
)
133 size
= ctx
->get_state_size(ctx
->user_data
, offset_from_dsba
);
136 return size
/ (sizeof(uint32_t) * element_dwords
);
138 /* In the absence of any information, just guess arbitrarily. */
143 ctx_disassemble_program(struct aub_viewer_decode_ctx
*ctx
,
144 uint32_t ksp
, const char *type
)
146 uint64_t addr
= ctx
->instruction_base
+ ksp
;
147 struct gen_batch_decode_bo bo
= ctx_get_bo(ctx
, addr
);
149 ImGui::TextColored(ctx
->cfg
->missing_color
,
150 "Shader unavailable addr=0x%012" PRIx64
, addr
);
155 if (ImGui::Button(type
) && ctx
->display_shader
)
156 ctx
->display_shader(ctx
->user_data
, type
, addr
);
161 handle_state_base_address(struct aub_viewer_decode_ctx
*ctx
,
162 struct gen_group
*inst
,
165 struct gen_field_iterator iter
;
166 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
168 uint64_t surface_base
= 0, dynamic_base
= 0, instruction_base
= 0;
169 bool surface_modify
= 0, dynamic_modify
= 0, instruction_modify
= 0;
171 while (gen_field_iterator_next(&iter
)) {
172 if (strcmp(iter
.name
, "Surface State Base Address") == 0) {
173 surface_base
= iter
.raw_value
;
174 } else if (strcmp(iter
.name
, "Dynamic State Base Address") == 0) {
175 dynamic_base
= iter
.raw_value
;
176 } else if (strcmp(iter
.name
, "Instruction Base Address") == 0) {
177 instruction_base
= iter
.raw_value
;
178 } else if (strcmp(iter
.name
, "Surface State Base Address Modify Enable") == 0) {
179 surface_modify
= iter
.raw_value
;
180 } else if (strcmp(iter
.name
, "Dynamic State Base Address Modify Enable") == 0) {
181 dynamic_modify
= iter
.raw_value
;
182 } else if (strcmp(iter
.name
, "Instruction Base Address Modify Enable") == 0) {
183 instruction_modify
= iter
.raw_value
;
188 ctx
->dynamic_base
= dynamic_base
;
191 ctx
->surface_base
= surface_base
;
193 if (instruction_modify
)
194 ctx
->instruction_base
= instruction_base
;
198 dump_binding_table(struct aub_viewer_decode_ctx
*ctx
, uint32_t offset
, int count
)
200 struct gen_group
*strct
=
201 gen_spec_find_struct(ctx
->spec
, "RENDER_SURFACE_STATE");
203 ImGui::TextColored(ctx
->cfg
->missing_color
, "did not find RENDER_SURFACE_STATE info");
208 count
= update_count(ctx
, offset
, 1, 8);
210 if (offset
% 32 != 0 || offset
>= UINT16_MAX
) {
211 ImGui::TextColored(ctx
->cfg
->missing_color
, "invalid binding table pointer");
215 struct gen_batch_decode_bo bind_bo
=
216 ctx_get_bo(ctx
, ctx
->surface_base
+ offset
);
218 if (bind_bo
.map
== NULL
) {
219 ImGui::TextColored(ctx
->cfg
->missing_color
,
220 "binding table unavailable addr=0x%012" PRIx64
,
221 ctx
->surface_base
+ offset
);
225 const uint32_t *pointers
= (const uint32_t *) bind_bo
.map
;
226 for (int i
= 0; i
< count
; i
++) {
227 if (pointers
[i
] == 0)
230 uint64_t addr
= ctx
->surface_base
+ pointers
[i
];
231 struct gen_batch_decode_bo bo
= ctx_get_bo(ctx
, addr
);
232 uint32_t size
= strct
->dw_length
* 4;
234 if (pointers
[i
] % 32 != 0 ||
235 addr
< bo
.addr
|| addr
+ size
>= bo
.addr
+ bo
.size
) {
236 ImGui::TextColored(ctx
->cfg
->missing_color
,
237 "pointer %u: %012x <not valid>", i
, pointers
[i
]);
241 const uint8_t *state
= (const uint8_t *) bo
.map
+ (addr
- bo
.addr
);
242 if (ImGui::TreeNodeEx(&pointers
[i
], ImGuiTreeNodeFlags_Framed
,
243 "pointer %u: %012x", i
, pointers
[i
])) {
244 aub_viewer_print_group(ctx
, strct
, addr
, state
);
251 dump_samplers(struct aub_viewer_decode_ctx
*ctx
, uint32_t offset
, int count
)
253 struct gen_group
*strct
= gen_spec_find_struct(ctx
->spec
, "SAMPLER_STATE");
256 count
= update_count(ctx
, offset
, strct
->dw_length
, 4);
258 uint64_t state_addr
= ctx
->dynamic_base
+ offset
;
259 struct gen_batch_decode_bo bo
= ctx_get_bo(ctx
, state_addr
);
260 const uint8_t *state_map
= (const uint8_t *) bo
.map
;
262 if (state_map
== NULL
) {
263 ImGui::TextColored(ctx
->cfg
->missing_color
,
264 "samplers unavailable addr=0x%012" PRIx64
, state_addr
);
268 if (offset
% 32 != 0 || state_addr
- bo
.addr
>= bo
.size
) {
269 ImGui::TextColored(ctx
->cfg
->missing_color
, "invalid sampler state pointer");
273 for (int i
= 0; i
< count
; i
++) {
274 if (ImGui::TreeNodeEx(state_map
, ImGuiTreeNodeFlags_Framed
,
275 "sampler state %d", i
)) {
276 aub_viewer_print_group(ctx
, strct
, state_addr
, state_map
);
285 handle_media_interface_descriptor_load(struct aub_viewer_decode_ctx
*ctx
,
286 struct gen_group
*inst
,
289 struct gen_group
*desc
=
290 gen_spec_find_struct(ctx
->spec
, "INTERFACE_DESCRIPTOR_DATA");
292 struct gen_field_iterator iter
;
293 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
294 uint32_t descriptor_offset
= 0;
295 int descriptor_count
= 0;
296 while (gen_field_iterator_next(&iter
)) {
297 if (strcmp(iter
.name
, "Interface Descriptor Data Start Address") == 0) {
298 descriptor_offset
= strtol(iter
.value
, NULL
, 16);
299 } else if (strcmp(iter
.name
, "Interface Descriptor Total Length") == 0) {
301 strtol(iter
.value
, NULL
, 16) / (desc
->dw_length
* 4);
305 uint64_t desc_addr
= ctx
->dynamic_base
+ descriptor_offset
;
306 struct gen_batch_decode_bo bo
= ctx_get_bo(ctx
, desc_addr
);
307 const uint32_t *desc_map
= (const uint32_t *) bo
.map
;
309 if (desc_map
== NULL
) {
310 ImGui::TextColored(ctx
->cfg
->missing_color
,
311 "interface descriptors unavailable addr=0x%012" PRIx64
, desc_addr
);
315 for (int i
= 0; i
< descriptor_count
; i
++) {
316 ImGui::Text("descriptor %d: %012x", i
, descriptor_offset
);
318 aub_viewer_print_group(ctx
, desc
, desc_addr
, desc_map
);
320 gen_field_iterator_init(&iter
, desc
, desc_map
, 0, false);
322 uint32_t sampler_offset
= 0, sampler_count
= 0;
323 uint32_t binding_table_offset
= 0, binding_entry_count
= 0;
324 while (gen_field_iterator_next(&iter
)) {
325 if (strcmp(iter
.name
, "Kernel Start Pointer") == 0) {
326 ksp
= strtoll(iter
.value
, NULL
, 16);
327 } else if (strcmp(iter
.name
, "Sampler State Pointer") == 0) {
328 sampler_offset
= strtol(iter
.value
, NULL
, 16);
329 } else if (strcmp(iter
.name
, "Sampler Count") == 0) {
330 sampler_count
= strtol(iter
.value
, NULL
, 10);
331 } else if (strcmp(iter
.name
, "Binding Table Pointer") == 0) {
332 binding_table_offset
= strtol(iter
.value
, NULL
, 16);
333 } else if (strcmp(iter
.name
, "Binding Table Entry Count") == 0) {
334 binding_entry_count
= strtol(iter
.value
, NULL
, 10);
338 ctx_disassemble_program(ctx
, ksp
, "compute shader");
340 dump_samplers(ctx
, sampler_offset
, sampler_count
);
341 dump_binding_table(ctx
, binding_table_offset
, binding_entry_count
);
343 desc_map
+= desc
->dw_length
;
344 desc_addr
+= desc
->dw_length
* 4;
349 handle_3dstate_vertex_buffers(struct aub_viewer_decode_ctx
*ctx
,
350 struct gen_group
*inst
,
353 struct gen_group
*vbs
= gen_spec_find_struct(ctx
->spec
, "VERTEX_BUFFER_STATE");
355 struct gen_batch_decode_bo vb
= {};
356 uint32_t vb_size
= 0;
361 struct gen_field_iterator iter
;
362 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
363 while (gen_field_iterator_next(&iter
)) {
364 if (iter
.struct_desc
!= vbs
)
367 uint64_t buffer_addr
;
369 struct gen_field_iterator vbs_iter
;
370 gen_field_iterator_init(&vbs_iter
, vbs
, &iter
.p
[iter
.start_bit
/ 32], 0, false);
371 while (gen_field_iterator_next(&vbs_iter
)) {
372 if (strcmp(vbs_iter
.name
, "Vertex Buffer Index") == 0) {
373 index
= vbs_iter
.raw_value
;
374 } else if (strcmp(vbs_iter
.name
, "Buffer Pitch") == 0) {
375 pitch
= vbs_iter
.raw_value
;
376 } else if (strcmp(vbs_iter
.name
, "Buffer Starting Address") == 0) {
377 buffer_addr
= vbs_iter
.raw_value
;
378 vb
= ctx_get_bo(ctx
, buffer_addr
);
379 } else if (strcmp(vbs_iter
.name
, "Buffer Size") == 0) {
380 vb_size
= vbs_iter
.raw_value
;
382 } else if (strcmp(vbs_iter
.name
, "End Address") == 0) {
383 if (vb
.map
&& vbs_iter
.raw_value
>= vb
.addr
)
384 vb_size
= vbs_iter
.raw_value
- vb
.addr
;
393 ImGui::Text("vertex buffer %d, size %d, pitch %d", index
, vb_size
, pitch
);
395 if (vb
.map
== NULL
) {
396 ImGui::TextColored(ctx
->cfg
->missing_color
,
397 "buffer contents unavailable addr=0x%012" PRIx64
, buffer_addr
);
401 if (vb
.map
== 0 || vb_size
== 0)
414 handle_3dstate_index_buffer(struct aub_viewer_decode_ctx
*ctx
,
415 struct gen_group
*inst
,
418 struct gen_batch_decode_bo ib
= {};
419 uint64_t buffer_addr
= 0;
420 uint32_t ib_size
= 0;
423 struct gen_field_iterator iter
;
424 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
425 while (gen_field_iterator_next(&iter
)) {
426 if (strcmp(iter
.name
, "Index Format") == 0) {
427 format
= iter
.raw_value
;
428 } else if (strcmp(iter
.name
, "Buffer Starting Address") == 0) {
429 buffer_addr
= iter
.raw_value
;
430 ib
= ctx_get_bo(ctx
, buffer_addr
);
431 } else if (strcmp(iter
.name
, "Buffer Size") == 0) {
432 ib_size
= iter
.raw_value
;
436 if (ib
.map
== NULL
) {
437 ImGui::TextColored(ctx
->cfg
->missing_color
,
438 "buffer contents unavailable addr=0x%012" PRIx64
,
443 const uint8_t *m
= (const uint8_t *) ib
.map
;
444 const uint8_t *ib_end
= m
+ MIN2(ib
.size
, ib_size
);
445 for (int i
= 0; m
< ib_end
&& i
< 10; i
++) {
461 decode_single_ksp(struct aub_viewer_decode_ctx
*ctx
,
462 struct gen_group
*inst
,
466 bool is_simd8
= false; /* vertex shaders on Gen8+ only */
467 bool is_enabled
= true;
469 struct gen_field_iterator iter
;
470 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
471 while (gen_field_iterator_next(&iter
)) {
472 if (strcmp(iter
.name
, "Kernel Start Pointer") == 0) {
473 ksp
= iter
.raw_value
;
474 } else if (strcmp(iter
.name
, "SIMD8 Dispatch Enable") == 0) {
475 is_simd8
= iter
.raw_value
;
476 } else if (strcmp(iter
.name
, "Dispatch Mode") == 0) {
477 is_simd8
= strcmp(iter
.value
, "SIMD8") == 0;
478 } else if (strcmp(iter
.name
, "Dispatch Enable") == 0) {
479 is_simd8
= strcmp(iter
.value
, "SIMD8") == 0;
480 } else if (strcmp(iter
.name
, "Enable") == 0) {
481 is_enabled
= iter
.raw_value
;
486 strcmp(inst
->name
, "VS_STATE") == 0 ? "vertex shader" :
487 strcmp(inst
->name
, "GS_STATE") == 0 ? "geometry shader" :
488 strcmp(inst
->name
, "SF_STATE") == 0 ? "strips and fans shader" :
489 strcmp(inst
->name
, "CLIP_STATE") == 0 ? "clip shader" :
490 strcmp(inst
->name
, "3DSTATE_DS") == 0 ? "tessellation evaluation shader" :
491 strcmp(inst
->name
, "3DSTATE_HS") == 0 ? "tessellation control shader" :
492 strcmp(inst
->name
, "3DSTATE_VS") == 0 ? (is_simd8
? "SIMD8 vertex shader" : "vec4 vertex shader") :
493 strcmp(inst
->name
, "3DSTATE_GS") == 0 ? (is_simd8
? "SIMD8 geometry shader" : "vec4 geometry shader") :
497 ctx_disassemble_program(ctx
, ksp
, type
);
501 decode_ps_kernels(struct aub_viewer_decode_ctx
*ctx
,
502 struct gen_group
*inst
,
505 uint64_t ksp
[3] = {0, 0, 0};
506 bool enabled
[3] = {false, false, false};
508 struct gen_field_iterator iter
;
509 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
510 while (gen_field_iterator_next(&iter
)) {
511 if (strncmp(iter
.name
, "Kernel Start Pointer ",
512 strlen("Kernel Start Pointer ")) == 0) {
513 int idx
= iter
.name
[strlen("Kernel Start Pointer ")] - '0';
514 ksp
[idx
] = strtol(iter
.value
, NULL
, 16);
515 } else if (strcmp(iter
.name
, "8 Pixel Dispatch Enable") == 0) {
516 enabled
[0] = strcmp(iter
.value
, "true") == 0;
517 } else if (strcmp(iter
.name
, "16 Pixel Dispatch Enable") == 0) {
518 enabled
[1] = strcmp(iter
.value
, "true") == 0;
519 } else if (strcmp(iter
.name
, "32 Pixel Dispatch Enable") == 0) {
520 enabled
[2] = strcmp(iter
.value
, "true") == 0;
524 /* Reorder KSPs to be [8, 16, 32] instead of the hardware order. */
525 if (enabled
[0] + enabled
[1] + enabled
[2] == 1) {
529 } else if (enabled
[2]) {
534 uint64_t tmp
= ksp
[1];
540 ctx_disassemble_program(ctx
, ksp
[0], "SIMD8 fragment shader");
542 ctx_disassemble_program(ctx
, ksp
[1], "SIMD16 fragment shader");
544 ctx_disassemble_program(ctx
, ksp
[2], "SIMD32 fragment shader");
548 decode_3dstate_constant(struct aub_viewer_decode_ctx
*ctx
,
549 struct gen_group
*inst
,
552 struct gen_group
*body
=
553 gen_spec_find_struct(ctx
->spec
, "3DSTATE_CONSTANT_BODY");
555 uint32_t read_length
[4] = {0};
556 uint64_t read_addr
[4];
558 struct gen_field_iterator outer
;
559 gen_field_iterator_init(&outer
, inst
, p
, 0, false);
560 while (gen_field_iterator_next(&outer
)) {
561 if (outer
.struct_desc
!= body
)
564 struct gen_field_iterator iter
;
565 gen_field_iterator_init(&iter
, body
, &outer
.p
[outer
.start_bit
/ 32],
568 while (gen_field_iterator_next(&iter
)) {
570 if (sscanf(iter
.name
, "Read Length[%d]", &idx
) == 1) {
571 read_length
[idx
] = iter
.raw_value
;
572 } else if (sscanf(iter
.name
, "Buffer[%d]", &idx
) == 1) {
573 read_addr
[idx
] = iter
.raw_value
;
577 for (int i
= 0; i
< 4; i
++) {
578 if (read_length
[i
] == 0)
581 struct gen_batch_decode_bo buffer
= ctx_get_bo(ctx
, read_addr
[i
]);
583 ImGui::TextColored(ctx
->cfg
->missing_color
,
584 "constant buffer %d unavailable addr=0x%012" PRIx64
,
589 unsigned size
= read_length
[i
] * 32;
590 ImGui::Text("constant buffer %d, size %u", i
, size
);
592 if (ctx
->edit_address
) {
593 if (ImGui::Button("Show/Edit buffer"))
594 ctx
->edit_address(ctx
->user_data
, read_addr
[i
], size
);
601 decode_3dstate_binding_table_pointers(struct aub_viewer_decode_ctx
*ctx
,
602 struct gen_group
*inst
,
605 dump_binding_table(ctx
, p
[1], -1);
609 decode_3dstate_sampler_state_pointers(struct aub_viewer_decode_ctx
*ctx
,
610 struct gen_group
*inst
,
613 dump_samplers(ctx
, p
[1], -1);
617 decode_3dstate_sampler_state_pointers_gen6(struct aub_viewer_decode_ctx
*ctx
,
618 struct gen_group
*inst
,
621 dump_samplers(ctx
, p
[1], -1);
622 dump_samplers(ctx
, p
[2], -1);
623 dump_samplers(ctx
, p
[3], -1);
627 str_ends_with(const char *str
, const char *end
)
629 int offset
= strlen(str
) - strlen(end
);
633 return strcmp(str
+ offset
, end
) == 0;
637 decode_dynamic_state_pointers(struct aub_viewer_decode_ctx
*ctx
,
638 struct gen_group
*inst
, const uint32_t *p
,
639 const char *struct_type
, int count
)
641 uint32_t state_offset
= 0;
643 struct gen_field_iterator iter
;
644 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
645 while (gen_field_iterator_next(&iter
)) {
646 if (str_ends_with(iter
.name
, "Pointer")) {
647 state_offset
= iter
.raw_value
;
652 uint64_t state_addr
= ctx
->dynamic_base
+ state_offset
;
653 struct gen_batch_decode_bo bo
= ctx_get_bo(ctx
, state_addr
);
654 const uint8_t *state_map
= (const uint8_t *) bo
.map
;
656 if (state_map
== NULL
) {
657 ImGui::TextColored(ctx
->cfg
->missing_color
,
658 "dynamic %s state unavailable addr=0x%012" PRIx64
,
659 struct_type
, state_addr
);
663 struct gen_group
*state
= gen_spec_find_struct(ctx
->spec
, struct_type
);
664 if (strcmp(struct_type
, "BLEND_STATE") == 0) {
665 /* Blend states are different from the others because they have a header
666 * struct called BLEND_STATE which is followed by a variable number of
667 * BLEND_STATE_ENTRY structs.
669 ImGui::Text("%s", struct_type
);
670 aub_viewer_print_group(ctx
, state
, state_addr
, state_map
);
672 state_addr
+= state
->dw_length
* 4;
673 state_map
+= state
->dw_length
* 4;
675 struct_type
= "BLEND_STATE_ENTRY";
676 state
= gen_spec_find_struct(ctx
->spec
, struct_type
);
679 for (int i
= 0; i
< count
; i
++) {
680 ImGui::Text("%s %d", struct_type
, i
);
681 aub_viewer_print_group(ctx
, state
, state_addr
, state_map
);
683 state_addr
+= state
->dw_length
* 4;
684 state_map
+= state
->dw_length
* 4;
689 decode_3dstate_viewport_state_pointers_cc(struct aub_viewer_decode_ctx
*ctx
,
690 struct gen_group
*inst
,
693 decode_dynamic_state_pointers(ctx
, inst
, p
, "CC_VIEWPORT", 4);
697 decode_3dstate_viewport_state_pointers_sf_clip(struct aub_viewer_decode_ctx
*ctx
,
698 struct gen_group
*inst
,
701 decode_dynamic_state_pointers(ctx
, inst
, p
, "SF_CLIP_VIEWPORT", 4);
705 decode_3dstate_blend_state_pointers(struct aub_viewer_decode_ctx
*ctx
,
706 struct gen_group
*inst
,
709 decode_dynamic_state_pointers(ctx
, inst
, p
, "BLEND_STATE", 1);
713 decode_3dstate_cc_state_pointers(struct aub_viewer_decode_ctx
*ctx
,
714 struct gen_group
*inst
,
717 decode_dynamic_state_pointers(ctx
, inst
, p
, "COLOR_CALC_STATE", 1);
721 decode_3dstate_scissor_state_pointers(struct aub_viewer_decode_ctx
*ctx
,
722 struct gen_group
*inst
,
725 decode_dynamic_state_pointers(ctx
, inst
, p
, "SCISSOR_RECT", 1);
729 decode_load_register_imm(struct aub_viewer_decode_ctx
*ctx
,
730 struct gen_group
*inst
,
733 struct gen_group
*reg
= gen_spec_find_register(ctx
->spec
, p
[1]);
736 ImGui::TreeNodeEx(&p
[1], ImGuiTreeNodeFlags_Framed
,
738 reg
->name
, reg
->register_offset
, p
[2])) {
739 aub_viewer_print_group(ctx
, reg
, reg
->register_offset
, &p
[2]);
745 decode_3dprimitive(struct aub_viewer_decode_ctx
*ctx
,
746 struct gen_group
*inst
,
749 if (ctx
->display_urb
) {
750 if (ImGui::Button("Show URB"))
751 ctx
->display_urb(ctx
->user_data
, ctx
->urb_stages
);
756 handle_urb(struct aub_viewer_decode_ctx
*ctx
,
757 struct gen_group
*inst
,
760 struct gen_field_iterator iter
;
761 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
762 while (gen_field_iterator_next(&iter
)) {
763 if (strstr(iter
.name
, "URB Starting Address")) {
764 ctx
->urb_stages
[ctx
->stage
].start
= iter
.raw_value
* 8192;
765 } else if (strstr(iter
.name
, "URB Entry Allocation Size")) {
766 ctx
->urb_stages
[ctx
->stage
].size
= (iter
.raw_value
+ 1) * 64;
767 } else if (strstr(iter
.name
, "Number of URB Entries")) {
768 ctx
->urb_stages
[ctx
->stage
].n_entries
= iter
.raw_value
;
772 ctx
->end_urb_offset
= MAX2(ctx
->urb_stages
[ctx
->stage
].start
+
773 ctx
->urb_stages
[ctx
->stage
].n_entries
*
774 ctx
->urb_stages
[ctx
->stage
].size
,
775 ctx
->end_urb_offset
);
779 handle_urb_read(struct aub_viewer_decode_ctx
*ctx
,
780 struct gen_group
*inst
,
783 struct gen_field_iterator iter
;
784 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
785 while (gen_field_iterator_next(&iter
)) {
786 /* Workaround the "Force * URB Entry Read Length" fields */
787 if (iter
.end_bit
- iter
.start_bit
< 2)
790 if (strstr(iter
.name
, "URB Entry Read Offset")) {
791 ctx
->urb_stages
[ctx
->stage
].rd_offset
= iter
.raw_value
* 32;
792 } else if (strstr(iter
.name
, "URB Entry Read Length")) {
793 ctx
->urb_stages
[ctx
->stage
].rd_length
= iter
.raw_value
* 32;
794 } else if (strstr(iter
.name
, "URB Entry Output Read Offset")) {
795 ctx
->urb_stages
[ctx
->stage
].wr_offset
= iter
.raw_value
* 32;
796 } else if (strstr(iter
.name
, "URB Entry Output Length")) {
797 ctx
->urb_stages
[ctx
->stage
].wr_length
= iter
.raw_value
* 32;
803 handle_urb_constant(struct aub_viewer_decode_ctx
*ctx
,
804 struct gen_group
*inst
,
807 struct gen_group
*body
=
808 gen_spec_find_struct(ctx
->spec
, "3DSTATE_CONSTANT_BODY");
810 struct gen_field_iterator outer
;
811 gen_field_iterator_init(&outer
, inst
, p
, 0, false);
812 while (gen_field_iterator_next(&outer
)) {
813 if (outer
.struct_desc
!= body
)
816 struct gen_field_iterator iter
;
817 gen_field_iterator_init(&iter
, body
, &outer
.p
[outer
.start_bit
/ 32],
820 ctx
->urb_stages
[ctx
->stage
].const_rd_length
= 0;
821 while (gen_field_iterator_next(&iter
)) {
823 if (sscanf(iter
.name
, "Read Length[%d]", &idx
) == 1) {
824 ctx
->urb_stages
[ctx
->stage
].const_rd_length
+= iter
.raw_value
* 32;
830 struct custom_decoder
{
831 const char *cmd_name
;
832 void (*decode
)(struct aub_viewer_decode_ctx
*ctx
,
833 struct gen_group
*inst
,
835 enum aub_decode_stage stage
;
836 } display_decoders
[] = {
837 { "STATE_BASE_ADDRESS", handle_state_base_address
},
838 { "MEDIA_INTERFACE_DESCRIPTOR_LOAD", handle_media_interface_descriptor_load
},
839 { "3DSTATE_VERTEX_BUFFERS", handle_3dstate_vertex_buffers
},
840 { "3DSTATE_INDEX_BUFFER", handle_3dstate_index_buffer
},
841 { "3DSTATE_VS", decode_single_ksp
, AUB_DECODE_STAGE_VS
, },
842 { "3DSTATE_GS", decode_single_ksp
, AUB_DECODE_STAGE_GS
, },
843 { "3DSTATE_DS", decode_single_ksp
, AUB_DECODE_STAGE_DS
, },
844 { "3DSTATE_HS", decode_single_ksp
, AUB_DECODE_STAGE_HS
, },
845 { "3DSTATE_PS", decode_ps_kernels
, AUB_DECODE_STAGE_PS
, },
846 { "3DSTATE_CONSTANT_VS", decode_3dstate_constant
, AUB_DECODE_STAGE_VS
, },
847 { "3DSTATE_CONSTANT_GS", decode_3dstate_constant
, AUB_DECODE_STAGE_GS
, },
848 { "3DSTATE_CONSTANT_DS", decode_3dstate_constant
, AUB_DECODE_STAGE_DS
, },
849 { "3DSTATE_CONSTANT_HS", decode_3dstate_constant
, AUB_DECODE_STAGE_HS
, },
850 { "3DSTATE_CONSTANT_PS", decode_3dstate_constant
, AUB_DECODE_STAGE_PS
, },
852 { "3DSTATE_BINDING_TABLE_POINTERS_VS", decode_3dstate_binding_table_pointers
, AUB_DECODE_STAGE_VS
, },
853 { "3DSTATE_BINDING_TABLE_POINTERS_GS", decode_3dstate_binding_table_pointers
, AUB_DECODE_STAGE_GS
, },
854 { "3DSTATE_BINDING_TABLE_POINTERS_HS", decode_3dstate_binding_table_pointers
, AUB_DECODE_STAGE_HS
, },
855 { "3DSTATE_BINDING_TABLE_POINTERS_DS", decode_3dstate_binding_table_pointers
, AUB_DECODE_STAGE_DS
, },
856 { "3DSTATE_BINDING_TABLE_POINTERS_PS", decode_3dstate_binding_table_pointers
, AUB_DECODE_STAGE_PS
, },
858 { "3DSTATE_SAMPLER_STATE_POINTERS_VS", decode_3dstate_sampler_state_pointers
, AUB_DECODE_STAGE_VS
, },
859 { "3DSTATE_SAMPLER_STATE_POINTERS_GS", decode_3dstate_sampler_state_pointers
, AUB_DECODE_STAGE_GS
, },
860 { "3DSTATE_SAMPLER_STATE_POINTERS_DS", decode_3dstate_sampler_state_pointers
, AUB_DECODE_STAGE_DS
, },
861 { "3DSTATE_SAMPLER_STATE_POINTERS_HS", decode_3dstate_sampler_state_pointers
, AUB_DECODE_STAGE_HS
, },
862 { "3DSTATE_SAMPLER_STATE_POINTERS_PS", decode_3dstate_sampler_state_pointers
, AUB_DECODE_STAGE_PS
, },
863 { "3DSTATE_SAMPLER_STATE_POINTERS", decode_3dstate_sampler_state_pointers_gen6
},
865 { "3DSTATE_VIEWPORT_STATE_POINTERS_CC", decode_3dstate_viewport_state_pointers_cc
},
866 { "3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP", decode_3dstate_viewport_state_pointers_sf_clip
},
867 { "3DSTATE_BLEND_STATE_POINTERS", decode_3dstate_blend_state_pointers
},
868 { "3DSTATE_CC_STATE_POINTERS", decode_3dstate_cc_state_pointers
},
869 { "3DSTATE_SCISSOR_STATE_POINTERS", decode_3dstate_scissor_state_pointers
},
870 { "MI_LOAD_REGISTER_IMM", decode_load_register_imm
},
871 { "3DPRIMITIVE", decode_3dprimitive
},
874 struct custom_decoder info_decoders
[] = {
875 { "STATE_BASE_ADDRESS", handle_state_base_address
},
876 { "3DSTATE_URB_VS", handle_urb
, AUB_DECODE_STAGE_VS
, },
877 { "3DSTATE_URB_GS", handle_urb
, AUB_DECODE_STAGE_GS
, },
878 { "3DSTATE_URB_DS", handle_urb
, AUB_DECODE_STAGE_DS
, },
879 { "3DSTATE_URB_HS", handle_urb
, AUB_DECODE_STAGE_HS
, },
880 { "3DSTATE_VS", handle_urb_read
, AUB_DECODE_STAGE_VS
, },
881 { "3DSTATE_GS", handle_urb_read
, AUB_DECODE_STAGE_GS
, },
882 { "3DSTATE_DS", handle_urb_read
, AUB_DECODE_STAGE_DS
, },
883 { "3DSTATE_HS", handle_urb_read
, AUB_DECODE_STAGE_HS
, },
884 { "3DSTATE_PS", handle_urb_read
, AUB_DECODE_STAGE_PS
, },
885 { "3DSTATE_CONSTANT_VS", handle_urb_constant
, AUB_DECODE_STAGE_VS
, },
886 { "3DSTATE_CONSTANT_GS", handle_urb_constant
, AUB_DECODE_STAGE_GS
, },
887 { "3DSTATE_CONSTANT_DS", handle_urb_constant
, AUB_DECODE_STAGE_DS
, },
888 { "3DSTATE_CONSTANT_HS", handle_urb_constant
, AUB_DECODE_STAGE_HS
, },
889 { "3DSTATE_CONSTANT_PS", handle_urb_constant
, AUB_DECODE_STAGE_PS
, },
893 aub_viewer_render_batch(struct aub_viewer_decode_ctx
*ctx
,
894 const void *_batch
, uint32_t batch_size
,
897 struct gen_group
*inst
;
898 const uint32_t *p
, *batch
= (const uint32_t *) _batch
, *end
= batch
+ batch_size
/ sizeof(uint32_t);
901 for (p
= batch
; p
< end
; p
+= length
) {
902 inst
= gen_spec_find_instruction(ctx
->spec
, ctx
->engine
, p
);
903 length
= gen_group_get_length(inst
, p
);
904 assert(inst
== NULL
|| length
> 0);
905 length
= MAX2(1, length
);
907 uint64_t offset
= batch_addr
+ ((char *)p
- (char *)batch
);
910 ImGui::TextColored(ctx
->cfg
->error_color
,
911 "0x%012" PRIx64
": unknown instruction %012x",
916 const char *inst_name
= gen_group_get_name(inst
);
918 for (unsigned i
= 0; i
< ARRAY_SIZE(info_decoders
); i
++) {
919 if (strcmp(inst_name
, info_decoders
[i
].cmd_name
) == 0) {
920 ctx
->stage
= info_decoders
[i
].stage
;
921 info_decoders
[i
].decode(ctx
, inst
, p
);
926 if (ctx
->decode_cfg
->command_filter
.PassFilter(inst
->name
) &&
928 ImGuiTreeNodeFlags_Framed
,
929 "0x%012" PRIx64
": %s",
930 offset
, inst
->name
)) {
931 aub_viewer_print_group(ctx
, inst
, offset
, p
);
933 for (unsigned i
= 0; i
< ARRAY_SIZE(display_decoders
); i
++) {
934 if (strcmp(inst_name
, display_decoders
[i
].cmd_name
) == 0) {
935 ctx
->stage
= display_decoders
[i
].stage
;
936 display_decoders
[i
].decode(ctx
, inst
, p
);
941 if (ctx
->edit_address
) {
942 if (ImGui::Button("Edit instruction"))
943 ctx
->edit_address(ctx
->user_data
, offset
, length
* 4);
949 if (strcmp(inst_name
, "MI_BATCH_BUFFER_START") == 0) {
950 struct gen_batch_decode_bo next_batch
= {};
952 struct gen_field_iterator iter
;
953 gen_field_iterator_init(&iter
, inst
, p
, 0, false);
954 while (gen_field_iterator_next(&iter
)) {
955 if (strcmp(iter
.name
, "Batch Buffer Start Address") == 0) {
956 next_batch
= ctx_get_bo(ctx
, iter
.raw_value
);
957 } else if (strcmp(iter
.name
, "Second Level Batch Buffer") == 0) {
958 second_level
= iter
.raw_value
;
962 if (next_batch
.map
== NULL
) {
963 ImGui::TextColored(ctx
->cfg
->missing_color
,
964 "Secondary batch at 0x%012" PRIx64
" unavailable",
967 aub_viewer_render_batch(ctx
, next_batch
.map
, next_batch
.size
,
971 /* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" set acts
972 * like a subroutine call. Commands that come afterwards get
973 * processed once the 2nd level batch buffer returns with
974 * MI_BATCH_BUFFER_END.
978 /* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" unset acts
979 * like a goto. Nothing after it will ever get processed. In
980 * order to prevent the recursion from growing, we just reset the
985 } else if (strcmp(inst_name
, "MI_BATCH_BUFFER_END") == 0) {