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