Skip to main content

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