1 /* -*- mesa-c++ -*-
2 * Copyright 2022 Collabora LTD
3 * Author: Gert Wollny <[email protected]>
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "sfn_nir_lower_tex.h"
8
9 #include "nir.h"
10 #include "nir_builder.h"
11 #include "nir_builtin_builder.h"
12
13 static bool
lower_coord_shift_normalized(nir_builder * b,nir_tex_instr * tex)14 lower_coord_shift_normalized(nir_builder *b, nir_tex_instr *tex)
15 {
16 b->cursor = nir_before_instr(&tex->instr);
17
18 nir_def *size = nir_i2f32(b, nir_get_texture_size(b, tex));
19 nir_def *scale = nir_frcp(b, size);
20
21 int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
22 nir_def *corr = nullptr;
23 if (unlikely(tex->array_is_lowered_cube)) {
24 auto corr2 = nir_fadd(b,
25 nir_trim_vector(b, tex->src[coord_index].src.ssa, 2),
26 nir_fmul_imm(b, scale, -0.5f));
27 corr = nir_vec3(b,
28 nir_channel(b, corr2, 0),
29 nir_channel(b, corr2, 1),
30 nir_channel(b, tex->src[coord_index].src.ssa, 2));
31 } else {
32 corr = nir_fadd(b,
33 nir_fmul_imm(b, scale, -0.5f),
34 tex->src[coord_index].src.ssa);
35 }
36
37 nir_src_rewrite(&tex->src[coord_index].src, corr);
38 return true;
39 }
40
41 static bool
lower_coord_shift_unnormalized(nir_builder * b,nir_tex_instr * tex)42 lower_coord_shift_unnormalized(nir_builder *b, nir_tex_instr *tex)
43 {
44 b->cursor = nir_before_instr(&tex->instr);
45 int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
46 nir_def *corr = nullptr;
47 if (unlikely(tex->array_is_lowered_cube)) {
48 auto corr2 = nir_fadd_imm(b,
49 nir_trim_vector(b, tex->src[coord_index].src.ssa, 2),
50 -0.5f);
51 corr = nir_vec3(b,
52 nir_channel(b, corr2, 0),
53 nir_channel(b, corr2, 1),
54 nir_channel(b, tex->src[coord_index].src.ssa, 2));
55 } else {
56 corr = nir_fadd_imm(b, tex->src[coord_index].src.ssa, -0.5f);
57 }
58 nir_src_rewrite(&tex->src[coord_index].src, corr);
59 return true;
60 }
61
62 static bool
r600_nir_lower_int_tg4_impl(nir_function_impl * impl)63 r600_nir_lower_int_tg4_impl(nir_function_impl *impl)
64 {
65 nir_builder b = nir_builder_create(impl);
66
67 bool progress = false;
68 nir_foreach_block(block, impl)
69 {
70 nir_foreach_instr_safe(instr, block)
71 {
72 if (instr->type == nir_instr_type_tex) {
73 nir_tex_instr *tex = nir_instr_as_tex(instr);
74 if (tex->op == nir_texop_tg4 && tex->sampler_dim != GLSL_SAMPLER_DIM_CUBE &&
75 nir_tex_instr_src_index(tex, nir_tex_src_backend1) < 0) {
76 if (nir_alu_type_get_base_type(tex->dest_type) != nir_type_float) {
77 if (tex->sampler_dim != GLSL_SAMPLER_DIM_RECT)
78 lower_coord_shift_normalized(&b, tex);
79 else
80 lower_coord_shift_unnormalized(&b, tex);
81 progress = true;
82 }
83 }
84 }
85 }
86 }
87 return progress;
88 }
89
90 /*
91 * This lowering pass works around a bug in r600 when doing TG4 from
92 * integral valued samplers.
93
94 * Gather4 should follow the same rules as bilinear filtering, but the hardware
95 * incorrectly forces nearest filtering if the texture format is integer.
96 * The only effect it has on Gather4, which always returns 4 texels for
97 * bilinear filtering, is that the final coordinates are off by 0.5 of
98 * the texel size.
99 */
100
101 bool
r600_nir_lower_int_tg4(nir_shader * shader)102 r600_nir_lower_int_tg4(nir_shader *shader)
103 {
104 bool progress = false;
105 bool need_lowering = false;
106
107 nir_foreach_uniform_variable(var, shader)
108 {
109 if (glsl_type_is_sampler(var->type)) {
110 if (glsl_base_type_is_integer(var->type->sampled_type)) {
111 need_lowering = true;
112 }
113 }
114 }
115
116 if (need_lowering) {
117 nir_foreach_function_impl(impl, shader)
118 {
119 if (r600_nir_lower_int_tg4_impl(impl))
120 progress = true;
121 }
122 }
123
124 return progress;
125 }
126
127 static bool
lower_txl_txf_array_or_cube(nir_builder * b,nir_tex_instr * tex)128 lower_txl_txf_array_or_cube(nir_builder *b, nir_tex_instr *tex)
129 {
130 assert(tex->op == nir_texop_txb || tex->op == nir_texop_txl);
131 assert(nir_tex_instr_src_index(tex, nir_tex_src_ddx) < 0);
132 assert(nir_tex_instr_src_index(tex, nir_tex_src_ddy) < 0);
133
134 b->cursor = nir_before_instr(&tex->instr);
135
136 int lod_idx = nir_tex_instr_src_index(tex, nir_tex_src_lod);
137 int bias_idx = nir_tex_instr_src_index(tex, nir_tex_src_bias);
138 int min_lod_idx = nir_tex_instr_src_index(tex, nir_tex_src_min_lod);
139 assert(lod_idx >= 0 || bias_idx >= 0);
140
141 nir_def *size = nir_i2f32(b, nir_get_texture_size(b, tex));
142 nir_def *lod = (lod_idx >= 0) ? tex->src[lod_idx].src.ssa
143 : nir_get_texture_lod(b, tex);
144
145 if (bias_idx >= 0)
146 lod = nir_fadd(b, lod, tex->src[bias_idx].src.ssa);
147
148 if (min_lod_idx >= 0)
149 lod = nir_fmax(b, lod, tex->src[min_lod_idx].src.ssa);
150
151 /* max lod? */
152
153 nir_def *lambda_exp = nir_fexp2(b, lod);
154 nir_def *scale = NULL;
155
156 if (tex->sampler_dim == GLSL_SAMPLER_DIM_CUBE) {
157 unsigned int swizzle[NIR_MAX_VEC_COMPONENTS] = {0, 0, 0, 0};
158 scale = nir_frcp(b, nir_channels(b, size, 1));
159 scale = nir_swizzle(b, scale, swizzle, 3);
160 } else if (tex->is_array) {
161 int cmp_mask = (1 << (size->num_components - 1)) - 1;
162 scale = nir_frcp(b, nir_channels(b, size, (nir_component_mask_t)cmp_mask));
163 }
164
165 nir_def *grad = nir_fmul(b, lambda_exp, scale);
166
167 if (lod_idx >= 0)
168 nir_tex_instr_remove_src(tex, lod_idx);
169 if (bias_idx >= 0)
170 nir_tex_instr_remove_src(tex, bias_idx);
171 if (min_lod_idx >= 0)
172 nir_tex_instr_remove_src(tex, min_lod_idx);
173 nir_tex_instr_add_src(tex, nir_tex_src_ddx, grad);
174 nir_tex_instr_add_src(tex, nir_tex_src_ddy, grad);
175
176 tex->op = nir_texop_txd;
177 return true;
178 }
179
180 static bool
r600_nir_lower_txl_txf_array_or_cube_impl(nir_function_impl * impl)181 r600_nir_lower_txl_txf_array_or_cube_impl(nir_function_impl *impl)
182 {
183 nir_builder b = nir_builder_create(impl);
184
185 bool progress = false;
186 nir_foreach_block(block, impl)
187 {
188 nir_foreach_instr_safe(instr, block)
189 {
190 if (instr->type == nir_instr_type_tex) {
191 nir_tex_instr *tex = nir_instr_as_tex(instr);
192
193 if (tex->is_shadow &&
194 (tex->op == nir_texop_txl || tex->op == nir_texop_txb) &&
195 (tex->is_array || tex->sampler_dim == GLSL_SAMPLER_DIM_CUBE))
196 progress |= lower_txl_txf_array_or_cube(&b, tex);
197 }
198 }
199 }
200 return progress;
201 }
202
203 bool
r600_nir_lower_txl_txf_array_or_cube(nir_shader * shader)204 r600_nir_lower_txl_txf_array_or_cube(nir_shader *shader)
205 {
206 bool progress = false;
207 nir_foreach_function_impl(impl, shader)
208 {
209 if (r600_nir_lower_txl_txf_array_or_cube_impl(impl))
210 progress = true;
211 }
212 return progress;
213 }
214
215 static bool
r600_nir_lower_cube_to_2darray_filer(const nir_instr * instr,const void * _options)216 r600_nir_lower_cube_to_2darray_filer(const nir_instr *instr, const void *_options)
217 {
218 if (instr->type != nir_instr_type_tex)
219 return false;
220
221 auto tex = nir_instr_as_tex(instr);
222 if (tex->sampler_dim != GLSL_SAMPLER_DIM_CUBE)
223 return false;
224
225 switch (tex->op) {
226 case nir_texop_tex:
227 case nir_texop_txb:
228 case nir_texop_txf:
229 case nir_texop_txl:
230 case nir_texop_lod:
231 case nir_texop_tg4:
232 case nir_texop_txd:
233 return true;
234 default:
235 return false;
236 }
237 }
238
239 static nir_def *
r600_nir_lower_cube_to_2darray_impl(nir_builder * b,nir_instr * instr,void * _options)240 r600_nir_lower_cube_to_2darray_impl(nir_builder *b, nir_instr *instr, void *_options)
241 {
242 b->cursor = nir_before_instr(instr);
243
244 auto tex = nir_instr_as_tex(instr);
245 int coord_idx = nir_tex_instr_src_index(tex, nir_tex_src_coord);
246 assert(coord_idx >= 0);
247
248 auto cubed = nir_cube_amd(b,
249 nir_trim_vector(b, tex->src[coord_idx].src.ssa, 3));
250 auto xy = nir_fmad(b,
251 nir_vec2(b, nir_channel(b, cubed, 1), nir_channel(b, cubed, 0)),
252 nir_frcp(b, nir_fabs(b, nir_channel(b, cubed, 2))),
253 nir_imm_float(b, 1.5));
254
255 nir_def *z = nir_channel(b, cubed, 3);
256 if (tex->is_array && tex->op != nir_texop_lod) {
257 auto slice = nir_fround_even(b, nir_channel(b, tex->src[coord_idx].src.ssa, 3));
258 z =
259 nir_fmad(b, nir_fmax(b, slice, nir_imm_float(b, 0.0)), nir_imm_float(b, 8.0), z);
260 }
261
262 if (tex->op == nir_texop_txd) {
263 int ddx_idx = nir_tex_instr_src_index(tex, nir_tex_src_ddx);
264 nir_src_rewrite(&tex->src[ddx_idx].src,
265 nir_fmul_imm(b, tex->src[ddx_idx].src.ssa, 0.5));
266
267 int ddy_idx = nir_tex_instr_src_index(tex, nir_tex_src_ddy);
268 nir_src_rewrite(&tex->src[ddy_idx].src,
269 nir_fmul_imm(b, tex->src[ddy_idx].src.ssa, 0.5));
270 }
271
272 auto new_coord = nir_vec3(b, nir_channel(b, xy, 0), nir_channel(b, xy, 1), z);
273 nir_src_rewrite(&tex->src[coord_idx].src, new_coord);
274 tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
275 tex->is_array = true;
276 tex->array_is_lowered_cube = true;
277
278 tex->coord_components = 3;
279
280 return NIR_LOWER_INSTR_PROGRESS;
281 }
282
283 bool
r600_nir_lower_cube_to_2darray(nir_shader * shader)284 r600_nir_lower_cube_to_2darray(nir_shader *shader)
285 {
286 return nir_shader_lower_instructions(shader,
287 r600_nir_lower_cube_to_2darray_filer,
288 r600_nir_lower_cube_to_2darray_impl,
289 nullptr);
290 }
291