webgl/webgl_mode/
inprocess.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;
6use std::sync::{Arc, Mutex};
7
8use canvas_traits::webgl::{GlType, WebGLContextId, WebGLMsg, WebGLThreads, webgl_channel};
9use compositing_traits::rendering_context::RenderingContext;
10use compositing_traits::{
11    CrossProcessCompositorApi, ExternalImageSource, WebRenderExternalImageApi,
12    WebRenderExternalImageRegistry,
13};
14use euclid::default::Size2D;
15use log::debug;
16use rustc_hash::FxHashMap;
17use surfman::chains::{SwapChainAPI, SwapChains, SwapChainsAPI};
18use surfman::{Device, SurfaceTexture};
19#[cfg(feature = "webxr")]
20use webxr::SurfmanGL as WebXRSurfman;
21#[cfg(feature = "webxr")]
22use webxr_api::LayerGrandManager as WebXRLayerGrandManager;
23
24use crate::webgl_thread::{WebGLThread, WebGLThreadInit};
25
26pub struct WebGLComm {
27    pub webgl_threads: WebGLThreads,
28    pub image_handler: Box<dyn WebRenderExternalImageApi>,
29    #[cfg(feature = "webxr")]
30    pub webxr_layer_grand_manager: WebXRLayerGrandManager<WebXRSurfman>,
31}
32
33impl WebGLComm {
34    /// Creates a new `WebGLComm` object.
35    pub fn new(
36        rendering_context: Rc<dyn RenderingContext>,
37        compositor_api: CrossProcessCompositorApi,
38        external_images: Arc<Mutex<WebRenderExternalImageRegistry>>,
39        api_type: GlType,
40    ) -> WebGLComm {
41        debug!("WebGLThreads::new()");
42        let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap();
43        let webrender_swap_chains = SwapChains::new();
44        #[cfg(feature = "webxr")]
45        let webxr_init = crate::webxr::WebXRBridgeInit::new(sender.clone());
46        #[cfg(feature = "webxr")]
47        let webxr_layer_grand_manager = webxr_init.layer_grand_manager();
48        let connection = rendering_context
49            .connection()
50            .expect("Failed to get connection");
51        let adapter = connection
52            .create_adapter()
53            .expect("Failed to create adapter");
54
55        // This implementation creates a single `WebGLThread` for all the pipelines.
56        let init = WebGLThreadInit {
57            compositor_api,
58            external_images,
59            sender: sender.clone(),
60            receiver,
61            webrender_swap_chains: webrender_swap_chains.clone(),
62            connection,
63            adapter,
64            api_type,
65            #[cfg(feature = "webxr")]
66            webxr_init,
67        };
68
69        let external = WebGLExternalImages::new(rendering_context, webrender_swap_chains);
70
71        WebGLThread::run_on_own_thread(init);
72
73        WebGLComm {
74            webgl_threads: WebGLThreads(sender),
75            image_handler: Box::new(external),
76            #[cfg(feature = "webxr")]
77            webxr_layer_grand_manager,
78        }
79    }
80}
81
82/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads.
83struct WebGLExternalImages {
84    rendering_context: Rc<dyn RenderingContext>,
85    swap_chains: SwapChains<WebGLContextId, Device>,
86    locked_front_buffers: FxHashMap<WebGLContextId, SurfaceTexture>,
87}
88
89impl WebGLExternalImages {
90    fn new(
91        rendering_context: Rc<dyn RenderingContext>,
92        swap_chains: SwapChains<WebGLContextId, Device>,
93    ) -> Self {
94        Self {
95            rendering_context,
96            swap_chains,
97            locked_front_buffers: FxHashMap::default(),
98        }
99    }
100
101    fn lock_swap_chain(&mut self, id: WebGLContextId) -> Option<(u32, Size2D<i32>)> {
102        debug!("... locking chain {:?}", id);
103        let front_buffer = self.swap_chains.get(id)?.take_surface()?;
104
105        if let Some((surface_texture, gl_texture, size)) =
106            self.rendering_context.create_texture(front_buffer)
107        {
108            self.locked_front_buffers.insert(id, surface_texture);
109
110            Some((gl_texture, size))
111        } else {
112            None
113        }
114    }
115
116    fn unlock_swap_chain(&mut self, id: WebGLContextId) -> Option<()> {
117        debug!("... unlocked chain {:?}", id);
118        let locked_front_buffer = self.locked_front_buffers.remove(&id)?;
119        if let Some(locked_front_buffer) =
120            self.rendering_context.destroy_texture(locked_front_buffer)
121        {
122            self.swap_chains
123                .get(id)?
124                .recycle_surface(locked_front_buffer);
125            Some(())
126        } else {
127            None
128        }
129    }
130}
131
132impl WebRenderExternalImageApi for WebGLExternalImages {
133    fn lock(&mut self, id: u64) -> (ExternalImageSource<'_>, Size2D<i32>) {
134        let id = WebGLContextId(id);
135        let (texture_id, size) = self.lock_swap_chain(id).unwrap_or_default();
136        (ExternalImageSource::NativeTexture(texture_id), size)
137    }
138
139    fn unlock(&mut self, id: u64) {
140        let id = WebGLContextId(id);
141        self.unlock_swap_chain(id);
142    }
143}