mirror of OpenBSD xenocara tree github.com/openbsd/xenocara
openbsd
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at jcs 225 lines 6.9 kB view raw
1/* 2 * Copyright 2023 Valve Corpoation 3 * Copyright 2020 Raspberry Pi Ltd 4 * SPDX-License-Identifier: MIT 5 */ 6 7#include "nir.h" 8#include "nir_builder.h" 9#include "nir_intrinsics_indices.h" 10 11static void 12rewrite_offset(nir_builder *b, nir_intrinsic_instr *instr, 13 uint32_t type_sz, uint32_t offset_src, nir_def *size) 14{ 15 /* Compute the maximum offset being accessed and if it is out of bounds 16 * rewrite it to 0 to ensure the access is within bounds. 17 */ 18 const uint32_t access_size = instr->num_components * type_sz; 19 nir_def *max_access_offset = 20 nir_iadd_imm(b, instr->src[offset_src].ssa, access_size - 1); 21 nir_def *offset = 22 nir_bcsel(b, nir_uge(b, max_access_offset, size), nir_imm_int(b, 0), 23 instr->src[offset_src].ssa); 24 25 /* Rewrite offset */ 26 nir_src_rewrite(&instr->src[offset_src], offset); 27} 28 29/* 30 * Wrap a intrinsic in an if, predicated on a "valid" condition. If the 31 * intrinsic produces a destination, it will be zero in the invalid case. 32 */ 33static void 34wrap_in_if(nir_builder *b, nir_intrinsic_instr *instr, nir_def *valid) 35{ 36 bool has_dest = nir_intrinsic_infos[instr->intrinsic].has_dest; 37 nir_def *res, *zero; 38 39 if (has_dest) { 40 zero = nir_imm_zero(b, instr->def.num_components, 41 instr->def.bit_size); 42 } 43 44 nir_push_if(b, valid); 45 { 46 nir_instr *orig = nir_instr_clone(b->shader, &instr->instr); 47 nir_builder_instr_insert(b, orig); 48 49 if (has_dest) 50 res = &nir_instr_as_intrinsic(orig)->def; 51 } 52 nir_pop_if(b, NULL); 53 54 if (has_dest) 55 nir_def_rewrite_uses(&instr->def, nir_if_phi(b, res, zero)); 56 57 /* We've cloned and wrapped, so drop original instruction */ 58 nir_instr_remove(&instr->instr); 59} 60 61static void 62lower_buffer_load(nir_builder *b, nir_intrinsic_instr *instr) 63{ 64 uint32_t type_sz = instr->def.bit_size / 8; 65 nir_def *size; 66 nir_def *index = instr->src[0].ssa; 67 68 if (instr->intrinsic == nir_intrinsic_load_ubo) { 69 size = nir_get_ubo_size(b, 32, index); 70 } else { 71 size = nir_get_ssbo_size(b, index); 72 } 73 74 rewrite_offset(b, instr, type_sz, 1, size); 75} 76 77static void 78lower_buffer_store(nir_builder *b, nir_intrinsic_instr *instr) 79{ 80 uint32_t type_sz = nir_src_bit_size(instr->src[0]) / 8; 81 rewrite_offset(b, instr, type_sz, 2, 82 nir_get_ssbo_size(b, instr->src[1].ssa)); 83} 84 85static void 86lower_buffer_atomic(nir_builder *b, nir_intrinsic_instr *instr) 87{ 88 rewrite_offset(b, instr, 4, 1, nir_get_ssbo_size(b, instr->src[0].ssa)); 89} 90 91static void 92lower_buffer_shared(nir_builder *b, nir_intrinsic_instr *instr) 93{ 94 uint32_t type_sz, offset_src; 95 if (instr->intrinsic == nir_intrinsic_load_shared) { 96 offset_src = 0; 97 type_sz = instr->def.bit_size / 8; 98 } else if (instr->intrinsic == nir_intrinsic_store_shared) { 99 offset_src = 1; 100 type_sz = nir_src_bit_size(instr->src[0]) / 8; 101 } else { 102 /* atomic */ 103 offset_src = 0; 104 type_sz = 4; 105 } 106 107 rewrite_offset(b, instr, type_sz, offset_src, 108 nir_imm_int(b, b->shader->info.shared_size)); 109} 110 111static void 112lower_image(nir_builder *b, nir_intrinsic_instr *instr, bool deref) 113{ 114 enum glsl_sampler_dim dim = nir_intrinsic_image_dim(instr); 115 uint32_t num_coords = nir_image_intrinsic_coord_components(instr); 116 bool is_array = nir_intrinsic_image_array(instr); 117 nir_def *coord = instr->src[1].ssa; 118 119 /* Get image size. imageSize for cubes returns the size of a single face. */ 120 unsigned size_components = num_coords; 121 if (dim == GLSL_SAMPLER_DIM_CUBE && !is_array) 122 size_components -= 1; 123 124 nir_def *size = nir_image_size(b, size_components, 32, 125 instr->src[0].ssa, nir_imm_int(b, 0), 126 .image_array = is_array, .image_dim = dim); 127 if (deref) { 128 nir_instr_as_intrinsic(size->parent_instr)->intrinsic = 129 nir_intrinsic_image_deref_size; 130 } 131 132 if (dim == GLSL_SAMPLER_DIM_CUBE) { 133 nir_def *z = is_array ? nir_imul_imm(b, nir_channel(b, size, 2), 6) 134 : nir_imm_int(b, 6); 135 136 size = nir_vec3(b, nir_channel(b, size, 0), nir_channel(b, size, 1), z); 137 } 138 139 nir_def *in_bounds = nir_ball(b, nir_ult(b, coord, size)); 140 141 if (dim == GLSL_SAMPLER_DIM_MS) { 142 nir_def *sample = instr->src[2].ssa; 143 nir_def *samples = nir_image_samples(b, 32, instr->src[0].ssa, 144 .image_array = is_array, .image_dim = dim); 145 if (deref) { 146 nir_instr_as_intrinsic(samples->parent_instr)->intrinsic = 147 nir_intrinsic_image_deref_samples; 148 } 149 150 in_bounds = nir_iand(b, in_bounds, nir_ult(b, sample, samples)); 151 } 152 153 /* Only execute if coordinates are in-bounds. Otherwise, return zero. */ 154 wrap_in_if(b, instr, in_bounds); 155} 156 157struct pass_opts { 158 nir_intrin_filter_cb filter; 159 const void *data; 160}; 161 162static bool 163lower(nir_builder *b, nir_intrinsic_instr *intr, void *_opts) 164{ 165 const struct pass_opts *opts = _opts; 166 if (!opts->filter(intr, opts->data)) 167 return false; 168 169 b->cursor = nir_before_instr(&intr->instr); 170 171 switch (intr->intrinsic) { 172 case nir_intrinsic_image_load: 173 case nir_intrinsic_image_store: 174 case nir_intrinsic_image_atomic: 175 case nir_intrinsic_image_atomic_swap: 176 lower_image(b, intr, false); 177 return true; 178 179 case nir_intrinsic_image_deref_load: 180 case nir_intrinsic_image_deref_store: 181 case nir_intrinsic_image_deref_atomic: 182 case nir_intrinsic_image_deref_atomic_swap: 183 lower_image(b, intr, true); 184 return true; 185 186 case nir_intrinsic_load_ubo: 187 case nir_intrinsic_load_ssbo: 188 lower_buffer_load(b, intr); 189 return true; 190 case nir_intrinsic_store_ssbo: 191 lower_buffer_store(b, intr); 192 return true; 193 case nir_intrinsic_ssbo_atomic: 194 case nir_intrinsic_ssbo_atomic_swap: 195 lower_buffer_atomic(b, intr); 196 return true; 197 198 case nir_intrinsic_store_shared: 199 case nir_intrinsic_load_shared: 200 case nir_intrinsic_shared_atomic: 201 case nir_intrinsic_shared_atomic_swap: 202 /* Vulkan's robustBufferAccess feature is only concerned with buffers that 203 * are bound through descriptor sets, so shared memory is not included, 204 * but this lowering may be useful for debugging. 205 */ 206 lower_buffer_shared(b, intr); 207 return true; 208 209 default: 210 unreachable("driver requested lowering for unsupported intrinsic"); 211 } 212} 213 214/* 215 * Buffer/image robustness lowering with robustBufferAccess/robustImageAccess 216 * semantics. This is sufficient for GL, but not for D3D. However, Vulkan 217 * drivers get buffer robustness lowered via nir_lower_explicit_io. 218 */ 219bool 220nir_lower_robust_access(nir_shader *s, nir_intrin_filter_cb filter, 221 const void *data) 222{ 223 struct pass_opts opt = { .filter = filter, .data = data }; 224 return nir_shader_intrinsics_pass(s, lower, nir_metadata_none, &opt); 225}