simplify device ownership logic
This commit is contained in:
parent
ce46ca1801
commit
dd02ea23cf
|
|
@ -223,7 +223,7 @@ impl SingleUseCommand {
|
|||
pub fn end(&self) -> VkResult<()> {
|
||||
assert_eq!(self.state(), CommandBufferState::Recording);
|
||||
unsafe {
|
||||
self.inner.dev().dev().end_command_buffer(self.handle())?;
|
||||
self.device().dev().end_command_buffer(self.handle())?;
|
||||
}
|
||||
self.state.set_executable();
|
||||
Ok(())
|
||||
|
|
@ -288,7 +288,7 @@ impl SingleUseCommand {
|
|||
wait: Option<(vk::Semaphore, vk::PipelineStageFlags)>,
|
||||
signal: Option<vk::Semaphore>,
|
||||
) -> crate::Result<()> {
|
||||
let fence = Arc::new(sync::Fence::from_pool(&self.device().pools().fences, None)?);
|
||||
let fence = Arc::new(sync::Fence::from_pool(self.device(), None)?);
|
||||
let future = self.submit_async(wait, signal, fence)?;
|
||||
future.block()?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ impl Renderer2 {
|
|||
let future = cmds.submit(
|
||||
Some((frame.acquire, vk::PipelineStageFlags::TRANSFER)),
|
||||
Some(frame.release),
|
||||
Arc::new(sync::Fence::from_pool(&self.device.pools().fences, None)?),
|
||||
Arc::new(sync::Fence::from_pool(&self.device, None)?),
|
||||
)?;
|
||||
|
||||
future.await;
|
||||
|
|
|
|||
|
|
@ -521,7 +521,7 @@ impl Pipeline {
|
|||
device
|
||||
.dev()
|
||||
.create_compute_pipelines(
|
||||
device.pools().pipeline_cache.raw,
|
||||
device.pools.pipeline_cache.raw,
|
||||
core::slice::from_ref(info),
|
||||
None,
|
||||
)
|
||||
|
|
@ -690,7 +690,7 @@ impl Pipeline {
|
|||
device
|
||||
.dev()
|
||||
.create_graphics_pipelines(
|
||||
device.pools().pipeline_cache.raw,
|
||||
device.pools.pipeline_cache.raw,
|
||||
core::slice::from_ref(&info),
|
||||
None,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ impl Wireframe {
|
|||
let future = cmd.submit_async(
|
||||
None,
|
||||
None,
|
||||
Arc::new(sync::Fence::from_pool(&dev.pools().fences, None)?),
|
||||
Arc::new(sync::Fence::from_pool(&dev, None)?),
|
||||
)?;
|
||||
|
||||
let pipeline = Self::create_pipeline(dev.clone())?;
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@ impl Swapchain {
|
|||
tracing::trace!(frame, "acquiring image for frame {frame}");
|
||||
|
||||
async move {
|
||||
let fence = Fence::from_pool(&self.swapchain.device().pools().fences, None)?;
|
||||
let fence = Fence::from_pool(self.swapchain.device(), None)?;
|
||||
let acquire = self.acquire_semaphores[frame];
|
||||
|
||||
// spawn on threadpool because it might block.
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ use std::{
|
|||
collections::{BTreeSet, HashMap, HashSet},
|
||||
ffi::CStr,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
use ash::{
|
||||
ext, khr,
|
||||
prelude::VkResult,
|
||||
vk::{self, Handle},
|
||||
vk,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use raw_window_handle::RawDisplayHandle;
|
||||
|
|
@ -93,12 +93,16 @@ bitflags::bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
struct DeviceDrop(ash::Device);
|
||||
struct DeviceDrop {
|
||||
device: ash::Device,
|
||||
pipeline_cache: PipelineCache,
|
||||
}
|
||||
impl Drop for DeviceDrop {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
_ = self.0.device_wait_idle();
|
||||
self.0.destroy_device(None);
|
||||
_ = self.device.device_wait_idle();
|
||||
self.pipeline_cache.destroy(&self.device);
|
||||
self.device.destroy_device(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -157,6 +161,7 @@ pub struct DeviceInner {
|
|||
pub queues: DeviceQueues,
|
||||
pub sync_threadpool: sync::SyncThreadpool,
|
||||
pub device_extensions: DeviceExtensions,
|
||||
pub pools: DevicePools,
|
||||
#[allow(dead_code)]
|
||||
pub enabled_extensions: Vec<&'static CStr>,
|
||||
|
||||
|
|
@ -450,7 +455,8 @@ impl PhysicalDeviceInfo {
|
|||
},
|
||||
})?;
|
||||
|
||||
let inner = DeviceInner {
|
||||
let pipeline_cache = PipelineCache::new(&device, &self).unwrap();
|
||||
let shared = Arc::new_cyclic(|inner: &Weak<DeviceInner>| DeviceInner {
|
||||
raw: device.clone(),
|
||||
alloc2: Mutex::new(alloc2),
|
||||
instance: instance.clone(),
|
||||
|
|
@ -459,14 +465,13 @@ impl PhysicalDeviceInfo {
|
|||
device_extensions,
|
||||
enabled_extensions,
|
||||
sync_threadpool: sync::SyncThreadpool::new(),
|
||||
_drop: DeviceDrop(device),
|
||||
};
|
||||
|
||||
let shared = Arc::new(inner);
|
||||
Ok(Device {
|
||||
pools: Arc::new(DevicePools::new(shared.clone())),
|
||||
shared,
|
||||
})
|
||||
pools: DevicePools::new(inner.clone(), pipeline_cache),
|
||||
_drop: DeviceDrop {
|
||||
device,
|
||||
pipeline_cache,
|
||||
},
|
||||
});
|
||||
Ok(Device(shared))
|
||||
}
|
||||
|
||||
fn required_extensions(&self, requested_extensions: &[Extension<'static>]) -> Vec<*const i8> {
|
||||
|
|
@ -496,28 +501,19 @@ impl PhysicalDeviceInfo {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct DevicePools {
|
||||
pub pipeline_cache: asdf::DeviceObject<PipelineCache, Arc<DeviceInner>>,
|
||||
pub fences: Arc<Pool<vk::Fence>>,
|
||||
pub pipeline_cache: PipelineCache,
|
||||
pub fences: Pool<vk::Fence>,
|
||||
pub binary_semaphores: Pool<BinarySemaphore>,
|
||||
pub timeline_semaphores: Pool<TimelineSemaphore>,
|
||||
}
|
||||
|
||||
impl AsRef<DevicePools> for DevicePools {
|
||||
fn as_ref(&self) -> &DevicePools {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl DevicePools {
|
||||
pub fn new(device: Arc<DeviceInner>) -> Self {
|
||||
fn new(device: Weak<DeviceInner>, pipeline_cache: PipelineCache) -> Self {
|
||||
Self {
|
||||
fences: Arc::new(Pool::new(device.clone())),
|
||||
fences: Pool::new(device.clone()),
|
||||
binary_semaphores: Pool::new(device.clone()),
|
||||
timeline_semaphores: Pool::new(device.clone()),
|
||||
pipeline_cache: asdf::DeviceObject::new(
|
||||
device.clone(),
|
||||
PipelineCache::new(&device.raw, &device.adapter).unwrap(),
|
||||
),
|
||||
pipeline_cache,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -551,20 +547,11 @@ impl DeviceRef for &Arc<Device> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Device {
|
||||
pub(crate) shared: Arc<DeviceInner>,
|
||||
pools: Arc<DevicePools>,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn pools(&self) -> &Arc<DevicePools> {
|
||||
&self.pools
|
||||
}
|
||||
}
|
||||
pub struct Device(Arc<DeviceInner>);
|
||||
|
||||
impl PartialEq for Device {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.shared, &other.shared)
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -574,7 +561,7 @@ impl core::ops::Deref for Device {
|
|||
type Target = DeviceInner;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.shared
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -716,75 +703,7 @@ impl DeviceInner {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceOwnedDebugObject<T> {
|
||||
pub device: Device,
|
||||
pub object: T,
|
||||
#[cfg(debug_assertions)]
|
||||
name: Option<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
impl<T: Eq> Eq for DeviceOwnedDebugObject<T> {}
|
||||
impl<T: PartialEq> PartialEq for DeviceOwnedDebugObject<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::sync::Arc::ptr_eq(&self.device.shared, &other.device.shared)
|
||||
&& self.object == other.object
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: std::fmt::Debug + vk::Handle + Copy> std::fmt::Debug for DeviceOwnedDebugObject<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut fmt = f.debug_struct(core::any::type_name::<T>());
|
||||
|
||||
fmt.field_with("device", |f| {
|
||||
write!(f, "0x{:x}", self.device.raw.handle().as_raw())
|
||||
})
|
||||
.field_with("handle", |f| write!(f, "0x{:x}", &self.object.as_raw()));
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
fmt.field("name", &self.name);
|
||||
}
|
||||
|
||||
fmt.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DeviceOwnedDebugObject<T> {
|
||||
pub fn new(
|
||||
device: crate::Device,
|
||||
object: T,
|
||||
name: Option<Cow<'static, str>>,
|
||||
) -> ash::prelude::VkResult<Self>
|
||||
where
|
||||
T: vk::Handle + Copy,
|
||||
{
|
||||
if let Some(name) = name.as_ref() {
|
||||
unsafe {
|
||||
device.debug_name_object(object, name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
device,
|
||||
object,
|
||||
#[cfg(debug_assertions)]
|
||||
name,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn dev(&self) -> &crate::Device {
|
||||
&self.device
|
||||
}
|
||||
pub fn handle(&self) -> T
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
self.object
|
||||
}
|
||||
}
|
||||
|
||||
pub use asdf::{DeviceObject, InnerDeviceObject};
|
||||
pub use asdf::DeviceObject;
|
||||
|
||||
pub trait DeviceHandle {
|
||||
/// # Safety
|
||||
|
|
@ -799,23 +718,19 @@ impl<O, T: ExternallyManagedObject<O>> ExternallyManagedObject<O> for Mutex<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::Buffer {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe {
|
||||
device.as_ref().raw.destroy_buffer(self, None);
|
||||
impl ExternallyManagedObject<Device> for vk::Buffer {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_buffer(self, None) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::Image {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe { device.as_ref().raw.destroy_image(self, None) };
|
||||
impl ExternallyManagedObject<Device> for vk::Image {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_image(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::ImageView {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe { device.as_ref().raw.destroy_image_view(self, None) };
|
||||
impl ExternallyManagedObject<Device> for vk::ImageView {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_image_view(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -825,46 +740,46 @@ impl DeviceHandle for vk::DescriptorPool {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::DescriptorPool {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe { device.as_ref().raw.destroy_descriptor_pool(self, None) };
|
||||
impl ExternallyManagedObject<Device> for vk::DescriptorPool {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_descriptor_pool(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::DescriptorSetLayout {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe { device.as_ref().raw.destroy_descriptor_set_layout(self, None) };
|
||||
impl ExternallyManagedObject<Device> for vk::DescriptorSetLayout {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_descriptor_set_layout(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::PipelineLayout {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe { device.as_ref().raw.destroy_pipeline_layout(self, None) };
|
||||
impl ExternallyManagedObject<Device> for vk::PipelineLayout {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_pipeline_layout(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::Sampler {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe { device.as_ref().raw.destroy_sampler(self, None) };
|
||||
impl ExternallyManagedObject<Device> for vk::Sampler {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_sampler(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::ShaderModule {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe { device.as_ref().raw.destroy_shader_module(self, None) };
|
||||
impl ExternallyManagedObject<Device> for vk::ShaderModule {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_shader_module(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::Pipeline {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe { device.as_ref().raw.destroy_pipeline(self, None) };
|
||||
impl ExternallyManagedObject<Device> for vk::Pipeline {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_pipeline(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::SwapchainKHR {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
impl ExternallyManagedObject<Device> for vk::SwapchainKHR {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe {
|
||||
if let Some(swapchain) = device.as_ref().device_extensions.swapchain.as_ref() {
|
||||
if let Some(swapchain) = device.device_extensions.swapchain.as_ref() {
|
||||
swapchain.destroy_swapchain(self, None)
|
||||
}
|
||||
}
|
||||
|
|
@ -880,17 +795,22 @@ pub trait Pooled: Sized {
|
|||
fn create_from_pool(pool: &Pool<Self>) -> Result<Self>;
|
||||
}
|
||||
|
||||
/// A pooled handle which knows how to return itself to its pool.
|
||||
pub trait Recycle: Sized {
|
||||
fn recycle(self, device: &Device);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pool<T> {
|
||||
pub pool: Mutex<Vec<T>>,
|
||||
pub device: Arc<DeviceInner>,
|
||||
device: Weak<DeviceInner>,
|
||||
}
|
||||
|
||||
impl<T> Pool<T> {
|
||||
pub fn push(&self, item: T) {
|
||||
self.pool.lock().push(item);
|
||||
}
|
||||
pub fn new(device: Arc<DeviceInner>) -> Self {
|
||||
pub fn new(device: Weak<DeviceInner>) -> Self {
|
||||
Self {
|
||||
pool: Mutex::new(Vec::new()),
|
||||
device,
|
||||
|
|
@ -899,6 +819,10 @@ impl<T> Pool<T> {
|
|||
pub fn pop(&self) -> Option<T> {
|
||||
self.pool.lock().pop()
|
||||
}
|
||||
|
||||
pub fn device(&self) -> Arc<DeviceInner> {
|
||||
self.device.upgrade().expect("pool outlived its device")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<Pool<T>> for Pool<T> {
|
||||
|
|
@ -907,7 +831,43 @@ impl<T> AsRef<Pool<T>> for Pool<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type PoolObject<T, U = Arc<Pool<T>>> = asdf::ExternallyManagedObject<T, U>;
|
||||
pub struct PoolObject<T: Recycle> {
|
||||
inner: std::mem::ManuallyDrop<T>,
|
||||
device: Device,
|
||||
}
|
||||
|
||||
impl<T: Recycle> PoolObject<T> {
|
||||
pub fn new(inner: T, device: Device) -> Self {
|
||||
Self {
|
||||
inner: std::mem::ManuallyDrop::new(inner),
|
||||
device,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn device(&self) -> &Device {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Recycle> Deref for PoolObject<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Recycle> DerefMut for PoolObject<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Recycle> Drop for PoolObject<T> {
|
||||
fn drop(&mut self) {
|
||||
let inner = unsafe { std::mem::ManuallyDrop::take(&mut self.inner) };
|
||||
inner.recycle(&self.device);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pooled> Pool<T> {
|
||||
pub fn get(&self) -> Result<T> {
|
||||
|
|
@ -929,7 +889,8 @@ impl<T: Pooled> Pool<T> {
|
|||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let name = name.map(Into::into).unwrap_or_default();
|
||||
<T as asdf::traits::DebugNameable>::debug_name(&obj, &self.device, &name);
|
||||
let device = self.device();
|
||||
<T as asdf::traits::DebugNameable>::debug_name(&obj, &device, &name);
|
||||
}
|
||||
|
||||
Ok(obj)
|
||||
|
|
@ -946,7 +907,7 @@ macro_rules! define_device_owned_handle {
|
|||
} $(=> |$this:ident| $dtor:stmt)?) => {
|
||||
$(#[$attr])*
|
||||
$ty_vis struct $ty {
|
||||
inner: $crate::device::DeviceOwnedDebugObject<$handle>,
|
||||
inner: $crate::device::DeviceObject<$handle>,
|
||||
$(
|
||||
$(#[$field_attr])*
|
||||
$field_vis $field_name: $field_ty,
|
||||
|
|
@ -955,10 +916,10 @@ macro_rules! define_device_owned_handle {
|
|||
|
||||
impl $crate::device::DeviceOwned<$handle> for $ty {
|
||||
fn device(&self) -> &$crate::device::Device {
|
||||
self.inner.dev()
|
||||
self.inner.device()
|
||||
}
|
||||
fn handle(&self) -> $handle {
|
||||
self.inner.handle()
|
||||
*self.inner
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -971,11 +932,11 @@ macro_rules! define_device_owned_handle {
|
|||
$($field_name: $field_ty,)*
|
||||
) -> ::ash::prelude::VkResult<Self> {
|
||||
Ok(Self {
|
||||
inner: $crate::device::DeviceOwnedDebugObject::new(
|
||||
inner: $crate::device::DeviceObject::new_debug_named(
|
||||
device,
|
||||
handle,
|
||||
name,
|
||||
)?,
|
||||
),
|
||||
$($field_name,)*
|
||||
})
|
||||
}
|
||||
|
|
@ -993,19 +954,17 @@ macro_rules! define_device_owned_handle {
|
|||
};
|
||||
}
|
||||
|
||||
// This module is an experiment in a more generic way to manage device-owned resources.
|
||||
// #[cfg(false)]
|
||||
pub mod asdf {
|
||||
use std::{
|
||||
mem::{ManuallyDrop, MaybeUninit},
|
||||
mem::ManuallyDrop,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use ash::vk;
|
||||
use ash::vk::Handle;
|
||||
|
||||
use crate::device::{DebugName, DeviceInner};
|
||||
use crate::Device;
|
||||
|
||||
pub mod traits {
|
||||
/// A trait describing an object owned by some manager-type, which is
|
||||
|
|
@ -1050,45 +1009,6 @@ pub mod asdf {
|
|||
owner,
|
||||
}
|
||||
}
|
||||
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>
|
||||
|
|
@ -1103,95 +1023,56 @@ pub mod asdf {
|
|||
}
|
||||
}
|
||||
|
||||
pub type InnerDeviceObject<T> = DeviceObject<T, Arc<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> = super::Device,
|
||||
> {
|
||||
inner: ExternallyManagedObject<T, O>,
|
||||
pub struct DeviceObject<T: traits::ExternallyManagedObject<Device>> {
|
||||
inner: ExternallyManagedObject<T, Device>,
|
||||
#[allow(dead_code)]
|
||||
name: Option<DebugName>,
|
||||
}
|
||||
|
||||
impl<
|
||||
T: traits::ExternallyManagedObject<O> + traits::DebugNameable,
|
||||
O: AsRef<super::DeviceInner>,
|
||||
> DeviceObject<T, O>
|
||||
{
|
||||
pub fn new_debug_named(owner: O, inner: T, name: Option<impl Into<DebugName>>) -> Self {
|
||||
impl<T: traits::ExternallyManagedObject<Device> + traits::DebugNameable> DeviceObject<T> {
|
||||
pub fn new_debug_named(
|
||||
device: Device,
|
||||
inner: T,
|
||||
name: Option<impl Into<DebugName>>,
|
||||
) -> Self {
|
||||
let name = name.map(Into::into);
|
||||
if let Some(ref name) = name {
|
||||
traits::DebugNameable::debug_name(&inner, owner.as_ref(), name);
|
||||
traits::DebugNameable::debug_name(&inner, &device, name);
|
||||
}
|
||||
|
||||
let obj = ExternallyManagedObject::new(inner, owner);
|
||||
let obj = ExternallyManagedObject::new(inner, device);
|
||||
|
||||
Self { inner: obj, name }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: traits::ExternallyManagedObject<O>, O: AsRef<super::DeviceInner>> DeviceObject<T, O> {
|
||||
pub fn new(owner: O, inner: T) -> Self {
|
||||
let inner = ExternallyManagedObject::new(inner, owner);
|
||||
impl<T: traits::ExternallyManagedObject<Device>> DeviceObject<T> {
|
||||
pub fn new(device: Device, inner: T) -> Self {
|
||||
let inner = ExternallyManagedObject::new(inner, device);
|
||||
|
||||
Self { inner, name: None }
|
||||
}
|
||||
|
||||
pub fn new_debug_named_with<D>(
|
||||
owner: O,
|
||||
inner: T,
|
||||
name: Option<impl Into<DebugName>>,
|
||||
debug_namable: impl FnOnce(&T) -> D,
|
||||
) -> Self
|
||||
pub fn device(&self) -> &Device {
|
||||
&self.inner.owner
|
||||
}
|
||||
|
||||
pub fn handle(&self) -> T
|
||||
where
|
||||
D: traits::DebugNameable,
|
||||
T: Copy,
|
||||
{
|
||||
let name = name.map(Into::into);
|
||||
if let Some(ref name) = name {
|
||||
traits::DebugNameable::debug_name(&debug_namable(&inner), owner.as_ref(), name);
|
||||
}
|
||||
|
||||
let obj = ExternallyManagedObject::new(inner, owner);
|
||||
|
||||
Self { inner: obj, name }
|
||||
}
|
||||
|
||||
pub fn device(&self) -> &O {
|
||||
self.inner.owner()
|
||||
*Deref::deref(self)
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Option<&str> {
|
||||
self.name.as_ref().map(|n| &**n)
|
||||
}
|
||||
|
||||
pub fn map_inner<U>(self, f: impl FnOnce(T) -> U) -> DeviceObject<U, O>
|
||||
where
|
||||
U: traits::ExternallyManagedObject<O>,
|
||||
{
|
||||
DeviceObject {
|
||||
inner: self.inner.map_inner(f),
|
||||
name: self.name,
|
||||
self.name.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_owner<U>(self, f: impl FnOnce(O) -> U) -> DeviceObject<T, U>
|
||||
impl<T> std::fmt::Debug for DeviceObject<T>
|
||||
where
|
||||
T: traits::ExternallyManagedObject<U>,
|
||||
U: AsRef<super::DeviceInner>,
|
||||
{
|
||||
DeviceObject {
|
||||
inner: self.inner.map_owner(f),
|
||||
name: self.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, O> std::fmt::Debug for DeviceObject<T, O>
|
||||
where
|
||||
T: std::fmt::Debug + traits::ExternallyManagedObject<O>,
|
||||
O: AsRef<super::DeviceInner>,
|
||||
T: std::fmt::Debug + traits::ExternallyManagedObject<Device>,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut fmt = f.debug_struct(core::any::type_name::<T>());
|
||||
|
|
@ -1200,8 +1081,7 @@ pub mod asdf {
|
|||
fmt.field_with("device", |f| {
|
||||
write!(
|
||||
f,
|
||||
"0x{:x}",
|
||||
self.inner.owner().as_ref().raw.handle().as_raw()
|
||||
"0x{:x}", self.inner.owner.raw.handle().as_raw()
|
||||
)
|
||||
})
|
||||
.field_with("handle", |f| write!(f, "{inner:?}"))
|
||||
|
|
@ -1211,10 +1091,9 @@ pub mod asdf {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, O> Deref for DeviceObject<T, O>
|
||||
impl<T> Deref for DeviceObject<T>
|
||||
where
|
||||
T: traits::ExternallyManagedObject<O>,
|
||||
O: AsRef<super::DeviceInner>,
|
||||
T: traits::ExternallyManagedObject<Device>,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
|
|
@ -1223,10 +1102,9 @@ pub mod asdf {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, O> DerefMut for DeviceObject<T, O>
|
||||
impl<T> DerefMut for DeviceObject<T>
|
||||
where
|
||||
T: traits::ExternallyManagedObject<O>,
|
||||
O: AsRef<super::DeviceInner>,
|
||||
T: traits::ExternallyManagedObject<Device>,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
|
|
@ -1234,29 +1112,39 @@ pub mod asdf {
|
|||
}
|
||||
|
||||
mod impls {
|
||||
use crate::device::{DeviceInner, DevicePools, GpuAllocation};
|
||||
use crate::device::GpuAllocation;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl<T: AsRef<DeviceInner>> traits::ExternallyManagedObject<T> for vk::Semaphore {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe {
|
||||
device.as_ref().raw.destroy_semaphore(self, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> traits::ExternallyManagedObject<T> for GpuAllocation {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
_ = device.as_ref().alloc2.lock().free(self);
|
||||
impl traits::ExternallyManagedObject<Device> for vk::Semaphore {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_semaphore(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
impl traits::ExternallyManagedObject<DevicePools> for vk::Semaphore {
|
||||
unsafe fn destroy(self, owner: &DevicePools) {
|
||||
owner
|
||||
.binary_semaphores
|
||||
.push(crate::sync::BinarySemaphore(self));
|
||||
impl traits::ExternallyManagedObject<Device> for GpuAllocation {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
_ = device.alloc2.lock().free(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl traits::ExternallyManagedObject<Device> for vk::CommandBuffer {
|
||||
unsafe fn destroy(self, _: &Device) {}
|
||||
}
|
||||
|
||||
impl traits::ExternallyManagedObject<Device> for vk::CommandPool {
|
||||
unsafe fn destroy(self, _: &Device) {}
|
||||
}
|
||||
|
||||
impl<T> crate::device::DeviceOwned<T> for DeviceObject<T>
|
||||
where
|
||||
T: vk::Handle + Copy + traits::ExternallyManagedObject<Device>,
|
||||
{
|
||||
fn device(&self) -> &Device {
|
||||
self.device()
|
||||
}
|
||||
fn handle(&self) -> T {
|
||||
self.handle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1275,30 +1163,27 @@ pub mod asdf {
|
|||
#[allow(dead_code)]
|
||||
#[cfg(test)]
|
||||
fn asdf() {
|
||||
use crate::device::{DevicePools, GpuAllocation};
|
||||
use crate::device::GpuAllocation;
|
||||
fn summon<T>() -> T {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
let _inner_ref: DeviceObject<vk::Semaphore, &DeviceInner> = DeviceObject::new_debug_named(
|
||||
summon::<&DeviceInner>(),
|
||||
let _inner_ref: DeviceObject<vk::Semaphore> = DeviceObject::new_debug_named(
|
||||
summon::<Device>(),
|
||||
summon::<vk::Semaphore>(),
|
||||
Some("my semaphore"),
|
||||
);
|
||||
|
||||
let _device_owned: DeviceObject<vk::Semaphore, super::Device> =
|
||||
DeviceObject::new_debug_named(
|
||||
let _device_owned: DeviceObject<vk::Semaphore> = DeviceObject::new_debug_named(
|
||||
summon::<super::Device>(),
|
||||
summon::<vk::Semaphore>(),
|
||||
Some("my other semaphore"),
|
||||
);
|
||||
|
||||
let _allocation: DeviceObject<GpuAllocation, Arc<super::DeviceInner>> = DeviceObject::new(
|
||||
summon::<Arc<super::DeviceInner>>(),
|
||||
summon::<GpuAllocation>(),
|
||||
);
|
||||
let _allocation: DeviceObject<GpuAllocation> =
|
||||
DeviceObject::new(summon::<Device>(), summon::<GpuAllocation>());
|
||||
|
||||
let _pool_owned: ExternallyManagedObject<vk::Semaphore, DevicePools> =
|
||||
ExternallyManagedObject::new(summon::<vk::Semaphore>(), summon::<DevicePools>());
|
||||
let _pool_owned: DeviceObject<vk::Semaphore> =
|
||||
DeviceObject::new(summon::<Device>(), summon::<vk::Semaphore>());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ mod device_ref_derive_tests {
|
|||
}
|
||||
|
||||
#[derive(renderer_macros::DeviceRef)]
|
||||
struct GenericWrapper<D> {
|
||||
struct GenericWrapper<D: DeviceRef> {
|
||||
#[device]
|
||||
device: D,
|
||||
tag: &'static str,
|
||||
|
|
|
|||
|
|
@ -1,23 +1,19 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ash::vk;
|
||||
|
||||
use ash::Device;
|
||||
|
||||
use crate::PhysicalDeviceInfo;
|
||||
use crate::device::DeviceInner;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PipelineCache {
|
||||
#[allow(dead_code)]
|
||||
key: u128,
|
||||
pub raw: vk::PipelineCache,
|
||||
}
|
||||
|
||||
impl crate::device::asdf::traits::ExternallyManagedObject<Arc<DeviceInner>> for PipelineCache {
|
||||
unsafe fn destroy(self, owner: &Arc<DeviceInner>) {
|
||||
impl PipelineCache {
|
||||
pub(crate) unsafe fn destroy(self, device: &ash::Device) {
|
||||
tracing::info!("destroying pipeline cache with key {:x}", self.key);
|
||||
if let Ok(data) = self.export(&owner.raw) {
|
||||
if let Ok(data) = self.export(device) {
|
||||
tracing::info!(
|
||||
"exported pipeline cache with key {:x} and size {} bytes",
|
||||
self.key,
|
||||
|
|
@ -27,11 +23,9 @@ impl crate::device::asdf::traits::ExternallyManagedObject<Arc<DeviceInner>> for
|
|||
tracing::error!("failed to write pipeline cache to disk: {err}");
|
||||
});
|
||||
}
|
||||
unsafe { owner.raw.destroy_pipeline_cache(self.raw, None) };
|
||||
}
|
||||
unsafe { device.destroy_pipeline_cache(self.raw, None) };
|
||||
}
|
||||
|
||||
impl PipelineCache {
|
||||
const MAGIC: [u8; 4] = *b"VYPC";
|
||||
const KEY_VERSION: u32 = 1;
|
||||
const PATH: &'static str = "pipeline_cache.bin";
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::device::{
|
||||
DevicePools, Pool, PoolObject, Pooled,
|
||||
Pool, PoolObject, Pooled, Recycle,
|
||||
asdf::{
|
||||
DeviceObject, InnerDeviceObject,
|
||||
DeviceObject,
|
||||
traits::ExternallyManagedObject as ExternallyManagedObjectTrait,
|
||||
},
|
||||
};
|
||||
|
|
@ -160,17 +160,17 @@ impl SyncThreadpool {
|
|||
|
||||
pub enum Fence {
|
||||
Dedicated {
|
||||
fence: InnerDeviceObject<vk::Fence>,
|
||||
fence: DeviceObject<vk::Fence>,
|
||||
},
|
||||
Pooled {
|
||||
fence: PoolObject<vk::Fence, Arc<Pool<vk::Fence>>>,
|
||||
fence: PoolObject<vk::Fence>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Pooled for vk::Fence {
|
||||
fn create_from_pool(pool: &Pool<Self>) -> Result<Self> {
|
||||
let fence = unsafe {
|
||||
pool.device
|
||||
pool.device()
|
||||
.raw
|
||||
.create_fence(&vk::FenceCreateInfo::default(), None)?
|
||||
};
|
||||
|
|
@ -179,17 +179,15 @@ impl Pooled for vk::Fence {
|
|||
}
|
||||
}
|
||||
|
||||
impl ExternallyManagedObjectTrait<Arc<Pool<vk::Fence>>> for vk::Fence {
|
||||
unsafe fn destroy(self, pool: &Arc<Pool<vk::Fence>>) {
|
||||
pool.push(self);
|
||||
impl Recycle for vk::Fence {
|
||||
fn recycle(self, device: &Device) {
|
||||
device.pools.fences.push(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<DeviceInner>> ExternallyManagedObjectTrait<T> for vk::Fence {
|
||||
unsafe fn destroy(self, device: &T) {
|
||||
unsafe {
|
||||
device.as_ref().raw.destroy_fence(self, None);
|
||||
}
|
||||
impl ExternallyManagedObjectTrait<Device> for vk::Fence {
|
||||
unsafe fn destroy(self, device: &Device) {
|
||||
unsafe { device.raw.destroy_fence(self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -207,14 +205,14 @@ impl Fence {
|
|||
.create_fence(&vk::FenceCreateInfo::default(), None)?
|
||||
};
|
||||
Ok(Self::Dedicated {
|
||||
fence: DeviceObject::new_debug_named(device.shared.clone(), fence, name),
|
||||
fence: DeviceObject::new_debug_named(device, fence, name),
|
||||
})
|
||||
}
|
||||
pub fn from_pool(pool: &Arc<Pool<vk::Fence>>, name: Option<&'static str>) -> Result<Fence> {
|
||||
let fence = pool.get_debug_named(name)?;
|
||||
pub fn from_pool(device: &Device, name: Option<&'static str>) -> Result<Fence> {
|
||||
let fence = device.pools.fences.get_debug_named(name)?;
|
||||
|
||||
Ok(Self::Pooled {
|
||||
fence: PoolObject::new(fence, pool.clone()),
|
||||
fence: PoolObject::new(fence, device.clone()),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -225,10 +223,10 @@ impl Fence {
|
|||
}
|
||||
}
|
||||
|
||||
fn device(&self) -> &Arc<DeviceInner> {
|
||||
fn device(&self) -> &Device {
|
||||
match self {
|
||||
Fence::Dedicated { fence } => &fence.device(),
|
||||
Fence::Pooled { fence } => &fence.owner().device,
|
||||
Fence::Dedicated { fence } => fence.device(),
|
||||
Fence::Pooled { fence } => fence.device(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,21 +276,21 @@ pub enum SemaphoreInner {
|
|||
Timeline(vk::Semaphore),
|
||||
}
|
||||
|
||||
impl ExternallyManagedObjectTrait<Arc<DevicePools>> for SemaphoreInner {
|
||||
unsafe fn destroy(self, owner: &Arc<DevicePools>) {
|
||||
impl Recycle for SemaphoreInner {
|
||||
fn recycle(self, owner: &Device) {
|
||||
match self {
|
||||
SemaphoreInner::Binary(semaphore) => {
|
||||
owner.binary_semaphores.push(BinarySemaphore(semaphore))
|
||||
owner.pools.binary_semaphores.push(BinarySemaphore(semaphore))
|
||||
}
|
||||
SemaphoreInner::Timeline(semaphore) => {
|
||||
owner.timeline_semaphores.push(TimelineSemaphore(semaphore))
|
||||
owner.pools.timeline_semaphores.push(TimelineSemaphore(semaphore))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternallyManagedObjectTrait<Arc<DeviceInner>> for SemaphoreInner {
|
||||
unsafe fn destroy(self, owner: &Arc<DeviceInner>) {
|
||||
impl ExternallyManagedObjectTrait<Device> for SemaphoreInner {
|
||||
unsafe fn destroy(self, owner: &Device) {
|
||||
match self {
|
||||
SemaphoreInner::Binary(semaphore) | SemaphoreInner::Timeline(semaphore) => {
|
||||
unsafe { owner.raw.destroy_semaphore(semaphore, None) };
|
||||
|
|
@ -336,11 +334,11 @@ impl From<TimelineSemaphore> for SemaphoreInner {
|
|||
|
||||
pub enum Semaphore {
|
||||
Dedicated {
|
||||
semaphore: InnerDeviceObject<SemaphoreInner>,
|
||||
semaphore: DeviceObject<SemaphoreInner>,
|
||||
},
|
||||
Pooled {
|
||||
#[allow(private_interfaces)]
|
||||
semaphore: PoolObject<SemaphoreInner, Arc<DevicePools>>,
|
||||
semaphore: PoolObject<SemaphoreInner>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -379,7 +377,7 @@ impl Pooled for BinarySemaphore {
|
|||
let mut type_info =
|
||||
vk::SemaphoreTypeCreateInfo::default().semaphore_type(vk::SemaphoreType::BINARY);
|
||||
let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info);
|
||||
let inner = unsafe { pool.device.raw.create_semaphore(&create_info, None)? };
|
||||
let inner = unsafe { pool.device().raw.create_semaphore(&create_info, None)? };
|
||||
Ok(Self(inner))
|
||||
}
|
||||
}
|
||||
|
|
@ -390,7 +388,7 @@ impl Pooled for TimelineSemaphore {
|
|||
.semaphore_type(vk::SemaphoreType::TIMELINE)
|
||||
.initial_value(0);
|
||||
let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info);
|
||||
let inner = unsafe { pool.device.raw.create_semaphore(&create_info, None)? };
|
||||
let inner = unsafe { pool.device().raw.create_semaphore(&create_info, None)? };
|
||||
Ok(Self(inner))
|
||||
}
|
||||
}
|
||||
|
|
@ -421,7 +419,7 @@ impl Semaphore {
|
|||
};
|
||||
|
||||
Ok(Self::Dedicated {
|
||||
semaphore: DeviceObject::new_debug_named(device.shared.clone(), inner, name),
|
||||
semaphore: DeviceObject::new_debug_named(device, inner, name),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -433,12 +431,12 @@ impl Semaphore {
|
|||
let semaphore = match semaphore_type {
|
||||
SemaphoreType::Binary => {
|
||||
let semaphore: SemaphoreInner =
|
||||
device.pools().binary_semaphores.get_debug_named(name)?.into();
|
||||
PoolObject::new(semaphore, device.pools().clone())
|
||||
device.pools.binary_semaphores.get_debug_named(name)?.into();
|
||||
PoolObject::new(semaphore, device)
|
||||
}
|
||||
SemaphoreType::Timeline(value) => {
|
||||
let semaphore: SemaphoreInner = device
|
||||
.pools()
|
||||
.pools
|
||||
.timeline_semaphores
|
||||
.get_debug_named(name)?
|
||||
.into();
|
||||
|
|
@ -450,7 +448,7 @@ impl Semaphore {
|
|||
device.raw.signal_semaphore(&info)?;
|
||||
}
|
||||
|
||||
PoolObject::new(semaphore, device.pools().clone())
|
||||
PoolObject::new(semaphore, device)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue