compositing/
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 compositing_traits::rendering_context::RenderingContext;
9use compositing_traits::{ExternalImageSource, WebRenderExternalImageApi};
10use euclid::default::Size2D;
11use log::debug;
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        let locked_front_buffer = self.locked_front_buffers.remove(&id)?;
61        let locked_front_buffer = self
62            .rendering_context
63            .destroy_texture(locked_front_buffer)?;
64
65        self.swap_chains
66            .get(id)
67            .expect("Should always have a SwapChain for a busy WebGLContext")
68            .recycle_surface(locked_front_buffer);
69
70        {
71            let mut busy_webgl_context_map = self.busy_webgl_context_map.write();
72            *busy_webgl_context_map.entry(id).or_insert(1) -= 1;
73        }
74
75        let _ = self.webgl_threads.finished_rendering_to_context(id);
76
77        Some(())
78    }
79}
80
81impl WebRenderExternalImageApi for WebGLExternalImages {
82    fn lock(&mut self, id: u64) -> (ExternalImageSource<'_>, Size2D<i32>) {
83        let (texture_id, size) = self.lock_swap_chain(WebGLContextId(id)).unwrap_or_default();
84        (ExternalImageSource::NativeTexture(texture_id), size)
85    }
86
87    fn unlock(&mut self, id: u64) {
88        self.unlock_swap_chain(WebGLContextId(id));
89    }
90}