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