tor-browser

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

server.rs (121922B)


      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    error::{error_to_string, ErrMsg, ErrorBuffer, ErrorBufferType, OwnedErrorBuffer},
      7    make_byte_buf, wgpu_string, AdapterInformation, BufferMapResult, ByteBuf, CommandEncoderAction,
      8    DeviceAction, FfiSlice, Message, PipelineError, QueueWriteAction, QueueWriteDataSource,
      9    ServerMessage, ShaderModuleCompilationMessage, SwapChainId, TextureAction,
     10 };
     11 
     12 use nsstring::{nsACString, nsCString};
     13 
     14 use wgc::id;
     15 use wgc::{pipeline::CreateShaderModuleError, resource::BufferAccessError};
     16 #[allow(unused_imports)]
     17 use wgh::Instance;
     18 use wgt::error::{ErrorType, WebGpuError};
     19 
     20 use std::borrow::Cow;
     21 #[allow(unused_imports)]
     22 use std::mem;
     23 #[cfg(target_os = "linux")]
     24 use std::os::fd::{FromRawFd, IntoRawFd, OwnedFd, RawFd};
     25 use std::os::raw::c_char;
     26 use std::ptr;
     27 use std::sync::atomic::{AtomicU32, Ordering};
     28 use std::time::Duration;
     29 
     30 #[allow(unused_imports)]
     31 use std::ffi::CString;
     32 
     33 #[cfg(target_os = "windows")]
     34 use windows::Win32::{Foundation, Graphics::Direct3D12};
     35 
     36 #[cfg(target_os = "linux")]
     37 use ash::{khr, vk};
     38 
     39 #[cfg(target_os = "macos")]
     40 use objc::{class, msg_send, sel, sel_impl};
     41 
     42 // The seemingly redundant u64 suffixes help cbindgen with generating the right C++ code.
     43 // See https://github.com/mozilla/cbindgen/issues/849.
     44 
     45 /// We limit the size of buffer allocations for stability reason.
     46 /// We can reconsider this limit in the future. Note that some drivers (mesa for example),
     47 /// have issues when the size of a buffer, mapping or copy command does not fit into a
     48 /// signed 32 bits integer, so beyond a certain size, large allocations will need some form
     49 /// of driver allow/blocklist.
     50 pub const MAX_BUFFER_SIZE: wgt::BufferAddress = 1u64 << 30u64;
     51 const MAX_BUFFER_SIZE_U32: u32 = MAX_BUFFER_SIZE as u32;
     52 
     53 // Mesa has issues with height/depth that don't fit in a 16 bits signed integers.
     54 const MAX_TEXTURE_EXTENT: u32 = std::i16::MAX as u32;
     55 // We have to restrict the number of bindings for any given resource type so that
     56 // the sum of these limits multiplied by the number of shader stages fits
     57 // maxBindingsPerBindGroup (1000). This restriction is arbitrary and is likely to
     58 // change eventually. See github.com/gpuweb/gpuweb/pull/4484
     59 // For now it's impractical for users to have very large numbers of bindings so this
     60 // limit should not be too restrictive until we add support for a bindless API.
     61 // Then we may have to ignore the spec or get it changed.
     62 const MAX_BINDINGS_PER_RESOURCE_TYPE: u32 = 64;
     63 
     64 #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
     65 fn emit_critical_invalid_note(what: &'static str) {
     66    // SAFETY: We ensure that the pointer provided is not null.
     67    let msg = CString::new(format!("{what} is invalid")).unwrap();
     68    unsafe { gfx_critical_note(msg.as_ptr()) }
     69 }
     70 
     71 fn restrict_limits(limits: wgt::Limits) -> wgt::Limits {
     72    wgt::Limits {
     73        max_buffer_size: limits.max_buffer_size.min(MAX_BUFFER_SIZE),
     74        max_texture_dimension_1d: limits.max_texture_dimension_1d.min(MAX_TEXTURE_EXTENT),
     75        max_texture_dimension_2d: limits.max_texture_dimension_2d.min(MAX_TEXTURE_EXTENT),
     76        max_texture_dimension_3d: limits.max_texture_dimension_3d.min(MAX_TEXTURE_EXTENT),
     77        max_sampled_textures_per_shader_stage: limits
     78            .max_sampled_textures_per_shader_stage
     79            .min(MAX_BINDINGS_PER_RESOURCE_TYPE),
     80        max_samplers_per_shader_stage: limits
     81            .max_samplers_per_shader_stage
     82            .min(MAX_BINDINGS_PER_RESOURCE_TYPE),
     83        max_storage_textures_per_shader_stage: limits
     84            .max_storage_textures_per_shader_stage
     85            .min(MAX_BINDINGS_PER_RESOURCE_TYPE),
     86        max_uniform_buffers_per_shader_stage: limits
     87            .max_uniform_buffers_per_shader_stage
     88            .min(MAX_BINDINGS_PER_RESOURCE_TYPE),
     89        max_storage_buffers_per_shader_stage: limits
     90            .max_storage_buffers_per_shader_stage
     91            .min(MAX_BINDINGS_PER_RESOURCE_TYPE),
     92        max_uniform_buffer_binding_size: limits
     93            .max_uniform_buffer_binding_size
     94            .min(MAX_BUFFER_SIZE_U32),
     95        max_storage_buffer_binding_size: limits
     96            .max_storage_buffer_binding_size
     97            .min(MAX_BUFFER_SIZE_U32),
     98        max_non_sampler_bindings: 500_000,
     99        ..limits
    100    }
    101 }
    102 
    103 /// Opaque pointer to `mozilla::webgpu::WebGPUParent`.
    104 #[derive(Debug, Clone, Copy)]
    105 #[repr(transparent)]
    106 pub struct WebGPUParentPtr(*mut core::ffi::c_void);
    107 
    108 // hide wgc's global in private
    109 pub struct Global {
    110    owner: WebGPUParentPtr,
    111    global: wgc::global::Global,
    112 }
    113 
    114 impl std::ops::Deref for Global {
    115    type Target = wgc::global::Global;
    116    fn deref(&self) -> &Self::Target {
    117        &self.global
    118    }
    119 }
    120 
    121 #[no_mangle]
    122 pub extern "C" fn wgpu_server_new(owner: WebGPUParentPtr) -> *mut Global {
    123    log::info!("Initializing WGPU server");
    124    let backends_pref = static_prefs::pref!("dom.webgpu.wgpu-backend").to_string();
    125    let backends = if backends_pref.is_empty() {
    126        #[cfg(windows)]
    127        {
    128            wgt::Backends::DX12
    129        }
    130        #[cfg(not(windows))]
    131        {
    132            wgt::Backends::PRIMARY
    133        }
    134    } else {
    135        log::info!(
    136            "Selecting backends based on dom.webgpu.wgpu-backend pref: {:?}",
    137            backends_pref
    138        );
    139        wgt::Backends::from_comma_list(&backends_pref)
    140    };
    141 
    142    let mut instance_flags = wgt::InstanceFlags::from_build_config().with_env();
    143    if !static_prefs::pref!("dom.webgpu.hal-labels") {
    144        instance_flags.insert(wgt::InstanceFlags::DISCARD_HAL_LABELS);
    145    }
    146 
    147    let dx12_shader_compiler = wgt::Dx12Compiler::DynamicDxc {
    148        dxc_path: "dxcompiler.dll".into(),
    149        max_shader_model: wgt::DxcShaderModel::V6_6,
    150    };
    151 
    152    let global = wgc::global::Global::new(
    153        "wgpu",
    154        wgt::InstanceDescriptor {
    155            backends,
    156            flags: instance_flags,
    157            backend_options: wgt::BackendOptions {
    158                gl: wgt::GlBackendOptions {
    159                    gles_minor_version: wgt::Gles3MinorVersion::Automatic,
    160                    fence_behavior: wgt::GlFenceBehavior::Normal,
    161                },
    162                dx12: wgt::Dx12BackendOptions {
    163                    shader_compiler: dx12_shader_compiler,
    164                    ..Default::default()
    165                },
    166                noop: wgt::NoopBackendOptions { enable: false },
    167            },
    168            memory_budget_thresholds: wgt::MemoryBudgetThresholds {
    169                for_resource_creation: Some(95),
    170                for_device_loss: Some(99),
    171            },
    172            display: None,
    173        },
    174        None,
    175    );
    176    let global = Global { owner, global };
    177    Box::into_raw(Box::new(global))
    178 }
    179 
    180 /// # Safety
    181 ///
    182 /// This function is unsafe because improper use may lead to memory
    183 /// problems. For example, a double-free may occur if the function is called
    184 /// twice on the same raw pointer.
    185 #[no_mangle]
    186 pub unsafe extern "C" fn wgpu_server_delete(global: *mut Global) {
    187    log::info!("Terminating WGPU server");
    188    let _ = Box::from_raw(global);
    189 }
    190 
    191 #[no_mangle]
    192 pub extern "C" fn wgpu_server_poll_all_devices(global: &Global, force_wait: bool) {
    193    global.poll_all_devices(force_wait).unwrap();
    194 }
    195 
    196 #[no_mangle]
    197 pub extern "C" fn wgpu_server_device_poll(
    198    global: &Global,
    199    device_id: id::DeviceId,
    200    force_wait: bool,
    201 ) {
    202    let maintain = if force_wait {
    203        wgt::PollType::Wait {
    204            submission_index: None,
    205            timeout: Some(Duration::from_secs(60)),
    206        }
    207    } else {
    208        wgt::PollType::Poll
    209    };
    210    global.device_poll(device_id, maintain).unwrap();
    211 }
    212 
    213 #[repr(C)]
    214 #[derive(Clone, Copy, Debug)]
    215 #[allow(clippy::upper_case_acronyms)]
    216 #[cfg(target_os = "macos")]
    217 struct NSOperatingSystemVersion {
    218    major: usize,
    219    minor: usize,
    220    patch: usize,
    221 }
    222 
    223 #[cfg(target_os = "macos")]
    224 impl NSOperatingSystemVersion {
    225    fn at_least(
    226        &self,
    227        mac_version: (usize, usize),
    228        ios_version: (usize, usize),
    229        is_mac: bool,
    230    ) -> bool {
    231        let version = if is_mac { mac_version } else { ios_version };
    232 
    233        self.major
    234            .cmp(&version.0)
    235            .then_with(|| self.minor.cmp(&version.1))
    236            .is_ge()
    237    }
    238 }
    239 
    240 #[allow(unreachable_code)]
    241 #[allow(unused_variables)]
    242 fn support_use_shared_texture_in_swap_chain(
    243    global: &Global,
    244    self_id: id::AdapterId,
    245    backend: wgt::Backend,
    246    is_hardware: bool,
    247 ) -> bool {
    248    #[cfg(target_os = "windows")]
    249    {
    250        if backend != wgt::Backend::Dx12 {
    251            log::info!(concat!(
    252                "WebGPU: disabling SharedTexture swapchain: \n",
    253                "wgpu backend is not Dx12"
    254            ));
    255            return false;
    256        }
    257        if !is_hardware {
    258            log::info!(concat!(
    259                "WebGPU: disabling SharedTexture swapchain: \n",
    260                "Dx12 backend is not hardware"
    261            ));
    262            return false;
    263        }
    264        return true;
    265    }
    266 
    267    #[cfg(target_os = "linux")]
    268    {
    269        if backend != wgt::Backend::Vulkan {
    270            log::info!(concat!(
    271                "WebGPU: disabling SharedTexture swapchain: \n",
    272                "wgpu backend is not Vulkan"
    273            ));
    274            return false;
    275        }
    276 
    277        let Some(hal_adapter) = (unsafe { global.adapter_as_hal::<wgc::api::Vulkan>(self_id) })
    278        else {
    279            unreachable!("given adapter ID was actually for a different backend");
    280        };
    281 
    282        let capabilities = hal_adapter.physical_device_capabilities();
    283        static REQUIRED: &[&'static std::ffi::CStr] = &[
    284            khr::external_memory_fd::NAME,
    285            ash::ext::external_memory_dma_buf::NAME,
    286            ash::ext::image_drm_format_modifier::NAME,
    287            khr::external_semaphore_fd::NAME,
    288        ];
    289        let all_extensions_supported = REQUIRED.iter().all(|&extension| {
    290            let supported = capabilities.supports_extension(extension);
    291            if !supported {
    292                log::info!(
    293                    concat!(
    294                        "WebGPU: disabling SharedTexture swapchain: \n",
    295                        "Vulkan extension not supported: {:?}",
    296                    ),
    297                    extension.to_string_lossy()
    298                );
    299            }
    300            supported
    301        });
    302        if !all_extensions_supported {
    303            return false;
    304        }
    305 
    306        // We need to be able to export the semaphore that gets signalled
    307        // when the GPU is done drawing on the ExternalTextureDMABuf.
    308        let semaphore_info = vk::PhysicalDeviceExternalSemaphoreInfo::default()
    309            .handle_type(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
    310        let mut semaphore_props = vk::ExternalSemaphoreProperties::default();
    311        unsafe {
    312            hal_adapter
    313                .shared_instance()
    314                .raw_instance()
    315                .get_physical_device_external_semaphore_properties(
    316                    hal_adapter.raw_physical_device(),
    317                    &semaphore_info,
    318                    &mut semaphore_props,
    319                );
    320        }
    321        if !semaphore_props
    322            .external_semaphore_features
    323            .contains(vk::ExternalSemaphoreFeatureFlags::EXPORTABLE)
    324        {
    325            log::info!(
    326                "WebGPU: disabling ExternalTexture swapchain: \n\
    327                        device can't export opaque file descriptor semaphores"
    328            );
    329            return false;
    330        }
    331 
    332        return true;
    333    }
    334 
    335    #[cfg(target_os = "macos")]
    336    {
    337        if backend != wgt::Backend::Metal {
    338            log::info!(concat!(
    339                "WebGPU: disabling SharedTexture swapchain: \n",
    340                "wgpu backend is not Metal"
    341            ));
    342            return false;
    343        }
    344        if !is_hardware {
    345            log::info!(concat!(
    346                "WebGPU: disabling SharedTexture swapchain: \n",
    347                "Metal backend is not hardware"
    348            ));
    349            return false;
    350        }
    351 
    352        let version: NSOperatingSystemVersion = unsafe {
    353            let process_info: *mut objc::runtime::Object =
    354                msg_send![class!(NSProcessInfo), processInfo];
    355            msg_send![process_info, operatingSystemVersion]
    356        };
    357 
    358        if !version.at_least((10, 14), (12, 0), /* os_is_mac */ true) {
    359            log::info!(concat!(
    360                "WebGPU: disabling SharedTexture swapchain:\n",
    361                "operating system version is not at least 10.14 (macOS) or 12.0 (iOS)\n",
    362                "shared event not supported"
    363            ));
    364            return false;
    365        }
    366 
    367        return true;
    368    }
    369 
    370    false
    371 }
    372 
    373 static TRACE_IDX: AtomicU32 = AtomicU32::new(0);
    374 
    375 unsafe fn adapter_request_device(
    376    global: &Global,
    377    self_id: id::AdapterId,
    378    mut desc: wgc::device::DeviceDescriptor,
    379    new_device_id: id::DeviceId,
    380    new_queue_id: id::QueueId,
    381 ) -> Option<String> {
    382    if let wgt::Trace::Directory(ref path) = desc.trace {
    383        log::warn!(
    384            concat!(
    385                "`DeviceDescriptor` from child process ",
    386                "should not request wgpu trace path, ",
    387                "but it did request `{}`"
    388            ),
    389            path.display()
    390        );
    391    }
    392    desc.trace = wgt::Trace::Off;
    393    if let Some(env_dir) = std::env::var_os("WGPU_TRACE") {
    394        let mut path = std::path::PathBuf::from(env_dir);
    395        let idx = TRACE_IDX.fetch_add(1, Ordering::Relaxed);
    396        path.push(idx.to_string());
    397 
    398        if std::fs::create_dir_all(&path).is_err() {
    399            log::warn!("Failed to create directory {:?} for wgpu recording.", path);
    400        } else {
    401            desc.trace = wgt::Trace::Directory(path);
    402        }
    403    }
    404 
    405    if desc.experimental_features.is_enabled() {
    406        log::warn!(
    407            concat!(
    408                "`DeviceDescriptor` from child process ",
    409                "should not enable experimental features, ",
    410                "but it did request {:?}"
    411            ),
    412            desc.experimental_features
    413        );
    414    }
    415 
    416    if wgpu_parent_is_external_texture_enabled() {
    417        // Enable features used for external texture support, if available. We
    418        // avoid adding unsupported features to required_features so that we
    419        // can still create a device in their absence, and will only fail when
    420        // performing an operation that actually requires the feature.
    421        for feature in [
    422            wgt::Features::EXTERNAL_TEXTURE,
    423            wgt::Features::TEXTURE_FORMAT_NV12,
    424            wgt::Features::TEXTURE_FORMAT_P010,
    425            wgt::Features::TEXTURE_FORMAT_16BIT_NORM,
    426        ] {
    427            if global.adapter_features(self_id).contains(feature) {
    428                desc.required_features.insert(feature);
    429            }
    430        }
    431    }
    432 
    433    // TODO: in https://github.com/gfx-rs/wgpu/pull/3626/files#diff-033343814319f5a6bd781494692ea626f06f6c3acc0753a12c867b53a646c34eR97
    434    // which introduced the queue id parameter, the queue id is also the device id. I don't know how applicable this is to
    435    // other situations (this one in particular).
    436 
    437    #[cfg(target_os = "linux")]
    438    {
    439        let hal_adapter = global.adapter_as_hal::<wgc::api::Vulkan>(self_id);
    440 
    441        let support_dma_buf = hal_adapter.as_ref().is_some_and(|hal_adapter| {
    442            let capabilities = hal_adapter.physical_device_capabilities();
    443 
    444            capabilities.supports_extension(khr::external_memory_fd::NAME)
    445                && capabilities.supports_extension(ash::ext::external_memory_dma_buf::NAME)
    446                && capabilities.supports_extension(ash::ext::image_drm_format_modifier::NAME)
    447                && capabilities.supports_extension(khr::external_semaphore_fd::NAME)
    448        });
    449 
    450        match (hal_adapter, support_dma_buf) {
    451            (None, _) => {
    452                emit_critical_invalid_note("Vulkan adapter");
    453            }
    454            (Some(_), false) => {}
    455            (Some(hal_adapter), true) => {
    456                let mut enabled_extensions =
    457                    hal_adapter.required_device_extensions(desc.required_features);
    458                enabled_extensions.push(khr::external_memory_fd::NAME);
    459                enabled_extensions.push(ash::ext::external_memory_dma_buf::NAME);
    460                enabled_extensions.push(ash::ext::image_drm_format_modifier::NAME);
    461                enabled_extensions.push(khr::external_semaphore_fd::NAME);
    462 
    463                let mut enabled_phd_features = hal_adapter
    464                    .physical_device_features(&enabled_extensions, desc.required_features);
    465 
    466                let raw_instance = hal_adapter.shared_instance().raw_instance();
    467                let raw_physical_device = hal_adapter.raw_physical_device();
    468 
    469                let queue_family_index = raw_instance
    470                    .get_physical_device_queue_family_properties(raw_physical_device)
    471                    .into_iter()
    472                    .enumerate()
    473                    .find_map(|(queue_family_index, info)| {
    474                        if info.queue_flags.contains(vk::QueueFlags::GRAPHICS) {
    475                            Some(queue_family_index as u32)
    476                        } else {
    477                            None
    478                        }
    479                    });
    480 
    481                let Some(queue_family_index) = queue_family_index else {
    482                    let msg = c"Vulkan device has no graphics queue";
    483                    gfx_critical_note(msg.as_ptr());
    484                    return Some(format!("Internal Error: Failed to create ash::Device"));
    485                };
    486 
    487                let family_info = vk::DeviceQueueCreateInfo::default()
    488                    .queue_family_index(queue_family_index)
    489                    .queue_priorities(&[1.0]);
    490                let family_infos = [family_info];
    491 
    492                let str_pointers = enabled_extensions
    493                    .iter()
    494                    .map(|&s| {
    495                        // Safe because `enabled_extensions` entries have static lifetime.
    496                        s.as_ptr()
    497                    })
    498                    .collect::<Vec<_>>();
    499 
    500                let pre_info = vk::DeviceCreateInfo::default()
    501                    .queue_create_infos(&family_infos)
    502                    .enabled_extension_names(&str_pointers);
    503                let info = enabled_phd_features.add_to_device_create(pre_info);
    504 
    505                let raw_device = match raw_instance.create_device(raw_physical_device, &info, None)
    506                {
    507                    Err(err) => {
    508                        let msg =
    509                            CString::new(format!("create_device() failed: {:?}", err)).unwrap();
    510                        gfx_critical_note(msg.as_ptr());
    511                        return Some(format!("Internal Error: Failed to create ash::Device"));
    512                    }
    513                    Ok(raw_device) => raw_device,
    514                };
    515 
    516                let hal_device = match hal_adapter.device_from_raw(
    517                    raw_device,
    518                    None,
    519                    &enabled_extensions,
    520                    desc.required_features,
    521                    &desc.memory_hints,
    522                    family_info.queue_family_index,
    523                    0,
    524                ) {
    525                    Err(err) => {
    526                        let msg =
    527                            CString::new(format!("device_from_raw() failed: {:?}", err)).unwrap();
    528                        gfx_critical_note(msg.as_ptr());
    529                        return Some(format!("Internal Error: Failed to create ash::Device"));
    530                    }
    531                    Ok(hal_device) => hal_device,
    532                };
    533 
    534                let res = global.create_device_from_hal(
    535                    self_id,
    536                    hal_device.into(),
    537                    &desc,
    538                    Some(new_device_id),
    539                    Some(new_queue_id),
    540                );
    541                if let Err(err) = res {
    542                    return Some(format!("{err}"));
    543                }
    544                return None;
    545            }
    546        }
    547    }
    548 
    549    let res =
    550        global.adapter_request_device(self_id, &desc, Some(new_device_id), Some(new_queue_id));
    551    if let Err(err) = res {
    552        return Some(format!("{err}"));
    553    } else {
    554        return None;
    555    }
    556 }
    557 
    558 #[repr(C)]
    559 pub struct DeviceLostClosure {
    560    pub callback: unsafe extern "C" fn(user_data: *mut u8, reason: u8, message: *const c_char),
    561    pub cleanup_callback: unsafe extern "C" fn(user_data: *mut u8),
    562    pub user_data: *mut u8,
    563 }
    564 unsafe impl Send for DeviceLostClosure {}
    565 
    566 impl DeviceLostClosure {
    567    fn call(self, reason: wgt::DeviceLostReason, message: String) {
    568        // Ensure message is structured as a null-terminated C string. It only
    569        // needs to live as long as the callback invocation.
    570        let message = std::ffi::CString::new(message).unwrap();
    571        unsafe {
    572            (self.callback)(self.user_data, reason as u8, message.as_ptr());
    573        }
    574        core::mem::forget(self);
    575    }
    576 }
    577 
    578 impl Drop for DeviceLostClosure {
    579    fn drop(&mut self) {
    580        unsafe {
    581            (self.cleanup_callback)(self.user_data);
    582        }
    583    }
    584 }
    585 
    586 #[no_mangle]
    587 pub unsafe extern "C" fn wgpu_server_set_device_lost_callback(
    588    global: &Global,
    589    self_id: id::DeviceId,
    590    closure: DeviceLostClosure,
    591 ) {
    592    let closure = Box::new(move |reason, message| closure.call(reason, message));
    593    global.device_set_device_lost_closure(self_id, closure);
    594 }
    595 
    596 impl ShaderModuleCompilationMessage {
    597    fn new(error: &CreateShaderModuleError, source: &str) -> Self {
    598        // The WebGPU spec says that if the message doesn't point to a particular position in
    599        // the source, the line number, position, offset and lengths should be zero.
    600        let line_number;
    601        let line_pos;
    602        let utf16_offset;
    603        let utf16_length;
    604 
    605        let location = match error {
    606            CreateShaderModuleError::Parsing(e) => e.inner.location(source),
    607            CreateShaderModuleError::Validation(e) => e.inner.location(source),
    608            _ => None,
    609        };
    610 
    611        if let Some(location) = location {
    612            let len_utf16 = |s: &str| s.chars().map(|c| c.len_utf16() as u64).sum();
    613            let start = location.offset as usize;
    614            let end = start + location.length as usize;
    615            utf16_offset = len_utf16(&source[0..start]);
    616            utf16_length = len_utf16(&source[start..end]);
    617 
    618            line_number = location.line_number as u64;
    619            // Naga reports a `line_pos` using UTF-8 bytes, so we cannot use it.
    620            let line_start = source[0..start].rfind('\n').map(|pos| pos + 1).unwrap_or(0);
    621            line_pos = len_utf16(&source[line_start..start]) + 1;
    622        } else {
    623            line_number = 0;
    624            line_pos = 0;
    625            utf16_offset = 0;
    626            utf16_length = 0;
    627        }
    628 
    629        let message = error.to_string();
    630 
    631        Self {
    632            line_number,
    633            line_pos,
    634            utf16_offset,
    635            utf16_length,
    636            message,
    637        }
    638    }
    639 }
    640 
    641 #[no_mangle]
    642 pub extern "C" fn wgpu_server_device_create_buffer(
    643    global: &Global,
    644    device_id: id::DeviceId,
    645    buffer_id: id::BufferId,
    646    label: Option<&nsACString>,
    647    size: wgt::BufferAddress,
    648    usage: u32,
    649    mapped_at_creation: bool,
    650    mut error_buf: ErrorBuffer,
    651 ) {
    652    let utf8_label = label.map(|utf16| utf16.to_string());
    653    let label = utf8_label.as_ref().map(|s| Cow::from(&s[..]));
    654    let usage = wgt::BufferUsages::from_bits_retain(usage);
    655 
    656    let desc = wgc::resource::BufferDescriptor {
    657        label,
    658        size,
    659        usage,
    660        mapped_at_creation,
    661    };
    662 
    663    let (_, error) = global.device_create_buffer(device_id, &desc, Some(buffer_id));
    664    if let Some(err) = error {
    665        error_buf.init(err, device_id);
    666    }
    667 }
    668 
    669 /// The status code provided to the buffer mapping closure.
    670 ///
    671 /// This is very similar to `BufferAccessResult`, except that this is FFI-friendly.
    672 #[repr(C)]
    673 pub enum BufferMapAsyncStatus {
    674    /// The Buffer is successfully mapped, `get_mapped_range` can be called.
    675    ///
    676    /// All other variants of this enum represent failures to map the buffer.
    677    Success,
    678    /// The buffer is already mapped.
    679    ///
    680    /// While this is treated as an error, it does not prevent mapped range from being accessed.
    681    AlreadyMapped,
    682    /// Mapping was already requested.
    683    MapAlreadyPending,
    684    /// An unknown error.
    685    Error,
    686    /// The context is Lost.
    687    ContextLost,
    688    /// The buffer is in an invalid state.
    689    Invalid,
    690    /// The range isn't fully contained in the buffer.
    691    InvalidRange,
    692    /// The range isn't properly aligned.
    693    InvalidAlignment,
    694    /// Incompatible usage flags.
    695    InvalidUsageFlags,
    696 }
    697 
    698 impl From<Result<(), BufferAccessError>> for BufferMapAsyncStatus {
    699    fn from(result: Result<(), BufferAccessError>) -> Self {
    700        match result {
    701            Ok(_) => BufferMapAsyncStatus::Success,
    702            Err(BufferAccessError::Device(_)) => BufferMapAsyncStatus::ContextLost,
    703            Err(BufferAccessError::InvalidResource(_))
    704            | Err(BufferAccessError::DestroyedResource(_)) => BufferMapAsyncStatus::Invalid,
    705            Err(BufferAccessError::AlreadyMapped) => BufferMapAsyncStatus::AlreadyMapped,
    706            Err(BufferAccessError::MapAlreadyPending) => BufferMapAsyncStatus::MapAlreadyPending,
    707            Err(BufferAccessError::MissingBufferUsage(_)) => {
    708                BufferMapAsyncStatus::InvalidUsageFlags
    709            }
    710            Err(BufferAccessError::UnalignedRange)
    711            | Err(BufferAccessError::UnalignedRangeSize { .. })
    712            | Err(BufferAccessError::UnalignedOffset { .. }) => {
    713                BufferMapAsyncStatus::InvalidAlignment
    714            }
    715            Err(BufferAccessError::OutOfBoundsUnderrun { .. })
    716            | Err(BufferAccessError::OutOfBoundsOverrun { .. })
    717            | Err(BufferAccessError::NegativeRange { .. }) => BufferMapAsyncStatus::InvalidRange,
    718            Err(BufferAccessError::Failed)
    719            | Err(BufferAccessError::NotMapped)
    720            | Err(BufferAccessError::MapAborted) => BufferMapAsyncStatus::Error,
    721            Err(_) => BufferMapAsyncStatus::Invalid,
    722        }
    723    }
    724 }
    725 
    726 #[repr(C)]
    727 pub struct BufferMapClosure {
    728    pub callback: unsafe extern "C" fn(user_data: *mut u8, status: BufferMapAsyncStatus),
    729    pub user_data: *mut u8,
    730 }
    731 unsafe impl Send for BufferMapClosure {}
    732 
    733 /// # Safety
    734 ///
    735 /// Callers are responsible for ensuring `closure` is well-formed.
    736 #[no_mangle]
    737 pub unsafe extern "C" fn wgpu_server_buffer_map(
    738    global: &Global,
    739    device_id: id::DeviceId,
    740    buffer_id: id::BufferId,
    741    start: wgt::BufferAddress,
    742    size: wgt::BufferAddress,
    743    map_mode: wgc::device::HostMap,
    744    closure: BufferMapClosure,
    745    mut error_buf: ErrorBuffer,
    746 ) {
    747    let closure = Box::new(move |result| {
    748        let _ = &closure;
    749        (closure.callback)(closure.user_data, BufferMapAsyncStatus::from(result))
    750    });
    751    let operation = wgc::resource::BufferMapOperation {
    752        host: map_mode,
    753        callback: Some(closure),
    754    };
    755    let result = global.buffer_map_async(buffer_id, start, Some(size), operation);
    756 
    757    if let Err(error) = result {
    758        error_buf.init(error, device_id);
    759    }
    760 }
    761 
    762 #[repr(C)]
    763 pub struct MappedBufferSlice {
    764    pub ptr: *mut u8,
    765    pub length: u64,
    766 }
    767 
    768 /// # Safety
    769 ///
    770 /// This function is unsafe as there is no guarantee that the given pointer is
    771 /// valid for `size` elements.
    772 #[no_mangle]
    773 pub unsafe extern "C" fn wgpu_server_buffer_get_mapped_range(
    774    global: &Global,
    775    device_id: id::DeviceId,
    776    buffer_id: id::BufferId,
    777    start: wgt::BufferAddress,
    778    size: wgt::BufferAddress,
    779    mut error_buf: ErrorBuffer,
    780 ) -> MappedBufferSlice {
    781    let result = global.buffer_get_mapped_range(buffer_id, start, Some(size));
    782 
    783    let (ptr, length) = result
    784        .map(|(ptr, len)| (ptr.as_ptr(), len))
    785        .unwrap_or_else(|error| {
    786            error_buf.init(error, device_id);
    787            (std::ptr::null_mut(), 0)
    788        });
    789    MappedBufferSlice { ptr, length }
    790 }
    791 
    792 #[no_mangle]
    793 pub extern "C" fn wgpu_server_buffer_unmap(
    794    global: &Global,
    795    device_id: id::DeviceId,
    796    buffer_id: id::BufferId,
    797    mut error_buf: ErrorBuffer,
    798 ) {
    799    if let Err(e) = global.buffer_unmap(buffer_id) {
    800        match e {
    801            // NOTE: This is presumed by CTS test cases, and was even formally specified in the
    802            // WebGPU spec. previously, but this doesn't seem formally specified now. :confused:
    803            //
    804            // TODO: upstream this; see <https://bugzilla.mozilla.org/show_bug.cgi?id=1842297>.
    805            BufferAccessError::InvalidResource(_) => (),
    806            other => error_buf.init(other, device_id),
    807        }
    808    }
    809 }
    810 
    811 #[no_mangle]
    812 pub unsafe extern "C" fn wgpu_server_device_create_texture(
    813    global: &Global,
    814    device_id: id::DeviceId,
    815    id_in: id::TextureId,
    816    desc: &wgt::TextureDescriptor<Option<&nsACString>, crate::FfiSlice<wgt::TextureFormat>>,
    817    mut error_buf: ErrorBuffer,
    818 ) {
    819    let desc = desc.map_label_and_view_formats(|l| wgpu_string(*l), |v| v.as_slice().to_vec());
    820    let (_, err) = global.device_create_texture(device_id, &desc, Some(id_in));
    821    if let Some(err) = err {
    822        error_buf.init(err, device_id);
    823    }
    824 }
    825 
    826 #[no_mangle]
    827 pub extern "C" fn wgpu_server_texture_destroy(global: &Global, id: id::TextureId) {
    828    global.texture_destroy(id);
    829 }
    830 
    831 #[no_mangle]
    832 pub extern "C" fn wgpu_server_texture_drop(global: &Global, id: id::TextureId) {
    833    global.texture_drop(id);
    834 }
    835 
    836 #[no_mangle]
    837 pub unsafe extern "C" fn wgpu_server_texture_create_view(
    838    global: &Global,
    839    device_id: id::DeviceId,
    840    texture_id: id::TextureId,
    841    id_in: id::TextureViewId,
    842    desc: &crate::TextureViewDescriptor,
    843    mut error_buf: ErrorBuffer,
    844 ) {
    845    let desc = wgc::resource::TextureViewDescriptor {
    846        label: wgpu_string(desc.label),
    847        format: desc.format.cloned(),
    848        dimension: desc.dimension.cloned(),
    849        range: wgt::ImageSubresourceRange {
    850            aspect: desc.aspect,
    851            base_mip_level: desc.base_mip_level,
    852            mip_level_count: desc.mip_level_count.map(|ptr| *ptr),
    853            base_array_layer: desc.base_array_layer,
    854            array_layer_count: desc.array_layer_count.map(|ptr| *ptr),
    855        },
    856        usage: None,
    857    };
    858    let (_, err) = global.texture_create_view(texture_id, &desc, Some(id_in));
    859    if let Some(err) = err {
    860        error_buf.init(err, device_id);
    861    }
    862 }
    863 
    864 #[no_mangle]
    865 pub extern "C" fn wgpu_server_texture_view_drop(global: &Global, id: id::TextureViewId) {
    866    global.texture_view_drop(id).unwrap();
    867 }
    868 
    869 #[allow(unused_variables)]
    870 #[no_mangle]
    871 #[cfg(target_os = "windows")]
    872 pub extern "C" fn wgpu_server_get_device_fence_handle(
    873    global: &Global,
    874    device_id: id::DeviceId,
    875 ) -> *mut core::ffi::c_void {
    876    unsafe {
    877        let Some(dx12_device) = global
    878            .device_as_hal::<wgc::api::Dx12>(device_id)
    879            .map(|device| device.raw_device().clone())
    880        else {
    881            return ptr::null_mut();
    882        };
    883 
    884        let Some(dx12_fence) = global
    885            .device_fence_as_hal::<wgc::api::Dx12>(device_id)
    886            .map(|fence| fence.raw_fence().clone())
    887        else {
    888            return ptr::null_mut();
    889        };
    890 
    891        match dx12_device.CreateSharedHandle(&dx12_fence, None, Foundation::GENERIC_ALL.0, None) {
    892            Ok(handle) => handle.0,
    893            Err(_) => ptr::null_mut(),
    894        }
    895    }
    896 }
    897 
    898 #[derive(Debug)]
    899 #[repr(C)]
    900 pub struct DMABufInfo {
    901    pub is_valid: bool,
    902    pub modifier: u64,
    903    pub plane_count: u32,
    904    pub offsets: [u64; 3],
    905    pub strides: [u64; 3],
    906 }
    907 
    908 #[derive(Debug)]
    909 #[cfg(target_os = "linux")]
    910 pub struct VkImageHandle {
    911    pub device: vk::Device,
    912    pub image: vk::Image,
    913    pub memory: vk::DeviceMemory,
    914    pub memory_size: u64,
    915    pub memory_type_index: u32,
    916    pub modifier: u64,
    917    pub layouts: Vec<vk::SubresourceLayout>,
    918 }
    919 
    920 #[cfg(target_os = "linux")]
    921 impl VkImageHandle {
    922    fn destroy(&self, global: &Global, device_id: id::DeviceId) {
    923        unsafe {
    924            let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else {
    925                return;
    926            };
    927 
    928            let device = hal_device.raw_device();
    929 
    930            (device.fp_v1_0().destroy_image)(self.device, self.image, ptr::null());
    931            (device.fp_v1_0().free_memory)(self.device, self.memory, ptr::null());
    932        };
    933    }
    934 }
    935 
    936 #[no_mangle]
    937 #[cfg(target_os = "linux")]
    938 pub extern "C" fn wgpu_vkimage_create_with_dma_buf(
    939    global: &Global,
    940    device_id: id::DeviceId,
    941    width: u32,
    942    height: u32,
    943    out_memory_size: *mut u64,
    944 ) -> *mut VkImageHandle {
    945    unsafe {
    946        let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else {
    947            emit_critical_invalid_note("Vulkan device");
    948            return ptr::null_mut();
    949        };
    950 
    951        let device = hal_device.raw_device();
    952        let physical_device = hal_device.raw_physical_device();
    953        let instance = hal_device.shared_instance().raw_instance();
    954 
    955        let count = {
    956            let mut drm_format_modifier_props_list =
    957                vk::DrmFormatModifierPropertiesListEXT::default();
    958            let mut format_properties_2 =
    959                vk::FormatProperties2::default().push_next(&mut drm_format_modifier_props_list);
    960 
    961            instance.get_physical_device_format_properties2(
    962                physical_device,
    963                vk::Format::B8G8R8A8_UNORM,
    964                &mut format_properties_2,
    965            );
    966            drm_format_modifier_props_list.drm_format_modifier_count
    967        };
    968 
    969        if count == 0 {
    970            let msg = c"get_physical_device_format_properties2() failed";
    971            gfx_critical_note(msg.as_ptr());
    972            return ptr::null_mut();
    973        }
    974 
    975        let mut modifier_props =
    976            vec![vk::DrmFormatModifierPropertiesEXT::default(); count as usize];
    977 
    978        let mut drm_format_modifier_props_list = vk::DrmFormatModifierPropertiesListEXT::default()
    979            .drm_format_modifier_properties(&mut modifier_props);
    980        let mut format_properties_2 =
    981            vk::FormatProperties2::default().push_next(&mut drm_format_modifier_props_list);
    982 
    983        instance.get_physical_device_format_properties2(
    984            physical_device,
    985            vk::Format::B8G8R8A8_UNORM,
    986            &mut format_properties_2,
    987        );
    988 
    989        let mut usage_flags = vk::ImageUsageFlags::empty();
    990        usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT;
    991 
    992        modifier_props.retain(|modifier_prop| {
    993            let support = is_dmabuf_supported(
    994                instance,
    995                physical_device,
    996                vk::Format::B8G8R8A8_UNORM,
    997                modifier_prop.drm_format_modifier,
    998                usage_flags,
    999            );
   1000            support
   1001        });
   1002 
   1003        if modifier_props.is_empty() {
   1004            let msg = c"format not supported for dmabuf import";
   1005            gfx_critical_note(msg.as_ptr());
   1006            return ptr::null_mut();
   1007        }
   1008 
   1009        let modifiers: Vec<u64> = modifier_props
   1010            .iter()
   1011            .map(|modifier_prop| modifier_prop.drm_format_modifier)
   1012            .collect();
   1013 
   1014        let mut modifier_list =
   1015            vk::ImageDrmFormatModifierListCreateInfoEXT::default().drm_format_modifiers(&modifiers);
   1016 
   1017        let extent = vk::Extent3D {
   1018            width,
   1019            height,
   1020            depth: 1,
   1021        };
   1022 
   1023        let mut external_image_create_info = vk::ExternalMemoryImageCreateInfo::default()
   1024            .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
   1025 
   1026        let mut export_memory_alloc_info = vk::ExportMemoryAllocateInfo::default()
   1027            .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
   1028 
   1029        let flags = vk::ImageCreateFlags::empty();
   1030 
   1031        let vk_info = vk::ImageCreateInfo::default()
   1032            .flags(flags)
   1033            .image_type(vk::ImageType::TYPE_2D)
   1034            // Bug 1971883: Rather than hard-coding this format, we should use
   1035            // whatever format was negotiated between `GPUCanvasContext.configure`
   1036            // and the GPU process.
   1037            .format(vk::Format::B8G8R8A8_UNORM)
   1038            .extent(extent)
   1039            .mip_levels(1)
   1040            .array_layers(1)
   1041            .samples(vk::SampleCountFlags::TYPE_1)
   1042            .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT)
   1043            .usage(usage_flags)
   1044            .sharing_mode(vk::SharingMode::EXCLUSIVE)
   1045            .initial_layout(vk::ImageLayout::UNDEFINED)
   1046            .push_next(&mut modifier_list)
   1047            .push_next(&mut external_image_create_info);
   1048 
   1049        let image = match device.create_image(&vk_info, None) {
   1050            Err(err) => {
   1051                let msg = CString::new(format!("create_image() failed: {:?}", err)).unwrap();
   1052                gfx_critical_note(msg.as_ptr());
   1053                return ptr::null_mut();
   1054            }
   1055            Ok(image) => image,
   1056        };
   1057 
   1058        let mut image_modifier_properties = vk::ImageDrmFormatModifierPropertiesEXT::default();
   1059        let image_drm_format_modifier =
   1060            ash::ext::image_drm_format_modifier::Device::new(instance, device);
   1061        let ret = image_drm_format_modifier
   1062            .get_image_drm_format_modifier_properties(image, &mut image_modifier_properties);
   1063        if ret.is_err() {
   1064            let msg = CString::new(format!(
   1065                "get_image_drm_format_modifier_properties() failed: {:?}",
   1066                ret
   1067            ))
   1068            .unwrap();
   1069            gfx_critical_note(msg.as_ptr());
   1070            return ptr::null_mut();
   1071        }
   1072 
   1073        let memory_req = device.get_image_memory_requirements(image);
   1074 
   1075        let mem_properties = instance.get_physical_device_memory_properties(physical_device);
   1076 
   1077        let index = mem_properties
   1078            .memory_types
   1079            .iter()
   1080            .enumerate()
   1081            .position(|(i, t)| {
   1082                ((1 << i) & memory_req.memory_type_bits) != 0
   1083                    && t.property_flags
   1084                        .contains(vk::MemoryPropertyFlags::DEVICE_LOCAL)
   1085            });
   1086 
   1087        let Some(index) = index else {
   1088            let msg = c"Failed to get DEVICE_LOCAL memory index";
   1089            gfx_critical_note(msg.as_ptr());
   1090            return ptr::null_mut();
   1091        };
   1092 
   1093        let mut dedicated_memory_info = vk::MemoryDedicatedAllocateInfo::default().image(image);
   1094 
   1095        let memory_allocate_info = vk::MemoryAllocateInfo::default()
   1096            .allocation_size(memory_req.size)
   1097            .memory_type_index(index as u32)
   1098            .push_next(&mut dedicated_memory_info)
   1099            .push_next(&mut export_memory_alloc_info);
   1100 
   1101        let memory = match device.allocate_memory(&memory_allocate_info, None) {
   1102            Err(err) => {
   1103                let msg = CString::new(format!("allocate_memory() failed: {:?}", err)).unwrap();
   1104                gfx_critical_note(msg.as_ptr());
   1105                return ptr::null_mut();
   1106            }
   1107            Ok(memory) => memory,
   1108        };
   1109 
   1110        let result = device.bind_image_memory(image, memory, /* offset */ 0);
   1111        if result.is_err() {
   1112            let msg = CString::new(format!("bind_image_memory() failed: {:?}", result)).unwrap();
   1113            gfx_critical_note(msg.as_ptr());
   1114            return ptr::null_mut();
   1115        }
   1116 
   1117        *out_memory_size = memory_req.size;
   1118 
   1119        let modifier_prop = modifier_props
   1120            .iter()
   1121            .find(|prop| prop.drm_format_modifier == image_modifier_properties.drm_format_modifier);
   1122        let Some(modifier_prop) = modifier_prop else {
   1123            let msg = c"failed to find modifier_prop";
   1124            gfx_critical_note(msg.as_ptr());
   1125            return ptr::null_mut();
   1126        };
   1127 
   1128        let plane_count = modifier_prop.drm_format_modifier_plane_count;
   1129 
   1130        let mut layouts = Vec::new();
   1131        for i in 0..plane_count {
   1132            // VUID-vkGetImageSubresourceLayout-tiling-09433: For
   1133            // `DMA_BUF` images, the planes must be identified using the
   1134            // `MEMORY_PLANE_i_EXT bits, not the `PLANE_i` bits.
   1135            let flag = match i {
   1136                0 => vk::ImageAspectFlags::MEMORY_PLANE_0_EXT,
   1137                1 => vk::ImageAspectFlags::MEMORY_PLANE_1_EXT,
   1138                2 => vk::ImageAspectFlags::MEMORY_PLANE_2_EXT,
   1139                _ => unreachable!(),
   1140            };
   1141            let subresource = vk::ImageSubresource::default().aspect_mask(flag);
   1142            let layout = device.get_image_subresource_layout(image, subresource);
   1143            layouts.push(layout);
   1144        }
   1145 
   1146        let image_handle = VkImageHandle {
   1147            device: device.handle(),
   1148            image,
   1149            memory,
   1150            memory_size: memory_req.size,
   1151            memory_type_index: index as u32,
   1152            modifier: image_modifier_properties.drm_format_modifier,
   1153            layouts,
   1154        };
   1155 
   1156        Box::into_raw(Box::new(image_handle))
   1157    }
   1158 }
   1159 
   1160 #[no_mangle]
   1161 #[cfg(target_os = "linux")]
   1162 pub unsafe extern "C" fn wgpu_vkimage_destroy(
   1163    global: &Global,
   1164    device_id: id::DeviceId,
   1165    handle: &VkImageHandle,
   1166 ) {
   1167    handle.destroy(global, device_id);
   1168 }
   1169 
   1170 #[no_mangle]
   1171 #[cfg(target_os = "linux")]
   1172 pub unsafe extern "C" fn wgpu_vkimage_delete(handle: *mut VkImageHandle) {
   1173    let _ = Box::from_raw(handle);
   1174 }
   1175 
   1176 #[no_mangle]
   1177 #[cfg(target_os = "linux")]
   1178 pub extern "C" fn wgpu_vkimage_get_file_descriptor(
   1179    global: &Global,
   1180    device_id: id::DeviceId,
   1181    handle: &VkImageHandle,
   1182 ) -> i32 {
   1183    unsafe {
   1184        let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else {
   1185            emit_critical_invalid_note("Vulkan device");
   1186            return -1;
   1187        };
   1188 
   1189        let device = hal_device.raw_device();
   1190        let instance = hal_device.shared_instance().raw_instance();
   1191 
   1192        let get_fd_info = vk::MemoryGetFdInfoKHR::default()
   1193            .memory(handle.memory)
   1194            .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
   1195 
   1196        let loader = khr::external_memory_fd::Device::new(instance, device);
   1197 
   1198        loader.get_memory_fd(&get_fd_info).unwrap_or(-1)
   1199    }
   1200 }
   1201 
   1202 #[no_mangle]
   1203 #[cfg(target_os = "linux")]
   1204 pub extern "C" fn wgpu_vkimage_get_dma_buf_info(handle: &VkImageHandle) -> DMABufInfo {
   1205    let mut offsets: [u64; 3] = [0; 3];
   1206    let mut strides: [u64; 3] = [0; 3];
   1207    let plane_count = handle.layouts.len();
   1208    for i in 0..plane_count {
   1209        offsets[i] = handle.layouts[i].offset;
   1210        strides[i] = handle.layouts[i].row_pitch;
   1211    }
   1212 
   1213    DMABufInfo {
   1214        is_valid: true,
   1215        modifier: handle.modifier,
   1216        plane_count: plane_count as u32,
   1217        offsets,
   1218        strides,
   1219    }
   1220 }
   1221 
   1222 #[cfg(target_os = "macos")]
   1223 pub struct MetalSharedEventHandle(metal::SharedEvent);
   1224 #[cfg(not(target_os = "macos"))]
   1225 pub struct MetalSharedEventHandle;
   1226 
   1227 #[no_mangle]
   1228 #[allow(unreachable_code)]
   1229 #[allow(unused_variables)]
   1230 pub extern "C" fn wgpu_server_get_device_fence_metal_shared_event(
   1231    global: &Global,
   1232    device_id: id::DeviceId,
   1233 ) -> *mut MetalSharedEventHandle {
   1234    #[cfg(target_os = "macos")]
   1235    {
   1236        let shared_event = unsafe {
   1237            global
   1238                .device_fence_as_hal::<wgc::api::Metal>(device_id)
   1239                .map(|fence| fence.raw_shared_event().unwrap().clone())
   1240        };
   1241        let shared_event = match shared_event {
   1242            Some(shared_event) => shared_event,
   1243            None => {
   1244                return ptr::null_mut();
   1245            }
   1246        };
   1247        return Box::into_raw(Box::new(MetalSharedEventHandle(shared_event)));
   1248    }
   1249 
   1250    ptr::null_mut()
   1251 }
   1252 
   1253 #[no_mangle]
   1254 #[allow(unreachable_code)]
   1255 #[allow(unused_variables)]
   1256 pub extern "C" fn wgpu_server_metal_shared_event_signaled_value(
   1257    shared_event: &mut MetalSharedEventHandle,
   1258 ) -> u64 {
   1259    #[cfg(target_os = "macos")]
   1260    {
   1261        return shared_event.0.signaled_value();
   1262    }
   1263 
   1264    u64::MAX
   1265 }
   1266 
   1267 #[no_mangle]
   1268 #[allow(unreachable_code)]
   1269 #[allow(unused_variables)]
   1270 pub extern "C" fn wgpu_server_delete_metal_shared_event(shared_event: *mut MetalSharedEventHandle) {
   1271    #[cfg(target_os = "macos")]
   1272    {
   1273        let _ = unsafe { Box::from_raw(shared_event) };
   1274    }
   1275 }
   1276 
   1277 extern "C" {
   1278    #[allow(dead_code)]
   1279    fn gfx_critical_note(msg: *const c_char);
   1280    fn wgpu_server_use_shared_texture_for_swap_chain(
   1281        parent: WebGPUParentPtr,
   1282        swap_chain_id: SwapChainId,
   1283    ) -> bool;
   1284    fn wgpu_server_disable_shared_texture_for_swap_chain(
   1285        parent: WebGPUParentPtr,
   1286        swap_chain_id: SwapChainId,
   1287    );
   1288    #[allow(dead_code)]
   1289    fn wgpu_server_ensure_shared_texture_for_swap_chain(
   1290        parent: WebGPUParentPtr,
   1291        swap_chain_id: SwapChainId,
   1292        device_id: id::DeviceId,
   1293        texture_id: id::TextureId,
   1294        width: u32,
   1295        height: u32,
   1296        format: wgt::TextureFormat,
   1297        usage: wgt::TextureUsages,
   1298    ) -> bool;
   1299    fn wgpu_server_ensure_shared_texture_for_readback(
   1300        parent: WebGPUParentPtr,
   1301        swap_chain_id: SwapChainId,
   1302        device_id: id::DeviceId,
   1303        texture_id: id::TextureId,
   1304        width: u32,
   1305        height: u32,
   1306        format: wgt::TextureFormat,
   1307        usage: wgt::TextureUsages,
   1308    );
   1309    #[cfg(target_os = "windows")]
   1310    fn wgpu_server_get_shared_texture_handle(
   1311        parent: WebGPUParentPtr,
   1312        id: id::TextureId,
   1313    ) -> *mut core::ffi::c_void;
   1314    #[cfg(target_os = "linux")]
   1315    #[allow(improper_ctypes)] // VkImageHandle is behind a pointer but this still triggers
   1316    fn wgpu_server_get_vk_image_handle(
   1317        parent: WebGPUParentPtr,
   1318        texture_id: id::TextureId,
   1319    ) -> *const VkImageHandle;
   1320    #[cfg(target_os = "linux")]
   1321    fn wgpu_server_get_dma_buf_fd(parent: WebGPUParentPtr, id: id::TextureId) -> i32;
   1322    #[cfg(target_os = "macos")]
   1323    fn wgpu_server_get_external_io_surface_id(parent: WebGPUParentPtr, id: id::TextureId) -> u32;
   1324    fn wgpu_server_remove_shared_texture(parent: WebGPUParentPtr, id: id::TextureId);
   1325    fn wgpu_parent_is_external_texture_enabled() -> bool;
   1326    fn wgpu_parent_external_texture_source_get_external_texture_descriptor<'a>(
   1327        parent: WebGPUParentPtr,
   1328        id: crate::ExternalTextureSourceId,
   1329        dest_color_space: crate::PredefinedColorSpace,
   1330    ) -> crate::ExternalTextureDescriptorFromSource<'a>;
   1331    fn wgpu_parent_destroy_external_texture_source(
   1332        parent: WebGPUParentPtr,
   1333        id: crate::ExternalTextureSourceId,
   1334    );
   1335    fn wgpu_parent_drop_external_texture_source(
   1336        parent: WebGPUParentPtr,
   1337        id: crate::ExternalTextureSourceId,
   1338    );
   1339    fn wgpu_server_dealloc_buffer_shmem(parent: WebGPUParentPtr, id: id::BufferId);
   1340    fn wgpu_server_pre_device_drop(parent: WebGPUParentPtr, id: id::DeviceId);
   1341    fn wgpu_server_set_buffer_map_data(
   1342        parent: WebGPUParentPtr,
   1343        device_id: id::DeviceId,
   1344        buffer_id: id::BufferId,
   1345        has_map_flags: bool,
   1346        mapped_offset: u64,
   1347        mapped_size: u64,
   1348        shmem_index: usize,
   1349    );
   1350    fn wgpu_server_device_push_error_scope(
   1351        parent: WebGPUParentPtr,
   1352        device_id: id::DeviceId,
   1353        filter: u8,
   1354    );
   1355    fn wgpu_server_device_pop_error_scope(
   1356        parent: WebGPUParentPtr,
   1357        device_id: id::DeviceId,
   1358        out_type: *mut u8,
   1359        out_message: *mut nsCString,
   1360    );
   1361    fn wgpu_parent_buffer_unmap(
   1362        parent: WebGPUParentPtr,
   1363        device_id: id::DeviceId,
   1364        buffer_id: id::BufferId,
   1365        flush: bool,
   1366    );
   1367    fn wgpu_parent_queue_submit(
   1368        parent: WebGPUParentPtr,
   1369        device_id: id::DeviceId,
   1370        queue_id: id::QueueId,
   1371        command_buffer_ids: *const id::CommandBufferId,
   1372        command_buffer_ids_length: usize,
   1373        texture_ids: *const id::TextureId,
   1374        texture_ids_length: usize,
   1375        external_texture_source_ids: *const crate::ExternalTextureSourceId,
   1376        external_texture_source_ids_length: usize,
   1377    );
   1378    fn wgpu_parent_create_swap_chain(
   1379        parent: WebGPUParentPtr,
   1380        device_id: id::DeviceId,
   1381        queue_id: id::QueueId,
   1382        width: i32,
   1383        height: i32,
   1384        format: crate::SurfaceFormat,
   1385        buffer_ids: *const id::BufferId,
   1386        buffer_ids_length: usize,
   1387        remote_texture_owner_id: crate::RemoteTextureOwnerId,
   1388        use_shared_texture_in_swap_chain: bool,
   1389    );
   1390    fn wgpu_parent_swap_chain_present(
   1391        parent: WebGPUParentPtr,
   1392        texture_id: id::TextureId,
   1393        command_encoder_id: id::CommandEncoderId,
   1394        command_buffer_id: id::CommandBufferId,
   1395        remote_texture_id: crate::RemoteTextureId,
   1396        remote_texture_owner_id: crate::RemoteTextureOwnerId,
   1397    );
   1398    fn wgpu_parent_swap_chain_drop(
   1399        parent: WebGPUParentPtr,
   1400        remote_texture_owner_id: crate::RemoteTextureOwnerId,
   1401        txn_type: crate::RemoteTextureTxnType,
   1402        txn_id: crate::RemoteTextureTxnId,
   1403    );
   1404    #[cfg(target_os = "windows")]
   1405    fn wgpu_parent_get_compositor_device_luid(out_luid: *mut crate::FfiLUID);
   1406    fn wgpu_parent_post_request_device(parent: WebGPUParentPtr, device_id: id::DeviceId);
   1407    fn wgpu_parent_build_buffer_map_closure(
   1408        parent: WebGPUParentPtr,
   1409        device_id: id::DeviceId,
   1410        buffer_id: id::BufferId,
   1411        mode: wgc::device::HostMap,
   1412        offset: u64,
   1413        size: u64,
   1414    ) -> BufferMapClosure;
   1415    fn wgpu_parent_build_submitted_work_done_closure(
   1416        parent: WebGPUParentPtr,
   1417        queue_id: id::QueueId,
   1418    ) -> SubmittedWorkDoneClosure;
   1419    fn wgpu_parent_handle_error(
   1420        parent: WebGPUParentPtr,
   1421        device_id: id::DeviceId,
   1422        ty: ErrorBufferType,
   1423        message: &nsCString,
   1424    );
   1425    fn wgpu_parent_send_server_message(parent: WebGPUParentPtr, message: &mut ByteBuf);
   1426 }
   1427 
   1428 #[cfg(target_os = "linux")]
   1429 pub unsafe fn is_dmabuf_supported(
   1430    instance: &ash::Instance,
   1431    physical_device: vk::PhysicalDevice,
   1432    format: vk::Format,
   1433    modifier: u64,
   1434    usage: vk::ImageUsageFlags,
   1435 ) -> bool {
   1436    let mut drm_props = vk::ExternalImageFormatProperties::default();
   1437    let mut props = vk::ImageFormatProperties2::default().push_next(&mut drm_props);
   1438 
   1439    let mut modifier_info =
   1440        vk::PhysicalDeviceImageDrmFormatModifierInfoEXT::default().drm_format_modifier(modifier);
   1441 
   1442    let mut external_format_info = vk::PhysicalDeviceExternalImageFormatInfo::default()
   1443        .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
   1444 
   1445    let format_info = vk::PhysicalDeviceImageFormatInfo2::default()
   1446        .format(format)
   1447        .ty(vk::ImageType::TYPE_2D)
   1448        .usage(usage)
   1449        .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT)
   1450        .push_next(&mut external_format_info)
   1451        .push_next(&mut modifier_info);
   1452 
   1453    match instance.get_physical_device_image_format_properties2(
   1454        physical_device,
   1455        &format_info,
   1456        &mut props,
   1457    ) {
   1458        Ok(_) => (),
   1459        Err(_) => {
   1460            //debug!(?format, ?modifier, "format not supported for dma import");
   1461            return false;
   1462        }
   1463    }
   1464 
   1465    drm_props
   1466        .external_memory_properties
   1467        .compatible_handle_types
   1468        .contains(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
   1469 }
   1470 
   1471 #[cfg(target_os = "linux")]
   1472 pub fn select_memory_type(
   1473    props: &vk::PhysicalDeviceMemoryProperties,
   1474    flags: vk::MemoryPropertyFlags,
   1475    memory_type_bits: Option<u32>,
   1476 ) -> Option<u32> {
   1477    for i in 0..props.memory_type_count {
   1478        if let Some(mask) = memory_type_bits {
   1479            if mask & (1 << i) == 0 {
   1480                continue;
   1481            }
   1482        }
   1483 
   1484        if flags.is_empty()
   1485            || props.memory_types[i as usize]
   1486                .property_flags
   1487                .contains(flags)
   1488        {
   1489            return Some(i);
   1490        }
   1491    }
   1492 
   1493    None
   1494 }
   1495 
   1496 impl Global {
   1497    #[cfg(target_os = "windows")]
   1498    fn create_texture_with_shared_texture_d3d11(
   1499        &self,
   1500        device_id: id::DeviceId,
   1501        texture_id: id::TextureId,
   1502        desc: &wgc::resource::TextureDescriptor,
   1503        swap_chain_id: Option<SwapChainId>,
   1504    ) -> bool {
   1505        let dx12_device = unsafe {
   1506            match self
   1507                .device_as_hal::<wgc::api::Dx12>(device_id)
   1508                .map(|hal_device| hal_device.raw_device().clone())
   1509            {
   1510                None => {
   1511                    emit_critical_invalid_note("dx12 device");
   1512                    return false;
   1513                }
   1514                Some(dx12_device) => dx12_device,
   1515            }
   1516        };
   1517 
   1518        let ret = unsafe {
   1519            wgpu_server_ensure_shared_texture_for_swap_chain(
   1520                self.owner,
   1521                swap_chain_id.unwrap(),
   1522                device_id,
   1523                texture_id,
   1524                desc.size.width,
   1525                desc.size.height,
   1526                desc.format,
   1527                desc.usage,
   1528            )
   1529        };
   1530        if ret != true {
   1531            let msg = c"Failed to create shared texture";
   1532            unsafe {
   1533                gfx_critical_note(msg.as_ptr());
   1534            }
   1535            return false;
   1536        }
   1537 
   1538        let handle = unsafe { wgpu_server_get_shared_texture_handle(self.owner, texture_id) };
   1539        if handle.is_null() {
   1540            let msg = c"Failed to get shared texture handle";
   1541            unsafe {
   1542                gfx_critical_note(msg.as_ptr());
   1543            }
   1544            return false;
   1545        }
   1546        let mut resource: Option<Direct3D12::ID3D12Resource> = None;
   1547        let res =
   1548            unsafe { dx12_device.OpenSharedHandle(Foundation::HANDLE(handle), &mut resource) };
   1549        if res.is_err() || resource.is_none() {
   1550            let msg = c"Failed to open shared handle";
   1551            unsafe {
   1552                gfx_critical_note(msg.as_ptr());
   1553            }
   1554            return false;
   1555        }
   1556 
   1557        let hal_texture = unsafe {
   1558            <wgh::api::Dx12 as wgh::Api>::Device::texture_from_raw(
   1559                resource.unwrap(),
   1560                wgt::TextureFormat::Bgra8Unorm,
   1561                wgt::TextureDimension::D2,
   1562                desc.size,
   1563                1,
   1564                1,
   1565            )
   1566        };
   1567        let (_, error) = unsafe {
   1568            self.create_texture_from_hal(Box::new(hal_texture), device_id, &desc, Some(texture_id))
   1569        };
   1570        if let Some(err) = error {
   1571            let msg = CString::new(format!("create_texture_from_hal() failed: {:?}", err)).unwrap();
   1572            unsafe {
   1573                gfx_critical_note(msg.as_ptr());
   1574            }
   1575            return false;
   1576        }
   1577 
   1578        true
   1579    }
   1580 
   1581    #[cfg(target_os = "linux")]
   1582    fn create_texture_with_shared_texture_dmabuf(
   1583        &self,
   1584        device_id: id::DeviceId,
   1585        texture_id: id::TextureId,
   1586        desc: &wgc::resource::TextureDescriptor,
   1587        swap_chain_id: Option<SwapChainId>,
   1588    ) -> bool {
   1589        unsafe {
   1590            let ret = wgpu_server_ensure_shared_texture_for_swap_chain(
   1591                self.owner,
   1592                swap_chain_id.unwrap(),
   1593                device_id,
   1594                texture_id,
   1595                desc.size.width,
   1596                desc.size.height,
   1597                desc.format,
   1598                desc.usage,
   1599            );
   1600            if ret != true {
   1601                let msg = c"Failed to create shared texture";
   1602                gfx_critical_note(msg.as_ptr());
   1603                return false;
   1604            }
   1605 
   1606            let handle = wgpu_server_get_vk_image_handle(self.owner, texture_id);
   1607            if handle.is_null() {
   1608                let msg = c"Failed to get VkImageHandle";
   1609                gfx_critical_note(msg.as_ptr());
   1610                return false;
   1611            }
   1612 
   1613            let vk_image_wrapper = &*handle;
   1614 
   1615            let fd = wgpu_server_get_dma_buf_fd(self.owner, texture_id);
   1616            if fd < 0 {
   1617                let msg = c"Failed to get DMABuf fd";
   1618                gfx_critical_note(msg.as_ptr());
   1619                return false;
   1620            }
   1621 
   1622            // Ensure to close file descriptor
   1623            let owned_fd = OwnedFd::from_raw_fd(fd as RawFd);
   1624 
   1625            let Some(hal_device) = self.device_as_hal::<wgc::api::Vulkan>(device_id) else {
   1626                emit_critical_invalid_note("Vulkan device");
   1627                return false;
   1628            };
   1629 
   1630            let device = hal_device.raw_device();
   1631 
   1632            let extent = vk::Extent3D {
   1633                width: desc.size.width,
   1634                height: desc.size.height,
   1635                depth: 1,
   1636            };
   1637            let mut usage_flags = vk::ImageUsageFlags::empty();
   1638            usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT;
   1639 
   1640            let mut external_image_create_info = vk::ExternalMemoryImageCreateInfo::default()
   1641                .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
   1642 
   1643            // Surprising rule:
   1644            //
   1645            // > VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-size-02267:
   1646            // > For each element of pPlaneLayouts, size must be 0
   1647            //
   1648            // Rationale:
   1649            //
   1650            // > In each element of pPlaneLayouts, the implementation must ignore
   1651            // > size. The implementation calculates the size of each plane, which
   1652            // > the application can query with vkGetImageSubresourceLayout.
   1653            //
   1654            // So, make a temporary copy of the plane layouts and zero
   1655            // out their sizes.
   1656            let memory_plane_layouts: Vec<_> = vk_image_wrapper
   1657                .layouts
   1658                .iter()
   1659                .map(|layout| vk::SubresourceLayout { size: 0, ..*layout })
   1660                .collect();
   1661 
   1662            // VUID-VkImageCreateInfo-pNext-00990
   1663            //
   1664            // Since `wgpu_vkimage_create_with_dma_buf` above succeeded in
   1665            // creating the original DMABuf image, if we pass the same
   1666            // parameters, including the DRM format modifier and plane layouts,
   1667            // we can assume that this call will succeed too.
   1668            //
   1669            // The only thing we're adding is the `ALIAS` flag, because this
   1670            // aliases the original image.
   1671            let mut modifier_list = vk::ImageDrmFormatModifierExplicitCreateInfoEXT::default()
   1672                .drm_format_modifier(vk_image_wrapper.modifier)
   1673                .plane_layouts(&memory_plane_layouts);
   1674 
   1675            let vk_info = vk::ImageCreateInfo::default()
   1676                .flags(vk::ImageCreateFlags::ALIAS)
   1677                .image_type(vk::ImageType::TYPE_2D)
   1678                // Bug 1971883: Rather than hard-coding this format, we should use
   1679                // whatever format was negotiated between `GPUCanvasContext.configure`
   1680                // and the GPU process.
   1681                .format(vk::Format::B8G8R8A8_UNORM)
   1682                .extent(extent)
   1683                .mip_levels(1)
   1684                .array_layers(1)
   1685                .samples(vk::SampleCountFlags::TYPE_1)
   1686                .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT)
   1687                .usage(usage_flags)
   1688                .sharing_mode(vk::SharingMode::EXCLUSIVE)
   1689                .initial_layout(vk::ImageLayout::UNDEFINED)
   1690                .push_next(&mut modifier_list)
   1691                .push_next(&mut external_image_create_info);
   1692 
   1693            let image = match device.create_image(&vk_info, None) {
   1694                Err(err) => {
   1695                    let msg = CString::new(format!(
   1696                        "Failed to get vk::Image: create_image() failed: {:?}",
   1697                        err
   1698                    ))
   1699                    .unwrap();
   1700                    gfx_critical_note(msg.as_ptr());
   1701                    return false;
   1702                }
   1703                Ok(image) => image,
   1704            };
   1705 
   1706            let memory_req = device.get_image_memory_requirements(image);
   1707            if memory_req.size > vk_image_wrapper.memory_size {
   1708                let msg = c"Invalid memory size";
   1709                gfx_critical_note(msg.as_ptr());
   1710                return false;
   1711            }
   1712 
   1713            let mut dedicated_memory_info = vk::MemoryDedicatedAllocateInfo::default().image(image);
   1714 
   1715            let mut import_memory_fd_info = vk::ImportMemoryFdInfoKHR::default()
   1716                .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
   1717                .fd(owned_fd.into_raw_fd());
   1718 
   1719            let memory_allocate_info = vk::MemoryAllocateInfo::default()
   1720                .allocation_size(vk_image_wrapper.memory_size)
   1721                .memory_type_index(vk_image_wrapper.memory_type_index)
   1722                .push_next(&mut dedicated_memory_info)
   1723                .push_next(&mut import_memory_fd_info);
   1724 
   1725            let memory = match device.allocate_memory(&memory_allocate_info, None) {
   1726                Err(err) => {
   1727                    let msg = CString::new(format!(
   1728                        "Failed to get vk::Image: allocate_memory() failed: {:?}",
   1729                        err
   1730                    ))
   1731                    .unwrap();
   1732                    gfx_critical_note(msg.as_ptr());
   1733                    return false;
   1734                }
   1735                Ok(memory) => memory,
   1736            };
   1737 
   1738            match device.bind_image_memory(image, memory, /* offset */ 0) {
   1739                Ok(()) => {}
   1740                Err(err) => {
   1741                    let msg = CString::new(format!(
   1742                        "Failed to get vk::Image: bind_image_memory() failed: {:?}",
   1743                        err
   1744                    ))
   1745                    .unwrap();
   1746                    gfx_critical_note(msg.as_ptr());
   1747                    return false;
   1748                }
   1749            }
   1750 
   1751            let hal_desc = wgh::TextureDescriptor {
   1752                label: None,
   1753                size: desc.size,
   1754                mip_level_count: desc.mip_level_count,
   1755                sample_count: desc.sample_count,
   1756                dimension: desc.dimension,
   1757                format: desc.format,
   1758                usage: wgt::TextureUses::COPY_DST | wgt::TextureUses::COLOR_TARGET,
   1759                memory_flags: wgh::MemoryFlags::empty(),
   1760                view_formats: vec![],
   1761            };
   1762 
   1763            let hal_texture = <wgh::api::Vulkan as wgh::Api>::Device::texture_from_raw(
   1764                &hal_device,
   1765                image,
   1766                &hal_desc,
   1767                None,
   1768                wgh::vulkan::TextureMemory::Dedicated(memory),
   1769            );
   1770 
   1771            let (_, error) = self.create_texture_from_hal(
   1772                Box::new(hal_texture),
   1773                device_id,
   1774                &desc,
   1775                Some(texture_id),
   1776            );
   1777            if let Some(err) = error {
   1778                let msg =
   1779                    CString::new(format!("create_texture_from_hal() failed: {:?}", err)).unwrap();
   1780                gfx_critical_note(msg.as_ptr());
   1781                return false;
   1782            }
   1783 
   1784            true
   1785        }
   1786    }
   1787 
   1788    fn device_action(
   1789        &self,
   1790        device_id: id::DeviceId,
   1791        action: DeviceAction,
   1792        shmem_mappings: FfiSlice<'_, FfiSlice<'_, u8>>,
   1793        response_byte_buf: &mut ByteBuf,
   1794        error_buf: &mut OwnedErrorBuffer,
   1795    ) {
   1796        match action {
   1797            DeviceAction::CreateBuffer {
   1798                buffer_id,
   1799                desc,
   1800                shmem_handle_index,
   1801            } => {
   1802                let has_map_flags = desc
   1803                    .usage
   1804                    .intersects(wgt::BufferUsages::MAP_READ | wgt::BufferUsages::MAP_WRITE);
   1805                let needs_shmem = has_map_flags || desc.mapped_at_creation;
   1806 
   1807                let shmem_data =
   1808                    unsafe { shmem_mappings.as_slice()[shmem_handle_index].as_slice() };
   1809 
   1810                let shmem_size = shmem_data.len();
   1811 
   1812                // If we requested a non-zero mappable buffer and get a size of zero, it
   1813                // indicates that the shmem allocation failed on the client side or
   1814                // mapping failed in the parent process.
   1815                let shmem_allocation_failed = needs_shmem && (shmem_size as u64) < desc.size;
   1816                if shmem_allocation_failed {
   1817                    assert_eq!(shmem_size, 0);
   1818                }
   1819 
   1820                // Don't trust the graphics driver with buffer sizes larger than our conservative max buffer size.
   1821                if shmem_allocation_failed || desc.size > MAX_BUFFER_SIZE {
   1822                    error_buf.init(ErrMsg::oom(), device_id);
   1823                    self.create_buffer_error(Some(buffer_id), &desc);
   1824                    return;
   1825                }
   1826 
   1827                if needs_shmem {
   1828                    unsafe {
   1829                        wgpu_server_set_buffer_map_data(
   1830                            self.owner,
   1831                            device_id,
   1832                            buffer_id,
   1833                            has_map_flags,
   1834                            0,
   1835                            if desc.mapped_at_creation {
   1836                                desc.size
   1837                            } else {
   1838                                0
   1839                            },
   1840                            shmem_handle_index,
   1841                        );
   1842                    }
   1843                }
   1844 
   1845                let (_, error) = self.device_create_buffer(device_id, &desc, Some(buffer_id));
   1846                if let Some(err) = error {
   1847                    error_buf.init(err, device_id);
   1848                }
   1849            }
   1850            #[allow(unused_variables)]
   1851            DeviceAction::CreateTexture(id, desc, swap_chain_id) => {
   1852                let max = MAX_TEXTURE_EXTENT;
   1853                if desc.size.width > max
   1854                    || desc.size.height > max
   1855                    || desc.size.depth_or_array_layers > max
   1856                {
   1857                    self.create_texture_error(Some(id), &desc);
   1858                    error_buf.init(ErrMsg::oom(), device_id);
   1859                    return;
   1860                }
   1861 
   1862                if [
   1863                    desc.size.width,
   1864                    desc.size.height,
   1865                    desc.size.depth_or_array_layers,
   1866                ]
   1867                .contains(&0)
   1868                {
   1869                    self.create_texture_error(Some(id), &desc);
   1870                    error_buf.init(
   1871                        ErrMsg {
   1872                            message: "size is zero".into(),
   1873                            r#type: ErrorType::Validation,
   1874                        },
   1875                        device_id,
   1876                    );
   1877                    return;
   1878                }
   1879 
   1880                let use_shared_texture = if let Some(id) = swap_chain_id {
   1881                    unsafe { wgpu_server_use_shared_texture_for_swap_chain(self.owner, id) }
   1882                } else {
   1883                    false
   1884                };
   1885 
   1886                if use_shared_texture {
   1887                    let limits = self.device_limits(device_id);
   1888                    if desc.size.width > limits.max_texture_dimension_2d
   1889                        || desc.size.height > limits.max_texture_dimension_2d
   1890                    {
   1891                        self.create_texture_error(Some(id), &desc);
   1892                        error_buf.init(
   1893                            ErrMsg {
   1894                                message: "size exceeds limits.max_texture_dimension_2d".into(),
   1895                                r#type: ErrorType::Validation,
   1896                            },
   1897                            device_id,
   1898                        );
   1899                        return;
   1900                    }
   1901 
   1902                    let features = self.device_features(device_id);
   1903                    if desc.format == wgt::TextureFormat::Bgra8Unorm
   1904                        && desc.usage.contains(wgt::TextureUsages::STORAGE_BINDING)
   1905                        && !features.contains(wgt::Features::BGRA8UNORM_STORAGE)
   1906                    {
   1907                        self.create_texture_error(Some(id), &desc);
   1908                        error_buf.init(
   1909                            ErrMsg {
   1910                                message: concat!(
   1911                                    "Bgra8Unorm with GPUStorageBinding usage ",
   1912                                    "with BGRA8UNORM_STORAGE disabled"
   1913                                )
   1914                                .into(),
   1915                                r#type: ErrorType::Validation,
   1916                            },
   1917                            device_id,
   1918                        );
   1919                        return;
   1920                    }
   1921 
   1922                    #[cfg(target_os = "windows")]
   1923                    {
   1924                        let is_created = self.create_texture_with_shared_texture_d3d11(
   1925                            device_id,
   1926                            id,
   1927                            &desc,
   1928                            swap_chain_id,
   1929                        );
   1930                        if is_created {
   1931                            return;
   1932                        }
   1933                    }
   1934 
   1935                    #[cfg(target_os = "linux")]
   1936                    {
   1937                        let is_created = self.create_texture_with_shared_texture_dmabuf(
   1938                            device_id,
   1939                            id,
   1940                            &desc,
   1941                            swap_chain_id,
   1942                        );
   1943                        if is_created {
   1944                            return;
   1945                        }
   1946                    }
   1947 
   1948                    #[cfg(target_os = "macos")]
   1949                    {
   1950                        let is_created = self.create_texture_with_shared_texture_iosurface(
   1951                            device_id,
   1952                            id,
   1953                            &desc,
   1954                            swap_chain_id,
   1955                        );
   1956                        if is_created {
   1957                            return;
   1958                        }
   1959                    }
   1960 
   1961                    unsafe {
   1962                        wgpu_server_disable_shared_texture_for_swap_chain(
   1963                            self.owner,
   1964                            swap_chain_id.unwrap(),
   1965                        )
   1966                    };
   1967                }
   1968 
   1969                if let Some(swap_chain_id) = swap_chain_id {
   1970                    unsafe {
   1971                        wgpu_server_ensure_shared_texture_for_readback(
   1972                            self.owner,
   1973                            swap_chain_id,
   1974                            device_id,
   1975                            id,
   1976                            desc.size.width,
   1977                            desc.size.height,
   1978                            desc.format,
   1979                            desc.usage,
   1980                        )
   1981                    };
   1982                }
   1983 
   1984                let (_, error) = self.device_create_texture(device_id, &desc, Some(id));
   1985                if let Some(err) = error {
   1986                    error_buf.init(err, device_id);
   1987                }
   1988            }
   1989            DeviceAction::CreateExternalTexture(id, desc) => {
   1990                // Obtain the descriptor from the source. A source ID of `None`
   1991                // indicates the client-side encountered an error when
   1992                // importing the source.
   1993                let source_desc = desc.source.and_then(|source| {
   1994                    let source_desc = unsafe {
   1995                        wgpu_parent_external_texture_source_get_external_texture_descriptor(
   1996                            self.owner,
   1997                            source,
   1998                            desc.color_space,
   1999                        )
   2000                    };
   2001                    let planes = unsafe { source_desc.planes.as_slice() };
   2002                    // The source having no planes indicates we encountered an
   2003                    // error on the server side when importing the source
   2004                    if planes.is_empty() {
   2005                        None
   2006                    } else {
   2007                        Some(source_desc)
   2008                    }
   2009                });
   2010                match source_desc {
   2011                    Some(source_desc) => {
   2012                        let planes = unsafe { source_desc.planes.as_slice() };
   2013                        let desc = wgt::ExternalTextureDescriptor {
   2014                            label: desc.label,
   2015                            width: source_desc.width,
   2016                            height: source_desc.height,
   2017                            format: source_desc.format,
   2018                            yuv_conversion_matrix: source_desc.yuv_conversion_matrix,
   2019                            gamut_conversion_matrix: source_desc.gamut_conversion_matrix,
   2020                            src_transfer_function: source_desc.src_transfer_function,
   2021                            dst_transfer_function: source_desc.dst_transfer_function,
   2022                            sample_transform: source_desc.sample_transform,
   2023                            load_transform: source_desc.load_transform,
   2024                        };
   2025                        let (_, error) =
   2026                            self.device_create_external_texture(device_id, &desc, planes, Some(id));
   2027                        if let Some(err) = error {
   2028                            error_buf.init(err, device_id);
   2029                        }
   2030                    }
   2031                    None => {
   2032                        // Create the external texture in an error state.
   2033                        let desc = wgt::ExternalTextureDescriptor {
   2034                            label: desc.label,
   2035                            width: 0,
   2036                            height: 0,
   2037                            format: wgt::ExternalTextureFormat::Rgba,
   2038                            yuv_conversion_matrix: Default::default(),
   2039                            gamut_conversion_matrix: Default::default(),
   2040                            src_transfer_function: Default::default(),
   2041                            dst_transfer_function: Default::default(),
   2042                            sample_transform: Default::default(),
   2043                            load_transform: Default::default(),
   2044                        };
   2045                        self.create_external_texture_error(Some(id), &desc);
   2046                    }
   2047                }
   2048            }
   2049            DeviceAction::CreateSampler(id, desc) => {
   2050                let (_, error) = self.device_create_sampler(device_id, &desc, Some(id));
   2051                if let Some(err) = error {
   2052                    error_buf.init(err, device_id);
   2053                }
   2054            }
   2055            DeviceAction::CreateBindGroupLayout(id, desc) => {
   2056                let (_, error) = self.device_create_bind_group_layout(device_id, &desc, Some(id));
   2057                if let Some(err) = error {
   2058                    error_buf.init(err, device_id);
   2059                }
   2060            }
   2061            DeviceAction::RenderPipelineGetBindGroupLayout(pipeline_id, index, bgl_id) => {
   2062                let (_, error) =
   2063                    self.render_pipeline_get_bind_group_layout(pipeline_id, index, Some(bgl_id));
   2064                if let Some(err) = error {
   2065                    error_buf.init(err, device_id);
   2066                }
   2067            }
   2068            DeviceAction::ComputePipelineGetBindGroupLayout(pipeline_id, index, bgl_id) => {
   2069                let (_, error) =
   2070                    self.compute_pipeline_get_bind_group_layout(pipeline_id, index, Some(bgl_id));
   2071                if let Some(err) = error {
   2072                    error_buf.init(err, device_id);
   2073                }
   2074            }
   2075            DeviceAction::CreatePipelineLayout(id, desc) => {
   2076                let (_, error) = self.device_create_pipeline_layout(device_id, &desc, Some(id));
   2077                if let Some(err) = error {
   2078                    error_buf.init(err, device_id);
   2079                }
   2080            }
   2081            DeviceAction::CreateBindGroup(id, desc) => {
   2082                let (_, error) = self.device_create_bind_group(device_id, &desc, Some(id));
   2083                if let Some(err) = error {
   2084                    error_buf.init(err, device_id);
   2085                }
   2086            }
   2087            DeviceAction::CreateShaderModule(id, label, code) => {
   2088                let desc = wgc::pipeline::ShaderModuleDescriptor {
   2089                    label,
   2090                    runtime_checks: wgt::ShaderRuntimeChecks::checked(),
   2091                };
   2092                let source = wgc::pipeline::ShaderModuleSource::Wgsl(Cow::Borrowed(code.as_ref()));
   2093                let (_, error) =
   2094                    self.device_create_shader_module(device_id, &desc, source, Some(id));
   2095 
   2096                let compilation_messages = if let Some(err) = error {
   2097                    // Per spec: "User agents should not include detailed compiler error messages or
   2098                    // shader text in the message text of validation errors arising here: these details
   2099                    // are accessible via getCompilationInfo()"
   2100                    let message = match &err {
   2101                        CreateShaderModuleError::Parsing(_) => "Parsing error".to_string(),
   2102                        CreateShaderModuleError::Validation(_) => {
   2103                            "Shader validation error".to_string()
   2104                        }
   2105                        CreateShaderModuleError::Device(device_err) => format!("{device_err:?}"),
   2106                        _ => format!("{err:?}"),
   2107                    };
   2108 
   2109                    error_buf.init(
   2110                        ErrMsg {
   2111                            message: format!("Shader module creation failed: {message}").into(),
   2112                            r#type: err.webgpu_error_type(),
   2113                        },
   2114                        device_id,
   2115                    );
   2116 
   2117                    vec![ShaderModuleCompilationMessage::new(&err, code.as_ref())]
   2118                } else {
   2119                    Vec::new()
   2120                };
   2121 
   2122                *response_byte_buf = make_byte_buf(&ServerMessage::CreateShaderModuleResponse(
   2123                    id,
   2124                    compilation_messages,
   2125                ));
   2126            }
   2127            DeviceAction::CreateComputePipeline(id, desc, is_async) => {
   2128                let (_, error) = self.device_create_compute_pipeline(device_id, &desc, Some(id));
   2129 
   2130                if is_async {
   2131                    let error = error
   2132                        .filter(|e| !matches!(e.webgpu_error_type(), ErrorType::DeviceLost))
   2133                        .map(|e| -> _ {
   2134                            let is_validation_error =
   2135                                matches!(e.webgpu_error_type(), ErrorType::Validation);
   2136                            PipelineError {
   2137                                is_validation_error,
   2138                                error: error_to_string(e),
   2139                            }
   2140                        });
   2141                    *response_byte_buf =
   2142                        make_byte_buf(&ServerMessage::CreateComputePipelineResponse {
   2143                            pipeline_id: id,
   2144                            error,
   2145                        });
   2146                } else {
   2147                    if let Some(err) = error {
   2148                        error_buf.init(err, device_id);
   2149                    }
   2150                }
   2151            }
   2152            DeviceAction::CreateRenderPipeline(id, desc, is_async) => {
   2153                let (_, error) = self.device_create_render_pipeline(device_id, &desc, Some(id));
   2154 
   2155                if is_async {
   2156                    let error = error
   2157                        .filter(|e| !matches!(e.webgpu_error_type(), ErrorType::DeviceLost))
   2158                        .map(|e| -> _ {
   2159                            let is_validation_error =
   2160                                matches!(e.webgpu_error_type(), ErrorType::Validation);
   2161                            PipelineError {
   2162                                is_validation_error,
   2163                                error: error_to_string(e),
   2164                            }
   2165                        });
   2166                    *response_byte_buf =
   2167                        make_byte_buf(&ServerMessage::CreateRenderPipelineResponse {
   2168                            pipeline_id: id,
   2169                            error,
   2170                        });
   2171                } else {
   2172                    if let Some(err) = error {
   2173                        error_buf.init(err, device_id);
   2174                    }
   2175                }
   2176            }
   2177            DeviceAction::CreateRenderBundle(id, encoder, desc) => {
   2178                let (_, error) = self.render_bundle_encoder_finish(encoder, &desc, Some(id));
   2179                if let Some(err) = error {
   2180                    error_buf.init(err, device_id);
   2181                }
   2182            }
   2183            DeviceAction::CreateRenderBundleError(buffer_id, label) => {
   2184                self.create_render_bundle_error(
   2185                    Some(buffer_id),
   2186                    &wgt::RenderBundleDescriptor { label },
   2187                );
   2188            }
   2189            DeviceAction::CreateQuerySet(id, desc) => {
   2190                let (_, error) = self.device_create_query_set(device_id, &desc, Some(id));
   2191                if let Some(err) = error {
   2192                    error_buf.init(err, device_id);
   2193                }
   2194            }
   2195            DeviceAction::CreateCommandEncoder(id, desc) => {
   2196                let (_, error) = self.device_create_command_encoder(device_id, &desc, Some(id));
   2197                if let Some(err) = error {
   2198                    error_buf.init(err, device_id);
   2199                }
   2200            }
   2201            DeviceAction::Error { message, r#type } => {
   2202                error_buf.init(
   2203                    ErrMsg {
   2204                        message: message.into(),
   2205                        r#type,
   2206                    },
   2207                    device_id,
   2208                );
   2209            }
   2210            DeviceAction::PushErrorScope(filter) => {
   2211                unsafe { wgpu_server_device_push_error_scope(self.owner, device_id, filter) };
   2212            }
   2213            DeviceAction::PopErrorScope => {
   2214                let mut ty = 0;
   2215                let mut message = nsCString::new();
   2216                unsafe {
   2217                    wgpu_server_device_pop_error_scope(self.owner, device_id, &mut ty, &mut message)
   2218                };
   2219                let message = message.to_utf8();
   2220 
   2221                *response_byte_buf = make_byte_buf(&ServerMessage::PopErrorScopeResponse(
   2222                    device_id, ty, message,
   2223                ));
   2224            }
   2225        }
   2226    }
   2227 
   2228    fn texture_action(
   2229        &self,
   2230        device_id: id::DeviceId,
   2231        self_id: id::TextureId,
   2232        action: TextureAction,
   2233        error_buf: &mut OwnedErrorBuffer,
   2234    ) {
   2235        match action {
   2236            TextureAction::CreateView(id, desc) => {
   2237                let (_, error) = self.texture_create_view(self_id, &desc, Some(id));
   2238                if let Some(err) = error {
   2239                    error_buf.init(err, device_id);
   2240                }
   2241            }
   2242        }
   2243    }
   2244 
   2245    fn command_encoder_action(
   2246        &self,
   2247        device_id: id::DeviceId,
   2248        self_id: id::CommandEncoderId,
   2249        action: CommandEncoderAction,
   2250        error_buf: &mut OwnedErrorBuffer,
   2251    ) {
   2252        match action {
   2253            CommandEncoderAction::CopyBufferToBuffer {
   2254                src,
   2255                src_offset,
   2256                dst,
   2257                dst_offset,
   2258                size,
   2259            } => {
   2260                if let Err(err) = self.command_encoder_copy_buffer_to_buffer(
   2261                    self_id, src, src_offset, dst, dst_offset, size,
   2262                ) {
   2263                    error_buf.init(err, device_id);
   2264                }
   2265            }
   2266            CommandEncoderAction::CopyBufferToTexture { src, dst, size } => {
   2267                if let Err(err) =
   2268                    self.command_encoder_copy_buffer_to_texture(self_id, &src, &dst, &size)
   2269                {
   2270                    error_buf.init(err, device_id);
   2271                }
   2272            }
   2273            CommandEncoderAction::CopyTextureToBuffer { src, dst, size } => {
   2274                if let Err(err) =
   2275                    self.command_encoder_copy_texture_to_buffer(self_id, &src, &dst, &size)
   2276                {
   2277                    error_buf.init(err, device_id);
   2278                }
   2279            }
   2280            CommandEncoderAction::CopyTextureToTexture { src, dst, size } => {
   2281                if let Err(err) =
   2282                    self.command_encoder_copy_texture_to_texture(self_id, &src, &dst, &size)
   2283                {
   2284                    error_buf.init(err, device_id);
   2285                }
   2286            }
   2287            CommandEncoderAction::RunComputePass { .. } => unimplemented!(),
   2288            CommandEncoderAction::WriteTimestamp {
   2289                query_set,
   2290                query_index,
   2291            } => {
   2292                if let Err(err) =
   2293                    self.command_encoder_write_timestamp(self_id, query_set, query_index)
   2294                {
   2295                    error_buf.init(err, device_id);
   2296                }
   2297            }
   2298            CommandEncoderAction::ResolveQuerySet {
   2299                query_set,
   2300                start_query,
   2301                query_count,
   2302                destination,
   2303                destination_offset,
   2304            } => {
   2305                if let Err(err) = self.command_encoder_resolve_query_set(
   2306                    self_id,
   2307                    query_set,
   2308                    start_query,
   2309                    query_count,
   2310                    destination,
   2311                    destination_offset,
   2312                ) {
   2313                    error_buf.init(err, device_id);
   2314                }
   2315            }
   2316            CommandEncoderAction::RunRenderPass { .. } => unimplemented!(),
   2317            CommandEncoderAction::ClearBuffer { dst, offset, size } => {
   2318                if let Err(err) = self.command_encoder_clear_buffer(self_id, dst, offset, size) {
   2319                    error_buf.init(err, device_id);
   2320                }
   2321            }
   2322            CommandEncoderAction::ClearTexture {
   2323                dst,
   2324                ref subresource_range,
   2325            } => {
   2326                if let Err(err) =
   2327                    self.command_encoder_clear_texture(self_id, dst, subresource_range)
   2328                {
   2329                    error_buf.init(err, device_id);
   2330                }
   2331            }
   2332            CommandEncoderAction::PushDebugGroup(marker) => {
   2333                if let Err(err) = self.command_encoder_push_debug_group(self_id, &marker) {
   2334                    error_buf.init(err, device_id);
   2335                }
   2336            }
   2337            CommandEncoderAction::PopDebugGroup => {
   2338                if let Err(err) = self.command_encoder_pop_debug_group(self_id) {
   2339                    error_buf.init(err, device_id);
   2340                }
   2341            }
   2342            CommandEncoderAction::InsertDebugMarker(marker) => {
   2343                if let Err(err) = self.command_encoder_insert_debug_marker(self_id, &marker) {
   2344                    error_buf.init(err, device_id);
   2345                }
   2346            }
   2347            CommandEncoderAction::BuildAccelerationStructures { .. } => {
   2348                unreachable!("internal error: attempted to build acceleration structures")
   2349            }
   2350            CommandEncoderAction::TransitionResources { .. } => {
   2351                unreachable!("internal error: attempted to transition resources")
   2352            }
   2353        }
   2354    }
   2355 }
   2356 
   2357 #[no_mangle]
   2358 pub unsafe extern "C" fn wgpu_server_pack_buffer_map_success(
   2359    buffer_id: id::BufferId,
   2360    is_writable: bool,
   2361    offset: u64,
   2362    size: u64,
   2363    bb: &mut ByteBuf,
   2364 ) {
   2365    let result = BufferMapResult::Success {
   2366        is_writable,
   2367        offset,
   2368        size,
   2369    };
   2370    *bb = make_byte_buf(&ServerMessage::BufferMapResponse(buffer_id, result));
   2371 }
   2372 
   2373 #[no_mangle]
   2374 pub unsafe extern "C" fn wgpu_server_pack_buffer_map_error(
   2375    buffer_id: id::BufferId,
   2376    error: &nsACString,
   2377    bb: &mut ByteBuf,
   2378 ) {
   2379    let error = error.to_utf8();
   2380    let result = BufferMapResult::Error(error);
   2381    *bb = make_byte_buf(&ServerMessage::BufferMapResponse(buffer_id, result));
   2382 }
   2383 
   2384 #[no_mangle]
   2385 pub unsafe extern "C" fn wgpu_server_pack_work_done(bb: &mut ByteBuf, queue_id: id::QueueId) {
   2386    *bb = make_byte_buf(&ServerMessage::QueueOnSubmittedWorkDoneResponse(queue_id));
   2387 }
   2388 
   2389 /// # Panics
   2390 ///
   2391 /// If the size of `buffer_ids` is not [`crate::MAX_SWAPCHAIN_BUFFER_COUNT`].
   2392 #[no_mangle]
   2393 pub unsafe extern "C" fn wgpu_server_pack_free_swap_chain_buffer_ids(
   2394    bb: &mut ByteBuf,
   2395    buffer_ids: FfiSlice<'_, id::BufferId>,
   2396 ) {
   2397    *bb = make_byte_buf(&ServerMessage::FreeSwapChainBufferIds(
   2398        buffer_ids.as_slice().try_into().unwrap(),
   2399    ));
   2400 }
   2401 
   2402 #[no_mangle]
   2403 pub unsafe extern "C" fn wgpu_server_messages(
   2404    global: &Global,
   2405    nr_of_messages: u32,
   2406    serialized_messages: &ByteBuf,
   2407    data_buffers: FfiSlice<'_, ByteBuf>,
   2408    shmem_mappings: FfiSlice<'_, FfiSlice<'_, u8>>,
   2409 ) {
   2410    let serialized_messages = serialized_messages.as_slice();
   2411    let data_buffers = data_buffers.as_slice();
   2412 
   2413    use bincode::Options;
   2414    let options = bincode::DefaultOptions::new()
   2415        .with_fixint_encoding()
   2416        .allow_trailing_bytes();
   2417    let mut deserializer = bincode::Deserializer::from_slice(serialized_messages, options);
   2418 
   2419    for _ in 0..nr_of_messages {
   2420        let message: Message = serde::Deserialize::deserialize(&mut deserializer).unwrap();
   2421        process_message(global, data_buffers, shmem_mappings, message);
   2422    }
   2423 }
   2424 
   2425 unsafe fn process_message(
   2426    global: &Global,
   2427    data_buffers: &[ByteBuf],
   2428    shmem_mappings: FfiSlice<'_, FfiSlice<'_, u8>>,
   2429    message: Message,
   2430 ) {
   2431    let response_byte_buf = &mut ByteBuf::new();
   2432    let error_buf = &mut OwnedErrorBuffer::new();
   2433 
   2434    match message {
   2435        Message::RequestAdapter {
   2436            adapter_id,
   2437            power_preference,
   2438            force_fallback_adapter,
   2439        } => {
   2440            let mut result = None;
   2441 
   2442            // Prefer to use the dx12 backend, if one exists, and use the same DXGI adapter as WebRender.
   2443            // If wgpu uses a different adapter than WebRender, textures created by
   2444            // webgpu::SharedTexture do not work with wgpu.
   2445            #[cfg(target_os = "windows")]
   2446            {
   2447                let mut adapter_luid = core::mem::MaybeUninit::<crate::FfiLUID>::uninit();
   2448                wgpu_parent_get_compositor_device_luid(adapter_luid.as_mut_ptr());
   2449                let adapter_luid = if adapter_luid.as_ptr().is_null() {
   2450                    None
   2451                } else {
   2452                    Some(adapter_luid.assume_init())
   2453                };
   2454 
   2455                if adapter_luid.is_some() && !force_fallback_adapter {
   2456                    if let Some(instance) = global.global.instance_as_hal::<wgc::api::Dx12>() {
   2457                        for adapter in instance.enumerate_adapters(None) {
   2458                            let raw_adapter = adapter.adapter.raw_adapter();
   2459                            let desc = unsafe { raw_adapter.GetDesc() };
   2460                            if let Ok(desc) = desc {
   2461                                if desc.AdapterLuid.LowPart == adapter_luid.unwrap().low_part
   2462                                    && desc.AdapterLuid.HighPart == adapter_luid.unwrap().high_part
   2463                                {
   2464                                    global.create_adapter_from_hal(
   2465                                        wgh::DynExposedAdapter::from(adapter),
   2466                                        Some(adapter_id),
   2467                                    );
   2468                                    result = Some(true);
   2469                                    break;
   2470                                }
   2471                            }
   2472                        }
   2473                        if result.is_none() {
   2474                            log::error!(concat!(
   2475                                "Failed to find D3D12 adapter with the same LUID ",
   2476                                "that the compositor is using!"
   2477                            ));
   2478                            result = Some(false);
   2479                        }
   2480                    }
   2481                }
   2482            }
   2483 
   2484            let desc = wgt::RequestAdapterOptions {
   2485                power_preference,
   2486                force_fallback_adapter,
   2487                compatible_surface: None,
   2488            };
   2489            if result.is_none() {
   2490                let created =
   2491                    match global.request_adapter(&desc, wgt::Backends::PRIMARY, Some(adapter_id)) {
   2492                        Ok(_) => true,
   2493                        Err(e) => {
   2494                            log::warn!("{e}");
   2495                            false
   2496                        }
   2497                    };
   2498                result = Some(created);
   2499            }
   2500 
   2501            let response = if result.unwrap() {
   2502                let wgt::AdapterInfo {
   2503                    name,
   2504                    vendor,
   2505                    device,
   2506                    device_type,
   2507                    driver,
   2508                    driver_info,
   2509                    backend,
   2510                    transient_saves_memory,
   2511                    device_pci_bus_id: _,
   2512                    subgroup_min_size,
   2513                    subgroup_max_size,
   2514                } = global.adapter_get_info(adapter_id);
   2515 
   2516                let is_hardware = match device_type {
   2517                    wgt::DeviceType::IntegratedGpu | wgt::DeviceType::DiscreteGpu => true,
   2518                    _ => false,
   2519                };
   2520 
   2521                if static_prefs::pref!("dom.webgpu.testing.assert-hardware-adapter")
   2522                    && !desc.force_fallback_adapter
   2523                {
   2524                    assert!(
   2525                        is_hardware,
   2526                        "Expected a hardware gpu adapter, got {:?}",
   2527                        device_type
   2528                    );
   2529                }
   2530 
   2531                let support_use_shared_texture_in_swap_chain =
   2532                    support_use_shared_texture_in_swap_chain(
   2533                        global,
   2534                        adapter_id,
   2535                        backend,
   2536                        is_hardware,
   2537                    );
   2538 
   2539                let info = AdapterInformation {
   2540                    id: adapter_id,
   2541                    limits: restrict_limits(global.adapter_limits(adapter_id)),
   2542                    features: global.adapter_features(adapter_id).features_webgpu,
   2543                    name: Cow::Owned(name),
   2544                    vendor,
   2545                    device,
   2546                    device_type,
   2547                    driver: Cow::Owned(driver),
   2548                    driver_info: Cow::Owned(driver_info),
   2549                    backend,
   2550                    support_use_shared_texture_in_swap_chain,
   2551                    transient_saves_memory,
   2552                    subgroup_min_size,
   2553                    subgroup_max_size,
   2554                };
   2555                Some(info)
   2556            } else {
   2557                None
   2558            };
   2559 
   2560            *response_byte_buf =
   2561                make_byte_buf(&ServerMessage::RequestAdapterResponse(adapter_id, response));
   2562        }
   2563        Message::RequestDevice {
   2564            adapter_id,
   2565            device_id,
   2566            queue_id,
   2567            desc,
   2568        } => {
   2569            let error = adapter_request_device(global, adapter_id, desc, device_id, queue_id);
   2570 
   2571            if error.is_none() {
   2572                wgpu_parent_post_request_device(global.owner, device_id);
   2573            }
   2574 
   2575            *response_byte_buf = make_byte_buf(&ServerMessage::RequestDeviceResponse(
   2576                device_id, queue_id, error,
   2577            ));
   2578        }
   2579        Message::Device(id, action) => {
   2580            global.device_action(id, action, shmem_mappings, response_byte_buf, error_buf)
   2581        }
   2582        Message::Texture(device_id, id, action) => {
   2583            global.texture_action(device_id, id, action, error_buf)
   2584        }
   2585        Message::CommandEncoder(device_id, id, action) => {
   2586            global.command_encoder_action(device_id, id, action, error_buf)
   2587        }
   2588        Message::CommandEncoderFinish(device_id, command_encoder_id, command_buffer_id, desc) => {
   2589            let (_, label_and_error) =
   2590                global.command_encoder_finish(command_encoder_id, &desc, Some(command_buffer_id));
   2591            if let Some((_label, err)) = label_and_error {
   2592                error_buf.init(err, device_id);
   2593            }
   2594        }
   2595        Message::ReplayRenderPass(device_id, id, pass) => {
   2596            crate::command::replay_render_pass(global, device_id, id, &pass, error_buf);
   2597        }
   2598        Message::ReplayComputePass(device_id, id, pass) => {
   2599            crate::command::replay_compute_pass(global, device_id, id, &pass, error_buf);
   2600        }
   2601        Message::QueueWrite {
   2602            device_id,
   2603            queue_id,
   2604            data_source,
   2605            action,
   2606        } => {
   2607            let data = match data_source {
   2608                QueueWriteDataSource::DataBuffer(data_buffer_index) => {
   2609                    data_buffers[data_buffer_index].as_slice()
   2610                }
   2611                QueueWriteDataSource::Shmem(shmem_handle_index) => {
   2612                    shmem_mappings.as_slice()[shmem_handle_index].as_slice()
   2613                }
   2614            };
   2615            let result = match action {
   2616                QueueWriteAction::Buffer { dst, offset } => {
   2617                    global.queue_write_buffer(queue_id, dst, offset, data)
   2618                }
   2619                QueueWriteAction::Texture { dst, layout, size } => {
   2620                    global.queue_write_texture(queue_id, &dst, data, &layout, &size)
   2621                }
   2622            };
   2623            if let Err(err) = result {
   2624                error_buf.init(err, device_id);
   2625            }
   2626        }
   2627        Message::BufferMap {
   2628            device_id,
   2629            buffer_id,
   2630            mode,
   2631            offset,
   2632            size,
   2633        } => {
   2634            let mode = match mode {
   2635                /* GPUMapMode.READ */ 1 => wgc::device::HostMap::Read,
   2636                /* GPUMapMode.WRITE */ 2 => wgc::device::HostMap::Write,
   2637                _ => {
   2638                    let message = concat!(
   2639                        "GPUBuffer.mapAsync 'mode' argument must be ",
   2640                        "either GPUMapMode.READ or GPUMapMode.WRITE"
   2641                    );
   2642                    error_buf.init(
   2643                        ErrMsg {
   2644                            message: message.into(),
   2645                            r#type: ErrorType::Validation,
   2646                        },
   2647                        device_id,
   2648                    );
   2649                    let response = BufferMapResult::Error(message.into());
   2650                    *response_byte_buf =
   2651                        make_byte_buf(&ServerMessage::BufferMapResponse(buffer_id, response));
   2652                    return;
   2653                }
   2654            };
   2655 
   2656            let closure = wgpu_parent_build_buffer_map_closure(
   2657                global.owner,
   2658                device_id,
   2659                buffer_id,
   2660                mode,
   2661                offset,
   2662                size,
   2663            );
   2664 
   2665            let closure = Box::new(move |result| {
   2666                let _ = &closure;
   2667                (closure.callback)(closure.user_data, BufferMapAsyncStatus::from(result))
   2668            });
   2669            let operation = wgc::resource::BufferMapOperation {
   2670                host: mode,
   2671                callback: Some(closure),
   2672            };
   2673            let result = global.buffer_map_async(buffer_id, offset, Some(size), operation);
   2674 
   2675            if let Err(error) = result {
   2676                error_buf.init(error, device_id);
   2677            }
   2678        }
   2679        Message::BufferUnmap(device_id, buffer_id, flush) => {
   2680            wgpu_parent_buffer_unmap(global.owner, device_id, buffer_id, flush);
   2681        }
   2682        Message::QueueSubmit(
   2683            device_id,
   2684            queue_id,
   2685            command_buffer_ids,
   2686            texture_ids,
   2687            external_texture_source_ids,
   2688        ) => wgpu_parent_queue_submit(
   2689            global.owner,
   2690            device_id,
   2691            queue_id,
   2692            command_buffer_ids.as_ptr(),
   2693            command_buffer_ids.len(),
   2694            texture_ids.as_ptr(),
   2695            texture_ids.len(),
   2696            external_texture_source_ids.as_ptr(),
   2697            external_texture_source_ids.len(),
   2698        ),
   2699        Message::QueueOnSubmittedWorkDone(queue_id) => {
   2700            let closure = wgpu_parent_build_submitted_work_done_closure(global.owner, queue_id);
   2701            let closure = Box::new(move || {
   2702                let _ = &closure;
   2703                (closure.callback)(closure.user_data)
   2704            });
   2705            global.queue_on_submitted_work_done(queue_id, closure);
   2706        }
   2707 
   2708        Message::CreateSwapChain {
   2709            device_id,
   2710            queue_id,
   2711            width,
   2712            height,
   2713            format,
   2714            buffer_ids,
   2715            remote_texture_owner_id,
   2716            use_shared_texture_in_swap_chain,
   2717        } => {
   2718            wgpu_parent_create_swap_chain(
   2719                global.owner,
   2720                device_id,
   2721                queue_id,
   2722                width,
   2723                height,
   2724                format,
   2725                buffer_ids.as_ptr(),
   2726                buffer_ids.len(),
   2727                remote_texture_owner_id,
   2728                use_shared_texture_in_swap_chain,
   2729            );
   2730        }
   2731        Message::SwapChainPresent {
   2732            texture_id,
   2733            command_encoder_id,
   2734            command_buffer_id,
   2735            remote_texture_id,
   2736            remote_texture_owner_id,
   2737        } => {
   2738            wgpu_parent_swap_chain_present(
   2739                global.owner,
   2740                texture_id,
   2741                command_encoder_id,
   2742                command_buffer_id,
   2743                remote_texture_id,
   2744                remote_texture_owner_id,
   2745            );
   2746        }
   2747        Message::SwapChainDrop {
   2748            remote_texture_owner_id,
   2749            txn_type,
   2750            txn_id,
   2751        } => {
   2752            wgpu_parent_swap_chain_drop(global.owner, remote_texture_owner_id, txn_type, txn_id);
   2753        }
   2754 
   2755        Message::DestroyBuffer(id) => {
   2756            wgpu_server_dealloc_buffer_shmem(global.owner, id);
   2757            global.buffer_destroy(id)
   2758        }
   2759        Message::DestroyTexture(id) => {
   2760            wgpu_server_remove_shared_texture(global.owner, id);
   2761            global.texture_destroy(id)
   2762        }
   2763        Message::DestroyExternalTexture(id) => global.external_texture_destroy(id),
   2764        Message::DestroyExternalTextureSource(id) => {
   2765            wgpu_parent_destroy_external_texture_source(global.owner, id)
   2766        }
   2767        Message::DestroyDevice(id) => global.device_destroy(id),
   2768 
   2769        Message::DropAdapter(id) => global.adapter_drop(id),
   2770        Message::DropDevice(id) => {
   2771            wgpu_server_pre_device_drop(global.owner, id);
   2772            global.device_drop(id)
   2773        }
   2774        Message::DropQueue(id) => global.queue_drop(id),
   2775        Message::DropBuffer(id) => {
   2776            wgpu_server_dealloc_buffer_shmem(global.owner, id);
   2777            global.buffer_drop(id)
   2778        }
   2779        Message::DropCommandEncoder(id) => global.command_encoder_drop(id),
   2780        Message::DropRenderPassEncoder(_id) => {}
   2781        Message::DropComputePassEncoder(_id) => {}
   2782        Message::DropRenderBundleEncoder(_id) => {}
   2783        Message::DropCommandBuffer(id) => global.command_buffer_drop(id),
   2784        Message::DropRenderBundle(id) => global.render_bundle_drop(id),
   2785        Message::DropBindGroupLayout(id) => global.bind_group_layout_drop(id),
   2786        Message::DropPipelineLayout(id) => global.pipeline_layout_drop(id),
   2787        Message::DropBindGroup(id) => global.bind_group_drop(id),
   2788        Message::DropShaderModule(id) => global.shader_module_drop(id),
   2789        Message::DropComputePipeline(id) => global.compute_pipeline_drop(id),
   2790        Message::DropRenderPipeline(id) => global.render_pipeline_drop(id),
   2791        Message::DropTexture(id) => {
   2792            wgpu_server_remove_shared_texture(global.owner, id);
   2793            global.texture_drop(id);
   2794        }
   2795        Message::DropTextureView(id) => global.texture_view_drop(id).unwrap(),
   2796        Message::DropExternalTexture(id) => global.external_texture_drop(id),
   2797        Message::DropExternalTextureSource(id) => {
   2798            wgpu_parent_drop_external_texture_source(global.owner, id)
   2799        }
   2800        Message::DropSampler(id) => global.sampler_drop(id),
   2801        Message::DropQuerySet(id) => global.query_set_drop(id),
   2802    }
   2803 
   2804    if let Some((device_id, ty, message)) = error_buf.get_inner_data() {
   2805        wgpu_parent_handle_error(global.owner, device_id, ty, message);
   2806    }
   2807    if !response_byte_buf.is_empty() {
   2808        wgpu_parent_send_server_message(global.owner, response_byte_buf);
   2809    }
   2810 }
   2811 
   2812 #[no_mangle]
   2813 pub extern "C" fn wgpu_server_device_create_encoder(
   2814    global: &Global,
   2815    device_id: id::DeviceId,
   2816    desc: &wgt::CommandEncoderDescriptor<Option<&nsACString>>,
   2817    new_id: id::CommandEncoderId,
   2818    mut error_buf: ErrorBuffer,
   2819 ) {
   2820    let utf8_label = desc.label.map(|utf16| utf16.to_string());
   2821    let label = utf8_label.as_ref().map(|s| Cow::from(&s[..]));
   2822 
   2823    let desc = desc.map_label(|_| label);
   2824    let (_, error) = global.device_create_command_encoder(device_id, &desc, Some(new_id));
   2825    if let Some(err) = error {
   2826        error_buf.init(err, device_id);
   2827    }
   2828 }
   2829 
   2830 #[no_mangle]
   2831 pub extern "C" fn wgpu_server_encoder_finish(
   2832    global: &Global,
   2833    device_id: id::DeviceId,
   2834    command_encoder_id: id::CommandEncoderId,
   2835    command_buffer_id: id::CommandBufferId,
   2836    desc: &wgt::CommandBufferDescriptor<Option<&nsACString>>,
   2837    mut error_buf: ErrorBuffer,
   2838 ) {
   2839    let label = wgpu_string(desc.label);
   2840    let desc = desc.map_label(|_| label);
   2841    let (_, label_and_error) =
   2842        global.command_encoder_finish(command_encoder_id, &desc, Some(command_buffer_id));
   2843    if let Some((_label, err)) = label_and_error {
   2844        error_buf.init(err, device_id);
   2845    }
   2846 }
   2847 
   2848 #[no_mangle]
   2849 pub unsafe extern "C" fn wgpu_server_encoder_copy_texture_to_buffer(
   2850    global: &Global,
   2851    device_id: id::DeviceId,
   2852    self_id: id::CommandEncoderId,
   2853    source: &wgc::command::TexelCopyTextureInfo,
   2854    dst_buffer: wgc::id::BufferId,
   2855    dst_layout: &crate::TexelCopyBufferLayout,
   2856    size: &wgt::Extent3d,
   2857    mut error_buf: ErrorBuffer,
   2858 ) {
   2859    let destination = wgc::command::TexelCopyBufferInfo {
   2860        buffer: dst_buffer,
   2861        layout: dst_layout.into_wgt(),
   2862    };
   2863    if let Err(err) =
   2864        global.command_encoder_copy_texture_to_buffer(self_id, source, &destination, size)
   2865    {
   2866        error_buf.init(err, device_id);
   2867    }
   2868 }
   2869 
   2870 #[no_mangle]
   2871 pub unsafe extern "C" fn wgpu_server_queue_write_texture(
   2872    global: &Global,
   2873    device_id: id::DeviceId,
   2874    queue_id: id::QueueId,
   2875    destination: &wgt::TexelCopyTextureInfo<id::TextureId>,
   2876    data: FfiSlice<u8>,
   2877    data_layout: &crate::TexelCopyBufferLayout,
   2878    size: &wgt::Extent3d,
   2879    mut error_buf: ErrorBuffer,
   2880 ) {
   2881    let data = data.as_slice();
   2882    let data_layout = data_layout.into_wgt();
   2883    if let Err(err) = global.queue_write_texture(queue_id, destination, data, &data_layout, size) {
   2884        error_buf.init(err, device_id);
   2885    }
   2886 }
   2887 
   2888 #[no_mangle]
   2889 pub unsafe extern "C" fn wgpu_server_queue_submit(
   2890    global: &Global,
   2891    device_id: id::DeviceId,
   2892    self_id: id::QueueId,
   2893    command_buffers: FfiSlice<'_, id::CommandBufferId>,
   2894    mut error_buf: ErrorBuffer,
   2895 ) -> u64 {
   2896    let result = global.queue_submit(self_id, command_buffers.as_slice());
   2897 
   2898    match result {
   2899        Err((_index, err)) => {
   2900            error_buf.init(err, device_id);
   2901            return 0;
   2902        }
   2903        Ok(wrapped_index) => wrapped_index,
   2904    }
   2905 }
   2906 
   2907 #[repr(C)]
   2908 pub struct SubmittedWorkDoneClosure {
   2909    pub callback: unsafe extern "C" fn(user_data: *mut u8),
   2910    pub user_data: *mut u8,
   2911 }
   2912 unsafe impl Send for SubmittedWorkDoneClosure {}
   2913 
   2914 #[derive(Debug)]
   2915 #[cfg(target_os = "linux")]
   2916 pub struct VkSemaphoreHandle {
   2917    pub semaphore: vk::Semaphore,
   2918 }
   2919 
   2920 #[no_mangle]
   2921 #[cfg(target_os = "linux")]
   2922 pub extern "C" fn wgpu_vksemaphore_create_signal_semaphore(
   2923    global: &Global,
   2924    queue_id: id::QueueId,
   2925 ) -> *mut VkSemaphoreHandle {
   2926    let semaphore_handle = unsafe {
   2927        let Some(hal_queue) = global.queue_as_hal::<wgc::api::Vulkan>(queue_id) else {
   2928            emit_critical_invalid_note("Vulkan queue");
   2929            return ptr::null_mut();
   2930        };
   2931        let device = hal_queue.raw_device();
   2932 
   2933        let mut export_semaphore_create_info = vk::ExportSemaphoreCreateInfo::default()
   2934            .handle_types(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
   2935        let create_info =
   2936            vk::SemaphoreCreateInfo::default().push_next(&mut export_semaphore_create_info);
   2937        let semaphore = match device.create_semaphore(&create_info, None) {
   2938            Err(err) => {
   2939                let msg = CString::new(format!("create_semaphore() failed: {:?}", err)).unwrap();
   2940                gfx_critical_note(msg.as_ptr());
   2941                return ptr::null_mut();
   2942            }
   2943            Ok(semaphore) => semaphore,
   2944        };
   2945 
   2946        hal_queue.add_signal_semaphore(semaphore, None);
   2947 
   2948        VkSemaphoreHandle { semaphore }
   2949    };
   2950 
   2951    Box::into_raw(Box::new(semaphore_handle))
   2952 }
   2953 
   2954 #[no_mangle]
   2955 #[cfg(target_os = "linux")]
   2956 pub unsafe extern "C" fn wgpu_vksemaphore_get_file_descriptor(
   2957    global: &Global,
   2958    device_id: id::DeviceId,
   2959    handle: &VkSemaphoreHandle,
   2960 ) -> i32 {
   2961    let file_descriptor = unsafe {
   2962        match global.device_as_hal::<wgc::api::Vulkan>(device_id) {
   2963            None => {
   2964                emit_critical_invalid_note("Vulkan device");
   2965                None
   2966            }
   2967            Some(hal_device) => {
   2968                let device = hal_device.raw_device();
   2969                let instance = hal_device.shared_instance().raw_instance();
   2970 
   2971                let external_semaphore_fd =
   2972                    khr::external_semaphore_fd::Device::new(instance, device);
   2973                let get_fd_info = vk::SemaphoreGetFdInfoKHR::default()
   2974                    .semaphore(handle.semaphore)
   2975                    .handle_type(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
   2976 
   2977                external_semaphore_fd.get_semaphore_fd(&get_fd_info).ok()
   2978            }
   2979        }
   2980    };
   2981 
   2982    // From [Wikipedia](https://en.wikipedia.org/wiki/File_descriptor):
   2983    //
   2984    // > File descriptors typically have non-negative integer values, with negative values
   2985    // > being reserved to indicate "no value" or error conditions.
   2986    file_descriptor.unwrap_or(-1)
   2987 }
   2988 
   2989 #[no_mangle]
   2990 #[cfg(target_os = "linux")]
   2991 pub unsafe extern "C" fn wgpu_vksemaphore_destroy(
   2992    global: &Global,
   2993    device_id: id::DeviceId,
   2994    handle: &VkSemaphoreHandle,
   2995 ) {
   2996    unsafe {
   2997        let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else {
   2998            emit_critical_invalid_note("Vulkan device");
   2999            return;
   3000        };
   3001        let device = hal_device.raw_device();
   3002        device.destroy_semaphore(handle.semaphore, None);
   3003    };
   3004 }
   3005 
   3006 #[no_mangle]
   3007 #[cfg(target_os = "linux")]
   3008 pub unsafe extern "C" fn wgpu_vksemaphore_delete(handle: *mut VkSemaphoreHandle) {
   3009    let _ = Box::from_raw(handle);
   3010 }
   3011 
   3012 #[no_mangle]
   3013 pub extern "C" fn wgpu_server_buffer_drop(global: &Global, self_id: id::BufferId) {
   3014    global.buffer_drop(self_id);
   3015 }
   3016 
   3017 #[no_mangle]
   3018 pub extern "C" fn wgpu_server_command_encoder_drop(global: &Global, self_id: id::CommandEncoderId) {
   3019    global.command_encoder_drop(self_id);
   3020 }
   3021 
   3022 #[no_mangle]
   3023 pub extern "C" fn wgpu_server_command_buffer_drop(global: &Global, self_id: id::CommandBufferId) {
   3024    global.command_buffer_drop(self_id);
   3025 }
   3026 
   3027 /// Imports a Direct3D texture from a shared handle.
   3028 #[cfg(target_os = "windows")]
   3029 #[no_mangle]
   3030 pub unsafe extern "C" fn wgpu_server_device_import_texture_from_shared_handle(
   3031    global: &Global,
   3032    device_id: id::DeviceId,
   3033    id_in: id::TextureId,
   3034    desc: &wgt::TextureDescriptor<Option<&nsACString>, crate::FfiSlice<wgt::TextureFormat>>,
   3035    handle: *mut core::ffi::c_void,
   3036    mut error_buf: ErrorBuffer,
   3037 ) {
   3038    let desc = desc.map_label_and_view_formats(|l| wgpu_string(*l), |v| v.as_slice().to_vec());
   3039 
   3040    let Some(hal_device) = global.device_as_hal::<wgc::api::Dx12>(device_id) else {
   3041        emit_critical_invalid_note("dx12 device");
   3042        global.create_texture_error(Some(id_in), &desc);
   3043        return;
   3044    };
   3045    let dx12_device = hal_device.raw_device();
   3046 
   3047    let mut resource: Option<Direct3D12::ID3D12Resource> = None;
   3048    let res = dx12_device.OpenSharedHandle(Foundation::HANDLE(handle), &mut resource);
   3049    if res.is_err() || resource.is_none() {
   3050        error_buf.init(
   3051            ErrMsg {
   3052                message: "Failed to import texture from shared handle".into(),
   3053                r#type: ErrorType::Internal,
   3054            },
   3055            device_id,
   3056        );
   3057        global.create_texture_error(Some(id_in), &desc);
   3058        return;
   3059    }
   3060 
   3061    let hal_texture = <wgh::api::Dx12 as wgh::Api>::Device::texture_from_raw(
   3062        resource.unwrap(),
   3063        desc.format,
   3064        desc.dimension,
   3065        desc.size,
   3066        desc.mip_level_count,
   3067        desc.sample_count,
   3068    );
   3069 
   3070    let (_, error) =
   3071        global.create_texture_from_hal(Box::new(hal_texture), device_id, &desc, Some(id_in));
   3072    if let Some(err) = error {
   3073        error_buf.init(err, device_id);
   3074    }
   3075 }
   3076 
   3077 /// Imports a fence from a shared handle and queues a GPU-side wait on the
   3078 /// specified queue for the fence to reach a specific value.
   3079 #[cfg(target_os = "windows")]
   3080 #[no_mangle]
   3081 pub unsafe extern "C" fn wgpu_server_device_wait_fence_from_shared_handle(
   3082    global: &Global,
   3083    device_id: id::DeviceId,
   3084    queue_id: id::QueueId,
   3085    fence_handle: *mut core::ffi::c_void,
   3086    fence_value: wgh::FenceValue,
   3087 ) -> bool {
   3088    let Some(hal_device) = global.device_as_hal::<wgc::api::Dx12>(device_id) else {
   3089        emit_critical_invalid_note("dx12 device");
   3090        return false;
   3091    };
   3092    let Some(hal_queue) = global.queue_as_hal::<wgc::api::Dx12>(queue_id) else {
   3093        emit_critical_invalid_note("dx12 queue");
   3094        return false;
   3095    };
   3096 
   3097    let mut fence: Option<Direct3D12::ID3D12Fence> = None;
   3098    let res = hal_device
   3099        .raw_device()
   3100        .OpenSharedHandle(Foundation::HANDLE(fence_handle), &mut fence);
   3101    let fence = match (res, fence) {
   3102        (Ok(_), Some(fence)) => fence,
   3103        _ => return false,
   3104    };
   3105 
   3106    let res = hal_queue.as_raw().Wait(&fence, fence_value);
   3107    res.is_ok()
   3108 }
   3109 
   3110 #[cfg(target_os = "macos")]
   3111 mod macos {
   3112    use std::ffi::CString;
   3113 
   3114    use super::{emit_critical_invalid_note, gfx_critical_note, Global};
   3115    use crate::{
   3116        error::ErrorBuffer,
   3117        server::{
   3118            wgpu_server_ensure_shared_texture_for_swap_chain,
   3119            wgpu_server_get_external_io_surface_id,
   3120        },
   3121        wgpu_string, SwapChainId,
   3122    };
   3123 
   3124    use nsstring::nsACString;
   3125    use objc::{msg_send, sel, sel_impl};
   3126    use wgc::id;
   3127 
   3128    /// Imports a Metal texture from the specified plane of an IOSurface.
   3129    #[no_mangle]
   3130    pub unsafe extern "C" fn wgpu_server_device_import_texture_from_iosurface(
   3131        global: &Global,
   3132        device_id: id::DeviceId,
   3133        id_in: id::TextureId,
   3134        desc: &wgt::TextureDescriptor<Option<&nsACString>, crate::FfiSlice<wgt::TextureFormat>>,
   3135        io_surface_id: u32,
   3136        plane: usize,
   3137        mut error_buf: ErrorBuffer,
   3138    ) {
   3139        let desc = desc.map_label_and_view_formats(|l| wgpu_string(*l), |v| v.as_slice().to_vec());
   3140 
   3141        let surface = io_surface::lookup(io_surface_id);
   3142 
   3143        let Some(hal_device) = global.device_as_hal::<wgc::api::Metal>(device_id) else {
   3144            emit_critical_invalid_note("metal device");
   3145            global.create_texture_error(Some(id_in), &desc);
   3146            return;
   3147        };
   3148        let metal_device = hal_device.raw_device();
   3149 
   3150        let metal_desc = metal::TextureDescriptor::new();
   3151        let texture_type = match desc.dimension {
   3152            wgt::TextureDimension::D1 => metal::MTLTextureType::D1,
   3153            wgt::TextureDimension::D2 => {
   3154                if desc.sample_count > 1 {
   3155                    metal_desc.set_sample_count(desc.sample_count as u64);
   3156                    metal::MTLTextureType::D2Multisample
   3157                } else if desc.size.depth_or_array_layers > 1 {
   3158                    metal_desc.set_array_length(desc.size.depth_or_array_layers as u64);
   3159                    metal::MTLTextureType::D2Array
   3160                } else {
   3161                    metal::MTLTextureType::D2
   3162                }
   3163            }
   3164            wgt::TextureDimension::D3 => {
   3165                metal_desc.set_depth(desc.size.depth_or_array_layers as u64);
   3166                metal::MTLTextureType::D3
   3167            }
   3168        };
   3169        metal_desc.set_texture_type(texture_type);
   3170        let format = match desc.format {
   3171            wgt::TextureFormat::Rgba8Unorm => metal::MTLPixelFormat::RGBA8Unorm,
   3172            wgt::TextureFormat::Bgra8Unorm => metal::MTLPixelFormat::BGRA8Unorm,
   3173            wgt::TextureFormat::R8Unorm => metal::MTLPixelFormat::R8Unorm,
   3174            wgt::TextureFormat::Rg8Unorm => metal::MTLPixelFormat::RG8Unorm,
   3175            wgt::TextureFormat::R16Unorm => metal::MTLPixelFormat::R16Unorm,
   3176            wgt::TextureFormat::Rg16Unorm => metal::MTLPixelFormat::RG16Unorm,
   3177            _ => unreachable!(),
   3178        };
   3179        metal_desc.set_pixel_format(format);
   3180        metal_desc.set_width(desc.size.width as u64);
   3181        metal_desc.set_height(desc.size.height as u64);
   3182        metal_desc.set_mipmap_level_count(desc.mip_level_count as u64);
   3183        metal_desc.set_storage_mode(metal::MTLStorageMode::Private);
   3184        metal_desc.set_usage(metal::MTLTextureUsage::ShaderRead);
   3185 
   3186        let metal_texture: metal::Texture = msg_send![
   3187            *metal_device,
   3188            newTextureWithDescriptor:metal_desc iosurface:surface.obj plane:plane
   3189        ];
   3190 
   3191        let hal_texture = <wgh::api::Metal as wgh::Api>::Device::texture_from_raw(
   3192            metal_texture,
   3193            desc.format,
   3194            texture_type,
   3195            desc.array_layer_count(),
   3196            desc.mip_level_count,
   3197            wgh::CopyExtent::map_extent_to_copy_size(&desc.size, desc.dimension),
   3198        );
   3199 
   3200        let (_, error) = unsafe {
   3201            global.create_texture_from_hal(Box::new(hal_texture), device_id, &desc, Some(id_in))
   3202        };
   3203        if let Some(err) = error {
   3204            error_buf.init(err, device_id);
   3205        }
   3206    }
   3207 
   3208    impl super::Global {
   3209        pub(super) fn create_texture_with_shared_texture_iosurface(
   3210            &self,
   3211            device_id: id::DeviceId,
   3212            texture_id: id::TextureId,
   3213            desc: &wgc::resource::TextureDescriptor,
   3214            swap_chain_id: Option<SwapChainId>,
   3215        ) -> bool {
   3216            use metal::foreign_types::ForeignType as _;
   3217 
   3218            let ret = unsafe {
   3219                wgpu_server_ensure_shared_texture_for_swap_chain(
   3220                    self.owner,
   3221                    swap_chain_id.unwrap(),
   3222                    device_id,
   3223                    texture_id,
   3224                    desc.size.width,
   3225                    desc.size.height,
   3226                    desc.format,
   3227                    desc.usage,
   3228                )
   3229            };
   3230            if ret != true {
   3231                let msg = c"Failed to create shared texture";
   3232                unsafe {
   3233                    gfx_critical_note(msg.as_ptr());
   3234                }
   3235                return false;
   3236            }
   3237 
   3238            let io_surface_id =
   3239                unsafe { wgpu_server_get_external_io_surface_id(self.owner, texture_id) };
   3240            if io_surface_id == 0 {
   3241                let msg = c"Failed to get io surface id";
   3242                unsafe {
   3243                    gfx_critical_note(msg.as_ptr());
   3244                }
   3245                return false;
   3246            }
   3247 
   3248            let io_surface = io_surface::lookup(io_surface_id);
   3249 
   3250            let desc_ref = &desc;
   3251 
   3252            let raw_texture: metal::Texture = unsafe {
   3253                let Some(hal_device) = self.device_as_hal::<wgc::api::Metal>(device_id) else {
   3254                    emit_critical_invalid_note("metal device");
   3255                    return false;
   3256                };
   3257 
   3258                let device = hal_device.raw_device();
   3259 
   3260                objc::rc::autoreleasepool(|| {
   3261                    let descriptor = metal::TextureDescriptor::new();
   3262                    let usage = metal::MTLTextureUsage::RenderTarget
   3263                        | metal::MTLTextureUsage::ShaderRead
   3264                        | metal::MTLTextureUsage::PixelFormatView;
   3265 
   3266                    descriptor.set_texture_type(metal::MTLTextureType::D2);
   3267                    descriptor.set_width(desc_ref.size.width as u64);
   3268                    descriptor.set_height(desc_ref.size.height as u64);
   3269                    descriptor.set_mipmap_level_count(desc_ref.mip_level_count as u64);
   3270                    descriptor.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm);
   3271                    descriptor.set_usage(usage);
   3272                    descriptor.set_storage_mode(metal::MTLStorageMode::Private);
   3273 
   3274                    msg_send![*device, newTextureWithDescriptor: descriptor iosurface:io_surface.obj plane:0]
   3275                })
   3276            };
   3277 
   3278            if raw_texture.as_ptr().is_null() {
   3279                let msg = c"Failed to create metal::Texture for swap chain";
   3280                unsafe {
   3281                    gfx_critical_note(msg.as_ptr());
   3282                }
   3283                return false;
   3284            }
   3285 
   3286            if let Some(label) = &desc_ref.label {
   3287                raw_texture.set_label(&label);
   3288            }
   3289 
   3290            let hal_texture = unsafe {
   3291                <wgh::api::Metal as wgh::Api>::Device::texture_from_raw(
   3292                    raw_texture,
   3293                    wgt::TextureFormat::Bgra8Unorm,
   3294                    metal::MTLTextureType::D2,
   3295                    1,
   3296                    1,
   3297                    wgh::CopyExtent {
   3298                        width: desc.size.width,
   3299                        height: desc.size.height,
   3300                        depth: 1,
   3301                    },
   3302                )
   3303            };
   3304 
   3305            let (_, error) = unsafe {
   3306                self.create_texture_from_hal(
   3307                    Box::new(hal_texture),
   3308                    device_id,
   3309                    &desc,
   3310                    Some(texture_id),
   3311                )
   3312            };
   3313            if let Some(err) = error {
   3314                let msg =
   3315                    CString::new(format!("create_texture_from_hal() failed: {:?}", err)).unwrap();
   3316                unsafe {
   3317                    gfx_critical_note(msg.as_ptr());
   3318                }
   3319                return false;
   3320            }
   3321 
   3322            true
   3323        }
   3324    }
   3325 }