1use alloc::{
2 borrow::{Cow, ToOwned as _},
3 collections::BTreeMap,
4 ffi::CString,
5 sync::Arc,
6 vec::Vec,
7};
8use core::{
9 ffi::CStr,
10 mem::{self, MaybeUninit},
11 num::NonZeroU32,
12 ptr,
13};
14
15use arrayvec::ArrayVec;
16use ash::{ext, khr, vk};
17use hashbrown::hash_map::Entry;
18use parking_lot::Mutex;
19
20use super::{conv, RawTlasInstance};
21use crate::TlasInstance;
22
23impl super::DeviceShared {
24 pub(super) unsafe fn set_object_name(&self, object: impl vk::Handle, name: &str) {
32 let Some(extension) = self.extension_fns.debug_utils.as_ref() else {
33 return;
34 };
35
36 let mut buffer: [u8; 64] = [0u8; 64];
39 let buffer_vec: Vec<u8>;
40
41 let name_bytes = if name.len() < buffer.len() {
43 buffer[..name.len()].copy_from_slice(name.as_bytes());
45 buffer[name.len()] = 0;
47 &buffer[..name.len() + 1]
48 } else {
49 buffer_vec = name
52 .as_bytes()
53 .iter()
54 .cloned()
55 .chain(core::iter::once(0))
56 .collect();
57 &buffer_vec
58 };
59
60 let name = CStr::from_bytes_until_nul(name_bytes).expect("We have added a null byte");
61
62 let _result = unsafe {
63 extension.set_debug_utils_object_name(
64 &vk::DebugUtilsObjectNameInfoEXT::default()
65 .object_handle(object)
66 .object_name(name),
67 )
68 };
69 }
70
71 pub fn make_render_pass(
72 &self,
73 key: super::RenderPassKey,
74 ) -> Result<vk::RenderPass, crate::DeviceError> {
75 Ok(match self.render_passes.lock().entry(key) {
76 Entry::Occupied(e) => *e.get(),
77 Entry::Vacant(e) => {
78 let super::RenderPassKey {
79 ref colors,
80 ref depth_stencil,
81 sample_count,
82 multiview,
83 } = *e.key();
84
85 let mut vk_attachments = Vec::new();
86 let mut color_refs = Vec::with_capacity(colors.len());
87 let mut resolve_refs = Vec::with_capacity(color_refs.capacity());
88 let mut ds_ref = None;
89 let samples = vk::SampleCountFlags::from_raw(sample_count);
90 let unused = vk::AttachmentReference {
91 attachment: vk::ATTACHMENT_UNUSED,
92 layout: vk::ImageLayout::UNDEFINED,
93 };
94 for cat in colors.iter() {
95 let (color_ref, resolve_ref) =
96 if let Some(super::ColorAttachmentKey { base, resolve }) = cat {
97 let super::AttachmentKey {
98 format,
99 layout,
100 ops,
101 } = *base;
102
103 let color_ref = vk::AttachmentReference {
104 attachment: vk_attachments.len() as u32,
105 layout,
106 };
107 vk_attachments.push({
108 let (load_op, store_op) = conv::map_attachment_ops(ops);
109 vk::AttachmentDescription::default()
110 .format(format)
111 .samples(samples)
112 .load_op(load_op)
113 .store_op(store_op)
114 .initial_layout(layout)
115 .final_layout(layout)
116 });
117 let resolve_ref = if let Some(rat) = resolve {
118 let super::AttachmentKey {
119 format,
120 layout,
121 ops,
122 } = *rat;
123
124 let (load_op, store_op) = conv::map_attachment_ops(ops);
125 let vk_attachment = vk::AttachmentDescription::default()
126 .format(format)
127 .samples(vk::SampleCountFlags::TYPE_1)
128 .load_op(load_op)
129 .store_op(store_op)
130 .initial_layout(layout)
131 .final_layout(layout);
132 vk_attachments.push(vk_attachment);
133
134 vk::AttachmentReference {
135 attachment: vk_attachments.len() as u32 - 1,
136 layout,
137 }
138 } else {
139 unused
140 };
141
142 (color_ref, resolve_ref)
143 } else {
144 (unused, unused)
145 };
146
147 color_refs.push(color_ref);
148 resolve_refs.push(resolve_ref);
149 }
150
151 if let Some(ds) = depth_stencil {
152 let super::DepthStencilAttachmentKey {
153 ref base,
154 stencil_ops,
155 } = *ds;
156
157 let super::AttachmentKey {
158 format,
159 layout,
160 ops,
161 } = *base;
162
163 ds_ref = Some(vk::AttachmentReference {
164 attachment: vk_attachments.len() as u32,
165 layout,
166 });
167 let (load_op, store_op) = conv::map_attachment_ops(ops);
168 let (stencil_load_op, stencil_store_op) = conv::map_attachment_ops(stencil_ops);
169 let vk_attachment = vk::AttachmentDescription::default()
170 .format(format)
171 .samples(samples)
172 .load_op(load_op)
173 .store_op(store_op)
174 .stencil_load_op(stencil_load_op)
175 .stencil_store_op(stencil_store_op)
176 .initial_layout(layout)
177 .final_layout(layout);
178 vk_attachments.push(vk_attachment);
179 }
180
181 let vk_subpasses = [{
182 let mut vk_subpass = vk::SubpassDescription::default()
183 .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
184 .color_attachments(&color_refs)
185 .resolve_attachments(&resolve_refs);
186
187 if self
188 .workarounds
189 .contains(super::Workarounds::EMPTY_RESOLVE_ATTACHMENT_LISTS)
190 && resolve_refs.is_empty()
191 {
192 vk_subpass.p_resolve_attachments = ptr::null();
193 }
194
195 if let Some(ref reference) = ds_ref {
196 vk_subpass = vk_subpass.depth_stencil_attachment(reference)
197 }
198 vk_subpass
199 }];
200
201 let mut vk_info = vk::RenderPassCreateInfo::default()
202 .attachments(&vk_attachments)
203 .subpasses(&vk_subpasses);
204
205 let mut multiview_info;
206 let mask;
207 if let Some(multiview) = multiview {
208 assert!(multiview.get() <= 8);
210 assert!(multiview.get() > 1);
211
212 mask = [(1 << multiview.get()) - 1];
216
217 multiview_info = vk::RenderPassMultiviewCreateInfoKHR::default()
219 .view_masks(&mask)
220 .correlation_masks(&mask);
221 vk_info = vk_info.push_next(&mut multiview_info);
222 }
223
224 let raw = unsafe {
225 self.raw
226 .create_render_pass(&vk_info, None)
227 .map_err(super::map_host_device_oom_err)?
228 };
229
230 *e.insert(raw)
231 }
232 })
233 }
234
235 fn make_memory_ranges<'a, I: 'a + Iterator<Item = crate::MemoryRange>>(
236 &self,
237 buffer: &'a super::Buffer,
238 ranges: I,
239 ) -> Option<impl 'a + Iterator<Item = vk::MappedMemoryRange>> {
240 let block = buffer.block.as_ref()?.lock();
241 let mask = self.private_caps.non_coherent_map_mask;
242 Some(ranges.map(move |range| {
243 vk::MappedMemoryRange::default()
244 .memory(*block.memory())
245 .offset((block.offset() + range.start) & !mask)
246 .size((range.end - range.start + mask) & !mask)
247 }))
248 }
249}
250
251impl gpu_alloc::MemoryDevice<vk::DeviceMemory> for super::DeviceShared {
252 unsafe fn allocate_memory(
253 &self,
254 size: u64,
255 memory_type: u32,
256 flags: gpu_alloc::AllocationFlags,
257 ) -> Result<vk::DeviceMemory, gpu_alloc::OutOfMemory> {
258 let mut info = vk::MemoryAllocateInfo::default()
259 .allocation_size(size)
260 .memory_type_index(memory_type);
261
262 let mut info_flags;
263
264 if flags.contains(gpu_alloc::AllocationFlags::DEVICE_ADDRESS) {
265 info_flags = vk::MemoryAllocateFlagsInfo::default()
266 .flags(vk::MemoryAllocateFlags::DEVICE_ADDRESS);
267 info = info.push_next(&mut info_flags);
268 }
269
270 match unsafe { self.raw.allocate_memory(&info, None) } {
271 Ok(memory) => {
272 self.memory_allocations_counter.add(1);
273 Ok(memory)
274 }
275 Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => {
276 Err(gpu_alloc::OutOfMemory::OutOfDeviceMemory)
277 }
278 Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY) => {
279 Err(gpu_alloc::OutOfMemory::OutOfHostMemory)
280 }
281 Err(err) => handle_unexpected(err),
286 }
287 }
288
289 unsafe fn deallocate_memory(&self, memory: vk::DeviceMemory) {
290 self.memory_allocations_counter.sub(1);
291
292 unsafe { self.raw.free_memory(memory, None) };
293 }
294
295 unsafe fn map_memory(
296 &self,
297 memory: &mut vk::DeviceMemory,
298 offset: u64,
299 size: u64,
300 ) -> Result<ptr::NonNull<u8>, gpu_alloc::DeviceMapError> {
301 match unsafe {
302 self.raw
303 .map_memory(*memory, offset, size, vk::MemoryMapFlags::empty())
304 } {
305 Ok(ptr) => Ok(ptr::NonNull::new(ptr.cast::<u8>())
306 .expect("Pointer to memory mapping must not be null")),
307 Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => {
308 Err(gpu_alloc::DeviceMapError::OutOfDeviceMemory)
309 }
310 Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY) => {
311 Err(gpu_alloc::DeviceMapError::OutOfHostMemory)
312 }
313 Err(vk::Result::ERROR_MEMORY_MAP_FAILED) => Err(gpu_alloc::DeviceMapError::MapFailed),
314 Err(err) => handle_unexpected(err),
315 }
316 }
317
318 unsafe fn unmap_memory(&self, memory: &mut vk::DeviceMemory) {
319 unsafe { self.raw.unmap_memory(*memory) };
320 }
321
322 unsafe fn invalidate_memory_ranges(
323 &self,
324 _ranges: &[gpu_alloc::MappedMemoryRange<'_, vk::DeviceMemory>],
325 ) -> Result<(), gpu_alloc::OutOfMemory> {
326 unimplemented!()
328 }
329
330 unsafe fn flush_memory_ranges(
331 &self,
332 _ranges: &[gpu_alloc::MappedMemoryRange<'_, vk::DeviceMemory>],
333 ) -> Result<(), gpu_alloc::OutOfMemory> {
334 unimplemented!()
336 }
337}
338
339impl
340 gpu_descriptor::DescriptorDevice<vk::DescriptorSetLayout, vk::DescriptorPool, vk::DescriptorSet>
341 for super::DeviceShared
342{
343 unsafe fn create_descriptor_pool(
344 &self,
345 descriptor_count: &gpu_descriptor::DescriptorTotalCount,
346 max_sets: u32,
347 flags: gpu_descriptor::DescriptorPoolCreateFlags,
348 ) -> Result<vk::DescriptorPool, gpu_descriptor::CreatePoolError> {
349 let unfiltered_counts = [
351 (vk::DescriptorType::SAMPLER, descriptor_count.sampler),
352 (
353 vk::DescriptorType::SAMPLED_IMAGE,
354 descriptor_count.sampled_image,
355 ),
356 (
357 vk::DescriptorType::STORAGE_IMAGE,
358 descriptor_count.storage_image,
359 ),
360 (
361 vk::DescriptorType::UNIFORM_BUFFER,
362 descriptor_count.uniform_buffer,
363 ),
364 (
365 vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC,
366 descriptor_count.uniform_buffer_dynamic,
367 ),
368 (
369 vk::DescriptorType::STORAGE_BUFFER,
370 descriptor_count.storage_buffer,
371 ),
372 (
373 vk::DescriptorType::STORAGE_BUFFER_DYNAMIC,
374 descriptor_count.storage_buffer_dynamic,
375 ),
376 (
377 vk::DescriptorType::ACCELERATION_STRUCTURE_KHR,
378 descriptor_count.acceleration_structure,
379 ),
380 ];
381
382 let filtered_counts = unfiltered_counts
383 .iter()
384 .cloned()
385 .filter(|&(_, count)| count != 0)
386 .map(|(ty, count)| vk::DescriptorPoolSize {
387 ty,
388 descriptor_count: count,
389 })
390 .collect::<ArrayVec<_, 8>>();
391
392 let mut vk_flags =
393 if flags.contains(gpu_descriptor::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND) {
394 vk::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND
395 } else {
396 vk::DescriptorPoolCreateFlags::empty()
397 };
398 if flags.contains(gpu_descriptor::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET) {
399 vk_flags |= vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET;
400 }
401 let vk_info = vk::DescriptorPoolCreateInfo::default()
402 .max_sets(max_sets)
403 .flags(vk_flags)
404 .pool_sizes(&filtered_counts);
405
406 match unsafe { self.raw.create_descriptor_pool(&vk_info, None) } {
407 Ok(pool) => Ok(pool),
408 Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY) => {
409 Err(gpu_descriptor::CreatePoolError::OutOfHostMemory)
410 }
411 Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => {
412 Err(gpu_descriptor::CreatePoolError::OutOfDeviceMemory)
413 }
414 Err(vk::Result::ERROR_FRAGMENTATION) => {
415 Err(gpu_descriptor::CreatePoolError::Fragmentation)
416 }
417 Err(err) => handle_unexpected(err),
418 }
419 }
420
421 unsafe fn destroy_descriptor_pool(&self, pool: vk::DescriptorPool) {
422 unsafe { self.raw.destroy_descriptor_pool(pool, None) }
423 }
424
425 unsafe fn alloc_descriptor_sets<'a>(
426 &self,
427 pool: &mut vk::DescriptorPool,
428 layouts: impl ExactSizeIterator<Item = &'a vk::DescriptorSetLayout>,
429 sets: &mut impl Extend<vk::DescriptorSet>,
430 ) -> Result<(), gpu_descriptor::DeviceAllocationError> {
431 let result = unsafe {
432 self.raw.allocate_descriptor_sets(
433 &vk::DescriptorSetAllocateInfo::default()
434 .descriptor_pool(*pool)
435 .set_layouts(
436 &smallvec::SmallVec::<[vk::DescriptorSetLayout; 32]>::from_iter(
437 layouts.cloned(),
438 ),
439 ),
440 )
441 };
442
443 match result {
444 Ok(vk_sets) => {
445 sets.extend(vk_sets);
446 Ok(())
447 }
448 Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY)
449 | Err(vk::Result::ERROR_OUT_OF_POOL_MEMORY) => {
450 Err(gpu_descriptor::DeviceAllocationError::OutOfHostMemory)
451 }
452 Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => {
453 Err(gpu_descriptor::DeviceAllocationError::OutOfDeviceMemory)
454 }
455 Err(vk::Result::ERROR_FRAGMENTED_POOL) => {
456 Err(gpu_descriptor::DeviceAllocationError::FragmentedPool)
457 }
458 Err(err) => handle_unexpected(err),
459 }
460 }
461
462 unsafe fn dealloc_descriptor_sets<'a>(
463 &self,
464 pool: &mut vk::DescriptorPool,
465 sets: impl Iterator<Item = vk::DescriptorSet>,
466 ) {
467 let result = unsafe {
468 self.raw.free_descriptor_sets(
469 *pool,
470 &smallvec::SmallVec::<[vk::DescriptorSet; 32]>::from_iter(sets),
471 )
472 };
473 match result {
474 Ok(()) => {}
475 Err(err) => handle_unexpected(err),
476 }
477 }
478}
479
480struct CompiledStage {
481 create_info: vk::PipelineShaderStageCreateInfo<'static>,
482 _entry_point: CString,
483 temp_raw_module: Option<vk::ShaderModule>,
484}
485
486impl super::Device {
487 pub(super) unsafe fn create_swapchain(
488 &self,
489 surface: &super::Surface,
490 config: &crate::SurfaceConfiguration,
491 provided_old_swapchain: Option<super::Swapchain>,
492 ) -> Result<super::Swapchain, crate::SurfaceError> {
493 profiling::scope!("Device::create_swapchain");
494 let functor = khr::swapchain::Device::new(&surface.instance.raw, &self.shared.raw);
495
496 let old_swapchain = match provided_old_swapchain {
497 Some(osc) => osc.raw,
498 None => vk::SwapchainKHR::null(),
499 };
500
501 let color_space = if config.format == wgt::TextureFormat::Rgba16Float {
502 vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT
505 } else {
506 vk::ColorSpaceKHR::SRGB_NONLINEAR
507 };
508
509 let original_format = self.shared.private_caps.map_texture_format(config.format);
510 let mut raw_flags = vk::SwapchainCreateFlagsKHR::empty();
511 let mut raw_view_formats: Vec<vk::Format> = vec![];
512 if !config.view_formats.is_empty() {
513 raw_flags |= vk::SwapchainCreateFlagsKHR::MUTABLE_FORMAT;
514 raw_view_formats = config
515 .view_formats
516 .iter()
517 .map(|f| self.shared.private_caps.map_texture_format(*f))
518 .collect();
519 raw_view_formats.push(original_format);
520 }
521
522 let mut info = vk::SwapchainCreateInfoKHR::default()
523 .flags(raw_flags)
524 .surface(surface.raw)
525 .min_image_count(config.maximum_frame_latency + 1) .image_format(original_format)
527 .image_color_space(color_space)
528 .image_extent(vk::Extent2D {
529 width: config.extent.width,
530 height: config.extent.height,
531 })
532 .image_array_layers(config.extent.depth_or_array_layers)
533 .image_usage(conv::map_texture_usage(config.usage))
534 .image_sharing_mode(vk::SharingMode::EXCLUSIVE)
535 .pre_transform(vk::SurfaceTransformFlagsKHR::IDENTITY)
536 .composite_alpha(conv::map_composite_alpha_mode(config.composite_alpha_mode))
537 .present_mode(conv::map_present_mode(config.present_mode))
538 .clipped(true)
539 .old_swapchain(old_swapchain);
540
541 let mut format_list_info = vk::ImageFormatListCreateInfo::default();
542 if !raw_view_formats.is_empty() {
543 format_list_info = format_list_info.view_formats(&raw_view_formats);
544 info = info.push_next(&mut format_list_info);
545 }
546
547 let result = {
548 profiling::scope!("vkCreateSwapchainKHR");
549 unsafe { functor.create_swapchain(&info, None) }
550 };
551
552 if old_swapchain != vk::SwapchainKHR::null() {
554 unsafe { functor.destroy_swapchain(old_swapchain, None) }
555 }
556
557 let raw = match result {
558 Ok(swapchain) => swapchain,
559 Err(error) => {
560 return Err(match error {
561 vk::Result::ERROR_SURFACE_LOST_KHR
562 | vk::Result::ERROR_INITIALIZATION_FAILED => crate::SurfaceError::Lost,
563 vk::Result::ERROR_NATIVE_WINDOW_IN_USE_KHR => {
564 crate::SurfaceError::Other("Native window is in use")
565 }
566 other => super::map_host_device_oom_and_lost_err(other).into(),
569 });
570 }
571 };
572
573 let images =
574 unsafe { functor.get_swapchain_images(raw) }.map_err(super::map_host_device_oom_err)?;
575
576 let surface_semaphores = (0..=images.len())
580 .map(|_| {
581 super::SwapchainImageSemaphores::new(&self.shared)
582 .map(Mutex::new)
583 .map(Arc::new)
584 })
585 .collect::<Result<Vec<_>, _>>()?;
586
587 Ok(super::Swapchain {
588 raw,
589 functor,
590 device: Arc::clone(&self.shared),
591 images,
592 config: config.clone(),
593 surface_semaphores,
594 next_semaphore_index: 0,
595 next_present_time: None,
596 })
597 }
598
599 pub unsafe fn texture_from_raw(
606 vk_image: vk::Image,
607 desc: &crate::TextureDescriptor,
608 drop_callback: Option<crate::DropCallback>,
609 ) -> super::Texture {
610 let mut raw_flags = vk::ImageCreateFlags::empty();
611 let mut view_formats = vec![];
612 for tf in desc.view_formats.iter() {
613 if *tf == desc.format {
614 continue;
615 }
616 view_formats.push(*tf);
617 }
618 if !view_formats.is_empty() {
619 raw_flags |=
620 vk::ImageCreateFlags::MUTABLE_FORMAT | vk::ImageCreateFlags::EXTENDED_USAGE;
621 view_formats.push(desc.format)
622 }
623 if desc.format.is_multi_planar_format() {
624 raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
625 }
626
627 let drop_guard = crate::DropGuard::from_option(drop_callback);
628
629 super::Texture {
630 raw: vk_image,
631 drop_guard,
632 external_memory: None,
633 block: None,
634 format: desc.format,
635 copy_size: desc.copy_extent(),
636 }
637 }
638
639 #[cfg(windows)]
640 fn find_memory_type_index(
641 &self,
642 type_bits_req: u32,
643 flags_req: vk::MemoryPropertyFlags,
644 ) -> Option<usize> {
645 let mem_properties = unsafe {
646 self.shared
647 .instance
648 .raw
649 .get_physical_device_memory_properties(self.shared.physical_device)
650 };
651
652 for (i, mem_ty) in mem_properties.memory_types_as_slice().iter().enumerate() {
654 let types_bits = 1 << i;
655 let is_required_memory_type = type_bits_req & types_bits != 0;
656 let has_required_properties = mem_ty.property_flags & flags_req == flags_req;
657 if is_required_memory_type && has_required_properties {
658 return Some(i);
659 }
660 }
661
662 None
663 }
664
665 fn create_image_without_memory(
666 &self,
667 desc: &crate::TextureDescriptor,
668 external_memory_image_create_info: Option<&mut vk::ExternalMemoryImageCreateInfo>,
669 ) -> Result<ImageWithoutMemory, crate::DeviceError> {
670 let copy_size = desc.copy_extent();
671
672 let mut raw_flags = vk::ImageCreateFlags::empty();
673 if desc.dimension == wgt::TextureDimension::D3
674 && desc.usage.contains(wgt::TextureUses::COLOR_TARGET)
675 {
676 raw_flags |= vk::ImageCreateFlags::TYPE_2D_ARRAY_COMPATIBLE;
677 }
678 if desc.is_cube_compatible() {
679 raw_flags |= vk::ImageCreateFlags::CUBE_COMPATIBLE;
680 }
681
682 let original_format = self.shared.private_caps.map_texture_format(desc.format);
683 let mut vk_view_formats = vec![];
684 if !desc.view_formats.is_empty() {
685 raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
686
687 if self.shared.private_caps.image_format_list {
688 vk_view_formats = desc
689 .view_formats
690 .iter()
691 .map(|f| self.shared.private_caps.map_texture_format(*f))
692 .collect();
693 vk_view_formats.push(original_format)
694 }
695 }
696 if desc.format.is_multi_planar_format() {
697 raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
698 }
699
700 let mut vk_info = vk::ImageCreateInfo::default()
701 .flags(raw_flags)
702 .image_type(conv::map_texture_dimension(desc.dimension))
703 .format(original_format)
704 .extent(conv::map_copy_extent(©_size))
705 .mip_levels(desc.mip_level_count)
706 .array_layers(desc.array_layer_count())
707 .samples(vk::SampleCountFlags::from_raw(desc.sample_count))
708 .tiling(vk::ImageTiling::OPTIMAL)
709 .usage(conv::map_texture_usage(desc.usage))
710 .sharing_mode(vk::SharingMode::EXCLUSIVE)
711 .initial_layout(vk::ImageLayout::UNDEFINED);
712
713 let mut format_list_info = vk::ImageFormatListCreateInfo::default();
714 if !vk_view_formats.is_empty() {
715 format_list_info = format_list_info.view_formats(&vk_view_formats);
716 vk_info = vk_info.push_next(&mut format_list_info);
717 }
718
719 if let Some(ext_info) = external_memory_image_create_info {
720 vk_info = vk_info.push_next(ext_info);
721 }
722
723 let raw = unsafe { self.shared.raw.create_image(&vk_info, None) }.map_err(map_err)?;
724 fn map_err(err: vk::Result) -> crate::DeviceError {
725 super::map_host_device_oom_and_ioca_err(err)
728 }
729 let req = unsafe { self.shared.raw.get_image_memory_requirements(raw) };
730
731 Ok(ImageWithoutMemory {
732 raw,
733 requirements: req,
734 copy_size,
735 })
736 }
737
738 #[cfg(windows)]
744 pub unsafe fn texture_from_d3d11_shared_handle(
745 &self,
746 d3d11_shared_handle: windows::Win32::Foundation::HANDLE,
747 desc: &crate::TextureDescriptor,
748 ) -> Result<super::Texture, crate::DeviceError> {
749 if !self
750 .shared
751 .features
752 .contains(wgt::Features::VULKAN_EXTERNAL_MEMORY_WIN32)
753 {
754 log::error!("Vulkan driver does not support VK_KHR_external_memory_win32");
755 return Err(crate::DeviceError::Unexpected);
756 }
757
758 let mut external_memory_image_info = vk::ExternalMemoryImageCreateInfo::default()
759 .handle_types(vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE);
760
761 let image =
762 self.create_image_without_memory(desc, Some(&mut external_memory_image_info))?;
763
764 let mut dedicated_allocate_info =
767 vk::MemoryDedicatedAllocateInfo::default().image(image.raw);
768
769 let mut import_memory_info = vk::ImportMemoryWin32HandleInfoKHR::default()
770 .handle_type(vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE)
771 .handle(d3d11_shared_handle.0 as _);
772 #[allow(clippy::unnecessary_mut_passed)]
774 {
775 import_memory_info.p_next = <*const _>::cast(&mut dedicated_allocate_info);
776 }
777
778 let mem_type_index = self
779 .find_memory_type_index(
780 image.requirements.memory_type_bits,
781 vk::MemoryPropertyFlags::DEVICE_LOCAL,
782 )
783 .ok_or(crate::DeviceError::Unexpected)?;
784
785 let memory_allocate_info = vk::MemoryAllocateInfo::default()
786 .allocation_size(image.requirements.size)
787 .memory_type_index(mem_type_index as _)
788 .push_next(&mut import_memory_info);
789 let memory = unsafe { self.shared.raw.allocate_memory(&memory_allocate_info, None) }
790 .map_err(super::map_host_device_oom_err)?;
791
792 unsafe { self.shared.raw.bind_image_memory(image.raw, memory, 0) }
793 .map_err(super::map_host_device_oom_err)?;
794
795 if let Some(label) = desc.label {
796 unsafe { self.shared.set_object_name(image.raw, label) };
797 }
798
799 self.counters.textures.add(1);
800
801 Ok(super::Texture {
802 raw: image.raw,
803 drop_guard: None,
804 external_memory: Some(memory),
805 block: None,
806 format: desc.format,
807 copy_size: image.copy_size,
808 })
809 }
810
811 fn create_shader_module_impl(
812 &self,
813 spv: &[u32],
814 ) -> Result<vk::ShaderModule, crate::DeviceError> {
815 let vk_info = vk::ShaderModuleCreateInfo::default()
816 .flags(vk::ShaderModuleCreateFlags::empty())
817 .code(spv);
818
819 let raw = unsafe {
820 profiling::scope!("vkCreateShaderModule");
821 self.shared
822 .raw
823 .create_shader_module(&vk_info, None)
824 .map_err(map_err)?
825 };
826 fn map_err(err: vk::Result) -> crate::DeviceError {
827 super::map_host_device_oom_err(err)
830 }
831 Ok(raw)
832 }
833
834 fn compile_stage(
835 &self,
836 stage: &crate::ProgrammableStage<super::ShaderModule>,
837 naga_stage: naga::ShaderStage,
838 binding_map: &naga::back::spv::BindingMap,
839 ) -> Result<CompiledStage, crate::PipelineError> {
840 let stage_flags = crate::auxil::map_naga_stage(naga_stage);
841 let vk_module = match *stage.module {
842 super::ShaderModule::Raw(raw) => raw,
843 super::ShaderModule::Intermediate {
844 ref naga_shader,
845 runtime_checks,
846 } => {
847 let pipeline_options = naga::back::spv::PipelineOptions {
848 entry_point: stage.entry_point.to_owned(),
849 shader_stage: naga_stage,
850 };
851 let needs_temp_options = !runtime_checks.bounds_checks
852 || !runtime_checks.force_loop_bounding
853 || !binding_map.is_empty()
854 || naga_shader.debug_source.is_some()
855 || !stage.zero_initialize_workgroup_memory;
856 let mut temp_options;
857 let options = if needs_temp_options {
858 temp_options = self.naga_options.clone();
859 if !runtime_checks.bounds_checks {
860 temp_options.bounds_check_policies = naga::proc::BoundsCheckPolicies {
861 index: naga::proc::BoundsCheckPolicy::Unchecked,
862 buffer: naga::proc::BoundsCheckPolicy::Unchecked,
863 image_load: naga::proc::BoundsCheckPolicy::Unchecked,
864 binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
865 };
866 }
867 if !runtime_checks.force_loop_bounding {
868 temp_options.force_loop_bounding = false;
869 }
870 if !binding_map.is_empty() {
871 temp_options.binding_map = binding_map.clone();
872 }
873
874 if let Some(ref debug) = naga_shader.debug_source {
875 temp_options.debug_info = Some(naga::back::spv::DebugInfo {
876 source_code: &debug.source_code,
877 file_name: debug.file_name.as_ref().into(),
878 language: naga::back::spv::SourceLanguage::WGSL,
879 })
880 }
881 if !stage.zero_initialize_workgroup_memory {
882 temp_options.zero_initialize_workgroup_memory =
883 naga::back::spv::ZeroInitializeWorkgroupMemoryMode::None;
884 }
885
886 &temp_options
887 } else {
888 &self.naga_options
889 };
890
891 let (module, info) = naga::back::pipeline_constants::process_overrides(
892 &naga_shader.module,
893 &naga_shader.info,
894 Some((naga_stage, stage.entry_point)),
895 stage.constants,
896 )
897 .map_err(|e| {
898 crate::PipelineError::PipelineConstants(stage_flags, format!("{e}"))
899 })?;
900
901 let spv = {
902 profiling::scope!("naga::spv::write_vec");
903 naga::back::spv::write_vec(&module, &info, options, Some(&pipeline_options))
904 }
905 .map_err(|e| crate::PipelineError::Linkage(stage_flags, format!("{e}")))?;
906 self.create_shader_module_impl(&spv)?
907 }
908 };
909
910 let mut flags = vk::PipelineShaderStageCreateFlags::empty();
911 if self.shared.features.contains(wgt::Features::SUBGROUP) {
912 flags |= vk::PipelineShaderStageCreateFlags::ALLOW_VARYING_SUBGROUP_SIZE
913 }
914
915 let entry_point = CString::new(stage.entry_point).unwrap();
916 let mut create_info = vk::PipelineShaderStageCreateInfo::default()
917 .flags(flags)
918 .stage(conv::map_shader_stage(stage_flags))
919 .module(vk_module);
920
921 create_info.p_name = entry_point.as_ptr();
923
924 Ok(CompiledStage {
925 create_info,
926 _entry_point: entry_point,
927 temp_raw_module: match *stage.module {
928 super::ShaderModule::Raw(_) => None,
929 super::ShaderModule::Intermediate { .. } => Some(vk_module),
930 },
931 })
932 }
933
934 pub fn queue_family_index(&self) -> u32 {
940 self.shared.family_index
941 }
942
943 pub fn queue_index(&self) -> u32 {
944 self.shared.queue_index
945 }
946
947 pub fn raw_device(&self) -> &ash::Device {
948 &self.shared.raw
949 }
950
951 pub fn raw_physical_device(&self) -> vk::PhysicalDevice {
952 self.shared.physical_device
953 }
954
955 pub fn raw_queue(&self) -> vk::Queue {
956 self.shared.raw_queue
957 }
958
959 pub fn enabled_device_extensions(&self) -> &[&'static CStr] {
960 &self.shared.enabled_extensions
961 }
962
963 pub fn shared_instance(&self) -> &super::InstanceShared {
964 &self.shared.instance
965 }
966
967 fn error_if_would_oom_on_resource_allocation(
968 &self,
969 needs_host_access: bool,
970 size: u64,
971 ) -> Result<(), crate::DeviceError> {
972 let Some(threshold) = self
973 .shared
974 .instance
975 .memory_budget_thresholds
976 .for_resource_creation
977 else {
978 return Ok(());
979 };
980
981 if !self
982 .shared
983 .enabled_extensions
984 .contains(&ext::memory_budget::NAME)
985 {
986 return Ok(());
987 }
988
989 let get_physical_device_properties = self
990 .shared
991 .instance
992 .get_physical_device_properties
993 .as_ref()
994 .unwrap();
995
996 let mut memory_budget_properties = vk::PhysicalDeviceMemoryBudgetPropertiesEXT::default();
997
998 let mut memory_properties =
999 vk::PhysicalDeviceMemoryProperties2::default().push_next(&mut memory_budget_properties);
1000
1001 unsafe {
1002 get_physical_device_properties.get_physical_device_memory_properties2(
1003 self.shared.physical_device,
1004 &mut memory_properties,
1005 );
1006 }
1007
1008 let mut host_visible_heaps = [false; vk::MAX_MEMORY_HEAPS];
1009 let mut device_local_heaps = [false; vk::MAX_MEMORY_HEAPS];
1010
1011 let memory_properties = memory_properties.memory_properties;
1012
1013 for i in 0..memory_properties.memory_type_count {
1014 let memory_type = memory_properties.memory_types[i as usize];
1015 let flags = memory_type.property_flags;
1016
1017 if flags.intersects(
1018 vk::MemoryPropertyFlags::LAZILY_ALLOCATED | vk::MemoryPropertyFlags::PROTECTED,
1019 ) {
1020 continue; }
1022
1023 if flags.contains(vk::MemoryPropertyFlags::HOST_VISIBLE) {
1024 host_visible_heaps[memory_type.heap_index as usize] = true;
1025 }
1026
1027 if flags.contains(vk::MemoryPropertyFlags::DEVICE_LOCAL) {
1028 device_local_heaps[memory_type.heap_index as usize] = true;
1029 }
1030 }
1031
1032 let heaps = if needs_host_access {
1033 host_visible_heaps
1034 } else {
1035 device_local_heaps
1036 };
1037
1038 for (i, check) in heaps.iter().enumerate() {
1043 if !check {
1044 continue;
1045 }
1046
1047 let heap_usage = memory_budget_properties.heap_usage[i];
1048 let heap_budget = memory_budget_properties.heap_budget[i];
1049
1050 if heap_usage + size >= heap_budget / 100 * threshold as u64 {
1051 return Err(crate::DeviceError::OutOfMemory);
1052 }
1053 }
1054
1055 Ok(())
1056 }
1057}
1058
1059impl crate::Device for super::Device {
1060 type A = super::Api;
1061
1062 unsafe fn create_buffer(
1063 &self,
1064 desc: &crate::BufferDescriptor,
1065 ) -> Result<super::Buffer, crate::DeviceError> {
1066 let vk_info = vk::BufferCreateInfo::default()
1067 .size(desc.size)
1068 .usage(conv::map_buffer_usage(desc.usage))
1069 .sharing_mode(vk::SharingMode::EXCLUSIVE);
1070
1071 let raw = unsafe {
1072 self.shared
1073 .raw
1074 .create_buffer(&vk_info, None)
1075 .map_err(super::map_host_device_oom_and_ioca_err)?
1076 };
1077 let req = unsafe { self.shared.raw.get_buffer_memory_requirements(raw) };
1078
1079 let mut alloc_usage = if desc
1080 .usage
1081 .intersects(wgt::BufferUses::MAP_READ | wgt::BufferUses::MAP_WRITE)
1082 {
1083 let mut flags = gpu_alloc::UsageFlags::HOST_ACCESS;
1084 flags.set(
1086 gpu_alloc::UsageFlags::DOWNLOAD,
1087 desc.usage.contains(wgt::BufferUses::MAP_READ),
1088 );
1089 flags.set(
1090 gpu_alloc::UsageFlags::UPLOAD,
1091 desc.usage.contains(wgt::BufferUses::MAP_WRITE),
1092 );
1093 flags
1094 } else {
1095 gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS
1096 };
1097 alloc_usage.set(
1098 gpu_alloc::UsageFlags::TRANSIENT,
1099 desc.memory_flags.contains(crate::MemoryFlags::TRANSIENT),
1100 );
1101
1102 let needs_host_access = alloc_usage.contains(gpu_alloc::UsageFlags::HOST_ACCESS);
1103
1104 self.error_if_would_oom_on_resource_allocation(needs_host_access, req.size)
1105 .inspect_err(|_| {
1106 unsafe { self.shared.raw.destroy_buffer(raw, None) };
1107 })?;
1108
1109 let alignment_mask = req.alignment - 1;
1110
1111 let block = unsafe {
1112 self.mem_allocator.lock().alloc(
1113 &*self.shared,
1114 gpu_alloc::Request {
1115 size: req.size,
1116 align_mask: alignment_mask,
1117 usage: alloc_usage,
1118 memory_types: req.memory_type_bits & self.valid_ash_memory_types,
1119 },
1120 )
1121 }
1122 .inspect_err(|_| {
1123 unsafe { self.shared.raw.destroy_buffer(raw, None) };
1124 })?;
1125
1126 unsafe {
1127 self.shared
1128 .raw
1129 .bind_buffer_memory(raw, *block.memory(), block.offset())
1130 }
1131 .map_err(super::map_host_device_oom_and_ioca_err)
1132 .inspect_err(|_| {
1133 unsafe { self.shared.raw.destroy_buffer(raw, None) };
1134 })?;
1135
1136 if let Some(label) = desc.label {
1137 unsafe { self.shared.set_object_name(raw, label) };
1138 }
1139
1140 self.counters.buffer_memory.add(block.size() as isize);
1141 self.counters.buffers.add(1);
1142
1143 Ok(super::Buffer {
1144 raw,
1145 block: Some(Mutex::new(super::BufferMemoryBacking::Managed(block))),
1146 })
1147 }
1148 unsafe fn destroy_buffer(&self, buffer: super::Buffer) {
1149 unsafe { self.shared.raw.destroy_buffer(buffer.raw, None) };
1150 if let Some(block) = buffer.block {
1151 let block = block.into_inner();
1152 self.counters.buffer_memory.sub(block.size() as isize);
1153 match block {
1154 super::BufferMemoryBacking::Managed(block) => unsafe {
1155 self.mem_allocator.lock().dealloc(&*self.shared, block)
1156 },
1157 super::BufferMemoryBacking::VulkanMemory { memory, .. } => unsafe {
1158 self.shared.raw.free_memory(memory, None);
1159 },
1160 }
1161 }
1162
1163 self.counters.buffers.sub(1);
1164 }
1165
1166 unsafe fn add_raw_buffer(&self, _buffer: &super::Buffer) {
1167 self.counters.buffers.add(1);
1168 }
1169
1170 unsafe fn map_buffer(
1171 &self,
1172 buffer: &super::Buffer,
1173 range: crate::MemoryRange,
1174 ) -> Result<crate::BufferMapping, crate::DeviceError> {
1175 if let Some(ref block) = buffer.block {
1176 let size = range.end - range.start;
1177 let mut block = block.lock();
1178 if let super::BufferMemoryBacking::Managed(ref mut block) = *block {
1179 let ptr = unsafe { block.map(&*self.shared, range.start, size as usize)? };
1180 let is_coherent = block
1181 .props()
1182 .contains(gpu_alloc::MemoryPropertyFlags::HOST_COHERENT);
1183 Ok(crate::BufferMapping { ptr, is_coherent })
1184 } else {
1185 crate::hal_usage_error("tried to map externally created buffer")
1186 }
1187 } else {
1188 crate::hal_usage_error("tried to map external buffer")
1189 }
1190 }
1191 unsafe fn unmap_buffer(&self, buffer: &super::Buffer) {
1192 if let Some(ref block) = buffer.block {
1193 match &mut *block.lock() {
1194 super::BufferMemoryBacking::Managed(block) => unsafe { block.unmap(&*self.shared) },
1195 super::BufferMemoryBacking::VulkanMemory { .. } => {
1196 crate::hal_usage_error("tried to unmap externally created buffer")
1197 }
1198 };
1199 } else {
1200 crate::hal_usage_error("tried to unmap external buffer")
1201 }
1202 }
1203
1204 unsafe fn flush_mapped_ranges<I>(&self, buffer: &super::Buffer, ranges: I)
1205 where
1206 I: Iterator<Item = crate::MemoryRange>,
1207 {
1208 if let Some(vk_ranges) = self.shared.make_memory_ranges(buffer, ranges) {
1209 unsafe {
1210 self.shared
1211 .raw
1212 .flush_mapped_memory_ranges(
1213 &smallvec::SmallVec::<[vk::MappedMemoryRange; 32]>::from_iter(vk_ranges),
1214 )
1215 }
1216 .unwrap();
1217 }
1218 }
1219 unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &super::Buffer, ranges: I)
1220 where
1221 I: Iterator<Item = crate::MemoryRange>,
1222 {
1223 if let Some(vk_ranges) = self.shared.make_memory_ranges(buffer, ranges) {
1224 unsafe {
1225 self.shared
1226 .raw
1227 .invalidate_mapped_memory_ranges(&smallvec::SmallVec::<
1228 [vk::MappedMemoryRange; 32],
1229 >::from_iter(vk_ranges))
1230 }
1231 .unwrap();
1232 }
1233 }
1234
1235 unsafe fn create_texture(
1236 &self,
1237 desc: &crate::TextureDescriptor,
1238 ) -> Result<super::Texture, crate::DeviceError> {
1239 let image = self.create_image_without_memory(desc, None)?;
1240
1241 self.error_if_would_oom_on_resource_allocation(false, image.requirements.size)
1242 .inspect_err(|_| {
1243 unsafe { self.shared.raw.destroy_image(image.raw, None) };
1244 })?;
1245
1246 let block = unsafe {
1247 self.mem_allocator.lock().alloc(
1248 &*self.shared,
1249 gpu_alloc::Request {
1250 size: image.requirements.size,
1251 align_mask: image.requirements.alignment - 1,
1252 usage: gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS,
1253 memory_types: image.requirements.memory_type_bits & self.valid_ash_memory_types,
1254 },
1255 )
1256 }
1257 .inspect_err(|_| {
1258 unsafe { self.shared.raw.destroy_image(image.raw, None) };
1259 })?;
1260
1261 self.counters.texture_memory.add(block.size() as isize);
1262
1263 unsafe {
1264 self.shared
1265 .raw
1266 .bind_image_memory(image.raw, *block.memory(), block.offset())
1267 }
1268 .map_err(super::map_host_device_oom_err)
1269 .inspect_err(|_| {
1270 unsafe { self.shared.raw.destroy_image(image.raw, None) };
1271 })?;
1272
1273 if let Some(label) = desc.label {
1274 unsafe { self.shared.set_object_name(image.raw, label) };
1275 }
1276
1277 self.counters.textures.add(1);
1278
1279 Ok(super::Texture {
1280 raw: image.raw,
1281 drop_guard: None,
1282 external_memory: None,
1283 block: Some(block),
1284 format: desc.format,
1285 copy_size: image.copy_size,
1286 })
1287 }
1288 unsafe fn destroy_texture(&self, texture: super::Texture) {
1289 if texture.drop_guard.is_none() {
1290 unsafe { self.shared.raw.destroy_image(texture.raw, None) };
1291 }
1292 if let Some(memory) = texture.external_memory {
1293 unsafe { self.shared.raw.free_memory(memory, None) };
1294 }
1295 if let Some(block) = texture.block {
1296 self.counters.texture_memory.sub(block.size() as isize);
1297
1298 unsafe { self.mem_allocator.lock().dealloc(&*self.shared, block) };
1299 }
1300
1301 self.counters.textures.sub(1);
1302 }
1303
1304 unsafe fn add_raw_texture(&self, _texture: &super::Texture) {
1305 self.counters.textures.add(1);
1306 }
1307
1308 unsafe fn create_texture_view(
1309 &self,
1310 texture: &super::Texture,
1311 desc: &crate::TextureViewDescriptor,
1312 ) -> Result<super::TextureView, crate::DeviceError> {
1313 let subresource_range = conv::map_subresource_range(&desc.range, texture.format);
1314 let raw_format = self.shared.private_caps.map_texture_format(desc.format);
1315 let mut vk_info = vk::ImageViewCreateInfo::default()
1316 .flags(vk::ImageViewCreateFlags::empty())
1317 .image(texture.raw)
1318 .view_type(conv::map_view_dimension(desc.dimension))
1319 .format(raw_format)
1320 .subresource_range(subresource_range);
1321 let layers =
1322 NonZeroU32::new(subresource_range.layer_count).expect("Unexpected zero layer count");
1323
1324 let mut image_view_info;
1325 if self.shared.private_caps.image_view_usage && !desc.usage.is_empty() {
1326 image_view_info =
1327 vk::ImageViewUsageCreateInfo::default().usage(conv::map_texture_usage(desc.usage));
1328 vk_info = vk_info.push_next(&mut image_view_info);
1329 }
1330
1331 let raw = unsafe { self.shared.raw.create_image_view(&vk_info, None) }
1332 .map_err(super::map_host_device_oom_and_ioca_err)?;
1333
1334 if let Some(label) = desc.label {
1335 unsafe { self.shared.set_object_name(raw, label) };
1336 }
1337
1338 self.counters.texture_views.add(1);
1339
1340 Ok(super::TextureView {
1341 raw_texture: texture.raw,
1342 raw,
1343 layers,
1344 format: desc.format,
1345 raw_format,
1346 base_mip_level: desc.range.base_mip_level,
1347 dimension: desc.dimension,
1348 })
1349 }
1350 unsafe fn destroy_texture_view(&self, view: super::TextureView) {
1351 unsafe { self.shared.raw.destroy_image_view(view.raw, None) };
1352
1353 self.counters.texture_views.sub(1);
1354 }
1355
1356 unsafe fn create_sampler(
1357 &self,
1358 desc: &crate::SamplerDescriptor,
1359 ) -> Result<super::Sampler, crate::DeviceError> {
1360 let mut create_info = vk::SamplerCreateInfo::default()
1361 .flags(vk::SamplerCreateFlags::empty())
1362 .mag_filter(conv::map_filter_mode(desc.mag_filter))
1363 .min_filter(conv::map_filter_mode(desc.min_filter))
1364 .mipmap_mode(conv::map_mip_filter_mode(desc.mipmap_filter))
1365 .address_mode_u(conv::map_address_mode(desc.address_modes[0]))
1366 .address_mode_v(conv::map_address_mode(desc.address_modes[1]))
1367 .address_mode_w(conv::map_address_mode(desc.address_modes[2]))
1368 .min_lod(desc.lod_clamp.start)
1369 .max_lod(desc.lod_clamp.end);
1370
1371 if let Some(fun) = desc.compare {
1372 create_info = create_info
1373 .compare_enable(true)
1374 .compare_op(conv::map_comparison(fun));
1375 }
1376
1377 if desc.anisotropy_clamp != 1 {
1378 create_info = create_info
1381 .anisotropy_enable(true)
1382 .max_anisotropy(desc.anisotropy_clamp as f32);
1383 }
1384
1385 if let Some(color) = desc.border_color {
1386 create_info = create_info.border_color(conv::map_border_color(color));
1387 }
1388
1389 let raw = self
1390 .shared
1391 .sampler_cache
1392 .lock()
1393 .create_sampler(&self.shared.raw, create_info)?;
1394
1395 if let Some(label) = desc.label {
1399 unsafe { self.shared.set_object_name(raw, label) };
1400 }
1401
1402 self.counters.samplers.add(1);
1403
1404 Ok(super::Sampler { raw, create_info })
1405 }
1406 unsafe fn destroy_sampler(&self, sampler: super::Sampler) {
1407 self.shared.sampler_cache.lock().destroy_sampler(
1408 &self.shared.raw,
1409 sampler.create_info,
1410 sampler.raw,
1411 );
1412
1413 self.counters.samplers.sub(1);
1414 }
1415
1416 unsafe fn create_command_encoder(
1417 &self,
1418 desc: &crate::CommandEncoderDescriptor<super::Queue>,
1419 ) -> Result<super::CommandEncoder, crate::DeviceError> {
1420 let vk_info = vk::CommandPoolCreateInfo::default()
1421 .queue_family_index(desc.queue.family_index)
1422 .flags(vk::CommandPoolCreateFlags::TRANSIENT);
1423
1424 let raw = unsafe {
1425 self.shared
1426 .raw
1427 .create_command_pool(&vk_info, None)
1428 .map_err(super::map_host_device_oom_err)?
1429 };
1430
1431 self.counters.command_encoders.add(1);
1432
1433 Ok(super::CommandEncoder {
1434 raw,
1435 device: Arc::clone(&self.shared),
1436 active: vk::CommandBuffer::null(),
1437 bind_point: vk::PipelineBindPoint::default(),
1438 temp: super::Temp::default(),
1439 free: Vec::new(),
1440 discarded: Vec::new(),
1441 rpass_debug_marker_active: false,
1442 end_of_pass_timer_query: None,
1443 framebuffers: Default::default(),
1444 temp_texture_views: Default::default(),
1445 counters: Arc::clone(&self.counters),
1446 })
1447 }
1448
1449 unsafe fn create_bind_group_layout(
1450 &self,
1451 desc: &crate::BindGroupLayoutDescriptor,
1452 ) -> Result<super::BindGroupLayout, crate::DeviceError> {
1453 let mut desc_count = gpu_descriptor::DescriptorTotalCount::default();
1454 let mut types = Vec::new();
1455 for entry in desc.entries {
1456 let count = entry.count.map_or(1, |c| c.get());
1457 if entry.binding as usize >= types.len() {
1458 types.resize(
1459 entry.binding as usize + 1,
1460 (vk::DescriptorType::INPUT_ATTACHMENT, 0),
1461 );
1462 }
1463 types[entry.binding as usize] = (
1464 conv::map_binding_type(entry.ty),
1465 entry.count.map_or(1, |c| c.get()),
1466 );
1467
1468 match entry.ty {
1469 wgt::BindingType::Buffer {
1470 ty,
1471 has_dynamic_offset,
1472 ..
1473 } => match ty {
1474 wgt::BufferBindingType::Uniform => {
1475 if has_dynamic_offset {
1476 desc_count.uniform_buffer_dynamic += count;
1477 } else {
1478 desc_count.uniform_buffer += count;
1479 }
1480 }
1481 wgt::BufferBindingType::Storage { .. } => {
1482 if has_dynamic_offset {
1483 desc_count.storage_buffer_dynamic += count;
1484 } else {
1485 desc_count.storage_buffer += count;
1486 }
1487 }
1488 },
1489 wgt::BindingType::Sampler { .. } => {
1490 desc_count.sampler += count;
1491 }
1492 wgt::BindingType::Texture { .. } => {
1493 desc_count.sampled_image += count;
1494 }
1495 wgt::BindingType::StorageTexture { .. } => {
1496 desc_count.storage_image += count;
1497 }
1498 wgt::BindingType::AccelerationStructure { .. } => {
1499 desc_count.acceleration_structure += count;
1500 }
1501 wgt::BindingType::ExternalTexture => unimplemented!(),
1502 }
1503 }
1504
1505 let vk_bindings = desc
1507 .entries
1508 .iter()
1509 .map(|entry| vk::DescriptorSetLayoutBinding {
1510 binding: entry.binding,
1511 descriptor_type: types[entry.binding as usize].0,
1512 descriptor_count: types[entry.binding as usize].1,
1513 stage_flags: conv::map_shader_stage(entry.visibility),
1514 p_immutable_samplers: ptr::null(),
1515 _marker: Default::default(),
1516 })
1517 .collect::<Vec<_>>();
1518
1519 let binding_arrays: Vec<_> = desc
1520 .entries
1521 .iter()
1522 .enumerate()
1523 .filter_map(|(idx, entry)| entry.count.map(|count| (idx as u32, count)))
1524 .collect();
1525
1526 let vk_info = vk::DescriptorSetLayoutCreateInfo::default()
1527 .bindings(&vk_bindings)
1528 .flags(if !binding_arrays.is_empty() {
1529 vk::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL
1530 } else {
1531 vk::DescriptorSetLayoutCreateFlags::empty()
1532 });
1533
1534 let partially_bound = desc
1535 .flags
1536 .contains(crate::BindGroupLayoutFlags::PARTIALLY_BOUND);
1537
1538 let binding_flag_vec = desc
1539 .entries
1540 .iter()
1541 .map(|entry| {
1542 let mut flags = vk::DescriptorBindingFlags::empty();
1543
1544 if partially_bound && entry.count.is_some() {
1545 flags |= vk::DescriptorBindingFlags::PARTIALLY_BOUND;
1546 }
1547
1548 if entry.count.is_some() {
1549 flags |= vk::DescriptorBindingFlags::UPDATE_AFTER_BIND;
1550 }
1551
1552 flags
1553 })
1554 .collect::<Vec<_>>();
1555
1556 let mut binding_flag_info = vk::DescriptorSetLayoutBindingFlagsCreateInfo::default()
1557 .binding_flags(&binding_flag_vec);
1558
1559 let vk_info = vk_info.push_next(&mut binding_flag_info);
1560
1561 let raw = unsafe {
1562 self.shared
1563 .raw
1564 .create_descriptor_set_layout(&vk_info, None)
1565 .map_err(super::map_host_device_oom_err)?
1566 };
1567
1568 if let Some(label) = desc.label {
1569 unsafe { self.shared.set_object_name(raw, label) };
1570 }
1571
1572 self.counters.bind_group_layouts.add(1);
1573
1574 Ok(super::BindGroupLayout {
1575 raw,
1576 desc_count,
1577 types: types.into_boxed_slice(),
1578 binding_arrays,
1579 })
1580 }
1581 unsafe fn destroy_bind_group_layout(&self, bg_layout: super::BindGroupLayout) {
1582 unsafe {
1583 self.shared
1584 .raw
1585 .destroy_descriptor_set_layout(bg_layout.raw, None)
1586 };
1587
1588 self.counters.bind_group_layouts.sub(1);
1589 }
1590
1591 unsafe fn create_pipeline_layout(
1592 &self,
1593 desc: &crate::PipelineLayoutDescriptor<super::BindGroupLayout>,
1594 ) -> Result<super::PipelineLayout, crate::DeviceError> {
1595 let vk_set_layouts = desc
1597 .bind_group_layouts
1598 .iter()
1599 .map(|bgl| bgl.raw)
1600 .collect::<Vec<_>>();
1601 let vk_push_constant_ranges = desc
1602 .push_constant_ranges
1603 .iter()
1604 .map(|pcr| vk::PushConstantRange {
1605 stage_flags: conv::map_shader_stage(pcr.stages),
1606 offset: pcr.range.start,
1607 size: pcr.range.end - pcr.range.start,
1608 })
1609 .collect::<Vec<_>>();
1610
1611 let vk_info = vk::PipelineLayoutCreateInfo::default()
1612 .flags(vk::PipelineLayoutCreateFlags::empty())
1613 .set_layouts(&vk_set_layouts)
1614 .push_constant_ranges(&vk_push_constant_ranges);
1615
1616 let raw = {
1617 profiling::scope!("vkCreatePipelineLayout");
1618 unsafe {
1619 self.shared
1620 .raw
1621 .create_pipeline_layout(&vk_info, None)
1622 .map_err(super::map_host_device_oom_err)?
1623 }
1624 };
1625
1626 if let Some(label) = desc.label {
1627 unsafe { self.shared.set_object_name(raw, label) };
1628 }
1629
1630 let mut binding_arrays = BTreeMap::new();
1631 for (group, &layout) in desc.bind_group_layouts.iter().enumerate() {
1632 for &(binding, binding_array_size) in &layout.binding_arrays {
1633 binding_arrays.insert(
1634 naga::ResourceBinding {
1635 group: group as u32,
1636 binding,
1637 },
1638 naga::back::spv::BindingInfo {
1639 binding_array_size: Some(binding_array_size.get()),
1640 },
1641 );
1642 }
1643 }
1644
1645 self.counters.pipeline_layouts.add(1);
1646
1647 Ok(super::PipelineLayout {
1648 raw,
1649 binding_arrays,
1650 })
1651 }
1652 unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {
1653 unsafe {
1654 self.shared
1655 .raw
1656 .destroy_pipeline_layout(pipeline_layout.raw, None)
1657 };
1658
1659 self.counters.pipeline_layouts.sub(1);
1660 }
1661
1662 unsafe fn create_bind_group(
1663 &self,
1664 desc: &crate::BindGroupDescriptor<
1665 super::BindGroupLayout,
1666 super::Buffer,
1667 super::Sampler,
1668 super::TextureView,
1669 super::AccelerationStructure,
1670 >,
1671 ) -> Result<super::BindGroup, crate::DeviceError> {
1672 let contains_binding_arrays = !desc.layout.binding_arrays.is_empty();
1673
1674 let desc_set_layout_flags = if contains_binding_arrays {
1675 gpu_descriptor::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND
1676 } else {
1677 gpu_descriptor::DescriptorSetLayoutCreateFlags::empty()
1678 };
1679
1680 let mut vk_sets = unsafe {
1681 self.desc_allocator.lock().allocate(
1682 &*self.shared,
1683 &desc.layout.raw,
1684 desc_set_layout_flags,
1685 &desc.layout.desc_count,
1686 1,
1687 )?
1688 };
1689
1690 let set = vk_sets.pop().unwrap();
1691 if let Some(label) = desc.label {
1692 unsafe { self.shared.set_object_name(*set.raw(), label) };
1693 }
1694
1695 struct ExtendStack<'a, T> {
1702 remainder: &'a mut [MaybeUninit<T>],
1703 }
1704
1705 impl<'a, T> ExtendStack<'a, T> {
1706 fn from_vec_capacity(vec: &'a mut Vec<T>) -> Self {
1707 Self {
1708 remainder: vec.spare_capacity_mut(),
1709 }
1710 }
1711
1712 fn extend_one(self, value: T) -> (Self, &'a mut T) {
1713 let (to_init, remainder) = self.remainder.split_first_mut().unwrap();
1714 let init = to_init.write(value);
1715 (Self { remainder }, init)
1716 }
1717
1718 fn extend(
1719 self,
1720 iter: impl IntoIterator<Item = T> + ExactSizeIterator,
1721 ) -> (Self, &'a mut [T]) {
1722 let (to_init, remainder) = self.remainder.split_at_mut(iter.len());
1723
1724 for (value, to_init) in iter.into_iter().zip(to_init.iter_mut()) {
1725 to_init.write(value);
1726 }
1727
1728 let init = {
1731 unsafe { mem::transmute::<&mut [MaybeUninit<T>], &mut [T]>(to_init) }
1738 };
1739 (Self { remainder }, init)
1740 }
1741 }
1742
1743 let mut writes = Vec::with_capacity(desc.entries.len());
1744 let mut buffer_infos = Vec::with_capacity(desc.buffers.len());
1745 let mut buffer_infos = ExtendStack::from_vec_capacity(&mut buffer_infos);
1746 let mut image_infos = Vec::with_capacity(desc.samplers.len() + desc.textures.len());
1747 let mut image_infos = ExtendStack::from_vec_capacity(&mut image_infos);
1748 let mut acceleration_structure_infos =
1753 Vec::with_capacity(desc.acceleration_structures.len());
1754 let mut acceleration_structure_infos =
1755 ExtendStack::from_vec_capacity(&mut acceleration_structure_infos);
1756 let mut raw_acceleration_structures =
1757 Vec::with_capacity(desc.acceleration_structures.len());
1758 let mut raw_acceleration_structures =
1759 ExtendStack::from_vec_capacity(&mut raw_acceleration_structures);
1760 for entry in desc.entries {
1761 let (ty, size) = desc.layout.types[entry.binding as usize];
1762 if size == 0 {
1763 continue; }
1765 let mut write = vk::WriteDescriptorSet::default()
1766 .dst_set(*set.raw())
1767 .dst_binding(entry.binding)
1768 .descriptor_type(ty);
1769
1770 write = match ty {
1771 vk::DescriptorType::SAMPLER => {
1772 let start = entry.resource_index;
1773 let end = start + entry.count;
1774 let local_image_infos;
1775 (image_infos, local_image_infos) =
1776 image_infos.extend(desc.samplers[start as usize..end as usize].iter().map(
1777 |sampler| vk::DescriptorImageInfo::default().sampler(sampler.raw),
1778 ));
1779 write.image_info(local_image_infos)
1780 }
1781 vk::DescriptorType::SAMPLED_IMAGE | vk::DescriptorType::STORAGE_IMAGE => {
1782 let start = entry.resource_index;
1783 let end = start + entry.count;
1784 let local_image_infos;
1785 (image_infos, local_image_infos) =
1786 image_infos.extend(desc.textures[start as usize..end as usize].iter().map(
1787 |binding| {
1788 let layout =
1789 conv::derive_image_layout(binding.usage, binding.view.format);
1790 vk::DescriptorImageInfo::default()
1791 .image_view(binding.view.raw)
1792 .image_layout(layout)
1793 },
1794 ));
1795 write.image_info(local_image_infos)
1796 }
1797 vk::DescriptorType::UNIFORM_BUFFER
1798 | vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC
1799 | vk::DescriptorType::STORAGE_BUFFER
1800 | vk::DescriptorType::STORAGE_BUFFER_DYNAMIC => {
1801 let start = entry.resource_index;
1802 let end = start + entry.count;
1803 let local_buffer_infos;
1804 (buffer_infos, local_buffer_infos) =
1805 buffer_infos.extend(desc.buffers[start as usize..end as usize].iter().map(
1806 |binding| {
1807 vk::DescriptorBufferInfo::default()
1808 .buffer(binding.buffer.raw)
1809 .offset(binding.offset)
1810 .range(
1811 binding.size.map_or(vk::WHOLE_SIZE, wgt::BufferSize::get),
1812 )
1813 },
1814 ));
1815 write.buffer_info(local_buffer_infos)
1816 }
1817 vk::DescriptorType::ACCELERATION_STRUCTURE_KHR => {
1818 let start = entry.resource_index;
1819 let end = start + entry.count;
1820
1821 let local_raw_acceleration_structures;
1822 (
1823 raw_acceleration_structures,
1824 local_raw_acceleration_structures,
1825 ) = raw_acceleration_structures.extend(
1826 desc.acceleration_structures[start as usize..end as usize]
1827 .iter()
1828 .map(|acceleration_structure| acceleration_structure.raw),
1829 );
1830
1831 let local_acceleration_structure_infos;
1832 (
1833 acceleration_structure_infos,
1834 local_acceleration_structure_infos,
1835 ) = acceleration_structure_infos.extend_one(
1836 vk::WriteDescriptorSetAccelerationStructureKHR::default()
1837 .acceleration_structures(local_raw_acceleration_structures),
1838 );
1839
1840 write
1841 .descriptor_count(entry.count)
1842 .push_next(local_acceleration_structure_infos)
1843 }
1844 _ => unreachable!(),
1845 };
1846
1847 writes.push(write);
1848 }
1849
1850 unsafe { self.shared.raw.update_descriptor_sets(&writes, &[]) };
1851
1852 self.counters.bind_groups.add(1);
1853
1854 Ok(super::BindGroup { set })
1855 }
1856
1857 unsafe fn destroy_bind_group(&self, group: super::BindGroup) {
1858 unsafe {
1859 self.desc_allocator
1860 .lock()
1861 .free(&*self.shared, Some(group.set))
1862 };
1863
1864 self.counters.bind_groups.sub(1);
1865 }
1866
1867 unsafe fn create_shader_module(
1868 &self,
1869 desc: &crate::ShaderModuleDescriptor,
1870 shader: crate::ShaderInput,
1871 ) -> Result<super::ShaderModule, crate::ShaderError> {
1872 let spv = match shader {
1873 crate::ShaderInput::Naga(naga_shader) => {
1874 if self
1875 .shared
1876 .workarounds
1877 .contains(super::Workarounds::SEPARATE_ENTRY_POINTS)
1878 || !naga_shader.module.overrides.is_empty()
1879 {
1880 return Ok(super::ShaderModule::Intermediate {
1881 naga_shader,
1882 runtime_checks: desc.runtime_checks,
1883 });
1884 }
1885 let mut naga_options = self.naga_options.clone();
1886 naga_options.debug_info =
1887 naga_shader
1888 .debug_source
1889 .as_ref()
1890 .map(|d| naga::back::spv::DebugInfo {
1891 source_code: d.source_code.as_ref(),
1892 file_name: d.file_name.as_ref().into(),
1893 language: naga::back::spv::SourceLanguage::WGSL,
1894 });
1895 if !desc.runtime_checks.bounds_checks {
1896 naga_options.bounds_check_policies = naga::proc::BoundsCheckPolicies {
1897 index: naga::proc::BoundsCheckPolicy::Unchecked,
1898 buffer: naga::proc::BoundsCheckPolicy::Unchecked,
1899 image_load: naga::proc::BoundsCheckPolicy::Unchecked,
1900 binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
1901 };
1902 }
1903 Cow::Owned(
1904 naga::back::spv::write_vec(
1905 &naga_shader.module,
1906 &naga_shader.info,
1907 &naga_options,
1908 None,
1909 )
1910 .map_err(|e| crate::ShaderError::Compilation(format!("{e}")))?,
1911 )
1912 }
1913 crate::ShaderInput::Msl { .. } => {
1914 panic!("MSL_SHADER_PASSTHROUGH is not enabled for this backend")
1915 }
1916 crate::ShaderInput::Dxil { .. } | crate::ShaderInput::Hlsl { .. } => {
1917 panic!("`Features::HLSL_DXIL_SHADER_PASSTHROUGH` is not enabled")
1918 }
1919 crate::ShaderInput::SpirV(spv) => Cow::Borrowed(spv),
1920 };
1921
1922 let raw = self.create_shader_module_impl(&spv)?;
1923
1924 if let Some(label) = desc.label {
1925 unsafe { self.shared.set_object_name(raw, label) };
1926 }
1927
1928 self.counters.shader_modules.add(1);
1929
1930 Ok(super::ShaderModule::Raw(raw))
1931 }
1932
1933 unsafe fn destroy_shader_module(&self, module: super::ShaderModule) {
1934 match module {
1935 super::ShaderModule::Raw(raw) => {
1936 unsafe { self.shared.raw.destroy_shader_module(raw, None) };
1937 }
1938 super::ShaderModule::Intermediate { .. } => {}
1939 }
1940
1941 self.counters.shader_modules.sub(1);
1942 }
1943
1944 unsafe fn create_render_pipeline(
1945 &self,
1946 desc: &crate::RenderPipelineDescriptor<
1947 super::PipelineLayout,
1948 super::ShaderModule,
1949 super::PipelineCache,
1950 >,
1951 ) -> Result<super::RenderPipeline, crate::PipelineError> {
1952 let dynamic_states = [
1953 vk::DynamicState::VIEWPORT,
1954 vk::DynamicState::SCISSOR,
1955 vk::DynamicState::BLEND_CONSTANTS,
1956 vk::DynamicState::STENCIL_REFERENCE,
1957 ];
1958 let mut compatible_rp_key = super::RenderPassKey {
1959 sample_count: desc.multisample.count,
1960 multiview: desc.multiview,
1961 ..Default::default()
1962 };
1963 let mut stages = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new();
1964 let mut vertex_buffers = Vec::with_capacity(desc.vertex_buffers.len());
1965 let mut vertex_attributes = Vec::new();
1966
1967 for (i, vb) in desc.vertex_buffers.iter().enumerate() {
1968 vertex_buffers.push(vk::VertexInputBindingDescription {
1969 binding: i as u32,
1970 stride: vb.array_stride as u32,
1971 input_rate: match vb.step_mode {
1972 wgt::VertexStepMode::Vertex => vk::VertexInputRate::VERTEX,
1973 wgt::VertexStepMode::Instance => vk::VertexInputRate::INSTANCE,
1974 },
1975 });
1976 for at in vb.attributes {
1977 vertex_attributes.push(vk::VertexInputAttributeDescription {
1978 location: at.shader_location,
1979 binding: i as u32,
1980 format: conv::map_vertex_format(at.format),
1981 offset: at.offset as u32,
1982 });
1983 }
1984 }
1985
1986 let vk_vertex_input = vk::PipelineVertexInputStateCreateInfo::default()
1987 .vertex_binding_descriptions(&vertex_buffers)
1988 .vertex_attribute_descriptions(&vertex_attributes);
1989
1990 let vk_input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
1991 .topology(conv::map_topology(desc.primitive.topology))
1992 .primitive_restart_enable(desc.primitive.strip_index_format.is_some());
1993
1994 let compiled_vs = self.compile_stage(
1995 &desc.vertex_stage,
1996 naga::ShaderStage::Vertex,
1997 &desc.layout.binding_arrays,
1998 )?;
1999 stages.push(compiled_vs.create_info);
2000 let compiled_fs = match desc.fragment_stage {
2001 Some(ref stage) => {
2002 let compiled = self.compile_stage(
2003 stage,
2004 naga::ShaderStage::Fragment,
2005 &desc.layout.binding_arrays,
2006 )?;
2007 stages.push(compiled.create_info);
2008 Some(compiled)
2009 }
2010 None => None,
2011 };
2012
2013 let mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::default()
2014 .polygon_mode(conv::map_polygon_mode(desc.primitive.polygon_mode))
2015 .front_face(conv::map_front_face(desc.primitive.front_face))
2016 .line_width(1.0)
2017 .depth_clamp_enable(desc.primitive.unclipped_depth);
2018 if let Some(face) = desc.primitive.cull_mode {
2019 vk_rasterization = vk_rasterization.cull_mode(conv::map_cull_face(face))
2020 }
2021 let mut vk_rasterization_conservative_state =
2022 vk::PipelineRasterizationConservativeStateCreateInfoEXT::default()
2023 .conservative_rasterization_mode(
2024 vk::ConservativeRasterizationModeEXT::OVERESTIMATE,
2025 );
2026 if desc.primitive.conservative {
2027 vk_rasterization = vk_rasterization.push_next(&mut vk_rasterization_conservative_state);
2028 }
2029
2030 let mut vk_depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default();
2031 if let Some(ref ds) = desc.depth_stencil {
2032 let vk_format = self.shared.private_caps.map_texture_format(ds.format);
2033 let vk_layout = if ds.is_read_only(desc.primitive.cull_mode) {
2034 vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL
2035 } else {
2036 vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL
2037 };
2038 compatible_rp_key.depth_stencil = Some(super::DepthStencilAttachmentKey {
2039 base: super::AttachmentKey::compatible(vk_format, vk_layout),
2040 stencil_ops: crate::AttachmentOps::all(),
2041 });
2042
2043 if ds.is_depth_enabled() {
2044 vk_depth_stencil = vk_depth_stencil
2045 .depth_test_enable(true)
2046 .depth_write_enable(ds.depth_write_enabled)
2047 .depth_compare_op(conv::map_comparison(ds.depth_compare));
2048 }
2049 if ds.stencil.is_enabled() {
2050 let s = &ds.stencil;
2051 let front = conv::map_stencil_face(&s.front, s.read_mask, s.write_mask);
2052 let back = conv::map_stencil_face(&s.back, s.read_mask, s.write_mask);
2053 vk_depth_stencil = vk_depth_stencil
2054 .stencil_test_enable(true)
2055 .front(front)
2056 .back(back);
2057 }
2058
2059 if ds.bias.is_enabled() {
2060 vk_rasterization = vk_rasterization
2061 .depth_bias_enable(true)
2062 .depth_bias_constant_factor(ds.bias.constant as f32)
2063 .depth_bias_clamp(ds.bias.clamp)
2064 .depth_bias_slope_factor(ds.bias.slope_scale);
2065 }
2066 }
2067
2068 let vk_viewport = vk::PipelineViewportStateCreateInfo::default()
2069 .flags(vk::PipelineViewportStateCreateFlags::empty())
2070 .scissor_count(1)
2071 .viewport_count(1);
2072
2073 let vk_sample_mask = [
2074 desc.multisample.mask as u32,
2075 (desc.multisample.mask >> 32) as u32,
2076 ];
2077 let vk_multisample = vk::PipelineMultisampleStateCreateInfo::default()
2078 .rasterization_samples(vk::SampleCountFlags::from_raw(desc.multisample.count))
2079 .alpha_to_coverage_enable(desc.multisample.alpha_to_coverage_enabled)
2080 .sample_mask(&vk_sample_mask);
2081
2082 let mut vk_attachments = Vec::with_capacity(desc.color_targets.len());
2083 for cat in desc.color_targets {
2084 let (key, attarchment) = if let Some(cat) = cat.as_ref() {
2085 let mut vk_attachment = vk::PipelineColorBlendAttachmentState::default()
2086 .color_write_mask(vk::ColorComponentFlags::from_raw(cat.write_mask.bits()));
2087 if let Some(ref blend) = cat.blend {
2088 let (color_op, color_src, color_dst) = conv::map_blend_component(&blend.color);
2089 let (alpha_op, alpha_src, alpha_dst) = conv::map_blend_component(&blend.alpha);
2090 vk_attachment = vk_attachment
2091 .blend_enable(true)
2092 .color_blend_op(color_op)
2093 .src_color_blend_factor(color_src)
2094 .dst_color_blend_factor(color_dst)
2095 .alpha_blend_op(alpha_op)
2096 .src_alpha_blend_factor(alpha_src)
2097 .dst_alpha_blend_factor(alpha_dst);
2098 }
2099
2100 let vk_format = self.shared.private_caps.map_texture_format(cat.format);
2101 (
2102 Some(super::ColorAttachmentKey {
2103 base: super::AttachmentKey::compatible(
2104 vk_format,
2105 vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
2106 ),
2107 resolve: None,
2108 }),
2109 vk_attachment,
2110 )
2111 } else {
2112 (None, vk::PipelineColorBlendAttachmentState::default())
2113 };
2114
2115 compatible_rp_key.colors.push(key);
2116 vk_attachments.push(attarchment);
2117 }
2118
2119 let vk_color_blend =
2120 vk::PipelineColorBlendStateCreateInfo::default().attachments(&vk_attachments);
2121
2122 let vk_dynamic_state =
2123 vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
2124
2125 let raw_pass = self.shared.make_render_pass(compatible_rp_key)?;
2126
2127 let vk_infos = [{
2128 vk::GraphicsPipelineCreateInfo::default()
2129 .layout(desc.layout.raw)
2130 .stages(&stages)
2131 .vertex_input_state(&vk_vertex_input)
2132 .input_assembly_state(&vk_input_assembly)
2133 .rasterization_state(&vk_rasterization)
2134 .viewport_state(&vk_viewport)
2135 .multisample_state(&vk_multisample)
2136 .depth_stencil_state(&vk_depth_stencil)
2137 .color_blend_state(&vk_color_blend)
2138 .dynamic_state(&vk_dynamic_state)
2139 .render_pass(raw_pass)
2140 }];
2141
2142 let pipeline_cache = desc
2143 .cache
2144 .map(|it| it.raw)
2145 .unwrap_or(vk::PipelineCache::null());
2146
2147 let mut raw_vec = {
2148 profiling::scope!("vkCreateGraphicsPipelines");
2149 unsafe {
2150 self.shared
2151 .raw
2152 .create_graphics_pipelines(pipeline_cache, &vk_infos, None)
2153 .map_err(|(_, e)| super::map_pipeline_err(e))
2154 }?
2155 };
2156
2157 let raw = raw_vec.pop().unwrap();
2158 if let Some(label) = desc.label {
2159 unsafe { self.shared.set_object_name(raw, label) };
2160 }
2161
2162 if let Some(raw_module) = compiled_vs.temp_raw_module {
2163 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2164 }
2165 if let Some(CompiledStage {
2166 temp_raw_module: Some(raw_module),
2167 ..
2168 }) = compiled_fs
2169 {
2170 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2171 }
2172
2173 self.counters.render_pipelines.add(1);
2174
2175 Ok(super::RenderPipeline { raw })
2176 }
2177 unsafe fn create_mesh_pipeline(
2178 &self,
2179 desc: &crate::MeshPipelineDescriptor<
2180 <Self::A as crate::Api>::PipelineLayout,
2181 <Self::A as crate::Api>::ShaderModule,
2182 <Self::A as crate::Api>::PipelineCache,
2183 >,
2184 ) -> Result<<Self::A as crate::Api>::RenderPipeline, crate::PipelineError> {
2185 let dynamic_states = [
2186 vk::DynamicState::VIEWPORT,
2187 vk::DynamicState::SCISSOR,
2188 vk::DynamicState::BLEND_CONSTANTS,
2189 vk::DynamicState::STENCIL_REFERENCE,
2190 ];
2191 let mut compatible_rp_key = super::RenderPassKey {
2192 sample_count: desc.multisample.count,
2193 multiview: desc.multiview,
2194 ..Default::default()
2195 };
2196 let mut stages = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new();
2197
2198 let vk_input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
2199 .topology(conv::map_topology(desc.primitive.topology))
2200 .primitive_restart_enable(desc.primitive.strip_index_format.is_some());
2201
2202 let compiled_ts = match desc.task_stage {
2203 Some(ref stage) => {
2204 let mut compiled = self.compile_stage(
2205 stage,
2206 naga::ShaderStage::Task,
2207 &desc.layout.binding_arrays,
2208 )?;
2209 compiled.create_info.stage = vk::ShaderStageFlags::TASK_EXT;
2210 stages.push(compiled.create_info);
2211 Some(compiled)
2212 }
2213 None => None,
2214 };
2215
2216 let mut compiled_ms = self.compile_stage(
2217 &desc.mesh_stage,
2218 naga::ShaderStage::Mesh,
2219 &desc.layout.binding_arrays,
2220 )?;
2221 compiled_ms.create_info.stage = vk::ShaderStageFlags::MESH_EXT;
2222 stages.push(compiled_ms.create_info);
2223 let compiled_fs = match desc.fragment_stage {
2224 Some(ref stage) => {
2225 let compiled = self.compile_stage(
2226 stage,
2227 naga::ShaderStage::Fragment,
2228 &desc.layout.binding_arrays,
2229 )?;
2230 stages.push(compiled.create_info);
2231 Some(compiled)
2232 }
2233 None => None,
2234 };
2235
2236 let mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::default()
2237 .polygon_mode(conv::map_polygon_mode(desc.primitive.polygon_mode))
2238 .front_face(conv::map_front_face(desc.primitive.front_face))
2239 .line_width(1.0)
2240 .depth_clamp_enable(desc.primitive.unclipped_depth);
2241 if let Some(face) = desc.primitive.cull_mode {
2242 vk_rasterization = vk_rasterization.cull_mode(conv::map_cull_face(face))
2243 }
2244 let mut vk_rasterization_conservative_state =
2245 vk::PipelineRasterizationConservativeStateCreateInfoEXT::default()
2246 .conservative_rasterization_mode(
2247 vk::ConservativeRasterizationModeEXT::OVERESTIMATE,
2248 );
2249 if desc.primitive.conservative {
2250 vk_rasterization = vk_rasterization.push_next(&mut vk_rasterization_conservative_state);
2251 }
2252
2253 let mut vk_depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default();
2254 if let Some(ref ds) = desc.depth_stencil {
2255 let vk_format = self.shared.private_caps.map_texture_format(ds.format);
2256 let vk_layout = if ds.is_read_only(desc.primitive.cull_mode) {
2257 vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL
2258 } else {
2259 vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL
2260 };
2261 compatible_rp_key.depth_stencil = Some(super::DepthStencilAttachmentKey {
2262 base: super::AttachmentKey::compatible(vk_format, vk_layout),
2263 stencil_ops: crate::AttachmentOps::all(),
2264 });
2265
2266 if ds.is_depth_enabled() {
2267 vk_depth_stencil = vk_depth_stencil
2268 .depth_test_enable(true)
2269 .depth_write_enable(ds.depth_write_enabled)
2270 .depth_compare_op(conv::map_comparison(ds.depth_compare));
2271 }
2272 if ds.stencil.is_enabled() {
2273 let s = &ds.stencil;
2274 let front = conv::map_stencil_face(&s.front, s.read_mask, s.write_mask);
2275 let back = conv::map_stencil_face(&s.back, s.read_mask, s.write_mask);
2276 vk_depth_stencil = vk_depth_stencil
2277 .stencil_test_enable(true)
2278 .front(front)
2279 .back(back);
2280 }
2281
2282 if ds.bias.is_enabled() {
2283 vk_rasterization = vk_rasterization
2284 .depth_bias_enable(true)
2285 .depth_bias_constant_factor(ds.bias.constant as f32)
2286 .depth_bias_clamp(ds.bias.clamp)
2287 .depth_bias_slope_factor(ds.bias.slope_scale);
2288 }
2289 }
2290
2291 let vk_viewport = vk::PipelineViewportStateCreateInfo::default()
2292 .flags(vk::PipelineViewportStateCreateFlags::empty())
2293 .scissor_count(1)
2294 .viewport_count(1);
2295
2296 let vk_sample_mask = [
2297 desc.multisample.mask as u32,
2298 (desc.multisample.mask >> 32) as u32,
2299 ];
2300 let vk_multisample = vk::PipelineMultisampleStateCreateInfo::default()
2301 .rasterization_samples(vk::SampleCountFlags::from_raw(desc.multisample.count))
2302 .alpha_to_coverage_enable(desc.multisample.alpha_to_coverage_enabled)
2303 .sample_mask(&vk_sample_mask);
2304
2305 let mut vk_attachments = Vec::with_capacity(desc.color_targets.len());
2306 for cat in desc.color_targets {
2307 let (key, attarchment) = if let Some(cat) = cat.as_ref() {
2308 let mut vk_attachment = vk::PipelineColorBlendAttachmentState::default()
2309 .color_write_mask(vk::ColorComponentFlags::from_raw(cat.write_mask.bits()));
2310 if let Some(ref blend) = cat.blend {
2311 let (color_op, color_src, color_dst) = conv::map_blend_component(&blend.color);
2312 let (alpha_op, alpha_src, alpha_dst) = conv::map_blend_component(&blend.alpha);
2313 vk_attachment = vk_attachment
2314 .blend_enable(true)
2315 .color_blend_op(color_op)
2316 .src_color_blend_factor(color_src)
2317 .dst_color_blend_factor(color_dst)
2318 .alpha_blend_op(alpha_op)
2319 .src_alpha_blend_factor(alpha_src)
2320 .dst_alpha_blend_factor(alpha_dst);
2321 }
2322
2323 let vk_format = self.shared.private_caps.map_texture_format(cat.format);
2324 (
2325 Some(super::ColorAttachmentKey {
2326 base: super::AttachmentKey::compatible(
2327 vk_format,
2328 vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
2329 ),
2330 resolve: None,
2331 }),
2332 vk_attachment,
2333 )
2334 } else {
2335 (None, vk::PipelineColorBlendAttachmentState::default())
2336 };
2337
2338 compatible_rp_key.colors.push(key);
2339 vk_attachments.push(attarchment);
2340 }
2341
2342 let vk_color_blend =
2343 vk::PipelineColorBlendStateCreateInfo::default().attachments(&vk_attachments);
2344
2345 let vk_dynamic_state =
2346 vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
2347
2348 let raw_pass = self.shared.make_render_pass(compatible_rp_key)?;
2349
2350 let vk_infos = [{
2351 vk::GraphicsPipelineCreateInfo::default()
2352 .layout(desc.layout.raw)
2353 .stages(&stages)
2354 .input_assembly_state(&vk_input_assembly)
2355 .rasterization_state(&vk_rasterization)
2356 .viewport_state(&vk_viewport)
2357 .multisample_state(&vk_multisample)
2358 .depth_stencil_state(&vk_depth_stencil)
2359 .color_blend_state(&vk_color_blend)
2360 .dynamic_state(&vk_dynamic_state)
2361 .render_pass(raw_pass)
2362 }];
2363
2364 let pipeline_cache = desc
2365 .cache
2366 .map(|it| it.raw)
2367 .unwrap_or(vk::PipelineCache::null());
2368
2369 let mut raw_vec = {
2370 profiling::scope!("vkCreateGraphicsPipelines");
2371 unsafe {
2372 self.shared
2373 .raw
2374 .create_graphics_pipelines(pipeline_cache, &vk_infos, None)
2375 .map_err(|(_, e)| super::map_pipeline_err(e))
2376 }?
2377 };
2378
2379 let raw = raw_vec.pop().unwrap();
2380 if let Some(label) = desc.label {
2381 unsafe { self.shared.set_object_name(raw, label) };
2382 }
2383 if let Some(CompiledStage {
2385 temp_raw_module: Some(raw_module),
2386 ..
2387 }) = compiled_ts
2388 {
2389 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2390 }
2391 if let Some(raw_module) = compiled_ms.temp_raw_module {
2392 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2393 }
2394 if let Some(CompiledStage {
2395 temp_raw_module: Some(raw_module),
2396 ..
2397 }) = compiled_fs
2398 {
2399 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2400 }
2401
2402 self.counters.render_pipelines.add(1);
2403
2404 Ok(super::RenderPipeline { raw })
2405 }
2406
2407 unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) {
2408 unsafe { self.shared.raw.destroy_pipeline(pipeline.raw, None) };
2409
2410 self.counters.render_pipelines.sub(1);
2411 }
2412
2413 unsafe fn create_compute_pipeline(
2414 &self,
2415 desc: &crate::ComputePipelineDescriptor<
2416 super::PipelineLayout,
2417 super::ShaderModule,
2418 super::PipelineCache,
2419 >,
2420 ) -> Result<super::ComputePipeline, crate::PipelineError> {
2421 let compiled = self.compile_stage(
2422 &desc.stage,
2423 naga::ShaderStage::Compute,
2424 &desc.layout.binding_arrays,
2425 )?;
2426
2427 let vk_infos = [{
2428 vk::ComputePipelineCreateInfo::default()
2429 .layout(desc.layout.raw)
2430 .stage(compiled.create_info)
2431 }];
2432
2433 let pipeline_cache = desc
2434 .cache
2435 .map(|it| it.raw)
2436 .unwrap_or(vk::PipelineCache::null());
2437
2438 let mut raw_vec = {
2439 profiling::scope!("vkCreateComputePipelines");
2440 unsafe {
2441 self.shared
2442 .raw
2443 .create_compute_pipelines(pipeline_cache, &vk_infos, None)
2444 .map_err(|(_, e)| super::map_pipeline_err(e))
2445 }?
2446 };
2447
2448 let raw = raw_vec.pop().unwrap();
2449 if let Some(label) = desc.label {
2450 unsafe { self.shared.set_object_name(raw, label) };
2451 }
2452
2453 if let Some(raw_module) = compiled.temp_raw_module {
2454 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2455 }
2456
2457 self.counters.compute_pipelines.add(1);
2458
2459 Ok(super::ComputePipeline { raw })
2460 }
2461
2462 unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) {
2463 unsafe { self.shared.raw.destroy_pipeline(pipeline.raw, None) };
2464
2465 self.counters.compute_pipelines.sub(1);
2466 }
2467
2468 unsafe fn create_pipeline_cache(
2469 &self,
2470 desc: &crate::PipelineCacheDescriptor<'_>,
2471 ) -> Result<super::PipelineCache, crate::PipelineCacheError> {
2472 let mut info = vk::PipelineCacheCreateInfo::default();
2473 if let Some(data) = desc.data {
2474 info = info.initial_data(data)
2475 }
2476 profiling::scope!("vkCreatePipelineCache");
2477 let raw = unsafe { self.shared.raw.create_pipeline_cache(&info, None) }
2478 .map_err(super::map_host_device_oom_err)?;
2479
2480 Ok(super::PipelineCache { raw })
2481 }
2482 fn pipeline_cache_validation_key(&self) -> Option<[u8; 16]> {
2483 Some(self.shared.pipeline_cache_validation_key)
2484 }
2485 unsafe fn destroy_pipeline_cache(&self, cache: super::PipelineCache) {
2486 unsafe { self.shared.raw.destroy_pipeline_cache(cache.raw, None) }
2487 }
2488 unsafe fn create_query_set(
2489 &self,
2490 desc: &wgt::QuerySetDescriptor<crate::Label>,
2491 ) -> Result<super::QuerySet, crate::DeviceError> {
2492 self.error_if_would_oom_on_resource_allocation(true, desc.count as u64 * 256)?;
2495
2496 let (vk_type, pipeline_statistics) = match desc.ty {
2497 wgt::QueryType::Occlusion => (
2498 vk::QueryType::OCCLUSION,
2499 vk::QueryPipelineStatisticFlags::empty(),
2500 ),
2501 wgt::QueryType::PipelineStatistics(statistics) => (
2502 vk::QueryType::PIPELINE_STATISTICS,
2503 conv::map_pipeline_statistics(statistics),
2504 ),
2505 wgt::QueryType::Timestamp => (
2506 vk::QueryType::TIMESTAMP,
2507 vk::QueryPipelineStatisticFlags::empty(),
2508 ),
2509 };
2510
2511 let vk_info = vk::QueryPoolCreateInfo::default()
2512 .query_type(vk_type)
2513 .query_count(desc.count)
2514 .pipeline_statistics(pipeline_statistics);
2515
2516 let raw = unsafe { self.shared.raw.create_query_pool(&vk_info, None) }
2517 .map_err(super::map_host_device_oom_err)?;
2518 if let Some(label) = desc.label {
2519 unsafe { self.shared.set_object_name(raw, label) };
2520 }
2521
2522 self.counters.query_sets.add(1);
2523
2524 Ok(super::QuerySet { raw })
2525 }
2526
2527 unsafe fn destroy_query_set(&self, set: super::QuerySet) {
2528 unsafe { self.shared.raw.destroy_query_pool(set.raw, None) };
2529
2530 self.counters.query_sets.sub(1);
2531 }
2532
2533 unsafe fn create_fence(&self) -> Result<super::Fence, crate::DeviceError> {
2534 self.counters.fences.add(1);
2535
2536 Ok(if self.shared.private_caps.timeline_semaphores {
2537 let mut sem_type_info =
2538 vk::SemaphoreTypeCreateInfo::default().semaphore_type(vk::SemaphoreType::TIMELINE);
2539 let vk_info = vk::SemaphoreCreateInfo::default().push_next(&mut sem_type_info);
2540 let raw = unsafe { self.shared.raw.create_semaphore(&vk_info, None) }
2541 .map_err(super::map_host_device_oom_err)?;
2542
2543 super::Fence::TimelineSemaphore(raw)
2544 } else {
2545 super::Fence::FencePool {
2546 last_completed: 0,
2547 active: Vec::new(),
2548 free: Vec::new(),
2549 }
2550 })
2551 }
2552 unsafe fn destroy_fence(&self, fence: super::Fence) {
2553 match fence {
2554 super::Fence::TimelineSemaphore(raw) => {
2555 unsafe { self.shared.raw.destroy_semaphore(raw, None) };
2556 }
2557 super::Fence::FencePool {
2558 active,
2559 free,
2560 last_completed: _,
2561 } => {
2562 for (_, raw) in active {
2563 unsafe { self.shared.raw.destroy_fence(raw, None) };
2564 }
2565 for raw in free {
2566 unsafe { self.shared.raw.destroy_fence(raw, None) };
2567 }
2568 }
2569 }
2570
2571 self.counters.fences.sub(1);
2572 }
2573 unsafe fn get_fence_value(
2574 &self,
2575 fence: &super::Fence,
2576 ) -> Result<crate::FenceValue, crate::DeviceError> {
2577 fence.get_latest(
2578 &self.shared.raw,
2579 self.shared.extension_fns.timeline_semaphore.as_ref(),
2580 )
2581 }
2582 unsafe fn wait(
2583 &self,
2584 fence: &super::Fence,
2585 wait_value: crate::FenceValue,
2586 timeout_ms: u32,
2587 ) -> Result<bool, crate::DeviceError> {
2588 let timeout_ns = timeout_ms as u64 * super::MILLIS_TO_NANOS;
2589 self.shared.wait_for_fence(fence, wait_value, timeout_ns)
2590 }
2591
2592 unsafe fn start_graphics_debugger_capture(&self) -> bool {
2593 #[cfg(feature = "renderdoc")]
2594 {
2595 let raw_vk_instance =
2597 vk::Handle::as_raw(self.shared.instance.raw.handle()) as *mut *mut _;
2598 let raw_vk_instance_dispatch_table = unsafe { *raw_vk_instance };
2599 unsafe {
2600 self.render_doc
2601 .start_frame_capture(raw_vk_instance_dispatch_table, ptr::null_mut())
2602 }
2603 }
2604 #[cfg(not(feature = "renderdoc"))]
2605 false
2606 }
2607 unsafe fn stop_graphics_debugger_capture(&self) {
2608 #[cfg(feature = "renderdoc")]
2609 {
2610 let raw_vk_instance =
2612 vk::Handle::as_raw(self.shared.instance.raw.handle()) as *mut *mut _;
2613 let raw_vk_instance_dispatch_table = unsafe { *raw_vk_instance };
2614
2615 unsafe {
2616 self.render_doc
2617 .end_frame_capture(raw_vk_instance_dispatch_table, ptr::null_mut())
2618 }
2619 }
2620 }
2621
2622 unsafe fn pipeline_cache_get_data(&self, cache: &super::PipelineCache) -> Option<Vec<u8>> {
2623 let data = unsafe { self.raw_device().get_pipeline_cache_data(cache.raw) };
2624 data.ok()
2625 }
2626
2627 unsafe fn get_acceleration_structure_build_sizes<'a>(
2628 &self,
2629 desc: &crate::GetAccelerationStructureBuildSizesDescriptor<'a, super::Buffer>,
2630 ) -> crate::AccelerationStructureBuildSizes {
2631 const CAPACITY: usize = 8;
2632
2633 let ray_tracing_functions = self
2634 .shared
2635 .extension_fns
2636 .ray_tracing
2637 .as_ref()
2638 .expect("Feature `RAY_TRACING` not enabled");
2639
2640 let (geometries, primitive_counts) = match *desc.entries {
2641 crate::AccelerationStructureEntries::Instances(ref instances) => {
2642 let instance_data = vk::AccelerationStructureGeometryInstancesDataKHR::default();
2643
2644 let geometry = vk::AccelerationStructureGeometryKHR::default()
2645 .geometry_type(vk::GeometryTypeKHR::INSTANCES)
2646 .geometry(vk::AccelerationStructureGeometryDataKHR {
2647 instances: instance_data,
2648 });
2649
2650 (
2651 smallvec::smallvec![geometry],
2652 smallvec::smallvec![instances.count],
2653 )
2654 }
2655 crate::AccelerationStructureEntries::Triangles(ref in_geometries) => {
2656 let mut primitive_counts =
2657 smallvec::SmallVec::<[u32; CAPACITY]>::with_capacity(in_geometries.len());
2658 let mut geometries = smallvec::SmallVec::<
2659 [vk::AccelerationStructureGeometryKHR; CAPACITY],
2660 >::with_capacity(in_geometries.len());
2661
2662 for triangles in in_geometries {
2663 let mut triangle_data =
2664 vk::AccelerationStructureGeometryTrianglesDataKHR::default()
2665 .index_type(vk::IndexType::NONE_KHR)
2666 .vertex_format(conv::map_vertex_format(triangles.vertex_format))
2667 .max_vertex(triangles.vertex_count)
2668 .vertex_stride(triangles.vertex_stride)
2669 .transform_data(vk::DeviceOrHostAddressConstKHR {
2679 device_address: if desc
2680 .flags
2681 .contains(wgt::AccelerationStructureFlags::USE_TRANSFORM)
2682 {
2683 unsafe {
2684 ray_tracing_functions
2685 .buffer_device_address
2686 .get_buffer_device_address(
2687 &vk::BufferDeviceAddressInfo::default().buffer(
2688 triangles
2689 .transform
2690 .as_ref()
2691 .unwrap()
2692 .buffer
2693 .raw,
2694 ),
2695 )
2696 }
2697 } else {
2698 0
2699 },
2700 });
2701
2702 let pritive_count = if let Some(ref indices) = triangles.indices {
2703 triangle_data =
2704 triangle_data.index_type(conv::map_index_format(indices.format));
2705 indices.count / 3
2706 } else {
2707 triangles.vertex_count
2708 };
2709
2710 let geometry = vk::AccelerationStructureGeometryKHR::default()
2711 .geometry_type(vk::GeometryTypeKHR::TRIANGLES)
2712 .geometry(vk::AccelerationStructureGeometryDataKHR {
2713 triangles: triangle_data,
2714 })
2715 .flags(conv::map_acceleration_structure_geometry_flags(
2716 triangles.flags,
2717 ));
2718
2719 geometries.push(geometry);
2720 primitive_counts.push(pritive_count);
2721 }
2722 (geometries, primitive_counts)
2723 }
2724 crate::AccelerationStructureEntries::AABBs(ref in_geometries) => {
2725 let mut primitive_counts =
2726 smallvec::SmallVec::<[u32; CAPACITY]>::with_capacity(in_geometries.len());
2727 let mut geometries = smallvec::SmallVec::<
2728 [vk::AccelerationStructureGeometryKHR; CAPACITY],
2729 >::with_capacity(in_geometries.len());
2730 for aabb in in_geometries {
2731 let aabbs_data = vk::AccelerationStructureGeometryAabbsDataKHR::default()
2732 .stride(aabb.stride);
2733
2734 let geometry = vk::AccelerationStructureGeometryKHR::default()
2735 .geometry_type(vk::GeometryTypeKHR::AABBS)
2736 .geometry(vk::AccelerationStructureGeometryDataKHR { aabbs: aabbs_data })
2737 .flags(conv::map_acceleration_structure_geometry_flags(aabb.flags));
2738
2739 geometries.push(geometry);
2740 primitive_counts.push(aabb.count);
2741 }
2742 (geometries, primitive_counts)
2743 }
2744 };
2745
2746 let ty = match *desc.entries {
2747 crate::AccelerationStructureEntries::Instances(_) => {
2748 vk::AccelerationStructureTypeKHR::TOP_LEVEL
2749 }
2750 _ => vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL,
2751 };
2752
2753 let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::default()
2754 .ty(ty)
2755 .flags(conv::map_acceleration_structure_flags(desc.flags))
2756 .geometries(&geometries);
2757
2758 let mut raw = Default::default();
2759 unsafe {
2760 ray_tracing_functions
2761 .acceleration_structure
2762 .get_acceleration_structure_build_sizes(
2763 vk::AccelerationStructureBuildTypeKHR::DEVICE,
2764 &geometry_info,
2765 &primitive_counts,
2766 &mut raw,
2767 )
2768 }
2769
2770 crate::AccelerationStructureBuildSizes {
2771 acceleration_structure_size: raw.acceleration_structure_size,
2772 update_scratch_size: raw.update_scratch_size,
2773 build_scratch_size: raw.build_scratch_size,
2774 }
2775 }
2776
2777 unsafe fn get_acceleration_structure_device_address(
2778 &self,
2779 acceleration_structure: &super::AccelerationStructure,
2780 ) -> wgt::BufferAddress {
2781 let ray_tracing_functions = self
2782 .shared
2783 .extension_fns
2784 .ray_tracing
2785 .as_ref()
2786 .expect("Feature `RAY_TRACING` not enabled");
2787
2788 unsafe {
2789 ray_tracing_functions
2790 .acceleration_structure
2791 .get_acceleration_structure_device_address(
2792 &vk::AccelerationStructureDeviceAddressInfoKHR::default()
2793 .acceleration_structure(acceleration_structure.raw),
2794 )
2795 }
2796 }
2797
2798 unsafe fn create_acceleration_structure(
2799 &self,
2800 desc: &crate::AccelerationStructureDescriptor,
2801 ) -> Result<super::AccelerationStructure, crate::DeviceError> {
2802 let ray_tracing_functions = self
2803 .shared
2804 .extension_fns
2805 .ray_tracing
2806 .as_ref()
2807 .expect("Feature `RAY_TRACING` not enabled");
2808
2809 let vk_buffer_info = vk::BufferCreateInfo::default()
2810 .size(desc.size)
2811 .usage(
2812 vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR
2813 | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS,
2814 )
2815 .sharing_mode(vk::SharingMode::EXCLUSIVE);
2816
2817 unsafe {
2818 let raw_buffer = self
2819 .shared
2820 .raw
2821 .create_buffer(&vk_buffer_info, None)
2822 .map_err(super::map_host_device_oom_and_ioca_err)?;
2823 let req = self.shared.raw.get_buffer_memory_requirements(raw_buffer);
2824
2825 self.error_if_would_oom_on_resource_allocation(false, req.size)
2826 .inspect_err(|_| {
2827 self.shared.raw.destroy_buffer(raw_buffer, None);
2828 })?;
2829
2830 let block = self
2831 .mem_allocator
2832 .lock()
2833 .alloc(
2834 &*self.shared,
2835 gpu_alloc::Request {
2836 size: req.size,
2837 align_mask: req.alignment - 1,
2838 usage: gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS,
2839 memory_types: req.memory_type_bits & self.valid_ash_memory_types,
2840 },
2841 )
2842 .inspect_err(|_| {
2843 self.shared.raw.destroy_buffer(raw_buffer, None);
2844 })?;
2845
2846 self.shared
2847 .raw
2848 .bind_buffer_memory(raw_buffer, *block.memory(), block.offset())
2849 .map_err(super::map_host_device_oom_and_ioca_err)
2850 .inspect_err(|_| {
2851 self.shared.raw.destroy_buffer(raw_buffer, None);
2852 })?;
2853
2854 if let Some(label) = desc.label {
2855 self.shared.set_object_name(raw_buffer, label);
2856 }
2857
2858 let vk_info = vk::AccelerationStructureCreateInfoKHR::default()
2859 .buffer(raw_buffer)
2860 .offset(0)
2861 .size(desc.size)
2862 .ty(conv::map_acceleration_structure_format(desc.format));
2863
2864 let raw_acceleration_structure = ray_tracing_functions
2865 .acceleration_structure
2866 .create_acceleration_structure(&vk_info, None)
2867 .map_err(super::map_host_oom_and_ioca_err)
2868 .inspect_err(|_| {
2869 self.shared.raw.destroy_buffer(raw_buffer, None);
2870 })?;
2871
2872 if let Some(label) = desc.label {
2873 self.shared
2874 .set_object_name(raw_acceleration_structure, label);
2875 }
2876
2877 let pool = if desc.allow_compaction {
2878 let vk_info = vk::QueryPoolCreateInfo::default()
2879 .query_type(vk::QueryType::ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR)
2880 .query_count(1);
2881
2882 let raw = self
2883 .shared
2884 .raw
2885 .create_query_pool(&vk_info, None)
2886 .map_err(super::map_host_device_oom_err)
2887 .inspect_err(|_| {
2888 ray_tracing_functions
2889 .acceleration_structure
2890 .destroy_acceleration_structure(raw_acceleration_structure, None);
2891 self.shared.raw.destroy_buffer(raw_buffer, None);
2892 })?;
2893 Some(raw)
2894 } else {
2895 None
2896 };
2897
2898 Ok(super::AccelerationStructure {
2899 raw: raw_acceleration_structure,
2900 buffer: raw_buffer,
2901 block: Mutex::new(block),
2902 compacted_size_query: pool,
2903 })
2904 }
2905 }
2906
2907 unsafe fn destroy_acceleration_structure(
2908 &self,
2909 acceleration_structure: super::AccelerationStructure,
2910 ) {
2911 let ray_tracing_functions = self
2912 .shared
2913 .extension_fns
2914 .ray_tracing
2915 .as_ref()
2916 .expect("Feature `RAY_TRACING` not enabled");
2917
2918 unsafe {
2919 ray_tracing_functions
2920 .acceleration_structure
2921 .destroy_acceleration_structure(acceleration_structure.raw, None);
2922 self.shared
2923 .raw
2924 .destroy_buffer(acceleration_structure.buffer, None);
2925 self.mem_allocator
2926 .lock()
2927 .dealloc(&*self.shared, acceleration_structure.block.into_inner());
2928 if let Some(query) = acceleration_structure.compacted_size_query {
2929 self.shared.raw.destroy_query_pool(query, None)
2930 }
2931 }
2932 }
2933
2934 fn get_internal_counters(&self) -> wgt::HalCounters {
2935 self.counters
2936 .memory_allocations
2937 .set(self.shared.memory_allocations_counter.read());
2938
2939 self.counters.as_ref().clone()
2940 }
2941
2942 fn tlas_instance_to_bytes(&self, instance: TlasInstance) -> Vec<u8> {
2943 const MAX_U24: u32 = (1u32 << 24u32) - 1u32;
2944 let temp = RawTlasInstance {
2945 transform: instance.transform,
2946 custom_data_and_mask: (instance.custom_data & MAX_U24)
2947 | (u32::from(instance.mask) << 24),
2948 shader_binding_table_record_offset_and_flags: 0,
2949 acceleration_structure_reference: instance.blas_address,
2950 };
2951 bytemuck::bytes_of(&temp).to_vec()
2952 }
2953
2954 fn check_if_oom(&self) -> Result<(), crate::DeviceError> {
2955 let Some(threshold) = self
2956 .shared
2957 .instance
2958 .memory_budget_thresholds
2959 .for_device_loss
2960 else {
2961 return Ok(());
2962 };
2963
2964 if !self
2965 .shared
2966 .enabled_extensions
2967 .contains(&ext::memory_budget::NAME)
2968 {
2969 return Ok(());
2970 }
2971
2972 let get_physical_device_properties = self
2973 .shared
2974 .instance
2975 .get_physical_device_properties
2976 .as_ref()
2977 .unwrap();
2978
2979 let mut memory_budget_properties = vk::PhysicalDeviceMemoryBudgetPropertiesEXT::default();
2980
2981 let mut memory_properties =
2982 vk::PhysicalDeviceMemoryProperties2::default().push_next(&mut memory_budget_properties);
2983
2984 unsafe {
2985 get_physical_device_properties.get_physical_device_memory_properties2(
2986 self.shared.physical_device,
2987 &mut memory_properties,
2988 );
2989 }
2990
2991 let memory_properties = memory_properties.memory_properties;
2992
2993 for i in 0..memory_properties.memory_heap_count {
2994 let heap_usage = memory_budget_properties.heap_usage[i as usize];
2995 let heap_budget = memory_budget_properties.heap_budget[i as usize];
2996
2997 if heap_usage >= heap_budget / 100 * threshold as u64 {
2998 return Err(crate::DeviceError::OutOfMemory);
2999 }
3000 }
3001
3002 Ok(())
3003 }
3004}
3005
3006impl super::DeviceShared {
3007 pub(super) fn new_binary_semaphore(&self) -> Result<vk::Semaphore, crate::DeviceError> {
3008 unsafe {
3009 self.raw
3010 .create_semaphore(&vk::SemaphoreCreateInfo::default(), None)
3011 .map_err(super::map_host_device_oom_err)
3012 }
3013 }
3014
3015 pub(super) fn wait_for_fence(
3016 &self,
3017 fence: &super::Fence,
3018 wait_value: crate::FenceValue,
3019 timeout_ns: u64,
3020 ) -> Result<bool, crate::DeviceError> {
3021 profiling::scope!("Device::wait");
3022 match *fence {
3023 super::Fence::TimelineSemaphore(raw) => {
3024 let semaphores = [raw];
3025 let values = [wait_value];
3026 let vk_info = vk::SemaphoreWaitInfo::default()
3027 .semaphores(&semaphores)
3028 .values(&values);
3029 let result = match self.extension_fns.timeline_semaphore {
3030 Some(super::ExtensionFn::Extension(ref ext)) => unsafe {
3031 ext.wait_semaphores(&vk_info, timeout_ns)
3032 },
3033 Some(super::ExtensionFn::Promoted) => unsafe {
3034 self.raw.wait_semaphores(&vk_info, timeout_ns)
3035 },
3036 None => unreachable!(),
3037 };
3038 match result {
3039 Ok(()) => Ok(true),
3040 Err(vk::Result::TIMEOUT) => Ok(false),
3041 Err(other) => Err(super::map_host_device_oom_and_lost_err(other)),
3042 }
3043 }
3044 super::Fence::FencePool {
3045 last_completed,
3046 ref active,
3047 free: _,
3048 } => {
3049 if wait_value <= last_completed {
3050 Ok(true)
3051 } else {
3052 match active.iter().find(|&&(value, _)| value >= wait_value) {
3053 Some(&(_, raw)) => {
3054 match unsafe { self.raw.wait_for_fences(&[raw], true, timeout_ns) } {
3055 Ok(()) => Ok(true),
3056 Err(vk::Result::TIMEOUT) => Ok(false),
3057 Err(other) => Err(super::map_host_device_oom_and_lost_err(other)),
3058 }
3059 }
3060 None => {
3061 crate::hal_usage_error(format!(
3062 "no signals reached value {wait_value}"
3063 ));
3064 }
3065 }
3066 }
3067 }
3068 }
3069 }
3070}
3071
3072impl From<gpu_alloc::AllocationError> for crate::DeviceError {
3073 fn from(error: gpu_alloc::AllocationError) -> Self {
3074 use gpu_alloc::AllocationError as Ae;
3075 match error {
3076 Ae::OutOfDeviceMemory | Ae::OutOfHostMemory | Ae::TooManyObjects => Self::OutOfMemory,
3077 Ae::NoCompatibleMemoryTypes => crate::hal_usage_error(error),
3078 }
3079 }
3080}
3081impl From<gpu_alloc::MapError> for crate::DeviceError {
3082 fn from(error: gpu_alloc::MapError) -> Self {
3083 use gpu_alloc::MapError as Me;
3084 match error {
3085 Me::OutOfDeviceMemory | Me::OutOfHostMemory | Me::MapFailed => Self::OutOfMemory,
3086 Me::NonHostVisible | Me::AlreadyMapped => crate::hal_usage_error(error),
3087 }
3088 }
3089}
3090impl From<gpu_descriptor::AllocationError> for crate::DeviceError {
3091 fn from(error: gpu_descriptor::AllocationError) -> Self {
3092 use gpu_descriptor::AllocationError as Ae;
3093 match error {
3094 Ae::OutOfDeviceMemory | Ae::OutOfHostMemory | Ae::Fragmentation => Self::OutOfMemory,
3095 }
3096 }
3097}
3098
3099fn handle_unexpected(err: vk::Result) -> ! {
3106 panic!("Unexpected Vulkan error: `{err}`")
3107}
3108
3109struct ImageWithoutMemory {
3110 raw: vk::Image,
3111 requirements: vk::MemoryRequirements,
3112 copy_size: crate::CopyExtent,
3113}