diff options
author | Imanol Fernandez <mortimergoro@gmail.com> | 2017-09-21 15:16:46 +0200 |
---|---|---|
committer | Imanol Fernandez <mortimergoro@gmail.com> | 2017-10-16 20:56:53 +0200 |
commit | 8ae0739bab8a3c74e0685d9f53bbb155e4458aba (patch) | |
tree | e1521882893206d2dd3bf06de5260f7bf0994cb7 /components | |
parent | a9022be0c3e30249845ca5947ac0c0a6743c7991 (diff) | |
download | servo-8ae0739bab8a3c74e0685d9f53bbb155e4458aba.tar.gz servo-8ae0739bab8a3c74e0685d9f53bbb155e4458aba.zip |
Implement DOM to texture
Diffstat (limited to 'components')
-rw-r--r-- | components/canvas/Cargo.toml | 1 | ||||
-rw-r--r-- | components/canvas/lib.rs | 1 | ||||
-rw-r--r-- | components/canvas/webgl_mode/inprocess.rs | 56 | ||||
-rw-r--r-- | components/canvas/webgl_thread.rs | 62 | ||||
-rw-r--r-- | components/canvas_traits/webgl.rs | 28 | ||||
-rw-r--r-- | components/config/prefs.rs | 4 | ||||
-rw-r--r-- | components/constellation/pipeline.rs | 1 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 3 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 41 | ||||
-rw-r--r-- | components/script/dom/webgltexture.rs | 12 | ||||
-rw-r--r-- | components/script/dom/webidls/WebGLRenderingContext.webidl | 3 | ||||
-rw-r--r-- | components/script/dom/window.rs | 11 | ||||
-rw-r--r-- | components/script/script_thread.rs | 7 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 6 | ||||
-rw-r--r-- | components/servo/lib.rs | 13 |
15 files changed, 236 insertions, 13 deletions
diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index 00eb302369a..651531ef783 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -21,5 +21,6 @@ ipc-channel = "0.8" log = "0.3.5" num-traits = "0.1.32" offscreen_gl_context = { version = "0.11", features = ["serde", "osmesa"] } +servo_config = {path = "../config"} webrender = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs index e26d8c2b582..809a69237c0 100644 --- a/components/canvas/lib.rs +++ b/components/canvas/lib.rs @@ -15,6 +15,7 @@ extern crate ipc_channel; #[macro_use] extern crate log; extern crate num_traits; extern crate offscreen_gl_context; +extern crate servo_config; extern crate webrender; extern crate webrender_api; diff --git a/components/canvas/webgl_mode/inprocess.rs b/components/canvas/webgl_mode/inprocess.rs index 71ab8d8a934..d8d4b4656f1 100644 --- a/components/canvas/webgl_mode/inprocess.rs +++ b/components/canvas/webgl_mode/inprocess.rs @@ -6,9 +6,12 @@ use ::gl_context::GLContextFactory; use ::webgl_thread::{WebGLExternalImageApi, WebGLExternalImageHandler, WebGLThreadObserver, WebGLThread}; use canvas_traits::webgl::{WebGLChan, WebGLContextId, WebGLMsg, WebGLPipeline, WebGLReceiver}; use canvas_traits::webgl::{WebGLSender, WebVRCommand, WebVRRenderHandler}; +use canvas_traits::webgl::DOMToTextureCommand; use canvas_traits::webgl::webgl_channel; use euclid::Size2D; +use fnv::FnvHashMap; use gleam::gl; +use servo_config::prefs::PREFS; use std::marker::PhantomData; use std::rc::Rc; use webrender; @@ -23,14 +26,19 @@ impl WebGLThreads { webrender_gl: Rc<gl::Gl>, webrender_api_sender: webrender_api::RenderApiSender, webvr_compositor: Option<Box<WebVRRenderHandler>>) - -> (WebGLThreads, Box<webrender::ExternalImageHandler>) { + -> (WebGLThreads, Box<webrender::ExternalImageHandler>, Option<Box<webrender::OutputImageHandler>>) { // This implementation creates a single `WebGLThread` for all the pipelines. let channel = WebGLThread::start(gl_factory, webrender_api_sender, webvr_compositor.map(|c| WebVRRenderWrapper(c)), PhantomData); + let output_handler = if PREFS.is_dom_to_texture_enabled() { + Some(Box::new(OutputHandler::new(webrender_gl.clone(), channel.clone()))) + } else { + None + }; let external = WebGLExternalImageHandler::new(WebGLExternalImages::new(webrender_gl, channel.clone())); - (WebGLThreads(channel), Box::new(external)) + (WebGLThreads(channel), Box::new(external), output_handler.map(|b| b as Box<_>)) } /// Gets the WebGLThread handle for each script pipeline. @@ -105,3 +113,47 @@ impl WebVRRenderHandler for WebVRRenderWrapper { self.0.handle(command, texture); } } + +/// struct used to implement DOMToTexture feature and webrender::OutputImageHandler trait. +type OutputHandlerData = Option<(u32, Size2D<i32>)>; +struct OutputHandler { + webrender_gl: Rc<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>, +} + +impl OutputHandler { + fn new(webrender_gl: Rc<gl::Gl>, channel: WebGLSender<WebGLMsg>) -> Self { + Self { + webrender_gl, + webgl_channel: channel, + lock_channel: webgl_channel().unwrap(), + sync_objects: Default::default(), + } + } +} + +/// Bridge between the WR frame outputs and WebGL to implement DOMToTexture synchronization. +impl webrender::OutputImageHandler for OutputHandler { + fn lock(&mut self, id: webrender_api::PipelineId) -> Option<(u32, webrender_api::DeviceIntSize)> { + // 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::DeviceIntSize::new(size.width, size.height)) + }) + } + + 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); + } + } +} diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 2bb9077954a..76dfa752ade 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -36,6 +36,8 @@ pub struct WebGLThread<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver webvr_compositor: Option<VR>, /// Generic observer that listens WebGLContext creation, resize or removal events. observer: OB, + /// Texture ids and sizes used in DOM to texture outputs. + dom_outputs: FnvHashMap<webrender_api::PipelineId, DOMToTextureData>, } impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR, OB> { @@ -52,6 +54,7 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR, next_webgl_id: 0, webvr_compositor, observer: observer, + dom_outputs: Default::default(), } } @@ -117,6 +120,9 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR, WebGLMsg::UpdateWebRenderImage(ctx_id, sender) => { self.handle_update_wr_image(ctx_id, sender); }, + WebGLMsg::DOMToTextureCommand(command) => { + self.handle_dom_to_texture(command); + }, WebGLMsg::Exit => { return true; } @@ -323,6 +329,54 @@ impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR, sender.send(image_key).unwrap(); } + fn handle_dom_to_texture(&mut self, command: DOMToTextureCommand) { + match command { + DOMToTextureCommand::Attach(context_id, texture_id, document_id, pipeline_id, size) => { + let ctx = Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) + .expect("WebGLContext not found in a WebGL DOMToTextureCommand::Attach command"); + // Initialize the texture that WR will use for frame outputs. + ctx.gl().tex_image_2d(gl::TEXTURE_2D, + 0, + gl::RGBA as gl::GLint, + size.width, + size.height, + 0, + gl::RGBA, + gl::UNSIGNED_BYTE, + None); + self.dom_outputs.insert(pipeline_id, DOMToTextureData { + context_id, texture_id, document_id, size + }); + self.webrender_api.enable_frame_output(document_id, pipeline_id, true); + }, + DOMToTextureCommand::Lock(pipeline_id, gl_sync, sender) => { + let contexts = &self.contexts; + let bound_context_id = &mut self.bound_context_id; + let result = self.dom_outputs.get(&pipeline_id).and_then(|data| { + let ctx = Self::make_current_if_needed(data.context_id, contexts, bound_context_id); + ctx.and_then(|ctx| { + // The next glWaitSync call is used to synchronize the two flows of + // OpenGL commands (WR and WebGL) in order to avoid using semi-ready WR textures. + // glWaitSync doesn't block WebGL CPU thread. + ctx.gl().wait_sync(gl_sync as gl::GLsync, 0, gl::TIMEOUT_IGNORED); + Some((data.texture_id.get(), data.size)) + }) + }); + + // Send the texture id and size to WR. + sender.send(result).unwrap(); + }, + DOMToTextureCommand::Detach(texture_id) => { + if let Some((pipeline_id, document_id)) = self.dom_outputs.iter() + .find(|&(_, v)| v.texture_id == texture_id) + .map(|(k, v)| (*k, v.document_id)) { + self.webrender_api.enable_frame_output(document_id, pipeline_id, false); + self.dom_outputs.remove(&pipeline_id); + } + }, + } + } + /// Gets a reference to a GLContextWrapper for a given WebGLContextId and makes it current if required. fn make_current_if_needed<'a>(context_id: WebGLContextId, contexts: &'a FnvHashMap<WebGLContextId, GLContextWrapper>, @@ -552,6 +606,14 @@ impl<T: WebGLExternalImageApi> webrender::ExternalImageHandler for WebGLExternal } } +/// Data about the linked DOM<->WebGLTexture elements. +struct DOMToTextureData { + context_id: WebGLContextId, + texture_id: WebGLTextureId, + document_id: webrender_api::DocumentId, + size: Size2D<i32>, +} + /// WebGL Commands Implementation pub struct WebGLImpl; diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 98c4115c69c..fb555b265b3 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -6,7 +6,7 @@ use euclid::Size2D; use nonzero::NonZeroU32; use offscreen_gl_context::{GLContextAttributes, GLLimits}; use std::fmt; -use webrender_api; +use webrender_api::{DocumentId, ImageKey, PipelineId}; /// Sender type used in WebGLCommands. pub use ::webgl_channel::WebGLSender; @@ -46,7 +46,9 @@ pub enum WebGLMsg { /// Unlock messages are always sent after a Lock message. Unlock(WebGLContextId), /// Creates or updates the image keys required for WebRender. - UpdateWebRenderImage(WebGLContextId, WebGLSender<webrender_api::ImageKey>), + UpdateWebRenderImage(WebGLContextId, WebGLSender<ImageKey>), + /// Commands used for the DOMToTexture feature. + DOMToTextureCommand(DOMToTextureCommand), /// Frees all resources and closes the thread. Exit, } @@ -86,6 +88,11 @@ impl WebGLMsgSender { } } + /// Returns the WebGLContextId associated to this sender + pub fn context_id(&self) -> WebGLContextId { + self.ctx_id + } + /// Send a WebGLCommand message #[inline] pub fn send(&self, command: WebGLCommand) -> WebGLSendResult { @@ -113,9 +120,13 @@ impl WebGLMsgSender { } #[inline] - pub fn send_update_wr_image(&self, sender: WebGLSender<webrender_api::ImageKey>) -> WebGLSendResult { + pub fn send_update_wr_image(&self, sender: WebGLSender<ImageKey>) -> WebGLSendResult { self.sender.send(WebGLMsg::UpdateWebRenderImage(self.ctx_id, sender)) } + + pub fn send_dom_to_texture(&self, command: DOMToTextureCommand) -> WebGLSendResult { + self.sender.send(WebGLMsg::DOMToTextureCommand(command)) + } } /// WebGL Commands for a specific WebGLContext @@ -379,6 +390,17 @@ pub trait WebVRRenderHandler: Send { fn handle(&mut self, command: WebVRCommand, texture: Option<(u32, Size2D<i32>)>); } +/// WebGL commands required to implement DOMToTexture feature. +#[derive(Clone, Deserialize, Serialize)] +pub enum DOMToTextureCommand { + /// Attaches a HTMLIFrameElement to a WebGLTexture. + Attach(WebGLContextId, WebGLTextureId, DocumentId, PipelineId, Size2D<i32>), + /// Releases the HTMLIFrameElement to WebGLTexture attachment. + Detach(WebGLTextureId), + /// Lock message used for a correct synchronization with WebRender GL flow. + Lock(PipelineId, usize, WebGLSender<Option<(u32, Size2D<i32>)>>), +} + impl fmt::Debug for WebGLCommand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::WebGLCommand::*; diff --git a/components/config/prefs.rs b/components/config/prefs.rs index 3bfb94772b1..397b060cc03 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -273,4 +273,8 @@ impl Preferences { pub fn is_webvr_enabled(&self) -> bool { self.get("dom.webvr.enabled").as_boolean().unwrap_or(false) } + + pub fn is_dom_to_texture_enabled(&self) -> bool { + self.get("dom.webgl.dom_to_texture.enabled").as_boolean().unwrap_or(false) + } } diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 57cf07d07d8..d5a41df4460 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -511,6 +511,7 @@ impl UnprivilegedPipelineContent { content_process_shutdown_chan: self.script_content_process_shutdown_chan, webgl_chan: self.webgl_chan, webvr_chan: self.webvr_chan, + webrender_document: self.webrender_document, }, self.load_data.clone()); LTF::create(self.id, diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index f7d582ffee8..5c7723f17de 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -110,7 +110,7 @@ use style::stylesheets::keyframes_rule::Keyframe; use style::values::specified::Length; use time::Duration; use uuid::Uuid; -use webrender_api::ImageKey; +use webrender_api::{DocumentId, ImageKey}; use webvr_traits::WebVRGamepadHand; /// A trait to allow tracing (only) DOM objects. @@ -397,6 +397,7 @@ unsafe_no_jsmanaged_fields!(OpaqueStyleAndLayoutData); unsafe_no_jsmanaged_fields!(PathBuf); unsafe_no_jsmanaged_fields!(CSSErrorReporter); unsafe_no_jsmanaged_fields!(DrawAPaintImageResult); +unsafe_no_jsmanaged_fields!(DocumentId); unsafe_no_jsmanaged_fields!(ImageKey); unsafe_no_jsmanaged_fields!(WebGLBufferId); unsafe_no_jsmanaged_fields!(WebGLChan); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index c20b2273123..d4624d3eb85 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -6,6 +6,7 @@ use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; use canvas_traits::canvas::{byte_swap, multiply_u8_pixel}; use canvas_traits::webgl::{WebGLContextShareMode, WebGLCommand, WebGLError}; use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLParameter, WebVRCommand}; +use canvas_traits::webgl::DOMToTextureCommand; use canvas_traits::webgl::WebGLError::*; use canvas_traits::webgl::webgl_channel; use core::cell::Ref; @@ -25,6 +26,7 @@ use dom::bindings::str::DOMString; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmlcanvaselement::utils as canvas_utils; +use dom::htmliframeelement::HTMLIFrameElement; use dom::node::{Node, NodeDamage, window_from_node}; use dom::webgl_extensions::WebGLExtensions; use dom::webgl_validations::WebGLValidator; @@ -3261,6 +3263,45 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 + fn TexImageDOM(&self, + target: u32, + level: i32, + internal_format: u32, + width: i32, + height: i32, + format: u32, + data_type: u32, + source: &HTMLIFrameElement) -> Fallible<()> { + // Currently DOMToTexture only supports TEXTURE_2D, RGBA, UNSIGNED_BYTE and no levels. + if target != constants::TEXTURE_2D || level != 0 || internal_format != constants::RGBA || + format != constants::RGBA || data_type != constants::UNSIGNED_BYTE { + return Ok(self.webgl_error(InvalidValue)); + } + + // Get bound texture + let texture = match self.bound_texture(constants::TEXTURE_2D) { + Some(texture) => texture, + None => { + return Ok(self.webgl_error(InvalidOperation)); + } + }; + + let pipeline_id = source.pipeline_id().ok_or(Error::InvalidState)?; + let document_id = self.global().downcast::<Window>().ok_or(Error::InvalidState)?.webrender_document(); + + texture.set_attached_to_dom(); + + let command = DOMToTextureCommand::Attach(self.webgl_sender.context_id(), + texture.id(), + document_id, + pipeline_id.to_webrender(), + Size2D::new(width, height)); + self.webgl_sender.send_dom_to_texture(command).unwrap(); + + Ok(()) + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 #[allow(unsafe_code)] unsafe fn TexSubImage2D(&self, cx: *mut JSContext, diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index 59be8681337..6927fd10a48 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -5,6 +5,7 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLError, WebGLMsgSender, WebGLResult, WebGLTextureId}; +use canvas_traits::webgl::DOMToTextureCommand; use dom::bindings::cell::DomRefCell; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::codegen::Bindings::WebGLTextureBinding; @@ -45,6 +46,8 @@ pub struct WebGLTexture { mag_filter: Cell<Option<u32>>, #[ignore_heap_size_of = "Defined in ipc-channel"] renderer: WebGLMsgSender, + /// True if this texture is used for the DOMToTexture feature. + attached_to_dom: Cell<bool>, } impl WebGLTexture { @@ -62,6 +65,7 @@ impl WebGLTexture { mag_filter: Cell::new(None), image_info_array: DomRefCell::new([ImageInfo::new(); MAX_LEVEL_COUNT * MAX_FACE_COUNT]), renderer: renderer, + attached_to_dom: Cell::new(false), } } @@ -179,6 +183,10 @@ impl WebGLTexture { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); + // Notify WR to release the frame output when using DOMToTexture feature + if self.attached_to_dom.get() { + let _ = self.renderer.send_dom_to_texture(DOMToTextureCommand::Detach(self.id)); + } let _ = self.renderer.send(WebGLCommand::DeleteTexture(self.id)); } } @@ -374,6 +382,10 @@ impl WebGLTexture { Some(self.image_info_at_face(0, self.base_mipmap_level)) } + + pub fn set_attached_to_dom(&self) { + self.attached_to_dom.set(true); + } } impl Drop for WebGLTexture { diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl index 885ad9486bb..ec729d1b5fb 100644 --- a/components/script/dom/webidls/WebGLRenderingContext.webidl +++ b/components/script/dom/webidls/WebGLRenderingContext.webidl @@ -654,6 +654,9 @@ interface WebGLRenderingContextBase [Throws] void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, TexImageSource? source); // May throw DOMException + [Throws, Pref="dom.webgl.dom_to_texture.enabled"] + void texImageDOM(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, + GLenum format, GLenum type, HTMLIFrameElement source); // May throw DOMException void texParameterf(GLenum target, GLenum pname, GLfloat param); void texParameteri(GLenum target, GLenum pname, GLint param); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 1e4bf803427..047cc1678ea 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -123,7 +123,7 @@ use timers::{IsInterval, TimerCallback}; use tinyfiledialogs::{self, MessageBoxIcon}; use url::Position; use webdriver_handlers::jsval_to_webdriver; -use webrender_api::ClipId; +use webrender_api::{ClipId, DocumentId}; use webvr_traits::WebVRMsg; /// Current state of the window object @@ -289,6 +289,9 @@ pub struct Window { test_worklet: MutNullableDom<Worklet>, /// https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet paint_worklet: MutNullableDom<Worklet>, + /// The Webrender Document id associated with this window. + #[ignore_heap_size_of = "defined in webrender_api"] + webrender_document: DocumentId, } impl Window { @@ -1760,6 +1763,10 @@ impl Window { .send(msg) .unwrap(); } + + pub fn webrender_document(&self) -> DocumentId { + self.webrender_document + } } impl Window { @@ -1794,6 +1801,7 @@ impl Window { webgl_chan: WebGLChan, webvr_chan: Option<IpcSender<WebVRMsg>>, microtask_queue: Rc<MicrotaskQueue>, + webrender_document: DocumentId, ) -> DomRoot<Self> { let layout_rpc: Box<LayoutRPC + Send> = { let (rpc_send, rpc_recv) = channel(); @@ -1868,6 +1876,7 @@ impl Window { unminified_js_dir: Default::default(), test_worklet: Default::default(), paint_worklet: Default::default(), + webrender_document, }); unsafe { diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 119fe4bec2c..6c722cec865 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -124,6 +124,7 @@ use time::{get_time, precise_time_ns, Tm}; use url::Position; use url::percent_encoding::percent_decode; use webdriver_handlers; +use webrender_api::DocumentId; use webvr_traits::{WebVREvent, WebVRMsg}; pub type ImageCacheMsg = (PipelineId, PendingImageResponse); @@ -495,6 +496,9 @@ pub struct ScriptThread { /// https://html.spec.whatwg.org/multipage/#custom-element-reactions-stack custom_element_reaction_stack: CustomElementReactionStack, + + /// The Webrender Document ID associated with this thread. + webrender_document: DocumentId, } /// In the event of thread panic, all data on the stack runs its destructor. However, there @@ -871,6 +875,8 @@ impl ScriptThread { transitioning_nodes: Default::default(), custom_element_reaction_stack: CustomElementReactionStack::new(), + + webrender_document: state.webrender_document, } } @@ -2062,6 +2068,7 @@ impl ScriptThread { self.webgl_chan.channel(), self.webvr_chan.clone(), self.microtask_queue.clone(), + self.webrender_document, ); // Initialize the browsing context for the window. diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 8b2c98b1eb6..e8081c9eeaf 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -69,7 +69,7 @@ use std::sync::mpsc::{Receiver, Sender, RecvTimeoutError}; use style_traits::CSSPixel; use style_traits::SpeculativePainter; use webdriver_msg::{LoadStatus, WebDriverScriptCommand}; -use webrender_api::{ClipId, DevicePixel, ImageKey}; +use webrender_api::{ClipId, DevicePixel, DocumentId, ImageKey}; use webvr_traits::{WebVREvent, WebVRMsg}; pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry}; @@ -554,7 +554,9 @@ pub struct InitialScriptState { /// A channel to the webgl thread used in this pipeline. pub webgl_chan: WebGLPipeline, /// A channel to the webvr thread, if available. - pub webvr_chan: Option<IpcSender<WebVRMsg>> + pub webvr_chan: Option<IpcSender<WebVRMsg>>, + /// The Webrender document ID associated with this thread. + pub webrender_document: DocumentId, } /// This trait allows creating a `ScriptThread` without depending on the `script` diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 262f5a22130..75b07015037 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -553,13 +553,18 @@ fn create_constellation(user_agent: Cow<'static, str>, }; // Initialize WebGL Thread entry point. - let (webgl_threads, image_handler) = WebGLThreads::new(gl_factory, - window_gl, - webrender_api_sender.clone(), - webvr_compositor.map(|c| c as Box<_>)); + let (webgl_threads, image_handler, output_handler) = WebGLThreads::new(gl_factory, + window_gl, + webrender_api_sender.clone(), + webvr_compositor.map(|c| c as Box<_>)); // Set webrender external image handler for WebGL textures webrender.set_external_image_handler(image_handler); + // Set DOM to texture handler, if enabled. + if let Some(output_handler) = output_handler { + webrender.set_output_image_handler(output_handler); + } + let initial_state = InitialConstellationState { compositor_proxy, embedder_proxy, |