diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/Cargo.toml | 1 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/Bindings.conf | 5 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 3 | ||||
-rw-r--r-- | components/script/dom/gpu.rs | 158 | ||||
-rw-r--r-- | components/script/dom/gpuadapter.rs | 63 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 2 | ||||
-rw-r--r-- | components/script/dom/navigator.rs | 8 | ||||
-rw-r--r-- | components/script/dom/webidls/GPU.webidl | 21 | ||||
-rw-r--r-- | components/script/dom/webidls/GPUAdapter.webidl | 14 | ||||
-rw-r--r-- | components/script/dom/webidls/Navigator.webidl | 5 | ||||
-rw-r--r-- | components/script/dom/webidls/WorkerNavigator.webidl | 5 | ||||
-rw-r--r-- | components/script/dom/window.rs | 11 | ||||
-rw-r--r-- | components/script/dom/workernavigator.rs | 8 | ||||
-rw-r--r-- | components/script/script_thread.rs | 6 |
14 files changed, 309 insertions, 1 deletions
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(), |