paint/
webrender_external_images.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::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
17/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads.
18pub 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}