1 /* -*- mesa-c++ -*-
2 * Copyright 2021 Collabora LTD
3 * Author: Gert Wollny <[email protected]>
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "nir.h"
8 #include "nir_builder.h"
9 #include "nir_intrinsics.h"
10 #include "nir_intrinsics_indices.h"
11 #include "sfn_nir.h"
12
13 static nir_def *
r600_legalize_image_load_store_impl(nir_builder * b,nir_instr * instr,UNUSED void * _options)14 r600_legalize_image_load_store_impl(nir_builder *b,
15 nir_instr *instr,
16 UNUSED void *_options)
17 {
18 b->cursor = nir_before_instr(instr);
19 auto ir = nir_instr_as_intrinsic(instr);
20
21 nir_def *default_value = nir_imm_vec4(b, 0.0, 0.0, 0.0, 0.0);
22
23 nir_def *result = NIR_LOWER_INSTR_PROGRESS_REPLACE;
24
25 bool load_value = ir->intrinsic != nir_intrinsic_image_store;
26
27 if (load_value)
28 default_value =
29 nir_imm_zero(b, ir->def.num_components, ir->def.bit_size);
30
31 auto image_exists =
32 nir_ult_imm(b, ir->src[0].ssa, b->shader->info.num_images);
33
34 nir_if *if_exists = nir_push_if(b, image_exists);
35
36 nir_if *load_if = nullptr;
37
38 if (ir->intrinsic != nir_intrinsic_image_size) {
39
40 /* Image exists start */
41 auto new_index =
42 nir_umin(b,
43 ir->src[0].ssa,
44 nir_imm_int(b, b->shader->info.num_images - 1));
45 nir_src_rewrite(&ir->src[0], new_index);
46
47 enum glsl_sampler_dim dim = nir_intrinsic_image_dim(ir);
48
49 unsigned num_components = 2;
50 switch (dim) {
51 case GLSL_SAMPLER_DIM_BUF:
52 case GLSL_SAMPLER_DIM_1D:
53 num_components = 1;
54 break;
55 case GLSL_SAMPLER_DIM_2D:
56 case GLSL_SAMPLER_DIM_MS:
57 case GLSL_SAMPLER_DIM_RECT:
58 case GLSL_SAMPLER_DIM_CUBE:
59 num_components = 2;
60 break;
61 case GLSL_SAMPLER_DIM_3D:
62 num_components = 3;
63 break;
64 default:
65 unreachable("Unexpected image size");
66 }
67
68 if (num_components < 3 && nir_intrinsic_image_array(ir))
69 num_components++;
70
71 auto img_size = nir_image_size(b,
72 num_components,
73 32,
74 ir->src[0].ssa,
75 nir_imm_int(b, 0),
76 dim,
77 nir_intrinsic_image_array(ir),
78 nir_intrinsic_format(ir),
79 nir_intrinsic_access(ir),
80 nir_intrinsic_range_base(ir));
81
82 unsigned mask = (1 << num_components) - 1;
83 unsigned num_src1_comp = MIN2(ir->src[1].ssa->num_components, num_components);
84 unsigned src1_mask = (1 << num_src1_comp) - 1;
85
86 auto in_range = nir_ult(b,
87 nir_channels(b, ir->src[1].ssa, src1_mask),
88 nir_channels(b, img_size, mask));
89
90 switch (num_components) {
91 case 2:
92 in_range = nir_iand(b, nir_channel(b, in_range, 0), nir_channel(b, in_range, 1));
93 break;
94 case 3: {
95 auto tmp = nir_iand(b, nir_channel(b, in_range, 0), nir_channel(b, in_range, 1));
96 in_range = nir_iand(b, tmp, nir_channel(b, in_range, 2));
97 break;
98 }
99 }
100
101 /* Access is in range start */
102 load_if = nir_push_if(b, in_range);
103 }
104
105 auto new_load = nir_instr_clone(b->shader, instr);
106 auto new_load_ir = nir_instr_as_intrinsic(new_load);
107
108 nir_builder_instr_insert(b, new_load);
109
110 if (load_value)
111 result = &new_load_ir->def;
112
113 if (ir->intrinsic != nir_intrinsic_image_size) {
114 /* Access is out of range start */
115 nir_if *load_else = nir_push_else(b, load_if);
116
117 nir_pop_if(b, load_else);
118 /* End range check */
119
120 if (load_value)
121 result = nir_if_phi(b, result, default_value);
122 }
123
124 /* Start image doesn't exists */
125 nir_if *else_exists = nir_push_else(b, if_exists);
126
127 /* Nothing to do, default is already set */
128 nir_pop_if(b, else_exists);
129
130 if (load_value)
131 result = nir_if_phi(b, result, default_value);
132
133 if (load_value)
134 b->cursor = nir_after_instr(result->parent_instr);
135 else
136 b->cursor = nir_after_cf_node(&else_exists->cf_node);
137
138 return result;
139 }
140
141 static bool
r600_legalize_image_load_store_filter(const nir_instr * instr,UNUSED const void * _options)142 r600_legalize_image_load_store_filter(const nir_instr *instr, UNUSED const void *_options)
143 {
144 if (instr->type != nir_instr_type_intrinsic)
145 return false;
146
147 auto ir = nir_instr_as_intrinsic(instr);
148 switch (ir->intrinsic) {
149 case nir_intrinsic_image_store:
150 case nir_intrinsic_image_load:
151 case nir_intrinsic_image_atomic:
152 case nir_intrinsic_image_atomic_swap:
153 case nir_intrinsic_image_size:
154 return true;
155 default:
156 return false;
157 }
158 }
159
160 /* This pass makes sure only existing images are accessd and
161 * the access is within range, if not zero is returned by all
162 * image ops that return a value.
163 */
164 bool
r600_legalize_image_load_store(nir_shader * shader)165 r600_legalize_image_load_store(nir_shader *shader)
166 {
167 bool progress = nir_shader_lower_instructions(shader,
168 r600_legalize_image_load_store_filter,
169 r600_legalize_image_load_store_impl,
170 nullptr);
171 return progress;
172 };
173