fence
This commit is contained in:
parent
7503a73a57
commit
e4c0479757
|
|
@ -2,7 +2,6 @@ use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::{BTreeSet, HashMap, HashSet},
|
collections::{BTreeSet, HashMap, HashSet},
|
||||||
ffi::CStr,
|
ffi::CStr,
|
||||||
mem::ManuallyDrop,
|
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
@ -442,9 +441,9 @@ impl PhysicalDeviceInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct DevicePools {
|
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) binary_semaphores: Pool<BinarySemaphore>,
|
||||||
pub(crate) timeline_semaphores: Pool<TimelineSemaphore>,
|
pub(crate) timeline_semaphores: Pool<TimelineSemaphore>,
|
||||||
}
|
}
|
||||||
|
|
@ -452,7 +451,7 @@ pub(crate) struct DevicePools {
|
||||||
impl DevicePools {
|
impl DevicePools {
|
||||||
pub fn new(device: Arc<DeviceInner>) -> Self {
|
pub fn new(device: Arc<DeviceInner>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
fences: Pool::new(device.clone()),
|
fences: Arc::new(Pool::new(device.clone())),
|
||||||
binary_semaphores: Pool::new(device.clone()),
|
binary_semaphores: Pool::new(device.clone()),
|
||||||
timeline_semaphores: Pool::new(device),
|
timeline_semaphores: Pool::new(device),
|
||||||
}
|
}
|
||||||
|
|
@ -716,7 +715,7 @@ impl<T: DeviceHandle> DeviceObject<T> {
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(name) = name.as_ref() {
|
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>;
|
fn create_from_pool(pool: &Pool<Self>) -> Result<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PoolObject<T: Pooled + vk::Handle + Clone> {
|
#[derive(Debug)]
|
||||||
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)]
|
|
||||||
pub struct Pool<T> {
|
pub struct Pool<T> {
|
||||||
pub(crate) pool: Arc<Mutex<Vec<T>>>,
|
pub(crate) pool: Mutex<Vec<T>>,
|
||||||
pub(crate) device: Arc<DeviceInner>,
|
pub(crate) device: Arc<DeviceInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -862,7 +818,7 @@ impl<T> Pool<T> {
|
||||||
}
|
}
|
||||||
pub fn new(device: Arc<DeviceInner>) -> Self {
|
pub fn new(device: Arc<DeviceInner>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pool: Arc::new(Mutex::new(Vec::new())),
|
pool: Mutex::new(Vec::new()),
|
||||||
device,
|
device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -871,27 +827,40 @@ impl<T> Pool<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Pooled + vk::Handle + Clone> Pool<T> {
|
impl<T> AsRef<Pool<T>> for Pool<T> {
|
||||||
pub fn get(&self) -> Result<PoolObject<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() {
|
let item = if let Some(item) = self.pool.lock().pop() {
|
||||||
item
|
item
|
||||||
} else {
|
} else {
|
||||||
T::create_from_pool(self)?
|
T::create_from_pool(self)?
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(PoolObject {
|
Ok(asdf::ExternallyManagedObject::new(item, self))
|
||||||
inner: ManuallyDrop::new(item),
|
|
||||||
pool: self.clone(),
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
name: None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_named(&self, name: Option<impl Into<Cow<'static, str>>>) -> Result<PoolObject<T>> {
|
pub fn get_debug_named(
|
||||||
let mut obj = self.get()?;
|
&'a self,
|
||||||
if let Some(name) = name {
|
name: Option<impl Into<Cow<'static, str>>>,
|
||||||
obj.name_object(name);
|
) -> 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)
|
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.
|
// This module is an experiment in a more generic way to manage device-owned resources.
|
||||||
#[cfg(false)]
|
// #[cfg(false)]
|
||||||
mod asdf {
|
pub(crate) mod asdf {
|
||||||
use std::{
|
use std::{
|
||||||
|
mem::{ManuallyDrop, MaybeUninit},
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
@ -964,24 +934,28 @@ mod asdf {
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
device::{DeviceInner, GpuAllocation},
|
device::{DeviceInner, DevicePools, GpuAllocation},
|
||||||
util::DebugName,
|
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> {
|
pub trait ExternallyManagedObject<T> {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// The caller must ensure this function is only called once for a given object.
|
/// 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 {
|
pub trait DebugNameable {
|
||||||
fn debug_name(&self, device: &super::DeviceInner, name: &str);
|
fn debug_name(&self, device: &super::DeviceInner, name: &str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExternallyManagedObject<T: traits::ExternallyManagedObject<O>, O> {
|
/// Wrapper for types which are owned by another type `O`, which is responsible for destruction.
|
||||||
inner: T,
|
pub struct ExternallyManagedObject<T: traits::ExternallyManagedObject<O>, O> {
|
||||||
|
inner: ManuallyDrop<T>,
|
||||||
owner: O,
|
owner: O,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1000,12 +974,51 @@ mod asdf {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: traits::ExternallyManagedObject<O>, O> ExternallyManagedObject<T, O> {
|
impl<T: traits::ExternallyManagedObject<O>, O> ExternallyManagedObject<T, O> {
|
||||||
fn new(inner: T, owner: O) -> Self {
|
pub fn new(inner: T, owner: O) -> Self {
|
||||||
Self { inner, owner }
|
Self {
|
||||||
|
inner: ManuallyDrop::new(inner),
|
||||||
|
owner,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn owner(&self) -> &O {
|
pub fn owner(&self) -> &O {
|
||||||
&self.owner
|
&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>
|
impl<T, O> Drop for ExternallyManagedObject<T, O>
|
||||||
|
|
@ -1014,12 +1027,17 @@ mod asdf {
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
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>,
|
inner: ExternallyManagedObject<T, O>,
|
||||||
name: Option<DebugName>,
|
name: Option<DebugName>,
|
||||||
}
|
}
|
||||||
|
|
@ -1065,23 +1083,42 @@ mod asdf {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod impls {
|
mod impls {
|
||||||
use crate::device::{DeviceInner, GpuAllocation};
|
use crate::device::{DeviceInner, DevicePools, GpuAllocation};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl<T: AsRef<DeviceInner>> traits::ExternallyManagedObject<T> for ash::vk::Semaphore {
|
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 {
|
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 {
|
impl<T: AsRef<DeviceInner>> traits::ExternallyManagedObject<T> for GpuAllocation {
|
||||||
unsafe fn destroy(&mut self, device: &T) {
|
unsafe fn destroy(self, device: &T) {
|
||||||
let mut swapped = GpuAllocation::default();
|
_ = device.as_ref().alloc2.lock().free(self);
|
||||||
std::mem::swap(self, &mut swapped);
|
}
|
||||||
_ = device.as_ref().alloc2.lock().free(swapped);
|
}
|
||||||
|
|
||||||
|
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 {
|
fn summon<T>() -> T {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
@ -1125,5 +1167,14 @@ mod asdf {
|
||||||
summon::<Arc<super::DeviceInner>>(),
|
summon::<Arc<super::DeviceInner>>(),
|
||||||
summon::<GpuAllocation>(),
|
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 {
|
pub enum Fence {
|
||||||
Dedicated { fence: DeviceObject<vk::Fence> },
|
Dedicated {
|
||||||
Pooled { fence: PoolObject<vk::Fence> },
|
fence: DeviceObject<vk::Fence>,
|
||||||
|
},
|
||||||
|
Pooled {
|
||||||
|
fence: PoolObject<vk::Fence, Arc<Pool<vk::Fence>>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pooled for 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 {
|
impl std::fmt::Debug for Fence {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("Fence").field("fence", &self.raw()).finish()
|
f.debug_struct("Fence").field("fence", &self.raw()).finish()
|
||||||
|
|
@ -188,12 +202,9 @@ impl Fence {
|
||||||
fence: DeviceObject::new(fence, device, name.map(Into::into)),
|
fence: DeviceObject::new(fence, device, name.map(Into::into)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn from_pool(pool: &Pool<vk::Fence>, name: Option<&'static str>) -> Result<Fence> {
|
pub fn from_pool(pool: &Arc<Pool<vk::Fence>>, name: Option<&'static str>) -> Result<Fence> {
|
||||||
let mut fence = pool.get()?;
|
let fence = pool.get_debug_named(name)?.map_owner(|_| pool.clone());
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
if let Some(name) = name {
|
|
||||||
fence.name_object(name);
|
|
||||||
}
|
|
||||||
Ok(Self::Pooled { fence })
|
Ok(Self::Pooled { fence })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,7 +218,7 @@ impl Fence {
|
||||||
fn device(&self) -> &Arc<DeviceInner> {
|
fn device(&self) -> &Arc<DeviceInner> {
|
||||||
match self {
|
match self {
|
||||||
Fence::Dedicated { fence } => &fence.device().shared,
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct BinarySemaphore(vk::Semaphore);
|
pub(crate) struct BinarySemaphore(pub(crate) vk::Semaphore);
|
||||||
#[derive(Debug, Clone)]
|
#[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
|
// This is just so that ash can name these semaphore newtypes
|
||||||
impl vk::Handle for BinarySemaphore {
|
impl vk::Handle for BinarySemaphore {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue