1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2015 Red Hat 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "nir.h" 25bf215546Sopenharmony_ci#include "nir_builder.h" 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci/* Lower glDrawPixels(). 28bf215546Sopenharmony_ci * 29bf215546Sopenharmony_ci * This is based on the logic in st_get_drawpix_shader() in TGSI compiler. 30bf215546Sopenharmony_ci * 31bf215546Sopenharmony_ci * Run before nir_lower_io. 32bf215546Sopenharmony_ci */ 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_citypedef struct { 35bf215546Sopenharmony_ci const nir_lower_drawpixels_options *options; 36bf215546Sopenharmony_ci nir_shader *shader; 37bf215546Sopenharmony_ci nir_builder b; 38bf215546Sopenharmony_ci nir_variable *texcoord, *texcoord_const, *scale, *bias, *tex, *pixelmap; 39bf215546Sopenharmony_ci} lower_drawpixels_state; 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_cistatic nir_ssa_def * 42bf215546Sopenharmony_ciget_texcoord(lower_drawpixels_state *state) 43bf215546Sopenharmony_ci{ 44bf215546Sopenharmony_ci if (state->texcoord == NULL) { 45bf215546Sopenharmony_ci nir_variable *texcoord = NULL; 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci /* find gl_TexCoord, if it exists: */ 48bf215546Sopenharmony_ci nir_foreach_shader_in_variable(var, state->shader) { 49bf215546Sopenharmony_ci if (var->data.location == VARYING_SLOT_TEX0) { 50bf215546Sopenharmony_ci texcoord = var; 51bf215546Sopenharmony_ci break; 52bf215546Sopenharmony_ci } 53bf215546Sopenharmony_ci } 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci /* otherwise create it: */ 56bf215546Sopenharmony_ci if (texcoord == NULL) { 57bf215546Sopenharmony_ci texcoord = nir_variable_create(state->shader, 58bf215546Sopenharmony_ci nir_var_shader_in, 59bf215546Sopenharmony_ci glsl_vec4_type(), 60bf215546Sopenharmony_ci "gl_TexCoord"); 61bf215546Sopenharmony_ci texcoord->data.location = VARYING_SLOT_TEX0; 62bf215546Sopenharmony_ci } 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci state->texcoord = texcoord; 65bf215546Sopenharmony_ci } 66bf215546Sopenharmony_ci return nir_load_var(&state->b, state->texcoord); 67bf215546Sopenharmony_ci} 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_cistatic nir_variable * 70bf215546Sopenharmony_cicreate_uniform(nir_shader *shader, const char *name, 71bf215546Sopenharmony_ci const gl_state_index16 state_tokens[STATE_LENGTH]) 72bf215546Sopenharmony_ci{ 73bf215546Sopenharmony_ci nir_variable *var = nir_variable_create(shader, 74bf215546Sopenharmony_ci nir_var_uniform, 75bf215546Sopenharmony_ci glsl_vec4_type(), 76bf215546Sopenharmony_ci name); 77bf215546Sopenharmony_ci var->num_state_slots = 1; 78bf215546Sopenharmony_ci var->state_slots = ralloc_array(var, nir_state_slot, 1); 79bf215546Sopenharmony_ci memcpy(var->state_slots[0].tokens, state_tokens, 80bf215546Sopenharmony_ci sizeof(var->state_slots[0].tokens)); 81bf215546Sopenharmony_ci return var; 82bf215546Sopenharmony_ci} 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_cistatic nir_ssa_def * 85bf215546Sopenharmony_ciget_scale(lower_drawpixels_state *state) 86bf215546Sopenharmony_ci{ 87bf215546Sopenharmony_ci if (state->scale == NULL) { 88bf215546Sopenharmony_ci state->scale = create_uniform(state->shader, "gl_PTscale", 89bf215546Sopenharmony_ci state->options->scale_state_tokens); 90bf215546Sopenharmony_ci } 91bf215546Sopenharmony_ci return nir_load_var(&state->b, state->scale); 92bf215546Sopenharmony_ci} 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_cistatic nir_ssa_def * 95bf215546Sopenharmony_ciget_bias(lower_drawpixels_state *state) 96bf215546Sopenharmony_ci{ 97bf215546Sopenharmony_ci if (state->bias == NULL) { 98bf215546Sopenharmony_ci state->bias = create_uniform(state->shader, "gl_PTbias", 99bf215546Sopenharmony_ci state->options->bias_state_tokens); 100bf215546Sopenharmony_ci } 101bf215546Sopenharmony_ci return nir_load_var(&state->b, state->bias); 102bf215546Sopenharmony_ci} 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_cistatic nir_ssa_def * 105bf215546Sopenharmony_ciget_texcoord_const(lower_drawpixels_state *state) 106bf215546Sopenharmony_ci{ 107bf215546Sopenharmony_ci if (state->texcoord_const == NULL) { 108bf215546Sopenharmony_ci state->texcoord_const = create_uniform(state->shader, 109bf215546Sopenharmony_ci "gl_MultiTexCoord0", 110bf215546Sopenharmony_ci state->options->texcoord_state_tokens); 111bf215546Sopenharmony_ci } 112bf215546Sopenharmony_ci return nir_load_var(&state->b, state->texcoord_const); 113bf215546Sopenharmony_ci} 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_cistatic void 116bf215546Sopenharmony_cilower_color(lower_drawpixels_state *state, nir_intrinsic_instr *intr) 117bf215546Sopenharmony_ci{ 118bf215546Sopenharmony_ci nir_builder *b = &state->b; 119bf215546Sopenharmony_ci nir_ssa_def *texcoord; 120bf215546Sopenharmony_ci nir_tex_instr *tex; 121bf215546Sopenharmony_ci nir_ssa_def *def; 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci assert(intr->dest.is_ssa); 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci b->cursor = nir_before_instr(&intr->instr); 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci texcoord = get_texcoord(state); 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci const struct glsl_type *sampler2D = 130bf215546Sopenharmony_ci glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, GLSL_TYPE_FLOAT); 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci if (!state->tex) { 133bf215546Sopenharmony_ci state->tex = 134bf215546Sopenharmony_ci nir_variable_create(b->shader, nir_var_uniform, sampler2D, "drawpix"); 135bf215546Sopenharmony_ci state->tex->data.binding = state->options->drawpix_sampler; 136bf215546Sopenharmony_ci state->tex->data.explicit_binding = true; 137bf215546Sopenharmony_ci state->tex->data.how_declared = nir_var_hidden; 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci nir_deref_instr *tex_deref = nir_build_deref_var(b, state->tex); 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci /* replace load_var(gl_Color) w/ texture sample: 143bf215546Sopenharmony_ci * TEX def, texcoord, drawpix_sampler, 2D 144bf215546Sopenharmony_ci */ 145bf215546Sopenharmony_ci tex = nir_tex_instr_create(state->shader, 3); 146bf215546Sopenharmony_ci tex->op = nir_texop_tex; 147bf215546Sopenharmony_ci tex->sampler_dim = GLSL_SAMPLER_DIM_2D; 148bf215546Sopenharmony_ci tex->coord_components = 2; 149bf215546Sopenharmony_ci tex->dest_type = nir_type_float32; 150bf215546Sopenharmony_ci tex->src[0].src_type = nir_tex_src_texture_deref; 151bf215546Sopenharmony_ci tex->src[0].src = nir_src_for_ssa(&tex_deref->dest.ssa); 152bf215546Sopenharmony_ci tex->src[1].src_type = nir_tex_src_sampler_deref; 153bf215546Sopenharmony_ci tex->src[1].src = nir_src_for_ssa(&tex_deref->dest.ssa); 154bf215546Sopenharmony_ci tex->src[2].src_type = nir_tex_src_coord; 155bf215546Sopenharmony_ci tex->src[2].src = 156bf215546Sopenharmony_ci nir_src_for_ssa(nir_channels(b, texcoord, 157bf215546Sopenharmony_ci (1 << tex->coord_components) - 1)); 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL); 160bf215546Sopenharmony_ci nir_builder_instr_insert(b, &tex->instr); 161bf215546Sopenharmony_ci def = &tex->dest.ssa; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci /* Apply the scale and bias. */ 164bf215546Sopenharmony_ci if (state->options->scale_and_bias) { 165bf215546Sopenharmony_ci /* MAD def, def, scale, bias; */ 166bf215546Sopenharmony_ci def = nir_ffma(b, def, get_scale(state), get_bias(state)); 167bf215546Sopenharmony_ci } 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci if (state->options->pixel_maps) { 170bf215546Sopenharmony_ci if (!state->pixelmap) { 171bf215546Sopenharmony_ci state->pixelmap = nir_variable_create(b->shader, nir_var_uniform, 172bf215546Sopenharmony_ci sampler2D, "pixelmap"); 173bf215546Sopenharmony_ci state->pixelmap->data.binding = state->options->pixelmap_sampler; 174bf215546Sopenharmony_ci state->pixelmap->data.explicit_binding = true; 175bf215546Sopenharmony_ci state->pixelmap->data.how_declared = nir_var_hidden; 176bf215546Sopenharmony_ci } 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci nir_deref_instr *pixelmap_deref = 179bf215546Sopenharmony_ci nir_build_deref_var(b, state->pixelmap); 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci /* do four pixel map look-ups with two TEX instructions: */ 182bf215546Sopenharmony_ci nir_ssa_def *def_xy, *def_zw; 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci /* TEX def.xy, def.xyyy, pixelmap_sampler, 2D; */ 185bf215546Sopenharmony_ci tex = nir_tex_instr_create(state->shader, 3); 186bf215546Sopenharmony_ci tex->op = nir_texop_tex; 187bf215546Sopenharmony_ci tex->sampler_dim = GLSL_SAMPLER_DIM_2D; 188bf215546Sopenharmony_ci tex->coord_components = 2; 189bf215546Sopenharmony_ci tex->sampler_index = state->options->pixelmap_sampler; 190bf215546Sopenharmony_ci tex->texture_index = state->options->pixelmap_sampler; 191bf215546Sopenharmony_ci tex->dest_type = nir_type_float32; 192bf215546Sopenharmony_ci tex->src[0].src_type = nir_tex_src_texture_deref; 193bf215546Sopenharmony_ci tex->src[0].src = nir_src_for_ssa(&pixelmap_deref->dest.ssa); 194bf215546Sopenharmony_ci tex->src[1].src_type = nir_tex_src_sampler_deref; 195bf215546Sopenharmony_ci tex->src[1].src = nir_src_for_ssa(&pixelmap_deref->dest.ssa); 196bf215546Sopenharmony_ci tex->src[2].src_type = nir_tex_src_coord; 197bf215546Sopenharmony_ci tex->src[2].src = nir_src_for_ssa(nir_channels(b, def, 0x3)); 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL); 200bf215546Sopenharmony_ci nir_builder_instr_insert(b, &tex->instr); 201bf215546Sopenharmony_ci def_xy = &tex->dest.ssa; 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci /* TEX def.zw, def.zwww, pixelmap_sampler, 2D; */ 204bf215546Sopenharmony_ci tex = nir_tex_instr_create(state->shader, 1); 205bf215546Sopenharmony_ci tex->op = nir_texop_tex; 206bf215546Sopenharmony_ci tex->sampler_dim = GLSL_SAMPLER_DIM_2D; 207bf215546Sopenharmony_ci tex->coord_components = 2; 208bf215546Sopenharmony_ci tex->sampler_index = state->options->pixelmap_sampler; 209bf215546Sopenharmony_ci tex->dest_type = nir_type_float32; 210bf215546Sopenharmony_ci tex->src[0].src_type = nir_tex_src_coord; 211bf215546Sopenharmony_ci tex->src[0].src = nir_src_for_ssa(nir_channels(b, def, 0xc)); 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL); 214bf215546Sopenharmony_ci nir_builder_instr_insert(b, &tex->instr); 215bf215546Sopenharmony_ci def_zw = &tex->dest.ssa; 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci /* def = vec4(def.xy, def.zw); */ 218bf215546Sopenharmony_ci def = nir_vec4(b, 219bf215546Sopenharmony_ci nir_channel(b, def_xy, 0), 220bf215546Sopenharmony_ci nir_channel(b, def_xy, 1), 221bf215546Sopenharmony_ci nir_channel(b, def_zw, 0), 222bf215546Sopenharmony_ci nir_channel(b, def_zw, 1)); 223bf215546Sopenharmony_ci } 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses(&intr->dest.ssa, def); 226bf215546Sopenharmony_ci} 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_cistatic void 229bf215546Sopenharmony_cilower_texcoord(lower_drawpixels_state *state, nir_intrinsic_instr *intr) 230bf215546Sopenharmony_ci{ 231bf215546Sopenharmony_ci state->b.cursor = nir_before_instr(&intr->instr); 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci nir_ssa_def *texcoord_const = get_texcoord_const(state); 234bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses(&intr->dest.ssa, texcoord_const); 235bf215546Sopenharmony_ci} 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_cistatic bool 238bf215546Sopenharmony_cilower_drawpixels_block(lower_drawpixels_state *state, nir_block *block) 239bf215546Sopenharmony_ci{ 240bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 241bf215546Sopenharmony_ci if (instr->type == nir_instr_type_intrinsic) { 242bf215546Sopenharmony_ci nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci switch (intr->intrinsic) { 245bf215546Sopenharmony_ci case nir_intrinsic_load_deref: { 246bf215546Sopenharmony_ci nir_deref_instr *deref = nir_src_as_deref(intr->src[0]); 247bf215546Sopenharmony_ci nir_variable *var = nir_deref_instr_get_variable(deref); 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci if (var->data.location == VARYING_SLOT_COL0) { 250bf215546Sopenharmony_ci /* gl_Color should not have array/struct derefs: */ 251bf215546Sopenharmony_ci assert(deref->deref_type == nir_deref_type_var); 252bf215546Sopenharmony_ci lower_color(state, intr); 253bf215546Sopenharmony_ci } else if (var->data.location == VARYING_SLOT_TEX0) { 254bf215546Sopenharmony_ci /* gl_TexCoord should not have array/struct derefs: */ 255bf215546Sopenharmony_ci assert(deref->deref_type == nir_deref_type_var); 256bf215546Sopenharmony_ci lower_texcoord(state, intr); 257bf215546Sopenharmony_ci } 258bf215546Sopenharmony_ci break; 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci case nir_intrinsic_load_color0: 262bf215546Sopenharmony_ci lower_color(state, intr); 263bf215546Sopenharmony_ci break; 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci case nir_intrinsic_load_interpolated_input: 266bf215546Sopenharmony_ci case nir_intrinsic_load_input: { 267bf215546Sopenharmony_ci if (nir_intrinsic_io_semantics(intr).location == VARYING_SLOT_TEX0) 268bf215546Sopenharmony_ci lower_texcoord(state, intr); 269bf215546Sopenharmony_ci break; 270bf215546Sopenharmony_ci } 271bf215546Sopenharmony_ci default: 272bf215546Sopenharmony_ci break; 273bf215546Sopenharmony_ci } 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci return true; 278bf215546Sopenharmony_ci} 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_cistatic void 281bf215546Sopenharmony_cilower_drawpixels_impl(lower_drawpixels_state *state, nir_function_impl *impl) 282bf215546Sopenharmony_ci{ 283bf215546Sopenharmony_ci nir_builder_init(&state->b, impl); 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci nir_foreach_block(block, impl) { 286bf215546Sopenharmony_ci lower_drawpixels_block(state, block); 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_block_index | 289bf215546Sopenharmony_ci nir_metadata_dominance); 290bf215546Sopenharmony_ci} 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_civoid 293bf215546Sopenharmony_cinir_lower_drawpixels(nir_shader *shader, 294bf215546Sopenharmony_ci const nir_lower_drawpixels_options *options) 295bf215546Sopenharmony_ci{ 296bf215546Sopenharmony_ci lower_drawpixels_state state = { 297bf215546Sopenharmony_ci .options = options, 298bf215546Sopenharmony_ci .shader = shader, 299bf215546Sopenharmony_ci }; 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci assert(shader->info.stage == MESA_SHADER_FRAGMENT); 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci nir_foreach_function(function, shader) { 304bf215546Sopenharmony_ci if (function->impl) 305bf215546Sopenharmony_ci lower_drawpixels_impl(&state, function->impl); 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci} 308