1 /*
2 * Copyright 2022 Alyssa Rosenzweig
3 * SPDX-License-Identifier: MIT
4 */
5
6 #pragma once
7
8 #include "asahi/genxml/agx_pack.h"
9 #include "asahi/lib/pool.h"
10
11 /* Opaque structure representing a USC program being constructed */
12 struct agx_usc_builder {
13 struct agx_ptr T;
14 uint8_t *head;
15
16 #ifndef NDEBUG
17 size_t size;
18 #endif
19 };
20
21 static struct agx_usc_builder
agx_alloc_usc_control(struct agx_pool * pool,unsigned num_reg_bindings)22 agx_alloc_usc_control(struct agx_pool *pool, unsigned num_reg_bindings)
23 {
24 STATIC_ASSERT(AGX_USC_UNIFORM_HIGH_LENGTH == AGX_USC_UNIFORM_LENGTH);
25 STATIC_ASSERT(AGX_USC_TEXTURE_LENGTH == AGX_USC_UNIFORM_LENGTH);
26 STATIC_ASSERT(AGX_USC_SAMPLER_LENGTH == AGX_USC_UNIFORM_LENGTH);
27
28 size_t size = AGX_USC_UNIFORM_LENGTH * num_reg_bindings;
29
30 size += AGX_USC_SHARED_LENGTH;
31 size += AGX_USC_SHADER_LENGTH;
32 size += AGX_USC_REGISTERS_LENGTH;
33 size += MAX2(AGX_USC_NO_PRESHADER_LENGTH, AGX_USC_PRESHADER_LENGTH);
34 size += AGX_USC_FRAGMENT_PROPERTIES_LENGTH;
35
36 struct agx_usc_builder b = {
37 .T = agx_pool_alloc_aligned(pool, size, 64),
38
39 #ifndef NDEBUG
40 .size = size,
41 #endif
42 };
43
44 b.head = (uint8_t *)b.T.cpu;
45
46 return b;
47 }
48
49 static bool
agx_usc_builder_validate(struct agx_usc_builder * b,size_t size)50 agx_usc_builder_validate(struct agx_usc_builder *b, size_t size)
51 {
52 #ifndef NDEBUG
53 assert(((b->head - (uint8_t *)b->T.cpu) + size) <= b->size);
54 #endif
55
56 return true;
57 }
58
59 #define agx_usc_pack(b, struct_name, template) \
60 for (bool it = \
61 agx_usc_builder_validate((b), AGX_USC_##struct_name##_LENGTH); \
62 it; it = false, (b)->head += AGX_USC_##struct_name##_LENGTH) \
63 agx_pack((b)->head, USC_##struct_name, template)
64
65 static void
agx_usc_uniform(struct agx_usc_builder * b,unsigned start_halfs,unsigned size_halfs,uint64_t buffer)66 agx_usc_uniform(struct agx_usc_builder *b, unsigned start_halfs,
67 unsigned size_halfs, uint64_t buffer)
68 {
69 assert((start_halfs + size_halfs) <= (1 << 9) && "uniform file overflow");
70 assert(size_halfs <= 64 && "caller's responsibility to split");
71
72 if (start_halfs & BITFIELD_BIT(8)) {
73 agx_usc_pack(b, UNIFORM_HIGH, cfg) {
74 cfg.start_halfs = start_halfs & BITFIELD_MASK(8);
75 cfg.size_halfs = size_halfs;
76 cfg.buffer = buffer;
77 }
78 } else {
79 agx_usc_pack(b, UNIFORM, cfg) {
80 cfg.start_halfs = start_halfs;
81 cfg.size_halfs = size_halfs;
82 cfg.buffer = buffer;
83 }
84 }
85 }
86
87 static uint32_t
agx_usc_fini(struct agx_usc_builder * b)88 agx_usc_fini(struct agx_usc_builder *b)
89 {
90 assert(b->T.gpu <= (1ull << 32) && "pipelines must be in low memory");
91 return b->T.gpu;
92 }
93
94 static void
agx_usc_shared_none(struct agx_usc_builder * b)95 agx_usc_shared_none(struct agx_usc_builder *b)
96 {
97 agx_usc_pack(b, SHARED, cfg) {
98 cfg.layout = AGX_SHARED_LAYOUT_VERTEX_COMPUTE;
99 cfg.bytes_per_threadgroup = 65536;
100 }
101 }
102