webxr_api/
layer.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::fmt::Debug;
6use std::num::NonZeroU32;
7use std::sync::atomic::{AtomicUsize, Ordering};
8
9use euclid::{Rect, Size2D};
10
11use crate::{Error, Viewport, Viewports};
12
13#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
15pub struct ContextId(pub u64);
16
17#[cfg(feature = "ipc")]
18use serde::{Deserialize, Serialize};
19
20pub trait GLTypes {
21    type Device;
22    type Context;
23    type Bindings;
24}
25
26pub trait GLContexts<GL: GLTypes> {
27    fn bindings(&mut self, device: &GL::Device, context_id: ContextId) -> Option<&GL::Bindings>;
28    fn context(&mut self, device: &GL::Device, context_id: ContextId) -> Option<&mut GL::Context>;
29}
30
31impl GLTypes for () {
32    type Bindings = ();
33    type Device = ();
34    type Context = ();
35}
36
37impl GLContexts<()> for () {
38    fn context(&mut self, _: &(), _: ContextId) -> Option<&mut ()> {
39        Some(self)
40    }
41
42    fn bindings(&mut self, _: &(), _: ContextId) -> Option<&()> {
43        Some(self)
44    }
45}
46
47pub trait LayerGrandManagerAPI<GL: GLTypes> {
48    fn create_layer_manager(&self, factory: LayerManagerFactory<GL>)
49    -> Result<LayerManager, Error>;
50
51    fn clone_layer_grand_manager(&self) -> LayerGrandManager<GL>;
52}
53
54pub struct LayerGrandManager<GL>(Box<dyn Send + LayerGrandManagerAPI<GL>>);
55
56impl<GL: GLTypes> Clone for LayerGrandManager<GL> {
57    fn clone(&self) -> Self {
58        self.0.clone_layer_grand_manager()
59    }
60}
61
62impl<GL> Debug for LayerGrandManager<GL> {
63    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
64        "LayerGrandManager(...)".fmt(fmt)
65    }
66}
67
68impl<GL: GLTypes> LayerGrandManager<GL> {
69    pub fn new<GM>(grand_manager: GM) -> LayerGrandManager<GL>
70    where
71        GM: 'static + Send + LayerGrandManagerAPI<GL>,
72    {
73        LayerGrandManager(Box::new(grand_manager))
74    }
75
76    pub fn create_layer_manager<F, M>(&self, factory: F) -> Result<LayerManager, Error>
77    where
78        F: 'static + Send + FnOnce(&mut GL::Device, &mut dyn GLContexts<GL>) -> Result<M, Error>,
79        M: 'static + LayerManagerAPI<GL>,
80    {
81        self.0
82            .create_layer_manager(LayerManagerFactory::new(factory))
83    }
84}
85
86pub trait LayerManagerAPI<GL: GLTypes> {
87    fn create_layer(
88        &mut self,
89        device: &mut GL::Device,
90        contexts: &mut dyn GLContexts<GL>,
91        context_id: ContextId,
92        init: LayerInit,
93    ) -> Result<LayerId, Error>;
94
95    fn destroy_layer(
96        &mut self,
97        device: &mut GL::Device,
98        contexts: &mut dyn GLContexts<GL>,
99        context_id: ContextId,
100        layer_id: LayerId,
101    );
102
103    fn layers(&self) -> &[(ContextId, LayerId)];
104
105    fn begin_frame(
106        &mut self,
107        device: &mut GL::Device,
108        contexts: &mut dyn GLContexts<GL>,
109        layers: &[(ContextId, LayerId)],
110    ) -> Result<Vec<SubImages>, Error>;
111
112    fn end_frame(
113        &mut self,
114        device: &mut GL::Device,
115        contexts: &mut dyn GLContexts<GL>,
116        layers: &[(ContextId, LayerId)],
117    ) -> Result<(), Error>;
118}
119
120pub struct LayerManager(Box<dyn Send + LayerManagerAPI<()>>);
121
122impl Debug for LayerManager {
123    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
124        "LayerManager(...)".fmt(fmt)
125    }
126}
127
128impl LayerManager {
129    pub fn create_layer(
130        &mut self,
131        context_id: ContextId,
132        init: LayerInit,
133    ) -> Result<LayerId, Error> {
134        self.0.create_layer(&mut (), &mut (), context_id, init)
135    }
136
137    pub fn destroy_layer(&mut self, context_id: ContextId, layer_id: LayerId) {
138        self.0.destroy_layer(&mut (), &mut (), context_id, layer_id);
139    }
140
141    pub fn begin_frame(
142        &mut self,
143        layers: &[(ContextId, LayerId)],
144    ) -> Result<Vec<SubImages>, Error> {
145        self.0.begin_frame(&mut (), &mut (), layers)
146    }
147
148    pub fn end_frame(&mut self, layers: &[(ContextId, LayerId)]) -> Result<(), Error> {
149        self.0.end_frame(&mut (), &mut (), layers)
150    }
151}
152
153impl LayerManager {
154    pub fn new<M>(manager: M) -> LayerManager
155    where
156        M: 'static + Send + LayerManagerAPI<()>,
157    {
158        LayerManager(Box::new(manager))
159    }
160}
161
162impl Drop for LayerManager {
163    fn drop(&mut self) {
164        log::debug!("Dropping LayerManager");
165        let layers: Vec<_> = self.0.layers().to_vec();
166        for (context_id, layer_id) in layers.into_iter() {
167            self.destroy_layer(context_id, layer_id);
168        }
169    }
170}
171
172#[allow(clippy::type_complexity)]
173pub struct LayerManagerFactory<GL: GLTypes>(
174    Box<
175        dyn Send
176            + FnOnce(
177                &mut GL::Device,
178                &mut dyn GLContexts<GL>,
179            ) -> Result<Box<dyn LayerManagerAPI<GL>>, Error>,
180    >,
181);
182
183impl<GL: GLTypes> Debug for LayerManagerFactory<GL> {
184    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
185        "LayerManagerFactory(...)".fmt(fmt)
186    }
187}
188
189impl<GL: GLTypes> LayerManagerFactory<GL> {
190    pub fn new<F, M>(factory: F) -> LayerManagerFactory<GL>
191    where
192        F: 'static + Send + FnOnce(&mut GL::Device, &mut dyn GLContexts<GL>) -> Result<M, Error>,
193        M: 'static + LayerManagerAPI<GL>,
194    {
195        LayerManagerFactory(Box::new(move |device, contexts| {
196            Ok(Box::new(factory(device, contexts)?))
197        }))
198    }
199
200    pub fn build(
201        self,
202        device: &mut GL::Device,
203        contexts: &mut dyn GLContexts<GL>,
204    ) -> Result<Box<dyn LayerManagerAPI<GL>>, Error> {
205        (self.0)(device, contexts)
206    }
207}
208
209#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
210#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
211pub struct LayerId(usize);
212
213static NEXT_LAYER_ID: AtomicUsize = AtomicUsize::new(0);
214
215impl Default for LayerId {
216    fn default() -> Self {
217        LayerId(NEXT_LAYER_ID.fetch_add(1, Ordering::SeqCst))
218    }
219}
220
221#[derive(Clone, Copy, Debug)]
222#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
223pub enum LayerInit {
224    /// <https://www.w3.org/TR/webxr/#dictdef-xrwebgllayerinit>
225    WebGLLayer {
226        antialias: bool,
227        depth: bool,
228        stencil: bool,
229        alpha: bool,
230        ignore_depth_values: bool,
231        framebuffer_scale_factor: f32,
232    },
233    /// <https://immersive-web.github.io/layers/#xrprojectionlayerinittype>
234    ProjectionLayer {
235        depth: bool,
236        stencil: bool,
237        alpha: bool,
238        scale_factor: f32,
239    },
240    // TODO: other layer types
241}
242
243impl LayerInit {
244    pub fn texture_size(&self, viewports: &Viewports) -> Size2D<i32, Viewport> {
245        match self {
246            LayerInit::WebGLLayer {
247                framebuffer_scale_factor: scale,
248                ..
249            } |
250            LayerInit::ProjectionLayer {
251                scale_factor: scale,
252                ..
253            } => {
254                let native_size = viewports
255                    .viewports
256                    .iter()
257                    .fold(Rect::zero(), |acc, view| acc.union(view))
258                    .size;
259                (native_size.to_f32() * *scale).to_i32()
260            },
261        }
262    }
263}
264
265/// <https://immersive-web.github.io/layers/#enumdef-xrlayerlayout>
266#[derive(Clone, Copy, Debug)]
267#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
268pub enum LayerLayout {
269    // TODO: Default
270    // Allocates one texture
271    Mono,
272    // Allocates one texture, which is split in half vertically, giving two subimages
273    StereoLeftRight,
274    // Allocates one texture, which is split in half horizonally, giving two subimages
275    StereoTopBottom,
276}
277
278#[derive(Clone, Debug)]
279#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
280pub struct SubImages {
281    pub layer_id: LayerId,
282    pub sub_image: Option<SubImage>,
283    pub view_sub_images: Vec<SubImage>,
284}
285
286/// <https://immersive-web.github.io/layers/#xrsubimagetype>
287#[derive(Clone, Debug)]
288#[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))]
289pub struct SubImage {
290    pub color_texture: Option<NonZeroU32>,
291    pub depth_stencil_texture: Option<NonZeroU32>,
292    pub texture_array_index: Option<u32>,
293    pub viewport: Rect<i32, Viewport>,
294}