Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/radeonsi/si_nir_optim.c
4570 views
1
/*
2
* Copyright 2021 Advanced Micro Devices, Inc.
3
*
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:
10
*
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
13
* Software.
14
*
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
21
* IN THE SOFTWARE.
22
*/
23
24
#include "si_pipe.h"
25
#include "nir.h"
26
#include "nir_builder.h"
27
#include "nir_worklist.h"
28
29
30
static bool
31
add_src_instr_to_worklist(nir_src *src, void *wl)
32
{
33
if (!src->is_ssa)
34
return false;
35
36
nir_instr_worklist_push_tail(wl, src->ssa->parent_instr);
37
return true;
38
}
39
40
static int
41
get_tex_unit(nir_tex_instr *tex)
42
{
43
int tex_index = nir_tex_instr_src_index(tex, nir_tex_src_texture_deref);
44
if (tex_index >= 0) {
45
nir_deref_instr *deref = nir_src_as_deref(tex->src[tex_index].src);
46
nir_variable *var = nir_deref_instr_get_variable(deref);
47
return var ? var->data.binding : 0;
48
}
49
return -1;
50
}
51
52
static int
53
check_instr_depends_on_tex(nir_intrinsic_instr *store)
54
{
55
int texunit = -1;
56
struct set *instrs = _mesa_set_create(NULL, _mesa_hash_pointer,
57
_mesa_key_pointer_equal);
58
nir_instr_worklist *work = nir_instr_worklist_create();
59
60
_mesa_set_add(instrs, &store->instr);
61
add_src_instr_to_worklist(&store->src[0], work);
62
63
nir_foreach_instr_in_worklist(instr, work) {
64
/* Don't process an instruction twice */
65
if (_mesa_set_search(instrs, instr))
66
continue;
67
68
_mesa_set_add(instrs, instr);
69
70
if (instr->type == nir_instr_type_alu ||
71
instr->type == nir_instr_type_load_const) {
72
/* TODO: ubo, etc */
73
if (!nir_foreach_src(instr, add_src_instr_to_worklist, work))
74
break;
75
continue;
76
} else if (instr->type == nir_instr_type_tex) {
77
if (texunit != -1) {
78
/* We can only depend on a single tex */
79
texunit = -1;
80
break;
81
} else {
82
texunit = get_tex_unit(nir_instr_as_tex(instr));
83
continue;
84
}
85
} else {
86
break;
87
}
88
}
89
90
nir_instr_worklist_destroy(work);
91
_mesa_set_destroy(instrs, NULL);
92
return texunit;
93
}
94
95
static bool
96
get_output_as_const_value(nir_shader *shader, float values[4])
97
{
98
nir_foreach_function(function, shader) {
99
nir_foreach_block_reverse(block, function->impl) {
100
nir_foreach_instr_reverse_safe(instr, block) {
101
switch (instr->type) {
102
case nir_instr_type_intrinsic: {
103
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
104
if (intrin->intrinsic == nir_intrinsic_store_output) {
105
nir_const_value *c = nir_src_as_const_value(intrin->src[0]);
106
if (c) {
107
nir_const_value_to_array(values, c, 4, f32);
108
return true;
109
}
110
return false;
111
}
112
FALLTHROUGH;
113
}
114
default:
115
continue;
116
}
117
}
118
}
119
}
120
return false;
121
}
122
123
struct replace_param {
124
float value[4];
125
int *texunit;
126
};
127
128
static bool
129
store_instr_depends_on_tex(nir_builder *b, nir_instr *instr, void *state)
130
{
131
if (instr->type != nir_instr_type_intrinsic)
132
return false;
133
134
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
135
if (intrin->intrinsic != nir_intrinsic_store_output)
136
return false;
137
138
struct replace_param *p = (struct replace_param*) state;
139
*(p->texunit) = check_instr_depends_on_tex(intrin);
140
141
return *(p->texunit) != -1;
142
}
143
144
145
static bool
146
replace_tex_by_imm(nir_builder *b, nir_instr *instr, void *state)
147
{
148
if (instr->type != nir_instr_type_tex)
149
return false;
150
151
nir_tex_instr *tex = nir_instr_as_tex(instr);
152
struct replace_param *p = (struct replace_param*) state;
153
154
if (get_tex_unit(tex) != *(p->texunit))
155
return false;
156
157
b->cursor = nir_instr_remove(&tex->instr);
158
nir_ssa_def *imm = nir_imm_vec4(b, p->value[0], p->value[1], p->value[2], p->value[3]);
159
nir_ssa_def_rewrite_uses(&tex->dest.ssa, imm);
160
return true;
161
}
162
163
164
/* This function returns true if a shader' sole output becomes constant when
165
* a given texunit is replaced by a constant value.
166
* The input constant value is passed as 'in' and the determined constant
167
* value is stored in 'out'. The texunit is also remembered.
168
*/
169
bool
170
si_nir_is_output_const_if_tex_is_const(nir_shader *shader, float *in, float *out, int *texunit)
171
{
172
assert(shader->info.stage == MESA_SHADER_FRAGMENT);
173
174
if (BITSET_COUNT(shader->info.textures_used) == 0 ||
175
util_bitcount64(shader->info.outputs_written) != 1)
176
return false;
177
178
/* Clone the shader */
179
nir_shader *sh = nir_shader_clone(ralloc_parent(shader), shader);
180
181
struct replace_param p;
182
memcpy(p.value, in, 4 * sizeof(float));
183
p.texunit = texunit;
184
185
/* Test if the single store_output only depends on constants and a single texture op */
186
if (nir_shader_instructions_pass(sh, store_instr_depends_on_tex, nir_metadata_all, &p)) {
187
assert(*p.texunit != -1);
188
189
/* Replace nir_tex_instr using texunit by vec4(v) */
190
nir_shader_instructions_pass(sh, replace_tex_by_imm,
191
nir_metadata_block_index |
192
nir_metadata_dominance, &p);
193
194
/* Optimize the cloned shader */
195
bool progress;
196
do {
197
progress = false;
198
NIR_PASS(progress, sh, nir_copy_prop);
199
NIR_PASS(progress, sh, nir_opt_remove_phis);
200
NIR_PASS(progress, sh, nir_opt_dce);
201
NIR_PASS(progress, sh, nir_opt_dead_cf);
202
NIR_PASS(progress, sh, nir_opt_algebraic);
203
NIR_PASS(progress, sh, nir_opt_constant_folding);
204
} while (progress);
205
206
/* Is the output a constant value? */
207
if (get_output_as_const_value(sh, out)) {
208
ralloc_free(sh);
209
return true;
210
}
211
}
212
ralloc_free(sh);
213
return false;
214
}
215
216