Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/compiler/glsl/gl_nir_lower_samplers_as_deref.c
4545 views
1
/*
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.
6
*
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:
13
*
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
16
* Software.
17
*
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.
25
*/
26
27
/**
28
* \file
29
*
30
* Lower sampler and image references of (non-bindless) uniforms by removing
31
* struct dereferences, and synthesizing new uniform variables without structs
32
* if required.
33
*
34
* This will allow backends to have a simple, uniform treatment of bindless and
35
* non-bindless samplers and images.
36
*
37
* Example:
38
*
39
* struct S {
40
* sampler2D tex[2];
41
* sampler2D other;
42
* };
43
* uniform S s[2];
44
*
45
* tmp = texture(s[n].tex[m], coord);
46
*
47
* Becomes:
48
*
49
* decl_var uniform INTERP_MODE_NONE sampler2D[2][2] [email protected] (...)
50
*
51
* vec1 32 ssa_idx = $(2 * n + m)
52
* vec4 32 ssa_out = tex ssa_coord (coord), [email protected][n][m] (texture), [email protected][n][m] (sampler)
53
*
54
* and [email protected] has var->data.binding set to the base index as defined by
55
* the opaque uniform mapping.
56
*/
57
58
#include "compiler/nir/nir.h"
59
#include "compiler/nir/nir_builder.h"
60
#include "compiler/nir/nir_deref.h"
61
#include "gl_nir.h"
62
#include "ir_uniform.h"
63
64
#include "util/compiler.h"
65
#include "main/mtypes.h"
66
67
struct lower_samplers_as_deref_state {
68
nir_shader *shader;
69
const struct gl_shader_program *shader_program;
70
struct hash_table *remap_table;
71
};
72
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
78
*
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
84
*/
85
static void
86
remove_struct_derefs_prep(nir_deref_instr **p, char **name,
87
unsigned *location, const struct glsl_type **type)
88
{
89
nir_deref_instr *cur = p[0], *next = p[1];
90
91
if (!next) {
92
*type = cur->type;
93
return;
94
}
95
96
switch (next->deref_type) {
97
case nir_deref_type_array: {
98
unsigned length = glsl_get_length(cur->type);
99
100
remove_struct_derefs_prep(&p[1], name, location, type);
101
102
*type = glsl_array_type(*type, length, glsl_get_explicit_stride(cur->type));
103
break;
104
}
105
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));
110
111
remove_struct_derefs_prep(&p[1], name, location, type);
112
break;
113
}
114
115
default:
116
unreachable("Invalid deref type");
117
break;
118
}
119
}
120
121
static void
122
record_images_used(struct shader_info *info,
123
nir_intrinsic_instr *instr)
124
{
125
nir_variable *var =
126
nir_deref_instr_get_variable(nir_src_as_deref(instr->src[0]));
127
128
/* Structs have been lowered already, so get_aoa_size is sufficient. */
129
const unsigned size =
130
glsl_type_is_array(var->type) ? glsl_get_aoa_size(var->type) : 1;
131
unsigned mask = ((1ull << MAX2(size, 1)) - 1) << var->data.binding;
132
133
info->images_used |= mask;
134
}
135
136
137
static nir_deref_instr *
138
lower_deref(nir_builder *b, struct lower_samplers_as_deref_state *state,
139
nir_deref_instr *deref)
140
{
141
nir_variable *var = nir_deref_instr_get_variable(deref);
142
gl_shader_stage stage = state->shader->info.stage;
143
144
if (var->data.bindless || var->data.mode != nir_var_uniform)
145
return NULL;
146
147
nir_deref_path path;
148
nir_deref_path_init(&path, deref, state->remap_table);
149
assert(path.path[0]->deref_type == nir_deref_type_var);
150
151
char *name = ralloc_asprintf(state->remap_table, "lower@%s", var->name);
152
unsigned location = var->data.location;
153
const struct glsl_type *type = NULL;
154
unsigned binding;
155
156
/*
157
* We end up needing to do this in two passes, in order to generate
158
* the name of the lowered var (and detecting whether there even are
159
* any struct deref's), and then the second pass to construct the
160
* actual deref instructions after looking up / generating a new
161
* nir_variable (since we need to construct the deref_var first)
162
*/
163
164
remove_struct_derefs_prep(path.path, &name, &location, &type);
165
166
if (state->shader_program && var->data.how_declared != nir_var_hidden) {
167
/* For GLSL programs, look up the bindings in the uniform storage. */
168
assert(location < state->shader_program->data->NumUniformStorage &&
169
state->shader_program->data->UniformStorage[location].opaque[stage].active);
170
171
binding = state->shader_program->data->UniformStorage[location].opaque[stage].index;
172
} else {
173
/* For ARB programs, built-in shaders, or internally generated sampler
174
* variables in GLSL programs, assume that whoever created the shader
175
* set the bindings correctly already.
176
*/
177
assert(var->data.explicit_binding);
178
binding = var->data.binding;
179
}
180
181
if (var->type == type) {
182
/* Fast path: We did not encounter any struct derefs. */
183
var->data.binding = binding;
184
return deref;
185
}
186
187
uint32_t hash = _mesa_hash_string(name);
188
struct hash_entry *h =
189
_mesa_hash_table_search_pre_hashed(state->remap_table, hash, name);
190
191
if (h) {
192
var = (nir_variable *)h->data;
193
} else {
194
var = nir_variable_create(state->shader, nir_var_uniform, type, name);
195
var->data.binding = binding;
196
197
/* Don't set var->data.location. The old structure location could be
198
* used to index into gl_uniform_storage, assuming the full structure
199
* was walked in order. With the new split variables, this invariant
200
* no longer holds and there's no meaningful way to start from a base
201
* location and access a particular array element. Just leave it 0.
202
*/
203
204
_mesa_hash_table_insert_pre_hashed(state->remap_table, hash, name, var);
205
}
206
207
/* construct a new deref based on lowered var (skipping the struct deref's
208
* from the original deref:
209
*/
210
nir_deref_instr *new_deref = nir_build_deref_var(b, var);
211
for (nir_deref_instr **p = &path.path[1]; *p; p++) {
212
if ((*p)->deref_type == nir_deref_type_struct)
213
continue;
214
215
assert((*p)->deref_type == nir_deref_type_array);
216
217
new_deref = nir_build_deref_array(b, new_deref,
218
nir_ssa_for_src(b, (*p)->arr.index, 1));
219
}
220
221
return new_deref;
222
}
223
224
static void
225
record_textures_used(struct shader_info *info,
226
nir_deref_instr *deref,
227
nir_texop op)
228
{
229
nir_variable *var = nir_deref_instr_get_variable(deref);
230
231
/* Structs have been lowered already, so get_aoa_size is sufficient. */
232
const unsigned size =
233
glsl_type_is_array(var->type) ? glsl_get_aoa_size(var->type) : 1;
234
235
BITSET_SET_RANGE(info->textures_used, var->data.binding, var->data.binding + (MAX2(size, 1) - 1));
236
237
if (op == nir_texop_txf ||
238
op == nir_texop_txf_ms ||
239
op == nir_texop_txf_ms_mcs)
240
BITSET_SET_RANGE(info->textures_used_by_txf, var->data.binding, var->data.binding + (MAX2(size, 1) - 1));
241
}
242
243
static bool
244
lower_sampler(nir_tex_instr *instr, struct lower_samplers_as_deref_state *state,
245
nir_builder *b)
246
{
247
int texture_idx =
248
nir_tex_instr_src_index(instr, nir_tex_src_texture_deref);
249
int sampler_idx =
250
nir_tex_instr_src_index(instr, nir_tex_src_sampler_deref);
251
252
b->cursor = nir_before_instr(&instr->instr);
253
254
if (texture_idx >= 0) {
255
assert(instr->src[texture_idx].src.is_ssa);
256
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: */
260
if (texture_deref) {
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);
264
}
265
}
266
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: */
272
if (sampler_deref) {
273
nir_instr_rewrite_src(&instr->instr, &instr->src[sampler_idx].src,
274
nir_src_for_ssa(&sampler_deref->dest.ssa));
275
}
276
}
277
278
return true;
279
}
280
281
static bool
282
lower_intrinsic(nir_intrinsic_instr *instr,
283
struct lower_samplers_as_deref_state *state,
284
nir_builder *b)
285
{
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) {
300
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]));
304
305
record_images_used(&state->shader->info, instr);
306
307
/* don't lower bindless: */
308
if (!deref)
309
return false;
310
nir_instr_rewrite_src(&instr->instr, &instr->src[0],
311
nir_src_for_ssa(&deref->dest.ssa));
312
return true;
313
}
314
315
return false;
316
}
317
318
static bool
319
lower_impl(nir_function_impl *impl, struct lower_samplers_as_deref_state *state)
320
{
321
nir_builder b;
322
nir_builder_init(&b, impl);
323
bool progress = false;
324
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);
331
}
332
}
333
334
if (progress) {
335
nir_metadata_preserve(impl, nir_metadata_block_index |
336
nir_metadata_dominance);
337
} else {
338
nir_metadata_preserve(impl, nir_metadata_all);
339
}
340
341
return progress;
342
}
343
344
bool
345
gl_nir_lower_samplers_as_deref(nir_shader *shader,
346
const struct gl_shader_program *shader_program)
347
{
348
bool progress = false;
349
struct lower_samplers_as_deref_state state;
350
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);
355
356
nir_foreach_function(function, shader) {
357
if (function->impl)
358
progress |= lower_impl(function->impl, &state);
359
}
360
361
/* keys are freed automatically by ralloc */
362
_mesa_hash_table_destroy(state.remap_table, NULL);
363
364
if (progress)
365
nir_remove_dead_derefs(shader);
366
367
return progress;
368
}
369
370