Skip to content

Commit b3a3dc3

Browse files
jamienicolteoxoy
authored andcommitted
[dx12] Support external textures on DX12
This implements the DX12 HAL part of external texture support, which is the final piece of the puzzle for external textures on DirectX 12. When creating a pipeline layout, HAL is responsible for mapping a single BindingType::ExternalTexture bind group entry to multiple descriptor ranges in the root signature it creates: 3 SRVs (one for each texture plane) and a CBV for the parameters buffer. Additionally we must expose the additional bindings to the Naga backend via the `external_texture_binding_map`. Lastly, when creating a bind group we write the descriptors for each of these bindings to the heap. And with that, we can finally enable the `EXTERNAL_TEXTURE` feature for the dx12 backend.
1 parent b538522 commit b3a3dc3

4 files changed

Lines changed: 139 additions & 58 deletions

File tree

wgpu-hal/src/dx12/adapter.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,8 @@ impl super::Adapter {
361361
| wgt::Features::DUAL_SOURCE_BLENDING
362362
| wgt::Features::TEXTURE_FORMAT_NV12
363363
| wgt::Features::FLOAT32_FILTERABLE
364-
| wgt::Features::TEXTURE_ATOMIC;
364+
| wgt::Features::TEXTURE_ATOMIC
365+
| wgt::Features::EXTERNAL_TEXTURE;
365366

366367
//TODO: in order to expose this, we need to run a compute shader
367368
// that extract the necessary statistics out of the D3D12 result.

wgpu-hal/src/dx12/conv.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,10 @@ pub fn map_binding_type(ty: &wgt::BindingType) -> Direct3D12::D3D12_DESCRIPTOR_R
135135
}
136136
| Bt::StorageTexture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
137137
Bt::AccelerationStructure { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
138-
Bt::ExternalTexture => unimplemented!(),
138+
// External textures require multiple bindings and therefore cannot
139+
// be mapped to a single descriptor range type. They must be handled
140+
// separately by the caller.
141+
Bt::ExternalTexture => unreachable!("External textures must be handled separately"),
139142
}
140143
}
141144

wgpu-hal/src/dx12/device.rs

Lines changed: 132 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,8 @@ impl crate::Device for super::Device {
807807
| wgt::BindingType::StorageTexture { .. }
808808
| wgt::BindingType::AccelerationStructure { .. } => num_views += count,
809809
wgt::BindingType::Sampler { .. } => has_sampler_in_group = true,
810-
wgt::BindingType::ExternalTexture => unimplemented!(),
810+
// Three texture planes and one params buffer
811+
wgt::BindingType::ExternalTexture => num_views += 4 * count,
811812
}
812813
}
813814

@@ -880,6 +881,7 @@ impl crate::Device for super::Device {
880881

881882
let mut binding_map = hlsl::BindingMap::default();
882883
let mut sampler_buffer_binding_map = hlsl::SamplerIndexBufferBindingMap::default();
884+
let mut external_texture_binding_map = hlsl::ExternalTextureBindingMap::default();
883885
let mut bind_cbv = hlsl::BindTarget::default();
884886
let mut bind_srv = hlsl::BindTarget::default();
885887
let mut bind_uav = hlsl::BindTarget::default();
@@ -939,6 +941,8 @@ impl crate::Device for super::Device {
939941
..
940942
} => {}
941943
wgt::BindingType::Sampler(_) => sampler_in_bind_group = true,
944+
// Three texture planes and one params buffer
945+
wgt::BindingType::ExternalTexture => total_non_dynamic_entries += 4,
942946
_ => total_non_dynamic_entries += 1,
943947
}
944948
}
@@ -993,61 +997,110 @@ impl crate::Device for super::Device {
993997
// SRV/CBV/UAV descriptor tables
994998
let range_base = ranges.len();
995999
for entry in bgl.entries.iter() {
996-
let (range_ty, has_dynamic_offset) = match entry.ty {
997-
wgt::BindingType::Buffer {
998-
ty,
999-
has_dynamic_offset: true,
1000-
..
1001-
} => match ty {
1002-
wgt::BufferBindingType::Uniform => continue,
1003-
wgt::BufferBindingType::Storage { .. } => {
1004-
(conv::map_binding_type(&entry.ty), true)
1005-
}
1006-
},
1007-
ref other => (conv::map_binding_type(other), false),
1008-
};
1009-
let bt = match range_ty {
1010-
Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV => &mut bind_cbv,
1011-
Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV => &mut bind_srv,
1012-
Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV => &mut bind_uav,
1013-
Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER => continue,
1014-
_ => todo!(),
1015-
};
1016-
1017-
let binding_array_size = entry.count.map(NonZeroU32::get);
1018-
1019-
let dynamic_storage_buffer_offsets_index = if has_dynamic_offset {
1020-
debug_assert!(
1021-
binding_array_size.is_none(),
1022-
"binding arrays and dynamic buffers are mutually exclusive"
1000+
let count = entry.count.map_or(1, NonZeroU32::get);
1001+
if let wgt::BindingType::ExternalTexture = entry.ty {
1002+
// External textures need 3 SRVs (a texture for each plane)
1003+
// and 1 CBV for the parameters buffer.
1004+
let bind_target = hlsl::ExternalTextureBindTarget {
1005+
planes: core::array::from_fn(|_| hlsl::BindTarget {
1006+
register: {
1007+
let register = bind_srv.register;
1008+
bind_srv.register += count;
1009+
register
1010+
},
1011+
..bind_srv
1012+
}),
1013+
params: hlsl::BindTarget {
1014+
register: {
1015+
let register = bind_cbv.register;
1016+
bind_cbv.register += count;
1017+
register
1018+
},
1019+
..bind_cbv
1020+
},
1021+
};
1022+
external_texture_binding_map.insert(
1023+
naga::ResourceBinding {
1024+
group: index as u32,
1025+
binding: entry.binding,
1026+
},
1027+
bind_target,
10231028
);
1024-
let ret = Some(dynamic_storage_buffers);
1025-
dynamic_storage_buffers += 1;
1026-
ret
1029+
for bt in bind_target.planes {
1030+
ranges.push(Direct3D12::D3D12_DESCRIPTOR_RANGE {
1031+
RangeType: Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
1032+
NumDescriptors: count,
1033+
BaseShaderRegister: bt.register,
1034+
RegisterSpace: bt.space as u32,
1035+
OffsetInDescriptorsFromTableStart:
1036+
Direct3D12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
1037+
});
1038+
}
1039+
ranges.push(Direct3D12::D3D12_DESCRIPTOR_RANGE {
1040+
RangeType: Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
1041+
NumDescriptors: count,
1042+
BaseShaderRegister: bind_target.params.register,
1043+
RegisterSpace: bind_target.params.space as u32,
1044+
OffsetInDescriptorsFromTableStart:
1045+
Direct3D12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
1046+
});
10271047
} else {
1028-
None
1029-
};
1048+
let (range_ty, has_dynamic_offset) = match entry.ty {
1049+
wgt::BindingType::Buffer {
1050+
ty,
1051+
has_dynamic_offset: true,
1052+
..
1053+
} => match ty {
1054+
wgt::BufferBindingType::Uniform => continue,
1055+
wgt::BufferBindingType::Storage { .. } => {
1056+
(conv::map_binding_type(&entry.ty), true)
1057+
}
1058+
},
1059+
ref other => (conv::map_binding_type(other), false),
1060+
};
1061+
let bt = match range_ty {
1062+
Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV => &mut bind_cbv,
1063+
Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV => &mut bind_srv,
1064+
Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV => &mut bind_uav,
1065+
Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER => continue,
1066+
_ => todo!(),
1067+
};
10301068

1031-
binding_map.insert(
1032-
naga::ResourceBinding {
1033-
group: index as u32,
1034-
binding: entry.binding,
1035-
},
1036-
hlsl::BindTarget {
1037-
binding_array_size,
1038-
dynamic_storage_buffer_offsets_index,
1039-
..*bt
1040-
},
1041-
);
1042-
ranges.push(Direct3D12::D3D12_DESCRIPTOR_RANGE {
1043-
RangeType: range_ty,
1044-
NumDescriptors: entry.count.map_or(1, |count| count.get()),
1045-
BaseShaderRegister: bt.register,
1046-
RegisterSpace: bt.space as u32,
1047-
OffsetInDescriptorsFromTableStart:
1048-
Direct3D12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
1049-
});
1050-
bt.register += entry.count.map(NonZeroU32::get).unwrap_or(1);
1069+
let binding_array_size = entry.count.map(NonZeroU32::get);
1070+
1071+
let dynamic_storage_buffer_offsets_index = if has_dynamic_offset {
1072+
debug_assert!(
1073+
binding_array_size.is_none(),
1074+
"binding arrays and dynamic buffers are mutually exclusive"
1075+
);
1076+
let ret = Some(dynamic_storage_buffers);
1077+
dynamic_storage_buffers += 1;
1078+
ret
1079+
} else {
1080+
None
1081+
};
1082+
1083+
binding_map.insert(
1084+
naga::ResourceBinding {
1085+
group: index as u32,
1086+
binding: entry.binding,
1087+
},
1088+
hlsl::BindTarget {
1089+
binding_array_size,
1090+
dynamic_storage_buffer_offsets_index,
1091+
..*bt
1092+
},
1093+
);
1094+
ranges.push(Direct3D12::D3D12_DESCRIPTOR_RANGE {
1095+
RangeType: range_ty,
1096+
NumDescriptors: count,
1097+
BaseShaderRegister: bt.register,
1098+
RegisterSpace: bt.space as u32,
1099+
OffsetInDescriptorsFromTableStart:
1100+
Direct3D12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
1101+
});
1102+
bt.register += count;
1103+
}
10511104
}
10521105

10531106
let mut sampler_index_within_bind_group = 0;
@@ -1388,7 +1441,7 @@ impl crate::Device for super::Device {
13881441
restrict_indexing: true,
13891442
sampler_heap_target,
13901443
sampler_buffer_binding_map,
1391-
external_texture_binding_map: hlsl::ExternalTextureBindingMap::default(),
1444+
external_texture_binding_map,
13921445
force_loop_bounding: true,
13931446
},
13941447
})
@@ -1574,7 +1627,31 @@ impl crate::Device for super::Device {
15741627
inner.stage.push(handle);
15751628
}
15761629
}
1577-
wgt::BindingType::ExternalTexture => unimplemented!(),
1630+
wgt::BindingType::ExternalTexture => {
1631+
// We don't yet support binding arrays of external textures.
1632+
// https://github.com/gfx-rs/wgpu/issues/8027
1633+
assert_eq!(entry.count, 1);
1634+
let external_texture = &desc.external_textures[entry.resource_index as usize];
1635+
for plane in &external_texture.planes {
1636+
let plane_handle = plane.view.handle_srv.unwrap();
1637+
cpu_views.as_mut().unwrap().stage.push(plane_handle.raw);
1638+
}
1639+
let gpu_address = external_texture.params.resolve_address();
1640+
let size = external_texture.params.resolve_size() as u32;
1641+
let inner = cpu_views.as_mut().unwrap();
1642+
let cpu_index = inner.stage.len() as u32;
1643+
let params_handle = desc.layout.cpu_heap_views.as_ref().unwrap().at(cpu_index);
1644+
let size_mask = Direct3D12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1;
1645+
let raw_desc = Direct3D12::D3D12_CONSTANT_BUFFER_VIEW_DESC {
1646+
BufferLocation: gpu_address,
1647+
SizeInBytes: ((size - 1) | size_mask) + 1,
1648+
};
1649+
unsafe {
1650+
self.raw
1651+
.CreateConstantBufferView(Some(&raw_desc), params_handle)
1652+
};
1653+
inner.stage.push(params_handle);
1654+
}
15781655
}
15791656
}
15801657

wgpu-types/src/features.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ bitflags_array! {
997997
/// all.
998998
///
999999
/// Supported platforms:
1000-
/// - None
1000+
/// - DX12
10011001
const EXTERNAL_TEXTURE = 1 << 30;
10021002

10031003
// Shader:

0 commit comments

Comments
 (0)