summaryrefslogtreecommitdiffstats
path: root/gfx/wgpu_bindings
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
commitfbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 (patch)
tree4c1ccaf5486d4f2009f9a338a98a83e886e29c97 /gfx/wgpu_bindings
parentReleasing progress-linux version 124.0.1-1~progress7.99u1. (diff)
downloadfirefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.tar.xz
firefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.zip
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/wgpu_bindings')
-rw-r--r--gfx/wgpu_bindings/Cargo.toml15
-rw-r--r--gfx/wgpu_bindings/moz.yaml4
-rw-r--r--gfx/wgpu_bindings/src/client.rs58
-rw-r--r--gfx/wgpu_bindings/src/command.rs1062
-rw-r--r--gfx/wgpu_bindings/src/lib.rs1
-rw-r--r--gfx/wgpu_bindings/src/server.rs47
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,