aboutsummaryrefslogtreecommitdiffstats
path: root/components/webgpu/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/webgpu/lib.rs')
-rw-r--r--components/webgpu/lib.rs153
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
+ }
+}