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