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