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