Advertisement
Guest User

Untitled

a guest
May 11th, 2021
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.98 KB | None | 0 0
  1. /*
  2. * Copyright © 2019 Valve Corporation
  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 "nir.h"
  25.  
  26. /* This pass optimizes GL access qualifiers. So far it does three things:
  27. *
  28. * - Infer readonly when it's missing.
  29. * - Infer writeonly when it's missing.
  30. * - Infer ACCESS_CAN_REORDER when the following are true:
  31. * - Either there are no writes, or ACCESS_NON_WRITEABLE is set. In either
  32. * case there are no writes to the underlying memory.
  33. * - ACCESS_VOLATILE is not set.
  34. *
  35. * If these conditions are true, then image and buffer reads may be treated as
  36. * if they were uniform buffer reads, i.e. they may be arbitrarily moved,
  37. * combined, rematerialized etc.
  38. */
  39.  
  40. struct access_state {
  41. nir_shader *shader;
  42. bool infer_non_readable;
  43.  
  44. struct set *vars_written;
  45. struct set *vars_read;
  46. bool images_written;
  47. bool buffers_written;
  48. bool images_read;
  49. bool buffers_read;
  50. };
  51.  
  52. static const nir_variable *
  53. get_binding_variable(struct access_state *state, nir_src rsrc)
  54. {
  55. nir_binding binding = nir_chase_binding(rsrc);
  56. const nir_variable *binding_var = nir_get_binding_variable(state->shader, binding);
  57.  
  58. if (!binding_var)
  59. return NULL;
  60.  
  61. /* Be conservative if another variable is using the same binding/desc_set
  62. * because the access mask might be different and we can't get it reliably.
  63. */
  64. nir_foreach_variable_with_modes(var, state->shader, nir_var_mem_ubo | nir_var_mem_ssbo) {
  65. if (binding_var != var &&
  66. var->data.descriptor_set == binding.desc_set &&
  67. var->data.binding == binding.binding) {
  68. return NULL;
  69. }
  70. }
  71.  
  72. return binding_var;
  73. }
  74.  
  75. static void
  76. gather_buffer_access(struct access_state *state, nir_ssa_def *def, bool read, bool write)
  77. {
  78. state->buffers_read |= read;
  79. state->buffers_written |= write;
  80.  
  81. if (!def)
  82. return;
  83.  
  84. const nir_variable *var = get_binding_variable(state, nir_src_for_ssa(def));
  85.  
  86. if (var) {
  87. if (read)
  88. _mesa_set_add(state->vars_read, var);
  89. if (write)
  90. _mesa_set_add(state->vars_written, var);
  91. } else {
  92. nir_foreach_variable_with_modes(possible_var, state->shader, nir_var_mem_ssbo) {
  93. if (read)
  94. _mesa_set_add(state->vars_read, possible_var);
  95. if (write)
  96. _mesa_set_add(state->vars_written, possible_var);
  97. }
  98. }
  99. }
  100.  
  101. static void
  102. gather_intrinsic(struct access_state *state, nir_intrinsic_instr *instr)
  103. {
  104. const nir_variable *var;
  105. bool read, write;
  106. switch (instr->intrinsic) {
  107. case nir_intrinsic_image_deref_load:
  108. case nir_intrinsic_image_deref_store:
  109. case nir_intrinsic_image_deref_sparse_load:
  110. case nir_intrinsic_image_deref_atomic_add:
  111. case nir_intrinsic_image_deref_atomic_imin:
  112. case nir_intrinsic_image_deref_atomic_umin:
  113. case nir_intrinsic_image_deref_atomic_imax:
  114. case nir_intrinsic_image_deref_atomic_umax:
  115. case nir_intrinsic_image_deref_atomic_and:
  116. case nir_intrinsic_image_deref_atomic_or:
  117. case nir_intrinsic_image_deref_atomic_xor:
  118. case nir_intrinsic_image_deref_atomic_exchange:
  119. case nir_intrinsic_image_deref_atomic_comp_swap:
  120. case nir_intrinsic_image_deref_atomic_fadd:
  121. case nir_intrinsic_image_deref_atomic_fmin:
  122. case nir_intrinsic_image_deref_atomic_fmax:
  123. var = nir_intrinsic_get_var(instr, 0);
  124. read = instr->intrinsic != nir_intrinsic_image_deref_store;
  125. write = instr->intrinsic != nir_intrinsic_image_deref_load &&
  126. instr->intrinsic != nir_intrinsic_image_deref_sparse_load;
  127.  
  128. /* In OpenGL, buffer images use normal buffer objects, whereas other
  129. * image types use textures which cannot alias with buffer objects.
  130. * Therefore we have to group buffer samplers together with SSBO's.
  131. */
  132. if (glsl_get_sampler_dim(glsl_without_array(var->type)) ==
  133. GLSL_SAMPLER_DIM_BUF) {
  134. state->buffers_read |= read;
  135. state->buffers_written |= write;
  136. } else {
  137. state->images_read |= read;
  138. state->images_written |= write;
  139. }
  140.  
  141. if (var->data.mode == nir_var_uniform && read)
  142. _mesa_set_add(state->vars_read, var);
  143. if (var->data.mode == nir_var_uniform && write)
  144. _mesa_set_add(state->vars_written, var);
  145. break;
  146.  
  147. case nir_intrinsic_bindless_image_load:
  148. case nir_intrinsic_bindless_image_store:
  149. case nir_intrinsic_bindless_image_sparse_load:
  150. case nir_intrinsic_bindless_image_atomic_add:
  151. case nir_intrinsic_bindless_image_atomic_imin:
  152. case nir_intrinsic_bindless_image_atomic_umin:
  153. case nir_intrinsic_bindless_image_atomic_imax:
  154. case nir_intrinsic_bindless_image_atomic_umax:
  155. case nir_intrinsic_bindless_image_atomic_and:
  156. case nir_intrinsic_bindless_image_atomic_or:
  157. case nir_intrinsic_bindless_image_atomic_xor:
  158. case nir_intrinsic_bindless_image_atomic_exchange:
  159. case nir_intrinsic_bindless_image_atomic_comp_swap:
  160. case nir_intrinsic_bindless_image_atomic_fadd:
  161. case nir_intrinsic_bindless_image_atomic_fmin:
  162. case nir_intrinsic_bindless_image_atomic_fmax:
  163. read = instr->intrinsic != nir_intrinsic_bindless_image_store;
  164. write = instr->intrinsic != nir_intrinsic_bindless_image_load &&
  165. instr->intrinsic != nir_intrinsic_bindless_image_sparse_load;
  166.  
  167. if (nir_intrinsic_image_dim(instr) == GLSL_SAMPLER_DIM_BUF) {
  168. state->buffers_read |= read;
  169. state->buffers_written |= write;
  170. } else {
  171. state->images_read |= read;
  172. state->images_written |= write;
  173. }
  174. break;
  175.  
  176. case nir_intrinsic_load_deref:
  177. case nir_intrinsic_store_deref:
  178. case nir_intrinsic_deref_atomic_add:
  179. case nir_intrinsic_deref_atomic_imin:
  180. case nir_intrinsic_deref_atomic_umin:
  181. case nir_intrinsic_deref_atomic_imax:
  182. case nir_intrinsic_deref_atomic_umax:
  183. case nir_intrinsic_deref_atomic_and:
  184. case nir_intrinsic_deref_atomic_or:
  185. case nir_intrinsic_deref_atomic_xor:
  186. case nir_intrinsic_deref_atomic_exchange:
  187. case nir_intrinsic_deref_atomic_comp_swap:
  188. case nir_intrinsic_deref_atomic_fadd:
  189. case nir_intrinsic_deref_atomic_fmin:
  190. case nir_intrinsic_deref_atomic_fmax:
  191. case nir_intrinsic_deref_atomic_fcomp_swap: {
  192. nir_deref_instr *deref = nir_src_as_deref(instr->src[0]);
  193. if (!nir_deref_mode_may_be(deref, nir_var_mem_ssbo | nir_var_mem_global))
  194. break;
  195.  
  196. bool ssbo = nir_deref_mode_is(deref, nir_var_mem_ssbo);
  197. gather_buffer_access(state, ssbo ? instr->src[0].ssa : NULL,
  198. instr->intrinsic != nir_intrinsic_store_deref,
  199. instr->intrinsic != nir_intrinsic_load_deref);
  200. break;
  201. }
  202.  
  203. default:
  204. break;
  205. }
  206. }
  207.  
  208. static bool
  209. process_variable(struct access_state *state, nir_variable *var)
  210. {
  211. const struct glsl_type *type = glsl_without_array(var->type);
  212. if (var->data.mode != nir_var_mem_ssbo &&
  213. !(var->data.mode == nir_var_uniform && glsl_type_is_image(type)))
  214. return false;
  215.  
  216. /* Ignore variables we've already marked */
  217. if (var->data.access & ACCESS_CAN_REORDER)
  218. return false;
  219.  
  220. unsigned access = var->data.access;
  221. bool is_buffer = var->data.mode == nir_var_mem_ssbo ||
  222. glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_BUF;
  223.  
  224. if (!(access & ACCESS_NON_WRITEABLE)) {
  225. if (is_buffer ? !state->buffers_written : !state->images_written)
  226. access |= ACCESS_NON_WRITEABLE;
  227. else if ((access & ACCESS_RESTRICT) && !_mesa_set_search(state->vars_written, var))
  228. access |= ACCESS_NON_WRITEABLE;
  229. }
  230.  
  231. if (state->infer_non_readable && !(access & ACCESS_NON_READABLE)) {
  232. if (is_buffer ? !state->buffers_read : !state->images_read)
  233. access |= ACCESS_NON_READABLE;
  234. else if ((access & ACCESS_RESTRICT) && !_mesa_set_search(state->vars_read, var))
  235. access |= ACCESS_NON_READABLE;
  236. }
  237.  
  238. bool changed = var->data.access != access;
  239. var->data.access = access;
  240. return changed;
  241. }
  242.  
  243. static bool
  244. update_access(struct access_state *state, nir_intrinsic_instr *instr, bool is_image, bool is_buffer)
  245. {
  246. enum gl_access_qualifier access = nir_intrinsic_access(instr);
  247.  
  248. bool is_memory_readonly = access & ACCESS_NON_WRITEABLE;
  249. bool is_memory_writeonly = access & ACCESS_NON_READABLE;
  250.  
  251. if (instr->intrinsic != nir_intrinsic_bindless_image_load &&
  252. instr->intrinsic != nir_intrinsic_bindless_image_store &&
  253. instr->intrinsic != nir_intrinsic_bindless_image_sparse_load) {
  254. const nir_variable *var = get_binding_variable(state, instr->src[0]);
  255. is_memory_readonly |= var && (var->data.access & ACCESS_NON_WRITEABLE);
  256. is_memory_writeonly |= var && (var->data.access & ACCESS_NON_READABLE);
  257. }
  258.  
  259. is_memory_readonly |= is_buffer ? !state->buffers_written : !state->images_written;
  260. is_memory_writeonly |= is_buffer ? !state->buffers_read : !state->images_read;
  261.  
  262. if (is_memory_readonly)
  263. access |= ACCESS_NON_WRITEABLE;
  264. if (state->infer_non_readable && is_memory_writeonly)
  265. access |= ACCESS_NON_READABLE;
  266. if (!(access & ACCESS_VOLATILE) && is_memory_readonly)
  267. access |= ACCESS_CAN_REORDER;
  268.  
  269. bool progress = nir_intrinsic_access(instr) != access;
  270. nir_intrinsic_set_access(instr, access);
  271. return progress;
  272. }
  273.  
  274. static bool
  275. process_intrinsic(struct access_state *state, nir_intrinsic_instr *instr)
  276. {
  277. switch (instr->intrinsic) {
  278. case nir_intrinsic_bindless_image_load:
  279. case nir_intrinsic_bindless_image_store:
  280. case nir_intrinsic_bindless_image_sparse_load:
  281. return update_access(state, instr, true,
  282. nir_intrinsic_image_dim(instr) == GLSL_SAMPLER_DIM_BUF);
  283.  
  284. case nir_intrinsic_load_deref:
  285. case nir_intrinsic_store_deref: {
  286. if (!nir_deref_mode_is(nir_src_as_deref(instr->src[0]), nir_var_mem_ssbo))
  287. return false;
  288.  
  289. return update_access(state, instr, false, true);
  290. }
  291.  
  292. case nir_intrinsic_image_deref_load:
  293. case nir_intrinsic_image_deref_store:
  294. case nir_intrinsic_image_deref_sparse_load: {
  295. nir_variable *var = nir_intrinsic_get_var(instr, 0);
  296.  
  297. bool is_buffer =
  298. glsl_get_sampler_dim(glsl_without_array(var->type)) == GLSL_SAMPLER_DIM_BUF;
  299.  
  300. return update_access(state, instr, true, is_buffer);
  301. }
  302.  
  303. default:
  304. return false;
  305. }
  306. }
  307.  
  308. static bool
  309. opt_access_impl(struct access_state *state,
  310. nir_function_impl *impl)
  311. {
  312. bool progress = false;
  313.  
  314. nir_foreach_block(block, impl) {
  315. nir_foreach_instr(instr, block) {
  316. if (instr->type == nir_instr_type_intrinsic)
  317. progress |= process_intrinsic(state,
  318. nir_instr_as_intrinsic(instr));
  319. }
  320. }
  321.  
  322. if (progress) {
  323. nir_metadata_preserve(impl,
  324. nir_metadata_block_index |
  325. nir_metadata_dominance |
  326. nir_metadata_live_ssa_defs |
  327. nir_metadata_loop_analysis);
  328. }
  329.  
  330.  
  331. return progress;
  332. }
  333.  
  334. bool
  335. nir_opt_access(nir_shader *shader, const nir_opt_access_options *options)
  336. {
  337. struct access_state state = {
  338. .shader = shader,
  339. .infer_non_readable = options->infer_non_readable,
  340. .vars_written = _mesa_pointer_set_create(NULL),
  341. .vars_read = _mesa_pointer_set_create(NULL),
  342. };
  343.  
  344. bool var_progress = false;
  345. bool progress = false;
  346.  
  347. nir_foreach_function(func, shader) {
  348. if (func->impl) {
  349. nir_foreach_block(block, func->impl) {
  350. nir_foreach_instr(instr, block) {
  351. if (instr->type == nir_instr_type_intrinsic)
  352. gather_intrinsic(&state, nir_instr_as_intrinsic(instr));
  353. }
  354. }
  355. }
  356. }
  357.  
  358. /* In Vulkan, buffers and images can alias. */
  359. if (options->is_vulkan) {
  360. state.buffers_written |= state.images_written;
  361. state.images_written |= state.buffers_written;
  362. state.buffers_read |= state.images_read;
  363. state.images_read |= state.buffers_read;
  364. }
  365.  
  366. nir_foreach_variable_with_modes(var, shader, nir_var_uniform |
  367. nir_var_mem_ubo |
  368. nir_var_mem_ssbo)
  369. var_progress |= process_variable(&state, var);
  370.  
  371. nir_foreach_function(func, shader) {
  372. if (func->impl) {
  373. progress |= opt_access_impl(&state, func->impl);
  374.  
  375. /* If we make a change to the uniforms, update all the impls. */
  376. if (var_progress) {
  377. nir_metadata_preserve(func->impl,
  378. nir_metadata_block_index |
  379. nir_metadata_dominance |
  380. nir_metadata_live_ssa_defs |
  381. nir_metadata_loop_analysis);
  382. }
  383. }
  384. }
  385.  
  386. progress |= var_progress;
  387.  
  388. _mesa_set_destroy(state.vars_read, NULL);
  389. _mesa_set_destroy(state.vars_written, NULL);
  390. return progress;
  391. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement