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