Skip to content

Commit e5a641b

Browse files
janie177MarijnS95
andauthored
Resource ownership cleanup (#151)
* Get rid of manually drop for dx12 resources. Warn the user when a resource is not freed before dropping. Adjust some comments and function signatures based on feedback. * Expect dx12 resources to be present when freeing the allocation. Print information about the resource when the user forgets to free one. * Don't rely on dx12 functions to extract a resource name, and instead store it in the resource manually. Co-authored-by: Marijn Suijten <[email protected]>
1 parent 289445e commit e5a641b

File tree

2 files changed

+68
-46
lines changed

2 files changed

+68
-46
lines changed

src/d3d12/mod.rs

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#![deny(clippy::unimplemented, clippy::unwrap_used, clippy::ok_expect)]
22

3-
use std::{fmt, mem::ManuallyDrop};
3+
use std::fmt;
44

5-
use log::{debug, Level};
5+
use log::{debug, warn, Level};
66

77
use windows::Win32::{Foundation::E_OUTOFMEMORY, Graphics::Direct3D12::*};
88

@@ -233,18 +233,6 @@ pub struct AllocatorCreateDesc {
233233
pub debug_settings: AllocatorDebugSettings,
234234
}
235235

236-
#[derive(Debug)]
237-
pub struct Allocation {
238-
chunk_id: Option<std::num::NonZeroU64>,
239-
offset: u64,
240-
size: u64,
241-
memory_block_index: usize,
242-
memory_type_index: usize,
243-
heap: ID3D12Heap,
244-
245-
name: Option<Box<str>>,
246-
}
247-
248236
pub enum ResourceType<'a> {
249237
/// Allocation equivalent to Dx12's CommittedResource.
250238
Committed {
@@ -257,19 +245,46 @@ pub enum ResourceType<'a> {
257245

258246
#[derive(Debug)]
259247
pub struct Resource {
248+
name: String,
260249
pub allocation: Option<Allocation>,
261-
pub resource: ManuallyDrop<ID3D12Resource>,
250+
resource: Option<ID3D12Resource>,
262251
pub memory_location: MemoryLocation,
263252
memory_type_index: Option<usize>,
264253
pub size: u64,
265254
}
266255

256+
impl Resource {
257+
pub fn resource(&self) -> &ID3D12Resource {
258+
self.resource.as_ref().expect("Resource was already freed.")
259+
}
260+
}
261+
262+
impl Drop for Resource {
263+
fn drop(&mut self) {
264+
if self.resource.is_some() {
265+
warn!("Dropping resource `{}` that was not freed. Call `Allocator::free_resource(resource)` instead.", self.name);
266+
}
267+
}
268+
}
269+
267270
#[derive(Debug)]
268271
pub struct CommittedAllocationStatistics {
269272
pub num_allocations: usize,
270273
pub total_size: u64,
271274
}
272275

276+
#[derive(Debug)]
277+
pub struct Allocation {
278+
chunk_id: Option<std::num::NonZeroU64>,
279+
offset: u64,
280+
size: u64,
281+
memory_block_index: usize,
282+
memory_type_index: usize,
283+
heap: ID3D12Heap,
284+
285+
name: Option<Box<str>>,
286+
}
287+
273288
impl Allocation {
274289
pub fn chunk_id(&self) -> Option<std::num::NonZeroU64> {
275290
self.chunk_id
@@ -813,8 +828,9 @@ impl Allocator {
813828
memory_type.committed_allocations.total_size += allocation_info.SizeInBytes;
814829

815830
Ok(Resource {
831+
name: desc.name.into(),
816832
allocation: None,
817-
resource: ManuallyDrop::new(resource),
833+
resource: Some(resource),
818834
size: allocation_info.SizeInBytes,
819835
memory_location: desc.memory_location,
820836
memory_type_index: Some(memory_type.memory_type_index),
@@ -856,8 +872,9 @@ impl Allocator {
856872
result.expect("Allocation succeeded but no resource was returned?");
857873
let size = allocation.size();
858874
Ok(Resource {
875+
name: desc.name.into(),
859876
allocation: Some(allocation),
860-
resource: ManuallyDrop::new(resource),
877+
resource: Some(resource),
861878
size,
862879
memory_location: desc.memory_location,
863880
memory_type_index: None,
@@ -868,13 +885,19 @@ impl Allocator {
868885
}
869886

870887
/// Free a resource and its memory.
871-
pub fn free_resource(&mut self, resource: Resource) -> Result<()> {
872-
let _ = ManuallyDrop::into_inner(resource.resource);
873-
if let Some(allocation) = resource.allocation {
888+
pub fn free_resource(&mut self, mut resource: Resource) -> Result<()> {
889+
// Explicitly drop the resource (which is backed by a refcounted COM object)
890+
// before freeing allocated memory. Windows-rs performs a Release() on drop().
891+
let _ = resource
892+
.resource
893+
.take()
894+
.expect("Resource was already freed.");
895+
896+
if let Some(allocation) = resource.allocation.take() {
874897
self.free(allocation)
875898
} else {
876-
// Committed resources are implicitly dropped when their refcount reaches 0.
877-
// We only have to change the allocation and size tracking.
899+
// Dx12 CommittedResources do not have an application managed allocation.
900+
// We only have to update the tracked allocation count and memory usage.
878901
if let Some(memory_type_index) = resource.memory_type_index {
879902
let memory_type = &mut self.memory_types[memory_type_index];
880903

src/vulkan/mod.rs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,13 @@ use crate::{
1717

1818
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1919
pub enum AllocationScheme {
20-
/// This allocation will be for a buffer, and it will be driver managed using vulkans DedicatedAllocation feature.
21-
/// The driver will be able to perform optimizations in some cases with this type of allocation.
22-
DedicatedBuffer { buffer: vk::Buffer },
23-
/// This allocation will be for a image, and it will be driver managed using vulkans DedicatedAllocation feature.
24-
/// The driver will be able to perform optimizations in some cases with this type of allocation.
25-
DedicatedImage { image: vk::Image },
26-
/// This allocation will be managed by the GPU allocator.
27-
/// It is possible that the allocation will reside in an allocation block shared with other resources.
20+
/// Perform a dedicated, driver-managed allocation for the given buffer, allowing
21+
/// it to perform optimizations on this type of allocation.
22+
DedicatedBuffer(vk::Buffer),
23+
/// Perform a dedicated, driver-managed allocation for the given image, allowing
24+
/// it to perform optimizations on this type of allocation.
25+
DedicatedImage(vk::Image),
26+
/// The memory for this resource will be allocated and managed by gpu-allocator.
2827
GpuAllocatorManaged,
2928
}
3029

@@ -169,10 +168,10 @@ impl MemoryBlock {
169168
mem_type_index: usize,
170169
mapped: bool,
171170
buffer_device_address: bool,
172-
allocation_scheme: &AllocationScheme,
171+
allocation_scheme: AllocationScheme,
173172
requires_personal_block: bool,
174173
) -> Result<Self> {
175-
let dedicated_allocation = *allocation_scheme != AllocationScheme::GpuAllocatorManaged;
174+
let dedicated_allocation = allocation_scheme != AllocationScheme::GpuAllocatorManaged;
176175
let device_memory = {
177176
let alloc_info = vk::MemoryAllocateInfo::builder()
178177
.allocation_size(size)
@@ -190,12 +189,12 @@ impl MemoryBlock {
190189
// Flag the memory as dedicated if required.
191190
let mut dedicated_memory_info = vk::MemoryDedicatedAllocateInfo::builder();
192191
let alloc_info = match allocation_scheme {
193-
AllocationScheme::DedicatedBuffer { buffer } => {
194-
dedicated_memory_info = dedicated_memory_info.buffer(*buffer);
192+
AllocationScheme::DedicatedBuffer(buffer) => {
193+
dedicated_memory_info = dedicated_memory_info.buffer(buffer);
195194
alloc_info.push_next(&mut dedicated_memory_info)
196195
}
197-
AllocationScheme::DedicatedImage { image } => {
198-
dedicated_memory_info = dedicated_memory_info.image(*image);
196+
AllocationScheme::DedicatedImage(image) => {
197+
dedicated_memory_info = dedicated_memory_info.image(image);
199198
alloc_info.push_next(&mut dedicated_memory_info)
200199
}
201200
AllocationScheme::GpuAllocatorManaged => alloc_info,
@@ -232,14 +231,14 @@ impl MemoryBlock {
232231
})
233232
.transpose()?;
234233

235-
let sub_allocator: Box<dyn allocator::SubAllocator> =
236-
if !matches!(allocation_scheme, AllocationScheme::GpuAllocatorManaged)
237-
|| requires_personal_block
238-
{
239-
Box::new(allocator::DedicatedBlockAllocator::new(size))
240-
} else {
241-
Box::new(allocator::FreeListAllocator::new(size))
242-
};
234+
let sub_allocator: Box<dyn allocator::SubAllocator> = if allocation_scheme
235+
!= AllocationScheme::GpuAllocatorManaged
236+
|| requires_personal_block
237+
{
238+
Box::new(allocator::DedicatedBlockAllocator::new(size))
239+
} else {
240+
Box::new(allocator::FreeListAllocator::new(size))
241+
};
243242

244243
Ok(Self {
245244
device_memory,
@@ -310,7 +309,7 @@ impl MemoryType {
310309
self.memory_type_index,
311310
self.mappable,
312311
self.buffer_device_address,
313-
&desc.allocation_scheme,
312+
desc.allocation_scheme,
314313
requires_personal_block,
315314
)?;
316315

@@ -408,7 +407,7 @@ impl MemoryType {
408407
self.memory_type_index,
409408
self.mappable,
410409
self.buffer_device_address,
411-
&desc.allocation_scheme,
410+
desc.allocation_scheme,
412411
false,
413412
)?;
414413

0 commit comments

Comments
 (0)