pipeline cache with properly managed descruction

This commit is contained in:
janis 2026-04-05 01:14:35 +02:00
parent e4c0479757
commit 2446c75d87
3 changed files with 181 additions and 163 deletions

View file

@ -110,11 +110,15 @@ pub struct DeviceInner {
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) enabled_extensions: Vec<&'static CStr>, pub(crate) enabled_extensions: Vec<&'static CStr>,
pub(crate) pipeline_cache: PipelineCache,
_drop: DeviceDrop, _drop: DeviceDrop,
} }
impl AsRef<DeviceInner> for DeviceInner {
fn as_ref(&self) -> &DeviceInner {
self
}
}
impl core::fmt::Debug for DeviceInner { impl core::fmt::Debug for DeviceInner {
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("DeviceInner") f.debug_struct("DeviceInner")
@ -400,7 +404,6 @@ impl PhysicalDeviceInfo {
raw: device.clone(), raw: device.clone(),
alloc2: Mutex::new(alloc2), alloc2: Mutex::new(alloc2),
instance: instance.clone(), instance: instance.clone(),
pipeline_cache: PipelineCache::new(&device, &self)?,
adapter: self, adapter: self,
queues: device_queues, queues: device_queues,
device_extensions, device_extensions,
@ -446,6 +449,13 @@ pub(crate) struct DevicePools {
pub(crate) fences: Arc<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>,
pub(crate) pipeline_cache: asdf::DeviceObject<PipelineCache, Arc<DeviceInner>>,
}
impl AsRef<DevicePools> for DevicePools {
fn as_ref(&self) -> &DevicePools {
self
}
} }
impl DevicePools { impl DevicePools {
@ -453,7 +463,11 @@ impl DevicePools {
Self { Self {
fences: Arc::new(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.clone()),
pipeline_cache: asdf::DeviceObject::new(
device.clone(),
PipelineCache::new(&device.raw, &device.adapter).unwrap(),
),
} }
} }
} }
@ -740,7 +754,7 @@ impl<T: DeviceHandle> DeviceObject<T> {
pub fn name(&self) -> Option<&str> { pub fn name(&self) -> Option<&str> {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
self.name.as_deref().map(|cow| cow.as_ref()) self.name.as_deref()
} }
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
{ {
@ -833,23 +847,20 @@ impl<T> AsRef<Pool<T>> for Pool<T> {
} }
} }
pub type PoolObject<T, U: AsRef<Pool<T>>> = asdf::ExternallyManagedObject<T, U>; pub type PoolObject<T, U = Arc<Pool<T>>> = asdf::ExternallyManagedObject<T, U>;
impl<'a, T: Pooled + asdf::traits::ExternallyManagedObject<&'a Pool<T>> + 'a> Pool<T> { impl<T: Pooled> Pool<T> {
pub fn get(&'a self) -> Result<PoolObject<T, &'a Pool<T>>> { pub fn get(&self) -> Result<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(asdf::ExternallyManagedObject::new(item, self)) Ok(item)
} }
pub fn get_debug_named( pub fn get_debug_named(&self, name: Option<impl Into<Cow<'static, str>>>) -> Result<T>
&'a self,
name: Option<impl Into<Cow<'static, str>>>,
) -> Result<PoolObject<T, &'a Pool<T>>>
where where
T: asdf::traits::DebugNameable, T: asdf::traits::DebugNameable,
{ {
@ -933,10 +944,7 @@ pub(crate) mod asdf {
use ash::vk; use ash::vk;
use crate::{ use crate::{device::DeviceInner, util::DebugName};
device::{DeviceInner, DevicePools, GpuAllocation},
util::DebugName,
};
pub mod traits { pub mod traits {
/// A trait describing an object owned by some manager-type, which is /// 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. /// Wrapper for types which are owned by another type `O`, which is responsible for destruction.
#[derive(Debug)]
pub struct ExternallyManagedObject<T: traits::ExternallyManagedObject<O>, O> { pub struct ExternallyManagedObject<T: traits::ExternallyManagedObject<O>, O> {
inner: ManuallyDrop<T>, inner: ManuallyDrop<T>,
owner: O, 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. /// A wrapper for vulkan types which are owned by the device, taking care of destruction.
#[derive(Debug)]
pub struct DeviceObject< pub struct DeviceObject<
T: traits::ExternallyManagedObject<O>, T: traits::ExternallyManagedObject<O>,
O: AsRef<super::DeviceInner> = Arc<super::DeviceInner>, O: AsRef<super::DeviceInner> = Arc<super::DeviceInner>,
> { > {
inner: ExternallyManagedObject<T, O>, inner: ExternallyManagedObject<T, O>,
#[allow(dead_code)]
name: Option<DebugName>, name: Option<DebugName>,
} }
@ -1047,7 +1058,7 @@ pub(crate) mod asdf {
O: AsRef<super::DeviceInner>, O: AsRef<super::DeviceInner>,
> DeviceObject<T, O> > DeviceObject<T, O>
{ {
fn new_debug_named(owner: O, inner: T, name: Option<impl Into<DebugName>>) -> Self { pub fn new_debug_named(owner: O, inner: T, name: Option<impl Into<DebugName>>) -> Self {
let name = name.map(Into::into); let name = name.map(Into::into);
if let Some(ref name) = name { if let Some(ref name) = name {
traits::DebugNameable::debug_name(&inner, owner.as_ref(), name); traits::DebugNameable::debug_name(&inner, owner.as_ref(), name);
@ -1060,12 +1071,12 @@ pub(crate) mod asdf {
} }
impl<T: traits::ExternallyManagedObject<O>, O: AsRef<super::DeviceInner>> DeviceObject<T, O> { impl<T: traits::ExternallyManagedObject<O>, O: AsRef<super::DeviceInner>> DeviceObject<T, O> {
fn new(owner: O, inner: T) -> Self { pub fn new(owner: O, inner: T) -> Self {
let inner = ExternallyManagedObject::new(inner, owner); let inner = ExternallyManagedObject::new(inner, owner);
Self { inner, name: None } Self { inner, name: None }
} }
fn device(&self) -> &O { pub fn device(&self) -> &O {
self.inner.owner() self.inner.owner()
} }
} }
@ -1109,25 +1120,6 @@ pub(crate) mod asdf {
} }
} }
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)),
}
}
}
impl AsRef<DeviceInner> for DeviceInner {
fn as_ref(&self) -> &DeviceInner {
self
}
}
impl<T> traits::DebugNameable for T impl<T> traits::DebugNameable for T
where where
T: vk::Handle + Copy, T: vk::Handle + Copy,
@ -1140,41 +1132,33 @@ pub(crate) mod asdf {
} }
} }
enum Semaphore { #[allow(dead_code)]
Binary(vk::Semaphore), #[cfg(test)]
Timeline(vk::Semaphore), fn asdf() {
} use crate::device::{DevicePools, GpuAllocation};
fn summon<T>() -> T { fn summon<T>() -> T {
unimplemented!() unimplemented!()
} }
fn asdf() { let _inner_ref: DeviceObject<vk::Semaphore, &DeviceInner> = DeviceObject::new_debug_named(
let inner_ref: DeviceObject<vk::Semaphore, &DeviceInner> = DeviceObject::new_debug_named(
summon::<&DeviceInner>(), summon::<&DeviceInner>(),
summon::<vk::Semaphore>(), summon::<vk::Semaphore>(),
Some("my semaphore"), Some("my semaphore"),
); );
let device_owned: DeviceObject<vk::Semaphore, super::Device> = let _device_owned: DeviceObject<vk::Semaphore, super::Device> =
DeviceObject::new_debug_named( DeviceObject::new_debug_named(
summon::<super::Device>(), summon::<super::Device>(),
summon::<vk::Semaphore>(), summon::<vk::Semaphore>(),
Some("my other semaphore"), Some("my other semaphore"),
); );
let allocation: DeviceObject<GpuAllocation, Arc<super::DeviceInner>> = DeviceObject::new( let _allocation: DeviceObject<GpuAllocation, Arc<super::DeviceInner>> = DeviceObject::new(
summon::<Arc<super::DeviceInner>>(), summon::<Arc<super::DeviceInner>>(),
summon::<GpuAllocation>(), summon::<GpuAllocation>(),
); );
let pool_owned: ExternallyManagedObject<vk::Semaphore, DevicePools> = let _pool_owned: ExternallyManagedObject<vk::Semaphore, DevicePools> =
ExternallyManagedObject::new(summon::<vk::Semaphore>(), summon::<DevicePools>()); ExternallyManagedObject::new(summon::<vk::Semaphore>(), summon::<DevicePools>());
let enum_semaphore_pooled: ExternallyManagedObject<Semaphore, DevicePools> =
ExternallyManagedObject::new(
Semaphore::Binary(summon::<vk::Semaphore>()),
summon::<DevicePools>(),
);
} }
} }

View file

@ -503,7 +503,7 @@ impl Pipeline {
device device
.dev() .dev()
.create_compute_pipelines( .create_compute_pipelines(
device.pipeline_cache.raw, device.pools.pipeline_cache.raw,
core::slice::from_ref(info), core::slice::from_ref(info),
None, None,
) )
@ -575,27 +575,23 @@ impl Pipeline {
}); });
let multisample = desc.multisample.map(|state| { let multisample = desc.multisample.map(|state| {
let info = vk::PipelineMultisampleStateCreateInfo::default() vk::PipelineMultisampleStateCreateInfo::default()
.flags(state.flags) .flags(state.flags)
.min_sample_shading(state.min_sample_shading) .min_sample_shading(state.min_sample_shading)
.rasterization_samples(state.rasterization_samples) .rasterization_samples(state.rasterization_samples)
.sample_mask(state.sample_mask) .sample_mask(state.sample_mask)
.sample_shading_enable(state.sample_shading_enable) .sample_shading_enable(state.sample_shading_enable)
.alpha_to_coverage_enable(state.alpha_to_coverage_enable) .alpha_to_coverage_enable(state.alpha_to_coverage_enable)
.alpha_to_one_enable(state.alpha_to_one_enable); .alpha_to_one_enable(state.alpha_to_one_enable)
info
}); });
let color_blend = desc.color_blend.map(|state| { let color_blend = desc.color_blend.map(|state| {
let info = vk::PipelineColorBlendStateCreateInfo::default() vk::PipelineColorBlendStateCreateInfo::default()
.flags(state.flags) .flags(state.flags)
.attachments(state.attachments) .attachments(state.attachments)
.blend_constants(state.blend_constants) .blend_constants(state.blend_constants)
.logic_op(state.logic_op.unwrap_or(Default::default())) .logic_op(state.logic_op.unwrap_or(Default::default()))
.logic_op_enable(state.logic_op.is_some()); .logic_op_enable(state.logic_op.is_some())
info
}); });
let depth_stencil = desc.depth_stencil.map(|state| { let depth_stencil = desc.depth_stencil.map(|state| {
@ -625,20 +621,16 @@ impl Pipeline {
}); });
let dynamic = desc.dynamic.map(|state| { let dynamic = desc.dynamic.map(|state| {
let info = vk::PipelineDynamicStateCreateInfo::default() vk::PipelineDynamicStateCreateInfo::default()
.flags(state.flags) .flags(state.flags)
.dynamic_states(state.dynamic_states); .dynamic_states(state.dynamic_states)
info
}); });
let mut rendering = desc.rendering.map(|state| { let mut rendering = desc.rendering.map(|state| {
let info = vk::PipelineRenderingCreateInfo::default() vk::PipelineRenderingCreateInfo::default()
.color_attachment_formats(state.color_formats) .color_attachment_formats(state.color_formats)
.depth_attachment_format(state.depth_format.unwrap_or_default()) .depth_attachment_format(state.depth_format.unwrap_or_default())
.stencil_attachment_format(state.stencil_format.unwrap_or_default()); .stencil_attachment_format(state.stencil_format.unwrap_or_default())
info
}); });
fn option_to_ptr<T>(option: &Option<T>) -> *const T { fn option_to_ptr<T>(option: &Option<T>) -> *const T {
@ -679,7 +671,7 @@ impl Pipeline {
device device
.dev() .dev()
.create_graphics_pipelines( .create_graphics_pipelines(
device.pipeline_cache.raw, device.pools.pipeline_cache.raw,
core::slice::from_ref(&info), core::slice::from_ref(&info),
None, None,
) )
@ -704,17 +696,33 @@ impl Pipeline {
} }
pub(crate) mod pipeline_cache { pub(crate) mod pipeline_cache {
use std::sync::Arc;
use ash::vk; use ash::vk;
use ash::Device; use ash::Device;
use crate::PhysicalDeviceInfo; use crate::PhysicalDeviceInfo;
use crate::device::DeviceInner;
#[derive(Debug)]
pub struct PipelineCache { pub struct PipelineCache {
#[allow(dead_code)]
key: u128, key: u128,
pub(crate) raw: vk::PipelineCache, pub(crate) raw: vk::PipelineCache,
} }
impl crate::device::asdf::traits::ExternallyManagedObject<Arc<DeviceInner>> for PipelineCache {
unsafe fn destroy(self, owner: &Arc<DeviceInner>) {
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 { impl PipelineCache {
const MAGIC: [u8; 4] = *b"VYPC"; const MAGIC: [u8; 4] = *b"VYPC";
const KEY_VERSION: u32 = 1; const KEY_VERSION: u32 = 1;
@ -785,7 +793,7 @@ pub(crate) mod pipeline_cache {
}); });
let info = vk::PipelineCacheCreateInfo::default() let info = vk::PipelineCacheCreateInfo::default()
.flags(vk::PipelineCacheCreateFlags::EXTERNALLY_SYNCHRONIZED) // .flags(vk::PipelineCacheCreateFlags::EXTERNALLY_SYNCHRONIZED)
.initial_data(data.as_deref().unwrap_or_default()); .initial_data(data.as_deref().unwrap_or_default());
let cache = unsafe { device.create_pipeline_cache(&info, None)? }; let cache = unsafe { device.create_pipeline_cache(&info, None)? };

View file

@ -1,5 +1,3 @@
#[cfg(debug_assertions)]
use std::borrow::Cow;
use std::{ use std::{
future::Future, future::Future,
marker::PhantomData, marker::PhantomData,
@ -7,7 +5,10 @@ use std::{
time::Duration, 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 crate::{Result, device::DeviceInner};
use super::Device; use super::Device;
@ -175,16 +176,20 @@ impl Pooled for vk::Fence {
} }
} }
impl<T> crate::device::asdf::traits::ExternallyManagedObject<T> for vk::Fence impl ExternallyManagedObjectTrait<Arc<Pool<vk::Fence>>> for vk::Fence {
where unsafe fn destroy(self, pool: &Arc<Pool<vk::Fence>>) {
T: AsRef<Pool<vk::Fence>>,
{
unsafe fn destroy(self, owner: &T) {
let pool = owner.as_ref();
pool.push(self); pool.push(self);
} }
} }
impl ExternallyManagedObjectTrait<Arc<DeviceInner>> for vk::Fence {
unsafe fn destroy(self, device: &Arc<DeviceInner>) {
unsafe {
device.raw.destroy_fence(self, None);
}
}
}
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()
@ -199,13 +204,15 @@ impl Fence {
.create_fence(&vk::FenceCreateInfo::default(), None)? .create_fence(&vk::FenceCreateInfo::default(), None)?
}; };
Ok(Self::Dedicated { 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<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 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 { pub fn raw(&self) -> vk::Fence {
@ -217,7 +224,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(),
Fence::Pooled { fence } => &fence.owner().device, Fence::Pooled { fence } => &fence.owner().device,
} }
} }
@ -262,23 +269,81 @@ pub enum SemaphoreType {
Timeline(u64), Timeline(u64),
} }
#[derive(Debug, Clone, Copy)]
pub enum SemaphoreInner {
Binary(vk::Semaphore),
Timeline(vk::Semaphore),
}
impl ExternallyManagedObjectTrait<Arc<DevicePools>> for SemaphoreInner {
unsafe fn destroy(self, owner: &Arc<DevicePools>) {
match self {
SemaphoreInner::Binary(semaphore) => {
owner.binary_semaphores.push(BinarySemaphore(semaphore))
}
SemaphoreInner::Timeline(semaphore) => {
owner.timeline_semaphores.push(TimelineSemaphore(semaphore))
}
}
}
}
impl ExternallyManagedObjectTrait<Arc<DeviceInner>> for SemaphoreInner {
unsafe fn destroy(self, owner: &Arc<DeviceInner>) {
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<BinarySemaphore> for SemaphoreInner {
fn from(value: BinarySemaphore) -> Self {
SemaphoreInner::Binary(value.0)
}
}
impl From<TimelineSemaphore> for SemaphoreInner {
fn from(value: TimelineSemaphore) -> Self {
SemaphoreInner::Timeline(value.0)
}
}
pub enum Semaphore { pub enum Semaphore {
Dedicated { Dedicated {
semaphore_type: SemaphoreType, semaphore: DeviceObject<SemaphoreInner>,
semaphore: DeviceObject<vk::Semaphore>,
}, },
Pooled { Pooled {
semaphore_type: SemaphoreType, #[allow(private_interfaces)]
semaphore: vk::Semaphore, semaphore: PoolObject<SemaphoreInner, Arc<DevicePools>>,
device: Device,
#[cfg(debug_assertions)]
name: Option<Cow<'static, str>>,
}, },
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub(crate) struct BinarySemaphore(pub(crate) vk::Semaphore); pub(crate) struct BinarySemaphore(pub(crate) vk::Semaphore);
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub(crate) struct TimelineSemaphore(pub(crate) 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
@ -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 { impl Semaphore {
pub fn new_dedicated( pub fn new_dedicated(
device: Device, device: Device,
@ -377,9 +412,13 @@ impl Semaphore {
let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info); let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info);
let inner = unsafe { device.dev().create_semaphore(&create_info, None)? }; 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 { Ok(Self::Dedicated {
semaphore_type, semaphore: DeviceObject::new_debug_named(device.shared, inner, name),
semaphore: DeviceObject::new(inner, device, name.map(Into::into)),
}) })
} }
@ -390,48 +429,35 @@ impl Semaphore {
) -> Result<Self> { ) -> Result<Self> {
let semaphore = match semaphore_type { let semaphore = match semaphore_type {
SemaphoreType::Binary => { SemaphoreType::Binary => {
if let Some(semaphore) = device.pools.binary_semaphores.pop() { let semaphore: SemaphoreInner =
semaphore.0 device.pools.binary_semaphores.get_debug_named(name)?.into();
} else { PoolObject::new(semaphore, device.pools)
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)? }
}
} }
SemaphoreType::Timeline(value) => { SemaphoreType::Timeline(value) => {
if let Some(semaphore) = device.pools.binary_semaphores.pop() { let semaphore: SemaphoreInner = device
semaphore.0 .pools
} else { .timeline_semaphores
let mut type_info = vk::SemaphoreTypeCreateInfo::default() .get_debug_named(name)?
.semaphore_type(vk::SemaphoreType::TIMELINE) .into();
.initial_value(value);
let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info); let info = vk::SemaphoreSignalInfo::default()
unsafe { device.raw.create_semaphore(&create_info, None)? } .semaphore(semaphore.raw())
.value(value);
unsafe {
device.raw.signal_semaphore(&info)?;
} }
PoolObject::new(semaphore, device.pools)
} }
}; };
#[cfg(debug_assertions)] Ok(Self::Pooled { semaphore })
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),
})
} }
pub fn semaphore(&self) -> vk::Semaphore { pub fn semaphore(&self) -> vk::Semaphore {
match self { match self {
Semaphore::Dedicated { semaphore, .. } => **semaphore, Semaphore::Dedicated { semaphore, .. } => semaphore.raw(),
Semaphore::Pooled { semaphore, .. } => *semaphore, Semaphore::Pooled { semaphore, .. } => semaphore.raw(),
} }
} }
} }