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