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. In the case that 43 * sample shading is enabled, Vulkan expects FragCoord to include sample 44 * positions. 45 */ 46 47static void 48update_fragcoord(nir_builder *b, nir_intrinsic_instr *intr) 49{ 50 nir_ssa_def *wpos = &intr->dest.ssa; 51 52 assert(intr->dest.is_ssa); 53 54 b->cursor = nir_after_instr(&intr->instr); 55 56 nir_ssa_def *spos = nir_load_sample_pos_or_center(b); 57 58 wpos = nir_fadd(b, wpos, 59 nir_vec4(b, 60 nir_channel(b, spos, 0), 61 nir_channel(b, spos, 1), 62 nir_imm_float(b, 0.0f), 63 nir_imm_float(b, 0.0f))); 64 65 nir_ssa_def_rewrite_uses_after(&intr->dest.ssa, wpos, 66 wpos->parent_instr); 67} 68 69static bool 70lower_wpos_center_block(nir_builder *b, nir_block *block) 71{ 72 bool progress = false; 73 74 nir_foreach_instr(instr, block) { 75 if (instr->type == nir_instr_type_intrinsic) { 76 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); 77 if (intr->intrinsic == nir_intrinsic_load_frag_coord) { 78 update_fragcoord(b, intr); 79 progress = true; 80 } 81 } 82 } 83 84 return progress; 85} 86 87bool 88nir_lower_wpos_center(nir_shader *shader) 89{ 90 bool progress = false; 91 nir_builder b; 92 93 assert(shader->info.stage == MESA_SHADER_FRAGMENT); 94 95 nir_foreach_function(function, shader) { 96 if (function->impl) { 97 nir_builder_init(&b, function->impl); 98 99 nir_foreach_block(block, function->impl) { 100 progress = lower_wpos_center_block(&b, block) || 101 progress; 102 } 103 nir_metadata_preserve(function->impl, nir_metadata_block_index | 104 nir_metadata_dominance); 105 } 106 } 107 108 return progress; 109} 110