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