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