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