asahi: Overhaul USC control packing
Break up the monolithic SET_SHADER_EXTENDED packet into the separate underlying commands (some only 2-byte sized and aligned), and add a builder for USC control streams like we did for PPP updates to make that change manageable. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18623>
This commit is contained in:
+49
-62
@@ -471,13 +471,18 @@
|
||||
|
||||
<!-- USC state starts -->
|
||||
<enum name="USC Control">
|
||||
<value name="Preshader" value="0x38"/>
|
||||
<value name="Fragment properties" value="0x58"/>
|
||||
<value name="No preshader" value="0x88"/>
|
||||
<value name="Shader" value="0x0d"/>
|
||||
<value name="Uniform" value="0x1d"/>
|
||||
<value name="Shader" value="0x4d"/>
|
||||
<value name="Shared" value="0x4d"/>
|
||||
<value name="Registers" value="0x8d"/>
|
||||
<value name="Sampler" value="0x9d"/>
|
||||
<value name="Texture" value="0xdd"/>
|
||||
</enum>
|
||||
|
||||
<struct name="Bind uniform" size="8">
|
||||
<struct name="USC Uniform" size="8">
|
||||
<field name="Tag" size="8" start="0:0" type="USC Control" default="Uniform"/>
|
||||
<field name="Start (halfs)" size="8" start="0:8" type="uint"/>
|
||||
<field name="Unk" size="4" start="0:16" type="hex" default="0x0"/>
|
||||
@@ -486,7 +491,7 @@
|
||||
<field name="Buffer" size="36" start="0:27" type="address" modifier="shr(3)"/>
|
||||
</struct>
|
||||
|
||||
<struct name="Bind texture" size="8">
|
||||
<struct name="USC Texture" size="8">
|
||||
<field name="Tag" size="8" start="0:0" type="USC Control" default="Texture"/>
|
||||
<field name="Start" size="8" start="0:8" type="uint"/>
|
||||
<!-- Exact split is unknown. Count is at least 5 bits. Less than 8 bits. -->
|
||||
@@ -494,7 +499,7 @@
|
||||
<field name="Buffer" size="36" start="0:27" type="address" modifier="shr(3)"/>
|
||||
</struct>
|
||||
|
||||
<struct name="Bind sampler" size="8">
|
||||
<struct name="USC Sampler" size="8">
|
||||
<field name="Tag" size="8" start="0:0" type="USC Control" default="Sampler"/>
|
||||
<field name="Start" size="8" start="0:8" type="uint"/>
|
||||
<field name="Count" size="7" start="0:20" type="uint"/>
|
||||
@@ -502,69 +507,51 @@
|
||||
<field name="Buffer" size="36" start="0:27" type="address" modifier="shr(3)"/>
|
||||
</struct>
|
||||
|
||||
<enum name="Preshader mode">
|
||||
<value name="Preshader" value="3"/>
|
||||
<value name="No preshader" value="8"/>
|
||||
</enum>
|
||||
|
||||
<struct name="Set shader" size="24">
|
||||
<field name="Tag" size="8" start="0:0" type="USC Control" default="Shader"/>
|
||||
<field name="Uses shared memory" size="1" start="0:8" type="bool"/>
|
||||
<field name="Unk 1" size="16" start="0:8" type="hex" default="0x90"/>
|
||||
<field name="Shared memory per threadgroup in 256 bytes" size="8" start="0:24" type="uint"/>
|
||||
<field name="Unk 2" size="8" start="1:0" type="hex" default="0x0d"/> <!-- TODO differs with stage -->
|
||||
<!--- Seemingly texture count related?,
|
||||
or number of registers in the preshader? 8 with <4 in the preshader,
|
||||
12 with more than that?
|
||||
-->
|
||||
<field name="Unk 2b" size="8" start="1:8" type="uint" default="4"/>
|
||||
<field name="Code" size="32" start="1:16" type="address"/>
|
||||
<field name="Unk 3" size="8" start="2:16" type="hex" default="0x8d"/>
|
||||
<field name="Register quadwords" size="5" start="2:24" type="uint"/> <!-- 0 for max -->
|
||||
<field name="Has fragment parameters" size="1" start="2:29" type="bool" default="false"/>
|
||||
<field name="Spill size" size="8" start="3:0" type="hex" default="0"/> <!-- TODO: determine relation, see docs/table.py -->
|
||||
<field name="Unk 4" size="12" start="3:8" type="hex" default="0x801"/>
|
||||
<field name="Preshader mode" size="4" start="3:20" type="Preshader mode" default="No preshader"/>
|
||||
<field name="Unk 6" size="8" start="3:24" type="hex" default="0x0"/>
|
||||
<field name="Preshader unk" size="16" start="4:0" type="hex" default="0x0"/>
|
||||
<field name="Preshader code" size="32" start="4:16" type="address"/>
|
||||
<field name="Unk 7" size="16" start="5:16" type="hex" default="0x0"/> <!-- garbage? -->
|
||||
<struct name="USC Shared" size="4">
|
||||
<field name="Tag" size="8" start="0" type="USC Control" default="Shared"/>
|
||||
<field name="Uses shared memory" size="1" start="8" type="bool"/>
|
||||
<field name="Unk 1" size="16" start="8" type="hex" default="0x90"/>
|
||||
<field name="Shared memory per threadgroup in 256 bytes" size="8" start="24" type="uint"/>
|
||||
</struct>
|
||||
|
||||
<struct name="Fragment Parameters" size="4">
|
||||
<field name="Unk 1" size="24" start="0" type="hex" default="0x580100"/>
|
||||
<struct name="USC Shader" size="6">
|
||||
<field name="Tag" size="8" start="0" type="USC Control" default="Shader"/>
|
||||
<field name="Loads varyings" size="1" start="8" type="bool"/>
|
||||
<field name="Unk 1" size="1" start="9" type="bool" default="0"/>
|
||||
<field name="Unk 2" size="6" start="10" type="uint" default="3"/>
|
||||
<field name="Code" size="32" start="16" type="address"/>
|
||||
</struct>
|
||||
|
||||
<struct name="USC Registers" size="4">
|
||||
<field name="Tag" size="8" start="0" type="USC Control" default="Registers"/>
|
||||
<field name="Register quadwords" size="5" start="8" type="uint"/> <!-- 0 for max -->
|
||||
<field name="Unk 1" size="1" start="13" type="bool" default="false"/>
|
||||
<field name="Spill size" size="8" start="16" type="hex" default="0"/> <!-- TODO: determine relation, see docs/table.py -->
|
||||
<field name="Unk 4" size="8" start="24" type="hex" default="0x1"/>
|
||||
</struct>
|
||||
|
||||
<struct name="USC No Preshader" size="2">
|
||||
<field name="Tag" size="8" start="0" type="USC Control" default="No preshader"/>
|
||||
</struct>
|
||||
|
||||
<struct name="USC Preshader" size="8">
|
||||
<field name="Tag" size="8" start="0" type="USC Control" default="Preshader"/>
|
||||
<field name="Unk" size="24" start="8" type="hex" default="0xc08000"/>
|
||||
<field name="Code" size="32" start="32" type="address"/>
|
||||
</struct>
|
||||
|
||||
<struct name="USC Fragment Properties" size="4">
|
||||
<field name="Tag" size="8" start="0" type="USC Control" default="Fragment properties"/>
|
||||
<!-- Guess. Set if the shader does not write the sample mask (including by
|
||||
discard_fragment) -->
|
||||
<field name="Early-z testing" size="1" start="24" type="bool"/>
|
||||
<field name="Unk 2" size="1" start="25" type="bool" default="true"/>
|
||||
<field name="Unconditional discard 1" size="1" start="26" type="bool"/>
|
||||
<field name="Unconditional discard 2" size="1" start="27" type="bool"/>
|
||||
<field name="Unk 3" size="4" start="28" type="hex" default="0xf"/>
|
||||
<field name="Early-z testing" size="1" start="8" type="bool"/>
|
||||
<field name="Unk 2" size="1" start="9" type="bool" default="true"/>
|
||||
<field name="Unconditional discard 1" size="1" start="10" type="bool"/>
|
||||
<field name="Unconditional discard 2" size="1" start="11" type="bool"/>
|
||||
<field name="Unk 3" size="4" start="12" type="hex" default="0xf"/>
|
||||
<field name="Unk 4" size="8" start="16" type="hex" default="0"/> <!-- TODO: determine relation, see docs/table.py -->
|
||||
<field name="Unk 5" size="8" start="24" type="hex" default="0x01"/>
|
||||
</struct>
|
||||
|
||||
<struct name="Set shader extended" size="28">
|
||||
<field name="Tag" size="8" start="0:0" type="USC Control" default="Shader"/>
|
||||
<field name="Uses shared memory" size="1" start="0:8" type="bool"/>
|
||||
<field name="Unk 1" size="16" start="0:8" type="hex" default="0x10bd"/>
|
||||
<field name="Shared memory per threadgroup in 256 bytes" size="8" start="0:24" type="uint" default="0x20"/>
|
||||
<field name="Unk 2" size="8" start="1:0" type="hex" default="0x0d"/>
|
||||
<field name="Loads varyings" size="1" start="1:8" type="bool"/>
|
||||
<field name="Unk 1 9" size="1" start="1:9" type="bool" default="0"/>
|
||||
<field name="Code size in 64 bytes" size="6" start="1:10" type="uint"/>
|
||||
<field name="Code" size="32" start="1:16" type="address"/>
|
||||
<field name="Unk 3" size="8" start="2:16" type="hex" default="0x28d"/>
|
||||
<field name="Register quadwords" size="5" start="2:24" type="uint"/> <!-- 0 for max -->
|
||||
<field name="Has fragment parameters" size="1" start="2:29" type="bool" default="true"/>
|
||||
<field name="Fragment parameters" size="32" start="3:0" type="Fragment Parameters"/>
|
||||
<field name="Spill size" size="8" start="4:0" type="hex" default="0"/> <!-- TODO: determine relation, see docs/table.py -->
|
||||
<field name="Unk 4" size="12" start="4:8" type="hex" default="0x801"/>
|
||||
<field name="Preshader mode" size="4" start="4:20" type="Preshader mode" default="No preshader"/>
|
||||
<field name="Unk 6" size="8" start="4:24" type="hex" default="0x0"/>
|
||||
<field name="Preshader unk" size="16" start="5:0" type="hex" default="0x0"/>
|
||||
<field name="Preshader code" size="32" start="5:16" type="address"/>
|
||||
<field name="Unk 7" size="16" start="6:16" type="hex" default="0x0"/> <!-- garbage? -->
|
||||
</struct>
|
||||
|
||||
<!-- USC commands end -->
|
||||
|
||||
<!-- VDM commands start. VDM commands are padded out to 8b alignment. -->
|
||||
|
||||
+72
-80
@@ -305,64 +305,63 @@ agxdecode_stateful(uint64_t va, const char *label, decode_cmd decoder, bool verb
|
||||
}
|
||||
}
|
||||
|
||||
unsigned COUNTER = 0;
|
||||
static unsigned
|
||||
agxdecode_pipeline(const uint8_t *map, uint64_t *link, UNUSED bool verbose)
|
||||
agxdecode_usc(const uint8_t *map, UNUSED uint64_t *link, UNUSED bool verbose)
|
||||
{
|
||||
uint8_t zeroes[16] = { 0 };
|
||||
enum agx_usc_control type = map[0];
|
||||
|
||||
if (map[0] == 0x4D && (map[11] & BITFIELD_BIT(5))) {
|
||||
agx_unpack(agxdecode_dump_stream, map, SET_SHADER_EXTENDED, cmd);
|
||||
DUMP_UNPACKED(SET_SHADER_EXTENDED, cmd, "Set shader\n");
|
||||
#define USC_CASE(name, human) \
|
||||
case AGX_USC_CONTROL_##name: { \
|
||||
DUMP_CL(USC_##name, map, human); \
|
||||
return AGX_USC_##name##_LENGTH; \
|
||||
}
|
||||
|
||||
if (cmd.preshader_mode == AGX_PRESHADER_MODE_PRESHADER) {
|
||||
agxdecode_log("Preshader\n");
|
||||
agx_disassemble(agxdecode_fetch_gpu_mem(cmd.preshader_code, 2048),
|
||||
2048, agxdecode_dump_stream);
|
||||
agxdecode_log("\n---\n");
|
||||
switch (type) {
|
||||
case AGX_USC_CONTROL_NO_PRESHADER: {
|
||||
DUMP_CL(USC_NO_PRESHADER, map, "No preshader");
|
||||
return STATE_DONE;
|
||||
}
|
||||
|
||||
case AGX_USC_CONTROL_PRESHADER: {
|
||||
agx_unpack(agxdecode_dump_stream, map, USC_PRESHADER, ctrl);
|
||||
DUMP_UNPACKED(USC_PRESHADER, ctrl, "Preshader\n");
|
||||
|
||||
agx_disassemble(agxdecode_fetch_gpu_mem(ctrl.code, 2048),
|
||||
8192, agxdecode_dump_stream);
|
||||
|
||||
return STATE_DONE;
|
||||
}
|
||||
|
||||
case AGX_USC_CONTROL_SHADER: {
|
||||
agx_unpack(agxdecode_dump_stream, map, USC_SHADER, ctrl);
|
||||
DUMP_UNPACKED(USC_SHADER, ctrl, "Shader\n");
|
||||
|
||||
agxdecode_log("\n");
|
||||
agx_disassemble(agxdecode_fetch_gpu_mem(ctrl.code, 2048),
|
||||
8192, agxdecode_dump_stream);
|
||||
agxdecode_log("\n");
|
||||
|
||||
return AGX_USC_SHADER_LENGTH;
|
||||
}
|
||||
|
||||
case AGX_USC_CONTROL_SAMPLER: {
|
||||
agx_unpack(agxdecode_dump_stream, map, USC_SAMPLER, temp);
|
||||
DUMP_UNPACKED(USC_SAMPLER, temp, "Sampler state\n");
|
||||
|
||||
uint8_t *samp = agxdecode_fetch_gpu_mem(temp.buffer,
|
||||
AGX_SAMPLER_LENGTH * temp.count);
|
||||
|
||||
for (unsigned i = 0; i < temp.count; ++i) {
|
||||
DUMP_CL(SAMPLER, samp, "Sampler");
|
||||
samp += AGX_SAMPLER_LENGTH;
|
||||
}
|
||||
|
||||
agxdecode_log("\n");
|
||||
agx_disassemble(agxdecode_fetch_gpu_mem(cmd.code, 2048),
|
||||
2048, agxdecode_dump_stream);
|
||||
agxdecode_log("\n");
|
||||
return AGX_USC_SAMPLER_LENGTH;
|
||||
}
|
||||
|
||||
char *name;
|
||||
asprintf(&name, "file%u.bin", COUNTER++);
|
||||
FILE *fp = fopen(name, "wb");
|
||||
fwrite(agxdecode_fetch_gpu_mem(cmd.code, 2048), 1, 2048, fp);
|
||||
fclose(fp);
|
||||
free(name);
|
||||
agxdecode_log("\n");
|
||||
|
||||
return AGX_SET_SHADER_EXTENDED_LENGTH;
|
||||
} else if (map[0] == 0x4D) {
|
||||
agx_unpack(agxdecode_dump_stream, map, SET_SHADER, cmd);
|
||||
DUMP_UNPACKED(SET_SHADER, cmd, "Set shader\n");
|
||||
fflush(agxdecode_dump_stream);
|
||||
|
||||
if (cmd.preshader_mode == AGX_PRESHADER_MODE_PRESHADER) {
|
||||
agxdecode_log("Preshader\n");
|
||||
agx_disassemble(agxdecode_fetch_gpu_mem(cmd.preshader_code, 2048),
|
||||
2048, agxdecode_dump_stream);
|
||||
agxdecode_log("\n---\n");
|
||||
}
|
||||
|
||||
agxdecode_log("\n");
|
||||
agx_disassemble(agxdecode_fetch_gpu_mem(cmd.code, 2048),
|
||||
2048, agxdecode_dump_stream);
|
||||
char *name;
|
||||
asprintf(&name, "file%u.bin", COUNTER++);
|
||||
FILE *fp = fopen(name, "wb");
|
||||
fwrite(agxdecode_fetch_gpu_mem(cmd.code, 2048), 1, 2048, fp);
|
||||
fclose(fp);
|
||||
free(name);
|
||||
agxdecode_log("\n");
|
||||
|
||||
return AGX_SET_SHADER_LENGTH;
|
||||
} else if (map[0] == 0xDD) {
|
||||
agx_unpack(agxdecode_dump_stream, map, BIND_TEXTURE, temp);
|
||||
DUMP_UNPACKED(BIND_TEXTURE, temp, "Bind texture\n");
|
||||
case AGX_USC_CONTROL_TEXTURE: {
|
||||
agx_unpack(agxdecode_dump_stream, map, USC_TEXTURE, temp);
|
||||
DUMP_UNPACKED(USC_TEXTURE, temp, "Texture state\n");
|
||||
|
||||
uint8_t *tex = agxdecode_fetch_gpu_mem(temp.buffer,
|
||||
AGX_TEXTURE_LENGTH * temp.count);
|
||||
@@ -376,29 +375,22 @@ agxdecode_pipeline(const uint8_t *map, uint64_t *link, UNUSED bool verbose)
|
||||
tex += AGX_TEXTURE_LENGTH;
|
||||
}
|
||||
|
||||
return AGX_BIND_TEXTURE_LENGTH;
|
||||
} else if (map[0] == 0x9D) {
|
||||
agx_unpack(agxdecode_dump_stream, map, BIND_SAMPLER, temp);
|
||||
DUMP_UNPACKED(BIND_SAMPLER, temp, "Bind sampler\n");
|
||||
|
||||
uint8_t *samp = agxdecode_fetch_gpu_mem(temp.buffer,
|
||||
AGX_SAMPLER_LENGTH * temp.count);
|
||||
|
||||
for (unsigned i = 0; i < temp.count; ++i) {
|
||||
DUMP_CL(SAMPLER, samp, "Sampler");
|
||||
samp += AGX_SAMPLER_LENGTH;
|
||||
}
|
||||
|
||||
return AGX_BIND_SAMPLER_LENGTH;
|
||||
} else if (map[0] == 0x1D) {
|
||||
DUMP_CL(BIND_UNIFORM, map, "Bind uniform");
|
||||
return AGX_BIND_UNIFORM_LENGTH;
|
||||
} else if (memcmp(map, zeroes, 16) == 0) {
|
||||
/* TODO: Termination */
|
||||
return STATE_DONE;
|
||||
} else {
|
||||
return 0;
|
||||
return AGX_USC_TEXTURE_LENGTH;
|
||||
}
|
||||
|
||||
USC_CASE(FRAGMENT_PROPERTIES, "Fragment properties");
|
||||
USC_CASE(UNIFORM, "Uniform");
|
||||
USC_CASE(SHARED, "Shared");
|
||||
USC_CASE(REGISTERS, "Registers");
|
||||
|
||||
default:
|
||||
fprintf(agxdecode_dump_stream, "Unknown USC control type: %u\n",
|
||||
type);
|
||||
hexdump(agxdecode_dump_stream, map, 8, false);
|
||||
return 8;
|
||||
}
|
||||
|
||||
#undef USC_CASE
|
||||
}
|
||||
|
||||
#define PPP_PRINT(map, header_name, struct_name, human) \
|
||||
@@ -438,7 +430,7 @@ agxdecode_record(uint64_t va, size_t size, bool verbose)
|
||||
|
||||
if (hdr.fragment_shader) {
|
||||
agx_unpack(agxdecode_dump_stream, map, FRAGMENT_SHADER, frag);
|
||||
agxdecode_stateful(frag.pipeline, "Fragment pipeline", agxdecode_pipeline, verbose);
|
||||
agxdecode_stateful(frag.pipeline, "Fragment pipeline", agxdecode_usc, verbose);
|
||||
|
||||
if (frag.cf_bindings) {
|
||||
uint8_t *cf = agxdecode_fetch_gpu_mem(frag.cf_bindings, 128);
|
||||
@@ -476,7 +468,7 @@ agxdecode_cdm(const uint8_t *map, uint64_t *link, bool verbose)
|
||||
switch (block_type) {
|
||||
case AGX_CDM_BLOCK_TYPE_COMPUTE_KERNEL: {
|
||||
agx_unpack(agxdecode_dump_stream, map, LAUNCH, cmd);
|
||||
agxdecode_stateful(cmd.pipeline, "Pipeline", agxdecode_pipeline, verbose);
|
||||
agxdecode_stateful(cmd.pipeline, "Pipeline", agxdecode_usc, verbose);
|
||||
DUMP_UNPACKED(LAUNCH, cmd, "Launch\n");
|
||||
return AGX_LAUNCH_LENGTH;
|
||||
}
|
||||
@@ -541,7 +533,7 @@ agxdecode_vdm(const uint8_t *map, uint64_t *link, bool verbose)
|
||||
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);
|
||||
agxdecode_stateful(word_1.pipeline, "Pipeline", agxdecode_usc, verbose);
|
||||
}
|
||||
|
||||
VDM_PRINT(vertex_shader_word_1, VERTEX_SHADER_WORD_1, "Vertex shader word 1");
|
||||
@@ -615,24 +607,24 @@ agxdecode_gfx(uint32_t *cmdbuf, uint64_t encoder, bool verbose)
|
||||
if (gfx.clear_pipeline_unk) {
|
||||
fprintf(agxdecode_dump_stream, "Unk: %X\n", gfx.clear_pipeline_unk);
|
||||
agxdecode_stateful(gfx.clear_pipeline, "Clear pipeline",
|
||||
agxdecode_pipeline, verbose);
|
||||
agxdecode_usc, verbose);
|
||||
}
|
||||
|
||||
if (gfx.store_pipeline_unk) {
|
||||
assert(gfx.store_pipeline_unk == 0x4);
|
||||
agxdecode_stateful(gfx.store_pipeline, "Store pipeline",
|
||||
agxdecode_pipeline, verbose);
|
||||
agxdecode_usc, verbose);
|
||||
}
|
||||
|
||||
assert((gfx.partial_reload_pipeline_unk & 0xF) == 0x4);
|
||||
if (gfx.partial_reload_pipeline) {
|
||||
agxdecode_stateful(gfx.partial_reload_pipeline,
|
||||
"Partial reload pipeline", agxdecode_pipeline, verbose);
|
||||
"Partial reload pipeline", agxdecode_usc, verbose);
|
||||
}
|
||||
|
||||
if (gfx.partial_store_pipeline) {
|
||||
agxdecode_stateful(gfx.partial_store_pipeline,
|
||||
"Partial store pipeline", agxdecode_pipeline, verbose);
|
||||
"Partial store pipeline", agxdecode_usc, verbose);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1193,20 +1193,68 @@ agx_delete_shader_state(struct pipe_context *ctx,
|
||||
free(so);
|
||||
}
|
||||
|
||||
/* Pipeline consists of a sequence of binding commands followed by a set shader command */
|
||||
struct agx_usc_builder {
|
||||
struct agx_ptr T;
|
||||
uint8_t *head;
|
||||
|
||||
#ifndef NDEBUG
|
||||
size_t size;
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct agx_usc_builder
|
||||
agx_alloc_usc_control(struct agx_pool *pool,
|
||||
unsigned num_reg_bindings)
|
||||
{
|
||||
STATIC_ASSERT(AGX_USC_TEXTURE_LENGTH == AGX_USC_UNIFORM_LENGTH);
|
||||
STATIC_ASSERT(AGX_USC_SAMPLER_LENGTH == AGX_USC_UNIFORM_LENGTH);
|
||||
|
||||
size_t size = AGX_USC_UNIFORM_LENGTH * num_reg_bindings;
|
||||
|
||||
size += AGX_USC_SHARED_LENGTH;
|
||||
size += AGX_USC_SHADER_LENGTH;
|
||||
size += AGX_USC_REGISTERS_LENGTH;
|
||||
size += MAX2(AGX_USC_NO_PRESHADER_LENGTH, AGX_USC_PRESHADER_LENGTH);
|
||||
size += AGX_USC_FRAGMENT_PROPERTIES_LENGTH;
|
||||
|
||||
struct agx_usc_builder b = {
|
||||
.T = agx_pool_alloc_aligned(pool, size, 64),
|
||||
|
||||
#ifndef NDEBUG
|
||||
.size = size,
|
||||
#endif
|
||||
};
|
||||
|
||||
b.head = (uint8_t *) b.T.cpu;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static bool
|
||||
agx_usc_builder_validate(struct agx_usc_builder *b, size_t size)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
assert(((b->head - (uint8_t *) b->T.cpu) + size) <= b->size);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define agx_usc_pack(b, struct_name, template) \
|
||||
for (bool it = agx_usc_builder_validate((b), AGX_USC_##struct_name##_LENGTH); \
|
||||
it; it = false, (b)->head += AGX_USC_##struct_name##_LENGTH) \
|
||||
agx_pack((b)->head, USC_##struct_name, template)
|
||||
|
||||
static uint32_t
|
||||
agx_usc_fini(struct agx_usc_builder *b)
|
||||
{
|
||||
assert(b->T.gpu <= (1ull << 32) && "pipelines must be in low memory");
|
||||
return b->T.gpu;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
agx_build_pipeline(struct agx_context *ctx, struct agx_compiled_shader *cs, enum pipe_shader_type stage)
|
||||
{
|
||||
/* Pipelines must be 64-byte aligned */
|
||||
struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
|
||||
(cs->info.push_ranges * AGX_BIND_UNIFORM_LENGTH) +
|
||||
AGX_BIND_TEXTURE_LENGTH +
|
||||
AGX_BIND_SAMPLER_LENGTH +
|
||||
AGX_SET_SHADER_EXTENDED_LENGTH + 8,
|
||||
64);
|
||||
|
||||
uint8_t *record = ptr.cpu;
|
||||
|
||||
unsigned nr_textures = ctx->stage[stage].texture_count;
|
||||
unsigned nr_samplers = ctx->stage[stage].sampler_count;
|
||||
|
||||
@@ -1235,25 +1283,26 @@ agx_build_pipeline(struct agx_context *ctx, struct agx_compiled_shader *cs, enum
|
||||
samplers[i] = sampler->desc;
|
||||
}
|
||||
|
||||
struct agx_usc_builder b =
|
||||
agx_alloc_usc_control(&ctx->batch->pipeline_pool,
|
||||
cs->info.push_ranges + 2);
|
||||
|
||||
if (nr_textures) {
|
||||
agx_pack(record, BIND_TEXTURE, cfg) {
|
||||
agx_usc_pack(&b, TEXTURE, cfg) {
|
||||
cfg.start = 0;
|
||||
cfg.count = nr_textures;
|
||||
cfg.buffer = T_tex.gpu;
|
||||
}
|
||||
|
||||
ctx->batch->textures = T_tex.gpu;
|
||||
record += AGX_BIND_TEXTURE_LENGTH;
|
||||
}
|
||||
|
||||
if (nr_samplers) {
|
||||
agx_pack(record, BIND_SAMPLER, cfg) {
|
||||
agx_usc_pack(&b, SAMPLER, cfg) {
|
||||
cfg.start = 0;
|
||||
cfg.count = nr_samplers;
|
||||
cfg.buffer = T_samp.gpu;
|
||||
}
|
||||
|
||||
record += AGX_BIND_SAMPLER_LENGTH;
|
||||
}
|
||||
|
||||
/* Must only upload uniforms after uploading textures so we can implement the
|
||||
@@ -1262,97 +1311,81 @@ agx_build_pipeline(struct agx_context *ctx, struct agx_compiled_shader *cs, enum
|
||||
for (unsigned i = 0; i < cs->info.push_ranges; ++i) {
|
||||
struct agx_push push = cs->info.push[i];
|
||||
|
||||
agx_pack(record, BIND_UNIFORM, cfg) {
|
||||
agx_usc_pack(&b, UNIFORM, cfg) {
|
||||
cfg.start_halfs = push.base;
|
||||
cfg.size_halfs = push.length;
|
||||
cfg.buffer = agx_push_location(ctx, push, stage);
|
||||
}
|
||||
|
||||
record += AGX_BIND_UNIFORM_LENGTH;
|
||||
}
|
||||
|
||||
/* TODO: Can we prepack this? */
|
||||
if (stage == PIPE_SHADER_FRAGMENT) {
|
||||
bool writes_sample_mask = ctx->fs->info.writes_sample_mask;
|
||||
|
||||
agx_pack(record, SET_SHADER_EXTENDED, cfg) {
|
||||
cfg.code = cs->bo->ptr.gpu;
|
||||
cfg.register_quadwords = 0;
|
||||
cfg.unk_3 = 0x8d;
|
||||
cfg.unk_1 = 0x10bd;
|
||||
agx_usc_pack(&b, SHARED, cfg) {
|
||||
if (stage == PIPE_SHADER_FRAGMENT) {
|
||||
cfg.uses_shared_memory = true;
|
||||
cfg.unk_1 = 0x10bc;
|
||||
cfg.shared_memory_per_threadgroup_in_256_bytes = 32;
|
||||
cfg.unk_2 = 0x0d;
|
||||
cfg.loads_varyings = true;
|
||||
cfg.fragment_parameters.early_z_testing = !writes_sample_mask;
|
||||
cfg.unk_4 = 0x800;
|
||||
cfg.preshader_unk = 0xc080;
|
||||
cfg.spill_size = 0x2;
|
||||
} else {
|
||||
cfg.unk_1 = 0x90;
|
||||
}
|
||||
|
||||
record += AGX_SET_SHADER_EXTENDED_LENGTH;
|
||||
} else {
|
||||
agx_pack(record, SET_SHADER, cfg) {
|
||||
cfg.code = cs->bo->ptr.gpu;
|
||||
cfg.register_quadwords = 0;
|
||||
cfg.unk_2b = cs->info.varyings.vs.nr_index;
|
||||
cfg.unk_2 = 0x0d;
|
||||
}
|
||||
|
||||
record += AGX_SET_SHADER_LENGTH;
|
||||
}
|
||||
|
||||
/* End pipeline */
|
||||
memset(record, 0, 8);
|
||||
assert(ptr.gpu < (1ull << 32));
|
||||
return ptr.gpu;
|
||||
agx_usc_pack(&b, SHADER, cfg) {
|
||||
cfg.loads_varyings = (stage == PIPE_SHADER_FRAGMENT);
|
||||
cfg.code = cs->bo->ptr.gpu;
|
||||
cfg.unk_2 = (stage == PIPE_SHADER_FRAGMENT) ? 2 : 3;
|
||||
}
|
||||
|
||||
agx_usc_pack(&b, REGISTERS, cfg) {
|
||||
cfg.register_quadwords = 0;
|
||||
cfg.unk_1 = (stage == PIPE_SHADER_FRAGMENT);
|
||||
}
|
||||
|
||||
if (stage == PIPE_SHADER_FRAGMENT) {
|
||||
agx_usc_pack(&b, FRAGMENT_PROPERTIES, cfg) {
|
||||
bool writes_sample_mask = ctx->fs->info.writes_sample_mask;
|
||||
cfg.early_z_testing = !writes_sample_mask;
|
||||
cfg.unk_4 = 0x2;
|
||||
cfg.unk_5 = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
agx_usc_pack(&b, NO_PRESHADER, cfg);
|
||||
|
||||
return agx_usc_fini(&b);
|
||||
}
|
||||
|
||||
/* Internal pipelines (TODO: refactor?) */
|
||||
uint64_t
|
||||
agx_build_clear_pipeline(struct agx_context *ctx, uint32_t code, uint64_t clear_buf)
|
||||
{
|
||||
struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
|
||||
(1 * AGX_BIND_UNIFORM_LENGTH) +
|
||||
AGX_SET_SHADER_EXTENDED_LENGTH + 8,
|
||||
64);
|
||||
struct agx_usc_builder b =
|
||||
agx_alloc_usc_control(&ctx->batch->pipeline_pool, 1);
|
||||
|
||||
uint8_t *record = ptr.cpu;
|
||||
|
||||
agx_pack(record, BIND_UNIFORM, cfg) {
|
||||
agx_usc_pack(&b, UNIFORM, cfg) {
|
||||
cfg.start_halfs = (6 * 2);
|
||||
cfg.size_halfs = 4;
|
||||
cfg.buffer = clear_buf;
|
||||
}
|
||||
|
||||
record += AGX_BIND_UNIFORM_LENGTH;
|
||||
|
||||
/* TODO: Can we prepack this? */
|
||||
agx_pack(record, SET_SHADER, cfg) {
|
||||
cfg.code = code;
|
||||
cfg.unk_1 = 0x10bd;
|
||||
agx_usc_pack(&b, SHARED, cfg) {
|
||||
cfg.uses_shared_memory = true;
|
||||
cfg.unk_1 = 0x10bc;
|
||||
cfg.shared_memory_per_threadgroup_in_256_bytes = 32;
|
||||
cfg.unk_2 = 0x0d;
|
||||
cfg.unk_3 = 0x8d;
|
||||
cfg.register_quadwords = 1;
|
||||
}
|
||||
|
||||
record += AGX_SET_SHADER_LENGTH;
|
||||
agx_usc_pack(&b, SHADER, cfg) {
|
||||
cfg.code = code;
|
||||
cfg.unk_2 = 3;
|
||||
}
|
||||
|
||||
/* End pipeline */
|
||||
memset(record, 0, 8);
|
||||
return ptr.gpu;
|
||||
agx_usc_pack(&b, REGISTERS, cfg) cfg.register_quadwords = 1;
|
||||
agx_usc_pack(&b, NO_PRESHADER, cfg);
|
||||
|
||||
return agx_usc_fini(&b);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
agx_build_reload_pipeline(struct agx_context *ctx, uint32_t code, struct pipe_surface *surf)
|
||||
{
|
||||
struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
|
||||
(1 * AGX_BIND_TEXTURE_LENGTH) +
|
||||
(1 * AGX_BIND_SAMPLER_LENGTH) +
|
||||
AGX_SET_SHADER_EXTENDED_LENGTH + 8,
|
||||
64);
|
||||
|
||||
uint8_t *record = ptr.cpu;
|
||||
struct agx_ptr sampler = agx_pool_alloc_aligned(&ctx->batch->pool, AGX_SAMPLER_LENGTH, 64);
|
||||
struct agx_ptr texture = agx_pool_alloc_aligned(&ctx->batch->pool, AGX_TEXTURE_LENGTH, 64);
|
||||
|
||||
@@ -1398,91 +1431,70 @@ agx_build_reload_pipeline(struct agx_context *ctx, uint32_t code, struct pipe_su
|
||||
cfg.unk_tiled = true;
|
||||
}
|
||||
|
||||
agx_pack(record, BIND_TEXTURE, cfg) {
|
||||
struct agx_usc_builder b =
|
||||
agx_alloc_usc_control(&ctx->batch->pipeline_pool, 2);
|
||||
|
||||
agx_usc_pack(&b, TEXTURE, cfg) {
|
||||
cfg.start = 0;
|
||||
cfg.count = 1;
|
||||
cfg.buffer = texture.gpu;
|
||||
}
|
||||
|
||||
record += AGX_BIND_TEXTURE_LENGTH;
|
||||
|
||||
agx_pack(record, BIND_SAMPLER, cfg) {
|
||||
agx_usc_pack(&b, SAMPLER, cfg) {
|
||||
cfg.start = 0;
|
||||
cfg.count = 1;
|
||||
cfg.buffer = sampler.gpu;
|
||||
}
|
||||
|
||||
record += AGX_BIND_SAMPLER_LENGTH;
|
||||
|
||||
/* TODO: Can we prepack this? */
|
||||
agx_pack(record, SET_SHADER_EXTENDED, cfg) {
|
||||
cfg.code = code;
|
||||
cfg.register_quadwords = 0;
|
||||
cfg.unk_3 = 0x8d;
|
||||
cfg.unk_2 = 0x0d;
|
||||
cfg.unk_4 = 0;
|
||||
cfg.fragment_parameters.unk_1 = 0x880100;
|
||||
cfg.fragment_parameters.early_z_testing = false;
|
||||
cfg.fragment_parameters.unk_2 = false;
|
||||
cfg.fragment_parameters.unk_3 = 0;
|
||||
cfg.preshader_mode = 0; // XXX
|
||||
agx_usc_pack(&b, SHARED, cfg) {
|
||||
cfg.uses_shared_memory = true;
|
||||
cfg.unk_1 = 0x10bc;
|
||||
cfg.shared_memory_per_threadgroup_in_256_bytes = 32;
|
||||
}
|
||||
|
||||
record += AGX_SET_SHADER_EXTENDED_LENGTH;
|
||||
agx_usc_pack(&b, SHADER, cfg) {
|
||||
cfg.code = code;
|
||||
cfg.unk_2 = 3;
|
||||
}
|
||||
|
||||
/* End pipeline */
|
||||
memset(record, 0, 8);
|
||||
return ptr.gpu;
|
||||
agx_usc_pack(&b, REGISTERS, cfg) cfg.register_quadwords = 0;
|
||||
agx_usc_pack(&b, NO_PRESHADER, cfg);
|
||||
|
||||
return agx_usc_fini(&b);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
agx_build_store_pipeline(struct agx_context *ctx, uint32_t code,
|
||||
uint64_t render_target)
|
||||
{
|
||||
struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
|
||||
(1 * AGX_BIND_TEXTURE_LENGTH) +
|
||||
(1 * AGX_BIND_UNIFORM_LENGTH) +
|
||||
AGX_SET_SHADER_EXTENDED_LENGTH + 8,
|
||||
64);
|
||||
struct agx_usc_builder b =
|
||||
agx_alloc_usc_control(&ctx->batch->pipeline_pool, 2);
|
||||
|
||||
uint8_t *record = ptr.cpu;
|
||||
|
||||
agx_pack(record, BIND_TEXTURE, cfg) {
|
||||
agx_usc_pack(&b, TEXTURE, cfg) {
|
||||
cfg.start = 0;
|
||||
cfg.count = 1;
|
||||
cfg.buffer = render_target;
|
||||
}
|
||||
|
||||
record += AGX_BIND_TEXTURE_LENGTH;
|
||||
|
||||
uint32_t unk[] = { 0, ~0 };
|
||||
|
||||
agx_pack(record, BIND_UNIFORM, cfg) {
|
||||
agx_usc_pack(&b, UNIFORM, cfg) {
|
||||
cfg.start_halfs = 4;
|
||||
cfg.size_halfs = 4;
|
||||
cfg.buffer = agx_pool_upload_aligned(&ctx->batch->pool, unk, sizeof(unk), 16);
|
||||
}
|
||||
|
||||
record += AGX_BIND_UNIFORM_LENGTH;
|
||||
|
||||
/* TODO: Can we prepack this? */
|
||||
agx_pack(record, SET_SHADER_EXTENDED, cfg) {
|
||||
cfg.code = code;
|
||||
cfg.register_quadwords = 1;
|
||||
cfg.unk_2 = 0xd;
|
||||
cfg.unk_3 = 0x8d;
|
||||
cfg.fragment_parameters.unk_1 = 0x880100;
|
||||
cfg.fragment_parameters.early_z_testing = false;
|
||||
cfg.fragment_parameters.unk_2 = false;
|
||||
cfg.fragment_parameters.unk_3 = 0;
|
||||
cfg.preshader_mode = 0; // XXX
|
||||
agx_usc_pack(&b, SHARED, cfg) {
|
||||
cfg.uses_shared_memory = true;
|
||||
cfg.unk_1 = 0x10bc;
|
||||
cfg.shared_memory_per_threadgroup_in_256_bytes = 32;
|
||||
}
|
||||
|
||||
record += AGX_SET_SHADER_EXTENDED_LENGTH;
|
||||
agx_usc_pack(&b, SHADER, cfg) cfg.code = code;
|
||||
agx_usc_pack(&b, REGISTERS, cfg) cfg.register_quadwords = 1;
|
||||
agx_usc_pack(&b, NO_PRESHADER, cfg);
|
||||
|
||||
/* End pipeline */
|
||||
memset(record, 0, 8);
|
||||
return ptr.gpu;
|
||||
return agx_usc_fini(&b);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user