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
124 if let Some(surface_texture) = self.surface_textures.remove(&layer_id) &&
125 let Ok(mut surface) = device.destroy_surface_texture(context, surface_texture)
126 {
127 let _ = device.destroy_surface(context, &mut surface);
128 }
129
130 if let Some(depth_stencil_texture) = self.depth_stencil_textures.remove(&layer_id) {
131 let gl = contexts.bindings(context_id).unwrap();
132 if let Some(depth_stencil_texture) = depth_stencil_texture {
133 unsafe {
134 gl.delete_texture(depth_stencil_texture);
135 }
136 }
137 }
138 }
139
140 fn layers(&self) -> &[(ContextId, LayerId)] {
141 &self.layers[..]
142 }
143
144 fn begin_frame(
145 &mut self,
146 contexts: &mut dyn GLContexts<SurfmanGL>,
147 layers: &[(ContextId, LayerId)],
148 ) -> Result<Vec<SubImages>, Error> {
149 layers
150 .iter()
151 .map(|&(context_id, layer_id)| {
152 let device = contexts.device(context_id).ok_or(Error::NoMatchingDevice)?;
153 let context = contexts
154 .context(context_id)
155 .ok_or(Error::NoMatchingDevice)?;
156 let swap_chain = self
157 .swap_chains
158 .get(layer_id)
159 .ok_or(Error::NoMatchingDevice)?;
160 let surface_size = Size2D::from_untyped(swap_chain.size());
161 let surface_texture = swap_chain
162 .take_surface_texture(&device, context)
163 .map_err(|_| Error::NoMatchingDevice)?;
164 let color_texture = device.surface_texture_object(&surface_texture);
165 let color_target = device.surface_gl_texture_target();
166 let depth_stencil_texture = self
167 .depth_stencil_textures
168 .get(&layer_id)
169 .cloned()
170 .flatten();
171 let texture_array_index = None;
172 let origin = Point2D::new(0, 0);
173 let sub_image = Some(SubImage {
174 color_texture: color_texture.map(|nt| nt.0),
175 depth_stencil_texture: depth_stencil_texture.map(|nt| nt.0),
176 texture_array_index,
177 viewport: Rect::new(origin, surface_size),
178 });
179 let view_sub_images = self
180 .viewports
181 .viewports
182 .iter()
183 .map(|&viewport| SubImage {
184 color_texture: color_texture.map(|nt| nt.0),
185 depth_stencil_texture: depth_stencil_texture.map(|texture| texture.0),
186 texture_array_index,
187 viewport,
188 })
189 .collect();
190 self.surface_textures.insert(layer_id, surface_texture);
191 self.clearer.clear(
192 contexts,
193 context_id,
194 layer_id,
195 color_texture,
196 color_target,
197 depth_stencil_texture,
198 );
199 Ok(SubImages {
200 layer_id,
201 sub_image,
202 view_sub_images,
203 })
204 })
205 .collect()
206 }
207
208 fn end_frame(
209 &mut self,
210 contexts: &mut dyn GLContexts<SurfmanGL>,
211 layers: &[(ContextId, LayerId)],
212 ) -> Result<(), Error> {
213 for &(context_id, layer_id) in layers {
214 let gl = contexts
215 .bindings(context_id)
216 .ok_or(Error::NoMatchingDevice)?;
217 unsafe {
218 gl.flush();
219 }
220 let device = contexts.device(context_id).ok_or(Error::NoMatchingDevice)?;
221 let context = contexts
222 .context(context_id)
223 .ok_or(Error::NoMatchingDevice)?;
224 let surface_texture = self
225 .surface_textures
226 .remove(&layer_id)
227 .ok_or(Error::NoMatchingDevice)?;
228 let swap_chain = self
229 .swap_chains
230 .get(layer_id)
231 .ok_or(Error::NoMatchingDevice)?;
232
233 swap_chain
234 .recycle_surface_texture(&device, context, surface_texture)
235 .map_err(|err| Error::BackendSpecific(format!("{:?}", err)))?;
236 swap_chain
237 .swap_buffers(&device, context, PreserveBuffer::No)
238 .map_err(|err| Error::BackendSpecific(format!("{:?}", err)))?;
239 }
240 Ok(())
241 }
242}