From 0ce1adf6839cfad66935ebb6b16a5b22100fa270 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Wed, 26 Mar 2025 16:05:15 +0200 Subject: [PATCH] brw: add pre ray trace intrinsic moves Some intrinsics are implemented by reading memory location that could be rewritten by a further tracing calls. So we need to move those reads prior to tracing operations in the shaders. Signed-off-by: Lionel Landwerlin Cc: mesa-stable Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/8979 Tested-by: Sviatoslav Peleshko Part-of: (cherry picked from commit c434050a0088ec3f07d63fd1019aea541632faed) --- .pick_status.json | 2 +- .../brw_nir_lower_rt_intrinsics_pre_trace.c | 111 ++++++++++++++++++ src/intel/compiler/brw_nir_rt.h | 2 + src/intel/compiler/meson.build | 1 + src/intel/vulkan/anv_pipeline.c | 2 + 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 src/intel/compiler/brw_nir_lower_rt_intrinsics_pre_trace.c diff --git a/.pick_status.json b/.pick_status.json index 89b9b53a9ab..6b74b2cb356 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -4,7 +4,7 @@ "description": "brw: add pre ray trace intrinsic moves", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": null, "notes": null diff --git a/src/intel/compiler/brw_nir_lower_rt_intrinsics_pre_trace.c b/src/intel/compiler/brw_nir_lower_rt_intrinsics_pre_trace.c new file mode 100644 index 00000000000..84771ed8935 --- /dev/null +++ b/src/intel/compiler/brw_nir_lower_rt_intrinsics_pre_trace.c @@ -0,0 +1,111 @@ +/* Copyright © 2025 Intel Corporation + * SPDX-License-Identifier: MIT + */ + +#include "brw_nir_rt.h" + +static bool +add_intrinsics_to_set(nir_builder *b, + nir_intrinsic_instr *intrin, + void *data) +{ + switch (intrin->intrinsic) { + case nir_intrinsic_load_ray_world_origin: + case nir_intrinsic_load_ray_world_direction: + case nir_intrinsic_load_ray_object_origin: + case nir_intrinsic_load_ray_object_direction: + case nir_intrinsic_load_ray_t_min: + case nir_intrinsic_load_ray_t_max: + case nir_intrinsic_load_ray_object_to_world: + case nir_intrinsic_load_ray_flags: { + struct set *intrinsics = data; + _mesa_set_add(intrinsics, intrin); + return false; + } + + default: + return false; + } +} + +/** Move some RT intrinsics pre shader calls + * + * Some RT intrinsics are implemented by reading the ray structure in memory. + * This structure is written just before triggering a tracing call. Those + * intrinsics should be considered as input values to the shader (kind of like + * thread payload in legacy stages). + * + * If the values are read after a bindless shader call, we need to move the + * read from memory prior to the call because called shaders could overwrite + * the memory location if they trigger another tracing call. + * + * Call this pass before nir_lower_shader_calls(). + */ +bool +brw_nir_lower_rt_intrinsics_pre_trace(nir_shader *nir) +{ + /* According to spec, only those stages can do a recursing traceRayEXT(). + */ + if (nir->info.stage != MESA_SHADER_CLOSEST_HIT && + nir->info.stage != MESA_SHADER_MISS) + return false; + + /* Find all the intrinsics we might need to move */ + struct set *intrinsics = _mesa_set_create(NULL, + _mesa_hash_pointer, + _mesa_key_pointer_equal); + + nir_shader_intrinsics_pass(nir, + add_intrinsics_to_set, + nir_metadata_all, + intrinsics); + + bool progress = false; + + if (intrinsics->entries > 0) { + nir_foreach_function_with_impl(func, impl, nir) { + nir_metadata_require(impl, nir_metadata_dominance); + + /* Going in reverse order of blocks, move the intrinsics gather above + * in the LCA block to trace calls. + */ + nir_foreach_block_reverse(block, impl) { + nir_foreach_instr_reverse_safe(instr, block) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *trace = nir_instr_as_intrinsic(instr); + if (trace->intrinsic != nir_intrinsic_trace_ray) + continue; + + set_foreach(intrinsics, entry) { + nir_intrinsic_instr *intrin = (void *)entry->key; + + /* Coming from a different function, ignore */ + if (nir_cf_node_get_function(&intrin->instr.block->cf_node) != impl) + continue; + + /* The trace dominates the intrinsic, move it before */ + nir_block *move_block = nir_dominance_lca(trace->instr.block, + intrin->instr.block); + if (move_block == trace->instr.block) { + if (nir_instr_is_before(&trace->instr, &intrin->instr)) { + nir_instr_move(nir_before_instr(&trace->instr), + &intrin->instr); + progress = true; + } + } else { + nir_instr_move(nir_before_block_after_phis(move_block), + &intrin->instr); + progress = true; + } + } + } + } + } + } + + _mesa_set_destroy(intrinsics, NULL); + + return progress; +} diff --git a/src/intel/compiler/brw_nir_rt.h b/src/intel/compiler/brw_nir_rt.h index 0893016d51c..aaa1ddc8659 100644 --- a/src/intel/compiler/brw_nir_rt.h +++ b/src/intel/compiler/brw_nir_rt.h @@ -55,6 +55,8 @@ void brw_nir_lower_shader_returns(nir_shader *shader); bool brw_nir_lower_shader_calls(nir_shader *shader, struct brw_bs_prog_key *key); +bool brw_nir_lower_rt_intrinsics_pre_trace(nir_shader *nir); + void brw_nir_lower_rt_intrinsics(nir_shader *shader, const struct brw_base_prog_key *key, const struct intel_device_info *devinfo); diff --git a/src/intel/compiler/meson.build b/src/intel/compiler/meson.build index 877d7bc0fb1..e8580c8824c 100644 --- a/src/intel/compiler/meson.build +++ b/src/intel/compiler/meson.build @@ -74,6 +74,7 @@ libintel_compiler_brw_files = files( 'brw_nir_lower_intersection_shader.c', 'brw_nir_lower_ray_queries.c', 'brw_nir_lower_rt_intrinsics.c', + 'brw_nir_lower_rt_intrinsics_pre_trace.c', 'brw_nir_lower_sample_index_in_coord.c', 'brw_nir_lower_shader_calls.c', 'brw_nir_lower_storage_image.c', diff --git a/src/intel/vulkan/anv_pipeline.c b/src/intel/vulkan/anv_pipeline.c index aa3a09a9411..0ab0cd87e19 100644 --- a/src/intel/vulkan/anv_pipeline.c +++ b/src/intel/vulkan/anv_pipeline.c @@ -3373,6 +3373,8 @@ compile_upload_rt_shader(struct anv_ray_tracing_pipeline *pipeline, .should_remat_callback = should_remat_cb, }; + NIR_PASS(_, nir, brw_nir_lower_rt_intrinsics_pre_trace); + NIR_PASS(_, nir, nir_lower_shader_calls, &opts, &resume_shaders, &num_resume_shaders, mem_ctx); NIR_PASS(_, nir, brw_nir_lower_shader_calls, &stage->key.bs);