radv/bvh: Add helpers for encoding

The build and update paths can use the same code.

Reviewed-by: Natalie Vock <natalie.vock@gmx.de>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34273>
This commit is contained in:
Konstantin Seurer 2025-03-25 11:00:58 +01:00 committed by Marge Bot
parent 3af19f336c
commit 95e7343a7d
6 changed files with 162 additions and 108 deletions

View file

@ -67,87 +67,6 @@ ir_type_to_bvh_type(uint32_t type)
return RADV_BVH_INVALID_NODE;
}
bool
radv_build_triangle(inout vk_aabb bounds, VOID_REF dst_ptr, vk_bvh_geometry_data geom_data, uint32_t global_id)
{
bool is_valid = true;
triangle_indices indices = load_indices(geom_data.indices, geom_data.index_format, global_id);
triangle_vertices vertices = load_vertices(geom_data.data, indices, geom_data.vertex_format, geom_data.stride);
/* An inactive triangle is one for which the first (X) component of any vertex is NaN. If any
* other vertex component is NaN, and the first is not, the behavior is undefined. If the vertex
* format does not have a NaN representation, then all triangles are considered active.
*/
if (isnan(vertices.vertex[0].x) || isnan(vertices.vertex[1].x) || isnan(vertices.vertex[2].x))
#if ALWAYS_ACTIVE
is_valid = false;
#else
return false;
#endif
if (geom_data.transform != NULL) {
mat4 transform = mat4(1.0);
for (uint32_t col = 0; col < 4; col++)
for (uint32_t row = 0; row < 3; row++)
transform[col][row] = DEREF(INDEX(float, geom_data.transform, col + row * 4));
for (uint32_t i = 0; i < 3; i++)
vertices.vertex[i] = transform * vertices.vertex[i];
}
REF(radv_bvh_triangle_node) node = REF(radv_bvh_triangle_node)(dst_ptr);
bounds.min = vec3(INFINITY);
bounds.max = vec3(-INFINITY);
for (uint32_t coord = 0; coord < 3; coord++)
for (uint32_t comp = 0; comp < 3; comp++) {
DEREF(node).coords[coord][comp] = vertices.vertex[coord][comp];
bounds.min[comp] = min(bounds.min[comp], vertices.vertex[coord][comp]);
bounds.max[comp] = max(bounds.max[comp], vertices.vertex[coord][comp]);
}
DEREF(node).triangle_id = global_id;
DEREF(node).geometry_id_and_flags = geom_data.geometry_id;
DEREF(node).id = 9;
return is_valid;
}
bool
radv_build_aabb(inout vk_aabb bounds, VOID_REF src_ptr, VOID_REF dst_ptr, uint32_t geometry_id, uint32_t global_id)
{
bool is_valid = true;
REF(radv_bvh_aabb_node) node = REF(radv_bvh_aabb_node)(dst_ptr);
for (uint32_t vec = 0; vec < 2; vec++)
for (uint32_t comp = 0; comp < 3; comp++) {
float coord = DEREF(INDEX(float, src_ptr, comp + vec * 3));
if (vec == 0)
bounds.min[comp] = coord;
else
bounds.max[comp] = coord;
}
/* An inactive AABB is one for which the minimum X coordinate is NaN. If any other component is
* NaN, and the first is not, the behavior is undefined.
*/
if (isnan(bounds.min.x))
#if ALWAYS_ACTIVE
is_valid = false;
#else
return false;
#endif
DEREF(node).primitive_id = global_id;
DEREF(node).geometry_id_and_flags = geometry_id;
return is_valid;
}
uint32_t
radv_encode_sbt_offset_and_flags(uint32_t src)
{

View file

@ -22,6 +22,7 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
#include "build_helpers.h"
#include "build_interface.h"
#include "encode.h"
layout(push_constant) uniform CONSTS {
encode_args args;
@ -50,13 +51,9 @@ main()
vk_ir_triangle_node src_node =
DEREF(REF(vk_ir_triangle_node)(OFFSET(args.intermediate_bvh, gl_GlobalInvocationID.x * ir_leaf_node_size)));
REF(radv_bvh_triangle_node) dst_node =
REF(radv_bvh_triangle_node)(OFFSET(args.output_bvh, dst_leaf_offset + gl_GlobalInvocationID.x * output_leaf_node_size));
VOID_REF dst_node = OFFSET(args.output_bvh, dst_leaf_offset + gl_GlobalInvocationID.x * output_leaf_node_size);
DEREF(dst_node).coords = src_node.coords;
DEREF(dst_node).triangle_id = src_node.triangle_id;
DEREF(dst_node).geometry_id_and_flags = src_node.geometry_id_and_flags;
DEREF(dst_node).id = 9;
radv_encode_triangle_gfx10_3(dst_node, src_node);
break;
}
@ -66,11 +63,9 @@ main()
vk_ir_aabb_node src_node =
DEREF(REF(vk_ir_aabb_node)(OFFSET(args.intermediate_bvh, gl_GlobalInvocationID.x * ir_leaf_node_size)));
REF(radv_bvh_aabb_node) dst_node =
REF(radv_bvh_aabb_node)(OFFSET(args.output_bvh, dst_leaf_offset + gl_GlobalInvocationID.x * output_leaf_node_size));
VOID_REF dst_node = OFFSET(args.output_bvh, dst_leaf_offset + gl_GlobalInvocationID.x * output_leaf_node_size);
DEREF(dst_node).primitive_id = src_node.primitive_id;
DEREF(dst_node).geometry_id_and_flags = src_node.geometry_id_and_flags;
radv_encode_aabb_gfx10_3(dst_node, src_node);
break;
}
@ -196,23 +191,7 @@ main()
if (type == vk_ir_node_instance) {
vk_ir_instance_node src_node =
DEREF(REF(vk_ir_instance_node)(OFFSET(args.intermediate_bvh, offset)));
REF(radv_bvh_instance_node) dst_node =
REF(radv_bvh_instance_node)(OFFSET(args.output_bvh, dst_offset));
radv_accel_struct_header blas_header =
DEREF(REF(radv_accel_struct_header)(src_node.base_ptr));
DEREF(dst_node).bvh_ptr = addr_to_node(src_node.base_ptr + blas_header.bvh_offset);
DEREF(dst_node).bvh_offset = blas_header.bvh_offset;
mat4 transform = mat4(src_node.otw_matrix);
mat4 inv_transform = transpose(inverse(transpose(transform)));
DEREF(dst_node).wto_matrix = mat3x4(inv_transform);
DEREF(dst_node).otw_matrix = mat3x4(transform);
DEREF(dst_node).custom_instance_and_mask = src_node.custom_instance_and_mask;
DEREF(dst_node).sbt_offset_and_flags = radv_encode_sbt_offset_and_flags(src_node.sbt_offset_and_flags);
DEREF(dst_node).instance_id = src_node.instance_id;
radv_encode_instance_gfx10_3(OFFSET(args.output_bvh, dst_offset), src_node);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright © 2022 Friedrich Vock
* Copyright © 2025 Valve Corporation
*
* SPDX-License-Identifier: MIT
*/
/* Helpers for encoding BVH nodes on different HW generations. */
#ifndef RADV_BVH_ENCODE_H
#define RADV_BVH_ENCODE_H
#include "build_helpers.h"
void
radv_encode_triangle_gfx10_3(VOID_REF dst_addr, vk_ir_triangle_node src)
{
REF(radv_bvh_triangle_node) dst = REF(radv_bvh_triangle_node)(dst_addr);
DEREF(dst).coords = src.coords;
DEREF(dst).triangle_id = src.triangle_id;
DEREF(dst).geometry_id_and_flags = src.geometry_id_and_flags;
DEREF(dst).id = 9;
}
void
radv_encode_aabb_gfx10_3(VOID_REF dst_addr, vk_ir_aabb_node src)
{
REF(radv_bvh_aabb_node) dst = REF(radv_bvh_aabb_node)(dst_addr);
DEREF(dst).primitive_id = src.primitive_id;
DEREF(dst).geometry_id_and_flags = src.geometry_id_and_flags;
}
void
radv_encode_instance_gfx10_3(VOID_REF dst_addr, vk_ir_instance_node src)
{
REF(radv_bvh_instance_node) dst = REF(radv_bvh_instance_node)(dst_addr);
radv_accel_struct_header blas_header = DEREF(REF(radv_accel_struct_header)(src.base_ptr));
DEREF(dst).bvh_ptr = addr_to_node(src.base_ptr + blas_header.bvh_offset);
DEREF(dst).bvh_offset = blas_header.bvh_offset;
mat4 transform = mat4(src.otw_matrix);
mat4 inv_transform = transpose(inverse(transpose(transform)));
DEREF(dst).wto_matrix = mat3x4(inv_transform);
DEREF(dst).otw_matrix = mat3x4(transform);
DEREF(dst).custom_instance_and_mask = src.custom_instance_and_mask;
DEREF(dst).sbt_offset_and_flags = radv_encode_sbt_offset_and_flags(src.sbt_offset_and_flags);
DEREF(dst).instance_id = src.instance_id;
}
#endif

View file

@ -47,6 +47,8 @@ bvh_includes = files(
'build_helpers.h',
'build_interface.h',
'bvh.h',
'encode.h',
'update.h',
vk_bvh_include_dir + '/vk_build_helpers.h',
vk_bvh_include_dir + '/vk_bvh.h',
)

View file

@ -21,6 +21,7 @@
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
#include "build_interface.h"
#include "update.h"
layout(push_constant) uniform CONSTS {
update_args args;

View file

@ -0,0 +1,98 @@
/*
* Copyright © 2022 Konstantin Seurer
* Copyright © 2025 Valve Corporation
*
* SPDX-License-Identifier: MIT
*/
#ifndef RADV_BVH_UPDATE_H
#define RADV_BVH_UPDATE_H
#include "encode.h"
bool
radv_build_triangle(inout vk_aabb bounds, VOID_REF dst_ptr, vk_bvh_geometry_data geom_data, uint32_t global_id)
{
bool is_valid = true;
triangle_indices indices = load_indices(geom_data.indices, geom_data.index_format, global_id);
triangle_vertices vertices = load_vertices(geom_data.data, indices, geom_data.vertex_format, geom_data.stride);
/* An inactive triangle is one for which the first (X) component of any vertex is NaN. If any
* other vertex component is NaN, and the first is not, the behavior is undefined. If the vertex
* format does not have a NaN representation, then all triangles are considered active.
*/
if (isnan(vertices.vertex[0].x) || isnan(vertices.vertex[1].x) || isnan(vertices.vertex[2].x))
#if ALWAYS_ACTIVE
is_valid = false;
#else
return false;
#endif
if (geom_data.transform != NULL) {
mat4 transform = mat4(1.0);
for (uint32_t col = 0; col < 4; col++)
for (uint32_t row = 0; row < 3; row++)
transform[col][row] = DEREF(INDEX(float, geom_data.transform, col + row * 4));
for (uint32_t i = 0; i < 3; i++)
vertices.vertex[i] = transform * vertices.vertex[i];
}
vk_ir_triangle_node node;
bounds.min = vec3(INFINITY);
bounds.max = vec3(-INFINITY);
for (uint32_t coord = 0; coord < 3; coord++) {
for (uint32_t comp = 0; comp < 3; comp++) {
node.coords[coord][comp] = vertices.vertex[coord][comp];
bounds.min[comp] = min(bounds.min[comp], vertices.vertex[coord][comp]);
bounds.max[comp] = max(bounds.max[comp], vertices.vertex[coord][comp]);
}
}
node.triangle_id = global_id;
node.geometry_id_and_flags = geom_data.geometry_id;
radv_encode_triangle_gfx10_3(dst_ptr, node);
return is_valid;
}
bool
radv_build_aabb(inout vk_aabb bounds, VOID_REF src_ptr, VOID_REF dst_ptr, uint32_t geometry_id, uint32_t global_id)
{
bool is_valid = true;
for (uint32_t vec = 0; vec < 2; vec++)
for (uint32_t comp = 0; comp < 3; comp++) {
float coord = DEREF(INDEX(float, src_ptr, comp + vec * 3));
if (vec == 0)
bounds.min[comp] = coord;
else
bounds.max[comp] = coord;
}
/* An inactive AABB is one for which the minimum X coordinate is NaN. If any other component is
* NaN, and the first is not, the behavior is undefined.
*/
if (isnan(bounds.min.x))
#if ALWAYS_ACTIVE
is_valid = false;
#else
return false;
#endif
vk_ir_aabb_node node;
node.primitive_id = global_id;
node.geometry_id_and_flags = geometry_id;
radv_encode_aabb_gfx10_3(dst_ptr, node);
return is_valid;
}
#endif