Skip to main content

vk_graph/cmd/
cmd_ref.rs

1use {
2    crate::{
3        AnyAccelerationStructureNode, AnyResource, Execution, Node,
4        driver::{
5            accel_struct::{
6                AccelerationStructureGeometry, AccelerationStructureGeometryInfo,
7                DeviceOrHostAddress,
8            },
9            device::Device,
10        },
11    },
12    ash::vk,
13    log::trace,
14    std::{cell::RefCell, ops::Deref},
15};
16
17/// Recording interface for general Vulkan commands.
18///
19/// This structure provides a strongly-typed set of methods which allow acceleration structures to
20/// be built and updated.
21///
22/// # Examples
23///
24/// Basic usage:
25///
26/// ```no_run
27/// # use ash::vk;
28/// # use vk_graph::Graph;
29/// # fn main() {
30/// # let mut my_graph = Graph::default();
31/// my_graph.begin_cmd()
32///         .record_cmd(move |cmd| {
33///             // Use provided command buffer functions or native calls
34///             assert_ne!(cmd.handle, vk::CommandBuffer::null());
35///         });
36/// # }
37/// ```
38#[derive(Clone, Copy)]
39pub struct CommandRef<'a> {
40    cmd: &'a crate::driver::cmd_buf::CommandBuffer,
41
42    #[cfg(feature = "checked")]
43    exec: &'a Execution,
44
45    #[cfg(feature = "checked")]
46    graph_id: crate::GraphId,
47
48    node_map: Option<&'a [usize]>,
49    resources: &'a [AnyResource],
50}
51
52impl<'a> CommandRef<'a> {
53    pub(crate) fn new(
54        cmd: &'a crate::driver::cmd_buf::CommandBuffer,
55        resources: &'a [AnyResource],
56        exec: &'a Execution,
57        #[cfg(feature = "checked")] graph_id: crate::GraphId,
58    ) -> Self {
59        Self {
60            cmd,
61            node_map: exec.node_map.as_deref(),
62            resources,
63
64            #[cfg(feature = "checked")]
65            exec,
66
67            #[cfg(feature = "checked")]
68            graph_id: exec.stream_graph_id.unwrap_or(graph_id),
69        }
70    }
71
72    /// Build acceleration structures.
73    ///
74    /// There is no ordering or synchronization implied between any of the individual acceleration
75    /// structure builds.
76    ///
77    /// Requires a scratch buffer which was created with the following requirements:
78    ///
79    /// - Flags must include [`vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS`]
80    /// - Size must be equal to or greater than the `build_size` value returned by
81    ///   `AccelerationStructure::size_of`, aligned to `min_accel_struct_scratch_offset_alignment`
82    ///   of `PhysicalDevice::vk_khr_acceleration_structure`.
83    ///
84    /// # Examples
85    ///
86    /// Basic usage:
87    ///
88    /// ```no_run
89    /// # use ash::vk;
90    /// # use vk_graph::cmd::BuildAccelerationStructureInfo;
91    /// # use vk_sync::AccessType;
92    /// # use vk_graph::driver::DriverError;
93    /// # use vk_graph::driver::device::{Device, DeviceInfo};
94    /// # use vk_graph::driver::accel_struct::{
95    /// #     AccelerationStructure,
96    /// #     AccelerationStructureGeometry,
97    /// #     AccelerationStructureGeometryData,
98    /// #     AccelerationStructureGeometryInfo,
99    /// #     AccelerationStructureInfo,
100    /// #     DeviceOrHostAddress,
101    /// # };
102    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
103    /// # use vk_graph::Graph;
104    /// # use vk_graph::driver::shader::Shader;
105    /// # fn main() -> Result<(), DriverError> {
106    /// # let device = Device::create(DeviceInfo::default())?;
107    /// # let mut my_graph = Graph::default();
108    /// # let info = AccelerationStructureInfo::blas(1);
109    /// # let blas_accel_struct = AccelerationStructure::create(&device, info)?;
110    /// # let blas_node = my_graph.bind_resource(blas_accel_struct);
111    /// # let scratch_buf_info =
112    /// #     BufferInfo::device_mem(8, vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS);
113    /// # let scratch_buf = Buffer::create(&device, scratch_buf_info)?;
114    /// # let scratch_buf = my_graph.bind_resource(scratch_buf);
115    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::INDEX_BUFFER);
116    /// # let my_idx_buf = Buffer::create(&device, buf_info)?;
117    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::VERTEX_BUFFER);
118    /// # let my_vtx_buf = Buffer::create(&device, buf_info)?;
119    /// # let index_buf = my_graph.bind_resource(my_idx_buf);
120    /// # let vertex_buf = my_graph.bind_resource(my_vtx_buf);
121    /// my_graph.begin_cmd()
122    ///         .resource_access(index_buf, AccessType::IndexBuffer)
123    ///         .resource_access(vertex_buf, AccessType::VertexBuffer)
124    ///         .resource_access(scratch_buf, AccessType::AccelerationStructureBufferWrite)
125    ///         .resource_access(blas_node, AccessType::AccelerationStructureBuildWrite)
126    ///         .record_cmd(move |cmd| {
127    ///             let scratch_addr = cmd.resource(scratch_buf).device_address();
128    ///             let geom = AccelerationStructureGeometry {
129    ///                 max_primitive_count: 64,
130    ///                 flags: vk::GeometryFlagsKHR::OPAQUE,
131    ///                 geometry: AccelerationStructureGeometryData::Triangles {
132    ///                     index_addr: DeviceOrHostAddress::DeviceAddress(
133    ///                         cmd.resource(index_buf).device_address()
134    ///                     ),
135    ///                     index_type: vk::IndexType::UINT32,
136    ///                     max_vertex: 42,
137    ///                     transform_addr: None,
138    ///                     vertex_addr: DeviceOrHostAddress::DeviceAddress(
139    ///                         cmd.resource(vertex_buf).device_address(),
140    ///                     ),
141    ///                     vertex_format: vk::Format::R32G32B32_SFLOAT,
142    ///                     vertex_stride: 12,
143    ///                 },
144    ///             };
145    ///             let build_range = vk::AccelerationStructureBuildRangeInfoKHR {
146    ///                 first_vertex: 0,
147    ///                 primitive_count: 1,
148    ///                 primitive_offset: 0,
149    ///                 transform_offset: 0,
150    ///             };
151    ///             let info = AccelerationStructureGeometryInfo::blas([(geom, build_range)]);
152    ///
153    ///             cmd.build_accel_struct(&[
154    ///                 BuildAccelerationStructureInfo::new(blas_node, scratch_addr, info)
155    ///             ]);
156    ///         });
157    /// # Ok(()) }
158    /// ```
159    ///
160    /// See also:
161    ///
162    /// - [`examples/ray_omni.rs`](/examples/ray_omni.rs)
163    /// - [`examples/ray_tracing.rs`](/examples/ray_tracing.rs)
164    /// - [`examples/rt_triangle.rs`](/examples/rt_triangle.rs)
165    pub fn build_accel_struct(&self, infos: &[BuildAccelerationStructureInfo]) -> &Self {
166        #[derive(Default)]
167        struct Tls {
168            geometries: Vec<vk::AccelerationStructureGeometryKHR<'static>>,
169            ranges: Vec<vk::AccelerationStructureBuildRangeInfoKHR>,
170        }
171
172        thread_local! {
173            static TLS: RefCell<Tls> = Default::default();
174        }
175
176        TLS.with_borrow_mut(|tls| {
177            tls.geometries.clear();
178            tls.geometries.extend(infos.iter().flat_map(|info| {
179                info.build_data.geometries.iter().map(|(geometry, _)| {
180                    <&AccelerationStructureGeometry as Into<
181                            vk::AccelerationStructureGeometryKHR,
182                        >>::into(geometry)
183                })
184            }));
185
186            tls.ranges.clear();
187            tls.ranges.extend(
188                infos
189                    .iter()
190                    .flat_map(|info| info.build_data.geometries.iter().map(|(_, range)| *range)),
191            );
192
193            let vk_ranges = {
194                let mut start = 0;
195                let mut vk_ranges = Vec::with_capacity(infos.len());
196                for info in infos {
197                    let end = start + info.build_data.geometries.len();
198                    vk_ranges.push(&tls.ranges[start..end]);
199                    start = end;
200                }
201
202                vk_ranges
203            };
204
205            let vk_infos = {
206                let mut start = 0;
207                let mut vk_infos = Vec::with_capacity(infos.len());
208                for info in infos {
209                    let end = start + info.build_data.geometries.len();
210                    vk_infos.push(
211                        vk::AccelerationStructureBuildGeometryInfoKHR::default()
212                            .ty(info.build_data.acceleration_structure_type)
213                            .flags(info.build_data.flags)
214                            .mode(vk::BuildAccelerationStructureModeKHR::BUILD)
215                            .dst_acceleration_structure(self.resource(info.accel_struct).handle)
216                            .geometries(&tls.geometries[start..end])
217                            .scratch_data(info.scratch_addr.into()),
218                    );
219                    start = end;
220                }
221
222                vk_infos
223            };
224
225            let khr_acceleration_structure =
226                Device::expect_vk_khr_acceleration_structure(&self.cmd.device);
227
228            unsafe {
229                khr_acceleration_structure.cmd_build_acceleration_structures(
230                    self.cmd.handle,
231                    &vk_infos,
232                    &vk_ranges,
233                );
234            }
235        });
236
237        self
238    }
239
240    /// Builds acceleration structures with some parameters provided on the device.
241    ///
242    /// There is no ordering or synchronization implied between any of the individual acceleration
243    /// structure builds.
244    ///
245    /// Each [`BuildAccelerationStructureIndirectInfo::range_base`] is a buffer device address which
246    /// points to an array of [`vk::AccelerationStructureBuildRangeInfoKHR`] structures defining
247    /// dynamic offsets to the addresses where geometry data is stored.
248    pub fn build_accel_struct_indirect(
249        &self,
250        infos: &[BuildAccelerationStructureIndirectInfo],
251    ) -> &Self {
252        #[derive(Default)]
253        struct Tls {
254            geometries: Vec<vk::AccelerationStructureGeometryKHR<'static>>,
255            max_primitive_counts: Vec<u32>,
256            range_bases: Vec<vk::DeviceAddress>,
257            range_strides: Vec<u32>,
258        }
259
260        thread_local! {
261            static TLS: RefCell<Tls> = Default::default();
262        }
263
264        TLS.with_borrow_mut(|tls| {
265            tls.geometries.clear();
266            tls.geometries.extend(infos.iter().flat_map(|info| {
267                info.build_data.geometries.iter().map(
268                    <&AccelerationStructureGeometry as Into<
269                        vk::AccelerationStructureGeometryKHR,
270                    >>::into,
271                )
272            }));
273
274            tls.max_primitive_counts.clear();
275            tls.max_primitive_counts
276                .extend(infos.iter().flat_map(|info| {
277                    info.build_data
278                        .geometries
279                        .iter()
280                        .map(|geometry| geometry.max_primitive_count)
281                }));
282
283            tls.range_bases.clear();
284            tls.range_strides.clear();
285            let (vk_infos, vk_max_primitive_counts) = {
286                let mut start = 0;
287                let mut vk_infos = Vec::with_capacity(infos.len());
288                let mut vk_max_primitive_counts = Vec::with_capacity(infos.len());
289                for info in infos {
290                    let end = start + info.build_data.geometries.len();
291                    vk_infos.push(
292                        vk::AccelerationStructureBuildGeometryInfoKHR::default()
293                            .ty(info.build_data.acceleration_structure_type)
294                            .flags(info.build_data.flags)
295                            .mode(vk::BuildAccelerationStructureModeKHR::BUILD)
296                            .dst_acceleration_structure(self.resource(info.accel_struct).handle)
297                            .geometries(&tls.geometries[start..end])
298                            .scratch_data(info.scratch_data.into()),
299                    );
300                    vk_max_primitive_counts.push(&tls.max_primitive_counts[start..end]);
301                    start = end;
302
303                    tls.range_bases.push(info.range_base);
304                    tls.range_strides.push(info.range_stride);
305                }
306
307                (vk_infos, vk_max_primitive_counts)
308            };
309
310            let khr_acceleration_structure =
311                Device::expect_vk_khr_acceleration_structure(&self.cmd.device);
312
313            unsafe {
314                khr_acceleration_structure.cmd_build_acceleration_structures_indirect(
315                    self.cmd.handle,
316                    &vk_infos,
317                    &tls.range_bases,
318                    &tls.range_strides,
319                    &vk_max_primitive_counts,
320                );
321            }
322        });
323
324        self
325    }
326
327    pub(crate) fn clone_resource_at(&self, node_idx: usize) -> AnyResource {
328        self.resources[node_idx].clone()
329    }
330
331    pub(crate) fn cmd_push_constants(
332        &self,
333        layout: vk::PipelineLayout,
334        push_consts: &[vk::PushConstantRange],
335        offset: u32,
336        data: &[u8],
337    ) {
338        for push_const in push_consts {
339            let push_const_end = push_const.offset + push_const.size;
340            let data_end = offset + data.len() as u32;
341            let end = data_end.min(push_const_end);
342            let start = offset.max(push_const.offset);
343
344            if end > start {
345                trace!(
346                    "      push constants {:?} {}..{}",
347                    push_const.stage_flags, start, end
348                );
349
350                unsafe {
351                    self.device.cmd_push_constants(
352                        self.handle,
353                        layout,
354                        push_const.stage_flags,
355                        start,
356                        &data[(start - offset) as usize..(end - offset) as usize],
357                    );
358                }
359            }
360        }
361    }
362
363    /// Update acceleration structures.
364    ///
365    /// There is no ordering or synchronization implied between any of the individual acceleration
366    /// structure updates.
367    ///
368    /// Requires a scratch buffer which was created with the following requirements:
369    ///
370    /// - Flags must include [`vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS`]
371    /// - Size must be equal to or greater than the `update_size` value returned by
372    ///   `AccelerationStructure::size_of`, aligned to `min_accel_struct_scratch_offset_alignment`
373    ///   of `PhysicalDevice::vk_khr_acceleration_structure`.
374    pub fn update_accel_struct(&self, infos: &[UpdateAccelerationStructureInfo]) -> &Self {
375        #[derive(Default)]
376        struct Tls {
377            geometries: Vec<vk::AccelerationStructureGeometryKHR<'static>>,
378            ranges: Vec<vk::AccelerationStructureBuildRangeInfoKHR>,
379        }
380
381        thread_local! {
382            static TLS: RefCell<Tls> = Default::default();
383        }
384
385        TLS.with_borrow_mut(|tls| {
386            tls.geometries.clear();
387            tls.geometries.extend(infos.iter().flat_map(|info| {
388                info.update_data.geometries.iter().map(|(geometry, _)| {
389                    <&AccelerationStructureGeometry as Into<
390                            vk::AccelerationStructureGeometryKHR,
391                        >>::into(geometry)
392                })
393            }));
394
395            tls.ranges.clear();
396            tls.ranges.extend(
397                infos
398                    .iter()
399                    .flat_map(|info| info.update_data.geometries.iter().map(|(_, range)| *range)),
400            );
401
402            let vk_ranges = {
403                let mut start = 0;
404                let mut vk_ranges = Vec::with_capacity(infos.len());
405                for info in infos {
406                    let end = start + info.update_data.geometries.len();
407                    vk_ranges.push(&tls.ranges[start..end]);
408                    start = end;
409                }
410
411                vk_ranges
412            };
413
414            let vk_infos = {
415                let mut start = 0;
416                let mut vk_infos = Vec::with_capacity(infos.len());
417                for info in infos {
418                    let end = start + info.update_data.geometries.len();
419                    vk_infos.push(
420                        vk::AccelerationStructureBuildGeometryInfoKHR::default()
421                            .ty(info.update_data.acceleration_structure_type)
422                            .flags(info.update_data.flags)
423                            .mode(vk::BuildAccelerationStructureModeKHR::UPDATE)
424                            .dst_acceleration_structure(self.resource(info.dst_accel_struct).handle)
425                            .src_acceleration_structure(self.resource(info.src_accel_struct).handle)
426                            .geometries(&tls.geometries[start..end])
427                            .scratch_data(info.scratch_addr.into()),
428                    );
429                    start = end;
430                }
431
432                vk_infos
433            };
434
435            let khr_acceleration_structure =
436                Device::expect_vk_khr_acceleration_structure(&self.cmd.device);
437
438            unsafe {
439                khr_acceleration_structure.cmd_build_acceleration_structures(
440                    self.cmd.handle,
441                    &vk_infos,
442                    &vk_ranges,
443                );
444            }
445        });
446
447        self
448    }
449
450    /// Updates acceleration structures with some parameters provided on the device.
451    ///
452    /// There is no ordering or synchronization implied between any of the individual acceleration
453    /// structure updates.
454    ///
455    /// Each [`UpdateAccelerationStructureIndirectInfo::range_base`] is a buffer device address
456    /// which points to an array of [`vk::AccelerationStructureBuildRangeInfoKHR`] structures
457    /// defining dynamic offsets to the addresses where geometry data is stored.
458    pub fn update_accel_struct_indirect(
459        &self,
460        infos: &[UpdateAccelerationStructureIndirectInfo],
461    ) -> &Self {
462        #[derive(Default)]
463        struct Tls {
464            geometries: Vec<vk::AccelerationStructureGeometryKHR<'static>>,
465            max_primitive_counts: Vec<u32>,
466            range_bases: Vec<vk::DeviceAddress>,
467            range_strides: Vec<u32>,
468        }
469
470        thread_local! {
471            static TLS: RefCell<Tls> = Default::default();
472        }
473
474        TLS.with_borrow_mut(|tls| {
475            tls.geometries.clear();
476            tls.geometries.extend(infos.iter().flat_map(|info| {
477                info.update_data.geometries.iter().map(
478                    <&AccelerationStructureGeometry as Into<
479                        vk::AccelerationStructureGeometryKHR,
480                    >>::into,
481                )
482            }));
483
484            tls.max_primitive_counts.clear();
485            tls.max_primitive_counts
486                .extend(infos.iter().flat_map(|info| {
487                    info.update_data
488                        .geometries
489                        .iter()
490                        .map(|geometry| geometry.max_primitive_count)
491                }));
492
493            tls.range_bases.clear();
494            tls.range_strides.clear();
495            let (vk_infos, vk_max_primitive_counts) = {
496                let mut start = 0;
497                let mut vk_infos = Vec::with_capacity(infos.len());
498                let mut vk_max_primitive_counts = Vec::with_capacity(infos.len());
499                for info in infos {
500                    let end = start + info.update_data.geometries.len();
501                    vk_infos.push(
502                        vk::AccelerationStructureBuildGeometryInfoKHR::default()
503                            .ty(info.update_data.acceleration_structure_type)
504                            .flags(info.update_data.flags)
505                            .mode(vk::BuildAccelerationStructureModeKHR::UPDATE)
506                            .src_acceleration_structure(self.resource(info.src_accel_struct).handle)
507                            .dst_acceleration_structure(self.resource(info.dst_accel_struct).handle)
508                            .geometries(&tls.geometries[start..end])
509                            .scratch_data(info.scratch_addr.into()),
510                    );
511                    vk_max_primitive_counts.push(&tls.max_primitive_counts[start..end]);
512                    start = end;
513
514                    tls.range_bases.push(info.range_base);
515                    tls.range_strides.push(info.range_stride);
516                }
517
518                (vk_infos, vk_max_primitive_counts)
519            };
520
521            let khr_acceleration_structure =
522                Device::expect_vk_khr_acceleration_structure(&self.cmd.device);
523
524            unsafe {
525                khr_acceleration_structure.cmd_build_acceleration_structures_indirect(
526                    self.cmd.handle,
527                    &vk_infos,
528                    &tls.range_bases,
529                    &tls.range_strides,
530                    &vk_max_primitive_counts,
531                );
532            }
533        });
534
535        self
536    }
537
538    /// Returns a borrow of the original Vulkan resource (buffer, image or acceleration structure)
539    /// which the given bound resource node represents.
540    pub fn resource<N>(&self, resource_node: N) -> &N::Resource
541    where
542        N: Node,
543    {
544        #[cfg(feature = "checked")]
545        resource_node.assert_owner(self.graph_id);
546
547        let mut node_idx = resource_node.index();
548        if let Some(node_map) = self.node_map {
549            node_idx = node_map[node_idx];
550        }
551
552        /*
553        You must have called an access function for this node on this execution before borrowing
554        the resource!
555
556        Code that attempts to access this function is attempting to get access to the Vulkan
557        resource (buffer, image, or acceleration structure). In order to access any resources the
558        access type must first be specified so the correct barriers may be added.
559
560        See: https://attackgoat.github.io/vk-graph/pipeline_sync.html
561        */
562        #[cfg(feature = "checked")]
563        assert!(
564            self.exec.accesses.contains(node_idx),
565            "unexpected node access: call an access function first"
566        );
567
568        resource_node.borrow_at(self.resources, node_idx)
569    }
570}
571
572impl<'a> Deref for CommandRef<'a> {
573    type Target = crate::driver::cmd_buf::CommandBuffer;
574
575    fn deref(&self) -> &Self::Target {
576        self.cmd
577    }
578}
579
580/// Specifies the information and data used to build an acceleration structure.
581///
582/// See [`vkCmdBuildAccelerationStructuresKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkCmdBuildAccelerationStructuresKHR.html).
583#[derive(Clone, Debug)]
584pub struct BuildAccelerationStructureInfo {
585    /// The acceleration structure to be written.
586    pub accel_struct: AnyAccelerationStructureNode,
587
588    /// Specifies the geometry data to use when building the acceleration structure.
589    pub build_data: AccelerationStructureGeometryInfo<(
590        AccelerationStructureGeometry,
591        vk::AccelerationStructureBuildRangeInfoKHR,
592    )>,
593
594    /// The temporary buffer or host address (with enough capacity per
595    /// `AccelerationStructure::size_of`).
596    pub scratch_addr: DeviceOrHostAddress,
597}
598
599impl BuildAccelerationStructureInfo {
600    /// Constructs new acceleration structure build information.
601    pub fn new(
602        accel_struct: impl Into<AnyAccelerationStructureNode>,
603        scratch_addr: impl Into<DeviceOrHostAddress>,
604        build_data: AccelerationStructureGeometryInfo<(
605            AccelerationStructureGeometry,
606            vk::AccelerationStructureBuildRangeInfoKHR,
607        )>,
608    ) -> Self {
609        let accel_struct = accel_struct.into();
610        let scratch_addr = scratch_addr.into();
611
612        Self {
613            accel_struct,
614            build_data,
615            scratch_addr,
616        }
617    }
618}
619
620/// Specifies the information and data used to build an acceleration structure with some parameters
621/// sourced on the device.
622///
623/// See [`vkCmdBuildAccelerationStructuresKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkCmdBuildAccelerationStructuresKHR.html).
624#[derive(Clone, Debug)]
625pub struct BuildAccelerationStructureIndirectInfo {
626    /// The acceleration structure to be written.
627    pub accel_struct: AnyAccelerationStructureNode,
628
629    /// Specifies the geometry data to use when building the acceleration structure.
630    pub build_data: AccelerationStructureGeometryInfo<AccelerationStructureGeometry>,
631
632    /// A buffer device address which points to `data.geometry.len()`
633    /// [vk::AccelerationStructureBuildRangeInfoKHR] structures defining dynamic offsets to the
634    /// addresses where geometry data is stored.
635    pub range_base: vk::DeviceAddress,
636
637    /// Byte stride between elements of [`Self::range_base`].
638    pub range_stride: u32,
639
640    /// The temporary buffer or host address (with enough capacity per
641    /// `AccelerationStructure::size_of`).
642    pub scratch_data: DeviceOrHostAddress,
643}
644
645impl BuildAccelerationStructureIndirectInfo {
646    /// Constructs new acceleration structure indirect build information.
647    pub fn new(
648        accel_struct: impl Into<AnyAccelerationStructureNode>,
649        scratch_data: impl Into<DeviceOrHostAddress>,
650        build_data: AccelerationStructureGeometryInfo<AccelerationStructureGeometry>,
651        range_base: vk::DeviceAddress,
652        range_stride: u32,
653    ) -> Self {
654        let accel_struct = accel_struct.into();
655        let scratch_data = scratch_data.into();
656
657        Self {
658            accel_struct,
659            build_data,
660            range_base,
661            range_stride,
662            scratch_data,
663        }
664    }
665}
666
667/// Specifies the information and data used to update an acceleration structure with some parameters
668/// sourced on the device.
669///
670/// See [`vkCmdBuildAccelerationStructuresKHR`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkCmdBuildAccelerationStructuresKHR.html).
671#[derive(Clone, Debug)]
672pub struct UpdateAccelerationStructureIndirectInfo {
673    /// The acceleration structure to be written.
674    pub dst_accel_struct: AnyAccelerationStructureNode,
675
676    /// A buffer device address which points to `data.geometry.len()`
677    /// [vk::AccelerationStructureBuildRangeInfoKHR] structures defining dynamic offsets to the
678    /// addresses where geometry data is stored.
679    pub range_base: vk::DeviceAddress,
680
681    /// Byte stride between elements of [`Self::range_base`].
682    pub range_stride: u32,
683
684    /// The temporary buffer or host address (with enough capacity per
685    /// `AccelerationStructure::size_of`).
686    pub scratch_addr: DeviceOrHostAddress,
687
688    /// The source acceleration structure to be read.
689    pub src_accel_struct: AnyAccelerationStructureNode,
690
691    /// Specifies the geometry data to use when building the acceleration structure.
692    pub update_data: AccelerationStructureGeometryInfo<AccelerationStructureGeometry>,
693}
694
695impl UpdateAccelerationStructureIndirectInfo {
696    /// Constructs new acceleration structure indirect update information.
697    pub fn new(
698        src_accel_struct: impl Into<AnyAccelerationStructureNode>,
699        dst_accel_struct: impl Into<AnyAccelerationStructureNode>,
700        scratch_addr: impl Into<DeviceOrHostAddress>,
701        update_data: AccelerationStructureGeometryInfo<AccelerationStructureGeometry>,
702        range_base: vk::DeviceAddress,
703        range_stride: u32,
704    ) -> Self {
705        let src_accel_struct = src_accel_struct.into();
706        let dst_accel_struct = dst_accel_struct.into();
707        let scratch_addr = scratch_addr.into();
708
709        Self {
710            dst_accel_struct,
711            range_base,
712            range_stride,
713            scratch_addr,
714            src_accel_struct,
715            update_data,
716        }
717    }
718}
719
720/// Specifies the information and data used to update an acceleration structure.
721#[derive(Clone, Debug)]
722pub struct UpdateAccelerationStructureInfo {
723    /// The acceleration structure to be written.
724    pub dst_accel_struct: AnyAccelerationStructureNode,
725
726    /// The temporary buffer or host address (with enough capacity per
727    /// `AccelerationStructure::size_of`).
728    pub scratch_addr: DeviceOrHostAddress,
729
730    /// The source acceleration structure to be read.
731    pub src_accel_struct: AnyAccelerationStructureNode,
732
733    /// Specifies the geometry data to use when updating the acceleration structure.
734    pub update_data: AccelerationStructureGeometryInfo<(
735        AccelerationStructureGeometry,
736        vk::AccelerationStructureBuildRangeInfoKHR,
737    )>,
738}
739
740impl UpdateAccelerationStructureInfo {
741    /// Constructs new acceleration structure update information.
742    pub fn new(
743        src_accel_struct: impl Into<AnyAccelerationStructureNode>,
744        dst_accel_struct: impl Into<AnyAccelerationStructureNode>,
745        scratch_addr: impl Into<DeviceOrHostAddress>,
746        update_data: AccelerationStructureGeometryInfo<(
747            AccelerationStructureGeometry,
748            vk::AccelerationStructureBuildRangeInfoKHR,
749        )>,
750    ) -> Self {
751        let src_accel_struct = src_accel_struct.into();
752        let dst_accel_struct = dst_accel_struct.into();
753        let scratch_addr = scratch_addr.into();
754
755        Self {
756            dst_accel_struct,
757            scratch_addr,
758            src_accel_struct,
759            update_data,
760        }
761    }
762}