• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2015 Red Hat
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  *    Rob Clark <robclark@freedesktop.org>
25  */
26 
27 #include "nir.h"
28 #include "nir_builder.h"
29 
30 #define MAX_CLIP_PLANES 8
31 
32 /* Generates the lowering code for user-clip-planes, generating CLIPDIST
33  * from UCP[n] + CLIPVERTEX or POSITION.  Additionally, an optional pass
34  * for fragment shaders to insert conditional kills based on the inter-
35  * polated CLIPDIST
36  *
37  * NOTE: should be run after nir_lower_outputs_to_temporaries() (or at
38  * least in scenarios where you can count on each output written once
39  * and only once).
40  */
41 
42 static nir_variable *
create_clipdist_var(nir_shader * shader,bool output,gl_varying_slot slot,unsigned array_size)43 create_clipdist_var(nir_shader *shader,
44                     bool output, gl_varying_slot slot, unsigned array_size)
45 {
46    nir_variable *var = rzalloc(shader, nir_variable);
47 
48    if (output) {
49       var->data.driver_location = shader->num_outputs;
50       var->data.mode = nir_var_shader_out;
51       shader->num_outputs += MAX2(1, DIV_ROUND_UP(array_size, 4));
52    } else {
53       var->data.driver_location = shader->num_inputs;
54       var->data.mode = nir_var_shader_in;
55       shader->num_inputs += MAX2(1, DIV_ROUND_UP(array_size, 4));
56    }
57    var->name = ralloc_asprintf(var, "clipdist_%d", slot - VARYING_SLOT_CLIP_DIST0);
58    var->data.index = 0;
59    var->data.location = slot;
60 
61    if (array_size > 0) {
62       var->type = glsl_array_type(glsl_float_type(), array_size,
63                                   sizeof(float));
64       var->data.compact = 1;
65    } else
66       var->type = glsl_vec4_type();
67 
68    nir_shader_add_variable(shader, var);
69    return var;
70 }
71 
72 static void
create_clipdist_vars(nir_shader * shader,nir_variable ** io_vars,unsigned ucp_enables,bool output,bool use_clipdist_array)73 create_clipdist_vars(nir_shader *shader, nir_variable **io_vars,
74                      unsigned ucp_enables, bool output,
75                      bool use_clipdist_array)
76 {
77    if (use_clipdist_array) {
78       io_vars[0] =
79          create_clipdist_var(shader, output,
80                              VARYING_SLOT_CLIP_DIST0,
81                              shader->info.clip_distance_array_size);
82    } else {
83       if (ucp_enables & 0x0f)
84          io_vars[0] =
85             create_clipdist_var(shader, output,
86                                 VARYING_SLOT_CLIP_DIST0, 0);
87       if (ucp_enables & 0xf0)
88          io_vars[1] =
89             create_clipdist_var(shader, output,
90                                 VARYING_SLOT_CLIP_DIST1, 0);
91    }
92 }
93 
94 static void
store_clipdist_output(nir_builder * b,nir_variable * out,int location,int location_offset,nir_def ** val,bool use_clipdist_array)95 store_clipdist_output(nir_builder *b, nir_variable *out, int location, int location_offset,
96                       nir_def **val, bool use_clipdist_array)
97 {
98    unsigned num_slots = b->shader->info.clip_distance_array_size;
99    nir_io_semantics semantics = {
100       .location = location,
101       .num_slots = b->shader->options->compact_arrays ? num_slots : 1,
102    };
103 
104    if (location == VARYING_SLOT_CLIP_DIST1 || location_offset)
105       num_slots -= 4;
106    else
107       num_slots = MIN2(num_slots, 4);
108    for (unsigned i = 0; i < num_slots; i++) {
109       nir_store_output(b,
110                        val[i] ? val[i] : nir_imm_zero(b, 1, 32),
111                        nir_imm_int(b, location_offset),
112                        .write_mask = 0x1,
113                        .component = i,
114                        .io_semantics = semantics,
115                        .base = out ? out->data.driver_location : 0);
116    }
117 }
118 
119 static void
load_clipdist_input(nir_builder * b,nir_variable * in,int location_offset,nir_def ** val,bool use_load_interp)120 load_clipdist_input(nir_builder *b, nir_variable *in, int location_offset,
121                     nir_def **val, bool use_load_interp)
122 {
123    nir_def *load;
124    if (use_load_interp) {
125       /* TODO: use sample when per-sample shading? */
126       nir_def *barycentric = nir_load_barycentric(
127          b, nir_intrinsic_load_barycentric_pixel, INTERP_MODE_NONE);
128       load = nir_load_interpolated_input(
129          b, 4, 32, barycentric, nir_imm_int(b, location_offset),
130          .base = in->data.driver_location,
131          .io_semantics.location = in->data.location);
132 
133    } else {
134       load = nir_load_input(b, 4, 32, nir_imm_int(b, location_offset),
135                             .base = in->data.driver_location,
136                             .io_semantics.location = in->data.location);
137    }
138 
139    val[0] = nir_channel(b, load, 0);
140    val[1] = nir_channel(b, load, 1);
141    val[2] = nir_channel(b, load, 2);
142    val[3] = nir_channel(b, load, 3);
143 }
144 
145 static nir_def *
find_output(nir_builder * b,unsigned location)146 find_output(nir_builder *b, unsigned location)
147 {
148    nir_def *comp[4] = {NULL};
149 
150    nir_foreach_function_impl(impl, b->shader) {
151       nir_foreach_block(block, impl) {
152          nir_foreach_instr_safe(instr, block) {
153             if (instr->type != nir_instr_type_intrinsic)
154                continue;
155 
156             nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
157 
158             if ((intr->intrinsic == nir_intrinsic_store_output ||
159                  intr->intrinsic == nir_intrinsic_store_per_vertex_output ||
160                  intr->intrinsic == nir_intrinsic_store_per_view_output ||
161                  intr->intrinsic == nir_intrinsic_store_per_primitive_output) &&
162                 nir_intrinsic_io_semantics(intr).location == location) {
163                assert(nir_src_is_const(*nir_get_io_offset_src(intr)));
164                unsigned component = nir_intrinsic_component(intr);
165                unsigned wrmask = nir_intrinsic_write_mask(intr);
166 
167                u_foreach_bit(i, wrmask) {
168                   unsigned index = component + i;
169 
170                   /* Each component should be written only once. */
171                   assert(!comp[index]);
172                   comp[index] = nir_channel(b, intr->src[0].ssa, i);
173                }
174 
175                /* Remove it because it's going to be replaced by CLIP_DIST. */
176                if (location == VARYING_SLOT_CLIP_VERTEX)
177                   nir_instr_remove(instr);
178             }
179          }
180       }
181    }
182    assert(comp[0] || comp[1] || comp[2] || comp[3]);
183 
184    for (unsigned i = 0; i < 4; i++) {
185       if (!comp[i])
186          comp[i] = nir_undef(b, 1, 32);
187    }
188 
189    return nir_vec(b, comp, 4);
190 }
191 
192 static bool
find_clipvertex_and_position_outputs(nir_shader * shader,nir_variable ** clipvertex,nir_variable ** position)193 find_clipvertex_and_position_outputs(nir_shader *shader,
194                                      nir_variable **clipvertex,
195                                      nir_variable **position)
196 {
197    if (shader->info.io_lowered) {
198       if (shader->info.outputs_written & (VARYING_BIT_CLIP_DIST0 | VARYING_BIT_CLIP_DIST1))
199          return false;
200       if (shader->info.outputs_written & (VARYING_BIT_POS | VARYING_BIT_CLIP_VERTEX))
201          return true;
202       return false;
203    }
204    nir_foreach_shader_out_variable(var, shader) {
205       switch (var->data.location) {
206       case VARYING_SLOT_POS:
207          *position = var;
208          break;
209       case VARYING_SLOT_CLIP_VERTEX:
210          *clipvertex = var;
211          break;
212       case VARYING_SLOT_CLIP_DIST0:
213       case VARYING_SLOT_CLIP_DIST1:
214          /* if shader is already writing CLIPDIST, then
215           * there should be no user-clip-planes to deal
216           * with.
217           *
218           * We assume nir_remove_dead_variables has removed the clipdist
219           * variables if they're not written.
220           */
221          return false;
222       }
223    }
224 
225    return *clipvertex || *position;
226 }
227 
228 static nir_def *
get_ucp(nir_builder * b,int plane,const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH])229 get_ucp(nir_builder *b, int plane,
230         const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH])
231 {
232    if (clipplane_state_tokens) {
233       char tmp[100];
234       snprintf(tmp, ARRAY_SIZE(tmp), "gl_ClipPlane%dMESA", plane);
235       nir_variable *var = nir_state_variable_create(b->shader,
236                                                     glsl_vec4_type(),
237                                                     tmp, clipplane_state_tokens[plane]);
238       return nir_load_var(b, var);
239    } else
240       return nir_load_user_clip_plane(b, plane);
241 }
242 
243 static uint64_t
update_mask(uint32_t ucp_enables)244 update_mask(uint32_t ucp_enables)
245 {
246    uint64_t mask = 0;
247 
248    if (ucp_enables & 0x0f)
249       mask |= VARYING_BIT_CLIP_DIST0;
250    if (ucp_enables & 0xf0)
251       mask |= VARYING_BIT_CLIP_DIST1;
252 
253    return mask;
254 }
255 
256 struct lower_clip_state {
257    nir_variable *position;
258    nir_variable *clipvertex;
259    nir_variable *out[2];
260    unsigned ucp_enables;
261    bool use_clipdist_array;
262    const gl_state_index16 (*clipplane_state_tokens)[STATE_LENGTH];
263 
264    /* This holds the current CLIP_VERTEX value for GS. */
265    nir_variable *clipvertex_gs_temp;
266 };
267 
268 static void
lower_clip_vertex_var(nir_builder * b,const struct lower_clip_state * state)269 lower_clip_vertex_var(nir_builder *b, const struct lower_clip_state *state)
270 {
271    nir_def *clipdist[MAX_CLIP_PLANES] = {NULL};
272    nir_def *cv = nir_load_var(b, state->clipvertex ? state->clipvertex
273                                                    : state->position);
274 
275    if (state->clipvertex) {
276       state->clipvertex->data.mode = nir_var_shader_temp;
277       nir_fixup_deref_modes(b->shader);
278    }
279 
280    for (int plane = 0; plane < MAX_CLIP_PLANES; plane++) {
281       if (state->ucp_enables & (1 << plane)) {
282          nir_def *ucp = get_ucp(b, plane, state->clipplane_state_tokens);
283 
284          /* calculate clipdist[plane] - dot(ucp, cv): */
285          clipdist[plane] = nir_fdot(b, ucp, cv);
286       } else {
287          /* 0.0 == don't-clip == disabled: */
288          clipdist[plane] = nir_imm_float(b, 0.0);
289       }
290       if (state->use_clipdist_array &&
291           plane < util_last_bit(state->ucp_enables)) {
292          nir_deref_instr *deref;
293          deref = nir_build_deref_array_imm(b,
294                                            nir_build_deref_var(b, state->out[0]),
295                                            plane);
296          nir_store_deref(b, deref, clipdist[plane], 1);
297       }
298    }
299 
300    if (!state->use_clipdist_array) {
301       if (state->ucp_enables & 0x0f)
302          nir_store_var(b, state->out[0], nir_vec(b, clipdist, 4), 0xf);
303       if (state->ucp_enables & 0xf0)
304          nir_store_var(b, state->out[1], nir_vec(b, &clipdist[4], 4), 0xf);
305       b->shader->info.outputs_written |= update_mask(state->ucp_enables);
306    }
307 }
308 
309 static void
lower_clip_vertex_intrin(nir_builder * b,const struct lower_clip_state * state)310 lower_clip_vertex_intrin(nir_builder *b, const struct lower_clip_state *state)
311 {
312    nir_def *clipdist[MAX_CLIP_PLANES] = {NULL};
313    nir_def *cv;
314 
315    if (state->clipvertex_gs_temp) {
316       cv = nir_load_deref(b, nir_build_deref_var(b, state->clipvertex_gs_temp));
317    } else {
318       cv = find_output(b, b->shader->info.outputs_written &
319                        VARYING_BIT_CLIP_VERTEX ?
320                           VARYING_SLOT_CLIP_VERTEX : VARYING_SLOT_POS);
321    }
322 
323    for (int plane = 0; plane < MAX_CLIP_PLANES; plane++) {
324       if (state->ucp_enables & (1 << plane)) {
325          nir_def *ucp = get_ucp(b, plane, state->clipplane_state_tokens);
326 
327          /* calculate clipdist[plane] - dot(ucp, cv): */
328          clipdist[plane] = nir_fdot(b, ucp, cv);
329       } else {
330          /* 0.0 == don't-clip == disabled: */
331          clipdist[plane] = nir_imm_float(b, 0.0);
332       }
333    }
334 
335    if (state->use_clipdist_array) {
336       /* Always emit the first vec4. */
337       store_clipdist_output(b, state->out[0], VARYING_SLOT_CLIP_DIST0, 0,
338                             &clipdist[0], state->use_clipdist_array);
339       if (state->ucp_enables & 0xf0) {
340          store_clipdist_output(b, state->out[0], VARYING_SLOT_CLIP_DIST0, 1,
341                                &clipdist[4], state->use_clipdist_array);
342       }
343    } else {
344       /* Always emit the first vec4. */
345       store_clipdist_output(b, state->out[0], VARYING_SLOT_CLIP_DIST0, 0,
346                             &clipdist[0], state->use_clipdist_array);
347       if (state->ucp_enables & 0xf0) {
348          store_clipdist_output(b, state->out[1], VARYING_SLOT_CLIP_DIST1, 0,
349                                &clipdist[4], state->use_clipdist_array);
350       }
351    }
352    b->shader->info.outputs_written |= update_mask(state->ucp_enables);
353 }
354 
355 /*
356  * VS lowering
357  */
358 
359 /* ucp_enables is bitmask of enabled ucps.  Actual ucp values are
360  * passed in to shader via user_clip_plane system-values
361  *
362  * If use_vars is true, the pass will use variable loads and stores instead
363  * of working with store_output intrinsics.
364  *
365  * If use_clipdist_array is true, the pass will use compact arrays for the
366  * clipdist output instead of two vec4s.
367  */
368 bool
nir_lower_clip_vs(nir_shader * shader,unsigned ucp_enables,bool use_vars,bool use_clipdist_array,const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH])369 nir_lower_clip_vs(nir_shader *shader, unsigned ucp_enables, bool use_vars,
370                   bool use_clipdist_array,
371                   const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH])
372 {
373    if (!ucp_enables)
374       return false;
375 
376    nir_function_impl *impl = nir_shader_get_entrypoint(shader);
377    nir_builder b = nir_builder_create(impl);
378 
379    /* NIR should ensure that, even in case of loops/if-else, there
380     * should be only a single predecessor block to end_block, which
381     * makes the perfect place to insert the clipdist calculations.
382     *
383     * NOTE: in case of early returns, these would have to be lowered
384     * to jumps to end_block predecessor in a previous pass.  Not sure
385     * if there is a good way to sanity check this, but for now the
386     * users of this pass don't support sub-routines.
387     */
388    assert(impl->end_block->predecessors->entries == 1);
389    b.cursor = nir_after_impl(impl);
390 
391    struct lower_clip_state state = {NULL};
392    state.ucp_enables = ucp_enables;
393    state.use_clipdist_array = use_clipdist_array;
394    state.clipplane_state_tokens = clipplane_state_tokens;
395 
396    /* find clipvertex/position outputs */
397    if (!find_clipvertex_and_position_outputs(shader, &state.clipvertex,
398                                              &state.position))
399       return false;
400 
401    shader->info.clip_distance_array_size = util_last_bit(ucp_enables);
402 
403    if (!use_vars || shader->info.io_lowered) {
404       /* If the driver has lowered IO instead of st/mesa, the driver expects
405        * that variables are present even with lowered IO, so create them.
406        */
407       if (!shader->info.io_lowered) {
408          create_clipdist_vars(shader, state.out, ucp_enables, true,
409                               use_clipdist_array);
410       }
411 
412       lower_clip_vertex_intrin(&b, &state);
413    } else {
414       create_clipdist_vars(shader, state.out, ucp_enables, true,
415                            use_clipdist_array);
416       lower_clip_vertex_var(&b, &state);
417    }
418 
419    nir_metadata_preserve(impl, nir_metadata_dominance);
420 
421    return true;
422 }
423 
424 /*
425  * GS lowering
426  */
427 
428 static bool
lower_clip_vertex_gs(nir_builder * b,nir_intrinsic_instr * intr,void * opaque)429 lower_clip_vertex_gs(nir_builder *b, nir_intrinsic_instr *intr, void *opaque)
430 {
431    const struct lower_clip_state *state =
432       (const struct lower_clip_state *)opaque;
433 
434    switch (intr->intrinsic) {
435    case nir_intrinsic_emit_vertex_with_counter:
436    case nir_intrinsic_emit_vertex:
437       b->cursor = nir_before_instr(&intr->instr);
438       if (b->shader->info.io_lowered)
439          lower_clip_vertex_intrin(b, state);
440       else
441          lower_clip_vertex_var(b, state);
442       return true;
443    default:
444       return false;
445    }
446 }
447 
448 /* Track the CLIP_VERTEX or POS value in a local variable, so that we can
449  * retrieve it at emit_vertex.
450  */
451 static bool
save_clipvertex_to_temp_gs(nir_builder * b,nir_intrinsic_instr * intr,void * opaque)452 save_clipvertex_to_temp_gs(nir_builder *b, nir_intrinsic_instr *intr,
453                            void *opaque)
454 {
455    const struct lower_clip_state *state =
456       (const struct lower_clip_state *)opaque;
457    gl_varying_slot clip_output_slot =
458       b->shader->info.outputs_written & VARYING_BIT_CLIP_VERTEX ?
459             VARYING_SLOT_CLIP_VERTEX : VARYING_SLOT_POS;
460 
461    if (intr->intrinsic != nir_intrinsic_store_output ||
462        nir_intrinsic_io_semantics(intr).location != clip_output_slot)
463       return false;
464 
465    b->cursor = nir_before_instr(&intr->instr);
466 
467    unsigned component = nir_intrinsic_component(intr);
468    unsigned writemask = nir_intrinsic_write_mask(intr);
469    nir_def *value = intr->src[0].ssa;
470 
471    /* Shift vector elements to the right by component. */
472    if (component) {
473       unsigned swizzle[4] = {0};
474 
475       for (unsigned i = 1; i < value->num_components; i++)
476          swizzle[component + i] = i;
477       value = nir_swizzle(b, value, swizzle,
478                           component + value->num_components);
479    }
480 
481    nir_store_deref(b, nir_build_deref_var(b, state->clipvertex_gs_temp),
482                    nir_pad_vec4(b, value), writemask << component);
483 
484    /* Remove the CLIP_VERTEX store because it will be replaced by CLIP_DIST
485     * stores.
486     */
487    if (clip_output_slot == VARYING_SLOT_CLIP_VERTEX)
488       nir_instr_remove(&intr->instr);
489    return true;
490 }
491 
492 bool
nir_lower_clip_gs(nir_shader * shader,unsigned ucp_enables,bool use_clipdist_array,const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH])493 nir_lower_clip_gs(nir_shader *shader, unsigned ucp_enables,
494                   bool use_clipdist_array,
495                   const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH])
496 {
497    if (!ucp_enables)
498       return false;
499 
500    struct lower_clip_state state = {NULL};
501    state.ucp_enables = ucp_enables;
502    state.use_clipdist_array = use_clipdist_array;
503    state.clipplane_state_tokens = clipplane_state_tokens;
504 
505    /* find clipvertex/position outputs */
506    if (!find_clipvertex_and_position_outputs(shader, &state.clipvertex,
507                                              &state.position))
508       return false;
509 
510    shader->info.clip_distance_array_size = util_last_bit(ucp_enables);
511 
512    if (shader->info.io_lowered) {
513       /* Track the current value of CLIP_VERTEX or POS in a local variable. */
514       state.clipvertex_gs_temp =
515          nir_local_variable_create(nir_shader_get_entrypoint(shader),
516                                    glsl_vec4_type(), "clipvertex_gs_temp");
517       if (!nir_shader_intrinsics_pass(shader, save_clipvertex_to_temp_gs,
518                                       nir_metadata_control_flow, &state))
519          return false;
520    } else {
521       /* insert CLIPDIST outputs */
522       create_clipdist_vars(shader, state.out, ucp_enables, true,
523                            use_clipdist_array);
524    }
525 
526    nir_shader_intrinsics_pass(shader, lower_clip_vertex_gs,
527                               nir_metadata_control_flow, &state);
528    return true;
529 }
530 
531 /*
532  * FS lowering
533  */
534 
535 static void
lower_clip_fs(nir_function_impl * impl,unsigned ucp_enables,nir_variable ** in,bool use_clipdist_array,bool use_load_interp)536 lower_clip_fs(nir_function_impl *impl, unsigned ucp_enables,
537               nir_variable **in, bool use_clipdist_array, bool use_load_interp)
538 {
539    nir_def *clipdist[MAX_CLIP_PLANES];
540    nir_builder b = nir_builder_at(nir_before_impl(impl));
541 
542    if (!use_clipdist_array) {
543       if (ucp_enables & 0x0f)
544          load_clipdist_input(&b, in[0], 0, &clipdist[0], use_load_interp);
545       if (ucp_enables & 0xf0)
546          load_clipdist_input(&b, in[1], 0, &clipdist[4], use_load_interp);
547    } else {
548       if (ucp_enables & 0x0f)
549          load_clipdist_input(&b, in[0], 0, &clipdist[0], use_load_interp);
550       if (ucp_enables & 0xf0)
551          load_clipdist_input(&b, in[0], 1, &clipdist[4], use_load_interp);
552    }
553    b.shader->info.inputs_read |= update_mask(ucp_enables);
554 
555    nir_def *cond = NULL;
556 
557    for (int plane = 0; plane < MAX_CLIP_PLANES; plane++) {
558       if (ucp_enables & (1 << plane)) {
559          nir_def *this_cond =
560             nir_flt_imm(&b, clipdist[plane], 0.0);
561 
562          cond = cond ? nir_ior(&b, cond, this_cond) : this_cond;
563       }
564    }
565 
566    if (cond != NULL) {
567       nir_discard_if(&b, cond);
568       b.shader->info.fs.uses_discard = true;
569    }
570 
571    nir_metadata_preserve(impl, nir_metadata_dominance);
572 }
573 
574 static bool
fs_has_clip_dist_input_var(nir_shader * shader,nir_variable ** io_vars,unsigned * ucp_enables)575 fs_has_clip_dist_input_var(nir_shader *shader, nir_variable **io_vars,
576                            unsigned *ucp_enables)
577 {
578    assert(shader->info.stage == MESA_SHADER_FRAGMENT);
579    nir_foreach_shader_in_variable(var, shader) {
580       switch (var->data.location) {
581       case VARYING_SLOT_CLIP_DIST0:
582          assert(var->data.compact);
583          io_vars[0] = var;
584          *ucp_enables &= (1 << glsl_get_length(var->type)) - 1;
585          return true;
586       default:
587          break;
588       }
589    }
590    return false;
591 }
592 
593 /* insert conditional kill based on interpolated CLIPDIST
594  */
595 bool
nir_lower_clip_fs(nir_shader * shader,unsigned ucp_enables,bool use_clipdist_array,bool use_load_interp)596 nir_lower_clip_fs(nir_shader *shader, unsigned ucp_enables,
597                   bool use_clipdist_array, bool use_load_interp)
598 {
599    nir_variable *in[2] = { 0 };
600 
601    if (!ucp_enables)
602       return false;
603 
604    /* this is probably broken until https://gitlab.freedesktop.org/mesa/mesa/-/issues/10826 is fixed */
605    assert(!shader->info.io_lowered);
606    shader->info.clip_distance_array_size = util_last_bit(ucp_enables);
607 
608    /* No hard reason to require use_clipdist_arr to work with
609     * frag-shader-based gl_ClipDistance, except that the only user that does
610     * not enable this does not support GL 3.0 (or EXT_clip_cull_distance).
611     */
612    if (!fs_has_clip_dist_input_var(shader, in, &ucp_enables))
613       create_clipdist_vars(shader, in, ucp_enables, false, use_clipdist_array);
614    else
615       assert(use_clipdist_array);
616 
617    nir_foreach_function_with_impl(function, impl, shader) {
618       if (!strcmp(function->name, "main")) {
619          lower_clip_fs(impl, ucp_enables, in, use_clipdist_array,
620                        use_load_interp);
621       }
622    }
623 
624    return true;
625 }
626