1 /*
2 * Copyright © 2022 Konstantin Seurer
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7 #ifndef BVH_BUILD_HELPERS_H
8 #define BVH_BUILD_HELPERS_H
9
10 #include "bvh.h"
11 #include "vk_build_helpers.h"
12
13 TYPE(radv_accel_struct_serialization_header, 8);
14 TYPE(radv_accel_struct_header, 8);
15 TYPE(radv_bvh_triangle_node, 4);
16 TYPE(radv_bvh_aabb_node, 4);
17 TYPE(radv_bvh_instance_node, 8);
18 TYPE(radv_bvh_box16_node, 4);
19 TYPE(radv_bvh_box32_node, 4);
20
21 uint32_t
id_to_offset(uint32_t id)22 id_to_offset(uint32_t id)
23 {
24 return (id & (~7u)) << 3;
25 }
26
27 uint32_t
id_to_type(uint32_t id)28 id_to_type(uint32_t id)
29 {
30 return id & 7u;
31 }
32
33 uint32_t
pack_node_id(uint32_t offset,uint32_t type)34 pack_node_id(uint32_t offset, uint32_t type)
35 {
36 return (offset >> 3) | type;
37 }
38
39 uint64_t
node_to_addr(uint64_t node)40 node_to_addr(uint64_t node)
41 {
42 node &= ~7ul;
43 node <<= 19;
44 return int64_t(node) >> 16;
45 }
46
47 uint64_t
addr_to_node(uint64_t addr)48 addr_to_node(uint64_t addr)
49 {
50 return (addr >> 3) & ((1ul << 45) - 1);
51 }
52
53 uint32_t
ir_type_to_bvh_type(uint32_t type)54 ir_type_to_bvh_type(uint32_t type)
55 {
56 switch (type) {
57 case vk_ir_node_triangle:
58 return radv_bvh_node_triangle;
59 case vk_ir_node_internal:
60 return radv_bvh_node_box32;
61 case vk_ir_node_instance:
62 return radv_bvh_node_instance;
63 case vk_ir_node_aabb:
64 return radv_bvh_node_aabb;
65 }
66 /* unreachable in valid nodes */
67 return RADV_BVH_INVALID_NODE;
68 }
69
70 /* A GLSL-adapted copy of VkAccelerationStructureInstanceKHR. */
71 struct AccelerationStructureInstance {
72 mat3x4 transform;
73 uint32_t custom_instance_and_mask;
74 uint32_t sbt_offset_and_flags;
75 uint64_t accelerationStructureReference;
76 };
77 TYPE(AccelerationStructureInstance, 8);
78
79 bool
build_triangle(inout vk_aabb bounds,VOID_REF dst_ptr,vk_bvh_geometry_data geom_data,uint32_t global_id)80 build_triangle(inout vk_aabb bounds, VOID_REF dst_ptr, vk_bvh_geometry_data geom_data, uint32_t global_id)
81 {
82 bool is_valid = true;
83 triangle_indices indices = load_indices(geom_data.indices, geom_data.index_format, global_id);
84
85 triangle_vertices vertices = load_vertices(geom_data.data, indices, geom_data.vertex_format, geom_data.stride);
86
87 /* An inactive triangle is one for which the first (X) component of any vertex is NaN. If any
88 * other vertex component is NaN, and the first is not, the behavior is undefined. If the vertex
89 * format does not have a NaN representation, then all triangles are considered active.
90 */
91 if (isnan(vertices.vertex[0].x) || isnan(vertices.vertex[1].x) || isnan(vertices.vertex[2].x))
92 #if ALWAYS_ACTIVE
93 is_valid = false;
94 #else
95 return false;
96 #endif
97
98 if (geom_data.transform != NULL) {
99 mat4 transform = mat4(1.0);
100
101 for (uint32_t col = 0; col < 4; col++)
102 for (uint32_t row = 0; row < 3; row++)
103 transform[col][row] = DEREF(INDEX(float, geom_data.transform, col + row * 4));
104
105 for (uint32_t i = 0; i < 3; i++)
106 vertices.vertex[i] = transform * vertices.vertex[i];
107 }
108
109 REF(radv_bvh_triangle_node) node = REF(radv_bvh_triangle_node)(dst_ptr);
110
111 bounds.min = vec3(INFINITY);
112 bounds.max = vec3(-INFINITY);
113
114 for (uint32_t coord = 0; coord < 3; coord++)
115 for (uint32_t comp = 0; comp < 3; comp++) {
116 DEREF(node).coords[coord][comp] = vertices.vertex[coord][comp];
117 bounds.min[comp] = min(bounds.min[comp], vertices.vertex[coord][comp]);
118 bounds.max[comp] = max(bounds.max[comp], vertices.vertex[coord][comp]);
119 }
120
121 DEREF(node).triangle_id = global_id;
122 DEREF(node).geometry_id_and_flags = geom_data.geometry_id;
123 DEREF(node).id = 9;
124
125 return is_valid;
126 }
127
128 bool
build_aabb(inout vk_aabb bounds,VOID_REF src_ptr,VOID_REF dst_ptr,uint32_t geometry_id,uint32_t global_id)129 build_aabb(inout vk_aabb bounds, VOID_REF src_ptr, VOID_REF dst_ptr, uint32_t geometry_id, uint32_t global_id)
130 {
131 bool is_valid = true;
132 REF(radv_bvh_aabb_node) node = REF(radv_bvh_aabb_node)(dst_ptr);
133
134 for (uint32_t vec = 0; vec < 2; vec++)
135 for (uint32_t comp = 0; comp < 3; comp++) {
136 float coord = DEREF(INDEX(float, src_ptr, comp + vec * 3));
137
138 if (vec == 0)
139 bounds.min[comp] = coord;
140 else
141 bounds.max[comp] = coord;
142 }
143
144 /* An inactive AABB is one for which the minimum X coordinate is NaN. If any other component is
145 * NaN, and the first is not, the behavior is undefined.
146 */
147 if (isnan(bounds.min.x))
148 #if ALWAYS_ACTIVE
149 is_valid = false;
150 #else
151 return false;
152 #endif
153
154 DEREF(node).primitive_id = global_id;
155 DEREF(node).geometry_id_and_flags = geometry_id;
156
157 return is_valid;
158 }
159
160 vk_aabb
calculate_instance_node_bounds(radv_accel_struct_header header,mat3x4 otw_matrix)161 calculate_instance_node_bounds(radv_accel_struct_header header, mat3x4 otw_matrix)
162 {
163 vk_aabb aabb;
164 for (uint32_t comp = 0; comp < 3; ++comp) {
165 aabb.min[comp] = otw_matrix[comp][3];
166 aabb.max[comp] = otw_matrix[comp][3];
167 for (uint32_t col = 0; col < 3; ++col) {
168 aabb.min[comp] +=
169 min(otw_matrix[comp][col] * header.aabb.min[col], otw_matrix[comp][col] * header.aabb.max[col]);
170 aabb.max[comp] +=
171 max(otw_matrix[comp][col] * header.aabb.min[col], otw_matrix[comp][col] * header.aabb.max[col]);
172 }
173 }
174 return aabb;
175 }
176
177 uint32_t
encode_sbt_offset_and_flags(uint32_t src)178 encode_sbt_offset_and_flags(uint32_t src)
179 {
180 uint32_t flags = src >> 24;
181 uint32_t ret = src & 0xffffffu;
182 if ((flags & VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR) != 0)
183 ret |= RADV_INSTANCE_FORCE_OPAQUE;
184 if ((flags & VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR) == 0)
185 ret |= RADV_INSTANCE_NO_FORCE_NOT_OPAQUE;
186 if ((flags & VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR) != 0)
187 ret |= RADV_INSTANCE_TRIANGLE_FACING_CULL_DISABLE;
188 if ((flags & VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR) != 0)
189 ret |= RADV_INSTANCE_TRIANGLE_FLIP_FACING;
190 return ret;
191 }
192
193 bool
build_instance(inout vk_aabb bounds,VOID_REF src_ptr,VOID_REF dst_ptr,uint32_t global_id)194 build_instance(inout vk_aabb bounds, VOID_REF src_ptr, VOID_REF dst_ptr, uint32_t global_id)
195 {
196 REF(radv_bvh_instance_node) node = REF(radv_bvh_instance_node)(dst_ptr);
197
198 AccelerationStructureInstance instance = DEREF(REF(AccelerationStructureInstance)(src_ptr));
199
200 /* An inactive instance is one whose acceleration structure handle is VK_NULL_HANDLE. Since the active terminology is
201 * only relevant for BVH updates, which we do not implement, we can also skip instances with mask == 0.
202 */
203 if (instance.accelerationStructureReference == 0 || instance.custom_instance_and_mask < (1u << 24u))
204 return false;
205
206 radv_accel_struct_header instance_header =
207 DEREF(REF(radv_accel_struct_header)(instance.accelerationStructureReference));
208
209 DEREF(node).bvh_ptr = addr_to_node(instance.accelerationStructureReference + instance_header.bvh_offset);
210 DEREF(node).bvh_offset = instance_header.bvh_offset;
211
212 mat4 transform = mat4(instance.transform);
213 mat4 inv_transform = transpose(inverse(transpose(transform)));
214 DEREF(node).wto_matrix = mat3x4(inv_transform);
215 DEREF(node).otw_matrix = mat3x4(transform);
216
217 bounds = calculate_instance_node_bounds(instance_header, mat3x4(transform));
218
219 DEREF(node).custom_instance_and_mask = instance.custom_instance_and_mask;
220 DEREF(node).sbt_offset_and_flags = encode_sbt_offset_and_flags(instance.sbt_offset_and_flags);
221 DEREF(node).instance_id = global_id;
222
223 return true;
224 }
225
226 /** Compute ceiling of integer quotient of A divided by B.
227 From macros.h */
228 #define DIV_ROUND_UP(A, B) (((A) + (B)-1) / (B))
229
230 #endif /* BUILD_HELPERS_H */
231