aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/Cargo.toml1
-rw-r--r--components/script/dom/bindings/codegen/Bindings.conf5
-rw-r--r--components/script/dom/bindings/trace.rs3
-rw-r--r--components/script/dom/gpu.rs158
-rw-r--r--components/script/dom/gpuadapter.rs63
-rw-r--r--components/script/dom/mod.rs2
-rw-r--r--components/script/dom/navigator.rs8
-rw-r--r--components/script/dom/webidls/GPU.webidl21
-rw-r--r--components/script/dom/webidls/GPUAdapter.webidl14
-rw-r--r--components/script/dom/webidls/Navigator.webidl5
-rw-r--r--components/script/dom/webidls/WorkerNavigator.webidl5
-rw-r--r--components/script/dom/window.rs11
-rw-r--r--components/script/dom/workernavigator.rs8
-rw-r--r--components/script/script_thread.rs6
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(),