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