1/* 2 * Copyright © 2020 Igalia S.L. 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include "nir.h" 25#include "nir_builder.h" 26#include "program/prog_instruction.h" 27 28/* Lower gl_PointCoord to account for user requested point-coord origin 29 * and for whether draw buffer is flipped. 30 */ 31 32typedef struct { 33 const gl_state_index16 *pntc_state_tokens; 34 nir_shader *shader; 35 nir_builder b; 36 nir_variable *pntc_transform; 37} lower_pntc_ytransform_state; 38 39static nir_ssa_def * 40get_pntc_transform(lower_pntc_ytransform_state *state) 41{ 42 if (state->pntc_transform == NULL) { 43 /* NOTE: name must be prefixed w/ "gl_" to trigger slot based 44 * special handling in uniform setup: 45 */ 46 nir_variable *var = nir_variable_create(state->shader, 47 nir_var_uniform, 48 glsl_vec4_type(), 49 "gl_PntcYTransform"); 50 51 var->num_state_slots = 1; 52 var->state_slots = ralloc_array(var, nir_state_slot, 1); 53 var->state_slots[0].swizzle = SWIZZLE_XYZW; 54 memcpy(var->state_slots[0].tokens, state->pntc_state_tokens, 55 sizeof(var->state_slots[0].tokens)); 56 var->data.how_declared = nir_var_hidden; 57 state->pntc_transform = var; 58 } 59 return nir_load_var(&state->b, state->pntc_transform); 60} 61 62static void 63lower_load_pointcoord(lower_pntc_ytransform_state *state, 64 nir_intrinsic_instr *intr) 65{ 66 nir_builder *b = &state->b; 67 b->cursor = nir_after_instr(&intr->instr); 68 69 nir_ssa_def *pntc = &intr->dest.ssa; 70 nir_ssa_def *transform = get_pntc_transform(state); 71 nir_ssa_def *y = nir_channel(b, pntc, 1); 72 /* The offset is 1 if we're flipping, 0 otherwise. */ 73 nir_ssa_def *offset = nir_channel(b, transform, 1); 74 /* Flip the sign of y if we're flipping. */ 75 nir_ssa_def *scaled = nir_fmul(b, y, nir_channel(b, transform, 0)); 76 77 /* Reassemble the vector. */ 78 nir_ssa_def *flipped_pntc = nir_vec2(b, 79 nir_channel(b, pntc, 0), 80 nir_fadd(b, offset, scaled)); 81 82 nir_ssa_def_rewrite_uses_after(&intr->dest.ssa, flipped_pntc, 83 flipped_pntc->parent_instr); 84} 85 86static void 87lower_pntc_ytransform_block(lower_pntc_ytransform_state *state, 88 nir_block *block) 89{ 90 nir_foreach_instr_safe(instr, block) { 91 if (instr->type == nir_instr_type_intrinsic) { 92 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); 93 if (intr->intrinsic == nir_intrinsic_load_deref) { 94 nir_deref_instr *deref = nir_src_as_deref(intr->src[0]); 95 nir_variable *var = nir_deref_instr_get_variable(deref); 96 97 if ((var->data.mode == nir_var_shader_in && 98 var->data.location == VARYING_SLOT_PNTC) || 99 (var->data.mode == nir_var_system_value && 100 var->data.location == SYSTEM_VALUE_POINT_COORD)) { 101 lower_load_pointcoord(state, intr); 102 } 103 } 104 } 105 } 106} 107 108bool 109nir_lower_pntc_ytransform(nir_shader *shader, 110 const gl_state_index16 pntc_state_tokens[][STATE_LENGTH]) 111{ 112 if (!shader->options->lower_wpos_pntc) 113 return false; 114 115 lower_pntc_ytransform_state state = { 116 .pntc_state_tokens = *pntc_state_tokens, 117 .shader = shader, 118 .pntc_transform = NULL, 119 }; 120 121 assert(shader->info.stage == MESA_SHADER_FRAGMENT); 122 123 nir_foreach_function(function, shader) { 124 if (function->impl) { 125 nir_builder_init(&state.b, function->impl); 126 127 nir_foreach_block(block, function->impl) { 128 lower_pntc_ytransform_block(&state, block); 129 } 130 nir_metadata_preserve(function->impl, nir_metadata_block_index | 131 nir_metadata_dominance); 132 } 133 } 134 135 return state.pntc_transform != NULL; 136} 137