2 * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
3 * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
4 * Copyright © 2014 Intel Corporation
5 * Copyright © 2017 Advanced Micro Devices, Inc.
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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * 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 NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
30 * Lower sampler and image references of (non-bindless) uniforms by removing
31 * struct dereferences, and synthesizing new uniform variables without structs
34 * This will allow backends to have a simple, uniform treatment of bindless and
35 * non-bindless samplers and images.
45 * tmp = texture(s[n].tex[m], coord);
49 * decl_var uniform INTERP_MODE_NONE sampler2D[2][2] lower@s.tex (...)
51 * vec1 32 ssa_idx = $(2 * n + m)
52 * vec4 32 ssa_out = tex ssa_coord (coord), lower@s.tex[n][m] (texture), lower@s.tex[n][m] (sampler)
54 * and lower@s.tex has var->data.binding set to the base index as defined by
55 * the opaque uniform mapping.
58 #include "compiler/nir/nir.h"
59 #include "compiler/nir/nir_builder.h"
60 #include "compiler/nir/nir_deref.h"
62 #include "ir_uniform.h"
64 #include "util/compiler.h"
65 #include "main/mtypes.h"
67 struct lower_samplers_as_deref_state
{
69 const struct gl_shader_program
*shader_program
;
70 struct hash_table
*remap_table
;
73 /* Prepare for removing struct derefs. This pre-pass generates the name
74 * of the lowered deref, and calculates the lowered type and location.
75 * After that, once looking up (or creating if needed) the lowered var,
76 * constructing the new chain of deref instructions is a simple loop
77 * that skips the struct deref's
79 * path: appended to as we descend down the chain of deref instrs
80 * and remove struct derefs
81 * location: increased as we descend down and remove struct derefs
82 * type: updated as we recurse back up the chain of deref instrs
83 * with the resulting type after removing struct derefs
86 remove_struct_derefs_prep(nir_deref_instr
**p
, char **name
,
87 unsigned *location
, const struct glsl_type
**type
)
89 nir_deref_instr
*cur
= p
[0], *next
= p
[1];
96 switch (next
->deref_type
) {
97 case nir_deref_type_array
: {
98 unsigned length
= glsl_get_length(cur
->type
);
100 remove_struct_derefs_prep(&p
[1], name
, location
, type
);
102 *type
= glsl_array_type(*type
, length
, glsl_get_explicit_stride(cur
->type
));
106 case nir_deref_type_struct
: {
107 *location
+= glsl_get_struct_location_offset(cur
->type
, next
->strct
.index
);
108 ralloc_asprintf_append(name
, ".%s",
109 glsl_get_struct_elem_name(cur
->type
, next
->strct
.index
));
111 remove_struct_derefs_prep(&p
[1], name
, location
, type
);
116 unreachable("Invalid deref type");
122 record_images_used(struct shader_info
*info
,
123 nir_deref_instr
*deref
)
125 nir_variable
*var
= nir_deref_instr_get_variable(deref
);
127 /* Structs have been lowered already, so get_aoa_size is sufficient. */
128 const unsigned size
=
129 glsl_type_is_array(var
->type
) ? glsl_get_aoa_size(var
->type
) : 1;
130 unsigned mask
= ((1ull << MAX2(size
, 1)) - 1) << var
->data
.binding
;
132 info
->images_used
|= mask
;
136 static nir_deref_instr
*
137 lower_deref(nir_builder
*b
, struct lower_samplers_as_deref_state
*state
,
138 nir_deref_instr
*deref
)
140 nir_variable
*var
= nir_deref_instr_get_variable(deref
);
141 gl_shader_stage stage
= state
->shader
->info
.stage
;
143 if (var
->data
.bindless
|| var
->data
.mode
!= nir_var_uniform
)
147 nir_deref_path_init(&path
, deref
, state
->remap_table
);
148 assert(path
.path
[0]->deref_type
== nir_deref_type_var
);
150 char *name
= ralloc_asprintf(state
->remap_table
, "lower@%s", var
->name
);
151 unsigned location
= var
->data
.location
;
152 const struct glsl_type
*type
= NULL
;
156 * We end up needing to do this in two passes, in order to generate
157 * the name of the lowered var (and detecting whether there even are
158 * any struct deref's), and then the second pass to construct the
159 * actual deref instructions after looking up / generating a new
160 * nir_variable (since we need to construct the deref_var first)
163 remove_struct_derefs_prep(path
.path
, &name
, &location
, &type
);
165 if (state
->shader_program
&& var
->data
.how_declared
!= nir_var_hidden
) {
166 /* For GLSL programs, look up the bindings in the uniform storage. */
167 assert(location
< state
->shader_program
->data
->NumUniformStorage
&&
168 state
->shader_program
->data
->UniformStorage
[location
].opaque
[stage
].active
);
170 binding
= state
->shader_program
->data
->UniformStorage
[location
].opaque
[stage
].index
;
172 /* For ARB programs, built-in shaders, or internally generated sampler
173 * variables in GLSL programs, assume that whoever created the shader
174 * set the bindings correctly already.
176 assert(var
->data
.explicit_binding
);
177 binding
= var
->data
.binding
;
180 if (var
->type
== type
) {
181 /* Fast path: We did not encounter any struct derefs. */
182 var
->data
.binding
= binding
;
186 uint32_t hash
= _mesa_hash_string(name
);
187 struct hash_entry
*h
=
188 _mesa_hash_table_search_pre_hashed(state
->remap_table
, hash
, name
);
191 var
= (nir_variable
*)h
->data
;
193 var
= nir_variable_create(state
->shader
, nir_var_uniform
, type
, name
);
194 var
->data
.binding
= binding
;
196 /* Don't set var->data.location. The old structure location could be
197 * used to index into gl_uniform_storage, assuming the full structure
198 * was walked in order. With the new split variables, this invariant
199 * no longer holds and there's no meaningful way to start from a base
200 * location and access a particular array element. Just leave it 0.
203 _mesa_hash_table_insert_pre_hashed(state
->remap_table
, hash
, name
, var
);
206 /* construct a new deref based on lowered var (skipping the struct deref's
207 * from the original deref:
209 nir_deref_instr
*new_deref
= nir_build_deref_var(b
, var
);
210 for (nir_deref_instr
**p
= &path
.path
[1]; *p
; p
++) {
211 if ((*p
)->deref_type
== nir_deref_type_struct
)
214 assert((*p
)->deref_type
== nir_deref_type_array
);
216 new_deref
= nir_build_deref_array(b
, new_deref
,
217 nir_ssa_for_src(b
, (*p
)->arr
.index
, 1));
224 record_textures_used(struct shader_info
*info
,
225 nir_deref_instr
*deref
,
228 nir_variable
*var
= nir_deref_instr_get_variable(deref
);
230 /* Structs have been lowered already, so get_aoa_size is sufficient. */
231 const unsigned size
=
232 glsl_type_is_array(var
->type
) ? glsl_get_aoa_size(var
->type
) : 1;
233 unsigned mask
= ((1ull << MAX2(size
, 1)) - 1) << var
->data
.binding
;
235 info
->textures_used
|= mask
;
237 if (op
== nir_texop_txf
||
238 op
== nir_texop_txf_ms
||
239 op
== nir_texop_txf_ms_mcs
)
240 info
->textures_used_by_txf
|= mask
;
244 lower_sampler(nir_tex_instr
*instr
, struct lower_samplers_as_deref_state
*state
,
248 nir_tex_instr_src_index(instr
, nir_tex_src_texture_deref
);
250 nir_tex_instr_src_index(instr
, nir_tex_src_sampler_deref
);
252 b
->cursor
= nir_before_instr(&instr
->instr
);
254 if (texture_idx
>= 0) {
255 assert(instr
->src
[texture_idx
].src
.is_ssa
);
257 nir_deref_instr
*texture_deref
=
258 lower_deref(b
, state
, nir_src_as_deref(instr
->src
[texture_idx
].src
));
259 /* only lower non-bindless: */
261 nir_instr_rewrite_src(&instr
->instr
, &instr
->src
[texture_idx
].src
,
262 nir_src_for_ssa(&texture_deref
->dest
.ssa
));
263 record_textures_used(&b
->shader
->info
, texture_deref
, instr
->op
);
267 if (sampler_idx
>= 0) {
268 assert(instr
->src
[sampler_idx
].src
.is_ssa
);
269 nir_deref_instr
*sampler_deref
=
270 lower_deref(b
, state
, nir_src_as_deref(instr
->src
[sampler_idx
].src
));
271 /* only lower non-bindless: */
273 nir_instr_rewrite_src(&instr
->instr
, &instr
->src
[sampler_idx
].src
,
274 nir_src_for_ssa(&sampler_deref
->dest
.ssa
));
282 lower_intrinsic(nir_intrinsic_instr
*instr
,
283 struct lower_samplers_as_deref_state
*state
,
286 if (instr
->intrinsic
== nir_intrinsic_image_deref_load
||
287 instr
->intrinsic
== nir_intrinsic_image_deref_store
||
288 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_add
||
289 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_imin
||
290 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_umin
||
291 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_imax
||
292 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_umax
||
293 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_and
||
294 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_or
||
295 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_xor
||
296 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_exchange
||
297 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_comp_swap
||
298 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_fadd
||
299 instr
->intrinsic
== nir_intrinsic_image_deref_size
) {
301 b
->cursor
= nir_before_instr(&instr
->instr
);
302 nir_deref_instr
*deref
=
303 lower_deref(b
, state
, nir_src_as_deref(instr
->src
[0]));
305 record_images_used(&state
->shader
->info
, deref
);
307 /* don't lower bindless: */
310 nir_instr_rewrite_src(&instr
->instr
, &instr
->src
[0],
311 nir_src_for_ssa(&deref
->dest
.ssa
));
319 lower_impl(nir_function_impl
*impl
, struct lower_samplers_as_deref_state
*state
)
322 nir_builder_init(&b
, impl
);
323 bool progress
= false;
325 nir_foreach_block(block
, impl
) {
326 nir_foreach_instr(instr
, block
) {
327 if (instr
->type
== nir_instr_type_tex
)
328 progress
|= lower_sampler(nir_instr_as_tex(instr
), state
, &b
);
329 else if (instr
->type
== nir_instr_type_intrinsic
)
330 progress
|= lower_intrinsic(nir_instr_as_intrinsic(instr
), state
, &b
);
335 nir_metadata_preserve(impl
, nir_metadata_block_index
|
336 nir_metadata_dominance
);
338 nir_metadata_preserve(impl
, nir_metadata_all
);
345 gl_nir_lower_samplers_as_deref(nir_shader
*shader
,
346 const struct gl_shader_program
*shader_program
)
348 bool progress
= false;
349 struct lower_samplers_as_deref_state state
;
351 state
.shader
= shader
;
352 state
.shader_program
= shader_program
;
353 state
.remap_table
= _mesa_hash_table_create(NULL
, _mesa_hash_string
,
354 _mesa_key_string_equal
);
356 nir_foreach_function(function
, shader
) {
358 progress
|= lower_impl(function
->impl
, &state
);
361 /* keys are freed automatically by ralloc */
362 _mesa_hash_table_destroy(state
.remap_table
, NULL
);
365 nir_remove_dead_derefs(shader
);