summaryrefslogtreecommitdiffstats
path: root/gfx/wgpu_bindings/src/client.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /gfx/wgpu_bindings/src/client.rs
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/wgpu_bindings/src/client.rs')
-rw-r--r--gfx/wgpu_bindings/src/client.rs1361
1 files changed, 1361 insertions, 0 deletions
diff --git a/gfx/wgpu_bindings/src/client.rs b/gfx/wgpu_bindings/src/client.rs
new file mode 100644
index 0000000000..bf53a8c871
--- /dev/null
+++ b/gfx/wgpu_bindings/src/client.rs
@@ -0,0 +1,1361 @@
+/* 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::{
+ cow_label, error::HasErrorBufferType, wgpu_string, AdapterInformation, ByteBuf,
+ CommandEncoderAction, DeviceAction, DropAction, ImageDataLayout, ImplicitLayout,
+ QueueWriteAction, RawString, TextureAction,
+};
+
+use crate::SwapChainId;
+
+use wgc::{id, identity::IdentityManager};
+use wgt::{Backend, TextureFormat};
+
+pub use wgc::command::{compute_ffi::*, render_ffi::*};
+use wgc::id::markers;
+
+use parking_lot::Mutex;
+
+use nsstring::{nsACString, nsString};
+
+use std::{borrow::Cow, ptr};
+
+// we can't call `from_raw_parts` unconditionally because the caller
+// may not even have a valid pointer (e.g. NULL) if the `length` is zero.
+fn make_slice<'a, T>(pointer: *const T, length: usize) -> &'a [T] {
+ if length == 0 {
+ &[]
+ } else {
+ unsafe { std::slice::from_raw_parts(pointer, length) }
+ }
+}
+
+fn make_byte_buf<T: serde::Serialize>(data: &T) -> ByteBuf {
+ let vec = bincode::serialize(data).unwrap();
+ ByteBuf::from_vec(vec)
+}
+
+#[repr(C)]
+pub struct ProgrammableStageDescriptor {
+ module: id::ShaderModuleId,
+ entry_point: RawString,
+}
+
+impl ProgrammableStageDescriptor {
+ fn to_wgpu(&self) -> wgc::pipeline::ProgrammableStageDescriptor {
+ wgc::pipeline::ProgrammableStageDescriptor {
+ module: self.module,
+ entry_point: cow_label(&self.entry_point).unwrap(),
+ }
+ }
+}
+
+#[repr(C)]
+pub struct ComputePipelineDescriptor<'a> {
+ label: Option<&'a nsACString>,
+ layout: Option<id::PipelineLayoutId>,
+ stage: ProgrammableStageDescriptor,
+}
+
+#[repr(C)]
+pub struct VertexBufferLayout {
+ array_stride: wgt::BufferAddress,
+ step_mode: wgt::VertexStepMode,
+ attributes: *const wgt::VertexAttribute,
+ attributes_length: usize,
+}
+
+#[repr(C)]
+pub struct VertexState {
+ stage: ProgrammableStageDescriptor,
+ buffers: *const VertexBufferLayout,
+ buffers_length: usize,
+}
+
+impl VertexState {
+ fn to_wgpu(&self) -> wgc::pipeline::VertexState {
+ let buffer_layouts = make_slice(self.buffers, self.buffers_length)
+ .iter()
+ .map(|vb| wgc::pipeline::VertexBufferLayout {
+ array_stride: vb.array_stride,
+ step_mode: vb.step_mode,
+ attributes: Cow::Borrowed(make_slice(vb.attributes, vb.attributes_length)),
+ })
+ .collect();
+ wgc::pipeline::VertexState {
+ stage: self.stage.to_wgpu(),
+ buffers: Cow::Owned(buffer_layouts),
+ }
+ }
+}
+
+#[repr(C)]
+pub struct ColorTargetState<'a> {
+ format: wgt::TextureFormat,
+ blend: Option<&'a wgt::BlendState>,
+ write_mask: wgt::ColorWrites,
+}
+
+#[repr(C)]
+pub struct FragmentState<'a> {
+ stage: ProgrammableStageDescriptor,
+ targets: *const ColorTargetState<'a>,
+ targets_length: usize,
+}
+
+impl FragmentState<'_> {
+ fn to_wgpu(&self) -> wgc::pipeline::FragmentState {
+ let color_targets = make_slice(self.targets, self.targets_length)
+ .iter()
+ .map(|ct| {
+ Some(wgt::ColorTargetState {
+ format: ct.format,
+ blend: ct.blend.cloned(),
+ write_mask: ct.write_mask,
+ })
+ })
+ .collect();
+ wgc::pipeline::FragmentState {
+ stage: self.stage.to_wgpu(),
+ targets: Cow::Owned(color_targets),
+ }
+ }
+}
+
+#[repr(C)]
+pub struct PrimitiveState<'a> {
+ topology: wgt::PrimitiveTopology,
+ strip_index_format: Option<&'a wgt::IndexFormat>,
+ front_face: wgt::FrontFace,
+ cull_mode: Option<&'a wgt::Face>,
+ polygon_mode: wgt::PolygonMode,
+ unclipped_depth: bool,
+}
+
+impl PrimitiveState<'_> {
+ fn to_wgpu(&self) -> wgt::PrimitiveState {
+ wgt::PrimitiveState {
+ topology: self.topology,
+ strip_index_format: self.strip_index_format.cloned(),
+ front_face: self.front_face.clone(),
+ cull_mode: self.cull_mode.cloned(),
+ polygon_mode: self.polygon_mode,
+ unclipped_depth: self.unclipped_depth,
+ conservative: false,
+ }
+ }
+}
+
+#[repr(C)]
+pub struct RenderPipelineDescriptor<'a> {
+ label: Option<&'a nsACString>,
+ layout: Option<id::PipelineLayoutId>,
+ vertex: &'a VertexState,
+ primitive: PrimitiveState<'a>,
+ fragment: Option<&'a FragmentState<'a>>,
+ depth_stencil: Option<&'a wgt::DepthStencilState>,
+ multisample: wgt::MultisampleState,
+}
+
+#[repr(C)]
+pub enum RawTextureSampleType {
+ Float,
+ UnfilterableFloat,
+ Uint,
+ Sint,
+ Depth,
+}
+
+#[repr(C)]
+pub enum RawBindingType {
+ UniformBuffer,
+ StorageBuffer,
+ ReadonlyStorageBuffer,
+ Sampler,
+ SampledTexture,
+ ReadonlyStorageTexture,
+ WriteonlyStorageTexture,
+}
+
+#[repr(C)]
+pub struct BindGroupLayoutEntry<'a> {
+ binding: u32,
+ visibility: wgt::ShaderStages,
+ ty: RawBindingType,
+ has_dynamic_offset: bool,
+ min_binding_size: Option<wgt::BufferSize>,
+ view_dimension: Option<&'a wgt::TextureViewDimension>,
+ texture_sample_type: Option<&'a RawTextureSampleType>,
+ multisampled: bool,
+ storage_texture_format: Option<&'a wgt::TextureFormat>,
+ sampler_filter: bool,
+ sampler_compare: bool,
+}
+
+#[repr(C)]
+pub struct BindGroupLayoutDescriptor<'a> {
+ label: Option<&'a nsACString>,
+ entries: *const BindGroupLayoutEntry<'a>,
+ entries_length: usize,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct BindGroupEntry {
+ binding: u32,
+ buffer: Option<id::BufferId>,
+ offset: wgt::BufferAddress,
+ size: Option<wgt::BufferSize>,
+ sampler: Option<id::SamplerId>,
+ texture_view: Option<id::TextureViewId>,
+}
+
+#[repr(C)]
+pub struct BindGroupDescriptor<'a> {
+ label: Option<&'a nsACString>,
+ layout: id::BindGroupLayoutId,
+ entries: *const BindGroupEntry,
+ entries_length: usize,
+}
+
+#[repr(C)]
+pub struct PipelineLayoutDescriptor<'a> {
+ label: Option<&'a nsACString>,
+ bind_group_layouts: *const id::BindGroupLayoutId,
+ bind_group_layouts_length: usize,
+}
+
+#[repr(C)]
+pub struct SamplerDescriptor<'a> {
+ label: Option<&'a nsACString>,
+ address_modes: [wgt::AddressMode; 3],
+ mag_filter: wgt::FilterMode,
+ min_filter: wgt::FilterMode,
+ mipmap_filter: wgt::FilterMode,
+ lod_min_clamp: f32,
+ lod_max_clamp: f32,
+ compare: Option<&'a wgt::CompareFunction>,
+ anisotropy_clamp: Option<&'a u16>,
+}
+
+#[repr(C)]
+pub struct TextureViewDescriptor<'a> {
+ label: Option<&'a nsACString>,
+ format: Option<&'a wgt::TextureFormat>,
+ dimension: Option<&'a wgt::TextureViewDimension>,
+ aspect: wgt::TextureAspect,
+ base_mip_level: u32,
+ mip_level_count: Option<&'a u32>,
+ base_array_layer: u32,
+ array_layer_count: Option<&'a u32>,
+}
+
+#[repr(C)]
+pub struct RenderBundleEncoderDescriptor<'a> {
+ label: Option<&'a nsACString>,
+ color_formats: *const wgt::TextureFormat,
+ color_formats_length: usize,
+ depth_stencil_format: Option<&'a wgt::TextureFormat>,
+ depth_read_only: bool,
+ stencil_read_only: bool,
+ sample_count: u32,
+}
+
+#[derive(Debug)]
+struct IdentityHub {
+ adapters: IdentityManager<markers::Adapter>,
+ devices: IdentityManager<markers::Device>,
+ buffers: IdentityManager<markers::Buffer>,
+ command_buffers: IdentityManager<markers::CommandBuffer>,
+ render_bundles: IdentityManager<markers::RenderBundle>,
+ bind_group_layouts: IdentityManager<markers::BindGroupLayout>,
+ pipeline_layouts: IdentityManager<markers::PipelineLayout>,
+ bind_groups: IdentityManager<markers::BindGroup>,
+ shader_modules: IdentityManager<markers::ShaderModule>,
+ compute_pipelines: IdentityManager<markers::ComputePipeline>,
+ render_pipelines: IdentityManager<markers::RenderPipeline>,
+ textures: IdentityManager<markers::Texture>,
+ texture_views: IdentityManager<markers::TextureView>,
+ samplers: IdentityManager<markers::Sampler>,
+}
+
+impl Default for IdentityHub {
+ fn default() -> Self {
+ IdentityHub {
+ adapters: IdentityManager::new(),
+ devices: IdentityManager::new(),
+ buffers: IdentityManager::new(),
+ command_buffers: IdentityManager::new(),
+ render_bundles: IdentityManager::new(),
+ bind_group_layouts: IdentityManager::new(),
+ pipeline_layouts: IdentityManager::new(),
+ bind_groups: IdentityManager::new(),
+ shader_modules: IdentityManager::new(),
+ compute_pipelines: IdentityManager::new(),
+ render_pipelines: IdentityManager::new(),
+ textures: IdentityManager::new(),
+ texture_views: IdentityManager::new(),
+ samplers: IdentityManager::new(),
+ }
+ }
+}
+
+impl ImplicitLayout<'_> {
+ fn new(identities: &mut IdentityHub, backend: Backend) -> Self {
+ ImplicitLayout {
+ pipeline: identities.pipeline_layouts.process(backend),
+ bind_groups: Cow::Owned(
+ (0..8) // hal::MAX_BIND_GROUPS
+ .map(|_| Some(identities.bind_group_layouts.process(backend)))
+ .collect(),
+ ),
+ }
+ }
+}
+
+#[derive(Debug, Default)]
+struct Identities {
+ vulkan: IdentityHub,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ metal: IdentityHub,
+ #[cfg(windows)]
+ dx12: IdentityHub,
+}
+
+impl Identities {
+ fn select(&mut self, backend: Backend) -> &mut IdentityHub {
+ match backend {
+ Backend::Vulkan => &mut self.vulkan,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ Backend::Metal => &mut self.metal,
+ #[cfg(windows)]
+ Backend::Dx12 => &mut self.dx12,
+ _ => panic!("Unexpected backend: {:?}", backend),
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct Client {
+ identities: Mutex<Identities>,
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_drop_action(client: &mut Client, byte_buf: &ByteBuf) {
+ let mut cursor = std::io::Cursor::new(byte_buf.as_slice());
+ let mut identities = client.identities.lock();
+ while let Ok(action) = bincode::deserialize_from(&mut cursor) {
+ match action {
+ DropAction::Adapter(id) => identities.select(id.backend()).adapters.free(id),
+ DropAction::Device(id) => identities.select(id.backend()).devices.free(id),
+ DropAction::ShaderModule(id) => identities.select(id.backend()).shader_modules.free(id),
+ DropAction::PipelineLayout(id) => {
+ identities.select(id.backend()).pipeline_layouts.free(id)
+ }
+ DropAction::BindGroupLayout(id) => {
+ identities.select(id.backend()).bind_group_layouts.free(id)
+ }
+ DropAction::BindGroup(id) => identities.select(id.backend()).bind_groups.free(id),
+ DropAction::CommandBuffer(id) => {
+ identities.select(id.backend()).command_buffers.free(id)
+ }
+ DropAction::RenderBundle(id) => identities.select(id.backend()).render_bundles.free(id),
+ DropAction::RenderPipeline(id) => {
+ identities.select(id.backend()).render_pipelines.free(id)
+ }
+ DropAction::ComputePipeline(id) => {
+ identities.select(id.backend()).compute_pipelines.free(id)
+ }
+ DropAction::Buffer(id) => identities.select(id.backend()).buffers.free(id),
+ DropAction::Texture(id) => identities.select(id.backend()).textures.free(id),
+ DropAction::TextureView(id) => identities.select(id.backend()).texture_views.free(id),
+ DropAction::Sampler(id) => identities.select(id.backend()).samplers.free(id),
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_kill_device_id(client: &Client, id: id::DeviceId) {
+ client
+ .identities
+ .lock()
+ .select(id.backend())
+ .devices
+ .free(id)
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct Infrastructure {
+ pub client: *mut Client,
+ pub error: *const u8,
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_new() -> Infrastructure {
+ log::info!("Initializing WGPU client");
+ let client = Box::new(Client {
+ identities: Mutex::new(Identities::default()),
+ });
+ Infrastructure {
+ client: Box::into_raw(client),
+ error: ptr::null(),
+ }
+}
+
+/// # Safety
+///
+/// This function is unsafe because improper use may lead to memory
+/// problems. For example, a double-free may occur if the function is called
+/// twice on the same raw pointer.
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_delete(client: *mut Client) {
+ log::info!("Terminating WGPU client");
+ let _client = Box::from_raw(client);
+}
+
+/// # Safety
+///
+/// This function is unsafe as there is no guarantee that the given pointer is
+/// valid for `id_length` elements.
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_make_adapter_ids(
+ client: &Client,
+ ids: *mut id::AdapterId,
+ id_length: usize,
+) -> usize {
+ let identities = client.identities.lock();
+ assert_ne!(id_length, 0);
+ let mut ids = std::slice::from_raw_parts_mut(ids, id_length).iter_mut();
+
+ *ids.next().unwrap() = identities.vulkan.adapters.process(Backend::Vulkan);
+
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ {
+ *ids.next().unwrap() = identities.metal.adapters.process(Backend::Metal);
+ }
+ #[cfg(windows)]
+ {
+ *ids.next().unwrap() = identities.dx12.adapters.process(Backend::Dx12);
+ }
+
+ id_length - ids.len()
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_fill_default_limits(limits: &mut wgt::Limits) {
+ *limits = wgt::Limits::default();
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_adapter_extract_info(
+ byte_buf: &ByteBuf,
+ info: &mut AdapterInformation<nsString>,
+) {
+ let AdapterInformation {
+ backend,
+ device_type,
+ device,
+ driver_info,
+ driver,
+ features,
+ id,
+ limits,
+ name,
+ vendor,
+ } = bincode::deserialize::<AdapterInformation<String>>(unsafe { byte_buf.as_slice() }).unwrap();
+
+ let nss = |s: &str| {
+ let mut ns_string = nsString::new();
+ ns_string.assign_str(s);
+ ns_string
+ };
+ *info = AdapterInformation {
+ backend,
+ device_type,
+ device,
+ driver_info: nss(&driver_info),
+ driver: nss(&driver),
+ features,
+ id,
+ limits,
+ name: nss(&name),
+ vendor,
+ };
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_serialize_device_descriptor(
+ desc: &wgt::DeviceDescriptor<Option<&nsACString>>,
+ bb: &mut ByteBuf,
+) {
+ let label = wgpu_string(desc.label);
+ *bb = make_byte_buf(&desc.map_label(|_| label));
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_make_device_id(
+ client: &Client,
+ adapter_id: id::AdapterId,
+) -> id::DeviceId {
+ let backend = adapter_id.backend();
+ client
+ .identities
+ .lock()
+ .select(backend)
+ .devices
+ .process(backend)
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_make_buffer_id(
+ client: &Client,
+ device_id: id::DeviceId,
+) -> id::BufferId {
+ let backend = device_id.backend();
+ client
+ .identities
+ .lock()
+ .select(backend)
+ .buffers
+ .process(backend)
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_create_texture(
+ client: &Client,
+ device_id: id::DeviceId,
+ desc: &wgt::TextureDescriptor<Option<&nsACString>, crate::FfiSlice<TextureFormat>>,
+ swap_chain_id: Option<&SwapChainId>,
+ bb: &mut ByteBuf,
+) -> id::TextureId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let id = client
+ .identities
+ .lock()
+ .select(backend)
+ .textures
+ .process(backend);
+
+ let view_formats = unsafe { desc.view_formats.as_slice() }.to_vec();
+
+ let action = DeviceAction::CreateTexture(
+ id,
+ desc.map_label_and_view_formats(|_| label, |_| view_formats),
+ swap_chain_id.copied(),
+ );
+ *bb = make_byte_buf(&action);
+
+ id
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_create_texture_view(
+ client: &Client,
+ device_id: id::DeviceId,
+ desc: &TextureViewDescriptor,
+ bb: &mut ByteBuf,
+) -> id::TextureViewId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let id = client
+ .identities
+ .lock()
+ .select(backend)
+ .texture_views
+ .process(backend);
+
+ let wgpu_desc = wgc::resource::TextureViewDescriptor {
+ label,
+ format: desc.format.cloned(),
+ dimension: desc.dimension.cloned(),
+ range: wgt::ImageSubresourceRange {
+ aspect: desc.aspect,
+ base_mip_level: desc.base_mip_level,
+ mip_level_count: desc.mip_level_count.map(|ptr| *ptr),
+ base_array_layer: desc.base_array_layer,
+ array_layer_count: desc.array_layer_count.map(|ptr| *ptr),
+ },
+ };
+
+ let action = TextureAction::CreateView(id, wgpu_desc);
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_create_sampler(
+ client: &Client,
+ device_id: id::DeviceId,
+ desc: &SamplerDescriptor,
+ bb: &mut ByteBuf,
+) -> id::SamplerId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let id = client
+ .identities
+ .lock()
+ .select(backend)
+ .samplers
+ .process(backend);
+
+ let wgpu_desc = wgc::resource::SamplerDescriptor {
+ label,
+ address_modes: desc.address_modes,
+ mag_filter: desc.mag_filter,
+ min_filter: desc.min_filter,
+ mipmap_filter: desc.mipmap_filter,
+ 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),
+ border_color: None,
+ };
+ let action = DeviceAction::CreateSampler(id, wgpu_desc);
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_make_encoder_id(
+ client: &Client,
+ device_id: id::DeviceId,
+) -> id::CommandEncoderId {
+ let backend = device_id.backend();
+ client
+ .identities
+ .lock()
+ .select(backend)
+ .command_buffers
+ .process(backend)
+ .transmute()
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_create_command_encoder(
+ client: &Client,
+ device_id: id::DeviceId,
+ desc: &wgt::CommandEncoderDescriptor<Option<&nsACString>>,
+ bb: &mut ByteBuf,
+) -> id::CommandEncoderId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let id = client
+ .identities
+ .lock()
+ .select(backend)
+ .command_buffers
+ .process(backend)
+ .transmute();
+
+ let action = DeviceAction::CreateCommandEncoder(id, desc.map_label(|_| label));
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_device_create_render_bundle_encoder(
+ device_id: id::DeviceId,
+ desc: &RenderBundleEncoderDescriptor,
+ bb: &mut ByteBuf,
+) -> *mut wgc::command::RenderBundleEncoder {
+ let label = wgpu_string(desc.label);
+
+ let color_formats: Vec<_> = make_slice(desc.color_formats, desc.color_formats_length)
+ .iter()
+ .map(|format| Some(format.clone()))
+ .collect();
+ let descriptor = wgc::command::RenderBundleEncoderDescriptor {
+ label,
+ color_formats: Cow::Owned(color_formats),
+ depth_stencil: desc
+ .depth_stencil_format
+ .map(|&format| wgt::RenderBundleDepthStencil {
+ format,
+ depth_read_only: desc.depth_read_only,
+ stencil_read_only: desc.stencil_read_only,
+ }),
+ sample_count: desc.sample_count,
+ multiview: None,
+ };
+ match wgc::command::RenderBundleEncoder::new(&descriptor, device_id, None) {
+ Ok(encoder) => Box::into_raw(Box::new(encoder)),
+ Err(e) => {
+ let message = format!("Error in `Device::create_render_bundle_encoder`: {}", e);
+ let action = DeviceAction::Error {
+ message,
+ r#type: e.error_type(),
+ };
+ *bb = make_byte_buf(&action);
+ ptr::null_mut()
+ }
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_render_bundle_encoder_destroy(
+ pass: *mut wgc::command::RenderBundleEncoder,
+) {
+ // The RB encoder is just a boxed Rust struct, it doesn't have any API primitives
+ // associated with it right now, but in the future it will.
+ let _ = Box::from_raw(pass);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_create_render_bundle(
+ client: &Client,
+ encoder: *mut wgc::command::RenderBundleEncoder,
+ device_id: id::DeviceId,
+ desc: &wgt::RenderBundleDescriptor<Option<&nsACString>>,
+ bb: &mut ByteBuf,
+) -> id::RenderBundleId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let id = client
+ .identities
+ .lock()
+ .select(backend)
+ .render_bundles
+ .process(backend);
+
+ let action =
+ DeviceAction::CreateRenderBundle(id, *Box::from_raw(encoder), desc.map_label(|_| label));
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_create_render_bundle_error(
+ client: &Client,
+ device_id: id::DeviceId,
+ label: Option<&nsACString>,
+ bb: &mut ByteBuf,
+) -> id::RenderBundleId {
+ let label = wgpu_string(label);
+
+ let backend = device_id.backend();
+ let id = client
+ .identities
+ .lock()
+ .select(backend)
+ .render_bundles
+ .process(backend);
+
+ let action = DeviceAction::CreateRenderBundleError(id, label);
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[repr(C)]
+pub struct ComputePassDescriptor<'a> {
+ pub label: Option<&'a nsACString>,
+ pub timestamp_writes: Option<&'a ComputePassTimestampWrites<'a>>,
+}
+
+#[repr(C)]
+pub struct ComputePassTimestampWrites<'a> {
+ pub query_set: id::QuerySetId,
+ pub beginning_of_pass_write_index: Option<&'a u32>,
+ pub end_of_pass_write_index: Option<&'a u32>,
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass(
+ encoder_id: id::CommandEncoderId,
+ desc: &ComputePassDescriptor,
+) -> *mut wgc::command::ComputePass {
+ let &ComputePassDescriptor {
+ label,
+ timestamp_writes,
+ } = desc;
+
+ let label = wgpu_string(label);
+
+ let timestamp_writes = timestamp_writes.map(|tsw| {
+ let &ComputePassTimestampWrites {
+ query_set,
+ beginning_of_pass_write_index,
+ end_of_pass_write_index,
+ } = tsw;
+ let beginning_of_pass_write_index = beginning_of_pass_write_index.cloned();
+ let end_of_pass_write_index = end_of_pass_write_index.cloned();
+ wgc::command::ComputePassTimestampWrites {
+ query_set,
+ beginning_of_pass_write_index,
+ end_of_pass_write_index,
+ }
+ });
+ let timestamp_writes = timestamp_writes.as_ref();
+
+ let pass = wgc::command::ComputePass::new(
+ encoder_id,
+ &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,
+ output: &mut ByteBuf,
+) {
+ let command = Box::from_raw(pass).into_command();
+ *output = make_byte_buf(&command);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_compute_pass_destroy(pass: *mut wgc::command::ComputePass) {
+ let _ = Box::from_raw(pass);
+}
+
+#[repr(C)]
+pub struct RenderPassDescriptor<'a> {
+ pub label: Option<&'a nsACString>,
+ pub color_attachments: *const wgc::command::RenderPassColorAttachment,
+ pub color_attachments_length: usize,
+ pub depth_stencil_attachment: *const wgc::command::RenderPassDepthStencilAttachment,
+ pub timestamp_writes: Option<&'a RenderPassTimestampWrites<'a>>,
+ pub occlusion_query_set: Option<wgc::id::QuerySetId>,
+}
+
+#[repr(C)]
+pub struct RenderPassTimestampWrites<'a> {
+ pub query_set: wgc::id::QuerySetId,
+ pub beginning_of_pass_write_index: Option<&'a u32>,
+ pub end_of_pass_write_index: Option<&'a u32>,
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_command_encoder_begin_render_pass(
+ encoder_id: id::CommandEncoderId,
+ desc: &RenderPassDescriptor,
+) -> *mut wgc::command::RenderPass {
+ let &RenderPassDescriptor {
+ label,
+ color_attachments,
+ color_attachments_length,
+ depth_stencil_attachment,
+ timestamp_writes,
+ occlusion_query_set,
+ } = desc;
+
+ let label = wgpu_string(label);
+
+ let timestamp_writes = timestamp_writes.map(|tsw| {
+ let &RenderPassTimestampWrites {
+ query_set,
+ beginning_of_pass_write_index,
+ end_of_pass_write_index,
+ } = tsw;
+ let beginning_of_pass_write_index = beginning_of_pass_write_index.cloned();
+ let end_of_pass_write_index = end_of_pass_write_index.cloned();
+ wgc::command::RenderPassTimestampWrites {
+ query_set,
+ beginning_of_pass_write_index,
+ end_of_pass_write_index,
+ }
+ });
+
+ let timestamp_writes = timestamp_writes.as_ref();
+
+ let color_attachments: Vec<_> = make_slice(color_attachments, color_attachments_length)
+ .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,
+ },
+ );
+ Box::into_raw(Box::new(pass))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_render_pass_finish(
+ pass: *mut wgc::command::RenderPass,
+ output: &mut ByteBuf,
+) {
+ let command = Box::from_raw(pass).into_command();
+ *output = make_byte_buf(&command);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_render_pass_destroy(pass: *mut wgc::command::RenderPass) {
+ let _ = Box::from_raw(pass);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_create_bind_group_layout(
+ client: &Client,
+ device_id: id::DeviceId,
+ desc: &BindGroupLayoutDescriptor,
+ bb: &mut ByteBuf,
+) -> id::BindGroupLayoutId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let id = client
+ .identities
+ .lock()
+ .select(backend)
+ .bind_group_layouts
+ .process(backend);
+
+ let mut entries = Vec::with_capacity(desc.entries_length);
+ for entry in make_slice(desc.entries, desc.entries_length) {
+ entries.push(wgt::BindGroupLayoutEntry {
+ binding: entry.binding,
+ visibility: entry.visibility,
+ count: None,
+ ty: match entry.ty {
+ RawBindingType::UniformBuffer => wgt::BindingType::Buffer {
+ ty: wgt::BufferBindingType::Uniform,
+ has_dynamic_offset: entry.has_dynamic_offset,
+ min_binding_size: entry.min_binding_size,
+ },
+ RawBindingType::StorageBuffer => wgt::BindingType::Buffer {
+ ty: wgt::BufferBindingType::Storage { read_only: false },
+ has_dynamic_offset: entry.has_dynamic_offset,
+ min_binding_size: entry.min_binding_size,
+ },
+ RawBindingType::ReadonlyStorageBuffer => wgt::BindingType::Buffer {
+ ty: wgt::BufferBindingType::Storage { read_only: true },
+ has_dynamic_offset: entry.has_dynamic_offset,
+ min_binding_size: entry.min_binding_size,
+ },
+ RawBindingType::Sampler => wgt::BindingType::Sampler(if entry.sampler_compare {
+ wgt::SamplerBindingType::Comparison
+ } else if entry.sampler_filter {
+ wgt::SamplerBindingType::Filtering
+ } else {
+ wgt::SamplerBindingType::NonFiltering
+ }),
+ RawBindingType::SampledTexture => wgt::BindingType::Texture {
+ //TODO: the spec has a bug here
+ view_dimension: *entry
+ .view_dimension
+ .unwrap_or(&wgt::TextureViewDimension::D2),
+ sample_type: match entry.texture_sample_type {
+ None | Some(RawTextureSampleType::Float) => {
+ wgt::TextureSampleType::Float { filterable: true }
+ }
+ Some(RawTextureSampleType::UnfilterableFloat) => {
+ wgt::TextureSampleType::Float { filterable: false }
+ }
+ Some(RawTextureSampleType::Uint) => wgt::TextureSampleType::Uint,
+ Some(RawTextureSampleType::Sint) => wgt::TextureSampleType::Sint,
+ Some(RawTextureSampleType::Depth) => wgt::TextureSampleType::Depth,
+ },
+ multisampled: entry.multisampled,
+ },
+ RawBindingType::ReadonlyStorageTexture => wgt::BindingType::StorageTexture {
+ access: wgt::StorageTextureAccess::ReadOnly,
+ view_dimension: *entry.view_dimension.unwrap(),
+ format: *entry.storage_texture_format.unwrap(),
+ },
+ RawBindingType::WriteonlyStorageTexture => wgt::BindingType::StorageTexture {
+ access: wgt::StorageTextureAccess::WriteOnly,
+ view_dimension: *entry.view_dimension.unwrap(),
+ format: *entry.storage_texture_format.unwrap(),
+ },
+ },
+ });
+ }
+ let wgpu_desc = wgc::binding_model::BindGroupLayoutDescriptor {
+ label,
+ entries: Cow::Owned(entries),
+ };
+
+ let action = DeviceAction::CreateBindGroupLayout(id, wgpu_desc);
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_render_pipeline_get_bind_group_layout(
+ client: &Client,
+ pipeline_id: id::RenderPipelineId,
+ index: u32,
+ bb: &mut ByteBuf,
+) -> id::BindGroupLayoutId {
+ let backend = pipeline_id.backend();
+ let bgl_id = client
+ .identities
+ .lock()
+ .select(backend)
+ .bind_group_layouts
+ .process(backend);
+
+ let action = DeviceAction::RenderPipelineGetBindGroupLayout(pipeline_id, index, bgl_id);
+ *bb = make_byte_buf(&action);
+
+ bgl_id
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_compute_pipeline_get_bind_group_layout(
+ client: &Client,
+ pipeline_id: id::ComputePipelineId,
+ index: u32,
+ bb: &mut ByteBuf,
+) -> id::BindGroupLayoutId {
+ let backend = pipeline_id.backend();
+ let bgl_id = client
+ .identities
+ .lock()
+ .select(backend)
+ .bind_group_layouts
+ .process(backend);
+
+ let action = DeviceAction::ComputePipelineGetBindGroupLayout(pipeline_id, index, bgl_id);
+ *bb = make_byte_buf(&action);
+
+ bgl_id
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_create_pipeline_layout(
+ client: &Client,
+ device_id: id::DeviceId,
+ desc: &PipelineLayoutDescriptor,
+ bb: &mut ByteBuf,
+) -> id::PipelineLayoutId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let id = client
+ .identities
+ .lock()
+ .select(backend)
+ .pipeline_layouts
+ .process(backend);
+
+ let wgpu_desc = wgc::binding_model::PipelineLayoutDescriptor {
+ label,
+ bind_group_layouts: Cow::Borrowed(make_slice(
+ desc.bind_group_layouts,
+ desc.bind_group_layouts_length,
+ )),
+ push_constant_ranges: Cow::Borrowed(&[]),
+ };
+
+ let action = DeviceAction::CreatePipelineLayout(id, wgpu_desc);
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_create_bind_group(
+ client: &Client,
+ device_id: id::DeviceId,
+ desc: &BindGroupDescriptor,
+ bb: &mut ByteBuf,
+) -> id::BindGroupId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let id = client
+ .identities
+ .lock()
+ .select(backend)
+ .bind_groups
+ .process(backend);
+
+ let mut entries = Vec::with_capacity(desc.entries_length);
+ for entry in make_slice(desc.entries, desc.entries_length) {
+ entries.push(wgc::binding_model::BindGroupEntry {
+ binding: entry.binding,
+ resource: if let Some(id) = entry.buffer {
+ wgc::binding_model::BindingResource::Buffer(wgc::binding_model::BufferBinding {
+ buffer_id: id,
+ offset: entry.offset,
+ size: entry.size,
+ })
+ } else if let Some(id) = entry.sampler {
+ wgc::binding_model::BindingResource::Sampler(id)
+ } else if let Some(id) = entry.texture_view {
+ wgc::binding_model::BindingResource::TextureView(id)
+ } else {
+ panic!("Unexpected binding entry {:?}", entry);
+ },
+ });
+ }
+ let wgpu_desc = wgc::binding_model::BindGroupDescriptor {
+ label,
+ layout: desc.layout,
+ entries: Cow::Owned(entries),
+ };
+
+ let action = DeviceAction::CreateBindGroup(id, wgpu_desc);
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_make_shader_module_id(
+ client: &Client,
+ device_id: id::DeviceId,
+) -> id::ShaderModuleId {
+ let backend = device_id.backend();
+ client
+ .identities
+ .lock()
+ .select(backend)
+ .shader_modules
+ .process(backend)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_create_compute_pipeline(
+ client: &Client,
+ device_id: id::DeviceId,
+ desc: &ComputePipelineDescriptor,
+ bb: &mut ByteBuf,
+ implicit_pipeline_layout_id: *mut Option<id::PipelineLayoutId>,
+ implicit_bind_group_layout_ids: *mut Option<id::BindGroupLayoutId>,
+) -> id::ComputePipelineId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let mut identities = client.identities.lock();
+ let id = identities
+ .select(backend)
+ .compute_pipelines
+ .process(backend);
+
+ let wgpu_desc = wgc::pipeline::ComputePipelineDescriptor {
+ label,
+ layout: desc.layout,
+ stage: desc.stage.to_wgpu(),
+ };
+
+ let implicit = match desc.layout {
+ Some(_) => None,
+ None => {
+ let implicit = ImplicitLayout::new(identities.select(backend), backend);
+ ptr::write(implicit_pipeline_layout_id, Some(implicit.pipeline));
+ for (i, bgl_id) in implicit.bind_groups.iter().enumerate() {
+ *implicit_bind_group_layout_ids.add(i) = *bgl_id;
+ }
+ Some(implicit)
+ }
+ };
+
+ let action = DeviceAction::CreateComputePipeline(id, wgpu_desc, implicit);
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_client_create_render_pipeline(
+ client: &Client,
+ device_id: id::DeviceId,
+ desc: &RenderPipelineDescriptor,
+ bb: &mut ByteBuf,
+ implicit_pipeline_layout_id: *mut Option<id::PipelineLayoutId>,
+ implicit_bind_group_layout_ids: *mut Option<id::BindGroupLayoutId>,
+) -> id::RenderPipelineId {
+ let label = wgpu_string(desc.label);
+
+ let backend = device_id.backend();
+ let mut identities = client.identities.lock();
+ let id = identities.select(backend).render_pipelines.process(backend);
+
+ let wgpu_desc = wgc::pipeline::RenderPipelineDescriptor {
+ label,
+ layout: desc.layout,
+ vertex: desc.vertex.to_wgpu(),
+ fragment: desc.fragment.map(FragmentState::to_wgpu),
+ primitive: desc.primitive.to_wgpu(),
+ depth_stencil: desc.depth_stencil.cloned(),
+ multisample: desc.multisample.clone(),
+ multiview: None,
+ };
+
+ let implicit = match desc.layout {
+ Some(_) => None,
+ None => {
+ let implicit = ImplicitLayout::new(identities.select(backend), backend);
+ ptr::write(implicit_pipeline_layout_id, Some(implicit.pipeline));
+ for (i, bgl_id) in implicit.bind_groups.iter().enumerate() {
+ *implicit_bind_group_layout_ids.add(i) = *bgl_id;
+ }
+ Some(implicit)
+ }
+ };
+
+ let action = DeviceAction::CreateRenderPipeline(id, wgpu_desc, implicit);
+ *bb = make_byte_buf(&action);
+ id
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_command_encoder_copy_buffer_to_buffer(
+ src: id::BufferId,
+ src_offset: wgt::BufferAddress,
+ dst: id::BufferId,
+ dst_offset: wgt::BufferAddress,
+ size: wgt::BufferAddress,
+ bb: &mut ByteBuf,
+) {
+ let action = CommandEncoderAction::CopyBufferToBuffer {
+ src,
+ src_offset,
+ dst,
+ dst_offset,
+ size,
+ };
+ *bb = make_byte_buf(&action);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_command_encoder_copy_texture_to_buffer(
+ src: wgc::command::ImageCopyTexture,
+ dst_buffer: wgc::id::BufferId,
+ dst_layout: &ImageDataLayout,
+ size: wgt::Extent3d,
+ bb: &mut ByteBuf,
+) {
+ let action = CommandEncoderAction::CopyTextureToBuffer {
+ src,
+ dst: wgc::command::ImageCopyBuffer {
+ buffer: dst_buffer,
+ layout: dst_layout.into_wgt(),
+ },
+ size,
+ };
+ *bb = make_byte_buf(&action);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_command_encoder_copy_buffer_to_texture(
+ src_buffer: wgc::id::BufferId,
+ src_layout: &ImageDataLayout,
+ dst: wgc::command::ImageCopyTexture,
+ size: wgt::Extent3d,
+ bb: &mut ByteBuf,
+) {
+ let action = CommandEncoderAction::CopyBufferToTexture {
+ src: wgc::command::ImageCopyBuffer {
+ buffer: src_buffer,
+ layout: src_layout.into_wgt(),
+ },
+ dst,
+ size,
+ };
+ *bb = make_byte_buf(&action);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_command_encoder_copy_texture_to_texture(
+ src: wgc::command::ImageCopyTexture,
+ dst: wgc::command::ImageCopyTexture,
+ size: wgt::Extent3d,
+ bb: &mut ByteBuf,
+) {
+ let action = CommandEncoderAction::CopyTextureToTexture { src, dst, size };
+ *bb = make_byte_buf(&action);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_command_encoder_clear_buffer(
+ dst: wgc::id::BufferId,
+ offset: u64,
+ size: Option<&u64>,
+ bb: &mut ByteBuf,
+) {
+ let action = CommandEncoderAction::ClearBuffer {
+ dst,
+ offset,
+ size: size.cloned(),
+ };
+ *bb = make_byte_buf(&action);
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_command_encoder_push_debug_group(marker: &nsACString, bb: &mut ByteBuf) {
+ let string = marker.to_string();
+ let action = CommandEncoderAction::PushDebugGroup(string);
+ *bb = make_byte_buf(&action);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_command_encoder_pop_debug_group(bb: &mut ByteBuf) {
+ let action = CommandEncoderAction::PopDebugGroup;
+ *bb = make_byte_buf(&action);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_command_encoder_insert_debug_marker(
+ marker: &nsACString,
+ bb: &mut ByteBuf,
+) {
+ let string = marker.to_string();
+ let action = CommandEncoderAction::InsertDebugMarker(string);
+ *bb = make_byte_buf(&action);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_queue_write_buffer(
+ dst: id::BufferId,
+ offset: wgt::BufferAddress,
+ bb: &mut ByteBuf,
+) {
+ let action = QueueWriteAction::Buffer { dst, offset };
+ *bb = make_byte_buf(&action);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn wgpu_queue_write_texture(
+ dst: wgt::ImageCopyTexture<id::TextureId>,
+ layout: ImageDataLayout,
+ size: wgt::Extent3d,
+ bb: &mut ByteBuf,
+) {
+ let layout = layout.into_wgt();
+ let action = QueueWriteAction::Texture { dst, layout, size };
+ *bb = make_byte_buf(&action);
+}
+
+/// Returns the block size or zero if the format has multiple aspects (for example depth+stencil).
+#[no_mangle]
+pub extern "C" fn wgpu_texture_format_block_size_single_aspect(format: wgt::TextureFormat) -> u32 {
+ format.block_copy_size(None).unwrap_or(0)
+}
+
+#[no_mangle]
+pub extern "C" fn wgpu_client_use_external_texture_in_swapChain(
+ device_id: id::DeviceId,
+ format: wgt::TextureFormat,
+) -> bool {
+ if device_id.backend() != wgt::Backend::Dx12 {
+ return false;
+ }
+
+ if !static_prefs::pref!("dom.webgpu.swap-chain.external-texture-dx12") {
+ return false;
+ }
+
+ let supported = match format {
+ wgt::TextureFormat::Bgra8Unorm => true,
+ _ => false,
+ };
+
+ supported
+}