Home | History | Annotate | Download | only in nir
      1 /*
      2  * Copyright  2015 Red Hat
      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 
     27 /* Lower glDrawPixels().
     28  *
     29  * This is based on the logic in st_get_drawpix_shader() in TGSI compiler.
     30  *
     31  * Run before nir_lower_io.
     32  */
     33 
     34 typedef struct {
     35    const nir_lower_drawpixels_options *options;
     36    nir_shader   *shader;
     37    nir_builder   b;
     38    nir_variable *texcoord, *scale, *bias;
     39 } lower_drawpixels_state;
     40 
     41 static nir_ssa_def *
     42 get_texcoord(lower_drawpixels_state *state)
     43 {
     44    if (state->texcoord == NULL) {
     45       nir_variable *texcoord = NULL;
     46 
     47       /* find gl_TexCoord, if it exists: */
     48       nir_foreach_variable(var, &state->shader->inputs) {
     49          if (var->data.location == VARYING_SLOT_TEX0) {
     50             texcoord = var;
     51             break;
     52          }
     53       }
     54 
     55       /* otherwise create it: */
     56       if (texcoord == NULL) {
     57          texcoord = nir_variable_create(state->shader,
     58                                         nir_var_shader_in,
     59                                         glsl_vec4_type(),
     60                                         "gl_TexCoord");
     61          texcoord->data.location = VARYING_SLOT_TEX0;
     62       }
     63 
     64       state->texcoord = texcoord;
     65    }
     66    return nir_load_var(&state->b, state->texcoord);
     67 }
     68 
     69 static nir_variable *
     70 create_uniform(nir_shader *shader, const char *name, const int state_tokens[5])
     71 {
     72    nir_variable *var = nir_variable_create(shader,
     73                                            nir_var_uniform,
     74                                            glsl_vec4_type(),
     75                                            name);
     76    var->num_state_slots = 1;
     77    var->state_slots = ralloc_array(var, nir_state_slot, 1);
     78    memcpy(var->state_slots[0].tokens, state_tokens,
     79           sizeof(var->state_slots[0].tokens));
     80    return var;
     81 }
     82 
     83 static nir_ssa_def *
     84 get_scale(lower_drawpixels_state *state)
     85 {
     86    if (state->scale == NULL) {
     87       state->scale = create_uniform(state->shader, "gl_PTscale",
     88                                     state->options->scale_state_tokens);
     89    }
     90    return nir_load_var(&state->b, state->scale);
     91 }
     92 
     93 static nir_ssa_def *
     94 get_bias(lower_drawpixels_state *state)
     95 {
     96    if (state->bias == NULL) {
     97       state->bias = create_uniform(state->shader, "gl_PTbias",
     98                                    state->options->bias_state_tokens);
     99    }
    100    return nir_load_var(&state->b, state->bias);
    101 }
    102 
    103 static nir_ssa_def *
    104 get_texcoord_const(lower_drawpixels_state *state)
    105 {
    106    if (state->bias == NULL) {
    107       state->bias = create_uniform(state->shader, "gl_MultiTexCoord0",
    108                                    state->options->texcoord_state_tokens);
    109    }
    110    return nir_load_var(&state->b, state->bias);
    111 }
    112 
    113 static void
    114 lower_color(lower_drawpixels_state *state, nir_intrinsic_instr *intr)
    115 {
    116    nir_builder *b = &state->b;
    117    nir_ssa_def *texcoord;
    118    nir_tex_instr *tex;
    119    nir_ssa_def *def;
    120 
    121    assert(intr->dest.is_ssa);
    122 
    123    b->cursor = nir_before_instr(&intr->instr);
    124 
    125    texcoord = get_texcoord(state);
    126 
    127    /* replace load_var(gl_Color) w/ texture sample:
    128     *   TEX def, texcoord, drawpix_sampler, 2D
    129     */
    130    tex = nir_tex_instr_create(state->shader, 1);
    131    tex->op = nir_texop_tex;
    132    tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
    133    tex->coord_components = 2;
    134    tex->sampler_index = state->options->drawpix_sampler;
    135    tex->texture_index = state->options->drawpix_sampler;
    136    tex->dest_type = nir_type_float;
    137    tex->src[0].src_type = nir_tex_src_coord;
    138    tex->src[0].src = nir_src_for_ssa(texcoord);
    139 
    140    nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL);
    141    nir_builder_instr_insert(b, &tex->instr);
    142    def = &tex->dest.ssa;
    143 
    144    /* Apply the scale and bias. */
    145    if (state->options->scale_and_bias) {
    146       /* MAD def, def, scale, bias; */
    147       def = nir_ffma(b, def, get_scale(state), get_bias(state));
    148    }
    149 
    150    if (state->options->pixel_maps) {
    151       static const unsigned swiz_xy[4] = {0,1};
    152       static const unsigned swiz_zw[4] = {2,3};
    153 
    154       /* do four pixel map look-ups with two TEX instructions: */
    155       nir_ssa_def *def_xy, *def_zw;
    156 
    157       /* TEX def.xy, def.xyyy, pixelmap_sampler, 2D; */
    158       tex = nir_tex_instr_create(state->shader, 1);
    159       tex->op = nir_texop_tex;
    160       tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
    161       tex->coord_components = 2;
    162       tex->sampler_index = state->options->pixelmap_sampler;
    163       tex->texture_index = state->options->pixelmap_sampler;
    164       tex->dest_type = nir_type_float;
    165       tex->src[0].src_type = nir_tex_src_coord;
    166       tex->src[0].src = nir_src_for_ssa(nir_swizzle(b, def, swiz_xy, 2, true));
    167 
    168       nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL);
    169       nir_builder_instr_insert(b, &tex->instr);
    170       def_xy = &tex->dest.ssa;
    171 
    172       /* TEX def.zw, def.zwww, pixelmap_sampler, 2D; */
    173       tex = nir_tex_instr_create(state->shader, 1);
    174       tex->op = nir_texop_tex;
    175       tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
    176       tex->coord_components = 2;
    177       tex->sampler_index = state->options->pixelmap_sampler;
    178       tex->dest_type = nir_type_float;
    179       tex->src[0].src_type = nir_tex_src_coord;
    180       tex->src[0].src = nir_src_for_ssa(nir_swizzle(b, def, swiz_zw, 2, true));
    181 
    182       nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL);
    183       nir_builder_instr_insert(b, &tex->instr);
    184       def_zw = &tex->dest.ssa;
    185 
    186       /* def = vec4(def.xy, def.zw); */
    187       def = nir_vec4(b,
    188                      nir_channel(b, def_xy, 0),
    189                      nir_channel(b, def_xy, 1),
    190                      nir_channel(b, def_zw, 0),
    191                      nir_channel(b, def_zw, 1));
    192    }
    193 
    194    nir_ssa_def_rewrite_uses(&intr->dest.ssa, nir_src_for_ssa(def));
    195 }
    196 
    197 static void
    198 lower_texcoord(lower_drawpixels_state *state, nir_intrinsic_instr *intr)
    199 {
    200    state->b.cursor = nir_before_instr(&intr->instr);
    201 
    202    nir_ssa_def *texcoord_const = get_texcoord_const(state);
    203    nir_ssa_def_rewrite_uses(&intr->dest.ssa, nir_src_for_ssa(texcoord_const));
    204 }
    205 
    206 static bool
    207 lower_drawpixels_block(lower_drawpixels_state *state, nir_block *block)
    208 {
    209    nir_foreach_instr_safe(instr, block) {
    210       if (instr->type == nir_instr_type_intrinsic) {
    211          nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
    212          if (intr->intrinsic == nir_intrinsic_load_var) {
    213             nir_deref_var *dvar = intr->variables[0];
    214             nir_variable *var = dvar->var;
    215 
    216             if (var->data.location == VARYING_SLOT_COL0) {
    217                /* gl_Color should not have array/struct deref's: */
    218                assert(dvar->deref.child == NULL);
    219                lower_color(state, intr);
    220             } else if (var->data.location == VARYING_SLOT_TEX0) {
    221                /* gl_TexCoord should not have array/struct deref's: */
    222                assert(dvar->deref.child == NULL);
    223                lower_texcoord(state, intr);
    224             }
    225          }
    226       }
    227    }
    228 
    229    return true;
    230 }
    231 
    232 static void
    233 lower_drawpixels_impl(lower_drawpixels_state *state, nir_function_impl *impl)
    234 {
    235    nir_builder_init(&state->b, impl);
    236 
    237    nir_foreach_block(block, impl) {
    238       lower_drawpixels_block(state, block);
    239    }
    240    nir_metadata_preserve(impl, nir_metadata_block_index |
    241                                nir_metadata_dominance);
    242 }
    243 
    244 void
    245 nir_lower_drawpixels(nir_shader *shader,
    246                      const nir_lower_drawpixels_options *options)
    247 {
    248    lower_drawpixels_state state = {
    249       .options = options,
    250       .shader = shader,
    251    };
    252 
    253    assert(shader->stage == MESA_SHADER_FRAGMENT);
    254 
    255    nir_foreach_function(function, shader) {
    256       if (function->impl)
    257          lower_drawpixels_impl(&state, function->impl);
    258    }
    259 }
    260