1 /* 2 * Copyright © 2015 Red Hat 3 * Copyright © 2016 Intel Corporation 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25 #include "nir.h" 26 #include "nir_builder.h" 27 #include "program/prog_instruction.h" 28 29 /** 30 * This pass adds <0.5, 0.5> to all uses of gl_FragCoord. 31 * 32 * Run before nir_lower_io(). 33 * 34 * For a more full featured pass, consider using nir_lower_wpos_ytransform(), 35 * which can handle pixel center integer / half integer, and origin lower 36 * left / upper left transformations. 37 * 38 * This simple pass is primarily intended for use by Vulkan drivers on 39 * hardware which provides an integer pixel center. Vulkan mandates that 40 * the pixel center must be half-integer, and also that the coordinate 41 * system's origin must be upper left. This means that there's no need 42 * for a uniform - we can always just add a constant. 43 */ 44 45 static void 46 add_half_to_fragcoord(nir_builder *b, nir_intrinsic_instr *intr) 47 { 48 nir_ssa_def *wpos = &intr->dest.ssa; 49 50 assert(intr->dest.is_ssa); 51 52 b->cursor = nir_after_instr(&intr->instr); 53 54 wpos = nir_fadd(b, wpos, nir_imm_vec4(b, 0.5f, 0.5f, 0.0f, 0.0f)); 55 56 nir_ssa_def_rewrite_uses_after(&intr->dest.ssa, nir_src_for_ssa(wpos), 57 wpos->parent_instr); 58 } 59 60 static bool 61 lower_wpos_center_block(nir_builder *b, nir_block *block) 62 { 63 bool progress = false; 64 65 nir_foreach_instr(instr, block) { 66 if (instr->type == nir_instr_type_intrinsic) { 67 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); 68 if (intr->intrinsic == nir_intrinsic_load_var) { 69 nir_deref_var *dvar = intr->variables[0]; 70 nir_variable *var = dvar->var; 71 72 if (var->data.mode == nir_var_shader_in && 73 var->data.location == VARYING_SLOT_POS) { 74 /* gl_FragCoord should not have array/struct deref's: */ 75 assert(dvar->deref.child == NULL); 76 add_half_to_fragcoord(b, intr); 77 progress = true; 78 } 79 } 80 } 81 } 82 83 return progress; 84 } 85 86 bool 87 nir_lower_wpos_center(nir_shader *shader) 88 { 89 bool progress = false; 90 nir_builder b; 91 92 assert(shader->stage == MESA_SHADER_FRAGMENT); 93 94 nir_foreach_function(function, shader) { 95 if (function->impl) { 96 nir_builder_init(&b, function->impl); 97 98 nir_foreach_block(block, function->impl) { 99 progress = lower_wpos_center_block(&b, block) || progress; 100 } 101 nir_metadata_preserve(function->impl, nir_metadata_block_index | 102 nir_metadata_dominance); 103 } 104 } 105 106 return progress; 107 } 108