Skip to content

Commit

Permalink
d3d12: Use Device10 Placed/CommittedResource functions for Enhanc…
Browse files Browse the repository at this point in the history
…ed-Barriers initial Layout

When using enhanced barriers new resource creation APIs need to be used
to set its initial layout rather than setting an initial state, which is
the legacy enumeration API.

In order to support this we need access to `Device10` where the new
methods reside, which we could query (`.cast()`) from `ID3D12Device` or
request from the user directly as done here.
  • Loading branch information
MarijnS95 committed May 16, 2023
1 parent bf4e665 commit d51f58d
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 73 deletions.
4 changes: 2 additions & 2 deletions examples/d3d12-buffer-winrs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Example showcasing [`gpu-allocator`] with types and functions from the [`windows`] crate.
use gpu_allocator::d3d12::{
AllocationCreateDesc, Allocator, AllocatorCreateDesc, ResourceCategory,
AllocationCreateDesc, Allocator, AllocatorCreateDesc, ID3D12DeviceVersion, ResourceCategory,
};
use gpu_allocator::MemoryLocation;
use log::*;
Expand Down Expand Up @@ -88,7 +88,7 @@ fn main() -> Result<()> {

// Setting up the allocator
let mut allocator = Allocator::new(&AllocatorCreateDesc {
device: device.clone(),
device: ID3D12DeviceVersion::Device(device.clone()),
debug_settings: Default::default(),
allocation_sizes: Default::default(),
})
Expand Down
241 changes: 170 additions & 71 deletions src/d3d12/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,20 @@ pub enum ResourceCategory {
OtherTexture,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ResourceStateOrBarrierLayout {
ResourceState(D3D12_RESOURCE_STATES),
BarrierLayout(D3D12_BARRIER_LAYOUT),
}

#[derive(Clone, Copy)]
pub struct ResourceCreateDesc<'a> {
pub name: &'a str,
pub memory_location: MemoryLocation,
pub resource_category: ResourceCategory,
pub resource_desc: &'a D3D12_RESOURCE_DESC,
pub clear_value: Option<&'a D3D12_CLEAR_VALUE>,
pub initial_state: D3D12_RESOURCE_STATES,
pub initial_state_or_layout: ResourceStateOrBarrierLayout,
pub resource_type: &'a ResourceType<'a>,
}

Expand Down Expand Up @@ -228,9 +234,31 @@ impl<'a> AllocationCreateDesc<'a> {
}
}

#[derive(Clone, Debug)]
pub enum ID3D12DeviceVersion {
/// Basic device compatible with legacy barriers only, i.e. can only be used in conjunction
/// with [`ResourceStateOrBarrierLayout::ResourceState`].
Device(ID3D12Device),
/// Required for enhanced barrier support, i.e. when using
/// [`ResourceStateOrBarrierLayout::BarrierLayout`].
Device10(ID3D12Device10),
}

impl std::ops::Deref for ID3D12DeviceVersion {
type Target = ID3D12Device;

fn deref(&self) -> &Self::Target {
match self {
Self::Device(device) => device,
// Windows-rs hides CanInto, we know that Device10 is a subclass of Device but there's not even a Deref.
Self::Device10(device10) => windows::core::CanInto::can_into(device10),
}
}
}

#[derive(Debug)]
pub struct AllocatorCreateDesc {
pub device: ID3D12Device,
pub device: ID3D12DeviceVersion,
pub debug_settings: AllocatorDebugSettings,
pub allocation_sizes: AllocationSizes,
}
Expand Down Expand Up @@ -391,7 +419,7 @@ struct MemoryType {
impl MemoryType {
fn allocate(
&mut self,
device: &ID3D12Device,
device: &ID3D12DeviceVersion,
desc: &AllocationCreateDesc<'_>,
backtrace: Option<backtrace::Backtrace>,
allocation_sizes: &AllocationSizes,
Expand Down Expand Up @@ -571,14 +599,14 @@ impl MemoryType {
}

pub struct Allocator {
device: ID3D12Device,
device: ID3D12DeviceVersion,
debug_settings: AllocatorDebugSettings,
memory_types: Vec<MemoryType>,
allocation_sizes: AllocationSizes,
}

impl Allocator {
pub fn device(&self) -> &ID3D12Device {
pub fn device(&self) -> &ID3D12DeviceVersion {
&self.device
}

Expand Down Expand Up @@ -791,54 +819,90 @@ impl Allocator {
let clear_value: Option<*const D3D12_CLEAR_VALUE> =
desc.clear_value.map(|v| -> *const _ { v });

if let Err(err) = unsafe {
self.device.CreateCommittedResource(
*heap_properties,
*heap_flags,
desc.resource_desc,
desc.initial_state,
clear_value,
&mut result,
)
if let Err(e) = unsafe {
match (&self.device, desc.initial_state_or_layout) {
(device, ResourceStateOrBarrierLayout::ResourceState(initial_state)) => {
device.CreateCommittedResource(
*heap_properties,
*heap_flags,
desc.resource_desc,
initial_state,
clear_value,
&mut result,
)
}
(
ID3D12DeviceVersion::Device10(device),
ResourceStateOrBarrierLayout::BarrierLayout(initial_layout),
) => {
let resource_desc1 = D3D12_RESOURCE_DESC1 {
Dimension: desc.resource_desc.Dimension,
Alignment: desc.resource_desc.Alignment,
Width: desc.resource_desc.Width,
Height: desc.resource_desc.Height,
DepthOrArraySize: desc.resource_desc.DepthOrArraySize,
MipLevels: desc.resource_desc.MipLevels,
Format: desc.resource_desc.Format,
SampleDesc: desc.resource_desc.SampleDesc,
Layout: desc.resource_desc.Layout,
Flags: desc.resource_desc.Flags,
// TODO: This is the only new field
SamplerFeedbackMipRegion: D3D12_MIP_REGION::default(),
};

device.CreateCommittedResource3(
*heap_properties,
*heap_flags,
&resource_desc1,
initial_layout,
clear_value,
None, // TODO
None, // TODO: https://github.com/microsoft/DirectX-Specs/blob/master/d3d/VulkanOn12.md#format-list-casting
&mut result,
)
}
_ => return Err(AllocationError::BarrierLayoutNeedsDevice10),
}
} {
Err(AllocationError::Internal(err.message().to_string()))
} else {
let resource =
result.expect("Allocation succeeded but no resource was returned?");
return Err(AllocationError::Internal(format!(
"ID3D12Device::CreateCommittedResource failed: {}",
e
)));
}

let allocation_info = unsafe {
self.device
.GetResourceAllocationInfo(0, &[*desc.resource_desc])
};
let resource = result.expect("Allocation succeeded but no resource was returned?");

let memory_type = self
.memory_types
.iter_mut()
.find(|memory_type| {
let is_location_compatible = desc.memory_location
== MemoryLocation::Unknown
|| desc.memory_location == memory_type.memory_location;

let is_category_compatible = memory_type.heap_category
== HeapCategory::All
|| memory_type.heap_category == desc.resource_category.into();

is_location_compatible && is_category_compatible
})
.ok_or(AllocationError::NoCompatibleMemoryTypeFound)?;

memory_type.committed_allocations.num_allocations += 1;
memory_type.committed_allocations.total_size += allocation_info.SizeInBytes;

Ok(Resource {
name: desc.name.into(),
allocation: None,
resource: Some(resource),
size: allocation_info.SizeInBytes,
memory_location: desc.memory_location,
memory_type_index: Some(memory_type.memory_type_index),
let allocation_info = unsafe {
self.device
.GetResourceAllocationInfo(0, &[*desc.resource_desc])
};

let memory_type = self
.memory_types
.iter_mut()
.find(|memory_type| {
let is_location_compatible = desc.memory_location
== MemoryLocation::Unknown
|| desc.memory_location == memory_type.memory_location;

let is_category_compatible = memory_type.heap_category == HeapCategory::All
|| memory_type.heap_category == desc.resource_category.into();

is_location_compatible && is_category_compatible
})
}
.ok_or(AllocationError::NoCompatibleMemoryTypeFound)?;

memory_type.committed_allocations.num_allocations += 1;
memory_type.committed_allocations.total_size += allocation_info.SizeInBytes;

Ok(Resource {
name: desc.name.into(),
allocation: None,
resource: Some(resource),
size: allocation_info.SizeInBytes,
memory_location: desc.memory_location,
memory_type_index: Some(memory_type.memory_type_index),
})
}
ResourceType::Placed => {
let allocation_desc = {
Expand All @@ -859,30 +923,65 @@ impl Allocator {
let allocation = self.allocate(&allocation_desc)?;

let mut result: Option<ID3D12Resource> = None;
if let Err(err) = unsafe {
self.device.CreatePlacedResource(
allocation.heap(),
allocation.offset(),
desc.resource_desc,
desc.initial_state,
None,
&mut result,
)
if let Err(e) = unsafe {
match (&self.device, desc.initial_state_or_layout) {
(device, ResourceStateOrBarrierLayout::ResourceState(initial_state)) => {
device.CreatePlacedResource(
allocation.heap(),
allocation.offset(),
desc.resource_desc,
initial_state,
None,
&mut result,
)
}
(
ID3D12DeviceVersion::Device10(device),
ResourceStateOrBarrierLayout::BarrierLayout(initial_layout),
) => {
let resource_desc1 = D3D12_RESOURCE_DESC1 {
Dimension: desc.resource_desc.Dimension,
Alignment: desc.resource_desc.Alignment,
Width: desc.resource_desc.Width,
Height: desc.resource_desc.Height,
DepthOrArraySize: desc.resource_desc.DepthOrArraySize,
MipLevels: desc.resource_desc.MipLevels,
Format: desc.resource_desc.Format,
SampleDesc: desc.resource_desc.SampleDesc,
Layout: desc.resource_desc.Layout,
Flags: desc.resource_desc.Flags,
// TODO: This is the only new field
SamplerFeedbackMipRegion: D3D12_MIP_REGION::default(),
};
device.CreatePlacedResource2(
allocation.heap(),
allocation.offset(),
&resource_desc1,
initial_layout,
None,
None, // TODO: https://github.com/microsoft/DirectX-Specs/blob/master/d3d/VulkanOn12.md#format-list-casting
&mut result,
)
}
_ => return Err(AllocationError::BarrierLayoutNeedsDevice10),
}
} {
Err(AllocationError::Internal(err.message().to_string()))
} else {
let resource =
result.expect("Allocation succeeded but no resource was returned?");
let size = allocation.size();
Ok(Resource {
name: desc.name.into(),
allocation: Some(allocation),
resource: Some(resource),
size,
memory_location: desc.memory_location,
memory_type_index: None,
})
return Err(AllocationError::Internal(format!(
"ID3D12Device::CreatePlacedResource failed: {}",
e
)));
}

let resource = result.expect("Allocation succeeded but no resource was returned?");
let size = allocation.size();
Ok(Resource {
name: desc.name.into(),
allocation: Some(allocation),
resource: Some(resource),
size,
memory_location: desc.memory_location,
memory_type_index: None,
})
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub enum AllocationError {
InvalidAllocatorCreateDesc(String),
#[error("Internal error: {0}")]
Internal(String),
#[error("Initial `BARRIER_LAYOUT` needs `Device10`")]
BarrierLayoutNeedsDevice10,
}

pub type Result<V, E = AllocationError> = ::std::result::Result<V, E>;

0 comments on commit d51f58d

Please sign in to comment.