wgpu_native_texture_interop/
sync_vulkan.rs1use std::sync::Mutex;
23
24use ash::vk;
25
26use crate::{
27 HostWgpuContext, ImportedTexture, InteropBackend, InteropError, InteropSynchronizer,
28 NativeFrame, SyncMechanism,
29};
30
31pub struct VulkanSemaphoreSynchronizer {
34 vk_device: ash::Device,
35 vk_queue: vk::Queue,
36 persistent_semaphore: vk::Semaphore,
37 external_semaphore_fd: ash::khr::external_semaphore_fd::Device,
38 submit_lock: Mutex<()>,
42}
43
44unsafe impl Send for VulkanSemaphoreSynchronizer {}
45unsafe impl Sync for VulkanSemaphoreSynchronizer {}
46
47impl VulkanSemaphoreSynchronizer {
48 pub fn new(host: &HostWgpuContext) -> Result<Self, InteropError> {
53 if host.backend != InteropBackend::Vulkan {
54 return Err(InteropError::BackendMismatch {
55 expected: "Vulkan",
56 actual: "non-Vulkan",
57 });
58 }
59
60 unsafe {
61 let hal_device = host.device.as_hal::<wgpu::wgc::api::Vulkan>().ok_or(
62 InteropError::BackendMismatch {
63 expected: "Vulkan",
64 actual: "non-Vulkan",
65 },
66 )?;
67 let vk_device = hal_device.raw_device().clone();
68 let vk_instance = hal_device.shared_instance().raw_instance().clone();
69 drop(hal_device);
70
71 let hal_queue = host.queue.as_hal::<wgpu::wgc::api::Vulkan>().ok_or(
72 InteropError::BackendMismatch {
73 expected: "Vulkan",
74 actual: "non-Vulkan",
75 },
76 )?;
77 let vk_queue = hal_queue.as_raw();
78 drop(hal_queue);
79
80 let semaphore = vk_device
81 .create_semaphore(&vk::SemaphoreCreateInfo::default(), None)
82 .map_err(|err| {
83 InteropError::Vulkan(format!("create_semaphore: {}", err))
84 })?;
85
86 let external_semaphore_fd =
87 ash::khr::external_semaphore_fd::Device::new(&vk_instance, &vk_device);
88
89 Ok(Self {
90 vk_device,
91 vk_queue,
92 persistent_semaphore: semaphore,
93 external_semaphore_fd,
94 submit_lock: Mutex::new(()),
95 })
96 }
97 }
98}
99
100impl InteropSynchronizer for VulkanSemaphoreSynchronizer {
101 fn producer_complete(
102 &self,
103 frame: &NativeFrame,
104 mechanism: SyncMechanism,
105 ) -> Result<(), InteropError> {
106 match mechanism {
107 SyncMechanism::ExplicitExternalSemaphore => {
108 let semaphore_fd = match frame {
109 NativeFrame::VulkanExternalImage(vk_frame) => vk_frame.wait_semaphore_fd,
110 _ => {
111 return Err(InteropError::Vulkan(
112 "ExplicitExternalSemaphore requires a VulkanExternalImage frame".into(),
113 ));
114 }
115 };
116 let Some(fd) = semaphore_fd else {
117 return Err(InteropError::Vulkan(
118 "frame.wait_semaphore_fd is None but mechanism is ExplicitExternalSemaphore"
119 .into(),
120 ));
121 };
122
123 let _guard = self.submit_lock.lock().map_err(|_| {
124 InteropError::Vulkan("submit_lock poisoned".into())
125 })?;
126
127 unsafe {
128 self.external_semaphore_fd
129 .import_semaphore_fd(
130 &vk::ImportSemaphoreFdInfoKHR::default()
131 .semaphore(self.persistent_semaphore)
132 .flags(vk::SemaphoreImportFlags::TEMPORARY)
133 .handle_type(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD)
134 .fd(fd),
135 )
136 .map_err(|err| {
137 InteropError::Vulkan(format!("import_semaphore_fd: {}", err))
138 })?;
139
140 let wait_semaphores = [self.persistent_semaphore];
141 let wait_stages = [vk::PipelineStageFlags::FRAGMENT_SHADER];
142 let submit_info = vk::SubmitInfo::default()
143 .wait_semaphores(&wait_semaphores)
144 .wait_dst_stage_mask(&wait_stages);
145
146 self.vk_device
147 .queue_submit(self.vk_queue, &[submit_info], vk::Fence::null())
148 .map_err(|err| InteropError::Vulkan(format!("queue_submit: {}", err)))?;
149 }
150 Ok(())
151 }
152 SyncMechanism::None | SyncMechanism::ImplicitGlFlush => Ok(()),
153 other => Err(InteropError::UnsupportedSynchronization(other)),
154 }
155 }
156
157 fn consumer_ready(
158 &self,
159 _texture: &ImportedTexture,
160 mechanism: SyncMechanism,
161 ) -> Result<(), InteropError> {
162 match mechanism {
163 SyncMechanism::None
164 | SyncMechanism::ImplicitGlFlush
165 | SyncMechanism::ExplicitExternalSemaphore => Ok(()),
166 other => Err(InteropError::UnsupportedSynchronization(other)),
167 }
168 }
169}
170
171impl Drop for VulkanSemaphoreSynchronizer {
172 fn drop(&mut self) {
173 unsafe {
174 self.vk_device
175 .destroy_semaphore(self.persistent_semaphore, None);
176 }
177 }
178}