#include "common/gen_decoder.h"
#include "gen_disasm.h"
#include "util/macros.h"
+#include "main/macros.h" /* Needed for ROUND_DOWN_TO */
#include <string.h>
FILE *fp, enum gen_batch_decode_flags flags,
const char *xml_path,
struct gen_batch_decode_bo (*get_bo)(void *,
+ bool,
uint64_t),
unsigned (*get_state_size)(void *, uint32_t),
void *user_data)
}
static struct gen_batch_decode_bo
-ctx_get_bo(struct gen_batch_decode_ctx *ctx, uint64_t addr)
+ctx_get_bo(struct gen_batch_decode_ctx *ctx, bool ppgtt, uint64_t addr)
{
if (gen_spec_get_gen(ctx->spec) >= gen_make_gen(8,0)) {
/* On Broadwell and above, we have 48-bit addresses which consume two
addr &= (~0ull >> 16);
}
- struct gen_batch_decode_bo bo = ctx->get_bo(ctx->user_data, addr);
+ struct gen_batch_decode_bo bo = ctx->get_bo(ctx->user_data, ppgtt, addr);
if (gen_spec_get_gen(ctx->spec) >= gen_make_gen(8,0))
bo.addr &= (~0ull >> 16);
uint32_t ksp, const char *type)
{
uint64_t addr = ctx->instruction_base + ksp;
- struct gen_batch_decode_bo bo = ctx_get_bo(ctx, addr);
+ struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, addr);
if (!bo.map)
return;
uint32_t pitch,
int max_lines)
{
- const uint32_t *dw_end = bo.map + MIN2(bo.size, read_length);
+ const uint32_t *dw_end =
+ bo.map + ROUND_DOWN_TO(MIN2(bo.size, read_length), 4);
int column_count = 0, line_count = -1;
for (const uint32_t *dw = bo.map; dw < dw_end; dw++) {
}
struct gen_batch_decode_bo bind_bo =
- ctx_get_bo(ctx, ctx->surface_base + offset);
+ ctx_get_bo(ctx, true, ctx->surface_base + offset);
if (bind_bo.map == NULL) {
fprintf(ctx->fp, " binding table unavailable\n");
continue;
uint64_t addr = ctx->surface_base + pointers[i];
- struct gen_batch_decode_bo bo = ctx_get_bo(ctx, addr);
+ struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, addr);
uint32_t size = strct->dw_length * 4;
if (pointers[i] % 32 != 0 ||
count = update_count(ctx, offset, strct->dw_length, 4);
uint64_t state_addr = ctx->dynamic_base + offset;
- struct gen_batch_decode_bo bo = ctx_get_bo(ctx, state_addr);
+ struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, state_addr);
const void *state_map = bo.map;
if (state_map == NULL) {
}
uint64_t desc_addr = ctx->dynamic_base + descriptor_offset;
- struct gen_batch_decode_bo bo = ctx_get_bo(ctx, desc_addr);
+ struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, desc_addr);
const void *desc_map = bo.map;
if (desc_map == NULL) {
} else if (strcmp(vbs_iter.name, "Buffer Pitch") == 0) {
pitch = vbs_iter.raw_value;
} else if (strcmp(vbs_iter.name, "Buffer Starting Address") == 0) {
- vb = ctx_get_bo(ctx, vbs_iter.raw_value);
+ vb = ctx_get_bo(ctx, true, vbs_iter.raw_value);
} else if (strcmp(vbs_iter.name, "Buffer Size") == 0) {
vb_size = vbs_iter.raw_value;
ready = true;
} else if (strcmp(vbs_iter.name, "End Address") == 0) {
if (vb.map && vbs_iter.raw_value >= vb.addr)
- vb_size = vbs_iter.raw_value - vb.addr;
+ vb_size = (vbs_iter.raw_value + 1) - vb.addr;
else
vb_size = 0;
ready = true;
if (strcmp(iter.name, "Index Format") == 0) {
format = iter.raw_value;
} else if (strcmp(iter.name, "Buffer Starting Address") == 0) {
- ib = ctx_get_bo(ctx, iter.raw_value);
+ ib = ctx_get_bo(ctx, true, iter.raw_value);
} else if (strcmp(iter.name, "Buffer Size") == 0) {
ib_size = iter.raw_value;
}
ctx_disassemble_program(ctx, ksp[1], "SIMD16 fragment shader");
if (enabled[2])
ctx_disassemble_program(ctx, ksp[2], "SIMD32 fragment shader");
- fprintf(ctx->fp, "\n");
+
+ if (enabled[0] || enabled[1] || enabled[2])
+ fprintf(ctx->fp, "\n");
+}
+
+static void
+decode_3dstate_constant_all(struct gen_batch_decode_ctx *ctx, const uint32_t *p)
+{
+ struct gen_group *inst =
+ gen_spec_find_instruction(ctx->spec, ctx->engine, p);
+ struct gen_group *body =
+ gen_spec_find_struct(ctx->spec, "3DSTATE_CONSTANT_ALL_DATA");
+
+ uint32_t read_length[4];
+ struct gen_batch_decode_bo buffer[4];
+ memset(buffer, 0, sizeof(buffer));
+
+ struct gen_field_iterator outer;
+ gen_field_iterator_init(&outer, inst, p, 0, false);
+ int idx = 0;
+ while (gen_field_iterator_next(&outer)) {
+ if (outer.struct_desc != body)
+ continue;
+
+ struct gen_field_iterator iter;
+ gen_field_iterator_init(&iter, body, &outer.p[outer.start_bit / 32],
+ 0, false);
+ while (gen_field_iterator_next(&iter)) {
+ if (!strcmp(iter.name, "Pointer To Constant Buffer")) {
+ buffer[idx] = ctx_get_bo(ctx, true, iter.raw_value);
+ } else if (!strcmp(iter.name, "Constant Buffer Read Length")) {
+ read_length[idx] = iter.raw_value;
+ }
+ }
+ idx++;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ if (read_length[i] == 0 || buffer[i].map == NULL)
+ continue;
+
+ unsigned size = read_length[i] * 32;
+ fprintf(ctx->fp, "constant buffer %d, size %u\n", i, size);
+
+ ctx_print_buffer(ctx, buffer[i], size, 0, -1);
+ }
}
static void
if (read_length[i] == 0)
continue;
- struct gen_batch_decode_bo buffer = ctx_get_bo(ctx, read_addr[i]);
+ struct gen_batch_decode_bo buffer = ctx_get_bo(ctx, true, read_addr[i]);
if (!buffer.map) {
fprintf(ctx->fp, "constant buffer %d unavailable\n", i);
continue;
}
}
+static void
+decode_gen6_3dstate_binding_table_pointers(struct gen_batch_decode_ctx *ctx,
+ const uint32_t *p)
+{
+ fprintf(ctx->fp, "VS Binding Table:\n");
+ dump_binding_table(ctx, p[1], -1);
+
+ fprintf(ctx->fp, "GS Binding Table:\n");
+ dump_binding_table(ctx, p[2], -1);
+
+ fprintf(ctx->fp, "PS Binding Table:\n");
+ dump_binding_table(ctx, p[3], -1);
+}
+
static void
decode_3dstate_binding_table_pointers(struct gen_batch_decode_ctx *ctx,
const uint32_t *p)
}
uint64_t state_addr = ctx->dynamic_base + state_offset;
- struct gen_batch_decode_bo bo = ctx_get_bo(ctx, state_addr);
+ struct gen_batch_decode_bo bo = ctx_get_bo(ctx, true, state_addr);
const void *state_map = bo.map;
if (state_map == NULL) {
state = gen_spec_find_struct(ctx->spec, struct_type);
}
+ count = update_count(ctx, state_offset, state->dw_length, count);
+
for (int i = 0; i < count; i++) {
fprintf(ctx->fp, "%s %d\n", struct_type, i);
ctx_print_group(ctx, state, state_addr, state_map);
decode_dynamic_state_pointers(ctx, "SCISSOR_RECT", p, 1);
}
+static void
+decode_3dstate_slice_table_state_pointers(struct gen_batch_decode_ctx *ctx,
+ const uint32_t *p)
+{
+ decode_dynamic_state_pointers(ctx, "SLICE_HASH_TABLE", p, 1);
+}
+
static void
decode_load_register_imm(struct gen_batch_decode_ctx *ctx, const uint32_t *p)
{
{ "3DSTATE_DS", decode_single_ksp },
{ "3DSTATE_HS", decode_single_ksp },
{ "3DSTATE_PS", decode_ps_kernels },
+ { "3DSTATE_WM", decode_ps_kernels },
{ "3DSTATE_CONSTANT_VS", decode_3dstate_constant },
{ "3DSTATE_CONSTANT_GS", decode_3dstate_constant },
{ "3DSTATE_CONSTANT_PS", decode_3dstate_constant },
{ "3DSTATE_CONSTANT_HS", decode_3dstate_constant },
{ "3DSTATE_CONSTANT_DS", decode_3dstate_constant },
+ { "3DSTATE_CONSTANT_ALL", decode_3dstate_constant_all },
+ { "3DSTATE_BINDING_TABLE_POINTERS", decode_gen6_3dstate_binding_table_pointers },
{ "3DSTATE_BINDING_TABLE_POINTERS_VS", decode_3dstate_binding_table_pointers },
{ "3DSTATE_BINDING_TABLE_POINTERS_HS", decode_3dstate_binding_table_pointers },
{ "3DSTATE_BINDING_TABLE_POINTERS_DS", decode_3dstate_binding_table_pointers },
{ "3DSTATE_BLEND_STATE_POINTERS", decode_3dstate_blend_state_pointers },
{ "3DSTATE_CC_STATE_POINTERS", decode_3dstate_cc_state_pointers },
{ "3DSTATE_SCISSOR_STATE_POINTERS", decode_3dstate_scissor_state_pointers },
+ { "3DSTATE_SLICE_TABLE_STATE_POINTERS", decode_3dstate_slice_table_state_pointers },
{ "MI_LOAD_REGISTER_IMM", decode_load_register_imm }
};
void
gen_print_batch(struct gen_batch_decode_ctx *ctx,
const uint32_t *batch, uint32_t batch_size,
- uint64_t batch_addr)
+ uint64_t batch_addr, bool from_ring)
{
const uint32_t *p, *end = batch + batch_size / sizeof(uint32_t);
int length;
struct gen_group *inst;
+ const char *reset_color = ctx->flags & GEN_BATCH_DECODE_IN_COLOR ? NORMAL : "";
+
+ if (ctx->n_batch_buffer_start >= 100) {
+ fprintf(ctx->fp, "%s0x%08"PRIx64": Max batch buffer jumps exceeded%s\n",
+ (ctx->flags & GEN_BATCH_DECODE_IN_COLOR) ? RED_COLOR : "",
+ (ctx->flags & GEN_BATCH_DECODE_OFFSETS) ? batch_addr : 0,
+ reset_color);
+ return;
+ }
+
+ ctx->n_batch_buffer_start++;
for (p = batch; p < end; p += length) {
inst = gen_ctx_find_instruction(ctx, p);
assert(inst == NULL || length > 0);
length = MAX2(1, length);
- const char *reset_color = ctx->flags & GEN_BATCH_DECODE_IN_COLOR ? NORMAL : "";
-
uint64_t offset;
if (ctx->flags & GEN_BATCH_DECODE_OFFSETS)
offset = batch_addr + ((char *)p - (char *)batch);
}
if (strcmp(inst_name, "MI_BATCH_BUFFER_START") == 0) {
- struct gen_batch_decode_bo next_batch = {};
- bool second_level;
+ uint64_t next_batch_addr = 0;
+ bool ppgtt = false;
+ bool second_level = false;
struct gen_field_iterator iter;
gen_field_iterator_init(&iter, inst, p, 0, false);
while (gen_field_iterator_next(&iter)) {
if (strcmp(iter.name, "Batch Buffer Start Address") == 0) {
- next_batch = ctx_get_bo(ctx, iter.raw_value);
+ next_batch_addr = iter.raw_value;
} else if (strcmp(iter.name, "Second Level Batch Buffer") == 0) {
second_level = iter.raw_value;
+ } else if (strcmp(iter.name, "Address Space Indicator") == 0) {
+ ppgtt = iter.raw_value;
}
}
+ struct gen_batch_decode_bo next_batch = ctx_get_bo(ctx, ppgtt, next_batch_addr);
+
if (next_batch.map == NULL) {
fprintf(ctx->fp, "Secondary batch at 0x%08"PRIx64" unavailable\n",
- next_batch.addr);
+ next_batch_addr);
} else {
gen_print_batch(ctx, next_batch.map, next_batch.size,
- next_batch.addr);
+ next_batch.addr, false);
}
if (second_level) {
/* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" set acts
* MI_BATCH_BUFFER_END.
*/
continue;
- } else {
+ } else if (!from_ring) {
/* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" unset acts
* like a goto. Nothing after it will ever get processed. In
* order to prevent the recursion from growing, we just reset the
break;
}
}
+
+ ctx->n_batch_buffer_start--;
}