1 /*
2 * Copyright 2021 Alyssa Rosenzweig
3 * Copyright (C) 2019-2021 Collabora, Ltd.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #ifndef AGX_STATE_H
26 #define AGX_STATE_H
27
28 #include "gallium/include/pipe/p_context.h"
29 #include "gallium/include/pipe/p_state.h"
30 #include "gallium/include/pipe/p_screen.h"
31 #include "gallium/auxiliary/util/u_blitter.h"
32 #include "asahi/lib/agx_pack.h"
33 #include "asahi/lib/agx_bo.h"
34 #include "asahi/lib/agx_device.h"
35 #include "asahi/lib/pool.h"
36 #include "asahi/compiler/agx_compile.h"
37 #include "compiler/nir/nir_lower_blend.h"
38 #include "util/hash_table.h"
39 #include "util/bitset.h"
40
41 struct agx_streamout_target {
42 struct pipe_stream_output_target base;
43 uint32_t offset;
44 };
45
46 struct agx_streamout {
47 struct pipe_stream_output_target *targets[PIPE_MAX_SO_BUFFERS];
48 unsigned num_targets;
49 };
50
51 static inline struct agx_streamout_target *
agx_so_target(struct pipe_stream_output_target * target)52 agx_so_target(struct pipe_stream_output_target *target)
53 {
54 return (struct agx_streamout_target *)target;
55 }
56
57 struct agx_compiled_shader {
58 /* Mapped executable memory */
59 struct agx_bo *bo;
60
61 /* Varying descriptor (TODO: is this the right place?) */
62 uint64_t varyings;
63
64 /* Metadata returned from the compiler */
65 struct agx_shader_info info;
66 };
67
68 struct agx_uncompiled_shader {
69 struct pipe_shader_state base;
70 struct nir_shader *nir;
71 struct hash_table *variants;
72
73 /* Set on VS, passed to FS for linkage */
74 unsigned base_varying;
75 };
76
77 struct agx_stage {
78 struct agx_uncompiled_shader *shader;
79 uint32_t dirty;
80
81 struct pipe_constant_buffer cb[PIPE_MAX_CONSTANT_BUFFERS];
82 uint32_t cb_mask;
83
84 /* Need full CSOs for u_blitter */
85 struct agx_sampler_state *samplers[PIPE_MAX_SAMPLERS];
86 struct agx_sampler_view *textures[PIPE_MAX_SHADER_SAMPLER_VIEWS];
87
88 unsigned sampler_count, texture_count;
89 };
90
91 /* Uploaded scissor descriptors */
92 struct agx_scissors {
93 struct agx_bo *bo;
94 unsigned count;
95 };
96
97 struct agx_batch {
98 unsigned width, height, nr_cbufs;
99 struct pipe_surface *cbufs[8];
100 struct pipe_surface *zsbuf;
101
102 /* PIPE_CLEAR_* bitmask */
103 uint32_t clear, draw;
104
105 float clear_color[4];
106
107 /* Resource list requirements, represented as a bit set indexed by BO
108 * handles (GEM handles on Linux, or IOGPU's equivalent on macOS) */
109 BITSET_WORD bo_list[256];
110
111 struct agx_pool pool, pipeline_pool;
112 struct agx_bo *encoder;
113 uint8_t *encoder_current;
114
115 struct agx_scissors scissor;
116 };
117
118 struct agx_zsa {
119 struct pipe_depth_stencil_alpha_state base;
120 struct agx_rasterizer_face_packed front, back;
121 };
122
123 struct agx_blend {
124 bool logicop_enable, blend_enable;
125
126 union {
127 nir_lower_blend_rt rt[8];
128 unsigned logicop_func;
129 };
130 };
131
132 struct asahi_shader_key {
133 struct agx_shader_key base;
134 struct agx_blend blend;
135 unsigned nr_cbufs;
136 enum pipe_format rt_formats[PIPE_MAX_COLOR_BUFS];
137 };
138
139 enum agx_dirty {
140 AGX_DIRTY_VERTEX = BITFIELD_BIT(0),
141 AGX_DIRTY_VIEWPORT = BITFIELD_BIT(1),
142 AGX_DIRTY_SCISSOR = BITFIELD_BIT(2),
143 };
144
145 struct agx_context {
146 struct pipe_context base;
147 struct agx_compiled_shader *vs, *fs;
148 uint32_t dirty;
149
150 struct agx_batch *batch;
151
152 struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS];
153 uint32_t vb_mask;
154
155 struct agx_stage stage[PIPE_SHADER_TYPES];
156 struct agx_attribute *attributes;
157 struct agx_rasterizer *rast;
158 struct agx_zsa zs;
159 struct agx_blend *blend;
160 struct pipe_blend_color blend_color;
161 struct pipe_viewport_state viewport;
162 struct pipe_scissor_state scissor;
163 struct pipe_stencil_ref stencil_ref;
164 struct agx_streamout streamout;
165 uint16_t sample_mask;
166 struct pipe_framebuffer_state framebuffer;
167
168 struct pipe_query *cond_query;
169 bool cond_cond;
170 enum pipe_render_cond_flag cond_mode;
171
172 bool is_noop;
173
174 uint8_t render_target[8][AGX_RENDER_TARGET_LENGTH];
175
176 struct blitter_context *blitter;
177 };
178
179 static inline struct agx_context *
agx_context(struct pipe_context * pctx)180 agx_context(struct pipe_context *pctx)
181 {
182 return (struct agx_context *) pctx;
183 }
184
185 struct agx_rasterizer {
186 struct pipe_rasterizer_state base;
187 uint8_t cull[AGX_CULL_LENGTH];
188 uint8_t line_width;
189 };
190
191 struct agx_query {
192 unsigned query;
193 };
194
195 struct agx_sampler_state {
196 struct pipe_sampler_state base;
197
198 /* Prepared descriptor */
199 struct agx_bo *desc;
200 };
201
202 struct agx_sampler_view {
203 struct pipe_sampler_view base;
204
205 /* Prepared descriptor */
206 struct agx_bo *desc;
207 };
208
209 struct agx_screen {
210 struct pipe_screen pscreen;
211 struct agx_device dev;
212 struct sw_winsys *winsys;
213 };
214
215 static inline struct agx_screen *
agx_screen(struct pipe_screen * p)216 agx_screen(struct pipe_screen *p)
217 {
218 return (struct agx_screen *)p;
219 }
220
221 static inline struct agx_device *
agx_device(struct pipe_screen * p)222 agx_device(struct pipe_screen *p)
223 {
224 return &(agx_screen(p)->dev);
225 }
226
227 /* TODO: UABI, fake for macOS */
228 #ifndef DRM_FORMAT_MOD_LINEAR
229 #define DRM_FORMAT_MOD_LINEAR 1
230 #endif
231 #define DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER (2)
232
233 struct agx_resource {
234 struct pipe_resource base;
235 uint64_t modifier;
236
237 /* Should probably be part of the modifier. Affects the tiling algorithm, or
238 * something like that.
239 */
240 bool mipmapped;
241
242 /* Hardware backing */
243 struct agx_bo *bo;
244
245 /* Software backing (XXX) */
246 struct sw_displaytarget *dt;
247 unsigned dt_stride;
248
249 BITSET_DECLARE(data_valid, PIPE_MAX_TEXTURE_LEVELS);
250
251 struct {
252 unsigned offset;
253 unsigned line_stride;
254 unsigned size;
255 } slices[PIPE_MAX_TEXTURE_LEVELS];
256
257 /* Bytes from one miptree to the next */
258 unsigned array_stride;
259
260 /* Metal does not support packed depth/stencil formats; presumably AGX does
261 * not either. Instead, we create separate depth and stencil resources,
262 * managed by u_transfer_helper. We provide the illusion of packed
263 * resources.
264 */
265 struct agx_resource *separate_stencil;
266
267 /* Internal format, since many depth/stencil formats are emulated. */
268 enum pipe_format internal_format;
269 };
270
271 static inline struct agx_resource *
agx_resource(struct pipe_resource * pctx)272 agx_resource(struct pipe_resource *pctx)
273 {
274 return (struct agx_resource *) pctx;
275 }
276
277 /*
278 * Within a resource containing multiple layers and multiple mip levels,
279 * returns the offset from the start of the backing BO of a given level/slice.
280 */
281 static inline uint32_t
agx_texture_offset(struct agx_resource * rsrc,unsigned level,unsigned z)282 agx_texture_offset(struct agx_resource *rsrc, unsigned level, unsigned z)
283 {
284 return rsrc->slices[level].offset + (z * rsrc->array_stride);
285 }
286
287 static inline void *
agx_map_texture_cpu(struct agx_resource * rsrc,unsigned level,unsigned z)288 agx_map_texture_cpu(struct agx_resource *rsrc, unsigned level, unsigned z)
289 {
290 return ((uint8_t *) rsrc->bo->ptr.cpu) + agx_texture_offset(rsrc, level, z);
291 }
292
293 static inline uint64_t
agx_map_texture_gpu(struct agx_resource * rsrc,unsigned level,unsigned z)294 agx_map_texture_gpu(struct agx_resource *rsrc, unsigned level, unsigned z)
295 {
296 return rsrc->bo->ptr.gpu + (uint64_t) agx_texture_offset(rsrc, level, z);
297 }
298
299 struct agx_transfer {
300 struct pipe_transfer base;
301 void *map;
302 struct {
303 struct pipe_resource *rsrc;
304 struct pipe_box box;
305 } staging;
306 };
307
308 static inline struct agx_transfer *
agx_transfer(struct pipe_transfer * p)309 agx_transfer(struct pipe_transfer *p)
310 {
311 return (struct agx_transfer *)p;
312 }
313
314 uint64_t
315 agx_push_location(struct agx_context *ctx, struct agx_push push,
316 enum pipe_shader_type stage);
317
318 uint64_t
319 agx_build_clear_pipeline(struct agx_context *ctx, uint32_t code, uint64_t clear_buf);
320
321 uint64_t
322 agx_build_store_pipeline(struct agx_context *ctx, uint32_t code,
323 uint64_t render_target);
324
325 uint64_t
326 agx_build_reload_pipeline(struct agx_context *ctx, uint32_t code, struct pipe_surface *surf);
327
328 /* Add a BO to a batch. This needs to be amortized O(1) since it's called in
329 * hot paths. To achieve this we model BO lists by bit sets */
330
331 static inline void
agx_batch_add_bo(struct agx_batch * batch,struct agx_bo * bo)332 agx_batch_add_bo(struct agx_batch *batch, struct agx_bo *bo)
333 {
334 if (unlikely(bo->handle > (sizeof(batch->bo_list) * 8)))
335 unreachable("todo: growable");
336
337 BITSET_SET(batch->bo_list, bo->handle);
338 }
339
340 /* Blit shaders */
341 void agx_blit(struct pipe_context *pipe,
342 const struct pipe_blit_info *info);
343
344 void agx_internal_shaders(struct agx_device *dev);
345
346 #endif
347