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