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