vulk_ext/vkx/
command_buffer.rs

1use std::mem::MaybeUninit;
2
3use super::*;
4
5#[derive(Debug)]
6pub struct CommandBuffer {
7    command_buffer: vk::CommandBuffer,
8}
9
10impl CommandBuffer {
11    //
12    // General
13    //
14
15    pub unsafe fn create(device: &Device) -> Result<Self> {
16        // Command buffer.
17        let command_buffer = {
18            let command_buffer_allocate_info = vk::CommandBufferAllocateInfo {
19                s_type: vk::StructureType::CommandBufferAllocateInfo,
20                p_next: null(),
21                command_pool: device.command_pool,
22                level: vk::CommandBufferLevel::Primary,
23                command_buffer_count: 1,
24            };
25            let mut command_buffer = MaybeUninit::uninit();
26            device.allocate_command_buffers(
27                &command_buffer_allocate_info,
28                command_buffer.as_mut_ptr(),
29            )?;
30            command_buffer.assume_init()
31        };
32
33        Ok(Self { command_buffer })
34    }
35
36    pub unsafe fn destroy(self, device: &Device) {
37        device.free_command_buffers(device.command_pool, 1, &self.command_buffer);
38    }
39
40    pub unsafe fn begin(&self, device: &Device) -> Result<()> {
41        // Reset command buffers by resetting the pool.
42        device.reset_command_buffer(self.command_buffer, vk::CommandBufferResetFlags::empty())?;
43
44        // Begin command buffer.
45        device.begin_command_buffer(
46            self.command_buffer,
47            &vk::CommandBufferBeginInfo {
48                s_type: vk::StructureType::CommandBufferBeginInfo,
49                p_next: null(),
50                flags: vk::CommandBufferUsageFlagBits::OneTimeSubmit.into(),
51                p_inheritance_info: null(),
52            },
53        )?;
54
55        Ok(())
56    }
57
58    pub unsafe fn end(&self, device: &Device) -> Result<()> {
59        device.end_command_buffer(self.command_buffer)?;
60        Ok(())
61    }
62
63    #[must_use]
64    pub unsafe fn handle(&self) -> vk::CommandBuffer {
65        self.command_buffer
66    }
67
68    //
69    // Dynamic rendering
70    //
71
72    pub unsafe fn begin_rendering<Image>(
73        &self,
74        device: &Device,
75        color_attachment: (&Image, [f32; 4]),
76        depth_attachment: Option<(&Image, f32)>,
77        resolve_attachment: Option<&Image>,
78    ) where
79        Image: ImageOps,
80    {
81        // Color attachment.
82        let mut color_attachment_info = vk::RenderingAttachmentInfo {
83            s_type: vk::StructureType::RenderingAttachmentInfo,
84            p_next: null(),
85            image_view: color_attachment.0.image_view_handle(),
86            image_layout: vk::ImageLayout::AttachmentOptimal,
87            resolve_mode: vk::ResolveModeFlagBits::None,
88            resolve_image_view: vk::ImageView::null(),
89            resolve_image_layout: vk::ImageLayout::Undefined,
90            load_op: vk::AttachmentLoadOp::Clear,
91            store_op: vk::AttachmentStoreOp::Store,
92            clear_value: vk::ClearValue {
93                color: vk::ClearColorValue {
94                    float32: color_attachment.1,
95                },
96            },
97        };
98
99        // Optional: resolve attachment.
100        if let Some(resolve_attachment) = resolve_attachment {
101            color_attachment_info.resolve_mode = vk::ResolveModeFlagBits::Average;
102            color_attachment_info.resolve_image_view = resolve_attachment.image_view_handle();
103            color_attachment_info.resolve_image_layout = vk::ImageLayout::AttachmentOptimal;
104        }
105
106        // Optional: depth attachment.
107        let mut depth_attachment_info = vk::RenderingAttachmentInfo {
108            s_type: vk::StructureType::RenderingAttachmentInfo,
109            p_next: null(),
110            image_view: vk::ImageView::null(),
111            image_layout: vk::ImageLayout::AttachmentOptimal,
112            resolve_mode: vk::ResolveModeFlagBits::None,
113            resolve_image_view: vk::ImageView::null(),
114            resolve_image_layout: vk::ImageLayout::Undefined,
115            load_op: vk::AttachmentLoadOp::Clear,
116            store_op: vk::AttachmentStoreOp::Store,
117            clear_value: vk::ClearValue {
118                depth_stencil: vk::ClearDepthStencilValue {
119                    depth: 1.0,
120                    stencil: 0,
121                },
122            },
123        };
124        if let Some((depth_attachment, depth)) = depth_attachment {
125            depth_attachment_info.image_view = depth_attachment.image_view_handle();
126            depth_attachment_info.clear_value.depth_stencil.depth = depth;
127        }
128
129        // Rendering info.
130        let mut rendering_info = vk::RenderingInfo {
131            s_type: vk::StructureType::RenderingInfo,
132            p_next: null(),
133            flags: vk::RenderingFlags::empty(),
134            render_area: color_attachment.0.rect_2d(),
135            layer_count: 1,
136            view_mask: 0,
137            color_attachment_count: 1,
138            p_color_attachments: &color_attachment_info,
139            p_depth_attachment: null(),
140            p_stencil_attachment: null(),
141        };
142        if depth_attachment.is_some() {
143            rendering_info.p_depth_attachment = &depth_attachment_info;
144        }
145
146        // Begin rendering.
147        device.cmd_begin_rendering(self.command_buffer, &rendering_info);
148    }
149
150    pub unsafe fn end_rendering(&self, device: &Device) {
151        device.cmd_end_rendering(self.command_buffer);
152    }
153
154    //
155    // Barriers
156    //
157
158    pub unsafe fn barrier(
159        &self,
160        device: &Device,
161        src_stage_mask: impl Into<vk::PipelineStageFlags2>,
162        src_access_mask: impl Into<vk::AccessFlags2>,
163        dst_stage_mask: impl Into<vk::PipelineStageFlags2>,
164        dst_access_mask: impl Into<vk::AccessFlags2>,
165    ) {
166        device.cmd_pipeline_barrier2(
167            self.command_buffer,
168            &vk::DependencyInfo {
169                s_type: vk::StructureType::DependencyInfo,
170                p_next: null(),
171                dependency_flags: vk::DependencyFlags::empty(),
172                memory_barrier_count: 1,
173                p_memory_barriers: &vk::MemoryBarrier2 {
174                    s_type: vk::StructureType::MemoryBarrier2,
175                    p_next: null(),
176                    src_stage_mask: src_stage_mask.into(),
177                    src_access_mask: src_access_mask.into(),
178                    dst_stage_mask: dst_stage_mask.into(),
179                    dst_access_mask: dst_access_mask.into(),
180                },
181                buffer_memory_barrier_count: 0,
182                p_buffer_memory_barriers: null(),
183                image_memory_barrier_count: 0,
184                p_image_memory_barriers: null(),
185            },
186        );
187    }
188
189    pub unsafe fn buffer_barrier(
190        &self,
191        device: &Device,
192        buffer: &impl BufferOps,
193        src_stage_mask: impl Into<vk::PipelineStageFlags2>,
194        src_access_mask: impl Into<vk::AccessFlags2>,
195        dst_stage_mask: impl Into<vk::PipelineStageFlags2>,
196        dst_access_mask: impl Into<vk::AccessFlags2>,
197    ) {
198        device.cmd_pipeline_barrier2(
199            self.command_buffer,
200            &vk::DependencyInfo {
201                s_type: vk::StructureType::DependencyInfo,
202                p_next: null(),
203                dependency_flags: vk::DependencyFlags::empty(),
204                memory_barrier_count: 0,
205                p_memory_barriers: null(),
206                buffer_memory_barrier_count: 1,
207                p_buffer_memory_barriers: &vk::BufferMemoryBarrier2 {
208                    s_type: vk::StructureType::BufferMemoryBarrier2,
209                    p_next: null(),
210                    src_stage_mask: src_stage_mask.into(),
211                    src_access_mask: src_access_mask.into(),
212                    dst_stage_mask: dst_stage_mask.into(),
213                    dst_access_mask: dst_access_mask.into(),
214                    src_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
215                    dst_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
216                    buffer: buffer.buffer_handle(),
217                    offset: 0,
218                    size: vk::WHOLE_SIZE,
219                },
220                image_memory_barrier_count: 0,
221                p_image_memory_barriers: null(),
222            },
223        );
224    }
225
226    pub unsafe fn image_barrier(
227        &self,
228        device: &Device,
229        image: &impl ImageOps,
230        src_stage_mask: impl Into<vk::PipelineStageFlags2>,
231        src_access_mask: impl Into<vk::AccessFlags2>,
232        dst_stage_mask: impl Into<vk::PipelineStageFlags2>,
233        dst_access_mask: impl Into<vk::AccessFlags2>,
234        old_layout: vk::ImageLayout,
235        new_layout: vk::ImageLayout,
236    ) {
237        device.cmd_pipeline_barrier2(
238            self.command_buffer,
239            &vk::DependencyInfo {
240                s_type: vk::StructureType::DependencyInfo,
241                p_next: null(),
242                dependency_flags: vk::DependencyFlags::empty(),
243                memory_barrier_count: 0,
244                p_memory_barriers: null(),
245                buffer_memory_barrier_count: 0,
246                p_buffer_memory_barriers: null(),
247                image_memory_barrier_count: 1,
248                p_image_memory_barriers: &vk::ImageMemoryBarrier2 {
249                    s_type: vk::StructureType::ImageMemoryBarrier2,
250                    p_next: null(),
251                    src_stage_mask: src_stage_mask.into(),
252                    src_access_mask: src_access_mask.into(),
253                    dst_stage_mask: dst_stage_mask.into(),
254                    dst_access_mask: dst_access_mask.into(),
255                    old_layout,
256                    new_layout,
257                    src_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
258                    dst_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
259                    image: image.image_handle(),
260                    subresource_range: image.subresource_range(),
261                },
262            },
263        );
264    }
265
266    //
267    // Draws/dispatches
268    //
269
270    pub unsafe fn draw_mesh_tasks(
271        &self,
272        device: &Device,
273        group_count_x: u32,
274        group_count_y: u32,
275        group_count_z: u32,
276    ) {
277        device.cmd_draw_mesh_tasks_ext(
278            self.command_buffer,
279            group_count_x,
280            group_count_y,
281            group_count_z,
282        );
283    }
284
285    pub unsafe fn draw_mesh_tasks_indirect(
286        &self,
287        device: &Device,
288        buffer: &impl BufferOps,
289        offset: vk::DeviceSize,
290        draw_count: u32,
291        stride: u32,
292    ) {
293        device.cmd_draw_mesh_tasks_indirect_ext(
294            self.command_buffer,
295            buffer.buffer_handle(),
296            offset,
297            draw_count,
298            stride,
299        );
300    }
301
302    pub unsafe fn draw_mesh_tasks_indirect_count(
303        &self,
304        device: &Device,
305        buffer: &impl BufferOps,
306        offset: vk::DeviceSize,
307        count_buffer: &impl BufferOps,
308        count_buffer_offset: vk::DeviceSize,
309        max_draw_count: u32,
310        stride: u32,
311    ) {
312        device.cmd_draw_mesh_tasks_indirect_count_ext(
313            self.command_buffer,
314            buffer.buffer_handle(),
315            offset,
316            count_buffer.buffer_handle(),
317            count_buffer_offset,
318            max_draw_count,
319            stride,
320        );
321    }
322
323    pub unsafe fn dispatch(
324        &self,
325        device: &Device,
326        group_count_x: u32,
327        group_count_y: u32,
328        group_count_z: u32,
329    ) {
330        device.cmd_dispatch(
331            self.command_buffer,
332            group_count_x,
333            group_count_y,
334            group_count_z,
335        );
336    }
337
338    pub unsafe fn dispatch_indirect(
339        &self,
340        device: &Device,
341        buffer: &impl BufferOps,
342        offset: vk::DeviceSize,
343    ) {
344        device.cmd_dispatch_indirect(self.command_buffer, buffer.buffer_handle(), offset);
345    }
346
347    //
348    // Copies
349    //
350
351    pub unsafe fn copy_buffer(
352        &self,
353        device: &Device,
354        src_buffer: (&impl BufferOps, vk::DeviceSize),
355        dst_buffer: (&impl BufferOps, vk::DeviceSize),
356        size: vk::DeviceSize,
357    ) {
358        device.cmd_copy_buffer2(
359            self.command_buffer,
360            &vk::CopyBufferInfo2 {
361                s_type: vk::StructureType::CopyBufferInfo2,
362                p_next: null(),
363                src_buffer: src_buffer.0.buffer_handle(),
364                dst_buffer: dst_buffer.0.buffer_handle(),
365                region_count: 1,
366                p_regions: &vk::BufferCopy2 {
367                    s_type: vk::StructureType::BufferCopy2,
368                    p_next: null(),
369                    src_offset: src_buffer.1,
370                    dst_offset: dst_buffer.1,
371                    size,
372                },
373            },
374        );
375    }
376
377    pub unsafe fn copy_image(
378        &self,
379        device: &Device,
380        src_image: (&impl ImageOps, vk::ImageLayout),
381        dst_image: (&impl ImageOps, vk::ImageLayout),
382        extent: vk::Extent3D,
383    ) {
384        device.cmd_copy_image2(
385            self.command_buffer,
386            &vk::CopyImageInfo2 {
387                s_type: vk::StructureType::CopyImageInfo2,
388                p_next: null(),
389                src_image: src_image.0.image_handle(),
390                src_image_layout: src_image.1,
391                dst_image: dst_image.0.image_handle(),
392                dst_image_layout: dst_image.1,
393                region_count: 1,
394                p_regions: &vk::ImageCopy2 {
395                    s_type: vk::StructureType::ImageCopy2,
396                    p_next: null(),
397                    src_subresource: src_image.0.subresource_layers(),
398                    src_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
399                    dst_subresource: dst_image.0.subresource_layers(),
400                    dst_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
401                    extent,
402                },
403            },
404        );
405    }
406
407    pub unsafe fn copy_buffer_to_image(
408        &self,
409        device: &Device,
410        src_buffer: (&impl BufferOps, vk::DeviceSize),
411        dst_image: &impl ImageOps,
412    ) {
413        device.cmd_copy_buffer_to_image2(
414            self.command_buffer,
415            &vk::CopyBufferToImageInfo2 {
416                s_type: vk::StructureType::CopyBufferToImageInfo2,
417                p_next: null(),
418                src_buffer: src_buffer.0.buffer_handle(),
419                dst_image: dst_image.image_handle(),
420                dst_image_layout: vk::ImageLayout::TransferDstOptimal,
421                region_count: 1,
422                p_regions: &vk::BufferImageCopy2 {
423                    s_type: vk::StructureType::BufferImageCopy2,
424                    p_next: null(),
425                    buffer_offset: src_buffer.1,
426                    buffer_row_length: 0,
427                    buffer_image_height: 0,
428                    image_subresource: dst_image.subresource_layers(),
429                    image_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
430                    image_extent: dst_image.extent_3d(),
431                },
432            },
433        );
434    }
435
436    pub unsafe fn copy_image_to_buffer(
437        &self,
438        device: &Device,
439        src_image: &impl ImageOps,
440        dst_buffer: (&impl BufferOps, vk::DeviceSize),
441    ) {
442        device.cmd_copy_image_to_buffer2(
443            self.command_buffer,
444            &vk::CopyImageToBufferInfo2 {
445                s_type: vk::StructureType::CopyImageToBufferInfo2,
446                p_next: null(),
447                src_image: src_image.image_handle(),
448                src_image_layout: vk::ImageLayout::TransferSrcOptimal,
449                dst_buffer: dst_buffer.0.buffer_handle(),
450                region_count: 1,
451                p_regions: &vk::BufferImageCopy2 {
452                    s_type: vk::StructureType::BufferImageCopy2,
453                    p_next: null(),
454                    buffer_offset: dst_buffer.1,
455                    buffer_row_length: 0,
456                    buffer_image_height: 0,
457                    image_subresource: src_image.subresource_layers(),
458                    image_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
459                    image_extent: src_image.extent_3d(),
460                },
461            },
462        );
463    }
464
465    //
466    // Descriptors/push constants
467    //
468
469    pub unsafe fn bind_descriptor_storage(
470        &self,
471        device: &Device,
472        descriptor_storage: &DescriptorStorage,
473        pipeline_bind_point: vk::PipelineBindPoint,
474    ) {
475        let ds = descriptor_storage;
476        device.cmd_bind_descriptor_buffers_ext(
477            self.command_buffer,
478            1,
479            &vk::DescriptorBufferBindingInfoEXT {
480                s_type: vk::StructureType::DescriptorBufferBindingInfoEXT,
481                p_next: null_mut(),
482                address: ds.allocation.device_address(),
483                usage: ds.usage,
484            },
485        );
486        device.cmd_set_descriptor_buffer_offsets_ext(
487            self.command_buffer,
488            pipeline_bind_point,
489            ds.pipeline_layout,
490            0,
491            ds.set_count,
492            ds.buffer_indices.as_ptr(),
493            ds.offsets.as_ptr(),
494        );
495    }
496
497    pub unsafe fn push_constants<T>(
498        &self,
499        device: &Device,
500        descriptor_storage: &DescriptorStorage,
501        data: &T,
502    ) -> Result<()> {
503        let ds = descriptor_storage;
504        let Some(pcr) = ds.push_constant_range else {
505            bail!("Missing push constant range");
506        };
507        ensure!(pcr.size as usize == size_of::<T>());
508        device.cmd_push_constants(
509            self.command_buffer,
510            ds.pipeline_layout,
511            pcr.stage_flags,
512            pcr.offset,
513            pcr.size,
514            (data as *const T).cast(),
515        );
516        Ok(())
517    }
518
519    //
520    // Shaders
521    //
522
523    pub unsafe fn bind_shader(&self, device: &Device, shader: &Shader) {
524        device.cmd_bind_shaders_ext(
525            self.command_buffer,
526            shader.stages.len() as _,
527            shader.stages.as_ptr(),
528            shader.shaders.as_ptr(),
529        );
530    }
531
532    //
533    // Rasterizer
534    //
535
536    pub unsafe fn set_viewport(&self, device: &Device, viewport: &vk::Viewport) {
537        device.cmd_set_viewport_with_count(self.command_buffer, 1, viewport);
538    }
539
540    pub unsafe fn set_viewport_flip_y(&self, device: &Device, viewport: &vk::Viewport) {
541        // VK_KHR_maintenance1: Allow negative height to be specified in the
542        // VkViewport::height field to perform y-inversion of the clip-space to
543        // framebuffer-space transform. This allows apps to avoid having to use
544        // gl_Position.y = -gl_Position.y in shaders also targeting other APIs.
545        self.set_viewport(
546            device,
547            &vk::Viewport {
548                x: viewport.x,
549                y: viewport.y + viewport.height,
550                width: viewport.width,
551                height: -viewport.height,
552                min_depth: viewport.min_depth,
553                max_depth: viewport.max_depth,
554            },
555        );
556    }
557
558    pub unsafe fn set_scissor(&self, device: &Device, scissor: &vk::Rect2D) {
559        device.cmd_set_scissor_with_count(self.command_buffer, 1, scissor);
560    }
561
562    pub unsafe fn set_samples(&self, device: &Device, samples: vk::SampleCountFlagBits) {
563        device.cmd_set_rasterization_samples_ext(self.command_buffer, samples);
564    }
565
566    pub unsafe fn set_front_face(&self, device: &Device, front_face: vk::FrontFace) {
567        device.cmd_set_front_face(self.command_buffer, front_face);
568    }
569
570    pub unsafe fn set_cull_mode(&self, device: &Device, cull_mode: impl Into<vk::CullModeFlags>) {
571        device.cmd_set_cull_mode(self.command_buffer, cull_mode.into());
572    }
573
574    pub unsafe fn set_depth_test(&self, device: &Device, depth_test: bool) {
575        device.cmd_set_depth_test_enable(self.command_buffer, depth_test.into());
576    }
577
578    pub unsafe fn set_depth_compare_op(&self, device: &Device, depth_compare_op: vk::CompareOp) {
579        device.cmd_set_depth_compare_op(self.command_buffer, depth_compare_op);
580    }
581
582    pub unsafe fn set_depth_write(&self, device: &Device, depth_write: bool) {
583        device.cmd_set_depth_write_enable(self.command_buffer, depth_write.into());
584    }
585
586    pub unsafe fn set_color_blend(&self, device: &Device, attachment: u32, color_blend: bool) {
587        device.cmd_set_color_blend_enable_ext(
588            self.command_buffer,
589            attachment,
590            1,
591            [color_blend.into()].as_ptr(),
592        );
593    }
594
595    pub unsafe fn set_color_blend_equation(
596        &self,
597        device: &Device,
598        attachment: u32,
599        color_blend_equation: &vk::ColorBlendEquationEXT,
600    ) {
601        device.cmd_set_color_blend_equation_ext(
602            self.command_buffer,
603            attachment,
604            1,
605            color_blend_equation,
606        );
607    }
608
609    pub unsafe fn set_color_write_mask(
610        &self,
611        device: &Device,
612        attachment: u32,
613        mask: vk::ColorComponentFlags,
614    ) {
615        device.cmd_set_color_write_mask_ext(self.command_buffer, attachment, 1, [mask].as_ptr());
616    }
617
618    pub unsafe fn set_color_write_mask_rgba(&self, device: &Device, attachment: u32) {
619        self.set_color_write_mask(
620            device,
621            attachment,
622            vk::ColorComponentFlagBits::R
623                | vk::ColorComponentFlagBits::G
624                | vk::ColorComponentFlagBits::B
625                | vk::ColorComponentFlagBits::A,
626        );
627    }
628
629    //
630    // Queries
631    //
632
633    pub unsafe fn write_timestamp(&self, device: &Device, timestamps: &TimestampQuery, index: u32) {
634        device.cmd_write_timestamp2(
635            self.command_buffer,
636            vk::PipelineStageFlagBits2::AllCommands.into(),
637            timestamps.query_pool,
638            index,
639        );
640    }
641
642    pub unsafe fn begin_statistics(&self, device: &Device, statistics: &StatisticsQuery) {
643        device.cmd_begin_query(
644            self.command_buffer,
645            statistics.pipeline_statistic_query_pool,
646            0,
647            vk::QueryControlFlags::empty(),
648        );
649        device.cmd_begin_query(
650            self.command_buffer,
651            statistics.mesh_primitives_generated_query_pool,
652            0,
653            vk::QueryControlFlags::empty(),
654        );
655    }
656
657    pub unsafe fn end_statistics(&self, device: &Device, statistics: &StatisticsQuery) {
658        device.cmd_end_query(
659            self.command_buffer,
660            statistics.pipeline_statistic_query_pool,
661            0,
662        );
663        device.cmd_end_query(
664            self.command_buffer,
665            statistics.mesh_primitives_generated_query_pool,
666            0,
667        );
668    }
669
670    //
671    // Ray tracing
672    //
673
674    pub unsafe fn build_acceleration_structures(
675        &self,
676        device: &Device,
677        ty: vk::AccelerationStructureTypeKHR,
678        dst_acceleration_structure: vk::AccelerationStructureKHR,
679        geometry_count: u32,
680        geometries: &vk::AccelerationStructureGeometryKHR,
681        primitive_count: u32,
682        scratch_data: &impl BufferOps,
683    ) {
684        let acceleration_structure_build_geometry_info_khr =
685            vk::AccelerationStructureBuildGeometryInfoKHR {
686                s_type: vk::StructureType::AccelerationStructureBuildGeometryInfoKHR,
687                p_next: null(),
688                ty,
689                flags: vk::BuildAccelerationStructureFlagBitsKHR::PreferFastTraceKHR.into(),
690                mode: vk::BuildAccelerationStructureModeKHR::BuildKHR,
691                src_acceleration_structure: vk::AccelerationStructureKHR::null(),
692                dst_acceleration_structure,
693                geometry_count,
694                p_geometries: geometries as *const _,
695                pp_geometries: null(),
696                scratch_data: vk::DeviceOrHostAddressKHR {
697                    device_address: scratch_data.memory().device_address(),
698                },
699            };
700        let acceleration_structure_build_range_info_khr =
701            vk::AccelerationStructureBuildRangeInfoKHR {
702                primitive_count,
703                primitive_offset: 0,
704                first_vertex: 0,
705                transform_offset: 0,
706            };
707
708        device.cmd_build_acceleration_structures_khr(
709            self.command_buffer,
710            1,
711            &acceleration_structure_build_geometry_info_khr,
712            [addr_of!(acceleration_structure_build_range_info_khr)].as_ptr(),
713        );
714    }
715
716    pub unsafe fn bind_ray_tracing_pipeline(&self, device: &Device, pipeline: vk::Pipeline) {
717        device.cmd_bind_pipeline(
718            self.command_buffer,
719            vk::PipelineBindPoint::RayTracingKHR,
720            pipeline,
721        );
722    }
723
724    pub unsafe fn trace_rays<Sbt>(
725        &self,
726        physical_device: &PhysicalDevice,
727        device: &Device,
728        raygen_sbt: Option<&Sbt>,
729        miss_sbt: Option<&Sbt>,
730        hit_sbt: Option<&Sbt>,
731        callable_sbt: Option<&Sbt>,
732        width: u32,
733        height: u32,
734    ) where
735        Sbt: BufferOps,
736    {
737        let rt_props = &physical_device.raytracing_pipeline_properties;
738        let shader_group_handle_size = u64::from(rt_props.shader_group_handle_size);
739
740        let mut raygen_sdar: vk::StridedDeviceAddressRegionKHR = zeroed();
741        if let Some(sbt) = raygen_sbt {
742            raygen_sdar.device_address = sbt.memory().device_address();
743            raygen_sdar.stride = shader_group_handle_size;
744            raygen_sdar.size = shader_group_handle_size;
745        }
746
747        let mut miss_sdar: vk::StridedDeviceAddressRegionKHR = zeroed();
748        if let Some(sbt) = miss_sbt {
749            miss_sdar.device_address = sbt.memory().device_address();
750            miss_sdar.stride = shader_group_handle_size;
751            miss_sdar.size = shader_group_handle_size;
752        }
753
754        let mut hit_sdar: vk::StridedDeviceAddressRegionKHR = zeroed();
755        if let Some(sbt) = hit_sbt {
756            hit_sdar.device_address = sbt.memory().device_address();
757            hit_sdar.stride = shader_group_handle_size;
758            hit_sdar.size = shader_group_handle_size;
759        }
760
761        let mut callable_sdar: vk::StridedDeviceAddressRegionKHR = zeroed();
762        if let Some(sbt) = callable_sbt {
763            callable_sdar.device_address = sbt.memory().device_address();
764            callable_sdar.stride = shader_group_handle_size;
765            callable_sdar.size = shader_group_handle_size;
766        }
767
768        device.cmd_trace_rays_khr(
769            self.command_buffer,
770            &raygen_sdar,
771            &miss_sdar,
772            &hit_sdar,
773            &callable_sdar,
774            width,
775            height,
776            1,
777        );
778    }
779}