/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use log::warn; use webrender::RenderApiSender; use wgpu_thread::WGPU; pub use {wgpu_core as wgc, wgpu_types as wgt}; pub mod identity; mod poll_thread; mod wgpu_thread; use std::borrow::Cow; use std::collections::HashMap; use std::num::NonZeroU64; use std::sync::{Arc, Mutex}; use arrayvec::ArrayVec; use euclid::default::Size2D; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use serde::{Deserialize, Serialize}; use servo_config::pref; use webrender_api::{DocumentId, ImageData, ImageDescriptor, ImageKey}; use webrender_traits::{ WebrenderExternalImageApi, WebrenderExternalImageRegistry, WebrenderImageSource, }; use wgc::id; mod dom_messages; mod script_messages; pub use dom_messages::*; pub use identity::*; pub use script_messages::*; pub type ErrorScopeId = NonZeroU64; pub use wgpu_thread::PRESENTATION_BUFFER_COUNT; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct WebGPU(pub IpcSender<(Option, WebGPURequest)>); impl WebGPU { pub fn new( webrender_api_sender: RenderApiSender, webrender_document: DocumentId, external_images: Arc>, wgpu_image_map: Arc>>, ) -> Option<(Self, IpcReceiver)> { if !pref!(dom.webgpu.enabled) { return None; } let (sender, receiver) = match ipc::channel() { Ok(sender_and_receiver) => sender_and_receiver, Err(e) => { warn!( "Failed to create sender and receiver for WGPU thread ({})", e ); return None; }, }; let sender_clone = sender.clone(); let (script_sender, script_recv) = match ipc::channel() { Ok(sender_and_receiver) => sender_and_receiver, Err(e) => { warn!( "Failed to create receiver and sender for WGPU thread ({})", e ); return None; }, }; if let Err(e) = std::thread::Builder::new() .name("WGPU".to_owned()) .spawn(move || { WGPU::new( receiver, sender_clone, script_sender, webrender_api_sender, webrender_document, external_images, wgpu_image_map, ) .run(); }) { warn!("Failed to spawn WGPU thread ({})", e); return None; } Some((WebGPU(sender), script_recv)) } pub fn exit(&self, sender: IpcSender<()>) -> Result<(), &'static str> { self.0 .send((None, WebGPURequest::Exit(sender))) .map_err(|_| "Failed to send Exit message") } } #[derive(Default)] pub struct WGPUExternalImages { pub images: Arc>>, pub locked_ids: HashMap>, } impl WebrenderExternalImageApi for WGPUExternalImages { fn lock(&mut self, id: u64) -> (WebrenderImageSource, Size2D) { let size; let data; if let Some(present_data) = self.images.lock().unwrap().get(&id) { size = present_data.size; data = present_data.data.clone(); } else { size = Size2D::new(0, 0); data = Vec::new(); } let _ = self.locked_ids.insert(id, data); ( WebrenderImageSource::Raw(self.locked_ids.get(&id).unwrap().as_slice()), size, ) } fn unlock(&mut self, id: u64) { let _ = self.locked_ids.remove(&id); } } pub struct PresentationData { device_id: id::DeviceId, queue_id: id::QueueId, pub data: Vec, pub size: Size2D, unassigned_buffer_ids: ArrayVec, available_buffer_ids: ArrayVec, queued_buffer_ids: ArrayVec, buffer_stride: u32, image_key: ImageKey, image_desc: ImageDescriptor, image_data: ImageData, } pub trait Transmute { fn transmute(self) -> id::Id; } impl Transmute for id::Id { fn transmute(self) -> id::Id { // if this is removed next one should be removed too. self.into_queue_id() } } impl Transmute for id::Id { fn transmute(self) -> id::Id { // SAFETY: This is safe because queue_id = device_id in wgpu unsafe { id::Id::from_raw(self.into_raw()) } } }