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