1/* 2 * Copyright © 2019 Red Hat Inc. 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 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24/** 25 * \file 26 * 27 * Lower image operations by turning the image_deref_* into a image_* on an 28 * index number or bindless_image_* intrinsic on a load_deref of the previous 29 * deref source. All applicable indicies are also set so that fetching the 30 * variable in the backend wouldn't be needed anymore. 31 */ 32 33#include "compiler/nir/nir.h" 34#include "compiler/nir/nir_builder.h" 35#include "compiler/nir/nir_deref.h" 36 37#include "compiler/glsl/gl_nir.h" 38 39static void 40type_size_align_1(const struct glsl_type *type, unsigned *size, unsigned *align) 41{ 42 unsigned s; 43 44 if (glsl_type_is_array(type)) 45 s = glsl_get_aoa_size(type); 46 else 47 s = 1; 48 49 *size = s; 50 *align = s; 51} 52 53static bool 54lower_impl(nir_builder *b, nir_instr *instr, bool bindless_only) 55{ 56 if (instr->type != nir_instr_type_intrinsic) 57 return false; 58 59 nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr); 60 61 nir_deref_instr *deref; 62 nir_variable *var; 63 64 switch (intrinsic->intrinsic) { 65 case nir_intrinsic_image_deref_atomic_add: 66 case nir_intrinsic_image_deref_atomic_imin: 67 case nir_intrinsic_image_deref_atomic_umin: 68 case nir_intrinsic_image_deref_atomic_imax: 69 case nir_intrinsic_image_deref_atomic_umax: 70 case nir_intrinsic_image_deref_atomic_and: 71 case nir_intrinsic_image_deref_atomic_or: 72 case nir_intrinsic_image_deref_atomic_xor: 73 case nir_intrinsic_image_deref_atomic_exchange: 74 case nir_intrinsic_image_deref_atomic_comp_swap: 75 case nir_intrinsic_image_deref_atomic_fadd: 76 case nir_intrinsic_image_deref_atomic_inc_wrap: 77 case nir_intrinsic_image_deref_atomic_dec_wrap: 78 case nir_intrinsic_image_deref_load: 79 case nir_intrinsic_image_deref_samples: 80 case nir_intrinsic_image_deref_size: 81 case nir_intrinsic_image_deref_store: { 82 deref = nir_src_as_deref(intrinsic->src[0]); 83 var = nir_deref_instr_get_variable(deref); 84 break; 85 } 86 default: 87 return false; 88 } 89 90 bool bindless = var->data.mode != nir_var_image || var->data.bindless; 91 if (bindless_only && !bindless) 92 return false; 93 94 b->cursor = nir_before_instr(instr); 95 96 nir_ssa_def *src; 97 if (bindless) { 98 src = nir_load_deref(b, deref); 99 } else { 100 src = nir_iadd_imm(b, 101 nir_build_deref_offset(b, deref, type_size_align_1), 102 var->data.driver_location); 103 } 104 nir_rewrite_image_intrinsic(intrinsic, src, bindless); 105 106 return true; 107} 108 109bool 110gl_nir_lower_images(nir_shader *shader, bool bindless_only) 111{ 112 bool progress = false; 113 114 nir_foreach_function(function, shader) { 115 if (function->impl) { 116 nir_builder b; 117 nir_builder_init(&b, function->impl); 118 119 bool impl_progress = false; 120 nir_foreach_block(block, function->impl) 121 nir_foreach_instr(instr, block) 122 impl_progress |= lower_impl(&b, instr, bindless_only); 123 124 if (impl_progress) { 125 nir_metadata_preserve(function->impl, 126 nir_metadata_block_index | 127 nir_metadata_dominance); 128 progress = true; 129 } else { 130 nir_metadata_preserve(function->impl, nir_metadata_all); 131 } 132 } 133 } 134 135 return progress; 136} 137