diff options
Diffstat (limited to 'components/webgpu/lib.rs')
-rw-r--r-- | components/webgpu/lib.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs new file mode 100644 index 00000000000..5cb449c6c3c --- /dev/null +++ b/components/webgpu/lib.rs @@ -0,0 +1,153 @@ +/* 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/. */ + +#[macro_use] +extern crate log; +#[macro_use] +extern crate serde; +#[macro_use] +pub extern crate wgpu_native as wgpu; + +use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +use servo_config::pref; +use wgpu::adapter_get_info; +use wgpu::TypedId; + +#[derive(Debug, Deserialize, Serialize)] +pub enum WebGPUResponse { + RequestAdapter(String, WebGPUAdapter), + RequestDevice, +} + +pub type WebGPUResponseResult = Result<WebGPUResponse, String>; + +#[derive(Debug, Deserialize, Serialize)] +pub enum WebGPURequest { + RequestAdapter(IpcSender<WebGPUResponseResult>, wgpu::RequestAdapterOptions), + RequestDevice, + Exit(IpcSender<()>), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct WebGPU(pub IpcSender<WebGPURequest>); + +impl WebGPU { + pub fn new() -> Option<Self> { + 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 receiciver for WGPU thread ({})", + e + ); + return None; + }, + }; + + if let Err(e) = std::thread::Builder::new() + .name("WGPU".to_owned()) + .spawn(move || { + WGPU::new(receiver).run(); + }) + { + warn!("Failed to spwan WGPU thread ({})", e); + return None; + } + Some(WebGPU(sender)) + } + + pub fn exit(&self, sender: IpcSender<()>) -> Result<(), &'static str> { + self.0 + .send(WebGPURequest::Exit(sender)) + .map_err(|_| "Failed to send Exit message") + } +} + +struct WGPU { + receiver: IpcReceiver<WebGPURequest>, + global: wgpu::Global, + adapters: Vec<WebGPUAdapter>, + // Track invalid adapters https://gpuweb.github.io/gpuweb/#invalid + _invalid_adapters: Vec<WebGPUAdapter>, +} + +impl WGPU { + fn new(receiver: IpcReceiver<WebGPURequest>) -> Self { + WGPU { + receiver, + global: wgpu::Global::new("webgpu-native"), + adapters: Vec::new(), + _invalid_adapters: Vec::new(), + } + } + + fn deinit(self) { + self.global.delete() + } + + fn run(mut self) { + while let Ok(msg) = self.receiver.recv() { + match msg { + WebGPURequest::RequestAdapter(sender, options) => { + let adapter_id = match wgpu::request_adapter( + &self.global, + &options, + // TODO: The ids we pass here should be generated by the client + &[ + wgpu::Id::zip(0, 0, wgpu::Backend::Vulkan), + wgpu::Id::zip(0, 0, wgpu::Backend::Metal), + wgpu::Id::zip(0, 0, wgpu::Backend::Dx12), + ], + ) { + Some(id) => id, + None => { + if let Err(e) = + sender.send(Err("Failed to get webgpu adapter".to_string())) + { + warn!( + "Failed to send response to WebGPURequest::RequestAdapter ({})", + e + ) + } + return; + }, + }; + let adapter = WebGPUAdapter(adapter_id); + self.adapters.push(adapter); + let info = + gfx_select!(adapter_id => adapter_get_info(&self.global, adapter_id)); + if let Err(e) = + sender.send(Ok(WebGPUResponse::RequestAdapter(info.name, adapter))) + { + warn!( + "Failed to send response to WebGPURequest::RequestAdapter ({})", + e + ) + } + }, + WebGPURequest::RequestDevice => {}, + WebGPURequest::Exit(sender) => { + self.deinit(); + if let Err(e) = sender.send(()) { + warn!("Failed to send response to WebGPURequest::Exit ({})", e) + } + return; + }, + } + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct WebGPUAdapter(pub wgpu::AdapterId); + +impl MallocSizeOf for WebGPUAdapter { + fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { + 0 + } +} |