diff options
Diffstat (limited to 'gfx/wgpu_bindings')
-rw-r--r-- | gfx/wgpu_bindings/Cargo.toml | 15 | ||||
-rw-r--r-- | gfx/wgpu_bindings/moz.yaml | 4 | ||||
-rw-r--r-- | gfx/wgpu_bindings/src/client.rs | 58 | ||||
-rw-r--r-- | gfx/wgpu_bindings/src/command.rs | 1062 | ||||
-rw-r--r-- | gfx/wgpu_bindings/src/lib.rs | 1 | ||||
-rw-r--r-- | gfx/wgpu_bindings/src/server.rs | 47 |
6 files changed, 1140 insertions, 47 deletions
diff --git a/gfx/wgpu_bindings/Cargo.toml b/gfx/wgpu_bindings/Cargo.toml index b24d09a955..21b4b8c7f7 100644 --- a/gfx/wgpu_bindings/Cargo.toml +++ b/gfx/wgpu_bindings/Cargo.toml @@ -17,7 +17,7 @@ default = [] [dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" # TODO: remove the replay feature on the next update containing https://github.com/gfx-rs/wgpu/pull/5182 features = ["serde", "replay", "trace", "strict_asserts", "wgsl", "api_log_info"] @@ -26,37 +26,37 @@ features = ["serde", "replay", "trace", "strict_asserts", "wgsl", "api_log_info" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" features = ["metal"] # We want the wgpu-core Direct3D backends on Windows. [target.'cfg(windows)'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" features = ["dx12"] # We want the wgpu-core Vulkan backend on Linux and Windows. [target.'cfg(any(windows, all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" features = ["vulkan"] [dependencies.wgt] package = "wgpu-types" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" [dependencies.wgh] package = "wgpu-hal" git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" features = ["windows_rs"] [target.'cfg(windows)'.dependencies.d3d12] git = "https://github.com/gfx-rs/wgpu" -rev = "07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a" +rev = "6040820099bc72b827a6a5f53d66dda3e301f944" [target.'cfg(windows)'.dependencies] winapi = "0.3" @@ -68,3 +68,4 @@ parking_lot = "0.12" serde = "1" nsstring = { path = "../../xpcom/rust/nsstring" } static_prefs = { path = "../../modules/libpref/init/static_prefs" } +arrayvec = "0.7" diff --git a/gfx/wgpu_bindings/moz.yaml b/gfx/wgpu_bindings/moz.yaml index 1c4f19cbb7..ffa746cb46 100644 --- a/gfx/wgpu_bindings/moz.yaml +++ b/gfx/wgpu_bindings/moz.yaml @@ -20,11 +20,11 @@ origin: # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: commit 07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a + release: 6040820099bc72b827a6a5f53d66dda3e301f944 (2024-03-12T14:49:44Z). # Revision to pull in # Must be a long or short commit SHA (long preferred) - revision: 07e59eb6fc7de3f682f1c401b9cf9f0da9ee4b4a + revision: 6040820099bc72b827a6a5f53d66dda3e301f944 license: ['MIT', 'Apache-2.0'] diff --git a/gfx/wgpu_bindings/src/client.rs b/gfx/wgpu_bindings/src/client.rs index bf53a8c871..c49dbea7a5 100644 --- a/gfx/wgpu_bindings/src/client.rs +++ b/gfx/wgpu_bindings/src/client.rs @@ -47,7 +47,7 @@ impl ProgrammableStageDescriptor { fn to_wgpu(&self) -> wgc::pipeline::ProgrammableStageDescriptor { wgc::pipeline::ProgrammableStageDescriptor { module: self.module, - entry_point: cow_label(&self.entry_point).unwrap(), + entry_point: cow_label(&self.entry_point), } } } @@ -177,6 +177,7 @@ pub enum RawBindingType { SampledTexture, ReadonlyStorageTexture, WriteonlyStorageTexture, + ReadWriteStorageTexture, } #[repr(C)] @@ -237,7 +238,7 @@ pub struct SamplerDescriptor<'a> { lod_min_clamp: f32, lod_max_clamp: f32, compare: Option<&'a wgt::CompareFunction>, - anisotropy_clamp: Option<&'a u16>, + max_anisotropy: u16, } #[repr(C)] @@ -614,7 +615,7 @@ pub extern "C" fn wgpu_client_create_sampler( lod_min_clamp: desc.lod_min_clamp, lod_max_clamp: desc.lod_max_clamp, compare: desc.compare.cloned(), - anisotropy_clamp: *desc.anisotropy_clamp.unwrap_or(&1), + anisotropy_clamp: desc.max_anisotropy, border_color: None, }; let action = DeviceAction::CreateSampler(id, wgpu_desc); @@ -769,9 +770,8 @@ pub struct ComputePassTimestampWrites<'a> { #[no_mangle] pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass( - encoder_id: id::CommandEncoderId, desc: &ComputePassDescriptor, -) -> *mut wgc::command::ComputePass { +) -> *mut crate::command::RecordedComputePass { let &ComputePassDescriptor { label, timestamp_writes, @@ -795,27 +795,24 @@ pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass( }); let timestamp_writes = timestamp_writes.as_ref(); - let pass = wgc::command::ComputePass::new( - encoder_id, - &wgc::command::ComputePassDescriptor { - label, - timestamp_writes, - }, - ); + let pass = crate::command::RecordedComputePass::new(&wgc::command::ComputePassDescriptor { + label, + timestamp_writes, + }); Box::into_raw(Box::new(pass)) } #[no_mangle] pub unsafe extern "C" fn wgpu_compute_pass_finish( - pass: *mut wgc::command::ComputePass, + pass: *mut crate::command::RecordedComputePass, output: &mut ByteBuf, ) { - let command = Box::from_raw(pass).into_command(); + let command = Box::from_raw(pass); *output = make_byte_buf(&command); } #[no_mangle] -pub unsafe extern "C" fn wgpu_compute_pass_destroy(pass: *mut wgc::command::ComputePass) { +pub unsafe extern "C" fn wgpu_compute_pass_destroy(pass: *mut crate::command::RecordedComputePass) { let _ = Box::from_raw(pass); } @@ -838,9 +835,8 @@ pub struct RenderPassTimestampWrites<'a> { #[no_mangle] pub unsafe extern "C" fn wgpu_command_encoder_begin_render_pass( - encoder_id: id::CommandEncoderId, desc: &RenderPassDescriptor, -) -> *mut wgc::command::RenderPass { +) -> *mut crate::command::RecordedRenderPass { let &RenderPassDescriptor { label, color_attachments, @@ -873,30 +869,27 @@ pub unsafe extern "C" fn wgpu_command_encoder_begin_render_pass( .iter() .map(|format| Some(format.clone())) .collect(); - let pass = wgc::command::RenderPass::new( - encoder_id, - &wgc::command::RenderPassDescriptor { - label, - color_attachments: Cow::Owned(color_attachments), - depth_stencil_attachment: depth_stencil_attachment.as_ref(), - timestamp_writes, - occlusion_query_set, - }, - ); + let pass = crate::command::RecordedRenderPass::new(&wgc::command::RenderPassDescriptor { + label, + color_attachments: Cow::Owned(color_attachments), + depth_stencil_attachment: depth_stencil_attachment.as_ref(), + timestamp_writes, + occlusion_query_set, + }); Box::into_raw(Box::new(pass)) } #[no_mangle] pub unsafe extern "C" fn wgpu_render_pass_finish( - pass: *mut wgc::command::RenderPass, + pass: *mut crate::command::RecordedRenderPass, output: &mut ByteBuf, ) { - let command = Box::from_raw(pass).into_command(); + let command = Box::from_raw(pass); *output = make_byte_buf(&command); } #[no_mangle] -pub unsafe extern "C" fn wgpu_render_pass_destroy(pass: *mut wgc::command::RenderPass) { +pub unsafe extern "C" fn wgpu_render_pass_destroy(pass: *mut crate::command::RecordedRenderPass) { let _ = Box::from_raw(pass); } @@ -974,6 +967,11 @@ pub unsafe extern "C" fn wgpu_client_create_bind_group_layout( view_dimension: *entry.view_dimension.unwrap(), format: *entry.storage_texture_format.unwrap(), }, + RawBindingType::ReadWriteStorageTexture => wgt::BindingType::StorageTexture { + access: wgt::StorageTextureAccess::ReadWrite, + view_dimension: *entry.view_dimension.unwrap(), + format: *entry.storage_texture_format.unwrap(), + }, }, }); } 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 +} diff --git a/gfx/wgpu_bindings/src/lib.rs b/gfx/wgpu_bindings/src/lib.rs index 3299234182..6e6b79c991 100644 --- a/gfx/wgpu_bindings/src/lib.rs +++ b/gfx/wgpu_bindings/src/lib.rs @@ -10,6 +10,7 @@ pub use wgc::command::{compute_ffi::*, render_ffi::*}; pub mod client; pub mod error; pub mod server; +pub mod command; pub use wgc::device::trace::Command as CommandEncoderAction; diff --git a/gfx/wgpu_bindings/src/server.rs b/gfx/wgpu_bindings/src/server.rs index 7a7e08aa30..8417fe84fb 100644 --- a/gfx/wgpu_bindings/src/server.rs +++ b/gfx/wgpu_bindings/src/server.rs @@ -410,7 +410,9 @@ pub extern "C" fn wgpu_server_device_create_shader_module( if let Some(err) = error { out_message.set_error(&err, &source_str[..]); let err_type = match &err { - CreateShaderModuleError::Device(DeviceError::OutOfMemory) => ErrorBufferType::OutOfMemory, + CreateShaderModuleError::Device(DeviceError::OutOfMemory) => { + ErrorBufferType::OutOfMemory + } CreateShaderModuleError::Device(DeviceError::Lost) => ErrorBufferType::DeviceLost, _ => ErrorBufferType::Validation, }; @@ -497,7 +499,8 @@ pub unsafe extern "C" fn wgpu_server_buffer_map( // the returned value of buffer_map_async. let result = gfx_select!(buffer_id => global.buffer_map_async( buffer_id, - start .. start + size, + start, + Some(size), operation )); @@ -580,9 +583,10 @@ pub extern "C" fn wgpu_server_get_device_fence_handle( if device_id.backend() == wgt::Backend::Dx12 { let mut handle = ptr::null_mut(); let dx12_device = unsafe { - global.device_as_hal::<wgc::api::Dx12, _, Option<d3d12::Device>>(device_id, |hal_device| { - hal_device.map(|device| device.raw_device().clone()) - }) + global.device_as_hal::<wgc::api::Dx12, _, Option<d3d12::Device>>( + device_id, + |hal_device| hal_device.map(|device| device.raw_device().clone()), + ) }; let dx12_device = match dx12_device { Some(device) => device, @@ -592,9 +596,10 @@ pub extern "C" fn wgpu_server_get_device_fence_handle( }; let dx12_fence = unsafe { - global.device_fence_as_hal::<wgc::api::Dx12, _, Option<d3d12::Fence>>(device_id, |hal_fence| { - hal_fence.map(|fence| fence.raw_fence().clone()) - }) + global.device_fence_as_hal::<wgc::api::Dx12, _, Option<d3d12::Fence>>( + device_id, + |hal_fence| hal_fence.map(|fence| fence.raw_fence().clone()), + ) }; let dx12_fence = match dx12_fence { Some(fence) => fence, @@ -1054,6 +1059,32 @@ pub unsafe extern "C" fn wgpu_server_command_encoder_action( } #[no_mangle] +pub unsafe extern "C" fn wgpu_server_render_pass( + global: &Global, + encoder_id: id::CommandEncoderId, + byte_buf: &ByteBuf, + error_buf: ErrorBuffer, +) { + let pass = bincode::deserialize(byte_buf.as_slice()).unwrap(); + let action = crate::command::replay_render_pass(encoder_id, &pass).into_command(); + + gfx_select!(encoder_id => global.command_encoder_action(encoder_id, action, error_buf)); +} + +#[no_mangle] +pub unsafe extern "C" fn wgpu_server_compute_pass( + global: &Global, + encoder_id: id::CommandEncoderId, + byte_buf: &ByteBuf, + error_buf: ErrorBuffer, +) { + let pass = bincode::deserialize(byte_buf.as_slice()).unwrap(); + let action = crate::command::replay_compute_pass(encoder_id, &pass).into_command(); + + gfx_select!(encoder_id => global.command_encoder_action(encoder_id, action, error_buf)); +} + +#[no_mangle] pub extern "C" fn wgpu_server_device_create_encoder( global: &Global, self_id: id::DeviceId, |