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