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 <lionel.g.landwerlin@intel.com>
Cc: mesa-stable
Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/8979
Tested-by: Sviatoslav Peleshko <sviatoslav.peleshko@globallogic.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34214>
(cherry picked from commit c434050a0088ec3f07d63fd1019aea541632faed)
This commit is contained in:
Lionel Landwerlin
2025-03-26 16:05:15 +02:00
committed by Eric Engestrom
parent 8780fd7da5
commit 0ce1adf683
5 changed files with 117 additions and 1 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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',

View File

@@ -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);