fence
This commit is contained in:
parent
7503a73a57
commit
e4c0479757
|
|
@ -2,7 +2,6 @@ use std::{
|
|||
borrow::Cow,
|
||||
collections::{BTreeSet, HashMap, HashSet},
|
||||
ffi::CStr,
|
||||
mem::ManuallyDrop,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
};
|
||||
|
|
@ -442,9 +441,9 @@ impl PhysicalDeviceInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DevicePools {
|
||||
pub(crate) fences: Pool<vk::Fence>,
|
||||
pub(crate) fences: Arc<Pool<vk::Fence>>,
|
||||
pub(crate) binary_semaphores: Pool<BinarySemaphore>,
|
||||
pub(crate) timeline_semaphores: Pool<TimelineSemaphore>,
|
||||
}
|
||||
|
|
@ -452,7 +451,7 @@ pub(crate) struct DevicePools {
|
|||
impl DevicePools {
|
||||
pub fn new(device: Arc<DeviceInner>) -> Self {
|
||||
Self {
|
||||
fences: Pool::new(device.clone()),
|
||||
fences: Arc::new(Pool::new(device.clone())),
|
||||
binary_semaphores: Pool::new(device.clone()),
|
||||
timeline_semaphores: Pool::new(device),
|
||||
}
|
||||
|
|
@ -716,7 +715,7 @@ impl<T: DeviceHandle> DeviceObject<T> {
|
|||
{
|
||||
unsafe {
|
||||
if let Some(name) = name.as_ref() {
|
||||
device.debug_name_object(inner.clone(), &name);
|
||||
device.debug_name_object(inner.clone(), name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -807,52 +806,9 @@ pub trait Pooled: Sized {
|
|||
fn create_from_pool(pool: &Pool<Self>) -> Result<Self>;
|
||||
}
|
||||
|
||||
pub struct PoolObject<T: Pooled + vk::Handle + Clone> {
|
||||
pub(crate) inner: ManuallyDrop<T>,
|
||||
pub(crate) pool: Pool<T>,
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) name: Option<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
impl<T: Pooled + vk::Handle + Clone> PoolObject<T> {
|
||||
pub fn name_object(&mut self, name: impl Into<Cow<'static, str>>) {
|
||||
#[cfg(debug_assertions)]
|
||||
unsafe {
|
||||
self.name = Some(name.into());
|
||||
self.pool
|
||||
.device
|
||||
.debug_name_object(T::clone(&self.inner), self.name.as_ref().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn device(&self) -> &Arc<DeviceInner> {
|
||||
&self.pool.device
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pooled + vk::Handle + Clone> Drop for PoolObject<T> {
|
||||
fn drop(&mut self) {
|
||||
let handle = unsafe { ManuallyDrop::take(&mut self.inner) };
|
||||
#[cfg(debug_assertions)]
|
||||
if self.name.is_some() {
|
||||
unsafe { self.pool.device.debug_name_object(handle.clone(), "") };
|
||||
}
|
||||
|
||||
self.pool.push(handle);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pooled + vk::Handle + Clone> Deref for PoolObject<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Pool<T> {
|
||||
pub(crate) pool: Arc<Mutex<Vec<T>>>,
|
||||
pub(crate) pool: Mutex<Vec<T>>,
|
||||
pub(crate) device: Arc<DeviceInner>,
|
||||
}
|
||||
|
||||
|
|
@ -862,7 +818,7 @@ impl<T> Pool<T> {
|
|||
}
|
||||
pub fn new(device: Arc<DeviceInner>) -> Self {
|
||||
Self {
|
||||
pool: Arc::new(Mutex::new(Vec::new())),
|
||||
pool: Mutex::new(Vec::new()),
|
||||
device,
|
||||
}
|
||||
}
|
||||
|
|
@ -871,27 +827,40 @@ impl<T> Pool<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Pooled + vk::Handle + Clone> Pool<T> {
|
||||
pub fn get(&self) -> Result<PoolObject<T>> {
|
||||
impl<T> AsRef<Pool<T>> for Pool<T> {
|
||||
fn as_ref(&self) -> &Pool<T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub type PoolObject<T, U: AsRef<Pool<T>>> = asdf::ExternallyManagedObject<T, U>;
|
||||
|
||||
impl<'a, T: Pooled + asdf::traits::ExternallyManagedObject<&'a Pool<T>> + 'a> Pool<T> {
|
||||
pub fn get(&'a self) -> Result<PoolObject<T, &'a Pool<T>>> {
|
||||
let item = if let Some(item) = self.pool.lock().pop() {
|
||||
item
|
||||
} else {
|
||||
T::create_from_pool(self)?
|
||||
};
|
||||
|
||||
Ok(PoolObject {
|
||||
inner: ManuallyDrop::new(item),
|
||||
pool: self.clone(),
|
||||
#[cfg(debug_assertions)]
|
||||
name: None,
|
||||
})
|
||||
Ok(asdf::ExternallyManagedObject::new(item, self))
|
||||
}
|
||||
|
||||
pub fn get_named(&self, name: Option<impl Into<Cow<'static, str>>>) -> Result<PoolObject<T>> {
|
||||
let mut obj = self.get()?;
|
||||
if let Some(name) = name {
|
||||
obj.name_object(name);
|
||||
pub fn get_debug_named(
|
||||
&'a self,
|
||||
name: Option<impl Into<Cow<'static, str>>>,
|
||||
) -> Result<PoolObject<T, &'a Pool<T>>>
|
||||
where
|
||||
T: asdf::traits::DebugNameable,
|
||||
{
|
||||
let obj = self.get()?;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let name = name.map(Into::into).unwrap_or_default();
|
||||
<T as asdf::traits::DebugNameable>::debug_name(&obj, &self.device, &name);
|
||||
}
|
||||
|
||||
Ok(obj)
|
||||
}
|
||||
}
|
||||
|
|
@ -954,9 +923,10 @@ macro_rules! define_device_owned_handle {
|
|||
}
|
||||
|
||||
// This module is an experiment in a more generic way to manage device-owned resources.
|
||||
#[cfg(false)]
|
||||
mod asdf {
|
||||
// #[cfg(false)]
|
||||
pub(crate) mod asdf {
|
||||
use std::{
|
||||
mem::{ManuallyDrop, MaybeUninit},
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
};
|
||||
|
|
@ -964,24 +934,28 @@ mod asdf {
|
|||
use ash::vk;
|
||||
|
||||
use crate::{
|
||||
device::{DeviceInner, GpuAllocation},
|
||||
device::{DeviceInner, DevicePools, GpuAllocation},
|
||||
util::DebugName,
|
||||
};
|
||||
|
||||
mod traits {
|
||||
pub mod traits {
|
||||
/// A trait describing an object owned by some manager-type, which is
|
||||
/// responsible for destroying it.
|
||||
pub trait ExternallyManagedObject<T> {
|
||||
/// # Safety
|
||||
/// The caller must ensure this function is only called once for a given object.
|
||||
unsafe fn destroy(&mut self, owner: &T);
|
||||
unsafe fn destroy(self, owner: &T);
|
||||
}
|
||||
|
||||
/// A trait describing an object which can have a debug name assigned to it.
|
||||
pub trait DebugNameable {
|
||||
fn debug_name(&self, device: &super::DeviceInner, name: &str);
|
||||
}
|
||||
}
|
||||
|
||||
struct ExternallyManagedObject<T: traits::ExternallyManagedObject<O>, O> {
|
||||
inner: T,
|
||||
/// Wrapper for types which are owned by another type `O`, which is responsible for destruction.
|
||||
pub struct ExternallyManagedObject<T: traits::ExternallyManagedObject<O>, O> {
|
||||
inner: ManuallyDrop<T>,
|
||||
owner: O,
|
||||
}
|
||||
|
||||
|
|
@ -1000,12 +974,51 @@ mod asdf {
|
|||
}
|
||||
|
||||
impl<T: traits::ExternallyManagedObject<O>, O> ExternallyManagedObject<T, O> {
|
||||
fn new(inner: T, owner: O) -> Self {
|
||||
Self { inner, owner }
|
||||
pub fn new(inner: T, owner: O) -> Self {
|
||||
Self {
|
||||
inner: ManuallyDrop::new(inner),
|
||||
owner,
|
||||
}
|
||||
fn owner(&self) -> &O {
|
||||
}
|
||||
pub fn owner(&self) -> &O {
|
||||
&self.owner
|
||||
}
|
||||
|
||||
pub fn map_inner<U>(self, f: impl FnOnce(T) -> U) -> ExternallyManagedObject<U, O>
|
||||
where
|
||||
U: traits::ExternallyManagedObject<O>,
|
||||
{
|
||||
unsafe {
|
||||
let mut this = MaybeUninit::new(self);
|
||||
let inner = ManuallyDrop::take(&mut this.assume_init_mut().inner);
|
||||
let owner = core::ptr::read(&raw const this.assume_init_mut().owner);
|
||||
|
||||
let new_inner = f(inner);
|
||||
|
||||
ExternallyManagedObject {
|
||||
inner: ManuallyDrop::new(new_inner),
|
||||
owner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_owner<U>(self, f: impl FnOnce(O) -> U) -> ExternallyManagedObject<T, U>
|
||||
where
|
||||
T: traits::ExternallyManagedObject<U>,
|
||||
{
|
||||
unsafe {
|
||||
let mut this = MaybeUninit::new(self);
|
||||
let inner = ManuallyDrop::take(&mut this.assume_init_mut().inner);
|
||||
|
||||
// get the old owner without calling `Self::drop`
|
||||
let owner = core::ptr::read(&raw const this.assume_init_mut().owner);
|
||||
|
||||
ExternallyManagedObject {
|
||||
inner: ManuallyDrop::new(inner),
|
||||
owner: f(owner),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, O> Drop for ExternallyManagedObject<T, O>
|
||||
|
|
@ -1014,12 +1027,17 @@ mod asdf {
|
|||
{
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.inner.destroy(&self.owner);
|
||||
let inner = ManuallyDrop::take(&mut self.inner);
|
||||
inner.destroy(&self.owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DeviceObject<T: traits::ExternallyManagedObject<O>, O: AsRef<super::DeviceInner>> {
|
||||
/// A wrapper for vulkan types which are owned by the device, taking care of destruction.
|
||||
pub struct DeviceObject<
|
||||
T: traits::ExternallyManagedObject<O>,
|
||||
O: AsRef<super::DeviceInner> = Arc<super::DeviceInner>,
|
||||
> {
|
||||
inner: ExternallyManagedObject<T, O>,
|
||||
name: Option<DebugName>,
|
||||
}
|
||||
|
|
@ -1065,23 +1083,42 @@ mod asdf {
|
|||
}
|
||||
|
||||
mod impls {
|
||||
use crate::device::{DeviceInner, GpuAllocation};
|
||||
use crate::device::{DeviceInner, DevicePools, GpuAllocation};
|
||||
|
||||
use super::*;
|
||||
|
||||
impl<T: AsRef<DeviceInner>> traits::ExternallyManagedObject<T> for ash::vk::Semaphore {
|
||||
unsafe fn destroy(&mut self, device: &T) {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe {
|
||||
device.as_ref().raw.destroy_semaphore(*self, None);
|
||||
device.as_ref().raw.destroy_semaphore(self, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> traits::ExternallyManagedObject<T> for GpuAllocation {
|
||||
unsafe fn destroy(&mut self, device: &T) {
|
||||
let mut swapped = GpuAllocation::default();
|
||||
std::mem::swap(self, &mut swapped);
|
||||
_ = device.as_ref().alloc2.lock().free(swapped);
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
_ = device.as_ref().alloc2.lock().free(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl traits::ExternallyManagedObject<DevicePools> for vk::Semaphore {
|
||||
unsafe fn destroy(self, owner: &DevicePools) {
|
||||
owner
|
||||
.binary_semaphores
|
||||
.push(crate::sync::BinarySemaphore(self));
|
||||
}
|
||||
}
|
||||
|
||||
impl traits::ExternallyManagedObject<DevicePools> for super::Semaphore {
|
||||
unsafe fn destroy(self, owner: &DevicePools) {
|
||||
match self {
|
||||
super::Semaphore::Binary(semaphore) => owner
|
||||
.binary_semaphores
|
||||
.push(crate::sync::BinarySemaphore(semaphore)),
|
||||
super::Semaphore::Timeline(semaphore) => owner
|
||||
.timeline_semaphores
|
||||
.push(crate::sync::TimelineSemaphore(semaphore)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1103,6 +1140,11 @@ mod asdf {
|
|||
}
|
||||
}
|
||||
|
||||
enum Semaphore {
|
||||
Binary(vk::Semaphore),
|
||||
Timeline(vk::Semaphore),
|
||||
}
|
||||
|
||||
fn summon<T>() -> T {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
@ -1125,5 +1167,14 @@ mod asdf {
|
|||
summon::<Arc<super::DeviceInner>>(),
|
||||
summon::<GpuAllocation>(),
|
||||
);
|
||||
|
||||
let pool_owned: ExternallyManagedObject<vk::Semaphore, DevicePools> =
|
||||
ExternallyManagedObject::new(summon::<vk::Semaphore>(), summon::<DevicePools>());
|
||||
|
||||
let enum_semaphore_pooled: ExternallyManagedObject<Semaphore, DevicePools> =
|
||||
ExternallyManagedObject::new(
|
||||
Semaphore::Binary(summon::<vk::Semaphore>()),
|
||||
summon::<DevicePools>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,8 +155,12 @@ impl SyncThreadpool {
|
|||
}
|
||||
|
||||
pub enum Fence {
|
||||
Dedicated { fence: DeviceObject<vk::Fence> },
|
||||
Pooled { fence: PoolObject<vk::Fence> },
|
||||
Dedicated {
|
||||
fence: DeviceObject<vk::Fence>,
|
||||
},
|
||||
Pooled {
|
||||
fence: PoolObject<vk::Fence, Arc<Pool<vk::Fence>>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Pooled for vk::Fence {
|
||||
|
|
@ -171,6 +175,16 @@ impl Pooled for vk::Fence {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> crate::device::asdf::traits::ExternallyManagedObject<T> for vk::Fence
|
||||
where
|
||||
T: AsRef<Pool<vk::Fence>>,
|
||||
{
|
||||
unsafe fn destroy(self, owner: &T) {
|
||||
let pool = owner.as_ref();
|
||||
pool.push(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Fence {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Fence").field("fence", &self.raw()).finish()
|
||||
|
|
@ -188,12 +202,9 @@ impl Fence {
|
|||
fence: DeviceObject::new(fence, device, name.map(Into::into)),
|
||||
})
|
||||
}
|
||||
pub fn from_pool(pool: &Pool<vk::Fence>, name: Option<&'static str>) -> Result<Fence> {
|
||||
let mut fence = pool.get()?;
|
||||
#[cfg(debug_assertions)]
|
||||
if let Some(name) = name {
|
||||
fence.name_object(name);
|
||||
}
|
||||
pub fn from_pool(pool: &Arc<Pool<vk::Fence>>, name: Option<&'static str>) -> Result<Fence> {
|
||||
let fence = pool.get_debug_named(name)?.map_owner(|_| pool.clone());
|
||||
|
||||
Ok(Self::Pooled { fence })
|
||||
}
|
||||
|
||||
|
|
@ -207,7 +218,7 @@ impl Fence {
|
|||
fn device(&self) -> &Arc<DeviceInner> {
|
||||
match self {
|
||||
Fence::Dedicated { fence } => &fence.device().shared,
|
||||
Fence::Pooled { fence } => fence.device(),
|
||||
Fence::Pooled { fence } => &fence.owner().device,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -266,9 +277,9 @@ pub enum Semaphore {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct BinarySemaphore(vk::Semaphore);
|
||||
pub(crate) struct BinarySemaphore(pub(crate) vk::Semaphore);
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct TimelineSemaphore(vk::Semaphore);
|
||||
pub(crate) struct TimelineSemaphore(pub(crate) vk::Semaphore);
|
||||
|
||||
// This is just so that ash can name these semaphore newtypes
|
||||
impl vk::Handle for BinarySemaphore {
|
||||
|
|
|
|||
Loading…
Reference in a new issue