1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2015 Red Hat 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Rob Clark <robclark@freedesktop.org> 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "nir.h" 28bf215546Sopenharmony_ci#include "nir_builder.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#define MAX_CLIP_PLANES 8 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci/* Generates the lowering code for user-clip-planes, generating CLIPDIST 33bf215546Sopenharmony_ci * from UCP[n] + CLIPVERTEX or POSITION. Additionally, an optional pass 34bf215546Sopenharmony_ci * for fragment shaders to insert conditional kills based on the inter- 35bf215546Sopenharmony_ci * polated CLIPDIST 36bf215546Sopenharmony_ci * 37bf215546Sopenharmony_ci * NOTE: should be run after nir_lower_outputs_to_temporaries() (or at 38bf215546Sopenharmony_ci * least in scenarios where you can count on each output written once 39bf215546Sopenharmony_ci * and only once). 40bf215546Sopenharmony_ci */ 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_cistatic nir_variable * 44bf215546Sopenharmony_cicreate_clipdist_var(nir_shader *shader, 45bf215546Sopenharmony_ci bool output, gl_varying_slot slot, unsigned array_size) 46bf215546Sopenharmony_ci{ 47bf215546Sopenharmony_ci nir_variable *var = rzalloc(shader, nir_variable); 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci if (output) { 50bf215546Sopenharmony_ci var->data.driver_location = shader->num_outputs; 51bf215546Sopenharmony_ci var->data.mode = nir_var_shader_out; 52bf215546Sopenharmony_ci shader->num_outputs += MAX2(1, DIV_ROUND_UP(array_size, 4)); 53bf215546Sopenharmony_ci } else { 54bf215546Sopenharmony_ci var->data.driver_location = shader->num_inputs; 55bf215546Sopenharmony_ci var->data.mode = nir_var_shader_in; 56bf215546Sopenharmony_ci shader->num_inputs += MAX2(1, DIV_ROUND_UP(array_size, 4)); 57bf215546Sopenharmony_ci } 58bf215546Sopenharmony_ci var->name = ralloc_asprintf(var, "clipdist_%d", var->data.driver_location); 59bf215546Sopenharmony_ci var->data.index = 0; 60bf215546Sopenharmony_ci var->data.location = slot; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci if (array_size > 0) { 63bf215546Sopenharmony_ci var->type = glsl_array_type(glsl_float_type(), array_size, 64bf215546Sopenharmony_ci sizeof(float)); 65bf215546Sopenharmony_ci var->data.compact = 1; 66bf215546Sopenharmony_ci } else 67bf215546Sopenharmony_ci var->type = glsl_vec4_type(); 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci nir_shader_add_variable(shader, var); 70bf215546Sopenharmony_ci return var; 71bf215546Sopenharmony_ci} 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_cistatic void 74bf215546Sopenharmony_cicreate_clipdist_vars(nir_shader *shader, nir_variable **io_vars, 75bf215546Sopenharmony_ci unsigned ucp_enables, bool output, 76bf215546Sopenharmony_ci bool use_clipdist_array) 77bf215546Sopenharmony_ci{ 78bf215546Sopenharmony_ci shader->info.clip_distance_array_size = util_last_bit(ucp_enables); 79bf215546Sopenharmony_ci if (use_clipdist_array) { 80bf215546Sopenharmony_ci io_vars[0] = 81bf215546Sopenharmony_ci create_clipdist_var(shader, output, 82bf215546Sopenharmony_ci VARYING_SLOT_CLIP_DIST0, 83bf215546Sopenharmony_ci shader->info.clip_distance_array_size); 84bf215546Sopenharmony_ci } else { 85bf215546Sopenharmony_ci if (ucp_enables & 0x0f) 86bf215546Sopenharmony_ci io_vars[0] = 87bf215546Sopenharmony_ci create_clipdist_var(shader, output, 88bf215546Sopenharmony_ci VARYING_SLOT_CLIP_DIST0, 0); 89bf215546Sopenharmony_ci if (ucp_enables & 0xf0) 90bf215546Sopenharmony_ci io_vars[1] = 91bf215546Sopenharmony_ci create_clipdist_var(shader, output, 92bf215546Sopenharmony_ci VARYING_SLOT_CLIP_DIST1, 0); 93bf215546Sopenharmony_ci } 94bf215546Sopenharmony_ci} 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_cistatic void 97bf215546Sopenharmony_cistore_clipdist_output(nir_builder *b, nir_variable *out, int location_offset, 98bf215546Sopenharmony_ci nir_ssa_def **val) 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci nir_io_semantics semantics = { 101bf215546Sopenharmony_ci .location = out->data.location, 102bf215546Sopenharmony_ci .num_slots = 1, 103bf215546Sopenharmony_ci }; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci nir_store_output(b, nir_vec4(b, val[0], val[1], val[2], val[3]), nir_imm_int(b, location_offset), 106bf215546Sopenharmony_ci .base = out->data.driver_location, 107bf215546Sopenharmony_ci .src_type = nir_type_float32, 108bf215546Sopenharmony_ci .write_mask = 0xf, 109bf215546Sopenharmony_ci .io_semantics = semantics); 110bf215546Sopenharmony_ci} 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_cistatic void 113bf215546Sopenharmony_ciload_clipdist_input(nir_builder *b, nir_variable *in, int location_offset, 114bf215546Sopenharmony_ci nir_ssa_def **val) 115bf215546Sopenharmony_ci{ 116bf215546Sopenharmony_ci nir_io_semantics semantics = { 117bf215546Sopenharmony_ci .location = in->data.location, 118bf215546Sopenharmony_ci .num_slots = 1, 119bf215546Sopenharmony_ci }; 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci nir_ssa_def *load; 122bf215546Sopenharmony_ci if (b->shader->options->use_interpolated_input_intrinsics) { 123bf215546Sopenharmony_ci /* TODO: use sample when per-sample shading? */ 124bf215546Sopenharmony_ci nir_ssa_def *barycentric = nir_load_barycentric( 125bf215546Sopenharmony_ci b, nir_intrinsic_load_barycentric_pixel, INTERP_MODE_NONE); 126bf215546Sopenharmony_ci load = nir_load_interpolated_input( 127bf215546Sopenharmony_ci b, 4, 32, barycentric, nir_imm_int(b, location_offset), 128bf215546Sopenharmony_ci .base = in->data.driver_location, 129bf215546Sopenharmony_ci .dest_type = nir_type_float32, 130bf215546Sopenharmony_ci .io_semantics = semantics); 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci } else { 133bf215546Sopenharmony_ci load = nir_load_input(b, 4, 32, nir_imm_int(b, location_offset), 134bf215546Sopenharmony_ci .base = in->data.driver_location, 135bf215546Sopenharmony_ci .dest_type = nir_type_float32, 136bf215546Sopenharmony_ci .io_semantics = semantics); 137bf215546Sopenharmony_ci } 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci val[0] = nir_channel(b, load, 0); 140bf215546Sopenharmony_ci val[1] = nir_channel(b, load, 1); 141bf215546Sopenharmony_ci val[2] = nir_channel(b, load, 2); 142bf215546Sopenharmony_ci val[3] = nir_channel(b, load, 3); 143bf215546Sopenharmony_ci} 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_cistatic nir_ssa_def * 146bf215546Sopenharmony_cifind_output_in_block(nir_block *block, unsigned drvloc) 147bf215546Sopenharmony_ci{ 148bf215546Sopenharmony_ci nir_foreach_instr(instr, block) { 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci if (instr->type == nir_instr_type_intrinsic) { 151bf215546Sopenharmony_ci nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); 152bf215546Sopenharmony_ci if ((intr->intrinsic == nir_intrinsic_store_output) && 153bf215546Sopenharmony_ci nir_intrinsic_base(intr) == drvloc) { 154bf215546Sopenharmony_ci assert(intr->src[0].is_ssa); 155bf215546Sopenharmony_ci assert(nir_src_is_const(intr->src[1])); 156bf215546Sopenharmony_ci return intr->src[0].ssa; 157bf215546Sopenharmony_ci } 158bf215546Sopenharmony_ci } 159bf215546Sopenharmony_ci } 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci return NULL; 162bf215546Sopenharmony_ci} 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci/* TODO: maybe this would be a useful helper? 165bf215546Sopenharmony_ci * NOTE: assumes each output is written exactly once (and unconditionally) 166bf215546Sopenharmony_ci * so if needed nir_lower_outputs_to_temporaries() 167bf215546Sopenharmony_ci */ 168bf215546Sopenharmony_cistatic nir_ssa_def * 169bf215546Sopenharmony_cifind_output(nir_shader *shader, unsigned drvloc) 170bf215546Sopenharmony_ci{ 171bf215546Sopenharmony_ci nir_ssa_def *def = NULL; 172bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 173bf215546Sopenharmony_ci if (function->impl) { 174bf215546Sopenharmony_ci nir_foreach_block_reverse(block, function->impl) { 175bf215546Sopenharmony_ci nir_ssa_def *new_def = find_output_in_block(block, drvloc); 176bf215546Sopenharmony_ci assert(!(new_def && def)); 177bf215546Sopenharmony_ci def = new_def; 178bf215546Sopenharmony_ci#if !defined(DEBUG) 179bf215546Sopenharmony_ci /* for debug builds, scan entire shader to assert 180bf215546Sopenharmony_ci * if output is written multiple times. For release 181bf215546Sopenharmony_ci * builds just assume all is well and bail when we 182bf215546Sopenharmony_ci * find first: 183bf215546Sopenharmony_ci */ 184bf215546Sopenharmony_ci if (def) 185bf215546Sopenharmony_ci break; 186bf215546Sopenharmony_ci#endif 187bf215546Sopenharmony_ci } 188bf215546Sopenharmony_ci } 189bf215546Sopenharmony_ci } 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci return def; 192bf215546Sopenharmony_ci} 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_cistatic bool 195bf215546Sopenharmony_cifind_clipvertex_and_position_outputs(nir_shader *shader, 196bf215546Sopenharmony_ci nir_variable **clipvertex, 197bf215546Sopenharmony_ci nir_variable **position) 198bf215546Sopenharmony_ci{ 199bf215546Sopenharmony_ci nir_foreach_shader_out_variable(var, shader) { 200bf215546Sopenharmony_ci switch (var->data.location) { 201bf215546Sopenharmony_ci case VARYING_SLOT_POS: 202bf215546Sopenharmony_ci *position = var; 203bf215546Sopenharmony_ci break; 204bf215546Sopenharmony_ci case VARYING_SLOT_CLIP_VERTEX: 205bf215546Sopenharmony_ci *clipvertex = var; 206bf215546Sopenharmony_ci break; 207bf215546Sopenharmony_ci case VARYING_SLOT_CLIP_DIST0: 208bf215546Sopenharmony_ci case VARYING_SLOT_CLIP_DIST1: 209bf215546Sopenharmony_ci /* if shader is already writing CLIPDIST, then 210bf215546Sopenharmony_ci * there should be no user-clip-planes to deal 211bf215546Sopenharmony_ci * with. 212bf215546Sopenharmony_ci * 213bf215546Sopenharmony_ci * We assume nir_remove_dead_variables has removed the clipdist 214bf215546Sopenharmony_ci * variables if they're not written. 215bf215546Sopenharmony_ci */ 216bf215546Sopenharmony_ci return false; 217bf215546Sopenharmony_ci } 218bf215546Sopenharmony_ci } 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci return *clipvertex || *position; 221bf215546Sopenharmony_ci} 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_cistatic nir_ssa_def * 224bf215546Sopenharmony_ciget_ucp(nir_builder *b, int plane, 225bf215546Sopenharmony_ci const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH]) 226bf215546Sopenharmony_ci{ 227bf215546Sopenharmony_ci if (clipplane_state_tokens) { 228bf215546Sopenharmony_ci char tmp[100]; 229bf215546Sopenharmony_ci snprintf(tmp, ARRAY_SIZE(tmp), "gl_ClipPlane%dMESA", plane); 230bf215546Sopenharmony_ci nir_variable *var = nir_variable_create(b->shader, 231bf215546Sopenharmony_ci nir_var_uniform, 232bf215546Sopenharmony_ci glsl_vec4_type(), 233bf215546Sopenharmony_ci tmp); 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci var->num_state_slots = 1; 236bf215546Sopenharmony_ci var->state_slots = ralloc_array(var, nir_state_slot, 1); 237bf215546Sopenharmony_ci memcpy(var->state_slots[0].tokens, 238bf215546Sopenharmony_ci clipplane_state_tokens[plane], 239bf215546Sopenharmony_ci sizeof(var->state_slots[0].tokens)); 240bf215546Sopenharmony_ci return nir_load_var(b, var); 241bf215546Sopenharmony_ci } else 242bf215546Sopenharmony_ci return nir_load_user_clip_plane(b, plane); 243bf215546Sopenharmony_ci} 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_cistatic void 247bf215546Sopenharmony_cilower_clip_outputs(nir_builder *b, nir_variable *position, 248bf215546Sopenharmony_ci nir_variable *clipvertex, nir_variable **out, 249bf215546Sopenharmony_ci unsigned ucp_enables, bool use_vars, 250bf215546Sopenharmony_ci bool use_clipdist_array, 251bf215546Sopenharmony_ci const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH]) 252bf215546Sopenharmony_ci{ 253bf215546Sopenharmony_ci nir_ssa_def *clipdist[MAX_CLIP_PLANES]; 254bf215546Sopenharmony_ci nir_ssa_def *cv; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci if (use_vars) { 257bf215546Sopenharmony_ci cv = nir_load_var(b, clipvertex ? clipvertex : position); 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci if (clipvertex) { 260bf215546Sopenharmony_ci clipvertex->data.mode = nir_var_shader_temp; 261bf215546Sopenharmony_ci nir_fixup_deref_modes(b->shader); 262bf215546Sopenharmony_ci } 263bf215546Sopenharmony_ci } else { 264bf215546Sopenharmony_ci if (clipvertex) 265bf215546Sopenharmony_ci cv = find_output(b->shader, clipvertex->data.driver_location); 266bf215546Sopenharmony_ci else { 267bf215546Sopenharmony_ci assert(position); 268bf215546Sopenharmony_ci cv = find_output(b->shader, position->data.driver_location); 269bf215546Sopenharmony_ci } 270bf215546Sopenharmony_ci } 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci for (int plane = 0; plane < MAX_CLIP_PLANES; plane++) { 273bf215546Sopenharmony_ci if (ucp_enables & (1 << plane)) { 274bf215546Sopenharmony_ci nir_ssa_def *ucp = get_ucp(b, plane, clipplane_state_tokens); 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci /* calculate clipdist[plane] - dot(ucp, cv): */ 277bf215546Sopenharmony_ci clipdist[plane] = nir_fdot(b, ucp, cv); 278bf215546Sopenharmony_ci } else { 279bf215546Sopenharmony_ci /* 0.0 == don't-clip == disabled: */ 280bf215546Sopenharmony_ci clipdist[plane] = nir_imm_float(b, 0.0); 281bf215546Sopenharmony_ci } 282bf215546Sopenharmony_ci if (use_clipdist_array && use_vars && plane < util_last_bit(ucp_enables)) { 283bf215546Sopenharmony_ci nir_deref_instr *deref; 284bf215546Sopenharmony_ci deref = nir_build_deref_array_imm(b, 285bf215546Sopenharmony_ci nir_build_deref_var(b, out[0]), 286bf215546Sopenharmony_ci plane); 287bf215546Sopenharmony_ci nir_store_deref(b, deref, clipdist[plane], 1); 288bf215546Sopenharmony_ci } 289bf215546Sopenharmony_ci } 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci if (!use_clipdist_array || !use_vars) { 292bf215546Sopenharmony_ci if (use_vars) { 293bf215546Sopenharmony_ci if (ucp_enables & 0x0f) 294bf215546Sopenharmony_ci nir_store_var(b, out[0], nir_vec(b, clipdist, 4), 0xf); 295bf215546Sopenharmony_ci if (ucp_enables & 0xf0) 296bf215546Sopenharmony_ci nir_store_var(b, out[1], nir_vec(b, &clipdist[4], 4), 0xf); 297bf215546Sopenharmony_ci } else if (use_clipdist_array) { 298bf215546Sopenharmony_ci if (ucp_enables & 0x0f) 299bf215546Sopenharmony_ci store_clipdist_output(b, out[0], 0, &clipdist[0]); 300bf215546Sopenharmony_ci if (ucp_enables & 0xf0) 301bf215546Sopenharmony_ci store_clipdist_output(b, out[0], 1, &clipdist[4]); 302bf215546Sopenharmony_ci } else { 303bf215546Sopenharmony_ci if (ucp_enables & 0x0f) 304bf215546Sopenharmony_ci store_clipdist_output(b, out[0], 0, &clipdist[0]); 305bf215546Sopenharmony_ci if (ucp_enables & 0xf0) 306bf215546Sopenharmony_ci store_clipdist_output(b, out[1], 0, &clipdist[4]); 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci } 309bf215546Sopenharmony_ci} 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci/* 312bf215546Sopenharmony_ci * VS lowering 313bf215546Sopenharmony_ci */ 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci/* ucp_enables is bitmask of enabled ucps. Actual ucp values are 316bf215546Sopenharmony_ci * passed in to shader via user_clip_plane system-values 317bf215546Sopenharmony_ci * 318bf215546Sopenharmony_ci * If use_vars is true, the pass will use variable loads and stores instead 319bf215546Sopenharmony_ci * of working with store_output intrinsics. 320bf215546Sopenharmony_ci * 321bf215546Sopenharmony_ci * If use_clipdist_array is true, the pass will use compact arrays for the 322bf215546Sopenharmony_ci * clipdist output instead of two vec4s. 323bf215546Sopenharmony_ci */ 324bf215546Sopenharmony_cibool 325bf215546Sopenharmony_cinir_lower_clip_vs(nir_shader *shader, unsigned ucp_enables, bool use_vars, 326bf215546Sopenharmony_ci bool use_clipdist_array, 327bf215546Sopenharmony_ci const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH]) 328bf215546Sopenharmony_ci{ 329bf215546Sopenharmony_ci nir_function_impl *impl = nir_shader_get_entrypoint(shader); 330bf215546Sopenharmony_ci nir_builder b; 331bf215546Sopenharmony_ci nir_variable *position = NULL; 332bf215546Sopenharmony_ci nir_variable *clipvertex = NULL; 333bf215546Sopenharmony_ci nir_variable *out[2] = { NULL }; 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci if (!ucp_enables) 336bf215546Sopenharmony_ci return false; 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci nir_builder_init(&b, impl); 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci /* NIR should ensure that, even in case of loops/if-else, there 341bf215546Sopenharmony_ci * should be only a single predecessor block to end_block, which 342bf215546Sopenharmony_ci * makes the perfect place to insert the clipdist calculations. 343bf215546Sopenharmony_ci * 344bf215546Sopenharmony_ci * NOTE: in case of early returns, these would have to be lowered 345bf215546Sopenharmony_ci * to jumps to end_block predecessor in a previous pass. Not sure 346bf215546Sopenharmony_ci * if there is a good way to sanity check this, but for now the 347bf215546Sopenharmony_ci * users of this pass don't support sub-routines. 348bf215546Sopenharmony_ci */ 349bf215546Sopenharmony_ci assert(impl->end_block->predecessors->entries == 1); 350bf215546Sopenharmony_ci b.cursor = nir_after_cf_list(&impl->body); 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_ci /* find clipvertex/position outputs */ 353bf215546Sopenharmony_ci if (!find_clipvertex_and_position_outputs(shader, &clipvertex, &position)) 354bf215546Sopenharmony_ci return false; 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_ci /* insert CLIPDIST outputs */ 357bf215546Sopenharmony_ci create_clipdist_vars(shader, out, ucp_enables, true, 358bf215546Sopenharmony_ci use_clipdist_array); 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_ci lower_clip_outputs(&b, position, clipvertex, out, ucp_enables, use_vars, 361bf215546Sopenharmony_ci use_clipdist_array, clipplane_state_tokens); 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_dominance); 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_ci return true; 366bf215546Sopenharmony_ci} 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_cistatic void 369bf215546Sopenharmony_cilower_clip_in_gs_block(nir_builder *b, nir_block *block, nir_variable *position, 370bf215546Sopenharmony_ci nir_variable *clipvertex, nir_variable **out, 371bf215546Sopenharmony_ci unsigned ucp_enables, bool use_clipdist_array, 372bf215546Sopenharmony_ci const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH]) 373bf215546Sopenharmony_ci{ 374bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 375bf215546Sopenharmony_ci if (instr->type != nir_instr_type_intrinsic) 376bf215546Sopenharmony_ci continue; 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 379bf215546Sopenharmony_ci switch (intrin->intrinsic) { 380bf215546Sopenharmony_ci case nir_intrinsic_emit_vertex_with_counter: 381bf215546Sopenharmony_ci case nir_intrinsic_emit_vertex: 382bf215546Sopenharmony_ci b->cursor = nir_before_instr(instr); 383bf215546Sopenharmony_ci lower_clip_outputs(b, position, clipvertex, out, ucp_enables, true, 384bf215546Sopenharmony_ci use_clipdist_array, clipplane_state_tokens); 385bf215546Sopenharmony_ci break; 386bf215546Sopenharmony_ci default: 387bf215546Sopenharmony_ci /* not interesting; skip this */ 388bf215546Sopenharmony_ci break; 389bf215546Sopenharmony_ci } 390bf215546Sopenharmony_ci } 391bf215546Sopenharmony_ci} 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci/* 394bf215546Sopenharmony_ci * GS lowering 395bf215546Sopenharmony_ci */ 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_cibool 398bf215546Sopenharmony_cinir_lower_clip_gs(nir_shader *shader, unsigned ucp_enables, 399bf215546Sopenharmony_ci bool use_clipdist_array, 400bf215546Sopenharmony_ci const gl_state_index16 clipplane_state_tokens[][STATE_LENGTH]) 401bf215546Sopenharmony_ci{ 402bf215546Sopenharmony_ci nir_function_impl *impl = nir_shader_get_entrypoint(shader); 403bf215546Sopenharmony_ci nir_builder b; 404bf215546Sopenharmony_ci nir_variable *position = NULL; 405bf215546Sopenharmony_ci nir_variable *clipvertex = NULL; 406bf215546Sopenharmony_ci nir_variable *out[2] = { NULL }; 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci if (!ucp_enables) 409bf215546Sopenharmony_ci return false; 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci /* find clipvertex/position outputs */ 412bf215546Sopenharmony_ci if (!find_clipvertex_and_position_outputs(shader, &clipvertex, &position)) 413bf215546Sopenharmony_ci return false; 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci /* insert CLIPDIST outputs */ 416bf215546Sopenharmony_ci create_clipdist_vars(shader, out, ucp_enables, true, 417bf215546Sopenharmony_ci use_clipdist_array); 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci nir_builder_init(&b, impl); 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci nir_foreach_block(block, impl) 422bf215546Sopenharmony_ci lower_clip_in_gs_block(&b, block, position, clipvertex, out, 423bf215546Sopenharmony_ci ucp_enables, use_clipdist_array, 424bf215546Sopenharmony_ci clipplane_state_tokens); 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_dominance); 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci return true; 429bf215546Sopenharmony_ci} 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci/* 432bf215546Sopenharmony_ci * FS lowering 433bf215546Sopenharmony_ci */ 434bf215546Sopenharmony_ci 435bf215546Sopenharmony_cistatic void 436bf215546Sopenharmony_cilower_clip_fs(nir_function_impl *impl, unsigned ucp_enables, 437bf215546Sopenharmony_ci nir_variable **in, bool use_clipdist_array) 438bf215546Sopenharmony_ci{ 439bf215546Sopenharmony_ci nir_ssa_def *clipdist[MAX_CLIP_PLANES]; 440bf215546Sopenharmony_ci nir_builder b; 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci nir_builder_init(&b, impl); 443bf215546Sopenharmony_ci b.cursor = nir_before_cf_list(&impl->body); 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci if (!use_clipdist_array) { 446bf215546Sopenharmony_ci if (ucp_enables & 0x0f) 447bf215546Sopenharmony_ci load_clipdist_input(&b, in[0], 0, &clipdist[0]); 448bf215546Sopenharmony_ci if (ucp_enables & 0xf0) 449bf215546Sopenharmony_ci load_clipdist_input(&b, in[1], 0, &clipdist[4]); 450bf215546Sopenharmony_ci } else { 451bf215546Sopenharmony_ci if (ucp_enables & 0x0f) 452bf215546Sopenharmony_ci load_clipdist_input(&b, in[0], 0, &clipdist[0]); 453bf215546Sopenharmony_ci if (ucp_enables & 0xf0) 454bf215546Sopenharmony_ci load_clipdist_input(&b, in[0], 1, &clipdist[4]); 455bf215546Sopenharmony_ci } 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci for (int plane = 0; plane < MAX_CLIP_PLANES; plane++) { 458bf215546Sopenharmony_ci if (ucp_enables & (1 << plane)) { 459bf215546Sopenharmony_ci nir_ssa_def *cond; 460bf215546Sopenharmony_ci 461bf215546Sopenharmony_ci cond = nir_flt(&b, clipdist[plane], nir_imm_float(&b, 0.0)); 462bf215546Sopenharmony_ci nir_discard_if(&b, cond); 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci b.shader->info.fs.uses_discard = true; 465bf215546Sopenharmony_ci } 466bf215546Sopenharmony_ci } 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_dominance); 469bf215546Sopenharmony_ci} 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_cistatic bool 472bf215546Sopenharmony_cifs_has_clip_dist_input_var(nir_shader *shader, nir_variable **io_vars, 473bf215546Sopenharmony_ci unsigned *ucp_enables) 474bf215546Sopenharmony_ci{ 475bf215546Sopenharmony_ci assert(shader->info.stage == MESA_SHADER_FRAGMENT); 476bf215546Sopenharmony_ci nir_foreach_shader_in_variable(var, shader) { 477bf215546Sopenharmony_ci switch (var->data.location) { 478bf215546Sopenharmony_ci case VARYING_SLOT_CLIP_DIST0: 479bf215546Sopenharmony_ci assert(var->data.compact); 480bf215546Sopenharmony_ci io_vars[0] = var; 481bf215546Sopenharmony_ci *ucp_enables &= (1 << glsl_get_length(var->type)) - 1; 482bf215546Sopenharmony_ci return true; 483bf215546Sopenharmony_ci default: 484bf215546Sopenharmony_ci break; 485bf215546Sopenharmony_ci } 486bf215546Sopenharmony_ci } 487bf215546Sopenharmony_ci return false; 488bf215546Sopenharmony_ci} 489bf215546Sopenharmony_ci 490bf215546Sopenharmony_ci/* insert conditional kill based on interpolated CLIPDIST 491bf215546Sopenharmony_ci */ 492bf215546Sopenharmony_cibool 493bf215546Sopenharmony_cinir_lower_clip_fs(nir_shader *shader, unsigned ucp_enables, 494bf215546Sopenharmony_ci bool use_clipdist_array) 495bf215546Sopenharmony_ci{ 496bf215546Sopenharmony_ci nir_variable *in[2] = {0}; 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci if (!ucp_enables) 499bf215546Sopenharmony_ci return false; 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci /* No hard reason to require use_clipdist_arr to work with 502bf215546Sopenharmony_ci * frag-shader-based gl_ClipDistance, except that the only user that does 503bf215546Sopenharmony_ci * not enable this does not support GL 3.0 (or EXT_clip_cull_distance). 504bf215546Sopenharmony_ci */ 505bf215546Sopenharmony_ci if (!fs_has_clip_dist_input_var(shader, in, &ucp_enables)) 506bf215546Sopenharmony_ci create_clipdist_vars(shader, in, ucp_enables, false, use_clipdist_array); 507bf215546Sopenharmony_ci else 508bf215546Sopenharmony_ci assert(use_clipdist_array); 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 511bf215546Sopenharmony_ci if (!strcmp(function->name, "main")) 512bf215546Sopenharmony_ci lower_clip_fs(function->impl, ucp_enables, in, use_clipdist_array); 513bf215546Sopenharmony_ci } 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci return true; 516bf215546Sopenharmony_ci} 517