diff options
Diffstat (limited to 'gfx/wgpu_bindings/src/command.rs')
-rw-r--r-- | gfx/wgpu_bindings/src/command.rs | 1062 |
1 files changed, 1062 insertions, 0 deletions
diff --git a/gfx/wgpu_bindings/src/command.rs b/gfx/wgpu_bindings/src/command.rs new file mode 100644 index 0000000000..acba975c13 --- /dev/null +++ b/gfx/wgpu_bindings/src/command.rs @@ -0,0 +1,1062 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{id, RawString}; +use std::{borrow::Cow, ffi, slice}; +use wgc::{command::{compute_ffi, render_ffi, ComputePassDescriptor, ComputePassTimestampWrites, RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPassTimestampWrites}, id::CommandEncoderId}; +use wgt::{BufferAddress, BufferSize, Color, DynamicOffset, IndexFormat}; + +use serde::{Serialize, Deserialize}; +use arrayvec::ArrayVec; + +/// A stream of commands for a render pass or compute pass. +/// +/// This also contains side tables referred to by certain commands, +/// like dynamic offsets for [`SetBindGroup`] or string data for +/// [`InsertDebugMarker`]. +/// +/// Render passes use `BasePass<RenderCommand>`, whereas compute +/// passes use `BasePass<ComputeCommand>`. +/// +/// [`SetBindGroup`]: RenderCommand::SetBindGroup +/// [`InsertDebugMarker`]: RenderCommand::InsertDebugMarker +#[doc(hidden)] +#[derive(Debug)] +#[derive(serde::Serialize, serde::Deserialize)] +pub struct BasePass<C> { + pub label: Option<String>, + + /// The stream of commands. + pub commands: Vec<C>, + + /// Dynamic offsets consumed by [`SetBindGroup`] commands in `commands`. + /// + /// Each successive `SetBindGroup` consumes the next + /// [`num_dynamic_offsets`] values from this list. + pub dynamic_offsets: Vec<wgt::DynamicOffset>, + + /// Strings used by debug instructions. + /// + /// Each successive [`PushDebugGroup`] or [`InsertDebugMarker`] + /// instruction consumes the next `len` bytes from this vector. + pub string_data: Vec<u8>, +} + +#[derive(Deserialize, Serialize)] +pub struct RecordedRenderPass { + base: BasePass<RenderCommand>, + color_attachments: ArrayVec<Option<RenderPassColorAttachment>, { wgh::MAX_COLOR_ATTACHMENTS }>, + depth_stencil_attachment: Option<RenderPassDepthStencilAttachment>, + timestamp_writes: Option<RenderPassTimestampWrites>, + occlusion_query_set_id: Option<id::QuerySetId>, +} + +impl RecordedRenderPass { + pub fn new(desc: &RenderPassDescriptor) -> Self { + Self { + base: BasePass { + label: desc.label.as_ref().map(|cow| cow.to_string()), + commands: Vec::new(), + dynamic_offsets: Vec::new(), + string_data: Vec::new(), + }, + color_attachments: desc.color_attachments.iter().cloned().collect(), + depth_stencil_attachment: desc.depth_stencil_attachment.cloned(), + timestamp_writes: desc.timestamp_writes.cloned(), + occlusion_query_set_id: desc.occlusion_query_set, + } + } +} + +#[derive(serde::Deserialize, serde::Serialize)] +pub struct RecordedComputePass { + base: BasePass<ComputeCommand>, + timestamp_writes: Option<ComputePassTimestampWrites>, +} + +impl RecordedComputePass { + pub fn new(desc: &ComputePassDescriptor) -> Self { + Self { + base: BasePass { + label: desc.label.as_ref().map(|cow| cow.to_string()), + commands: Vec::new(), + dynamic_offsets: Vec::new(), + string_data: Vec::new(), + }, + timestamp_writes: desc.timestamp_writes.cloned(), + } + } +} + +#[doc(hidden)] +#[derive(Clone, Copy, Debug)] +#[derive(serde::Serialize, serde::Deserialize)] +pub enum RenderCommand { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group_id: id::BindGroupId, + }, + SetPipeline(id::RenderPipelineId), + SetIndexBuffer { + buffer_id: id::BufferId, + index_format: wgt::IndexFormat, + offset: BufferAddress, + size: Option<BufferSize>, + }, + SetVertexBuffer { + slot: u32, + buffer_id: id::BufferId, + offset: BufferAddress, + size: Option<BufferSize>, + }, + SetBlendConstant(Color), + SetStencilReference(u32), + SetViewport { + x: f32, y: f32, w: f32, h: f32, + depth_min: f32, + depth_max: f32, + }, + SetScissor { x: u32, y: u32, w: u32, h: u32 }, + Draw { + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, + }, + DrawIndexed { + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, + }, + MultiDrawIndirect { + buffer_id: id::BufferId, + offset: BufferAddress, + /// Count of `None` represents a non-multi call. + count: Option<u32>, + indexed: bool, + }, + MultiDrawIndirectCount { + buffer_id: id::BufferId, + offset: BufferAddress, + count_buffer_id: id::BufferId, + count_buffer_offset: BufferAddress, + max_count: u32, + indexed: bool, + }, + PushDebugGroup { + color: u32, + len: usize, + }, + PopDebugGroup, + InsertDebugMarker { + color: u32, + len: usize, + }, + WriteTimestamp { + query_set_id: id::QuerySetId, + query_index: u32, + }, + BeginOcclusionQuery { + query_index: u32, + }, + EndOcclusionQuery, + BeginPipelineStatisticsQuery { + query_set_id: id::QuerySetId, + query_index: u32, + }, + EndPipelineStatisticsQuery, + ExecuteBundle(id::RenderBundleId), +} + +#[doc(hidden)] +#[derive(Clone, Copy, Debug)] +#[derive(serde::Serialize, serde::Deserialize)] +pub enum ComputeCommand { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group_id: id::BindGroupId, + }, + SetPipeline(id::ComputePipelineId), + Dispatch([u32; 3]), + DispatchIndirect { + buffer_id: id::BufferId, + offset: wgt::BufferAddress, + }, + PushDebugGroup { + color: u32, + len: usize, + }, + PopDebugGroup, + InsertDebugMarker { + color: u32, + len: usize, + }, + WriteTimestamp { + query_set_id: id::QuerySetId, + query_index: u32, + }, + BeginPipelineStatisticsQuery { + query_set_id: id::QuerySetId, + query_index: u32, + }, + EndPipelineStatisticsQuery, +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given pointer is +/// valid for `offset_length` elements. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_render_pass_set_bind_group( + pass: &mut RecordedRenderPass, + index: u32, + bind_group_id: id::BindGroupId, + offsets: *const DynamicOffset, + offset_length: usize, +) { + pass.base.dynamic_offsets + .extend_from_slice(unsafe { slice::from_raw_parts(offsets, offset_length) }); + + pass.base.commands.push(RenderCommand::SetBindGroup { + index, + num_dynamic_offsets: offset_length, + bind_group_id, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_pipeline( + pass: &mut RecordedRenderPass, + pipeline_id: id::RenderPipelineId, +) { + pass.base + .commands + .push(RenderCommand::SetPipeline(pipeline_id)); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_vertex_buffer( + pass: &mut RecordedRenderPass, + slot: u32, + buffer_id: id::BufferId, + offset: BufferAddress, + size: Option<BufferSize>, +) { + pass.base.commands.push(RenderCommand::SetVertexBuffer { + slot, + buffer_id, + offset, + size, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_index_buffer( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + index_format: IndexFormat, + offset: BufferAddress, + size: Option<BufferSize>, +) { + pass.base.commands.push(RenderCommand::SetIndexBuffer { + buffer_id, + index_format, + offset, + size, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_blend_constant(pass: &mut RecordedRenderPass, color: &Color) { + pass.base + .commands + .push(RenderCommand::SetBlendConstant(*color)); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_stencil_reference(pass: &mut RecordedRenderPass, value: u32) { + pass.base + .commands + .push(RenderCommand::SetStencilReference(value)); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_viewport( + pass: &mut RecordedRenderPass, + x: f32, + y: f32, + w: f32, + h: f32, + depth_min: f32, + depth_max: f32, +) { + pass.base.commands.push(RenderCommand::SetViewport { + x, y, w, h, + depth_min, + depth_max, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_set_scissor_rect( + pass: &mut RecordedRenderPass, + x: u32, + y: u32, + w: u32, + h: u32, +) { + pass.base + .commands + .push(RenderCommand::SetScissor { x, y, w, h }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_draw( + pass: &mut RecordedRenderPass, + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, +) { + pass.base.commands.push(RenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_draw_indexed( + pass: &mut RecordedRenderPass, + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, +) { + pass.base.commands.push(RenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_draw_indirect( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, +) { + pass.base.commands.push(RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count: None, + indexed: false, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_draw_indexed_indirect( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, +) { + pass.base.commands.push(RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count: None, + indexed: true, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indirect( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, + count: u32, +) { + pass.base.commands.push(RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count: Some(count), + indexed: false, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indexed_indirect( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, + count: u32, +) { + pass.base.commands.push(RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count: Some(count), + indexed: true, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indirect_count( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, + count_buffer_id: id::BufferId, + count_buffer_offset: BufferAddress, + max_count: u32, +) { + pass.base + .commands + .push(RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + indexed: false, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_multi_draw_indexed_indirect_count( + pass: &mut RecordedRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, + count_buffer_id: id::BufferId, + count_buffer_offset: BufferAddress, + max_count: u32, +) { + pass.base + .commands + .push(RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + indexed: true, + }); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given `label` +/// is a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_render_pass_push_debug_group( + pass: &mut RecordedRenderPass, + label: RawString, + color: u32, +) { + let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pass.base.string_data.extend_from_slice(bytes); + + pass.base.commands.push(RenderCommand::PushDebugGroup { + color, + len: bytes.len(), + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_pop_debug_group(pass: &mut RecordedRenderPass) { + pass.base.commands.push(RenderCommand::PopDebugGroup); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given `label` +/// is a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_render_pass_insert_debug_marker( + pass: &mut RecordedRenderPass, + label: RawString, + color: u32, +) { + let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pass.base.string_data.extend_from_slice(bytes); + + pass.base.commands.push(RenderCommand::InsertDebugMarker { + color, + len: bytes.len(), + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_write_timestamp( + pass: &mut RecordedRenderPass, + query_set_id: id::QuerySetId, + query_index: u32, +) { + pass.base.commands.push(RenderCommand::WriteTimestamp { + query_set_id, + query_index, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_begin_occlusion_query( + pass: &mut RecordedRenderPass, + query_index: u32, +) { + pass.base + .commands + .push(RenderCommand::BeginOcclusionQuery { query_index }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_end_occlusion_query(pass: &mut RecordedRenderPass) { + pass.base.commands.push(RenderCommand::EndOcclusionQuery); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_begin_pipeline_statistics_query( + pass: &mut RecordedRenderPass, + query_set_id: id::QuerySetId, + query_index: u32, +) { + pass.base + .commands + .push(RenderCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_render_pass_end_pipeline_statistics_query(pass: &mut RecordedRenderPass) { + pass.base + .commands + .push(RenderCommand::EndPipelineStatisticsQuery); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given pointer is +/// valid for `render_bundle_ids_length` elements. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_render_pass_execute_bundles( + pass: &mut RecordedRenderPass, + render_bundle_ids: *const id::RenderBundleId, + render_bundle_ids_length: usize, +) { + for &bundle_id in + unsafe { slice::from_raw_parts(render_bundle_ids, render_bundle_ids_length) } + { + pass.base + .commands + .push(RenderCommand::ExecuteBundle(bundle_id)); + } +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given pointer is +/// valid for `offset_length` elements. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_compute_pass_set_bind_group( + pass: &mut RecordedComputePass, + index: u32, + bind_group_id: id::BindGroupId, + offsets: *const DynamicOffset, + offset_length: usize, +) { + pass.base.dynamic_offsets + .extend_from_slice(unsafe { slice::from_raw_parts(offsets, offset_length) }); + + pass.base.commands.push(ComputeCommand::SetBindGroup { + index, + num_dynamic_offsets: offset_length, + bind_group_id, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_set_pipeline( + pass: &mut RecordedComputePass, + pipeline_id: id::ComputePipelineId, +) { + pass.base + .commands + .push(ComputeCommand::SetPipeline(pipeline_id)); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_dispatch_workgroups( + pass: &mut RecordedComputePass, + groups_x: u32, + groups_y: u32, + groups_z: u32, +) { + pass.base + .commands + .push(ComputeCommand::Dispatch([groups_x, groups_y, groups_z])); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_dispatch_workgroups_indirect( + pass: &mut RecordedComputePass, + buffer_id: id::BufferId, + offset: BufferAddress, +) { + pass.base + .commands + .push(ComputeCommand::DispatchIndirect { buffer_id, offset }); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given `label` +/// is a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_compute_pass_push_debug_group( + pass: &mut RecordedComputePass, + label: RawString, + color: u32, +) { + let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pass.base.string_data.extend_from_slice(bytes); + + pass.base.commands.push(ComputeCommand::PushDebugGroup { + color, + len: bytes.len(), + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_pop_debug_group(pass: &mut RecordedComputePass) { + pass.base.commands.push(ComputeCommand::PopDebugGroup); +} + +/// # Safety +/// +/// This function is unsafe as there is no guarantee that the given `label` +/// is a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn wgpu_recorded_compute_pass_insert_debug_marker( + pass: &mut RecordedComputePass, + label: RawString, + color: u32, +) { + let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes(); + pass.base.string_data.extend_from_slice(bytes); + + pass.base.commands.push(ComputeCommand::InsertDebugMarker { + color, + len: bytes.len(), + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_write_timestamp( + pass: &mut RecordedComputePass, + query_set_id: id::QuerySetId, + query_index: u32, +) { + pass.base.commands.push(ComputeCommand::WriteTimestamp { + query_set_id, + query_index, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_begin_pipeline_statistics_query( + pass: &mut RecordedComputePass, + query_set_id: id::QuerySetId, + query_index: u32, +) { + pass.base + .commands + .push(ComputeCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + }); +} + +#[no_mangle] +pub extern "C" fn wgpu_recorded_compute_pass_end_pipeline_statistics_query(pass: &mut RecordedComputePass) { + pass.base + .commands + .push(ComputeCommand::EndPipelineStatisticsQuery); +} + +pub fn replay_render_pass( + id: CommandEncoderId, + src_pass: &RecordedRenderPass +) -> wgc::command::RenderPass { + + let mut dst_pass = wgc::command::RenderPass::new( + id, + &wgc::command::RenderPassDescriptor { + label: src_pass.base.label.as_ref().map(|s| s.as_str().into()), + color_attachments: Cow::Borrowed(&src_pass.color_attachments), + depth_stencil_attachment: src_pass.depth_stencil_attachment.as_ref(), + timestamp_writes: src_pass.timestamp_writes.as_ref(), + occlusion_query_set: src_pass.occlusion_query_set_id, + }, + ); + + let mut dynamic_offsets = src_pass.base.dynamic_offsets.as_slice(); + let mut dynamic_offsets = |len| { + let offsets; + (offsets, dynamic_offsets) = dynamic_offsets.split_at(len); + offsets + }; + let mut strings = src_pass.base.string_data.as_slice(); + let mut strings = |len| { + let label; + (label, strings) = strings.split_at(len); + label + }; + for command in &src_pass.base.commands { + match *command { + RenderCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group_id, + } => { + let offsets = dynamic_offsets(num_dynamic_offsets); + unsafe { + render_ffi::wgpu_render_pass_set_bind_group( + &mut dst_pass, + index, + bind_group_id, + offsets.as_ptr(), + offsets.len(), + ); + } + } + RenderCommand::SetPipeline(pipeline_id) => { + render_ffi::wgpu_render_pass_set_pipeline(&mut dst_pass, pipeline_id); + } + RenderCommand::SetIndexBuffer { + buffer_id, + index_format, + offset, + size, + } => { + render_ffi::wgpu_render_pass_set_index_buffer( + &mut dst_pass, + buffer_id, + index_format, + offset, + size + ); + } + RenderCommand::SetVertexBuffer { + slot, + buffer_id, + offset, + size, + } => { + render_ffi::wgpu_render_pass_set_vertex_buffer( + &mut dst_pass, + slot, + buffer_id, + offset, + size + ) + } + RenderCommand::SetBlendConstant(ref color) => { + render_ffi::wgpu_render_pass_set_blend_constant(&mut dst_pass, color); + } + RenderCommand::SetStencilReference(value) => { + render_ffi::wgpu_render_pass_set_stencil_reference(&mut dst_pass, value); + } + RenderCommand::SetViewport { + x, y, w, h, + depth_min, + depth_max, + } => { + render_ffi::wgpu_render_pass_set_viewport( + &mut dst_pass, + x, y, w, h, + depth_min, + depth_max, + ); + } + RenderCommand::SetScissor { x, y, w, h } => { + render_ffi::wgpu_render_pass_set_scissor_rect( + &mut dst_pass, + x, y, w, h + ); + } + RenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + } => { + render_ffi::wgpu_render_pass_draw( + &mut dst_pass, + vertex_count, + instance_count, + first_vertex, + first_instance, + ); + } + RenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + } => { + render_ffi::wgpu_render_pass_draw_indexed( + &mut dst_pass, + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + ); + } + RenderCommand::MultiDrawIndirect { + buffer_id, + offset, + count, + indexed, + } => { + match (indexed, count) { + (false, Some(count)) => render_ffi::wgpu_render_pass_multi_draw_indirect( + &mut dst_pass, + buffer_id, + offset, + count, + ), + (false, None) => render_ffi::wgpu_render_pass_draw_indirect( + &mut dst_pass, + buffer_id, + offset, + ), + (true, Some(count)) => render_ffi::wgpu_render_pass_multi_draw_indexed_indirect( + &mut dst_pass, + buffer_id, + offset, + count, + ), + (true, None) => render_ffi::wgpu_render_pass_draw_indexed_indirect( + &mut dst_pass, + buffer_id, + offset, + ), + }; + } + RenderCommand::MultiDrawIndirectCount { + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + indexed, + } => { + if indexed { + render_ffi::wgpu_render_pass_multi_draw_indexed_indirect_count( + &mut dst_pass, + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + ); + } else { + render_ffi::wgpu_render_pass_multi_draw_indirect_count( + &mut dst_pass, + buffer_id, + offset, + count_buffer_id, + count_buffer_offset, + max_count, + ); + } + } + RenderCommand::PushDebugGroup { color, len } => { + let label = strings(len); + let label = std::ffi::CString::new(label).unwrap(); + unsafe { + render_ffi::wgpu_render_pass_push_debug_group( + &mut dst_pass, + label.as_ptr(), + color + ); + } + } + RenderCommand::PopDebugGroup => { + render_ffi::wgpu_render_pass_pop_debug_group(&mut dst_pass); + } + RenderCommand::InsertDebugMarker { color, len } => { + let label = strings(len); + let label = std::ffi::CString::new(label).unwrap(); + unsafe { + render_ffi::wgpu_render_pass_insert_debug_marker( + &mut dst_pass, + label.as_ptr(), + color, + ); + } + } + RenderCommand::WriteTimestamp { + query_set_id, + query_index, + } => { + render_ffi::wgpu_render_pass_write_timestamp( + &mut dst_pass, + query_set_id, + query_index, + ); + } + RenderCommand::BeginOcclusionQuery { query_index } => { + render_ffi::wgpu_render_pass_begin_occlusion_query( + &mut dst_pass, + query_index + ); + } + RenderCommand::EndOcclusionQuery => { + render_ffi::wgpu_render_pass_end_occlusion_query(&mut dst_pass); + } + RenderCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + } => { + render_ffi::wgpu_render_pass_begin_pipeline_statistics_query( + &mut dst_pass, + query_set_id, + query_index, + ); + } + RenderCommand::EndPipelineStatisticsQuery => { + render_ffi::wgpu_render_pass_end_pipeline_statistics_query(&mut dst_pass); + } + RenderCommand::ExecuteBundle(bundle_id) => { + unsafe { + render_ffi::wgpu_render_pass_execute_bundles( + &mut dst_pass, + &bundle_id, + 1, + ); + } + } + } + } + + dst_pass +} + +pub fn replay_compute_pass( + id: CommandEncoderId, + src_pass: &RecordedComputePass +) -> wgc::command::ComputePass { + let mut dst_pass = wgc::command::ComputePass::new( + id, + &wgc::command::ComputePassDescriptor { + label: src_pass.base.label.as_ref().map(|s| s.as_str().into()), + timestamp_writes: src_pass.timestamp_writes.as_ref(), + }, + ); + + let mut dynamic_offsets = src_pass.base.dynamic_offsets.as_slice(); + let mut dynamic_offsets = |len| { + let offsets; + (offsets, dynamic_offsets) = dynamic_offsets.split_at(len); + offsets + }; + let mut strings = src_pass.base.string_data.as_slice(); + let mut strings = |len| { + let label; + (label, strings) = strings.split_at(len); + label + }; + for command in &src_pass.base.commands { + match *command { + ComputeCommand::SetBindGroup { + index, + num_dynamic_offsets, + bind_group_id, + } => { + let offsets = dynamic_offsets(num_dynamic_offsets); + unsafe { + compute_ffi::wgpu_compute_pass_set_bind_group( + &mut dst_pass, + index, + bind_group_id, + offsets.as_ptr(), + offsets.len() + ); + } + } + ComputeCommand::SetPipeline(pipeline_id) => { + compute_ffi::wgpu_compute_pass_set_pipeline(&mut dst_pass, pipeline_id) + } + ComputeCommand::Dispatch([x, y, z]) => { + compute_ffi::wgpu_compute_pass_dispatch_workgroups(&mut dst_pass, x, y, z); + } + ComputeCommand::DispatchIndirect { buffer_id, offset } => { + compute_ffi::wgpu_compute_pass_dispatch_workgroups_indirect( + &mut dst_pass, + buffer_id, + offset, + ); + } + ComputeCommand::PushDebugGroup { color, len } => { + let label = strings(len); + let label = std::ffi::CString::new(label).unwrap(); + unsafe { + compute_ffi::wgpu_compute_pass_push_debug_group( + &mut dst_pass, + label.as_ptr(), + color + ); + } + } + ComputeCommand::PopDebugGroup => { + compute_ffi::wgpu_compute_pass_pop_debug_group(&mut dst_pass); + } + ComputeCommand::InsertDebugMarker { color, len } => { + let label = strings(len); + let label = std::ffi::CString::new(label).unwrap(); + unsafe { + compute_ffi::wgpu_compute_pass_insert_debug_marker( + &mut dst_pass, + label.as_ptr(), + color, + ); + } + } + ComputeCommand::WriteTimestamp { + query_set_id, + query_index, + } => { + compute_ffi::wgpu_compute_pass_write_timestamp( + &mut dst_pass, + query_set_id, + query_index, + ); + } + ComputeCommand::BeginPipelineStatisticsQuery { + query_set_id, + query_index, + } => { + compute_ffi::wgpu_compute_pass_begin_pipeline_statistics_query( + &mut dst_pass, + query_set_id, + query_index, + ); + } + ComputeCommand::EndPipelineStatisticsQuery => { + compute_ffi::wgpu_compute_pass_end_pipeline_statistics_query(&mut dst_pass); + } + } + } + + dst_pass +} |