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 pool_trim: Default::default(),
1435 })
1436 }
1437
1438 unsafe fn create_bind_group_layout(
1439 &self,
1440 desc: &crate::BindGroupLayoutDescriptor,
1441 ) -> Result<super::BindGroupLayout, crate::DeviceError> {
1442 let mut vk_bindings = Vec::new();
1447 let mut binding_flags = Vec::new();
1448 let mut binding_map = Vec::new();
1449 let mut next_binding = 0;
1450 let mut contains_binding_arrays = false;
1451 let mut desc_count = DescriptorCounts::default();
1452 for entry in desc.entries {
1453 if entry.count.is_some() {
1454 contains_binding_arrays = true;
1455 }
1456 if matches!(
1457 entry.ty,
1458 wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. }
1459 ) && !(wgt::ShaderStages::FRAGMENT | wgt::ShaderStages::COMPUTE)
1460 .contains(entry.visibility)
1461 {
1462 self.shared
1463 .texture_reads_before_fragment
1464 .store(true, core::sync::atomic::Ordering::Release);
1465 }
1466
1467 let partially_bound = desc
1468 .flags
1469 .contains(crate::BindGroupLayoutFlags::PARTIALLY_BOUND);
1470 let mut flags = vk::DescriptorBindingFlags::empty();
1471 if partially_bound && entry.count.is_some() {
1472 flags |= vk::DescriptorBindingFlags::PARTIALLY_BOUND;
1473 }
1474 if entry.count.is_some() {
1475 flags |= vk::DescriptorBindingFlags::UPDATE_AFTER_BIND;
1476 }
1477
1478 let count = entry.count.map_or(1, |c| c.get());
1479 match entry.ty {
1480 wgt::BindingType::ExternalTexture => unimplemented!(),
1481 _ => {
1482 vk_bindings.push(vk::DescriptorSetLayoutBinding {
1483 binding: next_binding,
1484 descriptor_type: conv::map_binding_type(entry.ty),
1485 descriptor_count: count,
1486 stage_flags: conv::map_shader_stage(entry.visibility),
1487 p_immutable_samplers: ptr::null(),
1488 _marker: Default::default(),
1489 });
1490 binding_flags.push(flags);
1491 binding_map.push((
1492 entry.binding,
1493 super::BindingInfo {
1494 binding: next_binding,
1495 binding_array_size: entry.count,
1496 },
1497 ));
1498 next_binding += 1;
1499 }
1500 }
1501
1502 match entry.ty {
1503 wgt::BindingType::Buffer {
1504 ty,
1505 has_dynamic_offset,
1506 ..
1507 } => match ty {
1508 wgt::BufferBindingType::Uniform => {
1509 if has_dynamic_offset {
1510 desc_count.uniform_buffer_dynamic += count;
1511 } else {
1512 desc_count.uniform_buffer += count;
1513 }
1514 }
1515 wgt::BufferBindingType::Storage { .. } => {
1516 if has_dynamic_offset {
1517 desc_count.storage_buffer_dynamic += count;
1518 } else {
1519 desc_count.storage_buffer += count;
1520 }
1521 }
1522 },
1523 wgt::BindingType::Sampler { .. } => {
1524 desc_count.sampler += count;
1525 }
1526 wgt::BindingType::Texture { .. } => {
1527 desc_count.sampled_image += count;
1528 }
1529 wgt::BindingType::StorageTexture { .. } => {
1530 desc_count.storage_image += count;
1531 }
1532 wgt::BindingType::AccelerationStructure { .. } => {
1533 desc_count.acceleration_structure += count;
1534 }
1535 wgt::BindingType::ExternalTexture => unimplemented!(),
1536 }
1537 }
1538
1539 let vk_info = vk::DescriptorSetLayoutCreateInfo::default()
1540 .bindings(&vk_bindings)
1541 .flags(if contains_binding_arrays {
1542 vk::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL
1543 } else {
1544 vk::DescriptorSetLayoutCreateFlags::empty()
1545 });
1546
1547 let mut binding_flag_info =
1548 vk::DescriptorSetLayoutBindingFlagsCreateInfo::default().binding_flags(&binding_flags);
1549
1550 let vk_info = vk_info.push_next(&mut binding_flag_info);
1551
1552 let raw = unsafe {
1553 self.shared
1554 .raw
1555 .create_descriptor_set_layout(&vk_info, None)
1556 .map_err(super::map_host_device_oom_err)?
1557 };
1558
1559 if let Some(label) = desc.label {
1560 unsafe { self.shared.set_object_name(raw, label) };
1561 }
1562
1563 let layout = super::BindGroupLayout {
1564 raw,
1565 desc_count,
1566 entries: desc.entries.into(),
1567 binding_map,
1568 contains_binding_arrays,
1569 };
1570
1571 let result = self
1572 .desc_allocator
1573 .lock()
1574 .register_layout(&self.shared.raw, &layout);
1575 if let Err(err) = result {
1576 unsafe {
1577 self.shared
1578 .raw
1579 .destroy_descriptor_set_layout(layout.raw, None)
1580 };
1581 return Err(err);
1582 }
1583
1584 self.counters.bind_group_layouts.add(1);
1585
1586 Ok(layout)
1587 }
1588 unsafe fn destroy_bind_group_layout(&self, bg_layout: super::BindGroupLayout) {
1589 self.desc_allocator
1590 .lock()
1591 .unregister_layout(&self.shared.raw, &bg_layout);
1592
1593 unsafe {
1594 self.shared
1595 .raw
1596 .destroy_descriptor_set_layout(bg_layout.raw, None)
1597 };
1598
1599 self.counters.bind_group_layouts.sub(1);
1600 }
1601
1602 unsafe fn create_pipeline_layout(
1603 &self,
1604 desc: &crate::PipelineLayoutDescriptor<super::BindGroupLayout>,
1605 ) -> Result<super::PipelineLayout, crate::DeviceError> {
1606 let vk_set_layouts = desc
1608 .bind_group_layouts
1609 .iter()
1610 .map(|bgl| match bgl {
1611 Some(bgl) => bgl.raw,
1612 None => {
1613 self.shared.empty_descriptor_set_layout
1621 }
1622 })
1623 .collect::<Vec<_>>();
1624 let vk_immediates_ranges: Option<vk::PushConstantRange> = if desc.immediate_size != 0 {
1625 Some(vk::PushConstantRange {
1626 stage_flags: vk::ShaderStageFlags::ALL,
1627 offset: 0,
1628 size: desc.immediate_size,
1629 })
1630 } else {
1631 None
1632 };
1633
1634 let vk_info = vk::PipelineLayoutCreateInfo::default()
1635 .flags(vk::PipelineLayoutCreateFlags::empty())
1636 .set_layouts(&vk_set_layouts)
1637 .push_constant_ranges(vk_immediates_ranges.as_slice());
1638
1639 let raw = {
1640 profiling::scope!("vkCreatePipelineLayout");
1641 unsafe {
1642 self.shared
1643 .raw
1644 .create_pipeline_layout(&vk_info, None)
1645 .map_err(super::map_host_device_oom_err)?
1646 }
1647 };
1648
1649 if let Some(label) = desc.label {
1650 unsafe { self.shared.set_object_name(raw, label) };
1651 }
1652
1653 let mut binding_map = BTreeMap::new();
1654 for (group, layout) in desc.bind_group_layouts.iter().enumerate() {
1655 let Some(layout) = layout else {
1656 continue;
1657 };
1658
1659 for &(binding, binding_info) in &layout.binding_map {
1660 binding_map.insert(
1661 naga::ResourceBinding {
1662 group: group as u32,
1663 binding,
1664 },
1665 naga::back::spv::BindingInfo {
1666 descriptor_set: group as u32,
1667 binding: binding_info.binding,
1668 binding_array_size: binding_info.binding_array_size.map(NonZeroU32::get),
1669 },
1670 );
1671 }
1672 }
1673
1674 self.counters.pipeline_layouts.add(1);
1675 Ok(super::PipelineLayout { raw, binding_map })
1676 }
1677 unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {
1678 unsafe {
1679 self.shared
1680 .raw
1681 .destroy_pipeline_layout(pipeline_layout.raw, None)
1682 };
1683
1684 self.counters.pipeline_layouts.sub(1);
1685 }
1686
1687 unsafe fn create_bind_group(
1688 &self,
1689 desc: &crate::BindGroupDescriptor<
1690 super::BindGroupLayout,
1691 super::Buffer,
1692 super::Sampler,
1693 super::TextureView,
1694 super::AccelerationStructure,
1695 >,
1696 ) -> Result<super::BindGroup, crate::DeviceError> {
1697 let set = unsafe {
1698 self.desc_allocator
1699 .lock()
1700 .alloc(&self.shared.raw, desc.layout)?
1701 };
1702
1703 if let Some(label) = desc.label {
1704 unsafe { self.shared.set_object_name(set.raw(), label) };
1705 }
1706
1707 struct ExtendStack<'a, T> {
1714 remainder: &'a mut [MaybeUninit<T>],
1715 }
1716
1717 impl<'a, T> ExtendStack<'a, T> {
1718 fn from_vec_capacity(vec: &'a mut Vec<T>) -> Self {
1719 Self {
1720 remainder: vec.spare_capacity_mut(),
1721 }
1722 }
1723
1724 fn extend_one(self, value: T) -> (Self, &'a mut T) {
1725 let (to_init, remainder) = self.remainder.split_first_mut().unwrap();
1726 let init = to_init.write(value);
1727 (Self { remainder }, init)
1728 }
1729
1730 fn extend(
1731 self,
1732 iter: impl IntoIterator<Item = T> + ExactSizeIterator,
1733 ) -> (Self, &'a mut [T]) {
1734 let (to_init, remainder) = self.remainder.split_at_mut(iter.len());
1735
1736 for (value, to_init) in iter.into_iter().zip(to_init.iter_mut()) {
1737 to_init.write(value);
1738 }
1739
1740 let init = {
1743 unsafe { mem::transmute::<&mut [MaybeUninit<T>], &mut [T]>(to_init) }
1750 };
1751 (Self { remainder }, init)
1752 }
1753 }
1754
1755 let mut writes = Vec::with_capacity(desc.entries.len());
1756 let mut buffer_infos = Vec::with_capacity(desc.buffers.len());
1757 let mut buffer_infos = ExtendStack::from_vec_capacity(&mut buffer_infos);
1758 let mut image_infos = Vec::with_capacity(desc.samplers.len() + desc.textures.len());
1759 let mut image_infos = ExtendStack::from_vec_capacity(&mut image_infos);
1760 let mut acceleration_structure_infos =
1765 Vec::with_capacity(desc.acceleration_structures.len());
1766 let mut acceleration_structure_infos =
1767 ExtendStack::from_vec_capacity(&mut acceleration_structure_infos);
1768 let mut raw_acceleration_structures =
1769 Vec::with_capacity(desc.acceleration_structures.len());
1770 let mut raw_acceleration_structures =
1771 ExtendStack::from_vec_capacity(&mut raw_acceleration_structures);
1772
1773 let layout_and_entry_iter = desc.entries.iter().map(|entry| {
1774 let layout = desc
1775 .layout
1776 .entries
1777 .iter()
1778 .find(|layout_entry| layout_entry.binding == entry.binding)
1779 .expect("internal error: no layout entry found with binding slot");
1780 (layout, entry)
1781 });
1782 let mut next_binding = 0;
1783 for (layout, entry) in layout_and_entry_iter {
1784 let write = vk::WriteDescriptorSet::default().dst_set(set.raw());
1785
1786 match layout.ty {
1787 wgt::BindingType::Sampler(_) => {
1788 let start = entry.resource_index;
1789 let end = start + entry.count;
1790 let local_image_infos;
1791 (image_infos, local_image_infos) =
1792 image_infos.extend(desc.samplers[start as usize..end as usize].iter().map(
1793 |sampler| vk::DescriptorImageInfo::default().sampler(sampler.raw),
1794 ));
1795 writes.push(
1796 write
1797 .dst_binding(next_binding)
1798 .descriptor_type(conv::map_binding_type(layout.ty))
1799 .image_info(local_image_infos),
1800 );
1801 next_binding += 1;
1802 }
1803 wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. } => {
1804 let start = entry.resource_index;
1805 let end = start + entry.count;
1806 let local_image_infos;
1807 (image_infos, local_image_infos) =
1808 image_infos.extend(desc.textures[start as usize..end as usize].iter().map(
1809 |binding| {
1810 let layout =
1811 conv::derive_image_layout(binding.usage, binding.view.format);
1812 vk::DescriptorImageInfo::default()
1813 .image_view(binding.view.raw)
1814 .image_layout(layout)
1815 },
1816 ));
1817 writes.push(
1818 write
1819 .dst_binding(next_binding)
1820 .descriptor_type(conv::map_binding_type(layout.ty))
1821 .image_info(local_image_infos),
1822 );
1823 next_binding += 1;
1824 }
1825 wgt::BindingType::Buffer { .. } => {
1826 let start = entry.resource_index;
1827 let end = start + entry.count;
1828 let local_buffer_infos;
1829 (buffer_infos, local_buffer_infos) =
1830 buffer_infos.extend(desc.buffers[start as usize..end as usize].iter().map(
1831 |binding| {
1832 vk::DescriptorBufferInfo::default()
1833 .buffer(binding.buffer.raw)
1834 .offset(binding.offset)
1835 .range(
1836 binding.size.map_or(vk::WHOLE_SIZE, wgt::BufferSize::get),
1837 )
1838 },
1839 ));
1840 writes.push(
1841 write
1842 .dst_binding(next_binding)
1843 .descriptor_type(conv::map_binding_type(layout.ty))
1844 .buffer_info(local_buffer_infos),
1845 );
1846 next_binding += 1;
1847 }
1848 wgt::BindingType::AccelerationStructure { .. } => {
1849 let start = entry.resource_index;
1850 let end = start + entry.count;
1851
1852 let local_raw_acceleration_structures;
1853 (
1854 raw_acceleration_structures,
1855 local_raw_acceleration_structures,
1856 ) = raw_acceleration_structures.extend(
1857 desc.acceleration_structures[start as usize..end as usize]
1858 .iter()
1859 .map(|acceleration_structure| acceleration_structure.raw),
1860 );
1861
1862 let local_acceleration_structure_infos;
1863 (
1864 acceleration_structure_infos,
1865 local_acceleration_structure_infos,
1866 ) = acceleration_structure_infos.extend_one(
1867 vk::WriteDescriptorSetAccelerationStructureKHR::default()
1868 .acceleration_structures(local_raw_acceleration_structures),
1869 );
1870
1871 writes.push(
1872 write
1873 .dst_binding(next_binding)
1874 .descriptor_type(conv::map_binding_type(layout.ty))
1875 .descriptor_count(entry.count)
1876 .push_next(local_acceleration_structure_infos),
1877 );
1878 next_binding += 1;
1879 }
1880 wgt::BindingType::ExternalTexture => unimplemented!(),
1881 }
1882 }
1883
1884 unsafe { self.shared.raw.update_descriptor_sets(&writes, &[]) };
1885
1886 self.counters.bind_groups.add(1);
1887
1888 Ok(super::BindGroup { set })
1889 }
1890
1891 unsafe fn destroy_bind_group(&self, group: super::BindGroup) {
1892 unsafe { self.desc_allocator.lock().free(&self.shared.raw, group.set) };
1893
1894 self.counters.bind_groups.sub(1);
1895 }
1896
1897 unsafe fn create_shader_module(
1898 &self,
1899 desc: &crate::ShaderModuleDescriptor,
1900 shader: crate::ShaderInput,
1901 ) -> Result<super::ShaderModule, crate::ShaderError> {
1902 let shader_module = match shader {
1903 crate::ShaderInput::Naga(naga_shader)
1904 if self
1905 .shared
1906 .workarounds
1907 .contains(super::Workarounds::SEPARATE_ENTRY_POINTS)
1908 || !naga_shader.module.overrides.is_empty() =>
1909 {
1910 super::ShaderModule::Intermediate {
1911 naga_shader,
1912 runtime_checks: desc.runtime_checks,
1913 }
1914 }
1915 crate::ShaderInput::Naga(naga_shader) => {
1916 let mut naga_options = self.naga_options.clone();
1917 naga_options.debug_info =
1918 naga_shader
1919 .debug_source
1920 .as_ref()
1921 .map(|d| naga::back::spv::DebugInfo {
1922 source_code: d.source_code.as_ref(),
1923 file_name: d.file_name.as_ref(),
1924 language: naga::back::spv::SourceLanguage::WGSL,
1925 });
1926 if !desc.runtime_checks.bounds_checks {
1927 naga_options.bounds_check_policies = naga::proc::BoundsCheckPolicies {
1928 index: naga::proc::BoundsCheckPolicy::Unchecked,
1929 buffer: naga::proc::BoundsCheckPolicy::Unchecked,
1930 image_load: naga::proc::BoundsCheckPolicy::Unchecked,
1931 binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
1932 };
1933 }
1934 let spv = naga::back::spv::write_vec(
1935 &naga_shader.module,
1936 &naga_shader.info,
1937 &naga_options,
1938 None,
1939 )
1940 .map_err(|e| crate::ShaderError::Compilation(format!("{e}")))?;
1941 super::ShaderModule::Raw(self.create_shader_module_impl(&spv, &desc.label)?)
1942 }
1943 crate::ShaderInput::SpirV(data) => {
1944 super::ShaderModule::Raw(self.create_shader_module_impl(data, &desc.label)?)
1945 }
1946 crate::ShaderInput::MetalLib { .. }
1947 | crate::ShaderInput::Msl { .. }
1948 | crate::ShaderInput::Dxil { .. }
1949 | crate::ShaderInput::Hlsl { .. }
1950 | crate::ShaderInput::Glsl { .. }
1951 | crate::ShaderInput::GlslTemplates(_) => unreachable!(),
1952 };
1953
1954 self.counters.shader_modules.add(1);
1955
1956 Ok(shader_module)
1957 }
1958
1959 unsafe fn destroy_shader_module(&self, module: super::ShaderModule) {
1960 match module {
1961 super::ShaderModule::Raw(raw) => {
1962 unsafe { self.shared.raw.destroy_shader_module(raw, None) };
1963 }
1964 super::ShaderModule::Intermediate { .. } => {}
1965 }
1966
1967 self.counters.shader_modules.sub(1);
1968 }
1969
1970 unsafe fn create_render_pipeline(
1971 &self,
1972 desc: &crate::RenderPipelineDescriptor<
1973 super::PipelineLayout,
1974 super::ShaderModule,
1975 super::PipelineCache,
1976 >,
1977 ) -> Result<super::RenderPipeline, crate::PipelineError> {
1978 let dynamic_states = [
1979 vk::DynamicState::VIEWPORT,
1980 vk::DynamicState::SCISSOR,
1981 vk::DynamicState::BLEND_CONSTANTS,
1982 vk::DynamicState::STENCIL_REFERENCE,
1983 ];
1984 let mut compatible_rp_key = super::RenderPassKey {
1985 sample_count: desc.multisample.count,
1986 multiview_mask: desc.multiview_mask,
1987 ..Default::default()
1988 };
1989 let mut stages = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new();
1990 let mut vertex_buffers = Vec::new();
1991 let mut vertex_attributes = Vec::new();
1992
1993 if let crate::VertexProcessor::Standard {
1994 vertex_buffers: desc_vertex_buffers,
1995 vertex_stage: _,
1996 } = &desc.vertex_processor
1997 {
1998 vertex_buffers = Vec::with_capacity(desc_vertex_buffers.len());
1999 for (i, vb) in desc_vertex_buffers.iter().enumerate() {
2000 let Some(vb) = vb else {
2001 continue;
2002 };
2003 vertex_buffers.push(vk::VertexInputBindingDescription {
2004 binding: i as u32,
2005 stride: vb.array_stride as u32,
2006 input_rate: match vb.step_mode {
2007 wgt::VertexStepMode::Vertex => vk::VertexInputRate::VERTEX,
2008 wgt::VertexStepMode::Instance => vk::VertexInputRate::INSTANCE,
2009 },
2010 });
2011 for at in vb.attributes {
2012 vertex_attributes.push(vk::VertexInputAttributeDescription {
2013 location: at.shader_location,
2014 binding: i as u32,
2015 format: conv::map_vertex_format(at.format),
2016 offset: at.offset as u32,
2017 });
2018 }
2019 }
2020 }
2021
2022 let vk_vertex_input = vk::PipelineVertexInputStateCreateInfo::default()
2023 .vertex_binding_descriptions(&vertex_buffers)
2024 .vertex_attribute_descriptions(&vertex_attributes);
2025
2026 let vk_input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
2027 .topology(conv::map_topology(desc.primitive.topology))
2028 .primitive_restart_enable(desc.primitive.strip_index_format.is_some());
2029
2030 let mut compiled_vs = None;
2031 let mut compiled_ms = None;
2032 let mut compiled_ts = None;
2033 match &desc.vertex_processor {
2034 crate::VertexProcessor::Standard {
2035 vertex_buffers: _,
2036 vertex_stage,
2037 } => {
2038 compiled_vs = Some(self.compile_stage(
2039 vertex_stage,
2040 naga::ShaderStage::Vertex,
2041 &desc.layout.binding_map,
2042 )?);
2043 stages.push(compiled_vs.as_ref().unwrap().create_info);
2044 }
2045 crate::VertexProcessor::Mesh {
2046 task_stage,
2047 mesh_stage,
2048 } => {
2049 if let Some(t) = task_stage.as_ref() {
2050 compiled_ts = Some(self.compile_stage(
2051 t,
2052 naga::ShaderStage::Task,
2053 &desc.layout.binding_map,
2054 )?);
2055 stages.push(compiled_ts.as_ref().unwrap().create_info);
2056 }
2057 compiled_ms = Some(self.compile_stage(
2058 mesh_stage,
2059 naga::ShaderStage::Mesh,
2060 &desc.layout.binding_map,
2061 )?);
2062 stages.push(compiled_ms.as_ref().unwrap().create_info);
2063 }
2064 }
2065 let compiled_fs = match desc.fragment_stage {
2066 Some(ref stage) => {
2067 let compiled = self.compile_stage(
2068 stage,
2069 naga::ShaderStage::Fragment,
2070 &desc.layout.binding_map,
2071 )?;
2072 stages.push(compiled.create_info);
2073 Some(compiled)
2074 }
2075 None => None,
2076 };
2077
2078 let mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::default()
2079 .polygon_mode(conv::map_polygon_mode(desc.primitive.polygon_mode))
2080 .front_face(conv::map_front_face(desc.primitive.front_face))
2081 .line_width(1.0)
2082 .depth_clamp_enable(desc.primitive.unclipped_depth);
2083 if let Some(face) = desc.primitive.cull_mode {
2084 vk_rasterization = vk_rasterization.cull_mode(conv::map_cull_face(face))
2085 }
2086 let mut vk_rasterization_conservative_state =
2087 vk::PipelineRasterizationConservativeStateCreateInfoEXT::default()
2088 .conservative_rasterization_mode(
2089 vk::ConservativeRasterizationModeEXT::OVERESTIMATE,
2090 );
2091 if desc.primitive.conservative {
2092 vk_rasterization = vk_rasterization.push_next(&mut vk_rasterization_conservative_state);
2093 }
2094
2095 let mut vk_depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default();
2096 if let Some(ref ds) = desc.depth_stencil {
2097 let vk_format = self.shared.private_caps.map_texture_format(ds.format);
2098 let vk_layout = if ds.is_read_only(desc.primitive.cull_mode) {
2099 vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL
2100 } else {
2101 vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL
2102 };
2103 compatible_rp_key.depth_stencil = Some(super::DepthStencilAttachmentKey {
2104 base: super::AttachmentKey::compatible(vk_format, vk_layout),
2105 stencil_ops: crate::AttachmentOps::all(),
2106 });
2107
2108 if ds.is_depth_enabled() {
2109 vk_depth_stencil = vk_depth_stencil
2110 .depth_test_enable(true)
2111 .depth_write_enable(ds.depth_write_enabled.unwrap_or_default())
2112 .depth_compare_op(conv::map_comparison(ds.depth_compare.unwrap_or_default()));
2113 }
2114 if ds.stencil.is_enabled() {
2115 let s = &ds.stencil;
2116 let front = conv::map_stencil_face(&s.front, s.read_mask, s.write_mask);
2117 let back = conv::map_stencil_face(&s.back, s.read_mask, s.write_mask);
2118 vk_depth_stencil = vk_depth_stencil
2119 .stencil_test_enable(true)
2120 .front(front)
2121 .back(back);
2122 }
2123
2124 if ds.bias.is_enabled() {
2125 vk_rasterization = vk_rasterization
2126 .depth_bias_enable(true)
2127 .depth_bias_constant_factor(ds.bias.constant as f32)
2128 .depth_bias_clamp(ds.bias.clamp)
2129 .depth_bias_slope_factor(ds.bias.slope_scale);
2130 }
2131 }
2132
2133 let vk_viewport = vk::PipelineViewportStateCreateInfo::default()
2134 .flags(vk::PipelineViewportStateCreateFlags::empty())
2135 .scissor_count(1)
2136 .viewport_count(1);
2137
2138 let vk_sample_mask = [
2139 desc.multisample.mask as u32,
2140 (desc.multisample.mask >> 32) as u32,
2141 ];
2142 let vk_multisample = vk::PipelineMultisampleStateCreateInfo::default()
2143 .rasterization_samples(vk::SampleCountFlags::from_raw(desc.multisample.count))
2144 .alpha_to_coverage_enable(desc.multisample.alpha_to_coverage_enabled)
2145 .sample_mask(&vk_sample_mask);
2146
2147 let mut vk_attachments = Vec::with_capacity(desc.color_targets.len());
2148 for cat in desc.color_targets {
2149 let (key, attarchment) = if let Some(cat) = cat.as_ref() {
2150 let mut vk_attachment = vk::PipelineColorBlendAttachmentState::default()
2151 .color_write_mask(vk::ColorComponentFlags::from_raw(cat.write_mask.bits()));
2152 if let Some(ref blend) = cat.blend {
2153 let (color_op, color_src, color_dst) = conv::map_blend_component(&blend.color);
2154 let (alpha_op, alpha_src, alpha_dst) = conv::map_blend_component(&blend.alpha);
2155 vk_attachment = vk_attachment
2156 .blend_enable(true)
2157 .color_blend_op(color_op)
2158 .src_color_blend_factor(color_src)
2159 .dst_color_blend_factor(color_dst)
2160 .alpha_blend_op(alpha_op)
2161 .src_alpha_blend_factor(alpha_src)
2162 .dst_alpha_blend_factor(alpha_dst);
2163 }
2164
2165 let vk_format = self.shared.private_caps.map_texture_format(cat.format);
2166 (
2167 Some(super::ColorAttachmentKey {
2168 base: super::AttachmentKey::compatible(
2169 vk_format,
2170 vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
2171 ),
2172 resolve: None,
2173 }),
2174 vk_attachment,
2175 )
2176 } else {
2177 (None, vk::PipelineColorBlendAttachmentState::default())
2178 };
2179
2180 compatible_rp_key.colors.push(key);
2181 vk_attachments.push(attarchment);
2182 }
2183
2184 let vk_color_blend =
2185 vk::PipelineColorBlendStateCreateInfo::default().attachments(&vk_attachments);
2186
2187 let vk_dynamic_state =
2188 vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
2189
2190 let raw_pass = self.shared.make_render_pass(compatible_rp_key)?;
2191
2192 let vk_infos = [{
2193 vk::GraphicsPipelineCreateInfo::default()
2194 .layout(desc.layout.raw)
2195 .stages(&stages)
2196 .vertex_input_state(&vk_vertex_input)
2197 .input_assembly_state(&vk_input_assembly)
2198 .rasterization_state(&vk_rasterization)
2199 .viewport_state(&vk_viewport)
2200 .multisample_state(&vk_multisample)
2201 .depth_stencil_state(&vk_depth_stencil)
2202 .color_blend_state(&vk_color_blend)
2203 .dynamic_state(&vk_dynamic_state)
2204 .render_pass(raw_pass)
2205 }];
2206
2207 let pipeline_cache = desc
2208 .cache
2209 .map(|it| it.raw)
2210 .unwrap_or(vk::PipelineCache::null());
2211
2212 let mut raw_vec = {
2213 profiling::scope!("vkCreateGraphicsPipelines");
2214 unsafe {
2215 self.shared
2216 .raw
2217 .create_graphics_pipelines(pipeline_cache, &vk_infos, None)
2218 .map_err(|(_, e)| super::map_pipeline_err(e))
2219 }?
2220 };
2221
2222 let raw = raw_vec.pop().unwrap();
2223 if let Some(label) = desc.label {
2224 unsafe { self.shared.set_object_name(raw, label) };
2225 }
2226
2227 if let Some(CompiledStage {
2228 temp_raw_module: Some(raw_module),
2229 ..
2230 }) = compiled_vs
2231 {
2232 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2233 }
2234 if let Some(CompiledStage {
2235 temp_raw_module: Some(raw_module),
2236 ..
2237 }) = compiled_ts
2238 {
2239 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2240 }
2241 if let Some(CompiledStage {
2242 temp_raw_module: Some(raw_module),
2243 ..
2244 }) = compiled_ms
2245 {
2246 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2247 }
2248 if let Some(CompiledStage {
2249 temp_raw_module: Some(raw_module),
2250 ..
2251 }) = compiled_fs
2252 {
2253 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2254 }
2255
2256 self.counters.render_pipelines.add(1);
2257
2258 Ok(super::RenderPipeline {
2259 raw,
2260 is_multiview: desc.multiview_mask.is_some(),
2261 })
2262 }
2263
2264 unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) {
2265 unsafe { self.shared.raw.destroy_pipeline(pipeline.raw, None) };
2266
2267 self.counters.render_pipelines.sub(1);
2268 }
2269
2270 unsafe fn create_compute_pipeline(
2271 &self,
2272 desc: &crate::ComputePipelineDescriptor<
2273 super::PipelineLayout,
2274 super::ShaderModule,
2275 super::PipelineCache,
2276 >,
2277 ) -> Result<super::ComputePipeline, crate::PipelineError> {
2278 let compiled = self.compile_stage(
2279 &desc.stage,
2280 naga::ShaderStage::Compute,
2281 &desc.layout.binding_map,
2282 )?;
2283
2284 let vk_infos = [{
2285 vk::ComputePipelineCreateInfo::default()
2286 .layout(desc.layout.raw)
2287 .stage(compiled.create_info)
2288 }];
2289
2290 let pipeline_cache = desc
2291 .cache
2292 .map(|it| it.raw)
2293 .unwrap_or(vk::PipelineCache::null());
2294
2295 let mut raw_vec = {
2296 profiling::scope!("vkCreateComputePipelines");
2297 unsafe {
2298 self.shared
2299 .raw
2300 .create_compute_pipelines(pipeline_cache, &vk_infos, None)
2301 .map_err(|(_, e)| super::map_pipeline_err(e))
2302 }?
2303 };
2304
2305 let raw = raw_vec.pop().unwrap();
2306 if let Some(label) = desc.label {
2307 unsafe { self.shared.set_object_name(raw, label) };
2308 }
2309
2310 if let Some(raw_module) = compiled.temp_raw_module {
2311 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2312 }
2313
2314 self.counters.compute_pipelines.add(1);
2315
2316 Ok(super::ComputePipeline { raw })
2317 }
2318
2319 unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) {
2320 unsafe { self.shared.raw.destroy_pipeline(pipeline.raw, None) };
2321
2322 self.counters.compute_pipelines.sub(1);
2323 }
2324
2325 unsafe fn create_ray_tracing_pipeline(
2326 &self,
2327 desc: &crate::RayTracingPipelineDescriptor<
2328 super::PipelineLayout,
2329 super::ShaderModule,
2330 super::PipelineCache,
2331 >,
2332 ) -> Result<super::RayTracingPipeline, crate::PipelineError> {
2333 let mut stages = Vec::new();
2334 let mut groups = Vec::new();
2335
2336 let compiled_ray_gen = self.compile_stage(
2337 &desc.ray_generation,
2338 naga::ShaderStage::RayGeneration,
2339 &desc.layout.binding_map,
2340 )?;
2341
2342 groups.push(
2343 vk::RayTracingShaderGroupCreateInfoKHR::default()
2344 .closest_hit_shader(vk::SHADER_UNUSED_KHR)
2345 .any_hit_shader(vk::SHADER_UNUSED_KHR)
2346 .intersection_shader(vk::SHADER_UNUSED_KHR)
2347 .general_shader(0) .ty(vk::RayTracingShaderGroupTypeKHR::GENERAL),
2349 );
2350
2351 stages.push(compiled_ray_gen.create_info);
2352
2353 let compiled_miss = self.compile_stage(
2354 &desc.miss,
2355 naga::ShaderStage::Miss,
2356 &desc.layout.binding_map,
2357 )?;
2358
2359 groups.push(
2360 vk::RayTracingShaderGroupCreateInfoKHR::default()
2361 .closest_hit_shader(vk::SHADER_UNUSED_KHR)
2362 .any_hit_shader(vk::SHADER_UNUSED_KHR)
2363 .intersection_shader(vk::SHADER_UNUSED_KHR)
2364 .general_shader(1) .ty(vk::RayTracingShaderGroupTypeKHR::GENERAL),
2366 );
2367
2368 stages.push(compiled_miss.create_info);
2369
2370 let mut compiled_stages = Vec::new();
2373
2374 for group in desc.intersection {
2375 let compiled_closest_hits = self.compile_stage(
2376 &group.closest_hit,
2377 naga::ShaderStage::ClosestHit,
2378 &desc.layout.binding_map,
2379 )?;
2380
2381 let closest_idx = stages.len();
2382
2383 stages.push(compiled_closest_hits.create_info);
2384
2385 compiled_stages.push(compiled_closest_hits);
2386
2387 let mut raw_hit: vk::RayTracingShaderGroupCreateInfoKHR<'_> =
2388 vk::RayTracingShaderGroupCreateInfoKHR::default()
2389 .closest_hit_shader(closest_idx as _)
2390 .any_hit_shader(vk::SHADER_UNUSED_KHR)
2391 .intersection_shader(vk::SHADER_UNUSED_KHR)
2392 .general_shader(vk::SHADER_UNUSED_KHR)
2393 .ty(vk::RayTracingShaderGroupTypeKHR::TRIANGLES_HIT_GROUP);
2394
2395 if let Some(any_hit) = &group.any_hit {
2396 let compiled_any_hit = self.compile_stage(
2397 any_hit,
2398 naga::ShaderStage::AnyHit,
2399 &desc.layout.binding_map,
2400 )?;
2401
2402 let any_idx = stages.len();
2403
2404 stages.push(compiled_any_hit.create_info);
2405
2406 compiled_stages.push(compiled_any_hit);
2407
2408 raw_hit = raw_hit.any_hit_shader(any_idx as _);
2409 }
2410
2411 groups.push(raw_hit);
2412 }
2413
2414 let create_infos = [{
2415 vk::RayTracingPipelineCreateInfoKHR::default()
2416 .layout(desc.layout.raw)
2417 .max_pipeline_ray_recursion_depth(desc.max_recursion_depth)
2418 .stages(&stages)
2419 .groups(&groups)
2420 }];
2421
2422 let pipeline_cache = desc
2423 .cache
2424 .map(|it| it.raw)
2425 .unwrap_or(vk::PipelineCache::null());
2426
2427 let fns = self
2428 .shared
2429 .extension_fns
2430 .ray_tracing_pipelines
2431 .as_ref()
2432 .unwrap();
2433 let pipelines = unsafe {
2434 fns.create_ray_tracing_pipelines(
2435 vk::DeferredOperationKHR::null(),
2436 pipeline_cache,
2437 &create_infos,
2438 None,
2439 )
2440 .map_err(|(_, e)| super::map_pipeline_err(e))
2441 }?;
2442
2443 if let Some(raw_module) = compiled_ray_gen.temp_raw_module {
2444 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2445 }
2446
2447 if let Some(raw_module) = compiled_miss.temp_raw_module {
2448 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2449 }
2450
2451 for raw_module in compiled_stages
2452 .into_iter()
2453 .flat_map(|stage| stage.temp_raw_module)
2454 {
2455 unsafe { self.shared.raw.destroy_shader_module(raw_module, None) };
2456 }
2457
2458 self.counters.ray_tracing_pipelines.add(1);
2459
2460 Ok(super::RayTracingPipeline { raw: pipelines[0] })
2461 }
2462
2463 unsafe fn destroy_ray_tracing_pipeline(&self, pipeline: super::RayTracingPipeline) {
2464 unsafe { self.shared.raw.destroy_pipeline(pipeline.raw, None) };
2465
2466 self.counters.ray_tracing_pipelines.sub(1);
2467 }
2468
2469 unsafe fn get_raytracing_pipeline_group_data(
2470 &self,
2471 pipeline: &super::RayTracingPipeline,
2472 groups: core::ops::Range<u32>,
2473 ) -> Result<Vec<u8>, crate::DeviceError> {
2474 let fns = self
2475 .shared
2476 .extension_fns
2477 .ray_tracing_pipelines
2478 .as_ref()
2479 .unwrap();
2480
2481 let num = groups.end - groups.start;
2482
2483 unsafe {
2484 fns.get_ray_tracing_shader_group_handles(
2485 pipeline.raw,
2486 groups.start,
2487 num,
2488 (num * self
2489 .shared
2490 .private_caps
2491 .ray_tracing_pipeline_group_data_size) as usize,
2492 )
2493 }
2494 .map_err(super::map_host_device_oom_err)
2495 }
2496
2497 unsafe fn create_pipeline_cache(
2498 &self,
2499 desc: &crate::PipelineCacheDescriptor<'_>,
2500 ) -> Result<super::PipelineCache, crate::PipelineCacheError> {
2501 let mut info = vk::PipelineCacheCreateInfo::default();
2502 if let Some(data) = desc.data {
2503 info = info.initial_data(data)
2504 }
2505 profiling::scope!("vkCreatePipelineCache");
2506 let raw = unsafe { self.shared.raw.create_pipeline_cache(&info, None) }
2507 .map_err(super::map_host_device_oom_err)?;
2508
2509 Ok(super::PipelineCache { raw })
2510 }
2511 fn pipeline_cache_validation_key(&self) -> Option<[u8; 16]> {
2512 Some(self.shared.pipeline_cache_validation_key)
2513 }
2514 unsafe fn destroy_pipeline_cache(&self, cache: super::PipelineCache) {
2515 unsafe { self.shared.raw.destroy_pipeline_cache(cache.raw, None) }
2516 }
2517 unsafe fn create_query_set(
2518 &self,
2519 desc: &wgt::QuerySetDescriptor<crate::Label>,
2520 ) -> Result<super::QuerySet, crate::DeviceError> {
2521 self.error_if_would_oom_on_resource_allocation(
2526 gpu_allocator::MemoryLocation::GpuToCpu,
2527 &vk::MemoryRequirements {
2528 size: desc.count as u64 * 256,
2529 alignment: 256,
2530 memory_type_bits: self.valid_ash_memory_types,
2531 },
2532 )?;
2533
2534 let (vk_type, pipeline_statistics) = match desc.ty {
2535 wgt::QueryType::Occlusion => (
2536 vk::QueryType::OCCLUSION,
2537 vk::QueryPipelineStatisticFlags::empty(),
2538 ),
2539 wgt::QueryType::PipelineStatistics(statistics) => (
2540 vk::QueryType::PIPELINE_STATISTICS,
2541 conv::map_pipeline_statistics(statistics),
2542 ),
2543 wgt::QueryType::Timestamp => (
2544 vk::QueryType::TIMESTAMP,
2545 vk::QueryPipelineStatisticFlags::empty(),
2546 ),
2547 };
2548
2549 let vk_info = vk::QueryPoolCreateInfo::default()
2550 .query_type(vk_type)
2551 .query_count(desc.count)
2552 .pipeline_statistics(pipeline_statistics);
2553
2554 let raw = unsafe { self.shared.raw.create_query_pool(&vk_info, None) }
2555 .map_err(super::map_host_device_oom_err)?;
2556 if let Some(label) = desc.label {
2557 unsafe { self.shared.set_object_name(raw, label) };
2558 }
2559
2560 self.counters.query_sets.add(1);
2561
2562 Ok(super::QuerySet { raw })
2563 }
2564
2565 unsafe fn destroy_query_set(&self, set: super::QuerySet) {
2566 unsafe { self.shared.raw.destroy_query_pool(set.raw, None) };
2567
2568 self.counters.query_sets.sub(1);
2569 }
2570
2571 unsafe fn create_fence(&self) -> Result<super::Fence, crate::DeviceError> {
2572 self.counters.fences.add(1);
2573
2574 Ok(if self.shared.private_caps.timeline_semaphores {
2575 let mut sem_type_info =
2576 vk::SemaphoreTypeCreateInfo::default().semaphore_type(vk::SemaphoreType::TIMELINE);
2577 let vk_info = vk::SemaphoreCreateInfo::default().push_next(&mut sem_type_info);
2578 let raw = unsafe { self.shared.raw.create_semaphore(&vk_info, None) }
2579 .map_err(super::map_host_device_oom_err)?;
2580
2581 super::Fence::TimelineSemaphore(raw)
2582 } else {
2583 super::Fence::FencePool(RwLock::new(super::FencePool {
2584 last_completed: 0,
2585 active: Vec::new(),
2586 free: Vec::new(),
2587 }))
2588 })
2589 }
2590 unsafe fn destroy_fence(&self, fence: super::Fence) {
2591 match fence {
2592 super::Fence::TimelineSemaphore(raw) => {
2593 unsafe { self.shared.raw.destroy_semaphore(raw, None) };
2594 }
2595 super::Fence::FencePool(pool) => {
2596 let super::FencePool {
2597 active,
2598 free,
2599 last_completed: _,
2600 } = pool.into_inner();
2601
2602 for (_, raw) in active {
2603 unsafe {
2604 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)
2605 };
2606 }
2607 for raw in free {
2608 unsafe { self.shared.raw.destroy_fence(raw, None) };
2609 }
2610 }
2611 }
2612
2613 self.counters.fences.sub(1);
2614 }
2615 unsafe fn get_fence_value(
2616 &self,
2617 fence: &super::Fence,
2618 ) -> Result<crate::FenceValue, crate::DeviceError> {
2619 fence.get_latest(
2620 &self.shared.raw,
2621 self.shared.extension_fns.timeline_semaphore.as_ref(),
2622 )
2623 }
2624 unsafe fn wait(
2625 &self,
2626 fence: &super::Fence,
2627 wait_value: crate::FenceValue,
2628 timeout: Option<Duration>,
2629 ) -> Result<bool, crate::DeviceError> {
2630 let timeout_ns = timeout
2631 .unwrap_or(Duration::MAX)
2632 .as_nanos()
2633 .min(u64::MAX as _) as u64;
2634 self.shared.wait_for_fence(fence, wait_value, timeout_ns)
2635 }
2636
2637 unsafe fn start_graphics_debugger_capture(&self) -> bool {
2638 #[cfg(feature = "renderdoc")]
2639 {
2640 let raw_vk_instance =
2642 vk::Handle::as_raw(self.shared.instance.raw.handle()) as *mut *mut _;
2643 let raw_vk_instance_dispatch_table = unsafe { *raw_vk_instance };
2644 unsafe {
2645 self.render_doc
2646 .start_frame_capture(raw_vk_instance_dispatch_table, ptr::null_mut())
2647 }
2648 }
2649 #[cfg(not(feature = "renderdoc"))]
2650 false
2651 }
2652 unsafe fn stop_graphics_debugger_capture(&self) {
2653 #[cfg(feature = "renderdoc")]
2654 {
2655 let raw_vk_instance =
2657 vk::Handle::as_raw(self.shared.instance.raw.handle()) as *mut *mut _;
2658 let raw_vk_instance_dispatch_table = unsafe { *raw_vk_instance };
2659
2660 unsafe {
2661 self.render_doc
2662 .end_frame_capture(raw_vk_instance_dispatch_table, ptr::null_mut())
2663 }
2664 }
2665 }
2666
2667 unsafe fn pipeline_cache_get_data(&self, cache: &super::PipelineCache) -> Option<Vec<u8>> {
2668 let data = unsafe { self.raw_device().get_pipeline_cache_data(cache.raw) };
2669 data.ok()
2670 }
2671
2672 unsafe fn get_acceleration_structure_build_sizes<'a>(
2673 &self,
2674 desc: &crate::GetAccelerationStructureBuildSizesDescriptor<'a, super::Buffer>,
2675 ) -> crate::AccelerationStructureBuildSizes {
2676 const CAPACITY: usize = 8;
2677
2678 let ray_tracing_functions = self
2679 .shared
2680 .extension_fns
2681 .ray_tracing
2682 .as_ref()
2683 .expect("Feature `RAY_TRACING` not enabled");
2684
2685 let (geometries, primitive_counts) = match *desc.entries {
2686 crate::AccelerationStructureEntries::Instances(ref instances) => {
2687 let instance_data = vk::AccelerationStructureGeometryInstancesDataKHR::default();
2688
2689 let geometry = vk::AccelerationStructureGeometryKHR::default()
2690 .geometry_type(vk::GeometryTypeKHR::INSTANCES)
2691 .geometry(vk::AccelerationStructureGeometryDataKHR {
2692 instances: instance_data,
2693 });
2694
2695 (
2696 smallvec::smallvec![geometry],
2697 smallvec::smallvec![instances.count],
2698 )
2699 }
2700 crate::AccelerationStructureEntries::Triangles(ref in_geometries) => {
2701 let mut primitive_counts =
2702 smallvec::SmallVec::<[u32; CAPACITY]>::with_capacity(in_geometries.len());
2703 let mut geometries = smallvec::SmallVec::<
2704 [vk::AccelerationStructureGeometryKHR; CAPACITY],
2705 >::with_capacity(in_geometries.len());
2706
2707 for triangles in in_geometries {
2708 let mut triangle_data =
2709 vk::AccelerationStructureGeometryTrianglesDataKHR::default()
2710 .index_type(vk::IndexType::NONE_KHR)
2711 .vertex_format(conv::map_vertex_format(triangles.vertex_format))
2712 .max_vertex(triangles.vertex_count)
2713 .vertex_stride(triangles.vertex_stride)
2714 .transform_data(vk::DeviceOrHostAddressConstKHR {
2724 device_address: if desc
2725 .flags
2726 .contains(wgt::AccelerationStructureFlags::USE_TRANSFORM)
2727 {
2728 unsafe {
2729 ray_tracing_functions
2730 .buffer_device_address
2731 .get_buffer_device_address(
2732 &vk::BufferDeviceAddressInfo::default().buffer(
2733 triangles
2734 .transform
2735 .as_ref()
2736 .unwrap()
2737 .buffer
2738 .raw,
2739 ),
2740 )
2741 }
2742 } else {
2743 0
2744 },
2745 });
2746
2747 let pritive_count = if let Some(ref indices) = triangles.indices {
2748 triangle_data =
2749 triangle_data.index_type(conv::map_index_format(indices.format));
2750 indices.count / 3
2751 } else {
2752 triangles.vertex_count / 3
2753 };
2754
2755 let geometry = vk::AccelerationStructureGeometryKHR::default()
2756 .geometry_type(vk::GeometryTypeKHR::TRIANGLES)
2757 .geometry(vk::AccelerationStructureGeometryDataKHR {
2758 triangles: triangle_data,
2759 })
2760 .flags(conv::map_acceleration_structure_geometry_flags(
2761 triangles.flags,
2762 ));
2763
2764 geometries.push(geometry);
2765 primitive_counts.push(pritive_count);
2766 }
2767 (geometries, primitive_counts)
2768 }
2769 crate::AccelerationStructureEntries::AABBs(ref in_geometries) => {
2770 let mut primitive_counts =
2771 smallvec::SmallVec::<[u32; CAPACITY]>::with_capacity(in_geometries.len());
2772 let mut geometries = smallvec::SmallVec::<
2773 [vk::AccelerationStructureGeometryKHR; CAPACITY],
2774 >::with_capacity(in_geometries.len());
2775 for aabb in in_geometries {
2776 let aabbs_data = vk::AccelerationStructureGeometryAabbsDataKHR::default()
2777 .stride(aabb.stride);
2778
2779 let geometry = vk::AccelerationStructureGeometryKHR::default()
2780 .geometry_type(vk::GeometryTypeKHR::AABBS)
2781 .geometry(vk::AccelerationStructureGeometryDataKHR { aabbs: aabbs_data })
2782 .flags(conv::map_acceleration_structure_geometry_flags(aabb.flags));
2783
2784 geometries.push(geometry);
2785 primitive_counts.push(aabb.count);
2786 }
2787 (geometries, primitive_counts)
2788 }
2789 };
2790
2791 let ty = match *desc.entries {
2792 crate::AccelerationStructureEntries::Instances(_) => {
2793 vk::AccelerationStructureTypeKHR::TOP_LEVEL
2794 }
2795 _ => vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL,
2796 };
2797
2798 let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::default()
2799 .ty(ty)
2800 .flags(conv::map_acceleration_structure_flags(desc.flags))
2801 .geometries(&geometries);
2802
2803 let mut raw = Default::default();
2804 unsafe {
2805 ray_tracing_functions
2806 .acceleration_structure
2807 .get_acceleration_structure_build_sizes(
2808 vk::AccelerationStructureBuildTypeKHR::DEVICE,
2809 &geometry_info,
2810 &primitive_counts,
2811 &mut raw,
2812 )
2813 }
2814
2815 crate::AccelerationStructureBuildSizes {
2816 acceleration_structure_size: raw.acceleration_structure_size,
2817 update_scratch_size: raw.update_scratch_size,
2818 build_scratch_size: raw.build_scratch_size,
2819 }
2820 }
2821
2822 unsafe fn get_acceleration_structure_device_address(
2823 &self,
2824 acceleration_structure: &super::AccelerationStructure,
2825 ) -> wgt::BufferAddress {
2826 let ray_tracing_functions = self
2827 .shared
2828 .extension_fns
2829 .ray_tracing
2830 .as_ref()
2831 .expect("Feature `RAY_TRACING` not enabled");
2832
2833 unsafe {
2834 ray_tracing_functions
2835 .acceleration_structure
2836 .get_acceleration_structure_device_address(
2837 &vk::AccelerationStructureDeviceAddressInfoKHR::default()
2838 .acceleration_structure(acceleration_structure.raw),
2839 )
2840 }
2841 }
2842
2843 unsafe fn create_acceleration_structure(
2844 &self,
2845 desc: &crate::AccelerationStructureDescriptor,
2846 ) -> Result<super::AccelerationStructure, crate::DeviceError> {
2847 let ray_tracing_functions = self
2848 .shared
2849 .extension_fns
2850 .ray_tracing
2851 .as_ref()
2852 .expect("Feature `RAY_TRACING` not enabled");
2853
2854 let vk_buffer_info = vk::BufferCreateInfo::default()
2855 .size(desc.size)
2856 .usage(
2857 vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR
2858 | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS,
2859 )
2860 .sharing_mode(vk::SharingMode::EXCLUSIVE);
2861
2862 unsafe {
2863 let raw_buffer = self
2864 .shared
2865 .raw
2866 .create_buffer(&vk_buffer_info, None)
2867 .map_err(super::map_host_device_oom_and_ioca_err)?;
2868
2869 let requirements = self.shared.raw.get_buffer_memory_requirements(raw_buffer);
2870
2871 self.error_if_would_oom_on_resource_allocation(
2872 gpu_allocator::MemoryLocation::GpuOnly,
2873 &requirements,
2874 )
2875 .inspect_err(|_| {
2876 self.shared.raw.destroy_buffer(raw_buffer, None);
2877 })?;
2878
2879 let name = desc
2880 .label
2881 .unwrap_or("Unlabeled acceleration structure buffer");
2882
2883 let allocation = self
2884 .mem_allocator
2885 .lock()
2886 .allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
2887 name,
2888 requirements,
2889 location: gpu_allocator::MemoryLocation::GpuOnly,
2890 linear: true, allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
2892 })
2893 .inspect_err(|_| {
2894 self.shared.raw.destroy_buffer(raw_buffer, None);
2895 })?;
2896
2897 self.shared
2898 .raw
2899 .bind_buffer_memory(raw_buffer, allocation.memory(), allocation.offset())
2900 .map_err(super::map_host_device_oom_and_ioca_err)
2901 .inspect_err(|_| {
2902 self.shared.raw.destroy_buffer(raw_buffer, None);
2903 })?;
2904
2905 if let Some(label) = desc.label {
2906 self.shared.set_object_name(raw_buffer, label);
2907 }
2908
2909 let vk_info = vk::AccelerationStructureCreateInfoKHR::default()
2910 .buffer(raw_buffer)
2911 .offset(0)
2912 .size(desc.size)
2913 .ty(conv::map_acceleration_structure_format(desc.format));
2914
2915 let raw_acceleration_structure = ray_tracing_functions
2916 .acceleration_structure
2917 .create_acceleration_structure(&vk_info, None)
2918 .map_err(super::map_host_oom_and_ioca_err)
2919 .inspect_err(|_| {
2920 self.shared.raw.destroy_buffer(raw_buffer, None);
2921 })?;
2922
2923 if let Some(label) = desc.label {
2924 self.shared
2925 .set_object_name(raw_acceleration_structure, label);
2926 }
2927
2928 let pool = if desc.allow_compaction {
2929 let vk_info = vk::QueryPoolCreateInfo::default()
2930 .query_type(vk::QueryType::ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR)
2931 .query_count(1);
2932
2933 let raw = self
2934 .shared
2935 .raw
2936 .create_query_pool(&vk_info, None)
2937 .map_err(super::map_host_device_oom_err)
2938 .inspect_err(|_| {
2939 ray_tracing_functions
2940 .acceleration_structure
2941 .destroy_acceleration_structure(raw_acceleration_structure, None);
2942 self.shared.raw.destroy_buffer(raw_buffer, None);
2943 })?;
2944 Some(raw)
2945 } else {
2946 None
2947 };
2948
2949 Ok(super::AccelerationStructure {
2950 raw: raw_acceleration_structure,
2951 buffer: raw_buffer,
2952 allocation,
2953 compacted_size_query: pool,
2954 })
2955 }
2956 }
2957
2958 unsafe fn destroy_acceleration_structure(
2959 &self,
2960 acceleration_structure: super::AccelerationStructure,
2961 ) {
2962 let ray_tracing_functions = self
2963 .shared
2964 .extension_fns
2965 .ray_tracing
2966 .as_ref()
2967 .expect("Feature `RAY_TRACING` not enabled");
2968
2969 unsafe {
2970 ray_tracing_functions
2971 .acceleration_structure
2972 .destroy_acceleration_structure(acceleration_structure.raw, None);
2973 self.shared
2974 .raw
2975 .destroy_buffer(acceleration_structure.buffer, None);
2976 let result = self
2977 .mem_allocator
2978 .lock()
2979 .free(acceleration_structure.allocation);
2980 if let Err(err) = result {
2981 log::warn!("Failed to free buffer acceleration structure: {err}");
2982 }
2983 if let Some(query) = acceleration_structure.compacted_size_query {
2984 self.shared.raw.destroy_query_pool(query, None)
2985 }
2986 }
2987 }
2988
2989 fn get_internal_counters(&self) -> wgt::HalCounters {
2990 self.counters
2991 .memory_allocations
2992 .set(self.shared.memory_allocations_counter.read());
2993
2994 self.counters.as_ref().clone()
2995 }
2996
2997 fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
2998 let gpu_allocator::AllocatorReport {
2999 allocations,
3000 blocks,
3001 total_allocated_bytes,
3002 total_capacity_bytes,
3003 } = self.mem_allocator.lock().generate_report();
3004
3005 let allocations = allocations
3006 .into_iter()
3007 .map(|alloc| wgt::AllocationReport {
3008 name: alloc.name,
3009 offset: alloc.offset,
3010 size: alloc.size,
3011 })
3012 .collect();
3013
3014 let blocks = blocks
3015 .into_iter()
3016 .map(|block| wgt::MemoryBlockReport {
3017 size: block.size,
3018 allocations: block.allocations.clone(),
3019 })
3020 .collect();
3021
3022 Some(wgt::AllocatorReport {
3023 allocations,
3024 blocks,
3025 total_allocated_bytes,
3026 total_reserved_bytes: total_capacity_bytes,
3027 })
3028 }
3029
3030 fn tlas_instance_to_bytes(&self, instance: TlasInstance) -> Vec<u8> {
3031 const MAX_U24: u32 = (1u32 << 24u32) - 1u32;
3032 let temp = RawTlasInstance {
3033 transform: instance.transform,
3034 custom_data_and_mask: (instance.custom_data & MAX_U24)
3035 | (u32::from(instance.mask) << 24),
3036 shader_binding_table_record_offset_and_flags: (instance
3037 .pipeline_intersection_data_offset
3038 & MAX_U24),
3039 acceleration_structure_reference: instance.blas_address,
3040 };
3041 bytemuck::bytes_of(&temp).to_vec()
3042 }
3043
3044 fn check_if_oom(&self) -> Result<(), crate::DeviceError> {
3045 let Some(threshold) = self
3046 .shared
3047 .instance
3048 .memory_budget_thresholds
3049 .for_device_loss
3050 else {
3051 return Ok(());
3052 };
3053
3054 let Some(memory_properties) = self.get_memory_properties() else {
3055 return Ok(());
3056 };
3057
3058 for i in 0..memory_properties.heaps().len() {
3059 let heap_usage = memory_properties.heap_usage()[i];
3060 let heap_budget = memory_properties.heap_budget()[i];
3061
3062 if heap_usage >= heap_budget / 100 * threshold as u64 {
3063 return Err(crate::DeviceError::OutOfMemory);
3064 }
3065 }
3066
3067 Ok(())
3068 }
3069}
3070
3071impl super::DeviceShared {
3072 pub(super) fn new_binary_semaphore(
3073 &self,
3074 name: &str,
3075 ) -> Result<vk::Semaphore, crate::DeviceError> {
3076 unsafe {
3077 let semaphore = self
3078 .raw
3079 .create_semaphore(&vk::SemaphoreCreateInfo::default(), None)
3080 .map_err(super::map_host_device_oom_err)?;
3081
3082 self.set_object_name(semaphore, name);
3083
3084 Ok(semaphore)
3085 }
3086 }
3087
3088 pub(super) fn wait_for_fence(
3089 &self,
3090 fence: &super::Fence,
3091 wait_value: crate::FenceValue,
3092 timeout_ns: u64,
3093 ) -> Result<bool, crate::DeviceError> {
3094 profiling::scope!("Device::wait");
3095 match *fence {
3096 super::Fence::TimelineSemaphore(raw) => {
3097 let semaphores = [raw];
3098 let values = [wait_value];
3099 let vk_info = vk::SemaphoreWaitInfo::default()
3100 .semaphores(&semaphores)
3101 .values(&values);
3102 let result = match self.extension_fns.timeline_semaphore {
3103 Some(super::ExtensionFn::Extension(ref ext)) => unsafe {
3104 ext.wait_semaphores(&vk_info, timeout_ns)
3105 },
3106 Some(super::ExtensionFn::Promoted) => unsafe {
3107 self.raw.wait_semaphores(&vk_info, timeout_ns)
3108 },
3109 None => unreachable!(),
3110 };
3111 match result {
3112 Ok(()) => Ok(true),
3113 Err(vk::Result::TIMEOUT) => Ok(false),
3114 Err(other) => Err(super::map_host_device_oom_and_lost_err(other)),
3115 }
3116 }
3117 super::Fence::FencePool(ref pool) => {
3118 let pool = pool.read();
3119 let super::FencePool {
3120 last_completed,
3121 ref active,
3122 free: _,
3123 } = *pool;
3124 if wait_value <= last_completed {
3125 Ok(true)
3126 } else {
3127 match active.iter().find(|&&(value, _)| value >= wait_value) {
3128 Some((_, fence)) => {
3129 let fence = fence.clone();
3131 drop(pool);
3132 match unsafe {
3133 self.raw.wait_for_fences(
3134 core::slice::from_ref(&fence),
3135 true,
3136 timeout_ns,
3137 )
3138 } {
3139 Ok(()) => Ok(true),
3140 Err(vk::Result::TIMEOUT) => Ok(false),
3141 Err(other) => Err(super::map_host_device_oom_and_lost_err(other)),
3142 }
3143 }
3144 None => {
3145 crate::hal_usage_error(format!(
3146 "no signals reached value {wait_value}"
3147 ));
3148 }
3149 }
3150 }
3151 }
3152 }
3153 }
3154}
3155
3156struct ImageWithoutMemory {
3157 raw: vk::Image,
3158 requirements: vk::MemoryRequirements,
3159}