diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-11-25 00:00:46 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-25 00:00:46 -0500 |
commit | ea3249550467bd9f5a1de8271ed4fcaa70a7cdda (patch) | |
tree | d7b4e5a7c79c34a953a2c6cc38201645a2759d6a | |
parent | c8791c0dbb0a9bf3cad94744750f9961ae03ade7 (diff) | |
parent | 47e39ec1e3f5ee8b6d72212872898b21e2bc7220 (diff) | |
download | servo-ea3249550467bd9f5a1de8271ed4fcaa70a7cdda.tar.gz servo-ea3249550467bd9f5a1de8271ed4fcaa70a7cdda.zip |
Auto merge of #24708 - szeged:webgpu-base, r=gterzian,kvark
Initial implementation of WebGPU API
<!-- Please describe your changes on the following line: -->
- Added the WebIDL bindings for GPU and GPUadapter interfaces.
- Created a background thread for WebGPU api calls.
- Established the async communication between the background thread and the WebGPU interfaces.
- Implemented the `requesAdapter` function of `navigator.gpu`
`./mach test-tidy` reports an error due to the different `arrayvec` version used in `servo` and `webgpu`, so added it to the ignore list in `servo-tidy.toml`
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes addresses a part of #https://github.com/servo/servo/issues/24706
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
cc @jdm, cc @kvark
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/24708)
<!-- Reviewable:end -->
31 files changed, 853 insertions, 7 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0947f0385e9..c216acf7031 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,12 +126,33 @@ dependencies = [ ] [[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] name = "ascii" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50" [[package]] +name = "ash" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003d1fb2eb12eb06d4a03dbe02eea67a9fac910fa97932ab9e3a75b96a1ea5e5" +dependencies = [ + "shared_library", +] + +[[package]] +name = "atom" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2" + +[[package]] name = "atomic_refcell" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -672,6 +693,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d" [[package]] +name = "colorful" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bca1619ff57dd7a56b58a8e25ef4199f123e78e503fe1653410350a1b98ae65" + +[[package]] name = "combine" version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -754,6 +781,7 @@ dependencies = [ "servo_remutex", "servo_url", "style_traits", + "webgpu", "webrender_api", "webvr_traits", "webxr-api", @@ -783,6 +811,12 @@ dependencies = [ ] [[package]] +name = "copyless" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127" + +[[package]] name = "core-foundation" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -866,7 +900,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" dependencies = [ - "arrayvec", + "arrayvec 0.4.6", "cfg-if", "crossbeam-utils", "lazy_static", @@ -942,6 +976,17 @@ dependencies = [ ] [[package]] +name = "d3d12" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7ed48e89905e5e146bcc1951cc3facb9e44aea9adf5dc01078cda1bd24b662" +dependencies = [ + "bitflags", + "libloading", + "winapi", +] + +[[package]] name = "darling" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1497,6 +1542,12 @@ dependencies = [ ] [[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + +[[package]] name = "generic-array" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1566,6 +1617,123 @@ dependencies = [ ] [[package]] +name = "gfx-auxil" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572eee952a9a23c99cfe3e4fd95d277784058a89ac3c77ff6fa3d80a4e321919" +dependencies = [ + "fxhash", + "gfx-hal", + "spirv_cross", +] + +[[package]] +name = "gfx-backend-dx11" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66c77836ff26cf9916e5c8745715a22eae1fc61d994ffa0bea8a7dbd708ece2" +dependencies = [ + "bitflags", + "gfx-auxil", + "gfx-hal", + "libloading", + "log", + "parking_lot", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "winapi", + "wio", +] + +[[package]] +name = "gfx-backend-dx12" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e913cc800fb12eaba2c420091a02aca9aafbefd672600dfc5b52654343d341" +dependencies = [ + "bitflags", + "d3d12", + "gfx-auxil", + "gfx-hal", + "log", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "winapi", +] + +[[package]] +name = "gfx-backend-empty" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d383e6bc48867cb37d298a20139fd1eec298f8f6d594690cd1c50ef25470cc7" +dependencies = [ + "gfx-hal", + "raw-window-handle", +] + +[[package]] +name = "gfx-backend-metal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de5c71f18ba805c95b84d6c78c472ef44485a6fc46e3b49fe1e6739c8d7b0c0" +dependencies = [ + "arrayvec 0.5.1", + "bitflags", + "block", + "cocoa 0.19.1", + "copyless", + "core-graphics", + "foreign-types", + "gfx-auxil", + "gfx-hal", + "lazy_static", + "log", + "metal", + "objc", + "parking_lot", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "storage-map", +] + +[[package]] +name = "gfx-backend-vulkan" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62538fedd66a78968a162e8e1a29d085ffbc97f8782634684b2f7da7aea59207" +dependencies = [ + "arrayvec 0.5.1", + "ash", + "byteorder", + "core-graphics", + "gfx-hal", + "lazy_static", + "log", + "objc", + "raw-window-handle", + "smallvec", + "winapi", + "x11", +] + +[[package]] +name = "gfx-hal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c88981665c780447bb08eb099e1ded330754a7246719bab927ee4a949c0ba7f" +dependencies = [ + "bitflags", + "raw-window-handle", + "smallvec", +] + +[[package]] name = "gfx_traits" version = "0.0.1" dependencies = [ @@ -2131,6 +2299,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" [[package]] +name = "hibitset" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e7292fd9f7fe89fa35c98048f2d0a69b79ed243604234d18f6f8a1aa6f408d" +dependencies = [ + "atom", +] + +[[package]] name = "histogram" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2293,7 +2470,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7371aa3c98fad60de2d9b517e2e1ed45593c32b0c77249310fa507749a2a318b" dependencies = [ - "arrayvec", + "arrayvec 0.4.6", "byteorder", "num-traits", ] @@ -2764,6 +2941,7 @@ dependencies = [ "style_traits", "surfman", "webdriver_server", + "webgpu", "webrender", "webrender_api", "webrender_traits", @@ -2833,7 +3011,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69589b8844c0b3745cc031a35b62bc33b0fb9e5ba7613756d802c52861dcdb4c" dependencies = [ - "arrayvec", + "arrayvec 0.4.6", "euclid", "num-traits", ] @@ -2989,6 +3167,21 @@ dependencies = [ ] [[package]] +name = "metal" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf8052f20601c7af6293d3f7bf7b9159aee5974804fe65d871d437f933ec1eb" +dependencies = [ + "bitflags", + "block", + "cocoa 0.19.1", + "core-graphics", + "foreign-types", + "log", + "objc", +] + +[[package]] name = "metrics" version = "0.0.1" dependencies = [ @@ -3393,6 +3586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d" dependencies = [ "malloc_buf", + "objc_exception", ] [[package]] @@ -3407,6 +3601,15 @@ dependencies = [ ] [[package]] +name = "objc_exception" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "098cd29a2fa3c230d3463ae069cecccc3fdfd64c0d2496ab5b96f82dab6a00dc" +dependencies = [ + "gcc", +] + +[[package]] name = "objc_id" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3893,6 +4096,12 @@ dependencies = [ ] [[package]] +name = "range-alloc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5927936723a9e8b715d37d7e4b390455087c4bdf25b9f702309460577b14f9" + +[[package]] name = "raqote" version = "0.7.4-alpha.0" source = "git+https://github.com/jrmuizel/raqote#2a801bca7253e053767ef5ea11b0ee77c52617c9" @@ -3906,6 +4115,15 @@ dependencies = [ ] [[package]] +name = "raw-window-handle" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9db80d08d3ed847ce4fb3def46de0af4bfb6155bd09bd6eaf28b5ac72541c1f1" +dependencies = [ + "libc", +] + +[[package]] name = "rayon" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3989,6 +4207,16 @@ dependencies = [ ] [[package]] +name = "relevant" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc232e13d37f4547f5b9b42a5efc380cabe5dbc1807f8b893580640b2ab0308" +dependencies = [ + "cfg-if", + "log", +] + +[[package]] name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3998,6 +4226,33 @@ dependencies = [ ] [[package]] +name = "rendy-descriptor" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f475bcc0505946e998590f1f0545c52ef4b559174a1b353a7ce6638def8b621e" +dependencies = [ + "gfx-hal", + "log", + "relevant", + "smallvec", +] + +[[package]] +name = "rendy-memory" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed492161a819feae7f27f418bb16035276ac20649c60d756699152cb5c1960ec" +dependencies = [ + "colorful", + "gfx-hal", + "hibitset", + "log", + "relevant", + "slab", + "smallvec", +] + +[[package]] name = "rle-decode-fast" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4077,7 +4332,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8eb11f5b0a98c8eca2fb1483f42646d8c340e83e46ab416f8a063a0fd0eeb20" dependencies = [ "approx", - "arrayvec", + "arrayvec 0.4.6", "ordered-float", "stb_truetype", ] @@ -4199,6 +4454,7 @@ dependencies = [ "utf-8", "uuid", "webdriver", + "webgpu", "webrender_api", "webvr_traits", "webxr-api", @@ -4291,6 +4547,7 @@ dependencies = [ "time", "url", "webdriver", + "webgpu", "webrender_api", "webvr_traits", "webxr-api", @@ -4905,6 +5162,14 @@ dependencies = [ ] [[package]] +name = "spirv_cross" +version = "0.16.0" +source = "git+https://github.com/kvark/spirv_cross?branch=wgpu#636677bad724797789239c16e6d332e9b4d97b86" +dependencies = [ + "cc", +] + +[[package]] name = "stable_deref_trait" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4927,6 +5192,15 @@ dependencies = [ ] [[package]] +name = "storage-map" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0a4829a5c591dc24a944a736d6b1e4053e51339a79fd5d4702c4c999a9c45e" +dependencies = [ + "lock_api", +] + +[[package]] name = "string" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4971,7 +5245,7 @@ name = "style" version = "0.0.1" dependencies = [ "app_units", - "arrayvec", + "arrayvec 0.4.6", "atomic_refcell", "bindgen", "bitflags", @@ -5583,7 +5857,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2606e9192f308ddc4f0b3c5d1bf3400e28a70fff956e9d9f46d23b094746d9f" dependencies = [ - "arrayvec", + "arrayvec 0.4.6", ] [[package]] @@ -5897,6 +6171,19 @@ dependencies = [ ] [[package]] +name = "webgpu" +version = "0.0.1" +dependencies = [ + "embedder_traits", + "ipc-channel", + "log", + "malloc_size_of", + "serde", + "servo_config", + "wgpu-native", +] + +[[package]] name = "webrender" version = "0.60.0" source = "git+https://github.com/servo/webrender#4f2d78adb6e07e3e5ab2da9765613ecf9e07eee0" @@ -6038,6 +6325,30 @@ dependencies = [ ] [[package]] +name = "wgpu-native" +version = "0.4.0" +source = "git+https://github.com/zakorgy/wgpu?branch=v0.4#128a16b9887a60a087a9d41ff68b20ce07cf6265" +dependencies = [ + "arrayvec 0.5.1", + "bitflags", + "copyless", + "fxhash", + "gfx-backend-dx11", + "gfx-backend-dx12", + "gfx-backend-empty", + "gfx-backend-metal", + "gfx-backend-vulkan", + "gfx-hal", + "log", + "parking_lot", + "rendy-descriptor", + "rendy-memory", + "serde", + "smallvec", + "vec_map", +] + +[[package]] name = "which" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index ee35ba935a9..3bb824b3417 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,5 @@ opt-level = 3 mio = { git = "https://github.com/servo/mio.git", branch = "servo" } # https://github.com/retep998/winapi-rs/pull/816 winapi = { git = "https://github.com/servo/winapi-rs", branch = "patch-1" } +spirv_cross = { git = "https://github.com/kvark/spirv_cross", branch = "wgpu" } +wgpu-native = { git = "https://github.com/zakorgy/wgpu", branch = "v0.4" } diff --git a/components/config/opts.rs b/components/config/opts.rs index 292d06c67dc..fb4e3112837 100644 --- a/components/config/opts.rs +++ b/components/config/opts.rs @@ -713,6 +713,12 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR "A preference to set to enable", "dom.bluetooth.enabled", ); + opts.optmulti( + "", + "pref", + "A preference to set to enable", + "dom.webgpu.enabled", + ); opts.optflag("b", "no-native-titlebar", "Do not use native titlebar"); opts.optflag("w", "webrender", "Use webrender backend"); opts.optopt("G", "graphics", "Select graphics backend (gl or es2)", "gl"); diff --git a/components/config/prefs.rs b/components/config/prefs.rs index 7e4fb7551a5..a1e8f96b906 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -159,6 +159,9 @@ mod gen { }, }, dom: { + webgpu: { + enabled: bool, + }, bluetooth: { enabled: bool, testing: { diff --git a/components/constellation/Cargo.toml b/components/constellation/Cargo.toml index ec360006aad..893930c701a 100644 --- a/components/constellation/Cargo.toml +++ b/components/constellation/Cargo.toml @@ -47,6 +47,7 @@ servo_geometry = {path = "../geometry"} servo_rand = {path = "../rand"} servo_remutex = {path = "../remutex"} servo_url = {path = "../url"} +webgpu = {path = "../webgpu"} webvr_traits = {path = "../webvr_traits"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 82b99938f3b..3bd77ebf137 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -172,6 +172,7 @@ use std::sync::Arc; use std::thread; use style_traits::viewport::ViewportConstraints; use style_traits::CSSPixel; +use webgpu::WebGPU; use webvr_traits::{WebVREvent, WebVRMsg}; type PendingApprovalNavigations = HashMap<PipelineId, (LoadData, HistoryEntryReplacement)>; @@ -440,6 +441,10 @@ pub struct Constellation<Message, LTF, STF> { /// Entry point to create and get channels to a WebGLThread. webgl_threads: Option<WebGLThreads>, + /// An IPC channel for the constellation to send messages to the + /// WebGPU threads. + webgpu: Option<WebGPU>, + /// A channel through which messages can be sent to the webvr thread. webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -521,6 +526,9 @@ pub struct InitialConstellationState { /// Entry point to create and get channels to a WebGLThread. pub webgl_threads: Option<WebGLThreads>, + /// A channel to the WebGPU threads. + pub webgpu: Option<WebGPU>, + /// A channel to the webgl thread. pub webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -836,6 +844,7 @@ where (rng, prob) }), webgl_threads: state.webgl_threads, + webgpu: state.webgpu, webvr_chan: state.webvr_chan, webxr_registry: state.webxr_registry, canvas_chan: CanvasPaintThread::start(), @@ -1090,6 +1099,7 @@ where .webgl_threads .as_ref() .map(|threads| threads.pipeline()), + webgpu: self.webgpu.clone(), webvr_chan: self.webvr_chan.clone(), webxr_registry: self.webxr_registry.clone(), player_context: self.player_context.clone(), @@ -2355,6 +2365,17 @@ where } } + if let Some(webgpu) = self.webgpu.as_ref() { + debug!("Exiting WebGPU thread."); + let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!"); + if let Err(e) = webgpu.exit(sender) { + warn!("Exit WebGPU Thread failed ({})", e); + } + if let Err(e) = receiver.recv() { + warn!("Failed to receive exit response from WebGPU ({})", e); + } + } + if let Some(chan) = self.webvr_chan.as_ref() { debug!("Exiting WebVR thread."); if let Err(e) = chan.send(WebVRMsg::Exit) { diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 3ac5ded15ed..fd7202aa9ec 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -46,6 +46,7 @@ use std::process; use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::sync::Arc; +use webgpu::WebGPU; use webvr_traits::WebVRMsg; /// A `Pipeline` is the constellation's view of a `Document`. Each pipeline has an @@ -188,6 +189,9 @@ pub struct InitialPipelineState { /// A channel to the WebGL thread. pub webgl_chan: Option<WebGLPipeline>, + /// A channel to the WebGPU threads. + pub webgpu: Option<WebGPU>, + /// A channel to the webvr thread. pub webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -299,6 +303,7 @@ impl Pipeline { webrender_document: state.webrender_document, webgl_chan: state.webgl_chan, webvr_chan: state.webvr_chan, + webgpu: state.webgpu, webxr_registry: state.webxr_registry, player_context: state.player_context, }; @@ -504,6 +509,7 @@ pub struct UnprivilegedPipelineContent { webrender_api_sender: webrender_api::RenderApiSender, webrender_document: webrender_api::DocumentId, webgl_chan: Option<WebGLPipeline>, + webgpu: Option<WebGPU>, webvr_chan: Option<IpcSender<WebVRMsg>>, webxr_registry: webxr_api::Registry, player_context: WindowGLContext, @@ -556,6 +562,7 @@ impl UnprivilegedPipelineContent { pipeline_namespace_id: self.pipeline_namespace_id, content_process_shutdown_chan: content_process_shutdown_chan, webgl_chan: self.webgl_chan, + webgpu: self.webgpu, webvr_chan: self.webvr_chan, webxr_registry: self.webxr_registry, webrender_document: self.webrender_document, diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index c44a9a06a54..855d3d4dbc8 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -113,6 +113,7 @@ utf-8 = "0.7" uuid = {version = "0.8", features = ["v4"]} xml5ever = "0.16" webdriver = "0.40" +webgpu = {path = "../webgpu"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr_traits = {path = "../webvr_traits"} webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 3ff7a044b53..5dc9e141ed5 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -134,7 +134,10 @@ DOMInterfaces = { 'XR': { 'inCompartments': ['SupportsSessionMode', 'RequestSession'], -} +}, +'GPU': { + 'inCompartments': ['RequestAdapter'], +} } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 2051a1a19d8..fbd4da02d5b 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -145,6 +145,7 @@ use tendril::stream::LossyDecoder; use tendril::{StrTendril, TendrilSink}; use time::{Duration, Timespec}; use uuid::Uuid; +use webgpu::{WebGPU, WebGPUAdapter}; use webrender_api::{DocumentId, ImageKey, RenderApiSender}; use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; use webxr_api::SwapChainId as WebXRSwapChainId; @@ -502,6 +503,8 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId); unsafe_no_jsmanaged_fields!(WebGLVertexArrayId); unsafe_no_jsmanaged_fields!(WebGLVersion); unsafe_no_jsmanaged_fields!(WebGLSLVersion); +unsafe_no_jsmanaged_fields!(WebGPU); +unsafe_no_jsmanaged_fields!(WebGPUAdapter); unsafe_no_jsmanaged_fields!(WebXRSwapChainId); unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand); diff --git a/components/script/dom/gpu.rs b/components/script/dom/gpu.rs new file mode 100644 index 00000000000..cbde108bc01 --- /dev/null +++ b/components/script/dom/gpu.rs @@ -0,0 +1,158 @@ +/* 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 crate::compartments::InCompartment; +use crate::dom::bindings::codegen::Bindings::GPUBinding::GPURequestAdapterOptions; +use crate::dom::bindings::codegen::Bindings::GPUBinding::{self, GPUMethods, GPUPowerPreference}; +use crate::dom::bindings::error::Error; +use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::str::DOMString; +use crate::dom::globalscope::GlobalScope; +use crate::dom::gpuadapter::GPUAdapter; +use crate::dom::promise::Promise; +use crate::task_source::TaskSource; +use dom_struct::dom_struct; +use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::router::ROUTER; +use js::jsapi::Heap; +use std::rc::Rc; +use webgpu::wgpu; +use webgpu::{WebGPU, WebGPURequest, WebGPUResponse, WebGPUResponseResult}; + +#[dom_struct] +pub struct GPU { + reflector_: Reflector, +} + +impl GPU { + pub fn new_inherited() -> GPU { + GPU { + reflector_: Reflector::new(), + } + } + + pub fn new(global: &GlobalScope) -> DomRoot<GPU> { + reflect_dom_object(Box::new(GPU::new_inherited()), global, GPUBinding::Wrap) + } + + fn wgpu_channel(&self) -> Option<WebGPU> { + self.global().as_window().webgpu_channel() + } +} + +pub trait AsyncWGPUListener { + fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>); +} + +struct WGPUResponse<T: AsyncWGPUListener + DomObject> { + trusted: TrustedPromise, + receiver: Trusted<T>, +} + +impl<T: AsyncWGPUListener + DomObject> WGPUResponse<T> { + #[allow(unrooted_must_root)] + fn response(self, response: WebGPUResponseResult) { + let promise = self.trusted.root(); + match response { + Ok(response) => self.receiver.root().handle_response(response, &promise), + Err(error) => promise.reject_error(Error::Type(format!( + "Received error from WebGPU thread: {}", + error + ))), + } + } +} + +pub fn response_async<T: AsyncWGPUListener + DomObject + 'static>( + promise: &Rc<Promise>, + receiver: &T, +) -> IpcSender<WebGPUResponseResult> { + let (action_sender, action_receiver) = ipc::channel().unwrap(); + let (task_source, canceller) = receiver + .global() + .as_window() + .task_manager() + .dom_manipulation_task_source_with_canceller(); + let mut trusted = Some(TrustedPromise::new(promise.clone())); + let trusted_receiver = Trusted::new(receiver); + ROUTER.add_route( + action_receiver.to_opaque(), + Box::new(move |message| { + let trusted = if let Some(trusted) = trusted.take() { + trusted + } else { + error!("WebGPU callback called twice!"); + return; + }; + + let context = WGPUResponse { + trusted, + receiver: trusted_receiver.clone(), + }; + let result = task_source.queue_with_canceller( + task!(process_webgpu_task: move|| { + context.response(message.to().unwrap()); + }), + &canceller, + ); + if let Err(err) = result { + error!("Failed to queue GPU listener-task: {:?}", err); + } + }), + ); + action_sender +} + +impl GPUMethods for GPU { + // https://gpuweb.github.io/gpuweb/#dom-gpu-requestadapter + fn RequestAdapter( + &self, + options: &GPURequestAdapterOptions, + comp: InCompartment, + ) -> Rc<Promise> { + let promise = Promise::new_in_current_compartment(&self.global(), comp); + let sender = response_async(&promise, self); + let power_preference = match options.powerPreference { + Some(GPUPowerPreference::Low_power) => wgpu::PowerPreference::LowPower, + Some(GPUPowerPreference::High_performance) => wgpu::PowerPreference::HighPerformance, + None => wgpu::PowerPreference::Default, + }; + + match self.wgpu_channel() { + Some(channel) => { + channel + .0 + .send(WebGPURequest::RequestAdapter( + sender, + wgpu::RequestAdapterOptions { power_preference }, + )) + .unwrap(); + }, + None => promise.reject_error(Error::Type("No WebGPU thread...".to_owned())), + }; + promise + } +} + +impl AsyncWGPUListener for GPU { + fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) { + match response { + WebGPUResponse::RequestAdapter(name, adapter) => { + let adapter = GPUAdapter::new( + &self.global(), + DOMString::from(name), + Heap::default(), + adapter, + ); + promise.resolve_native(&adapter); + }, + response => promise.reject_error(Error::Type(format!( + "Wrong response received for GPU from WebGPU thread {:?}", + response, + ))), + } + } +} diff --git a/components/script/dom/gpuadapter.rs b/components/script/dom/gpuadapter.rs new file mode 100644 index 00000000000..ec970439e8a --- /dev/null +++ b/components/script/dom/gpuadapter.rs @@ -0,0 +1,63 @@ +/* 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 crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::{self, GPUAdapterMethods}; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::str::DOMString; +use crate::dom::globalscope::GlobalScope; +use crate::script_runtime::JSContext as SafeJSContext; +use dom_struct::dom_struct; +use js::jsapi::{Heap, JSObject}; +use std::ptr::NonNull; +use webgpu::WebGPUAdapter; + +#[dom_struct] +pub struct GPUAdapter { + reflector_: Reflector, + name: DOMString, + #[ignore_malloc_size_of = "mozjs"] + extensions: Heap<*mut JSObject>, + adapter: WebGPUAdapter, +} + +impl GPUAdapter { + pub fn new_inherited( + name: DOMString, + extensions: Heap<*mut JSObject>, + adapter: WebGPUAdapter, + ) -> GPUAdapter { + GPUAdapter { + reflector_: Reflector::new(), + name, + extensions, + adapter, + } + } + + pub fn new( + global: &GlobalScope, + name: DOMString, + extensions: Heap<*mut JSObject>, + adapter: WebGPUAdapter, + ) -> DomRoot<GPUAdapter> { + reflect_dom_object( + Box::new(GPUAdapter::new_inherited(name, extensions, adapter)), + global, + GPUAdapterBinding::Wrap, + ) + } +} + +impl GPUAdapterMethods for GPUAdapter { + // https://gpuweb.github.io/gpuweb/#dom-gpuadapter-name + fn Name(&self) -> DOMString { + self.name.clone() + } + + // https://gpuweb.github.io/gpuweb/#dom-gpuadapter-extensions + fn Extensions(&self, _cx: SafeJSContext) -> NonNull<JSObject> { + NonNull::new(self.extensions.get()).unwrap() + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index ef562931bee..9fbf2e0cc6e 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -315,6 +315,8 @@ pub mod gamepadbuttonlist; pub mod gamepadevent; pub mod gamepadlist; pub mod globalscope; +pub mod gpu; +pub mod gpuadapter; pub mod hashchangeevent; pub mod headers; pub mod history; diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index 127883dd956..cb8fb2365cd 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -11,6 +11,7 @@ use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::bluetooth::Bluetooth; use crate::dom::gamepadlist::GamepadList; +use crate::dom::gpu::GPU; use crate::dom::mediadevices::MediaDevices; use crate::dom::mediasession::MediaSession; use crate::dom::mimetypearray::MimeTypeArray; @@ -36,6 +37,7 @@ pub struct Navigator { gamepads: MutNullableDom<GamepadList>, permissions: MutNullableDom<Permissions>, mediasession: MutNullableDom<MediaSession>, + gpu: MutNullableDom<GPU>, } impl Navigator { @@ -51,6 +53,7 @@ impl Navigator { gamepads: Default::default(), permissions: Default::default(), mediasession: Default::default(), + gpu: Default::default(), } } @@ -205,4 +208,9 @@ impl NavigatorMethods for Navigator { MediaSession::new(window) }) } + + // https://gpuweb.github.io/gpuweb/#dom-navigator-gpu + fn Gpu(&self) -> DomRoot<GPU> { + self.gpu.or_init(|| GPU::new(&self.global())) + } } diff --git a/components/script/dom/webidls/GPU.webidl b/components/script/dom/webidls/GPU.webidl new file mode 100644 index 00000000000..856c5027569 --- /dev/null +++ b/components/script/dom/webidls/GPU.webidl @@ -0,0 +1,21 @@ +/* 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/. */ + +// https://gpuweb.github.io/gpuweb/#gpu-interface +[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"] +interface GPU { + // May reject with DOMException // TODO: DOMException("OperationError")? + Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options = {}); +}; + +// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions +dictionary GPURequestAdapterOptions { + GPUPowerPreference powerPreference; +}; + +// https://gpuweb.github.io/gpuweb/#enumdef-gpupowerpreference +enum GPUPowerPreference { + "low-power", + "high-performance" +}; diff --git a/components/script/dom/webidls/GPUAdapter.webidl b/components/script/dom/webidls/GPUAdapter.webidl new file mode 100644 index 00000000000..0c2118a5f56 --- /dev/null +++ b/components/script/dom/webidls/GPUAdapter.webidl @@ -0,0 +1,14 @@ +/* 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/. */ + +// https://gpuweb.github.io/gpuweb/#gpuadapter +[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"] +interface GPUAdapter { + readonly attribute DOMString name; + readonly attribute object extensions; + //readonly attribute GPULimits limits; Don’t expose higher limits for now. + + // May reject with DOMException // TODO: DOMException("OperationError")? + // Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {}); +}; diff --git a/components/script/dom/webidls/Navigator.webidl b/components/script/dom/webidls/Navigator.webidl index 6b5b1e1f283..b51e2ba52f0 100644 --- a/components/script/dom/webidls/Navigator.webidl +++ b/components/script/dom/webidls/Navigator.webidl @@ -75,3 +75,8 @@ partial interface Navigator { partial interface Navigator { [Pref="dom.gamepad.enabled"] GamepadList getGamepads(); }; + +[Exposed=Window] +partial interface Navigator { + [SameObject, Pref="dom.webgpu.enabled"] readonly attribute GPU gpu; +}; diff --git a/components/script/dom/webidls/WorkerNavigator.webidl b/components/script/dom/webidls/WorkerNavigator.webidl index 119e22ea11f..5be43960802 100644 --- a/components/script/dom/webidls/WorkerNavigator.webidl +++ b/components/script/dom/webidls/WorkerNavigator.webidl @@ -15,3 +15,8 @@ WorkerNavigator includes NavigatorLanguage; partial interface WorkerNavigator { [Pref="dom.permissions.enabled"] readonly attribute Permissions permissions; }; + +[Exposed=DedicatedWorker] +partial interface WorkerNavigator { + [SameObject, Pref="dom.webgpu.enabled"] readonly attribute GPU gpu; +}; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 0c3a2db0899..4ae94520f1f 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -136,6 +136,7 @@ use style::str::HTML_SPACE_CHARACTERS; use style::stylesheets::CssRuleType; use style_traits::{CSSPixel, DevicePixel, ParsingMode}; use url::Position; +use webgpu::WebGPU; use webrender_api::units::{DeviceIntPoint, DeviceIntSize, LayoutPixel}; use webrender_api::{DocumentId, ExternalScrollId, RenderApiSender}; use webvr_traits::WebVRMsg; @@ -267,6 +268,10 @@ pub struct Window { #[ignore_malloc_size_of = "channels are hard"] webgl_chan: Option<WebGLChan>, + #[ignore_malloc_size_of = "channels are hard"] + /// A handle for communicating messages to the WebGPU threads. + webgpu: Option<WebGPU>, + /// A handle for communicating messages to the webvr thread, if available. #[ignore_malloc_size_of = "channels are hard"] webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -462,6 +467,10 @@ impl Window { .map(|chan| WebGLCommandSender::new(chan.clone(), self.get_event_loop_waker())) } + pub fn webgpu_channel(&self) -> Option<WebGPU> { + self.webgpu.clone() + } + pub fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> { self.webvr_chan.clone() } @@ -2206,6 +2215,7 @@ impl Window { navigation_start: u64, navigation_start_precise: u64, webgl_chan: Option<WebGLChan>, + webgpu: Option<WebGPU>, webvr_chan: Option<IpcSender<WebVRMsg>>, webxr_registry: webxr_api::Registry, microtask_queue: Rc<MicrotaskQueue>, @@ -2285,6 +2295,7 @@ impl Window { media_query_lists: DOMTracker::new(), test_runner: Default::default(), webgl_chan, + webgpu, webvr_chan, webxr_registry, permission_state_invocation_results: Default::default(), diff --git a/components/script/dom/workernavigator.rs b/components/script/dom/workernavigator.rs index 92dfa9951e5..cc1dfee13bd 100644 --- a/components/script/dom/workernavigator.rs +++ b/components/script/dom/workernavigator.rs @@ -7,6 +7,7 @@ use crate::dom::bindings::codegen::Bindings::WorkerNavigatorBinding::WorkerNavig use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; +use crate::dom::gpu::GPU; use crate::dom::navigatorinfo; use crate::dom::permissions::Permissions; use crate::dom::workerglobalscope::WorkerGlobalScope; @@ -17,6 +18,7 @@ use dom_struct::dom_struct; pub struct WorkerNavigator { reflector_: Reflector, permissions: MutNullableDom<Permissions>, + gpu: MutNullableDom<GPU>, } impl WorkerNavigator { @@ -24,6 +26,7 @@ impl WorkerNavigator { WorkerNavigator { reflector_: Reflector::new(), permissions: Default::default(), + gpu: Default::default(), } } @@ -97,4 +100,9 @@ impl WorkerNavigatorMethods for WorkerNavigator { self.permissions .or_init(|| Permissions::new(&self.global())) } + + // https://gpuweb.github.io/gpuweb/#dom-navigator-gpu + fn Gpu(&self) -> DomRoot<GPU> { + self.gpu.or_init(|| GPU::new(&self.global())) + } } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index eb6e267c740..b69eb851f2f 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -163,6 +163,7 @@ use style::dom::OpaqueNode; use style::thread_state::{self, ThreadState}; use time::{at_utc, get_time, precise_time_ns, Timespec}; use url::Position; +use webgpu::WebGPU; use webrender_api::units::LayoutPixel; use webrender_api::{DocumentId, RenderApiSender}; use webvr_traits::{WebVREvent, WebVRMsg}; @@ -629,6 +630,9 @@ pub struct ScriptThread { /// A handle to the WebGL thread webgl_chan: Option<WebGLPipeline>, + /// A handle to the WebGPU threads + webgpu: Option<WebGPU>, + /// A handle to the webvr thread, if available webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -1338,6 +1342,7 @@ impl ScriptThread { layout_to_constellation_chan: state.layout_to_constellation_chan, webgl_chan: state.webgl_chan, + webgpu: state.webgpu, webvr_chan: state.webvr_chan, webxr_registry: state.webxr_registry, @@ -3247,6 +3252,7 @@ impl ScriptThread { incomplete.navigation_start, incomplete.navigation_start_precise, self.webgl_chan.as_ref().map(|chan| chan.channel()), + self.webgpu.clone(), self.webvr_chan.clone(), self.webxr_registry.clone(), self.microtask_queue.clone(), diff --git a/components/script_traits/Cargo.toml b/components/script_traits/Cargo.toml index 3fbdfd1f918..6d736ff3492 100644 --- a/components/script_traits/Cargo.toml +++ b/components/script_traits/Cargo.toml @@ -39,6 +39,7 @@ style_traits = {path = "../style_traits", features = ["servo"]} time = "0.1.12" url = "2.0" webdriver = "0.40" +webgpu = {path = "../webgpu"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr_traits = {path = "../webvr_traits"} webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index a8a19b5a40a..efa877adb17 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -60,6 +60,7 @@ use std::sync::Arc; use std::time::Duration; use style_traits::CSSPixel; use style_traits::SpeculativePainter; +use webgpu::WebGPU; use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel}; use webrender_api::{DocumentId, ExternalScrollId, ImageKey, RenderApiSender}; use webvr_traits::{WebVREvent, WebVRMsg}; @@ -656,6 +657,8 @@ pub struct InitialScriptState { pub content_process_shutdown_chan: Sender<()>, /// A channel to the WebGL thread used in this pipeline. pub webgl_chan: Option<WebGLPipeline>, + /// A channel to the WebGPU threads. + pub webgpu: Option<WebGPU>, /// A channel to the webvr thread, if available. pub webvr_chan: Option<IpcSender<WebVRMsg>>, /// The XR device registry diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index 458ffb114a0..83f298fb96b 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -79,6 +79,7 @@ servo_url = {path = "../url"} sparkle = "0.1" style = {path = "../style", features = ["servo"]} style_traits = {path = "../style_traits", features = ["servo"]} +webgpu = {path = "../webgpu"} webrender = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webrender_traits = {path = "../webrender_traits"} diff --git a/components/servo/lib.rs b/components/servo/lib.rs index d201bc2d757..811a4a002d9 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -49,6 +49,7 @@ pub use servo_geometry; pub use servo_url; pub use style; pub use style_traits; +pub use webgpu; pub use webrender_api; pub use webrender_traits; pub use webvr; @@ -863,6 +864,8 @@ fn create_constellation( let resource_sender = public_resource_threads.sender(); + let webgpu = webgpu::WebGPU::new(); + let initial_state = InitialConstellationState { compositor_proxy, embedder_proxy, @@ -877,6 +880,7 @@ fn create_constellation( webrender_document, webrender_api_sender, webgl_threads, + webgpu, webvr_chan, webxr_registry, glplayer_threads, diff --git a/components/webgpu/Cargo.toml b/components/webgpu/Cargo.toml new file mode 100644 index 00000000000..7581cf768bd --- /dev/null +++ b/components/webgpu/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "webgpu" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MPL-2.0" +edition = "2018" +publish = false + +[lib] +name = "webgpu" +path = "lib.rs" + +[dependencies] +embedder_traits = {path = "../embedder_traits"} +ipc-channel = "0.12" +log = "0.4" +malloc_size_of = { path = "../malloc_size_of" } +serde = "1.0" +servo_config = {path = "../config"} +wgpu-native = { version = "0.4.0", features = ["serde"] } 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 + } +} diff --git a/docs/ORGANIZATION.md b/docs/ORGANIZATION.md index 2ec15f28b1c..d369a0b50b3 100644 --- a/docs/ORGANIZATION.md +++ b/docs/ORGANIZATION.md @@ -54,6 +54,8 @@ * assorted utility methods and types that are commonly used throughout the project. * webdriver_server * In-process server to allow manipulating browser instances via a WebDriver client. + * webgpu + * Implementation of threads for the WebGPU API. * etc * Useful tools and scripts for developers. * mach diff --git a/python/tidy/servo_tidy/tidy.py b/python/tidy/servo_tidy/tidy.py index f14112df5da..d2840cc884c 100644 --- a/python/tidy/servo_tidy/tidy.py +++ b/python/tidy/servo_tidy/tidy.py @@ -100,6 +100,7 @@ WEBIDL_STANDARDS = [ "//webaudio.github.io", "//immersive-web.github.io/", "//github.com/immersive-web/webxr-test-api/", + "//gpuweb.github.io", # Not a URL "// This interface is entirely internal to Servo, and should not be" + " accessible to\n// web pages." diff --git a/resources/prefs.json b/resources/prefs.json index d715ffab76f..8d5cd69c407 100644 --- a/resources/prefs.json +++ b/resources/prefs.json @@ -26,6 +26,7 @@ "dom.testing.htmlinputelement.select_files.enabled": false, "dom.webgl.dom_to_texture.enabled": false, "dom.webgl2.enabled": false, + "dom.webgpu.enabled": false, "dom.webrtc.enabled": false, "dom.webvr.enabled": false, "dom.webvr.event_polling_interval": 500, diff --git a/servo-tidy.toml b/servo-tidy.toml index 46181a8bf54..71f9fb08e36 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -27,6 +27,7 @@ rand = [ [ignore] # Ignored packages with duplicated versions packages = [ + "arrayvec", "cgl", "cocoa", "gleam", |