Home | History | Annotate | Download | only in nir
      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