xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/zink/zink_program_state.hpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 <[email protected]>
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          uses_dynamic_stride = check_vertex_strides(ctx);
143       if (!uses_dynamic_stride) {
144          uint32_t hash = 0;
145          /* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */
146          uint32_t vertex_buffers_enabled_mask = state->vertex_buffers_enabled_mask;
147          hash = XXH32(&vertex_buffers_enabled_mask, sizeof(uint32_t), hash);
148 
149          for (unsigned i = 0; i < state->element_state->num_bindings; i++) {
150             const unsigned buffer_id = ctx->element_state->hw_state.binding_map[i];
151             struct pipe_vertex_buffer *vb = ctx->vertex_buffers + buffer_id;
152             state->vertex_strides[buffer_id] = vb->buffer.resource ? state->element_state->b.strides[i] : 0;
153             hash = XXH32(&state->vertex_strides[buffer_id], sizeof(uint32_t), hash);
154          }
155          state->vertex_hash = hash ^ state->element_state->hash;
156       } else
157          state->vertex_hash = state->element_state->hash;
158       state->final_hash ^= state->vertex_hash;
159    }
160    state->modules_changed = false;
161    state->uses_dynamic_stride = uses_dynamic_stride;
162    state->idx = idx;
163    ctx->vertex_state_changed = false;
164 
165    const int rp_idx = state->render_pass ? 1 : 0;
166    /* shortcut for reusing previous pipeline across program changes */
167    if (DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT || DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT2) {
168       if (prog->last_finalized_hash[rp_idx][idx] == state->final_hash &&
169           !prog->inline_variants && likely(prog->last_pipeline[rp_idx][idx]) &&
170           /* this data is too big to compare in the fast-path */
171           likely(!prog->shaders[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask)) {
172          state->pipeline = prog->last_pipeline[rp_idx][idx]->pipeline;
173          return state->pipeline;
174       }
175    }
176    entry = _mesa_hash_table_search_pre_hashed(&prog->pipelines[rp_idx][idx], state->final_hash, state);
177 
178    if (!entry) {
179       /* always wait on async precompile/cache fence */
180       util_queue_fence_wait(&prog->base.cache_fence);
181       struct zink_gfx_pipeline_cache_entry *pc_entry = CALLOC_STRUCT(zink_gfx_pipeline_cache_entry);
182       if (!pc_entry)
183          return VK_NULL_HANDLE;
184       /* cache entries must have all state needed to construct pipelines
185        * TODO: maybe optimize this since all these values aren't actually needed
186        */
187       memcpy(&pc_entry->state, state, sizeof(*state));
188       pc_entry->state.rendering_info.pColorAttachmentFormats = pc_entry->state.rendering_formats;
189       pc_entry->prog = prog;
190       /* init the optimized background compile fence */
191       util_queue_fence_init(&pc_entry->fence);
192       entry = _mesa_hash_table_insert_pre_hashed(&prog->pipelines[rp_idx][idx], state->final_hash, pc_entry, pc_entry);
193       if (prog->base.uses_shobj && !prog->is_separable) {
194          memcpy(pc_entry->shobjs, prog->objs, sizeof(prog->objs));
195          zink_gfx_program_compile_queue(ctx, pc_entry);
196       } else if (HAVE_LIB && zink_can_use_pipeline_libs(ctx)) {
197          /* this is the graphics pipeline library path: find/construct all partial pipelines */
198          simple_mtx_lock(&prog->libs->lock);
199          struct set_entry *he = _mesa_set_search(&prog->libs->libs, &ctx->gfx_pipeline_state.optimal_key);
200          struct zink_gfx_library_key *gkey;
201          if (he) {
202             gkey = (struct zink_gfx_library_key *)he->key;
203          } else {
204             assert(!prog->is_separable);
205             gkey = zink_create_pipeline_lib(screen, prog, &ctx->gfx_pipeline_state);
206          }
207          simple_mtx_unlock(&prog->libs->lock);
208          struct zink_gfx_input_key *ikey = DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT ?
209                                              zink_find_or_create_input_dynamic(ctx, vkmode) :
210                                              zink_find_or_create_input(ctx, vkmode);
211          struct zink_gfx_output_key *okey = DYNAMIC_STATE >= ZINK_DYNAMIC_STATE3 && screen->have_full_ds3 ?
212                                              zink_find_or_create_output_ds3(ctx) :
213                                              zink_find_or_create_output(ctx);
214          /* partial pipelines are stored to the cache entry for async optimized pipeline compiles */
215          pc_entry->gpl.ikey = ikey;
216          pc_entry->gpl.gkey = gkey;
217          pc_entry->gpl.okey = okey;
218          /* try to hit optimized compile cache first if possible */
219          if (!prog->is_separable)
220             pc_entry->pipeline = zink_create_gfx_pipeline_combined(screen, prog, ikey->pipeline, &gkey->pipeline, 1, okey->pipeline, true, true);
221          if (!pc_entry->pipeline) {
222             /* create the non-optimized pipeline first using fast-linking to avoid stuttering */
223             pc_entry->pipeline = zink_create_gfx_pipeline_combined(screen, prog, ikey->pipeline, &gkey->pipeline, 1, okey->pipeline, false, false);
224             if (!prog->is_separable)
225                /* trigger async optimized pipeline compile if this was the fast-linked unoptimized pipeline */
226                zink_gfx_program_compile_queue(ctx, pc_entry);
227          }
228       } else {
229          /* optimize by default only when expecting precompiles in order to reduce stuttering */
230          if (DYNAMIC_STATE != ZINK_DYNAMIC_VERTEX_INPUT2 && DYNAMIC_STATE != ZINK_DYNAMIC_VERTEX_INPUT)
231             pc_entry->pipeline = zink_create_gfx_pipeline(screen, prog, prog->objs, state, state->element_state->binding_map, vkmode, !HAVE_LIB);
232          else
233             pc_entry->pipeline = zink_create_gfx_pipeline(screen, prog, prog->objs, state, NULL, vkmode, !HAVE_LIB);
234          if (HAVE_LIB && !prog->is_separable)
235             /* trigger async optimized pipeline compile if this was an unoptimized pipeline */
236             zink_gfx_program_compile_queue(ctx, pc_entry);
237       }
238       if (pc_entry->pipeline == VK_NULL_HANDLE)
239          return VK_NULL_HANDLE;
240 
241       zink_screen_update_pipeline_cache(screen, &prog->base, false);
242    }
243 
244    struct zink_gfx_pipeline_cache_entry *cache_entry = (struct zink_gfx_pipeline_cache_entry *)entry->data;
245    state->pipeline = cache_entry->pipeline;
246    /* update states for fastpath */
247    if (DYNAMIC_STATE >= ZINK_DYNAMIC_VERTEX_INPUT) {
248       prog->last_finalized_hash[rp_idx][idx] = state->final_hash;
249       prog->last_pipeline[rp_idx][idx] = cache_entry;
250    }
251    return state->pipeline;
252 }
253 
254 /* runtime-optimized pipeline state comparisons */
255 template <zink_pipeline_dynamic_state DYNAMIC_STATE, unsigned STAGE_MASK>
256 static bool
equals_gfx_pipeline_state(const void * a,const void * b)257 equals_gfx_pipeline_state(const void *a, const void *b)
258 {
259    const struct zink_gfx_pipeline_state *sa = (const struct zink_gfx_pipeline_state *)a;
260    const struct zink_gfx_pipeline_state *sb = (const struct zink_gfx_pipeline_state *)b;
261    if (DYNAMIC_STATE < ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT) {
262       if (sa->uses_dynamic_stride != sb->uses_dynamic_stride)
263          return false;
264    }
265    if (DYNAMIC_STATE == ZINK_PIPELINE_NO_DYNAMIC_STATE ||
266        (DYNAMIC_STATE < ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT && !sa->uses_dynamic_stride)) {
267       if (sa->vertex_buffers_enabled_mask != sb->vertex_buffers_enabled_mask)
268          return false;
269       /* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */
270       uint32_t mask_a = sa->vertex_buffers_enabled_mask;
271       uint32_t mask_b = sb->vertex_buffers_enabled_mask;
272       while (mask_a || mask_b) {
273          unsigned idx_a = u_bit_scan(&mask_a);
274          unsigned idx_b = u_bit_scan(&mask_b);
275          if (sa->vertex_strides[idx_a] != sb->vertex_strides[idx_b])
276             return false;
277       }
278    }
279 
280    /* each dynamic state extension has its own struct on the pipeline state to compare
281     * if all extensions are supported, none of them are accessed
282     */
283    if (DYNAMIC_STATE == ZINK_PIPELINE_NO_DYNAMIC_STATE) {
284       if (memcmp(&sa->dyn_state1, &sb->dyn_state1, offsetof(struct zink_pipeline_dynamic_state1, depth_stencil_alpha_state)))
285          return false;
286       if (!!sa->dyn_state1.depth_stencil_alpha_state != !!sb->dyn_state1.depth_stencil_alpha_state ||
287           (sa->dyn_state1.depth_stencil_alpha_state &&
288            memcmp(sa->dyn_state1.depth_stencil_alpha_state, sb->dyn_state1.depth_stencil_alpha_state,
289                   sizeof(struct zink_depth_stencil_alpha_hw_state))))
290          return false;
291    }
292    if (DYNAMIC_STATE < ZINK_PIPELINE_DYNAMIC_STATE3) {
293       if (DYNAMIC_STATE < ZINK_PIPELINE_DYNAMIC_STATE2) {
294          if (memcmp(&sa->dyn_state2, &sb->dyn_state2, sizeof(sa->dyn_state2)))
295             return false;
296       }
297       if (memcmp(&sa->dyn_state3, &sb->dyn_state3, sizeof(sa->dyn_state3)))
298          return false;
299    } else if (DYNAMIC_STATE != ZINK_PIPELINE_DYNAMIC_STATE2_PCP &&
300               DYNAMIC_STATE != ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT2_PCP &&
301               DYNAMIC_STATE != ZINK_PIPELINE_DYNAMIC_STATE3_PCP &&
302               DYNAMIC_STATE != ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT_PCP &&
303               (STAGE_MASK & BITFIELD_BIT(MESA_SHADER_TESS_EVAL)) &&
304               !(STAGE_MASK & BITFIELD_BIT(MESA_SHADER_TESS_CTRL))) {
305       if (sa->dyn_state2.vertices_per_patch != sb->dyn_state2.vertices_per_patch)
306          return false;
307    }
308    /* optimal keys are the fastest path: only a single uint32_t comparison for all shader module variants */
309    if (STAGE_MASK & STAGE_MASK_OPTIMAL) {
310       if (sa->optimal_key != sb->optimal_key)
311          return false;
312       if (STAGE_MASK & STAGE_MASK_OPTIMAL_SHADOW) {
313          if (sa->shadow != sb->shadow)
314             return false;
315       }
316    } else {
317       if (STAGE_MASK & BITFIELD_BIT(MESA_SHADER_TESS_CTRL)) {
318          if (sa->modules[MESA_SHADER_TESS_CTRL] != sb->modules[MESA_SHADER_TESS_CTRL])
319             return false;
320       }
321       if (STAGE_MASK & BITFIELD_BIT(MESA_SHADER_TESS_EVAL)) {
322          if (sa->modules[MESA_SHADER_TESS_EVAL] != sb->modules[MESA_SHADER_TESS_EVAL])
323             return false;
324       }
325       if (STAGE_MASK & BITFIELD_BIT(MESA_SHADER_GEOMETRY)) {
326          if (sa->modules[MESA_SHADER_GEOMETRY] != sb->modules[MESA_SHADER_GEOMETRY])
327             return false;
328       }
329       if (sa->modules[MESA_SHADER_VERTEX] != sb->modules[MESA_SHADER_VERTEX])
330          return false;
331       if (sa->modules[MESA_SHADER_FRAGMENT] != sb->modules[MESA_SHADER_FRAGMENT])
332          return false;
333    }
334    /* the base pipeline state is a 12 byte comparison */
335    return !memcmp(a, b, offsetof(struct zink_gfx_pipeline_state, hash));
336 }
337 
338 /* below is a bunch of code to pick the right equals_gfx_pipeline_state template for runtime */
339 template <zink_pipeline_dynamic_state DYNAMIC_STATE, unsigned STAGE_MASK>
340 static equals_gfx_pipeline_state_func
get_optimal_gfx_pipeline_stage_eq_func(bool optimal_keys,bool shadow_needs_shader_swizzle)341 get_optimal_gfx_pipeline_stage_eq_func(bool optimal_keys, bool shadow_needs_shader_swizzle)
342 {
343    if (optimal_keys) {
344       if (shadow_needs_shader_swizzle)
345          return equals_gfx_pipeline_state<DYNAMIC_STATE, STAGE_MASK | STAGE_MASK_OPTIMAL | STAGE_MASK_OPTIMAL_SHADOW>;
346       return equals_gfx_pipeline_state<DYNAMIC_STATE, STAGE_MASK | STAGE_MASK_OPTIMAL>;
347    }
348    return equals_gfx_pipeline_state<DYNAMIC_STATE, STAGE_MASK>;
349 }
350 
351 template <zink_pipeline_dynamic_state DYNAMIC_STATE>
352 static equals_gfx_pipeline_state_func
get_gfx_pipeline_stage_eq_func(struct zink_gfx_program * prog,bool optimal_keys)353 get_gfx_pipeline_stage_eq_func(struct zink_gfx_program *prog, bool optimal_keys)
354 {
355    bool shadow_needs_shader_swizzle = prog->shaders[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask > 0;
356    unsigned vertex_stages = prog->stages_present & BITFIELD_MASK(MESA_SHADER_FRAGMENT);
357    if (vertex_stages & BITFIELD_BIT(MESA_SHADER_TESS_CTRL)) {
358       if (prog->shaders[MESA_SHADER_TESS_CTRL]->non_fs.is_generated)
359          vertex_stages &= ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL);
360    }
361    if (vertex_stages & BITFIELD_BIT(MESA_SHADER_TESS_CTRL)) {
362       if (vertex_stages == BITFIELD_MASK(MESA_SHADER_FRAGMENT))
363          /* all stages */
364          return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
365                                                        BITFIELD_MASK(MESA_SHADER_COMPUTE)>(optimal_keys, shadow_needs_shader_swizzle);
366       if (vertex_stages == BITFIELD_MASK(MESA_SHADER_GEOMETRY))
367          /* tess only: includes generated tcs too */
368          return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
369                                                        BITFIELD_MASK(MESA_SHADER_COMPUTE) & ~BITFIELD_BIT(MESA_SHADER_GEOMETRY)>(optimal_keys, shadow_needs_shader_swizzle);
370       if (vertex_stages == (BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)))
371          /* geom only */
372          return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
373                                                        BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_FRAGMENT) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)>(optimal_keys, shadow_needs_shader_swizzle);
374    }
375    if (vertex_stages == (BITFIELD_MASK(MESA_SHADER_FRAGMENT) & ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL)))
376       /* all stages but tcs */
377       return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
378                                                     BITFIELD_MASK(MESA_SHADER_COMPUTE) & ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL)>(optimal_keys, shadow_needs_shader_swizzle);
379    if (vertex_stages == (BITFIELD_MASK(MESA_SHADER_GEOMETRY) & ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL)))
380       /* tess only: generated tcs */
381       return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
382                                                     BITFIELD_MASK(MESA_SHADER_COMPUTE) & ~(BITFIELD_BIT(MESA_SHADER_GEOMETRY) | BITFIELD_BIT(MESA_SHADER_TESS_CTRL))>(optimal_keys, shadow_needs_shader_swizzle);
383    if (vertex_stages == (BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)))
384       /* geom only */
385       return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
386                                                     BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_FRAGMENT) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)>(optimal_keys, shadow_needs_shader_swizzle);
387    return get_optimal_gfx_pipeline_stage_eq_func<DYNAMIC_STATE,
388                                                  BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_FRAGMENT)>(optimal_keys, shadow_needs_shader_swizzle);
389 }
390 
391 equals_gfx_pipeline_state_func
zink_get_gfx_pipeline_eq_func(struct zink_screen * screen,struct zink_gfx_program * prog)392 zink_get_gfx_pipeline_eq_func(struct zink_screen *screen, struct zink_gfx_program *prog)
393 {
394    if (screen->info.have_EXT_extended_dynamic_state) {
395       if (screen->info.have_EXT_extended_dynamic_state2) {
396          if (screen->info.have_EXT_extended_dynamic_state3) {
397             if (screen->info.have_EXT_vertex_input_dynamic_state) {
398                if (screen->info.dynamic_state2_feats.extendedDynamicState2PatchControlPoints)
399                   return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT_PCP>(prog, screen->optimal_keys);
400                else
401                   return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT>(prog, screen->optimal_keys);
402             } else {
403                if (screen->info.dynamic_state2_feats.extendedDynamicState2PatchControlPoints)
404                   return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE3_PCP>(prog, screen->optimal_keys);
405                else
406                   return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE3>(prog, screen->optimal_keys);
407             }
408          }
409          if (screen->info.have_EXT_vertex_input_dynamic_state) {
410             if (screen->info.dynamic_state2_feats.extendedDynamicState2PatchControlPoints)
411                return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT2_PCP>(prog, screen->optimal_keys);
412             else
413                return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_VERTEX_INPUT2>(prog, screen->optimal_keys);
414          } else {
415             if (screen->info.dynamic_state2_feats.extendedDynamicState2PatchControlPoints)
416                return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE2_PCP>(prog, screen->optimal_keys);
417             else
418                return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE2>(prog, screen->optimal_keys);
419          }
420       }
421       return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_DYNAMIC_STATE>(prog, screen->optimal_keys);
422    }
423    return get_gfx_pipeline_stage_eq_func<ZINK_PIPELINE_NO_DYNAMIC_STATE>(prog, screen->optimal_keys);
424 }
425