diff options
Diffstat (limited to 'components/shared/webxr/layer.rs')
-rw-r--r-- | components/shared/webxr/layer.rs | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/components/shared/webxr/layer.rs b/components/shared/webxr/layer.rs new file mode 100644 index 00000000000..b0a607f290f --- /dev/null +++ b/components/shared/webxr/layer.rs @@ -0,0 +1,296 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::Error; +use crate::Viewport; +use crate::Viewports; + +use euclid::Rect; +use euclid::Size2D; + +use std::fmt::Debug; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] +pub struct ContextId(pub u64); + +#[cfg(feature = "ipc")] +use serde::{Deserialize, Serialize}; + +pub trait GLTypes { + type Device; + type Context; + type Bindings; +} + +pub trait GLContexts<GL: GLTypes> { + fn bindings(&mut self, device: &GL::Device, context_id: ContextId) -> Option<&GL::Bindings>; + fn context(&mut self, device: &GL::Device, context_id: ContextId) -> Option<&mut GL::Context>; +} + +impl GLTypes for () { + type Bindings = (); + type Device = (); + type Context = (); +} + +impl GLContexts<()> for () { + fn context(&mut self, _: &(), _: ContextId) -> Option<&mut ()> { + Some(self) + } + + fn bindings(&mut self, _: &(), _: ContextId) -> Option<&()> { + Some(self) + } +} + +pub trait LayerGrandManagerAPI<GL: GLTypes> { + fn create_layer_manager(&self, factory: LayerManagerFactory<GL>) + -> Result<LayerManager, Error>; + + fn clone_layer_grand_manager(&self) -> LayerGrandManager<GL>; +} + +pub struct LayerGrandManager<GL>(Box<dyn Send + LayerGrandManagerAPI<GL>>); + +impl<GL: GLTypes> Clone for LayerGrandManager<GL> { + fn clone(&self) -> Self { + self.0.clone_layer_grand_manager() + } +} + +impl<GL> Debug for LayerGrandManager<GL> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + "LayerGrandManager(...)".fmt(fmt) + } +} + +impl<GL: GLTypes> LayerGrandManager<GL> { + pub fn new<GM>(grand_manager: GM) -> LayerGrandManager<GL> + where + GM: 'static + Send + LayerGrandManagerAPI<GL>, + { + LayerGrandManager(Box::new(grand_manager)) + } + + pub fn create_layer_manager<F, M>(&self, factory: F) -> Result<LayerManager, Error> + where + F: 'static + Send + FnOnce(&mut GL::Device, &mut dyn GLContexts<GL>) -> Result<M, Error>, + M: 'static + LayerManagerAPI<GL>, + { + self.0 + .create_layer_manager(LayerManagerFactory::new(factory)) + } +} + +pub trait LayerManagerAPI<GL: GLTypes> { + fn create_layer( + &mut self, + device: &mut GL::Device, + contexts: &mut dyn GLContexts<GL>, + context_id: ContextId, + init: LayerInit, + ) -> Result<LayerId, Error>; + + fn destroy_layer( + &mut self, + device: &mut GL::Device, + contexts: &mut dyn GLContexts<GL>, + context_id: ContextId, + layer_id: LayerId, + ); + + fn layers(&self) -> &[(ContextId, LayerId)]; + + fn begin_frame( + &mut self, + device: &mut GL::Device, + contexts: &mut dyn GLContexts<GL>, + layers: &[(ContextId, LayerId)], + ) -> Result<Vec<SubImages>, Error>; + + fn end_frame( + &mut self, + device: &mut GL::Device, + contexts: &mut dyn GLContexts<GL>, + layers: &[(ContextId, LayerId)], + ) -> Result<(), Error>; +} + +pub struct LayerManager(Box<dyn Send + LayerManagerAPI<()>>); + +impl Debug for LayerManager { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + "LayerManager(...)".fmt(fmt) + } +} + +impl LayerManager { + pub fn create_layer( + &mut self, + context_id: ContextId, + init: LayerInit, + ) -> Result<LayerId, Error> { + self.0.create_layer(&mut (), &mut (), context_id, init) + } + + pub fn destroy_layer(&mut self, context_id: ContextId, layer_id: LayerId) { + self.0.destroy_layer(&mut (), &mut (), context_id, layer_id); + } + + pub fn begin_frame( + &mut self, + layers: &[(ContextId, LayerId)], + ) -> Result<Vec<SubImages>, Error> { + self.0.begin_frame(&mut (), &mut (), layers) + } + + pub fn end_frame(&mut self, layers: &[(ContextId, LayerId)]) -> Result<(), Error> { + self.0.end_frame(&mut (), &mut (), layers) + } +} + +impl LayerManager { + pub fn new<M>(manager: M) -> LayerManager + where + M: 'static + Send + LayerManagerAPI<()>, + { + LayerManager(Box::new(manager)) + } +} + +impl Drop for LayerManager { + fn drop(&mut self) { + log::debug!("Dropping LayerManager"); + for (context_id, layer_id) in self.0.layers().to_vec() { + self.destroy_layer(context_id, layer_id); + } + } +} + +pub struct LayerManagerFactory<GL: GLTypes>( + Box< + dyn Send + + FnOnce( + &mut GL::Device, + &mut dyn GLContexts<GL>, + ) -> Result<Box<dyn LayerManagerAPI<GL>>, Error>, + >, +); + +impl<GL: GLTypes> Debug for LayerManagerFactory<GL> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + "LayerManagerFactory(...)".fmt(fmt) + } +} + +impl<GL: GLTypes> LayerManagerFactory<GL> { + pub fn new<F, M>(factory: F) -> LayerManagerFactory<GL> + where + F: 'static + Send + FnOnce(&mut GL::Device, &mut dyn GLContexts<GL>) -> Result<M, Error>, + M: 'static + LayerManagerAPI<GL>, + { + LayerManagerFactory(Box::new(move |device, contexts| { + Ok(Box::new(factory(device, contexts)?)) + })) + } + + pub fn build( + self, + device: &mut GL::Device, + contexts: &mut dyn GLContexts<GL>, + ) -> Result<Box<dyn LayerManagerAPI<GL>>, Error> { + (self.0)(device, contexts) + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] +pub struct LayerId(usize); + +static NEXT_LAYER_ID: AtomicUsize = AtomicUsize::new(0); + +impl LayerId { + pub fn new() -> LayerId { + LayerId(NEXT_LAYER_ID.fetch_add(1, Ordering::SeqCst)) + } +} + +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] +pub enum LayerInit { + // https://www.w3.org/TR/webxr/#dictdef-xrwebgllayerinit + WebGLLayer { + antialias: bool, + depth: bool, + stencil: bool, + alpha: bool, + ignore_depth_values: bool, + framebuffer_scale_factor: f32, + }, + // https://immersive-web.github.io/layers/#xrprojectionlayerinittype + ProjectionLayer { + depth: bool, + stencil: bool, + alpha: bool, + scale_factor: f32, + }, + // TODO: other layer types +} + +impl LayerInit { + pub fn texture_size(&self, viewports: &Viewports) -> Size2D<i32, Viewport> { + match self { + LayerInit::WebGLLayer { + framebuffer_scale_factor: scale, + .. + } + | LayerInit::ProjectionLayer { + scale_factor: scale, + .. + } => { + let native_size = viewports + .viewports + .iter() + .fold(Rect::zero(), |acc, view| acc.union(view)) + .size; + (native_size.to_f32() * *scale).to_i32() + } + } + } +} + +/// https://immersive-web.github.io/layers/#enumdef-xrlayerlayout +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] +pub enum LayerLayout { + // TODO: Default + // Allocates one texture + Mono, + // Allocates one texture, which is split in half vertically, giving two subimages + StereoLeftRight, + // Allocates one texture, which is split in half horizonally, giving two subimages + StereoTopBottom, +} + +#[derive(Clone, Debug)] +#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] +pub struct SubImages { + pub layer_id: LayerId, + pub sub_image: Option<SubImage>, + pub view_sub_images: Vec<SubImage>, +} + +/// https://immersive-web.github.io/layers/#xrsubimagetype +#[derive(Clone, Debug)] +#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] +pub struct SubImage { + pub color_texture: u32, + // TODO: make this Option<NonZeroU32> + pub depth_stencil_texture: Option<u32>, + pub texture_array_index: Option<u32>, + pub viewport: Rect<i32, Viewport>, +} |