use core::{mem::ManuallyDrop, ops::Deref};
use alloc::sync::Arc;
use hal::DynResource;
use crate::{
global::Global,
id::{
AdapterId, BlasId, BufferId, CommandEncoderId, DeviceId, QueueId, SurfaceId, TextureId,
TextureViewId, TlasId,
},
lock::RankData,
resource::RawResourceAccess,
snatch::SnatchGuard,
};
struct SimpleResourceGuard<Resource, HalType> {
_guard: Resource,
ptr: *const HalType,
}
impl<Resource, HalType> SimpleResourceGuard<Resource, HalType> {
pub fn new<C>(guard: Resource, callback: C) -> Option<Self>
where
C: Fn(&Resource) -> Option<&HalType>,
{
let ptr: *const HalType = callback(&guard)?;
Some(Self { _guard: guard, ptr })
}
}
impl<Resource, HalType> Deref for SimpleResourceGuard<Resource, HalType> {
type Target = HalType;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr }
}
}
unsafe impl<Resource, HalType> Send for SimpleResourceGuard<Resource, HalType>
where
Resource: Send,
HalType: Send,
{
}
unsafe impl<Resource, HalType> Sync for SimpleResourceGuard<Resource, HalType>
where
Resource: Sync,
HalType: Sync,
{
}
struct SnatchableResourceGuard<Resource, HalType>
where
Resource: RawResourceAccess,
{
resource: Arc<Resource>,
snatch_lock_rank_data: ManuallyDrop<RankData>,
ptr: *const HalType,
}
impl<Resource, HalType> SnatchableResourceGuard<Resource, HalType>
where
Resource: RawResourceAccess,
HalType: 'static,
{
pub fn new(resource: Arc<Resource>) -> Option<Self> {
let snatch_guard = resource.device().snatchable_lock.read();
let underlying = resource
.raw(&snatch_guard)?
.as_any()
.downcast_ref::<HalType>()?;
let ptr: *const HalType = underlying;
let snatch_lock_rank_data = SnatchGuard::forget(snatch_guard);
Some(Self {
resource,
snatch_lock_rank_data: ManuallyDrop::new(snatch_lock_rank_data),
ptr,
})
}
}
impl<Resource, HalType> Deref for SnatchableResourceGuard<Resource, HalType>
where
Resource: RawResourceAccess,
{
type Target = HalType;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr }
}
}
impl<Resource, HalType> Drop for SnatchableResourceGuard<Resource, HalType>
where
Resource: RawResourceAccess,
{
fn drop(&mut self) {
let data = unsafe { ManuallyDrop::take(&mut self.snatch_lock_rank_data) };
unsafe {
self.resource
.device()
.snatchable_lock
.force_unlock_read(data)
};
}
}
unsafe impl<Resource, HalType> Send for SnatchableResourceGuard<Resource, HalType>
where
Resource: RawResourceAccess + Send,
HalType: Send,
{
}
unsafe impl<Resource, HalType> Sync for SnatchableResourceGuard<Resource, HalType>
where
Resource: RawResourceAccess + Sync,
HalType: Sync,
{
}
impl Global {
pub unsafe fn buffer_as_hal<A: hal::Api>(
&self,
id: BufferId,
) -> Option<impl Deref<Target = A::Buffer>> {
profiling::scope!("Buffer::as_hal");
let hub = &self.hub;
let buffer = hub.buffers.get(id).get().ok()?;
SnatchableResourceGuard::new(buffer)
}
pub unsafe fn texture_as_hal<A: hal::Api>(
&self,
id: TextureId,
) -> Option<impl Deref<Target = A::Texture>> {
profiling::scope!("Texture::as_hal");
let hub = &self.hub;
let texture = hub.textures.get(id);
SnatchableResourceGuard::new(texture)
}
pub unsafe fn texture_view_as_hal<A: hal::Api>(
&self,
id: TextureViewId,
) -> Option<impl Deref<Target = A::TextureView>> {
profiling::scope!("TextureView::as_hal");
let hub = &self.hub;
let view = hub.texture_views.get(id).get().ok()?;
SnatchableResourceGuard::new(view)
}
pub unsafe fn adapter_as_hal<A: hal::Api>(
&self,
id: AdapterId,
) -> Option<impl Deref<Target = A::Adapter>> {
profiling::scope!("Adapter::as_hal");
let hub = &self.hub;
let adapter = hub.adapters.get(id);
SimpleResourceGuard::new(adapter, move |adapter| {
adapter.raw.adapter.as_any().downcast_ref()
})
}
pub unsafe fn device_as_hal<A: hal::Api>(
&self,
id: DeviceId,
) -> Option<impl Deref<Target = A::Device>> {
profiling::scope!("Device::as_hal");
let device = self.hub.devices.get(id);
SimpleResourceGuard::new(device, move |device| device.raw().as_any().downcast_ref())
}
pub unsafe fn device_fence_as_hal<A: hal::Api>(
&self,
id: DeviceId,
) -> Option<impl Deref<Target = A::Fence>> {
profiling::scope!("Device::fence_as_hal");
let device = self.hub.devices.get(id);
SimpleResourceGuard::new(device, move |device| device.fence.as_any().downcast_ref())
}
pub unsafe fn surface_as_hal<A: hal::Api>(
&self,
id: SurfaceId,
) -> Option<impl Deref<Target = A::Surface>> {
profiling::scope!("Surface::as_hal");
let surface = self.surfaces.get(id);
SimpleResourceGuard::new(surface, move |surface| {
surface.raw(A::VARIANT)?.as_any().downcast_ref()
})
}
pub unsafe fn command_encoder_as_hal_mut<
A: hal::Api,
F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
R,
>(
&self,
id: CommandEncoderId,
hal_command_encoder_callback: F,
) -> R {
profiling::scope!("CommandEncoder::as_hal");
let hub = &self.hub;
let cmd_enc = hub.command_encoders.get(id);
let mut cmd_buf_data = cmd_enc.data.lock();
cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {
cmd_buf
.encoder
.open()
.ok()
.and_then(|encoder| encoder.as_any_mut().downcast_mut())
}))
})
}
pub unsafe fn queue_as_hal<A: hal::Api>(
&self,
id: QueueId,
) -> Option<impl Deref<Target = A::Queue>> {
profiling::scope!("Queue::as_hal");
let queue = self.hub.queues.get(id);
SimpleResourceGuard::new(queue, move |queue| queue.raw().as_any().downcast_ref())
}
pub unsafe fn blas_as_hal<A: hal::Api>(
&self,
id: BlasId,
) -> Option<impl Deref<Target = A::AccelerationStructure>> {
profiling::scope!("Blas::as_hal");
let hub = &self.hub;
let blas = hub.blas_s.get(id).get().ok()?;
SnatchableResourceGuard::new(blas)
}
pub unsafe fn tlas_as_hal<A: hal::Api>(
&self,
id: TlasId,
) -> Option<impl Deref<Target = A::AccelerationStructure>> {
profiling::scope!("Tlas::as_hal");
let hub = &self.hub;
let tlas = hub.tlas_s.get(id).get().ok()?;
SnatchableResourceGuard::new(tlas)
}
}