101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2015 Red Hat 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2001e04c3fSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2101e04c3fSmrg * SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg#include "nir.h" 2501e04c3fSmrg#include "nir_builder.h" 2601e04c3fSmrg 2701e04c3fSmrg/* Lower glDrawPixels(). 2801e04c3fSmrg * 2901e04c3fSmrg * This is based on the logic in st_get_drawpix_shader() in TGSI compiler. 3001e04c3fSmrg * 3101e04c3fSmrg * Run before nir_lower_io. 3201e04c3fSmrg */ 3301e04c3fSmrg 3401e04c3fSmrgtypedef struct { 3501e04c3fSmrg const nir_lower_drawpixels_options *options; 3601e04c3fSmrg nir_shader *shader; 3701e04c3fSmrg nir_builder b; 387ec681f3Smrg nir_variable *texcoord, *texcoord_const, *scale, *bias, *tex, *pixelmap; 3901e04c3fSmrg} lower_drawpixels_state; 4001e04c3fSmrg 4101e04c3fSmrgstatic nir_ssa_def * 4201e04c3fSmrgget_texcoord(lower_drawpixels_state *state) 4301e04c3fSmrg{ 4401e04c3fSmrg if (state->texcoord == NULL) { 4501e04c3fSmrg nir_variable *texcoord = NULL; 4601e04c3fSmrg 4701e04c3fSmrg /* find gl_TexCoord, if it exists: */ 487ec681f3Smrg nir_foreach_shader_in_variable(var, state->shader) { 4901e04c3fSmrg if (var->data.location == VARYING_SLOT_TEX0) { 5001e04c3fSmrg texcoord = var; 5101e04c3fSmrg break; 5201e04c3fSmrg } 5301e04c3fSmrg } 5401e04c3fSmrg 5501e04c3fSmrg /* otherwise create it: */ 5601e04c3fSmrg if (texcoord == NULL) { 5701e04c3fSmrg texcoord = nir_variable_create(state->shader, 5801e04c3fSmrg nir_var_shader_in, 5901e04c3fSmrg glsl_vec4_type(), 6001e04c3fSmrg "gl_TexCoord"); 6101e04c3fSmrg texcoord->data.location = VARYING_SLOT_TEX0; 6201e04c3fSmrg } 6301e04c3fSmrg 6401e04c3fSmrg state->texcoord = texcoord; 6501e04c3fSmrg } 6601e04c3fSmrg return nir_load_var(&state->b, state->texcoord); 6701e04c3fSmrg} 6801e04c3fSmrg 6901e04c3fSmrgstatic nir_variable * 7001e04c3fSmrgcreate_uniform(nir_shader *shader, const char *name, 7101e04c3fSmrg const gl_state_index16 state_tokens[STATE_LENGTH]) 7201e04c3fSmrg{ 7301e04c3fSmrg nir_variable *var = nir_variable_create(shader, 7401e04c3fSmrg nir_var_uniform, 7501e04c3fSmrg glsl_vec4_type(), 7601e04c3fSmrg name); 7701e04c3fSmrg var->num_state_slots = 1; 7801e04c3fSmrg var->state_slots = ralloc_array(var, nir_state_slot, 1); 7901e04c3fSmrg memcpy(var->state_slots[0].tokens, state_tokens, 8001e04c3fSmrg sizeof(var->state_slots[0].tokens)); 8101e04c3fSmrg return var; 8201e04c3fSmrg} 8301e04c3fSmrg 8401e04c3fSmrgstatic nir_ssa_def * 8501e04c3fSmrgget_scale(lower_drawpixels_state *state) 8601e04c3fSmrg{ 8701e04c3fSmrg if (state->scale == NULL) { 8801e04c3fSmrg state->scale = create_uniform(state->shader, "gl_PTscale", 8901e04c3fSmrg state->options->scale_state_tokens); 9001e04c3fSmrg } 9101e04c3fSmrg return nir_load_var(&state->b, state->scale); 9201e04c3fSmrg} 9301e04c3fSmrg 9401e04c3fSmrgstatic nir_ssa_def * 9501e04c3fSmrgget_bias(lower_drawpixels_state *state) 9601e04c3fSmrg{ 9701e04c3fSmrg if (state->bias == NULL) { 9801e04c3fSmrg state->bias = create_uniform(state->shader, "gl_PTbias", 9901e04c3fSmrg state->options->bias_state_tokens); 10001e04c3fSmrg } 10101e04c3fSmrg return nir_load_var(&state->b, state->bias); 10201e04c3fSmrg} 10301e04c3fSmrg 10401e04c3fSmrgstatic nir_ssa_def * 10501e04c3fSmrgget_texcoord_const(lower_drawpixels_state *state) 10601e04c3fSmrg{ 1077ec681f3Smrg if (state->texcoord_const == NULL) { 1087ec681f3Smrg state->texcoord_const = create_uniform(state->shader, 1097ec681f3Smrg "gl_MultiTexCoord0", 11001e04c3fSmrg state->options->texcoord_state_tokens); 11101e04c3fSmrg } 1127ec681f3Smrg return nir_load_var(&state->b, state->texcoord_const); 11301e04c3fSmrg} 11401e04c3fSmrg 11501e04c3fSmrgstatic void 11601e04c3fSmrglower_color(lower_drawpixels_state *state, nir_intrinsic_instr *intr) 11701e04c3fSmrg{ 11801e04c3fSmrg nir_builder *b = &state->b; 11901e04c3fSmrg nir_ssa_def *texcoord; 12001e04c3fSmrg nir_tex_instr *tex; 12101e04c3fSmrg nir_ssa_def *def; 12201e04c3fSmrg 12301e04c3fSmrg assert(intr->dest.is_ssa); 12401e04c3fSmrg 12501e04c3fSmrg b->cursor = nir_before_instr(&intr->instr); 12601e04c3fSmrg 12701e04c3fSmrg texcoord = get_texcoord(state); 12801e04c3fSmrg 12901e04c3fSmrg const struct glsl_type *sampler2D = 13001e04c3fSmrg glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, GLSL_TYPE_FLOAT); 13101e04c3fSmrg 13201e04c3fSmrg if (!state->tex) { 13301e04c3fSmrg state->tex = 13401e04c3fSmrg nir_variable_create(b->shader, nir_var_uniform, sampler2D, "drawpix"); 13501e04c3fSmrg state->tex->data.binding = state->options->drawpix_sampler; 1367e102996Smaya state->tex->data.explicit_binding = true; 1377e102996Smaya state->tex->data.how_declared = nir_var_hidden; 13801e04c3fSmrg } 13901e04c3fSmrg 1407e102996Smaya nir_deref_instr *tex_deref = nir_build_deref_var(b, state->tex); 1417e102996Smaya 14201e04c3fSmrg /* replace load_var(gl_Color) w/ texture sample: 14301e04c3fSmrg * TEX def, texcoord, drawpix_sampler, 2D 14401e04c3fSmrg */ 1457e102996Smaya tex = nir_tex_instr_create(state->shader, 3); 14601e04c3fSmrg tex->op = nir_texop_tex; 14701e04c3fSmrg tex->sampler_dim = GLSL_SAMPLER_DIM_2D; 14801e04c3fSmrg tex->coord_components = 2; 1497ec681f3Smrg tex->dest_type = nir_type_float32; 1507e102996Smaya tex->src[0].src_type = nir_tex_src_texture_deref; 1517e102996Smaya tex->src[0].src = nir_src_for_ssa(&tex_deref->dest.ssa); 1527e102996Smaya tex->src[1].src_type = nir_tex_src_sampler_deref; 1537e102996Smaya tex->src[1].src = nir_src_for_ssa(&tex_deref->dest.ssa); 1547e102996Smaya tex->src[2].src_type = nir_tex_src_coord; 1557e102996Smaya tex->src[2].src = 15601e04c3fSmrg nir_src_for_ssa(nir_channels(b, texcoord, 15701e04c3fSmrg (1 << tex->coord_components) - 1)); 15801e04c3fSmrg 15901e04c3fSmrg nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL); 16001e04c3fSmrg nir_builder_instr_insert(b, &tex->instr); 16101e04c3fSmrg def = &tex->dest.ssa; 16201e04c3fSmrg 16301e04c3fSmrg /* Apply the scale and bias. */ 16401e04c3fSmrg if (state->options->scale_and_bias) { 16501e04c3fSmrg /* MAD def, def, scale, bias; */ 16601e04c3fSmrg def = nir_ffma(b, def, get_scale(state), get_bias(state)); 16701e04c3fSmrg } 16801e04c3fSmrg 16901e04c3fSmrg if (state->options->pixel_maps) { 17001e04c3fSmrg if (!state->pixelmap) { 17101e04c3fSmrg state->pixelmap = nir_variable_create(b->shader, nir_var_uniform, 17201e04c3fSmrg sampler2D, "pixelmap"); 17301e04c3fSmrg state->pixelmap->data.binding = state->options->pixelmap_sampler; 1747e102996Smaya state->pixelmap->data.explicit_binding = true; 1757e102996Smaya state->pixelmap->data.how_declared = nir_var_hidden; 17601e04c3fSmrg } 17701e04c3fSmrg 1787e102996Smaya nir_deref_instr *pixelmap_deref = 1797e102996Smaya nir_build_deref_var(b, state->pixelmap); 1807e102996Smaya 18101e04c3fSmrg /* do four pixel map look-ups with two TEX instructions: */ 18201e04c3fSmrg nir_ssa_def *def_xy, *def_zw; 18301e04c3fSmrg 18401e04c3fSmrg /* TEX def.xy, def.xyyy, pixelmap_sampler, 2D; */ 1857e102996Smaya tex = nir_tex_instr_create(state->shader, 3); 18601e04c3fSmrg tex->op = nir_texop_tex; 18701e04c3fSmrg tex->sampler_dim = GLSL_SAMPLER_DIM_2D; 18801e04c3fSmrg tex->coord_components = 2; 18901e04c3fSmrg tex->sampler_index = state->options->pixelmap_sampler; 19001e04c3fSmrg tex->texture_index = state->options->pixelmap_sampler; 1917ec681f3Smrg tex->dest_type = nir_type_float32; 1927e102996Smaya tex->src[0].src_type = nir_tex_src_texture_deref; 1937e102996Smaya tex->src[0].src = nir_src_for_ssa(&pixelmap_deref->dest.ssa); 1947e102996Smaya tex->src[1].src_type = nir_tex_src_sampler_deref; 1957e102996Smaya tex->src[1].src = nir_src_for_ssa(&pixelmap_deref->dest.ssa); 1967e102996Smaya tex->src[2].src_type = nir_tex_src_coord; 1977e102996Smaya tex->src[2].src = nir_src_for_ssa(nir_channels(b, def, 0x3)); 19801e04c3fSmrg 19901e04c3fSmrg nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL); 20001e04c3fSmrg nir_builder_instr_insert(b, &tex->instr); 20101e04c3fSmrg def_xy = &tex->dest.ssa; 20201e04c3fSmrg 20301e04c3fSmrg /* TEX def.zw, def.zwww, pixelmap_sampler, 2D; */ 20401e04c3fSmrg tex = nir_tex_instr_create(state->shader, 1); 20501e04c3fSmrg tex->op = nir_texop_tex; 20601e04c3fSmrg tex->sampler_dim = GLSL_SAMPLER_DIM_2D; 20701e04c3fSmrg tex->coord_components = 2; 20801e04c3fSmrg tex->sampler_index = state->options->pixelmap_sampler; 2097ec681f3Smrg tex->dest_type = nir_type_float32; 21001e04c3fSmrg tex->src[0].src_type = nir_tex_src_coord; 21101e04c3fSmrg tex->src[0].src = nir_src_for_ssa(nir_channels(b, def, 0xc)); 21201e04c3fSmrg 21301e04c3fSmrg nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL); 21401e04c3fSmrg nir_builder_instr_insert(b, &tex->instr); 21501e04c3fSmrg def_zw = &tex->dest.ssa; 21601e04c3fSmrg 21701e04c3fSmrg /* def = vec4(def.xy, def.zw); */ 21801e04c3fSmrg def = nir_vec4(b, 21901e04c3fSmrg nir_channel(b, def_xy, 0), 22001e04c3fSmrg nir_channel(b, def_xy, 1), 22101e04c3fSmrg nir_channel(b, def_zw, 0), 22201e04c3fSmrg nir_channel(b, def_zw, 1)); 22301e04c3fSmrg } 22401e04c3fSmrg 2257ec681f3Smrg nir_ssa_def_rewrite_uses(&intr->dest.ssa, def); 22601e04c3fSmrg} 22701e04c3fSmrg 22801e04c3fSmrgstatic void 22901e04c3fSmrglower_texcoord(lower_drawpixels_state *state, nir_intrinsic_instr *intr) 23001e04c3fSmrg{ 23101e04c3fSmrg state->b.cursor = nir_before_instr(&intr->instr); 23201e04c3fSmrg 23301e04c3fSmrg nir_ssa_def *texcoord_const = get_texcoord_const(state); 2347ec681f3Smrg nir_ssa_def_rewrite_uses(&intr->dest.ssa, texcoord_const); 23501e04c3fSmrg} 23601e04c3fSmrg 23701e04c3fSmrgstatic bool 23801e04c3fSmrglower_drawpixels_block(lower_drawpixels_state *state, nir_block *block) 23901e04c3fSmrg{ 24001e04c3fSmrg nir_foreach_instr_safe(instr, block) { 24101e04c3fSmrg if (instr->type == nir_instr_type_intrinsic) { 24201e04c3fSmrg nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); 2437ec681f3Smrg 2447ec681f3Smrg switch (intr->intrinsic) { 2457ec681f3Smrg case nir_intrinsic_load_deref: { 24601e04c3fSmrg nir_deref_instr *deref = nir_src_as_deref(intr->src[0]); 24701e04c3fSmrg nir_variable *var = nir_deref_instr_get_variable(deref); 24801e04c3fSmrg 24901e04c3fSmrg if (var->data.location == VARYING_SLOT_COL0) { 25001e04c3fSmrg /* gl_Color should not have array/struct derefs: */ 25101e04c3fSmrg assert(deref->deref_type == nir_deref_type_var); 25201e04c3fSmrg lower_color(state, intr); 25301e04c3fSmrg } else if (var->data.location == VARYING_SLOT_TEX0) { 25401e04c3fSmrg /* gl_TexCoord should not have array/struct derefs: */ 25501e04c3fSmrg assert(deref->deref_type == nir_deref_type_var); 25601e04c3fSmrg lower_texcoord(state, intr); 25701e04c3fSmrg } 2587ec681f3Smrg break; 2597ec681f3Smrg } 2607ec681f3Smrg 2617ec681f3Smrg case nir_intrinsic_load_color0: 2627ec681f3Smrg lower_color(state, intr); 2637ec681f3Smrg break; 2647ec681f3Smrg 2657ec681f3Smrg case nir_intrinsic_load_interpolated_input: 2667ec681f3Smrg case nir_intrinsic_load_input: { 2677ec681f3Smrg if (nir_intrinsic_io_semantics(intr).location == VARYING_SLOT_TEX0) 2687ec681f3Smrg lower_texcoord(state, intr); 2697ec681f3Smrg break; 2707ec681f3Smrg } 2717ec681f3Smrg default: 2727ec681f3Smrg break; 27301e04c3fSmrg } 27401e04c3fSmrg } 27501e04c3fSmrg } 27601e04c3fSmrg 27701e04c3fSmrg return true; 27801e04c3fSmrg} 27901e04c3fSmrg 28001e04c3fSmrgstatic void 28101e04c3fSmrglower_drawpixels_impl(lower_drawpixels_state *state, nir_function_impl *impl) 28201e04c3fSmrg{ 28301e04c3fSmrg nir_builder_init(&state->b, impl); 28401e04c3fSmrg 28501e04c3fSmrg nir_foreach_block(block, impl) { 28601e04c3fSmrg lower_drawpixels_block(state, block); 28701e04c3fSmrg } 28801e04c3fSmrg nir_metadata_preserve(impl, nir_metadata_block_index | 28901e04c3fSmrg nir_metadata_dominance); 29001e04c3fSmrg} 29101e04c3fSmrg 29201e04c3fSmrgvoid 29301e04c3fSmrgnir_lower_drawpixels(nir_shader *shader, 29401e04c3fSmrg const nir_lower_drawpixels_options *options) 29501e04c3fSmrg{ 29601e04c3fSmrg lower_drawpixels_state state = { 29701e04c3fSmrg .options = options, 29801e04c3fSmrg .shader = shader, 29901e04c3fSmrg }; 30001e04c3fSmrg 30101e04c3fSmrg assert(shader->info.stage == MESA_SHADER_FRAGMENT); 30201e04c3fSmrg 30301e04c3fSmrg nir_foreach_function(function, shader) { 30401e04c3fSmrg if (function->impl) 30501e04c3fSmrg lower_drawpixels_impl(&state, function->impl); 30601e04c3fSmrg } 30701e04c3fSmrg} 308