Skip to content

Commit a23af73

Browse files
authored
d3d12: Add support for castable formats on resource allocations (#221)
* dx castable formats * fmt * working castable formats on dx12 * add back device 10 * use helper func * remove duplication * Improve comment and flip match order * mip region default within `d3d12_resource_desc_1` function * better error handling as per PR discussion * improve comment
1 parent 68ffb9d commit a23af73

2 files changed

Lines changed: 145 additions & 51 deletions

File tree

src/d3d12/mod.rs

Lines changed: 140 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use std::{backtrace::Backtrace, fmt, sync::Arc};
44

55
use log::{debug, warn, Level};
66

7-
use windows::Win32::{Foundation::E_OUTOFMEMORY, Graphics::Direct3D12::*};
7+
use windows::Win32::{
8+
Foundation::E_OUTOFMEMORY,
9+
Graphics::{Direct3D12::*, Dxgi::Common::DXGI_FORMAT},
10+
};
811

912
#[cfg(feature = "public-winapi")]
1013
mod public_winapi {
@@ -110,6 +113,7 @@ pub struct ResourceCreateDesc<'a> {
110113
pub memory_location: MemoryLocation,
111114
pub resource_category: ResourceCategory,
112115
pub resource_desc: &'a D3D12_RESOURCE_DESC,
116+
pub castable_formats: &'a [DXGI_FORMAT],
113117
pub clear_value: Option<&'a D3D12_CLEAR_VALUE>,
114118
pub initial_state_or_layout: ResourceStateOrBarrierLayout,
115119
pub resource_type: &'a ResourceType<'a>,
@@ -242,6 +246,8 @@ pub enum ID3D12DeviceVersion {
242246
/// Required for enhanced barrier support, i.e. when using
243247
/// [`ResourceStateOrBarrierLayout::BarrierLayout`].
244248
Device10(ID3D12Device10),
249+
/// Required for castable formats support, implies use of enhanced barriers
250+
Device12(ID3D12Device12),
245251
}
246252

247253
impl std::ops::Deref for ID3D12DeviceVersion {
@@ -250,8 +256,9 @@ impl std::ops::Deref for ID3D12DeviceVersion {
250256
fn deref(&self) -> &Self::Target {
251257
match self {
252258
Self::Device(device) => device,
253-
// Windows-rs hides CanInto, we know that Device10 is a subclass of Device but there's not even a Deref.
259+
// Windows-rs hides CanInto, we know that Device10/Device12 is a subclass of Device but there's not even a Deref.
254260
Self::Device10(device10) => windows::core::CanInto::can_into(device10),
261+
Self::Device12(device12) => windows::core::CanInto::can_into(device12),
255262
}
256263
}
257264
}
@@ -806,6 +813,66 @@ impl Allocator {
806813
}
807814
}
808815

816+
fn d3d12_resource_desc_1(desc: &D3D12_RESOURCE_DESC) -> D3D12_RESOURCE_DESC1 {
817+
D3D12_RESOURCE_DESC1 {
818+
Dimension: desc.Dimension,
819+
Alignment: desc.Alignment,
820+
Width: desc.Width,
821+
Height: desc.Height,
822+
DepthOrArraySize: desc.DepthOrArraySize,
823+
MipLevels: desc.MipLevels,
824+
Format: desc.Format,
825+
SampleDesc: desc.SampleDesc,
826+
Layout: desc.Layout,
827+
Flags: desc.Flags,
828+
// TODO: This is the only new field
829+
SamplerFeedbackMipRegion: D3D12_MIP_REGION::default(),
830+
}
831+
}
832+
833+
fn resource_allocation_info(
834+
device: &ID3D12DeviceVersion,
835+
desc: &ResourceCreateDesc<'_>,
836+
) -> D3D12_RESOURCE_ALLOCATION_INFO {
837+
match device {
838+
ID3D12DeviceVersion::Device(device) => unsafe {
839+
device.GetResourceAllocationInfo(0, &[*desc.resource_desc])
840+
},
841+
ID3D12DeviceVersion::Device10(device) => unsafe {
842+
device.GetResourceAllocationInfo(0, &[*desc.resource_desc])
843+
},
844+
ID3D12DeviceVersion::Device12(device) => unsafe {
845+
let resource_desc1 = Self::d3d12_resource_desc_1(desc.resource_desc);
846+
847+
let resource_descs = &[resource_desc1];
848+
849+
// We always have one resource desc, hence we only have one mapping castable format array
850+
let num_castable_formats = desc.castable_formats.len() as u32;
851+
let num_castable_formats_array = &[num_castable_formats];
852+
853+
let castable_formats_array = &[desc.castable_formats.as_ptr()];
854+
855+
let (num_castable_formats_opt, castable_formats_opt) = if num_castable_formats > 0 {
856+
(
857+
Some(num_castable_formats_array.as_ptr()),
858+
Some(castable_formats_array.as_ptr()),
859+
)
860+
} else {
861+
(None, None)
862+
};
863+
864+
device.GetResourceAllocationInfo3(
865+
0,
866+
resource_descs.len() as u32,
867+
resource_descs.as_ptr(),
868+
num_castable_formats_opt,
869+
castable_formats_opt,
870+
None,
871+
)
872+
},
873+
}
874+
}
875+
809876
/// Create a resource according to the provided parameters.
810877
/// Created resources should be freed at the end of their lifetime by calling [`Self::free_resource()`].
811878
pub fn create_resource(&mut self, desc: &ResourceCreateDesc<'_>) -> Result<Resource> {
@@ -821,34 +888,37 @@ impl Allocator {
821888

822889
if let Err(e) = unsafe {
823890
match (&self.device, desc.initial_state_or_layout) {
824-
(device, ResourceStateOrBarrierLayout::ResourceState(initial_state)) => {
825-
device.CreateCommittedResource(
891+
(_, ResourceStateOrBarrierLayout::ResourceState(_))
892+
if !desc.castable_formats.is_empty() =>
893+
{
894+
return Err(AllocationError::CastableFormatsRequiresEnhancedBarriers)
895+
}
896+
(
897+
ID3D12DeviceVersion::Device12(device),
898+
ResourceStateOrBarrierLayout::BarrierLayout(initial_layout),
899+
) => {
900+
let resource_desc1 = Self::d3d12_resource_desc_1(desc.resource_desc);
901+
device.CreateCommittedResource3(
826902
*heap_properties,
827903
*heap_flags,
828-
desc.resource_desc,
829-
initial_state,
904+
&resource_desc1,
905+
initial_layout,
830906
clear_value,
907+
None, // TODO
908+
Some(desc.castable_formats),
831909
&mut result,
832910
)
833911
}
912+
(_, ResourceStateOrBarrierLayout::BarrierLayout(_))
913+
if !desc.castable_formats.is_empty() =>
914+
{
915+
return Err(AllocationError::CastableFormatsRequiresAtLeastDevice12)
916+
}
834917
(
835918
ID3D12DeviceVersion::Device10(device),
836919
ResourceStateOrBarrierLayout::BarrierLayout(initial_layout),
837920
) => {
838-
let resource_desc1 = D3D12_RESOURCE_DESC1 {
839-
Dimension: desc.resource_desc.Dimension,
840-
Alignment: desc.resource_desc.Alignment,
841-
Width: desc.resource_desc.Width,
842-
Height: desc.resource_desc.Height,
843-
DepthOrArraySize: desc.resource_desc.DepthOrArraySize,
844-
MipLevels: desc.resource_desc.MipLevels,
845-
Format: desc.resource_desc.Format,
846-
SampleDesc: desc.resource_desc.SampleDesc,
847-
Layout: desc.resource_desc.Layout,
848-
Flags: desc.resource_desc.Flags,
849-
// TODO: This is the only new field
850-
SamplerFeedbackMipRegion: D3D12_MIP_REGION::default(),
851-
};
921+
let resource_desc1 = Self::d3d12_resource_desc_1(desc.resource_desc);
852922

853923
device.CreateCommittedResource3(
854924
*heap_properties,
@@ -857,11 +927,23 @@ impl Allocator {
857927
initial_layout,
858928
clear_value,
859929
None, // TODO
860-
None, // TODO: https://github.com/microsoft/DirectX-Specs/blob/master/d3d/VulkanOn12.md#format-list-casting
930+
None,
931+
&mut result,
932+
)
933+
}
934+
(_, ResourceStateOrBarrierLayout::BarrierLayout(_)) => {
935+
return Err(AllocationError::BarrierLayoutNeedsDevice10)
936+
}
937+
(device, ResourceStateOrBarrierLayout::ResourceState(initial_state)) => {
938+
device.CreateCommittedResource(
939+
*heap_properties,
940+
*heap_flags,
941+
desc.resource_desc,
942+
initial_state,
943+
clear_value,
861944
&mut result,
862945
)
863946
}
864-
_ => return Err(AllocationError::BarrierLayoutNeedsDevice10),
865947
}
866948
} {
867949
return Err(AllocationError::Internal(format!(
@@ -872,10 +954,7 @@ impl Allocator {
872954

873955
let resource = result.expect("Allocation succeeded but no resource was returned?");
874956

875-
let allocation_info = unsafe {
876-
self.device
877-
.GetResourceAllocationInfo(0, &[*desc.resource_desc])
878-
};
957+
let allocation_info = Self::resource_allocation_info(&self.device, desc);
879958

880959
let memory_type = self
881960
.memory_types
@@ -906,10 +985,7 @@ impl Allocator {
906985
}
907986
ResourceType::Placed => {
908987
let allocation_desc = {
909-
let allocation_info = unsafe {
910-
self.device
911-
.GetResourceAllocationInfo(0, &[*desc.resource_desc])
912-
};
988+
let allocation_info = Self::resource_allocation_info(&self.device, desc);
913989

914990
AllocationCreateDesc {
915991
name: desc.name,
@@ -925,45 +1001,59 @@ impl Allocator {
9251001
let mut result: Option<ID3D12Resource> = None;
9261002
if let Err(e) = unsafe {
9271003
match (&self.device, desc.initial_state_or_layout) {
928-
(device, ResourceStateOrBarrierLayout::ResourceState(initial_state)) => {
929-
device.CreatePlacedResource(
1004+
(_, ResourceStateOrBarrierLayout::ResourceState(_))
1005+
if !desc.castable_formats.is_empty() =>
1006+
{
1007+
return Err(AllocationError::CastableFormatsRequiresEnhancedBarriers)
1008+
}
1009+
(
1010+
ID3D12DeviceVersion::Device12(device),
1011+
ResourceStateOrBarrierLayout::BarrierLayout(initial_layout),
1012+
) => {
1013+
let resource_desc1 = Self::d3d12_resource_desc_1(desc.resource_desc);
1014+
device.CreatePlacedResource2(
9301015
allocation.heap(),
9311016
allocation.offset(),
932-
desc.resource_desc,
933-
initial_state,
1017+
&resource_desc1,
1018+
initial_layout,
9341019
None,
1020+
Some(desc.castable_formats),
9351021
&mut result,
9361022
)
9371023
}
1024+
(_, ResourceStateOrBarrierLayout::BarrierLayout(_))
1025+
if !desc.castable_formats.is_empty() =>
1026+
{
1027+
return Err(AllocationError::CastableFormatsRequiresAtLeastDevice12)
1028+
}
9381029
(
9391030
ID3D12DeviceVersion::Device10(device),
9401031
ResourceStateOrBarrierLayout::BarrierLayout(initial_layout),
9411032
) => {
942-
let resource_desc1 = D3D12_RESOURCE_DESC1 {
943-
Dimension: desc.resource_desc.Dimension,
944-
Alignment: desc.resource_desc.Alignment,
945-
Width: desc.resource_desc.Width,
946-
Height: desc.resource_desc.Height,
947-
DepthOrArraySize: desc.resource_desc.DepthOrArraySize,
948-
MipLevels: desc.resource_desc.MipLevels,
949-
Format: desc.resource_desc.Format,
950-
SampleDesc: desc.resource_desc.SampleDesc,
951-
Layout: desc.resource_desc.Layout,
952-
Flags: desc.resource_desc.Flags,
953-
// TODO: This is the only new field
954-
SamplerFeedbackMipRegion: D3D12_MIP_REGION::default(),
955-
};
1033+
let resource_desc1 = Self::d3d12_resource_desc_1(desc.resource_desc);
9561034
device.CreatePlacedResource2(
9571035
allocation.heap(),
9581036
allocation.offset(),
9591037
&resource_desc1,
9601038
initial_layout,
9611039
None,
962-
None, // TODO: https://github.com/microsoft/DirectX-Specs/blob/master/d3d/VulkanOn12.md#format-list-casting
1040+
None,
1041+
&mut result,
1042+
)
1043+
}
1044+
(_, ResourceStateOrBarrierLayout::BarrierLayout(_)) => {
1045+
return Err(AllocationError::BarrierLayoutNeedsDevice10)
1046+
}
1047+
(device, ResourceStateOrBarrierLayout::ResourceState(initial_state)) => {
1048+
device.CreatePlacedResource(
1049+
allocation.heap(),
1050+
allocation.offset(),
1051+
desc.resource_desc,
1052+
initial_state,
1053+
None,
9631054
&mut result,
9641055
)
9651056
}
966-
_ => return Err(AllocationError::BarrierLayoutNeedsDevice10),
9671057
}
9681058
} {
9691059
return Err(AllocationError::Internal(format!(

src/result.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@ pub enum AllocationError {
1414
InvalidAllocatorCreateDesc(String),
1515
#[error("Internal error: {0}")]
1616
Internal(String),
17-
#[error("Initial `BARRIER_LAYOUT` needs `Device10`")]
17+
#[error("Initial `BARRIER_LAYOUT` needs at least `Device10`")]
1818
BarrierLayoutNeedsDevice10,
19+
#[error("Castable formats require enhanced barriers")]
20+
CastableFormatsRequiresEnhancedBarriers,
21+
#[error("Castable formats require at least `Device12`")]
22+
CastableFormatsRequiresAtLeastDevice12,
1923
}
2024

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

0 commit comments

Comments
 (0)