From c9fdaef3e1f9de2222907197032c4ff4ce57b802 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sat, 14 Aug 2021 00:40:41 -0400 Subject: [PATCH] dx12: switch root parameter updates from eager to lazy --- Cargo.toml | 2 +- wgpu-hal/src/dx12/command.rs | 29 ++++++++++++++++++++--------- wgpu-hal/src/dx12/device.rs | 5 ++--- wgpu-hal/src/dx12/mod.rs | 7 +++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 90bce2ccc0..7601192131 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ "wgpu-info", "wgpu-types", ] -default-members = ["wgpu", "player", "wgpu-hal", "wgpu-info"] +default-members = ["wgpu", "wgpu-hal", "wgpu-info"] [patch."https://github.com/gfx-rs/naga"] #naga = { path = "../naga" } diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index 130ac79ad0..83385a3709 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -31,6 +31,8 @@ impl super::CommandEncoder { list.BeginEvent(0, wide_label.as_ptr() as *const _, size); 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]); } @@ -63,24 +65,33 @@ impl super::CommandEncoder { _ => true, }; if needs_update { + self.pass.dirty_root_elements |= 1 << root_index; self.pass.root_elements[root_index as usize] = super::RootElement::SpecialConstantBuffer { base_vertex, 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) { + 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}; - let list = self.list.unwrap(); - for index in range { + while self.pass.dirty_root_elements != 0 { + let list = self.list.unwrap(); + let index = self.pass.dirty_root_elements.trailing_zeros(); + self.pass.dirty_root_elements ^= 1 << index; + 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 { base_vertex, base_instance, @@ -133,7 +144,7 @@ impl super::CommandEncoder { }; } 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 for super::CommandEncoder { } if self.pass.layout.signature == layout.shared.signature { - let update_range = info.base_root_index..root_index as super::RootIndex; - self.update_root_elements(update_range); + self.pass.dirty_root_elements |= (1 << root_index) - (1 << info.base_root_index); } else { // D3D12 requires full reset on signature change self.reset_signature(&layout.shared); @@ -924,6 +934,7 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn dispatch(&mut self, count: [u32; 3]) { + self.prepare_dispatch(); self.list.unwrap().dispatch(count); } unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) { diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index 994348d177..cccfc72fae 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -810,15 +810,14 @@ impl crate::Device for super::Device { wgt::BindingType::Buffer { has_dynamic_offset: true, .. - } - | wgt::BindingType::Sampler { .. } => continue, + } => continue, ref other => conv::map_binding_type(other), }; let bt = match range_ty { native::DescriptorRangeType::CBV => &mut bind_cbv, native::DescriptorRangeType::SRV => &mut bind_srv, native::DescriptorRangeType::UAV => &mut bind_uav, - native::DescriptorRangeType::Sampler => unreachable!(), + native::DescriptorRangeType::Sampler => continue, }; binding_map.insert( diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 8b789a87e2..21be83671e 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -305,11 +305,17 @@ struct PassState { resolves: ArrayVec, layout: PipelineLayoutShared, root_elements: [RootElement; MAX_ROOT_ELEMENTS], + dirty_root_elements: u64, vertex_buffers: [d3d12::D3D12_VERTEX_BUFFER_VIEW; crate::MAX_VERTEX_BUFFERS], dirty_vertex_buffers: usize, kind: PassKind, } +#[test] +fn test_dirty_mask() { + assert_eq!(MAX_ROOT_ELEMENTS, std::mem::size_of::() * 8); +} + impl PassState { fn new() -> Self { PassState { @@ -321,6 +327,7 @@ impl PassState { special_constants_root_index: None, }, root_elements: [RootElement::Empty; MAX_ROOT_ELEMENTS], + dirty_root_elements: 0, vertex_buffers: [unsafe { mem::zeroed() }; crate::MAX_VERTEX_BUFFERS], dirty_vertex_buffers: 0, kind: PassKind::Transfer,