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