switching to more generic DeviceObject impl

This commit is contained in:
janis 2026-04-10 01:47:34 +02:00
parent c73457b913
commit c731f79f81
7 changed files with 157 additions and 151 deletions

View file

@ -113,9 +113,9 @@ impl Buffer {
}
Ok(Self {
buffer: DeviceObject::new(buffer, device.clone(), desc.name.clone()),
buffer: DeviceObject::new_debug_named(device.clone(), buffer, desc.name.clone()),
desc,
alloc: Allocation::Owned(DeviceObject::new_without_name(alloc, device)),
alloc: Allocation::Owned(DeviceObject::new(device, alloc)),
})
}

View file

@ -534,7 +534,7 @@ pub mod traits {
unsafe {
self.device().dev().cmd_push_constants(
self.handle(),
layout.handle(),
layout.raw(),
stage,
offset,
bytes,
@ -575,12 +575,11 @@ pub mod traits {
descriptor_sets: &[vk::DescriptorSet],
) {
// assert_eq!(self.state(), CommandBufferState::Recording);
use crate::device::DeviceOwned;
unsafe {
self.device().dev().cmd_bind_descriptor_sets(
self.handle(),
bind_point,
layout.handle(),
layout.raw(),
0,
descriptor_sets,
&[],

View file

@ -16,6 +16,7 @@ use raw_window_handle::RawDisplayHandle;
use crate::{
Instance, PhysicalDeviceFeatures, PhysicalDeviceInfo, Result,
device::asdf::traits::ExternallyManagedObject,
pipeline::pipeline_cache::PipelineCache,
queue::{DeviceQueueInfos, DeviceQueues, Queue},
sync::{self, BinarySemaphore, TimelineSemaphore},
@ -54,14 +55,6 @@ pub(crate) struct DeviceExtensions {
type GpuAllocation = gpu_allocator::vulkan::Allocation;
impl DeviceHandle for GpuAllocation {
unsafe fn destroy(&mut self, device: &Device) {
let mut swapped = GpuAllocation::default();
std::mem::swap(self, &mut swapped);
_ = device.alloc2.lock().free(swapped);
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AllocationStrategy {
#[default]
@ -93,7 +86,7 @@ impl Allocation {
pub(crate) fn allocation_mut(&mut self) -> Option<&mut GpuAllocation> {
match self {
Allocation::Owned(obj) => Some(obj),
Allocation::Shared(arc) => Arc::get_mut(arc).map(|alloc| &mut alloc.inner),
Allocation::Shared(arc) => Arc::get_mut(arc).map(DerefMut::deref_mut),
Allocation::Unmanaged => None,
}
}
@ -700,76 +693,7 @@ impl<T> DeviceOwnedDebugObject<T> {
}
}
#[derive(Debug)]
pub struct DeviceObject<T: DeviceHandle> {
inner: T,
device: Device,
#[cfg(debug_assertions)]
name: Option<Cow<'static, str>>,
}
impl<T: DeviceHandle> Deref for DeviceObject<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T: DeviceHandle> DerefMut for DeviceObject<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T: DeviceHandle> DeviceObject<T> {
pub fn new(inner: T, device: Device, name: Option<Cow<'static, str>>) -> Self
where
T: vk::Handle + Clone,
{
unsafe {
if let Some(name) = name.as_ref() {
device.debug_name_object(inner.clone(), name);
}
}
Self {
inner,
device,
#[cfg(debug_assertions)]
name,
}
}
pub fn new_without_name(inner: T, device: Device) -> Self {
Self {
inner,
device,
#[cfg(debug_assertions)]
name: None,
}
}
pub fn device(&self) -> &Device {
&self.device
}
pub fn name(&self) -> Option<&str> {
#[cfg(debug_assertions)]
{
self.name.as_deref()
}
#[cfg(not(debug_assertions))]
{
None
}
}
}
impl<T: DeviceHandle> Drop for DeviceObject<T> {
fn drop(&mut self) {
unsafe {
self.inner.destroy(&self.device);
}
}
}
pub use asdf::{DeviceObject, InnerDeviceObject};
pub trait DeviceHandle {
/// # Safety
@ -777,35 +701,26 @@ pub trait DeviceHandle {
unsafe fn destroy(&mut self, device: &Device);
}
impl DeviceHandle for vk::Semaphore {
unsafe fn destroy(&mut self, device: &Device) {
impl<O, T: ExternallyManagedObject<O>> ExternallyManagedObject<O> for Mutex<T> {
unsafe fn destroy(self, owner: &O) {
// Safety guarantee is upheld by the caller.
unsafe { self.into_inner().destroy(owner) };
}
}
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::Buffer {
unsafe fn destroy(self, device: &T) {
unsafe {
device.dev().destroy_semaphore(*self, None);
device.as_ref().raw.destroy_buffer(self, None);
}
}
}
impl DeviceHandle for vk::Fence {
unsafe fn destroy(&mut self, device: &Device) {
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::SwapchainKHR {
unsafe fn destroy(self, device: &T) {
unsafe {
device.dev().destroy_fence(*self, None);
}
}
}
impl DeviceHandle for vk::Buffer {
unsafe fn destroy(&mut self, device: &Device) {
unsafe {
device.dev().destroy_buffer(*self, None);
}
}
}
impl DeviceHandle for vk::SwapchainKHR {
unsafe fn destroy(&mut self, device: &Device) {
unsafe {
if let Some(swapchain) = device.device_extensions.swapchain.as_ref() {
swapchain.destroy_swapchain(*self, None)
if let Some(swapchain) = device.as_ref().device_extensions.swapchain.as_ref() {
swapchain.destroy_swapchain(self, None)
}
}
}
@ -1042,11 +957,13 @@ pub(crate) 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.
#[derive(Debug)]
pub struct DeviceObject<
T: traits::ExternallyManagedObject<O>,
O: AsRef<super::DeviceInner> = Arc<super::DeviceInner>,
O: AsRef<super::DeviceInner> = super::Device,
> {
inner: ExternallyManagedObject<T, O>,
#[allow(dead_code)]
@ -1076,9 +993,54 @@ pub(crate) mod asdf {
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
where
D: traits::DebugNameable,
{
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()
}
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,
}
}
pub fn map_owner<U>(self, f: impl FnOnce(O) -> U) -> DeviceObject<T, U>
where
T: traits::ExternallyManagedObject<U>,
U: AsRef<super::DeviceInner>,
{
DeviceObject {
inner: self.inner.map_owner(f),
name: self.name,
}
}
}
impl<T, O> Deref for DeviceObject<T, O>
@ -1089,7 +1051,17 @@ pub(crate) mod asdf {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
&*self.inner
}
}
impl<T, O> DerefMut for DeviceObject<T, O>
where
T: traits::ExternallyManagedObject<O>,
O: AsRef<super::DeviceInner>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.inner
}
}
@ -1098,7 +1070,7 @@ pub(crate) mod asdf {
use super::*;
impl<T: AsRef<DeviceInner>> traits::ExternallyManagedObject<T> for ash::vk::Semaphore {
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);

View file

@ -1,7 +1,10 @@
use std::{borrow::Cow, mem::ManuallyDrop, sync::Arc};
use crate::{
device::{Allocation, AllocationStrategy, DeviceHandle, DeviceObject, QueueFlags},
device::{
Allocation, AllocationStrategy, DeviceInner, DeviceObject, QueueFlags,
asdf::traits::ExternallyManagedObject,
},
swapchain::Swapchain,
util::weak_vec::WeakVec,
};
@ -114,10 +117,10 @@ enum ImageInner {
Allocated(DeviceObject<vk::Image>, Allocation),
}
impl DeviceHandle for vk::Image {
unsafe fn destroy(&mut self, device: &Device) {
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::Image {
unsafe fn destroy(self, device: &T) {
unsafe {
device.dev().destroy_image(*self, None);
device.as_ref().raw.destroy_image(self, None);
}
}
}
@ -175,7 +178,7 @@ impl Image {
Self::new_with_allocation_unchecked(
device.clone(),
image,
Allocation::Owned(DeviceObject::new_without_name(alloc, device)),
Allocation::Owned(DeviceObject::new(device, alloc)),
desc,
)
}
@ -197,7 +200,7 @@ impl Image {
Ok(Self {
image: ImageInner::Allocated(
DeviceObject::new(image, device, desc.name.clone()),
DeviceObject::new_debug_named(device, image, desc.name.clone()),
allocation,
),
desc,
@ -475,7 +478,7 @@ impl Image {
let view = unsafe { device.raw.create_image_view(&create_info, None)? };
Ok(ManuallyDrop::new(ImageView {
view: DeviceObject::new(view, device.clone(), desc.name.clone()),
view: DeviceObject::new_debug_named(device.clone(), view, desc.name.clone()),
desc,
image: self.clone(),
}))
@ -682,10 +685,10 @@ impl ImageView {
}
}
impl DeviceHandle for vk::ImageView {
unsafe fn destroy(&mut self, device: &Device) {
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::ImageView {
unsafe fn destroy(self, device: &T) {
unsafe {
device.dev().destroy_image_view(*self, None);
device.as_ref().raw.destroy_image_view(self, None);
}
}
}

View file

@ -1,10 +1,13 @@
use std::{borrow::Cow, path::Path, sync::Arc};
use ash::{ext, prelude::*, vk};
use parking_lot::Mutex;
use crate::{
define_device_owned_handle,
device::{Device, DeviceHandle, DeviceObject},
device::{
Device, DeviceHandle, DeviceInner, DeviceObject, asdf::traits::ExternallyManagedObject,
},
make_extension,
};
@ -222,10 +225,19 @@ impl DeviceHandle for vk::DescriptorPool {
unsafe { device.dev().destroy_descriptor_pool(*self, None) };
}
}
impl<T: AsRef<DeviceInner>> ExternallyManagedObject<T> for vk::DescriptorPool {
unsafe fn destroy(self, device: &T) {
// SAFETY: We have exclusive ownership of the descriptor pool, so it's safe to destroy it.
unsafe {
device.as_ref().raw.destroy_descriptor_pool(self, None);
}
}
}
#[derive(Debug)]
pub struct DescriptorPool {
pool: DeviceObject<vk::DescriptorPool>,
lock: Mutex<()>,
}
impl DescriptorPool {
@ -238,20 +250,25 @@ impl DescriptorPool {
let handle = unsafe { device.dev().create_descriptor_pool(info, None)? };
Ok(Self {
pool: DeviceObject::new(handle, device, desc.name),
pool: DeviceObject::new_debug_named(device, handle, desc.name),
lock: Mutex::new(()),
})
}
pub fn allocate(&self, descs: &[DescriptorSetAllocDesc]) -> VkResult<Vec<vk::DescriptorSet>> {
let layouts = descs
.iter()
.map(|desc| desc.layout.handle())
.map(|desc| desc.layout.raw())
.collect::<Vec<_>>();
let info = &vk::DescriptorSetAllocateInfo::default()
.descriptor_pool(*self.pool)
.set_layouts(&layouts);
let sets = unsafe { self.pool.device().raw.allocate_descriptor_sets(info)? };
let sets = unsafe {
let _lock = self.lock.lock();
self.pool.device().raw.allocate_descriptor_sets(info)?
};
for (&set, desc) in sets.iter().zip(descs) {
if let Some(name) = desc.name.as_ref() {
@ -264,6 +281,7 @@ impl DescriptorPool {
#[allow(dead_code)]
pub fn reset(&self) -> VkResult<()> {
let _lock = self.lock.lock();
unsafe {
self.pool
.device()
@ -273,9 +291,14 @@ impl DescriptorPool {
}
}
impl DeviceHandle for vk::DescriptorSetLayout {
unsafe fn destroy(&mut self, device: &Device) {
unsafe { device.raw.destroy_descriptor_set_layout(*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);
}
}
}
@ -319,7 +342,7 @@ impl DescriptorSetLayout {
let layout = unsafe { device.raw.create_descriptor_set_layout(&info, None)? };
Ok(Self {
layout: DeviceObject::new(layout, device, desc.name),
layout: DeviceObject::new_debug_named(device, layout, desc.name),
})
}
@ -330,9 +353,11 @@ impl DescriptorSetLayout {
use crate::device::DeviceOwned;
impl DeviceHandle for vk::PipelineLayout {
unsafe fn destroy(&mut self, device: &Device) {
unsafe { device.raw.destroy_pipeline_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);
}
}
}
@ -354,7 +379,7 @@ impl PipelineLayout {
let layout = unsafe { device.raw.create_pipeline_layout(info, None)? };
Ok(Self {
layout: DeviceObject::new(layout, device, desc.name),
layout: DeviceObject::new_debug_named(device, layout, desc.name),
})
}
@ -458,9 +483,11 @@ impl Sampler {
}
}
impl DeviceHandle for vk::ShaderModule {
unsafe fn destroy(&mut self, device: &Device) {
unsafe { device.raw.destroy_shader_module(*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);
}
}
}
@ -487,7 +514,7 @@ impl ShaderModule {
let size = reader.read(bytemuck::cast_slice_mut(buffer.as_mut_slice()))?;
buffer.resize(size / 4, 0);
Ok(Self::new_from_memory(device, &buffer)?)
Self::new_from_memory(device, &buffer)
}
pub fn new_from_memory(device: Device, buffer: &[u32]) -> crate::Result<Self> {
@ -496,7 +523,7 @@ impl ShaderModule {
let module = unsafe { device.dev().create_shader_module(info, None)? };
Ok(Self {
module: DeviceObject::new(module, device, None),
module: DeviceObject::new(device, module),
})
}
}
@ -507,9 +534,11 @@ pub struct Pipeline {
bind_point: vk::PipelineBindPoint,
}
impl DeviceHandle for vk::Pipeline {
unsafe fn destroy(&mut self, device: &Device) {
unsafe { device.raw.destroy_pipeline(*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);
}
}
}
@ -550,7 +579,7 @@ impl Pipeline {
};
Ok(Self {
pipeline: DeviceObject::new(pipeline, device, desc.name),
pipeline: DeviceObject::new_debug_named(device, pipeline, desc.name),
bind_point: vk::PipelineBindPoint::COMPUTE,
})
}
@ -718,7 +747,7 @@ impl Pipeline {
};
Ok(Self {
pipeline: DeviceObject::new(pipeline, device, desc.name),
pipeline: DeviceObject::new_debug_named(device, pipeline, desc.name),
bind_point: vk::PipelineBindPoint::GRAPHICS,
})
}

View file

@ -488,10 +488,10 @@ impl Swapchain {
.swapchain
.clone()
.expect("swapchain extension not loaded"),
swapchain: DeviceObject::new(
swapchain,
swapchain: DeviceObject::new_debug_named(
device,
Some(format!("swapchain-{:x}", swapchain.as_raw()).into()),
swapchain,
Some(format!("swapchain-{:x}", swapchain.as_raw())),
),
images,
config,

View file

@ -7,7 +7,10 @@ use std::{
use crate::device::{
DevicePools, Pool, PoolObject, Pooled,
asdf::{DeviceObject, traits::ExternallyManagedObject as ExternallyManagedObjectTrait},
asdf::{
DeviceObject, InnerDeviceObject,
traits::ExternallyManagedObject as ExternallyManagedObjectTrait,
},
};
use crate::{Result, device::DeviceInner};
@ -157,7 +160,7 @@ impl SyncThreadpool {
pub enum Fence {
Dedicated {
fence: DeviceObject<vk::Fence>,
fence: InnerDeviceObject<vk::Fence>,
},
Pooled {
fence: PoolObject<vk::Fence, Arc<Pool<vk::Fence>>>,
@ -182,10 +185,10 @@ impl ExternallyManagedObjectTrait<Arc<Pool<vk::Fence>>> for vk::Fence {
}
}
impl ExternallyManagedObjectTrait<Arc<DeviceInner>> for vk::Fence {
unsafe fn destroy(self, device: &Arc<DeviceInner>) {
impl<T: AsRef<DeviceInner>> ExternallyManagedObjectTrait<T> for vk::Fence {
unsafe fn destroy(self, device: &T) {
unsafe {
device.raw.destroy_fence(self, None);
device.as_ref().raw.destroy_fence(self, None);
}
}
}
@ -333,7 +336,7 @@ impl From<TimelineSemaphore> for SemaphoreInner {
pub enum Semaphore {
Dedicated {
semaphore: DeviceObject<SemaphoreInner>,
semaphore: InnerDeviceObject<SemaphoreInner>,
},
Pooled {
#[allow(private_interfaces)]