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 "main/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_get_array_instance(*type
, length
);
106 case nir_deref_type_struct
: {
107 *location
+= glsl_get_record_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
);
113 /* skip over the struct type: */
119 unreachable("Invalid deref type");
124 static nir_deref_instr
*
125 lower_deref(nir_builder
*b
, struct lower_samplers_as_deref_state
*state
,
126 nir_deref_instr
*deref
)
128 nir_variable
*var
= nir_deref_instr_get_variable(deref
);
129 gl_shader_stage stage
= state
->shader
->info
.stage
;
131 if (var
->data
.bindless
|| var
->data
.mode
!= nir_var_uniform
)
135 nir_deref_path_init(&path
, deref
, state
->remap_table
);
136 assert(path
.path
[0]->deref_type
== nir_deref_type_var
);
138 char *name
= ralloc_asprintf(state
->remap_table
, "lower@%s", var
->name
);
139 unsigned location
= var
->data
.location
;
140 const struct glsl_type
*type
= NULL
;
144 * We end up needing to do this in two passes, in order to generate
145 * the name of the lowered var (and detecting whether there even are
146 * any struct deref's), and then the second pass to construct the
147 * actual deref instructions after looking up / generating a new
148 * nir_variable (since we need to construct the deref_var first)
151 remove_struct_derefs_prep(path
.path
, &name
, &location
, &type
);
153 assert(location
< state
->shader_program
->data
->NumUniformStorage
&&
154 state
->shader_program
->data
->UniformStorage
[location
].opaque
[stage
].active
);
156 binding
= state
->shader_program
->data
->UniformStorage
[location
].opaque
[stage
].index
;
158 if (var
->type
== type
) {
159 /* Fast path: We did not encounter any struct derefs. */
160 var
->data
.binding
= binding
;
164 uint32_t hash
= _mesa_key_hash_string(name
);
165 struct hash_entry
*h
=
166 _mesa_hash_table_search_pre_hashed(state
->remap_table
, hash
, name
);
169 var
= (nir_variable
*)h
->data
;
171 var
= nir_variable_create(state
->shader
, nir_var_uniform
, type
, name
);
172 var
->data
.binding
= binding
;
173 _mesa_hash_table_insert_pre_hashed(state
->remap_table
, hash
, name
, var
);
176 /* construct a new deref based on lowered var (skipping the struct deref's
177 * from the original deref:
179 nir_deref_instr
*new_deref
= nir_build_deref_var(b
, var
);
180 for (nir_deref_instr
**p
= &path
.path
[1]; *p
; p
++) {
181 if ((*p
)->deref_type
== nir_deref_type_struct
)
184 assert((*p
)->deref_type
== nir_deref_type_array
);
186 new_deref
= nir_build_deref_array(b
, new_deref
,
187 nir_ssa_for_src(b
, (*p
)->arr
.index
, 1));
194 lower_sampler(nir_tex_instr
*instr
, struct lower_samplers_as_deref_state
*state
,
198 nir_tex_instr_src_index(instr
, nir_tex_src_texture_deref
);
200 nir_tex_instr_src_index(instr
, nir_tex_src_sampler_deref
);
205 assert(texture_idx
>= 0 && sampler_idx
>= 0);
206 assert(instr
->src
[texture_idx
].src
.is_ssa
);
207 assert(instr
->src
[sampler_idx
].src
.is_ssa
);
208 assert(instr
->src
[texture_idx
].src
.ssa
== instr
->src
[sampler_idx
].src
.ssa
);
210 b
->cursor
= nir_before_instr(&instr
->instr
);
212 nir_deref_instr
*texture_deref
=
213 lower_deref(b
, state
, nir_src_as_deref(instr
->src
[texture_idx
].src
));
214 /* don't lower bindless: */
217 nir_instr_rewrite_src(&instr
->instr
, &instr
->src
[texture_idx
].src
,
218 nir_src_for_ssa(&texture_deref
->dest
.ssa
));
220 nir_deref_instr
*sampler_deref
=
221 lower_deref(b
, state
, nir_src_as_deref(instr
->src
[sampler_idx
].src
));
222 nir_instr_rewrite_src(&instr
->instr
, &instr
->src
[sampler_idx
].src
,
223 nir_src_for_ssa(&sampler_deref
->dest
.ssa
));
229 lower_intrinsic(nir_intrinsic_instr
*instr
,
230 struct lower_samplers_as_deref_state
*state
,
233 if (instr
->intrinsic
== nir_intrinsic_image_deref_load
||
234 instr
->intrinsic
== nir_intrinsic_image_deref_store
||
235 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_add
||
236 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_min
||
237 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_max
||
238 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_and
||
239 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_or
||
240 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_xor
||
241 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_exchange
||
242 instr
->intrinsic
== nir_intrinsic_image_deref_atomic_comp_swap
||
243 instr
->intrinsic
== nir_intrinsic_image_deref_size
) {
245 b
->cursor
= nir_before_instr(&instr
->instr
);
246 nir_deref_instr
*deref
=
247 lower_deref(b
, state
, nir_src_as_deref(instr
->src
[0]));
248 /* don't lower bindless: */
251 nir_instr_rewrite_src(&instr
->instr
, &instr
->src
[0],
252 nir_src_for_ssa(&deref
->dest
.ssa
));
260 lower_impl(nir_function_impl
*impl
, struct lower_samplers_as_deref_state
*state
)
263 nir_builder_init(&b
, impl
);
264 bool progress
= false;
266 nir_foreach_block(block
, impl
) {
267 nir_foreach_instr(instr
, block
) {
268 if (instr
->type
== nir_instr_type_tex
)
269 progress
|= lower_sampler(nir_instr_as_tex(instr
), state
, &b
);
270 else if (instr
->type
== nir_instr_type_intrinsic
)
271 progress
|= lower_intrinsic(nir_instr_as_intrinsic(instr
), state
, &b
);
279 gl_nir_lower_samplers_as_deref(nir_shader
*shader
,
280 const struct gl_shader_program
*shader_program
)
282 bool progress
= false;
283 struct lower_samplers_as_deref_state state
;
285 state
.shader
= shader
;
286 state
.shader_program
= shader_program
;
287 state
.remap_table
= _mesa_hash_table_create(NULL
, _mesa_key_hash_string
,
288 _mesa_key_string_equal
);
290 nir_foreach_function(function
, shader
) {
292 progress
|= lower_impl(function
->impl
, &state
);
295 /* keys are freed automatically by ralloc */
296 _mesa_hash_table_destroy(state
.remap_table
, NULL
);
299 nir_remove_dead_derefs(shader
);