wgpu_hal/vulkan/
command.rs

1use super::conv;
2use arrayvec::ArrayVec;
3use ash::vk;
4use core::{mem, ops::Range};
5use hashbrown::hash_map::Entry;
6
7const ALLOCATION_GRANULARITY: u32 = 16;
8const DST_IMAGE_LAYOUT: vk::ImageLayout = vk::ImageLayout::TRANSFER_DST_OPTIMAL;
9
10impl super::Texture {
11    fn map_buffer_copies<T>(&self, regions: T) -> impl Iterator<Item = vk::BufferImageCopy>
12    where
13        T: Iterator<Item = crate::BufferTextureCopy>,
14    {
15        let (block_width, block_height) = self.format.block_dimensions();
16        let format = self.format;
17        let copy_size = self.copy_size;
18        regions.map(move |r| {
19            let extent = r.texture_base.max_copy_size(&copy_size).min(&r.size);
20            let (image_subresource, image_offset) = conv::map_subresource_layers(&r.texture_base);
21            vk::BufferImageCopy {
22                buffer_offset: r.buffer_layout.offset,
23                buffer_row_length: r.buffer_layout.bytes_per_row.map_or(0, |bpr| {
24                    let block_size = format
25                        .block_copy_size(Some(r.texture_base.aspect.map()))
26                        .unwrap();
27                    block_width * (bpr / block_size)
28                }),
29                buffer_image_height: r
30                    .buffer_layout
31                    .rows_per_image
32                    .map_or(0, |rpi| rpi * block_height),
33                image_subresource,
34                image_offset,
35                image_extent: conv::map_copy_extent(&extent),
36            }
37        })
38    }
39}
40
41impl super::CommandEncoder {
42    fn write_pass_end_timestamp_if_requested(&mut self) {
43        if let Some((query_set, index)) = self.end_of_pass_timer_query.take() {
44            unsafe {
45                self.device.raw.cmd_write_timestamp(
46                    self.active,
47                    vk::PipelineStageFlags::BOTTOM_OF_PIPE,
48                    query_set,
49                    index,
50                );
51            }
52        }
53    }
54
55    fn make_framebuffer(
56        &mut self,
57        key: super::FramebufferKey,
58    ) -> Result<vk::Framebuffer, crate::DeviceError> {
59        Ok(match self.framebuffers.entry(key) {
60            Entry::Occupied(e) => *e.get(),
61            Entry::Vacant(e) => {
62                let super::FramebufferKey {
63                    raw_pass,
64                    ref attachment_views,
65                    attachment_identities: _,
66                    extent,
67                } = *e.key();
68
69                let vk_info = vk::FramebufferCreateInfo::default()
70                    .render_pass(raw_pass)
71                    .width(extent.width)
72                    .height(extent.height)
73                    .layers(extent.depth_or_array_layers)
74                    .attachments(attachment_views);
75
76                let raw = unsafe { self.device.raw.create_framebuffer(&vk_info, None).unwrap() };
77                *e.insert(raw)
78            }
79        })
80    }
81
82    fn make_temp_texture_view(
83        &mut self,
84        key: super::TempTextureViewKey,
85    ) -> Result<super::IdentifiedTextureView, crate::DeviceError> {
86        Ok(match self.temp_texture_views.entry(key) {
87            Entry::Occupied(e) => *e.get(),
88            Entry::Vacant(e) => {
89                let super::TempTextureViewKey {
90                    texture,
91                    texture_identity: _,
92                    format,
93                    mip_level,
94                    depth_slice,
95                } = *e.key();
96
97                let vk_info = vk::ImageViewCreateInfo::default()
98                    .image(texture)
99                    .view_type(vk::ImageViewType::TYPE_2D)
100                    .format(format)
101                    .subresource_range(vk::ImageSubresourceRange {
102                        aspect_mask: vk::ImageAspectFlags::COLOR,
103                        base_mip_level: mip_level,
104                        level_count: 1,
105                        base_array_layer: depth_slice,
106                        layer_count: 1,
107                    });
108                let raw = unsafe { self.device.raw.create_image_view(&vk_info, None) }
109                    .map_err(super::map_host_device_oom_and_ioca_err)?;
110
111                let identity = self.device.texture_view_identity_factory.next();
112
113                *e.insert(super::IdentifiedTextureView { raw, identity })
114            }
115        })
116    }
117}
118
119impl crate::CommandEncoder for super::CommandEncoder {
120    type A = super::Api;
121
122    unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> {
123        if self.free.is_empty() {
124            let vk_info = vk::CommandBufferAllocateInfo::default()
125                .command_pool(self.raw)
126                .command_buffer_count(ALLOCATION_GRANULARITY);
127            let cmd_buf_vec = unsafe {
128                self.device
129                    .raw
130                    .allocate_command_buffers(&vk_info)
131                    .map_err(super::map_host_device_oom_err)?
132            };
133            self.free.extend(cmd_buf_vec);
134        }
135        let raw = self.free.pop().unwrap();
136
137        // Set the name unconditionally, since there might be a
138        // previous name assigned to this.
139        unsafe { self.device.set_object_name(raw, label.unwrap_or_default()) };
140
141        // Reset some state in case the last renderpass was never ended.
142        self.rpass_debug_marker_active = false;
143        self.end_of_pass_timer_query = None;
144
145        let vk_info = vk::CommandBufferBeginInfo::default()
146            .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
147        unsafe { self.device.raw.begin_command_buffer(raw, &vk_info) }
148            .map_err(super::map_host_device_oom_err)?;
149        self.active = raw;
150
151        Ok(())
152    }
153
154    unsafe fn end_encoding(&mut self) -> Result<super::CommandBuffer, crate::DeviceError> {
155        let raw = self.active;
156        self.active = vk::CommandBuffer::null();
157        unsafe { self.device.raw.end_command_buffer(raw) }.map_err(map_err)?;
158        fn map_err(err: vk::Result) -> crate::DeviceError {
159            // We don't use VK_KHR_video_encode_queue
160            // VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR
161            super::map_host_device_oom_err(err)
162        }
163        Ok(super::CommandBuffer { raw })
164    }
165
166    unsafe fn discard_encoding(&mut self) {
167        // Safe use requires this is not called in the "closed" state, so the buffer
168        // shouldn't be null. Assert this to make sure we're not pushing null
169        // buffers to the discard pile.
170        assert_ne!(self.active, vk::CommandBuffer::null());
171
172        self.discarded.push(self.active);
173        self.active = vk::CommandBuffer::null();
174    }
175
176    unsafe fn reset_all<I>(&mut self, cmd_bufs: I)
177    where
178        I: Iterator<Item = super::CommandBuffer>,
179    {
180        self.temp.clear();
181        self.free
182            .extend(cmd_bufs.into_iter().map(|cmd_buf| cmd_buf.raw));
183        self.free.append(&mut self.discarded);
184        // Delete framebuffers from the framebuffer cache
185        for (_, framebuffer) in self.framebuffers.drain() {
186            unsafe { self.device.raw.destroy_framebuffer(framebuffer, None) };
187        }
188        let _ = unsafe {
189            self.device
190                .raw
191                .reset_command_pool(self.raw, vk::CommandPoolResetFlags::default())
192        };
193    }
194
195    unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
196    where
197        T: Iterator<Item = crate::BufferBarrier<'a, super::Buffer>>,
198    {
199        //Note: this is done so that we never end up with empty stage flags
200        let mut src_stages = vk::PipelineStageFlags::TOP_OF_PIPE;
201        let mut dst_stages = vk::PipelineStageFlags::BOTTOM_OF_PIPE;
202        let vk_barriers = &mut self.temp.buffer_barriers;
203        vk_barriers.clear();
204
205        for bar in barriers {
206            let (src_stage, src_access) =
207                conv::map_buffer_usage_to_barrier(bar.usage.from, self.device.queue_flags);
208            src_stages |= src_stage;
209            let (dst_stage, dst_access) =
210                conv::map_buffer_usage_to_barrier(bar.usage.to, self.device.queue_flags);
211            dst_stages |= dst_stage;
212
213            vk_barriers.push(
214                vk::BufferMemoryBarrier::default()
215                    .buffer(bar.buffer.raw)
216                    .size(vk::WHOLE_SIZE)
217                    .src_access_mask(src_access)
218                    .dst_access_mask(dst_access),
219            )
220        }
221
222        if !vk_barriers.is_empty() {
223            unsafe {
224                self.device.raw.cmd_pipeline_barrier(
225                    self.active,
226                    src_stages,
227                    dst_stages,
228                    vk::DependencyFlags::empty(),
229                    &[],
230                    vk_barriers,
231                    &[],
232                )
233            };
234        }
235    }
236
237    unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
238    where
239        T: Iterator<Item = crate::TextureBarrier<'a, super::Texture>>,
240    {
241        let mut src_stages = vk::PipelineStageFlags::empty();
242        let mut dst_stages = vk::PipelineStageFlags::empty();
243        let vk_barriers = &mut self.temp.image_barriers;
244        vk_barriers.clear();
245
246        for bar in barriers {
247            let range = conv::map_subresource_range_combined_aspect(
248                &bar.range,
249                bar.texture.format,
250                &self.device.private_caps,
251            );
252            let (src_stage, src_access) =
253                conv::map_texture_usage_to_barrier(bar.usage.from, self.device.queue_flags);
254            let src_layout = conv::derive_image_layout(bar.usage.from, bar.texture.format);
255            src_stages |= src_stage;
256            let (dst_stage, dst_access) =
257                conv::map_texture_usage_to_barrier(bar.usage.to, self.device.queue_flags);
258            let dst_layout = conv::derive_image_layout(bar.usage.to, bar.texture.format);
259            dst_stages |= dst_stage;
260
261            vk_barriers.push(
262                vk::ImageMemoryBarrier::default()
263                    .image(bar.texture.raw)
264                    .subresource_range(range)
265                    .src_access_mask(src_access)
266                    .dst_access_mask(dst_access)
267                    .old_layout(src_layout)
268                    .new_layout(dst_layout),
269            );
270        }
271
272        if !vk_barriers.is_empty() {
273            unsafe {
274                self.device.raw.cmd_pipeline_barrier(
275                    self.active,
276                    src_stages,
277                    dst_stages,
278                    vk::DependencyFlags::empty(),
279                    &[],
280                    &[],
281                    vk_barriers,
282                )
283            };
284        }
285    }
286
287    unsafe fn clear_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange) {
288        let range_size = range.end - range.start;
289        if self.device.workarounds.contains(
290            super::Workarounds::FORCE_FILL_BUFFER_WITH_SIZE_GREATER_4096_ALIGNED_OFFSET_16,
291        ) && range_size >= 4096
292            && !range.start.is_multiple_of(16)
293        {
294            let rounded_start = wgt::math::align_to(range.start, 16);
295            let prefix_size = rounded_start - range.start;
296
297            unsafe {
298                self.device.raw.cmd_fill_buffer(
299                    self.active,
300                    buffer.raw,
301                    range.start,
302                    prefix_size,
303                    0,
304                )
305            };
306
307            // This will never be zero, as rounding can only add up to 12 bytes, and the total size is 4096.
308            let suffix_size = range.end - rounded_start;
309
310            unsafe {
311                self.device.raw.cmd_fill_buffer(
312                    self.active,
313                    buffer.raw,
314                    rounded_start,
315                    suffix_size,
316                    0,
317                )
318            };
319        } else {
320            unsafe {
321                self.device
322                    .raw
323                    .cmd_fill_buffer(self.active, buffer.raw, range.start, range_size, 0)
324            };
325        }
326    }
327
328    unsafe fn copy_buffer_to_buffer<T>(
329        &mut self,
330        src: &super::Buffer,
331        dst: &super::Buffer,
332        regions: T,
333    ) where
334        T: Iterator<Item = crate::BufferCopy>,
335    {
336        let vk_regions_iter = regions.map(|r| vk::BufferCopy {
337            src_offset: r.src_offset,
338            dst_offset: r.dst_offset,
339            size: r.size.get(),
340        });
341
342        unsafe {
343            self.device.raw.cmd_copy_buffer(
344                self.active,
345                src.raw,
346                dst.raw,
347                &smallvec::SmallVec::<[vk::BufferCopy; 32]>::from_iter(vk_regions_iter),
348            )
349        };
350    }
351
352    unsafe fn copy_texture_to_texture<T>(
353        &mut self,
354        src: &super::Texture,
355        src_usage: wgt::TextureUses,
356        dst: &super::Texture,
357        regions: T,
358    ) where
359        T: Iterator<Item = crate::TextureCopy>,
360    {
361        let src_layout = conv::derive_image_layout(src_usage, src.format);
362
363        let vk_regions_iter = regions.map(|r| {
364            let (src_subresource, src_offset) = conv::map_subresource_layers(&r.src_base);
365            let (dst_subresource, dst_offset) = conv::map_subresource_layers(&r.dst_base);
366            let extent = r
367                .size
368                .min(&r.src_base.max_copy_size(&src.copy_size))
369                .min(&r.dst_base.max_copy_size(&dst.copy_size));
370            vk::ImageCopy {
371                src_subresource,
372                src_offset,
373                dst_subresource,
374                dst_offset,
375                extent: conv::map_copy_extent(&extent),
376            }
377        });
378
379        unsafe {
380            self.device.raw.cmd_copy_image(
381                self.active,
382                src.raw,
383                src_layout,
384                dst.raw,
385                DST_IMAGE_LAYOUT,
386                &smallvec::SmallVec::<[vk::ImageCopy; 32]>::from_iter(vk_regions_iter),
387            )
388        };
389    }
390
391    unsafe fn copy_buffer_to_texture<T>(
392        &mut self,
393        src: &super::Buffer,
394        dst: &super::Texture,
395        regions: T,
396    ) where
397        T: Iterator<Item = crate::BufferTextureCopy>,
398    {
399        let vk_regions_iter = dst.map_buffer_copies(regions);
400
401        unsafe {
402            self.device.raw.cmd_copy_buffer_to_image(
403                self.active,
404                src.raw,
405                dst.raw,
406                DST_IMAGE_LAYOUT,
407                &smallvec::SmallVec::<[vk::BufferImageCopy; 32]>::from_iter(vk_regions_iter),
408            )
409        };
410    }
411
412    unsafe fn copy_texture_to_buffer<T>(
413        &mut self,
414        src: &super::Texture,
415        src_usage: wgt::TextureUses,
416        dst: &super::Buffer,
417        regions: T,
418    ) where
419        T: Iterator<Item = crate::BufferTextureCopy>,
420    {
421        let src_layout = conv::derive_image_layout(src_usage, src.format);
422        let vk_regions_iter = src.map_buffer_copies(regions);
423
424        unsafe {
425            self.device.raw.cmd_copy_image_to_buffer(
426                self.active,
427                src.raw,
428                src_layout,
429                dst.raw,
430                &smallvec::SmallVec::<[vk::BufferImageCopy; 32]>::from_iter(vk_regions_iter),
431            )
432        };
433    }
434
435    unsafe fn begin_query(&mut self, set: &super::QuerySet, index: u32) {
436        unsafe {
437            self.device.raw.cmd_begin_query(
438                self.active,
439                set.raw,
440                index,
441                vk::QueryControlFlags::empty(),
442            )
443        };
444    }
445    unsafe fn end_query(&mut self, set: &super::QuerySet, index: u32) {
446        unsafe { self.device.raw.cmd_end_query(self.active, set.raw, index) };
447    }
448    unsafe fn write_timestamp(&mut self, set: &super::QuerySet, index: u32) {
449        unsafe {
450            self.device.raw.cmd_write_timestamp(
451                self.active,
452                vk::PipelineStageFlags::BOTTOM_OF_PIPE,
453                set.raw,
454                index,
455            )
456        };
457    }
458    unsafe fn read_acceleration_structure_compact_size(
459        &mut self,
460        acceleration_structure: &super::AccelerationStructure,
461        buffer: &super::Buffer,
462    ) {
463        let ray_tracing_functions = self
464            .device
465            .extension_fns
466            .ray_tracing
467            .as_ref()
468            .expect("Feature `RAY_TRACING` not enabled");
469        let query_pool = acceleration_structure
470            .compacted_size_query
471            .as_ref()
472            .unwrap();
473        unsafe {
474            self.device
475                .raw
476                .cmd_reset_query_pool(self.active, *query_pool, 0, 1);
477            ray_tracing_functions
478                .acceleration_structure
479                .cmd_write_acceleration_structures_properties(
480                    self.active,
481                    &[acceleration_structure.raw],
482                    vk::QueryType::ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR,
483                    *query_pool,
484                    0,
485                );
486            self.device.raw.cmd_copy_query_pool_results(
487                self.active,
488                *query_pool,
489                0,
490                1,
491                buffer.raw,
492                0,
493                wgt::QUERY_SIZE as vk::DeviceSize,
494                vk::QueryResultFlags::TYPE_64 | vk::QueryResultFlags::WAIT,
495            )
496        };
497    }
498    unsafe fn reset_queries(&mut self, set: &super::QuerySet, range: Range<u32>) {
499        unsafe {
500            self.device.raw.cmd_reset_query_pool(
501                self.active,
502                set.raw,
503                range.start,
504                range.end - range.start,
505            )
506        };
507    }
508    unsafe fn copy_query_results(
509        &mut self,
510        set: &super::QuerySet,
511        range: Range<u32>,
512        buffer: &super::Buffer,
513        offset: wgt::BufferAddress,
514        stride: wgt::BufferSize,
515    ) {
516        unsafe {
517            self.device.raw.cmd_copy_query_pool_results(
518                self.active,
519                set.raw,
520                range.start,
521                range.end - range.start,
522                buffer.raw,
523                offset,
524                stride.get(),
525                vk::QueryResultFlags::TYPE_64 | vk::QueryResultFlags::WAIT,
526            )
527        };
528    }
529
530    unsafe fn build_acceleration_structures<'a, T>(&mut self, descriptor_count: u32, descriptors: T)
531    where
532        super::Api: 'a,
533        T: IntoIterator<
534            Item = crate::BuildAccelerationStructureDescriptor<
535                'a,
536                super::Buffer,
537                super::AccelerationStructure,
538            >,
539        >,
540    {
541        const CAPACITY_OUTER: usize = 8;
542        const CAPACITY_INNER: usize = 1;
543        let descriptor_count = descriptor_count as usize;
544
545        let ray_tracing_functions = self
546            .device
547            .extension_fns
548            .ray_tracing
549            .as_ref()
550            .expect("Feature `RAY_TRACING` not enabled");
551
552        let get_device_address = |buffer: Option<&super::Buffer>| unsafe {
553            match buffer {
554                Some(buffer) => ray_tracing_functions
555                    .buffer_device_address
556                    .get_buffer_device_address(
557                        &vk::BufferDeviceAddressInfo::default().buffer(buffer.raw),
558                    ),
559                None => panic!("Buffers are required to build acceleration structures"),
560            }
561        };
562
563        // storage to all the data required for cmd_build_acceleration_structures
564        let mut ranges_storage = smallvec::SmallVec::<
565            [smallvec::SmallVec<[vk::AccelerationStructureBuildRangeInfoKHR; CAPACITY_INNER]>;
566                CAPACITY_OUTER],
567        >::with_capacity(descriptor_count);
568        let mut geometries_storage = smallvec::SmallVec::<
569            [smallvec::SmallVec<[vk::AccelerationStructureGeometryKHR; CAPACITY_INNER]>;
570                CAPACITY_OUTER],
571        >::with_capacity(descriptor_count);
572
573        // pointers to all the data required for cmd_build_acceleration_structures
574        let mut geometry_infos = smallvec::SmallVec::<
575            [vk::AccelerationStructureBuildGeometryInfoKHR; CAPACITY_OUTER],
576        >::with_capacity(descriptor_count);
577        let mut ranges_ptrs = smallvec::SmallVec::<
578            [&[vk::AccelerationStructureBuildRangeInfoKHR]; CAPACITY_OUTER],
579        >::with_capacity(descriptor_count);
580
581        for desc in descriptors {
582            let (geometries, ranges) = match *desc.entries {
583                crate::AccelerationStructureEntries::Instances(ref instances) => {
584                    let instance_data = vk::AccelerationStructureGeometryInstancesDataKHR::default(
585                    // TODO: Code is so large that rustfmt refuses to treat this... :(
586                    )
587                    .data(vk::DeviceOrHostAddressConstKHR {
588                        device_address: get_device_address(instances.buffer),
589                    });
590
591                    let geometry = vk::AccelerationStructureGeometryKHR::default()
592                        .geometry_type(vk::GeometryTypeKHR::INSTANCES)
593                        .geometry(vk::AccelerationStructureGeometryDataKHR {
594                            instances: instance_data,
595                        });
596
597                    let range = vk::AccelerationStructureBuildRangeInfoKHR::default()
598                        .primitive_count(instances.count)
599                        .primitive_offset(instances.offset);
600
601                    (smallvec::smallvec![geometry], smallvec::smallvec![range])
602                }
603                crate::AccelerationStructureEntries::Triangles(ref in_geometries) => {
604                    let mut ranges = smallvec::SmallVec::<
605                        [vk::AccelerationStructureBuildRangeInfoKHR; CAPACITY_INNER],
606                    >::with_capacity(in_geometries.len());
607                    let mut geometries = smallvec::SmallVec::<
608                        [vk::AccelerationStructureGeometryKHR; CAPACITY_INNER],
609                    >::with_capacity(in_geometries.len());
610                    for triangles in in_geometries {
611                        let mut triangle_data =
612                            vk::AccelerationStructureGeometryTrianglesDataKHR::default()
613                                // IndexType::NONE_KHR is not set by default (due to being provided by VK_KHR_acceleration_structure) but unless there is an
614                                // index buffer we need to have IndexType::NONE_KHR as our index type.
615                                .index_type(vk::IndexType::NONE_KHR)
616                                .vertex_data(vk::DeviceOrHostAddressConstKHR {
617                                    device_address: get_device_address(triangles.vertex_buffer)
618                                        + (triangles.first_vertex as u64 * triangles.vertex_stride),
619                                })
620                                .vertex_format(conv::map_vertex_format(triangles.vertex_format))
621                                .max_vertex(triangles.vertex_count)
622                                .vertex_stride(triangles.vertex_stride);
623
624                        let mut range = vk::AccelerationStructureBuildRangeInfoKHR::default();
625
626                        if let Some(ref indices) = triangles.indices {
627                            triangle_data = triangle_data
628                                .index_data(vk::DeviceOrHostAddressConstKHR {
629                                    device_address: get_device_address(indices.buffer),
630                                })
631                                .index_type(conv::map_index_format(indices.format));
632
633                            range = range
634                                .primitive_count(indices.count / 3)
635                                .primitive_offset(indices.offset);
636                        } else {
637                            range = range.primitive_count(triangles.vertex_count / 3);
638                        }
639
640                        if let Some(ref transform) = triangles.transform {
641                            let transform_device_address = unsafe {
642                                ray_tracing_functions
643                                    .buffer_device_address
644                                    .get_buffer_device_address(
645                                        &vk::BufferDeviceAddressInfo::default()
646                                            .buffer(transform.buffer.raw),
647                                    )
648                            };
649                            triangle_data =
650                                triangle_data.transform_data(vk::DeviceOrHostAddressConstKHR {
651                                    device_address: transform_device_address,
652                                });
653
654                            range = range.transform_offset(transform.offset);
655                        }
656
657                        let geometry = vk::AccelerationStructureGeometryKHR::default()
658                            .geometry_type(vk::GeometryTypeKHR::TRIANGLES)
659                            .geometry(vk::AccelerationStructureGeometryDataKHR {
660                                triangles: triangle_data,
661                            })
662                            .flags(conv::map_acceleration_structure_geometry_flags(
663                                triangles.flags,
664                            ));
665
666                        geometries.push(geometry);
667                        ranges.push(range);
668                    }
669                    (geometries, ranges)
670                }
671                crate::AccelerationStructureEntries::AABBs(ref in_geometries) => {
672                    let mut ranges = smallvec::SmallVec::<
673                        [vk::AccelerationStructureBuildRangeInfoKHR; CAPACITY_INNER],
674                    >::with_capacity(in_geometries.len());
675                    let mut geometries = smallvec::SmallVec::<
676                        [vk::AccelerationStructureGeometryKHR; CAPACITY_INNER],
677                    >::with_capacity(in_geometries.len());
678                    for aabb in in_geometries {
679                        let aabbs_data = vk::AccelerationStructureGeometryAabbsDataKHR::default()
680                            .data(vk::DeviceOrHostAddressConstKHR {
681                                device_address: get_device_address(aabb.buffer),
682                            })
683                            .stride(aabb.stride);
684
685                        let range = vk::AccelerationStructureBuildRangeInfoKHR::default()
686                            .primitive_count(aabb.count)
687                            .primitive_offset(aabb.offset);
688
689                        let geometry = vk::AccelerationStructureGeometryKHR::default()
690                            .geometry_type(vk::GeometryTypeKHR::AABBS)
691                            .geometry(vk::AccelerationStructureGeometryDataKHR {
692                                aabbs: aabbs_data,
693                            })
694                            .flags(conv::map_acceleration_structure_geometry_flags(aabb.flags));
695
696                        geometries.push(geometry);
697                        ranges.push(range);
698                    }
699                    (geometries, ranges)
700                }
701            };
702
703            ranges_storage.push(ranges);
704            geometries_storage.push(geometries);
705
706            let scratch_device_address = unsafe {
707                ray_tracing_functions
708                    .buffer_device_address
709                    .get_buffer_device_address(
710                        &vk::BufferDeviceAddressInfo::default().buffer(desc.scratch_buffer.raw),
711                    )
712            };
713            let ty = match *desc.entries {
714                crate::AccelerationStructureEntries::Instances(_) => {
715                    vk::AccelerationStructureTypeKHR::TOP_LEVEL
716                }
717                _ => vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL,
718            };
719            let mut geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::default()
720                .ty(ty)
721                .mode(conv::map_acceleration_structure_build_mode(desc.mode))
722                .flags(conv::map_acceleration_structure_flags(desc.flags))
723                .dst_acceleration_structure(desc.destination_acceleration_structure.raw)
724                .scratch_data(vk::DeviceOrHostAddressKHR {
725                    device_address: scratch_device_address + desc.scratch_buffer_offset,
726                });
727
728            if desc.mode == crate::AccelerationStructureBuildMode::Update {
729                geometry_info.src_acceleration_structure = desc
730                    .source_acceleration_structure
731                    .unwrap_or(desc.destination_acceleration_structure)
732                    .raw;
733            }
734
735            geometry_infos.push(geometry_info);
736        }
737
738        for (i, geometry_info) in geometry_infos.iter_mut().enumerate() {
739            geometry_info.geometry_count = geometries_storage[i].len() as u32;
740            geometry_info.p_geometries = geometries_storage[i].as_ptr();
741            ranges_ptrs.push(&ranges_storage[i]);
742        }
743
744        unsafe {
745            ray_tracing_functions
746                .acceleration_structure
747                .cmd_build_acceleration_structures(self.active, &geometry_infos, &ranges_ptrs);
748        }
749    }
750
751    unsafe fn place_acceleration_structure_barrier(
752        &mut self,
753        barrier: crate::AccelerationStructureBarrier,
754    ) {
755        let (src_stage, src_access) = conv::map_acceleration_structure_usage_to_barrier(
756            barrier.usage.from,
757            self.device.features,
758            self.device.queue_flags,
759        );
760        let (dst_stage, dst_access) = conv::map_acceleration_structure_usage_to_barrier(
761            barrier.usage.to,
762            self.device.features,
763            self.device.queue_flags,
764        );
765
766        unsafe {
767            self.device.raw.cmd_pipeline_barrier(
768                self.active,
769                src_stage | vk::PipelineStageFlags::TOP_OF_PIPE,
770                dst_stage | vk::PipelineStageFlags::BOTTOM_OF_PIPE,
771                vk::DependencyFlags::empty(),
772                &[vk::MemoryBarrier::default()
773                    .src_access_mask(src_access)
774                    .dst_access_mask(dst_access)],
775                &[],
776                &[],
777            )
778        };
779    }
780
781    unsafe fn set_acceleration_structure_dependencies(
782        _command_buffers: &[&super::CommandBuffer],
783        _dependencies: &[&super::AccelerationStructure],
784    ) {
785    }
786    // render
787
788    unsafe fn begin_render_pass(
789        &mut self,
790        desc: &crate::RenderPassDescriptor<super::QuerySet, super::TextureView>,
791    ) -> Result<(), crate::DeviceError> {
792        let mut vk_clear_values =
793            ArrayVec::<vk::ClearValue, { super::MAX_TOTAL_ATTACHMENTS }>::new();
794        let mut rp_key = super::RenderPassKey {
795            colors: ArrayVec::default(),
796            depth_stencil: None,
797            sample_count: desc.sample_count,
798            multiview_mask: desc.multiview_mask,
799        };
800        let mut fb_key = super::FramebufferKey {
801            raw_pass: vk::RenderPass::null(),
802            attachment_views: ArrayVec::default(),
803            attachment_identities: ArrayVec::default(),
804            extent: desc.extent,
805        };
806
807        for cat in desc.color_attachments {
808            if let Some(cat) = cat.as_ref() {
809                let color_view = if cat.target.view.dimension == wgt::TextureViewDimension::D3 {
810                    let key = super::TempTextureViewKey {
811                        texture: cat.target.view.raw_texture,
812                        texture_identity: cat.target.view.texture_identity,
813                        format: cat.target.view.raw_format,
814                        mip_level: cat.target.view.base_mip_level,
815                        depth_slice: cat.depth_slice.unwrap(),
816                    };
817                    self.make_temp_texture_view(key)?
818                } else {
819                    cat.target.view.identified_raw_view()
820                };
821
822                vk_clear_values.push(vk::ClearValue {
823                    color: unsafe { cat.make_vk_clear_color() },
824                });
825                let color = super::ColorAttachmentKey {
826                    base: cat.target.make_attachment_key(cat.ops),
827                    resolve: cat.resolve_target.as_ref().map(|target| {
828                        target.make_attachment_key(
829                            crate::AttachmentOps::LOAD_CLEAR | crate::AttachmentOps::STORE,
830                        )
831                    }),
832                };
833
834                rp_key.colors.push(Some(color));
835                fb_key.push_view(color_view);
836                if let Some(ref at) = cat.resolve_target {
837                    vk_clear_values.push(unsafe { mem::zeroed() });
838                    fb_key.push_view(at.view.identified_raw_view());
839                }
840            } else {
841                rp_key.colors.push(None);
842            }
843        }
844        if let Some(ref ds) = desc.depth_stencil_attachment {
845            vk_clear_values.push(vk::ClearValue {
846                depth_stencil: vk::ClearDepthStencilValue {
847                    depth: ds.clear_value.0,
848                    stencil: ds.clear_value.1,
849                },
850            });
851            rp_key.depth_stencil = Some(super::DepthStencilAttachmentKey {
852                base: ds.target.make_attachment_key(ds.depth_ops),
853                stencil_ops: ds.stencil_ops,
854            });
855            fb_key.push_view(ds.target.view.identified_raw_view());
856        }
857
858        let render_area = vk::Rect2D {
859            offset: vk::Offset2D { x: 0, y: 0 },
860            extent: vk::Extent2D {
861                width: desc.extent.width,
862                height: desc.extent.height,
863            },
864        };
865        let vk_viewports = [vk::Viewport {
866            x: 0.0,
867            y: desc.extent.height as f32,
868            width: desc.extent.width as f32,
869            height: -(desc.extent.height as f32),
870            min_depth: 0.0,
871            max_depth: 1.0,
872        }];
873
874        let raw_pass = self.device.make_render_pass(rp_key).unwrap();
875        fb_key.raw_pass = raw_pass;
876        let raw_framebuffer = self.make_framebuffer(fb_key).unwrap();
877
878        let vk_info = vk::RenderPassBeginInfo::default()
879            .render_pass(raw_pass)
880            .render_area(render_area)
881            .clear_values(&vk_clear_values)
882            .framebuffer(raw_framebuffer);
883
884        if let Some(label) = desc.label {
885            unsafe { self.begin_debug_marker(label) };
886            self.rpass_debug_marker_active = true;
887        }
888
889        // Start timestamp if any (before all other commands but after debug marker)
890        if let Some(timestamp_writes) = desc.timestamp_writes.as_ref() {
891            if let Some(index) = timestamp_writes.beginning_of_pass_write_index {
892                unsafe {
893                    self.write_timestamp(timestamp_writes.query_set, index);
894                }
895            }
896            self.end_of_pass_timer_query = timestamp_writes
897                .end_of_pass_write_index
898                .map(|index| (timestamp_writes.query_set.raw, index));
899        }
900
901        unsafe {
902            self.device
903                .raw
904                .cmd_set_viewport(self.active, 0, &vk_viewports);
905            self.device
906                .raw
907                .cmd_set_scissor(self.active, 0, &[render_area]);
908            self.device.raw.cmd_begin_render_pass(
909                self.active,
910                &vk_info,
911                vk::SubpassContents::INLINE,
912            );
913        };
914
915        self.bind_point = vk::PipelineBindPoint::GRAPHICS;
916
917        Ok(())
918    }
919    unsafe fn end_render_pass(&mut self) {
920        unsafe {
921            self.device.raw.cmd_end_render_pass(self.active);
922        }
923
924        // After all other commands but before debug marker, so this is still seen as part of this pass.
925        self.write_pass_end_timestamp_if_requested();
926
927        if self.rpass_debug_marker_active {
928            unsafe {
929                self.end_debug_marker();
930            }
931            self.rpass_debug_marker_active = false;
932        }
933    }
934
935    unsafe fn set_bind_group(
936        &mut self,
937        layout: &super::PipelineLayout,
938        index: u32,
939        group: &super::BindGroup,
940        dynamic_offsets: &[wgt::DynamicOffset],
941    ) {
942        let sets = [group.set.raw()];
943        unsafe {
944            self.device.raw.cmd_bind_descriptor_sets(
945                self.active,
946                self.bind_point,
947                layout.raw,
948                index,
949                &sets,
950                dynamic_offsets,
951            )
952        };
953    }
954    unsafe fn set_immediates(
955        &mut self,
956        layout: &super::PipelineLayout,
957        offset_bytes: u32,
958        data: &[u32],
959    ) {
960        unsafe {
961            self.device.raw.cmd_push_constants(
962                self.active,
963                layout.raw,
964                vk::ShaderStageFlags::ALL,
965                offset_bytes,
966                bytemuck::cast_slice(data),
967            )
968        };
969    }
970
971    unsafe fn insert_debug_marker(&mut self, label: &str) {
972        if let Some(ext) = self.device.extension_fns.debug_utils.as_ref() {
973            let cstr = self.temp.make_c_str(label);
974            let vk_label = vk::DebugUtilsLabelEXT::default().label_name(cstr);
975            unsafe { ext.cmd_insert_debug_utils_label(self.active, &vk_label) };
976        }
977    }
978    unsafe fn begin_debug_marker(&mut self, group_label: &str) {
979        if let Some(ext) = self.device.extension_fns.debug_utils.as_ref() {
980            let cstr = self.temp.make_c_str(group_label);
981            let vk_label = vk::DebugUtilsLabelEXT::default().label_name(cstr);
982            unsafe { ext.cmd_begin_debug_utils_label(self.active, &vk_label) };
983        }
984    }
985    unsafe fn end_debug_marker(&mut self) {
986        if let Some(ext) = self.device.extension_fns.debug_utils.as_ref() {
987            unsafe { ext.cmd_end_debug_utils_label(self.active) };
988        }
989    }
990
991    unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) {
992        unsafe {
993            self.current_pipeline_is_multiview = pipeline.is_multiview;
994            self.device.raw.cmd_bind_pipeline(
995                self.active,
996                vk::PipelineBindPoint::GRAPHICS,
997                pipeline.raw,
998            )
999        };
1000    }
1001
1002    unsafe fn set_index_buffer<'a>(
1003        &mut self,
1004        binding: crate::BufferBinding<'a, super::Buffer>,
1005        format: wgt::IndexFormat,
1006    ) {
1007        unsafe {
1008            self.device.raw.cmd_bind_index_buffer(
1009                self.active,
1010                binding.buffer.raw,
1011                binding.offset,
1012                conv::map_index_format(format),
1013            )
1014        };
1015    }
1016    unsafe fn set_vertex_buffer<'a>(
1017        &mut self,
1018        index: u32,
1019        binding: crate::BufferBinding<'a, super::Buffer>,
1020    ) {
1021        let vk_buffers = [binding.buffer.raw];
1022        let vk_offsets = [binding.offset];
1023        unsafe {
1024            self.device
1025                .raw
1026                .cmd_bind_vertex_buffers(self.active, index, &vk_buffers, &vk_offsets)
1027        };
1028    }
1029    unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: Range<f32>) {
1030        let vk_viewports = [vk::Viewport {
1031            x: rect.x,
1032            y: rect.y + rect.h,
1033            width: rect.w,
1034            height: -rect.h, // flip Y
1035            min_depth: depth_range.start,
1036            max_depth: depth_range.end,
1037        }];
1038        unsafe {
1039            self.device
1040                .raw
1041                .cmd_set_viewport(self.active, 0, &vk_viewports)
1042        };
1043    }
1044    unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect<u32>) {
1045        let vk_scissors = [vk::Rect2D {
1046            offset: vk::Offset2D {
1047                x: rect.x as i32,
1048                y: rect.y as i32,
1049            },
1050            extent: vk::Extent2D {
1051                width: rect.w,
1052                height: rect.h,
1053            },
1054        }];
1055        unsafe {
1056            self.device
1057                .raw
1058                .cmd_set_scissor(self.active, 0, &vk_scissors)
1059        };
1060    }
1061    unsafe fn set_stencil_reference(&mut self, value: u32) {
1062        unsafe {
1063            self.device.raw.cmd_set_stencil_reference(
1064                self.active,
1065                vk::StencilFaceFlags::FRONT_AND_BACK,
1066                value,
1067            )
1068        };
1069    }
1070    unsafe fn set_blend_constants(&mut self, color: &[f32; 4]) {
1071        unsafe { self.device.raw.cmd_set_blend_constants(self.active, color) };
1072    }
1073
1074    unsafe fn draw(
1075        &mut self,
1076        first_vertex: u32,
1077        vertex_count: u32,
1078        first_instance: u32,
1079        instance_count: u32,
1080    ) {
1081        if self.current_pipeline_is_multiview
1082            && (first_instance as u64 + instance_count as u64 - 1)
1083                > self.device.private_caps.multiview_instance_index_limit as u64
1084        {
1085            panic!("This vulkan device is affected by [#8333](https://github.com/gfx-rs/wgpu/issues/8333)");
1086        }
1087        unsafe {
1088            self.device.raw.cmd_draw(
1089                self.active,
1090                vertex_count,
1091                instance_count,
1092                first_vertex,
1093                first_instance,
1094            )
1095        };
1096    }
1097    unsafe fn draw_indexed(
1098        &mut self,
1099        first_index: u32,
1100        index_count: u32,
1101        base_vertex: i32,
1102        first_instance: u32,
1103        instance_count: u32,
1104    ) {
1105        if self.current_pipeline_is_multiview
1106            && (first_instance as u64 + instance_count as u64 - 1)
1107                > self.device.private_caps.multiview_instance_index_limit as u64
1108        {
1109            panic!("This vulkan device is affected by [#8333](https://github.com/gfx-rs/wgpu/issues/8333)");
1110        }
1111        unsafe {
1112            self.device.raw.cmd_draw_indexed(
1113                self.active,
1114                index_count,
1115                instance_count,
1116                first_index,
1117                base_vertex,
1118                first_instance,
1119            )
1120        };
1121    }
1122    unsafe fn draw_mesh_tasks(
1123        &mut self,
1124        group_count_x: u32,
1125        group_count_y: u32,
1126        group_count_z: u32,
1127    ) {
1128        if let Some(ref t) = self.device.extension_fns.mesh_shading {
1129            unsafe {
1130                t.cmd_draw_mesh_tasks(self.active, group_count_x, group_count_y, group_count_z);
1131            };
1132        } else {
1133            panic!("Feature `MESH_SHADING` not enabled");
1134        }
1135    }
1136    unsafe fn draw_indirect(
1137        &mut self,
1138        buffer: &super::Buffer,
1139        offset: wgt::BufferAddress,
1140        draw_count: u32,
1141    ) {
1142        if draw_count >= 1
1143            && self.device.private_caps.multi_draw_indirect
1144            && draw_count <= self.device.private_caps.max_draw_indirect_count
1145        {
1146            unsafe {
1147                self.device.raw.cmd_draw_indirect(
1148                    self.active,
1149                    buffer.raw,
1150                    offset,
1151                    draw_count,
1152                    size_of::<wgt::DrawIndirectArgs>() as u32,
1153                )
1154            };
1155        } else {
1156            for i in 0..draw_count {
1157                let indirect_offset = offset
1158                    + i as wgt::BufferAddress
1159                        * size_of::<wgt::DrawIndirectArgs>() as wgt::BufferAddress;
1160                unsafe {
1161                    self.device.raw.cmd_draw_indirect(
1162                        self.active,
1163                        buffer.raw,
1164                        indirect_offset,
1165                        1,
1166                        size_of::<wgt::DrawIndirectArgs>() as u32,
1167                    )
1168                };
1169            }
1170        }
1171    }
1172    unsafe fn draw_indexed_indirect(
1173        &mut self,
1174        buffer: &super::Buffer,
1175        offset: wgt::BufferAddress,
1176        draw_count: u32,
1177    ) {
1178        if draw_count >= 1
1179            && self.device.private_caps.multi_draw_indirect
1180            && draw_count <= self.device.private_caps.max_draw_indirect_count
1181        {
1182            unsafe {
1183                self.device.raw.cmd_draw_indexed_indirect(
1184                    self.active,
1185                    buffer.raw,
1186                    offset,
1187                    draw_count,
1188                    size_of::<wgt::DrawIndexedIndirectArgs>() as u32,
1189                )
1190            };
1191        } else {
1192            for i in 0..draw_count {
1193                let indirect_offset = offset
1194                    + i as wgt::BufferAddress
1195                        * size_of::<wgt::DrawIndexedIndirectArgs>() as wgt::BufferAddress;
1196                unsafe {
1197                    self.device.raw.cmd_draw_indexed_indirect(
1198                        self.active,
1199                        buffer.raw,
1200                        indirect_offset,
1201                        1,
1202                        size_of::<wgt::DrawIndexedIndirectArgs>() as u32,
1203                    )
1204                };
1205            }
1206        }
1207    }
1208    unsafe fn draw_mesh_tasks_indirect(
1209        &mut self,
1210        buffer: &<Self::A as crate::Api>::Buffer,
1211        offset: wgt::BufferAddress,
1212        draw_count: u32,
1213    ) {
1214        if let Some(ref t) = self.device.extension_fns.mesh_shading {
1215            unsafe {
1216                t.cmd_draw_mesh_tasks_indirect(
1217                    self.active,
1218                    buffer.raw,
1219                    offset,
1220                    draw_count,
1221                    size_of::<wgt::DispatchIndirectArgs>() as u32,
1222                );
1223            };
1224        } else {
1225            panic!("Feature `MESH_SHADING` not enabled");
1226        }
1227    }
1228    unsafe fn draw_indirect_count(
1229        &mut self,
1230        buffer: &super::Buffer,
1231        offset: wgt::BufferAddress,
1232        count_buffer: &super::Buffer,
1233        count_offset: wgt::BufferAddress,
1234        max_count: u32,
1235    ) {
1236        let stride = size_of::<wgt::DrawIndirectArgs>() as u32;
1237        match self.device.extension_fns.draw_indirect_count {
1238            Some(ref t) => {
1239                unsafe {
1240                    t.cmd_draw_indirect_count(
1241                        self.active,
1242                        buffer.raw,
1243                        offset,
1244                        count_buffer.raw,
1245                        count_offset,
1246                        max_count,
1247                        stride,
1248                    )
1249                };
1250            }
1251            None => panic!("Feature `DRAW_INDIRECT_COUNT` not enabled"),
1252        }
1253    }
1254    unsafe fn draw_indexed_indirect_count(
1255        &mut self,
1256        buffer: &super::Buffer,
1257        offset: wgt::BufferAddress,
1258        count_buffer: &super::Buffer,
1259        count_offset: wgt::BufferAddress,
1260        max_count: u32,
1261    ) {
1262        let stride = size_of::<wgt::DrawIndexedIndirectArgs>() as u32;
1263        match self.device.extension_fns.draw_indirect_count {
1264            Some(ref t) => {
1265                unsafe {
1266                    t.cmd_draw_indexed_indirect_count(
1267                        self.active,
1268                        buffer.raw,
1269                        offset,
1270                        count_buffer.raw,
1271                        count_offset,
1272                        max_count,
1273                        stride,
1274                    )
1275                };
1276            }
1277            None => panic!("Feature `DRAW_INDIRECT_COUNT` not enabled"),
1278        }
1279    }
1280    unsafe fn draw_mesh_tasks_indirect_count(
1281        &mut self,
1282        buffer: &<Self::A as crate::Api>::Buffer,
1283        offset: wgt::BufferAddress,
1284        count_buffer: &super::Buffer,
1285        count_offset: wgt::BufferAddress,
1286        max_count: u32,
1287    ) {
1288        if self.device.extension_fns.draw_indirect_count.is_none() {
1289            panic!("Feature `DRAW_INDIRECT_COUNT` not enabled");
1290        }
1291        if let Some(ref t) = self.device.extension_fns.mesh_shading {
1292            unsafe {
1293                t.cmd_draw_mesh_tasks_indirect_count(
1294                    self.active,
1295                    buffer.raw,
1296                    offset,
1297                    count_buffer.raw,
1298                    count_offset,
1299                    max_count,
1300                    size_of::<wgt::DispatchIndirectArgs>() as u32,
1301                );
1302            };
1303        } else {
1304            panic!("Feature `MESH_SHADING` not enabled");
1305        }
1306    }
1307
1308    // compute
1309
1310    unsafe fn begin_compute_pass(
1311        &mut self,
1312        desc: &crate::ComputePassDescriptor<'_, super::QuerySet>,
1313    ) {
1314        self.bind_point = vk::PipelineBindPoint::COMPUTE;
1315        if let Some(label) = desc.label {
1316            unsafe { self.begin_debug_marker(label) };
1317            self.rpass_debug_marker_active = true;
1318        }
1319
1320        if let Some(timestamp_writes) = desc.timestamp_writes.as_ref() {
1321            if let Some(index) = timestamp_writes.beginning_of_pass_write_index {
1322                unsafe {
1323                    self.write_timestamp(timestamp_writes.query_set, index);
1324                }
1325            }
1326            self.end_of_pass_timer_query = timestamp_writes
1327                .end_of_pass_write_index
1328                .map(|index| (timestamp_writes.query_set.raw, index));
1329        }
1330    }
1331    unsafe fn end_compute_pass(&mut self) {
1332        self.write_pass_end_timestamp_if_requested();
1333
1334        if self.rpass_debug_marker_active {
1335            unsafe { self.end_debug_marker() };
1336            self.rpass_debug_marker_active = false
1337        }
1338    }
1339
1340    unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {
1341        unsafe {
1342            self.device.raw.cmd_bind_pipeline(
1343                self.active,
1344                vk::PipelineBindPoint::COMPUTE,
1345                pipeline.raw,
1346            )
1347        };
1348    }
1349
1350    unsafe fn dispatch_workgroups(&mut self, count: [u32; 3]) {
1351        unsafe {
1352            self.device
1353                .raw
1354                .cmd_dispatch(self.active, count[0], count[1], count[2])
1355        };
1356    }
1357    unsafe fn dispatch_workgroups_indirect(
1358        &mut self,
1359        buffer: &super::Buffer,
1360        offset: wgt::BufferAddress,
1361    ) {
1362        unsafe {
1363            self.device
1364                .raw
1365                .cmd_dispatch_indirect(self.active, buffer.raw, offset)
1366        }
1367    }
1368
1369    // ray tracing
1370
1371    unsafe fn begin_ray_tracing_pass(&mut self, desc: &crate::RayTracingPassDescriptor<'_>) {
1372        self.bind_point = vk::PipelineBindPoint::RAY_TRACING_KHR;
1373        if let Some(label) = desc.label {
1374            unsafe { self.begin_debug_marker(label) };
1375            self.rpass_debug_marker_active = true;
1376        }
1377    }
1378    unsafe fn end_ray_tracing_pass(&mut self) {
1379        if self.rpass_debug_marker_active {
1380            unsafe { self.end_debug_marker() };
1381            self.rpass_debug_marker_active = false
1382        }
1383    }
1384
1385    unsafe fn trace_rays(
1386        &mut self,
1387        count: [u32; 3],
1388        ray_generation_group_data: crate::PipelineGroupData<super::Buffer>,
1389        miss_group_data: crate::PipelineGroupData<super::Buffer>,
1390        intersection_group_data: crate::PipelineGroupData<super::Buffer>,
1391    ) {
1392        let ray_tracing_functions = self
1393            .device
1394            .extension_fns
1395            .ray_tracing
1396            .as_ref()
1397            .expect("Feature `EXPERIMENTAL_RAY_TRACING` not enabled");
1398
1399        let ray_tracing_pipeline_functions = self
1400            .device
1401            .extension_fns
1402            .ray_tracing_pipelines
1403            .as_ref()
1404            .expect("Feature `EXPERIMENTAL_RAY_TRACING_PIPELINES` not enabled");
1405
1406        let get_device_address = |buffer: &super::Buffer| unsafe {
1407            ray_tracing_functions
1408                .buffer_device_address
1409                .get_buffer_device_address(
1410                    &vk::BufferDeviceAddressInfo::default().buffer(buffer.raw),
1411                )
1412        };
1413
1414        unsafe {
1415            ray_tracing_pipeline_functions.cmd_trace_rays(
1416                self.raw_handle(),
1417                &vk::StridedDeviceAddressRegionKHR {
1418                    device_address: get_device_address(ray_generation_group_data.buffer)
1419                        + ray_generation_group_data.offset,
1420                    stride: ray_generation_group_data.stride,
1421                    size: ray_generation_group_data.stride /* no need for multiplying by count, vulkan requires the ray gen sbt to be just one group */,
1422                },
1423                &vk::StridedDeviceAddressRegionKHR {
1424                    device_address: get_device_address(miss_group_data.buffer)
1425                        + miss_group_data.offset,
1426                    stride: miss_group_data.stride,
1427                    size: miss_group_data.stride * miss_group_data.count,
1428                },
1429                &vk::StridedDeviceAddressRegionKHR {
1430                    device_address: get_device_address(intersection_group_data.buffer)
1431                        + intersection_group_data.offset,
1432                    stride: intersection_group_data.stride,
1433                    size: intersection_group_data.stride * intersection_group_data.count,
1434                },
1435                &vk::StridedDeviceAddressRegionKHR {
1436                    device_address: 0,
1437                    stride: 0,
1438                    size: 0,
1439                },
1440                count[0],
1441                count[1],
1442                count[2],
1443            )
1444        };
1445    }
1446
1447    unsafe fn set_ray_tracing_pipeline(&mut self, pipeline: &super::RayTracingPipeline) {
1448        unsafe {
1449            self.device.raw.cmd_bind_pipeline(
1450                self.active,
1451                vk::PipelineBindPoint::RAY_TRACING_KHR,
1452                pipeline.raw,
1453            )
1454        };
1455    }
1456
1457    unsafe fn copy_acceleration_structure_to_acceleration_structure(
1458        &mut self,
1459        src: &super::AccelerationStructure,
1460        dst: &super::AccelerationStructure,
1461        copy: wgt::AccelerationStructureCopy,
1462    ) {
1463        let ray_tracing_functions = self
1464            .device
1465            .extension_fns
1466            .ray_tracing
1467            .as_ref()
1468            .expect("Feature `RAY_TRACING` not enabled");
1469
1470        let mode = match copy {
1471            wgt::AccelerationStructureCopy::Clone => vk::CopyAccelerationStructureModeKHR::CLONE,
1472            wgt::AccelerationStructureCopy::Compact => {
1473                vk::CopyAccelerationStructureModeKHR::COMPACT
1474            }
1475        };
1476
1477        unsafe {
1478            ray_tracing_functions
1479                .acceleration_structure
1480                .cmd_copy_acceleration_structure(
1481                    self.active,
1482                    &vk::CopyAccelerationStructureInfoKHR {
1483                        s_type: vk::StructureType::COPY_ACCELERATION_STRUCTURE_INFO_KHR,
1484                        p_next: core::ptr::null(),
1485                        src: src.raw,
1486                        dst: dst.raw,
1487                        mode,
1488                        _marker: Default::default(),
1489                    },
1490                );
1491        }
1492    }
1493}
1494
1495#[test]
1496fn check_dst_image_layout() {
1497    assert_eq!(
1498        conv::derive_image_layout(wgt::TextureUses::COPY_DST, wgt::TextureFormat::Rgba8Unorm),
1499        DST_IMAGE_LAYOUT
1500    );
1501}