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 = if self
906            .device
907            .workarounds
908            .contains(super::Workarounds::IGNORED_NEGATIVE_VIEWPORT_HEIGHT)
909        {
910            // The Y-flip happens in the vertex shader epilogue instead; see the
911            // workaround's documentation.
912            [vk::Viewport {
913                x: 0.0,
914                y: 0.0,
915                width: desc.extent.width as f32,
916                height: desc.extent.height as f32,
917                min_depth: 0.0,
918                max_depth: 1.0,
919            }]
920        } else {
921            [vk::Viewport {
922                x: 0.0,
923                y: desc.extent.height as f32,
924                width: desc.extent.width as f32,
925                height: -(desc.extent.height as f32),
926                min_depth: 0.0,
927                max_depth: 1.0,
928            }]
929        };
930
931        let raw_pass = self.device.make_render_pass(rp_key).unwrap();
932        fb_key.raw_pass = raw_pass;
933        let raw_framebuffer = self.make_framebuffer(fb_key).unwrap();
934
935        let vk_info = vk::RenderPassBeginInfo::default()
936            .render_pass(raw_pass)
937            .render_area(render_area)
938            .clear_values(&vk_clear_values)
939            .framebuffer(raw_framebuffer);
940
941        if let Some(label) = desc.label {
942            unsafe { self.begin_debug_marker(label) };
943            self.rpass_debug_marker_active = true;
944        }
945
946        // Start timestamp if any (before all other commands but after debug marker)
947        if let Some(timestamp_writes) = desc.timestamp_writes.as_ref() {
948            if let Some(index) = timestamp_writes.beginning_of_pass_write_index {
949                unsafe {
950                    self.write_timestamp(timestamp_writes.query_set, index);
951                }
952            }
953            self.end_of_pass_timer_query = timestamp_writes
954                .end_of_pass_write_index
955                .map(|index| (timestamp_writes.query_set.raw, index));
956        }
957
958        unsafe {
959            self.device
960                .raw
961                .cmd_set_viewport(self.active, 0, &vk_viewports);
962            self.device
963                .raw
964                .cmd_set_scissor(self.active, 0, &[render_area]);
965            self.device.raw.cmd_begin_render_pass(
966                self.active,
967                &vk_info,
968                vk::SubpassContents::INLINE,
969            );
970        };
971
972        self.bind_point = vk::PipelineBindPoint::GRAPHICS;
973
974        Ok(())
975    }
976    unsafe fn end_render_pass(&mut self) {
977        unsafe {
978            self.device.raw.cmd_end_render_pass(self.active);
979        }
980
981        // After all other commands but before debug marker, so this is still seen as part of this pass.
982        self.write_pass_end_timestamp_if_requested();
983
984        if self.rpass_debug_marker_active {
985            unsafe {
986                self.end_debug_marker();
987            }
988            self.rpass_debug_marker_active = false;
989        }
990    }
991
992    unsafe fn set_bind_group(
993        &mut self,
994        layout: &super::PipelineLayout,
995        index: u32,
996        group: &super::BindGroup,
997        dynamic_offsets: &[wgt::DynamicOffset],
998    ) {
999        let sets = [group.set.raw()];
1000        unsafe {
1001            self.device.raw.cmd_bind_descriptor_sets(
1002                self.active,
1003                self.bind_point,
1004                layout.raw,
1005                index,
1006                &sets,
1007                dynamic_offsets,
1008            )
1009        };
1010    }
1011    unsafe fn set_immediates(
1012        &mut self,
1013        layout: &super::PipelineLayout,
1014        offset_bytes: u32,
1015        data: &[u32],
1016    ) {
1017        unsafe {
1018            self.device.raw.cmd_push_constants(
1019                self.active,
1020                layout.raw,
1021                vk::ShaderStageFlags::ALL,
1022                offset_bytes,
1023                bytemuck::cast_slice(data),
1024            )
1025        };
1026    }
1027
1028    unsafe fn insert_debug_marker(&mut self, label: &str) {
1029        if let Some(ext) = self.device.extension_fns.debug_utils.as_ref() {
1030            let cstr = self.temp.make_c_str(label);
1031            let vk_label = vk::DebugUtilsLabelEXT::default().label_name(cstr);
1032            unsafe { ext.cmd_insert_debug_utils_label(self.active, &vk_label) };
1033        }
1034    }
1035    unsafe fn begin_debug_marker(&mut self, group_label: &str) {
1036        if let Some(ext) = self.device.extension_fns.debug_utils.as_ref() {
1037            let cstr = self.temp.make_c_str(group_label);
1038            let vk_label = vk::DebugUtilsLabelEXT::default().label_name(cstr);
1039            unsafe { ext.cmd_begin_debug_utils_label(self.active, &vk_label) };
1040        }
1041    }
1042    unsafe fn end_debug_marker(&mut self) {
1043        if let Some(ext) = self.device.extension_fns.debug_utils.as_ref() {
1044            unsafe { ext.cmd_end_debug_utils_label(self.active) };
1045        }
1046    }
1047
1048    unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) {
1049        unsafe {
1050            self.current_pipeline_is_multiview = pipeline.is_multiview;
1051            self.device.raw.cmd_bind_pipeline(
1052                self.active,
1053                vk::PipelineBindPoint::GRAPHICS,
1054                pipeline.raw,
1055            )
1056        };
1057    }
1058
1059    unsafe fn set_index_buffer<'a>(
1060        &mut self,
1061        binding: crate::BufferBinding<'a, super::Buffer, wgt::BufferAddress>,
1062        format: wgt::IndexFormat,
1063    ) {
1064        unsafe {
1065            self.device.raw.cmd_bind_index_buffer(
1066                self.active,
1067                binding.buffer.raw,
1068                binding.offset,
1069                conv::map_index_format(format),
1070            )
1071        };
1072    }
1073    unsafe fn set_vertex_buffer<'a>(
1074        &mut self,
1075        index: u32,
1076        binding: crate::BufferBinding<'a, super::Buffer, wgt::BufferAddress>,
1077    ) {
1078        let vk_buffers = [binding.buffer.raw];
1079        let vk_offsets = [binding.offset];
1080        unsafe {
1081            self.device
1082                .raw
1083                .cmd_bind_vertex_buffers(self.active, index, &vk_buffers, &vk_offsets)
1084        };
1085    }
1086    unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: Range<f32>) {
1087        let vk_viewports = if self
1088            .device
1089            .workarounds
1090            .contains(super::Workarounds::IGNORED_NEGATIVE_VIEWPORT_HEIGHT)
1091        {
1092            // The Y-flip happens in the vertex shader epilogue instead; see the
1093            // workaround's documentation.
1094            [vk::Viewport {
1095                x: rect.x,
1096                y: rect.y,
1097                width: rect.w,
1098                height: rect.h,
1099                min_depth: depth_range.start,
1100                max_depth: depth_range.end,
1101            }]
1102        } else {
1103            [vk::Viewport {
1104                x: rect.x,
1105                y: rect.y + rect.h,
1106                width: rect.w,
1107                height: -rect.h, // flip Y
1108                min_depth: depth_range.start,
1109                max_depth: depth_range.end,
1110            }]
1111        };
1112        unsafe {
1113            self.device
1114                .raw
1115                .cmd_set_viewport(self.active, 0, &vk_viewports)
1116        };
1117    }
1118    unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect<u32>) {
1119        let vk_scissors = [vk::Rect2D {
1120            offset: vk::Offset2D {
1121                x: rect.x as i32,
1122                y: rect.y as i32,
1123            },
1124            extent: vk::Extent2D {
1125                width: rect.w,
1126                height: rect.h,
1127            },
1128        }];
1129        unsafe {
1130            self.device
1131                .raw
1132                .cmd_set_scissor(self.active, 0, &vk_scissors)
1133        };
1134    }
1135    unsafe fn set_stencil_reference(&mut self, value: u32) {
1136        unsafe {
1137            self.device.raw.cmd_set_stencil_reference(
1138                self.active,
1139                vk::StencilFaceFlags::FRONT_AND_BACK,
1140                value,
1141            )
1142        };
1143    }
1144    unsafe fn set_blend_constants(&mut self, color: &[f32; 4]) {
1145        unsafe { self.device.raw.cmd_set_blend_constants(self.active, color) };
1146    }
1147
1148    unsafe fn draw(
1149        &mut self,
1150        first_vertex: u32,
1151        vertex_count: u32,
1152        first_instance: u32,
1153        instance_count: u32,
1154    ) {
1155        if self.current_pipeline_is_multiview
1156            && (first_instance as u64 + instance_count as u64 - 1)
1157                > self.device.private_caps.multiview_instance_index_limit as u64
1158        {
1159            panic!("This vulkan device is affected by [#8333](https://github.com/gfx-rs/wgpu/issues/8333)");
1160        }
1161        unsafe {
1162            self.device.raw.cmd_draw(
1163                self.active,
1164                vertex_count,
1165                instance_count,
1166                first_vertex,
1167                first_instance,
1168            )
1169        };
1170    }
1171    unsafe fn draw_indexed(
1172        &mut self,
1173        first_index: u32,
1174        index_count: u32,
1175        base_vertex: i32,
1176        first_instance: u32,
1177        instance_count: u32,
1178    ) {
1179        if self.current_pipeline_is_multiview
1180            && (first_instance as u64 + instance_count as u64 - 1)
1181                > self.device.private_caps.multiview_instance_index_limit as u64
1182        {
1183            panic!("This vulkan device is affected by [#8333](https://github.com/gfx-rs/wgpu/issues/8333)");
1184        }
1185        unsafe {
1186            self.device.raw.cmd_draw_indexed(
1187                self.active,
1188                index_count,
1189                instance_count,
1190                first_index,
1191                base_vertex,
1192                first_instance,
1193            )
1194        };
1195    }
1196    unsafe fn draw_mesh_tasks(
1197        &mut self,
1198        group_count_x: u32,
1199        group_count_y: u32,
1200        group_count_z: u32,
1201    ) {
1202        if let Some(ref t) = self.device.extension_fns.mesh_shading {
1203            unsafe {
1204                t.cmd_draw_mesh_tasks(self.active, group_count_x, group_count_y, group_count_z);
1205            };
1206        } else {
1207            panic!("Feature `MESH_SHADING` not enabled");
1208        }
1209    }
1210    unsafe fn draw_indirect(
1211        &mut self,
1212        buffer: &super::Buffer,
1213        offset: wgt::BufferAddress,
1214        draw_count: u32,
1215    ) {
1216        if draw_count >= 1
1217            && self.device.private_caps.multi_draw_indirect
1218            && draw_count <= self.device.private_caps.max_draw_indirect_count
1219        {
1220            unsafe {
1221                self.device.raw.cmd_draw_indirect(
1222                    self.active,
1223                    buffer.raw,
1224                    offset,
1225                    draw_count,
1226                    size_of::<wgt::DrawIndirectArgs>() as u32,
1227                )
1228            };
1229        } else {
1230            for i in 0..draw_count {
1231                let indirect_offset = offset
1232                    + i as wgt::BufferAddress
1233                        * size_of::<wgt::DrawIndirectArgs>() as wgt::BufferAddress;
1234                unsafe {
1235                    self.device.raw.cmd_draw_indirect(
1236                        self.active,
1237                        buffer.raw,
1238                        indirect_offset,
1239                        1,
1240                        size_of::<wgt::DrawIndirectArgs>() as u32,
1241                    )
1242                };
1243            }
1244        }
1245    }
1246    unsafe fn draw_indexed_indirect(
1247        &mut self,
1248        buffer: &super::Buffer,
1249        offset: wgt::BufferAddress,
1250        draw_count: u32,
1251    ) {
1252        if draw_count >= 1
1253            && self.device.private_caps.multi_draw_indirect
1254            && draw_count <= self.device.private_caps.max_draw_indirect_count
1255        {
1256            unsafe {
1257                self.device.raw.cmd_draw_indexed_indirect(
1258                    self.active,
1259                    buffer.raw,
1260                    offset,
1261                    draw_count,
1262                    size_of::<wgt::DrawIndexedIndirectArgs>() as u32,
1263                )
1264            };
1265        } else {
1266            for i in 0..draw_count {
1267                let indirect_offset = offset
1268                    + i as wgt::BufferAddress
1269                        * size_of::<wgt::DrawIndexedIndirectArgs>() as wgt::BufferAddress;
1270                unsafe {
1271                    self.device.raw.cmd_draw_indexed_indirect(
1272                        self.active,
1273                        buffer.raw,
1274                        indirect_offset,
1275                        1,
1276                        size_of::<wgt::DrawIndexedIndirectArgs>() as u32,
1277                    )
1278                };
1279            }
1280        }
1281    }
1282    unsafe fn draw_mesh_tasks_indirect(
1283        &mut self,
1284        buffer: &<Self::A as crate::Api>::Buffer,
1285        offset: wgt::BufferAddress,
1286        draw_count: u32,
1287    ) {
1288        if let Some(ref t) = self.device.extension_fns.mesh_shading {
1289            unsafe {
1290                t.cmd_draw_mesh_tasks_indirect(
1291                    self.active,
1292                    buffer.raw,
1293                    offset,
1294                    draw_count,
1295                    size_of::<wgt::DispatchIndirectArgs>() as u32,
1296                );
1297            };
1298        } else {
1299            panic!("Feature `MESH_SHADING` not enabled");
1300        }
1301    }
1302    unsafe fn draw_indirect_count(
1303        &mut self,
1304        buffer: &super::Buffer,
1305        offset: wgt::BufferAddress,
1306        count_buffer: &super::Buffer,
1307        count_offset: wgt::BufferAddress,
1308        max_count: u32,
1309    ) {
1310        let stride = size_of::<wgt::DrawIndirectArgs>() as u32;
1311        match self.device.extension_fns.draw_indirect_count {
1312            Some(ref t) => {
1313                unsafe {
1314                    t.cmd_draw_indirect_count(
1315                        self.active,
1316                        buffer.raw,
1317                        offset,
1318                        count_buffer.raw,
1319                        count_offset,
1320                        max_count,
1321                        stride,
1322                    )
1323                };
1324            }
1325            None => panic!("Feature `DRAW_INDIRECT_COUNT` not enabled"),
1326        }
1327    }
1328    unsafe fn draw_indexed_indirect_count(
1329        &mut self,
1330        buffer: &super::Buffer,
1331        offset: wgt::BufferAddress,
1332        count_buffer: &super::Buffer,
1333        count_offset: wgt::BufferAddress,
1334        max_count: u32,
1335    ) {
1336        let stride = size_of::<wgt::DrawIndexedIndirectArgs>() as u32;
1337        match self.device.extension_fns.draw_indirect_count {
1338            Some(ref t) => {
1339                unsafe {
1340                    t.cmd_draw_indexed_indirect_count(
1341                        self.active,
1342                        buffer.raw,
1343                        offset,
1344                        count_buffer.raw,
1345                        count_offset,
1346                        max_count,
1347                        stride,
1348                    )
1349                };
1350            }
1351            None => panic!("Feature `DRAW_INDIRECT_COUNT` not enabled"),
1352        }
1353    }
1354    unsafe fn draw_mesh_tasks_indirect_count(
1355        &mut self,
1356        buffer: &<Self::A as crate::Api>::Buffer,
1357        offset: wgt::BufferAddress,
1358        count_buffer: &super::Buffer,
1359        count_offset: wgt::BufferAddress,
1360        max_count: u32,
1361    ) {
1362        if self.device.extension_fns.draw_indirect_count.is_none() {
1363            panic!("Feature `DRAW_INDIRECT_COUNT` not enabled");
1364        }
1365        if let Some(ref t) = self.device.extension_fns.mesh_shading {
1366            unsafe {
1367                t.cmd_draw_mesh_tasks_indirect_count(
1368                    self.active,
1369                    buffer.raw,
1370                    offset,
1371                    count_buffer.raw,
1372                    count_offset,
1373                    max_count,
1374                    size_of::<wgt::DispatchIndirectArgs>() as u32,
1375                );
1376            };
1377        } else {
1378            panic!("Feature `MESH_SHADING` not enabled");
1379        }
1380    }
1381
1382    // compute
1383
1384    unsafe fn begin_compute_pass(
1385        &mut self,
1386        desc: &crate::ComputePassDescriptor<'_, super::QuerySet>,
1387    ) {
1388        self.bind_point = vk::PipelineBindPoint::COMPUTE;
1389        if let Some(label) = desc.label {
1390            unsafe { self.begin_debug_marker(label) };
1391            self.rpass_debug_marker_active = true;
1392        }
1393
1394        if let Some(timestamp_writes) = desc.timestamp_writes.as_ref() {
1395            if let Some(index) = timestamp_writes.beginning_of_pass_write_index {
1396                unsafe {
1397                    self.write_timestamp(timestamp_writes.query_set, index);
1398                }
1399            }
1400            self.end_of_pass_timer_query = timestamp_writes
1401                .end_of_pass_write_index
1402                .map(|index| (timestamp_writes.query_set.raw, index));
1403        }
1404    }
1405    unsafe fn end_compute_pass(&mut self) {
1406        self.write_pass_end_timestamp_if_requested();
1407
1408        if self.rpass_debug_marker_active {
1409            unsafe { self.end_debug_marker() };
1410            self.rpass_debug_marker_active = false
1411        }
1412    }
1413
1414    unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {
1415        unsafe {
1416            self.device.raw.cmd_bind_pipeline(
1417                self.active,
1418                vk::PipelineBindPoint::COMPUTE,
1419                pipeline.raw,
1420            )
1421        };
1422    }
1423
1424    unsafe fn dispatch_workgroups(&mut self, count: [u32; 3]) {
1425        unsafe {
1426            self.device
1427                .raw
1428                .cmd_dispatch(self.active, count[0], count[1], count[2])
1429        };
1430    }
1431    unsafe fn dispatch_workgroups_indirect(
1432        &mut self,
1433        buffer: &super::Buffer,
1434        offset: wgt::BufferAddress,
1435    ) {
1436        unsafe {
1437            self.device
1438                .raw
1439                .cmd_dispatch_indirect(self.active, buffer.raw, offset)
1440        }
1441    }
1442
1443    // ray tracing
1444
1445    unsafe fn begin_ray_tracing_pass(&mut self, desc: &crate::RayTracingPassDescriptor<'_>) {
1446        self.bind_point = vk::PipelineBindPoint::RAY_TRACING_KHR;
1447        if let Some(label) = desc.label {
1448            unsafe { self.begin_debug_marker(label) };
1449            self.rpass_debug_marker_active = true;
1450        }
1451    }
1452    unsafe fn end_ray_tracing_pass(&mut self) {
1453        if self.rpass_debug_marker_active {
1454            unsafe { self.end_debug_marker() };
1455            self.rpass_debug_marker_active = false
1456        }
1457    }
1458
1459    unsafe fn trace_rays(
1460        &mut self,
1461        count: [u32; 3],
1462        ray_generation_group_data: crate::PipelineGroupData<super::Buffer>,
1463        miss_group_data: crate::PipelineGroupData<super::Buffer>,
1464        intersection_group_data: crate::PipelineGroupData<super::Buffer>,
1465    ) {
1466        let ray_tracing_functions = self
1467            .device
1468            .extension_fns
1469            .ray_tracing
1470            .as_ref()
1471            .expect("Feature `EXPERIMENTAL_RAY_TRACING` not enabled");
1472
1473        let ray_tracing_pipeline_functions = self
1474            .device
1475            .extension_fns
1476            .ray_tracing_pipelines
1477            .as_ref()
1478            .expect("Feature `EXPERIMENTAL_RAY_TRACING_PIPELINES` not enabled");
1479
1480        let get_device_address = |buffer: &super::Buffer| unsafe {
1481            ray_tracing_functions
1482                .buffer_device_address
1483                .get_buffer_device_address(
1484                    &vk::BufferDeviceAddressInfo::default().buffer(buffer.raw),
1485                )
1486        };
1487
1488        unsafe {
1489            ray_tracing_pipeline_functions.cmd_trace_rays(
1490                self.raw_handle(),
1491                &vk::StridedDeviceAddressRegionKHR {
1492                    device_address: get_device_address(ray_generation_group_data.buffer)
1493                        + ray_generation_group_data.offset,
1494                    stride: ray_generation_group_data.stride,
1495                    size: ray_generation_group_data.stride /* no need for multiplying by count, vulkan requires the ray gen sbt to be just one group */,
1496                },
1497                &vk::StridedDeviceAddressRegionKHR {
1498                    device_address: get_device_address(miss_group_data.buffer)
1499                        + miss_group_data.offset,
1500                    stride: miss_group_data.stride,
1501                    size: miss_group_data.stride * miss_group_data.count,
1502                },
1503                &vk::StridedDeviceAddressRegionKHR {
1504                    device_address: get_device_address(intersection_group_data.buffer)
1505                        + intersection_group_data.offset,
1506                    stride: intersection_group_data.stride,
1507                    size: intersection_group_data.stride * intersection_group_data.count,
1508                },
1509                &vk::StridedDeviceAddressRegionKHR {
1510                    device_address: 0,
1511                    stride: 0,
1512                    size: 0,
1513                },
1514                count[0],
1515                count[1],
1516                count[2],
1517            )
1518        };
1519    }
1520
1521    unsafe fn set_ray_tracing_pipeline(&mut self, pipeline: &super::RayTracingPipeline) {
1522        unsafe {
1523            self.device.raw.cmd_bind_pipeline(
1524                self.active,
1525                vk::PipelineBindPoint::RAY_TRACING_KHR,
1526                pipeline.raw,
1527            )
1528        };
1529    }
1530
1531    unsafe fn copy_acceleration_structure_to_acceleration_structure(
1532        &mut self,
1533        src: &super::AccelerationStructure,
1534        dst: &super::AccelerationStructure,
1535        copy: wgt::AccelerationStructureCopy,
1536    ) {
1537        let ray_tracing_functions = self
1538            .device
1539            .extension_fns
1540            .ray_tracing
1541            .as_ref()
1542            .expect("Feature `RAY_TRACING` not enabled");
1543
1544        let mode = match copy {
1545            wgt::AccelerationStructureCopy::Clone => vk::CopyAccelerationStructureModeKHR::CLONE,
1546            wgt::AccelerationStructureCopy::Compact => {
1547                vk::CopyAccelerationStructureModeKHR::COMPACT
1548            }
1549        };
1550
1551        unsafe {
1552            ray_tracing_functions
1553                .acceleration_structure
1554                .cmd_copy_acceleration_structure(
1555                    self.active,
1556                    &vk::CopyAccelerationStructureInfoKHR {
1557                        s_type: vk::StructureType::COPY_ACCELERATION_STRUCTURE_INFO_KHR,
1558                        p_next: core::ptr::null(),
1559                        src: src.raw,
1560                        dst: dst.raw,
1561                        mode,
1562                        _marker: Default::default(),
1563                    },
1564                );
1565        }
1566    }
1567}
1568
1569#[cfg(test)]
1570mod tests {
1571    use super::*;
1572
1573    #[test]
1574    fn check_dst_image_layout() {
1575        assert_eq!(
1576            conv::derive_image_layout(wgt::TextureUses::COPY_DST, wgt::TextureFormat::Rgba8Unorm),
1577            DST_IMAGE_LAYOUT
1578        );
1579    }
1580}