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:
Alyssa Rosenzweig
2022-09-17 11:22:01 -04:00
parent 35d5558fa5
commit 933a9e350e
3 changed files with 259 additions and 268 deletions
+49 -62
View File
@@ -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
View File
@@ -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);
}
}
+138 -126
View File
@@ -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