2 * Copyright © 2019 Igalia S.L.
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
27 * A pass which detects tex instructions which are candidate to be executed
28 * prior to FS shader start, and change them to nir_texop_tex_prefetch.
32 coord_offset(nir_ssa_def
*ssa
)
34 nir_instr
*parent_instr
= ssa
->parent_instr
;
36 /* The coordinate of a texture sampling instruction eligible for
37 * pre-fetch is either going to be a load_interpolated_input/
38 * load_input, or a vec2 assembling non-swizzled components of
39 * a load_interpolated_input/load_input (due to varying packing)
42 if (parent_instr
->type
== nir_instr_type_alu
) {
43 nir_alu_instr
*alu
= nir_instr_as_alu(parent_instr
);
45 if (alu
->op
!= nir_op_vec2
)
48 if (!alu
->src
[0].src
.is_ssa
)
51 int base_offset
= coord_offset(alu
->src
[0].src
.ssa
) +
52 alu
->src
[0].swizzle
[0];
54 /* NOTE it might be possible to support more than 2D? */
55 for (int i
= 1; i
< 2; i
++) {
56 if (!alu
->src
[i
].src
.is_ssa
)
59 int nth_offset
= coord_offset(alu
->src
[i
].src
.ssa
) +
60 alu
->src
[i
].swizzle
[0];
62 if (nth_offset
!= (base_offset
+ i
))
69 if (parent_instr
->type
!= nir_instr_type_intrinsic
)
72 nir_intrinsic_instr
*input
= nir_instr_as_intrinsic(parent_instr
);
74 if (input
->intrinsic
!= nir_intrinsic_load_interpolated_input
)
77 /* limit to load_barycentric_pixel, other interpolation modes don't seem
80 if (!input
->src
[0].is_ssa
)
83 nir_intrinsic_instr
*interp
=
84 nir_instr_as_intrinsic(input
->src
[0].ssa
->parent_instr
);
86 if (interp
->intrinsic
!= nir_intrinsic_load_barycentric_pixel
)
89 /* we also need a const input offset: */
90 if (!nir_src_is_const(input
->src
[1]))
93 unsigned base
= nir_src_as_uint(input
->src
[1]) + nir_intrinsic_base(input
);
94 unsigned comp
= nir_intrinsic_component(input
);
96 return (4 * base
) + comp
;
100 ir3_nir_coord_offset(nir_ssa_def
*ssa
)
103 assert (ssa
->num_components
== 2);
104 return coord_offset(ssa
);
108 has_src(nir_tex_instr
*tex
, nir_tex_src_type type
)
110 return nir_tex_instr_src_index(tex
, type
) > 0;
114 lower_tex_prefetch_block(nir_block
*block
)
116 bool progress
= false;
118 nir_foreach_instr_safe (instr
, block
) {
119 if (instr
->type
!= nir_instr_type_tex
)
122 nir_tex_instr
*tex
= nir_instr_as_tex(instr
);
123 if (tex
->op
!= nir_texop_tex
)
126 if (has_src(tex
, nir_tex_src_bias
) ||
127 has_src(tex
, nir_tex_src_lod
) ||
128 has_src(tex
, nir_tex_src_comparator
) ||
129 has_src(tex
, nir_tex_src_projector
) ||
130 has_src(tex
, nir_tex_src_offset
) ||
131 has_src(tex
, nir_tex_src_ddx
) ||
132 has_src(tex
, nir_tex_src_ddy
) ||
133 has_src(tex
, nir_tex_src_ms_index
) ||
134 has_src(tex
, nir_tex_src_texture_offset
) ||
135 has_src(tex
, nir_tex_src_sampler_offset
))
138 /* only prefetch for simple 2d tex fetch case */
139 if (tex
->sampler_dim
!= GLSL_SAMPLER_DIM_2D
|| tex
->is_array
)
142 int idx
= nir_tex_instr_src_index(tex
, nir_tex_src_coord
);
143 /* First source should be the sampling coordinate. */
144 nir_tex_src
*coord
= &tex
->src
[idx
];
145 debug_assert(coord
->src
.is_ssa
);
147 if (ir3_nir_coord_offset(coord
->src
.ssa
) >= 0) {
148 tex
->op
= nir_texop_tex_prefetch
;
158 lower_tex_prefetch_func(nir_function_impl
*impl
)
160 /* Only instructions in the the outer-most block are considered
161 * eligible for pre-dispatch, because they need to be move-able
162 * to the beginning of the shader to avoid locking down the
163 * register holding the pre-fetched result for too long.
165 nir_block
*block
= nir_start_block(impl
);
169 bool progress
= lower_tex_prefetch_block(block
);
172 nir_metadata_preserve(impl
, nir_metadata_block_index
|
173 nir_metadata_dominance
);
180 ir3_nir_lower_tex_prefetch(nir_shader
*shader
)
182 bool progress
= false;
184 assert(shader
->info
.stage
== MESA_SHADER_FRAGMENT
);
186 nir_foreach_function (function
, shader
) {
187 /* Only texture sampling instructions inside the main function
188 * are eligible for pre-dispatch.
190 if (!function
->impl
|| !function
->is_entrypoint
)
193 progress
|= lower_tex_prefetch_func(function
->impl
);