1/* 2 * Copyright © 2020 Collabora, Ltd. 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 * Erik Faye-Lund <erik.faye-lund@collabora.com> 25 */ 26 27#include "nir.h" 28#include "nir_builder.h" 29#include "nir_deref.h" 30 31static nir_ssa_def * 32get_io_index(nir_builder *b, nir_deref_instr *deref) 33{ 34 nir_deref_path path; 35 nir_deref_path_init(&path, deref, NULL); 36 37 assert(path.path[0]->deref_type == nir_deref_type_var); 38 nir_deref_instr **p = &path.path[1]; 39 40 /* Just emit code and let constant-folding go to town */ 41 nir_ssa_def *offset = nir_imm_int(b, 0); 42 43 for (; *p; p++) { 44 if ((*p)->deref_type == nir_deref_type_array) { 45 unsigned size = glsl_get_length((*p)->type); 46 47 nir_ssa_def *mul = 48 nir_amul_imm(b, nir_ssa_for_src(b, (*p)->arr.index, 1), size); 49 50 offset = nir_iadd(b, offset, mul); 51 } else 52 unreachable("Unsupported deref type"); 53 } 54 55 nir_deref_path_finish(&path); 56 57 return offset; 58} 59 60static void 61nir_lower_texcoord_replace_impl(nir_function_impl *impl, 62 unsigned coord_replace, 63 bool point_coord_is_sysval, 64 bool yinvert) 65{ 66 nir_builder b; 67 68 nir_builder_init(&b, impl); 69 b.cursor = nir_before_cf_list(&impl->body); 70 71 nir_ssa_def *new_coord; 72 if (point_coord_is_sysval) { 73 new_coord = nir_load_system_value(&b, nir_intrinsic_load_point_coord, 74 0, 2, 32); 75 } else { 76 /* find or create pntc */ 77 nir_variable *pntc = nir_find_variable_with_location(b.shader, 78 nir_var_shader_in, 79 VARYING_SLOT_PNTC); 80 if (!pntc) { 81 pntc = nir_variable_create(b.shader, nir_var_shader_in, 82 glsl_vec_type(2), "gl_PointCoord"); 83 pntc->data.location = VARYING_SLOT_PNTC; 84 pntc->data.driver_location = b.shader->num_inputs++; 85 b.shader->info.inputs_read |= BITFIELD64_BIT(VARYING_SLOT_PNTC); 86 } 87 88 new_coord = nir_load_var(&b, pntc); 89 } 90 91 /* point-coord is two-component, need to add two implicit ones in case of 92 * projective texturing etc. 93 */ 94 nir_ssa_def *zero = nir_imm_zero(&b, 1, new_coord->bit_size); 95 nir_ssa_def *one = nir_imm_floatN_t(&b, 1.0, new_coord->bit_size); 96 nir_ssa_def *y = nir_channel(&b, new_coord, 1); 97 if (yinvert) 98 y = nir_fsub(&b, nir_imm_float(&b, 1.0), y); 99 new_coord = nir_vec4(&b, nir_channel(&b, new_coord, 0), 100 y, 101 zero, one); 102 103 nir_foreach_block(block, impl) { 104 nir_foreach_instr_safe(instr, block) { 105 if (instr->type != nir_instr_type_intrinsic) 106 continue; 107 108 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 109 if (intrin->intrinsic != nir_intrinsic_load_deref) 110 continue; 111 112 nir_variable *var = nir_intrinsic_get_var(intrin, 0); 113 if (var->data.mode != nir_var_shader_in || 114 var->data.location < VARYING_SLOT_TEX0 || 115 var->data.location > VARYING_SLOT_TEX7) 116 continue; 117 unsigned base = var->data.location - VARYING_SLOT_TEX0; 118 119 b.cursor = nir_after_instr(instr); 120 nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); 121 nir_ssa_def *index = get_io_index(&b, deref); 122 nir_ssa_def *mask = 123 nir_ishl(&b, nir_imm_int(&b, 1), 124 nir_iadd_imm(&b, index, base)); 125 126 nir_ssa_def *cond = 127 nir_i2b(&b, nir_iand_imm(&b, mask, coord_replace)); 128 nir_ssa_def *result = nir_bcsel(&b, cond, new_coord, 129 &intrin->dest.ssa); 130 131 nir_ssa_def_rewrite_uses_after(&intrin->dest.ssa, 132 result, 133 result->parent_instr); 134 } 135 } 136 137 nir_metadata_preserve(impl, nir_metadata_block_index | 138 nir_metadata_dominance); 139} 140 141void 142nir_lower_texcoord_replace(nir_shader *s, unsigned coord_replace, 143 bool point_coord_is_sysval, bool yinvert) 144{ 145 assert(s->info.stage == MESA_SHADER_FRAGMENT); 146 assert(coord_replace != 0); 147 148 nir_foreach_function(function, s) { 149 if (function->impl) 150 nir_lower_texcoord_replace_impl(function->impl, coord_replace, 151 point_coord_is_sysval, yinvert); 152 } 153} 154