tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

client.rs (72870B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use crate::{
      6    cow_label, wgpu_string, AdapterInformation, ByteBuf, CommandEncoderAction, DeviceAction,
      7    FfiSlice, QueueWriteAction, RawString, TexelCopyBufferLayout, TextureAction,
      8 };
      9 
     10 use crate::{BufferMapResult, Message, QueueWriteDataSource, ServerMessage, SwapChainId};
     11 
     12 use wgc::naga::front::wgsl::ImplementedLanguageExtension;
     13 use wgc::{command::RenderBundleEncoder, id, identity::IdentityManager};
     14 use wgt::{
     15    error::WebGpuError, BufferAddress, BufferSize, DynamicOffset, IndexFormat, TextureFormat,
     16 };
     17 
     18 use wgc::id::markers;
     19 
     20 use parking_lot::Mutex;
     21 
     22 use nsstring::{nsACString, nsCString, nsString};
     23 
     24 use std::array;
     25 use std::fmt::Write;
     26 use std::{borrow::Cow, ptr};
     27 
     28 use self::render_pass::{FfiRenderPassColorAttachment, RenderPassDepthStencilAttachment};
     29 
     30 pub mod render_pass;
     31 
     32 #[repr(C)]
     33 pub struct ConstantEntry {
     34    key: RawString,
     35    value: f64,
     36 }
     37 
     38 #[repr(C)]
     39 pub struct ProgrammableStageDescriptor<'a> {
     40    module: id::ShaderModuleId,
     41    entry_point: RawString,
     42    constants: FfiSlice<'a, ConstantEntry>,
     43 }
     44 
     45 impl ProgrammableStageDescriptor<'_> {
     46    fn to_wgpu(&self) -> wgc::pipeline::ProgrammableStageDescriptor<'_> {
     47        let constants = unsafe { self.constants.as_slice() }
     48            .iter()
     49            .map(|ce| {
     50                (
     51                    unsafe { std::ffi::CStr::from_ptr(ce.key) }
     52                        .to_str()
     53                        .unwrap()
     54                        .to_string(),
     55                    ce.value,
     56                )
     57            })
     58            .collect();
     59        wgc::pipeline::ProgrammableStageDescriptor {
     60            module: self.module,
     61            entry_point: cow_label(&self.entry_point),
     62            constants,
     63            zero_initialize_workgroup_memory: true,
     64        }
     65    }
     66 }
     67 
     68 #[repr(C)]
     69 pub struct ComputePipelineDescriptor<'a> {
     70    label: Option<&'a nsACString>,
     71    layout: Option<id::PipelineLayoutId>,
     72    stage: ProgrammableStageDescriptor<'a>,
     73 }
     74 
     75 #[repr(C)]
     76 pub struct VertexBufferLayout<'a> {
     77    array_stride: wgt::BufferAddress,
     78    step_mode: wgt::VertexStepMode,
     79    attributes: FfiSlice<'a, wgt::VertexAttribute>,
     80 }
     81 
     82 #[repr(C)]
     83 pub struct VertexState<'a> {
     84    stage: ProgrammableStageDescriptor<'a>,
     85    buffers: FfiSlice<'a, VertexBufferLayout<'a>>,
     86 }
     87 
     88 impl VertexState<'_> {
     89    fn to_wgpu(&self) -> wgc::pipeline::VertexState<'_> {
     90        let buffer_layouts = unsafe { self.buffers.as_slice() }
     91            .iter()
     92            .map(|vb| wgc::pipeline::VertexBufferLayout {
     93                array_stride: vb.array_stride,
     94                step_mode: vb.step_mode,
     95                attributes: Cow::Borrowed(unsafe { vb.attributes.as_slice() }),
     96            })
     97            .collect();
     98        wgc::pipeline::VertexState {
     99            stage: self.stage.to_wgpu(),
    100            buffers: Cow::Owned(buffer_layouts),
    101        }
    102    }
    103 }
    104 
    105 #[repr(C)]
    106 pub struct ColorTargetState<'a> {
    107    format: wgt::TextureFormat,
    108    blend: Option<&'a wgt::BlendState>,
    109    write_mask: wgt::ColorWrites,
    110 }
    111 
    112 #[repr(C)]
    113 pub struct FragmentState<'a> {
    114    stage: ProgrammableStageDescriptor<'a>,
    115    targets: FfiSlice<'a, ColorTargetState<'a>>,
    116 }
    117 
    118 impl FragmentState<'_> {
    119    fn to_wgpu(&self) -> wgc::pipeline::FragmentState<'_> {
    120        let color_targets = unsafe { self.targets.as_slice() }
    121            .iter()
    122            .map(|ct| {
    123                Some(wgt::ColorTargetState {
    124                    format: ct.format,
    125                    blend: ct.blend.cloned(),
    126                    write_mask: ct.write_mask,
    127                })
    128            })
    129            .collect();
    130        wgc::pipeline::FragmentState {
    131            stage: self.stage.to_wgpu(),
    132            targets: Cow::Owned(color_targets),
    133        }
    134    }
    135 }
    136 
    137 #[repr(C)]
    138 pub struct PrimitiveState<'a> {
    139    topology: wgt::PrimitiveTopology,
    140    strip_index_format: Option<&'a wgt::IndexFormat>,
    141    front_face: wgt::FrontFace,
    142    cull_mode: Option<&'a wgt::Face>,
    143    polygon_mode: wgt::PolygonMode,
    144    unclipped_depth: bool,
    145 }
    146 
    147 impl PrimitiveState<'_> {
    148    fn to_wgpu(&self) -> wgt::PrimitiveState {
    149        wgt::PrimitiveState {
    150            topology: self.topology,
    151            strip_index_format: self.strip_index_format.cloned(),
    152            front_face: self.front_face.clone(),
    153            cull_mode: self.cull_mode.cloned(),
    154            polygon_mode: self.polygon_mode,
    155            unclipped_depth: self.unclipped_depth,
    156            conservative: false,
    157        }
    158    }
    159 }
    160 
    161 #[repr(C)]
    162 pub struct RenderPipelineDescriptor<'a> {
    163    label: Option<&'a nsACString>,
    164    layout: Option<id::PipelineLayoutId>,
    165    vertex: &'a VertexState<'a>,
    166    primitive: PrimitiveState<'a>,
    167    fragment: Option<&'a FragmentState<'a>>,
    168    depth_stencil: Option<&'a wgt::DepthStencilState>,
    169    multisample: wgt::MultisampleState,
    170 }
    171 
    172 #[repr(C)]
    173 pub enum RawTextureSampleType {
    174    Float,
    175    UnfilterableFloat,
    176    Uint,
    177    Sint,
    178    Depth,
    179 }
    180 
    181 #[repr(C)]
    182 pub enum RawBindingType {
    183    UniformBuffer,
    184    StorageBuffer,
    185    ReadonlyStorageBuffer,
    186    Sampler,
    187    SampledTexture,
    188    ReadonlyStorageTexture,
    189    WriteonlyStorageTexture,
    190    ReadWriteStorageTexture,
    191    ExternalTexture,
    192 }
    193 
    194 #[repr(C)]
    195 pub struct BindGroupLayoutEntry<'a> {
    196    binding: u32,
    197    visibility: wgt::ShaderStages,
    198    ty: RawBindingType,
    199    has_dynamic_offset: bool,
    200    min_binding_size: Option<wgt::BufferSize>,
    201    view_dimension: Option<&'a wgt::TextureViewDimension>,
    202    texture_sample_type: Option<&'a RawTextureSampleType>,
    203    multisampled: bool,
    204    storage_texture_format: Option<&'a wgt::TextureFormat>,
    205    sampler_filter: bool,
    206    sampler_compare: bool,
    207 }
    208 
    209 #[repr(C)]
    210 pub struct BindGroupLayoutDescriptor<'a> {
    211    label: Option<&'a nsACString>,
    212    entries: FfiSlice<'a, BindGroupLayoutEntry<'a>>,
    213 }
    214 
    215 #[repr(C)]
    216 #[derive(Debug)]
    217 pub struct BindGroupEntry {
    218    binding: u32,
    219    buffer: Option<id::BufferId>,
    220    offset: wgt::BufferAddress,
    221 
    222    // In `wgpu_core::binding_model::BufferBinding`, these are an
    223    // `Option<BufferAddress>`. But since `BufferAddress` can be zero, that is
    224    // not a type that cbindgen can express in C++, so we use this pair of
    225    // values instead.
    226    size_passed: bool,
    227    size: wgt::BufferAddress,
    228 
    229    sampler: Option<id::SamplerId>,
    230    texture_view: Option<id::TextureViewId>,
    231    external_texture: Option<id::ExternalTextureId>,
    232 }
    233 
    234 #[repr(C)]
    235 pub struct BindGroupDescriptor<'a> {
    236    label: Option<&'a nsACString>,
    237    layout: id::BindGroupLayoutId,
    238    entries: FfiSlice<'a, BindGroupEntry>,
    239 }
    240 
    241 #[repr(C)]
    242 pub struct PipelineLayoutDescriptor<'a> {
    243    label: Option<&'a nsACString>,
    244    bind_group_layouts: FfiSlice<'a, id::BindGroupLayoutId>,
    245 }
    246 
    247 #[repr(C)]
    248 pub struct SamplerDescriptor<'a> {
    249    label: Option<&'a nsACString>,
    250    address_modes: [wgt::AddressMode; 3],
    251    mag_filter: wgt::FilterMode,
    252    min_filter: wgt::FilterMode,
    253    mipmap_filter: wgt::MipmapFilterMode,
    254    lod_min_clamp: f32,
    255    lod_max_clamp: f32,
    256    compare: Option<&'a wgt::CompareFunction>,
    257    max_anisotropy: u16,
    258 }
    259 
    260 #[repr(C)]
    261 pub struct RenderBundleEncoderDescriptor<'a> {
    262    label: Option<&'a nsACString>,
    263    color_formats: FfiSlice<'a, wgt::TextureFormat>,
    264    depth_stencil_format: Option<&'a wgt::TextureFormat>,
    265    depth_read_only: bool,
    266    stencil_read_only: bool,
    267    sample_count: u32,
    268 }
    269 
    270 #[derive(Debug)]
    271 struct IdentityHub {
    272    adapters: IdentityManager<markers::Adapter>,
    273    devices: IdentityManager<markers::Device>,
    274    queues: IdentityManager<markers::Queue>,
    275    buffers: IdentityManager<markers::Buffer>,
    276    command_encoders: IdentityManager<markers::CommandEncoder>,
    277    render_pass_encoders: IdentityManager<markers::RenderPassEncoder>,
    278    compute_pass_encoders: IdentityManager<markers::ComputePassEncoder>,
    279    render_bundle_encoders: IdentityManager<markers::RenderBundleEncoder>,
    280    command_buffers: IdentityManager<markers::CommandBuffer>,
    281    render_bundles: IdentityManager<markers::RenderBundle>,
    282    bind_group_layouts: IdentityManager<markers::BindGroupLayout>,
    283    pipeline_layouts: IdentityManager<markers::PipelineLayout>,
    284    bind_groups: IdentityManager<markers::BindGroup>,
    285    shader_modules: IdentityManager<markers::ShaderModule>,
    286    compute_pipelines: IdentityManager<markers::ComputePipeline>,
    287    render_pipelines: IdentityManager<markers::RenderPipeline>,
    288    textures: IdentityManager<markers::Texture>,
    289    texture_views: IdentityManager<markers::TextureView>,
    290    external_texture_sources: IdentityManager<crate::ExternalTextureSource>,
    291    external_textures: IdentityManager<markers::ExternalTexture>,
    292    samplers: IdentityManager<markers::Sampler>,
    293    query_sets: IdentityManager<markers::QuerySet>,
    294 }
    295 
    296 impl Default for IdentityHub {
    297    fn default() -> Self {
    298        IdentityHub {
    299            adapters: IdentityManager::new(),
    300            devices: IdentityManager::new(),
    301            queues: IdentityManager::new(),
    302            buffers: IdentityManager::new(),
    303            command_encoders: IdentityManager::new(),
    304            render_pass_encoders: IdentityManager::new(),
    305            compute_pass_encoders: IdentityManager::new(),
    306            render_bundle_encoders: IdentityManager::new(),
    307            command_buffers: IdentityManager::new(),
    308            render_bundles: IdentityManager::new(),
    309            bind_group_layouts: IdentityManager::new(),
    310            pipeline_layouts: IdentityManager::new(),
    311            bind_groups: IdentityManager::new(),
    312            shader_modules: IdentityManager::new(),
    313            compute_pipelines: IdentityManager::new(),
    314            render_pipelines: IdentityManager::new(),
    315            textures: IdentityManager::new(),
    316            texture_views: IdentityManager::new(),
    317            external_texture_sources: IdentityManager::new(),
    318            external_textures: IdentityManager::new(),
    319            samplers: IdentityManager::new(),
    320            query_sets: IdentityManager::new(),
    321        }
    322    }
    323 }
    324 
    325 /// Opaque pointer to `mozilla::webgpu::WebGPUChild`.
    326 #[derive(Debug, Clone, Copy)]
    327 #[repr(transparent)]
    328 pub struct WebGPUChildPtr(*mut core::ffi::c_void);
    329 
    330 #[derive(Debug)]
    331 pub struct Client {
    332    owner: WebGPUChildPtr,
    333    message_queue: Mutex<MessageQueue>,
    334    identities: Mutex<IdentityHub>,
    335 }
    336 
    337 impl Client {
    338    fn queue_message(&self, message: &Message) {
    339        let mut message_queue = self.message_queue.lock();
    340        message_queue.push(self.owner, message);
    341    }
    342    fn get_serialized_messages(&self) -> (u32, Vec<u8>) {
    343        let mut message_queue = self.message_queue.lock();
    344        message_queue.flush()
    345    }
    346 }
    347 
    348 #[derive(Debug)]
    349 struct MessageQueue {
    350    on_message_queued: extern "C" fn(WebGPUChildPtr),
    351 
    352    serialized_messages: std::io::Cursor<Vec<u8>>,
    353    nr_of_queued_messages: u32,
    354 }
    355 
    356 impl MessageQueue {
    357    fn new(on_message_queued: extern "C" fn(WebGPUChildPtr)) -> Self {
    358        Self {
    359            on_message_queued,
    360            serialized_messages: std::io::Cursor::new(Vec::new()),
    361            nr_of_queued_messages: 0,
    362        }
    363    }
    364 
    365    fn push(&mut self, child: WebGPUChildPtr, message: &Message) {
    366        use bincode::Options;
    367        let options = bincode::DefaultOptions::new()
    368            .with_fixint_encoding()
    369            .allow_trailing_bytes();
    370        let mut serializer = bincode::Serializer::new(&mut self.serialized_messages, options);
    371 
    372        use serde::Serialize;
    373        message.serialize(&mut serializer).unwrap();
    374 
    375        self.nr_of_queued_messages = self.nr_of_queued_messages.checked_add(1).unwrap();
    376        (self.on_message_queued)(child);
    377 
    378        // Force send when we have queued up at least 4k messages.
    379        // We must comply with some static limits:
    380        //   - `IPC::Message::MAX_DESCRIPTORS_PER_MESSAGE` (32767): currently,
    381        //     no message can refer to more than one shmem handle; 4k is well below 32k.
    382        //   - `IPC::Channel::kMaximumMessageSize` (256 * 1024 * 1024, when fuzzing):
    383        //     with a limit of 4k messages, each message can be up to 64KiB; while we have
    384        //     some messages that can have arbitrary size (ex. `CreateShaderModule`) most
    385        //     have a static size.
    386        // If we ever violate the limits, the worst that can happen is that we trigger asserts.
    387        if self.nr_of_queued_messages >= 4 * 1024 {
    388            let (nr_of_messages, serialized_messages) = self.flush();
    389            let serialized_messages = ByteBuf::from_vec(serialized_messages);
    390            unsafe { wgpu_child_send_messages(child, nr_of_messages, serialized_messages) };
    391        }
    392    }
    393 
    394    fn flush(&mut self) -> (u32, Vec<u8>) {
    395        let nr_of_messages = self.nr_of_queued_messages;
    396        self.nr_of_queued_messages = 0;
    397        (
    398            nr_of_messages,
    399            core::mem::take(&mut self.serialized_messages).into_inner(),
    400        )
    401    }
    402 }
    403 
    404 #[no_mangle]
    405 pub extern "C" fn wgpu_client_get_queued_messages(
    406    client: &Client,
    407    serialized_messages_bb: &mut ByteBuf,
    408 ) -> u32 {
    409    let (nr_of_messages, serialized_messages) = client.get_serialized_messages();
    410    *serialized_messages_bb = ByteBuf::from_vec(serialized_messages);
    411    nr_of_messages
    412 }
    413 
    414 #[no_mangle]
    415 pub extern "C" fn wgpu_client_new(
    416    owner: WebGPUChildPtr,
    417    on_message_queued: extern "C" fn(WebGPUChildPtr),
    418 ) -> *mut Client {
    419    log::info!("Initializing WGPU client");
    420    let client = Client {
    421        owner,
    422        message_queue: Mutex::new(MessageQueue::new(on_message_queued)),
    423        identities: Mutex::new(IdentityHub::default()),
    424    };
    425    Box::into_raw(Box::new(client))
    426 }
    427 
    428 /// # Safety
    429 ///
    430 /// This function is unsafe because improper use may lead to memory
    431 /// problems. For example, a double-free may occur if the function is called
    432 /// twice on the same raw pointer.
    433 #[no_mangle]
    434 pub unsafe extern "C" fn wgpu_client_delete(client: *mut Client) {
    435    log::info!("Terminating WGPU client");
    436    let _client = Box::from_raw(client);
    437 }
    438 
    439 #[no_mangle]
    440 pub extern "C" fn wgpu_client_fill_default_limits(limits: &mut wgt::Limits) {
    441    *limits = wgt::Limits::default();
    442 }
    443 
    444 /// Writes the single `WGSLLanguageFeature` associated with `index`, appending its identifier to the
    445 /// provided `buffer`. If `index` does not correspond to a valid feature index, then do nothing.
    446 ///
    447 /// This function enables an FFI consumer to extract all implemented features in a loop, like so:
    448 ///
    449 /// ```rust
    450 /// let mut buffer = nsstring::nsCString::new();
    451 /// for index in 0usize.. {
    452 ///     buffer.truncate();
    453 ///     wgpu_client_instance_get_wgsl_language_feature(&mut buffer, index);
    454 ///     if buffer.is_empty() {
    455 ///         break;
    456 ///     }
    457 ///     // Handle the identifier in `buffer`…
    458 /// }
    459 /// ```
    460 #[no_mangle]
    461 pub extern "C" fn wgpu_client_instance_get_wgsl_language_feature(
    462    buffer: &mut nsstring::nsCString,
    463    index: usize,
    464 ) {
    465    match ImplementedLanguageExtension::all().get(index) {
    466        Some(some) => buffer.write_str(some.to_ident()).unwrap(),
    467        None => (),
    468    }
    469 }
    470 
    471 #[repr(C)]
    472 pub struct FfiDeviceDescriptor<'a> {
    473    pub label: Option<&'a nsACString>,
    474    pub required_features: wgt::FeaturesWebGPU,
    475    pub required_limits: wgt::Limits,
    476 }
    477 
    478 #[repr(C)]
    479 pub struct DeviceQueueId {
    480    device: id::DeviceId,
    481    queue: id::QueueId,
    482 }
    483 
    484 #[no_mangle]
    485 pub extern "C" fn wgpu_client_request_device(
    486    client: &Client,
    487    adapter_id: id::AdapterId,
    488    desc: &FfiDeviceDescriptor,
    489 ) -> DeviceQueueId {
    490    let identities = client.identities.lock();
    491    let device_id = identities.devices.process();
    492    let queue_id = identities.queues.process();
    493    drop(identities);
    494 
    495    let label = wgpu_string(desc.label);
    496    let required_features =
    497        wgt::Features::from_internal_flags(wgt::FeaturesWGPU::empty(), desc.required_features);
    498    let desc = wgt::DeviceDescriptor {
    499        label,
    500        required_features,
    501        required_limits: desc.required_limits.clone(),
    502        memory_hints: wgt::MemoryHints::MemoryUsage,
    503        // The content process is untrusted, so this value is ignored
    504        // by the GPU process. The GPU process overwrites this with
    505        // the result of consulting the `WGPU_TRACE` environment
    506        // variable itself in `wgpu_server_adapter_request_device`.
    507        trace: wgt::Trace::Off,
    508        // The content process is untrusted, so this value is ignored
    509        // by the GPU process. The GPU process overwrites this with
    510        // `ExperimentalFeatures::disabled()`.
    511        experimental_features: wgt::ExperimentalFeatures::disabled(),
    512    };
    513    let message = Message::RequestDevice {
    514        adapter_id,
    515        device_id,
    516        queue_id,
    517        desc,
    518    };
    519    client.queue_message(&message);
    520    DeviceQueueId {
    521        device: device_id,
    522        queue: queue_id,
    523    }
    524 }
    525 
    526 #[no_mangle]
    527 pub extern "C" fn wgpu_client_make_render_pass_encoder_id(
    528    client: &Client,
    529 ) -> id::RenderPassEncoderId {
    530    client.identities.lock().render_pass_encoders.process()
    531 }
    532 #[no_mangle]
    533 pub extern "C" fn wgpu_client_make_compute_pass_encoder_id(
    534    client: &Client,
    535 ) -> id::ComputePassEncoderId {
    536    client.identities.lock().compute_pass_encoders.process()
    537 }
    538 #[no_mangle]
    539 pub extern "C" fn wgpu_client_make_render_bundle_encoder_id(
    540    client: &Client,
    541 ) -> id::RenderBundleEncoderId {
    542    client.identities.lock().render_bundle_encoders.process()
    543 }
    544 
    545 #[rustfmt::skip]
    546 mod drop {
    547    use super::*;
    548 
    549    #[no_mangle] pub extern "C" fn wgpu_client_destroy_buffer(client: &Client, id: id::BufferId) { client.queue_message(&Message::DestroyBuffer(id)); }
    550    #[no_mangle] pub extern "C" fn wgpu_client_destroy_texture(client: &Client, id: id::TextureId) { client.queue_message(&Message::DestroyTexture(id)); }
    551    #[no_mangle] pub extern "C" fn wgpu_client_destroy_external_texture(client: &Client, id: id::ExternalTextureId) { client.queue_message(&Message::DestroyExternalTexture(id)); }
    552    #[no_mangle] pub extern "C" fn wgpu_client_destroy_external_texture_source(client: &Client, id: crate::ExternalTextureSourceId) { client.queue_message(&&Message::DestroyExternalTextureSource(id)); }
    553    #[no_mangle] pub extern "C" fn wgpu_client_destroy_device(client: &Client, id: id::DeviceId) { client.queue_message(&Message::DestroyDevice(id)); }
    554 
    555    #[no_mangle] pub extern "C" fn wgpu_client_drop_adapter(client: &Client, id: id::AdapterId) { client.queue_message(&Message::DropAdapter(id)); client.identities.lock().adapters.free(id); }
    556    #[no_mangle] pub extern "C" fn wgpu_client_drop_device(client: &Client, id: id::DeviceId) { client.queue_message(&Message::DropDevice(id)); client.identities.lock().devices.free(id); }
    557    #[no_mangle] pub extern "C" fn wgpu_client_drop_queue(client: &Client, id: id::QueueId) { client.queue_message(&Message::DropQueue(id)); client.identities.lock().queues.free(id); }
    558    #[no_mangle] pub extern "C" fn wgpu_client_drop_buffer(client: &Client, id: id::BufferId) { client.queue_message(&Message::DropBuffer(id)); client.identities.lock().buffers.free(id); }
    559    #[no_mangle] pub extern "C" fn wgpu_client_drop_command_encoder(client: &Client, id: id::CommandEncoderId) { client.queue_message(&Message::DropCommandEncoder(id)); client.identities.lock().command_encoders.free(id); }
    560    #[no_mangle] pub extern "C" fn wgpu_client_drop_render_pass_encoder(client: &Client, id: id::RenderPassEncoderId) { client.queue_message(&Message::DropRenderPassEncoder(id)); client.identities.lock().render_pass_encoders.free(id); }
    561    #[no_mangle] pub extern "C" fn wgpu_client_drop_compute_pass_encoder(client: &Client, id: id::ComputePassEncoderId) { client.queue_message(&Message::DropComputePassEncoder(id)); client.identities.lock().compute_pass_encoders.free(id); }
    562    #[no_mangle] pub extern "C" fn wgpu_client_drop_render_bundle_encoder(client: &Client, id: id::RenderBundleEncoderId) { client.queue_message(&Message::DropRenderBundleEncoder(id)); client.identities.lock().render_bundle_encoders.free(id); }
    563    #[no_mangle] pub extern "C" fn wgpu_client_drop_command_buffer(client: &Client, id: id::CommandBufferId) { client.queue_message(&Message::DropCommandBuffer(id)); client.identities.lock().command_buffers.free(id); }
    564    #[no_mangle] pub extern "C" fn wgpu_client_drop_render_bundle(client: &Client, id: id::RenderBundleId) { client.queue_message(&Message::DropRenderBundle(id)); client.identities.lock().render_bundles.free(id); }
    565    #[no_mangle] pub extern "C" fn wgpu_client_drop_bind_group_layout(client: &Client, id: id::BindGroupLayoutId) { client.queue_message(&Message::DropBindGroupLayout(id)); client.identities.lock().bind_group_layouts.free(id); }
    566    #[no_mangle] pub extern "C" fn wgpu_client_drop_pipeline_layout(client: &Client, id: id::PipelineLayoutId) { client.queue_message(&Message::DropPipelineLayout(id)); client.identities.lock().pipeline_layouts.free(id); }
    567    #[no_mangle] pub extern "C" fn wgpu_client_drop_bind_group(client: &Client, id: id::BindGroupId) { client.queue_message(&Message::DropBindGroup(id)); client.identities.lock().bind_groups.free(id); }
    568    #[no_mangle] pub extern "C" fn wgpu_client_drop_shader_module(client: &Client, id: id::ShaderModuleId) { client.queue_message(&Message::DropShaderModule(id)); client.identities.lock().shader_modules.free(id); }
    569    #[no_mangle] pub extern "C" fn wgpu_client_drop_compute_pipeline(client: &Client, id: id::ComputePipelineId) { client.queue_message(&Message::DropComputePipeline(id)); client.identities.lock().compute_pipelines.free(id); }
    570    #[no_mangle] pub extern "C" fn wgpu_client_drop_render_pipeline(client: &Client, id: id::RenderPipelineId) { client.queue_message(&Message::DropRenderPipeline(id)); client.identities.lock().render_pipelines.free(id); }
    571    #[no_mangle] pub extern "C" fn wgpu_client_drop_texture(client: &Client, id: id::TextureId) { client.queue_message(&Message::DropTexture(id)); client.identities.lock().textures.free(id); }
    572    #[no_mangle] pub extern "C" fn wgpu_client_drop_texture_view(client: &Client, id: id::TextureViewId) { client.queue_message(&Message::DropTextureView(id)); client.identities.lock().texture_views.free(id); }
    573    #[no_mangle] pub extern "C" fn wgpu_client_drop_external_texture(client: &Client, id: id::ExternalTextureId) { client.queue_message(&Message::DropExternalTexture(id)); client.identities.lock().external_textures.free(id); }
    574    #[no_mangle] pub extern "C" fn wgpu_client_drop_external_texture_source(client: &Client, id: crate::ExternalTextureSourceId) { client.queue_message(&Message::DropExternalTextureSource(id)); client.identities.lock().external_texture_sources.free(id); }
    575    #[no_mangle] pub extern "C" fn wgpu_client_drop_sampler(client: &Client, id: id::SamplerId) { client.queue_message(&Message::DropSampler(id)); client.identities.lock().samplers.free(id); }
    576    #[no_mangle] pub extern "C" fn wgpu_client_drop_query_set(client: &Client, id: id::QuerySetId) { client.queue_message(&Message::DropQuerySet(id)); client.identities.lock().query_sets.free(id); }
    577 }
    578 
    579 #[repr(C)]
    580 pub struct FfiShaderModuleCompilationMessage {
    581    pub line_number: u64,
    582    pub line_pos: u64,
    583    pub utf16_offset: u64,
    584    pub utf16_length: u64,
    585    pub message: nsString,
    586 }
    587 
    588 extern "C" {
    589    fn wgpu_child_send_messages(
    590        child: WebGPUChildPtr,
    591        nr_of_messages: u32,
    592        serialized_messages: ByteBuf,
    593    );
    594    fn wgpu_child_resolve_request_adapter_promise(
    595        child: WebGPUChildPtr,
    596        adapter_id: id::AdapterId,
    597        adapter_info: Option<&AdapterInformation<nsString>>,
    598    );
    599    fn wgpu_child_resolve_request_device_promise(
    600        child: WebGPUChildPtr,
    601        device_id: id::DeviceId,
    602        queue_id: id::QueueId,
    603        error: Option<&nsCString>,
    604    );
    605    fn wgpu_child_resolve_pop_error_scope_promise(
    606        child: WebGPUChildPtr,
    607        device_id: id::DeviceId,
    608        ty: u8,
    609        message: &nsCString,
    610    );
    611    fn wgpu_child_resolve_create_pipeline_promise(
    612        child: WebGPUChildPtr,
    613        pipeline_id: id::RawId,
    614        is_render_pipeline: bool,
    615        is_validation_error: bool,
    616        error: Option<&nsCString>,
    617    );
    618    fn wgpu_child_resolve_create_shader_module_promise(
    619        child: WebGPUChildPtr,
    620        shader_module_id: id::ShaderModuleId,
    621        messages: FfiSlice<FfiShaderModuleCompilationMessage>,
    622    );
    623    fn wgpu_child_resolve_buffer_map_promise(
    624        child: WebGPUChildPtr,
    625        buffer_id: id::BufferId,
    626        is_writable: bool,
    627        offset: u64,
    628        size: u64,
    629        error: Option<&nsCString>,
    630    );
    631    fn wgpu_child_resolve_on_submitted_work_done_promise(
    632        child: WebGPUChildPtr,
    633        queue_id: id::QueueId,
    634    );
    635 }
    636 
    637 #[no_mangle]
    638 pub extern "C" fn wgpu_client_receive_server_message(client: &Client, byte_buf: &ByteBuf) {
    639    let message: ServerMessage = bincode::deserialize(unsafe { byte_buf.as_slice() }).unwrap();
    640    match message {
    641        ServerMessage::RequestAdapterResponse(adapter_id, adapter_information) => {
    642            if let Some(AdapterInformation {
    643                backend,
    644                device_type,
    645                device,
    646                driver_info,
    647                driver,
    648                features,
    649                id,
    650                limits,
    651                name,
    652                vendor,
    653                support_use_shared_texture_in_swap_chain,
    654                transient_saves_memory,
    655                subgroup_min_size,
    656                subgroup_max_size,
    657            }) = adapter_information
    658            {
    659                let nss = |s: &str| {
    660                    let mut ns_string = nsString::new();
    661                    ns_string.assign_str(s);
    662                    ns_string
    663                };
    664                let adapter_info = AdapterInformation {
    665                    backend,
    666                    device_type,
    667                    device,
    668                    driver_info: nss(&driver_info),
    669                    driver: nss(&driver),
    670                    features,
    671                    id,
    672                    limits,
    673                    name: nss(&name),
    674                    vendor,
    675                    support_use_shared_texture_in_swap_chain,
    676                    transient_saves_memory,
    677                    subgroup_min_size,
    678                    subgroup_max_size,
    679                };
    680                unsafe {
    681                    wgpu_child_resolve_request_adapter_promise(
    682                        client.owner,
    683                        adapter_id,
    684                        Some(&adapter_info),
    685                    );
    686                }
    687            } else {
    688                unsafe {
    689                    wgpu_child_resolve_request_adapter_promise(client.owner, adapter_id, None);
    690                }
    691                client.identities.lock().adapters.free(adapter_id)
    692            }
    693        }
    694        ServerMessage::RequestDeviceResponse(device_id, queue_id, error) => {
    695            if let Some(error) = error {
    696                let error = nsCString::from(error);
    697                unsafe {
    698                    wgpu_child_resolve_request_device_promise(
    699                        client.owner,
    700                        device_id,
    701                        queue_id,
    702                        Some(&error),
    703                    );
    704                }
    705                let identities = client.identities.lock();
    706                identities.devices.free(device_id);
    707                identities.queues.free(queue_id);
    708            } else {
    709                unsafe {
    710                    wgpu_child_resolve_request_device_promise(
    711                        client.owner,
    712                        device_id,
    713                        queue_id,
    714                        None,
    715                    );
    716                }
    717            }
    718        }
    719        ServerMessage::PopErrorScopeResponse(device_id, ty, message) => {
    720            let message = nsCString::from(message.as_ref());
    721            unsafe {
    722                wgpu_child_resolve_pop_error_scope_promise(client.owner, device_id, ty, &message);
    723            }
    724        }
    725        ServerMessage::CreateRenderPipelineResponse { pipeline_id, error } => {
    726            let is_render_pipeline = true;
    727            if let Some(error) = error {
    728                let ns_error = nsCString::from(error.error);
    729                unsafe {
    730                    wgpu_child_resolve_create_pipeline_promise(
    731                        client.owner,
    732                        pipeline_id.into_raw(),
    733                        is_render_pipeline,
    734                        error.is_validation_error,
    735                        Some(&ns_error),
    736                    );
    737                }
    738                client.identities.lock().render_pipelines.free(pipeline_id);
    739            } else {
    740                unsafe {
    741                    wgpu_child_resolve_create_pipeline_promise(
    742                        client.owner,
    743                        pipeline_id.into_raw(),
    744                        is_render_pipeline,
    745                        false,
    746                        None,
    747                    );
    748                }
    749            }
    750        }
    751        ServerMessage::CreateComputePipelineResponse { pipeline_id, error } => {
    752            let is_render_pipeline = false;
    753            if let Some(error) = error {
    754                let ns_error = nsCString::from(error.error);
    755                unsafe {
    756                    wgpu_child_resolve_create_pipeline_promise(
    757                        client.owner,
    758                        pipeline_id.into_raw(),
    759                        is_render_pipeline,
    760                        error.is_validation_error,
    761                        Some(&ns_error),
    762                    );
    763                }
    764                client.identities.lock().compute_pipelines.free(pipeline_id);
    765            } else {
    766                unsafe {
    767                    wgpu_child_resolve_create_pipeline_promise(
    768                        client.owner,
    769                        pipeline_id.into_raw(),
    770                        is_render_pipeline,
    771                        false,
    772                        None,
    773                    );
    774                }
    775            }
    776        }
    777        ServerMessage::CreateShaderModuleResponse(shader_module_id, compilation_messages) => {
    778            let ffi_compilation_messages: Vec<_> = compilation_messages
    779                .iter()
    780                .map(|m| FfiShaderModuleCompilationMessage {
    781                    line_number: m.line_number,
    782                    line_pos: m.line_pos,
    783                    utf16_offset: m.utf16_offset,
    784                    utf16_length: m.utf16_length,
    785                    message: nsString::from(&m.message),
    786                })
    787                .collect();
    788 
    789            unsafe {
    790                wgpu_child_resolve_create_shader_module_promise(
    791                    client.owner,
    792                    shader_module_id,
    793                    FfiSlice::from_slice(&ffi_compilation_messages),
    794                )
    795            }
    796        }
    797        ServerMessage::BufferMapResponse(buffer_id, buffer_map_result) => {
    798            match buffer_map_result {
    799                BufferMapResult::Success {
    800                    is_writable,
    801                    offset,
    802                    size,
    803                } => unsafe {
    804                    wgpu_child_resolve_buffer_map_promise(
    805                        client.owner,
    806                        buffer_id,
    807                        is_writable,
    808                        offset,
    809                        size,
    810                        None,
    811                    );
    812                },
    813                BufferMapResult::Error(error) => {
    814                    let ns_error = nsCString::from(error.as_ref());
    815                    unsafe {
    816                        wgpu_child_resolve_buffer_map_promise(
    817                            client.owner,
    818                            buffer_id,
    819                            false,
    820                            0,
    821                            0,
    822                            Some(&ns_error),
    823                        );
    824                    }
    825                }
    826            };
    827        }
    828        ServerMessage::QueueOnSubmittedWorkDoneResponse(queue_id) => unsafe {
    829            wgpu_child_resolve_on_submitted_work_done_promise(client.owner, queue_id);
    830        },
    831 
    832        ServerMessage::FreeSwapChainBufferIds(buffer_ids) => {
    833            let identities = client.identities.lock();
    834            for id in buffer_ids {
    835                identities.buffers.free(id);
    836            }
    837        }
    838    }
    839 }
    840 
    841 #[no_mangle]
    842 pub extern "C" fn wgpu_client_request_adapter(
    843    client: &Client,
    844    power_preference: wgt::PowerPreference,
    845    force_fallback_adapter: bool,
    846 ) -> id::AdapterId {
    847    let adapter_id = client.identities.lock().adapters.process();
    848    let message = Message::RequestAdapter {
    849        adapter_id,
    850        power_preference,
    851        force_fallback_adapter,
    852    };
    853    client.queue_message(&message);
    854    adapter_id
    855 }
    856 
    857 #[no_mangle]
    858 pub extern "C" fn wgpu_client_pop_error_scope(client: &Client, device_id: id::DeviceId) {
    859    let message = Message::Device(device_id, DeviceAction::PopErrorScope);
    860    client.queue_message(&message);
    861 }
    862 
    863 #[no_mangle]
    864 pub extern "C" fn wgpu_client_create_shader_module(
    865    client: &Client,
    866    device_id: id::DeviceId,
    867    label: Option<&nsACString>,
    868    code: &nsACString,
    869 ) -> id::ShaderModuleId {
    870    let shader_module_id = client.identities.lock().shader_modules.process();
    871    let label = wgpu_string(label);
    872    let action =
    873        DeviceAction::CreateShaderModule(shader_module_id, label, Cow::Owned(code.to_string()));
    874    let message = Message::Device(device_id, action);
    875    client.queue_message(&message);
    876    shader_module_id
    877 }
    878 
    879 #[no_mangle]
    880 pub extern "C" fn wgpu_client_on_submitted_work_done(client: &Client, queue_id: id::QueueId) {
    881    let message = Message::QueueOnSubmittedWorkDone(queue_id);
    882    client.queue_message(&message);
    883 }
    884 
    885 #[no_mangle]
    886 pub extern "C" fn wgpu_client_create_swap_chain(
    887    client: &Client,
    888    device_id: id::DeviceId,
    889    queue_id: id::QueueId,
    890    width: i32,
    891    height: i32,
    892    format: crate::SurfaceFormat,
    893    remote_texture_owner_id: crate::RemoteTextureOwnerId,
    894    use_shared_texture_in_swap_chain: bool,
    895 ) {
    896    let identities = client.identities.lock();
    897    let buffer_ids: [id::BufferId; crate::MAX_SWAPCHAIN_BUFFER_COUNT] =
    898        array::from_fn(|_| identities.buffers.process());
    899    drop(identities);
    900 
    901    let message = Message::CreateSwapChain {
    902        device_id,
    903        queue_id,
    904        width,
    905        height,
    906        format,
    907        buffer_ids,
    908        remote_texture_owner_id,
    909        use_shared_texture_in_swap_chain,
    910    };
    911    client.queue_message(&message);
    912 }
    913 
    914 #[no_mangle]
    915 pub extern "C" fn wgpu_client_swap_chain_present(
    916    client: &Client,
    917    texture_id: id::TextureId,
    918    command_encoder_id: id::CommandEncoderId,
    919    command_buffer_id: id::CommandBufferId,
    920    remote_texture_id: crate::RemoteTextureId,
    921    remote_texture_owner_id: crate::RemoteTextureOwnerId,
    922 ) {
    923    let message = Message::SwapChainPresent {
    924        texture_id,
    925        command_encoder_id,
    926        command_buffer_id,
    927        remote_texture_id,
    928        remote_texture_owner_id,
    929    };
    930    client.queue_message(&message);
    931 }
    932 
    933 #[no_mangle]
    934 pub extern "C" fn wgpu_client_swap_chain_drop(
    935    client: &Client,
    936    remote_texture_owner_id: crate::RemoteTextureOwnerId,
    937    txn_type: crate::RemoteTextureTxnType,
    938    txn_id: crate::RemoteTextureTxnId,
    939 ) {
    940    let message = Message::SwapChainDrop {
    941        remote_texture_owner_id,
    942        txn_type,
    943        txn_id,
    944    };
    945    client.queue_message(&message);
    946 }
    947 
    948 #[no_mangle]
    949 pub extern "C" fn wgpu_client_queue_submit(
    950    client: &Client,
    951    device_id: id::DeviceId,
    952    queue_id: id::QueueId,
    953    command_buffers: FfiSlice<'_, id::CommandBufferId>,
    954    swap_chain_textures: FfiSlice<'_, id::TextureId>,
    955    external_texture_sources: FfiSlice<'_, crate::ExternalTextureSourceId>,
    956 ) {
    957    let message = Message::QueueSubmit(
    958        device_id,
    959        queue_id,
    960        Cow::Borrowed(unsafe { command_buffers.as_slice() }),
    961        Cow::Borrowed(unsafe { swap_chain_textures.as_slice() }),
    962        Cow::Borrowed(unsafe { external_texture_sources.as_slice() }),
    963    );
    964    client.queue_message(&message);
    965 }
    966 
    967 #[no_mangle]
    968 pub extern "C" fn wgpu_client_buffer_map(
    969    client: &Client,
    970    device_id: id::DeviceId,
    971    buffer_id: id::BufferId,
    972    mode: u32,
    973    offset: u64,
    974    size: u64,
    975 ) {
    976    let message = Message::BufferMap {
    977        device_id,
    978        buffer_id,
    979        mode,
    980        offset,
    981        size,
    982    };
    983    client.queue_message(&message);
    984 }
    985 
    986 #[no_mangle]
    987 pub extern "C" fn wgpu_client_buffer_unmap(
    988    client: &Client,
    989    device_id: id::DeviceId,
    990    buffer_id: id::BufferId,
    991    flush: bool,
    992 ) {
    993    let message = Message::BufferUnmap(device_id, buffer_id, flush);
    994    client.queue_message(&message);
    995 }
    996 
    997 #[no_mangle]
    998 pub extern "C" fn wgpu_client_push_error_scope(
    999    client: &Client,
   1000    device_id: id::DeviceId,
   1001    filter: u8,
   1002 ) {
   1003    let action = DeviceAction::PushErrorScope(filter);
   1004    let message = Message::Device(device_id, action);
   1005    client.queue_message(&message);
   1006 }
   1007 
   1008 #[no_mangle]
   1009 pub extern "C" fn wgpu_client_create_buffer(
   1010    client: &Client,
   1011    device_id: id::DeviceId,
   1012    desc: &wgt::BufferDescriptor<Option<&nsACString>>,
   1013    shmem_handle_index: usize,
   1014 ) -> id::BufferId {
   1015    let buffer_id = client.identities.lock().buffers.process();
   1016    let label = wgpu_string(desc.label);
   1017    let desc = desc.map_label(|_| label);
   1018    let action = DeviceAction::CreateBuffer {
   1019        buffer_id,
   1020        desc,
   1021        shmem_handle_index,
   1022    };
   1023    let message = Message::Device(device_id, action);
   1024    client.queue_message(&message);
   1025    buffer_id
   1026 }
   1027 
   1028 #[no_mangle]
   1029 pub extern "C" fn wgpu_client_create_texture(
   1030    client: &Client,
   1031    device_id: id::DeviceId,
   1032    desc: &wgt::TextureDescriptor<Option<&nsACString>, FfiSlice<TextureFormat>>,
   1033    swap_chain_id: Option<&SwapChainId>,
   1034 ) -> id::TextureId {
   1035    let label = wgpu_string(desc.label);
   1036 
   1037    let id = client.identities.lock().textures.process();
   1038 
   1039    let view_formats = unsafe { desc.view_formats.as_slice() }.to_vec();
   1040 
   1041    let action = DeviceAction::CreateTexture(
   1042        id,
   1043        desc.map_label_and_view_formats(|_| label, |_| view_formats),
   1044        swap_chain_id.copied(),
   1045    );
   1046    let message = Message::Device(device_id, action);
   1047    client.queue_message(&message);
   1048 
   1049    id
   1050 }
   1051 
   1052 #[no_mangle]
   1053 pub extern "C" fn wgpu_client_make_texture_id(client: &Client) -> id::TextureId {
   1054    client.identities.lock().textures.process()
   1055 }
   1056 
   1057 #[no_mangle]
   1058 pub extern "C" fn wgpu_client_free_texture_id(client: &Client, id: id::TextureId) {
   1059    client.identities.lock().textures.free(id)
   1060 }
   1061 
   1062 #[no_mangle]
   1063 pub extern "C" fn wgpu_client_create_texture_view(
   1064    client: &Client,
   1065    device_id: id::DeviceId,
   1066    texture_id: id::TextureId,
   1067    desc: &crate::TextureViewDescriptor,
   1068 ) -> id::TextureViewId {
   1069    let label = wgpu_string(desc.label);
   1070 
   1071    let id = client.identities.lock().texture_views.process();
   1072 
   1073    let wgpu_desc = wgc::resource::TextureViewDescriptor {
   1074        label,
   1075        format: desc.format.cloned(),
   1076        dimension: desc.dimension.cloned(),
   1077        range: wgt::ImageSubresourceRange {
   1078            aspect: desc.aspect,
   1079            base_mip_level: desc.base_mip_level,
   1080            mip_level_count: desc.mip_level_count.map(|ptr| *ptr),
   1081            base_array_layer: desc.base_array_layer,
   1082            array_layer_count: desc.array_layer_count.map(|ptr| *ptr),
   1083        },
   1084        usage: None,
   1085    };
   1086 
   1087    let action = TextureAction::CreateView(id, wgpu_desc);
   1088    let message = Message::Texture(device_id, texture_id, action);
   1089    client.queue_message(&message);
   1090    id
   1091 }
   1092 
   1093 #[no_mangle]
   1094 pub extern "C" fn wgpu_client_make_texture_view_id(client: &Client) -> id::TextureViewId {
   1095    client.identities.lock().texture_views.process()
   1096 }
   1097 
   1098 #[no_mangle]
   1099 pub extern "C" fn wgpu_client_free_texture_view_id(client: &Client, id: id::TextureViewId) {
   1100    client.identities.lock().texture_views.free(id)
   1101 }
   1102 
   1103 #[no_mangle]
   1104 pub extern "C" fn wgpu_client_make_external_texture_source_id(
   1105    client: &Client,
   1106 ) -> crate::ExternalTextureSourceId {
   1107    client.identities.lock().external_texture_sources.process()
   1108 }
   1109 
   1110 #[no_mangle]
   1111 pub extern "C" fn wgpu_client_create_external_texture(
   1112    client: &Client,
   1113    device_id: id::DeviceId,
   1114    desc: &crate::ExternalTextureDescriptor<Option<&nsACString>>,
   1115 ) -> id::ExternalTextureId {
   1116    let desc = desc.map_label(|l| wgpu_string(*l));
   1117    let id = client.identities.lock().external_textures.process();
   1118 
   1119    let action = DeviceAction::CreateExternalTexture(id, desc);
   1120    let message = Message::Device(device_id, action);
   1121    client.queue_message(&message);
   1122    id
   1123 }
   1124 
   1125 #[no_mangle]
   1126 pub extern "C" fn wgpu_client_create_sampler(
   1127    client: &Client,
   1128    device_id: id::DeviceId,
   1129    desc: &SamplerDescriptor,
   1130 ) -> id::SamplerId {
   1131    let label = wgpu_string(desc.label);
   1132 
   1133    let id = client.identities.lock().samplers.process();
   1134 
   1135    let wgpu_desc = wgc::resource::SamplerDescriptor {
   1136        label,
   1137        address_modes: desc.address_modes,
   1138        mag_filter: desc.mag_filter,
   1139        min_filter: desc.min_filter,
   1140        mipmap_filter: desc.mipmap_filter,
   1141        lod_min_clamp: desc.lod_min_clamp,
   1142        lod_max_clamp: desc.lod_max_clamp,
   1143        compare: desc.compare.cloned(),
   1144        anisotropy_clamp: desc.max_anisotropy,
   1145        border_color: None,
   1146    };
   1147    let action = DeviceAction::CreateSampler(id, wgpu_desc);
   1148    let message = Message::Device(device_id, action);
   1149    client.queue_message(&message);
   1150    id
   1151 }
   1152 
   1153 #[no_mangle]
   1154 pub extern "C" fn wgpu_client_make_command_encoder_id(client: &Client) -> id::CommandEncoderId {
   1155    client.identities.lock().command_encoders.process()
   1156 }
   1157 
   1158 #[no_mangle]
   1159 pub extern "C" fn wgpu_client_free_command_encoder_id(client: &Client, id: id::CommandEncoderId) {
   1160    client.identities.lock().command_encoders.free(id)
   1161 }
   1162 
   1163 #[no_mangle]
   1164 pub extern "C" fn wgpu_client_make_command_buffer_id(client: &Client) -> id::CommandBufferId {
   1165    client.identities.lock().command_buffers.process()
   1166 }
   1167 
   1168 #[no_mangle]
   1169 pub extern "C" fn wgpu_client_free_command_buffer_id(client: &Client, id: id::CommandBufferId) {
   1170    client.identities.lock().command_buffers.free(id)
   1171 }
   1172 
   1173 #[no_mangle]
   1174 pub extern "C" fn wgpu_client_create_command_encoder(
   1175    client: &Client,
   1176    device_id: id::DeviceId,
   1177    desc: &wgt::CommandEncoderDescriptor<Option<&nsACString>>,
   1178 ) -> id::CommandEncoderId {
   1179    let label = wgpu_string(desc.label);
   1180 
   1181    let id = client.identities.lock().command_encoders.process();
   1182 
   1183    let action = DeviceAction::CreateCommandEncoder(id, desc.map_label(|_| label));
   1184    let message = Message::Device(device_id, action);
   1185    client.queue_message(&message);
   1186    id
   1187 }
   1188 
   1189 #[no_mangle]
   1190 pub extern "C" fn wgpu_device_create_render_bundle_encoder(
   1191    client: &Client,
   1192    device_id: id::DeviceId,
   1193    desc: &RenderBundleEncoderDescriptor,
   1194 ) -> *mut wgc::command::RenderBundleEncoder {
   1195    let label = wgpu_string(desc.label);
   1196 
   1197    let color_formats: Vec<_> = unsafe { desc.color_formats.as_slice() }
   1198        .iter()
   1199        .map(|format| Some(format.clone()))
   1200        .collect();
   1201    let descriptor = wgc::command::RenderBundleEncoderDescriptor {
   1202        label,
   1203        color_formats: Cow::Owned(color_formats),
   1204        depth_stencil: desc
   1205            .depth_stencil_format
   1206            .map(|&format| wgt::RenderBundleDepthStencil {
   1207                format,
   1208                depth_read_only: desc.depth_read_only,
   1209                stencil_read_only: desc.stencil_read_only,
   1210            }),
   1211        sample_count: desc.sample_count,
   1212        multiview: None,
   1213    };
   1214    match wgc::command::RenderBundleEncoder::new(&descriptor, device_id) {
   1215        Ok(encoder) => Box::into_raw(Box::new(encoder)),
   1216        Err(e) => {
   1217            let message = format!("Error in `Device::create_render_bundle_encoder`: {}", e);
   1218            let action = DeviceAction::Error {
   1219                message,
   1220                r#type: e.webgpu_error_type(),
   1221            };
   1222            let message = Message::Device(device_id, action);
   1223            client.queue_message(&message);
   1224            ptr::null_mut()
   1225        }
   1226    }
   1227 }
   1228 
   1229 #[no_mangle]
   1230 pub unsafe extern "C" fn wgpu_render_bundle_encoder_destroy(
   1231    pass: *mut wgc::command::RenderBundleEncoder,
   1232 ) {
   1233    // The RB encoder is just a boxed Rust struct, it doesn't have any API primitives
   1234    // associated with it right now, but in the future it will.
   1235    let _ = Box::from_raw(pass);
   1236 }
   1237 
   1238 #[no_mangle]
   1239 pub unsafe extern "C" fn wgpu_client_create_render_bundle(
   1240    client: &Client,
   1241    device_id: id::DeviceId,
   1242    encoder: *mut wgc::command::RenderBundleEncoder,
   1243    desc: &wgt::RenderBundleDescriptor<Option<&nsACString>>,
   1244 ) -> id::RenderBundleId {
   1245    let label = wgpu_string(desc.label);
   1246 
   1247    let id = client.identities.lock().render_bundles.process();
   1248 
   1249    let action =
   1250        DeviceAction::CreateRenderBundle(id, *Box::from_raw(encoder), desc.map_label(|_| label));
   1251    let message = Message::Device(device_id, action);
   1252    client.queue_message(&message);
   1253    id
   1254 }
   1255 
   1256 #[no_mangle]
   1257 pub unsafe extern "C" fn wgpu_client_create_render_bundle_error(
   1258    client: &Client,
   1259    device_id: id::DeviceId,
   1260    label: Option<&nsACString>,
   1261 ) -> id::RenderBundleId {
   1262    let label = wgpu_string(label);
   1263 
   1264    let id = client.identities.lock().render_bundles.process();
   1265 
   1266    let action = DeviceAction::CreateRenderBundleError(id, label);
   1267    let message = Message::Device(device_id, action);
   1268    client.queue_message(&message);
   1269    id
   1270 }
   1271 
   1272 #[repr(C)]
   1273 pub struct RawQuerySetDescriptor<'a> {
   1274    label: Option<&'a nsACString>,
   1275    ty: RawQueryType,
   1276    count: u32,
   1277 }
   1278 
   1279 #[repr(C)]
   1280 #[derive(Clone, Copy, Debug)]
   1281 pub enum RawQueryType {
   1282    Occlusion,
   1283    Timestamp,
   1284 }
   1285 
   1286 #[no_mangle]
   1287 pub extern "C" fn wgpu_client_create_query_set(
   1288    client: &Client,
   1289    device_id: id::DeviceId,
   1290    desc: &RawQuerySetDescriptor,
   1291 ) -> wgc::id::QuerySetId {
   1292    let &RawQuerySetDescriptor { label, ty, count } = desc;
   1293 
   1294    let label = wgpu_string(label);
   1295    let ty = match ty {
   1296        RawQueryType::Occlusion => wgt::QueryType::Occlusion,
   1297        RawQueryType::Timestamp => wgt::QueryType::Timestamp,
   1298    };
   1299 
   1300    let desc = wgc::resource::QuerySetDescriptor { label, ty, count };
   1301 
   1302    let id = client.identities.lock().query_sets.process();
   1303 
   1304    let action = DeviceAction::CreateQuerySet(id, desc);
   1305    let message = Message::Device(device_id, action);
   1306    client.queue_message(&message);
   1307 
   1308    id
   1309 }
   1310 
   1311 #[repr(C)]
   1312 pub struct ComputePassDescriptor<'a> {
   1313    pub label: Option<&'a nsACString>,
   1314    pub timestamp_writes: Option<&'a PassTimestampWrites<'a>>,
   1315 }
   1316 
   1317 #[repr(C)]
   1318 pub struct PassTimestampWrites<'a> {
   1319    pub query_set: id::QuerySetId,
   1320    pub beginning_of_pass_write_index: Option<&'a u32>,
   1321    pub end_of_pass_write_index: Option<&'a u32>,
   1322 }
   1323 
   1324 #[no_mangle]
   1325 pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass(
   1326    desc: &ComputePassDescriptor,
   1327 ) -> *mut crate::command::RecordedComputePass {
   1328    let &ComputePassDescriptor {
   1329        label,
   1330        timestamp_writes,
   1331    } = desc;
   1332 
   1333    let label = wgpu_string(label);
   1334 
   1335    let timestamp_writes = timestamp_writes.map(|tsw| {
   1336        let &PassTimestampWrites {
   1337            query_set,
   1338            beginning_of_pass_write_index,
   1339            end_of_pass_write_index,
   1340        } = tsw;
   1341        let beginning_of_pass_write_index = beginning_of_pass_write_index.cloned();
   1342        let end_of_pass_write_index = end_of_pass_write_index.cloned();
   1343        wgc::command::PassTimestampWrites {
   1344            query_set,
   1345            beginning_of_pass_write_index,
   1346            end_of_pass_write_index,
   1347        }
   1348    });
   1349 
   1350    let pass = crate::command::RecordedComputePass::new(&wgc::command::ComputePassDescriptor {
   1351        label,
   1352        timestamp_writes,
   1353    });
   1354    Box::into_raw(Box::new(pass))
   1355 }
   1356 
   1357 #[no_mangle]
   1358 pub unsafe extern "C" fn wgpu_compute_pass_finish(
   1359    client: &Client,
   1360    device_id: id::DeviceId,
   1361    encoder_id: id::CommandEncoderId,
   1362    pass: *mut crate::command::RecordedComputePass,
   1363 ) {
   1364    let pass = *Box::from_raw(pass);
   1365    let message = Message::ReplayComputePass(device_id, encoder_id, pass);
   1366    client.queue_message(&message);
   1367 }
   1368 
   1369 #[no_mangle]
   1370 pub unsafe extern "C" fn wgpu_compute_pass_destroy(pass: *mut crate::command::RecordedComputePass) {
   1371    let _ = Box::from_raw(pass);
   1372 }
   1373 
   1374 #[repr(C)]
   1375 pub struct RenderPassDescriptor<'a> {
   1376    pub label: Option<&'a nsACString>,
   1377    pub color_attachments: FfiSlice<'a, FfiRenderPassColorAttachment>,
   1378    pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachment>,
   1379    pub timestamp_writes: Option<&'a PassTimestampWrites<'a>>,
   1380    pub occlusion_query_set: Option<wgc::id::QuerySetId>,
   1381 }
   1382 
   1383 #[no_mangle]
   1384 pub unsafe extern "C" fn wgpu_command_encoder_begin_render_pass(
   1385    desc: &RenderPassDescriptor,
   1386 ) -> *mut crate::command::RecordedRenderPass {
   1387    let &RenderPassDescriptor {
   1388        label,
   1389        color_attachments,
   1390        depth_stencil_attachment,
   1391        timestamp_writes,
   1392        occlusion_query_set,
   1393    } = desc;
   1394 
   1395    let label = wgpu_string(label).map(|l| l.to_string());
   1396 
   1397    let timestamp_writes = timestamp_writes.map(|tsw| {
   1398        let &PassTimestampWrites {
   1399            query_set,
   1400            beginning_of_pass_write_index,
   1401            end_of_pass_write_index,
   1402        } = tsw;
   1403        let beginning_of_pass_write_index = beginning_of_pass_write_index.cloned();
   1404        let end_of_pass_write_index = end_of_pass_write_index.cloned();
   1405        wgc::command::PassTimestampWrites {
   1406            query_set,
   1407            beginning_of_pass_write_index,
   1408            end_of_pass_write_index,
   1409        }
   1410    });
   1411 
   1412    let color_attachments: Vec<_> = color_attachments
   1413        .as_slice()
   1414        .iter()
   1415        .map(|color_attachment| Some(color_attachment.clone().to_wgpu()))
   1416        .collect();
   1417    let depth_stencil_attachment = depth_stencil_attachment.cloned().map(|dsa| dsa.to_wgpu());
   1418    let pass = crate::command::RecordedRenderPass::new(
   1419        label,
   1420        color_attachments,
   1421        depth_stencil_attachment,
   1422        timestamp_writes,
   1423        occlusion_query_set,
   1424    );
   1425    Box::into_raw(Box::new(pass))
   1426 }
   1427 
   1428 #[no_mangle]
   1429 pub unsafe extern "C" fn wgpu_render_pass_finish(
   1430    client: &Client,
   1431    device_id: id::DeviceId,
   1432    encoder_id: id::CommandEncoderId,
   1433    pass: *mut crate::command::RecordedRenderPass,
   1434 ) {
   1435    let pass = *Box::from_raw(pass);
   1436    let message = Message::ReplayRenderPass(device_id, encoder_id, pass);
   1437    client.queue_message(&message);
   1438 }
   1439 
   1440 #[no_mangle]
   1441 pub unsafe extern "C" fn wgpu_render_pass_destroy(pass: *mut crate::command::RecordedRenderPass) {
   1442    let _ = Box::from_raw(pass);
   1443 }
   1444 
   1445 #[no_mangle]
   1446 pub unsafe extern "C" fn wgpu_client_create_bind_group_layout(
   1447    client: &Client,
   1448    device_id: id::DeviceId,
   1449    desc: &BindGroupLayoutDescriptor,
   1450 ) -> id::BindGroupLayoutId {
   1451    let label = wgpu_string(desc.label);
   1452 
   1453    let id = client.identities.lock().bind_group_layouts.process();
   1454 
   1455    let entries = desc
   1456        .entries
   1457        .as_slice()
   1458        .iter()
   1459        .map(|entry| {
   1460            wgt::BindGroupLayoutEntry {
   1461                binding: entry.binding,
   1462                visibility: entry.visibility,
   1463                count: None,
   1464                ty: match entry.ty {
   1465                    RawBindingType::UniformBuffer => wgt::BindingType::Buffer {
   1466                        ty: wgt::BufferBindingType::Uniform,
   1467                        has_dynamic_offset: entry.has_dynamic_offset,
   1468                        min_binding_size: entry.min_binding_size,
   1469                    },
   1470                    RawBindingType::StorageBuffer => wgt::BindingType::Buffer {
   1471                        ty: wgt::BufferBindingType::Storage { read_only: false },
   1472                        has_dynamic_offset: entry.has_dynamic_offset,
   1473                        min_binding_size: entry.min_binding_size,
   1474                    },
   1475                    RawBindingType::ReadonlyStorageBuffer => wgt::BindingType::Buffer {
   1476                        ty: wgt::BufferBindingType::Storage { read_only: true },
   1477                        has_dynamic_offset: entry.has_dynamic_offset,
   1478                        min_binding_size: entry.min_binding_size,
   1479                    },
   1480                    RawBindingType::Sampler => {
   1481                        wgt::BindingType::Sampler(if entry.sampler_compare {
   1482                            wgt::SamplerBindingType::Comparison
   1483                        } else if entry.sampler_filter {
   1484                            wgt::SamplerBindingType::Filtering
   1485                        } else {
   1486                            wgt::SamplerBindingType::NonFiltering
   1487                        })
   1488                    }
   1489                    RawBindingType::SampledTexture => wgt::BindingType::Texture {
   1490                        //TODO: the spec has a bug here
   1491                        view_dimension: *entry
   1492                            .view_dimension
   1493                            .unwrap_or(&wgt::TextureViewDimension::D2),
   1494                        sample_type: match entry.texture_sample_type {
   1495                            None | Some(RawTextureSampleType::Float) => {
   1496                                wgt::TextureSampleType::Float { filterable: true }
   1497                            }
   1498                            Some(RawTextureSampleType::UnfilterableFloat) => {
   1499                                wgt::TextureSampleType::Float { filterable: false }
   1500                            }
   1501                            Some(RawTextureSampleType::Uint) => wgt::TextureSampleType::Uint,
   1502                            Some(RawTextureSampleType::Sint) => wgt::TextureSampleType::Sint,
   1503                            Some(RawTextureSampleType::Depth) => wgt::TextureSampleType::Depth,
   1504                        },
   1505                        multisampled: entry.multisampled,
   1506                    },
   1507                    RawBindingType::ReadonlyStorageTexture => wgt::BindingType::StorageTexture {
   1508                        access: wgt::StorageTextureAccess::ReadOnly,
   1509                        view_dimension: *entry.view_dimension.unwrap(),
   1510                        format: *entry.storage_texture_format.unwrap(),
   1511                    },
   1512                    RawBindingType::WriteonlyStorageTexture => wgt::BindingType::StorageTexture {
   1513                        access: wgt::StorageTextureAccess::WriteOnly,
   1514                        view_dimension: *entry.view_dimension.unwrap(),
   1515                        format: *entry.storage_texture_format.unwrap(),
   1516                    },
   1517                    RawBindingType::ReadWriteStorageTexture => wgt::BindingType::StorageTexture {
   1518                        access: wgt::StorageTextureAccess::ReadWrite,
   1519                        view_dimension: *entry.view_dimension.unwrap(),
   1520                        format: *entry.storage_texture_format.unwrap(),
   1521                    },
   1522                    RawBindingType::ExternalTexture => wgt::BindingType::ExternalTexture,
   1523                },
   1524            }
   1525        })
   1526        .collect();
   1527    let wgpu_desc = wgc::binding_model::BindGroupLayoutDescriptor {
   1528        label,
   1529        entries: Cow::Owned(entries),
   1530    };
   1531 
   1532    let action = DeviceAction::CreateBindGroupLayout(id, wgpu_desc);
   1533    let message = Message::Device(device_id, action);
   1534    client.queue_message(&message);
   1535    id
   1536 }
   1537 
   1538 #[no_mangle]
   1539 pub unsafe extern "C" fn wgpu_client_render_pipeline_get_bind_group_layout(
   1540    client: &Client,
   1541    device_id: id::DeviceId,
   1542    pipeline_id: id::RenderPipelineId,
   1543    index: u32,
   1544 ) -> id::BindGroupLayoutId {
   1545    let bgl_id = client.identities.lock().bind_group_layouts.process();
   1546 
   1547    let action = DeviceAction::RenderPipelineGetBindGroupLayout(pipeline_id, index, bgl_id);
   1548    let message = Message::Device(device_id, action);
   1549    client.queue_message(&message);
   1550 
   1551    bgl_id
   1552 }
   1553 
   1554 #[no_mangle]
   1555 pub unsafe extern "C" fn wgpu_client_compute_pipeline_get_bind_group_layout(
   1556    client: &Client,
   1557    device_id: id::DeviceId,
   1558    pipeline_id: id::ComputePipelineId,
   1559    index: u32,
   1560 ) -> id::BindGroupLayoutId {
   1561    let bgl_id = client.identities.lock().bind_group_layouts.process();
   1562 
   1563    let action = DeviceAction::ComputePipelineGetBindGroupLayout(pipeline_id, index, bgl_id);
   1564    let message = Message::Device(device_id, action);
   1565    client.queue_message(&message);
   1566 
   1567    bgl_id
   1568 }
   1569 
   1570 #[no_mangle]
   1571 pub unsafe extern "C" fn wgpu_client_create_pipeline_layout(
   1572    client: &Client,
   1573    device_id: id::DeviceId,
   1574    desc: &PipelineLayoutDescriptor,
   1575 ) -> id::PipelineLayoutId {
   1576    let label = wgpu_string(desc.label);
   1577 
   1578    let id = client.identities.lock().pipeline_layouts.process();
   1579 
   1580    let wgpu_desc = wgc::binding_model::PipelineLayoutDescriptor {
   1581        label,
   1582        bind_group_layouts: Cow::Borrowed(desc.bind_group_layouts.as_slice()),
   1583        immediate_size: 0,
   1584    };
   1585 
   1586    let action = DeviceAction::CreatePipelineLayout(id, wgpu_desc);
   1587    let message = Message::Device(device_id, action);
   1588    client.queue_message(&message);
   1589    id
   1590 }
   1591 
   1592 #[no_mangle]
   1593 pub unsafe extern "C" fn wgpu_client_create_bind_group(
   1594    client: &Client,
   1595    device_id: id::DeviceId,
   1596    desc: &BindGroupDescriptor,
   1597 ) -> id::BindGroupId {
   1598    let label = wgpu_string(desc.label);
   1599 
   1600    let id = client.identities.lock().bind_groups.process();
   1601 
   1602    let entries = desc
   1603        .entries
   1604        .as_slice()
   1605        .iter()
   1606        .map(|entry| wgc::binding_model::BindGroupEntry {
   1607            binding: entry.binding,
   1608            resource: if let Some(id) = entry.buffer {
   1609                wgc::binding_model::BindingResource::Buffer(wgc::binding_model::BufferBinding {
   1610                    buffer: id,
   1611                    offset: entry.offset,
   1612                    size: entry.size_passed.then_some(entry.size),
   1613                })
   1614            } else if let Some(id) = entry.sampler {
   1615                wgc::binding_model::BindingResource::Sampler(id)
   1616            } else if let Some(id) = entry.texture_view {
   1617                wgc::binding_model::BindingResource::TextureView(id)
   1618            } else if let Some(id) = entry.external_texture {
   1619                wgc::binding_model::BindingResource::ExternalTexture(id)
   1620            } else {
   1621                panic!("Unexpected binding entry {:?}", entry);
   1622            },
   1623        })
   1624        .collect();
   1625    let wgpu_desc = wgc::binding_model::BindGroupDescriptor {
   1626        label,
   1627        layout: desc.layout,
   1628        entries: Cow::Owned(entries),
   1629    };
   1630 
   1631    let action = DeviceAction::CreateBindGroup(id, wgpu_desc);
   1632    let message = Message::Device(device_id, action);
   1633    client.queue_message(&message);
   1634    id
   1635 }
   1636 
   1637 #[no_mangle]
   1638 pub unsafe extern "C" fn wgpu_client_create_compute_pipeline(
   1639    client: &Client,
   1640    device_id: id::DeviceId,
   1641    desc: &ComputePipelineDescriptor,
   1642    is_async: bool,
   1643 ) -> id::ComputePipelineId {
   1644    let label = wgpu_string(desc.label);
   1645 
   1646    let identities = client.identities.lock();
   1647    let id = identities.compute_pipelines.process();
   1648 
   1649    let wgpu_desc = wgc::pipeline::ComputePipelineDescriptor {
   1650        label,
   1651        layout: desc.layout,
   1652        stage: desc.stage.to_wgpu(),
   1653        cache: None,
   1654    };
   1655 
   1656    let action = DeviceAction::CreateComputePipeline(id, wgpu_desc, is_async);
   1657    let message = Message::Device(device_id, action);
   1658    client.queue_message(&message);
   1659    id
   1660 }
   1661 
   1662 #[no_mangle]
   1663 pub unsafe extern "C" fn wgpu_client_create_render_pipeline(
   1664    client: &Client,
   1665    device_id: id::DeviceId,
   1666    desc: &RenderPipelineDescriptor,
   1667    is_async: bool,
   1668 ) -> id::RenderPipelineId {
   1669    let label = wgpu_string(desc.label);
   1670 
   1671    let identities = client.identities.lock();
   1672    let id = identities.render_pipelines.process();
   1673 
   1674    let wgpu_desc = wgc::pipeline::RenderPipelineDescriptor {
   1675        label,
   1676        layout: desc.layout,
   1677        vertex: desc.vertex.to_wgpu(),
   1678        fragment: desc.fragment.map(FragmentState::to_wgpu),
   1679        primitive: desc.primitive.to_wgpu(),
   1680        depth_stencil: desc.depth_stencil.cloned(),
   1681        multisample: desc.multisample.clone(),
   1682        multiview_mask: None,
   1683        cache: None,
   1684    };
   1685 
   1686    let action = DeviceAction::CreateRenderPipeline(id, wgpu_desc, is_async);
   1687    let message = Message::Device(device_id, action);
   1688    client.queue_message(&message);
   1689    id
   1690 }
   1691 
   1692 #[no_mangle]
   1693 pub unsafe extern "C" fn wgpu_command_encoder_copy_buffer_to_buffer(
   1694    client: &Client,
   1695    device_id: id::DeviceId,
   1696    command_encoder_id: id::CommandEncoderId,
   1697    src: id::BufferId,
   1698    src_offset: wgt::BufferAddress,
   1699    dst: id::BufferId,
   1700    dst_offset: wgt::BufferAddress,
   1701    size: wgt::BufferAddress,
   1702 ) {
   1703    // In Javascript, `size === undefined` means "copy from src_offset to end of
   1704    // buffer". The `size` argument to this function uses a value of
   1705    // `wgt::BufferAddress::MAX` to encode that case. (Valid copy
   1706    // sizes must be multiples of four, so in the case that the application
   1707    // really asked to copy BufferAddress::MAX bytes,
   1708    // CommandEncoder::CopyBufferToBuffer decrements it by four, which
   1709    // will still fail for mis-alignment.)
   1710    let size = (size != wgt::BufferAddress::MAX).then_some(size);
   1711    let action = CommandEncoderAction::CopyBufferToBuffer {
   1712        src,
   1713        src_offset,
   1714        dst,
   1715        dst_offset,
   1716        size,
   1717    };
   1718    let message = Message::CommandEncoder(device_id, command_encoder_id, action);
   1719    client.queue_message(&message);
   1720 }
   1721 
   1722 #[no_mangle]
   1723 pub unsafe extern "C" fn wgpu_command_encoder_copy_texture_to_buffer(
   1724    client: &Client,
   1725    device_id: id::DeviceId,
   1726    command_encoder_id: id::CommandEncoderId,
   1727    src: wgc::command::TexelCopyTextureInfo,
   1728    dst_buffer: wgc::id::BufferId,
   1729    dst_layout: &TexelCopyBufferLayout,
   1730    size: wgt::Extent3d,
   1731 ) {
   1732    let action = CommandEncoderAction::CopyTextureToBuffer {
   1733        src,
   1734        dst: wgc::command::TexelCopyBufferInfo {
   1735            buffer: dst_buffer,
   1736            layout: dst_layout.into_wgt(),
   1737        },
   1738        size,
   1739    };
   1740    let message = Message::CommandEncoder(device_id, command_encoder_id, action);
   1741    client.queue_message(&message);
   1742 }
   1743 
   1744 #[no_mangle]
   1745 pub unsafe extern "C" fn wgpu_command_encoder_copy_buffer_to_texture(
   1746    client: &Client,
   1747    device_id: id::DeviceId,
   1748    command_encoder_id: id::CommandEncoderId,
   1749    src_buffer: wgc::id::BufferId,
   1750    src_layout: &TexelCopyBufferLayout,
   1751    dst: wgc::command::TexelCopyTextureInfo,
   1752    size: wgt::Extent3d,
   1753 ) {
   1754    let action = CommandEncoderAction::CopyBufferToTexture {
   1755        src: wgc::command::TexelCopyBufferInfo {
   1756            buffer: src_buffer,
   1757            layout: src_layout.into_wgt(),
   1758        },
   1759        dst,
   1760        size,
   1761    };
   1762    let message = Message::CommandEncoder(device_id, command_encoder_id, action);
   1763    client.queue_message(&message);
   1764 }
   1765 
   1766 #[no_mangle]
   1767 pub unsafe extern "C" fn wgpu_command_encoder_copy_texture_to_texture(
   1768    client: &Client,
   1769    device_id: id::DeviceId,
   1770    command_encoder_id: id::CommandEncoderId,
   1771    src: wgc::command::TexelCopyTextureInfo,
   1772    dst: wgc::command::TexelCopyTextureInfo,
   1773    size: wgt::Extent3d,
   1774 ) {
   1775    let action = CommandEncoderAction::CopyTextureToTexture { src, dst, size };
   1776    let message = Message::CommandEncoder(device_id, command_encoder_id, action);
   1777    client.queue_message(&message);
   1778 }
   1779 
   1780 #[no_mangle]
   1781 pub unsafe extern "C" fn wgpu_command_encoder_clear_buffer(
   1782    client: &Client,
   1783    device_id: id::DeviceId,
   1784    command_encoder_id: id::CommandEncoderId,
   1785    dst: wgc::id::BufferId,
   1786    offset: u64,
   1787    size: Option<&u64>,
   1788 ) {
   1789    let action = CommandEncoderAction::ClearBuffer {
   1790        dst,
   1791        offset,
   1792        size: size.cloned(),
   1793    };
   1794    let message = Message::CommandEncoder(device_id, command_encoder_id, action);
   1795    client.queue_message(&message);
   1796 }
   1797 
   1798 #[no_mangle]
   1799 pub extern "C" fn wgpu_command_encoder_push_debug_group(
   1800    client: &Client,
   1801    device_id: id::DeviceId,
   1802    command_encoder_id: id::CommandEncoderId,
   1803    marker: &nsACString,
   1804 ) {
   1805    let string = marker.to_string();
   1806    let action = CommandEncoderAction::PushDebugGroup(string);
   1807    let message = Message::CommandEncoder(device_id, command_encoder_id, action);
   1808    client.queue_message(&message);
   1809 }
   1810 
   1811 #[no_mangle]
   1812 pub unsafe extern "C" fn wgpu_command_encoder_pop_debug_group(
   1813    client: &Client,
   1814    device_id: id::DeviceId,
   1815    command_encoder_id: id::CommandEncoderId,
   1816 ) {
   1817    let action = CommandEncoderAction::PopDebugGroup;
   1818    let message = Message::CommandEncoder(device_id, command_encoder_id, action);
   1819    client.queue_message(&message);
   1820 }
   1821 
   1822 #[no_mangle]
   1823 pub unsafe extern "C" fn wgpu_command_encoder_insert_debug_marker(
   1824    client: &Client,
   1825    device_id: id::DeviceId,
   1826    command_encoder_id: id::CommandEncoderId,
   1827    marker: &nsACString,
   1828 ) {
   1829    let string = marker.to_string();
   1830    let action = CommandEncoderAction::InsertDebugMarker(string);
   1831    let message = Message::CommandEncoder(device_id, command_encoder_id, action);
   1832    client.queue_message(&message);
   1833 }
   1834 
   1835 #[no_mangle]
   1836 pub unsafe extern "C" fn wgpu_command_encoder_resolve_query_set(
   1837    client: &Client,
   1838    device_id: id::DeviceId,
   1839    command_encoder_id: id::CommandEncoderId,
   1840    query_set_id: id::QuerySetId,
   1841    start_query: u32,
   1842    query_count: u32,
   1843    destination: id::BufferId,
   1844    destination_offset: wgt::BufferAddress,
   1845 ) {
   1846    let action = CommandEncoderAction::ResolveQuerySet {
   1847        query_set: query_set_id,
   1848        start_query,
   1849        query_count,
   1850        destination,
   1851        destination_offset,
   1852    };
   1853    let message = Message::CommandEncoder(device_id, command_encoder_id, action);
   1854    client.queue_message(&message);
   1855 }
   1856 
   1857 #[no_mangle]
   1858 pub unsafe extern "C" fn wgpu_report_internal_error(
   1859    client: &Client,
   1860    device_id: id::DeviceId,
   1861    message: *const core::ffi::c_char,
   1862 ) {
   1863    let action = DeviceAction::Error {
   1864        message: core::ffi::CStr::from_ptr(message)
   1865            .to_str()
   1866            .unwrap()
   1867            .to_string(),
   1868        r#type: wgt::error::ErrorType::Internal,
   1869    };
   1870    let message = Message::Device(device_id, action);
   1871    client.queue_message(&message);
   1872 }
   1873 
   1874 #[no_mangle]
   1875 pub unsafe extern "C" fn wgpu_report_validation_error(
   1876    client: &Client,
   1877    device_id: id::DeviceId,
   1878    message: *const core::ffi::c_char,
   1879 ) {
   1880    let action = DeviceAction::Error {
   1881        message: core::ffi::CStr::from_ptr(message)
   1882            .to_str()
   1883            .unwrap()
   1884            .to_string(),
   1885        r#type: wgt::error::ErrorType::Validation,
   1886    };
   1887    let message = Message::Device(device_id, action);
   1888    client.queue_message(&message);
   1889 }
   1890 
   1891 #[no_mangle]
   1892 pub unsafe extern "C" fn wgpu_command_encoder_finish(
   1893    client: &Client,
   1894    device_id: id::DeviceId,
   1895    command_encoder_id: id::CommandEncoderId,
   1896    desc: &wgt::CommandBufferDescriptor<Option<&nsACString>>,
   1897 ) -> id::CommandBufferId {
   1898    let command_buffer_id = client.identities.lock().command_buffers.process();
   1899    let label = wgpu_string(desc.label);
   1900    let message = Message::CommandEncoderFinish(
   1901        device_id,
   1902        command_encoder_id,
   1903        command_buffer_id,
   1904        desc.map_label(|_| label),
   1905    );
   1906    client.queue_message(&message);
   1907    command_buffer_id
   1908 }
   1909 
   1910 #[no_mangle]
   1911 pub unsafe extern "C" fn wgpu_queue_write_buffer_inline(
   1912    client: &Client,
   1913    device_id: id::DeviceId,
   1914    queue_id: id::QueueId,
   1915    dst: id::BufferId,
   1916    offset: wgt::BufferAddress,
   1917    data_buffer_index: usize,
   1918 ) {
   1919    let data_source = QueueWriteDataSource::DataBuffer(data_buffer_index);
   1920 
   1921    let action = QueueWriteAction::Buffer { dst, offset };
   1922    let message = Message::QueueWrite {
   1923        device_id,
   1924        queue_id,
   1925        data_source,
   1926        action,
   1927    };
   1928    client.queue_message(&message);
   1929 }
   1930 
   1931 #[no_mangle]
   1932 pub unsafe extern "C" fn wgpu_queue_write_buffer_via_shmem(
   1933    client: &Client,
   1934    device_id: id::DeviceId,
   1935    queue_id: id::QueueId,
   1936    dst: id::BufferId,
   1937    offset: wgt::BufferAddress,
   1938    shmem_handle_index: usize,
   1939 ) {
   1940    let data_source = QueueWriteDataSource::Shmem(shmem_handle_index);
   1941 
   1942    let action = QueueWriteAction::Buffer { dst, offset };
   1943    let message = Message::QueueWrite {
   1944        device_id,
   1945        queue_id,
   1946        data_source,
   1947        action,
   1948    };
   1949    client.queue_message(&message);
   1950 }
   1951 
   1952 #[no_mangle]
   1953 pub unsafe extern "C" fn wgpu_queue_write_texture_via_shmem(
   1954    client: &Client,
   1955    device_id: id::DeviceId,
   1956    queue_id: id::QueueId,
   1957    dst: wgt::TexelCopyTextureInfo<id::TextureId>,
   1958    layout: TexelCopyBufferLayout,
   1959    size: wgt::Extent3d,
   1960    shmem_handle_index: usize,
   1961 ) {
   1962    let data_source = QueueWriteDataSource::Shmem(shmem_handle_index);
   1963 
   1964    let layout = layout.into_wgt();
   1965    let action = QueueWriteAction::Texture { dst, layout, size };
   1966    let message = Message::QueueWrite {
   1967        device_id,
   1968        queue_id,
   1969        data_source,
   1970        action,
   1971    };
   1972    client.queue_message(&message);
   1973 }
   1974 
   1975 #[repr(C)]
   1976 pub struct TextureFormatBlockInfo {
   1977    copy_size: u32,
   1978    width: u32,
   1979    height: u32,
   1980 }
   1981 
   1982 /// Obtain the block size and dimensions for a single aspect.
   1983 ///
   1984 /// Populates `info` and returns true on success. Returns false if `format` has
   1985 /// multiple aspects and `aspect` is `All`.
   1986 #[no_mangle]
   1987 pub extern "C" fn wgpu_texture_format_get_block_info(
   1988    format: wgt::TextureFormat,
   1989    aspect: wgt::TextureAspect,
   1990    info: &mut TextureFormatBlockInfo,
   1991 ) -> bool {
   1992    let (width, height) = format.block_dimensions();
   1993    let (copy_size, ret) = match format.block_copy_size(Some(aspect)) {
   1994        Some(size) => (size, true),
   1995        None => (0, false),
   1996    };
   1997    *info = TextureFormatBlockInfo {
   1998        width,
   1999        height,
   2000        copy_size,
   2001    };
   2002    ret
   2003 }
   2004 
   2005 #[no_mangle]
   2006 pub extern "C" fn wgpu_client_use_shared_texture_in_swapChain(format: wgt::TextureFormat) -> bool {
   2007    let supported = match format {
   2008        wgt::TextureFormat::Bgra8Unorm => true,
   2009        _ => false,
   2010    };
   2011 
   2012    supported
   2013 }
   2014 
   2015 #[no_mangle]
   2016 pub unsafe extern "C" fn wgpu_render_bundle_set_bind_group(
   2017    bundle: &mut RenderBundleEncoder,
   2018    index: u32,
   2019    bind_group_id: Option<id::BindGroupId>,
   2020    offsets: *const DynamicOffset,
   2021    offset_length: usize,
   2022 ) {
   2023    wgc::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
   2024        bundle,
   2025        index,
   2026        bind_group_id,
   2027        offsets,
   2028        offset_length,
   2029    )
   2030 }
   2031 
   2032 #[no_mangle]
   2033 pub extern "C" fn wgpu_render_bundle_set_pipeline(
   2034    bundle: &mut RenderBundleEncoder,
   2035    pipeline_id: id::RenderPipelineId,
   2036 ) {
   2037    wgc::command::bundle_ffi::wgpu_render_bundle_set_pipeline(bundle, pipeline_id)
   2038 }
   2039 
   2040 #[no_mangle]
   2041 pub extern "C" fn wgpu_render_bundle_set_vertex_buffer(
   2042    bundle: &mut RenderBundleEncoder,
   2043    slot: u32,
   2044    buffer_id: id::BufferId,
   2045    offset: BufferAddress,
   2046    size: Option<&BufferSize>,
   2047 ) {
   2048    wgc::command::bundle_ffi::wgpu_render_bundle_set_vertex_buffer(
   2049        bundle,
   2050        slot,
   2051        buffer_id,
   2052        offset,
   2053        size.copied(),
   2054    )
   2055 }
   2056 
   2057 #[no_mangle]
   2058 pub extern "C" fn wgpu_render_bundle_set_index_buffer(
   2059    encoder: &mut RenderBundleEncoder,
   2060    buffer: id::BufferId,
   2061    index_format: IndexFormat,
   2062    offset: BufferAddress,
   2063    size: Option<&BufferSize>,
   2064 ) {
   2065    wgc::command::bundle_ffi::wgpu_render_bundle_set_index_buffer(
   2066        encoder,
   2067        buffer,
   2068        index_format,
   2069        offset,
   2070        size.copied(),
   2071    )
   2072 }
   2073 
   2074 #[no_mangle]
   2075 pub extern "C" fn wgpu_render_bundle_draw(
   2076    bundle: &mut RenderBundleEncoder,
   2077    vertex_count: u32,
   2078    instance_count: u32,
   2079    first_vertex: u32,
   2080    first_instance: u32,
   2081 ) {
   2082    wgc::command::bundle_ffi::wgpu_render_bundle_draw(
   2083        bundle,
   2084        vertex_count,
   2085        instance_count,
   2086        first_vertex,
   2087        first_instance,
   2088    )
   2089 }
   2090 
   2091 #[no_mangle]
   2092 pub extern "C" fn wgpu_render_bundle_draw_indexed(
   2093    bundle: &mut RenderBundleEncoder,
   2094    index_count: u32,
   2095    instance_count: u32,
   2096    first_index: u32,
   2097    base_vertex: i32,
   2098    first_instance: u32,
   2099 ) {
   2100    wgc::command::bundle_ffi::wgpu_render_bundle_draw_indexed(
   2101        bundle,
   2102        index_count,
   2103        instance_count,
   2104        first_index,
   2105        base_vertex,
   2106        first_instance,
   2107    )
   2108 }
   2109 
   2110 #[no_mangle]
   2111 pub extern "C" fn wgpu_render_bundle_draw_indirect(
   2112    bundle: &mut RenderBundleEncoder,
   2113    buffer_id: id::BufferId,
   2114    offset: BufferAddress,
   2115 ) {
   2116    wgc::command::bundle_ffi::wgpu_render_bundle_draw_indirect(bundle, buffer_id, offset)
   2117 }
   2118 
   2119 #[no_mangle]
   2120 pub extern "C" fn wgpu_render_bundle_draw_indexed_indirect(
   2121    bundle: &mut RenderBundleEncoder,
   2122    buffer_id: id::BufferId,
   2123    offset: BufferAddress,
   2124 ) {
   2125    wgc::command::bundle_ffi::wgpu_render_bundle_draw_indexed_indirect(bundle, buffer_id, offset)
   2126 }
   2127 
   2128 #[no_mangle]
   2129 pub unsafe extern "C" fn wgpu_render_bundle_push_debug_group(
   2130    _bundle: &mut RenderBundleEncoder,
   2131    _label: RawString,
   2132 ) {
   2133    wgc::command::bundle_ffi::wgpu_render_bundle_push_debug_group(_bundle, _label)
   2134 }
   2135 
   2136 #[no_mangle]
   2137 pub extern "C" fn wgpu_render_bundle_pop_debug_group(_bundle: &mut RenderBundleEncoder) {
   2138    wgc::command::bundle_ffi::wgpu_render_bundle_pop_debug_group(_bundle)
   2139 }
   2140 
   2141 #[no_mangle]
   2142 pub unsafe extern "C" fn wgpu_render_bundle_insert_debug_marker(
   2143    _bundle: &mut RenderBundleEncoder,
   2144    _label: RawString,
   2145 ) {
   2146    wgc::command::bundle_ffi::wgpu_render_bundle_insert_debug_marker(_bundle, _label)
   2147 }