From d51f58d4cd6e7b7e582ba0150ce1819b41cf6924 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 18 Apr 2023 16:59:35 +0200 Subject: [PATCH] d3d12: Use `Device10` `Placed/CommittedResource` functions for Enhanced-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. --- examples/d3d12-buffer-winrs.rs | 4 +- src/d3d12/mod.rs | 241 +++++++++++++++++++++++---------- src/result.rs | 2 + 3 files changed, 174 insertions(+), 73 deletions(-) diff --git a/examples/d3d12-buffer-winrs.rs b/examples/d3d12-buffer-winrs.rs index deb7d94d..fedbea5f 100644 --- a/examples/d3d12-buffer-winrs.rs +++ b/examples/d3d12-buffer-winrs.rs @@ -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::*; @@ -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(), }) diff --git a/src/d3d12/mod.rs b/src/d3d12/mod.rs index 2a77b603..cf400fee 100644 --- a/src/d3d12/mod.rs +++ b/src/d3d12/mod.rs @@ -98,6 +98,12 @@ 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, @@ -105,7 +111,7 @@ pub struct ResourceCreateDesc<'a> { 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>, } @@ -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, } @@ -391,7 +419,7 @@ struct MemoryType { impl MemoryType { fn allocate( &mut self, - device: &ID3D12Device, + device: &ID3D12DeviceVersion, desc: &AllocationCreateDesc<'_>, backtrace: Option, allocation_sizes: &AllocationSizes, @@ -571,14 +599,14 @@ impl MemoryType { } pub struct Allocator { - device: ID3D12Device, + device: ID3D12DeviceVersion, debug_settings: AllocatorDebugSettings, memory_types: Vec, allocation_sizes: AllocationSizes, } impl Allocator { - pub fn device(&self) -> &ID3D12Device { + pub fn device(&self) -> &ID3D12DeviceVersion { &self.device } @@ -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 = { @@ -859,30 +923,65 @@ impl Allocator { let allocation = self.allocate(&allocation_desc)?; let mut result: Option = 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, + }) } } } diff --git a/src/result.rs b/src/result.rs index f57d832b..7d5336d5 100644 --- a/src/result.rs +++ b/src/result.rs @@ -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 = ::std::result::Result;