asahi: Express VDM commands according to PowerVR

Piles of unknown bits go away, as we find they're either "field present"
bits or block types. And yep, the block type enum lines up between AGX
and RGX.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
This commit is contained in:
Alyssa Rosenzweig 2022-09-05 15:49:39 -04:00 committed by Marge Bot
parent 80d8273705
commit 6f5c8d0e24
4 changed files with 246 additions and 103 deletions

View file

@ -129,13 +129,13 @@ agx_ppp_fini(uint8_t **out, struct agx_ppp_update *ppp)
assert(ppp->gpu_base < (1ull << 40));
assert(size_words < (1ull << 24));
agx_pack(*out, RECORD, cfg) {
agx_pack(*out, PPP_STATE, cfg) {
cfg.pointer_hi = (ppp->gpu_base >> 32);
cfg.pointer_lo = (uint32_t) ppp->gpu_base;
cfg.size_words = size_words;
};
*out += AGX_RECORD_LENGTH;
*out += AGX_PPP_STATE_LENGTH;
}
#endif

View file

@ -554,45 +554,19 @@
<field name="Unk 7" size="16" start="6:16" type="hex" default="0x0"/> <!-- garbage? -->
</struct>
<!-- VDM commands start -->
<!-- VDM commands start. VDM commands are padded out to 8b alignment. -->
<enum name="VDM Block Type">
<value name="PPP State Update" value="0"/>
<value name="VDM State Update" value="2"/>
<value name="Index List" value="3"/>
<value name="Stream terminate" value="6"/>
</enum>
<!--- Command to bind a vertex pipeline, followed by subcommands. Counts are
specified in 32-bit word units. Intepretation per-shader stage. -->
<struct name="Bind vertex pipeline" size="24">
<field name="Tag" size="32" start="0:0" type="hex" default="0x4000002e"/>
<!-- 4 if more than 32 textures bound -->
<field name="Unk 1" size="4" start="1:0" type="hex" default="0x2"/>
<field name="Groups of 8 immediate textures" start="1:4" size="3" type="uint"/>
<field name="Groups of 4 samplers" start="1:9" size="3" type="uint"/>
<!-- When more than 48 textures bound, switches to 0x8, unk1 switches to
0x6, and some funny sort of bindless access(?) is used in the shader -->
<field name="Unk 2" size="4" start="1:12" type="hex" default="0x1"/>
<field name="Padding 1" size="8" start="1:24" type="hex" default="0x0"/>
<field name="Pipeline" size="32" start="2:0" type="address"/>
<field name="Output count 1" size="8" start="3:0" type="uint" default="0"/>
<field name="Output count 2" size="8" start="3:8" type="uint" default="0"/>
<field name="Padding 2" size="16" start="3:16" type="hex" default="0x0"/>
<field name="More than 4 textures" start="4:0" size="1" type="bool"/>
<field name="Unk 3" size="32" start="5:0" type="address"/> <!-- C020000 -->
</struct>
<!-- Subcommands are packed inside sized records -->
<struct name="Record" size="8">
<field name="Pointer (hi)" size="8" start="0:0" type="hex"/>
<field name="Size (words)" size="8" start="0:8" type="uint"/>
<field name="Tag" size="16" start="0:16" type="hex" default="0x0000"/>
<field name="Pointer (lo)" size="32" start="0:32" type="address"/>
</struct>
<!--- Command to issue a direct non-indexed draw -->
<struct name="Draw" size="16">
<field name="Unk" size="8" start="0:0" type="hex" default="0x0"/>
<field name="Primitive" size="8" start="0:8" type="Primitive"/>
<field name="Unk 2" size="8" start="0:16" type="hex" default="0xc0"/>
<field name="Command" size="8" start="0:24" type="hex" default="0x61"/>
<field name="Vertex count" size="32" start="1:0" type="uint"/>
<field name="Instance count" size="32" start="2:0" type="uint"/> <!-- must be nonzero -->
<field name="Vertex start" size="32" start="3:0" type="uint"/>
<struct name="PPP State" size="8">
<field name="Pointer (hi)" size="8" start="0" type="hex"/>
<field name="Size (words)" size="8" start="8" type="uint"/>
<field name="Block Type" size="3" start="29" type="VDM Block Type" default="PPP State Update"/>
<field name="Pointer (lo)" size="32" start="32" type="address"/>
</struct>
<enum name="Index size">
@ -601,21 +575,90 @@
<value name="U32" value="2"/>
</enum>
<struct name="Indexed draw" size="32">
<field name="Unk 1" size="8" start="0:0" type="hex" default="0x1"/>
<field name="Command" size="8" start="0:24" type="hex" default="0x40"/>
<field name="Restart index" size="32" start="1:0" type="hex"/>
<field name="Primitive" size="8" start="2:8" type="Primitive"/>
<field name="Restart enable" size="1" start="2:16" type="bool"/> <!-- Metal sets this bit for strips -->
<field name="Index size" size="3" start="2:17" type="Index size"/>
<field name="Unk 2c" size="4" start="2:20" type="hex" default="0xF"/>
<field name="Draw Command" size="8" start="2:24" type="hex" default="0x61"/>
<field name="Index buffer lo" size="32" start="3:0" type="hex"/>
<field name="Index buffer hi" size="8" start="2:0" type="hex"/>
<field name="Index count" size="32" start="4:0" type="uint"/>
<field name="Instance count" size="32" start="5:0" type="uint"/>
<field name="Base vertex" size="32" start="6:0" type="uint"/>
<field name="Index buffer size" size="32" start="7:0" type="uint" modifier="shr(2)"/>
<struct name="VDM State" size="4">
<field name="Restart index present" size="1" start="0" type="bool"/>
<field name="Vertex shader word 0 present" size="1" start="1" type="bool"/>
<field name="Vertex shader word 1 present" size="1" start="2" type="bool"/>
<field name="Vertex outputs present" size="1" start="3" type="bool"/>
<field name="Vertex unknown present" size="1" start="5" type="bool"/>
<field name="Block Type" size="3" start="29" type="VDM Block Type" default="VDM State Update"/>
</struct>
<struct name="VDM State Restart Index" size="4">
<field name="Value" size="32" start="0" type="hex"/>
</struct>
<struct name="VDM State Vertex Shader Word 0" size="4">
<!-- 4 if more than 32 textures bound -->
<field name="Unk 1" size="4" start="0" type="hex" default="0x2"/>
<field name="Groups of 8 immediate textures" start="4" size="3" type="uint"/>
<field name="Groups of 4 samplers" start="9" size="3" type="uint"/>
<!-- When more than 48 textures bound, switches to 0x8, unk1 switches to
0x6, and some funny sort of bindless access(?) is used in the shader -->
<field name="Unk 2" size="4" start="12" type="hex" default="0x1"/>
<field name="Padding 1" size="8" start="24" type="hex" default="0x0"/>
</struct>
<struct name="VDM State Vertex Shader Word 1" size="4">
<field name="Pipeline" size="32" start="0" type="address"/>
</struct>
<struct name="VDM State Vertex Outputs" size="4">
<field name="Output count 1" size="8" start="0" type="uint" default="0"/>
<field name="Output count 2" size="8" start="8" type="uint" default="0"/>
<field name="Padding 2" size="16" start="16" type="hex" default="0x0"/>
</struct>
<struct name="VDM State Vertex Unknown" size="4">
<!-- XXX Probably not? -->
<field name="More than 4 textures" start="0" size="1" type="bool"/>
</struct>
<!--- Command to issue a direct non-indexed draw -->
<struct name="Index List" size="4">
<field name="Index buffer hi" size="8" start="0" type="hex"/>
<field name="Primitive" size="8" start="8" type="Primitive"/>
<!-- Metal sets this bit for strips, probably wrong though -->
<field name="Restart enable" size="1" start="16" type="bool"/>
<field name="Index size" size="3" start="17" type="Index size"/>
<!-- XXX: Might be backwards, not sure how to check that -->
<field name="Index buffer present" size="1" start="20" type="bool"/>
<field name="Index buffer size present" size="1" start="21" type="bool"/>
<!-- XXX: Might be mixed up, not sure how to check that -->
<field name="Index count present" size="1" start="22" type="bool" default="true"/>
<field name="Instance count present" size="1" start="23" type="bool" default="true"/>
<field name="Start present" size="1" start="24" type="bool" default="true"/>
<field name="Block Type" size="3" start="29" type="VDM Block Type" default="Index List"/>
</struct>
<struct name="Index List: Buffer lo" size="4">
<!-- Index buffer lsb -->
<field name="Buffer lo" size="32" start="0" type="hex"/>
</struct>
<struct name="Index List: Count" size="4">
<!-- Vertex count for non-indexed, index count for index count -->
<field name="Count" size="32" start="0" type="uint"/>
</struct>
<struct name="Index List: Instances" size="4">
<field name="Count" size="32" start="0" type="uint"/> <!-- must be nonzero -->
</struct>
<struct name="Index List: Start" size="4">
<!-- Base vertex for indexed draws -->
<field name="Start" size="32" start="0" type="uint"/>
</struct>
<struct name="Index List: Buffer size" size="4">
<field name="Size" size="32" start="0" type="uint" modifier="shr(2)"/>
</struct>
<struct name="Stream Terminate" size="8">
<field name="Block Type" size="3" start="29" type="VDM Block Type" default="Stream Terminate"/>
</struct>
<!-- VDM commands end -->

View file

@ -464,24 +464,19 @@ static unsigned
agxdecode_cmd(const uint8_t *map, bool verbose)
{
if (map[0] == 0x02 && map[1] == 0x10 && map[2] == 0x00 && map[3] == 0x00) {
/* XXX: This is a CDM command not a VDM one */
agx_unpack(agxdecode_dump_stream, map, LAUNCH, cmd);
agxdecode_stateful(cmd.pipeline, "Pipeline", agxdecode_pipeline, verbose);
DUMP_UNPACKED(LAUNCH, cmd, "Launch\n");
return AGX_LAUNCH_LENGTH;
} else if (map[0] == 0x2E && map[1] == 0x00 && map[2] == 0x00 && map[3] == 0x40) {
agx_unpack(agxdecode_dump_stream, map, BIND_VERTEX_PIPELINE, cmd);
agxdecode_stateful(cmd.pipeline, "Pipeline", agxdecode_pipeline, verbose);
DUMP_UNPACKED(BIND_VERTEX_PIPELINE, cmd, "Bind vertex pipeline\n");
return AGX_BIND_VERTEX_PIPELINE_LENGTH;
} else if (map[3] == 0x40) {
DUMP_CL(INDEXED_DRAW, map, "Indexed Draw");
return AGX_INDEXED_DRAW_LENGTH;
} else if (map[3] == 0x61) {
DUMP_CL(DRAW, map, "Draw");
return AGX_DRAW_LENGTH;
} else if (map[2] == 0x00 && map[3] == 0x00) {
/* No need to explicitly dump the record */
agx_unpack(agxdecode_dump_stream, map, RECORD, cmd);
}
/* Bits 29-31 contain the block type */
enum agx_vdm_block_type block_type = (map[3] >> 5);
switch (block_type) {
case AGX_VDM_BLOCK_TYPE_PPP_STATE_UPDATE: {
agx_unpack(agxdecode_dump_stream, map, PPP_STATE, cmd);
uint64_t address = (((uint64_t) cmd.pointer_hi) << 32) | cmd.pointer_lo;
struct agx_bo *mem = agxdecode_find_mapped_gpu_mem_containing(address);
@ -489,15 +484,74 @@ agxdecode_cmd(const uint8_t *map, bool verbose)
if (mem)
agxdecode_record(address, cmd.size_words * 4, verbose);
else
DUMP_UNPACKED(RECORD, cmd, "Non-existant record (XXX)\n");
DUMP_UNPACKED(PPP_STATE, cmd, "Non-existant record (XXX)\n");
return AGX_RECORD_LENGTH;
} else if (map[1] == 0 && map[2] == 0 && map[3] == 0xC0 && map[4] == 0x00) {
ASSERTED unsigned zero[4] = { 0 };
assert(memcmp(map + 4, zero, sizeof(zero)) == 0);
return AGX_PPP_STATE_LENGTH;
}
case AGX_VDM_BLOCK_TYPE_VDM_STATE_UPDATE: {
size_t length = AGX_VDM_STATE_LENGTH;
agx_unpack(agxdecode_dump_stream, map, VDM_STATE, hdr);
map += AGX_VDM_STATE_LENGTH;
#define VDM_PRINT(header_name, STRUCT_NAME, human) \
if (hdr.header_name##_present) { \
DUMP_CL(VDM_STATE_##STRUCT_NAME, map, human); \
map += AGX_VDM_STATE_##STRUCT_NAME##_LENGTH; \
length += AGX_VDM_STATE_##STRUCT_NAME##_LENGTH; \
}
VDM_PRINT(restart_index, RESTART_INDEX, "Restart index");
VDM_PRINT(vertex_shader_word_0, VERTEX_SHADER_WORD_0, "Vertex shader word 0");
if (hdr.vertex_shader_word_1_present) {
agx_unpack(agxdecode_dump_stream, map, VDM_STATE_VERTEX_SHADER_WORD_1,
word_1);
fprintf(agxdecode_dump_stream, "Pipeline %X\n", (uint32_t) word_1.pipeline);
agxdecode_stateful(word_1.pipeline, "Pipeline", agxdecode_pipeline, verbose);
}
VDM_PRINT(vertex_shader_word_1, VERTEX_SHADER_WORD_1, "Vertex shader word 1");
VDM_PRINT(vertex_outputs, VERTEX_OUTPUTS, "Vertex outputs");
VDM_PRINT(vertex_unknown, VERTEX_UNKNOWN, "Vertex unknown");
#undef VDM_PRINT
return ALIGN_POT(length, 8);
}
case AGX_VDM_BLOCK_TYPE_INDEX_LIST: {
size_t length = AGX_INDEX_LIST_LENGTH;
agx_unpack(agxdecode_dump_stream, map, INDEX_LIST, hdr);
DUMP_UNPACKED(INDEX_LIST, hdr, "Index List\n");
map += AGX_INDEX_LIST_LENGTH;
#define IDX_PRINT(header_name, STRUCT_NAME, human) \
if (hdr.header_name##_present) { \
DUMP_CL(INDEX_LIST_##STRUCT_NAME, map, human); \
map += AGX_INDEX_LIST_##STRUCT_NAME##_LENGTH; \
length += AGX_INDEX_LIST_##STRUCT_NAME##_LENGTH; \
}
IDX_PRINT(index_buffer, BUFFER_LO, "Index buffer");
IDX_PRINT(index_buffer_size, BUFFER_SIZE, "Index buffer size");
IDX_PRINT(index_count, COUNT, "Index count");
IDX_PRINT(instance_count, INSTANCES, "Instance count");
IDX_PRINT(start, START, "Start");
#undef IDX_PRINT
return ALIGN_POT(length, 8);
}
case AGX_VDM_BLOCK_TYPE_STREAM_TERMINATE: {
DUMP_CL(STREAM_TERMINATE, map, "Stream Terminate");
return STATE_DONE;
} else {
return 0;
}
default:
fprintf(agxdecode_dump_stream, "Unknown VDM block type: %u\n",
block_type);
hexdump(agxdecode_dump_stream, map, 8, false);
return 8;
}
}

View file

@ -1512,18 +1512,40 @@ agx_encode_state(struct agx_context *ctx, uint8_t *out,
#define IS_DIRTY(ST) !!(ctx->dirty & AGX_DIRTY_##ST)
if (IS_DIRTY(VS)) {
unsigned tex_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;
agx_pack(out, BIND_VERTEX_PIPELINE, cfg) {
cfg.pipeline = agx_build_pipeline(ctx, ctx->vs, PIPE_SHADER_VERTEX);
cfg.output_count_1 = ctx->vs->info.varyings.vs.nr_index;
cfg.output_count_2 = cfg.output_count_1;
agx_pack(out, VDM_STATE, cfg) {
cfg.vertex_shader_word_0_present = true;
cfg.vertex_shader_word_1_present = true;
cfg.vertex_outputs_present = true;
cfg.vertex_unknown_present = true;
}
out += AGX_VDM_STATE_LENGTH;
unsigned tex_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;
agx_pack(out, VDM_STATE_VERTEX_SHADER_WORD_0, cfg) {
cfg.groups_of_8_immediate_textures = DIV_ROUND_UP(tex_count, 8);
cfg.groups_of_4_samplers = DIV_ROUND_UP(tex_count, 4);
}
out += AGX_VDM_STATE_VERTEX_SHADER_WORD_0_LENGTH;
agx_pack(out, VDM_STATE_VERTEX_SHADER_WORD_1, cfg) {
cfg.pipeline = agx_build_pipeline(ctx, ctx->vs, PIPE_SHADER_VERTEX);
}
out += AGX_VDM_STATE_VERTEX_SHADER_WORD_1_LENGTH;
agx_pack(out, VDM_STATE_VERTEX_OUTPUTS, cfg) {
cfg.output_count_1 = ctx->vs->info.varyings.vs.nr_index;
cfg.output_count_2 = cfg.output_count_1;
}
out += AGX_VDM_STATE_VERTEX_OUTPUTS_LENGTH;
agx_pack(out, VDM_STATE_VERTEX_UNKNOWN, cfg) {
cfg.more_than_4_textures = tex_count >= 4;
}
out += AGX_VDM_STATE_VERTEX_UNKNOWN_LENGTH;
out += AGX_BIND_VERTEX_PIPELINE_LENGTH;
/* Pad up to a multiple of 8 bytes */
memset(out, 0, 4);
out += 4;
}
struct agx_pool *pool = &ctx->batch->pool;
@ -1793,39 +1815,63 @@ agx_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
enum agx_primitive prim = agx_primitive_for_pipe(info->mode);
unsigned idx_size = info->index_size;
uint64_t ib = idx_size ? agx_index_buffer_ptr(batch, draws, info) : 0;
if (idx_size) {
uint64_t ib = agx_index_buffer_ptr(batch, draws, info);
/* Index sizes are encoded logarithmically */
STATIC_ASSERT(__builtin_ctz(1) == AGX_INDEX_SIZE_U8);
STATIC_ASSERT(__builtin_ctz(2) == AGX_INDEX_SIZE_U16);
STATIC_ASSERT(__builtin_ctz(4) == AGX_INDEX_SIZE_U32);
assert((idx_size == 1) || (idx_size == 2) || (idx_size == 4));
agx_pack(out, INDEXED_DRAW, cfg) {
cfg.restart_index = info->restart_index;
cfg.primitive = prim;
agx_pack(out, VDM_STATE, cfg) cfg.restart_index_present = true;
out += AGX_VDM_STATE_LENGTH;
agx_pack(out, VDM_STATE_RESTART_INDEX, cfg) {
cfg.value = info->restart_index;
}
out += AGX_VDM_STATE_RESTART_INDEX_LENGTH;
}
agx_pack(out, INDEX_LIST, cfg) {
cfg.primitive = prim;
cfg.index_count_present = true;
cfg.instance_count_present = true;
cfg.start_present = true;
if (idx_size) {
cfg.restart_enable = info->primitive_restart;
cfg.index_size = __builtin_ctz(idx_size);
cfg.index_buffer_lo = (ib & BITFIELD_MASK(32));
cfg.index_buffer_hi = (ib >> 32);
cfg.index_buffer_size = ALIGN_POT(draws->count * idx_size, 4);
cfg.index_count = draws->count;
cfg.instance_count = info->instance_count;
cfg.base_vertex = draws->index_bias;
};
cfg.index_size = __builtin_ctz(idx_size);
cfg.index_buffer_present = true;
cfg.index_buffer_size_present = true;
}
}
out += AGX_INDEX_LIST_LENGTH;
out += AGX_INDEXED_DRAW_LENGTH;
} else {
agx_pack(out, DRAW, cfg) {
cfg.primitive = prim;
cfg.vertex_start = draws->start;
cfg.vertex_count = draws->count;
cfg.instance_count = info->instance_count;
};
if (idx_size) {
agx_pack(out, INDEX_LIST_BUFFER_LO, cfg) {
cfg.buffer_lo = ib & BITFIELD_MASK(32);
}
out += AGX_INDEX_LIST_BUFFER_LO_LENGTH;
}
out += AGX_DRAW_LENGTH;
agx_pack(out, INDEX_LIST_COUNT, cfg) cfg.count = draws->count;
out += AGX_INDEX_LIST_COUNT_LENGTH;
agx_pack(out, INDEX_LIST_INSTANCES, cfg) cfg.count = info->instance_count;
out += AGX_INDEX_LIST_INSTANCES_LENGTH;
agx_pack(out, INDEX_LIST_START, cfg) {
cfg.start = idx_size ? draws->index_bias : draws->start;
}
out += AGX_INDEX_LIST_START_LENGTH;
if (idx_size) {
agx_pack(out, INDEX_LIST_BUFFER_SIZE, cfg) {
cfg.size = ALIGN_POT(draws->count * idx_size, 4);
}
out += AGX_INDEX_LIST_BUFFER_SIZE_LENGTH;
}
batch->encoder_current = out;