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