xref: /aosp_15_r20/external/mesa3d/src/asahi/lib/agx_usc.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 "agx_compile.h"
10 
11 /* Opaque structure representing a USC program being constructed */
12 struct agx_usc_builder {
13    uint8_t *head;
14 
15 #ifndef NDEBUG
16    uint8_t *begin;
17    size_t size;
18 #endif
19 };
20 
21 static inline unsigned
agx_usc_size(unsigned num_reg_bindings)22 agx_usc_size(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    return size;
37 }
38 
39 static struct agx_usc_builder
agx_usc_builder(void * out,ASSERTED size_t size)40 agx_usc_builder(void *out, ASSERTED size_t size)
41 {
42    return (struct agx_usc_builder){
43       .head = out,
44 
45 #ifndef NDEBUG
46       .begin = out,
47       .size = size,
48 #endif
49    };
50 }
51 
52 static bool
agx_usc_builder_validate(struct agx_usc_builder * b,size_t size)53 agx_usc_builder_validate(struct agx_usc_builder *b, size_t size)
54 {
55 #ifndef NDEBUG
56    assert(((b->head - b->begin) + size) <= b->size);
57 #endif
58 
59    return true;
60 }
61 
62 #define agx_usc_pack(b, struct_name, template)                                 \
63    for (bool it =                                                              \
64            agx_usc_builder_validate((b), AGX_USC_##struct_name##_LENGTH);      \
65         it; it = false, (b)->head += AGX_USC_##struct_name##_LENGTH)           \
66       agx_pack((b)->head, USC_##struct_name, template)
67 
68 #define agx_usc_push_blob(b, blob, length)                                     \
69    for (bool it = agx_usc_builder_validate((b), length); it;                   \
70         it = false, (b)->head += length)                                       \
71       memcpy((b)->head, blob, length);
72 
73 #define agx_usc_push_packed(b, struct_name, packed)                            \
74    agx_usc_push_blob(b, packed.opaque, AGX_USC_##struct_name##_LENGTH);
75 
76 static void
agx_usc_uniform(struct agx_usc_builder * b,unsigned start_halfs,unsigned size_halfs,uint64_t buffer)77 agx_usc_uniform(struct agx_usc_builder *b, unsigned start_halfs,
78                 unsigned size_halfs, uint64_t buffer)
79 {
80    assert((start_halfs + size_halfs) <= (1 << 9) && "uniform file overflow");
81    assert(size_halfs <= 64 && "caller's responsibility to split");
82    assert(size_halfs > 0 && "no empty uniforms");
83 
84    if (start_halfs & BITFIELD_BIT(8)) {
85       agx_usc_pack(b, UNIFORM_HIGH, cfg) {
86          cfg.start_halfs = start_halfs & BITFIELD_MASK(8);
87          cfg.size_halfs = size_halfs;
88          cfg.buffer = buffer;
89       }
90    } else {
91       agx_usc_pack(b, UNIFORM, cfg) {
92          cfg.start_halfs = start_halfs;
93          cfg.size_halfs = size_halfs;
94          cfg.buffer = buffer;
95       }
96    }
97 }
98 
99 static void
agx_usc_shared_none(struct agx_usc_builder * b)100 agx_usc_shared_none(struct agx_usc_builder *b)
101 {
102    agx_usc_pack(b, SHARED, cfg) {
103       cfg.layout = AGX_SHARED_LAYOUT_VERTEX_COMPUTE;
104       cfg.bytes_per_threadgroup = 65536;
105    }
106 }
107 
108 static void
agx_usc_shared_non_fragment(struct agx_usc_builder * b,struct agx_shader_info * info,unsigned variable_shared_mem)109 agx_usc_shared_non_fragment(struct agx_usc_builder *b,
110                             struct agx_shader_info *info,
111                             unsigned variable_shared_mem)
112 {
113    if (info->stage == PIPE_SHADER_FRAGMENT) {
114       return;
115    } else if (info->stage == PIPE_SHADER_COMPUTE && info->imageblock_stride) {
116       assert(info->local_size == 0 && "we don't handle this interaction");
117       assert(variable_shared_mem == 0 && "we don't handle this interaction");
118 
119       agx_usc_pack(b, SHARED, cfg) {
120          cfg.layout = AGX_SHARED_LAYOUT_32X32;
121          cfg.uses_shared_memory = true;
122          cfg.sample_count = 1;
123          cfg.sample_stride_in_8_bytes =
124             DIV_ROUND_UP(info->imageblock_stride, 8);
125          cfg.bytes_per_threadgroup = cfg.sample_stride_in_8_bytes * 8 * 32 * 32;
126       }
127    } else if (info->stage == PIPE_SHADER_COMPUTE ||
128               info->stage == PIPE_SHADER_TESS_CTRL) {
129       unsigned size = info->local_size + variable_shared_mem;
130 
131       agx_usc_pack(b, SHARED, cfg) {
132          cfg.layout = AGX_SHARED_LAYOUT_VERTEX_COMPUTE;
133          cfg.bytes_per_threadgroup = size > 0 ? size : 65536;
134          cfg.uses_shared_memory = size > 0;
135       }
136    } else {
137       agx_usc_shared_none(b);
138    }
139 }
140