use crate::{
RafxBuffer, RafxCommandBuffer, RafxDeviceContext, RafxDrawIndexedIndirectCommand,
RafxDrawIndirectCommand, RafxResult, RafxRootSignature, RafxShaderStageFlags,
};
#[cfg(feature = "rafx-dx12")]
use windows::Win32::Graphics::Direct3D12 as d3d12;
#[cfg(feature = "rafx-dx12")]
fn create_indirect_draw_with_push_constant_command_signature(
device: &d3d12::ID3D12Device,
root_signature: &d3d12::ID3D12RootSignature,
indexed: bool,
) -> RafxResult<d3d12::ID3D12CommandSignature> {
let mut sig = d3d12::D3D12_COMMAND_SIGNATURE_DESC::default();
let mut draw_arg = d3d12::D3D12_INDIRECT_ARGUMENT_DESC::default();
let mut root_constant_arg = d3d12::D3D12_INDIRECT_ARGUMENT_DESC::default();
if !indexed {
draw_arg.Type = d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
sig.ByteStride = std::mem::size_of::<RafxDrawIndirectCommand>() as u32 + 4;
} else {
draw_arg.Type = d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
sig.ByteStride = std::mem::size_of::<RafxDrawIndexedIndirectCommand>() as u32 + 4;
}
root_constant_arg.Type = d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
root_constant_arg.Anonymous.Constant.RootParameterIndex = 0;
root_constant_arg.Anonymous.Constant.DestOffsetIn32BitValues = 0;
root_constant_arg.Anonymous.Constant.Num32BitValuesToSet = 1;
sig.NumArgumentDescs = 2;
let args = [root_constant_arg, draw_arg];
sig.pArgumentDescs = args.as_ptr();
let mut result: Option<d3d12::ID3D12CommandSignature> = None;
unsafe {
device.CreateCommandSignature(&sig, root_signature, &mut result)?;
}
Ok(result.unwrap())
}
pub struct RafxDrawIndirectCommandWithPushConstant {
pub push_constant: u32,
pub command: RafxDrawIndirectCommand,
}
pub struct RafxDrawIndexedIndirectCommandWithPushConstant {
pub push_constant: u32,
pub command: RafxDrawIndexedIndirectCommand,
}
pub fn indirect_command_size(_device_context: &RafxDeviceContext) -> u64 {
#[cfg(feature = "rafx-dx12")]
if _device_context.is_dx12() {
return std::mem::size_of::<RafxDrawIndirectCommand>() as u64 + 4;
}
std::mem::size_of::<RafxDrawIndirectCommand>() as u64
}
pub fn indexed_indirect_command_size(_device_context: &RafxDeviceContext) -> u64 {
#[cfg(feature = "rafx-dx12")]
if _device_context.is_dx12() {
return std::mem::size_of::<RafxDrawIndexedIndirectCommand>() as u64 + 4;
}
std::mem::size_of::<RafxDrawIndexedIndirectCommand>() as u64
}
#[derive(Clone)]
pub struct RafxIndexedIndirectCommandSignature {
_root_signature: RafxRootSignature,
#[cfg(feature = "rafx-dx12")]
dx12_indirect_command_signature: Option<d3d12::ID3D12CommandSignature>,
}
impl RafxIndexedIndirectCommandSignature {
pub fn new(
root_signature: &RafxRootSignature,
_shader_flags: RafxShaderStageFlags,
) -> RafxResult<Self> {
#[cfg(feature = "rafx-dx12")]
if let Some(root_signature_dx12) = root_signature.dx12_root_signature() {
let descriptor = root_signature_dx12.find_push_constant_descriptor(_shader_flags).ok_or_else(|| crate::RafxError::StringError(format!(
"Tried to create a RafxIndexedIndirectCommandSignature for shader flags {:?} but no push constants were found",
_shader_flags
)))?;
let command_signature = create_indirect_draw_with_push_constant_command_signature(
root_signature_dx12.device_context().d3d12_device(),
root_signature_dx12.dx12_root_signature(),
true,
)?;
return Ok(RafxIndexedIndirectCommandSignature {
_root_signature: root_signature.clone(),
dx12_indirect_command_signature: Some(command_signature),
});
}
Ok(RafxIndexedIndirectCommandSignature {
_root_signature: root_signature.clone(),
#[cfg(feature = "rafx-dx12")]
dx12_indirect_command_signature: None,
})
}
pub fn draw_indexed_indirect(
&self,
command_buffer: &RafxCommandBuffer,
indirect_buffer: &RafxBuffer,
indirect_buffer_offset_in_bytes: u32,
draw_count: u32,
) -> RafxResult<()> {
#[cfg(feature = "rafx-dx12")]
if let Some(dx12_command_buffer) = command_buffer.dx12_command_buffer() {
let command_list = dx12_command_buffer.dx12_graphics_command_list();
unsafe {
let command_signature = self.dx12_indirect_command_signature.as_ref().unwrap();
assert!(
indirect_buffer.buffer_def().size as u32 - indirect_buffer_offset_in_bytes
>= 24 * draw_count
);
command_list.ExecuteIndirect(
command_signature,
draw_count,
indirect_buffer.dx12_buffer().unwrap().dx12_resource(),
indirect_buffer_offset_in_bytes as u64,
None,
0,
);
}
return Ok(());
}
command_buffer.cmd_draw_indexed_indirect(
indirect_buffer,
indirect_buffer_offset_in_bytes,
draw_count,
)
}
}
pub struct RafxIndexedIndirectCommandEncoder<'a> {
_buffer: &'a RafxBuffer,
#[cfg(feature = "rafx-dx12")]
is_dx12: bool,
mapped_memory: *mut u8,
command_count: usize,
}
impl<'a> RafxIndexedIndirectCommandEncoder<'a> {
pub fn new(buffer: &'a RafxBuffer) -> Self {
#[cfg(not(feature = "rafx-dx12"))]
let is_dx12 = false;
#[cfg(feature = "rafx-dx12")]
let is_dx12 = buffer.dx12_buffer().is_some();
let command_size = if is_dx12 {
std::mem::size_of::<RafxDrawIndexedIndirectCommand>() + 4
} else {
std::mem::size_of::<RafxDrawIndexedIndirectCommand>()
};
let command_count = (buffer.buffer_def().size as usize / command_size) as usize;
RafxIndexedIndirectCommandEncoder {
_buffer: buffer,
#[cfg(feature = "rafx-dx12")]
is_dx12,
mapped_memory: buffer.mapped_memory().unwrap(),
command_count,
}
}
pub fn set_command(
&self,
index: usize,
command: RafxDrawIndexedIndirectCommand,
) {
assert!(index < self.command_count);
unsafe {
#[cfg(feature = "rafx-dx12")]
if self.is_dx12 {
let mut ptr =
self.mapped_memory as *mut RafxDrawIndexedIndirectCommandWithPushConstant;
let push_constant = command.first_instance;
*ptr.add(index) = RafxDrawIndexedIndirectCommandWithPushConstant {
command,
push_constant,
};
return;
}
let ptr = self.mapped_memory as *mut RafxDrawIndexedIndirectCommand;
*ptr.add(index) = command;
}
}
}