2 * Copyright © 2019 Valve Corporation
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:
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
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
26 /* This pass optimizes GL access qualifiers. So far it does two things:
28 * - Infer readonly when it's missing.
29 * - Infer ACCESS_CAN_REORDER when the following are true:
30 * - Either there are no writes, or ACCESS_NON_WRITEABLE and ACCESS_RESTRICT
31 * are both set. In either case there are no writes to the underlying
33 * - If ACCESS_COHERENT is set, then there must be no memory barriers
34 * involving the access. Coherent accesses may return different results
35 * before and after barriers.
36 * - ACCESS_VOLATILE is not set.
38 * If these conditions are true, then image and buffer reads may be treated as
39 * if they were uniform buffer reads, i.e. they may be arbitrarily moved,
40 * combined, rematerialized etc.
44 struct set
*vars_written
;
52 gather_intrinsic(struct access_state
*state
, nir_intrinsic_instr
*instr
)
55 switch (instr
->intrinsic
) {
56 case nir_intrinsic_image_deref_store
:
57 case nir_intrinsic_image_deref_atomic_add
:
58 case nir_intrinsic_image_deref_atomic_imin
:
59 case nir_intrinsic_image_deref_atomic_umin
:
60 case nir_intrinsic_image_deref_atomic_imax
:
61 case nir_intrinsic_image_deref_atomic_umax
:
62 case nir_intrinsic_image_deref_atomic_and
:
63 case nir_intrinsic_image_deref_atomic_or
:
64 case nir_intrinsic_image_deref_atomic_xor
:
65 case nir_intrinsic_image_deref_atomic_exchange
:
66 case nir_intrinsic_image_deref_atomic_comp_swap
:
67 case nir_intrinsic_image_deref_atomic_fadd
:
68 var
= nir_intrinsic_get_var(instr
, 0);
70 /* In OpenGL, buffer images use normal buffer objects, whereas other
71 * image types use textures which cannot alias with buffer objects.
72 * Therefore we have to group buffer samplers together with SSBO's.
74 if (glsl_get_sampler_dim(glsl_without_array(var
->type
)) ==
76 state
->buffers_written
= true;
78 state
->images_written
= true;
80 if (var
->data
.mode
== nir_var_uniform
)
81 _mesa_set_add(state
->vars_written
, var
);
84 case nir_intrinsic_bindless_image_store
:
85 case nir_intrinsic_bindless_image_atomic_add
:
86 case nir_intrinsic_bindless_image_atomic_imin
:
87 case nir_intrinsic_bindless_image_atomic_umin
:
88 case nir_intrinsic_bindless_image_atomic_imax
:
89 case nir_intrinsic_bindless_image_atomic_umax
:
90 case nir_intrinsic_bindless_image_atomic_and
:
91 case nir_intrinsic_bindless_image_atomic_or
:
92 case nir_intrinsic_bindless_image_atomic_xor
:
93 case nir_intrinsic_bindless_image_atomic_exchange
:
94 case nir_intrinsic_bindless_image_atomic_comp_swap
:
95 case nir_intrinsic_bindless_image_atomic_fadd
:
96 if (nir_intrinsic_image_dim(instr
) == GLSL_SAMPLER_DIM_BUF
)
97 state
->buffers_written
= true;
99 state
->images_written
= true;
102 case nir_intrinsic_store_deref
:
103 case nir_intrinsic_deref_atomic_add
:
104 case nir_intrinsic_deref_atomic_imin
:
105 case nir_intrinsic_deref_atomic_umin
:
106 case nir_intrinsic_deref_atomic_imax
:
107 case nir_intrinsic_deref_atomic_umax
:
108 case nir_intrinsic_deref_atomic_and
:
109 case nir_intrinsic_deref_atomic_or
:
110 case nir_intrinsic_deref_atomic_xor
:
111 case nir_intrinsic_deref_atomic_exchange
:
112 case nir_intrinsic_deref_atomic_comp_swap
:
113 case nir_intrinsic_deref_atomic_fadd
:
114 case nir_intrinsic_deref_atomic_fmin
:
115 case nir_intrinsic_deref_atomic_fmax
:
116 case nir_intrinsic_deref_atomic_fcomp_swap
:
117 var
= nir_intrinsic_get_var(instr
, 0);
118 if (var
->data
.mode
!= nir_var_mem_ssbo
)
121 _mesa_set_add(state
->vars_written
, var
);
122 state
->buffers_written
= true;
124 case nir_intrinsic_memory_barrier
:
125 state
->buffer_barriers
= true;
126 state
->image_barriers
= true;
129 case nir_intrinsic_memory_barrier_buffer
:
130 state
->buffer_barriers
= true;
133 case nir_intrinsic_memory_barrier_image
:
134 state
->image_barriers
= true;
137 case nir_intrinsic_scoped_memory_barrier
:
138 /* TODO: Could be more granular if we had nir_var_mem_image. */
139 if (nir_intrinsic_memory_modes(instr
) & (nir_var_mem_ubo
|
142 state
->buffer_barriers
= true;
143 state
->image_barriers
= true;
153 process_variable(struct access_state
*state
, nir_variable
*var
)
155 if (var
->data
.mode
!= nir_var_mem_ssbo
&&
156 !(var
->data
.mode
== nir_var_uniform
&&
157 glsl_type_is_image(var
->type
)))
160 /* Ignore variables we've already marked */
161 if (var
->data
.access
& ACCESS_CAN_REORDER
)
164 if (!(var
->data
.access
& ACCESS_NON_WRITEABLE
) &&
165 !_mesa_set_search(state
->vars_written
, var
)) {
166 var
->data
.access
|= ACCESS_NON_WRITEABLE
;
174 can_reorder(struct access_state
*state
, enum gl_access_qualifier access
,
175 bool is_buffer
, bool is_ssbo
)
177 bool is_any_written
= is_buffer
? state
->buffers_written
:
178 state
->images_written
;
180 /* Can we guarantee that the underlying memory is never written? */
181 if (!is_any_written
||
182 ((access
& ACCESS_NON_WRITEABLE
) &&
183 (access
& ACCESS_RESTRICT
))) {
184 /* Note: memoryBarrierBuffer() is only guaranteed to flush buffer
185 * variables and not imageBuffer's, so we only consider the GL-level
188 bool is_any_barrier
= is_ssbo
?
189 state
->buffer_barriers
: state
->image_barriers
;
191 return (!is_any_barrier
|| !(access
& ACCESS_COHERENT
)) &&
192 !(access
& ACCESS_VOLATILE
);
199 process_intrinsic(struct access_state
*state
, nir_intrinsic_instr
*instr
)
201 switch (instr
->intrinsic
) {
202 case nir_intrinsic_bindless_image_load
:
203 if (nir_intrinsic_access(instr
) & ACCESS_CAN_REORDER
)
206 /* We have less information about bindless intrinsics, since we can't
207 * always trace uses back to the variable. Don't try and infer if it's
208 * read-only, unless there are no image writes at all.
210 bool progress
= false;
212 nir_intrinsic_image_dim(instr
) == GLSL_SAMPLER_DIM_BUF
;
214 bool is_any_written
=
215 is_buffer
? state
->buffers_written
: state
->images_written
;
217 if (!(nir_intrinsic_access(instr
) & ACCESS_NON_WRITEABLE
) &&
220 nir_intrinsic_set_access(instr
,
221 nir_intrinsic_access(instr
) |
222 ACCESS_NON_WRITEABLE
);
225 if (can_reorder(state
, nir_intrinsic_access(instr
), is_buffer
, false)) {
227 nir_intrinsic_set_access(instr
,
228 nir_intrinsic_access(instr
) |
234 case nir_intrinsic_load_deref
:
235 case nir_intrinsic_image_deref_load
: {
236 nir_variable
*var
= nir_intrinsic_get_var(instr
, 0);
238 if (instr
->intrinsic
== nir_intrinsic_load_deref
&&
239 var
->data
.mode
!= nir_var_mem_ssbo
)
242 if (nir_intrinsic_access(instr
) & ACCESS_CAN_REORDER
)
245 bool progress
= false;
247 /* Check if we were able to mark the whole variable non-writeable */
248 if (!(nir_intrinsic_access(instr
) & ACCESS_NON_WRITEABLE
) &&
249 var
->data
.access
& ACCESS_NON_WRITEABLE
) {
251 nir_intrinsic_set_access(instr
,
252 nir_intrinsic_access(instr
) |
253 ACCESS_NON_WRITEABLE
);
256 bool is_ssbo
= var
->data
.mode
== nir_var_mem_ssbo
;
258 bool is_buffer
= is_ssbo
||
259 glsl_get_sampler_dim(glsl_without_array(var
->type
)) == GLSL_SAMPLER_DIM_BUF
;
261 if (can_reorder(state
, nir_intrinsic_access(instr
), is_buffer
, is_ssbo
)) {
263 nir_intrinsic_set_access(instr
,
264 nir_intrinsic_access(instr
) |
277 opt_access_impl(struct access_state
*state
,
278 nir_function_impl
*impl
)
280 bool progress
= false;
282 nir_foreach_block(block
, impl
) {
283 nir_foreach_instr(instr
, block
) {
284 if (instr
->type
== nir_instr_type_intrinsic
)
285 progress
|= process_intrinsic(state
,
286 nir_instr_as_intrinsic(instr
));
291 nir_metadata_preserve(impl
,
292 nir_metadata_block_index
|
293 nir_metadata_dominance
|
294 nir_metadata_live_ssa_defs
|
295 nir_metadata_loop_analysis
);
303 nir_opt_access(nir_shader
*shader
)
305 struct access_state state
= {
306 .vars_written
= _mesa_pointer_set_create(NULL
),
309 bool var_progress
= false;
310 bool progress
= false;
312 nir_foreach_function(func
, shader
) {
314 nir_foreach_block(block
, func
->impl
) {
315 nir_foreach_instr(instr
, block
) {
316 if (instr
->type
== nir_instr_type_intrinsic
)
317 gather_intrinsic(&state
, nir_instr_as_intrinsic(instr
));
323 nir_foreach_variable(var
, &shader
->uniforms
)
324 var_progress
|= process_variable(&state
, var
);
326 nir_foreach_function(func
, shader
) {
328 progress
|= opt_access_impl(&state
, func
->impl
);
330 /* If we make a change to the uniforms, update all the impls. */
332 nir_metadata_preserve(func
->impl
,
333 nir_metadata_block_index
|
334 nir_metadata_dominance
|
335 nir_metadata_live_ssa_defs
|
336 nir_metadata_loop_analysis
);
341 progress
|= var_progress
;
343 _mesa_set_destroy(state
.vars_written
, NULL
);