xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/r600/sfn/sfn_nir_lower_tex.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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