1use core::{mem::ManuallyDrop, ops::Deref};
2
3use alloc::sync::Arc;
4use hal::DynResource;
5
6use crate::{
7 device::Device,
8 global::Global,
9 hal_api::HalApi,
10 id::{
11 AdapterId, BlasId, BufferId, CommandEncoderId, DeviceId, QueueId, SurfaceId, TextureId,
12 TextureViewId, TlasId,
13 },
14 lock::{RankData, RwLockReadGuard},
15 resource::RawResourceAccess,
16 snatch::SnatchGuard,
17};
18
19struct SimpleResourceGuard<Resource, HalType> {
21 _guard: Resource,
22 ptr: *const HalType,
23}
24
25impl<Resource, HalType> SimpleResourceGuard<Resource, HalType> {
26 pub fn new<C>(guard: Resource, callback: C) -> Option<Self>
28 where
29 C: Fn(&Resource) -> Option<&HalType>,
30 {
31 let ptr: *const HalType = callback(&guard)?;
33
34 Some(Self { _guard: guard, ptr })
35 }
36}
37
38impl<Resource, HalType> Deref for SimpleResourceGuard<Resource, HalType> {
39 type Target = HalType;
40
41 fn deref(&self) -> &Self::Target {
42 unsafe { &*self.ptr }
45 }
46}
47
48unsafe impl<Resource, HalType> Send for SimpleResourceGuard<Resource, HalType>
49where
50 Resource: Send,
51 HalType: Send,
52{
53}
54unsafe impl<Resource, HalType> Sync for SimpleResourceGuard<Resource, HalType>
55where
56 Resource: Sync,
57 HalType: Sync,
58{
59}
60
61struct SnatchableResourceGuard<Resource, HalType>
63where
64 Resource: RawResourceAccess,
65{
66 resource: Arc<Resource>,
67 snatch_lock_rank_data: ManuallyDrop<RankData>,
68 ptr: *const HalType,
69}
70
71impl<Resource, HalType> SnatchableResourceGuard<Resource, HalType>
72where
73 Resource: RawResourceAccess,
74 HalType: 'static,
75{
76 pub fn new(resource: Arc<Resource>) -> Option<Self> {
82 let snatch_guard = resource.device().snatchable_lock.read();
84
85 let underlying = resource
87 .raw(&snatch_guard)?
88 .as_any()
89 .downcast_ref::<HalType>()?;
90
91 let ptr: *const HalType = underlying;
94
95 let snatch_lock_rank_data = SnatchGuard::forget(snatch_guard);
98
99 Some(Self {
102 resource,
103 snatch_lock_rank_data: ManuallyDrop::new(snatch_lock_rank_data),
104 ptr,
105 })
106 }
107}
108
109impl<Resource, HalType> Deref for SnatchableResourceGuard<Resource, HalType>
110where
111 Resource: RawResourceAccess,
112{
113 type Target = HalType;
114
115 fn deref(&self) -> &Self::Target {
116 unsafe { &*self.ptr }
120 }
121}
122
123impl<Resource, HalType> Drop for SnatchableResourceGuard<Resource, HalType>
124where
125 Resource: RawResourceAccess,
126{
127 fn drop(&mut self) {
128 let data = unsafe { ManuallyDrop::take(&mut self.snatch_lock_rank_data) };
131
132 unsafe {
137 self.resource
138 .device()
139 .snatchable_lock
140 .force_unlock_read(data)
141 };
142 }
143}
144
145unsafe impl<Resource, HalType> Send for SnatchableResourceGuard<Resource, HalType>
146where
147 Resource: RawResourceAccess + Send,
148 HalType: Send,
149{
150}
151unsafe impl<Resource, HalType> Sync for SnatchableResourceGuard<Resource, HalType>
152where
153 Resource: RawResourceAccess + Sync,
154 HalType: Sync,
155{
156}
157
158struct FenceGuard<Fence> {
160 device: Arc<Device>,
161 fence_lock_rank_data: ManuallyDrop<RankData>,
162 ptr: *const Fence,
163}
164
165impl<Fence> FenceGuard<Fence>
166where
167 Fence: 'static,
168{
169 pub fn new(device: Arc<Device>) -> Option<Self> {
174 let fence_guard = device.fence.read();
176
177 let ptr: *const Fence = fence_guard.as_any().downcast_ref::<Fence>()?;
180
181 let fence_lock_rank_data = RwLockReadGuard::forget(fence_guard);
184
185 Some(Self {
188 device,
189 fence_lock_rank_data: ManuallyDrop::new(fence_lock_rank_data),
190 ptr,
191 })
192 }
193}
194
195impl<Fence> Deref for FenceGuard<Fence> {
196 type Target = Fence;
197
198 fn deref(&self) -> &Self::Target {
199 unsafe { &*self.ptr }
203 }
204}
205
206impl<Fence> Drop for FenceGuard<Fence> {
207 fn drop(&mut self) {
208 let data = unsafe { ManuallyDrop::take(&mut self.fence_lock_rank_data) };
211
212 unsafe {
217 self.device.fence.force_unlock_read(data);
218 };
219 }
220}
221
222unsafe impl<Fence> Send for FenceGuard<Fence> where Fence: Send {}
223unsafe impl<Fence> Sync for FenceGuard<Fence> where Fence: Sync {}
224
225impl Global {
226 pub unsafe fn buffer_as_hal<A: HalApi>(
230 &self,
231 id: BufferId,
232 ) -> Option<impl Deref<Target = A::Buffer>> {
233 profiling::scope!("Buffer::as_hal");
234
235 let hub = &self.hub;
236
237 let buffer = hub.buffers.get(id).get().ok()?;
238
239 SnatchableResourceGuard::new(buffer)
240 }
241
242 pub unsafe fn texture_as_hal<A: HalApi>(
246 &self,
247 id: TextureId,
248 ) -> Option<impl Deref<Target = A::Texture>> {
249 profiling::scope!("Texture::as_hal");
250
251 let hub = &self.hub;
252
253 let texture = hub.textures.get(id).get().ok()?;
254
255 SnatchableResourceGuard::new(texture)
256 }
257
258 pub unsafe fn texture_view_as_hal<A: HalApi>(
262 &self,
263 id: TextureViewId,
264 ) -> Option<impl Deref<Target = A::TextureView>> {
265 profiling::scope!("TextureView::as_hal");
266
267 let hub = &self.hub;
268
269 let view = hub.texture_views.get(id).get().ok()?;
270
271 SnatchableResourceGuard::new(view)
272 }
273
274 pub unsafe fn adapter_as_hal<A: HalApi>(
278 &self,
279 id: AdapterId,
280 ) -> Option<impl Deref<Target = A::Adapter>> {
281 profiling::scope!("Adapter::as_hal");
282
283 let hub = &self.hub;
284 let adapter = hub.adapters.get(id);
285
286 SimpleResourceGuard::new(adapter, move |adapter| {
287 adapter.raw.adapter.as_any().downcast_ref()
288 })
289 }
290
291 pub unsafe fn device_as_hal<A: HalApi>(
295 &self,
296 id: DeviceId,
297 ) -> Option<impl Deref<Target = A::Device>> {
298 profiling::scope!("Device::as_hal");
299
300 let device = self.hub.devices.get(id);
301
302 SimpleResourceGuard::new(device, move |device| device.raw().as_any().downcast_ref())
303 }
304
305 pub unsafe fn device_fence_as_hal<A: HalApi>(
309 &self,
310 id: DeviceId,
311 ) -> Option<impl Deref<Target = A::Fence>> {
312 profiling::scope!("Device::fence_as_hal");
313
314 let device = self.hub.devices.get(id);
315
316 FenceGuard::new(device)
317 }
318
319 pub unsafe fn surface_as_hal<A: HalApi>(
322 &self,
323 id: SurfaceId,
324 ) -> Option<impl Deref<Target = A::Surface>> {
325 profiling::scope!("Surface::as_hal");
326
327 let surface = self.surfaces.get(id);
328
329 SimpleResourceGuard::new(surface, move |surface| {
330 surface.raw(A::VARIANT)?.as_any().downcast_ref()
331 })
332 }
333
334 pub unsafe fn command_encoder_as_hal_mut<
338 A: HalApi,
339 F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
340 R,
341 >(
342 &self,
343 id: CommandEncoderId,
344 hal_command_encoder_callback: F,
345 ) -> R {
346 profiling::scope!("CommandEncoder::as_hal");
347
348 let hub = &self.hub;
349
350 let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id());
351 let mut cmd_buf_data = cmd_buf.data.lock();
352 cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
353 hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {
354 cmd_buf
355 .encoder
356 .open()
357 .ok()
358 .and_then(|encoder| encoder.as_any_mut().downcast_mut())
359 }))
360 })
361 }
362
363 pub unsafe fn queue_as_hal<A: HalApi>(
367 &self,
368 id: QueueId,
369 ) -> Option<impl Deref<Target = A::Queue>> {
370 profiling::scope!("Queue::as_hal");
371
372 let queue = self.hub.queues.get(id);
373
374 SimpleResourceGuard::new(queue, move |queue| queue.raw().as_any().downcast_ref())
375 }
376
377 pub unsafe fn blas_as_hal<A: HalApi>(
381 &self,
382 id: BlasId,
383 ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
384 profiling::scope!("Blas::as_hal");
385
386 let hub = &self.hub;
387
388 let blas = hub.blas_s.get(id).get().ok()?;
389
390 SnatchableResourceGuard::new(blas)
391 }
392
393 pub unsafe fn tlas_as_hal<A: HalApi>(
397 &self,
398 id: TlasId,
399 ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
400 profiling::scope!("Tlas::as_hal");
401
402 let hub = &self.hub;
403
404 let tlas = hub.tlas_s.get(id).get().ok()?;
405
406 SnatchableResourceGuard::new(tlas)
407 }
408}