diff --git a/crates/renderer/src/device.rs b/crates/renderer/src/device.rs index aa39daf..6d9e103 100644 --- a/crates/renderer/src/device.rs +++ b/crates/renderer/src/device.rs @@ -110,11 +110,15 @@ pub struct DeviceInner { #[allow(dead_code)] pub(crate) enabled_extensions: Vec<&'static CStr>, - pub(crate) pipeline_cache: PipelineCache, - _drop: DeviceDrop, } +impl AsRef for DeviceInner { + fn as_ref(&self) -> &DeviceInner { + self + } +} + impl core::fmt::Debug for DeviceInner { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("DeviceInner") @@ -400,7 +404,6 @@ impl PhysicalDeviceInfo { raw: device.clone(), alloc2: Mutex::new(alloc2), instance: instance.clone(), - pipeline_cache: PipelineCache::new(&device, &self)?, adapter: self, queues: device_queues, device_extensions, @@ -446,6 +449,13 @@ pub(crate) struct DevicePools { pub(crate) fences: Arc>, pub(crate) binary_semaphores: Pool, pub(crate) timeline_semaphores: Pool, + pub(crate) pipeline_cache: asdf::DeviceObject>, +} + +impl AsRef for DevicePools { + fn as_ref(&self) -> &DevicePools { + self + } } impl DevicePools { @@ -453,7 +463,11 @@ impl DevicePools { Self { fences: Arc::new(Pool::new(device.clone())), binary_semaphores: Pool::new(device.clone()), - timeline_semaphores: Pool::new(device), + timeline_semaphores: Pool::new(device.clone()), + pipeline_cache: asdf::DeviceObject::new( + device.clone(), + PipelineCache::new(&device.raw, &device.adapter).unwrap(), + ), } } } @@ -740,7 +754,7 @@ impl DeviceObject { pub fn name(&self) -> Option<&str> { #[cfg(debug_assertions)] { - self.name.as_deref().map(|cow| cow.as_ref()) + self.name.as_deref() } #[cfg(not(debug_assertions))] { @@ -833,23 +847,20 @@ impl AsRef> for Pool { } } -pub type PoolObject>> = asdf::ExternallyManagedObject; +pub type PoolObject>> = asdf::ExternallyManagedObject; -impl<'a, T: Pooled + asdf::traits::ExternallyManagedObject<&'a Pool> + 'a> Pool { - pub fn get(&'a self) -> Result>> { +impl Pool { + pub fn get(&self) -> Result { let item = if let Some(item) = self.pool.lock().pop() { item } else { T::create_from_pool(self)? }; - Ok(asdf::ExternallyManagedObject::new(item, self)) + Ok(item) } - pub fn get_debug_named( - &'a self, - name: Option>>, - ) -> Result>> + pub fn get_debug_named(&self, name: Option>>) -> Result where T: asdf::traits::DebugNameable, { @@ -933,10 +944,7 @@ pub(crate) mod asdf { use ash::vk; - use crate::{ - device::{DeviceInner, DevicePools, GpuAllocation}, - util::DebugName, - }; + use crate::{device::DeviceInner, util::DebugName}; pub mod traits { /// A trait describing an object owned by some manager-type, which is @@ -954,6 +962,7 @@ pub(crate) mod asdf { } /// Wrapper for types which are owned by another type `O`, which is responsible for destruction. + #[derive(Debug)] pub struct ExternallyManagedObject, O> { inner: ManuallyDrop, owner: O, @@ -1034,11 +1043,13 @@ pub(crate) mod asdf { } /// A wrapper for vulkan types which are owned by the device, taking care of destruction. + #[derive(Debug)] pub struct DeviceObject< T: traits::ExternallyManagedObject, O: AsRef = Arc, > { inner: ExternallyManagedObject, + #[allow(dead_code)] name: Option, } @@ -1047,7 +1058,7 @@ pub(crate) mod asdf { O: AsRef, > DeviceObject { - fn new_debug_named(owner: O, inner: T, name: Option>) -> Self { + pub fn new_debug_named(owner: O, inner: T, name: Option>) -> Self { let name = name.map(Into::into); if let Some(ref name) = name { traits::DebugNameable::debug_name(&inner, owner.as_ref(), name); @@ -1060,12 +1071,12 @@ pub(crate) mod asdf { } impl, O: AsRef> DeviceObject { - fn new(owner: O, inner: T) -> Self { + pub fn new(owner: O, inner: T) -> Self { let inner = ExternallyManagedObject::new(inner, owner); Self { inner, name: None } } - fn device(&self) -> &O { + pub fn device(&self) -> &O { self.inner.owner() } } @@ -1109,25 +1120,6 @@ pub(crate) mod asdf { } } - impl traits::ExternallyManagedObject 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)), - } - } - } - - impl AsRef for DeviceInner { - fn as_ref(&self) -> &DeviceInner { - self - } - } - impl traits::DebugNameable for T where T: vk::Handle + Copy, @@ -1140,41 +1132,33 @@ pub(crate) mod asdf { } } - enum Semaphore { - Binary(vk::Semaphore), - Timeline(vk::Semaphore), - } - - fn summon() -> T { - unimplemented!() - } - + #[allow(dead_code)] + #[cfg(test)] fn asdf() { - let inner_ref: DeviceObject = DeviceObject::new_debug_named( + use crate::device::{DevicePools, GpuAllocation}; + fn summon() -> T { + unimplemented!() + } + + let _inner_ref: DeviceObject = DeviceObject::new_debug_named( summon::<&DeviceInner>(), summon::(), Some("my semaphore"), ); - let device_owned: DeviceObject = + let _device_owned: DeviceObject = DeviceObject::new_debug_named( summon::(), summon::(), Some("my other semaphore"), ); - let allocation: DeviceObject> = DeviceObject::new( + let _allocation: DeviceObject> = DeviceObject::new( summon::>(), summon::(), ); - let pool_owned: ExternallyManagedObject = + let _pool_owned: ExternallyManagedObject = ExternallyManagedObject::new(summon::(), summon::()); - - let enum_semaphore_pooled: ExternallyManagedObject = - ExternallyManagedObject::new( - Semaphore::Binary(summon::()), - summon::(), - ); } } diff --git a/crates/renderer/src/pipeline.rs b/crates/renderer/src/pipeline.rs index a2043ac..c5a221c 100644 --- a/crates/renderer/src/pipeline.rs +++ b/crates/renderer/src/pipeline.rs @@ -503,7 +503,7 @@ impl Pipeline { device .dev() .create_compute_pipelines( - device.pipeline_cache.raw, + device.pools.pipeline_cache.raw, core::slice::from_ref(info), None, ) @@ -575,27 +575,23 @@ impl Pipeline { }); let multisample = desc.multisample.map(|state| { - let info = vk::PipelineMultisampleStateCreateInfo::default() + vk::PipelineMultisampleStateCreateInfo::default() .flags(state.flags) .min_sample_shading(state.min_sample_shading) .rasterization_samples(state.rasterization_samples) .sample_mask(state.sample_mask) .sample_shading_enable(state.sample_shading_enable) .alpha_to_coverage_enable(state.alpha_to_coverage_enable) - .alpha_to_one_enable(state.alpha_to_one_enable); - - info + .alpha_to_one_enable(state.alpha_to_one_enable) }); let color_blend = desc.color_blend.map(|state| { - let info = vk::PipelineColorBlendStateCreateInfo::default() + vk::PipelineColorBlendStateCreateInfo::default() .flags(state.flags) .attachments(state.attachments) .blend_constants(state.blend_constants) .logic_op(state.logic_op.unwrap_or(Default::default())) - .logic_op_enable(state.logic_op.is_some()); - - info + .logic_op_enable(state.logic_op.is_some()) }); let depth_stencil = desc.depth_stencil.map(|state| { @@ -625,20 +621,16 @@ impl Pipeline { }); let dynamic = desc.dynamic.map(|state| { - let info = vk::PipelineDynamicStateCreateInfo::default() + vk::PipelineDynamicStateCreateInfo::default() .flags(state.flags) - .dynamic_states(state.dynamic_states); - - info + .dynamic_states(state.dynamic_states) }); let mut rendering = desc.rendering.map(|state| { - let info = vk::PipelineRenderingCreateInfo::default() + vk::PipelineRenderingCreateInfo::default() .color_attachment_formats(state.color_formats) .depth_attachment_format(state.depth_format.unwrap_or_default()) - .stencil_attachment_format(state.stencil_format.unwrap_or_default()); - - info + .stencil_attachment_format(state.stencil_format.unwrap_or_default()) }); fn option_to_ptr(option: &Option) -> *const T { @@ -679,7 +671,7 @@ impl Pipeline { device .dev() .create_graphics_pipelines( - device.pipeline_cache.raw, + device.pools.pipeline_cache.raw, core::slice::from_ref(&info), None, ) @@ -704,17 +696,33 @@ impl Pipeline { } pub(crate) mod pipeline_cache { + use std::sync::Arc; + use ash::vk; use ash::Device; use crate::PhysicalDeviceInfo; + use crate::device::DeviceInner; + #[derive(Debug)] pub struct PipelineCache { + #[allow(dead_code)] key: u128, pub(crate) raw: vk::PipelineCache, } + impl crate::device::asdf::traits::ExternallyManagedObject> for PipelineCache { + unsafe fn destroy(self, owner: &Arc) { + if let Ok(data) = self.export(&owner.raw) { + _ = Self::write_to_disk(self.key, &data).inspect_err(|err| { + tracing::error!("failed to write pipeline cache to disk: {err}"); + }); + } + unsafe { owner.raw.destroy_pipeline_cache(self.raw, None) }; + } + } + impl PipelineCache { const MAGIC: [u8; 4] = *b"VYPC"; const KEY_VERSION: u32 = 1; @@ -785,7 +793,7 @@ pub(crate) mod pipeline_cache { }); let info = vk::PipelineCacheCreateInfo::default() - .flags(vk::PipelineCacheCreateFlags::EXTERNALLY_SYNCHRONIZED) + // .flags(vk::PipelineCacheCreateFlags::EXTERNALLY_SYNCHRONIZED) .initial_data(data.as_deref().unwrap_or_default()); let cache = unsafe { device.create_pipeline_cache(&info, None)? }; diff --git a/crates/renderer/src/sync.rs b/crates/renderer/src/sync.rs index efe7327..ec630cd 100644 --- a/crates/renderer/src/sync.rs +++ b/crates/renderer/src/sync.rs @@ -1,5 +1,3 @@ -#[cfg(debug_assertions)] -use std::borrow::Cow; use std::{ future::Future, marker::PhantomData, @@ -7,7 +5,10 @@ use std::{ time::Duration, }; -use crate::device::{DeviceObject, Pool, PoolObject, Pooled}; +use crate::device::{ + DevicePools, Pool, PoolObject, Pooled, + asdf::{DeviceObject, traits::ExternallyManagedObject as ExternallyManagedObjectTrait}, +}; use crate::{Result, device::DeviceInner}; use super::Device; @@ -175,16 +176,20 @@ impl Pooled for vk::Fence { } } -impl crate::device::asdf::traits::ExternallyManagedObject for vk::Fence -where - T: AsRef>, -{ - unsafe fn destroy(self, owner: &T) { - let pool = owner.as_ref(); +impl ExternallyManagedObjectTrait>> for vk::Fence { + unsafe fn destroy(self, pool: &Arc>) { pool.push(self); } } +impl ExternallyManagedObjectTrait> for vk::Fence { + unsafe fn destroy(self, device: &Arc) { + unsafe { + device.raw.destroy_fence(self, None); + } + } +} + 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() @@ -199,13 +204,15 @@ impl Fence { .create_fence(&vk::FenceCreateInfo::default(), None)? }; Ok(Self::Dedicated { - fence: DeviceObject::new(fence, device, name.map(Into::into)), + fence: DeviceObject::new_debug_named(device.shared, fence, name), }) } pub fn from_pool(pool: &Arc>, name: Option<&'static str>) -> Result { - let fence = pool.get_debug_named(name)?.map_owner(|_| pool.clone()); + let fence = pool.get_debug_named(name)?; - Ok(Self::Pooled { fence }) + Ok(Self::Pooled { + fence: PoolObject::new(fence, pool.clone()), + }) } pub fn raw(&self) -> vk::Fence { @@ -217,7 +224,7 @@ impl Fence { fn device(&self) -> &Arc { match self { - Fence::Dedicated { fence } => &fence.device().shared, + Fence::Dedicated { fence } => &fence.device(), Fence::Pooled { fence } => &fence.owner().device, } } @@ -262,23 +269,81 @@ pub enum SemaphoreType { Timeline(u64), } +#[derive(Debug, Clone, Copy)] +pub enum SemaphoreInner { + Binary(vk::Semaphore), + Timeline(vk::Semaphore), +} + +impl ExternallyManagedObjectTrait> for SemaphoreInner { + unsafe fn destroy(self, owner: &Arc) { + match self { + SemaphoreInner::Binary(semaphore) => { + owner.binary_semaphores.push(BinarySemaphore(semaphore)) + } + SemaphoreInner::Timeline(semaphore) => { + owner.timeline_semaphores.push(TimelineSemaphore(semaphore)) + } + } + } +} + +impl ExternallyManagedObjectTrait> for SemaphoreInner { + unsafe fn destroy(self, owner: &Arc) { + match self { + SemaphoreInner::Binary(semaphore) | SemaphoreInner::Timeline(semaphore) => { + unsafe { owner.raw.destroy_semaphore(semaphore, None) }; + } + } + } +} + +impl crate::device::asdf::traits::DebugNameable for SemaphoreInner { + fn debug_name(&self, device: &DeviceInner, name: &str) { + unsafe { + device.debug_name_object(self.raw(), name); + } + } +} + +impl SemaphoreInner { + pub fn raw(&self) -> vk::Semaphore { + match self { + SemaphoreInner::Binary(semaphore) | SemaphoreInner::Timeline(semaphore) => *semaphore, + } + } + pub fn semaphore_type(&self) -> SemaphoreType { + match self { + SemaphoreInner::Binary(_) => SemaphoreType::Binary, + SemaphoreInner::Timeline(_) => SemaphoreType::Timeline(!0), + } + } +} + +impl From for SemaphoreInner { + fn from(value: BinarySemaphore) -> Self { + SemaphoreInner::Binary(value.0) + } +} +impl From for SemaphoreInner { + fn from(value: TimelineSemaphore) -> Self { + SemaphoreInner::Timeline(value.0) + } +} + pub enum Semaphore { Dedicated { - semaphore_type: SemaphoreType, - semaphore: DeviceObject, + semaphore: DeviceObject, }, Pooled { - semaphore_type: SemaphoreType, - semaphore: vk::Semaphore, - device: Device, - #[cfg(debug_assertions)] - name: Option>, + #[allow(private_interfaces)] + semaphore: PoolObject>, }, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub(crate) struct BinarySemaphore(pub(crate) vk::Semaphore); -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub(crate) struct TimelineSemaphore(pub(crate) vk::Semaphore); // This is just so that ash can name these semaphore newtypes @@ -327,36 +392,6 @@ impl Pooled for TimelineSemaphore { } } -impl Drop for Semaphore { - fn drop(&mut self) { - if let Semaphore::Pooled { - device, - semaphore_type, - semaphore, - name, - } = self - { - #[cfg(debug_assertions)] - if name.is_some() { - // reset the name to avoid confusion in case this semaphore is re-used - unsafe { device.debug_name_object(*semaphore, "") }; - } - match semaphore_type { - SemaphoreType::Binary => device - .pools - .binary_semaphores - .push(BinarySemaphore(*semaphore)), - SemaphoreType::Timeline(_) => { - device - .pools - .timeline_semaphores - .push(TimelineSemaphore(*semaphore)); - } - } - } - } -} - impl Semaphore { pub fn new_dedicated( device: Device, @@ -377,9 +412,13 @@ impl Semaphore { let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info); let inner = unsafe { device.dev().create_semaphore(&create_info, None)? }; + let inner = match semaphore_type { + SemaphoreType::Binary => SemaphoreInner::Binary(inner), + SemaphoreType::Timeline(_) => SemaphoreInner::Timeline(inner), + }; + Ok(Self::Dedicated { - semaphore_type, - semaphore: DeviceObject::new(inner, device, name.map(Into::into)), + semaphore: DeviceObject::new_debug_named(device.shared, inner, name), }) } @@ -390,48 +429,35 @@ impl Semaphore { ) -> Result { let semaphore = match semaphore_type { SemaphoreType::Binary => { - if let Some(semaphore) = device.pools.binary_semaphores.pop() { - semaphore.0 - } else { - let mut type_info = vk::SemaphoreTypeCreateInfo::default() - .semaphore_type(vk::SemaphoreType::BINARY); - let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info); - unsafe { device.raw.create_semaphore(&create_info, None)? } - } + let semaphore: SemaphoreInner = + device.pools.binary_semaphores.get_debug_named(name)?.into(); + PoolObject::new(semaphore, device.pools) } SemaphoreType::Timeline(value) => { - if let Some(semaphore) = device.pools.binary_semaphores.pop() { - semaphore.0 - } else { - let mut type_info = vk::SemaphoreTypeCreateInfo::default() - .semaphore_type(vk::SemaphoreType::TIMELINE) - .initial_value(value); - let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info); - unsafe { device.raw.create_semaphore(&create_info, None)? } + let semaphore: SemaphoreInner = device + .pools + .timeline_semaphores + .get_debug_named(name)? + .into(); + + let info = vk::SemaphoreSignalInfo::default() + .semaphore(semaphore.raw()) + .value(value); + unsafe { + device.raw.signal_semaphore(&info)?; } + + PoolObject::new(semaphore, device.pools) } }; - #[cfg(debug_assertions)] - if let Some(name) = name { - unsafe { - device.debug_name_object(semaphore, name); - } - } - - Ok(Self::Pooled { - semaphore_type, - semaphore, - device, - #[cfg(debug_assertions)] - name: name.map(Into::into), - }) + Ok(Self::Pooled { semaphore }) } pub fn semaphore(&self) -> vk::Semaphore { match self { - Semaphore::Dedicated { semaphore, .. } => **semaphore, - Semaphore::Pooled { semaphore, .. } => *semaphore, + Semaphore::Dedicated { semaphore, .. } => semaphore.raw(), + Semaphore::Pooled { semaphore, .. } => semaphore.raw(), } } }