1use core::{mem::ManuallyDrop, ops::Deref};
2
3use alloc::sync::Arc;
4use hal::DynResource;
5
6use crate::{
7 global::Global,
8 id::{
9 AdapterId, BlasId, BufferId, CommandEncoderId, DeviceId, QueueId, SurfaceId, TextureId,
10 TextureViewId, TlasId,
11 },
12 lock::RankData,
13 resource::RawResourceAccess,
14 snatch::SnatchGuard,
15};
16
17struct SimpleResourceGuard<Resource, HalType> {
19 _guard: Resource,
20 ptr: *const HalType,
21}
22
23impl<Resource, HalType> SimpleResourceGuard<Resource, HalType> {
24 pub fn new<C>(guard: Resource, callback: C) -> Option<Self>
26 where
27 C: Fn(&Resource) -> Option<&HalType>,
28 {
29 let ptr: *const HalType = callback(&guard)?;
31
32 Some(Self { _guard: guard, ptr })
33 }
34}
35
36impl<Resource, HalType> Deref for SimpleResourceGuard<Resource, HalType> {
37 type Target = HalType;
38
39 fn deref(&self) -> &Self::Target {
40 unsafe { &*self.ptr }
43 }
44}
45
46unsafe impl<Resource, HalType> Send for SimpleResourceGuard<Resource, HalType>
47where
48 Resource: Send,
49 HalType: Send,
50{
51}
52unsafe impl<Resource, HalType> Sync for SimpleResourceGuard<Resource, HalType>
53where
54 Resource: Sync,
55 HalType: Sync,
56{
57}
58
59struct SnatchableResourceGuard<Resource, HalType>
61where
62 Resource: RawResourceAccess,
63{
64 resource: Arc<Resource>,
65 snatch_lock_rank_data: ManuallyDrop<RankData>,
66 ptr: *const HalType,
67}
68
69impl<Resource, HalType> SnatchableResourceGuard<Resource, HalType>
70where
71 Resource: RawResourceAccess,
72 HalType: 'static,
73{
74 pub fn new(resource: Arc<Resource>) -> Option<Self> {
80 let snatch_guard = resource.device().snatchable_lock.read();
82
83 let underlying = resource
85 .raw(&snatch_guard)?
86 .as_any()
87 .downcast_ref::<HalType>()?;
88
89 let ptr: *const HalType = underlying;
92
93 let snatch_lock_rank_data = SnatchGuard::forget(snatch_guard);
96
97 Some(Self {
100 resource,
101 snatch_lock_rank_data: ManuallyDrop::new(snatch_lock_rank_data),
102 ptr,
103 })
104 }
105}
106
107impl<Resource, HalType> Deref for SnatchableResourceGuard<Resource, HalType>
108where
109 Resource: RawResourceAccess,
110{
111 type Target = HalType;
112
113 fn deref(&self) -> &Self::Target {
114 unsafe { &*self.ptr }
118 }
119}
120
121impl<Resource, HalType> Drop for SnatchableResourceGuard<Resource, HalType>
122where
123 Resource: RawResourceAccess,
124{
125 fn drop(&mut self) {
126 let data = unsafe { ManuallyDrop::take(&mut self.snatch_lock_rank_data) };
129
130 unsafe {
135 self.resource
136 .device()
137 .snatchable_lock
138 .force_unlock_read(data)
139 };
140 }
141}
142
143unsafe impl<Resource, HalType> Send for SnatchableResourceGuard<Resource, HalType>
144where
145 Resource: RawResourceAccess + Send,
146 HalType: Send,
147{
148}
149unsafe impl<Resource, HalType> Sync for SnatchableResourceGuard<Resource, HalType>
150where
151 Resource: RawResourceAccess + Sync,
152 HalType: Sync,
153{
154}
155
156impl Global {
157 pub unsafe fn buffer_as_hal<A: hal::Api>(
161 &self,
162 id: BufferId,
163 ) -> Option<impl Deref<Target = A::Buffer>> {
164 profiling::scope!("Buffer::as_hal");
165
166 let hub = &self.hub;
167
168 let buffer = hub.buffers.get(id).get().ok()?;
169
170 SnatchableResourceGuard::new(buffer)
171 }
172
173 pub unsafe fn texture_as_hal<A: hal::Api>(
177 &self,
178 id: TextureId,
179 ) -> Option<impl Deref<Target = A::Texture>> {
180 profiling::scope!("Texture::as_hal");
181
182 let hub = &self.hub;
183
184 let texture = hub.textures.get(id).get().ok()?;
185
186 SnatchableResourceGuard::new(texture)
187 }
188
189 pub unsafe fn texture_view_as_hal<A: hal::Api>(
193 &self,
194 id: TextureViewId,
195 ) -> Option<impl Deref<Target = A::TextureView>> {
196 profiling::scope!("TextureView::as_hal");
197
198 let hub = &self.hub;
199
200 let view = hub.texture_views.get(id).get().ok()?;
201
202 SnatchableResourceGuard::new(view)
203 }
204
205 pub unsafe fn adapter_as_hal<A: hal::Api>(
209 &self,
210 id: AdapterId,
211 ) -> Option<impl Deref<Target = A::Adapter>> {
212 profiling::scope!("Adapter::as_hal");
213
214 let hub = &self.hub;
215 let adapter = hub.adapters.get(id);
216
217 SimpleResourceGuard::new(adapter, move |adapter| {
218 adapter.raw.adapter.as_any().downcast_ref()
219 })
220 }
221
222 pub unsafe fn device_as_hal<A: hal::Api>(
226 &self,
227 id: DeviceId,
228 ) -> Option<impl Deref<Target = A::Device>> {
229 profiling::scope!("Device::as_hal");
230
231 let device = self.hub.devices.get(id);
232
233 SimpleResourceGuard::new(device, move |device| device.raw().as_any().downcast_ref())
234 }
235
236 pub unsafe fn device_fence_as_hal<A: hal::Api>(
240 &self,
241 id: DeviceId,
242 ) -> Option<impl Deref<Target = A::Fence>> {
243 profiling::scope!("Device::fence_as_hal");
244
245 let device = self.hub.devices.get(id);
246
247 SimpleResourceGuard::new(device, move |device| device.fence.as_any().downcast_ref())
248 }
249
250 pub unsafe fn surface_as_hal<A: hal::Api>(
253 &self,
254 id: SurfaceId,
255 ) -> Option<impl Deref<Target = A::Surface>> {
256 profiling::scope!("Surface::as_hal");
257
258 let surface = self.surfaces.get(id);
259
260 SimpleResourceGuard::new(surface, move |surface| {
261 surface.raw(A::VARIANT)?.as_any().downcast_ref()
262 })
263 }
264
265 pub unsafe fn command_encoder_as_hal_mut<
275 A: hal::Api,
276 F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
277 R,
278 >(
279 &self,
280 id: CommandEncoderId,
281 hal_command_encoder_callback: F,
282 ) -> R {
283 profiling::scope!("CommandEncoder::as_hal");
284
285 let hub = &self.hub;
286
287 let cmd_enc = hub.command_encoders.get(id);
288 let mut cmd_buf_data = cmd_enc.data.lock();
289 cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
290 hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {
291 cmd_buf
292 .encoder
293 .open()
294 .ok()
295 .and_then(|encoder| encoder.as_any_mut().downcast_mut())
296 }))
297 })
298 }
299
300 pub unsafe fn queue_as_hal<A: hal::Api>(
304 &self,
305 id: QueueId,
306 ) -> Option<impl Deref<Target = A::Queue>> {
307 profiling::scope!("Queue::as_hal");
308
309 let queue = self.hub.queues.get(id);
310
311 SimpleResourceGuard::new(queue, move |queue| queue.raw().as_any().downcast_ref())
312 }
313
314 pub unsafe fn blas_as_hal<A: hal::Api>(
318 &self,
319 id: BlasId,
320 ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
321 profiling::scope!("Blas::as_hal");
322
323 let hub = &self.hub;
324
325 let blas = hub.blas_s.get(id).get().ok()?;
326
327 SnatchableResourceGuard::new(blas)
328 }
329
330 pub unsafe fn tlas_as_hal<A: hal::Api>(
334 &self,
335 id: TlasId,
336 ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
337 profiling::scope!("Tlas::as_hal");
338
339 let hub = &self.hub;
340
341 let tlas = hub.tlas_s.get(id).get().ok()?;
342
343 SnatchableResourceGuard::new(tlas)
344 }
345}