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.
59 #include "nir_builder.h"
60 #include "compiler/glsl/ir_uniform.h"
62 #include "main/compiler.h"
63 #include "main/mtypes.h"
64 #include "program/prog_parameter.h"
65 #include "program/program.h"
67 struct lower_samplers_as_deref_state
{
69 const struct gl_shader_program
*shader_program
;
70 struct hash_table
*remap_table
;
74 remove_struct_derefs(nir_deref
*tail
,
75 struct lower_samplers_as_deref_state
*state
,
76 nir_builder
*b
, char **path
, unsigned *location
)
81 switch (tail
->child
->deref_type
) {
82 case nir_deref_type_array
: {
83 unsigned length
= glsl_get_length(tail
->type
);
85 remove_struct_derefs(tail
->child
, state
, b
, path
, location
);
87 tail
->type
= glsl_get_array_instance(tail
->child
->type
, length
);
91 case nir_deref_type_struct
: {
92 nir_deref_struct
*deref_struct
= nir_deref_as_struct(tail
->child
);
94 *location
+= glsl_get_record_location_offset(tail
->type
, deref_struct
->index
);
95 ralloc_asprintf_append(path
, ".%s",
96 glsl_get_struct_elem_name(tail
->type
, deref_struct
->index
));
98 remove_struct_derefs(tail
->child
, state
, b
, path
, location
);
100 /* Drop the struct deref and re-parent. */
101 ralloc_steal(tail
, tail
->child
->child
);
102 tail
->type
= tail
->child
->type
;
103 tail
->child
= tail
->child
->child
;
108 unreachable("Invalid deref type");
114 lower_deref(nir_deref_var
*deref
,
115 struct lower_samplers_as_deref_state
*state
,
118 nir_variable
*var
= deref
->var
;
119 gl_shader_stage stage
= state
->shader
->stage
;
120 unsigned location
= var
->data
.location
;
122 const struct glsl_type
*orig_type
= deref
->deref
.type
;
125 assert(var
->data
.mode
== nir_var_uniform
);
127 path
= ralloc_asprintf(state
->remap_table
, "lower@%s", var
->name
);
128 remove_struct_derefs(&deref
->deref
, state
, b
, &path
, &location
);
130 assert(location
< state
->shader_program
->data
->NumUniformStorage
&&
131 state
->shader_program
->data
->UniformStorage
[location
].opaque
[stage
].active
);
133 binding
= state
->shader_program
->data
->UniformStorage
[location
].opaque
[stage
].index
;
135 if (orig_type
== deref
->deref
.type
) {
136 /* Fast path: We did not encounter any struct derefs. */
137 var
->data
.binding
= binding
;
141 uint32_t hash
= _mesa_key_hash_string(path
);
142 struct hash_entry
*h
=
143 _mesa_hash_table_search_pre_hashed(state
->remap_table
, hash
, path
);
146 var
= (nir_variable
*)h
->data
;
148 var
= nir_variable_create(state
->shader
, nir_var_uniform
, deref
->deref
.type
, path
);
149 var
->data
.binding
= binding
;
150 _mesa_hash_table_insert_pre_hashed(state
->remap_table
, hash
, path
, var
);
157 lower_sampler(nir_tex_instr
*instr
, struct lower_samplers_as_deref_state
*state
,
160 /* In GLSL, we only fill out the texture field. The sampler is inferred */
161 assert(instr
->texture
!= NULL
);
162 assert(instr
->sampler
== NULL
);
164 b
->cursor
= nir_before_instr(&instr
->instr
);
165 lower_deref(instr
->texture
, state
, b
);
167 if (instr
->op
!= nir_texop_txf_ms
&&
168 instr
->op
!= nir_texop_txf_ms_mcs
&&
169 instr
->op
!= nir_texop_samples_identical
) {
170 nir_instr_rewrite_deref(&instr
->instr
, &instr
->sampler
,
171 nir_deref_var_clone(instr
->texture
, instr
));
173 assert(!instr
->sampler
);
180 lower_intrinsic(nir_intrinsic_instr
*instr
,
181 struct lower_samplers_as_deref_state
*state
,
184 if (instr
->intrinsic
== nir_intrinsic_image_load
||
185 instr
->intrinsic
== nir_intrinsic_image_store
||
186 instr
->intrinsic
== nir_intrinsic_image_atomic_add
||
187 instr
->intrinsic
== nir_intrinsic_image_atomic_min
||
188 instr
->intrinsic
== nir_intrinsic_image_atomic_max
||
189 instr
->intrinsic
== nir_intrinsic_image_atomic_and
||
190 instr
->intrinsic
== nir_intrinsic_image_atomic_or
||
191 instr
->intrinsic
== nir_intrinsic_image_atomic_xor
||
192 instr
->intrinsic
== nir_intrinsic_image_atomic_exchange
||
193 instr
->intrinsic
== nir_intrinsic_image_atomic_comp_swap
||
194 instr
->intrinsic
== nir_intrinsic_image_size
) {
195 b
->cursor
= nir_before_instr(&instr
->instr
);
196 lower_deref(instr
->variables
[0], state
, b
);
204 lower_impl(nir_function_impl
*impl
, struct lower_samplers_as_deref_state
*state
)
207 nir_builder_init(&b
, impl
);
208 bool progress
= false;
210 nir_foreach_block(block
, impl
) {
211 nir_foreach_instr(instr
, block
) {
212 if (instr
->type
== nir_instr_type_tex
)
213 progress
|= lower_sampler(nir_instr_as_tex(instr
), state
, &b
);
214 else if (instr
->type
== nir_instr_type_intrinsic
)
215 progress
|= lower_intrinsic(nir_instr_as_intrinsic(instr
), state
, &b
);
223 nir_lower_samplers_as_deref(nir_shader
*shader
,
224 const struct gl_shader_program
*shader_program
)
226 bool progress
= false;
227 struct lower_samplers_as_deref_state state
;
229 state
.shader
= shader
;
230 state
.shader_program
= shader_program
;
231 state
.remap_table
= _mesa_hash_table_create(NULL
, _mesa_key_hash_string
,
232 _mesa_key_string_equal
);
234 nir_foreach_function(function
, shader
) {
236 progress
|= lower_impl(function
->impl
, &state
);
239 /* keys are freed automatically by ralloc */
240 _mesa_hash_table_destroy(state
.remap_table
, NULL
);