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