fix swapchain/surface drop logic error

This commit is contained in:
janis 2026-04-04 00:43:50 +02:00
parent 60760ba67f
commit 3c59cf022a
3 changed files with 52 additions and 15 deletions

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, sync::Arc}; use std::{borrow::Cow, mem::ManuallyDrop, sync::Arc};
use crate::{ use crate::{
device::{Allocation, AllocationStrategy, DeviceHandle, DeviceObject, QueueFlags}, device::{Allocation, AllocationStrategy, DeviceHandle, DeviceObject, QueueFlags},
@ -408,7 +408,10 @@ impl Image {
// } // }
// } // }
pub fn create_view(self: &Arc<Self>, mut desc: ImageViewDesc) -> crate::Result<ImageView> { pub fn create_view(
self: &Arc<Self>,
mut desc: ImageViewDesc,
) -> crate::Result<ManuallyDrop<ImageView>> {
// validate // validate
if !view_kind_compatible(self.desc.kind, desc.kind) { if !view_kind_compatible(self.desc.kind, desc.kind) {
tracing::error!( tracing::error!(
@ -471,11 +474,11 @@ impl Image {
let device = self.image.device(); let device = self.image.device();
let view = unsafe { device.raw.create_image_view(&create_info, None)? }; let view = unsafe { device.raw.create_image_view(&create_info, None)? };
Ok(ImageView { Ok(ManuallyDrop::new(ImageView {
view: DeviceObject::new(view, device.clone(), desc.name.clone()), view: DeviceObject::new(view, device.clone(), desc.name.clone()),
desc, desc,
image: self.clone(), image: self.clone(),
}) }))
} }
} }

View file

@ -1,5 +1,6 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
mem::ManuallyDrop,
num::NonZero, num::NonZero,
ops::Deref, ops::Deref,
sync::{ sync::{
@ -21,6 +22,7 @@ use crate::{
device::{Device, DeviceObject}, device::{Device, DeviceObject},
images::{self, ImageViewDesc}, images::{self, ImageViewDesc},
sync::Fence, sync::Fence,
util::DropGuard,
}; };
use derive_more::Debug; use derive_more::Debug;
@ -30,16 +32,12 @@ pub struct Surface {
pub(crate) raw: vk::SurfaceKHR, pub(crate) raw: vk::SurfaceKHR,
#[debug(skip)] #[debug(skip)]
pub(crate) functor: khr::surface::Instance, pub(crate) functor: khr::surface::Instance,
pub(crate) instance: Instance,
pub(crate) swapchain: RwLock<Option<Arc<Swapchain>>>, pub(crate) swapchain: RwLock<Option<Arc<Swapchain>>>,
}
impl Drop for Surface { // destroy surface after any fields that depend on it
fn drop(&mut self) { _drop_guard: DropGuard,
unsafe { // drop reference to instance after destroying the surface
self.functor.destroy_surface(self.raw, None); pub(crate) instance: Instance,
}
}
} }
impl Surface { impl Surface {
@ -82,9 +80,18 @@ impl Surface {
Ok(Self { Ok(Self {
raw, raw,
functor,
swapchain: RwLock::new(None), swapchain: RwLock::new(None),
instance: instance.clone(), instance: instance.clone(),
// the surface must be destroyed after the swapchain
_drop_guard: DropGuard::new({
let functor = functor.clone();
move || {
functor.destroy_surface(raw, None);
}
}),
functor,
}) })
} }
} }
@ -117,9 +124,18 @@ impl Surface {
Ok(Self { Ok(Self {
raw, raw,
functor,
swapchain: RwLock::new(None), swapchain: RwLock::new(None),
instance: instance.clone(), instance: instance.clone(),
// the surface must be destroyed after the swapchain
_drop_guard: DropGuard::new({
let functor = functor.clone();
move || unsafe {
functor.destroy_surface(raw, None);
}
}),
functor,
}) })
} }
@ -571,7 +587,7 @@ impl Swapchain {
SwapchainImage { SwapchainImage {
index: idx as u32, index: idx as u32,
swapchain: self, swapchain: self,
view, view: ManuallyDrop::into_inner(view),
acquire, acquire,
release, release,
}, },

View file

@ -1,5 +1,6 @@
use std::{ use std::{
borrow::Cow, borrow::Cow,
mem::ManuallyDrop,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
}; };
@ -76,6 +77,23 @@ pub(crate) mod weak_vec {
} }
} }
#[derive(derive_more::Debug)]
pub(crate) struct DropGuard(#[debug(skip)] ManuallyDrop<Box<dyn FnOnce()>>);
impl DropGuard {
pub(crate) fn new(f: impl FnOnce() + 'static) -> Self {
Self(ManuallyDrop::new(Box::new(f)))
}
}
impl Drop for DropGuard {
fn drop(&mut self) {
unsafe {
ManuallyDrop::take(&mut self.0)();
}
}
}
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub struct DebugName { pub struct DebugName {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]