Skip to content

Commit

Permalink
[d3d12] fix being able to use dispatchWorkgroupsIndirect without va…
Browse files Browse the repository at this point in the history
…lidation (#6767)
  • Loading branch information
teoxoy authored Dec 17, 2024
1 parent ea75568 commit 04a1040
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 74 deletions.
9 changes: 8 additions & 1 deletion wgpu-core/src/device/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2612,10 +2612,17 @@ impl Device {
.map(|bgl| bgl.raw())
.collect::<ArrayVec<_, { hal::MAX_BIND_GROUPS }>>();

let additional_flags = if cfg!(feature = "indirect-validation") {
hal::PipelineLayoutFlags::INDIRECT_BUILTIN_UPDATE
} else {
hal::PipelineLayoutFlags::empty()
};

let hal_desc = hal::PipelineLayoutDescriptor {
label: desc.label.to_hal(self.instance_flags),
flags: hal::PipelineLayoutFlags::FIRST_VERTEX_INSTANCE
| hal::PipelineLayoutFlags::NUM_WORK_GROUPS,
| hal::PipelineLayoutFlags::NUM_WORK_GROUPS
| additional_flags,
bind_group_layouts: &raw_bind_group_layouts,
push_constant_ranges: desc.push_constant_ranges.as_ref(),
};
Expand Down
2 changes: 1 addition & 1 deletion wgpu-core/src/indirect_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl IndirectValidation {

let pipeline_layout_desc = hal::PipelineLayoutDescriptor {
label: None,
flags: hal::PipelineLayoutFlags::FIRST_VERTEX_INSTANCE,
flags: hal::PipelineLayoutFlags::empty(),
bind_group_layouts: &[
dst_bind_group_layout.as_ref(),
src_bind_group_layout.as_ref(),
Expand Down
16 changes: 14 additions & 2 deletions wgpu-hal/src/dx12/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1223,13 +1223,25 @@ impl crate::CommandEncoder for super::CommandEncoder {
}

unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) {
self.update_root_elements();
if self
.pass
.layout
.special_constants
.as_ref()
.and_then(|sc| sc.indirect_cmd_signatures.as_ref())
.is_some()
{
self.update_root_elements();
} else {
self.prepare_dispatch([0; 3]);
}

let cmd_signature = &self
.pass
.layout
.special_constants
.as_ref()
.map(|sc| &sc.cmd_signatures)
.and_then(|sc| sc.indirect_cmd_signatures.as_ref())
.unwrap_or_else(|| &self.shared.cmd_signatures)
.dispatch;
unsafe {
Expand Down
141 changes: 74 additions & 67 deletions wgpu-hal/src/dx12/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1122,78 +1122,85 @@ impl crate::Device for super::Device {
.into_device_result("Root signature creation")?;

let special_constants = if let Some(root_index) = special_constants_root_index {
let constant_indirect_argument_desc = Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT,
Anonymous: Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC_0 {
Constant: Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC_0_1 {
RootParameterIndex: root_index,
DestOffsetIn32BitValues: 0,
Num32BitValuesToSet: 3,
let cmd_signatures = if desc
.flags
.contains(crate::PipelineLayoutFlags::INDIRECT_BUILTIN_UPDATE)
{
let constant_indirect_argument_desc = Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT,
Anonymous: Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC_0 {
Constant: Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC_0_1 {
RootParameterIndex: root_index,
DestOffsetIn32BitValues: 0,
Num32BitValuesToSet: 3,
},
},
},
};
let special_constant_buffer_args_len = {
// Hack: construct a dummy value of the special constants buffer value we need to
// fill, and calculate the size of each member.
let super::RootElement::SpecialConstantBuffer {
first_vertex,
first_instance,
other,
} = (super::RootElement::SpecialConstantBuffer {
first_vertex: 0,
first_instance: 0,
other: 0,
})
else {
unreachable!();
};
size_of_val(&first_vertex) + size_of_val(&first_instance) + size_of_val(&other)
};
let cmd_signatures = super::CommandSignatures {
draw: Self::create_command_signature(
&self.raw,
Some(&raw),
special_constant_buffer_args_len + size_of::<wgt::DrawIndirectArgs>(),
&[
constant_indirect_argument_desc,
Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW,
..Default::default()
},
],
0,
)?,
draw_indexed: Self::create_command_signature(
&self.raw,
Some(&raw),
special_constant_buffer_args_len + size_of::<wgt::DrawIndexedIndirectArgs>(),
&[
constant_indirect_argument_desc,
Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED,
..Default::default()
},
],
0,
)?,
dispatch: Self::create_command_signature(
&self.raw,
Some(&raw),
special_constant_buffer_args_len + size_of::<wgt::DispatchIndirectArgs>(),
&[
constant_indirect_argument_desc,
Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
..Default::default()
},
],
0,
)?,
let special_constant_buffer_args_len = {
// Hack: construct a dummy value of the special constants buffer value we need to
// fill, and calculate the size of each member.
let super::RootElement::SpecialConstantBuffer {
first_vertex,
first_instance,
other,
} = (super::RootElement::SpecialConstantBuffer {
first_vertex: 0,
first_instance: 0,
other: 0,
})
else {
unreachable!();
};
size_of_val(&first_vertex) + size_of_val(&first_instance) + size_of_val(&other)
};
Some(super::CommandSignatures {
draw: Self::create_command_signature(
&self.raw,
Some(&raw),
special_constant_buffer_args_len + size_of::<wgt::DrawIndirectArgs>(),
&[
constant_indirect_argument_desc,
Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW,
..Default::default()
},
],
0,
)?,
draw_indexed: Self::create_command_signature(
&self.raw,
Some(&raw),
special_constant_buffer_args_len
+ size_of::<wgt::DrawIndexedIndirectArgs>(),
&[
constant_indirect_argument_desc,
Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED,
..Default::default()
},
],
0,
)?,
dispatch: Self::create_command_signature(
&self.raw,
Some(&raw),
special_constant_buffer_args_len + size_of::<wgt::DispatchIndirectArgs>(),
&[
constant_indirect_argument_desc,
Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
..Default::default()
},
],
0,
)?,
})
} else {
None
};

Some(super::PipelineLayoutSpecialConstants {
root_index,
cmd_signatures,
indirect_cmd_signatures: cmd_signatures,
})
} else {
None
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hal/src/dx12/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ unsafe impl Sync for PipelineLayoutShared {}
#[derive(Debug, Clone)]
struct PipelineLayoutSpecialConstants {
root_index: RootIndex,
cmd_signatures: CommandSignatures,
indirect_cmd_signatures: Option<CommandSignatures>,
}

unsafe impl Send for PipelineLayoutSpecialConstants {}
Expand Down
9 changes: 7 additions & 2 deletions wgpu-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1513,10 +1513,15 @@ bitflags!(
/// Pipeline layout creation flags.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct PipelineLayoutFlags: u32 {
/// Include support for `first_vertex` / `first_instance` drawing.
/// D3D12: Add support for `first_vertex` and `first_instance` builtins
/// via push constants for direct execution.
const FIRST_VERTEX_INSTANCE = 1 << 0;
/// Include support for num work groups builtin.
/// D3D12: Add support for `num_workgroups` builtins via push constants
/// for direct execution.
const NUM_WORK_GROUPS = 1 << 1;
/// D3D12: Add support for the builtins that the other flags enable for
/// indirect execution.
const INDIRECT_BUILTIN_UPDATE = 1 << 2;
}
);

Expand Down

0 comments on commit 04a1040

Please sign in to comment.