diff --git a/src/amd/vulkan/radv_rra_gfx12.c b/src/amd/vulkan/radv_rra_gfx12.c index 66b72b31140..0aad6987ea9 100644 --- a/src/amd/vulkan/radv_rra_gfx12.c +++ b/src/amd/vulkan/radv_rra_gfx12.c @@ -19,6 +19,25 @@ struct rra_instance_sideband_data { mat3x4 otw_matrix; }; +static const char *node_type_names[16] = { + [radv_bvh_node_triangle + 0] = "triangle0", + [radv_bvh_node_triangle + 1] = "triangle1", + [radv_bvh_node_triangle + 2] = "triangle2", + [radv_bvh_node_triangle + 3] = "triangle3", + [radv_bvh_node_box16] = "invalid4", + [radv_bvh_node_box32] = "box32", + [radv_bvh_node_instance] = "instance", + [radv_bvh_node_aabb] = "invalid7", + [8] = "invalid8", + [9] = "invalid9", + [10] = "invalid10", + [11] = "invalid11", + [12] = "invalid12", + [13] = "invalid13", + [14] = "invalid14", + [15] = "invalid15", +}; + bool rra_validate_node_gfx12(struct hash_table_u64 *accel_struct_vas, uint8_t *data, void *node, uint32_t geometry_count, uint32_t size, bool is_bottom_level, uint32_t depth) @@ -33,6 +52,66 @@ rra_validate_node_gfx12(struct hash_table_u64 *accel_struct_vas, uint8_t *data, uint32_t cur_offset = (uint8_t *)node - data; snprintf(ctx.location, sizeof(ctx.location), "internal node (offset=%u)", cur_offset); + struct radv_gfx12_box_node *box = node; + uint32_t valid_child_count_minus_one = box->child_count_exponents >> 28; + if (valid_child_count_minus_one == 0xf) + return ctx.failed; + + uint32_t internal_id = box->internal_base_id; + uint32_t primitive_id = box->primitive_base_id; + for (uint32_t i = 0; i <= valid_child_count_minus_one; i++) { + uint32_t child_type = (box->children[i].dword2 >> 24) & 0xf; + uint32_t child_size = box->children[i].dword2 >> 28; + + uint32_t child_id; + if (child_type == radv_bvh_node_box32) { + child_id = internal_id; + internal_id += (child_size * RADV_GFX12_BVH_NODE_SIZE) >> 3; + } else { + child_id = primitive_id; + primitive_id += (child_size * RADV_GFX12_BVH_NODE_SIZE) >> 3; + } + + uint32_t child_offset = (child_id & (~7u)) << 3; + + if (child_offset >= size) { + rra_validation_fail(&ctx, "Invalid child offset (child index %u)", i); + continue; + } + + struct rra_validation_context child_ctx = {0}; + snprintf(child_ctx.location, sizeof(child_ctx.location), "%s node (offset=%u)", node_type_names[child_type], + child_offset); + + void *child_node = data + child_offset; + + if (child_type == radv_bvh_node_box32) { + ctx.failed |= rra_validate_node_gfx12(accel_struct_vas, data, child_node, geometry_count, size, + is_bottom_level, depth + 1); + } else if (child_type == radv_bvh_node_instance) { + struct radv_gfx12_instance_node *child = (struct radv_gfx12_instance_node *)(child_node); + const struct radv_gfx12_instance_node_user_data *user_data = + (const void *)((const uint8_t *)child + sizeof(struct radv_gfx12_instance_node)); + + uint64_t blas_va = radv_node_to_addr(child->pointer_flags_bvh_addr) - user_data->bvh_offset; + if (!_mesa_hash_table_u64_search(accel_struct_vas, blas_va)) + rra_validation_fail(&child_ctx, "Invalid blas_addr(0x%llx)", (unsigned long long)blas_va); + } else { + uint32_t indices_midpoint = BITSET_EXTRACT(child_node, 42, 10); + if (indices_midpoint < 54 + 28) { + rra_validation_fail(&child_ctx, "Invalid indices_midpoint(%u)", indices_midpoint); + } else { + uint32_t geometry_id = BITSET_EXTRACT(child_node, indices_midpoint - 28, 28); + if (geometry_id >= geometry_count) { + rra_validation_fail(&child_ctx, "Invalid geometry_id(%u) >= geometry_count(%u)", geometry_id, + geometry_count); + } + } + if (!BITSET_TEST((BITSET_WORD *)child_node, 1024 - 29)) + rra_validation_fail(&child_ctx, "prim_range_stop is not set"); + } + } + return ctx.failed; }