1 /*
2 * Copyright © 2022 Valve Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
25 */
26
27
28 /**
29 * this file is used to optimize pipeline state management
30 * pipeline state comparisons are the most significant cause of CPU overhead aside from descriptors,
31 * so more effort must be taken to reduce it by any means
32 */
33 #include "zink_types.h"
34 #include "zink_pipeline.h"
35 #include "zink_program.h"
36 #include "zink_screen.h"
37
38 /* runtime-optimized pipeline state hashing */
39 template <zink_dynamic_state DYNAMIC_STATE>
40 static uint32_t
hash_gfx_pipeline_state(const void * key,struct zink_screen * screen)41 hash_gfx_pipeline_state(const void *key, struct zink_screen *screen)
42 {
43 const struct zink_gfx_pipeline_state *state = (const struct zink_gfx_pipeline_state *)key;
44 uint32_t hash = _mesa_hash_data(key, screen->have_full_ds3 ?
45 offsetof(struct zink_gfx_pipeline_state, sample_mask) :
46 offsetof(struct zink_gfx_pipeline_state, hash));
47 if (DYNAMIC_STATE < ZINK_DYNAMIC_STATE2)
48 hash = XXH32(&state->dyn_state3, sizeof(state->dyn_state3), hash);
49 if (DYNAMIC_STATE < ZINK_DYNAMIC_STATE3)
50 hash = XXH32(&state->dyn_state2, sizeof(state->dyn_state2), hash);
51 if (DYNAMIC_STATE != ZINK_NO_DYNAMIC_STATE)
52 return hash;
53 return XXH32(&state->dyn_state1, sizeof(state->dyn_state1), hash);
54 }
55
56 template <bool HAS_DYNAMIC>
57 static unsigned
get_pipeline_idx(enum mesa_prim mode,VkPrimitiveTopology vkmode)58 get_pipeline_idx(enum mesa_prim mode, VkPrimitiveTopology vkmode)
59 {
60 /* VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY specifies that the topology state in
61 * VkPipelineInputAssemblyStateCreateInfo only specifies the topology class,
62 * and the specific topology order and adjacency must be set dynamically
63 * with vkCmdSetPrimitiveTopology before any drawing commands.
64 */
65 if (HAS_DYNAMIC) {
66 return get_primtype_idx(mode);
67 }
68 return vkmode;
69 }
70
71 /*
72 VUID-vkCmdBindVertexBuffers2-pStrides-06209
73 If pStrides is not NULL each element of pStrides must be either 0 or greater than or equal
74 to the maximum extent of all vertex input attributes fetched from the corresponding
75 binding, where the extent is calculated as the VkVertexInputAttributeDescription::offset
76 plus VkVertexInputAttributeDescription::format size
77
78 * thus, if the stride doesn't meet the minimum requirement for a binding,
79 * disable the dynamic state here and use a fully-baked pipeline
80 */
81 static bool
check_vertex_strides(struct zink_context * ctx)82 check_vertex_strides(struct zink_context *ctx)
83 {
84 const struct zink_vertex_elements_state *ves = ctx->element_state;
85 for (unsigned i = 0; i < ves->hw_state.num_bindings; i++) {
86 const struct pipe_vertex_buffer *vb = ctx->vertex_buffers + ves->hw_state.binding_map[i];
87 unsigned stride = vb->buffer.resource ? ves->hw_state.b.strides[i] : 0;
88 if (stride && stride < ves->min_stride[i])
89 return false;
90 }
91 return true;
92 }
93
94 /* runtime-optimized function to recalc pipeline state and find a usable pipeline:
95 * in theory, zink supports many feature levels,
96 * but it's important to provide a more optimized codepath for drivers that support all the best features
97 */
98 template <zink_dynamic_state DYNAMIC_STATE, bool HAVE_LIB>
99 VkPipeline
zink_get_gfx_pipeline(struct zink_context * ctx,struct zink_gfx_program * prog,struct zink_gfx_pipeline_state * state,enum mesa_prim mode)100 zink_get_gfx_pipeline(struct zink_context *ctx,
101 struct zink_gfx_program *prog,
102 struct zink_gfx_pipeline_state *state,
103 enum mesa_prim mode)
104 {
105 struct zink_screen *screen = zink_screen(ctx->base.screen);
106 bool uses_dynamic_stride = state->uses_dynamic_stride;
107
108 VkPrimitiveTopology vkmode = zink_primitive_topology(mode);
109 const unsigned idx = screen->info.dynamic_state3_props.dynamicPrimitiveTopologyUnrestricted ?
110 0 :
111 get_pipeline_idx<DYNAMIC_STATE >= ZINK_DYNAMIC_STATE>(mode, vkmode);
112 assert(idx <= ARRAY_SIZE(prog->pipelines[0]));
113 if (!state->dirty && !state->modules_changed &&
114 ((DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT || DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT2) && !ctx->vertex_state_changed) &&
115 idx == state->idx)
116 return state->pipeline;
117
118 struct hash_entry *entry = NULL;
119
120 /* recalc the base pipeline state hash */
121 if (state->dirty) {
122 if (state->pipeline) //avoid on first hash
123 state->final_hash ^= state->hash;
124 state->hash = hash_gfx_pipeline_state<DYNAMIC_STATE>(state, screen);
125 state->final_hash ^= state->hash;
126 state->dirty = false;
127 }
128 /* extra safety asserts for optimal path to catch refactoring bugs */
129 if (prog->optimal_keys) {
130 ASSERTED const union zink_shader_key_optimal *opt = (union zink_shader_key_optimal*)&prog->last_variant_hash;
131 ASSERTED union zink_shader_key_optimal sanitized = {};
132 sanitized.val = zink_sanitize_optimal_key(ctx->gfx_stages, ctx->gfx_pipeline_state.shader_keys_optimal.key.val);
133 assert(opt->val == sanitized.val);
134 assert(state->optimal_key == sanitized.val);
135 }
136 /* recalc vertex state if missing optimal extensions */
137 if (DYNAMIC_STATE != ZINK_DYNAMIC_VERTEX_INPUT2 && DYNAMIC_STATE != ZINK_DYNAMIC_VERTEX_INPUT && ctx->vertex_state_changed) {
138 if (state->pipeline)
139 state->final_hash ^= state->vertex_hash;
140 /* even if dynamic stride is available, it may not be usable with the current pipeline */
141 if (DYNAMIC_STATE != ZINK_NO_DYNAMIC_STATE)
142 #if defined(MVK_VERSION)
143 if (screen->have_dynamic_state_vertex_input_binding_stride)
144 #endif
145 uses_dynamic_stride = check_vertex_strides(ctx);
146 if (!uses_dynamic_stride) {
147 uint32_t hash = 0;
148 /* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */
149 uint32_t vertex_buffers_enabled_mask = state->vertex_buffers_enabled_mask;
150 hash = XXH32(&vertex_buffers_enabled_mask, sizeof(uint32_t), hash);
151
152 for (unsigned i = 0; i < state->element_state->num_bindings; i++) {
153 const unsigned buffer_id = ctx->element_state->hw_state.binding_map[i];
154 struct pipe_vertex_buffer *vb = ctx->vertex_buffers + buffer_id;
155 state->vertex_strides[buffer_id] = vb->buffer.resource ? state->element_state->b.strides[i] : 0;
156 hash = XXH32(&state->vertex_strides[buffer_id], sizeof(uint32_t), hash);
157 }
158 state->vertex_hash = hash ^ state->element_state->hash;
159 } else
160 state->vertex_hash = state->element_state->hash;
161 state->final_hash ^= state->vertex_hash;
162 }
163 state->modules_changed = false;
164 state->uses_dynamic_stride = uses_dynamic_stride;
165 state->idx = idx;
166 ctx->vertex_state_changed = false;
167
168 const int rp_idx = state->render_pass ? 1 : 0;
169 /* shortcut for reusing previous pipeline across program changes */
170 if (DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT || DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT2) {
171 if (prog->last_finalized_hash[rp_idx][idx] == state->final_hash &&
172 !prog->inline_variants && likely(prog->last_pipeline[rp_idx][idx]) &&
173 /* this data is too big to compare in the fast-path */
174 likely(!prog->shaders[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask)) {
175 state->pipeline = prog->last_pipeline[rp_idx][idx]->pipeline;
176 return state->pipeline;
177 }
178 }
179 entry = _mesa_hash_table_search_pre_hashed(&prog->pipelines[rp_idx][idx], state->final_hash, state);
180
181 if (!entry) {
182 /* always wait on async precompile/cache fence */
183 util_queue_fence_wait(&prog->base.cache_fence);
184 struct zink_gfx_pipeline_cache_entry *pc_entry = CALLOC_STRUCT(zink_gfx_pipeline_cache_entry);
185 if (!pc_entry)
186 return VK_NULL_HANDLE;
187 /* cache entries must have all state needed to construct pipelines
188 * TODO: maybe optimize this since all these values aren't actually needed
189 */
190 memcpy(&pc_entry->state, state, sizeof(*state));
191 pc_entry->state.rendering_info.pColorAttachmentFormats = pc_entry->state.rendering_formats;
192 pc_entry->prog = prog;
193 /* init the optimized background compile fence */
194 util_queue_fence_init(&pc_entry->fence);
195 entry = _mesa_hash_table_insert_pre_hashed(&prog->pipelines[rp_idx][idx], state->final_hash, pc_entry, pc_entry);
196 if (prog->base.uses_shobj && !prog->is_separable) {
197 memcpy(pc_entry->shobjs, prog->objs, sizeof(prog->objs));
198 zink_gfx_program_compile_queue(ctx, pc_entry);
199 } else if (HAVE_LIB && zink_can_use_pipeline_libs(ctx)) {
200 /* this is the graphics pipeline library path: find/construct all partial pipelines */
201 simple_mtx_lock(&prog->libs->lock);
202 struct set_entry *he = _mesa_set_search(&prog->libs->libs, &ctx->gfx_pipeline_state.optimal_key);
203 struct zink_gfx_library_key *gkey;
204 if (he) {
205 gkey = (struct zink_gfx_library_key *)he->key;
206 } else {
207 assert(!prog->is_separable);
208 gkey = zink_create_pipeline_lib(screen, prog, &ctx->gfx_pipeline_state);
209 }
210 simple_mtx_unlock(&prog->libs->lock);
211 struct zink_gfx_input_key *ikey = DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT ?
212 zink_find_or_create_input_dynamic(ctx, vkmode) :
213 zink_find_or_create_input(ctx, vkmode);
214 struct zink_gfx_output_key *okey = DYNAMIC_STATE >= ZINK_DYNAMIC_STATE3 && screen->have_full_ds3 ?
215 zink_find_or_create_output_ds3(ctx) :
216 zink_find_or_create_output(ctx);
217 /* partial pipelines are stored to the cache entry for async optimized pipeline compiles */
218 pc_entry->gpl.ikey = ikey;
219 pc_entry->gpl.gkey = gkey;
220 pc_entry->gpl.okey = okey;
221 /* try to hit optimized compile cache first if possible */
222 if (!prog->is_separable)
223 pc_entry->pipeline = zink_create_gfx_pipeline_combined(screen, prog, ikey->pipeline, &gkey->pipeline, 1, okey->pipeline, true, true);
224 if (!pc_entry->pipeline) {
225 /* create the non-optimized pipeline first using fast-linking to avoid stuttering */
226 pc_entry->pipeline = zink_create_gfx_pipeline_combined(screen, prog, ikey->pipeline, &gkey->pipeline, 1, okey->pipeline, false, false);
227 if (!prog->is_separable)
228 /* trigger async optimized pipeline compile if this was the fast-linked unoptimized pipeline */
229 zink_gfx_program_compile_queue(ctx, pc_entry);
230 }
231 } else {
232 /* optimize by default only when expecting precompiles in order to reduce stuttering */
233 if (DYNAMIC_STATE != ZINK_DYNAMIC_VERTEX_INPUT2 && DYNAMIC_STATE != ZINK_DYNAMIC_VERTEX_INPUT)
234 pc_entry->pipeline = zink_create_gfx_pipeline(screen, prog, prog->objs, state, state->element_state->binding_map, vkmode, !HAVE_LIB);
235 else
236 pc_entry->pipeline = zink_create_gfx_pipeline(screen, prog, prog->objs, state, NULL, vkmode, !HAVE_LIB);
237 if (HAVE_LIB && !prog->is_separable)
238 /* trigger async optimized pipeline compile if this was an unoptimized pipeline */
239 zink_gfx_program_compile_queue(ctx, pc_entry);
240 }
241 if (pc_entry->pipeline == VK_NULL_HANDLE)
242 return VK_NULL_HANDLE;
243
244 zink_screen_update_pipeline_cache(screen, &prog->base, false);
245 }
246
247 struct zink_gfx_pipeline_cache_entry *cache_entry = (struct zink_gfx_pipeline_cache_entry *)entry->data;
248 state->pipeline = cache_entry->pipeline;
249 /* update states for fastpath */
250 if (DYNAMIC_STATE >= ZINK_DYNAMIC_VERTEX_INPUT) {
251 prog->last_finalized_hash[rp_idx][idx] = state->final_hash;
252 prog->last_pipeline[rp_idx][idx] = cache_entry;
253 }
254 return state->pipeline;
255 }
256
257 /* runtime-optimized pipeline state comparisons */
258 template <zink_pipeline_dynamic_state DYNAMIC_STATE, unsigned STAGE_MASK>
259 static bool
equals_gfx_pipeline_state(const void * a,const void * b)260 equals_gfx_pipeline_state(const void *a, const void *b)
261 {
262 const struct zink_gfx_pipeline_state *sa = (const struct zink_gfx_pipeline_state *)a;
263 const struct zink_gfx_pipeline_state *sb = (const struct zink_gfx_pipeline_state *)b;
264 if (DYNAMIC_STATE < ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT) {
265 if (sa->uses_dynamic_stride != sb->uses_dynamic_stride)
266 return false;
267 }
268 if (DYNAMIC_STATE == ZINK_PIPELINE_NO_DYNAMIC_STATE ||
269 (DYNAMIC_STATE < ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT && !sa->uses_dynamic_stride)) {
270 if (sa->vertex_buffers_enabled_mask != sb->vertex_buffers_enabled_mask)
271 return false;
272 /* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */
273 uint32_t mask_a = sa->vertex_buffers_enabled_mask;
274 uint32_t mask_b = sb->vertex_buffers_enabled_mask;
275 while (mask_a || mask_b) {
276 unsigned idx_a = u_bit_scan(&mask_a);
277 unsigned idx_b = u_bit_scan(&mask_b);
278 if (sa->vertex_strides[idx_a] != sb->vertex_strides[idx_b])
279 return false;
280 }
281 }
282
283 /* each dynamic state extension has its own struct on the pipeline state to compare
284 * if all extensions are supported, none of them are accessed
285 */
286 if (DYNAMIC_STATE == ZINK_PIPELINE_NO_DYNAMIC_STATE) {
287 if (memcmp(&sa->dyn_state1, &sb->dyn_state1, offsetof(struct zink_pipeline_dynamic_state1, depth_stencil_alpha_state)))
288 return false;
289 if (!!sa->dyn_state1.depth_stencil_alpha_state != !!sb->dyn_state1.depth_stencil_alpha_state ||
290 (sa->dyn_state1.depth_stencil_alpha_state &&
291 memcmp(sa->dyn_state1.depth_stencil_alpha_state, sb->dyn_state1.depth_stencil_alpha_state,
292 sizeof(struct zink_depth_stencil_alpha_hw_state))))
293 return false;
294 }
295 if (DYNAMIC_STATE < ZINK_PIPELINE_DYNAMIC_STATE3) {
296 if (DYNAMIC_STATE < ZINK_PIPELINE_DYNAMIC_STATE2) {
297 if (memcmp(&sa->dyn_state2, &sb->dyn_state2, sizeof(sa->dyn_state2)))
298 return false;
299 }
300 if (memcmp(&sa->dyn_state3, &sb->dyn_state3, sizeof(sa->dyn_state3)))
301 return false;
302 } else if (DYNAMIC_STATE != ZINK_PIPELINE_DYNAMIC_STATE2_PCP &&
303 DYNAMIC_STATE != ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT2_PCP &&
304 DYNAMIC_STATE != ZINK_PIPELINE_DYNAMIC_STATE3_PCP &&
305 DYNAMIC_STATE != ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT_PCP &&
306 (STAGE_MASK & BITFIELD_BIT(MESA_SHADER_TESS_EVAL)) &&
307 !(STAGE_MASK & BITFIELD_BIT(MESA_SHADER_TESS_CTRL))) {
308 if (sa->dyn_state2.vertices_per_patch != sb->dyn_state2.vertices_per_patch)
309 return false;
310 }
311 /* optimal keys are the fastest path: only a single uint32_t comparison for all shader module variants */
312 if (STAGE_MASK & STAGE_MASK_OPTIMAL) {
313 if (sa->optimal_key != sb->optimal_key)
314 return false;
315 if (STAGE_MASK & STAGE_MASK_OPTIMAL_SHADOW) {
316 if (sa->shadow != sb->shadow)
317 return false;
318 }
319 } else {
320 if (STAGE_MASK & BITFIELD_BIT(MESA_SHADER_TESS_CTRL)) {
321 if (sa->modules[MESA_SHADER_TESS_CTRL] != sb->modules[MESA_SHADER_TESS_CTRL])
322 return false;
323 }
324 if (STAGE_MASK & BITFIELD_BIT(MESA_SHADER_TESS_EVAL)) {
325 if (sa->modules[MESA_SHADER_TESS_EVAL] != sb->modules[MESA_SHADER_TESS_EVAL])
326 return false;
327 }
328 if (STAGE_MASK & BITFIELD_BIT(MESA_SHADER_GEOMETRY)) {
329 if (sa->modules[MESA_SHADER_GEOMETRY] != sb->modules[MESA_SHADER_GEOMETRY])
330 return false;
331 }
332 if (sa->modules[MESA_SHADER_VERTEX] != sb->modules[MESA_SHADER_VERTEX])
333 return false;
334 if (sa->modules[MESA_SHADER_FRAGMENT] != sb->modules[MESA_SHADER_FRAGMENT])
335 return false;
336 }
337 /* the base pipeline state is a 12 byte comparison */
338 return !memcmp(a, b, offsetof(struct zink_gfx_pipeline_state, hash));
339 }
340
341 /* below is a bunch of code to pick the right equals_gfx_pipeline_state template for runtime */
342 template <zink_pipeline_dynamic_state DYNAMIC_STATE, unsigned STAGE_MASK>
343 static equals_gfx_pipeline_state_func
get_optimal_gfx_pipeline_stage_eq_func(bool optimal_keys,bool shadow_needs_shader_swizzle)344 get_optimal_gfx_pipeline_stage_eq_func(bool optimal_keys, bool shadow_needs_shader_swizzle)
345 {
346 if (optimal_keys) {
347 if (shadow_needs_shader_swizzle)
348 return equals_gfx_pipeline_state<DYNAMIC_STATE, STAGE_MASK | STAGE_MASK_OPTIMAL | STAGE_MASK_OPTIMAL_SHADOW>;
349 return equals_gfx_pipeline_state<DYNAMIC_STATE, STAGE_MASK | STAGE_MASK_OPTIMAL>;
350 }
351 return equals_gfx_pipeline_state<DYNAMIC_STATE, STAGE_MASK>;
352 }
353
354 template <zink_pipeline_dynamic_state DYNAMIC_STATE>
355 static equals_gfx_pipeline_state_func
get_gfx_pipeline_stage_eq_func(struct zink_gfx_program * prog,bool optimal_keys)356 get_gfx_pipeline_stage_eq_func(struct zink_gfx_program *prog, bool optimal_keys)
357 {
358 bool shadow_needs_shader_swizzle = prog->shaders[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask > 0;
359 unsigned vertex_stages = prog->stages_present & BITFIELD_MASK(MESA_SHADER_FRAGMENT);
360 if (vertex_stages & BITFIELD_BIT(MESA_SHADER_TESS_CTRL)) {
361 if (prog->shaders[MESA_SHADER_TESS_CTRL]->non_fs.is_generated)
362 vertex_stages &= ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL);
363 }
364 if (vertex_stages & BITFIELD_BIT(MESA_SHADER_TESS_CTRL)) {
365 if (vertex_stages == BITFIELD_MASK(MESA_SHADER_FRAGMENT))
366 /* all stages */
367 return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
368 BITFIELD_MASK(MESA_SHADER_COMPUTE)>(optimal_keys, shadow_needs_shader_swizzle);
369 if (vertex_stages == BITFIELD_MASK(MESA_SHADER_GEOMETRY))
370 /* tess only: includes generated tcs too */
371 return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
372 BITFIELD_MASK(MESA_SHADER_COMPUTE) & ~BITFIELD_BIT(MESA_SHADER_GEOMETRY)>(optimal_keys, shadow_needs_shader_swizzle);
373 if (vertex_stages == (BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)))
374 /* geom only */
375 return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
376 BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_FRAGMENT) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)>(optimal_keys, shadow_needs_shader_swizzle);
377 }
378 if (vertex_stages == (BITFIELD_MASK(MESA_SHADER_FRAGMENT) & ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL)))
379 /* all stages but tcs */
380 return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
381 BITFIELD_MASK(MESA_SHADER_COMPUTE) & ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL)>(optimal_keys, shadow_needs_shader_swizzle);
382 if (vertex_stages == (BITFIELD_MASK(MESA_SHADER_GEOMETRY) & ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL)))
383 /* tess only: generated tcs */
384 return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
385 BITFIELD_MASK(MESA_SHADER_COMPUTE) & ~(BITFIELD_BIT(MESA_SHADER_GEOMETRY) | BITFIELD_BIT(MESA_SHADER_TESS_CTRL))>(optimal_keys, shadow_needs_shader_swizzle);
386 if (vertex_stages == (BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)))
387 /* geom only */
388 return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
389 BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_FRAGMENT) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)>(optimal_keys, shadow_needs_shader_swizzle);
390 return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
391 BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_FRAGMENT)>(optimal_keys, shadow_needs_shader_swizzle);
392 }
393
394 equals_gfx_pipeline_state_func
zink_get_gfx_pipeline_eq_func(struct zink_screen * screen,struct zink_gfx_program * prog)395 zink_get_gfx_pipeline_eq_func(struct zink_screen *screen, struct zink_gfx_program *prog)
396 {
397 if (screen->info.have_EXT_extended_dynamic_state) {
398 if (screen->info.have_EXT_extended_dynamic_state2) {
399 if (screen->info.have_EXT_extended_dynamic_state3) {
400 if (screen->info.have_EXT_vertex_input_dynamic_state) {
401 if (screen->info.dynamic_state2_feats.extendedDynamicState2PatchControlPoints)
402 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT_PCP>(prog, screen->optimal_keys);
403 else
404 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT>(prog, screen->optimal_keys);
405 } else {
406 if (screen->info.dynamic_state2_feats.extendedDynamicState2PatchControlPoints)
407 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE3_PCP>(prog, screen->optimal_keys);
408 else
409 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE3>(prog, screen->optimal_keys);
410 }
411 }
412 if (screen->info.have_EXT_vertex_input_dynamic_state) {
413 if (screen->info.dynamic_state2_feats.extendedDynamicState2PatchControlPoints)
414 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT2_PCP>(prog, screen->optimal_keys);
415 else
416 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT2>(prog, screen->optimal_keys);
417 } else {
418 if (screen->info.dynamic_state2_feats.extendedDynamicState2PatchControlPoints)
419 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE2_PCP>(prog, screen->optimal_keys);
420 else
421 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE2>(prog, screen->optimal_keys);
422 }
423 }
424 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE>(prog, screen->optimal_keys);
425 }
426 return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_NO_DYNAMIC_STATE>(prog, screen->optimal_keys);
427 }
428