paint/
webrender_external_images.rs1use std::rc::Rc;
6
7use canvas_traits::webgl::{WebGLContextId, WebGLThreads};
8use euclid::default::Size2D;
9use log::debug;
10use paint_api::rendering_context::RenderingContext;
11use paint_api::{ExternalImageSource, WebRenderExternalImageApi};
12use rustc_hash::FxHashMap;
13use surfman::chains::{SwapChainAPI, SwapChains, SwapChainsAPI};
14use surfman::{Device, SurfaceTexture};
15use webgl::webgl_thread::WebGLContextBusyMap;
16
17pub struct WebGLExternalImages {
19 webgl_threads: WebGLThreads,
20 rendering_context: Rc<dyn RenderingContext>,
21 swap_chains: SwapChains<WebGLContextId, Device>,
22 busy_webgl_context_map: WebGLContextBusyMap,
23 locked_front_buffers: FxHashMap<WebGLContextId, SurfaceTexture>,
24}
25
26impl WebGLExternalImages {
27 pub fn new(
28 webgl_threads: WebGLThreads,
29 rendering_context: Rc<dyn RenderingContext>,
30 swap_chains: SwapChains<WebGLContextId, Device>,
31 busy_webgl_context_map: WebGLContextBusyMap,
32 ) -> Self {
33 Self {
34 webgl_threads,
35 rendering_context,
36 swap_chains,
37 busy_webgl_context_map,
38 locked_front_buffers: FxHashMap::default(),
39 }
40 }
41
42 fn lock_swap_chain(&mut self, id: WebGLContextId) -> Option<(u32, Size2D<i32>)> {
43 debug!("... locking chain {:?}", id);
44
45 {
46 let mut busy_webgl_context_map = self.busy_webgl_context_map.write();
47 *busy_webgl_context_map.entry(id).or_default() += 1;
48 }
49
50 let front_buffer = self.swap_chains.get(id)?.take_surface()?;
51 let (surface_texture, gl_texture, size) =
52 self.rendering_context.create_texture(front_buffer)?;
53 self.locked_front_buffers.insert(id, surface_texture);
54
55 Some((gl_texture, size))
56 }
57
58 fn unlock_swap_chain(&mut self, id: WebGLContextId) -> Option<()> {
59 debug!("... unlocked chain {:?}", id);
60
61 {
62 let mut busy_webgl_context_map = self.busy_webgl_context_map.write();
63 *busy_webgl_context_map.entry(id).or_insert(1) -= 1;
64 }
65
66 let locked_front_buffer = self.locked_front_buffers.remove(&id)?;
67 let locked_front_buffer = self
68 .rendering_context
69 .destroy_texture(locked_front_buffer)?;
70
71 self.swap_chains
72 .get(id)
73 .expect("Should always have a SwapChain for a busy WebGLContext")
74 .recycle_surface(locked_front_buffer);
75
76 let _ = self.webgl_threads.finished_rendering_to_context(id);
77
78 Some(())
79 }
80}
81
82impl WebRenderExternalImageApi for WebGLExternalImages {
83 fn lock(&mut self, id: u64) -> (ExternalImageSource<'_>, Size2D<i32>) {
84 let (texture_id, size) = self.lock_swap_chain(WebGLContextId(id)).unwrap_or_default();
85 (ExternalImageSource::NativeTexture(texture_id), size)
86 }
87
88 fn unlock(&mut self, id: u64) {
89 self.unlock_swap_chain(WebGLContextId(id));
90 }
91}