17ec681f3Smrg/* 27ec681f3Smrg * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. 37ec681f3Smrg * Copyright (C) 2008 VMware, Inc. All Rights Reserved. 47ec681f3Smrg * Copyright © 2014 Intel Corporation 57ec681f3Smrg * 67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 87ec681f3Smrg * to deal in the Software without restriction, including without limitation 97ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 117ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 127ec681f3Smrg * 137ec681f3Smrg * The above copyright notice and this permission notice (including the next 147ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 157ec681f3Smrg * Software. 167ec681f3Smrg * 177ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 187ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 207ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 217ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 227ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 237ec681f3Smrg * DEALINGS IN THE SOFTWARE. 247ec681f3Smrg */ 257ec681f3Smrg 267ec681f3Smrg#include "nir/nir.h" 277ec681f3Smrg#include "nir_builder.h" 287ec681f3Smrg 297ec681f3Smrgstatic void 307ec681f3Smrglower_tex_src_to_offset(nir_builder *b, 317ec681f3Smrg nir_tex_instr *instr, unsigned src_idx) 327ec681f3Smrg{ 337ec681f3Smrg nir_ssa_def *index = NULL; 347ec681f3Smrg unsigned base_index = 0; 357ec681f3Smrg unsigned array_elements = 1; 367ec681f3Smrg nir_tex_src *src = &instr->src[src_idx]; 377ec681f3Smrg bool is_sampler = src->src_type == nir_tex_src_sampler_deref; 387ec681f3Smrg 397ec681f3Smrg /* We compute first the offsets */ 407ec681f3Smrg nir_deref_instr *deref = nir_instr_as_deref(src->src.ssa->parent_instr); 417ec681f3Smrg while (deref->deref_type != nir_deref_type_var) { 427ec681f3Smrg assert(deref->parent.is_ssa); 437ec681f3Smrg nir_deref_instr *parent = 447ec681f3Smrg nir_instr_as_deref(deref->parent.ssa->parent_instr); 457ec681f3Smrg 467ec681f3Smrg assert(deref->deref_type == nir_deref_type_array); 477ec681f3Smrg 487ec681f3Smrg if (nir_src_is_const(deref->arr.index) && index == NULL) { 497ec681f3Smrg /* We're still building a direct index */ 507ec681f3Smrg unsigned index_in_array = nir_src_as_uint(deref->arr.index); 517ec681f3Smrg 527ec681f3Smrg /* Section 5.11 (Out-of-Bounds Accesses) of the GLSL 4.60 spec says: 537ec681f3Smrg * 547ec681f3Smrg * In the subsections described above for array, vector, matrix and 557ec681f3Smrg * structure accesses, any out-of-bounds access produced undefined 567ec681f3Smrg * behavior.... Out-of-bounds reads return undefined values, which 577ec681f3Smrg * include values from other variables of the active program or zero. 587ec681f3Smrg * 597ec681f3Smrg * Robustness extensions suggest to return zero on out-of-bounds 607ec681f3Smrg * accesses, however it's not applicable to the arrays of samplers, 617ec681f3Smrg * so just clamp the index. 627ec681f3Smrg * 637ec681f3Smrg * Otherwise instr->sampler_index or instr->texture_index would be out 647ec681f3Smrg * of bounds, and they are used as an index to arrays of driver state. 657ec681f3Smrg */ 667ec681f3Smrg if (index_in_array < glsl_array_size(parent->type)) { 677ec681f3Smrg base_index += index_in_array * array_elements; 687ec681f3Smrg } else { 697ec681f3Smrg base_index = glsl_array_size(parent->type) - 1; 707ec681f3Smrg } 717ec681f3Smrg } else { 727ec681f3Smrg if (index == NULL) { 737ec681f3Smrg /* We used to be direct but not anymore */ 747ec681f3Smrg index = nir_imm_int(b, base_index); 757ec681f3Smrg base_index = 0; 767ec681f3Smrg } 777ec681f3Smrg 787ec681f3Smrg index = nir_iadd(b, index, 797ec681f3Smrg nir_imul(b, nir_imm_int(b, array_elements), 807ec681f3Smrg nir_ssa_for_src(b, deref->arr.index, 1))); 817ec681f3Smrg } 827ec681f3Smrg 837ec681f3Smrg array_elements *= glsl_get_length(parent->type); 847ec681f3Smrg 857ec681f3Smrg deref = parent; 867ec681f3Smrg } 877ec681f3Smrg 887ec681f3Smrg if (index) 897ec681f3Smrg index = nir_umin(b, index, nir_imm_int(b, array_elements - 1)); 907ec681f3Smrg 917ec681f3Smrg /* We hit the deref_var. This is the end of the line */ 927ec681f3Smrg assert(deref->deref_type == nir_deref_type_var); 937ec681f3Smrg 947ec681f3Smrg base_index += deref->var->data.binding; 957ec681f3Smrg 967ec681f3Smrg /* We have the offsets, we apply them, rewriting the source or removing 977ec681f3Smrg * instr if needed 987ec681f3Smrg */ 997ec681f3Smrg if (index) { 1007ec681f3Smrg nir_instr_rewrite_src(&instr->instr, &src->src, 1017ec681f3Smrg nir_src_for_ssa(index)); 1027ec681f3Smrg 1037ec681f3Smrg src->src_type = is_sampler ? 1047ec681f3Smrg nir_tex_src_sampler_offset : 1057ec681f3Smrg nir_tex_src_texture_offset; 1067ec681f3Smrg } else { 1077ec681f3Smrg nir_tex_instr_remove_src(instr, src_idx); 1087ec681f3Smrg } 1097ec681f3Smrg 1107ec681f3Smrg if (is_sampler) { 1117ec681f3Smrg instr->sampler_index = base_index; 1127ec681f3Smrg } else { 1137ec681f3Smrg instr->texture_index = base_index; 1147ec681f3Smrg } 1157ec681f3Smrg} 1167ec681f3Smrg 1177ec681f3Smrgstatic bool 1187ec681f3Smrglower_sampler(nir_builder *b, nir_tex_instr *instr) 1197ec681f3Smrg{ 1207ec681f3Smrg int texture_idx = 1217ec681f3Smrg nir_tex_instr_src_index(instr, nir_tex_src_texture_deref); 1227ec681f3Smrg 1237ec681f3Smrg if (texture_idx >= 0) { 1247ec681f3Smrg b->cursor = nir_before_instr(&instr->instr); 1257ec681f3Smrg 1267ec681f3Smrg lower_tex_src_to_offset(b, instr, texture_idx); 1277ec681f3Smrg } 1287ec681f3Smrg 1297ec681f3Smrg int sampler_idx = 1307ec681f3Smrg nir_tex_instr_src_index(instr, nir_tex_src_sampler_deref); 1317ec681f3Smrg 1327ec681f3Smrg if (sampler_idx >= 0) { 1337ec681f3Smrg lower_tex_src_to_offset(b, instr, sampler_idx); 1347ec681f3Smrg } 1357ec681f3Smrg 1367ec681f3Smrg if (texture_idx < 0 && sampler_idx < 0) 1377ec681f3Smrg return false; 1387ec681f3Smrg 1397ec681f3Smrg return true; 1407ec681f3Smrg} 1417ec681f3Smrg 1427ec681f3Smrgstatic bool 1437ec681f3Smrglower_impl(nir_function_impl *impl) 1447ec681f3Smrg{ 1457ec681f3Smrg nir_builder b; 1467ec681f3Smrg nir_builder_init(&b, impl); 1477ec681f3Smrg bool progress = false; 1487ec681f3Smrg 1497ec681f3Smrg nir_foreach_block(block, impl) { 1507ec681f3Smrg nir_foreach_instr(instr, block) { 1517ec681f3Smrg if (instr->type == nir_instr_type_tex) 1527ec681f3Smrg progress |= lower_sampler(&b, nir_instr_as_tex(instr)); 1537ec681f3Smrg } 1547ec681f3Smrg } 1557ec681f3Smrg 1567ec681f3Smrg if (progress) { 1577ec681f3Smrg nir_metadata_preserve(impl, nir_metadata_block_index | 1587ec681f3Smrg nir_metadata_dominance); 1597ec681f3Smrg } else { 1607ec681f3Smrg nir_metadata_preserve(impl, nir_metadata_all); 1617ec681f3Smrg } 1627ec681f3Smrg 1637ec681f3Smrg return progress; 1647ec681f3Smrg} 1657ec681f3Smrg 1667ec681f3Smrgbool 1677ec681f3Smrgnir_lower_samplers(nir_shader *shader) 1687ec681f3Smrg{ 1697ec681f3Smrg bool progress = false; 1707ec681f3Smrg 1717ec681f3Smrg /* Next, lower derefs to offsets. */ 1727ec681f3Smrg nir_foreach_function(function, shader) { 1737ec681f3Smrg if (function->impl) 1747ec681f3Smrg progress |= lower_impl(function->impl); 1757ec681f3Smrg } 1767ec681f3Smrg 1777ec681f3Smrg return progress; 1787ec681f3Smrg} 179