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 }