1 /*
2 * Copyright © 2024 Collabora Ltd.
3 * SPDX-License-Identifier: MIT
4 */
5
6 #ifndef PANVK_CMD_DRAW_H
7 #define PANVK_CMD_DRAW_H
8
9 #ifndef PAN_ARCH
10 #error "PAN_ARCH must be defined"
11 #endif
12
13 #include "panvk_blend.h"
14 #include "panvk_cmd_oq.h"
15 #include "panvk_entrypoints.h"
16 #include "panvk_image.h"
17 #include "panvk_image_view.h"
18 #include "panvk_physical_device.h"
19
20 #include "vk_command_buffer.h"
21 #include "vk_format.h"
22
23 #include "pan_props.h"
24
25 #define MAX_VBS 16
26 #define MAX_RTS 8
27
28 struct panvk_cmd_buffer;
29
30 struct panvk_attrib_buf {
31 uint64_t address;
32 unsigned size;
33 };
34
35 struct panvk_resolve_attachment {
36 VkResolveModeFlagBits mode;
37 struct panvk_image_view *dst_iview;
38 };
39
40 struct panvk_rendering_state {
41 VkRenderingFlags flags;
42 uint32_t layer_count;
43 uint32_t view_mask;
44
45 enum vk_rp_attachment_flags bound_attachments;
46 struct {
47 struct panvk_image_view *iviews[MAX_RTS];
48 VkFormat fmts[MAX_RTS];
49 uint8_t samples[MAX_RTS];
50 struct panvk_resolve_attachment resolve[MAX_RTS];
51 } color_attachments;
52
53 struct pan_image_view zs_pview;
54 struct pan_image_view s_pview;
55
56 struct {
57 struct panvk_image_view *iview;
58 VkFormat fmt;
59 struct panvk_resolve_attachment resolve;
60 } z_attachment, s_attachment;
61
62 struct {
63 struct pan_fb_info info;
64 bool crc_valid[MAX_RTS];
65
66 #if PAN_ARCH <= 7
67 uint32_t bo_count;
68 struct pan_kmod_bo *bos[MAX_RTS + 2];
69 #endif
70 } fb;
71
72 #if PAN_ARCH >= 10
73 struct panfrost_ptr fbds;
74 uint64_t tiler;
75
76 /* When a secondary command buffer has to flush draws, it disturbs the
77 * inherited context, and the primary command buffer needs to know. */
78 bool invalidate_inherited_ctx;
79
80 /* True if the last render pass was suspended. */
81 bool suspended;
82
83 struct {
84 /* != 0 if the render pass contains one or more occlusion queries to
85 * signal. */
86 uint64_t chain;
87
88 /* Point to the syncobj of the last occlusion query that was passed
89 * to a draw. */
90 uint64_t last;
91 } oq;
92 #endif
93 };
94
95 enum panvk_cmd_graphics_dirty_state {
96 PANVK_CMD_GRAPHICS_DIRTY_VS,
97 PANVK_CMD_GRAPHICS_DIRTY_FS,
98 PANVK_CMD_GRAPHICS_DIRTY_VB,
99 PANVK_CMD_GRAPHICS_DIRTY_IB,
100 PANVK_CMD_GRAPHICS_DIRTY_OQ,
101 PANVK_CMD_GRAPHICS_DIRTY_DESC_STATE,
102 PANVK_CMD_GRAPHICS_DIRTY_RENDER_STATE,
103 PANVK_CMD_GRAPHICS_DIRTY_VS_PUSH_UNIFORMS,
104 PANVK_CMD_GRAPHICS_DIRTY_FS_PUSH_UNIFORMS,
105 PANVK_CMD_GRAPHICS_DIRTY_STATE_COUNT,
106 };
107
108 struct panvk_cmd_graphics_state {
109 struct panvk_descriptor_state desc_state;
110
111 struct {
112 struct vk_vertex_input_state vi;
113 struct vk_sample_locations_state sl;
114 } dynamic;
115
116 struct panvk_occlusion_query_state occlusion_query;
117 struct panvk_graphics_sysvals sysvals;
118
119 #if PAN_ARCH <= 7
120 struct panvk_shader_link link;
121 #endif
122
123 struct {
124 const struct panvk_shader *shader;
125 struct panvk_shader_desc_state desc;
126 uint64_t push_uniforms;
127 bool required;
128 #if PAN_ARCH <= 7
129 uint64_t rsd;
130 #endif
131 } fs;
132
133 struct {
134 const struct panvk_shader *shader;
135 struct panvk_shader_desc_state desc;
136 uint64_t push_uniforms;
137 #if PAN_ARCH <= 7
138 uint64_t attribs;
139 uint64_t attrib_bufs;
140 #endif
141 } vs;
142
143 struct {
144 struct panvk_attrib_buf bufs[MAX_VBS];
145 unsigned count;
146 } vb;
147
148 /* Index buffer */
149 struct {
150 struct panvk_buffer *buffer;
151 uint64_t offset;
152 uint8_t index_size;
153 } ib;
154
155 struct {
156 struct panvk_blend_info info;
157 } cb;
158
159 struct panvk_rendering_state render;
160
161 #if PAN_ARCH <= 7
162 uint64_t vpd;
163 #endif
164
165 #if PAN_ARCH >= 10
166 uint64_t tsd;
167 #endif
168
169 BITSET_DECLARE(dirty, PANVK_CMD_GRAPHICS_DIRTY_STATE_COUNT);
170 };
171
172 #define dyn_gfx_state_dirty(__cmdbuf, __name) \
173 BITSET_TEST((__cmdbuf)->vk.dynamic_graphics_state.dirty, \
174 MESA_VK_DYNAMIC_##__name)
175
176 #define gfx_state_dirty(__cmdbuf, __name) \
177 BITSET_TEST((__cmdbuf)->state.gfx.dirty, PANVK_CMD_GRAPHICS_DIRTY_##__name)
178
179 #define gfx_state_set_dirty(__cmdbuf, __name) \
180 BITSET_SET((__cmdbuf)->state.gfx.dirty, PANVK_CMD_GRAPHICS_DIRTY_##__name)
181
182 #define gfx_state_clear_all_dirty(__cmdbuf) \
183 BITSET_ZERO((__cmdbuf)->state.gfx.dirty)
184
185 #define gfx_state_set_all_dirty(__cmdbuf) \
186 BITSET_ONES((__cmdbuf)->state.gfx.dirty)
187
188 #define set_gfx_sysval(__cmdbuf, __dirty, __name, __val) \
189 do { \
190 struct panvk_graphics_sysvals __new_sysval; \
191 __new_sysval.__name = __val; \
192 if (memcmp(&(__cmdbuf)->state.gfx.sysvals.__name, &__new_sysval.__name, \
193 sizeof(__new_sysval.__name))) { \
194 (__cmdbuf)->state.gfx.sysvals.__name = __new_sysval.__name; \
195 BITSET_SET_RANGE(__dirty, sysval_fau_start(graphics, __name), \
196 sysval_fau_end(graphics, __name)); \
197 } \
198 } while (0)
199
200 static inline uint32_t
panvk_select_tiler_hierarchy_mask(const struct panvk_physical_device * phys_dev,const struct panvk_cmd_graphics_state * state)201 panvk_select_tiler_hierarchy_mask(const struct panvk_physical_device *phys_dev,
202 const struct panvk_cmd_graphics_state *state)
203 {
204 struct panfrost_tiler_features tiler_features =
205 panfrost_query_tiler_features(&phys_dev->kmod.props);
206
207 uint32_t hierarchy_mask =
208 pan_select_tiler_hierarchy_mask(state->render.fb.info.width,
209 state->render.fb.info.height,
210 tiler_features.max_levels);
211
212 /* For effective tile size larger than 16x16, disable first level */
213 if (state->render.fb.info.tile_size > 16 * 16)
214 hierarchy_mask &= ~1;
215
216 return hierarchy_mask;
217 }
218
219 static inline bool
fs_required(const struct panvk_cmd_graphics_state * state,const struct vk_dynamic_graphics_state * dyn_state)220 fs_required(const struct panvk_cmd_graphics_state *state,
221 const struct vk_dynamic_graphics_state *dyn_state)
222 {
223 const struct pan_shader_info *fs_info =
224 state->fs.shader ? &state->fs.shader->info : NULL;
225 const struct vk_color_blend_state *cb = &dyn_state->cb;
226 const struct vk_rasterization_state *rs = &dyn_state->rs;
227
228 if (rs->rasterizer_discard_enable || !fs_info)
229 return false;
230
231 /* If we generally have side effects */
232 if (fs_info->fs.sidefx)
233 return true;
234
235 /* If colour is written we need to execute */
236 for (unsigned i = 0; i < cb->attachment_count; ++i) {
237 if ((cb->color_write_enables & BITFIELD_BIT(i)) &&
238 cb->attachments[i].write_mask)
239 return true;
240 }
241
242 /* If alpha-to-coverage is enabled, we need to run the fragment shader even
243 * if we don't have a color attachment, so depth/stencil updates can be
244 * discarded if alpha, and thus coverage, is 0. */
245 if (dyn_state->ms.alpha_to_coverage_enable)
246 return true;
247
248 /* If the sample mask is updated, we need to run the fragment shader,
249 * otherwise the fixed-function depth/stencil results will apply to all
250 * samples. */
251 if (fs_info->outputs_written & BITFIELD64_BIT(FRAG_RESULT_SAMPLE_MASK))
252 return true;
253
254 /* If depth is written and not implied we need to execute.
255 * TODO: Predicate on Z/S writes being enabled */
256 return (fs_info->fs.writes_depth || fs_info->fs.writes_stencil);
257 }
258
259 static inline bool
cached_fs_required(ASSERTED const struct panvk_cmd_graphics_state * state,ASSERTED const struct vk_dynamic_graphics_state * dyn_state,bool cached_value)260 cached_fs_required(ASSERTED const struct panvk_cmd_graphics_state *state,
261 ASSERTED const struct vk_dynamic_graphics_state *dyn_state,
262 bool cached_value)
263 {
264 /* Make sure the cached value was properly initialized. */
265 assert(fs_required(state, dyn_state) == cached_value);
266 return cached_value;
267 }
268
269 #define get_fs(__cmdbuf) \
270 (cached_fs_required(&(__cmdbuf)->state.gfx, \
271 &(__cmdbuf)->vk.dynamic_graphics_state, \
272 (__cmdbuf)->state.gfx.fs.required) \
273 ? (__cmdbuf)->state.gfx.fs.shader \
274 : NULL)
275
276 /* Anything that might change the value returned by get_fs() makes users of the
277 * fragment shader dirty, because not using the fragment shader (when
278 * fs_required() returns false) impacts various other things, like VS -> FS
279 * linking in the JM backend, or the update of the fragment shader pointer in
280 * the CSF backend. Call gfx_state_dirty(cmdbuf, FS) if you only care about
281 * fragment shader updates. */
282
283 #define fs_user_dirty(__cmdbuf) \
284 (gfx_state_dirty(cmdbuf, FS) || \
285 dyn_gfx_state_dirty(cmdbuf, RS_RASTERIZER_DISCARD_ENABLE) || \
286 dyn_gfx_state_dirty(cmdbuf, CB_ATTACHMENT_COUNT) || \
287 dyn_gfx_state_dirty(cmdbuf, CB_COLOR_WRITE_ENABLES) || \
288 dyn_gfx_state_dirty(cmdbuf, CB_WRITE_MASKS) || \
289 dyn_gfx_state_dirty(cmdbuf, MS_ALPHA_TO_COVERAGE_ENABLE))
290
291 /* After a draw, all dirty flags are cleared except the FS dirty flag which
292 * needs to be set again if the draw didn't use the fragment shader. */
293
294 #define clear_dirty_after_draw(__cmdbuf) \
295 do { \
296 bool __set_fs_dirty = \
297 (__cmdbuf)->state.gfx.fs.shader != get_fs(__cmdbuf); \
298 bool __set_fs_push_dirty = \
299 __set_fs_dirty && gfx_state_dirty(__cmdbuf, FS_PUSH_UNIFORMS); \
300 vk_dynamic_graphics_state_clear_dirty( \
301 &(__cmdbuf)->vk.dynamic_graphics_state); \
302 gfx_state_clear_all_dirty(__cmdbuf); \
303 if (__set_fs_dirty) \
304 gfx_state_set_dirty(__cmdbuf, FS); \
305 if (__set_fs_push_dirty) \
306 gfx_state_set_dirty(__cmdbuf, FS_PUSH_UNIFORMS); \
307 } while (0)
308
309 void
310 panvk_per_arch(cmd_init_render_state)(struct panvk_cmd_buffer *cmdbuf,
311 const VkRenderingInfo *pRenderingInfo);
312
313 void
314 panvk_per_arch(cmd_force_fb_preload)(struct panvk_cmd_buffer *cmdbuf,
315 const VkRenderingInfo *render_info);
316
317 void
318 panvk_per_arch(cmd_preload_render_area_border)(struct panvk_cmd_buffer *cmdbuf,
319 const VkRenderingInfo *render_info);
320
321 void panvk_per_arch(cmd_resolve_attachments)(struct panvk_cmd_buffer *cmdbuf);
322
323 struct panvk_draw_info {
324 struct {
325 uint32_t size;
326 uint32_t offset;
327 } index;
328
329 struct {
330 #if PAN_ARCH <= 7
331 int32_t raw_offset;
332 #endif
333 int32_t base;
334 uint32_t count;
335 } vertex;
336
337 struct {
338 int32_t base;
339 uint32_t count;
340 } instance;
341
342 struct {
343 uint64_t buffer_dev_addr;
344 uint32_t draw_count;
345 uint32_t stride;
346 } indirect;
347
348 #if PAN_ARCH <= 7
349 uint32_t layer_id;
350 #endif
351 };
352
353 void
354 panvk_per_arch(cmd_prepare_draw_sysvals)(struct panvk_cmd_buffer *cmdbuf,
355 const struct panvk_draw_info *info);
356
357 #endif
358