Add webgpu feature flag (#34444)

* Move script gpu files into webgpu folder

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* Modify gpu webidls

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* move gpu realted webidl

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* add webgpu feature to script

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* add dummy implementation for gpucanvascontext

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* fmt

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* add skip-if CARGO_FEATURE_WEBGPU

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* Move NavigatorGPU and workerNavigator GPU to webgpu idl

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* fmt and cleanup

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* review fix

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* enable webgpu by default and also some fmt fix

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

* Add pref back, fix imports, small cleanups

Signed-off-by: atbrakhi <atbrakhi@igalia.com>

---------

Signed-off-by: atbrakhi <atbrakhi@igalia.com>
This commit is contained in:
atbrakhi 2024-12-05 17:07:27 +01:00 committed by GitHub
parent bba3bc6ac2
commit 1591a3b506
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 295 additions and 105 deletions

2
Cargo.lock generated
View file

@ -9100,4 +9100,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
dependencies = [ dependencies = [
"simd-adler32", "simd-adler32",
] ]

View file

@ -15,6 +15,7 @@ path = "lib.rs"
default = [] default = []
multiview = [] multiview = []
tracing = ["dep:tracing"] tracing = ["dep:tracing"]
webgpu = ["script_traits/webgpu"]
[dependencies] [dependencies]
background_hang_monitor_api = { workspace = true } background_hang_monitor_api = { workspace = true }

View file

@ -151,9 +151,13 @@ use servo_config::{opts, pref};
use servo_rand::{random, Rng, ServoRng, SliceRandom}; use servo_rand::{random, Rng, ServoRng, SliceRandom};
use servo_url::{Host, ImmutableOrigin, ServoUrl}; use servo_url::{Host, ImmutableOrigin, ServoUrl};
use style_traits::CSSPixel; use style_traits::CSSPixel;
#[cfg(feature = "webgpu")]
use webgpu::swapchain::WGPUImageMap; use webgpu::swapchain::WGPUImageMap;
#[cfg(feature = "webgpu")]
use webgpu::{self, WebGPU, WebGPURequest, WebGPUResponse}; use webgpu::{self, WebGPU, WebGPURequest, WebGPUResponse};
use webrender::{RenderApi, RenderApiSender}; #[cfg(feature = "webgpu")]
use webrender::RenderApi;
use webrender::RenderApiSender;
use webrender_api::DocumentId; use webrender_api::DocumentId;
use webrender_traits::WebrenderExternalImageRegistry; use webrender_traits::WebrenderExternalImageRegistry;
@ -209,6 +213,7 @@ struct MessagePortInfo {
entangled_with: Option<MessagePortId>, entangled_with: Option<MessagePortId>,
} }
#[cfg(feature = "webgpu")]
/// Webrender related objects required by WebGPU threads /// Webrender related objects required by WebGPU threads
struct WebrenderWGPU { struct WebrenderWGPU {
/// Webrender API. /// Webrender API.
@ -251,6 +256,7 @@ struct BrowsingContextGroup {
event_loops: HashMap<Host, Weak<EventLoop>>, event_loops: HashMap<Host, Weak<EventLoop>>,
/// The set of all WebGPU channels in this BrowsingContextGroup. /// The set of all WebGPU channels in this BrowsingContextGroup.
#[cfg(feature = "webgpu")]
webgpus: HashMap<Host, WebGPU>, webgpus: HashMap<Host, WebGPU>,
} }
@ -388,6 +394,7 @@ pub struct Constellation<STF, SWF> {
webrender_document: DocumentId, webrender_document: DocumentId,
/// Webrender related objects required by WebGPU threads /// Webrender related objects required by WebGPU threads
#[cfg(feature = "webgpu")]
webrender_wgpu: WebrenderWGPU, webrender_wgpu: WebrenderWGPU,
/// A map of message-port Id to info. /// A map of message-port Id to info.
@ -543,6 +550,7 @@ pub struct InitialConstellationState {
/// User agent string to report in network requests. /// User agent string to report in network requests.
pub user_agent: Cow<'static, str>, pub user_agent: Cow<'static, str>,
#[cfg(feature = "webgpu")]
pub wgpu_image_map: WGPUImageMap, pub wgpu_image_map: WGPUImageMap,
} }
@ -704,6 +712,7 @@ where
// Zero is reserved for the embedder. // Zero is reserved for the embedder.
PipelineNamespace::install(PipelineNamespaceId(1)); PipelineNamespace::install(PipelineNamespaceId(1));
#[cfg(feature = "webgpu")]
let webrender_wgpu = WebrenderWGPU { let webrender_wgpu = WebrenderWGPU {
webrender_api: state.webrender_api_sender.create_api(), webrender_api: state.webrender_api_sender.create_api(),
webrender_external_images: state.webrender_external_images, webrender_external_images: state.webrender_external_images,
@ -758,6 +767,7 @@ where
scheduler_receiver, scheduler_receiver,
document_states: HashMap::new(), document_states: HashMap::new(),
webrender_document: state.webrender_document, webrender_document: state.webrender_document,
#[cfg(feature = "webgpu")]
webrender_wgpu, webrender_wgpu,
shutting_down: false, shutting_down: false,
handled_warnings: VecDeque::new(), handled_warnings: VecDeque::new(),
@ -1830,12 +1840,14 @@ where
EmbedderMsg::MediaSessionEvent(event), EmbedderMsg::MediaSessionEvent(event),
)); ));
}, },
#[cfg(feature = "webgpu")]
FromScriptMsg::RequestAdapter(response_sender, options, ids) => self FromScriptMsg::RequestAdapter(response_sender, options, ids) => self
.handle_wgpu_request( .handle_wgpu_request(
source_pipeline_id, source_pipeline_id,
BrowsingContextId::from(source_top_ctx_id), BrowsingContextId::from(source_top_ctx_id),
FromScriptMsg::RequestAdapter(response_sender, options, ids), FromScriptMsg::RequestAdapter(response_sender, options, ids),
), ),
#[cfg(feature = "webgpu")]
FromScriptMsg::GetWebGPUChan(response_sender) => self.handle_wgpu_request( FromScriptMsg::GetWebGPUChan(response_sender) => self.handle_wgpu_request(
source_pipeline_id, source_pipeline_id,
BrowsingContextId::from(source_top_ctx_id), BrowsingContextId::from(source_top_ctx_id),
@ -2034,6 +2046,7 @@ where
feature = "tracing", feature = "tracing",
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
)] )]
#[cfg(feature = "webgpu")]
fn handle_wgpu_request( fn handle_wgpu_request(
&mut self, &mut self,
source_pipeline_id: PipelineId, source_pipeline_id: PipelineId,
@ -2747,6 +2760,7 @@ where
} }
debug!("Exiting WebGPU threads."); debug!("Exiting WebGPU threads.");
#[cfg(feature = "webgpu")]
let receivers = self let receivers = self
.browsing_context_group_set .browsing_context_group_set
.values() .values()
@ -2763,6 +2777,7 @@ where
}) })
.flatten(); .flatten();
#[cfg(feature = "webgpu")]
for receiver in receivers { for receiver in receivers {
if let Err(e) = receiver.recv() { if let Err(e) = receiver.recv() {
warn!("Failed to receive exit response from WebGPU ({:?})", e); warn!("Failed to receive exit response from WebGPU ({:?})", e);

View file

@ -183,7 +183,9 @@ mod from_script {
Self::ForwardDOMMessage(..) => target!("ForwardDOMMessage"), Self::ForwardDOMMessage(..) => target!("ForwardDOMMessage"),
Self::ScheduleJob(..) => target!("ScheduleJob"), Self::ScheduleJob(..) => target!("ScheduleJob"),
Self::MediaSessionEvent(..) => target!("MediaSessionEvent"), Self::MediaSessionEvent(..) => target!("MediaSessionEvent"),
#[cfg(feature = "webgpu")]
Self::RequestAdapter(..) => target!("RequestAdapter"), Self::RequestAdapter(..) => target!("RequestAdapter"),
#[cfg(feature = "webgpu")]
Self::GetWebGPUChan(..) => target!("GetWebGPUChan"), Self::GetWebGPUChan(..) => target!("GetWebGPUChan"),
Self::TitleChanged(..) => target!("TitleChanged"), Self::TitleChanged(..) => target!("TitleChanged"),
} }

View file

@ -21,6 +21,7 @@ webgl_backtrace = ["canvas_traits/webgl_backtrace"]
js_backtrace = [] js_backtrace = []
refcell_backtrace = ["accountable-refcell"] refcell_backtrace = ["accountable-refcell"]
webxr = ["webxr-api"] webxr = ["webxr-api"]
webgpu = []
[build-dependencies] [build-dependencies]
phf_codegen = "0.11" phf_codegen = "0.11"

View file

@ -47,8 +47,9 @@ use crate::dom::errorevent::ErrorEvent;
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::identityhub::IdentityHub;
use crate::dom::messageevent::MessageEvent; use crate::dom::messageevent::MessageEvent;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::worker::{TrustedWorkerAddress, Worker}; use crate::dom::worker::{TrustedWorkerAddress, Worker};
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::fetch::load_whole_resource; use crate::fetch::load_whole_resource;
@ -253,7 +254,7 @@ impl DedicatedWorkerGlobalScope {
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
browsing_context: Option<BrowsingContextId>, browsing_context: Option<BrowsingContextId>,
gpu_id_hub: Arc<IdentityHub>, #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
control_receiver: Receiver<DedicatedWorkerControlMsg>, control_receiver: Receiver<DedicatedWorkerControlMsg>,
) -> DedicatedWorkerGlobalScope { ) -> DedicatedWorkerGlobalScope {
DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope {
@ -265,6 +266,7 @@ impl DedicatedWorkerGlobalScope {
runtime, runtime,
from_devtools_receiver, from_devtools_receiver,
closing, closing,
#[cfg(feature = "webgpu")]
gpu_id_hub, gpu_id_hub,
), ),
task_queue: TaskQueue::new(receiver, own_sender.clone()), task_queue: TaskQueue::new(receiver, own_sender.clone()),
@ -291,7 +293,7 @@ impl DedicatedWorkerGlobalScope {
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
browsing_context: Option<BrowsingContextId>, browsing_context: Option<BrowsingContextId>,
gpu_id_hub: Arc<IdentityHub>, #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
control_receiver: Receiver<DedicatedWorkerControlMsg>, control_receiver: Receiver<DedicatedWorkerControlMsg>,
) -> DomRoot<DedicatedWorkerGlobalScope> { ) -> DomRoot<DedicatedWorkerGlobalScope> {
let cx = runtime.cx(); let cx = runtime.cx();
@ -308,6 +310,7 @@ impl DedicatedWorkerGlobalScope {
closing, closing,
image_cache, image_cache,
browsing_context, browsing_context,
#[cfg(feature = "webgpu")]
gpu_id_hub, gpu_id_hub,
control_receiver, control_receiver,
)); ));
@ -330,7 +333,7 @@ impl DedicatedWorkerGlobalScope {
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
browsing_context: Option<BrowsingContextId>, browsing_context: Option<BrowsingContextId>,
gpu_id_hub: Arc<IdentityHub>, #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
control_receiver: Receiver<DedicatedWorkerControlMsg>, control_receiver: Receiver<DedicatedWorkerControlMsg>,
context_sender: Sender<ThreadSafeJSContext>, context_sender: Sender<ThreadSafeJSContext>,
) -> JoinHandle<()> { ) -> JoinHandle<()> {
@ -416,6 +419,7 @@ impl DedicatedWorkerGlobalScope {
closing, closing,
image_cache, image_cache,
browsing_context, browsing_context,
#[cfg(feature = "webgpu")]
gpu_id_hub, gpu_id_hub,
control_receiver, control_receiver,
); );

View file

@ -64,6 +64,7 @@ impl DissimilarOriginWindow {
global_to_clone_from.microtask_queue().clone(), global_to_clone_from.microtask_queue().clone(),
global_to_clone_from.is_headless(), global_to_clone_from.is_headless(),
global_to_clone_from.get_user_agent(), global_to_clone_from.get_user_agent(),
#[cfg(feature = "webgpu")]
global_to_clone_from.wgpu_id_hub(), global_to_clone_from.wgpu_id_hub(),
Some(global_to_clone_from.is_secure_context()), Some(global_to_clone_from.is_secure_context()),
false, false,

View file

@ -67,6 +67,7 @@ use style::stylesheet_set::DocumentStylesheetSet;
use style::stylesheets::{Origin, OriginSet, Stylesheet}; use style::stylesheets::{Origin, OriginSet, Stylesheet};
use url::Host; use url::Host;
use uuid::Uuid; use uuid::Uuid;
#[cfg(feature = "webgpu")]
use webgpu::swapchain::WebGPUContextId; use webgpu::swapchain::WebGPUContextId;
use webrender_api::units::DeviceIntRect; use webrender_api::units::DeviceIntRect;
@ -126,7 +127,6 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::focusevent::FocusEvent; use crate::dom::focusevent::FocusEvent;
use crate::dom::fontfaceset::FontFaceSet; use crate::dom::fontfaceset::FontFaceSet;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpucanvascontext::GPUCanvasContext;
use crate::dom::hashchangeevent::HashChangeEvent; use crate::dom::hashchangeevent::HashChangeEvent;
use crate::dom::htmlanchorelement::HTMLAnchorElement; use crate::dom::htmlanchorelement::HTMLAnchorElement;
use crate::dom::htmlareaelement::HTMLAreaElement; use crate::dom::htmlareaelement::HTMLAreaElement;
@ -175,6 +175,8 @@ use crate::dom::types::VisibilityStateEntry;
use crate::dom::uievent::UIEvent; use crate::dom::uievent::UIEvent;
use crate::dom::virtualmethods::vtable_for; use crate::dom::virtualmethods::vtable_for;
use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::webglrenderingcontext::WebGLRenderingContext;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::gpucanvascontext::GPUCanvasContext;
use crate::dom::wheelevent::WheelEvent; use crate::dom::wheelevent::WheelEvent;
use crate::dom::window::{ReflowReason, Window}; use crate::dom::window::{ReflowReason, Window};
use crate::dom::windowproxy::WindowProxy; use crate::dom::windowproxy::WindowProxy;
@ -446,6 +448,7 @@ pub struct Document {
dirty_webgl_contexts: dirty_webgl_contexts:
DomRefCell<HashMapTracedValues<WebGLContextId, Dom<WebGLRenderingContext>>>, DomRefCell<HashMapTracedValues<WebGLContextId, Dom<WebGLRenderingContext>>>,
/// List of all WebGPU context IDs that need flushing. /// List of all WebGPU context IDs that need flushing.
#[cfg(feature = "webgpu")]
dirty_webgpu_contexts: DomRefCell<HashMapTracedValues<WebGPUContextId, Dom<GPUCanvasContext>>>, dirty_webgpu_contexts: DomRefCell<HashMapTracedValues<WebGPUContextId, Dom<GPUCanvasContext>>>,
/// <https://w3c.github.io/slection-api/#dfn-selection> /// <https://w3c.github.io/slection-api/#dfn-selection>
selection: MutNullableDom<Selection>, selection: MutNullableDom<Selection>,
@ -3026,6 +3029,7 @@ impl Document {
receiver.recv().unwrap(); receiver.recv().unwrap();
} }
#[cfg(feature = "webgpu")]
pub fn add_dirty_webgpu_canvas(&self, context: &GPUCanvasContext) { pub fn add_dirty_webgpu_canvas(&self, context: &GPUCanvasContext) {
self.dirty_webgpu_contexts self.dirty_webgpu_contexts
.borrow_mut() .borrow_mut()
@ -3034,6 +3038,7 @@ impl Document {
} }
#[allow(crown::unrooted_must_root)] #[allow(crown::unrooted_must_root)]
#[cfg(feature = "webgpu")]
pub fn flush_dirty_webgpu_canvases(&self) { pub fn flush_dirty_webgpu_canvases(&self) {
self.dirty_webgpu_contexts self.dirty_webgpu_contexts
.borrow_mut() .borrow_mut()
@ -3424,6 +3429,7 @@ impl Document {
shadow_roots_styles_changed: Cell::new(false), shadow_roots_styles_changed: Cell::new(false),
media_controls: DomRefCell::new(HashMap::new()), media_controls: DomRefCell::new(HashMap::new()),
dirty_webgl_contexts: DomRefCell::new(HashMapTracedValues::new()), dirty_webgl_contexts: DomRefCell::new(HashMapTracedValues::new()),
#[cfg(feature = "webgpu")]
dirty_webgpu_contexts: DomRefCell::new(HashMapTracedValues::new()), dirty_webgpu_contexts: DomRefCell::new(HashMapTracedValues::new()),
selection: MutNullableDom::new(None), selection: MutNullableDom::new(None),
animation_timeline: if pref!(layout.animations.test.enabled) { animation_timeline: if pref!(layout.animations.test.enabled) {

View file

@ -62,9 +62,11 @@ use script_traits::{
}; };
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl}; use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use uuid::Uuid; use uuid::Uuid;
#[cfg(feature = "webgpu")]
use webgpu::{DeviceLostReason, WebGPUDevice}; use webgpu::{DeviceLostReason, WebGPUDevice};
use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions; use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
#[cfg(feature = "webgpu")]
use super::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason; use super::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason;
use super::bindings::error::Fallible; use super::bindings::error::Fallible;
use super::bindings::trace::{HashMapTracedValues, RootedTraceableBox}; use super::bindings::trace::{HashMapTracedValues, RootedTraceableBox};
@ -104,9 +106,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::file::File; use crate::dom::file::File;
use crate::dom::gamepad::{contains_user_gesture, Gamepad}; use crate::dom::gamepad::{contains_user_gesture, Gamepad};
use crate::dom::gamepadevent::GamepadEventType; use crate::dom::gamepadevent::GamepadEventType;
use crate::dom::gpudevice::GPUDevice;
use crate::dom::htmlscriptelement::{ScriptId, SourceCode}; use crate::dom::htmlscriptelement::{ScriptId, SourceCode};
use crate::dom::identityhub::IdentityHub;
use crate::dom::imagebitmap::ImageBitmap; use crate::dom::imagebitmap::ImageBitmap;
use crate::dom::messageevent::MessageEvent; use crate::dom::messageevent::MessageEvent;
use crate::dom::messageport::MessagePort; use crate::dom::messageport::MessagePort;
@ -117,6 +117,10 @@ use crate::dom::promise::Promise;
use crate::dom::readablestream::{ExternalUnderlyingSource, ReadableStream}; use crate::dom::readablestream::{ExternalUnderlyingSource, ReadableStream};
use crate::dom::serviceworker::ServiceWorker; use crate::dom::serviceworker::ServiceWorker;
use crate::dom::serviceworkerregistration::ServiceWorkerRegistration; use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::gpudevice::GPUDevice;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::dom::workletglobalscope::WorkletGlobalScope; use crate::dom::workletglobalscope::WorkletGlobalScope;
@ -331,9 +335,11 @@ pub struct GlobalScope {
/// Identity Manager for WebGPU resources /// Identity Manager for WebGPU resources
#[ignore_malloc_size_of = "defined in wgpu"] #[ignore_malloc_size_of = "defined in wgpu"]
#[no_trace] #[no_trace]
#[cfg(feature = "webgpu")]
gpu_id_hub: Arc<IdentityHub>, gpu_id_hub: Arc<IdentityHub>,
/// WebGPU devices /// WebGPU devices
#[cfg(feature = "webgpu")]
gpu_devices: DomRefCell<HashMapTracedValues<WebGPUDevice, WeakRef<GPUDevice>>>, gpu_devices: DomRefCell<HashMapTracedValues<WebGPUDevice, WeakRef<GPUDevice>>>,
// https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute // https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute
@ -767,7 +773,7 @@ impl GlobalScope {
microtask_queue: Rc<MicrotaskQueue>, microtask_queue: Rc<MicrotaskQueue>,
is_headless: bool, is_headless: bool,
user_agent: Cow<'static, str>, user_agent: Cow<'static, str>,
gpu_id_hub: Arc<IdentityHub>, #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
inherited_secure_context: Option<bool>, inherited_secure_context: Option<bool>,
unminify_js: bool, unminify_js: bool,
) -> Self { ) -> Self {
@ -803,7 +809,9 @@ impl GlobalScope {
consumed_rejections: Default::default(), consumed_rejections: Default::default(),
is_headless, is_headless,
user_agent, user_agent,
#[cfg(feature = "webgpu")]
gpu_id_hub, gpu_id_hub,
#[cfg(feature = "webgpu")]
gpu_devices: DomRefCell::new(HashMapTracedValues::new()), gpu_devices: DomRefCell::new(HashMapTracedValues::new()),
frozen_supported_performance_entry_types: CachedFrozenArray::new(), frozen_supported_performance_entry_types: CachedFrozenArray::new(),
https_state: Cell::new(HttpsState::None), https_state: Cell::new(HttpsState::None),
@ -3148,16 +3156,19 @@ impl GlobalScope {
None None
} }
#[cfg(feature = "webgpu")]
pub fn wgpu_id_hub(&self) -> Arc<IdentityHub> { pub fn wgpu_id_hub(&self) -> Arc<IdentityHub> {
self.gpu_id_hub.clone() self.gpu_id_hub.clone()
} }
#[cfg(feature = "webgpu")]
pub fn add_gpu_device(&self, device: &GPUDevice) { pub fn add_gpu_device(&self, device: &GPUDevice) {
self.gpu_devices self.gpu_devices
.borrow_mut() .borrow_mut()
.insert(device.id(), WeakRef::new(device)); .insert(device.id(), WeakRef::new(device));
} }
#[cfg(feature = "webgpu")]
pub fn remove_gpu_device(&self, device: WebGPUDevice) { pub fn remove_gpu_device(&self, device: WebGPUDevice) {
let device = self let device = self
.gpu_devices .gpu_devices
@ -3167,6 +3178,7 @@ impl GlobalScope {
assert!(device.root().is_none()) assert!(device.root().is_none())
} }
#[cfg(feature = "webgpu")]
pub fn gpu_device_lost(&self, device: WebGPUDevice, reason: DeviceLostReason, msg: String) { pub fn gpu_device_lost(&self, device: WebGPUDevice, reason: DeviceLostReason, msg: String) {
let reason = match reason { let reason = match reason {
DeviceLostReason::Unknown => GPUDeviceLostReason::Unknown, DeviceLostReason::Unknown => GPUDeviceLostReason::Unknown,
@ -3184,6 +3196,7 @@ impl GlobalScope {
} }
} }
#[cfg(feature = "webgpu")]
pub fn handle_uncaptured_gpu_error( pub fn handle_uncaptured_gpu_error(
&self, &self,
device: WebGPUDevice, device: WebGPUDevice,

View file

@ -0,0 +1,41 @@
/* 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 dom_struct::dom_struct;
use script_layout_interface::HTMLCanvasDataSource;
use crate::dom::bindings::codegen::Bindings::GPUCanvasContextBinding::GPUCanvasContextMethods;
use crate::dom::bindings::codegen::UnionTypes;
use crate::dom::bindings::reflector::Reflector;
use crate::dom::bindings::root::{DomRoot, LayoutDom};
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutCanvasRenderingContextHelpers};
#[dom_struct]
pub struct GPUCanvasContext {
reflector_: Reflector,
}
impl GPUCanvasContext {
#[allow(dead_code)]
fn new_inherited() -> Self {
unimplemented!()
}
pub fn new(_global: &GlobalScope, _canvas: &HTMLCanvasElement) -> DomRoot<Self> {
unimplemented!()
}
}
impl GPUCanvasContextMethods<crate::DomTypeHolder> for GPUCanvasContext {
fn Canvas(&self) -> UnionTypes::HTMLCanvasElementOrOffscreenCanvas {
unimplemented!()
}
}
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, GPUCanvasContext> {
fn canvas_data_source(self) -> HTMLCanvasDataSource {
unimplemented!()
}
}

View file

@ -9,11 +9,14 @@ use euclid::default::{Rect, Size2D};
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix}; use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
use image::codecs::png::PngEncoder; use image::codecs::png::PngEncoder;
use image::{ColorType, ImageEncoder}; use image::{ColorType, ImageEncoder};
use ipc_channel::ipc::{self as ipcchan, IpcSharedMemory}; use ipc_channel::ipc::IpcSharedMemory;
#[cfg(feature = "webgpu")]
use ipc_channel::ipc::{self as ipcchan};
use js::error::throw_type_error; use js::error::throw_type_error;
use js::rust::{HandleObject, HandleValue}; use js::rust::{HandleObject, HandleValue};
use profile_traits::ipc; use profile_traits::ipc;
use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource}; use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
#[cfg(feature = "webgpu")]
use script_traits::ScriptMsg; use script_traits::ScriptMsg;
use servo_media::streams::registry::MediaStreamId; use servo_media::streams::registry::MediaStreamId;
use servo_media::streams::MediaStreamType; use servo_media::streams::MediaStreamType;
@ -40,6 +43,7 @@ use crate::dom::canvasrenderingcontext2d::{
use crate::dom::document::Document; use crate::dom::document::Document;
use crate::dom::element::{AttributeMutation, Element, LayoutElementHelpers}; use crate::dom::element::{AttributeMutation, Element, LayoutElementHelpers};
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
#[cfg(not(feature = "webgpu"))]
use crate::dom::gpucanvascontext::GPUCanvasContext; use crate::dom::gpucanvascontext::GPUCanvasContext;
use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlelement::HTMLElement;
use crate::dom::mediastream::MediaStream; use crate::dom::mediastream::MediaStream;
@ -48,6 +52,8 @@ use crate::dom::node::{window_from_node, Node};
use crate::dom::virtualmethods::VirtualMethods; use crate::dom::virtualmethods::VirtualMethods;
use crate::dom::webgl2renderingcontext::WebGL2RenderingContext; use crate::dom::webgl2renderingcontext::WebGL2RenderingContext;
use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::webglrenderingcontext::WebGLRenderingContext;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::gpucanvascontext::GPUCanvasContext;
use crate::script_runtime::{CanGc, JSContext}; use crate::script_runtime::{CanGc, JSContext};
const DEFAULT_WIDTH: u32 = 300; const DEFAULT_WIDTH: u32 = 300;
@ -59,6 +65,7 @@ pub enum CanvasContext {
Context2d(Dom<CanvasRenderingContext2D>), Context2d(Dom<CanvasRenderingContext2D>),
WebGL(Dom<WebGLRenderingContext>), WebGL(Dom<WebGLRenderingContext>),
WebGL2(Dom<WebGL2RenderingContext>), WebGL2(Dom<WebGL2RenderingContext>),
#[cfg(feature = "webgpu")]
WebGPU(Dom<GPUCanvasContext>), WebGPU(Dom<GPUCanvasContext>),
} }
@ -107,6 +114,7 @@ impl HTMLCanvasElement {
}, },
CanvasContext::WebGL(ref context) => context.recreate(size), CanvasContext::WebGL(ref context) => context.recreate(size),
CanvasContext::WebGL2(ref context) => context.recreate(size), CanvasContext::WebGL2(ref context) => context.recreate(size),
#[cfg(feature = "webgpu")]
CanvasContext::WebGPU(ref context) => context.resize(), CanvasContext::WebGPU(ref context) => context.resize(),
} }
} }
@ -143,6 +151,7 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> {
}, },
Some(CanvasContext::WebGL(context)) => context.to_layout().canvas_data_source(), Some(CanvasContext::WebGL(context)) => context.to_layout().canvas_data_source(),
Some(CanvasContext::WebGL2(context)) => context.to_layout().canvas_data_source(), Some(CanvasContext::WebGL2(context)) => context.to_layout().canvas_data_source(),
#[cfg(feature = "webgpu")]
Some(CanvasContext::WebGPU(context)) => context.to_layout().canvas_data_source(), Some(CanvasContext::WebGPU(context)) => context.to_layout().canvas_data_source(),
None => HTMLCanvasDataSource::Empty, None => HTMLCanvasDataSource::Empty,
} }
@ -248,6 +257,12 @@ impl HTMLCanvasElement {
Some(context) Some(context)
} }
#[cfg(not(feature = "webgpu"))]
fn get_or_init_webgpu_context(&self) -> Option<DomRoot<GPUCanvasContext>> {
None
}
#[cfg(feature = "webgpu")]
fn get_or_init_webgpu_context(&self) -> Option<DomRoot<GPUCanvasContext>> { fn get_or_init_webgpu_context(&self) -> Option<DomRoot<GPUCanvasContext>> {
if let Some(ctx) = self.context() { if let Some(ctx) = self.context() {
return match *ctx { return match *ctx {
@ -328,6 +343,7 @@ impl HTMLCanvasElement {
// TODO: add a method in WebGL2RenderingContext to get the pixels. // TODO: add a method in WebGL2RenderingContext to get the pixels.
return None; return None;
}, },
#[cfg(feature = "webgpu")]
Some(&CanvasContext::WebGPU(_)) => { Some(&CanvasContext::WebGPU(_)) => {
// TODO: add a method in GPUCanvasContext to get the pixels. // TODO: add a method in GPUCanvasContext to get the pixels.
return None; return None;
@ -370,6 +386,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
"webgl2" | "experimental-webgl2" => self "webgl2" | "experimental-webgl2" => self
.get_or_init_webgl2_context(cx, options, can_gc) .get_or_init_webgl2_context(cx, options, can_gc)
.map(RenderingContext::WebGL2RenderingContext), .map(RenderingContext::WebGL2RenderingContext),
#[cfg(feature = "webgpu")]
"webgpu" => self "webgpu" => self
.get_or_init_webgpu_context() .get_or_init_webgpu_context()
.map(RenderingContext::GPUCanvasContext), .map(RenderingContext::GPUCanvasContext),
@ -412,6 +429,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
} }
}, },
//TODO: Add method get_image_data to GPUCanvasContext //TODO: Add method get_image_data to GPUCanvasContext
#[cfg(feature = "webgpu")]
Some(CanvasContext::WebGPU(_)) => return Ok(USVString("data:,".into())), Some(CanvasContext::WebGPU(_)) => return Ok(USVString("data:,".into())),
None => { None => {
// Each pixel is fully-transparent black. // Each pixel is fully-transparent black.

View file

@ -402,7 +402,6 @@ pub mod htmltrackelement;
pub mod htmlulistelement; pub mod htmlulistelement;
pub mod htmlunknownelement; pub mod htmlunknownelement;
pub mod htmlvideoelement; pub mod htmlvideoelement;
pub mod identityhub;
pub mod iirfilternode; pub mod iirfilternode;
pub mod imagebitmap; pub mod imagebitmap;
pub mod imagedata; pub mod imagedata;
@ -580,8 +579,14 @@ pub mod websocket;
mod webxr; mod webxr;
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
pub use self::webxr::*; pub use self::webxr::*;
mod webgpu; #[cfg(feature = "webgpu")]
pub mod webgpu;
#[cfg(feature = "webgpu")]
pub use self::webgpu::*; pub use self::webgpu::*;
#[cfg(not(feature = "webgpu"))]
pub mod gpucanvascontext;
#[cfg(not(feature = "webgpu"))]
pub use gpucanvascontext::GPUCanvasContext;
pub mod wheelevent; pub mod wheelevent;
pub mod window; pub mod window;
pub mod windowproxy; pub mod windowproxy;

View file

@ -26,6 +26,7 @@ use crate::dom::navigatorinfo;
use crate::dom::permissions::Permissions; use crate::dom::permissions::Permissions;
use crate::dom::pluginarray::PluginArray; use crate::dom::pluginarray::PluginArray;
use crate::dom::serviceworkercontainer::ServiceWorkerContainer; use crate::dom::serviceworkercontainer::ServiceWorkerContainer;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::gpu::GPU; use crate::dom::webgpu::gpu::GPU;
use crate::dom::window::Window; use crate::dom::window::Window;
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
@ -52,6 +53,7 @@ pub struct Navigator {
gamepads: DomRefCell<Vec<MutNullableDom<Gamepad>>>, gamepads: DomRefCell<Vec<MutNullableDom<Gamepad>>>,
permissions: MutNullableDom<Permissions>, permissions: MutNullableDom<Permissions>,
mediasession: MutNullableDom<MediaSession>, mediasession: MutNullableDom<MediaSession>,
#[cfg(feature = "webgpu")]
gpu: MutNullableDom<GPU>, gpu: MutNullableDom<GPU>,
/// <https://www.w3.org/TR/gamepad/#dfn-hasgamepadgesture> /// <https://www.w3.org/TR/gamepad/#dfn-hasgamepadgesture>
has_gamepad_gesture: Cell<bool>, has_gamepad_gesture: Cell<bool>,
@ -71,6 +73,7 @@ impl Navigator {
gamepads: Default::default(), gamepads: Default::default(),
permissions: Default::default(), permissions: Default::default(),
mediasession: Default::default(), mediasession: Default::default(),
#[cfg(feature = "webgpu")]
gpu: Default::default(), gpu: Default::default(),
has_gamepad_gesture: Cell::new(false), has_gamepad_gesture: Cell::new(false),
} }
@ -282,6 +285,7 @@ impl NavigatorMethods<crate::DomTypeHolder> for Navigator {
} }
// https://gpuweb.github.io/gpuweb/#dom-navigator-gpu // https://gpuweb.github.io/gpuweb/#dom-navigator-gpu
#[cfg(feature = "webgpu")]
fn Gpu(&self) -> DomRoot<GPU> { fn Gpu(&self) -> DomRoot<GPU> {
self.gpu.or_init(|| GPU::new(&self.global())) self.gpu.or_init(|| GPU::new(&self.global()))
} }

View file

@ -39,7 +39,8 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::extendableevent::ExtendableEvent; use crate::dom::extendableevent::ExtendableEvent;
use crate::dom::extendablemessageevent::ExtendableMessageEvent; use crate::dom::extendablemessageevent::ExtendableMessageEvent;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::identityhub::IdentityHub; #[cfg(feature = "webgpu")]
use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::worker::TrustedWorkerAddress; use crate::dom::worker::TrustedWorkerAddress;
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::fetch::load_whole_resource; use crate::fetch::load_whole_resource;
@ -240,6 +241,7 @@ impl ServiceWorkerGlobalScope {
runtime, runtime,
from_devtools_receiver, from_devtools_receiver,
closing, closing,
#[cfg(feature = "webgpu")]
Arc::new(IdentityHub::default()), Arc::new(IdentityHub::default()),
), ),
task_queue: TaskQueue::new(receiver, own_sender.clone()), task_queue: TaskQueue::new(receiver, own_sender.clone()),

View file

@ -21,8 +21,8 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuadapter::GPUAdapter;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::webgpu::gpuadapter::GPUAdapter;
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
use crate::task_source::{TaskSource, TaskSourceName}; use crate::task_source::{TaskSource, TaskSourceName};

View file

@ -20,11 +20,11 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpudevice::GPUDevice;
use crate::dom::gpusupportedfeatures::gpu_to_wgt_feature;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::types::{GPUAdapterInfo, GPUSupportedLimits}; use crate::dom::types::{GPUAdapterInfo, GPUSupportedLimits};
use crate::dom::webgpu::gpu::{response_async, AsyncWGPUListener}; use crate::dom::webgpu::gpu::{response_async, AsyncWGPUListener};
use crate::dom::webgpu::gpudevice::GPUDevice;
use crate::dom::webgpu::gpusupportedfeatures::gpu_to_wgt_feature;
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;

View file

@ -16,8 +16,8 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout; use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpudevice::GPUDevice; use crate::dom::webgpu::gpudevice::GPUDevice;
#[dom_struct] #[dom_struct]
pub struct GPUBindGroup { pub struct GPUBindGroup {

View file

@ -17,8 +17,8 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuconvert::convert_bind_group_layout_entry; use crate::dom::webgpu::gpuconvert::convert_bind_group_layout_entry;
use crate::dom::gpudevice::GPUDevice; use crate::dom::webgpu::gpudevice::GPUDevice;
#[dom_struct] #[dom_struct]
pub struct GPUBindGroupLayout { pub struct GPUBindGroupLayout {

View file

@ -23,9 +23,9 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpudevice::GPUDevice;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::webgpu::gpu::{response_async, AsyncWGPUListener}; use crate::dom::webgpu::gpu::{response_async, AsyncWGPUListener};
use crate::dom::webgpu::gpudevice::GPUDevice;
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::{CanGc, JSContext}; use crate::script_runtime::{CanGc, JSContext};

View file

@ -20,11 +20,12 @@ use webrender_api::ImageKey;
use super::gpuconvert::convert_texture_descriptor; use super::gpuconvert::convert_texture_descriptor;
use super::gputexture::GPUTexture; use super::gputexture::GPUTexture;
use crate::dom::bindings::codegen::Bindings::GPUCanvasContextBinding::GPUCanvasContextMethods;
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUTexture_Binding::GPUTextureMethods; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUTexture_Binding::GPUTextureMethods;
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
GPUCanvasAlphaMode, GPUCanvasConfiguration, GPUCanvasContextMethods, GPUDeviceMethods, GPUCanvasAlphaMode, GPUCanvasConfiguration, GPUDeviceMethods, GPUExtent3D, GPUExtent3DDict,
GPUExtent3D, GPUExtent3DDict, GPUObjectDescriptorBase, GPUTextureDescriptor, GPUObjectDescriptorBase, GPUTextureDescriptor, GPUTextureDimension, GPUTextureFormat,
GPUTextureDimension, GPUTextureFormat, GPUTextureUsageConstants, GPUTextureUsageConstants,
}; };
use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas; use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::error::{Error, Fallible};

View file

@ -20,12 +20,12 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubuffer::GPUBuffer; use crate::dom::webgpu::gpubuffer::GPUBuffer;
use crate::dom::gpucommandbuffer::GPUCommandBuffer; use crate::dom::webgpu::gpucommandbuffer::GPUCommandBuffer;
use crate::dom::gpucomputepassencoder::GPUComputePassEncoder; use crate::dom::webgpu::gpucomputepassencoder::GPUComputePassEncoder;
use crate::dom::gpuconvert::{convert_load_op, convert_store_op}; use crate::dom::webgpu::gpuconvert::{convert_load_op, convert_store_op};
use crate::dom::gpudevice::GPUDevice; use crate::dom::webgpu::gpudevice::GPUDevice;
use crate::dom::gpurenderpassencoder::GPURenderPassEncoder; use crate::dom::webgpu::gpurenderpassencoder::GPURenderPassEncoder;
#[dom_struct] #[dom_struct]
pub struct GPUCommandEncoder { pub struct GPUCommandEncoder {

View file

@ -11,10 +11,10 @@ use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubindgroup::GPUBindGroup; use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
use crate::dom::gpubuffer::GPUBuffer; use crate::dom::webgpu::gpubuffer::GPUBuffer;
use crate::dom::gpucommandencoder::GPUCommandEncoder; use crate::dom::webgpu::gpucommandencoder::GPUCommandEncoder;
use crate::dom::gpucomputepipeline::GPUComputePipeline; use crate::dom::webgpu::gpucomputepipeline::GPUComputePipeline;
#[dom_struct] #[dom_struct]
pub struct GPUComputePassEncoder { pub struct GPUComputePassEncoder {

View file

@ -16,8 +16,8 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout; use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpudevice::GPUDevice; use crate::dom::webgpu::gpudevice::GPUDevice;
#[dom_struct] #[dom_struct]
pub struct GPUComputePipeline { pub struct GPUComputePipeline {

View file

@ -42,24 +42,24 @@ use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuadapter::GPUAdapter;
use crate::dom::gpubindgroup::GPUBindGroup;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpubuffer::GPUBuffer;
use crate::dom::gpucommandencoder::GPUCommandEncoder;
use crate::dom::gpucomputepipeline::GPUComputePipeline;
use crate::dom::gpupipelinelayout::GPUPipelineLayout;
use crate::dom::gpuqueue::GPUQueue;
use crate::dom::gpurenderbundleencoder::GPURenderBundleEncoder;
use crate::dom::gpurenderpipeline::GPURenderPipeline;
use crate::dom::gpusampler::GPUSampler;
use crate::dom::gpushadermodule::GPUShaderModule;
use crate::dom::gpusupportedfeatures::GPUSupportedFeatures;
use crate::dom::gputexture::GPUTexture;
use crate::dom::gpuuncapturederrorevent::GPUUncapturedErrorEvent;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::types::GPUError; use crate::dom::types::GPUError;
use crate::dom::webgpu::gpu::response_async; use crate::dom::webgpu::gpu::response_async;
use crate::dom::webgpu::gpuadapter::GPUAdapter;
use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::webgpu::gpubuffer::GPUBuffer;
use crate::dom::webgpu::gpucommandencoder::GPUCommandEncoder;
use crate::dom::webgpu::gpucomputepipeline::GPUComputePipeline;
use crate::dom::webgpu::gpupipelinelayout::GPUPipelineLayout;
use crate::dom::webgpu::gpuqueue::GPUQueue;
use crate::dom::webgpu::gpurenderbundleencoder::GPURenderBundleEncoder;
use crate::dom::webgpu::gpurenderpipeline::GPURenderPipeline;
use crate::dom::webgpu::gpusampler::GPUSampler;
use crate::dom::webgpu::gpushadermodule::GPUShaderModule;
use crate::dom::webgpu::gpusupportedfeatures::GPUSupportedFeatures;
use crate::dom::webgpu::gputexture::GPUTexture;
use crate::dom::webgpu::gpuuncapturederrorevent::GPUUncapturedErrorEvent;
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;

View file

@ -16,7 +16,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpudevice::GPUDevice; use crate::dom::webgpu::gpudevice::GPUDevice;
#[dom_struct] #[dom_struct]
pub struct GPUPipelineLayout { pub struct GPUPipelineLayout {

View file

@ -19,10 +19,10 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubuffer::GPUBuffer;
use crate::dom::gpucommandbuffer::GPUCommandBuffer;
use crate::dom::gpudevice::GPUDevice;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::webgpu::gpubuffer::GPUBuffer;
use crate::dom::webgpu::gpucommandbuffer::GPUCommandBuffer;
use crate::dom::webgpu::gpudevice::GPUDevice;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
#[dom_struct] #[dom_struct]

View file

@ -20,11 +20,11 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubindgroup::GPUBindGroup; use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
use crate::dom::gpubuffer::GPUBuffer; use crate::dom::webgpu::gpubuffer::GPUBuffer;
use crate::dom::gpudevice::GPUDevice; use crate::dom::webgpu::gpudevice::GPUDevice;
use crate::dom::gpurenderbundle::GPURenderBundle; use crate::dom::webgpu::gpurenderbundle::GPURenderBundle;
use crate::dom::gpurenderpipeline::GPURenderPipeline; use crate::dom::webgpu::gpurenderpipeline::GPURenderPipeline;
#[dom_struct] #[dom_struct]
pub struct GPURenderBundleEncoder { pub struct GPURenderBundleEncoder {

View file

@ -15,11 +15,11 @@ use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubindgroup::GPUBindGroup; use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
use crate::dom::gpubuffer::GPUBuffer; use crate::dom::webgpu::gpubuffer::GPUBuffer;
use crate::dom::gpucommandencoder::GPUCommandEncoder; use crate::dom::webgpu::gpucommandencoder::GPUCommandEncoder;
use crate::dom::gpurenderbundle::GPURenderBundle; use crate::dom::webgpu::gpurenderbundle::GPURenderBundle;
use crate::dom::gpurenderpipeline::GPURenderPipeline; use crate::dom::webgpu::gpurenderpipeline::GPURenderPipeline;
#[dom_struct] #[dom_struct]
pub struct GPURenderPassEncoder { pub struct GPURenderPassEncoder {

View file

@ -14,8 +14,8 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout; use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpudevice::{GPUDevice, PipelineLayout}; use crate::dom::webgpu::gpudevice::{GPUDevice, PipelineLayout};
#[dom_struct] #[dom_struct]
pub struct GPURenderPipeline { pub struct GPURenderPipeline {

View file

@ -14,7 +14,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpudevice::GPUDevice; use crate::dom::webgpu::gpudevice::GPUDevice;
#[dom_struct] #[dom_struct]
pub struct GPUSampler { pub struct GPUSampler {

View file

@ -19,8 +19,8 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpudevice::GPUDevice; use crate::dom::webgpu::gpudevice::GPUDevice;
use crate::dom::gputextureview::GPUTextureView; use crate::dom::webgpu::gputextureview::GPUTextureView;
#[dom_struct] #[dom_struct]
pub struct GPUTexture { pub struct GPUTexture {

View file

@ -11,7 +11,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gputexture::GPUTexture; use crate::dom::webgpu::gputexture::GPUTexture;
#[dom_struct] #[dom_struct]
pub struct GPUTextureView { pub struct GPUTextureView {

View file

@ -15,7 +15,7 @@ use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::event::Event; use crate::dom::event::Event;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuerror::GPUError; use crate::dom::webgpu::gpuerror::GPUError;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
#[dom_struct] #[dom_struct]

View file

@ -42,3 +42,4 @@ pub mod gputextureusage;
pub mod gputextureview; pub mod gputextureview;
pub mod gpuuncapturederrorevent; pub mod gpuuncapturederrorevent;
pub mod gpuvalidationerror; pub mod gpuvalidationerror;
pub mod identityhub;

View file

@ -0,0 +1,9 @@
/* 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://html.spec.whatwg.org/multipage/#htmlcanvaselement
[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
interface GPUCanvasContext {
readonly attribute (HTMLCanvasElement or OffscreenCanvas) canvas;
};

View file

@ -14,7 +14,6 @@ Navigator includes NavigatorLanguage;
//Navigator includes NavigatorStorageUtils; //Navigator includes NavigatorStorageUtils;
Navigator includes NavigatorPlugins; Navigator includes NavigatorPlugins;
Navigator includes NavigatorCookies; Navigator includes NavigatorCookies;
Navigator includes NavigatorGPU;
Navigator includes NavigatorConcurrentHardware; Navigator includes NavigatorConcurrentHardware;
// https://html.spec.whatwg.org/multipage/#navigatorid // https://html.spec.whatwg.org/multipage/#navigatorid

View file

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// skip-unless CARGO_FEATURE_WEBGPU
// Source: WebGPU (https://gpuweb.github.io/gpuweb/) // Source: WebGPU (https://gpuweb.github.io/gpuweb/)
// Direct source: https://github.com/w3c/webref/blob/curated/ed/idl/webgpu.idl // Direct source: https://github.com/w3c/webref/blob/curated/ed/idl/webgpu.idl
@ -66,10 +68,9 @@ interface GPUAdapterInfo {
interface mixin NavigatorGPU { interface mixin NavigatorGPU {
[SameObject, Pref="dom.webgpu.enabled", Exposed=(Window /* ,DedicatedWorker */)] readonly attribute GPU gpu; [SameObject, Pref="dom.webgpu.enabled", Exposed=(Window /* ,DedicatedWorker */)] readonly attribute GPU gpu;
}; };
// NOTE: see `Navigator.webidl`
// Navigator includes NavigatorGPU; Navigator includes NavigatorGPU;
// NOTE: see `WorkerNavigator.webidl` WorkerNavigator includes NavigatorGPU;
// WorkerNavigator includes NavigatorGPU;
[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"] [Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
interface GPU { interface GPU {
@ -1137,17 +1138,12 @@ enum GPUQueryType {
"timestamp" "timestamp"
}; };
[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
interface GPUCanvasContext {
readonly attribute (HTMLCanvasElement or OffscreenCanvas) canvas;
// Calling configure() a second time invalidates the previous one, partial interface GPUCanvasContext {
// and all of the textures it's produced. [Throws, Pref="dom.webgpu.enabled"]
[Throws]
undefined configure(GPUCanvasConfiguration descriptor); undefined configure(GPUCanvasConfiguration descriptor);
undefined unconfigure(); [Pref="dom.webgpu.enabled"] undefined unconfigure();
[Throws, Pref="dom.webgpu.enabled"]
[Throws]
GPUTexture getCurrentTexture(); GPUTexture getCurrentTexture();
}; };

View file

@ -17,7 +17,3 @@ partial interface WorkerNavigator {
[Pref="dom.permissions.enabled"] readonly attribute Permissions permissions; [Pref="dom.permissions.enabled"] readonly attribute Permissions permissions;
}; };
[Exposed=DedicatedWorker]
partial interface WorkerNavigator {
[SameObject, Pref="dom.webgpu.enabled"] readonly attribute GPU gpu;
};

View file

@ -124,7 +124,6 @@ use crate::dom::hashchangeevent::HashChangeEvent;
use crate::dom::history::History; use crate::dom::history::History;
use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection}; use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection};
use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::htmliframeelement::HTMLIFrameElement;
use crate::dom::identityhub::IdentityHub;
use crate::dom::location::Location; use crate::dom::location::Location;
use crate::dom::mediaquerylist::{MediaQueryList, MediaQueryListMatchState}; use crate::dom::mediaquerylist::{MediaQueryList, MediaQueryListMatchState};
use crate::dom::mediaquerylistevent::MediaQueryListEvent; use crate::dom::mediaquerylistevent::MediaQueryListEvent;
@ -138,6 +137,8 @@ use crate::dom::selection::Selection;
use crate::dom::storage::Storage; use crate::dom::storage::Storage;
use crate::dom::testrunner::TestRunner; use crate::dom::testrunner::TestRunner;
use crate::dom::webglrenderingcontext::WebGLCommandSender; use crate::dom::webglrenderingcontext::WebGLCommandSender;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::windowproxy::{WindowProxy, WindowProxyHandler}; use crate::dom::windowproxy::{WindowProxy, WindowProxyHandler};
use crate::dom::worklet::Worklet; use crate::dom::worklet::Worklet;
use crate::dom::workletglobalscope::WorkletGlobalScopeType; use crate::dom::workletglobalscope::WorkletGlobalScopeType;
@ -1875,6 +1876,7 @@ impl Window {
// If this reflow is for display, ensure webgl canvases are composited with // If this reflow is for display, ensure webgl canvases are composited with
// up-to-date contents. // up-to-date contents.
if for_display { if for_display {
#[cfg(feature = "webgpu")]
document.flush_dirty_webgpu_canvases(); document.flush_dirty_webgpu_canvases();
document.flush_dirty_webgl_canvases(); document.flush_dirty_webgl_canvases();
} }
@ -2601,7 +2603,7 @@ impl Window {
replace_surrogates: bool, replace_surrogates: bool,
user_agent: Cow<'static, str>, user_agent: Cow<'static, str>,
player_context: WindowGLContext, player_context: WindowGLContext,
gpu_id_hub: Arc<IdentityHub>, #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
inherited_secure_context: Option<bool>, inherited_secure_context: Option<bool>,
) -> DomRoot<Self> { ) -> DomRoot<Self> {
let error_reporter = CSSErrorReporter { let error_reporter = CSSErrorReporter {
@ -2628,6 +2630,7 @@ impl Window {
microtask_queue, microtask_queue,
is_headless, is_headless,
user_agent, user_agent,
#[cfg(feature = "webgpu")]
gpu_id_hub, gpu_id_hub,
inherited_secure_context, inherited_secure_context,
unminify_js, unminify_js,

View file

@ -234,6 +234,7 @@ impl WorkerMethods<crate::DomTypeHolder> for Worker {
closing.clone(), closing.clone(),
global.image_cache(), global.image_cache(),
browsing_context, browsing_context,
#[cfg(feature = "webgpu")]
global.wgpu_id_hub(), global.wgpu_id_hub(),
control_receiver, control_receiver,
context_sender, context_sender,

View file

@ -46,10 +46,11 @@ use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::crypto::Crypto; use crate::dom::crypto::Crypto;
use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::identityhub::IdentityHub;
use crate::dom::performance::Performance; use crate::dom::performance::Performance;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope; use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::window::{base64_atob, base64_btoa}; use crate::dom::window::{base64_atob, base64_btoa};
use crate::dom::workerlocation::WorkerLocation; use crate::dom::workerlocation::WorkerLocation;
use crate::dom::workernavigator::WorkerNavigator; use crate::dom::workernavigator::WorkerNavigator;
@ -140,7 +141,7 @@ impl WorkerGlobalScope {
runtime: Runtime, runtime: Runtime,
devtools_receiver: Receiver<DevtoolScriptControlMsg>, devtools_receiver: Receiver<DevtoolScriptControlMsg>,
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
gpu_id_hub: Arc<IdentityHub>, #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
) -> Self { ) -> Self {
// Install a pipeline-namespace in the current thread. // Install a pipeline-namespace in the current thread.
PipelineNamespace::auto_install(); PipelineNamespace::auto_install();
@ -164,6 +165,7 @@ impl WorkerGlobalScope {
runtime.microtask_queue.clone(), runtime.microtask_queue.clone(),
init.is_headless, init.is_headless,
init.user_agent, init.user_agent,
#[cfg(feature = "webgpu")]
gpu_id_hub, gpu_id_hub,
init.inherited_secure_context, init.inherited_secure_context,
false, false,

View file

@ -13,6 +13,7 @@ use crate::dom::bindings::utils::to_frozen_array;
use crate::dom::navigator::hardware_concurrency; use crate::dom::navigator::hardware_concurrency;
use crate::dom::navigatorinfo; use crate::dom::navigatorinfo;
use crate::dom::permissions::Permissions; use crate::dom::permissions::Permissions;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::gpu::GPU; use crate::dom::webgpu::gpu::GPU;
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::script_runtime::JSContext; use crate::script_runtime::JSContext;
@ -22,6 +23,7 @@ use crate::script_runtime::JSContext;
pub struct WorkerNavigator { pub struct WorkerNavigator {
reflector_: Reflector, reflector_: Reflector,
permissions: MutNullableDom<Permissions>, permissions: MutNullableDom<Permissions>,
#[cfg(feature = "webgpu")]
gpu: MutNullableDom<GPU>, gpu: MutNullableDom<GPU>,
} }
@ -30,6 +32,7 @@ impl WorkerNavigator {
WorkerNavigator { WorkerNavigator {
reflector_: Reflector::new(), reflector_: Reflector::new(),
permissions: Default::default(), permissions: Default::default(),
#[cfg(feature = "webgpu")]
gpu: Default::default(), gpu: Default::default(),
} }
} }
@ -108,6 +111,7 @@ impl WorkerNavigatorMethods<crate::DomTypeHolder> for WorkerNavigator {
} }
// https://gpuweb.github.io/gpuweb/#dom-navigator-gpu // https://gpuweb.github.io/gpuweb/#dom-navigator-gpu
#[cfg(feature = "webgpu")]
fn Gpu(&self) -> DomRoot<GPU> { fn Gpu(&self) -> DomRoot<GPU> {
self.gpu.or_init(|| GPU::new(&self.global())) self.gpu.or_init(|| GPU::new(&self.global()))
} }

View file

@ -22,9 +22,10 @@ use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::identityhub::IdentityHub;
use crate::dom::paintworkletglobalscope::{PaintWorkletGlobalScope, PaintWorkletTask}; use crate::dom::paintworkletglobalscope::{PaintWorkletGlobalScope, PaintWorkletTask};
use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask}; use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask};
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::worklet::WorkletExecutor; use crate::dom::worklet::WorkletExecutor;
use crate::script_module::ScriptFetchOptions; use crate::script_module::ScriptFetchOptions;
use crate::script_runtime::{CanGc, JSContext}; use crate::script_runtime::{CanGc, JSContext};
@ -99,6 +100,7 @@ impl WorkletGlobalScope {
Default::default(), Default::default(),
init.is_headless, init.is_headless,
init.user_agent.clone(), init.user_agent.clone(),
#[cfg(feature = "webgpu")]
init.gpu_id_hub.clone(), init.gpu_id_hub.clone(),
init.inherited_secure_context, init.inherited_secure_context,
false, false,
@ -193,6 +195,7 @@ pub struct WorkletGlobalScopeInit {
/// An optional string allowing the user agent to be set for testing /// An optional string allowing the user agent to be set for testing
pub user_agent: Cow<'static, str>, pub user_agent: Cow<'static, str>,
/// Identity manager for WebGPU resources /// Identity manager for WebGPU resources
#[cfg(feature = "webgpu")]
pub gpu_id_hub: Arc<IdentityHub>, pub gpu_id_hub: Arc<IdentityHub>,
/// Is considered secure /// Is considered secure
pub inherited_secure_context: Option<bool>, pub inherited_secure_context: Option<bool>,

View file

@ -158,6 +158,7 @@ pub enum ScriptThreadEventCategory {
EnterFullscreen, EnterFullscreen,
ExitFullscreen, ExitFullscreen,
PerformanceTimelineTask, PerformanceTimelineTask,
#[cfg(feature = "webgpu")]
WebGPUMsg, WebGPUMsg,
} }

View file

@ -94,6 +94,7 @@ use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use style::dom::OpaqueNode; use style::dom::OpaqueNode;
use style::thread_state::{self, ThreadState}; use style::thread_state::{self, ThreadState};
use url::Position; use url::Position;
#[cfg(feature = "webgpu")]
use webgpu::{WebGPUDevice, WebGPUMsg}; use webgpu::{WebGPUDevice, WebGPUMsg};
use webrender_api::DocumentId; use webrender_api::DocumentId;
use webrender_traits::CrossProcessCompositorApi; use webrender_traits::CrossProcessCompositorApi;
@ -128,7 +129,6 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlanchorelement::HTMLAnchorElement; use crate::dom::htmlanchorelement::HTMLAnchorElement;
use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::htmliframeelement::HTMLIFrameElement;
use crate::dom::identityhub::IdentityHub;
use crate::dom::mutationobserver::MutationObserver; use crate::dom::mutationobserver::MutationObserver;
use crate::dom::node::{window_from_node, Node, ShadowIncluding}; use crate::dom::node::{window_from_node, Node, ShadowIncluding};
use crate::dom::performanceentry::PerformanceEntry; use crate::dom::performanceentry::PerformanceEntry;
@ -136,6 +136,8 @@ use crate::dom::performancepainttiming::PerformancePaintTiming;
use crate::dom::serviceworker::TrustedServiceWorkerAddress; use crate::dom::serviceworker::TrustedServiceWorkerAddress;
use crate::dom::servoparser::{ParserContext, ServoParser}; use crate::dom::servoparser::{ParserContext, ServoParser};
use crate::dom::uievent::UIEvent; use crate::dom::uievent::UIEvent;
#[cfg(feature = "webgpu")]
use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::window::{ReflowReason, Window}; use crate::dom::window::{ReflowReason, Window};
use crate::dom::windowproxy::{CreatorBrowsingContextInfo, WindowProxy}; use crate::dom::windowproxy::{CreatorBrowsingContextInfo, WindowProxy};
use crate::dom::worker::TrustedWorkerAddress; use crate::dom::worker::TrustedWorkerAddress;
@ -279,6 +281,7 @@ enum MixedMessage {
FromScript(MainThreadScriptMsg), FromScript(MainThreadScriptMsg),
FromDevtools(DevtoolScriptControlMsg), FromDevtools(DevtoolScriptControlMsg),
FromImageCache((PipelineId, PendingImageResponse)), FromImageCache((PipelineId, PendingImageResponse)),
#[cfg(feature = "webgpu")]
FromWebGPUServer(WebGPUMsg), FromWebGPUServer(WebGPUMsg),
} }
@ -739,10 +742,12 @@ pub struct ScriptThread {
/// Identity manager for WebGPU resources /// Identity manager for WebGPU resources
#[no_trace] #[no_trace]
#[cfg(feature = "webgpu")]
gpu_id_hub: Arc<IdentityHub>, gpu_id_hub: Arc<IdentityHub>,
/// Receiver to receive commands from optional WebGPU server. /// Receiver to receive commands from optional WebGPU server.
#[no_trace] #[no_trace]
#[cfg(feature = "webgpu")]
webgpu_port: RefCell<Option<Receiver<WebGPUMsg>>>, webgpu_port: RefCell<Option<Receiver<WebGPUMsg>>>,
// Secure context // Secure context
@ -1136,6 +1141,7 @@ impl ScriptThread {
image_cache: script_thread.image_cache.clone(), image_cache: script_thread.image_cache.clone(),
is_headless: script_thread.headless, is_headless: script_thread.headless,
user_agent: script_thread.user_agent.clone(), user_agent: script_thread.user_agent.clone(),
#[cfg(feature = "webgpu")]
gpu_id_hub: script_thread.gpu_id_hub.clone(), gpu_id_hub: script_thread.gpu_id_hub.clone(),
inherited_secure_context: script_thread.inherited_secure_context, inherited_secure_context: script_thread.inherited_secure_context,
}; };
@ -1359,7 +1365,9 @@ impl ScriptThread {
node_ids: Default::default(), node_ids: Default::default(),
is_user_interacting: Cell::new(false), is_user_interacting: Cell::new(false),
#[cfg(feature = "webgpu")]
gpu_id_hub: Arc::new(IdentityHub::default()), gpu_id_hub: Arc::new(IdentityHub::default()),
#[cfg(feature = "webgpu")]
webgpu_port: RefCell::new(None), webgpu_port: RefCell::new(None),
inherited_secure_context: state.inherited_secure_context, inherited_secure_context: state.inherited_secure_context,
layout_factory, layout_factory,
@ -1739,9 +1747,9 @@ impl ScriptThread {
/// Handle incoming messages from other tasks and the task queue. /// Handle incoming messages from other tasks and the task queue.
fn handle_msgs(&self, can_gc: CanGc) -> bool { fn handle_msgs(&self, can_gc: CanGc) -> bool {
use self::MixedMessage::{ #[cfg(feature = "webgpu")]
FromConstellation, FromDevtools, FromImageCache, FromScript, FromWebGPUServer, use self::MixedMessage::FromWebGPUServer;
}; use self::MixedMessage::{FromConstellation, FromDevtools, FromImageCache, FromScript};
// Proritize rendering tasks and others, and gather all other events as `sequential`. // Proritize rendering tasks and others, and gather all other events as `sequential`.
let mut sequential = vec![]; let mut sequential = vec![];
@ -1764,8 +1772,25 @@ impl ScriptThread {
recv(self.devtools_chan.as_ref().map(|_| &self.devtools_port).unwrap_or(&crossbeam_channel::never())) -> msg recv(self.devtools_chan.as_ref().map(|_| &self.devtools_port).unwrap_or(&crossbeam_channel::never())) -> msg
=> FromDevtools(msg.unwrap()), => FromDevtools(msg.unwrap()),
recv(self.image_cache_port) -> msg => FromImageCache(msg.unwrap()), recv(self.image_cache_port) -> msg => FromImageCache(msg.unwrap()),
recv(self.webgpu_port.borrow().as_ref().unwrap_or(&crossbeam_channel::never())) -> msg recv({
=> FromWebGPUServer(msg.unwrap()), #[cfg(feature = "webgpu")]
{
self.webgpu_port.borrow().as_ref().unwrap_or(&crossbeam_channel::never())
}
#[cfg(not(feature = "webgpu"))]
{
&crossbeam_channel::never::<()>()
}
}) -> msg => {
#[cfg(feature = "webgpu")]
{
FromWebGPUServer(msg.unwrap())
}
#[cfg(not(feature = "webgpu"))]
{
unreachable!("This should never be hit when webgpu is disabled");
}
},
}; };
debug!("Got event."); debug!("Got event.");
@ -1890,6 +1915,7 @@ impl ScriptThread {
Err(_) => match self.task_queue.take_tasks_and_recv() { Err(_) => match self.task_queue.take_tasks_and_recv() {
Err(_) => match self.devtools_port.try_recv() { Err(_) => match self.devtools_port.try_recv() {
Err(_) => match self.image_cache_port.try_recv() { Err(_) => match self.image_cache_port.try_recv() {
#[cfg(feature = "webgpu")]
Err(_) => match &*self.webgpu_port.borrow() { Err(_) => match &*self.webgpu_port.borrow() {
Some(p) => match p.try_recv() { Some(p) => match p.try_recv() {
Err(_) => break, Err(_) => break,
@ -1898,6 +1924,8 @@ impl ScriptThread {
None => break, None => break,
}, },
Ok(ev) => event = FromImageCache(ev), Ok(ev) => event = FromImageCache(ev),
#[cfg(not(feature = "webgpu"))]
Err(_) => break,
}, },
Ok(ev) => event = FromDevtools(ev), Ok(ev) => event = FromDevtools(ev),
}, },
@ -1953,6 +1981,7 @@ impl ScriptThread {
FromScript(inner_msg) => self.handle_msg_from_script(inner_msg), FromScript(inner_msg) => self.handle_msg_from_script(inner_msg),
FromDevtools(inner_msg) => self.handle_msg_from_devtools(inner_msg, can_gc), FromDevtools(inner_msg) => self.handle_msg_from_devtools(inner_msg, can_gc),
FromImageCache(inner_msg) => self.handle_msg_from_image_cache(inner_msg), FromImageCache(inner_msg) => self.handle_msg_from_image_cache(inner_msg),
#[cfg(feature = "webgpu")]
FromWebGPUServer(inner_msg) => { FromWebGPUServer(inner_msg) => {
self.handle_msg_from_webgpu_server(inner_msg, can_gc) self.handle_msg_from_webgpu_server(inner_msg, can_gc)
}, },
@ -2053,6 +2082,7 @@ impl ScriptThread {
}, },
_ => ScriptThreadEventCategory::ScriptEvent, _ => ScriptThreadEventCategory::ScriptEvent,
}, },
#[cfg(feature = "webgpu")]
MixedMessage::FromWebGPUServer(_) => ScriptThreadEventCategory::WebGPUMsg, MixedMessage::FromWebGPUServer(_) => ScriptThreadEventCategory::WebGPUMsg,
} }
} }
@ -2093,6 +2123,7 @@ impl ScriptThread {
ScriptHangAnnotation::PerformanceTimelineTask ScriptHangAnnotation::PerformanceTimelineTask
}, },
ScriptThreadEventCategory::PortMessage => ScriptHangAnnotation::PortMessage, ScriptThreadEventCategory::PortMessage => ScriptHangAnnotation::PortMessage,
#[cfg(feature = "webgpu")]
ScriptThreadEventCategory::WebGPUMsg => ScriptHangAnnotation::WebGPUMsg, ScriptThreadEventCategory::WebGPUMsg => ScriptHangAnnotation::WebGPUMsg,
}; };
self.background_hang_monitor self.background_hang_monitor
@ -2139,6 +2170,7 @@ impl ScriptThread {
PaintMetric(id, ..) => Some(id), PaintMetric(id, ..) => Some(id),
ExitFullScreen(id, ..) => Some(id), ExitFullScreen(id, ..) => Some(id),
MediaSessionAction(..) => None, MediaSessionAction(..) => None,
#[cfg(feature = "webgpu")]
SetWebGPUPort(..) => None, SetWebGPUPort(..) => None,
SetScrollStates(id, ..) => Some(id), SetScrollStates(id, ..) => Some(id),
SetEpochPaintTime(id, ..) => Some(id), SetEpochPaintTime(id, ..) => Some(id),
@ -2155,6 +2187,7 @@ impl ScriptThread {
MainThreadScriptMsg::WakeUp => None, MainThreadScriptMsg::WakeUp => None,
}, },
MixedMessage::FromImageCache((pipeline_id, _)) => Some(pipeline_id), MixedMessage::FromImageCache((pipeline_id, _)) => Some(pipeline_id),
#[cfg(feature = "webgpu")]
MixedMessage::FromWebGPUServer(..) => None, MixedMessage::FromWebGPUServer(..) => None,
} }
} }
@ -2287,6 +2320,7 @@ impl ScriptThread {
profiler_chan, profiler_chan,
f f
), ),
#[cfg(feature = "webgpu")]
ScriptThreadEventCategory::WebGPUMsg => { ScriptThreadEventCategory::WebGPUMsg => {
time_profile!(ProfilerCategory::ScriptWebGPUMsg, None, profiler_chan, f) time_profile!(ProfilerCategory::ScriptWebGPUMsg, None, profiler_chan, f)
}, },
@ -2438,6 +2472,7 @@ impl ScriptThread {
ConstellationControlMsg::MediaSessionAction(pipeline_id, action) => { ConstellationControlMsg::MediaSessionAction(pipeline_id, action) => {
self.handle_media_session_action(pipeline_id, action, can_gc) self.handle_media_session_action(pipeline_id, action, can_gc)
}, },
#[cfg(feature = "webgpu")]
ConstellationControlMsg::SetWebGPUPort(port) => { ConstellationControlMsg::SetWebGPUPort(port) => {
if self.webgpu_port.borrow().is_some() { if self.webgpu_port.borrow().is_some() {
warn!("WebGPU port already exists for this content process"); warn!("WebGPU port already exists for this content process");
@ -2509,6 +2544,7 @@ impl ScriptThread {
window.layout_mut().set_epoch_paint_time(epoch, time); window.layout_mut().set_epoch_paint_time(epoch, time);
} }
#[cfg(feature = "webgpu")]
fn handle_msg_from_webgpu_server(&self, msg: WebGPUMsg, can_gc: CanGc) { fn handle_msg_from_webgpu_server(&self, msg: WebGPUMsg, can_gc: CanGc) {
match msg { match msg {
WebGPUMsg::FreeAdapter(id) => self.gpu_id_hub.free_adapter_id(id), WebGPUMsg::FreeAdapter(id) => self.gpu_id_hub.free_adapter_id(id),
@ -3768,6 +3804,7 @@ impl ScriptThread {
self.replace_surrogates, self.replace_surrogates,
self.user_agent.clone(), self.user_agent.clone(),
self.player_context.clone(), self.player_context.clone(),
#[cfg(feature = "webgpu")]
self.gpu_id_hub.clone(), self.gpu_id_hub.clone(),
incomplete.inherited_secure_context, incomplete.inherited_secure_context,
); );

View file

@ -39,6 +39,10 @@ webxr = [
"canvas/webxr", "canvas/webxr",
"script/webxr", "script/webxr",
] ]
webgpu = [
"script/webgpu",
"constellation/webgpu",
]
[dependencies] [dependencies]
background_hang_monitor = { path = "../background_hang_monitor" } background_hang_monitor = { path = "../background_hang_monitor" }

View file

@ -88,6 +88,9 @@ use surfman::platform::generic::multi::context::NativeContext as LinuxNativeCont
use surfman::{GLApi, GLVersion}; use surfman::{GLApi, GLVersion};
#[cfg(all(target_os = "linux", not(target_env = "ohos")))] #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
use surfman::{NativeConnection, NativeContext}; use surfman::{NativeConnection, NativeContext};
#[cfg(feature = "webgpu")]
pub use webgpu;
#[cfg(feature = "webgpu")]
use webgpu::swapchain::WGPUImageMap; use webgpu::swapchain::WGPUImageMap;
use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT}; use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT};
use webrender_api::{ColorF, DocumentId, FramePublishId}; use webrender_api::{ColorF, DocumentId, FramePublishId};
@ -100,7 +103,7 @@ pub use {
constellation, devtools, devtools_traits, embedder_traits, euclid, fonts, ipc_channel, constellation, devtools, devtools_traits, embedder_traits, euclid, fonts, ipc_channel,
keyboard_types, layout_thread_2020, media, net, net_traits, profile, profile_traits, script, keyboard_types, layout_thread_2020, media, net, net_traits, profile, profile_traits, script,
script_layout_interface, script_traits, servo_config as config, servo_config, servo_geometry, script_layout_interface, script_traits, servo_config as config, servo_config, servo_geometry,
servo_url as url, servo_url, style, style_traits, webgpu, webrender_api, webrender_traits, servo_url as url, servo_url, style, style_traits, webrender_api, webrender_traits,
}; };
#[cfg(feature = "webdriver")] #[cfg(feature = "webdriver")]
@ -424,8 +427,11 @@ where
embedder.register_webxr(&mut webxr_main_thread, embedder_proxy.clone()); embedder.register_webxr(&mut webxr_main_thread, embedder_proxy.clone());
} }
#[cfg(feature = "webgpu")]
let wgpu_image_handler = webgpu::WGPUExternalImages::default(); let wgpu_image_handler = webgpu::WGPUExternalImages::default();
#[cfg(feature = "webgpu")]
let wgpu_image_map = wgpu_image_handler.images.clone(); let wgpu_image_map = wgpu_image_handler.images.clone();
#[cfg(feature = "webgpu")]
external_image_handlers.set_handler( external_image_handlers.set_handler(
Box::new(wgpu_image_handler), Box::new(wgpu_image_handler),
WebrenderImageHandlerType::WebGPU, WebrenderImageHandlerType::WebGPU,
@ -468,6 +474,7 @@ where
glplayer_threads, glplayer_threads,
window_size, window_size,
external_images, external_images,
#[cfg(feature = "webgpu")]
wgpu_image_map, wgpu_image_map,
protocols, protocols,
); );
@ -1058,7 +1065,7 @@ fn create_constellation(
glplayer_threads: Option<GLPlayerThreads>, glplayer_threads: Option<GLPlayerThreads>,
initial_window_size: WindowSizeData, initial_window_size: WindowSizeData,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
wgpu_image_map: WGPUImageMap, #[cfg(feature = "webgpu")] wgpu_image_map: WGPUImageMap,
protocols: ProtocolRegistry, protocols: ProtocolRegistry,
) -> Sender<ConstellationMsg> { ) -> Sender<ConstellationMsg> {
// Global configuration options, parsed from the command line. // Global configuration options, parsed from the command line.
@ -1110,6 +1117,7 @@ fn create_constellation(
player_context, player_context,
user_agent, user_agent,
webrender_external_images: external_images, webrender_external_images: external_images,
#[cfg(feature = "webgpu")]
wgpu_image_map, wgpu_image_map,
}; };

View file

@ -11,6 +11,9 @@ rust-version.workspace = true
name = "script_traits" name = "script_traits"
path = "lib.rs" path = "lib.rs"
[features]
webgpu = []
[dependencies] [dependencies]
background_hang_monitor_api = { workspace = true } background_hang_monitor_api = { workspace = true }
base = { workspace = true } base = { workspace = true }

View file

@ -55,6 +55,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use servo_atoms::Atom; use servo_atoms::Atom;
use servo_url::{ImmutableOrigin, ServoUrl}; use servo_url::{ImmutableOrigin, ServoUrl};
use style_traits::{CSSPixel, SpeculativePainter}; use style_traits::{CSSPixel, SpeculativePainter};
#[cfg(feature = "webgpu")]
use webgpu::WebGPUMsg; use webgpu::WebGPUMsg;
use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel}; use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel};
use webrender_api::{DocumentId, ExternalScrollId, ImageKey}; use webrender_api::{DocumentId, ExternalScrollId, ImageKey};
@ -380,6 +381,7 @@ pub enum ConstellationControlMsg {
/// Notifies the media session about a user requested media session action. /// Notifies the media session about a user requested media session action.
MediaSessionAction(PipelineId, MediaSessionActionType), MediaSessionAction(PipelineId, MediaSessionActionType),
/// Notifies script thread that WebGPU server has started /// Notifies script thread that WebGPU server has started
#[cfg(feature = "webgpu")]
SetWebGPUPort(IpcReceiver<WebGPUMsg>), SetWebGPUPort(IpcReceiver<WebGPUMsg>),
/// The compositor scrolled and is updating the scroll states of the nodes in the given /// The compositor scrolled and is updating the scroll states of the nodes in the given
/// pipeline via the Constellation. /// pipeline via the Constellation.
@ -422,6 +424,7 @@ impl fmt::Debug for ConstellationControlMsg {
PaintMetric(..) => "PaintMetric", PaintMetric(..) => "PaintMetric",
ExitFullScreen(..) => "ExitFullScreen", ExitFullScreen(..) => "ExitFullScreen",
MediaSessionAction(..) => "MediaSessionAction", MediaSessionAction(..) => "MediaSessionAction",
#[cfg(feature = "webgpu")]
SetWebGPUPort(..) => "SetWebGPUPort", SetWebGPUPort(..) => "SetWebGPUPort",
SetScrollStates(..) => "SetScrollStates", SetScrollStates(..) => "SetScrollStates",
SetEpochPaintTime(..) => "SetEpochPaintTime", SetEpochPaintTime(..) => "SetEpochPaintTime",

View file

@ -23,6 +23,7 @@ use net_traits::CoreResourceMsg;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_url::{ImmutableOrigin, ServoUrl}; use servo_url::{ImmutableOrigin, ServoUrl};
use style_traits::CSSPixel; use style_traits::CSSPixel;
#[cfg(feature = "webgpu")]
use webgpu::{wgc, WebGPU, WebGPUResponse}; use webgpu::{wgc, WebGPU, WebGPUResponse};
use crate::{ use crate::{
@ -247,12 +248,14 @@ pub enum ScriptMsg {
/// Notifies the constellation about media session events /// Notifies the constellation about media session events
/// (i.e. when there is metadata for the active media session, playback state changes...). /// (i.e. when there is metadata for the active media session, playback state changes...).
MediaSessionEvent(PipelineId, MediaSessionEvent), MediaSessionEvent(PipelineId, MediaSessionEvent),
#[cfg(feature = "webgpu")]
/// Create a WebGPU Adapter instance /// Create a WebGPU Adapter instance
RequestAdapter( RequestAdapter(
IpcSender<WebGPUResponse>, IpcSender<WebGPUResponse>,
wgc::instance::RequestAdapterOptions, wgc::instance::RequestAdapterOptions,
wgc::id::AdapterId, wgc::id::AdapterId,
), ),
#[cfg(feature = "webgpu")]
/// Get WebGPU channel /// Get WebGPU channel
GetWebGPUChan(IpcSender<Option<WebGPU>>), GetWebGPUChan(IpcSender<Option<WebGPU>>),
/// Notify the constellation of a pipeline's document's title. /// Notify the constellation of a pipeline's document's title.
@ -312,7 +315,9 @@ impl fmt::Debug for ScriptMsg {
ForwardDOMMessage(..) => "ForwardDOMMessage", ForwardDOMMessage(..) => "ForwardDOMMessage",
ScheduleJob(..) => "ScheduleJob", ScheduleJob(..) => "ScheduleJob",
MediaSessionEvent(..) => "MediaSessionEvent", MediaSessionEvent(..) => "MediaSessionEvent",
#[cfg(feature = "webgpu")]
RequestAdapter(..) => "RequestAdapter", RequestAdapter(..) => "RequestAdapter",
#[cfg(feature = "webgpu")]
GetWebGPUChan(..) => "GetWebGPUChan", GetWebGPUChan(..) => "GetWebGPUChan",
TitleChanged(..) => "TitleChanged", TitleChanged(..) => "TitleChanged",
}; };

View file

@ -39,7 +39,7 @@ ProductName = "Servo"
[features] [features]
debugmozjs = ["libservo/debugmozjs"] debugmozjs = ["libservo/debugmozjs"]
default = ["max_log_level", "webdriver", "webxr"] default = ["max_log_level", "webdriver", "webxr", "webgpu"]
jitspew = ["libservo/jitspew"] jitspew = ["libservo/jitspew"]
js_backtrace = ["libservo/js_backtrace"] js_backtrace = ["libservo/js_backtrace"]
layout_2013 = ["libservo/layout_2013"] layout_2013 = ["libservo/layout_2013"]
@ -55,6 +55,7 @@ tracing-perfetto = ["tracing", "dep:tracing-perfetto"]
webdriver = ["libservo/webdriver"] webdriver = ["libservo/webdriver"]
webgl_backtrace = ["libservo/webgl_backtrace"] webgl_backtrace = ["libservo/webgl_backtrace"]
webxr = ["dep:webxr", "libservo/webxr"] webxr = ["dep:webxr", "libservo/webxr"]
webgpu = ["libservo/webgpu"]
[dependencies] [dependencies]
libc = { workspace = true } libc = { workspace = true }