1use std::collections::HashMap;
8use std::rc::Rc;
9
10use euclid::{Point2D, Rect, Size2D};
11use glow::{self as gl, Context as Gl, HasContext, PixelUnpackData};
12use surfman::chains::{PreserveBuffer, SwapChains, SwapChainsAPI};
13use surfman::{Context as SurfmanContext, Device as SurfmanDevice, SurfaceAccess, SurfaceTexture};
14use webxr_api::{
15 ContextId, Error, GLContexts, GLTypes, LayerId, LayerInit, LayerManagerAPI, SubImage,
16 SubImages, Viewports,
17};
18
19use crate::gl_utils::GlClearer;
20
21#[derive(Clone, Copy, Debug)]
22pub enum SurfmanGL {}
23
24impl GLTypes for SurfmanGL {
25 type Device = Rc<SurfmanDevice>;
26 type Context = SurfmanContext;
27 type Bindings = Gl;
28}
29
30pub struct SurfmanLayerManager {
31 layers: Vec<(ContextId, LayerId)>,
32 swap_chains: SwapChains<LayerId, SurfmanDevice>,
33 surface_textures: HashMap<LayerId, SurfaceTexture>,
34 depth_stencil_textures: HashMap<LayerId, Option<gl::NativeTexture>>,
35 viewports: Viewports,
36 clearer: GlClearer,
37}
38
39impl SurfmanLayerManager {
40 pub fn new(
41 viewports: Viewports,
42 swap_chains: SwapChains<LayerId, SurfmanDevice>,
43 ) -> SurfmanLayerManager {
44 let layers = Vec::new();
45 let surface_textures = HashMap::new();
46 let depth_stencil_textures = HashMap::new();
47 let clearer = GlClearer::new(false);
48 SurfmanLayerManager {
49 layers,
50 swap_chains,
51 surface_textures,
52 depth_stencil_textures,
53 viewports,
54 clearer,
55 }
56 }
57}
58
59impl LayerManagerAPI<SurfmanGL> for SurfmanLayerManager {
60 fn create_layer(
61 &mut self,
62 contexts: &mut dyn GLContexts<SurfmanGL>,
63 context_id: ContextId,
64 init: LayerInit,
65 ) -> Result<LayerId, Error> {
66 let texture_size = init.texture_size(&self.viewports);
67 let layer_id = LayerId::default();
68 let access = SurfaceAccess::GPUOnly;
69 let size = texture_size.to_untyped();
70 let has_depth_stencil = match init {
72 LayerInit::WebGLLayer { stencil, depth, .. } => stencil | depth,
73 LayerInit::ProjectionLayer { stencil, depth, .. } => stencil | depth,
74 };
75 let device = contexts.device(context_id).ok_or(Error::NoMatchingDevice)?;
76 if has_depth_stencil {
77 let gl = contexts
78 .bindings(context_id)
79 .ok_or(Error::NoMatchingDevice)?;
80 let depth_stencil_texture = unsafe { gl.create_texture().ok() };
81 unsafe {
82 gl.bind_texture(gl::TEXTURE_2D, depth_stencil_texture);
83 gl.tex_image_2d(
84 gl::TEXTURE_2D,
85 0,
86 gl::DEPTH24_STENCIL8 as _,
87 size.width,
88 size.height,
89 0,
90 gl::DEPTH_STENCIL,
91 gl::UNSIGNED_INT_24_8,
92 PixelUnpackData::Slice(None),
93 );
94 }
95 self.depth_stencil_textures
96 .insert(layer_id, depth_stencil_texture);
97 }
98 let context = contexts
99 .context(context_id)
100 .ok_or(Error::NoMatchingDevice)?;
101 self.swap_chains
102 .create_detached_swap_chain(layer_id, size, &device, context, access)
103 .map_err(|err| Error::BackendSpecific(format!("{:?}", err)))?;
104 self.layers.push((context_id, layer_id));
105 Ok(layer_id)
106 }
107
108 fn destroy_layer(
109 &mut self,
110 contexts: &mut dyn GLContexts<SurfmanGL>,
111 context_id: ContextId,
112 layer_id: LayerId,
113 ) {
114 self.clearer.destroy_layer(contexts, context_id, layer_id);
115 let Some(device) = contexts.device(context_id) else {
116 return;
117 };
118 let Some(context) = contexts.context(context_id) else {
119 return;
120 };
121 self.layers.retain(|&ids| ids != (context_id, layer_id));
122 let _ = self.swap_chains.destroy(layer_id, &device, context);
123 self.surface_textures.remove(&layer_id);
124 if let Some(depth_stencil_texture) = self.depth_stencil_textures.remove(&layer_id) {
125 let gl = contexts.bindings(context_id).unwrap();
126 if let Some(depth_stencil_texture) = depth_stencil_texture {
127 unsafe {
128 gl.delete_texture(depth_stencil_texture);
129 }
130 }
131 }
132 }
133
134 fn layers(&self) -> &[(ContextId, LayerId)] {
135 &self.layers[..]
136 }
137
138 fn begin_frame(
139 &mut self,
140 contexts: &mut dyn GLContexts<SurfmanGL>,
141 layers: &[(ContextId, LayerId)],
142 ) -> Result<Vec<SubImages>, Error> {
143 layers
144 .iter()
145 .map(|&(context_id, layer_id)| {
146 let device = contexts.device(context_id).ok_or(Error::NoMatchingDevice)?;
147 let context = contexts
148 .context(context_id)
149 .ok_or(Error::NoMatchingDevice)?;
150 let swap_chain = self
151 .swap_chains
152 .get(layer_id)
153 .ok_or(Error::NoMatchingDevice)?;
154 let surface_size = Size2D::from_untyped(swap_chain.size());
155 let surface_texture = swap_chain
156 .take_surface_texture(&device, context)
157 .map_err(|_| Error::NoMatchingDevice)?;
158 let color_texture = device.surface_texture_object(&surface_texture);
159 let color_target = device.surface_gl_texture_target();
160 let depth_stencil_texture = self
161 .depth_stencil_textures
162 .get(&layer_id)
163 .cloned()
164 .flatten();
165 let texture_array_index = None;
166 let origin = Point2D::new(0, 0);
167 let sub_image = Some(SubImage {
168 color_texture: color_texture.map(|nt| nt.0),
169 depth_stencil_texture: depth_stencil_texture.map(|nt| nt.0),
170 texture_array_index,
171 viewport: Rect::new(origin, surface_size),
172 });
173 let view_sub_images = self
174 .viewports
175 .viewports
176 .iter()
177 .map(|&viewport| SubImage {
178 color_texture: color_texture.map(|nt| nt.0),
179 depth_stencil_texture: depth_stencil_texture.map(|texture| texture.0),
180 texture_array_index,
181 viewport,
182 })
183 .collect();
184 self.surface_textures.insert(layer_id, surface_texture);
185 self.clearer.clear(
186 contexts,
187 context_id,
188 layer_id,
189 color_texture,
190 color_target,
191 depth_stencil_texture,
192 );
193 Ok(SubImages {
194 layer_id,
195 sub_image,
196 view_sub_images,
197 })
198 })
199 .collect()
200 }
201
202 fn end_frame(
203 &mut self,
204 contexts: &mut dyn GLContexts<SurfmanGL>,
205 layers: &[(ContextId, LayerId)],
206 ) -> Result<(), Error> {
207 for &(context_id, layer_id) in layers {
208 let gl = contexts
209 .bindings(context_id)
210 .ok_or(Error::NoMatchingDevice)?;
211 unsafe {
212 gl.flush();
213 }
214 let device = contexts.device(context_id).ok_or(Error::NoMatchingDevice)?;
215 let context = contexts
216 .context(context_id)
217 .ok_or(Error::NoMatchingDevice)?;
218 let surface_texture = self
219 .surface_textures
220 .remove(&layer_id)
221 .ok_or(Error::NoMatchingDevice)?;
222 let swap_chain = self
223 .swap_chains
224 .get(layer_id)
225 .ok_or(Error::NoMatchingDevice)?;
226
227 swap_chain
228 .recycle_surface_texture(&device, context, surface_texture)
229 .map_err(|err| Error::BackendSpecific(format!("{:?}", err)))?;
230 swap_chain
231 .swap_buffers(&device, context, PreserveBuffer::No)
232 .map_err(|err| Error::BackendSpecific(format!("{:?}", err)))?;
233 }
234 Ok(())
235 }
236}