2 * Copyright © 2015 Broadcom
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * This lowering pass supports (as configured via nir_lower_tex_options)
26 * various texture related conversions:
27 * + texture projector lowering: converts the coordinate division for
28 * texture projection to be done in ALU instructions instead of
29 * asking the texture operation to do so.
30 * + lowering RECT: converts the un-normalized RECT texture coordinates
31 * to normalized coordinates with txs plus ALU instructions
32 * + saturate s/t/r coords: to emulate certain texture clamp/wrap modes,
33 * inserts instructions to clamp specified coordinates to [0.0, 1.0].
34 * Note that this automatically triggers texture projector lowering if
35 * needed, since clamping must happen after projector lowering.
39 #include "nir_builder.h"
43 const nir_lower_tex_options
*options
;
48 project_src(nir_builder
*b
, nir_tex_instr
*tex
)
50 /* Find the projector in the srcs list, if present. */
52 for (proj_index
= 0; proj_index
< tex
->num_srcs
; proj_index
++) {
53 if (tex
->src
[proj_index
].src_type
== nir_tex_src_projector
)
56 if (proj_index
== tex
->num_srcs
)
59 b
->cursor
= nir_before_instr(&tex
->instr
);
61 nir_ssa_def
*inv_proj
=
62 nir_frcp(b
, nir_ssa_for_src(b
, tex
->src
[proj_index
].src
, 1));
64 /* Walk through the sources projecting the arguments. */
65 for (unsigned i
= 0; i
< tex
->num_srcs
; i
++) {
66 switch (tex
->src
[i
].src_type
) {
67 case nir_tex_src_coord
:
68 case nir_tex_src_comparitor
:
73 nir_ssa_def
*unprojected
=
74 nir_ssa_for_src(b
, tex
->src
[i
].src
, nir_tex_instr_src_size(tex
, i
));
75 nir_ssa_def
*projected
= nir_fmul(b
, unprojected
, inv_proj
);
77 /* Array indices don't get projected, so make an new vector with the
78 * coordinate's array index untouched.
80 if (tex
->is_array
&& tex
->src
[i
].src_type
== nir_tex_src_coord
) {
81 switch (tex
->coord_components
) {
83 projected
= nir_vec4(b
,
84 nir_channel(b
, projected
, 0),
85 nir_channel(b
, projected
, 1),
86 nir_channel(b
, projected
, 2),
87 nir_channel(b
, unprojected
, 3));
90 projected
= nir_vec3(b
,
91 nir_channel(b
, projected
, 0),
92 nir_channel(b
, projected
, 1),
93 nir_channel(b
, unprojected
, 2));
96 projected
= nir_vec2(b
,
97 nir_channel(b
, projected
, 0),
98 nir_channel(b
, unprojected
, 1));
101 unreachable("bad texture coord count for array");
106 nir_instr_rewrite_src(&tex
->instr
,
108 nir_src_for_ssa(projected
));
111 /* Now move the later tex sources down the array so that the projector
114 nir_instr_rewrite_src(&tex
->instr
, &tex
->src
[proj_index
].src
,
116 for (unsigned i
= proj_index
+ 1; i
< tex
->num_srcs
; i
++) {
117 tex
->src
[i
-1].src_type
= tex
->src
[i
].src_type
;
118 nir_instr_move_src(&tex
->instr
, &tex
->src
[i
-1].src
, &tex
->src
[i
].src
);
124 get_texture_size(nir_builder
*b
, nir_tex_instr
*tex
)
126 b
->cursor
= nir_before_instr(&tex
->instr
);
128 /* RECT textures should not be array: */
129 assert(!tex
->is_array
);
133 txs
= nir_tex_instr_create(b
->shader
, 1);
134 txs
->op
= nir_texop_txs
;
135 txs
->sampler_dim
= GLSL_SAMPLER_DIM_RECT
;
136 txs
->sampler_index
= tex
->sampler_index
;
138 /* only single src, the lod: */
139 txs
->src
[0].src
= nir_src_for_ssa(nir_imm_int(b
, 0));
140 txs
->src
[0].src_type
= nir_tex_src_lod
;
142 nir_ssa_dest_init(&txs
->instr
, &txs
->dest
, 2, NULL
);
143 nir_builder_instr_insert(b
, &txs
->instr
);
145 return nir_i2f(b
, &txs
->dest
.ssa
);
149 lower_rect(nir_builder
*b
, nir_tex_instr
*tex
)
151 nir_ssa_def
*txs
= get_texture_size(b
, tex
);
152 nir_ssa_def
*scale
= nir_frcp(b
, txs
);
154 /* Walk through the sources normalizing the requested arguments. */
155 for (unsigned i
= 0; i
< tex
->num_srcs
; i
++) {
156 if (tex
->src
[i
].src_type
!= nir_tex_src_coord
)
159 nir_ssa_def
*coords
=
160 nir_ssa_for_src(b
, tex
->src
[i
].src
, tex
->coord_components
);
161 nir_instr_rewrite_src(&tex
->instr
,
163 nir_src_for_ssa(nir_fmul(b
, coords
, scale
)));
166 tex
->sampler_dim
= GLSL_SAMPLER_DIM_2D
;
170 saturate_src(nir_builder
*b
, nir_tex_instr
*tex
, unsigned sat_mask
)
172 b
->cursor
= nir_before_instr(&tex
->instr
);
174 /* Walk through the sources saturating the requested arguments. */
175 for (unsigned i
= 0; i
< tex
->num_srcs
; i
++) {
176 if (tex
->src
[i
].src_type
!= nir_tex_src_coord
)
180 nir_ssa_for_src(b
, tex
->src
[i
].src
, tex
->coord_components
);
182 /* split src into components: */
183 nir_ssa_def
*comp
[4];
185 for (unsigned j
= 0; j
< tex
->coord_components
; j
++)
186 comp
[j
] = nir_channel(b
, src
, j
);
188 /* clamp requested components, array index does not get clamped: */
189 unsigned ncomp
= tex
->coord_components
;
193 for (unsigned j
= 0; j
< ncomp
; j
++) {
194 if ((1 << j
) & sat_mask
) {
195 if (tex
->sampler_dim
== GLSL_SAMPLER_DIM_RECT
) {
196 /* non-normalized texture coords, so clamp to texture
197 * size rather than [0.0, 1.0]
199 nir_ssa_def
*txs
= get_texture_size(b
, tex
);
200 comp
[j
] = nir_fmax(b
, comp
[j
], nir_imm_float(b
, 0.0));
201 comp
[j
] = nir_fmin(b
, comp
[j
], nir_channel(b
, txs
, j
));
203 comp
[j
] = nir_fsat(b
, comp
[j
]);
208 /* and move the result back into a single vecN: */
209 src
= nir_vec(b
, comp
, tex
->coord_components
);
211 nir_instr_rewrite_src(&tex
->instr
,
213 nir_src_for_ssa(src
));
218 nir_lower_tex_block(nir_block
*block
, void *void_state
)
220 lower_tex_state
*state
= void_state
;
221 nir_builder
*b
= &state
->b
;
223 nir_foreach_instr_safe(block
, instr
) {
224 if (instr
->type
!= nir_instr_type_tex
)
227 nir_tex_instr
*tex
= nir_instr_as_tex(instr
);
228 bool lower_txp
= !!(state
->options
->lower_txp
& (1 << tex
->sampler_dim
));
230 /* mask of src coords to saturate (clamp): */
231 unsigned sat_mask
= 0;
233 if ((1 << tex
->sampler_index
) & state
->options
->saturate_r
)
234 sat_mask
|= (1 << 2); /* .z */
235 if ((1 << tex
->sampler_index
) & state
->options
->saturate_t
)
236 sat_mask
|= (1 << 1); /* .y */
237 if ((1 << tex
->sampler_index
) & state
->options
->saturate_s
)
238 sat_mask
|= (1 << 0); /* .x */
240 /* If we are clamping any coords, we must lower projector first
241 * as clamping happens *after* projection:
243 if (lower_txp
|| sat_mask
) {
245 state
->progress
= true;
248 if ((tex
->sampler_dim
== GLSL_SAMPLER_DIM_RECT
) &&
249 state
->options
->lower_rect
) {
251 state
->progress
= true;
255 saturate_src(b
, tex
, sat_mask
);
256 state
->progress
= true;
264 nir_lower_tex_impl(nir_function_impl
*impl
, lower_tex_state
*state
)
266 nir_builder_init(&state
->b
, impl
);
268 nir_foreach_block(impl
, nir_lower_tex_block
, state
);
270 nir_metadata_preserve(impl
, nir_metadata_block_index
|
271 nir_metadata_dominance
);
275 nir_lower_tex(nir_shader
*shader
, const nir_lower_tex_options
*options
)
277 lower_tex_state state
;
278 state
.options
= options
;
279 state
.progress
= false;
281 nir_foreach_overload(shader
, overload
) {
283 nir_lower_tex_impl(overload
->impl
, &state
);
286 return state
.progress
;