dx12: switch root parameter updates from eager to lazy

This commit is contained in:
Dzmitry Malyshau 2021-08-14 00:40:41 -04:00
parent 3f42b59ccc
commit c9fdaef3e1
4 changed files with 30 additions and 13 deletions

View File

@ -9,7 +9,7 @@ members = [
"wgpu-info", "wgpu-info",
"wgpu-types", "wgpu-types",
] ]
default-members = ["wgpu", "player", "wgpu-hal", "wgpu-info"] default-members = ["wgpu", "wgpu-hal", "wgpu-info"]
[patch."https://github.com/gfx-rs/naga"] [patch."https://github.com/gfx-rs/naga"]
#naga = { path = "../naga" } #naga = { path = "../naga" }

View File

@ -31,6 +31,8 @@ impl super::CommandEncoder {
list.BeginEvent(0, wide_label.as_ptr() as *const _, size); list.BeginEvent(0, wide_label.as_ptr() as *const _, size);
self.pass.has_label = true; self.pass.has_label = true;
} }
self.pass.dirty_root_elements = 0;
self.pass.dirty_vertex_buffers = 0;
list.set_descriptor_heaps(&[self.shared.heap_views.raw, self.shared.heap_samplers.raw]); list.set_descriptor_heaps(&[self.shared.heap_views.raw, self.shared.heap_samplers.raw]);
} }
@ -63,24 +65,33 @@ impl super::CommandEncoder {
_ => true, _ => true,
}; };
if needs_update { if needs_update {
self.pass.dirty_root_elements |= 1 << root_index;
self.pass.root_elements[root_index as usize] = self.pass.root_elements[root_index as usize] =
super::RootElement::SpecialConstantBuffer { super::RootElement::SpecialConstantBuffer {
base_vertex, base_vertex,
base_instance, base_instance,
}; };
list.set_graphics_root_constant(root_index, base_vertex as u32, 0);
list.set_graphics_root_constant(root_index, base_instance, 1);
} }
} }
self.update_root_elements();
} }
fn update_root_elements(&self, range: Range<super::RootIndex>) { fn prepare_dispatch(&mut self) {
self.update_root_elements();
}
//Note: we have to call this lazily before draw calls. Otherwise, D3D complains
// about the root parameters being incompatible with root signature.
fn update_root_elements(&mut self) {
use super::{BufferViewKind as Bvk, PassKind as Pk}; use super::{BufferViewKind as Bvk, PassKind as Pk};
while self.pass.dirty_root_elements != 0 {
let list = self.list.unwrap(); let list = self.list.unwrap();
for index in range { let index = self.pass.dirty_root_elements.trailing_zeros();
self.pass.dirty_root_elements ^= 1 << index;
match self.pass.root_elements[index as usize] { match self.pass.root_elements[index as usize] {
super::RootElement::Empty => {} super::RootElement::Empty => log::error!("Root index {} is not bound", index),
super::RootElement::SpecialConstantBuffer { super::RootElement::SpecialConstantBuffer {
base_vertex, base_vertex,
base_instance, base_instance,
@ -133,7 +144,7 @@ impl super::CommandEncoder {
}; };
} }
self.pass.layout = layout.clone(); self.pass.layout = layout.clone();
self.update_root_elements(0..layout.total_root_elements); self.pass.dirty_root_elements = (1 << layout.total_root_elements) - 1;
} }
} }
@ -695,8 +706,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
} }
if self.pass.layout.signature == layout.shared.signature { if self.pass.layout.signature == layout.shared.signature {
let update_range = info.base_root_index..root_index as super::RootIndex; self.pass.dirty_root_elements |= (1 << root_index) - (1 << info.base_root_index);
self.update_root_elements(update_range);
} else { } else {
// D3D12 requires full reset on signature change // D3D12 requires full reset on signature change
self.reset_signature(&layout.shared); self.reset_signature(&layout.shared);
@ -924,6 +934,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
} }
unsafe fn dispatch(&mut self, count: [u32; 3]) { unsafe fn dispatch(&mut self, count: [u32; 3]) {
self.prepare_dispatch();
self.list.unwrap().dispatch(count); self.list.unwrap().dispatch(count);
} }
unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) { unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) {

View File

@ -810,15 +810,14 @@ impl crate::Device<super::Api> for super::Device {
wgt::BindingType::Buffer { wgt::BindingType::Buffer {
has_dynamic_offset: true, has_dynamic_offset: true,
.. ..
} } => continue,
| wgt::BindingType::Sampler { .. } => continue,
ref other => conv::map_binding_type(other), ref other => conv::map_binding_type(other),
}; };
let bt = match range_ty { let bt = match range_ty {
native::DescriptorRangeType::CBV => &mut bind_cbv, native::DescriptorRangeType::CBV => &mut bind_cbv,
native::DescriptorRangeType::SRV => &mut bind_srv, native::DescriptorRangeType::SRV => &mut bind_srv,
native::DescriptorRangeType::UAV => &mut bind_uav, native::DescriptorRangeType::UAV => &mut bind_uav,
native::DescriptorRangeType::Sampler => unreachable!(), native::DescriptorRangeType::Sampler => continue,
}; };
binding_map.insert( binding_map.insert(

View File

@ -305,11 +305,17 @@ struct PassState {
resolves: ArrayVec<PassResolve, { crate::MAX_COLOR_TARGETS }>, resolves: ArrayVec<PassResolve, { crate::MAX_COLOR_TARGETS }>,
layout: PipelineLayoutShared, layout: PipelineLayoutShared,
root_elements: [RootElement; MAX_ROOT_ELEMENTS], root_elements: [RootElement; MAX_ROOT_ELEMENTS],
dirty_root_elements: u64,
vertex_buffers: [d3d12::D3D12_VERTEX_BUFFER_VIEW; crate::MAX_VERTEX_BUFFERS], vertex_buffers: [d3d12::D3D12_VERTEX_BUFFER_VIEW; crate::MAX_VERTEX_BUFFERS],
dirty_vertex_buffers: usize, dirty_vertex_buffers: usize,
kind: PassKind, kind: PassKind,
} }
#[test]
fn test_dirty_mask() {
assert_eq!(MAX_ROOT_ELEMENTS, std::mem::size_of::<u64>() * 8);
}
impl PassState { impl PassState {
fn new() -> Self { fn new() -> Self {
PassState { PassState {
@ -321,6 +327,7 @@ impl PassState {
special_constants_root_index: None, special_constants_root_index: None,
}, },
root_elements: [RootElement::Empty; MAX_ROOT_ELEMENTS], root_elements: [RootElement::Empty; MAX_ROOT_ELEMENTS],
dirty_root_elements: 0,
vertex_buffers: [unsafe { mem::zeroed() }; crate::MAX_VERTEX_BUFFERS], vertex_buffers: [unsafe { mem::zeroed() }; crate::MAX_VERTEX_BUFFERS],
dirty_vertex_buffers: 0, dirty_vertex_buffers: 0,
kind: PassKind::Transfer, kind: PassKind::Transfer,