use super::{
AccelerationStructure, ArgumentEncoder, Buffer, ComputePipelineState, CullMode, DepthClipMode,
DepthStencilState, IndexType, IndirectCommandBuffer, IndirectComputeCommand,
IndirectRenderCommand, IntersectionFunctionTable, PrimitiveType, Region, RenderPipelineState,
ResourceID, SamplerState, Size, Texture, TriangleFillMode, VisibleFunctionTable, Winding,
};
use crate::Error;
enum RecordedIndirectRenderOperation<'a> {
Reset,
SetBarrier,
ClearBarrier,
DrawPatches {
number_of_patch_control_points: usize,
patch_start: usize,
patch_count: usize,
patch_index_buffer: Option<&'a Buffer>,
patch_index_buffer_offset: usize,
instance_count: usize,
base_instance: usize,
tessellation_factor_buffer: &'a Buffer,
tessellation_factor_buffer_offset: usize,
instance_stride: usize,
},
DrawIndexedPatches {
number_of_patch_control_points: usize,
patch_start: usize,
patch_count: usize,
patch_index_buffer: Option<&'a Buffer>,
patch_index_buffer_offset: usize,
control_point_index_buffer: &'a Buffer,
control_point_index_buffer_offset: usize,
instance_count: usize,
base_instance: usize,
tessellation_factor_buffer: &'a Buffer,
tessellation_factor_buffer_offset: usize,
instance_stride: usize,
},
}
#[derive(Clone, Copy)]
enum RecordedIndirectComputeOperation {
Reset,
SetBarrier,
ClearBarrier,
}
#[derive(Default)]
pub struct IndirectRenderCommandRecording<'a> {
operations: Vec<RecordedIndirectRenderOperation<'a>>,
}
impl<'a> IndirectRenderCommandRecording<'a> {
pub fn reset(&mut self) {
self.operations.push(RecordedIndirectRenderOperation::Reset);
}
pub fn set_barrier(&mut self) {
self.operations
.push(RecordedIndirectRenderOperation::SetBarrier);
}
pub fn clear_barrier(&mut self) {
self.operations
.push(RecordedIndirectRenderOperation::ClearBarrier);
}
#[allow(clippy::too_many_arguments)]
pub fn draw_patches(
&mut self,
number_of_patch_control_points: usize,
patch_start: usize,
patch_count: usize,
patch_index_buffer: Option<&'a Buffer>,
patch_index_buffer_offset: usize,
instance_count: usize,
base_instance: usize,
tessellation_factor_buffer: &'a Buffer,
tessellation_factor_buffer_offset: usize,
instance_stride: usize,
) {
self.operations
.push(RecordedIndirectRenderOperation::DrawPatches {
number_of_patch_control_points,
patch_start,
patch_count,
patch_index_buffer,
patch_index_buffer_offset,
instance_count,
base_instance,
tessellation_factor_buffer,
tessellation_factor_buffer_offset,
instance_stride,
});
}
#[allow(clippy::too_many_arguments)]
pub fn draw_indexed_patches(
&mut self,
number_of_patch_control_points: usize,
patch_start: usize,
patch_count: usize,
patch_index_buffer: Option<&'a Buffer>,
patch_index_buffer_offset: usize,
control_point_index_buffer: &'a Buffer,
control_point_index_buffer_offset: usize,
instance_count: usize,
base_instance: usize,
tessellation_factor_buffer: &'a Buffer,
tessellation_factor_buffer_offset: usize,
instance_stride: usize,
) {
self.operations
.push(RecordedIndirectRenderOperation::DrawIndexedPatches {
number_of_patch_control_points,
patch_start,
patch_count,
patch_index_buffer,
patch_index_buffer_offset,
control_point_index_buffer,
control_point_index_buffer_offset,
instance_count,
base_instance,
tessellation_factor_buffer,
tessellation_factor_buffer_offset,
instance_stride,
});
}
}
#[derive(Default)]
pub struct IndirectComputeCommandRecording {
operations: Vec<RecordedIndirectComputeOperation>,
}
impl IndirectComputeCommandRecording {
pub fn reset(&mut self) {
self.operations
.push(RecordedIndirectComputeOperation::Reset);
}
pub fn set_barrier(&mut self) {
self.operations
.push(RecordedIndirectComputeOperation::SetBarrier);
}
pub fn clear_barrier(&mut self) {
self.operations
.push(RecordedIndirectComputeOperation::ClearBarrier);
}
}
impl IndirectCommandBuffer {
pub fn gpu_resource_id(&self) -> Result<ResourceID, Error> {
self.inner.gpu_resource_id().map_err(Error::from_ffi)
}
pub fn with_indirect_render_command<R>(
&self,
command_index: usize,
body: impl for<'recording> FnOnce(&mut IndirectRenderCommandRecording<'recording>) -> R,
) -> Result<R, Error> {
let mut recording = IndirectRenderCommandRecording::default();
let result = body(&mut recording);
self.inner
.with_indirect_render_command(command_index, |inner| {
for operation in recording.operations {
match operation {
RecordedIndirectRenderOperation::Reset => inner.reset()?,
RecordedIndirectRenderOperation::SetBarrier => inner.set_barrier()?,
RecordedIndirectRenderOperation::ClearBarrier => inner.clear_barrier()?,
RecordedIndirectRenderOperation::DrawPatches {
number_of_patch_control_points,
patch_start,
patch_count,
patch_index_buffer,
patch_index_buffer_offset,
instance_count,
base_instance,
tessellation_factor_buffer,
tessellation_factor_buffer_offset,
instance_stride,
} => inner.draw_patches(
number_of_patch_control_points,
patch_start,
patch_count,
patch_index_buffer.map(|value| &value.inner),
patch_index_buffer_offset,
instance_count,
base_instance,
&tessellation_factor_buffer.inner,
tessellation_factor_buffer_offset,
instance_stride,
)?,
RecordedIndirectRenderOperation::DrawIndexedPatches {
number_of_patch_control_points,
patch_start,
patch_count,
patch_index_buffer,
patch_index_buffer_offset,
control_point_index_buffer,
control_point_index_buffer_offset,
instance_count,
base_instance,
tessellation_factor_buffer,
tessellation_factor_buffer_offset,
instance_stride,
} => inner.draw_indexed_patches(
number_of_patch_control_points,
patch_start,
patch_count,
patch_index_buffer.map(|value| &value.inner),
patch_index_buffer_offset,
&control_point_index_buffer.inner,
control_point_index_buffer_offset,
instance_count,
base_instance,
&tessellation_factor_buffer.inner,
tessellation_factor_buffer_offset,
instance_stride,
)?,
}
}
Ok(())
})
.map_err(Error::from_ffi)?
.map_err(Error::from_ffi)?;
Ok(result)
}
pub fn with_indirect_compute_command<R>(
&self,
command_index: usize,
body: impl FnOnce(&mut IndirectComputeCommandRecording) -> R,
) -> Result<R, Error> {
let mut recording = IndirectComputeCommandRecording::default();
let result = body(&mut recording);
self.inner
.with_indirect_compute_command(command_index, |inner| {
for operation in recording.operations {
match operation {
RecordedIndirectComputeOperation::Reset => inner.reset()?,
RecordedIndirectComputeOperation::SetBarrier => inner.set_barrier()?,
RecordedIndirectComputeOperation::ClearBarrier => inner.clear_barrier()?,
}
}
Ok(())
})
.map_err(Error::from_ffi)?
.map_err(Error::from_ffi)?;
Ok(result)
}
pub fn reset_commands(&self, range: std::ops::Range<usize>) -> Result<(), Error> {
self.inner.reset_commands(range).map_err(Error::from_ffi)
}
}
impl ArgumentEncoder {
pub fn new_argument_encoder(&self, index: usize) -> Result<Self, Error> {
self.inner
.new_argument_encoder(index)
.map(Self::from_ffi)
.map_err(Error::from_ffi)
}
pub fn set_argument_buffer(&self, buffer: &Buffer, offset: usize) -> Result<(), Error> {
self.inner
.set_argument_buffer(&buffer.inner, offset)
.map_err(Error::from_ffi)
}
pub fn set_argument_buffer_element(
&self,
buffer: &Buffer,
start_offset: usize,
array_element: usize,
) -> Result<(), Error> {
self.inner
.set_argument_buffer_element(&buffer.inner, start_offset, array_element)
.map_err(Error::from_ffi)
}
pub fn with_constant_data<R>(
&self,
index: usize,
argument_buffer: &Buffer,
argument_buffer_offset: usize,
member_range: std::ops::Range<usize>,
body: impl for<'data> FnOnce(&'data mut [u8]) -> R,
) -> Result<R, Error> {
self.inner
.with_constant_data(
index,
&argument_buffer.inner,
argument_buffer_offset,
member_range,
body,
)
.map_err(Error::from_ffi)
}
pub fn set_buffer(
&self,
buffer: Option<&Buffer>,
offset: usize,
index: usize,
) -> Result<(), Error> {
self.inner
.set_buffer(buffer.map(|value| &value.inner), offset, index)
.map_err(Error::from_ffi)
}
pub fn set_buffers(
&self,
bindings: &[(Option<&Buffer>, usize)],
start_index: usize,
) -> Result<(), Error> {
let ffi = bindings
.iter()
.map(|(buffer, offset)| (buffer.map(|value| &value.inner), *offset))
.collect::<Vec<_>>();
self.inner
.set_buffers(&ffi, start_index)
.map_err(Error::from_ffi)
}
pub fn set_texture(&self, texture: Option<&Texture>, index: usize) -> Result<(), Error> {
self.inner
.set_texture(texture.map(|value| &value.inner), index)
.map_err(Error::from_ffi)
}
pub fn set_textures(
&self,
textures: &[Option<&Texture>],
start_index: usize,
) -> Result<(), Error> {
let ffi = textures
.iter()
.map(|texture| texture.map(|value| &value.inner))
.collect::<Vec<_>>();
self.inner
.set_textures(&ffi, start_index)
.map_err(Error::from_ffi)
}
pub fn set_acceleration_structure(
&self,
value: Option<&AccelerationStructure>,
index: usize,
) -> Result<(), Error> {
self.inner
.set_acceleration_structure(value.map(|value| &value.inner), index)
.map_err(Error::from_ffi)
}
pub fn set_compute_pipeline_state(
&self,
value: Option<&ComputePipelineState>,
index: usize,
) -> Result<(), Error> {
self.inner
.set_compute_pipeline_state(value.map(|value| &value.inner), index)
.map_err(Error::from_ffi)
}
pub fn set_compute_pipeline_states(
&self,
values: &[Option<&ComputePipelineState>],
start_index: usize,
) -> Result<(), Error> {
let ffi = values
.iter()
.map(|value| value.map(|value| &value.inner))
.collect::<Vec<_>>();
self.inner
.set_compute_pipeline_states(&ffi, start_index)
.map_err(Error::from_ffi)
}
pub fn set_depth_stencil_state(
&self,
value: Option<&DepthStencilState>,
index: usize,
) -> Result<(), Error> {
self.inner
.set_depth_stencil_state(value.map(|value| &value.inner), index)
.map_err(Error::from_ffi)
}
pub fn set_depth_stencil_states(
&self,
values: &[Option<&DepthStencilState>],
start_index: usize,
) -> Result<(), Error> {
let ffi = values
.iter()
.map(|value| value.map(|value| &value.inner))
.collect::<Vec<_>>();
self.inner
.set_depth_stencil_states(&ffi, start_index)
.map_err(Error::from_ffi)
}
pub fn set_indirect_command_buffer(
&self,
value: Option<&IndirectCommandBuffer>,
index: usize,
) -> Result<(), Error> {
self.inner
.set_indirect_command_buffer(value.map(|value| &value.inner), index)
.map_err(Error::from_ffi)
}
pub fn set_indirect_command_buffers(
&self,
values: &[Option<&IndirectCommandBuffer>],
start_index: usize,
) -> Result<(), Error> {
let ffi = values
.iter()
.map(|value| value.map(|value| &value.inner))
.collect::<Vec<_>>();
self.inner
.set_indirect_command_buffers(&ffi, start_index)
.map_err(Error::from_ffi)
}
pub fn set_intersection_function_table(
&self,
value: Option<&IntersectionFunctionTable>,
index: usize,
) -> Result<(), Error> {
self.inner
.set_intersection_function_table(value.map(|value| &value.inner), index)
.map_err(Error::from_ffi)
}
pub fn set_intersection_function_tables(
&self,
values: &[Option<&IntersectionFunctionTable>],
start_index: usize,
) -> Result<(), Error> {
let ffi = values
.iter()
.map(|value| value.map(|value| &value.inner))
.collect::<Vec<_>>();
self.inner
.set_intersection_function_tables(&ffi, start_index)
.map_err(Error::from_ffi)
}
pub fn set_render_pipeline_state(
&self,
value: Option<&RenderPipelineState>,
index: usize,
) -> Result<(), Error> {
self.inner
.set_render_pipeline_state(value.map(|value| &value.inner), index)
.map_err(Error::from_ffi)
}
pub fn set_render_pipeline_states(
&self,
values: &[Option<&RenderPipelineState>],
start_index: usize,
) -> Result<(), Error> {
let ffi = values
.iter()
.map(|value| value.map(|value| &value.inner))
.collect::<Vec<_>>();
self.inner
.set_render_pipeline_states(&ffi, start_index)
.map_err(Error::from_ffi)
}
pub fn set_sampler_state(
&self,
value: Option<&SamplerState>,
index: usize,
) -> Result<(), Error> {
self.inner
.set_sampler_state(value.map(|value| &value.inner), index)
.map_err(Error::from_ffi)
}
pub fn set_sampler_states(
&self,
values: &[Option<&SamplerState>],
start_index: usize,
) -> Result<(), Error> {
let ffi = values
.iter()
.map(|value| value.map(|value| &value.inner))
.collect::<Vec<_>>();
self.inner
.set_sampler_states(&ffi, start_index)
.map_err(Error::from_ffi)
}
pub fn set_visible_function_table(
&self,
value: Option<&VisibleFunctionTable>,
index: usize,
) -> Result<(), Error> {
self.inner
.set_visible_function_table(value.map(|value| &value.inner), index)
.map_err(Error::from_ffi)
}
pub fn set_visible_function_tables(
&self,
values: &[Option<&VisibleFunctionTable>],
start_index: usize,
) -> Result<(), Error> {
let ffi = values
.iter()
.map(|value| value.map(|value| &value.inner))
.collect::<Vec<_>>();
self.inner
.set_visible_function_tables(&ffi, start_index)
.map_err(Error::from_ffi)
}
}
impl IndirectRenderCommand {
pub fn reset(&self) -> Result<(), Error> {
self.inner.reset().map_err(Error::from_ffi)
}
pub fn set_barrier(&self) -> Result<(), Error> {
self.inner.set_barrier().map_err(Error::from_ffi)
}
pub fn clear_barrier(&self) -> Result<(), Error> {
self.inner.clear_barrier().map_err(Error::from_ffi)
}
pub fn set_vertex_buffer(
&self,
buffer: Option<&Buffer>,
offset: usize,
index: usize,
) -> Result<(), Error> {
self.inner
.set_vertex_buffer(buffer.map(|value| &value.inner), offset, index)
.map_err(Error::from_ffi)
}
pub fn set_vertex_buffer_with_stride(
&self,
buffer: Option<&Buffer>,
offset: usize,
stride: usize,
index: usize,
) -> Result<(), Error> {
self.inner
.set_vertex_buffer_with_stride(
buffer.map(|value| &value.inner),
offset,
Some(stride),
index,
)
.map_err(Error::from_ffi)
}
pub fn set_fragment_buffer(
&self,
buffer: Option<&Buffer>,
offset: usize,
index: usize,
) -> Result<(), Error> {
self.inner
.set_fragment_buffer(buffer.map(|value| &value.inner), offset, index)
.map_err(Error::from_ffi)
}
pub fn set_mesh_buffer(
&self,
buffer: Option<&Buffer>,
offset: usize,
index: usize,
) -> Result<(), Error> {
self.inner
.set_mesh_buffer(buffer.map(|value| &value.inner), offset, index)
.map_err(Error::from_ffi)
}
pub fn set_object_buffer(
&self,
buffer: Option<&Buffer>,
offset: usize,
index: usize,
) -> Result<(), Error> {
self.inner
.set_object_buffer(buffer.map(|value| &value.inner), offset, index)
.map_err(Error::from_ffi)
}
pub fn set_render_pipeline_state(&self, state: &RenderPipelineState) -> Result<(), Error> {
self.inner
.set_render_pipeline_state(&state.inner)
.map_err(Error::from_ffi)
}
pub fn set_depth_stencil_state(&self, state: Option<&DepthStencilState>) -> Result<(), Error> {
self.inner
.set_depth_stencil_state(state.map(|value| &value.inner))
.map_err(Error::from_ffi)
}
pub fn set_cull_mode(&self, value: CullMode) -> Result<(), Error> {
self.inner.set_cull_mode(value).map_err(Error::from_ffi)
}
pub fn set_depth_clip_mode(&self, value: DepthClipMode) -> Result<(), Error> {
self.inner
.set_depth_clip_mode(value)
.map_err(Error::from_ffi)
}
pub fn set_front_facing_winding(&self, value: Winding) -> Result<(), Error> {
self.inner
.set_front_facing_winding(value)
.map_err(Error::from_ffi)
}
pub fn set_triangle_fill_mode(&self, value: TriangleFillMode) -> Result<(), Error> {
self.inner
.set_triangle_fill_mode(value)
.map_err(Error::from_ffi)
}
pub fn set_depth_bias(
&self,
depth_bias: f32,
slope_scale: f32,
clamp: f32,
) -> Result<(), Error> {
self.inner
.set_depth_bias(depth_bias, slope_scale, clamp)
.map_err(Error::from_ffi)
}
pub fn set_object_threadgroup_memory_length(
&self,
length: usize,
index: usize,
) -> Result<(), Error> {
self.inner
.set_object_threadgroup_memory_length(length, index)
.map_err(Error::from_ffi)
}
pub fn draw_primitives(
&self,
primitive_type: PrimitiveType,
vertex_start: usize,
vertex_count: usize,
instance_count: usize,
base_instance: usize,
) -> Result<(), Error> {
self.inner
.draw_primitives(
primitive_type,
vertex_start,
vertex_count,
instance_count,
base_instance,
)
.map_err(Error::from_ffi)
}
#[allow(clippy::too_many_arguments)]
pub fn draw_indexed_primitives(
&self,
primitive_type: PrimitiveType,
index_count: usize,
index_type: IndexType,
index_buffer: &Buffer,
index_buffer_offset: usize,
instance_count: usize,
base_vertex: isize,
base_instance: usize,
) -> Result<(), Error> {
self.inner
.draw_indexed_primitives(
primitive_type,
index_count,
index_type,
&index_buffer.inner,
index_buffer_offset,
instance_count,
base_vertex,
base_instance,
)
.map_err(Error::from_ffi)
}
pub fn draw_mesh_threadgroups(
&self,
groups: Size,
object_threads: Size,
mesh_threads: Size,
) -> Result<(), Error> {
self.inner
.draw_mesh_threadgroups(groups, object_threads, mesh_threads)
.map_err(Error::from_ffi)
}
pub fn draw_mesh_threads(
&self,
threads: Size,
object_threads: Size,
mesh_threads: Size,
) -> Result<(), Error> {
self.inner
.draw_mesh_threads(threads, object_threads, mesh_threads)
.map_err(Error::from_ffi)
}
}
impl IndirectComputeCommand {
pub fn reset(&self) -> Result<(), Error> {
self.inner.reset().map_err(Error::from_ffi)
}
pub fn set_barrier(&self) -> Result<(), Error> {
self.inner.set_barrier().map_err(Error::from_ffi)
}
pub fn clear_barrier(&self) -> Result<(), Error> {
self.inner.clear_barrier().map_err(Error::from_ffi)
}
pub fn set_compute_pipeline_state(&self, state: &ComputePipelineState) -> Result<(), Error> {
self.inner
.set_compute_pipeline_state(&state.inner)
.map_err(Error::from_ffi)
}
pub fn set_kernel_buffer(
&self,
buffer: Option<&Buffer>,
offset: usize,
index: usize,
) -> Result<(), Error> {
self.inner
.set_kernel_buffer(buffer.map(|value| &value.inner), offset, index)
.map_err(Error::from_ffi)
}
pub fn set_kernel_buffer_with_stride(
&self,
buffer: Option<&Buffer>,
offset: usize,
stride: usize,
index: usize,
) -> Result<(), Error> {
self.inner
.set_kernel_buffer_with_stride(
buffer.map(|value| &value.inner),
offset,
Some(stride),
index,
)
.map_err(Error::from_ffi)
}
pub fn set_imageblock_size(&self, width: usize, height: usize) -> Result<(), Error> {
self.inner
.set_imageblock_size(width, height)
.map_err(Error::from_ffi)
}
pub fn set_stage_in_region(&self, region: Region) -> Result<(), Error> {
self.inner
.set_stage_in_region(region)
.map_err(Error::from_ffi)
}
pub fn set_threadgroup_memory_length(&self, length: usize, index: usize) -> Result<(), Error> {
self.inner
.set_threadgroup_memory_length(length, index)
.map_err(Error::from_ffi)
}
pub fn concurrent_dispatch_threadgroups(
&self,
groups: Size,
threads_per_group: Size,
) -> Result<(), Error> {
self.inner
.concurrent_dispatch_threadgroups(groups, threads_per_group)
.map_err(Error::from_ffi)
}
pub fn concurrent_dispatch_threads(
&self,
threads: Size,
threads_per_group: Size,
) -> Result<(), Error> {
self.inner
.concurrent_dispatch_threads(threads, threads_per_group)
.map_err(Error::from_ffi)
}
}