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