Skip to main content

wgpu_hal/vulkan/
command.rs

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