hal/dx12: flip the root signature upside down

This commit is contained in:
Dzmitry Malyshau
2021-07-15 01:37:49 -04:00
parent 37bf7d8409
commit e2bd9c935c
2 changed files with 43 additions and 20 deletions

View File

@@ -994,29 +994,22 @@ impl crate::Device<super::Api> for super::Device {
// SRV/CBV/UAV tables are added to the signature first, then Sampler tables,
// and finally dynamic uniform descriptors.
//
// Dynamic uniform buffers are implemented as root descriptors.
// This allows to handle the dynamic offsets properly, which would not be feasible
// with a combination of root constant and descriptor table.
// Buffers with dynamic offsets are implemented as root descriptors.
// This is easier than trying to patch up the offset on the shader side.
//
// Root signature layout:
// Root Constants: Register: Offest/4, Space: 0
// ...
// DescriptorTable0: Space: 1 (SrvCbvUav)
// DescriptorTable0: Space: 1 (Sampler)
// Root Descriptors 0
// DescriptorTable1: Space: 2 (SrvCbvUav)
// Root Descriptors 1
// Root Constants: Register: Offset/4, Space: 0
// ...
// (bind group [3]) - Space: 1
// View descriptor table, if any
// Sampler descriptor table, if any
// Root descriptors (for dynamic offset buffers)
// (bind group [2]) - Space: 2
// ...
// (bind group [0]) - Space: 4
//TODO: reverse the order, according to this advice in
//Note: lower bind group indices are put futher down the root signature. See:
// https://microsoft.github.io/DirectX-Specs/d3d/ResourceBinding.html#binding-model
//> Furthermore, applications should generally sort the layout
//> of the root arguments in decreasing order of change frequency.
//> This way if some implementations need to switch to a different
//> memory storage scheme to version parts of a heavily populated
//> root arguments, the data that is changing at the highest frequency
//> (near the start of the root arguments) is most likely to run
//> as efficiently as possible.
let root_constants: &[()] = &[];
@@ -1046,7 +1039,7 @@ impl crate::Device<super::Api> for super::Device {
let mut bind_group_infos =
arrayvec::ArrayVec::<super::BindGroupInfo, { crate::MAX_BIND_GROUPS }>::default();
for (index, bgl) in desc.bind_group_layouts.iter().enumerate() {
for (index, bgl) in desc.bind_group_layouts.iter().rev().enumerate() {
let space = root_space_offset + index as u32;
let mut info = super::BindGroupInfo {
tables: super::TableTypes::empty(),
@@ -1160,6 +1153,8 @@ impl crate::Device<super::Api> for super::Device {
// Ensure that we didn't reallocate!
debug_assert_eq!(ranges.len(), total_non_dynamic_entries);
// remember that we pushed them in reverse
bind_group_infos.reverse();
let (blob, error) = self
.library

View File

@@ -1,7 +1,35 @@
/*!
# DirectX12 API internals.
## Pipeline Layout
Generally the mapping is straightforwad.
## Resource transitions
D3D12 API matches WebGPU internal states very well. The only
caveat here is issuing a special UAV barrier whenever both source
and destination states match, and they are for storage sync.
## Memory
For now, all resources are created with "committed" memory.
## Resource binding
See ['Device::create_pipeline_layout`] documentation for the structure
of the root signature corresponding to WebGPU pipeline layout.
Binding groups is mostly straightforward, with one big caveat:
all bindings have to be reset whenever the pipeline layout changes.
This is the rule of D3D12, and we can do nothing to help it.
We detect this change at both [`crate::CommandEncoder::set_bind_group`]
and [`crate::CommandEncoder::set_render_pipeline`] with
[`crate::CommandEncoder::set_compute_pipeline`].
For this reason, in order avoid repeating the binding code,
we are binding everything in [`CommandEncoder::update_root_elements`].
When the pipeline layout is changed, we reset all bindings.
Otherwise, we pass a range corresponding only to the current bind group.
!*/