aboutsummaryrefslogtreecommitdiffstats
path: root/components/canvas
diff options
context:
space:
mode:
Diffstat (limited to 'components/canvas')
-rw-r--r--components/canvas/Cargo.toml1
-rw-r--r--components/canvas/webgl_mode/inprocess.rs250
-rw-r--r--components/canvas/webgl_mode/mod.rs2
-rw-r--r--components/canvas/webgl_thread.rs195
4 files changed, 321 insertions, 127 deletions
diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml
index dbc3b2a7200..03a77826ac7 100644
--- a/components/canvas/Cargo.toml
+++ b/components/canvas/Cargo.toml
@@ -21,6 +21,7 @@ azure = {git = "https://github.com/servo/rust-azure", optional = true}
byteorder = "1"
canvas_traits = {path = "../canvas_traits"}
cssparser = "0.25"
+embedder_traits = {path = "../embedder_traits"}
euclid = "0.20"
fnv = "1.0"
gleam = "0.6.7"
diff --git a/components/canvas/webgl_mode/inprocess.rs b/components/canvas/webgl_mode/inprocess.rs
index 76d468390db..d499a1cb148 100644
--- a/components/canvas/webgl_mode/inprocess.rs
+++ b/components/canvas/webgl_mode/inprocess.rs
@@ -3,15 +3,19 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::gl_context::GLContextFactory;
-use crate::webgl_thread::WebGLThread;
+use crate::webgl_thread::{TexturesMap, WebGLMainThread, WebGLThread, WebGLThreadInit};
use canvas_traits::webgl::webgl_channel;
use canvas_traits::webgl::DOMToTextureCommand;
use canvas_traits::webgl::{WebGLChan, WebGLContextId, WebGLMsg, WebGLPipeline, WebGLReceiver};
-use canvas_traits::webgl::{WebGLSender, WebVRCommand, WebVRRenderHandler};
+use canvas_traits::webgl::{WebGLSender, WebVRRenderHandler};
+use embedder_traits::EventLoopWaker;
use euclid::default::Size2D;
use fnv::FnvHashMap;
use gleam::gl;
use servo_config::pref;
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::default::Default;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry};
@@ -19,37 +23,70 @@ use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry
/// WebGL Threading API entry point that lives in the constellation.
pub struct WebGLThreads(WebGLSender<WebGLMsg>);
+pub enum ThreadMode {
+ MainThread(Box<dyn EventLoopWaker>),
+ OffThread(Rc<dyn gl::Gl>),
+}
+
impl WebGLThreads {
/// Creates a new WebGLThreads object
pub fn new(
gl_factory: GLContextFactory,
- webrender_gl: Rc<dyn gl::Gl>,
webrender_api_sender: webrender_api::RenderApiSender,
webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
+ mode: ThreadMode,
) -> (
WebGLThreads,
+ Option<WebGLMainThread>,
Box<dyn WebrenderExternalImageApi>,
Option<Box<dyn webrender::OutputImageHandler>>,
) {
+ let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap();
// This implementation creates a single `WebGLThread` for all the pipelines.
- let channel = WebGLThread::start(
+ let init = WebGLThreadInit {
gl_factory,
webrender_api_sender,
- webvr_compositor.map(|c| WebVRRenderWrapper(c)),
+ webvr_compositor,
external_images,
- );
+ sender: sender.clone(),
+ receiver,
+ };
+
let output_handler = if pref!(dom.webgl.dom_to_texture.enabled) {
- Some(Box::new(OutputHandler::new(
- webrender_gl.clone(),
- channel.clone(),
- )))
+ Some(Box::new(match mode {
+ ThreadMode::MainThread(..) => OutputHandler::new_main_thread(),
+ ThreadMode::OffThread(ref webrender_gl) => {
+ OutputHandler::new_off_thread(webrender_gl.clone(), sender.clone())
+ },
+ }))
} else {
None
};
- let external = WebGLExternalImages::new(webrender_gl, channel.clone());
+
+ let (external, webgl_thread) = match mode {
+ ThreadMode::MainThread(event_loop_waker) => {
+ let textures = Rc::new(RefCell::new(HashMap::new()));
+ let thread_data =
+ WebGLThread::run_on_current_thread(init, event_loop_waker, textures.clone());
+ (
+ WebGLExternalImages::new_main_thread(textures),
+ Some(thread_data),
+ )
+ },
+
+ ThreadMode::OffThread(webrender_gl) => {
+ WebGLThread::run_on_own_thread(init);
+ (
+ WebGLExternalImages::new_off_thread(webrender_gl, sender.clone()),
+ None,
+ )
+ },
+ };
+
(
- WebGLThreads(channel),
+ WebGLThreads(sender),
+ webgl_thread,
Box::new(external),
output_handler.map(|b| b as Box<_>),
)
@@ -70,88 +107,113 @@ impl WebGLThreads {
}
/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads.
-struct WebGLExternalImages {
- webrender_gl: Rc<dyn gl::Gl>,
- webgl_channel: WebGLSender<WebGLMsg>,
- // Used to avoid creating a new channel on each received WebRender request.
- lock_channel: (
- WebGLSender<(u32, Size2D<i32>, usize)>,
- WebGLReceiver<(u32, Size2D<i32>, usize)>,
- ),
+enum WebGLExternalImages {
+ OffThread {
+ webrender_gl: Rc<dyn gl::Gl>,
+ webgl_channel: WebGLSender<WebGLMsg>,
+ // Used to avoid creating a new channel on each received WebRender request.
+ lock_channel: (
+ WebGLSender<(u32, Size2D<i32>, usize)>,
+ WebGLReceiver<(u32, Size2D<i32>, usize)>,
+ ),
+ },
+ MainThread {
+ textures: TexturesMap,
+ },
}
impl WebGLExternalImages {
- fn new(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self {
- Self {
+ fn new_off_thread(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self {
+ WebGLExternalImages::OffThread {
webrender_gl,
webgl_channel: channel,
lock_channel: webgl_channel().unwrap(),
}
}
+
+ fn new_main_thread(textures: TexturesMap) -> Self {
+ WebGLExternalImages::MainThread { textures }
+ }
}
impl WebrenderExternalImageApi for WebGLExternalImages {
fn lock(&mut self, id: u64) -> (u32, Size2D<i32>) {
- // WebGL Thread has it's own GL command queue that we need to synchronize with the WR GL command queue.
- // The WebGLMsg::Lock message inserts a fence in the WebGL command queue.
- self.webgl_channel
- .send(WebGLMsg::Lock(
- WebGLContextId(id as usize),
- self.lock_channel.0.clone(),
- ))
- .unwrap();
- let (image_id, size, gl_sync) = self.lock_channel.1.recv().unwrap();
- // The next glWaitSync call is run on the WR thread and it's used to synchronize the two
- // flows of OpenGL commands in order to avoid WR using a semi-ready WebGL texture.
- // glWaitSync doesn't block WR thread, it affects only internal OpenGL subsystem.
- self.webrender_gl
- .wait_sync(gl_sync as gl::GLsync, 0, gl::TIMEOUT_IGNORED);
- (image_id, size)
- }
+ match *self {
+ WebGLExternalImages::OffThread {
+ ref webgl_channel,
+ ref webrender_gl,
+ ref lock_channel,
+ } => {
+ // WebGL Thread has it's own GL command queue that we need to synchronize with the WR GL command queue.
+ // The WebGLMsg::Lock message inserts a fence in the WebGL command queue.
+ webgl_channel
+ .send(WebGLMsg::Lock(
+ WebGLContextId(id as usize),
+ lock_channel.0.clone(),
+ ))
+ .unwrap();
+ let (image_id, size, gl_sync) = lock_channel.1.recv().unwrap();
+ // The next glWaitSync call is run on the WR thread and it's used to synchronize the two
+ // flows of OpenGL commands in order to avoid WR using a semi-ready WebGL texture.
+ // glWaitSync doesn't block WR thread, it affects only internal OpenGL subsystem.
+ webrender_gl.wait_sync(gl_sync as gl::GLsync, 0, gl::TIMEOUT_IGNORED);
+ (image_id, size)
+ },
- fn unlock(&mut self, id: u64) {
- self.webgl_channel
- .send(WebGLMsg::Unlock(WebGLContextId(id as usize)))
- .unwrap();
+ WebGLExternalImages::MainThread { ref textures } => {
+ let textures = textures.borrow();
+ let entry = textures
+ .get(&WebGLContextId(id as usize))
+ .expect("no texture entry???");
+ (entry.0, entry.1)
+ },
+ }
}
-}
-/// Wrapper to send WebVR commands used in `WebGLThread`.
-struct WebVRRenderWrapper(Box<dyn WebVRRenderHandler>);
+ fn unlock(&mut self, id: u64) {
+ match *self {
+ WebGLExternalImages::OffThread {
+ ref webgl_channel, ..
+ } => {
+ webgl_channel
+ .send(WebGLMsg::Unlock(WebGLContextId(id as usize)))
+ .unwrap();
+ },
-impl WebVRRenderHandler for WebVRRenderWrapper {
- fn handle(
- &mut self,
- gl: &dyn gl::Gl,
- command: WebVRCommand,
- texture: Option<(u32, Size2D<i32>)>,
- ) {
- self.0.handle(gl, command, texture);
+ WebGLExternalImages::MainThread { .. } => {},
+ }
}
}
/// struct used to implement DOMToTexture feature and webrender::OutputImageHandler trait.
type OutputHandlerData = Option<(u32, Size2D<i32>)>;
-struct OutputHandler {
- webrender_gl: Rc<dyn gl::Gl>,
- webgl_channel: WebGLSender<WebGLMsg>,
- // Used to avoid creating a new channel on each received WebRender request.
- lock_channel: (
- WebGLSender<OutputHandlerData>,
- WebGLReceiver<OutputHandlerData>,
- ),
- sync_objects: FnvHashMap<webrender_api::PipelineId, gl::GLsync>,
+enum OutputHandler {
+ OffThread {
+ webrender_gl: Rc<dyn gl::Gl>,
+ webgl_channel: WebGLSender<WebGLMsg>,
+ // Used to avoid creating a new channel on each received WebRender request.
+ lock_channel: (
+ WebGLSender<OutputHandlerData>,
+ WebGLReceiver<OutputHandlerData>,
+ ),
+ sync_objects: FnvHashMap<webrender_api::PipelineId, gl::GLsync>,
+ },
+ MainThread,
}
impl OutputHandler {
- fn new(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self {
- Self {
+ fn new_off_thread(webrender_gl: Rc<dyn gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self {
+ OutputHandler::OffThread {
webrender_gl,
webgl_channel: channel,
lock_channel: webgl_channel().unwrap(),
sync_objects: Default::default(),
}
}
+
+ fn new_main_thread() -> Self {
+ OutputHandler::MainThread
+ }
}
/// Bridge between the WR frame outputs and WebGL to implement DOMToTexture synchronization.
@@ -160,29 +222,49 @@ impl webrender::OutputImageHandler for OutputHandler {
&mut self,
id: webrender_api::PipelineId,
) -> Option<(u32, webrender_api::units::FramebufferIntSize)> {
- // Insert a fence in the WR command queue
- let gl_sync = self
- .webrender_gl
- .fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
- // The lock command adds a WaitSync call on the WebGL command flow.
- let command = DOMToTextureCommand::Lock(id, gl_sync as usize, self.lock_channel.0.clone());
- self.webgl_channel
- .send(WebGLMsg::DOMToTextureCommand(command))
- .unwrap();
- self.lock_channel.1.recv().unwrap().map(|(tex_id, size)| {
- (
- tex_id,
- webrender_api::units::FramebufferIntSize::new(size.width, size.height),
- )
- })
+ match *self {
+ OutputHandler::OffThread {
+ ref webrender_gl,
+ ref lock_channel,
+ ref webgl_channel,
+ ..
+ } => {
+ // Insert a fence in the WR command queue
+ let gl_sync = webrender_gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
+ // The lock command adds a WaitSync call on the WebGL command flow.
+ let command =
+ DOMToTextureCommand::Lock(id, gl_sync as usize, lock_channel.0.clone());
+ webgl_channel
+ .send(WebGLMsg::DOMToTextureCommand(command))
+ .unwrap();
+ lock_channel.1.recv().unwrap().map(|(tex_id, size)| {
+ (
+ tex_id,
+ webrender_api::units::FramebufferIntSize::new(size.width, size.height),
+ )
+ })
+ },
+
+ OutputHandler::MainThread => unimplemented!(),
+ }
}
fn unlock(&mut self, id: webrender_api::PipelineId) {
- if let Some(gl_sync) = self.sync_objects.remove(&id) {
- // Flush the Sync object into the GPU's command queue to guarantee that it it's signaled.
- self.webrender_gl.flush();
- // Mark the sync object for deletion.
- self.webrender_gl.delete_sync(gl_sync);
+ match *self {
+ OutputHandler::OffThread {
+ ref webrender_gl,
+ ref mut sync_objects,
+ ..
+ } => {
+ if let Some(gl_sync) = sync_objects.remove(&id) {
+ // Flush the Sync object into the GPU's command queue to guarantee that it it's signaled.
+ webrender_gl.flush();
+ // Mark the sync object for deletion.
+ webrender_gl.delete_sync(gl_sync);
+ }
+ },
+
+ OutputHandler::MainThread => {},
}
}
}
diff --git a/components/canvas/webgl_mode/mod.rs b/components/canvas/webgl_mode/mod.rs
index b16ddc31c2e..5aa85947d21 100644
--- a/components/canvas/webgl_mode/mod.rs
+++ b/components/canvas/webgl_mode/mod.rs
@@ -3,4 +3,4 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
mod inprocess;
-pub use self::inprocess::WebGLThreads;
+pub use self::inprocess::{ThreadMode, WebGLThreads};
diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs
index ce73b03cf09..715b6d8b8ca 100644
--- a/components/canvas/webgl_thread.rs
+++ b/components/canvas/webgl_thread.rs
@@ -5,6 +5,7 @@
use super::gl_context::{map_attrs_to_script_attrs, GLContextFactory, GLContextWrapper};
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
use canvas_traits::webgl::*;
+use embedder_traits::EventLoopWaker;
use euclid::default::Size2D;
use fnv::FnvHashMap;
use gleam::gl;
@@ -13,13 +14,17 @@ use ipc_channel::ipc::IpcSender;
use offscreen_gl_context::{DrawBuffer, GLContext, NativeGLContextMethods};
use pixels::{self, PixelFormat};
use std::borrow::Cow;
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::mem;
+use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::thread;
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
/// WebGL Threading API entry point that lives in the constellation.
/// It allows to get a WebGLThread handle for each script pipeline.
-pub use crate::webgl_mode::WebGLThreads;
+pub use crate::webgl_mode::{ThreadMode, WebGLThreads};
struct GLContextData {
ctx: GLContextWrapper,
@@ -50,7 +55,7 @@ impl Default for GLState {
/// A WebGLThread manages the life cycle and message multiplexing of
/// a set of WebGLContexts living in the same thread.
-pub struct WebGLThread<VR: WebVRRenderHandler + 'static> {
+pub(crate) struct WebGLThread {
/// Factory used to create a new GLContext shared with the WR/Main thread.
gl_factory: GLContextFactory,
/// Channel used to generate/update or delete `webrender_api::ImageKey`s.
@@ -62,20 +67,74 @@ pub struct WebGLThread<VR: WebVRRenderHandler + 'static> {
/// Current bound context.
bound_context_id: Option<WebGLContextId>,
/// Handler user to send WebVR commands.
- webvr_compositor: Option<VR>,
+ webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
/// Texture ids and sizes used in DOM to texture outputs.
dom_outputs: FnvHashMap<webrender_api::PipelineId, DOMToTextureData>,
/// List of registered webrender external images.
/// We use it to get an unique ID for new WebGLContexts.
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
+ /// The receiver that will be used for processing WebGL messages.
+ receiver: WebGLReceiver<WebGLMsg>,
+ /// The receiver that should be used to send WebGL messages for processing.
+ sender: WebGLSender<WebGLMsg>,
}
-impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
- pub fn new(
- gl_factory: GLContextFactory,
- webrender_api_sender: webrender_api::RenderApiSender,
- webvr_compositor: Option<VR>,
- external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
+/// A map of GL contexts to backing textures and their sizes.
+/// Only used for accessing this information when the WebGL processing is run
+/// on the main thread and the compositor needs access to this information
+/// synchronously.
+pub(crate) type TexturesMap = Rc<RefCell<HashMap<WebGLContextId, (u32, Size2D<i32>)>>>;
+
+#[derive(PartialEq)]
+enum EventLoop {
+ Blocking,
+ Nonblocking,
+}
+
+/// The data required to initialize an instance of the WebGLThread type.
+pub(crate) struct WebGLThreadInit {
+ pub gl_factory: GLContextFactory,
+ pub webrender_api_sender: webrender_api::RenderApiSender,
+ pub webvr_compositor: Option<Box<dyn WebVRRenderHandler>>,
+ pub external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
+ pub sender: WebGLSender<WebGLMsg>,
+ pub receiver: WebGLReceiver<WebGLMsg>,
+}
+
+/// The extra data required to run an instance of WebGLThread when it is
+/// not running in its own thread.
+pub struct WebGLMainThread {
+ thread_data: WebGLThread,
+ shut_down: bool,
+ textures: TexturesMap,
+}
+
+impl WebGLMainThread {
+ /// Synchronously process all outstanding WebGL messages.
+ pub fn process(&mut self) {
+ if self.shut_down {
+ return;
+ }
+
+ // Any context could be current when we start.
+ self.thread_data.bound_context_id = None;
+ self.shut_down = !self
+ .thread_data
+ .process(EventLoop::Nonblocking, Some(self.textures.clone()))
+ }
+}
+
+impl WebGLThread {
+ /// Create a new instance of WebGLThread.
+ pub(crate) fn new(
+ WebGLThreadInit {
+ gl_factory,
+ webrender_api_sender,
+ webvr_compositor,
+ external_images,
+ sender,
+ receiver,
+ }: WebGLThreadInit,
) -> Self {
WebGLThread {
gl_factory,
@@ -86,49 +145,83 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
webvr_compositor,
dom_outputs: Default::default(),
external_images,
+ sender,
+ receiver,
}
}
- /// Creates a new `WebGLThread` and returns a Sender to
- /// communicate with it.
- pub fn start(
- gl_factory: GLContextFactory,
- webrender_api_sender: webrender_api::RenderApiSender,
- webvr_compositor: Option<VR>,
- external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
- ) -> WebGLSender<WebGLMsg> {
- let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap();
- let result = sender.clone();
+ /// Perform all initialization required to run an instance of WebGLThread
+ /// concurrently on the current thread. Returns a `WebGLMainThread` instance
+ /// that can be used to process any outstanding WebGL messages at any given
+ /// point in time.
+ pub(crate) fn run_on_current_thread(
+ mut init: WebGLThreadInit,
+ event_loop_waker: Box<dyn EventLoopWaker>,
+ textures: TexturesMap,
+ ) -> WebGLMainThread {
+ // Interpose a new channel in between the existing WebGL channel endpoints.
+ // This will bounce all WebGL messages through a second thread adding a small
+ // delay, but this will also ensure that the main thread will wake up and
+ // process the WebGL message when it arrives.
+ let (from_router_sender, from_router_receiver) = webgl_channel::<WebGLMsg>().unwrap();
+ let receiver = mem::replace(&mut init.receiver, from_router_receiver);
+
+ let thread_data = WebGLThread::new(init);
+
thread::Builder::new()
- .name("WebGLThread".to_owned())
+ .name("WebGL main thread pump".to_owned())
.spawn(move || {
- let mut renderer = WebGLThread::new(
- gl_factory,
- webrender_api_sender,
- webvr_compositor,
- external_images,
- );
- let webgl_chan = WebGLChan(sender);
- loop {
- let msg = receiver.recv().unwrap();
- let exit = renderer.handle_msg(msg, &webgl_chan);
- if exit {
- return;
- }
+ while let Ok(msg) = receiver.recv() {
+ let _ = from_router_sender.send(msg);
+ event_loop_waker.wake();
}
})
.expect("Thread spawning failed");
- result
+ WebGLMainThread {
+ thread_data,
+ textures,
+ shut_down: false,
+ }
+ }
+
+ /// Perform all initialization required to run an instance of WebGLThread
+ /// in parallel on its own dedicated thread.
+ pub(crate) fn run_on_own_thread(init: WebGLThreadInit) {
+ thread::Builder::new()
+ .name("WebGL thread".to_owned())
+ .spawn(move || {
+ let mut data = WebGLThread::new(init);
+ data.process(EventLoop::Blocking, None);
+ })
+ .expect("Thread spawning failed");
+ }
+
+ fn process(&mut self, loop_type: EventLoop, textures: Option<TexturesMap>) -> bool {
+ let webgl_chan = WebGLChan(self.sender.clone());
+ while let Ok(msg) = match loop_type {
+ EventLoop::Blocking => self.receiver.recv(),
+ EventLoop::Nonblocking => self.receiver.try_recv(),
+ } {
+ let exit = self.handle_msg(msg, &webgl_chan, textures.as_ref());
+ if exit {
+ return false;
+ }
+ }
+ true
}
/// Handles a generic WebGLMsg message
- #[inline]
- fn handle_msg(&mut self, msg: WebGLMsg, webgl_chan: &WebGLChan) -> bool {
+ fn handle_msg(
+ &mut self,
+ msg: WebGLMsg,
+ webgl_chan: &WebGLChan,
+ textures: Option<&TexturesMap>,
+ ) -> bool {
trace!("processing {:?}", msg);
match msg {
WebGLMsg::CreateContext(version, size, attributes, result_sender) => {
- let result = self.create_webgl_context(version, size, attributes);
+ let result = self.create_webgl_context(version, size, attributes, textures);
result_sender
.send(result.map(|(id, limits, share_mode)| {
let data = Self::make_current_if_needed(
@@ -173,10 +266,10 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
.unwrap();
},
WebGLMsg::ResizeContext(ctx_id, size, sender) => {
- self.resize_webgl_context(ctx_id, size, sender);
+ self.resize_webgl_context(ctx_id, size, sender, textures);
},
WebGLMsg::RemoveContext(ctx_id) => {
- self.remove_webgl_context(ctx_id);
+ self.remove_webgl_context(ctx_id, textures);
},
WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => {
self.handle_webgl_command(ctx_id, command, backtrace);
@@ -296,6 +389,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
version: WebGLVersion,
size: Size2D<u32>,
attributes: GLContextAttributes,
+ textures: Option<&TexturesMap>,
) -> Result<(WebGLContextId, GLLimits, WebGLContextShareMode), String> {
// Creating a new GLContext may make the current bound context_id dirty.
// Clear it to ensure that make_current() is called in subsequent commands.
@@ -332,6 +426,11 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
state: Default::default(),
},
);
+
+ if let Some(ref textures) = textures {
+ textures.borrow_mut().insert(id, (texture_id, size));
+ }
+
self.cached_context_info.insert(
id,
WebGLContextInfo {
@@ -354,6 +453,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
context_id: WebGLContextId,
size: Size2D<u32>,
sender: WebGLSender<Result<(), String>>,
+ textures: Option<&TexturesMap>,
) {
let data = Self::make_current_if_needed_mut(
context_id,
@@ -378,6 +478,13 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
// Update webgl texture size. Texture id may change too.
info.texture_id = texture_id;
info.size = real_size;
+
+ if let Some(ref textures) = textures {
+ textures
+ .borrow_mut()
+ .insert(context_id, (texture_id, real_size));
+ }
+
// Update WR image if needed. Resize image updates are only required for SharedTexture mode.
// Readback mode already updates the image every frame to send the raw pixels.
// See `handle_update_wr_image`.
@@ -403,7 +510,7 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
}
/// Removes a WebGLContext and releases attached resources.
- fn remove_webgl_context(&mut self, context_id: WebGLContextId) {
+ fn remove_webgl_context(&mut self, context_id: WebGLContextId, textures: Option<&TexturesMap>) {
// Release webrender image keys.
if let Some(info) = self.cached_context_info.remove(&context_id) {
let mut txn = webrender_api::Transaction::new();
@@ -422,6 +529,10 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
// Release GL context.
self.contexts.remove(&context_id);
+ if let Some(ref textures) = textures {
+ textures.borrow_mut().remove(&context_id);
+ }
+
// Removing a GLContext may make the current bound context_id dirty.
self.bound_context_id = None;
}
@@ -729,12 +840,12 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
}
}
-impl<VR: WebVRRenderHandler + 'static> Drop for WebGLThread<VR> {
+impl Drop for WebGLThread {
fn drop(&mut self) {
// Call remove_context functions in order to correctly delete WebRender image keys.
let context_ids: Vec<WebGLContextId> = self.contexts.keys().map(|id| *id).collect();
for id in context_ids {
- self.remove_webgl_context(id);
+ self.remove_webgl_context(id, None);
}
}
}