0f0de2134296053154bb7f5981fb0749f5bd79c5
3 * Copyright (c) 2019 Collabora LTD
5 * Author: Gert Wollny <gert.wollny@collabora.com>
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * on the rights to use, copy, modify, merge, publish, distribute, sub
11 * license, and/or sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include "sfn_instruction_tex.h"
28 #include "nir_builder.h"
29 #include "nir_builtin_builder.h"
33 TexInstruction::TexInstruction(Opcode op
, const GPRVector
&dest
, const GPRVector
&src
,
34 unsigned sid
, unsigned rid
, PValue sampler_offset
):
43 m_dest_swizzle
{0,1,2,3},
44 m_sampler_offset(sampler_offset
)
47 memset(m_offset
, 0, sizeof (m_offset
));
49 add_remappable_src_value(&m_src
);
50 add_remappable_src_value(&m_sampler_offset
);
51 add_remappable_dst_value(&m_dst
);
54 void TexInstruction::set_gather_comp(int cmp
)
59 void TexInstruction::replace_values(const ValueSet
& candiates
, PValue new_value
)
61 // I wonder whether we can actually end up here ...
62 for (auto c
: candiates
) {
63 if (*c
== *m_src
.reg_i(c
->chan()))
64 m_src
.set_reg_i(c
->chan(), new_value
);
65 if (*c
== *m_dst
.reg_i(c
->chan()))
66 m_dst
.set_reg_i(c
->chan(), new_value
);
70 void TexInstruction::set_offset(unsigned index
, int32_t val
)
73 m_offset
[index
] = val
;
76 int TexInstruction::get_offset(unsigned index
) const
79 return (m_offset
[index
] << 1 & 0x1f);
82 bool TexInstruction::is_equal_to(const Instruction
& rhs
) const
84 assert(rhs
.type() == tex
);
85 const auto& r
= static_cast<const TexInstruction
&>(rhs
);
86 return (m_opcode
== r
.m_opcode
&&
89 m_sampler_id
== r
.m_sampler_id
&&
90 m_resource_id
== r
.m_resource_id
);
93 void TexInstruction::do_print(std::ostream
& os
) const
95 const char *map_swz
= "xyzw01?_";
96 os
<< opname(m_opcode
) << " R" << m_dst
.sel() << ".";
97 for (int i
= 0; i
< 4; ++i
)
98 os
<< map_swz
[m_dest_swizzle
[i
]];
101 << " RESID:" << m_resource_id
<< " SAMPLER:"
105 const char *TexInstruction::opname(Opcode op
)
108 case ld
: return "LD";
109 case get_resinfo
: return "GET_TEXTURE_RESINFO";
110 case get_nsampled
: return "GET_NUMBER_OF_SAMPLES";
111 case get_tex_lod
: return "GET_LOD";
112 case get_gradient_h
: return "GET_GRADIENTS_H";
113 case get_gradient_v
: return "GET_GRADIENTS_V";
114 case set_offsets
: return "SET_TEXTURE_OFFSETS";
115 case keep_gradients
: return "KEEP_GRADIENTS";
116 case set_gradient_h
: return "SET_GRADIENTS_H";
117 case set_gradient_v
: return "SET_GRADIENTS_V";
118 case sample
: return "SAMPLE";
119 case sample_l
: return "SAMPLE_L";
120 case sample_lb
: return "SAMPLE_LB";
121 case sample_lz
: return "SAMPLE_LZ";
122 case sample_g
: return "SAMPLE_G";
123 case sample_g_lb
: return "SAMPLE_G_L";
124 case gather4
: return "GATHER4";
125 case gather4_o
: return "GATHER4_O";
126 case sample_c
: return "SAMPLE_C";
127 case sample_c_l
: return "SAMPLE_C_L";
128 case sample_c_lb
: return "SAMPLE_C_LB";
129 case sample_c_lz
: return "SAMPLE_C_LZ";
130 case sample_c_g
: return "SAMPLE_C_G";
131 case sample_c_g_lb
: return "SAMPLE_C_G_L";
132 case gather4_c
: return "GATHER4_C";
133 case gather4_c_o
: return "OP_GATHER4_C_O";
140 static bool lower_coord_shift_normalized(nir_builder
& b
, nir_tex_instr
*tex
)
142 b
.cursor
= nir_before_instr(&tex
->instr
);
144 nir_ssa_def
* size
= nir_i2f32(&b
, nir_get_texture_size(&b
, tex
));
145 nir_ssa_def
*scale
= nir_frcp(&b
, size
);
147 int coord_index
= nir_tex_instr_src_index(tex
, nir_tex_src_coord
);
148 nir_ssa_def
*corr
= nir_fadd(&b
,
149 nir_fmul(&b
, nir_imm_float(&b
, -0.5f
), scale
),
150 tex
->src
[coord_index
].src
.ssa
);
151 nir_instr_rewrite_src(&tex
->instr
, &tex
->src
[coord_index
].src
,
152 nir_src_for_ssa(corr
));
156 static bool lower_coord_shift_unnormalized(nir_builder
& b
, nir_tex_instr
*tex
)
158 b
.cursor
= nir_before_instr(&tex
->instr
);
159 int coord_index
= nir_tex_instr_src_index(tex
, nir_tex_src_coord
);
160 nir_ssa_def
*corr
= nir_fadd(&b
, tex
->src
[coord_index
].src
.ssa
,
161 nir_imm_float(&b
, -0.5f
));
162 nir_instr_rewrite_src(&tex
->instr
, &tex
->src
[coord_index
].src
,
163 nir_src_for_ssa(corr
));
168 r600_nir_lower_int_tg4_impl(nir_function_impl
*impl
, const std::vector
<bool>& lower
)
171 nir_builder_init(&b
, impl
);
173 bool progress
= false;
174 nir_foreach_block(block
, impl
) {
175 nir_foreach_instr_safe(instr
, block
) {
176 if (instr
->type
== nir_instr_type_tex
) {
177 nir_tex_instr
*tex
= nir_instr_as_tex(instr
);
178 if (tex
->op
== nir_texop_tg4
&&
179 tex
->sampler_dim
!= GLSL_SAMPLER_DIM_CUBE
) {
180 if (lower
[tex
->sampler_index
]) {
181 if (tex
->sampler_dim
!= GLSL_SAMPLER_DIM_RECT
)
182 lower_coord_shift_normalized(b
, tex
);
184 lower_coord_shift_unnormalized(b
, tex
);
195 * This lowering pass works around a bug in r600 when doing TG4 from
196 * integral valued samplers.
198 * Gather4 should follow the same rules as bilinear filtering, but the hardware
199 * incorrectly forces nearest filtering if the texture format is integer.
200 * The only effect it has on Gather4, which always returns 4 texels for
201 * bilinear filtering, is that the final coordinates are off by 0.5 of
205 bool r600_nir_lower_int_tg4(nir_shader
*shader
)
207 bool progress
= false;
208 bool need_lowering
= false;
212 std::vector
<bool> lower_sampler(shader
->uniforms
.length(), false);
213 auto is
= lower_sampler
.begin();
215 nir_foreach_variable(var
, &shader
->uniforms
) {
216 if (var
->type
->is_sampler()) {
217 if (glsl_base_type_is_integer(var
->type
->sampled_type
)) {
218 need_lowering
= *is
= true;
226 nir_foreach_function(function
, shader
) {
227 if (function
->impl
&& r600_nir_lower_int_tg4_impl(function
->impl
, lower_sampler
))
236 bool lower_txl_txf_array_or_cube(nir_builder
*b
, nir_tex_instr
*tex
)
238 assert(tex
->op
== nir_texop_txb
|| tex
->op
== nir_texop_txl
);
239 assert(nir_tex_instr_src_index(tex
, nir_tex_src_ddx
) < 0);
240 assert(nir_tex_instr_src_index(tex
, nir_tex_src_ddy
) < 0);
242 b
->cursor
= nir_before_instr(&tex
->instr
);
244 int lod_idx
= nir_tex_instr_src_index(tex
, nir_tex_src_lod
);
245 int bias_idx
= nir_tex_instr_src_index(tex
, nir_tex_src_bias
);
246 int min_lod_idx
= nir_tex_instr_src_index(tex
, nir_tex_src_min_lod
);
247 assert (lod_idx
>= 0 || bias_idx
>= 0);
249 nir_ssa_def
*size
= nir_i2f32(b
, nir_get_texture_size(b
, tex
));
250 nir_ssa_def
*lod
= (lod_idx
>= 0) ?
251 nir_ssa_for_src(b
, tex
->src
[lod_idx
].src
, 1) :
252 nir_get_texture_lod(b
, tex
);
255 lod
= nir_fadd(b
, lod
,nir_ssa_for_src(b
, tex
->src
[bias_idx
].src
, 1));
257 if (min_lod_idx
>= 0)
258 lod
= nir_fmax(b
, lod
, nir_ssa_for_src(b
, tex
->src
[min_lod_idx
].src
, 1));
262 nir_ssa_def
*lambda_exp
= nir_fexp2(b
, lod
);
263 nir_ssa_def
*scale
= NULL
;
266 int cmp_mask
= (1 << (size
->num_components
- 1)) - 1;
267 scale
= nir_frcp(b
, nir_channels(b
, size
,
268 (nir_component_mask_t
)cmp_mask
));
269 } else if (tex
->sampler_dim
== GLSL_SAMPLER_DIM_CUBE
) {
270 unsigned int swizzle
[NIR_MAX_VEC_COMPONENTS
] = {0,0,0,0};
271 scale
= nir_frcp(b
, nir_channels(b
, size
, 1));
272 scale
= nir_swizzle(b
, scale
, swizzle
, 3);
275 nir_ssa_def
*grad
= nir_fmul(b
, lambda_exp
, scale
);
278 nir_tex_instr_remove_src(tex
, lod_idx
);
280 nir_tex_instr_remove_src(tex
, bias_idx
);
281 if (min_lod_idx
>= 0)
282 nir_tex_instr_remove_src(tex
, min_lod_idx
);
283 nir_tex_instr_add_src(tex
, nir_tex_src_ddx
, nir_src_for_ssa(grad
));
284 nir_tex_instr_add_src(tex
, nir_tex_src_ddy
, nir_src_for_ssa(grad
));
286 tex
->op
= nir_texop_txd
;
292 r600_nir_lower_txl_txf_array_or_cube_impl(nir_function_impl
*impl
)
295 nir_builder_init(&b
, impl
);
297 bool progress
= false;
298 nir_foreach_block(block
, impl
) {
299 nir_foreach_instr_safe(instr
, block
) {
300 if (instr
->type
== nir_instr_type_tex
) {
301 nir_tex_instr
*tex
= nir_instr_as_tex(instr
);
303 if (tex
->is_shadow
&&
304 (tex
->op
== nir_texop_txl
|| tex
->op
== nir_texop_txb
) &&
305 (tex
->is_array
|| tex
->sampler_dim
== GLSL_SAMPLER_DIM_CUBE
))
306 progress
|= lower_txl_txf_array_or_cube(&b
, tex
);
314 r600_nir_lower_txl_txf_array_or_cube(nir_shader
*shader
)
316 bool progress
= false;
317 nir_foreach_function(function
, shader
) {
318 if (function
->impl
&& r600_nir_lower_txl_txf_array_or_cube_impl(function
->impl
))