simplify device ownership logic

This commit is contained in:
janis 2026-10-24 18:11:14 +02:00
parent ce46ca1801
commit dd02ea23cf
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
9 changed files with 225 additions and 348 deletions

View file

@ -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(())

View file

@ -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;

View file

@ -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,
)

View file

@ -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())?;

View file

@ -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.

View file

@ -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>());
}
}

View file

@ -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,

View file

@ -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";

View file

@ -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)
}
};