mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
feat: webxr
feature flag (#34241)
* Add webxr feature flag Add webxr feature flag to embedder_traits Add webxr flag to constellation Add webxr flag to compositor Add webxr flag to canvas Turn registry into optional Add webxr flag to servo lib Signed-off-by: Wu Yu Wei <yuweiwu@pm.me> Co-authored-by: august kline <me@augustkline.com> * Cargo fmt Signed-off-by: Wu Yu Wei <yuweiwu@pm.me> * Add missing license Signed-off-by: Wu Yu Wei <yuweiwu@pm.me> * Cargo clippy Signed-off-by: Wu Yu Wei <yuweiwu@pm.me> --------- Signed-off-by: Wu Yu Wei <yuweiwu@pm.me> Co-authored-by: august kline <me@augustkline.com>
This commit is contained in:
parent
91f96cc9dd
commit
47a243614f
21 changed files with 456 additions and 374 deletions
|
@ -13,6 +13,7 @@ path = "lib.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
webgl_backtrace = ["canvas_traits/webgl_backtrace"]
|
webgl_backtrace = ["canvas_traits/webgl_backtrace"]
|
||||||
|
webxr = ["dep:webxr", "dep:webxr-api"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
app_units = { workspace = true }
|
app_units = { workspace = true }
|
||||||
|
@ -46,5 +47,5 @@ unicode-script = { workspace = true }
|
||||||
webrender = { workspace = true }
|
webrender = { workspace = true }
|
||||||
webrender_api = { workspace = true }
|
webrender_api = { workspace = true }
|
||||||
webrender_traits = { workspace = true }
|
webrender_traits = { workspace = true }
|
||||||
webxr = { workspace = true, features = ["ipc"] }
|
webxr = { workspace = true, features = ["ipc"], optional = true }
|
||||||
webxr-api = { workspace = true, features = ["ipc"] }
|
webxr-api = { workspace = true, features = ["ipc"], optional = true }
|
||||||
|
|
|
@ -13,3 +13,5 @@ pub mod canvas_paint_thread;
|
||||||
mod webgl_limits;
|
mod webgl_limits;
|
||||||
mod webgl_mode;
|
mod webgl_mode;
|
||||||
pub mod webgl_thread;
|
pub mod webgl_thread;
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
|
mod webxr;
|
||||||
|
|
|
@ -17,14 +17,17 @@ use webrender_traits::{
|
||||||
RenderingContext, WebrenderExternalImageApi, WebrenderExternalImageRegistry,
|
RenderingContext, WebrenderExternalImageApi, WebrenderExternalImageRegistry,
|
||||||
WebrenderImageSource,
|
WebrenderImageSource,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
use webxr::SurfmanGL as WebXRSurfman;
|
use webxr::SurfmanGL as WebXRSurfman;
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
use webxr_api::LayerGrandManager as WebXRLayerGrandManager;
|
use webxr_api::LayerGrandManager as WebXRLayerGrandManager;
|
||||||
|
|
||||||
use crate::webgl_thread::{WebGLThread, WebGLThreadInit, WebXRBridgeInit};
|
use crate::webgl_thread::{WebGLThread, WebGLThreadInit};
|
||||||
|
|
||||||
pub struct WebGLComm {
|
pub struct WebGLComm {
|
||||||
pub webgl_threads: WebGLThreads,
|
pub webgl_threads: WebGLThreads,
|
||||||
pub image_handler: Box<dyn WebrenderExternalImageApi>,
|
pub image_handler: Box<dyn WebrenderExternalImageApi>,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
pub webxr_layer_grand_manager: WebXRLayerGrandManager<WebXRSurfman>,
|
pub webxr_layer_grand_manager: WebXRLayerGrandManager<WebXRSurfman>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +43,9 @@ impl WebGLComm {
|
||||||
debug!("WebGLThreads::new()");
|
debug!("WebGLThreads::new()");
|
||||||
let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap();
|
let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap();
|
||||||
let webrender_swap_chains = SwapChains::new();
|
let webrender_swap_chains = SwapChains::new();
|
||||||
let webxr_init = WebXRBridgeInit::new(sender.clone());
|
#[cfg(feature = "webxr")]
|
||||||
|
let webxr_init = crate::webxr::WebXRBridgeInit::new(sender.clone());
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
let webxr_layer_grand_manager = webxr_init.layer_grand_manager();
|
let webxr_layer_grand_manager = webxr_init.layer_grand_manager();
|
||||||
|
|
||||||
// This implementation creates a single `WebGLThread` for all the pipelines.
|
// This implementation creates a single `WebGLThread` for all the pipelines.
|
||||||
|
@ -54,6 +59,7 @@ impl WebGLComm {
|
||||||
connection: surfman.connection(),
|
connection: surfman.connection(),
|
||||||
adapter: surfman.adapter(),
|
adapter: surfman.adapter(),
|
||||||
api_type,
|
api_type,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
webxr_init,
|
webxr_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,6 +70,7 @@ impl WebGLComm {
|
||||||
WebGLComm {
|
WebGLComm {
|
||||||
webgl_threads: WebGLThreads(sender),
|
webgl_threads: WebGLThreads(sender),
|
||||||
image_handler: Box::new(external),
|
image_handler: Box::new(external),
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
webxr_layer_grand_manager,
|
webxr_layer_grand_manager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::{slice, thread};
|
use std::{slice, thread};
|
||||||
|
@ -11,14 +10,16 @@ use std::{slice, thread};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
|
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
|
||||||
use canvas_traits::webgl;
|
use canvas_traits::webgl;
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
|
use canvas_traits::webgl::WebXRCommand;
|
||||||
use canvas_traits::webgl::{
|
use canvas_traits::webgl::{
|
||||||
webgl_channel, ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, AlphaTreatment,
|
ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, AlphaTreatment,
|
||||||
GLContextAttributes, GLLimits, GlType, InternalFormatIntVec, ProgramLinkInfo, TexDataType,
|
GLContextAttributes, GLLimits, GlType, InternalFormatIntVec, ProgramLinkInfo, TexDataType,
|
||||||
TexFormat, WebGLBufferId, WebGLChan, WebGLCommand, WebGLCommandBacktrace, WebGLContextId,
|
TexFormat, WebGLBufferId, WebGLChan, WebGLCommand, WebGLCommandBacktrace, WebGLContextId,
|
||||||
WebGLCreateContextResult, WebGLFramebufferBindingRequest, WebGLFramebufferId, WebGLMsg,
|
WebGLCreateContextResult, WebGLFramebufferBindingRequest, WebGLFramebufferId, WebGLMsg,
|
||||||
WebGLMsgSender, WebGLProgramId, WebGLQueryId, WebGLReceiver, WebGLRenderbufferId,
|
WebGLMsgSender, WebGLProgramId, WebGLQueryId, WebGLReceiver, WebGLRenderbufferId,
|
||||||
WebGLSLVersion, WebGLSamplerId, WebGLSender, WebGLShaderId, WebGLSyncId, WebGLTextureId,
|
WebGLSLVersion, WebGLSamplerId, WebGLSender, WebGLShaderId, WebGLSyncId, WebGLTextureId,
|
||||||
WebGLVersion, WebGLVertexArrayId, WebXRCommand, WebXRLayerManagerId, YAxisTreatment,
|
WebGLVersion, WebGLVertexArrayId, YAxisTreatment,
|
||||||
};
|
};
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
|
@ -39,22 +40,15 @@ use webrender_api::{
|
||||||
ImageData, ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey,
|
ImageData, ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey,
|
||||||
};
|
};
|
||||||
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
|
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
|
||||||
use webxr::SurfmanGL as WebXRSurfman;
|
|
||||||
use webxr_api::{
|
|
||||||
ContextId as WebXRContextId, Error as WebXRError, GLContexts as WebXRContexts,
|
|
||||||
GLTypes as WebXRTypes, LayerGrandManager as WebXRLayerGrandManager,
|
|
||||||
LayerGrandManagerAPI as WebXRLayerGrandManagerAPI, LayerId as WebXRLayerId,
|
|
||||||
LayerInit as WebXRLayerInit, LayerManager as WebXRLayerManager,
|
|
||||||
LayerManagerAPI as WebXRLayerManagerAPI, LayerManagerFactory as WebXRLayerManagerFactory,
|
|
||||||
SubImages as WebXRSubImages,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::webgl_limits::GLLimitsDetect;
|
use crate::webgl_limits::GLLimitsDetect;
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
|
use crate::webxr::{WebXRBridge, WebXRBridgeContexts, WebXRBridgeInit};
|
||||||
|
|
||||||
struct GLContextData {
|
pub(crate) struct GLContextData {
|
||||||
ctx: Context,
|
pub(crate) ctx: Context,
|
||||||
gl: Rc<Gl>,
|
pub(crate) gl: Rc<Gl>,
|
||||||
glow: glow::Context,
|
pub(crate) glow: glow::Context,
|
||||||
state: GLState,
|
state: GLState,
|
||||||
attributes: GLContextAttributes,
|
attributes: GLContextAttributes,
|
||||||
}
|
}
|
||||||
|
@ -212,6 +206,7 @@ pub(crate) struct WebGLThread {
|
||||||
webrender_swap_chains: SwapChains<WebGLContextId, Device>,
|
webrender_swap_chains: SwapChains<WebGLContextId, Device>,
|
||||||
/// Whether this context is a GL or GLES context.
|
/// Whether this context is a GL or GLES context.
|
||||||
api_type: GlType,
|
api_type: GlType,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
/// The bridge to WebXR
|
/// The bridge to WebXR
|
||||||
pub webxr_bridge: WebXRBridge,
|
pub webxr_bridge: WebXRBridge,
|
||||||
}
|
}
|
||||||
|
@ -227,6 +222,7 @@ pub(crate) struct WebGLThreadInit {
|
||||||
pub connection: Connection,
|
pub connection: Connection,
|
||||||
pub adapter: Adapter,
|
pub adapter: Adapter,
|
||||||
pub api_type: GlType,
|
pub api_type: GlType,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
pub webxr_init: WebXRBridgeInit,
|
pub webxr_init: WebXRBridgeInit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,6 +242,7 @@ impl WebGLThread {
|
||||||
connection,
|
connection,
|
||||||
adapter,
|
adapter,
|
||||||
api_type,
|
api_type,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
webxr_init,
|
webxr_init,
|
||||||
}: WebGLThreadInit,
|
}: WebGLThreadInit,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -263,6 +260,7 @@ impl WebGLThread {
|
||||||
receiver: receiver.into_inner(),
|
receiver: receiver.into_inner(),
|
||||||
webrender_swap_chains,
|
webrender_swap_chains,
|
||||||
api_type,
|
api_type,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
webxr_bridge: WebXRBridge::new(webxr_init),
|
webxr_bridge: WebXRBridge::new(webxr_init),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,8 +361,9 @@ impl WebGLThread {
|
||||||
WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => {
|
WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => {
|
||||||
self.handle_webgl_command(ctx_id, command, backtrace);
|
self.handle_webgl_command(ctx_id, command, backtrace);
|
||||||
},
|
},
|
||||||
WebGLMsg::WebXRCommand(command) => {
|
WebGLMsg::WebXRCommand(_command) => {
|
||||||
self.handle_webxr_command(command);
|
#[cfg(feature = "webxr")]
|
||||||
|
self.handle_webxr_command(_command);
|
||||||
},
|
},
|
||||||
WebGLMsg::SwapBuffers(swap_ids, sender, sent_time) => {
|
WebGLMsg::SwapBuffers(swap_ids, sender, sent_time) => {
|
||||||
self.handle_swap_buffers(swap_ids, sender, sent_time);
|
self.handle_swap_buffers(swap_ids, sender, sent_time);
|
||||||
|
@ -380,6 +379,7 @@ impl WebGLThread {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
/// Handles a WebXR message
|
/// Handles a WebXR message
|
||||||
fn handle_webxr_command(&mut self, command: WebXRCommand) {
|
fn handle_webxr_command(&mut self, command: WebXRCommand) {
|
||||||
trace!("processing {:?}", command);
|
trace!("processing {:?}", command);
|
||||||
|
@ -723,17 +723,20 @@ impl WebGLThread {
|
||||||
&mut self.bound_context_id,
|
&mut self.bound_context_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Destroy WebXR layers associated with this context
|
#[cfg(feature = "webxr")]
|
||||||
let webxr_context_id = WebXRContextId::from(context_id);
|
{
|
||||||
let mut webxr_contexts = WebXRBridgeContexts {
|
// Destroy WebXR layers associated with this context
|
||||||
contexts: &mut self.contexts,
|
let webxr_context_id = webxr_api::ContextId::from(context_id);
|
||||||
bound_context_id: &mut self.bound_context_id,
|
let mut webxr_contexts = WebXRBridgeContexts {
|
||||||
};
|
contexts: &mut self.contexts,
|
||||||
self.webxr_bridge.destroy_all_layers(
|
bound_context_id: &mut self.bound_context_id,
|
||||||
&mut self.device,
|
};
|
||||||
&mut webxr_contexts,
|
self.webxr_bridge.destroy_all_layers(
|
||||||
webxr_context_id,
|
&mut self.device,
|
||||||
);
|
&mut webxr_contexts,
|
||||||
|
webxr_context_id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Release GL context.
|
// Release GL context.
|
||||||
let mut data = match self.contexts.remove(&context_id) {
|
let mut data = match self.contexts.remove(&context_id) {
|
||||||
|
@ -849,7 +852,7 @@ impl WebGLThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a reference to a Context for a given WebGLContextId and makes it current if required.
|
/// Gets a reference to a Context for a given WebGLContextId and makes it current if required.
|
||||||
fn make_current_if_needed<'a>(
|
pub(crate) fn make_current_if_needed<'a>(
|
||||||
device: &Device,
|
device: &Device,
|
||||||
context_id: WebGLContextId,
|
context_id: WebGLContextId,
|
||||||
contexts: &'a FnvHashMap<WebGLContextId, GLContextData>,
|
contexts: &'a FnvHashMap<WebGLContextId, GLContextData>,
|
||||||
|
@ -868,7 +871,7 @@ impl WebGLThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a mutable reference to a GLContextWrapper for a WebGLContextId and makes it current if required.
|
/// Gets a mutable reference to a GLContextWrapper for a WebGLContextId and makes it current if required.
|
||||||
fn make_current_if_needed_mut<'a>(
|
pub(crate) fn make_current_if_needed_mut<'a>(
|
||||||
device: &Device,
|
device: &Device,
|
||||||
context_id: WebGLContextId,
|
context_id: WebGLContextId,
|
||||||
contexts: &'a mut FnvHashMap<WebGLContextId, GLContextData>,
|
contexts: &'a mut FnvHashMap<WebGLContextId, GLContextData>,
|
||||||
|
@ -3016,313 +3019,3 @@ impl FramebufferRebindingInfo {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bridge between WebGL and WebXR
|
|
||||||
pub(crate) struct WebXRBridge {
|
|
||||||
factory_receiver: crossbeam_channel::Receiver<WebXRLayerManagerFactory<WebXRSurfman>>,
|
|
||||||
managers: HashMap<WebXRLayerManagerId, Box<dyn WebXRLayerManagerAPI<WebXRSurfman>>>,
|
|
||||||
next_manager_id: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebXRBridge {
|
|
||||||
pub(crate) fn new(init: WebXRBridgeInit) -> WebXRBridge {
|
|
||||||
let WebXRBridgeInit {
|
|
||||||
factory_receiver, ..
|
|
||||||
} = init;
|
|
||||||
let managers = HashMap::new();
|
|
||||||
let next_manager_id = 1;
|
|
||||||
WebXRBridge {
|
|
||||||
factory_receiver,
|
|
||||||
managers,
|
|
||||||
next_manager_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebXRBridge {
|
|
||||||
#[allow(unsafe_code)]
|
|
||||||
fn create_layer_manager(
|
|
||||||
&mut self,
|
|
||||||
device: &mut Device,
|
|
||||||
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
|
||||||
) -> Result<WebXRLayerManagerId, WebXRError> {
|
|
||||||
let factory = self
|
|
||||||
.factory_receiver
|
|
||||||
.recv()
|
|
||||||
.map_err(|_| WebXRError::CommunicationError)?;
|
|
||||||
let manager = factory.build(device, contexts)?;
|
|
||||||
let manager_id = unsafe { WebXRLayerManagerId::new(self.next_manager_id) };
|
|
||||||
self.next_manager_id += 1;
|
|
||||||
self.managers.insert(manager_id, manager);
|
|
||||||
Ok(manager_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destroy_layer_manager(&mut self, manager_id: WebXRLayerManagerId) {
|
|
||||||
self.managers.remove(&manager_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_layer(
|
|
||||||
&mut self,
|
|
||||||
manager_id: WebXRLayerManagerId,
|
|
||||||
device: &mut Device,
|
|
||||||
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
|
||||||
context_id: WebXRContextId,
|
|
||||||
layer_init: WebXRLayerInit,
|
|
||||||
) -> Result<WebXRLayerId, WebXRError> {
|
|
||||||
let manager = self
|
|
||||||
.managers
|
|
||||||
.get_mut(&manager_id)
|
|
||||||
.ok_or(WebXRError::NoMatchingDevice)?;
|
|
||||||
manager.create_layer(device, contexts, context_id, layer_init)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destroy_layer(
|
|
||||||
&mut self,
|
|
||||||
manager_id: WebXRLayerManagerId,
|
|
||||||
device: &mut Device,
|
|
||||||
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
|
||||||
context_id: WebXRContextId,
|
|
||||||
layer_id: WebXRLayerId,
|
|
||||||
) {
|
|
||||||
if let Some(manager) = self.managers.get_mut(&manager_id) {
|
|
||||||
manager.destroy_layer(device, contexts, context_id, layer_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destroy_all_layers(
|
|
||||||
&mut self,
|
|
||||||
device: &mut Device,
|
|
||||||
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
|
||||||
context_id: WebXRContextId,
|
|
||||||
) {
|
|
||||||
for manager in self.managers.values_mut() {
|
|
||||||
#[allow(clippy::unnecessary_to_owned)] // Needs mutable borrow later in destroy
|
|
||||||
for (other_id, layer_id) in manager.layers().to_vec() {
|
|
||||||
if other_id == context_id {
|
|
||||||
manager.destroy_layer(device, contexts, context_id, layer_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn begin_frame(
|
|
||||||
&mut self,
|
|
||||||
manager_id: WebXRLayerManagerId,
|
|
||||||
device: &mut Device,
|
|
||||||
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
|
||||||
layers: &[(WebXRContextId, WebXRLayerId)],
|
|
||||||
) -> Result<Vec<WebXRSubImages>, WebXRError> {
|
|
||||||
let manager = self
|
|
||||||
.managers
|
|
||||||
.get_mut(&manager_id)
|
|
||||||
.ok_or(WebXRError::NoMatchingDevice)?;
|
|
||||||
manager.begin_frame(device, contexts, layers)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end_frame(
|
|
||||||
&mut self,
|
|
||||||
manager_id: WebXRLayerManagerId,
|
|
||||||
device: &mut Device,
|
|
||||||
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
|
||||||
layers: &[(WebXRContextId, WebXRLayerId)],
|
|
||||||
) -> Result<(), WebXRError> {
|
|
||||||
let manager = self
|
|
||||||
.managers
|
|
||||||
.get_mut(&manager_id)
|
|
||||||
.ok_or(WebXRError::NoMatchingDevice)?;
|
|
||||||
manager.end_frame(device, contexts, layers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct WebXRBridgeInit {
|
|
||||||
sender: WebGLSender<WebGLMsg>,
|
|
||||||
factory_receiver: crossbeam_channel::Receiver<WebXRLayerManagerFactory<WebXRSurfman>>,
|
|
||||||
factory_sender: crossbeam_channel::Sender<WebXRLayerManagerFactory<WebXRSurfman>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebXRBridgeInit {
|
|
||||||
pub(crate) fn new(sender: WebGLSender<WebGLMsg>) -> WebXRBridgeInit {
|
|
||||||
let (factory_sender, factory_receiver) = crossbeam_channel::unbounded();
|
|
||||||
WebXRBridgeInit {
|
|
||||||
sender,
|
|
||||||
factory_sender,
|
|
||||||
factory_receiver,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn layer_grand_manager(&self) -> WebXRLayerGrandManager<WebXRSurfman> {
|
|
||||||
WebXRLayerGrandManager::new(WebXRBridgeGrandManager {
|
|
||||||
sender: self.sender.clone(),
|
|
||||||
factory_sender: self.factory_sender.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WebXRBridgeGrandManager {
|
|
||||||
sender: WebGLSender<WebGLMsg>,
|
|
||||||
// WebXR layer manager factories use generic trait objects under the
|
|
||||||
// hood, which aren't deserializable (even using typetag)
|
|
||||||
// so we can't send them over the regular webgl channel.
|
|
||||||
// Fortunately, the webgl thread runs in the same process as
|
|
||||||
// the webxr threads, so we can use a crossbeam channel to send
|
|
||||||
// factories.
|
|
||||||
factory_sender: crossbeam_channel::Sender<WebXRLayerManagerFactory<WebXRSurfman>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebXRLayerGrandManagerAPI<WebXRSurfman> for WebXRBridgeGrandManager {
|
|
||||||
fn create_layer_manager(
|
|
||||||
&self,
|
|
||||||
factory: WebXRLayerManagerFactory<WebXRSurfman>,
|
|
||||||
) -> Result<WebXRLayerManager, WebXRError> {
|
|
||||||
let (sender, receiver) = webgl_channel().ok_or(WebXRError::CommunicationError)?;
|
|
||||||
let _ = self.factory_sender.send(factory);
|
|
||||||
let _ = self
|
|
||||||
.sender
|
|
||||||
.send(WebGLMsg::WebXRCommand(WebXRCommand::CreateLayerManager(
|
|
||||||
sender,
|
|
||||||
)));
|
|
||||||
let sender = self.sender.clone();
|
|
||||||
let manager_id = receiver
|
|
||||||
.recv()
|
|
||||||
.map_err(|_| WebXRError::CommunicationError)??;
|
|
||||||
let layers = Vec::new();
|
|
||||||
Ok(WebXRLayerManager::new(WebXRBridgeManager {
|
|
||||||
manager_id,
|
|
||||||
sender,
|
|
||||||
layers,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone_layer_grand_manager(&self) -> WebXRLayerGrandManager<WebXRSurfman> {
|
|
||||||
WebXRLayerGrandManager::new(WebXRBridgeGrandManager {
|
|
||||||
sender: self.sender.clone(),
|
|
||||||
factory_sender: self.factory_sender.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WebXRBridgeManager {
|
|
||||||
sender: WebGLSender<WebGLMsg>,
|
|
||||||
manager_id: WebXRLayerManagerId,
|
|
||||||
layers: Vec<(WebXRContextId, WebXRLayerId)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<GL: WebXRTypes> WebXRLayerManagerAPI<GL> for WebXRBridgeManager {
|
|
||||||
fn create_layer(
|
|
||||||
&mut self,
|
|
||||||
_: &mut GL::Device,
|
|
||||||
_: &mut dyn WebXRContexts<GL>,
|
|
||||||
context_id: WebXRContextId,
|
|
||||||
init: WebXRLayerInit,
|
|
||||||
) -> Result<WebXRLayerId, WebXRError> {
|
|
||||||
let (sender, receiver) = webgl_channel().ok_or(WebXRError::CommunicationError)?;
|
|
||||||
let _ = self
|
|
||||||
.sender
|
|
||||||
.send(WebGLMsg::WebXRCommand(WebXRCommand::CreateLayer(
|
|
||||||
self.manager_id,
|
|
||||||
context_id,
|
|
||||||
init,
|
|
||||||
sender,
|
|
||||||
)));
|
|
||||||
let layer_id = receiver
|
|
||||||
.recv()
|
|
||||||
.map_err(|_| WebXRError::CommunicationError)??;
|
|
||||||
self.layers.push((context_id, layer_id));
|
|
||||||
Ok(layer_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destroy_layer(
|
|
||||||
&mut self,
|
|
||||||
_: &mut GL::Device,
|
|
||||||
_: &mut dyn WebXRContexts<GL>,
|
|
||||||
context_id: WebXRContextId,
|
|
||||||
layer_id: WebXRLayerId,
|
|
||||||
) {
|
|
||||||
self.layers.retain(|&ids| ids != (context_id, layer_id));
|
|
||||||
let _ = self
|
|
||||||
.sender
|
|
||||||
.send(WebGLMsg::WebXRCommand(WebXRCommand::DestroyLayer(
|
|
||||||
self.manager_id,
|
|
||||||
context_id,
|
|
||||||
layer_id,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layers(&self) -> &[(WebXRContextId, WebXRLayerId)] {
|
|
||||||
&self.layers[..]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn begin_frame(
|
|
||||||
&mut self,
|
|
||||||
_: &mut GL::Device,
|
|
||||||
_: &mut dyn WebXRContexts<GL>,
|
|
||||||
layers: &[(WebXRContextId, WebXRLayerId)],
|
|
||||||
) -> Result<Vec<WebXRSubImages>, WebXRError> {
|
|
||||||
let (sender, receiver) = webgl_channel().ok_or(WebXRError::CommunicationError)?;
|
|
||||||
let _ = self
|
|
||||||
.sender
|
|
||||||
.send(WebGLMsg::WebXRCommand(WebXRCommand::BeginFrame(
|
|
||||||
self.manager_id,
|
|
||||||
layers.to_vec(),
|
|
||||||
sender,
|
|
||||||
)));
|
|
||||||
receiver
|
|
||||||
.recv()
|
|
||||||
.map_err(|_| WebXRError::CommunicationError)?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end_frame(
|
|
||||||
&mut self,
|
|
||||||
_: &mut GL::Device,
|
|
||||||
_: &mut dyn WebXRContexts<GL>,
|
|
||||||
layers: &[(WebXRContextId, WebXRLayerId)],
|
|
||||||
) -> Result<(), WebXRError> {
|
|
||||||
let (sender, receiver) = webgl_channel().ok_or(WebXRError::CommunicationError)?;
|
|
||||||
let _ = self
|
|
||||||
.sender
|
|
||||||
.send(WebGLMsg::WebXRCommand(WebXRCommand::EndFrame(
|
|
||||||
self.manager_id,
|
|
||||||
layers.to_vec(),
|
|
||||||
sender,
|
|
||||||
)));
|
|
||||||
receiver
|
|
||||||
.recv()
|
|
||||||
.map_err(|_| WebXRError::CommunicationError)?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for WebXRBridgeManager {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let _ = self
|
|
||||||
.sender
|
|
||||||
.send(WebGLMsg::WebXRCommand(WebXRCommand::DestroyLayerManager(
|
|
||||||
self.manager_id,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WebXRBridgeContexts<'a> {
|
|
||||||
contexts: &'a mut FnvHashMap<WebGLContextId, GLContextData>,
|
|
||||||
bound_context_id: &'a mut Option<WebGLContextId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> WebXRContexts<WebXRSurfman> for WebXRBridgeContexts<'a> {
|
|
||||||
fn context(&mut self, device: &Device, context_id: WebXRContextId) -> Option<&mut Context> {
|
|
||||||
let data = WebGLThread::make_current_if_needed_mut(
|
|
||||||
device,
|
|
||||||
WebGLContextId::from(context_id),
|
|
||||||
self.contexts,
|
|
||||||
self.bound_context_id,
|
|
||||||
)?;
|
|
||||||
Some(&mut data.ctx)
|
|
||||||
}
|
|
||||||
fn bindings(&mut self, device: &Device, context_id: WebXRContextId) -> Option<&glow::Context> {
|
|
||||||
let data = WebGLThread::make_current_if_needed(
|
|
||||||
device,
|
|
||||||
WebGLContextId::from(context_id),
|
|
||||||
self.contexts,
|
|
||||||
self.bound_context_id,
|
|
||||||
)?;
|
|
||||||
Some(&data.glow)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
332
components/canvas/webxr.rs
Normal file
332
components/canvas/webxr.rs
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
/* 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 std::collections::HashMap;
|
||||||
|
|
||||||
|
use canvas_traits::webgl::{
|
||||||
|
webgl_channel, WebGLContextId, WebGLMsg, WebGLSender, WebXRCommand, WebXRLayerManagerId,
|
||||||
|
};
|
||||||
|
use fnv::FnvHashMap;
|
||||||
|
use surfman::{Context, Device};
|
||||||
|
use webxr::SurfmanGL as WebXRSurfman;
|
||||||
|
use webxr_api::{
|
||||||
|
ContextId as WebXRContextId, Error as WebXRError, GLContexts as WebXRContexts,
|
||||||
|
GLTypes as WebXRTypes, LayerGrandManager as WebXRLayerGrandManager,
|
||||||
|
LayerGrandManagerAPI as WebXRLayerGrandManagerAPI, LayerId as WebXRLayerId,
|
||||||
|
LayerInit as WebXRLayerInit, LayerManager as WebXRLayerManager,
|
||||||
|
LayerManagerAPI as WebXRLayerManagerAPI, LayerManagerFactory as WebXRLayerManagerFactory,
|
||||||
|
SubImages as WebXRSubImages,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::webgl_thread::{GLContextData, WebGLThread};
|
||||||
|
|
||||||
|
/// Bridge between WebGL and WebXR
|
||||||
|
pub(crate) struct WebXRBridge {
|
||||||
|
factory_receiver: crossbeam_channel::Receiver<WebXRLayerManagerFactory<WebXRSurfman>>,
|
||||||
|
managers: HashMap<WebXRLayerManagerId, Box<dyn WebXRLayerManagerAPI<WebXRSurfman>>>,
|
||||||
|
next_manager_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebXRBridge {
|
||||||
|
pub(crate) fn new(init: WebXRBridgeInit) -> WebXRBridge {
|
||||||
|
let WebXRBridgeInit {
|
||||||
|
factory_receiver, ..
|
||||||
|
} = init;
|
||||||
|
let managers = HashMap::new();
|
||||||
|
let next_manager_id = 1;
|
||||||
|
WebXRBridge {
|
||||||
|
factory_receiver,
|
||||||
|
managers,
|
||||||
|
next_manager_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebXRBridge {
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
pub(crate) fn create_layer_manager(
|
||||||
|
&mut self,
|
||||||
|
device: &mut Device,
|
||||||
|
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
||||||
|
) -> Result<WebXRLayerManagerId, WebXRError> {
|
||||||
|
let factory = self
|
||||||
|
.factory_receiver
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| WebXRError::CommunicationError)?;
|
||||||
|
let manager = factory.build(device, contexts)?;
|
||||||
|
let manager_id = unsafe { WebXRLayerManagerId::new(self.next_manager_id) };
|
||||||
|
self.next_manager_id += 1;
|
||||||
|
self.managers.insert(manager_id, manager);
|
||||||
|
Ok(manager_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn destroy_layer_manager(&mut self, manager_id: WebXRLayerManagerId) {
|
||||||
|
self.managers.remove(&manager_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn create_layer(
|
||||||
|
&mut self,
|
||||||
|
manager_id: WebXRLayerManagerId,
|
||||||
|
device: &mut Device,
|
||||||
|
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
||||||
|
context_id: WebXRContextId,
|
||||||
|
layer_init: WebXRLayerInit,
|
||||||
|
) -> Result<WebXRLayerId, WebXRError> {
|
||||||
|
let manager = self
|
||||||
|
.managers
|
||||||
|
.get_mut(&manager_id)
|
||||||
|
.ok_or(WebXRError::NoMatchingDevice)?;
|
||||||
|
manager.create_layer(device, contexts, context_id, layer_init)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn destroy_layer(
|
||||||
|
&mut self,
|
||||||
|
manager_id: WebXRLayerManagerId,
|
||||||
|
device: &mut Device,
|
||||||
|
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
||||||
|
context_id: WebXRContextId,
|
||||||
|
layer_id: WebXRLayerId,
|
||||||
|
) {
|
||||||
|
if let Some(manager) = self.managers.get_mut(&manager_id) {
|
||||||
|
manager.destroy_layer(device, contexts, context_id, layer_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn destroy_all_layers(
|
||||||
|
&mut self,
|
||||||
|
device: &mut Device,
|
||||||
|
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
||||||
|
context_id: WebXRContextId,
|
||||||
|
) {
|
||||||
|
for manager in self.managers.values_mut() {
|
||||||
|
#[allow(clippy::unnecessary_to_owned)] // Needs mutable borrow later in destroy
|
||||||
|
for (other_id, layer_id) in manager.layers().to_vec() {
|
||||||
|
if other_id == context_id {
|
||||||
|
manager.destroy_layer(device, contexts, context_id, layer_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn begin_frame(
|
||||||
|
&mut self,
|
||||||
|
manager_id: WebXRLayerManagerId,
|
||||||
|
device: &mut Device,
|
||||||
|
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
||||||
|
layers: &[(WebXRContextId, WebXRLayerId)],
|
||||||
|
) -> Result<Vec<WebXRSubImages>, WebXRError> {
|
||||||
|
let manager = self
|
||||||
|
.managers
|
||||||
|
.get_mut(&manager_id)
|
||||||
|
.ok_or(WebXRError::NoMatchingDevice)?;
|
||||||
|
manager.begin_frame(device, contexts, layers)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn end_frame(
|
||||||
|
&mut self,
|
||||||
|
manager_id: WebXRLayerManagerId,
|
||||||
|
device: &mut Device,
|
||||||
|
contexts: &mut dyn WebXRContexts<WebXRSurfman>,
|
||||||
|
layers: &[(WebXRContextId, WebXRLayerId)],
|
||||||
|
) -> Result<(), WebXRError> {
|
||||||
|
let manager = self
|
||||||
|
.managers
|
||||||
|
.get_mut(&manager_id)
|
||||||
|
.ok_or(WebXRError::NoMatchingDevice)?;
|
||||||
|
manager.end_frame(device, contexts, layers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct WebXRBridgeInit {
|
||||||
|
sender: WebGLSender<WebGLMsg>,
|
||||||
|
factory_receiver: crossbeam_channel::Receiver<WebXRLayerManagerFactory<WebXRSurfman>>,
|
||||||
|
factory_sender: crossbeam_channel::Sender<WebXRLayerManagerFactory<WebXRSurfman>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebXRBridgeInit {
|
||||||
|
pub(crate) fn new(sender: WebGLSender<WebGLMsg>) -> WebXRBridgeInit {
|
||||||
|
let (factory_sender, factory_receiver) = crossbeam_channel::unbounded();
|
||||||
|
WebXRBridgeInit {
|
||||||
|
sender,
|
||||||
|
factory_sender,
|
||||||
|
factory_receiver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn layer_grand_manager(&self) -> WebXRLayerGrandManager<WebXRSurfman> {
|
||||||
|
WebXRLayerGrandManager::new(WebXRBridgeGrandManager {
|
||||||
|
sender: self.sender.clone(),
|
||||||
|
factory_sender: self.factory_sender.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WebXRBridgeGrandManager {
|
||||||
|
sender: WebGLSender<WebGLMsg>,
|
||||||
|
// WebXR layer manager factories use generic trait objects under the
|
||||||
|
// hood, which aren't deserializable (even using typetag)
|
||||||
|
// so we can't send them over the regular webgl channel.
|
||||||
|
// Fortunately, the webgl thread runs in the same process as
|
||||||
|
// the webxr threads, so we can use a crossbeam channel to send
|
||||||
|
// factories.
|
||||||
|
factory_sender: crossbeam_channel::Sender<WebXRLayerManagerFactory<WebXRSurfman>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebXRLayerGrandManagerAPI<WebXRSurfman> for WebXRBridgeGrandManager {
|
||||||
|
fn create_layer_manager(
|
||||||
|
&self,
|
||||||
|
factory: WebXRLayerManagerFactory<WebXRSurfman>,
|
||||||
|
) -> Result<WebXRLayerManager, WebXRError> {
|
||||||
|
let (sender, receiver) = webgl_channel().ok_or(WebXRError::CommunicationError)?;
|
||||||
|
let _ = self.factory_sender.send(factory);
|
||||||
|
let _ = self
|
||||||
|
.sender
|
||||||
|
.send(WebGLMsg::WebXRCommand(WebXRCommand::CreateLayerManager(
|
||||||
|
sender,
|
||||||
|
)));
|
||||||
|
let sender = self.sender.clone();
|
||||||
|
let manager_id = receiver
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| WebXRError::CommunicationError)??;
|
||||||
|
let layers = Vec::new();
|
||||||
|
Ok(WebXRLayerManager::new(WebXRBridgeManager {
|
||||||
|
manager_id,
|
||||||
|
sender,
|
||||||
|
layers,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_layer_grand_manager(&self) -> WebXRLayerGrandManager<WebXRSurfman> {
|
||||||
|
WebXRLayerGrandManager::new(WebXRBridgeGrandManager {
|
||||||
|
sender: self.sender.clone(),
|
||||||
|
factory_sender: self.factory_sender.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WebXRBridgeManager {
|
||||||
|
sender: WebGLSender<WebGLMsg>,
|
||||||
|
manager_id: WebXRLayerManagerId,
|
||||||
|
layers: Vec<(WebXRContextId, WebXRLayerId)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<GL: WebXRTypes> WebXRLayerManagerAPI<GL> for WebXRBridgeManager {
|
||||||
|
fn create_layer(
|
||||||
|
&mut self,
|
||||||
|
_: &mut GL::Device,
|
||||||
|
_: &mut dyn WebXRContexts<GL>,
|
||||||
|
context_id: WebXRContextId,
|
||||||
|
init: WebXRLayerInit,
|
||||||
|
) -> Result<WebXRLayerId, WebXRError> {
|
||||||
|
let (sender, receiver) = webgl_channel().ok_or(WebXRError::CommunicationError)?;
|
||||||
|
let _ = self
|
||||||
|
.sender
|
||||||
|
.send(WebGLMsg::WebXRCommand(WebXRCommand::CreateLayer(
|
||||||
|
self.manager_id,
|
||||||
|
context_id,
|
||||||
|
init,
|
||||||
|
sender,
|
||||||
|
)));
|
||||||
|
let layer_id = receiver
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| WebXRError::CommunicationError)??;
|
||||||
|
self.layers.push((context_id, layer_id));
|
||||||
|
Ok(layer_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy_layer(
|
||||||
|
&mut self,
|
||||||
|
_: &mut GL::Device,
|
||||||
|
_: &mut dyn WebXRContexts<GL>,
|
||||||
|
context_id: WebXRContextId,
|
||||||
|
layer_id: WebXRLayerId,
|
||||||
|
) {
|
||||||
|
self.layers.retain(|&ids| ids != (context_id, layer_id));
|
||||||
|
let _ = self
|
||||||
|
.sender
|
||||||
|
.send(WebGLMsg::WebXRCommand(WebXRCommand::DestroyLayer(
|
||||||
|
self.manager_id,
|
||||||
|
context_id,
|
||||||
|
layer_id,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layers(&self) -> &[(WebXRContextId, WebXRLayerId)] {
|
||||||
|
&self.layers[..]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_frame(
|
||||||
|
&mut self,
|
||||||
|
_: &mut GL::Device,
|
||||||
|
_: &mut dyn WebXRContexts<GL>,
|
||||||
|
layers: &[(WebXRContextId, WebXRLayerId)],
|
||||||
|
) -> Result<Vec<WebXRSubImages>, WebXRError> {
|
||||||
|
let (sender, receiver) = webgl_channel().ok_or(WebXRError::CommunicationError)?;
|
||||||
|
let _ = self
|
||||||
|
.sender
|
||||||
|
.send(WebGLMsg::WebXRCommand(WebXRCommand::BeginFrame(
|
||||||
|
self.manager_id,
|
||||||
|
layers.to_vec(),
|
||||||
|
sender,
|
||||||
|
)));
|
||||||
|
receiver
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| WebXRError::CommunicationError)?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_frame(
|
||||||
|
&mut self,
|
||||||
|
_: &mut GL::Device,
|
||||||
|
_: &mut dyn WebXRContexts<GL>,
|
||||||
|
layers: &[(WebXRContextId, WebXRLayerId)],
|
||||||
|
) -> Result<(), WebXRError> {
|
||||||
|
let (sender, receiver) = webgl_channel().ok_or(WebXRError::CommunicationError)?;
|
||||||
|
let _ = self
|
||||||
|
.sender
|
||||||
|
.send(WebGLMsg::WebXRCommand(WebXRCommand::EndFrame(
|
||||||
|
self.manager_id,
|
||||||
|
layers.to_vec(),
|
||||||
|
sender,
|
||||||
|
)));
|
||||||
|
receiver
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| WebXRError::CommunicationError)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for WebXRBridgeManager {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self
|
||||||
|
.sender
|
||||||
|
.send(WebGLMsg::WebXRCommand(WebXRCommand::DestroyLayerManager(
|
||||||
|
self.manager_id,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct WebXRBridgeContexts<'a> {
|
||||||
|
pub(crate) contexts: &'a mut FnvHashMap<WebGLContextId, GLContextData>,
|
||||||
|
pub(crate) bound_context_id: &'a mut Option<WebGLContextId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> WebXRContexts<WebXRSurfman> for WebXRBridgeContexts<'a> {
|
||||||
|
fn context(&mut self, device: &Device, context_id: WebXRContextId) -> Option<&mut Context> {
|
||||||
|
let data = WebGLThread::make_current_if_needed_mut(
|
||||||
|
device,
|
||||||
|
WebGLContextId::from(context_id),
|
||||||
|
self.contexts,
|
||||||
|
self.bound_context_id,
|
||||||
|
)?;
|
||||||
|
Some(&mut data.ctx)
|
||||||
|
}
|
||||||
|
fn bindings(&mut self, device: &Device, context_id: WebXRContextId) -> Option<&glow::Context> {
|
||||||
|
let data = WebGLThread::make_current_if_needed(
|
||||||
|
device,
|
||||||
|
WebGLContextId::from(context_id),
|
||||||
|
self.contexts,
|
||||||
|
self.bound_context_id,
|
||||||
|
)?;
|
||||||
|
Some(&data.glow)
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ path = "lib.rs"
|
||||||
default = []
|
default = []
|
||||||
multiview = []
|
multiview = []
|
||||||
tracing = ["dep:tracing"]
|
tracing = ["dep:tracing"]
|
||||||
|
webxr = ["dep:webxr"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base = { workspace = true }
|
base = { workspace = true }
|
||||||
|
@ -46,7 +47,7 @@ tracing = { workspace = true, optional = true }
|
||||||
webrender = { workspace = true }
|
webrender = { workspace = true }
|
||||||
webrender_api = { workspace = true }
|
webrender_api = { workspace = true }
|
||||||
webrender_traits = { workspace = true }
|
webrender_traits = { workspace = true }
|
||||||
webxr = { workspace = true }
|
webxr = { workspace = true, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
surfman = { workspace = true }
|
surfman = { workspace = true }
|
||||||
|
|
|
@ -169,6 +169,7 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
|
||||||
/// The GL bindings for webrender
|
/// The GL bindings for webrender
|
||||||
webrender_gl: Rc<dyn gleam::gl::Gl>,
|
webrender_gl: Rc<dyn gleam::gl::Gl>,
|
||||||
|
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
/// Some XR devices want to run on the main thread.
|
/// Some XR devices want to run on the main thread.
|
||||||
pub webxr_main_thread: webxr::MainThreadRegistry,
|
pub webxr_main_thread: webxr::MainThreadRegistry,
|
||||||
|
|
||||||
|
@ -409,6 +410,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
||||||
webrender_api: state.webrender_api,
|
webrender_api: state.webrender_api,
|
||||||
rendering_context: state.rendering_context,
|
rendering_context: state.rendering_context,
|
||||||
webrender_gl: state.webrender_gl,
|
webrender_gl: state.webrender_gl,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
webxr_main_thread: state.webxr_main_thread,
|
webxr_main_thread: state.webxr_main_thread,
|
||||||
pending_paint_metrics: HashMap::new(),
|
pending_paint_metrics: HashMap::new(),
|
||||||
cursor: Cursor::None,
|
cursor: Cursor::None,
|
||||||
|
@ -1803,7 +1805,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
||||||
pipeline_ids.push(*pipeline_id);
|
pipeline_ids.push(*pipeline_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let animation_state = if pipeline_ids.is_empty() && !self.webxr_main_thread.running() {
|
#[cfg(feature = "webxr")]
|
||||||
|
let webxr_running = self.webxr_main_thread.running();
|
||||||
|
#[cfg(not(feature = "webxr"))]
|
||||||
|
let webxr_running = false;
|
||||||
|
let animation_state = if pipeline_ids.is_empty() && webxr_running {
|
||||||
windowing::AnimationState::Idle
|
windowing::AnimationState::Idle
|
||||||
} else {
|
} else {
|
||||||
windowing::AnimationState::Animating
|
windowing::AnimationState::Animating
|
||||||
|
@ -2395,6 +2401,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
||||||
CompositionRequest::CompositeNow(_) => self.composite(),
|
CompositionRequest::CompositeNow(_) => self.composite(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
// Run the WebXR main thread
|
// Run the WebXR main thread
|
||||||
self.webxr_main_thread.run_one_frame();
|
self.webxr_main_thread.run_one_frame();
|
||||||
|
|
||||||
|
|
|
@ -42,5 +42,6 @@ pub struct InitialCompositorState {
|
||||||
pub webrender_api: RenderApi,
|
pub webrender_api: RenderApi,
|
||||||
pub rendering_context: RenderingContext,
|
pub rendering_context: RenderingContext,
|
||||||
pub webrender_gl: Rc<dyn gleam::gl::Gl>,
|
pub webrender_gl: Rc<dyn gleam::gl::Gl>,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
pub webxr_main_thread: webxr::MainThreadRegistry,
|
pub webxr_main_thread: webxr::MainThreadRegistry,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::fmt::{Debug, Error, Formatter};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use base::id::{PipelineId, TopLevelBrowsingContextId};
|
use base::id::{PipelineId, TopLevelBrowsingContextId};
|
||||||
use embedder_traits::{EmbedderProxy, EventLoopWaker};
|
use embedder_traits::EventLoopWaker;
|
||||||
use euclid::Scale;
|
use euclid::Scale;
|
||||||
use keyboard_types::KeyboardEvent;
|
use keyboard_types::KeyboardEvent;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
|
@ -219,8 +219,14 @@ pub trait EmbedderMethods {
|
||||||
/// Returns a thread-safe object to wake up the window's event loop.
|
/// Returns a thread-safe object to wake up the window's event loop.
|
||||||
fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker>;
|
fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker>;
|
||||||
|
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
/// Register services with a WebXR Registry.
|
/// Register services with a WebXR Registry.
|
||||||
fn register_webxr(&mut self, _: &mut webxr::MainThreadRegistry, _: EmbedderProxy) {}
|
fn register_webxr(
|
||||||
|
&mut self,
|
||||||
|
_: &mut webxr::MainThreadRegistry,
|
||||||
|
_: embedder_traits::EmbedderProxy,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the user agent string to report in network requests.
|
/// Returns the user agent string to report in network requests.
|
||||||
fn get_user_agent_string(&self) -> Option<String> {
|
fn get_user_agent_string(&self) -> Option<String> {
|
||||||
|
|
|
@ -455,7 +455,7 @@ pub struct Constellation<STF, SWF> {
|
||||||
webgl_threads: Option<WebGLThreads>,
|
webgl_threads: Option<WebGLThreads>,
|
||||||
|
|
||||||
/// The XR device registry
|
/// The XR device registry
|
||||||
webxr_registry: webxr_api::Registry,
|
webxr_registry: Option<webxr_api::Registry>,
|
||||||
|
|
||||||
/// A channel through which messages can be sent to the canvas paint thread.
|
/// A channel through which messages can be sent to the canvas paint thread.
|
||||||
canvas_sender: Sender<ConstellationCanvasMsg>,
|
canvas_sender: Sender<ConstellationCanvasMsg>,
|
||||||
|
@ -533,7 +533,7 @@ pub struct InitialConstellationState {
|
||||||
pub webgl_threads: Option<WebGLThreads>,
|
pub webgl_threads: Option<WebGLThreads>,
|
||||||
|
|
||||||
/// The XR device registry
|
/// The XR device registry
|
||||||
pub webxr_registry: webxr_api::Registry,
|
pub webxr_registry: Option<webxr_api::Registry>,
|
||||||
|
|
||||||
pub glplayer_threads: Option<GLPlayerThreads>,
|
pub glplayer_threads: Option<GLPlayerThreads>,
|
||||||
|
|
||||||
|
|
|
@ -191,7 +191,7 @@ pub struct InitialPipelineState {
|
||||||
pub webgl_chan: Option<WebGLPipeline>,
|
pub webgl_chan: Option<WebGLPipeline>,
|
||||||
|
|
||||||
/// The XR device registry
|
/// The XR device registry
|
||||||
pub webxr_registry: webxr_api::Registry,
|
pub webxr_registry: Option<webxr_api::Registry>,
|
||||||
|
|
||||||
/// Application window's GL Context for Media player
|
/// Application window's GL Context for Media player
|
||||||
pub player_context: WindowGLContext,
|
pub player_context: WindowGLContext,
|
||||||
|
@ -496,7 +496,7 @@ pub struct UnprivilegedPipelineContent {
|
||||||
cross_process_compositor_api: CrossProcessCompositorApi,
|
cross_process_compositor_api: CrossProcessCompositorApi,
|
||||||
webrender_document: DocumentId,
|
webrender_document: DocumentId,
|
||||||
webgl_chan: Option<WebGLPipeline>,
|
webgl_chan: Option<WebGLPipeline>,
|
||||||
webxr_registry: webxr_api::Registry,
|
webxr_registry: Option<webxr_api::Registry>,
|
||||||
player_context: WindowGLContext,
|
player_context: WindowGLContext,
|
||||||
user_agent: Cow<'static, str>,
|
user_agent: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,7 +287,7 @@ pub struct Window {
|
||||||
|
|
||||||
#[ignore_malloc_size_of = "defined in webxr"]
|
#[ignore_malloc_size_of = "defined in webxr"]
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
webxr_registry: webxr_api::Registry,
|
webxr_registry: Option<webxr_api::Registry>,
|
||||||
|
|
||||||
/// All of the elements that have an outstanding image request that was
|
/// All of the elements that have an outstanding image request that was
|
||||||
/// initiated by layout during a reflow. They are stored in the script thread
|
/// initiated by layout during a reflow. They are stored in the script thread
|
||||||
|
@ -495,7 +495,7 @@ impl Window {
|
||||||
.map(|chan| WebGLCommandSender::new(chan.clone()))
|
.map(|chan| WebGLCommandSender::new(chan.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webxr_registry(&self) -> webxr_api::Registry {
|
pub fn webxr_registry(&self) -> Option<webxr_api::Registry> {
|
||||||
self.webxr_registry.clone()
|
self.webxr_registry.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2579,7 +2579,7 @@ impl Window {
|
||||||
creator_url: ServoUrl,
|
creator_url: ServoUrl,
|
||||||
navigation_start: CrossProcessInstant,
|
navigation_start: CrossProcessInstant,
|
||||||
webgl_chan: Option<WebGLChan>,
|
webgl_chan: Option<WebGLChan>,
|
||||||
webxr_registry: webxr_api::Registry,
|
webxr_registry: Option<webxr_api::Registry>,
|
||||||
microtask_queue: Rc<MicrotaskQueue>,
|
microtask_queue: Rc<MicrotaskQueue>,
|
||||||
webrender_document: DocumentId,
|
webrender_document: DocumentId,
|
||||||
compositor_api: CrossProcessCompositorApi,
|
compositor_api: CrossProcessCompositorApi,
|
||||||
|
|
|
@ -147,9 +147,9 @@ impl XRSystemMethods for XRSystem {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
window
|
if let Some(mut r) = window.webxr_registry() {
|
||||||
.webxr_registry()
|
r.supports_session(mode.into(), sender);
|
||||||
.supports_session(mode.into(), sender);
|
}
|
||||||
|
|
||||||
promise
|
promise
|
||||||
}
|
}
|
||||||
|
@ -265,9 +265,9 @@ impl XRSystemMethods for XRSystem {
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
window
|
if let Some(mut r) = window.webxr_registry() {
|
||||||
.webxr_registry()
|
r.request_session(mode.into(), init, sender, frame_sender);
|
||||||
.request_session(mode.into(), init, sender, frame_sender);
|
}
|
||||||
promise
|
promise
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,9 +175,9 @@ impl XRTestMethods for XRTest {
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
window
|
if let Some(mut r) = window.webxr_registry() {
|
||||||
.webxr_registry()
|
r.simulate_device_connection(init, sender);
|
||||||
.simulate_device_connection(init, sender);
|
}
|
||||||
|
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
|
@ -669,7 +669,7 @@ pub struct ScriptThread {
|
||||||
|
|
||||||
/// The WebXR device registry
|
/// The WebXR device registry
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
webxr_registry: webxr_api::Registry,
|
webxr_registry: Option<webxr_api::Registry>,
|
||||||
|
|
||||||
/// The worklet thread pool
|
/// The worklet thread pool
|
||||||
worklet_thread_pool: DomRefCell<Option<Rc<WorkletThreadPool>>>,
|
worklet_thread_pool: DomRefCell<Option<Rc<WorkletThreadPool>>>,
|
||||||
|
|
|
@ -31,6 +31,13 @@ webgl_backtrace = [
|
||||||
"canvas/webgl_backtrace",
|
"canvas/webgl_backtrace",
|
||||||
"canvas_traits/webgl_backtrace",
|
"canvas_traits/webgl_backtrace",
|
||||||
]
|
]
|
||||||
|
webxr = [
|
||||||
|
"dep:webxr",
|
||||||
|
"dep:webxr-api",
|
||||||
|
"compositing/webxr",
|
||||||
|
"embedder_traits/webxr",
|
||||||
|
"canvas/webxr",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
background_hang_monitor = { path = "../background_hang_monitor" }
|
background_hang_monitor = { path = "../background_hang_monitor" }
|
||||||
|
@ -82,8 +89,8 @@ webgpu = { path = "../webgpu" }
|
||||||
webrender = { workspace = true }
|
webrender = { workspace = true }
|
||||||
webrender_api = { workspace = true }
|
webrender_api = { workspace = true }
|
||||||
webrender_traits = { workspace = true }
|
webrender_traits = { workspace = true }
|
||||||
webxr = { workspace = true }
|
webxr = { workspace = true, optional = true }
|
||||||
webxr-api = { workspace = true }
|
webxr-api = { workspace = true, optional = true }
|
||||||
|
|
||||||
[target.'cfg(all(not(target_os = "windows"), not(target_os = "ios"), not(target_os = "android"), not(target_arch = "arm"), not(target_arch = "aarch64")))'.dependencies]
|
[target.'cfg(all(not(target_os = "windows"), not(target_os = "ios"), not(target_os = "android"), not(target_arch = "arm"), not(target_arch = "aarch64")))'.dependencies]
|
||||||
gaol = "0.2.1"
|
gaol = "0.2.1"
|
||||||
|
|
|
@ -396,6 +396,7 @@ where
|
||||||
|
|
||||||
let WebGLComm {
|
let WebGLComm {
|
||||||
webgl_threads,
|
webgl_threads,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
webxr_layer_grand_manager,
|
webxr_layer_grand_manager,
|
||||||
image_handler,
|
image_handler,
|
||||||
} = WebGLComm::new(
|
} = WebGLComm::new(
|
||||||
|
@ -410,9 +411,11 @@ where
|
||||||
external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL);
|
external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL);
|
||||||
|
|
||||||
// Create the WebXR main thread
|
// Create the WebXR main thread
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
let mut webxr_main_thread =
|
let mut webxr_main_thread =
|
||||||
webxr::MainThreadRegistry::new(event_loop_waker, webxr_layer_grand_manager)
|
webxr::MainThreadRegistry::new(event_loop_waker, webxr_layer_grand_manager)
|
||||||
.expect("Failed to create WebXR device registry");
|
.expect("Failed to create WebXR device registry");
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
if pref!(dom.webxr.enabled) {
|
if pref!(dom.webxr.enabled) {
|
||||||
embedder.register_webxr(&mut webxr_main_thread, embedder_proxy.clone());
|
embedder.register_webxr(&mut webxr_main_thread, embedder_proxy.clone());
|
||||||
}
|
}
|
||||||
|
@ -454,6 +457,7 @@ where
|
||||||
devtools_sender,
|
devtools_sender,
|
||||||
webrender_document,
|
webrender_document,
|
||||||
webrender_api_sender,
|
webrender_api_sender,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
webxr_main_thread.registry(),
|
webxr_main_thread.registry(),
|
||||||
player_context,
|
player_context,
|
||||||
Some(webgl_threads),
|
Some(webgl_threads),
|
||||||
|
@ -491,6 +495,7 @@ where
|
||||||
webrender_api,
|
webrender_api,
|
||||||
rendering_context,
|
rendering_context,
|
||||||
webrender_gl,
|
webrender_gl,
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
webxr_main_thread,
|
webxr_main_thread,
|
||||||
},
|
},
|
||||||
composite_target,
|
composite_target,
|
||||||
|
@ -1033,7 +1038,7 @@ fn create_constellation(
|
||||||
devtools_sender: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
|
devtools_sender: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
|
||||||
webrender_document: DocumentId,
|
webrender_document: DocumentId,
|
||||||
webrender_api_sender: RenderApiSender,
|
webrender_api_sender: RenderApiSender,
|
||||||
webxr_registry: webxr_api::Registry,
|
#[cfg(feature = "webxr")] webxr_registry: webxr_api::Registry,
|
||||||
player_context: WindowGLContext,
|
player_context: WindowGLContext,
|
||||||
webgl_threads: Option<WebGLThreads>,
|
webgl_threads: Option<WebGLThreads>,
|
||||||
glplayer_threads: Option<GLPlayerThreads>,
|
glplayer_threads: Option<GLPlayerThreads>,
|
||||||
|
@ -1082,7 +1087,10 @@ fn create_constellation(
|
||||||
mem_profiler_chan,
|
mem_profiler_chan,
|
||||||
webrender_document,
|
webrender_document,
|
||||||
webrender_api_sender,
|
webrender_api_sender,
|
||||||
webxr_registry,
|
#[cfg(feature = "webxr")]
|
||||||
|
webxr_registry: Some(webxr_registry),
|
||||||
|
#[cfg(not(feature = "webxr"))]
|
||||||
|
webxr_registry: None,
|
||||||
webgl_threads,
|
webgl_threads,
|
||||||
glplayer_threads,
|
glplayer_threads,
|
||||||
player_context,
|
player_context,
|
||||||
|
|
|
@ -11,6 +11,9 @@ rust-version.workspace = true
|
||||||
name = "embedder_traits"
|
name = "embedder_traits"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
webxr = ["dep:webxr-api"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base = { workspace = true }
|
base = { workspace = true }
|
||||||
cfg-if = { workspace = true }
|
cfg-if = { workspace = true }
|
||||||
|
@ -23,4 +26,4 @@ num-traits = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
servo_url = { path = "../../url" }
|
servo_url = { path = "../../url" }
|
||||||
webrender_api = { workspace = true }
|
webrender_api = { workspace = true }
|
||||||
webxr-api = { workspace = true, features = ["ipc"] }
|
webxr-api = { workspace = true, features = ["ipc"], optional = true }
|
||||||
|
|
|
@ -15,7 +15,6 @@ use num_derive::FromPrimitive;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
||||||
pub use webxr_api::MainThreadWaker as EventLoopWaker;
|
|
||||||
|
|
||||||
/// A cursor for the window. This is different from a CSS cursor (see
|
/// A cursor for the window. This is different from a CSS cursor (see
|
||||||
/// `CursorKind`) in that it has no `Auto` value.
|
/// `CursorKind`) in that it has no `Auto` value.
|
||||||
|
@ -59,6 +58,21 @@ pub enum Cursor {
|
||||||
ZoomOut,
|
ZoomOut,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "webxr")]
|
||||||
|
pub use webxr_api::MainThreadWaker as EventLoopWaker;
|
||||||
|
#[cfg(not(feature = "webxr"))]
|
||||||
|
pub trait EventLoopWaker: 'static + Send {
|
||||||
|
fn clone_box(&self) -> Box<dyn EventLoopWaker>;
|
||||||
|
fn wake(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "webxr"))]
|
||||||
|
impl Clone for Box<dyn EventLoopWaker> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
EventLoopWaker::clone_box(self.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sends messages to the embedder.
|
/// Sends messages to the embedder.
|
||||||
pub struct EmbedderProxy {
|
pub struct EmbedderProxy {
|
||||||
pub sender: Sender<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
|
pub sender: Sender<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
|
||||||
|
|
|
@ -658,7 +658,7 @@ pub struct InitialScriptState {
|
||||||
/// A channel to the WebGL thread used in this pipeline.
|
/// A channel to the WebGL thread used in this pipeline.
|
||||||
pub webgl_chan: Option<WebGLPipeline>,
|
pub webgl_chan: Option<WebGLPipeline>,
|
||||||
/// The XR device registry
|
/// The XR device registry
|
||||||
pub webxr_registry: webxr_api::Registry,
|
pub webxr_registry: Option<webxr_api::Registry>,
|
||||||
/// The Webrender document ID associated with this thread.
|
/// The Webrender document ID associated with this thread.
|
||||||
pub webrender_document: DocumentId,
|
pub webrender_document: DocumentId,
|
||||||
/// Access to the compositor across a process boundary.
|
/// Access to the compositor across a process boundary.
|
||||||
|
|
|
@ -39,7 +39,7 @@ ProductName = "Servo"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debugmozjs = ["libservo/debugmozjs"]
|
debugmozjs = ["libservo/debugmozjs"]
|
||||||
default = ["layout_2013", "max_log_level", "webdriver"]
|
default = ["layout_2013", "max_log_level", "webdriver", "libservo/webxr"]
|
||||||
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"]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue