mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00: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]
|
||||
webgl_backtrace = ["canvas_traits/webgl_backtrace"]
|
||||
webxr = ["dep:webxr", "dep:webxr-api"]
|
||||
|
||||
[dependencies]
|
||||
app_units = { workspace = true }
|
||||
|
@ -46,5 +47,5 @@ unicode-script = { workspace = true }
|
|||
webrender = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
webrender_traits = { workspace = true }
|
||||
webxr = { workspace = true, features = ["ipc"] }
|
||||
webxr-api = { workspace = true, features = ["ipc"] }
|
||||
webxr = { workspace = true, features = ["ipc"], optional = true }
|
||||
webxr-api = { workspace = true, features = ["ipc"], optional = true }
|
||||
|
|
|
@ -13,3 +13,5 @@ pub mod canvas_paint_thread;
|
|||
mod webgl_limits;
|
||||
mod webgl_mode;
|
||||
pub mod webgl_thread;
|
||||
#[cfg(feature = "webxr")]
|
||||
mod webxr;
|
||||
|
|
|
@ -17,14 +17,17 @@ use webrender_traits::{
|
|||
RenderingContext, WebrenderExternalImageApi, WebrenderExternalImageRegistry,
|
||||
WebrenderImageSource,
|
||||
};
|
||||
#[cfg(feature = "webxr")]
|
||||
use webxr::SurfmanGL as WebXRSurfman;
|
||||
#[cfg(feature = "webxr")]
|
||||
use webxr_api::LayerGrandManager as WebXRLayerGrandManager;
|
||||
|
||||
use crate::webgl_thread::{WebGLThread, WebGLThreadInit, WebXRBridgeInit};
|
||||
use crate::webgl_thread::{WebGLThread, WebGLThreadInit};
|
||||
|
||||
pub struct WebGLComm {
|
||||
pub webgl_threads: WebGLThreads,
|
||||
pub image_handler: Box<dyn WebrenderExternalImageApi>,
|
||||
#[cfg(feature = "webxr")]
|
||||
pub webxr_layer_grand_manager: WebXRLayerGrandManager<WebXRSurfman>,
|
||||
}
|
||||
|
||||
|
@ -40,7 +43,9 @@ impl WebGLComm {
|
|||
debug!("WebGLThreads::new()");
|
||||
let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap();
|
||||
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();
|
||||
|
||||
// This implementation creates a single `WebGLThread` for all the pipelines.
|
||||
|
@ -54,6 +59,7 @@ impl WebGLComm {
|
|||
connection: surfman.connection(),
|
||||
adapter: surfman.adapter(),
|
||||
api_type,
|
||||
#[cfg(feature = "webxr")]
|
||||
webxr_init,
|
||||
};
|
||||
|
||||
|
@ -64,6 +70,7 @@ impl WebGLComm {
|
|||
WebGLComm {
|
||||
webgl_threads: WebGLThreads(sender),
|
||||
image_handler: Box::new(external),
|
||||
#[cfg(feature = "webxr")]
|
||||
webxr_layer_grand_manager,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{slice, thread};
|
||||
|
@ -11,14 +10,16 @@ use std::{slice, thread};
|
|||
use bitflags::bitflags;
|
||||
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
|
||||
use canvas_traits::webgl;
|
||||
#[cfg(feature = "webxr")]
|
||||
use canvas_traits::webgl::WebXRCommand;
|
||||
use canvas_traits::webgl::{
|
||||
webgl_channel, ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, AlphaTreatment,
|
||||
ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, AlphaTreatment,
|
||||
GLContextAttributes, GLLimits, GlType, InternalFormatIntVec, ProgramLinkInfo, TexDataType,
|
||||
TexFormat, WebGLBufferId, WebGLChan, WebGLCommand, WebGLCommandBacktrace, WebGLContextId,
|
||||
WebGLCreateContextResult, WebGLFramebufferBindingRequest, WebGLFramebufferId, WebGLMsg,
|
||||
WebGLMsgSender, WebGLProgramId, WebGLQueryId, WebGLReceiver, WebGLRenderbufferId,
|
||||
WebGLSLVersion, WebGLSamplerId, WebGLSender, WebGLShaderId, WebGLSyncId, WebGLTextureId,
|
||||
WebGLVersion, WebGLVertexArrayId, WebXRCommand, WebXRLayerManagerId, YAxisTreatment,
|
||||
WebGLVersion, WebGLVertexArrayId, YAxisTreatment,
|
||||
};
|
||||
use euclid::default::Size2D;
|
||||
use fnv::FnvHashMap;
|
||||
|
@ -39,22 +40,15 @@ use webrender_api::{
|
|||
ImageData, ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey,
|
||||
};
|
||||
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;
|
||||
#[cfg(feature = "webxr")]
|
||||
use crate::webxr::{WebXRBridge, WebXRBridgeContexts, WebXRBridgeInit};
|
||||
|
||||
struct GLContextData {
|
||||
ctx: Context,
|
||||
gl: Rc<Gl>,
|
||||
glow: glow::Context,
|
||||
pub(crate) struct GLContextData {
|
||||
pub(crate) ctx: Context,
|
||||
pub(crate) gl: Rc<Gl>,
|
||||
pub(crate) glow: glow::Context,
|
||||
state: GLState,
|
||||
attributes: GLContextAttributes,
|
||||
}
|
||||
|
@ -212,6 +206,7 @@ pub(crate) struct WebGLThread {
|
|||
webrender_swap_chains: SwapChains<WebGLContextId, Device>,
|
||||
/// Whether this context is a GL or GLES context.
|
||||
api_type: GlType,
|
||||
#[cfg(feature = "webxr")]
|
||||
/// The bridge to WebXR
|
||||
pub webxr_bridge: WebXRBridge,
|
||||
}
|
||||
|
@ -227,6 +222,7 @@ pub(crate) struct WebGLThreadInit {
|
|||
pub connection: Connection,
|
||||
pub adapter: Adapter,
|
||||
pub api_type: GlType,
|
||||
#[cfg(feature = "webxr")]
|
||||
pub webxr_init: WebXRBridgeInit,
|
||||
}
|
||||
|
||||
|
@ -246,6 +242,7 @@ impl WebGLThread {
|
|||
connection,
|
||||
adapter,
|
||||
api_type,
|
||||
#[cfg(feature = "webxr")]
|
||||
webxr_init,
|
||||
}: WebGLThreadInit,
|
||||
) -> Self {
|
||||
|
@ -263,6 +260,7 @@ impl WebGLThread {
|
|||
receiver: receiver.into_inner(),
|
||||
webrender_swap_chains,
|
||||
api_type,
|
||||
#[cfg(feature = "webxr")]
|
||||
webxr_bridge: WebXRBridge::new(webxr_init),
|
||||
}
|
||||
}
|
||||
|
@ -363,8 +361,9 @@ impl WebGLThread {
|
|||
WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => {
|
||||
self.handle_webgl_command(ctx_id, command, backtrace);
|
||||
},
|
||||
WebGLMsg::WebXRCommand(command) => {
|
||||
self.handle_webxr_command(command);
|
||||
WebGLMsg::WebXRCommand(_command) => {
|
||||
#[cfg(feature = "webxr")]
|
||||
self.handle_webxr_command(_command);
|
||||
},
|
||||
WebGLMsg::SwapBuffers(swap_ids, sender, sent_time) => {
|
||||
self.handle_swap_buffers(swap_ids, sender, sent_time);
|
||||
|
@ -380,6 +379,7 @@ impl WebGLThread {
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(feature = "webxr")]
|
||||
/// Handles a WebXR message
|
||||
fn handle_webxr_command(&mut self, command: WebXRCommand) {
|
||||
trace!("processing {:?}", command);
|
||||
|
@ -723,17 +723,20 @@ impl WebGLThread {
|
|||
&mut self.bound_context_id,
|
||||
);
|
||||
|
||||
// Destroy WebXR layers associated with this context
|
||||
let webxr_context_id = WebXRContextId::from(context_id);
|
||||
let mut webxr_contexts = WebXRBridgeContexts {
|
||||
contexts: &mut self.contexts,
|
||||
bound_context_id: &mut self.bound_context_id,
|
||||
};
|
||||
self.webxr_bridge.destroy_all_layers(
|
||||
&mut self.device,
|
||||
&mut webxr_contexts,
|
||||
webxr_context_id,
|
||||
);
|
||||
#[cfg(feature = "webxr")]
|
||||
{
|
||||
// Destroy WebXR layers associated with this context
|
||||
let webxr_context_id = webxr_api::ContextId::from(context_id);
|
||||
let mut webxr_contexts = WebXRBridgeContexts {
|
||||
contexts: &mut self.contexts,
|
||||
bound_context_id: &mut self.bound_context_id,
|
||||
};
|
||||
self.webxr_bridge.destroy_all_layers(
|
||||
&mut self.device,
|
||||
&mut webxr_contexts,
|
||||
webxr_context_id,
|
||||
);
|
||||
}
|
||||
|
||||
// Release GL context.
|
||||
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.
|
||||
fn make_current_if_needed<'a>(
|
||||
pub(crate) fn make_current_if_needed<'a>(
|
||||
device: &Device,
|
||||
context_id: WebGLContextId,
|
||||
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.
|
||||
fn make_current_if_needed_mut<'a>(
|
||||
pub(crate) fn make_current_if_needed_mut<'a>(
|
||||
device: &Device,
|
||||
context_id: WebGLContextId,
|
||||
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 = []
|
||||
multiview = []
|
||||
tracing = ["dep:tracing"]
|
||||
webxr = ["dep:webxr"]
|
||||
|
||||
[dependencies]
|
||||
base = { workspace = true }
|
||||
|
@ -46,7 +47,7 @@ tracing = { workspace = true, optional = true }
|
|||
webrender = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
webrender_traits = { workspace = true }
|
||||
webxr = { workspace = true }
|
||||
webxr = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
surfman = { workspace = true }
|
||||
|
|
|
@ -169,6 +169,7 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
|
|||
/// The GL bindings for webrender
|
||||
webrender_gl: Rc<dyn gleam::gl::Gl>,
|
||||
|
||||
#[cfg(feature = "webxr")]
|
||||
/// Some XR devices want to run on the main thread.
|
||||
pub webxr_main_thread: webxr::MainThreadRegistry,
|
||||
|
||||
|
@ -409,6 +410,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
webrender_api: state.webrender_api,
|
||||
rendering_context: state.rendering_context,
|
||||
webrender_gl: state.webrender_gl,
|
||||
#[cfg(feature = "webxr")]
|
||||
webxr_main_thread: state.webxr_main_thread,
|
||||
pending_paint_metrics: HashMap::new(),
|
||||
cursor: Cursor::None,
|
||||
|
@ -1803,7 +1805,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
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
|
||||
} else {
|
||||
windowing::AnimationState::Animating
|
||||
|
@ -2395,6 +2401,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
CompositionRequest::CompositeNow(_) => self.composite(),
|
||||
}
|
||||
|
||||
#[cfg(feature = "webxr")]
|
||||
// Run the WebXR main thread
|
||||
self.webxr_main_thread.run_one_frame();
|
||||
|
||||
|
|
|
@ -42,5 +42,6 @@ pub struct InitialCompositorState {
|
|||
pub webrender_api: RenderApi,
|
||||
pub rendering_context: RenderingContext,
|
||||
pub webrender_gl: Rc<dyn gleam::gl::Gl>,
|
||||
#[cfg(feature = "webxr")]
|
||||
pub webxr_main_thread: webxr::MainThreadRegistry,
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::fmt::{Debug, Error, Formatter};
|
|||
use std::time::Duration;
|
||||
|
||||
use base::id::{PipelineId, TopLevelBrowsingContextId};
|
||||
use embedder_traits::{EmbedderProxy, EventLoopWaker};
|
||||
use embedder_traits::EventLoopWaker;
|
||||
use euclid::Scale;
|
||||
use keyboard_types::KeyboardEvent;
|
||||
use libc::c_void;
|
||||
|
@ -219,8 +219,14 @@ pub trait EmbedderMethods {
|
|||
/// Returns a thread-safe object to wake up the window's event loop.
|
||||
fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker>;
|
||||
|
||||
#[cfg(feature = "webxr")]
|
||||
/// 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.
|
||||
fn get_user_agent_string(&self) -> Option<String> {
|
||||
|
|
|
@ -455,7 +455,7 @@ pub struct Constellation<STF, SWF> {
|
|||
webgl_threads: Option<WebGLThreads>,
|
||||
|
||||
/// 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.
|
||||
canvas_sender: Sender<ConstellationCanvasMsg>,
|
||||
|
@ -533,7 +533,7 @@ pub struct InitialConstellationState {
|
|||
pub webgl_threads: Option<WebGLThreads>,
|
||||
|
||||
/// The XR device registry
|
||||
pub webxr_registry: webxr_api::Registry,
|
||||
pub webxr_registry: Option<webxr_api::Registry>,
|
||||
|
||||
pub glplayer_threads: Option<GLPlayerThreads>,
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ pub struct InitialPipelineState {
|
|||
pub webgl_chan: Option<WebGLPipeline>,
|
||||
|
||||
/// 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
|
||||
pub player_context: WindowGLContext,
|
||||
|
@ -496,7 +496,7 @@ pub struct UnprivilegedPipelineContent {
|
|||
cross_process_compositor_api: CrossProcessCompositorApi,
|
||||
webrender_document: DocumentId,
|
||||
webgl_chan: Option<WebGLPipeline>,
|
||||
webxr_registry: webxr_api::Registry,
|
||||
webxr_registry: Option<webxr_api::Registry>,
|
||||
player_context: WindowGLContext,
|
||||
user_agent: Cow<'static, str>,
|
||||
}
|
||||
|
|
|
@ -287,7 +287,7 @@ pub struct Window {
|
|||
|
||||
#[ignore_malloc_size_of = "defined in webxr"]
|
||||
#[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
|
||||
/// 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()))
|
||||
}
|
||||
|
||||
pub fn webxr_registry(&self) -> webxr_api::Registry {
|
||||
pub fn webxr_registry(&self) -> Option<webxr_api::Registry> {
|
||||
self.webxr_registry.clone()
|
||||
}
|
||||
|
||||
|
@ -2579,7 +2579,7 @@ impl Window {
|
|||
creator_url: ServoUrl,
|
||||
navigation_start: CrossProcessInstant,
|
||||
webgl_chan: Option<WebGLChan>,
|
||||
webxr_registry: webxr_api::Registry,
|
||||
webxr_registry: Option<webxr_api::Registry>,
|
||||
microtask_queue: Rc<MicrotaskQueue>,
|
||||
webrender_document: DocumentId,
|
||||
compositor_api: CrossProcessCompositorApi,
|
||||
|
|
|
@ -147,9 +147,9 @@ impl XRSystemMethods for XRSystem {
|
|||
};
|
||||
}),
|
||||
);
|
||||
window
|
||||
.webxr_registry()
|
||||
.supports_session(mode.into(), sender);
|
||||
if let Some(mut r) = window.webxr_registry() {
|
||||
r.supports_session(mode.into(), sender);
|
||||
}
|
||||
|
||||
promise
|
||||
}
|
||||
|
@ -265,9 +265,9 @@ impl XRSystemMethods for XRSystem {
|
|||
);
|
||||
}),
|
||||
);
|
||||
window
|
||||
.webxr_registry()
|
||||
.request_session(mode.into(), init, sender, frame_sender);
|
||||
if let Some(mut r) = window.webxr_registry() {
|
||||
r.request_session(mode.into(), init, sender, frame_sender);
|
||||
}
|
||||
promise
|
||||
}
|
||||
|
||||
|
|
|
@ -175,9 +175,9 @@ impl XRTestMethods for XRTest {
|
|||
);
|
||||
}),
|
||||
);
|
||||
window
|
||||
.webxr_registry()
|
||||
.simulate_device_connection(init, sender);
|
||||
if let Some(mut r) = window.webxr_registry() {
|
||||
r.simulate_device_connection(init, sender);
|
||||
}
|
||||
|
||||
p
|
||||
}
|
||||
|
|
|
@ -669,7 +669,7 @@ pub struct ScriptThread {
|
|||
|
||||
/// The WebXR device registry
|
||||
#[no_trace]
|
||||
webxr_registry: webxr_api::Registry,
|
||||
webxr_registry: Option<webxr_api::Registry>,
|
||||
|
||||
/// The worklet thread pool
|
||||
worklet_thread_pool: DomRefCell<Option<Rc<WorkletThreadPool>>>,
|
||||
|
|
|
@ -31,6 +31,13 @@ webgl_backtrace = [
|
|||
"canvas/webgl_backtrace",
|
||||
"canvas_traits/webgl_backtrace",
|
||||
]
|
||||
webxr = [
|
||||
"dep:webxr",
|
||||
"dep:webxr-api",
|
||||
"compositing/webxr",
|
||||
"embedder_traits/webxr",
|
||||
"canvas/webxr",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
background_hang_monitor = { path = "../background_hang_monitor" }
|
||||
|
@ -82,8 +89,8 @@ webgpu = { path = "../webgpu" }
|
|||
webrender = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
webrender_traits = { workspace = true }
|
||||
webxr = { workspace = true }
|
||||
webxr-api = { workspace = true }
|
||||
webxr = { workspace = true, optional = 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]
|
||||
gaol = "0.2.1"
|
||||
|
|
|
@ -396,6 +396,7 @@ where
|
|||
|
||||
let WebGLComm {
|
||||
webgl_threads,
|
||||
#[cfg(feature = "webxr")]
|
||||
webxr_layer_grand_manager,
|
||||
image_handler,
|
||||
} = WebGLComm::new(
|
||||
|
@ -410,9 +411,11 @@ where
|
|||
external_image_handlers.set_handler(image_handler, WebrenderImageHandlerType::WebGL);
|
||||
|
||||
// Create the WebXR main thread
|
||||
#[cfg(feature = "webxr")]
|
||||
let mut webxr_main_thread =
|
||||
webxr::MainThreadRegistry::new(event_loop_waker, webxr_layer_grand_manager)
|
||||
.expect("Failed to create WebXR device registry");
|
||||
#[cfg(feature = "webxr")]
|
||||
if pref!(dom.webxr.enabled) {
|
||||
embedder.register_webxr(&mut webxr_main_thread, embedder_proxy.clone());
|
||||
}
|
||||
|
@ -454,6 +457,7 @@ where
|
|||
devtools_sender,
|
||||
webrender_document,
|
||||
webrender_api_sender,
|
||||
#[cfg(feature = "webxr")]
|
||||
webxr_main_thread.registry(),
|
||||
player_context,
|
||||
Some(webgl_threads),
|
||||
|
@ -491,6 +495,7 @@ where
|
|||
webrender_api,
|
||||
rendering_context,
|
||||
webrender_gl,
|
||||
#[cfg(feature = "webxr")]
|
||||
webxr_main_thread,
|
||||
},
|
||||
composite_target,
|
||||
|
@ -1033,7 +1038,7 @@ fn create_constellation(
|
|||
devtools_sender: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
|
||||
webrender_document: DocumentId,
|
||||
webrender_api_sender: RenderApiSender,
|
||||
webxr_registry: webxr_api::Registry,
|
||||
#[cfg(feature = "webxr")] webxr_registry: webxr_api::Registry,
|
||||
player_context: WindowGLContext,
|
||||
webgl_threads: Option<WebGLThreads>,
|
||||
glplayer_threads: Option<GLPlayerThreads>,
|
||||
|
@ -1082,7 +1087,10 @@ fn create_constellation(
|
|||
mem_profiler_chan,
|
||||
webrender_document,
|
||||
webrender_api_sender,
|
||||
webxr_registry,
|
||||
#[cfg(feature = "webxr")]
|
||||
webxr_registry: Some(webxr_registry),
|
||||
#[cfg(not(feature = "webxr"))]
|
||||
webxr_registry: None,
|
||||
webgl_threads,
|
||||
glplayer_threads,
|
||||
player_context,
|
||||
|
|
|
@ -11,6 +11,9 @@ rust-version.workspace = true
|
|||
name = "embedder_traits"
|
||||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
webxr = ["dep:webxr-api"]
|
||||
|
||||
[dependencies]
|
||||
base = { workspace = true }
|
||||
cfg-if = { workspace = true }
|
||||
|
@ -23,4 +26,4 @@ num-traits = { workspace = true }
|
|||
serde = { workspace = true }
|
||||
servo_url = { path = "../../url" }
|
||||
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 servo_url::ServoUrl;
|
||||
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
|
||||
/// `CursorKind`) in that it has no `Auto` value.
|
||||
|
@ -59,6 +58,21 @@ pub enum Cursor {
|
|||
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.
|
||||
pub struct EmbedderProxy {
|
||||
pub sender: Sender<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
|
||||
|
|
|
@ -658,7 +658,7 @@ pub struct InitialScriptState {
|
|||
/// A channel to the WebGL thread used in this pipeline.
|
||||
pub webgl_chan: Option<WebGLPipeline>,
|
||||
/// 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.
|
||||
pub webrender_document: DocumentId,
|
||||
/// Access to the compositor across a process boundary.
|
||||
|
|
|
@ -39,7 +39,7 @@ ProductName = "Servo"
|
|||
|
||||
[features]
|
||||
debugmozjs = ["libservo/debugmozjs"]
|
||||
default = ["layout_2013", "max_log_level", "webdriver"]
|
||||
default = ["layout_2013", "max_log_level", "webdriver", "libservo/webxr"]
|
||||
jitspew = ["libservo/jitspew"]
|
||||
js_backtrace = ["libservo/js_backtrace"]
|
||||
layout_2013 = ["libservo/layout_2013"]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue