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