1 /* -*- mesa-c++ -*-
2 * Copyright 2021 Collabora LTD
3 * Author: Gert Wollny <gert.wollny@collabora.com>
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 if (num_components == 3 && dim == GLSL_SAMPLER_DIM_CUBE) {
87 img_size = nir_vec3(b,
88 nir_channel(b, img_size, 0),
89 nir_channel(b, img_size, 1),
90 nir_imul_imm(b, nir_channel(b, img_size, 2), 6));
91 }
92
93 auto in_range = nir_ult(b,
94 nir_channels(b, ir->src[1].ssa, src1_mask),
95 nir_channels(b, img_size, mask));
96
97 switch (num_components) {
98 case 2:
99 in_range = nir_iand(b, nir_channel(b, in_range, 0), nir_channel(b, in_range, 1));
100 break;
101 case 3: {
102 auto tmp = nir_iand(b, nir_channel(b, in_range, 0), nir_channel(b, in_range, 1));
103 in_range = nir_iand(b, tmp, nir_channel(b, in_range, 2));
104 break;
105 }
106 }
107
108 /* Access is in range start */
109 load_if = nir_push_if(b, in_range);
110 }
111
112 auto new_load = nir_instr_clone(b->shader, instr);
113 auto new_load_ir = nir_instr_as_intrinsic(new_load);
114
115 nir_builder_instr_insert(b, new_load);
116
117 if (load_value)
118 result = &new_load_ir->def;
119
120 if (ir->intrinsic != nir_intrinsic_image_size) {
121 /* Access is out of range start */
122 nir_if *load_else = nir_push_else(b, load_if);
123
124 nir_pop_if(b, load_else);
125 /* End range check */
126
127 if (load_value)
128 result = nir_if_phi(b, result, default_value);
129 }
130
131 /* Start image doesn't exists */
132 nir_if *else_exists = nir_push_else(b, if_exists);
133
134 /* Nothing to do, default is already set */
135 nir_pop_if(b, else_exists);
136
137 if (load_value)
138 result = nir_if_phi(b, result, default_value);
139
140 if (load_value)
141 b->cursor = nir_after_instr(result->parent_instr);
142 else
143 b->cursor = nir_after_cf_node(&else_exists->cf_node);
144
145 return result;
146 }
147
148 static bool
r600_legalize_image_load_store_filter(const nir_instr * instr,UNUSED const void * _options)149 r600_legalize_image_load_store_filter(const nir_instr *instr, UNUSED const void *_options)
150 {
151 if (instr->type != nir_instr_type_intrinsic)
152 return false;
153
154 auto ir = nir_instr_as_intrinsic(instr);
155 switch (ir->intrinsic) {
156 case nir_intrinsic_image_store:
157 case nir_intrinsic_image_load:
158 case nir_intrinsic_image_atomic:
159 case nir_intrinsic_image_atomic_swap:
160 case nir_intrinsic_image_size:
161 return true;
162 default:
163 return false;
164 }
165 }
166
167 /* This pass makes sure only existing images are accessd and
168 * the access is within range, if not zero is returned by all
169 * image ops that return a value.
170 */
171 bool
r600_legalize_image_load_store(nir_shader * shader)172 r600_legalize_image_load_store(nir_shader *shader)
173 {
174 bool progress = nir_shader_lower_instructions(shader,
175 r600_legalize_image_load_store_filter,
176 r600_legalize_image_load_store_impl,
177 nullptr);
178 return progress;
179 };
180