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
41struct agx_streamout_target {
42   struct pipe_stream_output_target base;
43   uint32_t offset;
44};
45
46struct agx_streamout {
47   struct pipe_stream_output_target *targets[PIPE_MAX_SO_BUFFERS];
48   unsigned num_targets;
49};
50
51static inline struct agx_streamout_target *
52agx_so_target(struct pipe_stream_output_target *target)
53{
54   return (struct agx_streamout_target *)target;
55}
56
57struct 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
68struct 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
77struct 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 */
92struct agx_scissors {
93      struct agx_bo *bo;
94      unsigned count;
95};
96
97struct 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
118struct agx_zsa {
119   struct pipe_depth_stencil_alpha_state base;
120   struct agx_rasterizer_face_packed front, back;
121};
122
123struct 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
132struct 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
139enum 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
145struct 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
179static inline struct agx_context *
180agx_context(struct pipe_context *pctx)
181{
182   return (struct agx_context *) pctx;
183}
184
185struct agx_rasterizer {
186   struct pipe_rasterizer_state base;
187   uint8_t cull[AGX_CULL_LENGTH];
188   uint8_t line_width;
189};
190
191struct agx_query {
192   unsigned	query;
193};
194
195struct agx_sampler_state {
196   struct pipe_sampler_state base;
197
198   /* Prepared descriptor */
199   struct agx_bo *desc;
200};
201
202struct agx_sampler_view {
203   struct pipe_sampler_view base;
204
205   /* Prepared descriptor */
206   struct agx_bo *desc;
207};
208
209struct agx_screen {
210   struct pipe_screen pscreen;
211   struct agx_device dev;
212   struct sw_winsys *winsys;
213};
214
215static inline struct agx_screen *
216agx_screen(struct pipe_screen *p)
217{
218   return (struct agx_screen *)p;
219}
220
221static inline struct agx_device *
222agx_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
233struct agx_resource {
234   struct pipe_resource	base;
235   uint64_t modifier;
236
237   /* Hardware backing */
238   struct agx_bo *bo;
239
240   /* Software backing (XXX) */
241   struct sw_displaytarget	*dt;
242   unsigned dt_stride;
243
244   BITSET_DECLARE(data_valid, PIPE_MAX_TEXTURE_LEVELS);
245
246   struct {
247      unsigned offset;
248      unsigned line_stride;
249   } slices[PIPE_MAX_TEXTURE_LEVELS];
250
251   /* Bytes from one miptree to the next */
252   unsigned array_stride;
253};
254
255static inline struct agx_resource *
256agx_resource(struct pipe_resource *pctx)
257{
258   return (struct agx_resource *) pctx;
259}
260
261struct agx_transfer {
262   struct pipe_transfer base;
263   void *map;
264   struct {
265      struct pipe_resource *rsrc;
266      struct pipe_box box;
267   } staging;
268};
269
270static inline struct agx_transfer *
271agx_transfer(struct pipe_transfer *p)
272{
273   return (struct agx_transfer *)p;
274}
275
276uint64_t
277agx_push_location(struct agx_context *ctx, struct agx_push push,
278                  enum pipe_shader_type stage);
279
280uint64_t
281agx_build_clear_pipeline(struct agx_context *ctx, uint32_t code, uint64_t clear_buf);
282
283uint64_t
284agx_build_store_pipeline(struct agx_context *ctx, uint32_t code,
285                         uint64_t render_target);
286
287uint64_t
288agx_build_reload_pipeline(struct agx_context *ctx, uint32_t code, struct pipe_surface *surf);
289
290/* Add a BO to a batch. This needs to be amortized O(1) since it's called in
291 * hot paths. To achieve this we model BO lists by bit sets */
292
293static inline void
294agx_batch_add_bo(struct agx_batch *batch, struct agx_bo *bo)
295{
296   if (unlikely(bo->handle > (sizeof(batch->bo_list) * 8)))
297      unreachable("todo: growable");
298
299   BITSET_SET(batch->bo_list, bo->handle);
300}
301
302/* Blit shaders */
303void agx_blit(struct pipe_context *pipe,
304              const struct pipe_blit_info *info);
305
306void agx_internal_shaders(struct agx_device *dev);
307
308#endif
309