1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2020 Mike Blumenkrantz 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 * Mike Blumenkrantz <michael.blumenkrantz@gmail.com> 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "nir.h" 28bf215546Sopenharmony_ci#include "nir_builder.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci/** 32bf215546Sopenharmony_ci * This pass uses the enabled clip planes from the rasterizer state to rewrite 33bf215546Sopenharmony_ci * vertex shader store operations and store a 0 to the corresponding gl_ClipDistance[n] 34bf215546Sopenharmony_ci * value if the plane is disabled 35bf215546Sopenharmony_ci */ 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci/* recursively nest if/else blocks until we get to an array index, 38bf215546Sopenharmony_ci * then overwrite it if that plane isn't enabled 39bf215546Sopenharmony_ci */ 40bf215546Sopenharmony_cistatic void 41bf215546Sopenharmony_cirecursive_if_chain(nir_builder *b, nir_deref_instr *deref, nir_ssa_def *value, unsigned clip_plane_enable, nir_ssa_def *index, unsigned start, unsigned end) 42bf215546Sopenharmony_ci{ 43bf215546Sopenharmony_ci if (start == end - 1) { 44bf215546Sopenharmony_ci /* store the original value again if the clip plane is enabled */ 45bf215546Sopenharmony_ci if (clip_plane_enable & (1 << start)) 46bf215546Sopenharmony_ci nir_store_deref(b, deref, value, 1 << start); 47bf215546Sopenharmony_ci else 48bf215546Sopenharmony_ci nir_store_deref(b, deref, nir_imm_int(b, 0), 1 << start); 49bf215546Sopenharmony_ci return; 50bf215546Sopenharmony_ci } 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci unsigned mid = start + (end - start) / 2; 53bf215546Sopenharmony_ci nir_push_if(b, nir_ilt(b, index, nir_imm_int(b, mid))); 54bf215546Sopenharmony_ci recursive_if_chain(b, deref, value, clip_plane_enable, index, start, mid); 55bf215546Sopenharmony_ci nir_push_else(b, NULL); 56bf215546Sopenharmony_ci recursive_if_chain(b, deref, value, clip_plane_enable, index, mid, end); 57bf215546Sopenharmony_ci nir_pop_if(b, NULL); 58bf215546Sopenharmony_ci} 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci/* vulkan (and some drivers) provides no concept of enabling clip planes through api, 61bf215546Sopenharmony_ci * so we rewrite disabled clip planes to a zero value in order to disable them 62bf215546Sopenharmony_ci */ 63bf215546Sopenharmony_cistatic bool 64bf215546Sopenharmony_cilower_clip_plane_store(nir_intrinsic_instr *instr, unsigned clip_plane_enable, nir_builder *b) 65bf215546Sopenharmony_ci{ 66bf215546Sopenharmony_ci nir_variable *out; 67bf215546Sopenharmony_ci unsigned plane; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci if (instr->intrinsic != nir_intrinsic_store_deref) 70bf215546Sopenharmony_ci return false; 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci nir_deref_instr *deref = nir_src_as_deref(instr->src[0]); 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci out = nir_deref_instr_get_variable(deref); 75bf215546Sopenharmony_ci if ((out->data.location != VARYING_SLOT_CLIP_DIST0 && 76bf215546Sopenharmony_ci out->data.location != VARYING_SLOT_CLIP_DIST1) || 77bf215546Sopenharmony_ci out->data.mode != nir_var_shader_out) 78bf215546Sopenharmony_ci return false; 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci b->cursor = nir_after_instr(&instr->instr); 81bf215546Sopenharmony_ci if (deref->deref_type == nir_deref_type_var) { 82bf215546Sopenharmony_ci int wrmask = nir_intrinsic_write_mask(instr); 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci nir_ssa_def *components[4]; 85bf215546Sopenharmony_ci int start = out->data.location == VARYING_SLOT_CLIP_DIST1 ? 4 : 0; 86bf215546Sopenharmony_ci /* rewrite components as zeroes for planes that aren't enabled */ 87bf215546Sopenharmony_ci for (int i = 0; i < 4; i++) { 88bf215546Sopenharmony_ci if (wrmask & (1 << i)) { 89bf215546Sopenharmony_ci if (!(clip_plane_enable & (1 << (start + i)))) 90bf215546Sopenharmony_ci components[i] = nir_imm_int(b, 0); 91bf215546Sopenharmony_ci else 92bf215546Sopenharmony_ci components[i] = nir_channel(b, nir_ssa_for_src(b, instr->src[1], nir_src_num_components(instr->src[1])), i); 93bf215546Sopenharmony_ci } else 94bf215546Sopenharmony_ci components[i] = nir_ssa_undef(b, 1, 32); 95bf215546Sopenharmony_ci } 96bf215546Sopenharmony_ci nir_store_deref(b, deref, nir_vec(b, components, instr->num_components), wrmask); 97bf215546Sopenharmony_ci } else if (nir_src_is_const(deref->arr.index)) { 98bf215546Sopenharmony_ci /* storing using a constant index */ 99bf215546Sopenharmony_ci plane = nir_src_as_uint(deref->arr.index); 100bf215546Sopenharmony_ci /* no need to make changes if the clip plane is enabled */ 101bf215546Sopenharmony_ci if (clip_plane_enable & (1 << plane)) 102bf215546Sopenharmony_ci return false; 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci assert(nir_intrinsic_write_mask(instr) == 1); 105bf215546Sopenharmony_ci nir_store_deref(b, deref, nir_imm_int(b, 0), 1); 106bf215546Sopenharmony_ci } else { 107bf215546Sopenharmony_ci /* storing using a variable index */ 108bf215546Sopenharmony_ci nir_ssa_def *index = nir_ssa_for_src(b, deref->arr.index, 1); 109bf215546Sopenharmony_ci unsigned length = glsl_get_length(nir_deref_instr_parent(deref)->type); 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci recursive_if_chain(b, deref, instr->src[1].ssa, clip_plane_enable, index, 0, length); 112bf215546Sopenharmony_ci } 113bf215546Sopenharmony_ci nir_instr_remove(&instr->instr); 114bf215546Sopenharmony_ci return true; 115bf215546Sopenharmony_ci} 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_cibool 118bf215546Sopenharmony_cinir_lower_clip_disable(nir_shader *shader, unsigned clip_plane_enable) 119bf215546Sopenharmony_ci{ 120bf215546Sopenharmony_ci bool progress = false; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci /* if all user planes are enabled in API that are written in the array, always ignore; 123bf215546Sopenharmony_ci * this explicitly covers the 2x vec4 case 124bf215546Sopenharmony_ci */ 125bf215546Sopenharmony_ci if (clip_plane_enable == u_bit_consecutive(0, shader->info.clip_distance_array_size)) 126bf215546Sopenharmony_ci return false; 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 129bf215546Sopenharmony_ci if (function->impl) { 130bf215546Sopenharmony_ci nir_builder builder; 131bf215546Sopenharmony_ci nir_builder_init(&builder, function->impl); 132bf215546Sopenharmony_ci nir_foreach_block(block, function->impl) { 133bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 134bf215546Sopenharmony_ci if (instr->type == nir_instr_type_intrinsic) 135bf215546Sopenharmony_ci progress |= lower_clip_plane_store(nir_instr_as_intrinsic(instr), 136bf215546Sopenharmony_ci clip_plane_enable, 137bf215546Sopenharmony_ci &builder); 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci } 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci nir_metadata_preserve(function->impl, nir_metadata_block_index | nir_metadata_dominance); 142bf215546Sopenharmony_ci } 143bf215546Sopenharmony_ci } 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci return progress; 146bf215546Sopenharmony_ci} 147