diff options
author | Imanol Fernandez <mortimergoro@gmail.com> | 2017-08-15 16:05:22 +0200 |
---|---|---|
committer | Imanol Fernandez <mortimergoro@gmail.com> | 2017-08-15 22:14:32 +0200 |
commit | 703962fe61d673536eb982b45795ae13748f0f6a (patch) | |
tree | c85f3cb5d55babab03d56dac8b0d10d588b0a0f9 | |
parent | e9cbbc58cc9655a15bc603effabbd4a4ff62b454 (diff) | |
download | servo-703962fe61d673536eb982b45795ae13748f0f6a.tar.gz servo-703962fe61d673536eb982b45795ae13748f0f6a.zip |
Improve WebGL architecture.
54 files changed, 3154 insertions, 1426 deletions
diff --git a/Cargo.lock b/Cargo.lock index 759122f23e5..4455b98c203 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -325,6 +325,7 @@ version = "0.0.1" dependencies = [ "azure 0.20.1 (git+https://github.com/servo/rust-azure)", "canvas_traits 0.0.1", + "compositing 0.0.1", "cssparser 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -332,7 +333,7 @@ dependencies = [ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "offscreen_gl_context 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "servo_config 0.0.1", + "webrender 0.48.0 (git+https://github.com/servo/webrender)", "webrender_api 0.48.0 (git+https://github.com/servo/webrender)", ] @@ -345,7 +346,10 @@ dependencies = [ "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "offscreen_gl_context 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "servo_config 0.0.1", "webrender_api 0.48.0 (git+https://github.com/servo/webrender)", ] @@ -526,7 +530,6 @@ dependencies = [ "msg 0.0.1", "net 0.0.1", "net_traits 0.0.1", - "offscreen_gl_context 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "profile_traits 0.0.1", "script_traits 0.0.1", "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2596,7 +2599,6 @@ dependencies = [ "metrics 0.0.1", "msg 0.0.1", "net_traits 0.0.1", - "offscreen_gl_context 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "profile_traits 0.0.1", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3529,12 +3531,13 @@ dependencies = [ name = "webvr" version = "0.0.1" dependencies = [ + "canvas_traits 0.0.1", + "euclid 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "script_traits 0.0.1", "servo_config 0.0.1", - "webrender_api 0.48.0 (git+https://github.com/servo/webrender)", "webvr_traits 0.0.1", ] diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index ad149daccb6..e8bf234a052 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -12,6 +12,7 @@ path = "lib.rs" [dependencies] azure = {git = "https://github.com/servo/rust-azure"} canvas_traits = {path = "../canvas_traits"} +compositing = {path = "../compositing"} cssparser = "0.19" euclid = "0.15" gleam = "0.4" @@ -19,5 +20,5 @@ ipc-channel = "0.8" log = "0.3.5" num-traits = "0.1.32" offscreen_gl_context = { version = "0.11", features = ["serde"] } -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/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index b7e21777001..8fe05d1f6a9 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -8,7 +8,7 @@ use azure::azure_hl::{BackendType, DrawOptions, DrawTarget, Pattern, StrokeOptio use azure::azure_hl::{Color, ColorPattern, DrawSurfaceOptions, Filter, PathBuilder}; use azure::azure_hl::{ExtendMode, GradientStop, LinearGradientPattern, RadialGradientPattern}; use azure::azure_hl::SurfacePattern; -use canvas_traits::*; +use canvas_traits::canvas::*; use cssparser::RGBA; use euclid::{Transform2D, Point2D, Vector2D, Rect, Size2D}; use ipc_channel::ipc::{self, IpcSender}; @@ -193,12 +193,8 @@ impl<'a> CanvasPaintThread<'a> { Canvas2dMsg::SetShadowColor(ref color) => painter.set_shadow_color(color.to_azure_style()), } }, - CanvasMsg::Common(message) => { - match message { - CanvasCommonMsg::Close => break, - CanvasCommonMsg::Recreate(size) => painter.recreate(size), - } - }, + CanvasMsg::Close => break, + CanvasMsg::Recreate(size) => painter.recreate(size), CanvasMsg::FromScript(message) => { match message { FromScriptMsg::SendPixels(chan) => { @@ -213,8 +209,6 @@ impl<'a> CanvasPaintThread<'a> { } } } - CanvasMsg::WebGL(_) => panic!("Wrong WebGL message sent to Canvas2D thread"), - CanvasMsg::WebVR(_) => panic!("Wrong WebVR message sent to Canvas2D thread"), } } }).expect("Thread spawning failed"); @@ -571,7 +565,7 @@ impl<'a> CanvasPaintThread<'a> { }) } - fn send_data(&mut self, chan: IpcSender<CanvasData>) { + fn send_data(&mut self, chan: IpcSender<CanvasImageData>) { self.drawtarget.snapshot().get_data_surface().with_data(|element| { let size = self.drawtarget.get_size(); @@ -614,7 +608,7 @@ impl<'a> CanvasPaintThread<'a> { let data = CanvasImageData { image_key: self.image_key.unwrap(), }; - chan.send(CanvasData::Image(data)).unwrap(); + chan.send(data).unwrap(); }) } diff --git a/components/canvas/gl_context.rs b/components/canvas/gl_context.rs new file mode 100644 index 00000000000..69a26c0e03c --- /dev/null +++ b/components/canvas/gl_context.rs @@ -0,0 +1,203 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use canvas_traits::webgl::WebGLCommand; +use compositing::compositor_thread::{CompositorProxy, self}; +use euclid::Size2D; +use gleam::gl; +use offscreen_gl_context::{ColorAttachmentType, GLContext, GLContextAttributes, GLContextDispatcher, GLLimits}; +use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle, NativeGLContextMethods}; +use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle}; +use std::sync::{Arc, Mutex}; +use super::webgl_thread::WebGLImpl; + +/// The GLContextFactory is used to create shared GL contexts with the main thread GL context. +/// Currently, shared textures are used to render WebGL textures into the WR compositor. +/// In order to create a shared context, the GLContextFactory stores the handle of the main GL context. +pub enum GLContextFactory { + Native(NativeGLContextHandle, Option<MainThreadDispatcher>), + OSMesa(OSMesaContextHandle), +} + +impl GLContextFactory { + /// Creates a new GLContextFactory that uses the currently bound GL context to create shared contexts. + pub fn current_native_handle(proxy: &CompositorProxy) -> Option<GLContextFactory> { + NativeGLContext::current_handle().map(|handle| { + if cfg!(target_os = "windows") { + // Used to dispatch functions from the GLContext thread to the main thread's event loop. + // Required to allow WGL GLContext sharing in Windows. + GLContextFactory::Native(handle, Some(MainThreadDispatcher::new(proxy.clone_compositor_proxy()))) + } else { + GLContextFactory::Native(handle, None) + } + }) + } + + /// Creates a new GLContextFactory that uses the currently bound OSMesa context to create shared contexts. + pub fn current_osmesa_handle() -> Option<GLContextFactory> { + OSMesaContext::current_handle().map(GLContextFactory::OSMesa) + } + + /// Creates a new shared GLContext with the main GLContext + pub fn new_shared_context(&self, + size: Size2D<i32>, + attributes: GLContextAttributes) -> Result<GLContextWrapper, &'static str> { + match *self { + GLContextFactory::Native(ref handle, ref dispatcher) => { + let dispatcher = dispatcher.as_ref().map(|d| Box::new(d.clone()) as Box<_>); + let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size, + attributes, + ColorAttachmentType::Texture, + gl::GlType::default(), + Some(handle), + dispatcher); + ctx.map(GLContextWrapper::Native) + } + GLContextFactory::OSMesa(ref handle) => { + let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(), + attributes, + ColorAttachmentType::Texture, + gl::GlType::default(), + Some(handle), + None); + ctx.map(GLContextWrapper::OSMesa) + } + } + } + + /// Creates a new non-shared GLContext + pub fn new_context(&self, + size: Size2D<i32>, + attributes: GLContextAttributes) -> Result<GLContextWrapper, &'static str> { + match *self { + GLContextFactory::Native(..) => { + let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size, + attributes, + ColorAttachmentType::Texture, + gl::GlType::default(), + None, + None); + ctx.map(GLContextWrapper::Native) + } + GLContextFactory::OSMesa(_) => { + let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(), + attributes, + ColorAttachmentType::Texture, + gl::GlType::default(), + None, + None); + ctx.map(GLContextWrapper::OSMesa) + } + } + } +} + + +/// GLContextWrapper used to abstract NativeGLContext and OSMesaContext types +pub enum GLContextWrapper { + Native(GLContext<NativeGLContext>), + OSMesa(GLContext<OSMesaContext>), +} + +impl GLContextWrapper { + pub fn make_current(&self) { + match *self { + GLContextWrapper::Native(ref ctx) => { + ctx.make_current().unwrap(); + } + GLContextWrapper::OSMesa(ref ctx) => { + ctx.make_current().unwrap(); + } + } + } + + pub fn unbind(&self) { + match *self { + GLContextWrapper::Native(ref ctx) => { + ctx.unbind().unwrap(); + } + GLContextWrapper::OSMesa(ref ctx) => { + ctx.unbind().unwrap(); + } + } + } + + pub fn apply_command(&self, cmd: WebGLCommand) { + match *self { + GLContextWrapper::Native(ref ctx) => { + WebGLImpl::apply(ctx, cmd); + } + GLContextWrapper::OSMesa(ref ctx) => { + WebGLImpl::apply(ctx, cmd); + } + } + } + + pub fn gl(&self) -> &gl::Gl { + match *self { + GLContextWrapper::Native(ref ctx) => { + ctx.gl() + } + GLContextWrapper::OSMesa(ref ctx) => { + ctx.gl() + } + } + } + + pub fn get_info(&self) -> (Size2D<i32>, u32, GLLimits) { + match *self { + GLContextWrapper::Native(ref ctx) => { + let (real_size, texture_id) = { + let draw_buffer = ctx.borrow_draw_buffer().unwrap(); + (draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap()) + }; + + let limits = ctx.borrow_limits().clone(); + + (real_size, texture_id, limits) + } + GLContextWrapper::OSMesa(ref ctx) => { + let (real_size, texture_id) = { + let draw_buffer = ctx.borrow_draw_buffer().unwrap(); + (draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap()) + }; + + let limits = ctx.borrow_limits().clone(); + + (real_size, texture_id, limits) + } + } + } + + pub fn resize(&mut self, size: Size2D<i32>) -> Result<(), &'static str> { + match *self { + GLContextWrapper::Native(ref mut ctx) => { + ctx.resize(size) + } + GLContextWrapper::OSMesa(ref mut ctx) => { + ctx.resize(size) + } + } + } +} + +/// Implements GLContextDispatcher to dispatch functions from GLContext threads to the main thread's event loop. +/// It's used in Windows to allow WGL GLContext sharing. +#[derive(Clone)] +pub struct MainThreadDispatcher { + compositor_proxy: Arc<Mutex<CompositorProxy>> +} + +impl MainThreadDispatcher { + fn new(proxy: CompositorProxy) -> Self { + Self { + compositor_proxy: Arc::new(Mutex::new(proxy)), + } + } +} +impl GLContextDispatcher for MainThreadDispatcher { + fn dispatch(&self, f: Box<Fn() + Send>) { + self.compositor_proxy.lock().unwrap().send(compositor_thread::Msg::Dispatch(f)); + } +} diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs index a3d90909637..b9f0823a07d 100644 --- a/components/canvas/lib.rs +++ b/components/canvas/lib.rs @@ -6,16 +6,18 @@ extern crate azure; extern crate canvas_traits; +extern crate compositing; extern crate cssparser; extern crate euclid; extern crate gleam; extern crate ipc_channel; -#[macro_use] -extern crate log; +#[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; pub mod canvas_paint_thread; -pub mod webgl_paint_thread; +pub mod gl_context; +mod webgl_mode; +pub mod webgl_thread; diff --git a/components/canvas/webgl_mode/inprocess.rs b/components/canvas/webgl_mode/inprocess.rs new file mode 100644 index 00000000000..257f1395545 --- /dev/null +++ b/components/canvas/webgl_mode/inprocess.rs @@ -0,0 +1,95 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +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::webgl_channel; +use euclid::Size2D; +use std::marker::PhantomData; +use webrender; +use webrender_api; + +/// WebGL Threading API entry point that lives in the constellation. +pub struct WebGLThreads(WebGLSender<WebGLMsg>); + +impl WebGLThreads { + /// Creates a new WebGLThreads object + pub fn new(gl_factory: GLContextFactory, + webrender_api_sender: webrender_api::RenderApiSender, + webvr_compositor: Option<Box<WebVRRenderHandler>>) + -> (WebGLThreads, Box<webrender::ExternalImageHandler>) { + // 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 external = WebGLExternalImageHandler::new(WebGLExternalImages::new(channel.clone())); + (WebGLThreads(channel), Box::new(external)) + } + + /// Gets the WebGLThread handle for each script pipeline. + pub fn pipeline(&self) -> WebGLPipeline { + // This mode creates a single thread, so the existing WebGLChan is just cloned. + WebGLPipeline(WebGLChan(self.0.clone())) + } + + /// Sends a exit message to close the WebGLThreads and release all WebGLContexts. + pub fn exit(&self) -> Result<(), &'static str> { + self.0.send(WebGLMsg::Exit).map_err(|_| "Failed to send Exit message") + } +} + +/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads. +struct WebGLExternalImages { + webgl_channel: WebGLSender<WebGLMsg>, + // Used to avoid creating a new channel on each received WebRender request. + lock_channel: (WebGLSender<(u32, Size2D<i32>)>, WebGLReceiver<(u32, Size2D<i32>)>), +} + +impl WebGLExternalImages { + fn new(channel: WebGLSender<WebGLMsg>) -> Self { + Self { + webgl_channel: channel, + lock_channel: webgl_channel().unwrap(), + } + } +} + +impl WebGLExternalImageApi for WebGLExternalImages { + fn lock(&mut self, ctx_id: WebGLContextId) -> (u32, Size2D<i32>) { + self.webgl_channel.send(WebGLMsg::Lock(ctx_id, self.lock_channel.0.clone())).unwrap(); + self.lock_channel.1.recv().unwrap() + } + + fn unlock(&mut self, ctx_id: WebGLContextId) { + self.webgl_channel.send(WebGLMsg::Unlock(ctx_id)).unwrap(); + } +} + +/// Custom observer used in a `WebGLThread`. +impl WebGLThreadObserver for PhantomData<()> { + fn on_context_create(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>) { + debug!("WebGLContext created (ctx_id: {:?} texture_id: {:?} size: {:?}", ctx_id, texture_id, size); + } + + fn on_context_resize(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>) { + debug!("WebGLContext resized (ctx_id: {:?} texture_id: {:?} size: {:?}", ctx_id, texture_id, size); + } + + fn on_context_delete(&mut self, ctx_id: WebGLContextId) { + debug!("WebGLContext deleted (ctx_id: {:?})", ctx_id); + } +} + + +/// Wrapper to send WebVR commands used in `WebGLThread`. +struct WebVRRenderWrapper(Box<WebVRRenderHandler>); + +impl WebVRRenderHandler for WebVRRenderWrapper { + fn handle(&mut self, command: WebVRCommand, texture: Option<(u32, Size2D<i32>)>) { + self.0.handle(command, texture); + } +} diff --git a/components/canvas/webgl_mode/mod.rs b/components/canvas/webgl_mode/mod.rs new file mode 100644 index 00000000000..660818fb096 --- /dev/null +++ b/components/canvas/webgl_mode/mod.rs @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +mod inprocess; +pub use self::inprocess::WebGLThreads; diff --git a/components/canvas/webgl_paint_thread.rs b/components/canvas/webgl_paint_thread.rs deleted file mode 100644 index 2b6819effba..00000000000 --- a/components/canvas/webgl_paint_thread.rs +++ /dev/null @@ -1,379 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use canvas_traits::{CanvasCommonMsg, CanvasData, CanvasMsg, CanvasImageData}; -use canvas_traits::{FromLayoutMsg, FromScriptMsg, byte_swap}; -use euclid::Size2D; -use gleam::gl; -use ipc_channel::ipc::{self, IpcSender}; -use offscreen_gl_context::{ColorAttachmentType, GLContext, GLLimits}; -use offscreen_gl_context::{GLContextAttributes, NativeGLContext, OSMesaContext}; -use servo_config::opts; -use std::borrow::ToOwned; -use std::mem; -use std::sync::Arc; -use std::sync::mpsc::channel; -use std::thread; -use webrender_api; - -enum GLContextWrapper { - Native(GLContext<NativeGLContext>), - OSMesa(GLContext<OSMesaContext>), -} - -impl GLContextWrapper { - fn new(size: Size2D<i32>, - attributes: GLContextAttributes, - gl_type: gl::GlType) -> Result<GLContextWrapper, &'static str> { - if opts::get().should_use_osmesa() { - let ctx = GLContext::<OSMesaContext>::new(size, - attributes, - ColorAttachmentType::Texture, - gl_type, - None); - ctx.map(GLContextWrapper::OSMesa) - } else { - let ctx = GLContext::<NativeGLContext>::new(size, - attributes, - ColorAttachmentType::Texture, - gl_type, - None); - ctx.map(GLContextWrapper::Native) - } - } - - pub fn get_limits(&self) -> GLLimits { - match *self { - GLContextWrapper::Native(ref ctx) => { - ctx.borrow_limits().clone() - } - GLContextWrapper::OSMesa(ref ctx) => { - ctx.borrow_limits().clone() - } - } - } - - fn resize(&mut self, size: Size2D<i32>) -> Result<Size2D<i32>, &'static str> { - match *self { - GLContextWrapper::Native(ref mut ctx) => { - ctx.resize(size)?; - Ok(ctx.borrow_draw_buffer().unwrap().size()) - } - GLContextWrapper::OSMesa(ref mut ctx) => { - ctx.resize(size)?; - Ok(ctx.borrow_draw_buffer().unwrap().size()) - } - } - } - - fn gl(&self) -> &gl::Gl { - match *self { - GLContextWrapper::Native(ref ctx) => { - ctx.gl() - } - GLContextWrapper::OSMesa(ref ctx) => { - ctx.gl() - } - } - } - - pub fn make_current(&self) { - match *self { - GLContextWrapper::Native(ref ctx) => { - ctx.make_current().unwrap(); - } - GLContextWrapper::OSMesa(ref ctx) => { - ctx.make_current().unwrap(); - } - } - } - - pub fn apply_command(&self, cmd: webrender_api::WebGLCommand) { - match *self { - GLContextWrapper::Native(ref ctx) => { - cmd.apply(ctx); - } - GLContextWrapper::OSMesa(ref ctx) => { - cmd.apply(ctx); - } - } - } -} - -enum WebGLPaintTaskData { - WebRender(webrender_api::RenderApi, webrender_api::WebGLContextId), - Readback { - context: GLContextWrapper, - webrender_api: webrender_api::RenderApi, - image_key: Option<webrender_api::ImageKey>, - /// An old webrender image key that can be deleted when the next epoch ends. - old_image_key: Option<webrender_api::ImageKey>, - /// An old webrender image key that can be deleted when the current epoch ends. - very_old_image_key: Option<webrender_api::ImageKey>, - }, -} - -pub struct WebGLPaintThread { - size: Size2D<i32>, - data: WebGLPaintTaskData, -} - -fn create_readback_painter(size: Size2D<i32>, - attrs: GLContextAttributes, - webrender_api: webrender_api::RenderApi, - gl_type: gl::GlType) - -> Result<(WebGLPaintThread, GLLimits), String> { - let context = GLContextWrapper::new(size, attrs, gl_type)?; - let limits = context.get_limits(); - let painter = WebGLPaintThread { - size: size, - data: WebGLPaintTaskData::Readback { - context: context, - webrender_api: webrender_api, - image_key: None, - old_image_key: None, - very_old_image_key: None, - }, - }; - - Ok((painter, limits)) -} - -impl WebGLPaintThread { - fn new(size: Size2D<i32>, - attrs: GLContextAttributes, - webrender_api_sender: webrender_api::RenderApiSender, - gl_type: gl::GlType) - -> Result<(WebGLPaintThread, GLLimits), String> { - let wr_api = webrender_api_sender.create_api(); - let device_size = webrender_api::DeviceIntSize::from_untyped(&size); - match wr_api.request_webgl_context(&device_size, attrs) { - Ok((id, limits)) => { - let painter = WebGLPaintThread { - data: WebGLPaintTaskData::WebRender(wr_api, id), - size: size - }; - Ok((painter, limits)) - }, - Err(msg) => { - warn!("Initial context creation failed, falling back to readback: {}", msg); - create_readback_painter(size, attrs, wr_api, gl_type) - } - } - } - - fn handle_webgl_message(&self, message: webrender_api::WebGLCommand) { - debug!("WebGL message: {:?}", message); - match self.data { - WebGLPaintTaskData::WebRender(ref api, id) => { - api.send_webgl_command(id, message); - } - WebGLPaintTaskData::Readback { ref context, .. } => { - context.apply_command(message); - } - } - } - - fn handle_webvr_message(&self, message: webrender_api::VRCompositorCommand) { - match self.data { - WebGLPaintTaskData::WebRender(ref api, id) => { - api.send_vr_compositor_command(id, message); - } - WebGLPaintTaskData::Readback { .. } => { - error!("Webrender is required for WebVR implementation"); - } - } - } - - - /// Creates a new `WebGLPaintThread` and returns an `IpcSender` to - /// communicate with it. - pub fn start(size: Size2D<i32>, - attrs: GLContextAttributes, - webrender_api_sender: webrender_api::RenderApiSender) - -> Result<(IpcSender<CanvasMsg>, GLLimits), String> { - let (sender, receiver) = ipc::channel::<CanvasMsg>().unwrap(); - let (result_chan, result_port) = channel(); - thread::Builder::new().name("WebGLThread".to_owned()).spawn(move || { - let gl_type = gl::GlType::default(); - let mut painter = match WebGLPaintThread::new(size, attrs, webrender_api_sender, gl_type) { - Ok((thread, limits)) => { - result_chan.send(Ok(limits)).unwrap(); - thread - }, - Err(e) => { - result_chan.send(Err(e)).unwrap(); - return - } - }; - painter.init(); - loop { - match receiver.recv().unwrap() { - CanvasMsg::WebGL(message) => painter.handle_webgl_message(message), - CanvasMsg::Common(message) => { - match message { - CanvasCommonMsg::Close => break, - // TODO(emilio): handle error nicely - CanvasCommonMsg::Recreate(size) => painter.recreate(size).unwrap(), - } - }, - CanvasMsg::FromScript(message) => { - match message { - FromScriptMsg::SendPixels(chan) =>{ - // Read the comment on - // HTMLCanvasElement::fetch_all_data. - chan.send(None).unwrap(); - } - } - } - CanvasMsg::FromLayout(message) => { - match message { - FromLayoutMsg::SendData(chan) => - painter.send_data(chan), - } - } - CanvasMsg::Canvas2d(_) => panic!("Wrong message sent to WebGLThread"), - CanvasMsg::WebVR(message) => painter.handle_webvr_message(message) - } - } - }).expect("Thread spawning failed"); - - result_port.recv().unwrap().map(|limits| (sender, limits)) - } - - fn send_data(&mut self, chan: IpcSender<CanvasData>) { - match self.data { - WebGLPaintTaskData::Readback { - ref context, - ref webrender_api, - ref mut image_key, - ref mut old_image_key, - ref mut very_old_image_key, - } => { - let width = self.size.width as usize; - let height = self.size.height as usize; - - let mut pixels = context.gl().read_pixels(0, 0, - self.size.width as gl::GLsizei, - self.size.height as gl::GLsizei, - gl::RGBA, gl::UNSIGNED_BYTE); - // flip image vertically (texture is upside down) - let orig_pixels = pixels.clone(); - let stride = width * 4; - for y in 0..height { - let dst_start = y * stride; - let src_start = (height - y - 1) * stride; - let src_slice = &orig_pixels[src_start .. src_start + stride]; - (&mut pixels[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]); - } - - // rgba -> bgra - byte_swap(&mut pixels); - - let descriptor = webrender_api::ImageDescriptor { - width: width as u32, - height: height as u32, - stride: None, - format: webrender_api::ImageFormat::BGRA8, - offset: 0, - is_opaque: false, - }; - let data = webrender_api::ImageData::Raw(Arc::new(pixels)); - - let mut updates = webrender_api::ResourceUpdates::new(); - - match *image_key { - Some(image_key) => { - updates.update_image(image_key, - descriptor, - data, - None); - } - None => { - *image_key = Some(webrender_api.generate_image_key()); - updates.add_image(image_key.unwrap(), - descriptor, - data, - None); - } - } - - if let Some(image_key) = mem::replace(very_old_image_key, old_image_key.take()) { - updates.delete_image(image_key); - } - - webrender_api.update_resources(updates); - - let image_data = CanvasImageData { - image_key: image_key.unwrap(), - }; - - chan.send(CanvasData::Image(image_data)).unwrap(); - } - WebGLPaintTaskData::WebRender(_, id) => { - chan.send(CanvasData::WebGL(id)).unwrap(); - } - } - } - - #[allow(unsafe_code)] - fn recreate(&mut self, size: Size2D<i32>) -> Result<(), &'static str> { - match self.data { - WebGLPaintTaskData::Readback { ref mut context, ref mut image_key, ref mut old_image_key, .. } => { - if size.width > self.size.width || - size.height > self.size.height { - self.size = context.resize(size)?; - } else { - self.size = size; - context.gl().scissor(0, 0, size.width, size.height); - } - // Webrender doesn't let images change size, so we clear the webrender image key. - if let Some(image_key) = image_key.take() { - // If this executes, then we are in a new epoch since we last recreated the canvas, - // so `old_image_key` must be `None`. - debug_assert!(old_image_key.is_none()); - *old_image_key = Some(image_key); - } - } - WebGLPaintTaskData::WebRender(ref api, id) => { - let device_size = webrender_api::DeviceIntSize::from_untyped(&size); - api.resize_webgl_context(id, &device_size); - } - } - - Ok(()) - } - - fn init(&mut self) { - if let WebGLPaintTaskData::Readback { ref context, .. } = self.data { - context.make_current(); - } - } -} - -impl Drop for WebGLPaintThread { - fn drop(&mut self) { - if let WebGLPaintTaskData::Readback { - ref mut webrender_api, - image_key, - old_image_key, - very_old_image_key, - .. - } = self.data { - let mut updates = webrender_api::ResourceUpdates::new(); - - if let Some(image_key) = image_key { - updates.delete_image(image_key); - } - if let Some(image_key) = old_image_key { - updates.delete_image(image_key); - } - if let Some(image_key) = very_old_image_key { - updates.delete_image(image_key); - } - - webrender_api.update_resources(updates); - } - } -} diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs new file mode 100644 index 00000000000..907233a3b89 --- /dev/null +++ b/components/canvas/webgl_thread.rs @@ -0,0 +1,1204 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use canvas_traits::canvas::byte_swap; +use canvas_traits::webgl::*; +use euclid::Size2D; +use gleam::gl; +use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods}; +use std::collections::HashMap; +use std::mem; +use std::thread; +use super::gl_context::{GLContextFactory, GLContextWrapper}; +use webrender; +use webrender_api; + +/// WebGL Threading API entry point that lives in the constellation. +/// It allows to get a WebGLThread handle for each script pipeline. +pub use ::webgl_mode::WebGLThreads; + +/// 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, OB: WebGLThreadObserver> { + /// 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. + webrender_api: webrender_api::RenderApi, + /// Map of live WebGLContexts. + contexts: HashMap<WebGLContextId, GLContextWrapper>, + /// Cached information for WebGLContexts. + cached_context_info: HashMap<WebGLContextId, WebGLContextInfo>, + /// Current bound context. + bound_context_id: Option<WebGLContextId>, + /// Id generator for new WebGLContexts. + next_webgl_id: usize, + /// Handler user to send WebVR commands. + webvr_compositor: Option<VR>, + /// Generic observer that listens WebGLContext creation, resize or removal events. + observer: OB, +} + +impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> WebGLThread<VR, OB> { + pub fn new(gl_factory: GLContextFactory, + webrender_api_sender: webrender_api::RenderApiSender, + webvr_compositor: Option<VR>, + observer: OB) -> Self { + WebGLThread { + gl_factory, + webrender_api: webrender_api_sender.create_api(), + contexts: HashMap::new(), + cached_context_info: HashMap::new(), + bound_context_id: None, + next_webgl_id: 0, + webvr_compositor, + observer: observer, + } + } + + /// 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>, + observer: OB) + -> WebGLSender<WebGLMsg> { + let (sender, receiver) = webgl_channel::<WebGLMsg>().unwrap(); + let result = sender.clone(); + thread::Builder::new().name("WebGLThread".to_owned()).spawn(move || { + let mut renderer = WebGLThread::new(gl_factory, + webrender_api_sender, + webvr_compositor, + observer); + let webgl_chan = WebGLChan(sender); + loop { + let msg = receiver.recv().unwrap(); + let exit = renderer.handle_msg(msg, &webgl_chan); + if exit { + return; + } + } + }).expect("Thread spawning failed"); + + result + } + + /// Handles a generic WebGLMsg message + #[inline] + fn handle_msg(&mut self, msg: WebGLMsg, webgl_chan: &WebGLChan) -> bool { + match msg { + WebGLMsg::CreateContext(size, attributes, result_sender) => { + let result = self.create_webgl_context(size, attributes); + result_sender.send(result.map(|(id, limits, share_mode)| + WebGLCreateContextResult { + sender: WebGLMsgSender::new(id, webgl_chan.clone()), + limits: limits, + share_mode: share_mode, + } + )).unwrap(); + }, + WebGLMsg::ResizeContext(ctx_id, size, sender) => { + self.resize_webgl_context(ctx_id, size, sender); + }, + WebGLMsg::RemoveContext(ctx_id) => { + self.remove_webgl_context(ctx_id); + }, + WebGLMsg::WebGLCommand(ctx_id, command) => { + self.handle_webgl_command(ctx_id, command); + }, + WebGLMsg::WebVRCommand(ctx_id, command) => { + self.handle_webvr_command(ctx_id, command); + }, + WebGLMsg::Lock(ctx_id, sender) => { + self.handle_lock(ctx_id, sender); + }, + WebGLMsg::Unlock(ctx_id) => { + self.handle_unlock(ctx_id); + }, + WebGLMsg::UpdateWebRenderImage(ctx_id, sender) => { + self.handle_update_wr_image(ctx_id, sender); + }, + WebGLMsg::Exit => { + return true; + } + } + + false + } + + /// Handles a WebGLCommand for a specific WebGLContext + fn handle_webgl_command(&mut self, context_id: WebGLContextId, command: WebGLCommand) { + if let Some(ctx) = Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) { + ctx.apply_command(command); + } + } + + /// Handles a WebVRCommand for a specific WebGLContext + fn handle_webvr_command(&mut self, context_id: WebGLContextId, command: WebVRCommand) { + Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id); + let texture = match command { + WebVRCommand::SubmitFrame(..) => { + self.cached_context_info.get(&context_id) + }, + _ => None + }; + self.webvr_compositor.as_mut().unwrap().handle(command, texture.map(|t| (t.texture_id, t.size))); + } + + /// Handles a lock external callback received from webrender::ExternalImageHandler + fn handle_lock(&mut self, context_id: WebGLContextId, sender: WebGLSender<(u32, Size2D<i32>)>) { + let ctx = Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) + .expect("WebGLContext not found in a WebGLMsg::Lock message"); + let info = self.cached_context_info.get_mut(&context_id).unwrap(); + // Use a OpenGL Fence to perform the lock. + info.gl_sync = Some(ctx.gl().fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0)); + + sender.send((info.texture_id, info.size)).unwrap(); + } + + /// Handles an unlock external callback received from webrender::ExternalImageHandler + fn handle_unlock(&mut self, context_id: WebGLContextId) { + let ctx = Self::make_current_if_needed(context_id, &self.contexts, &mut self.bound_context_id) + .expect("WebGLContext not found in a WebGLMsg::Unlock message"); + let info = self.cached_context_info.get_mut(&context_id).unwrap(); + if let Some(gl_sync) = info.gl_sync.take() { + // glFlush must be called before glWaitSync. + ctx.gl().flush(); + // Wait until the GLSync object is signaled. + ctx.gl().wait_sync(gl_sync, 0, gl::TIMEOUT_IGNORED); + // Release the GLSync object. + ctx.gl().delete_sync(gl_sync); + } + } + + /// Creates a new WebGLContext + fn create_webgl_context(&mut self, + size: Size2D<i32>, + attributes: GLContextAttributes) + -> Result<(WebGLContextId, GLLimits, WebGLContextShareMode), String> { + // First try to create a shared context for the best performance. + // Fallback to readback mode if the shared context creation fails. + let result = self.gl_factory.new_shared_context(size, attributes) + .map(|r| (r, WebGLContextShareMode::SharedTexture)) + .or_else(|_| { + let ctx = self.gl_factory.new_context(size, attributes); + ctx.map(|r| (r, WebGLContextShareMode::Readback)) + }); + + // Creating a new GLContext may make the current bound context_id dirty. + // Clear it to ensure that make_current() is called in subsequent commands. + self.bound_context_id = None; + + match result { + Ok((ctx, share_mode)) => { + let id = WebGLContextId(self.next_webgl_id); + let (size, texture_id, limits) = ctx.get_info(); + self.next_webgl_id += 1; + self.contexts.insert(id, ctx); + self.cached_context_info.insert(id, WebGLContextInfo { + texture_id, + size, + alpha: attributes.alpha, + image_key: None, + share_mode, + gl_sync: None, + old_image_key: None, + very_old_image_key: None, + }); + + self.observer.on_context_create(id, texture_id, size); + + Ok((id, limits, share_mode)) + }, + Err(msg) => { + Err(msg.to_owned()) + } + } + } + + /// Resizes a WebGLContext + fn resize_webgl_context(&mut self, + context_id: WebGLContextId, + size: Size2D<i32>, + sender: WebGLSender<Result<(), String>>) { + let ctx = Self::make_current_if_needed_mut(context_id, &mut self.contexts, &mut self.bound_context_id); + match ctx.resize(size) { + Ok(_) => { + let (real_size, texture_id, _) = ctx.get_info(); + self.observer.on_context_resize(context_id, texture_id, real_size); + + let info = self.cached_context_info.get_mut(&context_id).unwrap(); + // Update webgl texture size. Texture id may change too. + info.texture_id = texture_id; + info.size = real_size; + // WR doesn't support resizing and requires to create a new `ImageKey`. + // Mark the current image_key to be deleted later in the next epoch. + if let Some(image_key) = info.image_key.take() { + // If this executes, then we are in a new epoch since we last recreated the canvas, + // so `old_image_key` must be `None`. + debug_assert!(info.old_image_key.is_none()); + info.old_image_key = Some(image_key); + } + + sender.send(Ok(())).unwrap(); + }, + Err(msg) => { + sender.send(Err(msg.into())).unwrap(); + } + } + } + + /// Removes a WebGLContext and releases attached resources. + fn remove_webgl_context(&mut self, context_id: WebGLContextId) { + // Release webrender image keys. + if let Some(info) = self.cached_context_info.remove(&context_id) { + let mut updates = webrender_api::ResourceUpdates::new(); + + if let Some(image_key) = info.image_key { + updates.delete_image(image_key); + } + if let Some(image_key) = info.old_image_key { + updates.delete_image(image_key); + } + if let Some(image_key) = info.very_old_image_key { + updates.delete_image(image_key); + } + + self.webrender_api.update_resources(updates) + } + + // Release GL context. + if self.contexts.remove(&context_id).is_some() { + self.observer.on_context_delete(context_id); + } + + // Removing a GLContext may make the current bound context_id dirty. + self.bound_context_id = None; + } + + /// Handles the creation/update of webrender_api::ImageKeys fpr a specific WebGLContext. + /// This method is invoked from a UpdateWebRenderImage message sent by the layout thread. + /// If SharedTexture is used the UpdateWebRenderImage message is sent only after a WebGLContext creation or resize. + /// If Readback is used UpdateWebRenderImage message is sent always on each layout iteration in order to + /// submit the updated raw pixels. + fn handle_update_wr_image(&mut self, context_id: WebGLContextId, sender: WebGLSender<webrender_api::ImageKey>) { + let info = self.cached_context_info.get_mut(&context_id).unwrap(); + let webrender_api = &self.webrender_api; + + let image_key = match info.share_mode { + WebGLContextShareMode::SharedTexture => { + let size = info.size; + let alpha = info.alpha; + // Reuse existing ImageKey or generate a new one. + // When using a shared texture ImageKeys are only generated after a WebGLContext creation or resize. + *info.image_key.get_or_insert_with(|| { + Self::create_wr_external_image(webrender_api, size, alpha, context_id) + }) + }, + WebGLContextShareMode::Readback => { + let pixels = Self::raw_pixels(&self.contexts[&context_id], info.size); + match info.image_key.clone() { + Some(image_key) => { + // ImageKey was already created, but WR Images must + // be updated every frame in readback mode to send the new raw pixels. + Self::update_wr_readback_image(webrender_api, + info.size, + info.alpha, + image_key, + pixels); + + image_key + }, + None => { + // Generate a new ImageKey for Readback mode. + let image_key = Self::create_wr_readback_image(webrender_api, + info.size, + info.alpha, + pixels); + info.image_key = Some(image_key); + image_key + } + } + } + }; + + // Delete old image + if let Some(image_key) = mem::replace(&mut info.very_old_image_key, info.old_image_key.take()) { + let mut updates = webrender_api::ResourceUpdates::new(); + updates.delete_image(image_key); + self.webrender_api.update_resources(updates); + } + + // Send the ImageKey to the Layout thread. + sender.send(image_key).unwrap(); + } + + /// 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 HashMap<WebGLContextId, GLContextWrapper>, + bound_id: &mut Option<WebGLContextId>) -> Option<&'a GLContextWrapper> { + contexts.get(&context_id).and_then(|ctx| { + if Some(context_id) != *bound_id { + ctx.make_current(); + *bound_id = Some(context_id); + } + + Some(ctx) + }) + } + + /// Gets a mutable reference to a GLContextWrapper for a WebGLContextId and makes it current if required. + fn make_current_if_needed_mut<'a>(context_id: WebGLContextId, + contexts: &'a mut HashMap<WebGLContextId, GLContextWrapper>, + bound_id: &mut Option<WebGLContextId>) -> &'a mut GLContextWrapper { + let ctx = contexts.get_mut(&context_id).expect("WebGLContext not found!"); + if Some(context_id) != *bound_id { + ctx.make_current(); + *bound_id = Some(context_id); + } + ctx + } + + /// Creates a `webrender_api::ImageKey` that uses shared textures. + fn create_wr_external_image(webrender_api: &webrender_api::RenderApi, + size: Size2D<i32>, + alpha: bool, + context_id: WebGLContextId) -> webrender_api::ImageKey { + let descriptor = Self::image_descriptor(size, alpha); + + let data = webrender_api::ExternalImageData { + id: webrender_api::ExternalImageId(context_id.0 as u64), + channel_index: 0, + image_type: webrender_api::ExternalImageType::Texture2DHandle, + }; + let data = webrender_api::ImageData::External(data); + + let image_key = webrender_api.generate_image_key(); + let mut updates = webrender_api::ResourceUpdates::new(); + updates.add_image(image_key, + descriptor, + data, + None); + webrender_api.update_resources(updates); + + image_key + } + + /// Creates a `webrender_api::ImageKey` that uses raw pixels. + fn create_wr_readback_image(webrender_api: &webrender_api::RenderApi, + size: Size2D<i32>, + alpha: bool, + data: Vec<u8>) -> webrender_api::ImageKey { + let descriptor = Self::image_descriptor(size, alpha); + let data = webrender_api::ImageData::new(data); + + let image_key = webrender_api.generate_image_key(); + let mut updates = webrender_api::ResourceUpdates::new(); + updates.add_image(image_key, + descriptor, + data, + None); + webrender_api.update_resources(updates); + + image_key + } + + /// Updates a `webrender_api::ImageKey` that uses raw pixels. + fn update_wr_readback_image(webrender_api: &webrender_api::RenderApi, + size: Size2D<i32>, + alpha: bool, + image_key: webrender_api::ImageKey, + data: Vec<u8>) { + let descriptor = Self::image_descriptor(size, alpha); + let data = webrender_api::ImageData::new(data); + + let mut updates = webrender_api::ResourceUpdates::new(); + updates.update_image(image_key, + descriptor, + data, + None); + webrender_api.update_resources(updates); + } + + /// Helper function to create a `webrender_api::ImageDescriptor`. + fn image_descriptor(size: Size2D<i32>, alpha: bool) -> webrender_api::ImageDescriptor { + webrender_api::ImageDescriptor { + width: size.width as u32, + height: size.height as u32, + stride: None, + format: if alpha { webrender_api::ImageFormat::BGRA8 } else { webrender_api::ImageFormat::RGB8 }, + offset: 0, + is_opaque: !alpha, + } + } + + /// Helper function to fetch the raw pixels used in readback mode. + fn raw_pixels(context: &GLContextWrapper, size: Size2D<i32>) -> Vec<u8> { + let width = size.width as usize; + let height = size.height as usize; + + let mut pixels = context.gl().read_pixels(0, 0, + size.width as gl::GLsizei, + size.height as gl::GLsizei, + gl::RGBA, gl::UNSIGNED_BYTE); + // flip image vertically (texture is upside down) + let orig_pixels = pixels.clone(); + let stride = width * 4; + for y in 0..height { + let dst_start = y * stride; + let src_start = (height - y - 1) * stride; + let src_slice = &orig_pixels[src_start .. src_start + stride]; + (&mut pixels[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]); + } + byte_swap(&mut pixels); + pixels + } +} + +impl<VR: WebVRRenderHandler + 'static, OB: WebGLThreadObserver> Drop for WebGLThread<VR, OB> { + 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); + } + } +} + +/// Helper struct to store cached WebGLContext information. +struct WebGLContextInfo { + /// Render to texture identifier used by the WebGLContext. + texture_id: u32, + /// Size of the WebGLContext. + size: Size2D<i32>, + /// True if the WebGLContext uses an alpha channel. + alpha: bool, + /// Currently used WebRender image key. + image_key: Option<webrender_api::ImageKey>, + /// The sharing mode used to send the image to WebRender. + share_mode: WebGLContextShareMode, + /// GLSync Object used for a correct synchronization with Webrender external image callbacks. + gl_sync: Option<gl::GLsync>, + /// An old WebRender image key that can be deleted when the next epoch ends. + old_image_key: Option<webrender_api::ImageKey>, + /// An old WebRender image key that can be deleted when the current epoch ends. + very_old_image_key: Option<webrender_api::ImageKey>, +} + +/// Trait used to observe events in a WebGL Thread. +/// Used in webrender::ExternalImageHandler when multiple WebGL threads are used. +pub trait WebGLThreadObserver: Send + 'static { + fn on_context_create(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>); + fn on_context_resize(&mut self, ctx_id: WebGLContextId, texture_id: u32, size: Size2D<i32>); + fn on_context_delete(&mut self, ctx_id: WebGLContextId); +} + +/// This trait is used as a bridge between the `WebGLThreads` implementation and +/// the WR ExternalImageHandler API implemented in the `WebGLExternalImageHandler` struct. +/// `WebGLExternalImageHandler<T>` takes care of type conversions between WR and WebGL info (e.g keys, uvs). +/// It uses this trait to notify lock/unlock messages and get the required info that WR needs. +/// `WebGLThreads` receives lock/unlock message notifications and takes care of sending +/// the unlock/lock messages to the appropiate `WebGLThread`. +pub trait WebGLExternalImageApi { + fn lock(&mut self, ctx_id: WebGLContextId) -> (u32, Size2D<i32>); + fn unlock(&mut self, ctx_id: WebGLContextId); +} + +/// WebRender External Image Handler implementation +pub struct WebGLExternalImageHandler<T: WebGLExternalImageApi> { + handler: T, +} + +impl<T: WebGLExternalImageApi> WebGLExternalImageHandler<T> { + pub fn new(handler: T) -> Self { + Self { + handler: handler + } + } +} + +impl<T: WebGLExternalImageApi> webrender::ExternalImageHandler for WebGLExternalImageHandler<T> { + /// Lock the external image. Then, WR could start to read the image content. + /// The WR client should not change the image content until the unlock() call. + fn lock(&mut self, + key: webrender_api::ExternalImageId, + _channel_index: u8) -> webrender::ExternalImage { + let ctx_id = WebGLContextId(key.0 as _); + let (texture_id, size) = self.handler.lock(ctx_id); + + webrender::ExternalImage { + u0: 0.0, + u1: size.width as f32, + v1: 0.0, + v0: size.height as f32, + source: webrender::ExternalImageSource::NativeTexture(texture_id), + } + + } + /// Unlock the external image. The WR should not read the image content + /// after this call. + fn unlock(&mut self, + key: webrender_api::ExternalImageId, + _channel_index: u8) { + let ctx_id = WebGLContextId(key.0 as _); + self.handler.unlock(ctx_id); + } +} + +/// WebGL Commands Implementation +pub struct WebGLImpl; + +impl WebGLImpl { + pub fn apply<Native: NativeGLContextMethods>(ctx: &GLContext<Native>, command: WebGLCommand) { + match command { + WebGLCommand::GetContextAttributes(sender) => + sender.send(*ctx.borrow_attributes()).unwrap(), + WebGLCommand::ActiveTexture(target) => + ctx.gl().active_texture(target), + WebGLCommand::AttachShader(program_id, shader_id) => + ctx.gl().attach_shader(program_id.get(), shader_id.get()), + WebGLCommand::DetachShader(program_id, shader_id) => + ctx.gl().detach_shader(program_id.get(), shader_id.get()), + WebGLCommand::BindAttribLocation(program_id, index, name) => + ctx.gl().bind_attrib_location(program_id.get(), index, &name), + WebGLCommand::BlendColor(r, g, b, a) => + ctx.gl().blend_color(r, g, b, a), + WebGLCommand::BlendEquation(mode) => + ctx.gl().blend_equation(mode), + WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha) => + ctx.gl().blend_equation_separate(mode_rgb, mode_alpha), + WebGLCommand::BlendFunc(src, dest) => + ctx.gl().blend_func(src, dest), + WebGLCommand::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha) => + ctx.gl().blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha), + WebGLCommand::BufferData(buffer_type, data, usage) => + gl::buffer_data(ctx.gl(), buffer_type, &data, usage), + WebGLCommand::BufferSubData(buffer_type, offset, data) => + gl::buffer_sub_data(ctx.gl(), buffer_type, offset, &data), + WebGLCommand::Clear(mask) => + ctx.gl().clear(mask), + WebGLCommand::ClearColor(r, g, b, a) => + ctx.gl().clear_color(r, g, b, a), + WebGLCommand::ClearDepth(depth) => + ctx.gl().clear_depth(depth), + WebGLCommand::ClearStencil(stencil) => + ctx.gl().clear_stencil(stencil), + WebGLCommand::ColorMask(r, g, b, a) => + ctx.gl().color_mask(r, g, b, a), + WebGLCommand::CopyTexImage2D(target, level, internal_format, x, y, width, height, border) => + ctx.gl().copy_tex_image_2d(target, level, internal_format, x, y, width, height, border), + WebGLCommand::CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) => + ctx.gl().copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height), + WebGLCommand::CullFace(mode) => + ctx.gl().cull_face(mode), + WebGLCommand::DepthFunc(func) => + ctx.gl().depth_func(func), + WebGLCommand::DepthMask(flag) => + ctx.gl().depth_mask(flag), + WebGLCommand::DepthRange(near, far) => + ctx.gl().depth_range(near, far), + WebGLCommand::Disable(cap) => + ctx.gl().disable(cap), + WebGLCommand::Enable(cap) => + ctx.gl().enable(cap), + WebGLCommand::FramebufferRenderbuffer(target, attachment, renderbuffertarget, rb) => + ctx.gl().framebuffer_renderbuffer(target, attachment, renderbuffertarget, + rb.map_or(0, WebGLRenderbufferId::get)), + WebGLCommand::FramebufferTexture2D(target, attachment, textarget, texture, level) => + ctx.gl().framebuffer_texture_2d(target, attachment, textarget, + texture.map_or(0, WebGLTextureId::get), level), + WebGLCommand::FrontFace(mode) => + ctx.gl().front_face(mode), + WebGLCommand::DisableVertexAttribArray(attrib_id) => + ctx.gl().disable_vertex_attrib_array(attrib_id), + WebGLCommand::DrawArrays(mode, first, count) => + ctx.gl().draw_arrays(mode, first, count), + WebGLCommand::DrawElements(mode, count, type_, offset) => + ctx.gl().draw_elements(mode, count, type_, offset as u32), + WebGLCommand::EnableVertexAttribArray(attrib_id) => + ctx.gl().enable_vertex_attrib_array(attrib_id), + WebGLCommand::Hint(name, val) => + ctx.gl().hint(name, val), + WebGLCommand::IsEnabled(cap, chan) => + chan.send(ctx.gl().is_enabled(cap) != 0).unwrap(), + WebGLCommand::LineWidth(width) => + ctx.gl().line_width(width), + WebGLCommand::PixelStorei(name, val) => + ctx.gl().pixel_store_i(name, val), + WebGLCommand::PolygonOffset(factor, units) => + ctx.gl().polygon_offset(factor, units), + WebGLCommand::ReadPixels(x, y, width, height, format, pixel_type, chan) => + Self::read_pixels(ctx.gl(), x, y, width, height, format, pixel_type, chan), + WebGLCommand::RenderbufferStorage(target, format, width, height) => + ctx.gl().renderbuffer_storage(target, format, width, height), + WebGLCommand::SampleCoverage(value, invert) => + ctx.gl().sample_coverage(value, invert), + WebGLCommand::Scissor(x, y, width, height) => + ctx.gl().scissor(x, y, width, height), + WebGLCommand::StencilFunc(func, ref_, mask) => + ctx.gl().stencil_func(func, ref_, mask), + WebGLCommand::StencilFuncSeparate(face, func, ref_, mask) => + ctx.gl().stencil_func_separate(face, func, ref_, mask), + WebGLCommand::StencilMask(mask) => + ctx.gl().stencil_mask(mask), + WebGLCommand::StencilMaskSeparate(face, mask) => + ctx.gl().stencil_mask_separate(face, mask), + WebGLCommand::StencilOp(fail, zfail, zpass) => + ctx.gl().stencil_op(fail, zfail, zpass), + WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) => + ctx.gl().stencil_op_separate(face, fail, zfail, zpass), + WebGLCommand::GetActiveAttrib(program_id, index, chan) => + Self::active_attrib(ctx.gl(), program_id, index, chan), + WebGLCommand::GetActiveUniform(program_id, index, chan) => + Self::active_uniform(ctx.gl(), program_id, index, chan), + WebGLCommand::GetAttribLocation(program_id, name, chan) => + Self::attrib_location(ctx.gl(), program_id, name, chan), + WebGLCommand::GetVertexAttrib(index, pname, chan) => + Self::vertex_attrib(ctx.gl(), index, pname, chan), + WebGLCommand::GetVertexAttribOffset(index, pname, chan) => + Self::vertex_attrib_offset(ctx.gl(), index, pname, chan), + WebGLCommand::GetBufferParameter(target, param_id, chan) => + Self::buffer_parameter(ctx.gl(), target, param_id, chan), + WebGLCommand::GetParameter(param_id, chan) => + Self::parameter(ctx.gl(), param_id, chan), + WebGLCommand::GetProgramParameter(program_id, param_id, chan) => + Self::program_parameter(ctx.gl(), program_id, param_id, chan), + WebGLCommand::GetShaderParameter(shader_id, param_id, chan) => + Self::shader_parameter(ctx.gl(), shader_id, param_id, chan), + WebGLCommand::GetShaderPrecisionFormat(shader_type, precision_type, chan) => + Self::shader_precision_format(ctx.gl(), shader_type, precision_type, chan), + WebGLCommand::GetExtensions(chan) => + Self::get_extensions(ctx.gl(), chan), + WebGLCommand::GetUniformLocation(program_id, name, chan) => + Self::uniform_location(ctx.gl(), program_id, name, chan), + WebGLCommand::GetShaderInfoLog(shader_id, chan) => + Self::shader_info_log(ctx.gl(), shader_id, chan), + WebGLCommand::GetProgramInfoLog(program_id, chan) => + Self::program_info_log(ctx.gl(), program_id, chan), + WebGLCommand::CompileShader(shader_id, source) => + Self::compile_shader(ctx.gl(), shader_id, source), + WebGLCommand::CreateBuffer(chan) => + Self::create_buffer(ctx.gl(), chan), + WebGLCommand::CreateFramebuffer(chan) => + Self::create_framebuffer(ctx.gl(), chan), + WebGLCommand::CreateRenderbuffer(chan) => + Self::create_renderbuffer(ctx.gl(), chan), + WebGLCommand::CreateTexture(chan) => + Self::create_texture(ctx.gl(), chan), + WebGLCommand::CreateProgram(chan) => + Self::create_program(ctx.gl(), chan), + WebGLCommand::CreateShader(shader_type, chan) => + Self::create_shader(ctx.gl(), shader_type, chan), + WebGLCommand::DeleteBuffer(id) => + ctx.gl().delete_buffers(&[id.get()]), + WebGLCommand::DeleteFramebuffer(id) => + ctx.gl().delete_framebuffers(&[id.get()]), + WebGLCommand::DeleteRenderbuffer(id) => + ctx.gl().delete_renderbuffers(&[id.get()]), + WebGLCommand::DeleteTexture(id) => + ctx.gl().delete_textures(&[id.get()]), + WebGLCommand::DeleteProgram(id) => + ctx.gl().delete_program(id.get()), + WebGLCommand::DeleteShader(id) => + ctx.gl().delete_shader(id.get()), + WebGLCommand::BindBuffer(target, id) => + ctx.gl().bind_buffer(target, id.map_or(0, WebGLBufferId::get)), + WebGLCommand::BindFramebuffer(target, request) => + Self::bind_framebuffer(ctx.gl(), target, request, ctx), + WebGLCommand::BindRenderbuffer(target, id) => + ctx.gl().bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get)), + WebGLCommand::BindTexture(target, id) => + ctx.gl().bind_texture(target, id.map_or(0, WebGLTextureId::get)), + WebGLCommand::LinkProgram(program_id) => + ctx.gl().link_program(program_id.get()), + WebGLCommand::Uniform1f(uniform_id, v) => + ctx.gl().uniform_1f(uniform_id, v), + WebGLCommand::Uniform1fv(uniform_id, v) => + ctx.gl().uniform_1fv(uniform_id, &v), + WebGLCommand::Uniform1i(uniform_id, v) => + ctx.gl().uniform_1i(uniform_id, v), + WebGLCommand::Uniform1iv(uniform_id, v) => + ctx.gl().uniform_1iv(uniform_id, &v), + WebGLCommand::Uniform2f(uniform_id, x, y) => + ctx.gl().uniform_2f(uniform_id, x, y), + WebGLCommand::Uniform2fv(uniform_id, v) => + ctx.gl().uniform_2fv(uniform_id, &v), + WebGLCommand::Uniform2i(uniform_id, x, y) => + ctx.gl().uniform_2i(uniform_id, x, y), + WebGLCommand::Uniform2iv(uniform_id, v) => + ctx.gl().uniform_2iv(uniform_id, &v), + WebGLCommand::Uniform3f(uniform_id, x, y, z) => + ctx.gl().uniform_3f(uniform_id, x, y, z), + WebGLCommand::Uniform3fv(uniform_id, v) => + ctx.gl().uniform_3fv(uniform_id, &v), + WebGLCommand::Uniform3i(uniform_id, x, y, z) => + ctx.gl().uniform_3i(uniform_id, x, y, z), + WebGLCommand::Uniform3iv(uniform_id, v) => + ctx.gl().uniform_3iv(uniform_id, &v), + WebGLCommand::Uniform4f(uniform_id, x, y, z, w) => + ctx.gl().uniform_4f(uniform_id, x, y, z, w), + WebGLCommand::Uniform4fv(uniform_id, v) => + ctx.gl().uniform_4fv(uniform_id, &v), + WebGLCommand::Uniform4i(uniform_id, x, y, z, w) => + ctx.gl().uniform_4i(uniform_id, x, y, z, w), + WebGLCommand::Uniform4iv(uniform_id, v) => + ctx.gl().uniform_4iv(uniform_id, &v), + WebGLCommand::UniformMatrix2fv(uniform_id, transpose, v) => + ctx.gl().uniform_matrix_2fv(uniform_id, transpose, &v), + WebGLCommand::UniformMatrix3fv(uniform_id, transpose, v) => + ctx.gl().uniform_matrix_3fv(uniform_id, transpose, &v), + WebGLCommand::UniformMatrix4fv(uniform_id, transpose, v) => + ctx.gl().uniform_matrix_4fv(uniform_id, transpose, &v), + WebGLCommand::UseProgram(program_id) => + ctx.gl().use_program(program_id.get()), + WebGLCommand::ValidateProgram(program_id) => + ctx.gl().validate_program(program_id.get()), + WebGLCommand::VertexAttrib(attrib_id, x, y, z, w) => + ctx.gl().vertex_attrib_4f(attrib_id, x, y, z, w), + WebGLCommand::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) => + ctx.gl().vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset), + WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset) => + ctx.gl().vertex_attrib_pointer(attrib_id, size, data_type, normalized, stride, offset), + WebGLCommand::Viewport(x, y, width, height) => + ctx.gl().viewport(x, y, width, height), + WebGLCommand::TexImage2D(target, level, internal, width, height, format, data_type, data) => + ctx.gl().tex_image_2d(target, level, internal, width, height, + /*border*/0, format, data_type, Some(&data)), + WebGLCommand::TexParameteri(target, name, value) => + ctx.gl().tex_parameter_i(target, name, value), + WebGLCommand::TexParameterf(target, name, value) => + ctx.gl().tex_parameter_f(target, name, value), + WebGLCommand::TexSubImage2D(target, level, xoffset, yoffset, x, y, width, height, data) => + ctx.gl().tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height, &data), + WebGLCommand::DrawingBufferWidth(sender) => + sender.send(ctx.borrow_draw_buffer().unwrap().size().width).unwrap(), + WebGLCommand::DrawingBufferHeight(sender) => + sender.send(ctx.borrow_draw_buffer().unwrap().size().height).unwrap(), + WebGLCommand::Finish(sender) => + Self::finish(ctx.gl(), sender), + WebGLCommand::Flush => + ctx.gl().flush(), + WebGLCommand::GenerateMipmap(target) => + ctx.gl().generate_mipmap(target), + WebGLCommand::CreateVertexArray(chan) => + Self::create_vertex_array(ctx.gl(), chan), + WebGLCommand::DeleteVertexArray(id) => + ctx.gl().delete_vertex_arrays(&[id.get()]), + WebGLCommand::BindVertexArray(id) => + ctx.gl().bind_vertex_array(id.map_or(0, WebGLVertexArrayId::get)), + } + + // TODO: update test expectations in order to enable debug assertions + //if cfg!(debug_assertions) { + let error = ctx.gl().get_error(); + assert!(error == gl::NO_ERROR, "Unexpected WebGL error: 0x{:x} ({})", error, error); + //} + } + + fn read_pixels(gl: &gl::Gl, x: i32, y: i32, width: i32, height: i32, format: u32, pixel_type: u32, + chan: WebGLSender<Vec<u8>>) { + let result = gl.read_pixels(x, y, width, height, format, pixel_type); + chan.send(result).unwrap() + } + + fn active_attrib(gl: &gl::Gl, + program_id: WebGLProgramId, + index: u32, + chan: WebGLSender<WebGLResult<(i32, u32, String)>>) { + let result = if index >= gl.get_program_iv(program_id.get(), gl::ACTIVE_ATTRIBUTES) as u32 { + Err(WebGLError::InvalidValue) + } else { + Ok(gl.get_active_attrib(program_id.get(), index)) + }; + chan.send(result).unwrap(); + } + + fn active_uniform(gl: &gl::Gl, + program_id: WebGLProgramId, + index: u32, + chan: WebGLSender<WebGLResult<(i32, u32, String)>>) { + let result = if index >= gl.get_program_iv(program_id.get(), gl::ACTIVE_UNIFORMS) as u32 { + Err(WebGLError::InvalidValue) + } else { + Ok(gl.get_active_uniform(program_id.get(), index)) + }; + chan.send(result).unwrap(); + } + + fn attrib_location(gl: &gl::Gl, + program_id: WebGLProgramId, + name: String, + chan: WebGLSender<Option<i32>> ) { + let attrib_location = gl.get_attrib_location(program_id.get(), &name); + + let attrib_location = if attrib_location == -1 { + None + } else { + Some(attrib_location) + }; + + chan.send(attrib_location).unwrap(); + } + + fn parameter(gl: &gl::Gl, + param_id: u32, + chan: WebGLSender<WebGLResult<WebGLParameter>>) { + let result = match param_id { + gl::ACTIVE_TEXTURE | + gl::ALPHA_BITS | + gl::BLEND_DST_ALPHA | + gl::BLEND_DST_RGB | + gl::BLEND_EQUATION_ALPHA | + gl::BLEND_EQUATION_RGB | + gl::BLEND_SRC_ALPHA | + gl::BLEND_SRC_RGB | + gl::BLUE_BITS | + gl::CULL_FACE_MODE | + gl::DEPTH_BITS | + gl::DEPTH_FUNC | + gl::FRONT_FACE | + //gl::GENERATE_MIPMAP_HINT | + gl::GREEN_BITS | + //gl::IMPLEMENTATION_COLOR_READ_FORMAT | + //gl::IMPLEMENTATION_COLOR_READ_TYPE | + gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS | + gl::MAX_CUBE_MAP_TEXTURE_SIZE | + //gl::MAX_FRAGMENT_UNIFORM_VECTORS | + gl::MAX_RENDERBUFFER_SIZE | + gl::MAX_TEXTURE_IMAGE_UNITS | + gl::MAX_TEXTURE_SIZE | + //gl::MAX_VARYING_VECTORS | + gl::MAX_VERTEX_ATTRIBS | + gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS | + //gl::MAX_VERTEX_UNIFORM_VECTORS | + gl::PACK_ALIGNMENT | + gl::RED_BITS | + gl::SAMPLE_BUFFERS | + gl::SAMPLES | + gl::STENCIL_BACK_FAIL | + gl::STENCIL_BACK_FUNC | + gl::STENCIL_BACK_PASS_DEPTH_FAIL | + gl::STENCIL_BACK_PASS_DEPTH_PASS | + gl::STENCIL_BACK_REF | + gl::STENCIL_BACK_VALUE_MASK | + gl::STENCIL_BACK_WRITEMASK | + gl::STENCIL_BITS | + gl::STENCIL_CLEAR_VALUE | + gl::STENCIL_FAIL | + gl::STENCIL_FUNC | + gl::STENCIL_PASS_DEPTH_FAIL | + gl::STENCIL_PASS_DEPTH_PASS | + gl::STENCIL_REF | + gl::STENCIL_VALUE_MASK | + gl::STENCIL_WRITEMASK | + gl::SUBPIXEL_BITS | + gl::UNPACK_ALIGNMENT => + //gl::UNPACK_COLORSPACE_CONVERSION_WEBGL => + Ok(WebGLParameter::Int(gl.get_integer_v(param_id))), + + gl::BLEND | + gl::CULL_FACE | + gl::DEPTH_TEST | + gl::DEPTH_WRITEMASK | + gl::DITHER | + gl::POLYGON_OFFSET_FILL | + gl::SAMPLE_COVERAGE_INVERT | + gl::STENCIL_TEST => + //gl::UNPACK_FLIP_Y_WEBGL | + //gl::UNPACK_PREMULTIPLY_ALPHA_WEBGL => + Ok(WebGLParameter::Bool(gl.get_boolean_v(param_id) != 0)), + + gl::DEPTH_CLEAR_VALUE | + gl::LINE_WIDTH | + gl::POLYGON_OFFSET_FACTOR | + gl::POLYGON_OFFSET_UNITS | + gl::SAMPLE_COVERAGE_VALUE => + Ok(WebGLParameter::Float(gl.get_float_v(param_id))), + + gl::VERSION => Ok(WebGLParameter::String("WebGL 1.0".to_owned())), + gl::RENDERER | + gl::VENDOR => Ok(WebGLParameter::String("Mozilla/Servo".to_owned())), + gl::SHADING_LANGUAGE_VERSION => Ok(WebGLParameter::String("WebGL GLSL ES 1.0".to_owned())), + + // TODO(zbarsky, emilio): Implement support for the following valid parameters + // Float32Array + gl::ALIASED_LINE_WIDTH_RANGE | + //gl::ALIASED_POINT_SIZE_RANGE | + //gl::BLEND_COLOR | + gl::COLOR_CLEAR_VALUE | + gl::DEPTH_RANGE | + + // WebGLBuffer + gl::ARRAY_BUFFER_BINDING | + gl::ELEMENT_ARRAY_BUFFER_BINDING | + + // WebGLFrameBuffer + gl::FRAMEBUFFER_BINDING | + + // WebGLRenderBuffer + gl::RENDERBUFFER_BINDING | + + // WebGLProgram + gl::CURRENT_PROGRAM | + + // WebGLTexture + gl::TEXTURE_BINDING_2D | + gl::TEXTURE_BINDING_CUBE_MAP | + + // sequence<GlBoolean> + gl::COLOR_WRITEMASK | + + // Uint32Array + gl::COMPRESSED_TEXTURE_FORMATS | + + // Int32Array + gl::MAX_VIEWPORT_DIMS | + gl::SCISSOR_BOX | + gl::VIEWPORT => Err(WebGLError::InvalidEnum), + + // Invalid parameters + _ => Err(WebGLError::InvalidEnum) + }; + + chan.send(result).unwrap(); + } + + fn finish(gl: &gl::Gl, chan: WebGLSender<()>) { + gl.finish(); + chan.send(()).unwrap(); + } + + fn vertex_attrib(gl: &gl::Gl, + index: u32, + pname: u32, + chan: WebGLSender<WebGLResult<WebGLParameter>>) { + let result = if index >= gl.get_integer_v(gl::MAX_VERTEX_ATTRIBS) as u32 { + Err(WebGLError::InvalidValue) + } else { + match pname { + gl::VERTEX_ATTRIB_ARRAY_ENABLED | + gl::VERTEX_ATTRIB_ARRAY_NORMALIZED => + Ok(WebGLParameter::Bool(gl.get_vertex_attrib_iv(index, pname) != 0)), + gl::VERTEX_ATTRIB_ARRAY_SIZE | + gl::VERTEX_ATTRIB_ARRAY_STRIDE | + gl::VERTEX_ATTRIB_ARRAY_TYPE => + Ok(WebGLParameter::Int(gl.get_vertex_attrib_iv(index, pname))), + gl::CURRENT_VERTEX_ATTRIB => + Ok(WebGLParameter::FloatArray(gl.get_vertex_attrib_fv(index, pname))), + // gl::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING should return WebGLBuffer + _ => Err(WebGLError::InvalidEnum), + } + }; + + chan.send(result).unwrap(); + } + + fn vertex_attrib_offset(gl: &gl::Gl, + index: u32, + pname: u32, + chan: WebGLSender<WebGLResult<isize>>) { + let result = match pname { + gl::VERTEX_ATTRIB_ARRAY_POINTER => Ok(gl.get_vertex_attrib_pointer_v(index, pname)), + _ => Err(WebGLError::InvalidEnum), + }; + + chan.send(result).unwrap(); + } + + fn buffer_parameter(gl: &gl::Gl, + target: u32, + param_id: u32, + chan: WebGLSender<WebGLResult<WebGLParameter>>) { + let result = match param_id { + gl::BUFFER_SIZE | + gl::BUFFER_USAGE => + Ok(WebGLParameter::Int(gl.get_buffer_parameter_iv(target, param_id))), + _ => Err(WebGLError::InvalidEnum), + }; + + chan.send(result).unwrap(); + } + + fn program_parameter(gl: &gl::Gl, + program_id: WebGLProgramId, + param_id: u32, + chan: WebGLSender<WebGLResult<WebGLParameter>>) { + let result = match param_id { + gl::DELETE_STATUS | + gl::LINK_STATUS | + gl::VALIDATE_STATUS => + Ok(WebGLParameter::Bool(gl.get_program_iv(program_id.get(), param_id) != 0)), + gl::ATTACHED_SHADERS | + gl::ACTIVE_ATTRIBUTES | + gl::ACTIVE_UNIFORMS => + Ok(WebGLParameter::Int(gl.get_program_iv(program_id.get(), param_id))), + _ => Err(WebGLError::InvalidEnum), + }; + + chan.send(result).unwrap(); + } + + fn shader_parameter(gl: &gl::Gl, + shader_id: WebGLShaderId, + param_id: u32, + chan: WebGLSender<WebGLResult<WebGLParameter>>) { + let result = match param_id { + gl::SHADER_TYPE => + Ok(WebGLParameter::Int(gl.get_shader_iv(shader_id.get(), param_id))), + gl::DELETE_STATUS | + gl::COMPILE_STATUS => + Ok(WebGLParameter::Bool(gl.get_shader_iv(shader_id.get(), param_id) != 0)), + _ => Err(WebGLError::InvalidEnum), + }; + + chan.send(result).unwrap(); + } + + fn shader_precision_format(gl: &gl::Gl, + shader_type: u32, + precision_type: u32, + chan: WebGLSender<WebGLResult<(i32, i32, i32)>>) { + let result = match precision_type { + gl::LOW_FLOAT | + gl::MEDIUM_FLOAT | + gl::HIGH_FLOAT | + gl::LOW_INT | + gl::MEDIUM_INT | + gl::HIGH_INT => { + Ok(gl.get_shader_precision_format(shader_type, precision_type)) + }, + _=> { + Err(WebGLError::InvalidEnum) + } + }; + + chan.send(result).unwrap(); + } + + fn get_extensions(gl: &gl::Gl, chan: WebGLSender<String>) { + chan.send(gl.get_string(gl::EXTENSIONS)).unwrap(); + } + + fn uniform_location(gl: &gl::Gl, + program_id: WebGLProgramId, + name: String, + chan: WebGLSender<Option<i32>>) { + let location = gl.get_uniform_location(program_id.get(), &name); + let location = if location == -1 { + None + } else { + Some(location) + }; + + chan.send(location).unwrap(); + } + + + fn shader_info_log(gl: &gl::Gl, shader_id: WebGLShaderId, chan: WebGLSender<String>) { + let log = gl.get_shader_info_log(shader_id.get()); + chan.send(log).unwrap(); + } + + fn program_info_log(gl: &gl::Gl, program_id: WebGLProgramId, chan: WebGLSender<String>) { + let log = gl.get_program_info_log(program_id.get()); + chan.send(log).unwrap(); + } + + #[allow(unsafe_code)] + fn create_buffer(gl: &gl::Gl, chan: WebGLSender<Option<WebGLBufferId>>) { + let buffer = gl.gen_buffers(1)[0]; + let buffer = if buffer == 0 { + None + } else { + Some(unsafe { WebGLBufferId::new(buffer) }) + }; + chan.send(buffer).unwrap(); + } + + #[allow(unsafe_code)] + fn create_framebuffer(gl: &gl::Gl, chan: WebGLSender<Option<WebGLFramebufferId>>) { + let framebuffer = gl.gen_framebuffers(1)[0]; + let framebuffer = if framebuffer == 0 { + None + } else { + Some(unsafe { WebGLFramebufferId::new(framebuffer) }) + }; + chan.send(framebuffer).unwrap(); + } + + #[allow(unsafe_code)] + fn create_renderbuffer(gl: &gl::Gl, chan: WebGLSender<Option<WebGLRenderbufferId>>) { + let renderbuffer = gl.gen_renderbuffers(1)[0]; + let renderbuffer = if renderbuffer == 0 { + None + } else { + Some(unsafe { WebGLRenderbufferId::new(renderbuffer) }) + }; + chan.send(renderbuffer).unwrap(); + } + + #[allow(unsafe_code)] + fn create_texture(gl: &gl::Gl, chan: WebGLSender<Option<WebGLTextureId>>) { + let texture = gl.gen_textures(1)[0]; + let texture = if texture == 0 { + None + } else { + Some(unsafe { WebGLTextureId::new(texture) }) + }; + chan.send(texture).unwrap(); + } + + #[allow(unsafe_code)] + fn create_program(gl: &gl::Gl, chan: WebGLSender<Option<WebGLProgramId>>) { + let program = gl.create_program(); + let program = if program == 0 { + None + } else { + Some(unsafe { WebGLProgramId::new(program) }) + }; + chan.send(program).unwrap(); + } + + #[allow(unsafe_code)] + fn create_shader(gl: &gl::Gl, shader_type: u32, chan: WebGLSender<Option<WebGLShaderId>>) { + let shader = gl.create_shader(shader_type); + let shader = if shader == 0 { + None + } else { + Some(unsafe { WebGLShaderId::new(shader) }) + }; + chan.send(shader).unwrap(); + } + + #[allow(unsafe_code)] + fn create_vertex_array(gl: &gl::Gl, chan: WebGLSender<Option<WebGLVertexArrayId>>) { + let vao = gl.gen_vertex_arrays(1)[0]; + let vao = if vao == 0 { + None + } else { + Some(unsafe { WebGLVertexArrayId::new(vao) }) + }; + chan.send(vao).unwrap(); + } + + #[inline] + fn bind_framebuffer<Native: NativeGLContextMethods>(gl: &gl::Gl, + target: u32, + request: WebGLFramebufferBindingRequest, + ctx: &GLContext<Native>) { + let id = match request { + WebGLFramebufferBindingRequest::Explicit(id) => id.get(), + WebGLFramebufferBindingRequest::Default => + ctx.borrow_draw_buffer().unwrap().get_framebuffer(), + }; + + gl.bind_framebuffer(target, id); + } + + + #[inline] + fn compile_shader(gl: &gl::Gl, shader_id: WebGLShaderId, source: String) { + gl.shader_source(shader_id.get(), &[source.as_bytes()]); + gl.compile_shader(shader_id.get()); + } +} diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml index afc23f4a2e0..43cc74e60b1 100644 --- a/components/canvas_traits/Cargo.toml +++ b/components/canvas_traits/Cargo.toml @@ -15,5 +15,8 @@ euclid = "0.15" heapsize = "0.4" heapsize_derive = "0.1" ipc-channel = "0.8" +lazy_static = "0.2" +offscreen_gl_context = { version = "0.11", features = ["serde"] } serde = "1.0" +servo_config = {path = "../config"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} diff --git a/components/canvas_traits/canvas.rs b/components/canvas_traits/canvas.rs new file mode 100644 index 00000000000..92444d03799 --- /dev/null +++ b/components/canvas_traits/canvas.rs @@ -0,0 +1,409 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use cssparser::RGBA; +use euclid::{Transform2D, Point2D, Vector2D, Rect, Size2D}; +use ipc_channel::ipc::IpcSender; +use std::default::Default; +use std::str::FromStr; +use webrender_api; + +#[derive(Clone, Deserialize, Serialize)] +pub enum FillRule { + Nonzero, + Evenodd, +} + +#[derive(Clone, Deserialize, Serialize)] +pub enum CanvasMsg { + Canvas2d(Canvas2dMsg), + FromLayout(FromLayoutMsg), + FromScript(FromScriptMsg), + Recreate(Size2D<i32>), + Close, +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct CanvasImageData { + pub image_key: webrender_api::ImageKey, +} + +#[derive(Clone, Deserialize, Serialize)] +pub enum Canvas2dMsg { + Arc(Point2D<f32>, f32, f32, f32, bool), + ArcTo(Point2D<f32>, Point2D<f32>, f32), + DrawImage(Vec<u8>, Size2D<f64>, Rect<f64>, Rect<f64>, bool), + DrawImageSelf(Size2D<f64>, Rect<f64>, Rect<f64>, bool), + DrawImageInOther( + IpcSender<CanvasMsg>, Size2D<f64>, Rect<f64>, Rect<f64>, bool, IpcSender<()>), + BeginPath, + BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>), + ClearRect(Rect<f32>), + Clip, + ClosePath, + Fill, + FillRect(Rect<f32>), + GetImageData(Rect<i32>, Size2D<f64>, IpcSender<Vec<u8>>), + IsPointInPath(f64, f64, FillRule, IpcSender<bool>), + LineTo(Point2D<f32>), + MoveTo(Point2D<f32>), + PutImageData(Vec<u8>, Vector2D<f64>, Size2D<f64>, Rect<f64>), + QuadraticCurveTo(Point2D<f32>, Point2D<f32>), + Rect(Rect<f32>), + RestoreContext, + SaveContext, + StrokeRect(Rect<f32>), + Stroke, + SetFillStyle(FillOrStrokeStyle), + SetStrokeStyle(FillOrStrokeStyle), + SetLineWidth(f32), + SetLineCap(LineCapStyle), + SetLineJoin(LineJoinStyle), + SetMiterLimit(f32), + SetGlobalAlpha(f32), + SetGlobalComposition(CompositionOrBlending), + SetTransform(Transform2D<f32>), + SetShadowOffsetX(f64), + SetShadowOffsetY(f64), + SetShadowBlur(f64), + SetShadowColor(RGBA), +} + +#[derive(Clone, Deserialize, Serialize)] +pub enum FromLayoutMsg { + SendData(IpcSender<CanvasImageData>), +} + +#[derive(Clone, Deserialize, Serialize)] +pub enum FromScriptMsg { + SendPixels(IpcSender<Option<Vec<u8>>>), +} + +#[derive(Clone, Deserialize, Serialize, HeapSizeOf)] +pub struct CanvasGradientStop { + pub offset: f64, + pub color: RGBA, +} + +#[derive(Clone, Deserialize, Serialize, HeapSizeOf)] +pub struct LinearGradientStyle { + pub x0: f64, + pub y0: f64, + pub x1: f64, + pub y1: f64, + pub stops: Vec<CanvasGradientStop> +} + +impl LinearGradientStyle { + pub fn new(x0: f64, y0: f64, x1: f64, y1: f64, stops: Vec<CanvasGradientStop>) + -> LinearGradientStyle { + LinearGradientStyle { + x0: x0, + y0: y0, + x1: x1, + y1: y1, + stops: stops, + } + } +} + +#[derive(Clone, Deserialize, Serialize, HeapSizeOf)] +pub struct RadialGradientStyle { + pub x0: f64, + pub y0: f64, + pub r0: f64, + pub x1: f64, + pub y1: f64, + pub r1: f64, + pub stops: Vec<CanvasGradientStop> +} + +impl RadialGradientStyle { + pub fn new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64, stops: Vec<CanvasGradientStop>) + -> RadialGradientStyle { + RadialGradientStyle { + x0: x0, + y0: y0, + r0: r0, + x1: x1, + y1: y1, + r1: r1, + stops: stops, + } + } +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct SurfaceStyle { + pub surface_data: Vec<u8>, + pub surface_size: Size2D<i32>, + pub repeat_x: bool, + pub repeat_y: bool, +} + +impl SurfaceStyle { + pub fn new(surface_data: Vec<u8>, surface_size: Size2D<i32>, repeat_x: bool, repeat_y: bool) + -> SurfaceStyle { + SurfaceStyle { + surface_data: surface_data, + surface_size: surface_size, + repeat_x: repeat_x, + repeat_y: repeat_y, + } + } +} + + +#[derive(Clone, Deserialize, Serialize)] +pub enum FillOrStrokeStyle { + Color(RGBA), + LinearGradient(LinearGradientStyle), + RadialGradient(RadialGradientStyle), + Surface(SurfaceStyle), +} + +#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] +pub enum LineCapStyle { + Butt = 0, + Round = 1, + Square = 2, +} + +impl FromStr for LineCapStyle { + type Err = (); + + fn from_str(string: &str) -> Result<LineCapStyle, ()> { + match string { + "butt" => Ok(LineCapStyle::Butt), + "round" => Ok(LineCapStyle::Round), + "square" => Ok(LineCapStyle::Square), + _ => Err(()), + } + } +} + +#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] +pub enum LineJoinStyle { + Round = 0, + Bevel = 1, + Miter = 2, +} + +impl FromStr for LineJoinStyle { + type Err = (); + + fn from_str(string: &str) -> Result<LineJoinStyle, ()> { + match string { + "round" => Ok(LineJoinStyle::Round), + "bevel" => Ok(LineJoinStyle::Bevel), + "miter" => Ok(LineJoinStyle::Miter), + _ => Err(()), + } + } +} + +#[derive(Copy, Clone, PartialEq, Deserialize, Serialize)] +pub enum RepetitionStyle { + Repeat, + RepeatX, + RepeatY, + NoRepeat, +} + +impl FromStr for RepetitionStyle { + type Err = (); + + fn from_str(string: &str) -> Result<RepetitionStyle, ()> { + match string { + "repeat" => Ok(RepetitionStyle::Repeat), + "repeat-x" => Ok(RepetitionStyle::RepeatX), + "repeat-y" => Ok(RepetitionStyle::RepeatY), + "no-repeat" => Ok(RepetitionStyle::NoRepeat), + _ => Err(()), + } + } +} + +#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] +pub enum CompositionStyle { + SrcIn, + SrcOut, + SrcOver, + SrcAtop, + DestIn, + DestOut, + DestOver, + DestAtop, + Copy, + Lighter, + Xor, +} + +impl FromStr for CompositionStyle { + type Err = (); + + fn from_str(string: &str) -> Result<CompositionStyle, ()> { + match string { + "source-in" => Ok(CompositionStyle::SrcIn), + "source-out" => Ok(CompositionStyle::SrcOut), + "source-over" => Ok(CompositionStyle::SrcOver), + "source-atop" => Ok(CompositionStyle::SrcAtop), + "destination-in" => Ok(CompositionStyle::DestIn), + "destination-out" => Ok(CompositionStyle::DestOut), + "destination-over" => Ok(CompositionStyle::DestOver), + "destination-atop" => Ok(CompositionStyle::DestAtop), + "copy" => Ok(CompositionStyle::Copy), + "lighter" => Ok(CompositionStyle::Lighter), + "xor" => Ok(CompositionStyle::Xor), + _ => Err(()) + } + } +} + +impl CompositionStyle { + pub fn to_str(&self) -> &str { + match *self { + CompositionStyle::SrcIn => "source-in", + CompositionStyle::SrcOut => "source-out", + CompositionStyle::SrcOver => "source-over", + CompositionStyle::SrcAtop => "source-atop", + CompositionStyle::DestIn => "destination-in", + CompositionStyle::DestOut => "destination-out", + CompositionStyle::DestOver => "destination-over", + CompositionStyle::DestAtop => "destination-atop", + CompositionStyle::Copy => "copy", + CompositionStyle::Lighter => "lighter", + CompositionStyle::Xor => "xor", + } + } +} + +#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] +pub enum BlendingStyle { + Multiply, + Screen, + Overlay, + Darken, + Lighten, + ColorDodge, + ColorBurn, + HardLight, + SoftLight, + Difference, + Exclusion, + Hue, + Saturation, + Color, + Luminosity, +} + +impl FromStr for BlendingStyle { + type Err = (); + + fn from_str(string: &str) -> Result<BlendingStyle, ()> { + match string { + "multiply" => Ok(BlendingStyle::Multiply), + "screen" => Ok(BlendingStyle::Screen), + "overlay" => Ok(BlendingStyle::Overlay), + "darken" => Ok(BlendingStyle::Darken), + "lighten" => Ok(BlendingStyle::Lighten), + "color-dodge" => Ok(BlendingStyle::ColorDodge), + "color-burn" => Ok(BlendingStyle::ColorBurn), + "hard-light" => Ok(BlendingStyle::HardLight), + "soft-light" => Ok(BlendingStyle::SoftLight), + "difference" => Ok(BlendingStyle::Difference), + "exclusion" => Ok(BlendingStyle::Exclusion), + "hue" => Ok(BlendingStyle::Hue), + "saturation" => Ok(BlendingStyle::Saturation), + "color" => Ok(BlendingStyle::Color), + "luminosity" => Ok(BlendingStyle::Luminosity), + _ => Err(()) + } + } +} + +impl BlendingStyle { + pub fn to_str(&self) -> &str { + match *self { + BlendingStyle::Multiply => "multiply", + BlendingStyle::Screen => "screen", + BlendingStyle::Overlay => "overlay", + BlendingStyle::Darken => "darken", + BlendingStyle::Lighten => "lighten", + BlendingStyle::ColorDodge => "color-dodge", + BlendingStyle::ColorBurn => "color-burn", + BlendingStyle::HardLight => "hard-light", + BlendingStyle::SoftLight => "soft-light", + BlendingStyle::Difference => "difference", + BlendingStyle::Exclusion => "exclusion", + BlendingStyle::Hue => "hue", + BlendingStyle::Saturation => "saturation", + BlendingStyle::Color => "color", + BlendingStyle::Luminosity => "luminosity", + } + } +} + +#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] +pub enum CompositionOrBlending { + Composition(CompositionStyle), + Blending(BlendingStyle), +} + +impl Default for CompositionOrBlending { + fn default() -> CompositionOrBlending { + CompositionOrBlending::Composition(CompositionStyle::SrcOver) + } +} + +impl FromStr for CompositionOrBlending { + type Err = (); + + fn from_str(string: &str) -> Result<CompositionOrBlending, ()> { + if let Ok(op) = CompositionStyle::from_str(string) { + return Ok(CompositionOrBlending::Composition(op)); + } + + if let Ok(op) = BlendingStyle::from_str(string) { + return Ok(CompositionOrBlending::Blending(op)); + } + + Err(()) + } +} + +// TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this. +pub fn byte_swap(data: &mut [u8]) { + let length = data.len(); + // FIXME(rust #27741): Range::step_by is not stable yet as of this writing. + let mut i = 0; + while i < length { + let r = data[i + 2]; + data[i + 2] = data[i + 0]; + data[i + 0] = r; + i += 4; + } +} + +pub fn multiply_u8_pixel(a: u8, b: u8) -> u8 { + return (a as u32 * b as u32 / 255) as u8; +} + +pub fn byte_swap_and_premultiply(data: &mut [u8]) { + let length = data.len(); + + let mut i = 0; + while i < length { + let r = data[i + 2]; + let g = data[i + 1]; + let b = data[i + 0]; + let a = data[i + 3]; + + data[i + 0] = multiply_u8_pixel(r, a); + data[i + 1] = multiply_u8_pixel(g, a); + data[i + 2] = multiply_u8_pixel(b, a); + + i += 4; + } +} diff --git a/components/canvas_traits/lib.rs b/components/canvas_traits/lib.rs index 1f6d9eda087..7830d669e3e 100644 --- a/components/canvas_traits/lib.rs +++ b/components/canvas_traits/lib.rs @@ -4,432 +4,22 @@ #![crate_name = "canvas_traits"] #![crate_type = "rlib"] +#![feature(nonzero)] #![deny(unsafe_code)] +extern crate core; extern crate cssparser; extern crate euclid; extern crate heapsize; #[macro_use] extern crate heapsize_derive; extern crate ipc_channel; +#[macro_use] extern crate lazy_static; +extern crate offscreen_gl_context; #[macro_use] extern crate serde; +extern crate servo_config; extern crate webrender_api; -use cssparser::RGBA; -use euclid::{Transform2D, Point2D, Vector2D, Rect, Size2D}; -use ipc_channel::ipc::IpcSender; -use std::default::Default; -use std::str::FromStr; -use webrender_api::{WebGLCommand, WebGLContextId, VRCompositorCommand}; - -#[derive(Clone, Deserialize, Serialize)] -pub enum FillRule { - Nonzero, - Evenodd, -} - -#[derive(Clone, Deserialize, Serialize)] -pub enum CanvasMsg { - Canvas2d(Canvas2dMsg), - Common(CanvasCommonMsg), - FromLayout(FromLayoutMsg), - FromScript(FromScriptMsg), - WebGL(WebGLCommand), - WebVR(VRCompositorCommand) -} - -#[derive(Clone, Deserialize, Serialize)] -pub enum CanvasCommonMsg { - Close, - Recreate(Size2D<i32>), -} - -#[derive(Clone, Deserialize, Serialize)] -pub enum CanvasData { - Image(CanvasImageData), - WebGL(WebGLContextId), -} - -#[derive(Clone, Deserialize, Serialize)] -pub struct CanvasImageData { - pub image_key: webrender_api::ImageKey, -} - -#[derive(Clone, Deserialize, Serialize)] -pub enum FromLayoutMsg { - SendData(IpcSender<CanvasData>), -} - -#[derive(Clone, Deserialize, Serialize)] -pub enum FromScriptMsg { - SendPixels(IpcSender<Option<Vec<u8>>>), -} - -#[derive(Clone, Deserialize, Serialize)] -pub enum Canvas2dMsg { - Arc(Point2D<f32>, f32, f32, f32, bool), - ArcTo(Point2D<f32>, Point2D<f32>, f32), - DrawImage(Vec<u8>, Size2D<f64>, Rect<f64>, Rect<f64>, bool), - DrawImageSelf(Size2D<f64>, Rect<f64>, Rect<f64>, bool), - DrawImageInOther( - IpcSender<CanvasMsg>, Size2D<f64>, Rect<f64>, Rect<f64>, bool, IpcSender<()>), - BeginPath, - BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>), - ClearRect(Rect<f32>), - Clip, - ClosePath, - Fill, - FillRect(Rect<f32>), - GetImageData(Rect<i32>, Size2D<f64>, IpcSender<Vec<u8>>), - IsPointInPath(f64, f64, FillRule, IpcSender<bool>), - LineTo(Point2D<f32>), - MoveTo(Point2D<f32>), - PutImageData(Vec<u8>, Vector2D<f64>, Size2D<f64>, Rect<f64>), - QuadraticCurveTo(Point2D<f32>, Point2D<f32>), - Rect(Rect<f32>), - RestoreContext, - SaveContext, - StrokeRect(Rect<f32>), - Stroke, - SetFillStyle(FillOrStrokeStyle), - SetStrokeStyle(FillOrStrokeStyle), - SetLineWidth(f32), - SetLineCap(LineCapStyle), - SetLineJoin(LineJoinStyle), - SetMiterLimit(f32), - SetGlobalAlpha(f32), - SetGlobalComposition(CompositionOrBlending), - SetTransform(Transform2D<f32>), - SetShadowOffsetX(f64), - SetShadowOffsetY(f64), - SetShadowBlur(f64), - SetShadowColor(RGBA), -} - -#[derive(Clone, Deserialize, Serialize, HeapSizeOf)] -pub struct CanvasGradientStop { - pub offset: f64, - pub color: RGBA, -} - -#[derive(Clone, Deserialize, Serialize, HeapSizeOf)] -pub struct LinearGradientStyle { - pub x0: f64, - pub y0: f64, - pub x1: f64, - pub y1: f64, - pub stops: Vec<CanvasGradientStop> -} - -impl LinearGradientStyle { - pub fn new(x0: f64, y0: f64, x1: f64, y1: f64, stops: Vec<CanvasGradientStop>) - -> LinearGradientStyle { - LinearGradientStyle { - x0: x0, - y0: y0, - x1: x1, - y1: y1, - stops: stops, - } - } -} - -#[derive(Clone, Deserialize, Serialize, HeapSizeOf)] -pub struct RadialGradientStyle { - pub x0: f64, - pub y0: f64, - pub r0: f64, - pub x1: f64, - pub y1: f64, - pub r1: f64, - pub stops: Vec<CanvasGradientStop> -} - -impl RadialGradientStyle { - pub fn new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64, stops: Vec<CanvasGradientStop>) - -> RadialGradientStyle { - RadialGradientStyle { - x0: x0, - y0: y0, - r0: r0, - x1: x1, - y1: y1, - r1: r1, - stops: stops, - } - } -} - -#[derive(Clone, Deserialize, Serialize)] -pub struct SurfaceStyle { - pub surface_data: Vec<u8>, - pub surface_size: Size2D<i32>, - pub repeat_x: bool, - pub repeat_y: bool, -} - -impl SurfaceStyle { - pub fn new(surface_data: Vec<u8>, surface_size: Size2D<i32>, repeat_x: bool, repeat_y: bool) - -> SurfaceStyle { - SurfaceStyle { - surface_data: surface_data, - surface_size: surface_size, - repeat_x: repeat_x, - repeat_y: repeat_y, - } - } -} - - -#[derive(Clone, Deserialize, Serialize)] -pub enum FillOrStrokeStyle { - Color(RGBA), - LinearGradient(LinearGradientStyle), - RadialGradient(RadialGradientStyle), - Surface(SurfaceStyle), -} - -#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] -pub enum LineCapStyle { - Butt = 0, - Round = 1, - Square = 2, -} - -impl FromStr for LineCapStyle { - type Err = (); - - fn from_str(string: &str) -> Result<LineCapStyle, ()> { - match string { - "butt" => Ok(LineCapStyle::Butt), - "round" => Ok(LineCapStyle::Round), - "square" => Ok(LineCapStyle::Square), - _ => Err(()), - } - } -} - -#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] -pub enum LineJoinStyle { - Round = 0, - Bevel = 1, - Miter = 2, -} - -impl FromStr for LineJoinStyle { - type Err = (); - - fn from_str(string: &str) -> Result<LineJoinStyle, ()> { - match string { - "round" => Ok(LineJoinStyle::Round), - "bevel" => Ok(LineJoinStyle::Bevel), - "miter" => Ok(LineJoinStyle::Miter), - _ => Err(()), - } - } -} - -#[derive(Copy, Clone, PartialEq, Deserialize, Serialize)] -pub enum RepetitionStyle { - Repeat, - RepeatX, - RepeatY, - NoRepeat, -} - -impl FromStr for RepetitionStyle { - type Err = (); - - fn from_str(string: &str) -> Result<RepetitionStyle, ()> { - match string { - "repeat" => Ok(RepetitionStyle::Repeat), - "repeat-x" => Ok(RepetitionStyle::RepeatX), - "repeat-y" => Ok(RepetitionStyle::RepeatY), - "no-repeat" => Ok(RepetitionStyle::NoRepeat), - _ => Err(()), - } - } -} - -#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] -pub enum CompositionStyle { - SrcIn, - SrcOut, - SrcOver, - SrcAtop, - DestIn, - DestOut, - DestOver, - DestAtop, - Copy, - Lighter, - Xor, -} - -impl FromStr for CompositionStyle { - type Err = (); - - fn from_str(string: &str) -> Result<CompositionStyle, ()> { - match string { - "source-in" => Ok(CompositionStyle::SrcIn), - "source-out" => Ok(CompositionStyle::SrcOut), - "source-over" => Ok(CompositionStyle::SrcOver), - "source-atop" => Ok(CompositionStyle::SrcAtop), - "destination-in" => Ok(CompositionStyle::DestIn), - "destination-out" => Ok(CompositionStyle::DestOut), - "destination-over" => Ok(CompositionStyle::DestOver), - "destination-atop" => Ok(CompositionStyle::DestAtop), - "copy" => Ok(CompositionStyle::Copy), - "lighter" => Ok(CompositionStyle::Lighter), - "xor" => Ok(CompositionStyle::Xor), - _ => Err(()) - } - } -} - -impl CompositionStyle { - pub fn to_str(&self) -> &str { - match *self { - CompositionStyle::SrcIn => "source-in", - CompositionStyle::SrcOut => "source-out", - CompositionStyle::SrcOver => "source-over", - CompositionStyle::SrcAtop => "source-atop", - CompositionStyle::DestIn => "destination-in", - CompositionStyle::DestOut => "destination-out", - CompositionStyle::DestOver => "destination-over", - CompositionStyle::DestAtop => "destination-atop", - CompositionStyle::Copy => "copy", - CompositionStyle::Lighter => "lighter", - CompositionStyle::Xor => "xor", - } - } -} - -#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] -pub enum BlendingStyle { - Multiply, - Screen, - Overlay, - Darken, - Lighten, - ColorDodge, - ColorBurn, - HardLight, - SoftLight, - Difference, - Exclusion, - Hue, - Saturation, - Color, - Luminosity, -} - -impl FromStr for BlendingStyle { - type Err = (); - - fn from_str(string: &str) -> Result<BlendingStyle, ()> { - match string { - "multiply" => Ok(BlendingStyle::Multiply), - "screen" => Ok(BlendingStyle::Screen), - "overlay" => Ok(BlendingStyle::Overlay), - "darken" => Ok(BlendingStyle::Darken), - "lighten" => Ok(BlendingStyle::Lighten), - "color-dodge" => Ok(BlendingStyle::ColorDodge), - "color-burn" => Ok(BlendingStyle::ColorBurn), - "hard-light" => Ok(BlendingStyle::HardLight), - "soft-light" => Ok(BlendingStyle::SoftLight), - "difference" => Ok(BlendingStyle::Difference), - "exclusion" => Ok(BlendingStyle::Exclusion), - "hue" => Ok(BlendingStyle::Hue), - "saturation" => Ok(BlendingStyle::Saturation), - "color" => Ok(BlendingStyle::Color), - "luminosity" => Ok(BlendingStyle::Luminosity), - _ => Err(()) - } - } -} - -impl BlendingStyle { - pub fn to_str(&self) -> &str { - match *self { - BlendingStyle::Multiply => "multiply", - BlendingStyle::Screen => "screen", - BlendingStyle::Overlay => "overlay", - BlendingStyle::Darken => "darken", - BlendingStyle::Lighten => "lighten", - BlendingStyle::ColorDodge => "color-dodge", - BlendingStyle::ColorBurn => "color-burn", - BlendingStyle::HardLight => "hard-light", - BlendingStyle::SoftLight => "soft-light", - BlendingStyle::Difference => "difference", - BlendingStyle::Exclusion => "exclusion", - BlendingStyle::Hue => "hue", - BlendingStyle::Saturation => "saturation", - BlendingStyle::Color => "color", - BlendingStyle::Luminosity => "luminosity", - } - } -} - -#[derive(Copy, Clone, PartialEq, Deserialize, Serialize, HeapSizeOf)] -pub enum CompositionOrBlending { - Composition(CompositionStyle), - Blending(BlendingStyle), -} - -impl Default for CompositionOrBlending { - fn default() -> CompositionOrBlending { - CompositionOrBlending::Composition(CompositionStyle::SrcOver) - } -} - -impl FromStr for CompositionOrBlending { - type Err = (); - - fn from_str(string: &str) -> Result<CompositionOrBlending, ()> { - if let Ok(op) = CompositionStyle::from_str(string) { - return Ok(CompositionOrBlending::Composition(op)); - } - - if let Ok(op) = BlendingStyle::from_str(string) { - return Ok(CompositionOrBlending::Blending(op)); - } - - Err(()) - } -} - -// TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this. -pub fn byte_swap(data: &mut [u8]) { - let length = data.len(); - // FIXME(rust #27741): Range::step_by is not stable yet as of this writing. - let mut i = 0; - while i < length { - let r = data[i + 2]; - data[i + 2] = data[i + 0]; - data[i + 0] = r; - i += 4; - } -} - -pub fn multiply_u8_pixel(a: u8, b: u8) -> u8 { - return (a as u32 * b as u32 / 255) as u8; -} - -pub fn byte_swap_and_premultiply(data: &mut [u8]) { - let length = data.len(); - - let mut i = 0; - while i < length { - let r = data[i + 2]; - let g = data[i + 1]; - let b = data[i + 0]; - let a = data[i + 3]; - - data[i + 0] = multiply_u8_pixel(r, a); - data[i + 1] = multiply_u8_pixel(g, a); - data[i + 2] = multiply_u8_pixel(b, a); - - i += 4; - } -} +pub mod canvas; +pub mod webgl; +mod webgl_channel; diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs new file mode 100644 index 00000000000..1bd6eb0649b --- /dev/null +++ b/components/canvas_traits/webgl.rs @@ -0,0 +1,506 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use core::nonzero::NonZero; +use euclid::Size2D; +use offscreen_gl_context::{GLContextAttributes, GLLimits}; +use std::fmt; +use webrender_api; + +/// Sender type used in WebGLCommands. +pub use ::webgl_channel::WebGLSender; +/// Receiver type used in WebGLCommands. +pub use ::webgl_channel::WebGLReceiver; +/// Result type for send()/recv() calls in in WebGLCommands. +pub use ::webgl_channel::WebGLSendResult; +/// Helper function that creates a WebGL channel (WebGLSender, WebGLReceiver) to be used in WebGLCommands. +pub use ::webgl_channel::webgl_channel; +/// Entry point type used in a Script Pipeline to get the WebGLChan to be used in that thread. +pub use ::webgl_channel::WebGLPipeline; +/// Entry point channel type used for sending WebGLMsg messages to the WebGL renderer. +pub use ::webgl_channel::WebGLChan; + +/// WebGL Message API +#[derive(Clone, Deserialize, Serialize)] +pub enum WebGLMsg { + /// Creates a new WebGLContext. + CreateContext(Size2D<i32>, GLContextAttributes, WebGLSender<Result<(WebGLCreateContextResult), String>>), + /// Resizes a WebGLContext. + ResizeContext(WebGLContextId, Size2D<i32>, WebGLSender<Result<(), String>>), + /// Drops a WebGLContext. + RemoveContext(WebGLContextId), + /// Runs a WebGLCommand in a specific WebGLContext. + WebGLCommand(WebGLContextId, WebGLCommand), + /// Runs a WebVRCommand in a specific WebGLContext. + WebVRCommand(WebGLContextId, WebVRCommand), + /// Locks a specific WebGLContext. Lock messages are used for a correct synchronization + /// with WebRender external image API. + /// WR locks a external texture when it wants to use the shared texture contents. + /// The WR client should not change the shared texture content until the Unlock call. + /// Currently OpenGL Sync Objects are used to implement the synchronization mechanism. + Lock(WebGLContextId, WebGLSender<(u32, Size2D<i32>)>), + /// Unlocks a specific WebGLContext. Unlock messages are used for a correct synchronization + /// with WebRender external image API. + /// The WR unlocks a context when it finished reading the shared texture contents. + /// 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>), + /// Frees all resources and closes the thread. + Exit, +} + +/// Contains the WebGLCommand sender and information about a WebGLContext +#[derive(Clone, Deserialize, Serialize)] +pub struct WebGLCreateContextResult { + /// Sender instance to send commands to the specific WebGLContext + pub sender: WebGLMsgSender, + /// Information about the internal GL Context. + pub limits: GLLimits, + /// How the WebGLContext is shared with WebRender. + pub share_mode: WebGLContextShareMode, +} + +#[derive(Clone, Copy, Deserialize, HeapSizeOf, Serialize)] +pub enum WebGLContextShareMode { + /// Fast: a shared texture_id is used in WebRender. + SharedTexture, + /// Slow: glReadPixels is used to send pixels to WebRender each frame. + Readback, +} + +/// Helper struct to send WebGLCommands to a specific WebGLContext. +#[derive(Clone, Deserialize, HeapSizeOf, Serialize)] +pub struct WebGLMsgSender { + ctx_id: WebGLContextId, + #[ignore_heap_size_of = "channels are hard"] + sender: WebGLChan, +} + +impl WebGLMsgSender { + pub fn new(id: WebGLContextId, sender: WebGLChan) -> Self { + WebGLMsgSender { + ctx_id: id, + sender: sender, + } + } + + /// Send a WebGLCommand message + #[inline] + pub fn send(&self, command: WebGLCommand) -> WebGLSendResult { + self.sender.send(WebGLMsg::WebGLCommand(self.ctx_id, command)) + } + + /// Send a WebVRCommand message + #[inline] + pub fn send_vr(&self, command: WebVRCommand) -> WebGLSendResult { + self.sender.send(WebGLMsg::WebVRCommand(self.ctx_id, command)) + } + + /// Send a resize message + #[inline] + pub fn send_resize(&self, + size: Size2D<i32>, + sender: WebGLSender<Result<(), String>>) + -> WebGLSendResult { + self.sender.send(WebGLMsg::ResizeContext(self.ctx_id, size, sender)) + } + + #[inline] + pub fn send_remove(&self) -> WebGLSendResult { + self.sender.send(WebGLMsg::RemoveContext(self.ctx_id)) + } + + #[inline] + pub fn send_update_wr_image(&self, sender: WebGLSender<webrender_api::ImageKey>) -> WebGLSendResult { + self.sender.send(WebGLMsg::UpdateWebRenderImage(self.ctx_id, sender)) + } +} + +/// WebGL Commands for a specific WebGLContext +#[derive(Clone, Deserialize, Serialize)] +pub enum WebGLCommand { + GetContextAttributes(WebGLSender<GLContextAttributes>), + ActiveTexture(u32), + BlendColor(f32, f32, f32, f32), + BlendEquation(u32), + BlendEquationSeparate(u32, u32), + BlendFunc(u32, u32), + BlendFuncSeparate(u32, u32, u32, u32), + AttachShader(WebGLProgramId, WebGLShaderId), + DetachShader(WebGLProgramId, WebGLShaderId), + BindAttribLocation(WebGLProgramId, u32, String), + BufferData(u32, Vec<u8>, u32), + BufferSubData(u32, isize, Vec<u8>), + Clear(u32), + ClearColor(f32, f32, f32, f32), + ClearDepth(f64), + ClearStencil(i32), + ColorMask(bool, bool, bool, bool), + CullFace(u32), + FrontFace(u32), + DepthFunc(u32), + DepthMask(bool), + DepthRange(f64, f64), + Enable(u32), + Disable(u32), + CompileShader(WebGLShaderId, String), + CopyTexImage2D(u32, i32, u32, i32, i32, i32, i32, i32), + CopyTexSubImage2D(u32, i32, i32, i32, i32, i32, i32, i32), + CreateBuffer(WebGLSender<Option<WebGLBufferId>>), + CreateFramebuffer(WebGLSender<Option<WebGLFramebufferId>>), + CreateRenderbuffer(WebGLSender<Option<WebGLRenderbufferId>>), + CreateTexture(WebGLSender<Option<WebGLTextureId>>), + CreateProgram(WebGLSender<Option<WebGLProgramId>>), + CreateShader(u32, WebGLSender<Option<WebGLShaderId>>), + DeleteBuffer(WebGLBufferId), + DeleteFramebuffer(WebGLFramebufferId), + DeleteRenderbuffer(WebGLRenderbufferId), + DeleteTexture(WebGLTextureId), + DeleteProgram(WebGLProgramId), + DeleteShader(WebGLShaderId), + BindBuffer(u32, Option<WebGLBufferId>), + BindFramebuffer(u32, WebGLFramebufferBindingRequest), + BindRenderbuffer(u32, Option<WebGLRenderbufferId>), + BindTexture(u32, Option<WebGLTextureId>), + DisableVertexAttribArray(u32), + DrawArrays(u32, i32, i32), + DrawElements(u32, i32, u32, i64), + EnableVertexAttribArray(u32), + FramebufferRenderbuffer(u32, u32, u32, Option<WebGLRenderbufferId>), + FramebufferTexture2D(u32, u32, u32, Option<WebGLTextureId>, i32), + GetBufferParameter(u32, u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetExtensions(WebGLSender<String>), + GetParameter(u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetProgramParameter(WebGLProgramId, u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetShaderParameter(WebGLShaderId, u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetShaderPrecisionFormat(u32, u32, WebGLSender<WebGLResult<(i32, i32, i32)>>), + GetActiveAttrib(WebGLProgramId, u32, WebGLSender<WebGLResult<(i32, u32, String)>>), + GetActiveUniform(WebGLProgramId, u32, WebGLSender<WebGLResult<(i32, u32, String)>>), + GetAttribLocation(WebGLProgramId, String, WebGLSender<Option<i32>>), + GetUniformLocation(WebGLProgramId, String, WebGLSender<Option<i32>>), + GetVertexAttrib(u32, u32, WebGLSender<WebGLResult<WebGLParameter>>), + GetVertexAttribOffset(u32, u32, WebGLSender<WebGLResult<isize>>), + GetShaderInfoLog(WebGLShaderId, WebGLSender<String>), + GetProgramInfoLog(WebGLProgramId, WebGLSender<String>), + PolygonOffset(f32, f32), + RenderbufferStorage(u32, u32, i32, i32), + ReadPixels(i32, i32, i32, i32, u32, u32, WebGLSender<Vec<u8>>), + SampleCoverage(f32, bool), + Scissor(i32, i32, i32, i32), + StencilFunc(u32, i32, u32), + StencilFuncSeparate(u32, u32, i32, u32), + StencilMask(u32), + StencilMaskSeparate(u32, u32), + StencilOp(u32, u32, u32), + StencilOpSeparate(u32, u32, u32, u32), + Hint(u32, u32), + IsEnabled(u32, WebGLSender<bool>), + LineWidth(f32), + PixelStorei(u32, i32), + LinkProgram(WebGLProgramId), + Uniform1f(i32, f32), + Uniform1fv(i32, Vec<f32>), + Uniform1i(i32, i32), + Uniform1iv(i32, Vec<i32>), + Uniform2f(i32, f32, f32), + Uniform2fv(i32, Vec<f32>), + Uniform2i(i32, i32, i32), + Uniform2iv(i32, Vec<i32>), + Uniform3f(i32, f32, f32, f32), + Uniform3fv(i32, Vec<f32>), + Uniform3i(i32, i32, i32, i32), + Uniform3iv(i32, Vec<i32>), + Uniform4f(i32, f32, f32, f32, f32), + Uniform4fv(i32, Vec<f32>), + Uniform4i(i32, i32, i32, i32, i32), + Uniform4iv(i32, Vec<i32>), + UniformMatrix2fv(i32, bool, Vec<f32>), + UniformMatrix3fv(i32, bool, Vec<f32>), + UniformMatrix4fv(i32, bool, Vec<f32>), + UseProgram(WebGLProgramId), + ValidateProgram(WebGLProgramId), + VertexAttrib(u32, f32, f32, f32, f32), + VertexAttribPointer(u32, i32, u32, bool, i32, u32), + VertexAttribPointer2f(u32, i32, bool, i32, u32), + Viewport(i32, i32, i32, i32), + TexImage2D(u32, i32, i32, i32, i32, u32, u32, Vec<u8>), + TexParameteri(u32, u32, i32), + TexParameterf(u32, u32, f32), + TexSubImage2D(u32, i32, i32, i32, i32, i32, u32, u32, Vec<u8>), + DrawingBufferWidth(WebGLSender<i32>), + DrawingBufferHeight(WebGLSender<i32>), + Finish(WebGLSender<()>), + Flush, + GenerateMipmap(u32), + CreateVertexArray(WebGLSender<Option<WebGLVertexArrayId>>), + DeleteVertexArray(WebGLVertexArrayId), + BindVertexArray(Option<WebGLVertexArrayId>), +} + +macro_rules! define_resource_id_struct { + ($name:ident) => { + #[derive(Clone, Copy, Eq, Hash, PartialEq)] + pub struct $name(NonZero<u32>); + + impl $name { + #[allow(unsafe_code)] + #[inline] + pub unsafe fn new(id: u32) -> Self { + $name(NonZero::new_unchecked(id)) + } + + #[inline] + pub fn get(self) -> u32 { + self.0.get() + } + } + + }; +} + +macro_rules! define_resource_id { + ($name:ident) => { + define_resource_id_struct!($name); + + #[allow(unsafe_code)] + impl<'de> ::serde::Deserialize<'de> for $name { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where D: ::serde::Deserializer<'de> + { + let id = try!(u32::deserialize(deserializer)); + if id == 0 { + Err(::serde::de::Error::custom("expected a non-zero value")) + } else { + Ok(unsafe { $name::new(id) }) + } + } + } + + impl ::serde::Serialize for $name { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where S: ::serde::Serializer + { + self.get().serialize(serializer) + } + } + + impl ::std::fmt::Debug for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> { + fmt.debug_tuple(stringify!($name)) + .field(&self.get()) + .finish() + } + } + + impl ::std::fmt::Display for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> { + write!(fmt, "{}", self.get()) + } + } + + impl ::heapsize::HeapSizeOf for $name { + fn heap_size_of_children(&self) -> usize { 0 } + } + } +} + +define_resource_id!(WebGLBufferId); +define_resource_id!(WebGLFramebufferId); +define_resource_id!(WebGLRenderbufferId); +define_resource_id!(WebGLTextureId); +define_resource_id!(WebGLProgramId); +define_resource_id!(WebGLShaderId); +define_resource_id!(WebGLVertexArrayId); + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +pub struct WebGLContextId(pub usize); + +impl ::heapsize::HeapSizeOf for WebGLContextId { + fn heap_size_of_children(&self) -> usize { 0 } +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub enum WebGLError { + InvalidEnum, + InvalidFramebufferOperation, + InvalidOperation, + InvalidValue, + OutOfMemory, + ContextLost, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum WebGLFramebufferBindingRequest { + Explicit(WebGLFramebufferId), + Default, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum WebGLParameter { + Int(i32), + Bool(bool), + String(String), + Float(f32), + FloatArray(Vec<f32>), + Invalid, +} + +pub type WebGLResult<T> = Result<T, WebGLError>; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum WebGLShaderParameter { + Int(i32), + Bool(bool), + Invalid, +} + +pub type WebVRDeviceId = u32; + +// WebVR commands that must be called in the WebGL render thread. +#[derive(Clone, Deserialize, Serialize)] +pub enum WebVRCommand { + /// Start presenting to a VR device. + Create(WebVRDeviceId), + /// Synchronize the pose information to be used in the frame. + SyncPoses(WebVRDeviceId, f64, f64, WebGLSender<Result<Vec<u8>, ()>>), + /// Submit the frame to a VR device using the specified texture coordinates. + SubmitFrame(WebVRDeviceId, [f32; 4], [f32; 4]), + /// Stop presenting to a VR device + Release(WebVRDeviceId) +} + +// Trait object that handles WebVR commands. +// Receives the texture id and size associated to the WebGLContext. +pub trait WebVRRenderHandler: Send { + fn handle(&mut self, command: WebVRCommand, texture: Option<(u32, Size2D<i32>)>); +} + +impl fmt::Debug for WebGLCommand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::WebGLCommand::*; + let name = match *self { + GetContextAttributes(..) => "GetContextAttributes", + ActiveTexture(..) => "ActiveTexture", + BlendColor(..) => "BlendColor", + BlendEquation(..) => "BlendEquation", + BlendEquationSeparate(..) => "BlendEquationSeparate", + BlendFunc(..) => "BlendFunc", + BlendFuncSeparate(..) => "BlendFuncSeparate", + AttachShader(..) => "AttachShader", + DetachShader(..) => "DetachShader", + BindAttribLocation(..) => "BindAttribLocation", + BufferData(..) => "BufferData", + BufferSubData(..) => "BufferSubData", + Clear(..) => "Clear", + ClearColor(..) => "ClearColor", + ClearDepth(..) => "ClearDepth", + ClearStencil(..) => "ClearStencil", + ColorMask(..) => "ColorMask", + CopyTexImage2D(..) => "CopyTexImage2D", + CopyTexSubImage2D(..) => "CopyTexSubImage2D", + CullFace(..) => "CullFace", + FrontFace(..) => "FrontFace", + DepthFunc(..) => "DepthFunc", + DepthMask(..) => "DepthMask", + DepthRange(..) => "DepthRange", + Enable(..) => "Enable", + Disable(..) => "Disable", + CompileShader(..) => "CompileShader", + CreateBuffer(..) => "CreateBuffer", + CreateFramebuffer(..) => "CreateFramebuffer", + CreateRenderbuffer(..) => "CreateRenderbuffer", + CreateTexture(..) => "CreateTexture", + CreateProgram(..) => "CreateProgram", + CreateShader(..) => "CreateShader", + DeleteBuffer(..) => "DeleteBuffer", + DeleteFramebuffer(..) => "DeleteFramebuffer", + DeleteRenderbuffer(..) => "DeleteRenderBuffer", + DeleteTexture(..) => "DeleteTexture", + DeleteProgram(..) => "DeleteProgram", + DeleteShader(..) => "DeleteShader", + BindBuffer(..) => "BindBuffer", + BindFramebuffer(..) => "BindFramebuffer", + BindRenderbuffer(..) => "BindRenderbuffer", + BindTexture(..) => "BindTexture", + DisableVertexAttribArray(..) => "DisableVertexAttribArray", + DrawArrays(..) => "DrawArrays", + DrawElements(..) => "DrawElements", + EnableVertexAttribArray(..) => "EnableVertexAttribArray", + FramebufferRenderbuffer(..) => "FramebufferRenderbuffer", + FramebufferTexture2D(..) => "FramebufferTexture2D", + GetBufferParameter(..) => "GetBufferParameter", + GetExtensions(..) => "GetExtensions", + GetParameter(..) => "GetParameter", + GetProgramParameter(..) => "GetProgramParameter", + GetShaderParameter(..) => "GetShaderParameter", + GetShaderPrecisionFormat(..) => "GetShaderPrecisionFormat", + GetActiveAttrib(..) => "GetActiveAttrib", + GetActiveUniform(..) => "GetActiveUniform", + GetAttribLocation(..) => "GetAttribLocation", + GetUniformLocation(..) => "GetUniformLocation", + GetShaderInfoLog(..) => "GetShaderInfoLog", + GetProgramInfoLog(..) => "GetProgramInfoLog", + GetVertexAttrib(..) => "GetVertexAttrib", + GetVertexAttribOffset(..) => "GetVertexAttribOffset", + PolygonOffset(..) => "PolygonOffset", + ReadPixels(..) => "ReadPixels", + RenderbufferStorage(..) => "RenderbufferStorage", + SampleCoverage(..) => "SampleCoverage", + Scissor(..) => "Scissor", + StencilFunc(..) => "StencilFunc", + StencilFuncSeparate(..) => "StencilFuncSeparate", + StencilMask(..) => "StencilMask", + StencilMaskSeparate(..) => "StencilMaskSeparate", + StencilOp(..) => "StencilOp", + StencilOpSeparate(..) => "StencilOpSeparate", + Hint(..) => "Hint", + IsEnabled(..) => "IsEnabled", + LineWidth(..) => "LineWidth", + PixelStorei(..) => "PixelStorei", + LinkProgram(..) => "LinkProgram", + Uniform1f(..) => "Uniform1f", + Uniform1fv(..) => "Uniform1fv", + Uniform1i(..) => "Uniform1i", + Uniform1iv(..) => "Uniform1iv", + Uniform2f(..) => "Uniform2f", + Uniform2fv(..) => "Uniform2fv", + Uniform2i(..) => "Uniform2i", + Uniform2iv(..) => "Uniform2iv", + Uniform3f(..) => "Uniform3f", + Uniform3fv(..) => "Uniform3fv", + Uniform3i(..) => "Uniform3i", + Uniform3iv(..) => "Uniform3iv", + Uniform4f(..) => "Uniform4f", + Uniform4fv(..) => "Uniform4fv", + Uniform4i(..) => "Uniform4i", + Uniform4iv(..) => "Uniform4iv", + UniformMatrix2fv(..) => "UniformMatrix2fv", + UniformMatrix3fv(..) => "UniformMatrix3fv", + UniformMatrix4fv(..) => "UniformMatrix4fv", + UseProgram(..) => "UseProgram", + ValidateProgram(..) => "ValidateProgram", + VertexAttrib(..) => "VertexAttrib", + VertexAttribPointer2f(..) => "VertexAttribPointer2f", + VertexAttribPointer(..) => "VertexAttribPointer", + Viewport(..) => "Viewport", + TexImage2D(..) => "TexImage2D", + TexParameteri(..) => "TexParameteri", + TexParameterf(..) => "TexParameterf", + TexSubImage2D(..) => "TexSubImage2D", + DrawingBufferWidth(..) => "DrawingBufferWidth", + DrawingBufferHeight(..) => "DrawingBufferHeight", + Finish(..) => "Finish", + Flush => "Flush", + GenerateMipmap(..) => "GenerateMipmap", + CreateVertexArray(..) => "CreateVertexArray", + DeleteVertexArray(..) => "DeleteVertexArray", + BindVertexArray(..) => "BindVertexArray" + }; + + write!(f, "CanvasWebGLMsg::{}(..)", name) + } +} diff --git a/components/canvas_traits/webgl_channel/ipc.rs b/components/canvas_traits/webgl_channel/ipc.rs new file mode 100644 index 00000000000..ac3020bbc7a --- /dev/null +++ b/components/canvas_traits/webgl_channel/ipc.rs @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use ipc_channel; +use serde::{Deserialize, Serialize}; +use std::io; + +pub type WebGLSender<T> = ipc_channel::ipc::IpcSender<T>; +pub type WebGLReceiver<T> = ipc_channel::ipc::IpcReceiver<T>; + +pub fn webgl_channel<T: Serialize + for<'de> Deserialize<'de>>() + -> Result<(WebGLSender<T>, WebGLReceiver<T>), io::Error> { + ipc_channel::ipc::channel() +} diff --git a/components/canvas_traits/webgl_channel/mod.rs b/components/canvas_traits/webgl_channel/mod.rs new file mode 100644 index 00000000000..1ac4ce15cb1 --- /dev/null +++ b/components/canvas_traits/webgl_channel/mod.rs @@ -0,0 +1,87 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Enum wrappers to be able to select different channel implementations at runtime. + +mod ipc; +mod mpsc; + +use ::webgl::WebGLMsg; +use serde::{Deserialize, Serialize}; +use servo_config::opts; + +lazy_static! { + static ref IS_MULTIPROCESS: bool = { + opts::multiprocess() + }; +} + +#[derive(Clone, Deserialize, Serialize)] +pub enum WebGLSender<T: Serialize> { + Ipc(ipc::WebGLSender<T>), + Mpsc(mpsc::WebGLSender<T>), +} + +impl<T: Serialize> WebGLSender<T> { + #[inline] + pub fn send(&self, msg: T) -> WebGLSendResult { + match *self { + WebGLSender::Ipc(ref sender) => { + sender.send(msg).map_err(|_| ()) + }, + WebGLSender::Mpsc(ref sender) => { + sender.send(msg).map_err(|_| ()) + } + } + } +} + +pub type WebGLSendResult = Result<(), ()>; + +pub enum WebGLReceiver<T> where T: for<'de> Deserialize<'de> + Serialize { + Ipc(ipc::WebGLReceiver<T>), + Mpsc(mpsc::WebGLReceiver<T>), +} + +impl<T> WebGLReceiver<T> where T: for<'de> Deserialize<'de> + Serialize { + pub fn recv(&self) -> Result<T, ()> { + match *self { + WebGLReceiver::Ipc(ref receiver) => { + receiver.recv().map_err(|_| ()) + }, + WebGLReceiver::Mpsc(ref receiver) => { + receiver.recv().map_err(|_| ()) + } + } + } +} + +pub fn webgl_channel<T>() -> Result<(WebGLSender<T>, WebGLReceiver<T>), ()> + where T: for<'de> Deserialize<'de> + Serialize { + if *IS_MULTIPROCESS { + ipc::webgl_channel().map(|(tx, rx)| (WebGLSender::Ipc(tx), WebGLReceiver::Ipc(rx))) + .map_err(|_| ()) + } else { + mpsc::webgl_channel().map(|(tx, rx)| (WebGLSender::Mpsc(tx), WebGLReceiver::Mpsc(rx))) + } +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct WebGLChan(pub WebGLSender<WebGLMsg>); + +impl WebGLChan { + #[inline] + pub fn send(&self, msg: WebGLMsg) -> WebGLSendResult { + self.0.send(msg) + } +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct WebGLPipeline(pub WebGLChan); + +impl WebGLPipeline { + pub fn channel(&self) -> WebGLChan { + self.0.clone() + } +} diff --git a/components/canvas_traits/webgl_channel/mpsc.rs b/components/canvas_traits/webgl_channel/mpsc.rs new file mode 100644 index 00000000000..b0fe29241f3 --- /dev/null +++ b/components/canvas_traits/webgl_channel/mpsc.rs @@ -0,0 +1,51 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use serde::{Deserialize, Serialize}; +use serde::{Deserializer, Serializer}; +use std::sync::mpsc; + +#[macro_use] +macro_rules! unreachable_serializable { + ($name:ident) => { + impl<T> Serialize for $name<T> { + fn serialize<S: Serializer>(&self, _: S) -> Result<S::Ok, S::Error> { + unreachable!(); + } + } + + impl<'a, T> Deserialize<'a> for $name<T> { + fn deserialize<D>(_: D) -> Result<$name<T>, D::Error> + where D: Deserializer<'a> { + unreachable!(); + } + } + }; +} + +#[derive(Clone)] +pub struct WebGLSender<T>(mpsc::Sender<T>); +pub struct WebGLReceiver<T>(mpsc::Receiver<T>); + +impl<T> WebGLSender<T> { + #[inline] + pub fn send(&self, data: T) -> Result<(), mpsc::SendError<T>> { + self.0.send(data) + } +} + +impl<T> WebGLReceiver<T> { + #[inline] + pub fn recv(&self) -> Result<T, mpsc::RecvError> { + self.0.recv() + } +} + +pub fn webgl_channel<T>() -> Result<(WebGLSender<T>, WebGLReceiver<T>), ()> { + let (sender, receiver) = mpsc::channel(); + Ok((WebGLSender(sender), WebGLReceiver(receiver))) +} + +unreachable_serializable!(WebGLReceiver); +unreachable_serializable!(WebGLSender); diff --git a/components/constellation/Cargo.toml b/components/constellation/Cargo.toml index ff6bd2700f0..f2ab08dc190 100644 --- a/components/constellation/Cargo.toml +++ b/components/constellation/Cargo.toml @@ -30,7 +30,6 @@ metrics = {path = "../metrics"} msg = {path = "../msg"} net = {path = "../net"} net_traits = {path = "../net_traits"} -offscreen_gl_context = { version = "0.11", features = ["serde"] } profile_traits = {path = "../profile_traits"} script_traits = {path = "../script_traits"} serde = "1.0" diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 1685a32d8d2..3e9b0cc80be 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -70,8 +70,8 @@ use bluetooth_traits::BluetoothRequest; use browsingcontext::{BrowsingContext, SessionHistoryChange, SessionHistoryEntry}; use browsingcontext::{FullyActiveBrowsingContextsIterator, AllBrowsingContextsIterator}; use canvas::canvas_paint_thread::CanvasPaintThread; -use canvas::webgl_paint_thread::WebGLPaintThread; -use canvas_traits::CanvasMsg; +use canvas::webgl_thread::WebGLThreads; +use canvas_traits::canvas::CanvasMsg; use clipboard::{ClipboardContext, ClipboardProvider}; use compositing::SendableFrameTree; use compositing::compositor_thread::CompositorProxy; @@ -96,7 +96,6 @@ use net_traits::pub_domains::reg_host; use net_traits::request::RequestInit; use net_traits::storage_thread::{StorageThreadMsg, StorageType}; use network_listener::NetworkListener; -use offscreen_gl_context::{GLContextAttributes, GLLimits}; use pipeline::{InitialPipelineState, Pipeline}; use profile_traits::mem; use profile_traits::time; @@ -298,8 +297,11 @@ pub struct Constellation<Message, LTF, STF> { /// Phantom data that keeps the Rust type system happy. phantom: PhantomData<(Message, LTF, STF)>, + /// Entry point to create and get channels to a WebGLThread. + webgl_threads: WebGLThreads, + /// A channel through which messages can be sent to the webvr thread. - webvr_thread: Option<IpcSender<WebVRMsg>>, + webvr_chan: Option<IpcSender<WebVRMsg>>, } /// State needed to construct a constellation. @@ -337,6 +339,12 @@ pub struct InitialConstellationState { /// Webrender API. pub webrender_api_sender: webrender_api::RenderApiSender, + /// Entry point to create and get channels to a WebGLThread. + pub webgl_threads: WebGLThreads, + + /// A channel to the webgl thread. + pub webvr_chan: Option<IpcSender<WebVRMsg>>, + /// Whether the constellation supports the clipboard. /// TODO: this field is not used, remove it? pub supports_clipboard: bool, @@ -581,7 +589,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> info!("Using seed {} for random pipeline closure.", seed); (rng, prob) }), - webvr_thread: None + webgl_threads: state.webgl_threads, + webvr_chan: state.webvr_chan, }; constellation.run(); @@ -700,7 +709,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> webrender_api_sender: self.webrender_api_sender.clone(), webrender_document: self.webrender_document, is_private, - webvr_thread: self.webvr_thread.clone() + webgl_chan: self.webgl_threads.pipeline(), + webvr_chan: self.webvr_chan.clone() }); let pipeline = match result { @@ -994,10 +1004,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> FromCompositorMsg::LogEntry(top_level_browsing_context_id, thread_name, entry) => { self.handle_log_entry(top_level_browsing_context_id, thread_name, entry); } - FromCompositorMsg::SetWebVRThread(webvr_thread) => { - assert!(self.webvr_thread.is_none()); - self.webvr_thread = Some(webvr_thread) - } FromCompositorMsg::WebVREvents(pipeline_ids, events) => { debug!("constellation got {:?} WebVR events", events.len()); self.handle_webvr_events(pipeline_ids, events); @@ -1154,10 +1160,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> debug!("constellation got create-canvas-paint-thread message"); self.handle_create_canvas_paint_thread_msg(&size, sender) } - FromScriptMsg::CreateWebGLPaintThread(size, attributes, sender) => { - debug!("constellation got create-WebGL-paint-thread message"); - self.handle_create_webgl_paint_thread_msg(&size, attributes, sender) - } FromScriptMsg::NodeStatus(message) => { debug!("constellation got NodeStatus message"); self.compositor_proxy.send(ToCompositorMsg::Status(source_top_ctx_id, message)); @@ -1367,7 +1369,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - if let Some(chan) = self.webvr_thread.as_ref() { + debug!("Exiting WebGL thread."); + if let Err(e) = self.webgl_threads.exit() { + warn!("Exit WebGL Thread failed ({})", e); + } + + if let Some(chan) = self.webvr_chan.as_ref() { debug!("Exiting WebVR thread."); if let Err(e) = chan.send(WebVRMsg::Exit) { warn!("Exit WebVR thread failed ({})", e); @@ -2135,19 +2142,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - fn handle_create_webgl_paint_thread_msg( - &mut self, - size: &Size2D<i32>, - attributes: GLContextAttributes, - response_sender: IpcSender<Result<(IpcSender<CanvasMsg>, GLLimits), String>>) { - let webrender_api = self.webrender_api_sender.clone(); - let response = WebGLPaintThread::start(*size, attributes, webrender_api); - - if let Err(e) = response_sender.send(response) { - warn!("Create WebGL paint thread response failed ({})", e); - } - } - fn handle_webdriver_msg(&mut self, msg: WebDriverCommandMsg) { // Find the script channel for the given parent pipeline, // and pass the event to that script thread. diff --git a/components/constellation/lib.rs b/components/constellation/lib.rs index d2ac0f00dea..1c444ff6603 100644 --- a/components/constellation/lib.rs +++ b/components/constellation/lib.rs @@ -30,7 +30,6 @@ extern crate metrics; extern crate msg; extern crate net; extern crate net_traits; -extern crate offscreen_gl_context; extern crate profile_traits; extern crate script_traits; #[macro_use] extern crate serde; diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 92a5fb041ef..74ce33ff564 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use bluetooth_traits::BluetoothRequest; +use canvas_traits::webgl::WebGLPipeline; use compositing::CompositionPipeline; use compositing::CompositorProxy; use compositing::compositor_thread::Msg as CompositorMsg; @@ -171,8 +172,12 @@ pub struct InitialPipelineState { /// Whether this pipeline is considered private. pub is_private: bool, + + /// A channel to the webgl thread. + pub webgl_chan: WebGLPipeline, + /// A channel to the webvr thread. - pub webvr_thread: Option<IpcSender<WebVRMsg>>, + pub webvr_chan: Option<IpcSender<WebVRMsg>>, } impl Pipeline { @@ -270,7 +275,8 @@ impl Pipeline { script_content_process_shutdown_port: script_content_process_shutdown_port, webrender_api_sender: state.webrender_api_sender, webrender_document: state.webrender_document, - webvr_thread: state.webvr_thread, + webgl_chan: state.webgl_chan, + webvr_chan: state.webvr_chan, }; // Spawn the child process. @@ -470,7 +476,8 @@ pub struct UnprivilegedPipelineContent { script_content_process_shutdown_port: IpcReceiver<()>, webrender_api_sender: webrender_api::RenderApiSender, webrender_document: webrender_api::DocumentId, - webvr_thread: Option<IpcSender<WebVRMsg>>, + webgl_chan: WebGLPipeline, + webvr_chan: Option<IpcSender<WebVRMsg>>, } impl UnprivilegedPipelineContent { @@ -499,7 +506,8 @@ impl UnprivilegedPipelineContent { window_size: self.window_size, pipeline_namespace_id: self.pipeline_namespace_id, content_process_shutdown_chan: self.script_content_process_shutdown_chan, - webvr_thread: self.webvr_thread, + webgl_chan: self.webgl_chan, + webvr_chan: self.webvr_chan, }, self.load_data.clone()); LTF::create(self.id, diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 8fa0c33df49..c83ae8fe864 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -34,7 +34,7 @@ use style_traits::cursor::Cursor; use text::TextRun; use text::glyph::ByteIndex; use webrender_api::{self, ClipAndScrollInfo, ClipId, ColorF, GradientStop, LocalClip}; -use webrender_api::{MixBlendMode, ScrollPolicy, ScrollSensitivity, TransformStyle, WebGLContextId}; +use webrender_api::{MixBlendMode, ScrollPolicy, ScrollSensitivity, TransformStyle}; pub use style::dom::OpaqueNode; @@ -599,7 +599,6 @@ pub enum DisplayItem { SolidColor(Box<SolidColorDisplayItem>), Text(Box<TextDisplayItem>), Image(Box<ImageDisplayItem>), - WebGL(Box<WebGLDisplayItem>), Border(Box<BorderDisplayItem>), Gradient(Box<GradientDisplayItem>), RadialGradient(Box<RadialGradientDisplayItem>), @@ -929,14 +928,6 @@ pub struct ImageDisplayItem { /// 5.3. pub image_rendering: image_rendering::T, } - -#[derive(Clone, HeapSizeOf, Deserialize, Serialize)] -pub struct WebGLDisplayItem { - pub base: BaseDisplayItem, - pub context_id: WebGLContextId, -} - - /// Paints an iframe. #[derive(Clone, HeapSizeOf, Deserialize, Serialize)] pub struct IframeDisplayItem { @@ -1250,7 +1241,6 @@ impl DisplayItem { DisplayItem::SolidColor(ref solid_color) => &solid_color.base, DisplayItem::Text(ref text) => &text.base, DisplayItem::Image(ref image_item) => &image_item.base, - DisplayItem::WebGL(ref webgl_item) => &webgl_item.base, DisplayItem::Border(ref border) => &border.base, DisplayItem::Gradient(ref gradient) => &gradient.base, DisplayItem::RadialGradient(ref gradient) => &gradient.base, @@ -1376,7 +1366,6 @@ impl fmt::Debug for DisplayItem { text.range.begin().0 as usize..(text.range.begin().0 + text.range.length().0) as usize]) } DisplayItem::Image(_) => "Image".to_owned(), - DisplayItem::WebGL(_) => "WebGL".to_owned(), DisplayItem::Border(_) => "Border".to_owned(), DisplayItem::Gradient(_) => "Gradient".to_owned(), DisplayItem::RadialGradient(_) => "RadialGradient".to_owned(), diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 3fc63df7c49..75e288e4826 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -12,13 +12,13 @@ use app_units::{AU_PER_PX, Au}; use block::{BlockFlow, BlockStackingContextType}; -use canvas_traits::{CanvasData, CanvasMsg, FromLayoutMsg}; +use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg}; use context::LayoutContext; use euclid::{Transform3D, Point2D, Vector2D, Rect, SideOffsets2D, Size2D, TypedSize2D}; use flex::FlexFlow; use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED}; use flow_ref::FlowRef; -use fragment::{CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmentInfo}; +use fragment::{CanvasFragmentSource, CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmentInfo}; use fragment::{SpecificFragmentInfo, TruncatedFragmentInfo}; use gfx::display_list; use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails, BorderDisplayItem}; @@ -28,7 +28,7 @@ use gfx::display_list::{GradientDisplayItem, IframeDisplayItem, ImageBorder, Ima use gfx::display_list::{LineDisplayItem, NormalBorder, OpaqueNode, PushTextShadowDisplayItem}; use gfx::display_list::{PopTextShadowDisplayItem, RadialGradientDisplayItem, ScrollRoot}; use gfx::display_list::{ScrollRootType, SolidColorDisplayItem, StackingContext, StackingContextType}; -use gfx::display_list::{TextDisplayItem, TextOrientation, WebGLDisplayItem, WebRenderImageInfo}; +use gfx::display_list::{TextDisplayItem, TextOrientation, WebRenderImageInfo}; use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId}; use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc; @@ -1978,15 +1978,22 @@ impl FragmentDisplayListBuilding for Fragment { let computed_width = canvas_fragment_info.dom_width.to_px(); let computed_height = canvas_fragment_info.dom_height.to_px(); - let canvas_data = match canvas_fragment_info.ipc_renderer { - Some(ref ipc_renderer) => { - let ipc_renderer = ipc_renderer.lock().unwrap(); - let (sender, receiver) = ipc::channel().unwrap(); - ipc_renderer.send(CanvasMsg::FromLayout( - FromLayoutMsg::SendData(sender))).unwrap(); - receiver.recv().unwrap() + let (image_key, format) = match canvas_fragment_info.source { + CanvasFragmentSource::WebGL(image_key) => { + (image_key, PixelFormat::BGRA8) }, - None => return, + CanvasFragmentSource::Image(ref ipc_renderer) => { + match *ipc_renderer { + Some(ref ipc_renderer) => { + let ipc_renderer = ipc_renderer.lock().unwrap(); + let (sender, receiver) = ipc::channel().unwrap(); + ipc_renderer.send(CanvasMsg::FromLayout( + FromLayoutMsg::SendData(sender))).unwrap(); + (receiver.recv().unwrap().image_key, PixelFormat::BGRA8) + }, + None => return, + } + } }; let base = state.create_base_display_item( @@ -1995,29 +2002,19 @@ impl FragmentDisplayListBuilding for Fragment { self.node, self.style.get_cursor(Cursor::Default), DisplayListSection::Content); - let display_item = match canvas_data { - CanvasData::Image(canvas_data) => { - DisplayItem::Image(box ImageDisplayItem { - base: base, - webrender_image: WebRenderImageInfo { - width: computed_width as u32, - height: computed_height as u32, - format: PixelFormat::BGRA8, - key: Some(canvas_data.image_key), - }, - image_data: None, - stretch_size: stacking_relative_content_box.size, - tile_spacing: Size2D::zero(), - image_rendering: image_rendering::T::auto, - }) - } - CanvasData::WebGL(context_id) => { - DisplayItem::WebGL(box WebGLDisplayItem { - base: base, - context_id: context_id, - }) - } - }; + let display_item = DisplayItem::Image(box ImageDisplayItem { + base: base, + webrender_image: WebRenderImageInfo { + width: computed_width as u32, + height: computed_height as u32, + format: format, + key: Some(image_key), + }, + image_data: None, + stretch_size: stacking_relative_content_box.size, + tile_spacing: Size2D::zero(), + image_rendering: image_rendering::T::auto, + }); state.add_display_item(display_item); } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 2510b185d1c..f4928262e99 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -8,7 +8,7 @@ use ServoArc; use app_units::Au; -use canvas_traits::CanvasMsg; +use canvas_traits::canvas::CanvasMsg; use context::{LayoutContext, with_thread_local_font_context}; use euclid::{Transform3D, Point2D, Vector2D, Radians, Rect, Size2D}; use floats::ClearType; @@ -30,7 +30,7 @@ use msg::constellation_msg::{BrowsingContextId, PipelineId}; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder}; use range::*; -use script_layout_interface::HTMLCanvasData; +use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource}; use script_layout_interface::SVGSVGData; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use serde::ser::{Serialize, SerializeStruct, Serializer}; @@ -53,6 +53,7 @@ use style::values::{self, Either, Auto}; use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto}; use text; use text::TextRunScanner; +use webrender_api; use wrapper::ThreadSafeLayoutNodeHelpers; // From gfxFontConstants.h in Firefox. @@ -322,17 +323,31 @@ impl InlineAbsoluteFragmentInfo { } #[derive(Clone)] +pub enum CanvasFragmentSource { + WebGL(webrender_api::ImageKey), + Image(Option<Arc<Mutex<IpcSender<CanvasMsg>>>>) +} + +#[derive(Clone)] pub struct CanvasFragmentInfo { - pub ipc_renderer: Option<Arc<Mutex<IpcSender<CanvasMsg>>>>, + pub source: CanvasFragmentSource, pub dom_width: Au, pub dom_height: Au, } impl CanvasFragmentInfo { pub fn new(data: HTMLCanvasData) -> CanvasFragmentInfo { + let source = match data.source { + HTMLCanvasDataSource::WebGL(texture_id) => { + CanvasFragmentSource::WebGL(texture_id) + }, + HTMLCanvasDataSource::Image(ipc_sender) => { + CanvasFragmentSource::Image(ipc_sender.map(|renderer| Arc::new(Mutex::new(renderer)))) + } + }; + CanvasFragmentInfo { - ipc_renderer: data.ipc_renderer - .map(|renderer| Arc::new(Mutex::new(renderer))), + source: source, dom_width: Au::from_px(data.width as i32), dom_height: Au::from_px(data.height as i32), } diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs index 6b8b334d52d..6e5a774e283 100644 --- a/components/layout/webrender_helpers.rs +++ b/components/layout/webrender_helpers.rs @@ -305,11 +305,6 @@ impl WebRenderDisplayItemConverter for DisplayItem { } } } - DisplayItem::WebGL(ref item) => { - builder.push_webgl_canvas(item.base.bounds.to_rectf(), - Some(item.base.local_clip), - item.context_id); - } DisplayItem::Border(ref item) => { let rect = item.base.bounds.to_rectf(); let widths = item.border_widths.to_border_widths(); diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 81017cd344e..4168fb4effa 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -30,8 +30,11 @@ //! `JSTraceable` to a datatype. use app_units::Au; -use canvas_traits::{CanvasGradientStop, LinearGradientStyle, RadialGradientStyle}; -use canvas_traits::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; +use canvas_traits::canvas::{CanvasGradientStop, LinearGradientStyle, RadialGradientStyle}; +use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle}; +use canvas_traits::webgl::{WebGLBufferId, WebGLFramebufferId, WebGLProgramId, WebGLRenderbufferId}; +use canvas_traits::webgl::{WebGLChan, WebGLContextShareMode, WebGLError, WebGLPipeline, WebGLMsgSender}; +use canvas_traits::webgl::{WebGLReceiver, WebGLSender, WebGLShaderId, WebGLTextureId, WebGLVertexArrayId}; use cssparser::RGBA; use devtools_traits::{CSSError, TimelineMarkerType, WorkerId}; use dom::abstractworker::SharedRt; @@ -105,8 +108,7 @@ use style::stylesheets::keyframes_rule::Keyframe; use style::values::specified::Length; use time::Duration; use uuid::Uuid; -use webrender_api::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId}; -use webrender_api::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId, WebGLVertexArrayId}; +use webrender_api::ImageKey; use webvr_traits::WebVRGamepadHand; /// A trait to allow tracing (only) DOM objects. @@ -391,8 +393,13 @@ unsafe_no_jsmanaged_fields!(OpaqueStyleAndLayoutData); unsafe_no_jsmanaged_fields!(PathBuf); unsafe_no_jsmanaged_fields!(CSSErrorReporter); unsafe_no_jsmanaged_fields!(DrawAPaintImageResult); +unsafe_no_jsmanaged_fields!(ImageKey); unsafe_no_jsmanaged_fields!(WebGLBufferId); +unsafe_no_jsmanaged_fields!(WebGLChan); +unsafe_no_jsmanaged_fields!(WebGLContextShareMode); unsafe_no_jsmanaged_fields!(WebGLFramebufferId); +unsafe_no_jsmanaged_fields!(WebGLMsgSender); +unsafe_no_jsmanaged_fields!(WebGLPipeline); unsafe_no_jsmanaged_fields!(WebGLProgramId); unsafe_no_jsmanaged_fields!(WebGLRenderbufferId); unsafe_no_jsmanaged_fields!(WebGLShaderId); @@ -466,6 +473,20 @@ unsafe impl<T: Send> JSTraceable for Sender<T> { } } +unsafe impl<T: Send> JSTraceable for WebGLReceiver<T> where T: for<'de> Deserialize<'de> + Serialize { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + +unsafe impl<T: Send> JSTraceable for WebGLSender<T> where T: for<'de> Deserialize<'de> + Serialize { + #[inline] + unsafe fn trace(&self, _: *mut JSTracer) { + // Do nothing + } +} + unsafe impl JSTraceable for Transform2D<f32> { #[inline] unsafe fn trace(&self, _trc: *mut JSTracer) { diff --git a/components/script/dom/canvasgradient.rs b/components/script/dom/canvasgradient.rs index 64df591f760..3a0707ab5eb 100644 --- a/components/script/dom/canvasgradient.rs +++ b/components/script/dom/canvasgradient.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::{CanvasGradientStop, FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle}; +use canvas_traits::canvas::{CanvasGradientStop, FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle}; use cssparser::{Parser, ParserInput, RGBA}; use cssparser::Color as CSSColor; use dom::bindings::cell::DOMRefCell; diff --git a/components/script/dom/canvaspattern.rs b/components/script/dom/canvaspattern.rs index 5d9dd5cb767..46bcbedcef0 100644 --- a/components/script/dom/canvaspattern.rs +++ b/components/script/dom/canvaspattern.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::{FillOrStrokeStyle, RepetitionStyle, SurfaceStyle}; +use canvas_traits::canvas::{FillOrStrokeStyle, RepetitionStyle, SurfaceStyle}; use dom::bindings::codegen::Bindings::CanvasPatternBinding; use dom::bindings::js::Root; use dom::bindings::reflector::{Reflector, reflect_dom_object}; diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 55d2ef3ceb4..d4fcfae4ab8 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -2,10 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::{Canvas2dMsg, CanvasCommonMsg, CanvasMsg}; -use canvas_traits::{CompositionOrBlending, FillOrStrokeStyle, FillRule}; -use canvas_traits::{LineCapStyle, LineJoinStyle, LinearGradientStyle}; -use canvas_traits::{RadialGradientStyle, RepetitionStyle, byte_swap_and_premultiply}; +use canvas_traits::canvas::{Canvas2dMsg, CanvasMsg}; +use canvas_traits::canvas::{CompositionOrBlending, FillOrStrokeStyle, FillRule}; +use canvas_traits::canvas::{LineCapStyle, LineJoinStyle, LinearGradientStyle}; +use canvas_traits::canvas::{RadialGradientStyle, RepetitionStyle, byte_swap_and_premultiply}; use cssparser::{Parser, ParserInput, RGBA}; use cssparser::Color as CSSColor; use dom::bindings::cell::DOMRefCell; @@ -163,7 +163,7 @@ impl CanvasRenderingContext2D { pub fn set_bitmap_dimensions(&self, size: Size2D<i32>) { self.reset_to_initial_state(); self.ipc_renderer - .send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))) + .send(CanvasMsg::Recreate(size)) .unwrap(); } @@ -173,10 +173,6 @@ impl CanvasRenderingContext2D { *self.state.borrow_mut() = CanvasContextState::new(); } - pub fn ipc_renderer(&self) -> IpcSender<CanvasMsg> { - self.ipc_renderer.clone() - } - fn mark_as_dirty(&self) { if let Some(ref canvas) = self.canvas { canvas.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); @@ -1392,7 +1388,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { impl Drop for CanvasRenderingContext2D { fn drop(&mut self) { - if let Err(err) = self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Close)) { + if let Err(err) = self.ipc_renderer.send(CanvasMsg::Close) { warn!("Could not close canvas: {}", err) } } diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index a95ff766171..3d89c08b230 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use base64; -use canvas_traits::{CanvasMsg, FromScriptMsg}; +use canvas_traits::canvas::{CanvasMsg, FromScriptMsg}; use dom::attr::Attr; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods; @@ -30,11 +30,11 @@ use euclid::Size2D; use html5ever::{LocalName, Prefix}; use image::ColorType; use image::png::PNGEncoder; -use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::ipc; use js::error::throw_type_error; use js::jsapi::{HandleValue, JSContext}; use offscreen_gl_context::GLContextAttributes; -use script_layout_interface::HTMLCanvasData; +use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource}; use std::iter::repeat; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; @@ -106,21 +106,22 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> { fn data(&self) -> HTMLCanvasData { unsafe { let canvas = &*self.unsafe_get(); - let ipc_renderer = canvas.context.borrow_for_layout().as_ref().map(|context| { - match *context { - CanvasContext::Context2d(ref context) => { - context.to_layout().get_ipc_renderer() - }, - CanvasContext::WebGL(ref context) => { - context.to_layout().get_ipc_renderer() - }, + let source = match canvas.context.borrow_for_layout().as_ref() { + Some(&CanvasContext::Context2d(ref context)) => { + HTMLCanvasDataSource::Image(Some(context.to_layout().get_ipc_renderer())) + }, + Some(&CanvasContext::WebGL(ref context)) => { + context.to_layout().canvas_data_source() + }, + None => { + HTMLCanvasDataSource::Image(None) } - }); + }; let width_attr = canvas.upcast::<Element>().get_attr_for_layout(&ns!(), &local_name!("width")); let height_attr = canvas.upcast::<Element>().get_attr_for_layout(&ns!(), &local_name!("height")); HTMLCanvasData { - ipc_renderer: ipc_renderer, + source: source, width: width_attr.map_or(DEFAULT_WIDTH, |val| val.as_uint()), height: height_attr.map_or(DEFAULT_HEIGHT, |val| val.as_uint()), } @@ -150,15 +151,6 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> { impl HTMLCanvasElement { - pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> { - self.context.borrow().as_ref().map(|context| { - match *context { - CanvasContext::Context2d(ref context) => context.ipc_renderer(), - CanvasContext::WebGL(ref context) => context.ipc_renderer(), - } - }) - } - pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> { if self.context.borrow().is_none() { let window = window_from_node(self); @@ -221,22 +213,26 @@ impl HTMLCanvasElement { return None } - let data = if let Some(renderer) = self.ipc_renderer() { - let (sender, receiver) = ipc::channel().unwrap(); - let msg = CanvasMsg::FromScript(FromScriptMsg::SendPixels(sender)); - renderer.send(msg).unwrap(); + let data = match self.context.borrow().as_ref() { + Some(&CanvasContext::Context2d(ref context)) => { + let (sender, receiver) = ipc::channel().unwrap(); + let msg = CanvasMsg::FromScript(FromScriptMsg::SendPixels(sender)); + context.get_ipc_renderer().send(msg).unwrap(); - match receiver.recv().unwrap() { - Some(pixels) => pixels, - None => { - // TODO(emilio, #14109): Not sure if WebGL canvas is - // required for 2d spec, but I think it's not, if so, make - // this return a readback from the GL context. - return None; + match receiver.recv().unwrap() { + Some(pixels) => pixels, + None => { + return None; + } } + }, + Some(&CanvasContext::WebGL(_)) => { + // TODO: add a method in WebGLRenderingContext to get the pixels. + return None; + }, + None => { + repeat(0xffu8).take((size.height as usize) * (size.width as usize) * 4).collect() } - } else { - repeat(0xffu8).take((size.height as usize) * (size.width as usize) * 4).collect() }; Some((data, size)) diff --git a/components/script/dom/paintrenderingcontext2d.rs b/components/script/dom/paintrenderingcontext2d.rs index c3aa9e4c98b..c6b62b50e15 100644 --- a/components/script/dom/paintrenderingcontext2d.rs +++ b/components/script/dom/paintrenderingcontext2d.rs @@ -2,9 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::CanvasData; -use canvas_traits::CanvasMsg; -use canvas_traits::FromLayoutMsg; +use canvas_traits::canvas::CanvasImageData; +use canvas_traits::canvas::CanvasMsg; +use canvas_traits::canvas::FromLayoutMsg; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasFillRule; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineCap; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineJoin; @@ -58,9 +58,9 @@ impl PaintRenderingContext2D { PaintRenderingContext2DBinding::Wrap) } - pub fn send_data(&self, sender: IpcSender<CanvasData>) { + pub fn send_data(&self, sender: IpcSender<CanvasImageData>) { let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendData(sender)); - let _ = self.context.ipc_renderer().send(msg); + let _ = self.context.get_ipc_renderer().send(msg); } pub fn take_missing_image_urls(&self) -> Vec<ServoUrl> { diff --git a/components/script/dom/paintworkletglobalscope.rs b/components/script/dom/paintworkletglobalscope.rs index b0a43cbf25d..607c432c78a 100644 --- a/components/script/dom/paintworkletglobalscope.rs +++ b/components/script/dom/paintworkletglobalscope.rs @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::CanvasData; use dom::bindings::callback::CallbackContainer; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::PaintWorkletGlobalScopeBinding; @@ -298,7 +297,7 @@ impl PaintWorkletGlobalScope { let (sender, receiver) = ipc::channel().expect("IPC channel creation."); rendering_context.send_data(sender); let image_key = match receiver.recv() { - Ok(CanvasData::Image(data)) => Some(data.image_key), + Ok(data) => Some(data.image_key), _ => None, }; diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index 54f06fb928f..a36bd27ad29 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::CanvasMsg; +use canvas_traits::webgl::{webgl_channel, WebGLReceiver, WebVRCommand}; use core::ops::Deref; use dom::bindings::callback::ExceptionHandling; use dom::bindings::cell::DOMRefCell; @@ -32,8 +32,7 @@ use dom::vrpose::VRPose; use dom::vrstageparameters::VRStageParameters; use dom::webglrenderingcontext::WebGLRenderingContext; use dom_struct::dom_struct; -use ipc_channel::ipc; -use ipc_channel::ipc::{IpcSender, IpcReceiver}; +use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::JSContext; use script_runtime::CommonScriptMsg; use script_runtime::ScriptThreadEventCategory::WebVREvent; @@ -43,7 +42,6 @@ use std::mem; use std::rc::Rc; use std::sync::mpsc; use std::thread; -use webrender_api::VRCompositorCommand; use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRLayer, WebVRMsg}; #[dom_struct] @@ -71,7 +69,7 @@ pub struct VRDisplay { // Compositor VRFrameData synchonization frame_data_status: Cell<VRFrameDataStatus>, #[ignore_heap_size_of = "channels are hard"] - frame_data_receiver: DOMRefCell<Option<IpcReceiver<Result<Vec<u8>, ()>>>>, + frame_data_receiver: DOMRefCell<Option<WebGLReceiver<Result<Vec<u8>, ()>>>>, running_display_raf: Cell<bool>, paused: Cell<bool>, stopped_on_pause: Cell<bool>, @@ -386,11 +384,10 @@ impl VRDisplayMethods for VRDisplay { return; } - let api_sender = self.layer_ctx.get().unwrap().ipc_renderer(); - let display_id = self.display.borrow().display_id as u64; + let display_id = self.display.borrow().display_id; let layer = self.layer.borrow(); - let msg = VRCompositorCommand::SubmitFrame(display_id, layer.left_bounds, layer.right_bounds); - api_sender.send(CanvasMsg::WebVR(msg)).unwrap(); + let msg = WebVRCommand::SubmitFrame(display_id, layer.left_bounds, layer.right_bounds); + self.layer_ctx.get().unwrap().send_vr_command(msg); } // https://w3c.github.io/webvr/spec/1.1/#dom-vrdisplay-getlayers @@ -489,11 +486,11 @@ impl VRDisplay { fn init_present(&self) { self.presenting.set(true); - let (sync_sender, sync_receiver) = ipc::channel().unwrap(); + let (sync_sender, sync_receiver) = webgl_channel().unwrap(); *self.frame_data_receiver.borrow_mut() = Some(sync_receiver); - let display_id = self.display.borrow().display_id as u64; - let api_sender = self.layer_ctx.get().unwrap().ipc_renderer(); + let display_id = self.display.borrow().display_id; + let api_sender = self.layer_ctx.get().unwrap().webgl_sender(); let js_sender = self.global().script_chan(); let address = Trusted::new(&*self); let near_init = self.depth_near.get(); @@ -511,7 +508,7 @@ impl VRDisplay { let mut far = far_init; // Initialize compositor - api_sender.send(CanvasMsg::WebVR(VRCompositorCommand::Create(display_id))).unwrap(); + api_sender.send_vr(WebVRCommand::Create(display_id)).unwrap(); loop { // Run RAF callbacks on JavaScript thread let msg = box NotifyDisplayRAF { @@ -521,8 +518,8 @@ impl VRDisplay { js_sender.send(CommonScriptMsg::RunnableMsg(WebVREvent, msg)).unwrap(); // Run Sync Poses in parallell on Render thread - let msg = VRCompositorCommand::SyncPoses(display_id, near, far, sync_sender.clone()); - api_sender.send(CanvasMsg::WebVR(msg)).unwrap(); + let msg = WebVRCommand::SyncPoses(display_id, near, far, sync_sender.clone()); + api_sender.send_vr(msg).unwrap(); // Wait until both SyncPoses & RAF ends if let Ok(depth) = raf_receiver.recv().unwrap() { @@ -541,10 +538,9 @@ impl VRDisplay { self.presenting.set(false); *self.frame_data_receiver.borrow_mut() = None; - let api_sender = self.layer_ctx.get().unwrap().ipc_renderer(); - let display_id = self.display.borrow().display_id as u64; - let msg = VRCompositorCommand::Release(display_id); - api_sender.send(CanvasMsg::WebVR(msg)).unwrap(); + let api_sender = self.layer_ctx.get().unwrap().webgl_sender(); + let display_id = self.display.borrow().display_id; + api_sender.send_vr(WebVRCommand::Release(display_id)).unwrap(); } // Only called when the JSContext is destroyed while presenting. @@ -627,7 +623,7 @@ impl Runnable for NotifyDisplayRAF { } -// WebVR Spect: If the number of values in the leftBounds/rightBounds arrays +// WebVR Spec: If the number of values in the leftBounds/rightBounds arrays // is not 0 or 4 for any of the passed layers the promise is rejected fn parse_bounds(src: &Option<Vec<Finite<f32>>>, dst: &mut [f32; 4]) -> Result<(), &'static str> { match *src { diff --git a/components/script/dom/webgl_extensions/ext/oesvertexarrayobject.rs b/components/script/dom/webgl_extensions/ext/oesvertexarrayobject.rs index 097742f5441..48385a3d50f 100644 --- a/components/script/dom/webgl_extensions/ext/oesvertexarrayobject.rs +++ b/components/script/dom/webgl_extensions/ext/oesvertexarrayobject.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::CanvasMsg; +use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLError}; use dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::{self, OESVertexArrayObjectMethods}; use dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants; use dom::bindings::js::{JS, MutNullableJS, Root}; @@ -15,7 +15,6 @@ use js::jsapi::JSContext; use js::jsval::{JSVal, NullValue}; use std::iter; use super::{WebGLExtension, WebGLExtensions}; -use webrender_api::{self, WebGLCommand, WebGLError}; #[dom_struct] pub struct OESVertexArrayObject { @@ -48,8 +47,8 @@ impl OESVertexArrayObject { impl OESVertexArrayObjectMethods for OESVertexArrayObject { // https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ fn CreateVertexArrayOES(&self) -> Option<Root<WebGLVertexArrayObjectOES>> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::CreateVertexArray(sender))); + let (sender, receiver) = webgl_channel().unwrap(); + self.ctx.send_command(WebGLCommand::CreateVertexArray(sender)); let result = receiver.recv().unwrap(); result.map(|vao_id| WebGLVertexArrayObjectOES::new(&self.global(), vao_id)) @@ -66,7 +65,7 @@ impl OESVertexArrayObjectMethods for OESVertexArrayObject { if let Some(bound_vao) = self.bound_vao.get() { if bound_vao.id() == vao.id() { self.bound_vao.set(None); - self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::BindVertexArray(None))); + self.ctx.send_command(WebGLCommand::BindVertexArray(None)); } } @@ -80,7 +79,7 @@ impl OESVertexArrayObjectMethods for OESVertexArrayObject { } // Delete the vao - self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::DeleteVertexArray(vao.id()))); + self.ctx.send_command(WebGLCommand::DeleteVertexArray(vao.id())); vao.set_deleted(); } } @@ -114,7 +113,7 @@ impl OESVertexArrayObjectMethods for OESVertexArrayObject { return; } - self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::BindVertexArray(Some(vao.id())))); + self.ctx.send_command(WebGLCommand::BindVertexArray(Some(vao.id()))); vao.set_ever_bound(); self.bound_vao.set(Some(&vao)); @@ -124,7 +123,7 @@ impl OESVertexArrayObjectMethods for OESVertexArrayObject { let element_array = vao.bound_buffer_element_array(); self.ctx.set_bound_buffer_element_array(element_array.as_ref().map(|buffer| &**buffer)); } else { - self.ctx.send_renderer_message(CanvasMsg::WebGL(WebGLCommand::BindVertexArray(None))); + self.ctx.send_command(WebGLCommand::BindVertexArray(None)); self.bound_vao.set(None); self.ctx.set_bound_attrib_buffers(iter::empty()); } diff --git a/components/script/dom/webgl_extensions/ext/webglvertexarrayobjectoes.rs b/components/script/dom/webgl_extensions/ext/webglvertexarrayobjectoes.rs index e44b7c9bc42..2fe109cafa6 100644 --- a/components/script/dom/webgl_extensions/ext/webglvertexarrayobjectoes.rs +++ b/components/script/dom/webgl_extensions/ext/webglvertexarrayobjectoes.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use canvas_traits::webgl::WebGLVertexArrayId; use core::cell::Ref; use core::iter::FromIterator; use dom::bindings::cell::DOMRefCell; @@ -15,7 +16,6 @@ use dom::webglobject::WebGLObject; use dom_struct::dom_struct; use std::cell::Cell; use std::collections::HashMap; -use webrender_api::WebGLVertexArrayId; #[dom_struct] pub struct WebGLVertexArrayObjectOES { diff --git a/components/script/dom/webgl_extensions/extensions.rs b/components/script/dom/webgl_extensions/extensions.rs index 28c32dede64..2a780b129ff 100644 --- a/components/script/dom/webgl_extensions/extensions.rs +++ b/components/script/dom/webgl_extensions/extensions.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use canvas_traits::webgl::WebGLError; use core::iter::FromIterator; use core::nonzero::NonZero; use dom::bindings::cell::DOMRefCell; @@ -19,7 +20,6 @@ use std::cell::Ref; use std::collections::{HashMap, HashSet}; use super::{ext, WebGLExtension}; use super::wrapper::{WebGLExtensionWrapper, TypedWebGLExtensionWrapper}; -use webrender_api::WebGLError; // Data types that are implemented for texImage2D and texSubImage2D in WebGLRenderingContext // but must trigger a InvalidValue error until the related WebGL Extensions are enabled. diff --git a/components/script/dom/webgl_validations/tex_image_2d.rs b/components/script/dom/webgl_validations/tex_image_2d.rs index 41b2795bc14..cd5320453c7 100644 --- a/components/script/dom/webgl_validations/tex_image_2d.rs +++ b/components/script/dom/webgl_validations/tex_image_2d.rs @@ -2,13 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use canvas_traits::webgl::WebGLError::*; use dom::bindings::js::Root; use dom::webglrenderingcontext::WebGLRenderingContext; use dom::webgltexture::WebGLTexture; use std::{self, fmt}; use super::WebGLValidator; use super::types::{TexImageTarget, TexDataType, TexFormat}; -use webrender_api::WebGLError::*; /// The errors that the texImage* family of functions can generate. #[derive(Debug)] diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs index 448956a9b90..96db4466d56 100644 --- a/components/script/dom/webglbuffer.rs +++ b/components/script/dom/webglbuffer.rs @@ -3,7 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl -use canvas_traits::CanvasMsg; +use canvas_traits::webgl::{WebGLBufferId, WebGLCommand, WebGLError, WebGLMsgSender, WebGLResult, WebGLVertexArrayId}; +use canvas_traits::webgl::webgl_channel; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::WebGLBufferBinding; use dom::bindings::js::Root; @@ -11,11 +12,9 @@ use dom::bindings::reflector::reflect_dom_object; use dom::webglobject::WebGLObject; use dom::window::Window; use dom_struct::dom_struct; -use ipc_channel::ipc::IpcSender; use std::cell::Cell; use std::collections::HashSet; -use webrender_api; -use webrender_api::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult, WebGLVertexArrayId}; + #[dom_struct] pub struct WebGLBuffer { @@ -29,11 +28,11 @@ pub struct WebGLBuffer { vao_references: DOMRefCell<Option<HashSet<WebGLVertexArrayId>>>, pending_delete: Cell<bool>, #[ignore_heap_size_of = "Defined in ipc-channel"] - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, } impl WebGLBuffer { - fn new_inherited(renderer: IpcSender<CanvasMsg>, + fn new_inherited(renderer: WebGLMsgSender, id: WebGLBufferId) -> WebGLBuffer { WebGLBuffer { @@ -48,17 +47,17 @@ impl WebGLBuffer { } } - pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>) + pub fn maybe_new(window: &Window, renderer: WebGLMsgSender) -> Option<Root<WebGLBuffer>> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateBuffer(sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + renderer.send(WebGLCommand::CreateBuffer(sender)).unwrap(); let result = receiver.recv().unwrap(); result.map(|buffer_id| WebGLBuffer::new(window, renderer, buffer_id)) } pub fn new(window: &Window, - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, id: WebGLBufferId) -> Root<WebGLBuffer> { reflect_dom_object(box WebGLBuffer::new_inherited(renderer, id), @@ -81,7 +80,7 @@ impl WebGLBuffer { } else { self.target.set(Some(target)); } - let msg = CanvasMsg::WebGL(WebGLCommand::BindBuffer(target, Some(self.id))); + let msg = WebGLCommand::BindBuffer(target, Some(self.id)); self.renderer.send(msg).unwrap(); Ok(()) @@ -94,9 +93,7 @@ impl WebGLBuffer { } } self.capacity.set(data.len()); - self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::BufferData(target, data.to_vec(), usage))) - .unwrap(); + self.renderer.send(WebGLCommand::BufferData(target, data.to_vec(), usage)).unwrap(); Ok(()) } @@ -108,7 +105,7 @@ impl WebGLBuffer { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteBuffer(self.id))); + let _ = self.renderer.send(WebGLCommand::DeleteBuffer(self.id)); } } @@ -144,7 +141,7 @@ impl WebGLBuffer { if let Some(ref mut vao_refs) = *self.vao_references.borrow_mut() { if vao_refs.take(&id).is_some() && self.pending_delete.get() { // WebGL spec: The deleted buffers should no longer be valid when the VAOs are deleted - let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteBuffer(self.id))); + let _ = self.renderer.send(WebGLCommand::DeleteBuffer(self.id)); self.is_deleted.set(true); } } diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index bb486c80c38..7a6b1090064 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -3,7 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl -use canvas_traits::CanvasMsg; +use canvas_traits::webgl::{WebGLCommand, WebGLFramebufferBindingRequest, WebGLFramebufferId}; +use canvas_traits::webgl::{WebGLMsgSender, WebGLResult, WebGLError}; +use canvas_traits::webgl::webgl_channel; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::WebGLFramebufferBinding; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; @@ -14,10 +16,7 @@ use dom::webglrenderbuffer::WebGLRenderbuffer; use dom::webgltexture::WebGLTexture; use dom::window::Window; use dom_struct::dom_struct; -use ipc_channel::ipc::IpcSender; use std::cell::Cell; -use webrender_api; -use webrender_api::{WebGLCommand, WebGLFramebufferBindingRequest, WebGLFramebufferId, WebGLResult, WebGLError}; #[must_root] #[derive(JSTraceable, Clone, HeapSizeOf)] @@ -36,7 +35,7 @@ pub struct WebGLFramebuffer { size: Cell<Option<(i32, i32)>>, status: Cell<u32>, #[ignore_heap_size_of = "Defined in ipc-channel"] - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, // The attachment points for textures and renderbuffers on this // FBO. @@ -47,7 +46,7 @@ pub struct WebGLFramebuffer { } impl WebGLFramebuffer { - fn new_inherited(renderer: IpcSender<CanvasMsg>, + fn new_inherited(renderer: WebGLMsgSender, id: WebGLFramebufferId) -> WebGLFramebuffer { WebGLFramebuffer { @@ -65,17 +64,17 @@ impl WebGLFramebuffer { } } - pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>) + pub fn maybe_new(window: &Window, renderer: WebGLMsgSender) -> Option<Root<WebGLFramebuffer>> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateFramebuffer(sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + renderer.send(WebGLCommand::CreateFramebuffer(sender)).unwrap(); let result = receiver.recv().unwrap(); result.map(|fb_id| WebGLFramebuffer::new(window, renderer, fb_id)) } pub fn new(window: &Window, - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, id: WebGLFramebufferId) -> Root<WebGLFramebuffer> { reflect_dom_object(box WebGLFramebuffer::new_inherited(renderer, id), @@ -98,13 +97,13 @@ impl WebGLFramebuffer { self.target.set(Some(target)); let cmd = WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Explicit(self.id)); - self.renderer.send(CanvasMsg::WebGL(cmd)).unwrap(); + self.renderer.send(cmd).unwrap(); } pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteFramebuffer(self.id))); + let _ = self.renderer.send(WebGLCommand::DeleteFramebuffer(self.id)); } } @@ -205,10 +204,10 @@ impl WebGLFramebuffer { } }; - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::FramebufferRenderbuffer(constants::FRAMEBUFFER, - attachment, - constants::RENDERBUFFER, - rb_id))).unwrap(); + self.renderer.send(WebGLCommand::FramebufferRenderbuffer(constants::FRAMEBUFFER, + attachment, + constants::RENDERBUFFER, + rb_id)).unwrap(); self.update_status(); Ok(()) @@ -281,11 +280,11 @@ impl WebGLFramebuffer { } }; - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::FramebufferTexture2D(constants::FRAMEBUFFER, - attachment, - textarget, - tex_id, - level))).unwrap(); + self.renderer.send(WebGLCommand::FramebufferTexture2D(constants::FRAMEBUFFER, + attachment, + textarget, + tex_id, + level)).unwrap(); self.update_status(); Ok(()) diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index c76a2f3da18..6c298bb83fb 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -3,7 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl -use canvas_traits::CanvasMsg; +use canvas_traits::webgl::{WebGLCommand, WebGLError, WebGLMsgSender, WebGLParameter, WebGLProgramId, WebGLResult}; +use canvas_traits::webgl::webgl_channel; use dom::bindings::codegen::Bindings::WebGLProgramBinding; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::js::{MutNullableJS, Root}; @@ -15,10 +16,7 @@ use dom::webglrenderingcontext::MAX_UNIFORM_AND_ATTRIBUTE_LEN; use dom::webglshader::WebGLShader; use dom::window::Window; use dom_struct::dom_struct; -use ipc_channel::ipc::IpcSender; use std::cell::Cell; -use webrender_api; -use webrender_api::{WebGLCommand, WebGLError, WebGLParameter, WebGLProgramId, WebGLResult}; #[dom_struct] pub struct WebGLProgram { @@ -30,11 +28,11 @@ pub struct WebGLProgram { fragment_shader: MutNullableJS<WebGLShader>, vertex_shader: MutNullableJS<WebGLShader>, #[ignore_heap_size_of = "Defined in ipc-channel"] - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, } impl WebGLProgram { - fn new_inherited(renderer: IpcSender<CanvasMsg>, + fn new_inherited(renderer: WebGLMsgSender, id: WebGLProgramId) -> WebGLProgram { WebGLProgram { @@ -49,17 +47,17 @@ impl WebGLProgram { } } - pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>) + pub fn maybe_new(window: &Window, renderer: WebGLMsgSender) -> Option<Root<WebGLProgram>> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateProgram(sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + renderer.send(WebGLCommand::CreateProgram(sender)).unwrap(); let result = receiver.recv().unwrap(); result.map(|program_id| WebGLProgram::new(window, renderer, program_id)) } pub fn new(window: &Window, - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, id: WebGLProgramId) -> Root<WebGLProgram> { reflect_dom_object(box WebGLProgram::new_inherited(renderer, id), @@ -78,7 +76,7 @@ impl WebGLProgram { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteProgram(self.id))); + let _ = self.renderer.send(WebGLCommand::DeleteProgram(self.id)); if let Some(shader) = self.fragment_shader.get() { shader.decrement_attached_counter(); @@ -117,7 +115,7 @@ impl WebGLProgram { } self.linked.set(true); - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::LinkProgram(self.id))).unwrap(); + self.renderer.send(WebGLCommand::LinkProgram(self.id)).unwrap(); Ok(()) } @@ -130,7 +128,7 @@ impl WebGLProgram { return Err(WebGLError::InvalidOperation); } - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::UseProgram(self.id))).unwrap(); + self.renderer.send(WebGLCommand::UseProgram(self.id)).unwrap(); Ok(()) } @@ -139,7 +137,7 @@ impl WebGLProgram { if self.is_deleted() { return Err(WebGLError::InvalidOperation); } - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::ValidateProgram(self.id))).unwrap(); + self.renderer.send(WebGLCommand::ValidateProgram(self.id)).unwrap(); Ok(()) } @@ -166,7 +164,7 @@ impl WebGLProgram { shader_slot.set(Some(shader)); shader.increment_attached_counter(); - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::AttachShader(self.id, shader.id()))).unwrap(); + self.renderer.send(WebGLCommand::AttachShader(self.id, shader.id())).unwrap(); Ok(()) } @@ -196,7 +194,7 @@ impl WebGLProgram { shader_slot.set(None); shader.decrement_attached_counter(); - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DetachShader(self.id, shader.id()))).unwrap(); + self.renderer.send(WebGLCommand::DetachShader(self.id, shader.id())).unwrap(); Ok(()) } @@ -216,7 +214,7 @@ impl WebGLProgram { } self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::BindAttribLocation(self.id, index, String::from(name)))) + .send(WebGLCommand::BindAttribLocation(self.id, index, String::from(name))) .unwrap(); Ok(()) } @@ -225,9 +223,9 @@ impl WebGLProgram { if self.is_deleted() { return Err(WebGLError::InvalidValue); } - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::GetActiveUniform(self.id, index, sender))) + .send(WebGLCommand::GetActiveUniform(self.id, index, sender)) .unwrap(); receiver.recv().unwrap().map(|(size, ty, name)| @@ -239,9 +237,9 @@ impl WebGLProgram { if self.is_deleted() { return Err(WebGLError::InvalidValue); } - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::GetActiveAttrib(self.id, index, sender))) + .send(WebGLCommand::GetActiveAttrib(self.id, index, sender)) .unwrap(); receiver.recv().unwrap().map(|(size, ty, name)| @@ -266,9 +264,9 @@ impl WebGLProgram { return Ok(None); } - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::GetAttribLocation(self.id, String::from(name), sender))) + .send(WebGLCommand::GetAttribLocation(self.id, String::from(name), sender)) .unwrap(); Ok(receiver.recv().unwrap()) } @@ -287,9 +285,9 @@ impl WebGLProgram { return Ok(None); } - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::GetUniformLocation(self.id, String::from(name), sender))) + .send(WebGLCommand::GetUniformLocation(self.id, String::from(name), sender)) .unwrap(); Ok(receiver.recv().unwrap()) } @@ -308,15 +306,15 @@ impl WebGLProgram { return Ok("One or more shaders failed to compile".to_string()); } } - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::GetProgramInfoLog(self.id, sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.renderer.send(WebGLCommand::GetProgramInfoLog(self.id, sender)).unwrap(); Ok(receiver.recv().unwrap()) } /// glGetProgramParameter pub fn parameter(&self, param_id: u32) -> WebGLResult<WebGLParameter> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::GetProgramParameter(self.id, param_id, sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.renderer.send(WebGLCommand::GetProgramParameter(self.id, param_id, sender)).unwrap(); receiver.recv().unwrap() } } diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs index 03589365c43..9a855651cc9 100644 --- a/components/script/dom/webglrenderbuffer.rs +++ b/components/script/dom/webglrenderbuffer.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl -use canvas_traits::CanvasMsg; +use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLError, WebGLMsgSender, WebGLRenderbufferId, WebGLResult}; use dom::bindings::codegen::Bindings::WebGLRenderbufferBinding; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::js::Root; @@ -11,10 +11,7 @@ use dom::bindings::reflector::reflect_dom_object; use dom::webglobject::WebGLObject; use dom::window::Window; use dom_struct::dom_struct; -use ipc_channel::ipc::IpcSender; use std::cell::Cell; -use webrender_api; -use webrender_api::{WebGLCommand, WebGLRenderbufferId, WebGLResult, WebGLError}; #[dom_struct] pub struct WebGLRenderbuffer { @@ -25,11 +22,11 @@ pub struct WebGLRenderbuffer { size: Cell<Option<(i32, i32)>>, internal_format: Cell<Option<u32>>, #[ignore_heap_size_of = "Defined in ipc-channel"] - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, } impl WebGLRenderbuffer { - fn new_inherited(renderer: IpcSender<CanvasMsg>, + fn new_inherited(renderer: WebGLMsgSender, id: WebGLRenderbufferId) -> WebGLRenderbuffer { WebGLRenderbuffer { @@ -43,17 +40,17 @@ impl WebGLRenderbuffer { } } - pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>) + pub fn maybe_new(window: &Window, renderer: WebGLMsgSender) -> Option<Root<WebGLRenderbuffer>> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateRenderbuffer(sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + renderer.send(WebGLCommand::CreateRenderbuffer(sender)).unwrap(); let result = receiver.recv().unwrap(); result.map(|renderbuffer_id| WebGLRenderbuffer::new(window, renderer, renderbuffer_id)) } pub fn new(window: &Window, - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, id: WebGLRenderbufferId) -> Root<WebGLRenderbuffer> { reflect_dom_object(box WebGLRenderbuffer::new_inherited(renderer, id), @@ -74,14 +71,14 @@ impl WebGLRenderbuffer { pub fn bind(&self, target: u32) { self.ever_bound.set(true); - let msg = CanvasMsg::WebGL(WebGLCommand::BindRenderbuffer(target, Some(self.id))); + let msg = WebGLCommand::BindRenderbuffer(target, Some(self.id)); self.renderer.send(msg).unwrap(); } pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteRenderbuffer(self.id))); + let _ = self.renderer.send(WebGLCommand::DeleteRenderbuffer(self.id)); } } @@ -110,8 +107,7 @@ impl WebGLRenderbuffer { // FIXME: Invalidate completeness after the call - let msg = CanvasMsg::WebGL(WebGLCommand::RenderbufferStorage(constants::RENDERBUFFER, - internal_format, width, height)); + let msg = WebGLCommand::RenderbufferStorage(constants::RENDERBUFFER, internal_format, width, height); self.renderer.send(msg).unwrap(); self.size.set(Some((width, height))); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 20fe133e02c..c45362b4fe2 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -3,7 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; -use canvas_traits::{CanvasCommonMsg, CanvasMsg, byte_swap, multiply_u8_pixel}; +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::WebGLError::*; +use canvas_traits::webgl::webgl_channel; use core::cell::Ref; use core::iter::FromIterator; use core::nonzero::NonZero; @@ -19,7 +23,6 @@ use dom::bindings::js::{JS, LayoutJS, MutNullableJS, Root}; use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; use dom::bindings::str::DOMString; use dom::event::{Event, EventBubbles, EventCancelable}; -use dom::globalscope::GlobalScope; use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmlcanvaselement::utils as canvas_utils; use dom::node::{Node, NodeDamage, window_from_node}; @@ -42,7 +45,6 @@ use dom::window::Window; use dom_struct::dom_struct; use euclid::Size2D; use half::f16; -use ipc_channel::ipc::{self, IpcSender}; use js::conversions::ConversionBehavior; use js::jsapi::{JSContext, JSObject, Type, Rooted}; use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UndefinedValue}; @@ -50,13 +52,11 @@ use js::typedarray::{TypedArray, TypedArrayElement, Float32, Int32}; use net_traits::image::base::PixelFormat; use net_traits::image_cache::ImageResponse; use offscreen_gl_context::{GLContextAttributes, GLLimits}; -use script_traits::ScriptMsg; +use script_layout_interface::HTMLCanvasDataSource; use servo_config::prefs::PREFS; use std::cell::Cell; use std::collections::HashMap; use webrender_api; -use webrender_api::{WebGLCommand, WebGLError, WebGLFramebufferBindingRequest, WebGLParameter}; -use webrender_api::WebGLError::*; type ImagePixelResult = Result<(Vec<u8>, Size2D<i32>, bool), ()>; pub const MAX_UNIFORM_AND_ATTRIBUTE_LEN: usize = 256; @@ -92,9 +92,7 @@ macro_rules! handle_object_deletion { } if let Some(command) = $unbind_command { - $self_.ipc_renderer - .send(CanvasMsg::WebGL(command)) - .unwrap(); + $self_.send_command(command); } } }; @@ -135,12 +133,15 @@ bitflags! { #[dom_struct] pub struct WebGLRenderingContext { reflector_: Reflector, - #[ignore_heap_size_of = "Defined in ipc-channel"] - ipc_renderer: IpcSender<CanvasMsg>, + #[ignore_heap_size_of = "Channels are hard"] + webgl_sender: WebGLMsgSender, + #[ignore_heap_size_of = "Defined in webrender"] + webrender_image: Cell<Option<webrender_api::ImageKey>>, + share_mode: WebGLContextShareMode, #[ignore_heap_size_of = "Defined in offscreen_gl_context"] limits: GLLimits, canvas: JS<HTMLCanvasElement>, - #[ignore_heap_size_of = "Defined in webrender_api"] + #[ignore_heap_size_of = "Defined in canvas_traits"] last_error: Cell<Option<WebGLError>>, texture_unpacking_settings: Cell<TextureUnpacking>, texture_unpacking_alignment: Cell<u32>, @@ -158,7 +159,7 @@ pub struct WebGLRenderingContext { current_scissor: Cell<(i32, i32, i32, i32)>, #[ignore_heap_size_of = "Because it's small"] current_clear_color: Cell<(f32, f32, f32, f32)>, - extension_manager: WebGLExtensions + extension_manager: WebGLExtensions, } impl WebGLRenderingContext { @@ -171,17 +172,19 @@ impl WebGLRenderingContext { return Err("WebGL context creation error forced by pref `webgl.testing.context_creation_error`".into()); } - let (sender, receiver) = ipc::channel().unwrap(); - let script_to_constellation_chan = window.upcast::<GlobalScope>().script_to_constellation_chan(); - script_to_constellation_chan.send(ScriptMsg::CreateWebGLPaintThread(size, attrs, sender)) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + let webgl_chan = window.webgl_chan(); + webgl_chan.send(WebGLMsg::CreateContext(size, attrs, sender)) + .unwrap(); let result = receiver.recv().unwrap(); - result.map(|(ipc_renderer, context_limits)| { + result.map(|ctx_data| { WebGLRenderingContext { reflector_: Reflector::new(), - ipc_renderer: ipc_renderer, - limits: context_limits, + webgl_sender: ctx_data.sender, + webrender_image: Cell::new(None), + share_mode: ctx_data.share_mode, + limits: ctx_data.limits, canvas: JS::from_ref(canvas), last_error: Cell::new(None), texture_unpacking_settings: Cell::new(CONVERT_COLORSPACE), @@ -253,31 +256,43 @@ impl WebGLRenderingContext { } pub fn recreate(&self, size: Size2D<i32>) { - self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.webgl_sender.send_resize(size, sender).unwrap(); + + if let Err(msg) = receiver.recv().unwrap() { + error!("Error resizing WebGLContext: {}", msg); + return; + }; + + // Reset webrender_image because resize creates a new image_key. + // The new image key is set in the next handle_layout() method. + self.webrender_image.set(None); // ClearColor needs to be restored because after a resize the GLContext is recreated // and the framebuffer is cleared using the default black transparent color. let color = self.current_clear_color.get(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::ClearColor(color.0, color.1, color.2, color.3))) - .unwrap(); + self.send_command(WebGLCommand::ClearColor(color.0, color.1, color.2, color.3)); // WebGL Spec: Scissor rect must not change if the canvas is resized. // See: webgl/conformance-1.0.3/conformance/rendering/gl-scissor-canvas-dimensions.html // NativeContext handling library changes the scissor after a resize, so we need to reset the // default scissor when the canvas was created or the last scissor that the user set. let rect = self.current_scissor.get(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Scissor(rect.0, rect.1, rect.2, rect.3))) - .unwrap() + self.send_command(WebGLCommand::Scissor(rect.0, rect.1, rect.2, rect.3)); + } + + pub fn webgl_sender(&self) -> WebGLMsgSender { + self.webgl_sender.clone() } - pub fn ipc_renderer(&self) -> IpcSender<CanvasMsg> { - self.ipc_renderer.clone() + #[inline] + pub fn send_command(&self, command: WebGLCommand) { + self.webgl_sender.send(command).unwrap(); } - pub fn send_renderer_message(&self, msg: CanvasMsg) { - self.ipc_renderer.send(msg).unwrap(); + #[inline] + pub fn send_vr_command(&self, command: WebVRCommand) { + self.webgl_sender.send_vr(command).unwrap(); } pub fn get_extension_manager<'a>(&'a self) -> &'a WebGLExtensions { @@ -370,9 +385,7 @@ impl WebGLRenderingContext { self.current_vertex_attrib_0.set((x, y, z, w)) } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::VertexAttrib(indx, x, y, z, w))) - .unwrap(); + self.send_command(WebGLCommand::VertexAttrib(indx, x, y, z, w)); } fn get_current_framebuffer_size(&self) -> Option<(i32, i32)> { @@ -705,8 +718,8 @@ impl WebGLRenderingContext { // WebGLContext (probably via GetPixels()). ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLCanvasElement(canvas) => { if let Some((mut data, size)) = canvas.fetch_all_data() { - byte_swap(&mut data); // Pixels got from Canvas have already alpha premultiplied + byte_swap(&mut data); (data, size, true) } else { return Err(()); @@ -945,9 +958,7 @@ impl WebGLRenderingContext { // GL_UNPACK_ALIGNMENT, while for textures from images or // canvas (produced by rgba8_image_to_tex_image_data()), it // will be 1. - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::PixelStorei(constants::UNPACK_ALIGNMENT, unpacking_alignment as i32))) - .unwrap(); + self.send_command(WebGLCommand::PixelStorei(constants::UNPACK_ALIGNMENT, unpacking_alignment as i32)); let format = internal_format.as_gl_constant(); let data_type = data_type.as_gl_constant(); @@ -961,9 +972,7 @@ impl WebGLRenderingContext { data_type, pixels); - self.ipc_renderer - .send(CanvasMsg::WebGL(msg)) - .unwrap(); + self.send_command(msg); if let Some(fb) = self.bound_framebuffer.get() { fb.invalidate_texture(&*texture); @@ -1005,9 +1014,7 @@ impl WebGLRenderingContext { // GL_UNPACK_ALIGNMENT, while for textures from images or // canvas (produced by rgba8_image_to_tex_image_data()), it // will be 1. - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::PixelStorei(constants::UNPACK_ALIGNMENT, unpacking_alignment as i32))) - .unwrap(); + self.send_command(WebGLCommand::PixelStorei(constants::UNPACK_ALIGNMENT, unpacking_alignment as i32)); // TODO(emilio): convert colorspace if requested let msg = WebGLCommand::TexSubImage2D(target.as_gl_constant(), @@ -1016,9 +1023,7 @@ impl WebGLRenderingContext { format.as_gl_constant(), data_type.as_gl_constant(), pixels); - self.ipc_renderer - .send(CanvasMsg::WebGL(msg)) - .unwrap() + self.send_command(msg); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14 @@ -1035,17 +1040,38 @@ impl WebGLRenderingContext { } fn get_gl_extensions(&self) -> String { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::GetExtensions(sender))) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::GetExtensions(sender)); receiver.recv().unwrap() } + + fn layout_handle(&self) -> webrender_api::ImageKey { + match self.share_mode { + WebGLContextShareMode::SharedTexture => { + // WR using ExternalTexture requires a single update message. + self.webrender_image.get().unwrap_or_else(|| { + let (sender, receiver) = webgl_channel().unwrap(); + self.webgl_sender.send_update_wr_image(sender).unwrap(); + let image_key = receiver.recv().unwrap(); + self.webrender_image.set(Some(image_key)); + + image_key + }) + }, + WebGLContextShareMode::Readback => { + // WR using Readback requires to update WR image every frame + // in order to send the new raw pixels. + let (sender, receiver) = webgl_channel().unwrap(); + self.webgl_sender.send_update_wr_image(sender).unwrap(); + receiver.recv().unwrap() + } + } + } } impl Drop for WebGLRenderingContext { fn drop(&mut self) { - self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Close)).unwrap(); + self.webgl_sender.send_remove().unwrap(); } } @@ -1101,45 +1127,36 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 fn Flush(&self) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Flush)) - .unwrap(); + self.send_command(WebGLCommand::Flush); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 fn Finish(&self) { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Finish(sender))) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::Finish(sender)); receiver.recv().unwrap() } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1 fn DrawingBufferWidth(&self) -> i32 { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::DrawingBufferWidth(sender))) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::DrawingBufferWidth(sender)); receiver.recv().unwrap() } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1 fn DrawingBufferHeight(&self) -> i32 { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::DrawingBufferHeight(sender))) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::DrawingBufferHeight(sender)); receiver.recv().unwrap() } #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 unsafe fn GetBufferParameter(&self, _cx: *mut JSContext, target: u32, parameter: u32) -> JSVal { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::GetBufferParameter(target, parameter, sender))) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::GetBufferParameter(target, parameter, sender)); + match handle_potential_webgl_error!(self, receiver.recv().unwrap(), WebGLParameter::Invalid) { WebGLParameter::Int(val) => Int32Value(val), WebGLParameter::Bool(_) => panic!("Buffer parameter should not be bool"), @@ -1205,10 +1222,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } } - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::GetParameter(parameter, sender))) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::GetParameter(parameter, sender)); + match handle_potential_webgl_error!(self, receiver.recv().unwrap(), WebGLParameter::Invalid) { WebGLParameter::Int(val) => Int32Value(val), WebGLParameter::Bool(val) => BooleanValue(val), @@ -1243,13 +1259,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.2 fn GetContextAttributes(&self) -> Option<WebGLContextAttributes> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); // If the send does not succeed, assume context lost - if let Err(_) = self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::GetContextAttributes(sender))) { + if self.webgl_sender.send(WebGLCommand::GetContextAttributes(sender)).is_err() { return None; } + let attrs = receiver.recv().unwrap(); Some(WebGLContextAttributes { @@ -1285,12 +1301,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn ActiveTexture(&self, texture: u32) { - self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::ActiveTexture(texture))).unwrap(); + self.send_command(WebGLCommand::ActiveTexture(texture)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn BlendColor(&self, r: f32, g: f32, b: f32, a: f32) { - self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::BlendColor(r, g, b, a))).unwrap(); + self.send_command(WebGLCommand::BlendColor(r, g, b, a)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -1299,7 +1315,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidEnum); } - self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::BlendEquation(mode))).unwrap(); + self.send_command(WebGLCommand::BlendEquation(mode)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -1308,9 +1324,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidEnum); } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha))) - .unwrap(); + self.send_command(WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -1327,9 +1341,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidOperation); } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::BlendFunc(src_factor, dest_factor))) - .unwrap(); + self.send_command(WebGLCommand::BlendFunc(src_factor, dest_factor)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -1346,8 +1358,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidOperation); } - self.ipc_renderer.send( - CanvasMsg::WebGL(WebGLCommand::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha))).unwrap(); + self.send_command(WebGLCommand::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 @@ -1393,9 +1404,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } else { slot.set(None); // Unbind the current buffer - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::BindBuffer(target, None))) - .unwrap() + self.send_command(WebGLCommand::BindBuffer(target, None)); } } @@ -1420,7 +1429,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } else { // Bind the default framebuffer let cmd = WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Default); - self.ipc_renderer.send(CanvasMsg::WebGL(cmd)).unwrap(); + self.send_command(cmd); self.bound_framebuffer.set(framebuffer); } } @@ -1442,9 +1451,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { _ => { self.bound_renderbuffer.set(None); // Unbind the currently bound renderbuffer - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::BindRenderbuffer(target, None))) - .unwrap() + self.send_command(WebGLCommand::BindRenderbuffer(target, None)); } } } @@ -1465,9 +1472,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } else { slot.set(None); // Unbind the currently bound texture - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::BindTexture(target, None))) - .unwrap() + self.send_command(WebGLCommand::BindTexture(target, None)); } } @@ -1585,9 +1590,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if (offset as usize) + data_vec.len() > bound_buffer.capacity() { return Ok(self.webgl_error(InvalidValue)); } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::BufferSubData(target, offset as isize, data_vec))) - .unwrap(); + self.send_command(WebGLCommand::BufferSubData(target, offset as isize, data_vec)); Ok(()) } @@ -1670,7 +1673,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { width as i32, height as i32, border as i32); - self.ipc_renderer.send(CanvasMsg::WebGL(msg)).unwrap() + self.send_command(msg); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 @@ -1714,7 +1717,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { x, y, width as i32, height as i32); - self.ipc_renderer.send(CanvasMsg::WebGL(msg)).unwrap(); + self.send_command(msg); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 @@ -1723,46 +1726,36 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return; } - self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::Clear(mask))).unwrap(); + self.send_command(WebGLCommand::Clear(mask)); self.mark_as_dirty(); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn ClearColor(&self, red: f32, green: f32, blue: f32, alpha: f32) { self.current_clear_color.set((red, green, blue, alpha)); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::ClearColor(red, green, blue, alpha))) - .unwrap() + self.send_command(WebGLCommand::ClearColor(red, green, blue, alpha)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn ClearDepth(&self, depth: f32) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::ClearDepth(depth as f64))) - .unwrap() + self.send_command(WebGLCommand::ClearDepth(depth as f64)) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn ClearStencil(&self, stencil: i32) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::ClearStencil(stencil))) - .unwrap() + self.send_command(WebGLCommand::ClearStencil(stencil)) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn ColorMask(&self, r: bool, g: bool, b: bool, a: bool) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::ColorMask(r, g, b, a))) - .unwrap() + self.send_command(WebGLCommand::ColorMask(r, g, b, a)) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn CullFace(&self, mode: u32) { match mode { constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::CullFace(mode))) - .unwrap(), + self.send_command(WebGLCommand::CullFace(mode)), _ => self.webgl_error(InvalidEnum), } } @@ -1771,9 +1764,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { fn FrontFace(&self, mode: u32) { match mode { constants::CW | constants::CCW => - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::FrontFace(mode))) - .unwrap(), + self.send_command(WebGLCommand::FrontFace(mode)), _ => self.webgl_error(InvalidEnum), } } @@ -1784,18 +1775,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { constants::EQUAL | constants::LEQUAL | constants::GREATER | constants::NOTEQUAL | constants::GEQUAL | constants::ALWAYS => - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::DepthFunc(func))) - .unwrap(), + self.send_command(WebGLCommand::DepthFunc(func)), _ => self.webgl_error(InvalidEnum), } } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn DepthMask(&self, flag: bool) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::DepthMask(flag))) - .unwrap() + self.send_command(WebGLCommand::DepthMask(flag)) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -1809,26 +1796,20 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidOperation); } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::DepthRange(near as f64, far as f64))) - .unwrap() + self.send_command(WebGLCommand::DepthRange(near as f64, far as f64)) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn Enable(&self, cap: u32) { if self.validate_feature_enum(cap) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Enable(cap))) - .unwrap(); + self.send_command(WebGLCommand::Enable(cap)); } } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn Disable(&self, cap: u32) { if self.validate_feature_enum(cap) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Disable(cap))) - .unwrap() + self.send_command(WebGLCommand::Disable(cap)); } } @@ -1843,27 +1824,27 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // generated objects, either here or in the webgl thread // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 fn CreateBuffer(&self) -> Option<Root<WebGLBuffer>> { - WebGLBuffer::maybe_new(self.global().as_window(), self.ipc_renderer.clone()) + WebGLBuffer::maybe_new(self.global().as_window(), self.webgl_sender.clone()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6 fn CreateFramebuffer(&self) -> Option<Root<WebGLFramebuffer>> { - WebGLFramebuffer::maybe_new(self.global().as_window(), self.ipc_renderer.clone()) + WebGLFramebuffer::maybe_new(self.global().as_window(), self.webgl_sender.clone()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7 fn CreateRenderbuffer(&self) -> Option<Root<WebGLRenderbuffer>> { - WebGLRenderbuffer::maybe_new(self.global().as_window(), self.ipc_renderer.clone()) + WebGLRenderbuffer::maybe_new(self.global().as_window(), self.webgl_sender.clone()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 fn CreateTexture(&self) -> Option<Root<WebGLTexture>> { - WebGLTexture::maybe_new(self.global().as_window(), self.ipc_renderer.clone()) + WebGLTexture::maybe_new(self.global().as_window(), self.webgl_sender.clone()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 fn CreateProgram(&self) -> Option<Root<WebGLProgram>> { - WebGLProgram::maybe_new(self.global().as_window(), self.ipc_renderer.clone()) + WebGLProgram::maybe_new(self.global().as_window(), self.webgl_sender.clone()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 @@ -1875,7 +1856,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return None; } } - WebGLShader::maybe_new(self.global().as_window(), self.ipc_renderer.clone(), shader_type) + WebGLShader::maybe_new(self.global().as_window(), self.webgl_sender.clone(), shader_type) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 @@ -1999,9 +1980,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return; } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::DrawArrays(mode, first, count))) - .unwrap(); + self.send_command(WebGLCommand::DrawArrays(mode, first, count)); self.mark_as_dirty(); }, _ => self.webgl_error(InvalidEnum), @@ -2065,9 +2044,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { constants::LINE_LOOP | constants::LINES | constants::TRIANGLE_STRIP | constants::TRIANGLE_FAN | constants::TRIANGLES => { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::DrawElements(mode, count, type_, offset))) - .unwrap(); + self.send_command(WebGLCommand::DrawElements(mode, count, type_, offset)); self.mark_as_dirty(); }, _ => self.webgl_error(InvalidEnum), @@ -2080,9 +2057,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidValue); } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::EnableVertexAttribArray(attrib_id))) - .unwrap() + self.send_command(WebGLCommand::EnableVertexAttribArray(attrib_id)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -2091,9 +2066,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidValue); } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::DisableVertexAttribArray(attrib_id))) - .unwrap() + self.send_command(WebGLCommand::DisableVertexAttribArray(attrib_id)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -2223,11 +2196,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { shader_type: u32, precision_type: u32) -> Option<Root<WebGLShaderPrecisionFormat>> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::GetShaderPrecisionFormat(shader_type, - precision_type, - sender))) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::GetShaderPrecisionFormat(shader_type, + precision_type, + sender)); + match receiver.recv().unwrap() { Ok((range_min, range_max, precision)) => { Some(WebGLShaderPrecisionFormat::new(self.global().as_window(), range_min, range_max, precision)) @@ -2268,8 +2241,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return jsval.get(); } - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::GetVertexAttrib(index, pname, sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::GetVertexAttrib(index, pname, sender)); match handle_potential_webgl_error!(self, receiver.recv().unwrap(), WebGLParameter::Invalid) { WebGLParameter::Int(val) => Int32Value(val), @@ -2287,8 +2260,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn GetVertexAttribOffset(&self, index: u32, pname: u32) -> i64 { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::GetVertexAttribOffset(index, pname, sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::GetVertexAttribOffset(index, pname, sender)); handle_potential_webgl_error!(self, receiver.recv().unwrap(), 0) as i64 } @@ -2307,9 +2280,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { _ => return self.webgl_error(InvalidEnum), } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Hint(target, mode))) - .unwrap() + self.send_command(WebGLCommand::Hint(target, mode)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 @@ -2321,10 +2292,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn IsEnabled(&self, cap: u32) -> bool { if self.validate_feature_enum(cap) { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::IsEnabled(cap, sender))) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::IsEnabled(cap, sender)); return receiver.recv().unwrap(); } @@ -2362,9 +2331,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidValue); } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::LineWidth(width))) - .unwrap() + self.send_command(WebGLCommand::LineWidth(width)) } // NOTE: Usage of this function could affect rendering while we keep using @@ -2420,9 +2387,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn PolygonOffset(&self, factor: f32, units: f32) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::PolygonOffset(factor, units))) - .unwrap() + self.send_command(WebGLCommand::PolygonOffset(factor, units)) } #[allow(unsafe_code)] @@ -2522,10 +2487,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { _ => return Ok(self.webgl_error(InvalidOperation)), }; - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::ReadPixels(x, y, width, height, format, pixel_type, sender))) - .unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.send_command(WebGLCommand::ReadPixels(x, y, width, height, format, pixel_type, sender)); let result = receiver.recv().unwrap(); @@ -2541,7 +2504,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn SampleCoverage(&self, value: f32, invert: bool) { - self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::SampleCoverage(value, invert))).unwrap(); + self.send_command(WebGLCommand::SampleCoverage(value, invert)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4 @@ -2551,9 +2514,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } self.current_scissor.set((x, y, width, height)); - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Scissor(x, y, width, height))) - .unwrap() + self.send_command(WebGLCommand::Scissor(x, y, width, height)); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -2561,9 +2522,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { match func { constants::NEVER | constants::LESS | constants::EQUAL | constants::LEQUAL | constants::GREATER | constants::NOTEQUAL | constants::GEQUAL | constants::ALWAYS => - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::StencilFunc(func, ref_, mask))) - .unwrap(), + self.send_command(WebGLCommand::StencilFunc(func, ref_, mask)), _ => self.webgl_error(InvalidEnum), } } @@ -2578,27 +2537,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { match func { constants::NEVER | constants::LESS | constants::EQUAL | constants::LEQUAL | constants::GREATER | constants::NOTEQUAL | constants::GEQUAL | constants::ALWAYS => - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::StencilFuncSeparate(face, func, ref_, mask))) - .unwrap(), + self.send_command(WebGLCommand::StencilFuncSeparate(face, func, ref_, mask)), _ => self.webgl_error(InvalidEnum), } } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn StencilMask(&self, mask: u32) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::StencilMask(mask))) - .unwrap() + self.send_command(WebGLCommand::StencilMask(mask)) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 fn StencilMaskSeparate(&self, face: u32, mask: u32) { match face { constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::StencilMaskSeparate(face, mask))) - .unwrap(), + self.send_command(WebGLCommand::StencilMaskSeparate(face, mask)), _ => return self.webgl_error(InvalidEnum), } } @@ -2607,9 +2560,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { fn StencilOp(&self, fail: u32, zfail: u32, zpass: u32) { if self.validate_stencil_actions(fail) && self.validate_stencil_actions(zfail) && self.validate_stencil_actions(zpass) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::StencilOp(fail, zfail, zpass))) - .unwrap() + self.send_command(WebGLCommand::StencilOp(fail, zfail, zpass)); } else { self.webgl_error(InvalidEnum) } @@ -2624,9 +2575,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_stencil_actions(fail) && self.validate_stencil_actions(zfail) && self.validate_stencil_actions(zpass) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass))) - .unwrap() + self.send_command(WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass)) } else { self.webgl_error(InvalidEnum) } @@ -2658,9 +2607,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { uniform: Option<&WebGLUniformLocation>, val: f32) { if self.validate_uniform_parameters(uniform, UniformSetterType::Float, &[val]) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform1f(uniform.unwrap().id(), val))) - .unwrap() + self.send_command(WebGLCommand::Uniform1f(uniform.unwrap().id(), val)) } } @@ -2669,9 +2616,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { uniform: Option<&WebGLUniformLocation>, val: i32) { if self.validate_uniform_parameters(uniform, UniformSetterType::Int, &[val]) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform1i(uniform.unwrap().id(), val))) - .unwrap() + self.send_command(WebGLCommand::Uniform1i(uniform.unwrap().id(), val)) } } @@ -2685,9 +2630,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let data_vec = typed_array_or_sequence_to_vec::<Int32>(cx, data, ConversionBehavior::Default)?; if self.validate_uniform_parameters(uniform, UniformSetterType::Int, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform1iv(uniform.unwrap().id(), data_vec))) - .unwrap() + self.send_command(WebGLCommand::Uniform1iv(uniform.unwrap().id(), data_vec)) } Ok(()) @@ -2703,9 +2646,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let data_vec = typed_array_or_sequence_to_vec::<Float32>(cx, data, ())?; if self.validate_uniform_parameters(uniform, UniformSetterType::Float, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform1fv(uniform.unwrap().id(), data_vec))) - .unwrap() + self.send_command(WebGLCommand::Uniform1fv(uniform.unwrap().id(), data_vec)); } Ok(()) @@ -2716,9 +2657,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { uniform: Option<&WebGLUniformLocation>, x: f32, y: f32) { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec2, &[x, y]) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform2f(uniform.unwrap().id(), x, y))) - .unwrap() + self.send_command(WebGLCommand::Uniform2f(uniform.unwrap().id(), x, y)); } } @@ -2734,9 +2673,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec2, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform2fv(uniform.unwrap().id(), data_vec))) - .unwrap() + self.send_command(WebGLCommand::Uniform2fv(uniform.unwrap().id(), data_vec)); } Ok(()) @@ -2749,9 +2686,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec2, &[x, y]) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform2i(uniform.unwrap().id(), x, y))) - .unwrap() + self.send_command(WebGLCommand::Uniform2i(uniform.unwrap().id(), x, y)); } } @@ -2767,9 +2702,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec2, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform2iv(uniform.unwrap().id(), data_vec))) - .unwrap() + self.send_command(WebGLCommand::Uniform2iv(uniform.unwrap().id(), data_vec)); } Ok(()) @@ -2782,9 +2715,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec3, &[x, y, z]) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform3f(uniform.unwrap().id(), x, y, z))) - .unwrap() + self.send_command(WebGLCommand::Uniform3f(uniform.unwrap().id(), x, y, z)); } } @@ -2800,9 +2731,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec3, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform3fv(uniform.unwrap().id(), data_vec))) - .unwrap() + self.send_command(WebGLCommand::Uniform3fv(uniform.unwrap().id(), data_vec)) } Ok(()) @@ -2815,9 +2744,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec3, &[x, y, z]) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform3i(uniform.unwrap().id(), x, y, z))) - .unwrap() + self.send_command(WebGLCommand::Uniform3i(uniform.unwrap().id(), x, y, z)) } } @@ -2833,9 +2760,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec3, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform3iv(uniform.unwrap().id(), data_vec))) - .unwrap() + self.send_command(WebGLCommand::Uniform3iv(uniform.unwrap().id(), data_vec)) } Ok(()) @@ -2848,9 +2773,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec4, &[x, y, z, w]) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform4i(uniform.unwrap().id(), x, y, z, w))) - .unwrap() + self.send_command(WebGLCommand::Uniform4i(uniform.unwrap().id(), x, y, z, w)) } } @@ -2867,9 +2790,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec4, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform4iv(uniform.unwrap().id(), data_vec))) - .unwrap() + self.send_command(WebGLCommand::Uniform4iv(uniform.unwrap().id(), data_vec)) } Ok(()) @@ -2882,9 +2803,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec4, &[x, y, z, w]) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform4f(uniform.unwrap().id(), x, y, z, w))) - .unwrap() + self.send_command(WebGLCommand::Uniform4f(uniform.unwrap().id(), x, y, z, w)) } } @@ -2900,9 +2819,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec4, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform4fv(uniform.unwrap().id(), data_vec))) - .unwrap() + self.send_command(WebGLCommand::Uniform4fv(uniform.unwrap().id(), data_vec)) } Ok(()) @@ -2920,9 +2837,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatMat2, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::UniformMatrix2fv(uniform.unwrap().id(), transpose, data_vec))) - .unwrap() + self.send_command(WebGLCommand::UniformMatrix2fv(uniform.unwrap().id(), transpose, data_vec)); } Ok(()) @@ -2940,9 +2855,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatMat3, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::UniformMatrix3fv(uniform.unwrap().id(), transpose, data_vec))) - .unwrap() + self.send_command(WebGLCommand::UniformMatrix3fv(uniform.unwrap().id(), transpose, data_vec)); } Ok(()) @@ -2960,9 +2873,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatMat4, &data_vec) { - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::UniformMatrix4fv(uniform.unwrap().id(), transpose, data_vec))) - .unwrap() + self.send_command(WebGLCommand::UniformMatrix4fv(uniform.unwrap().id(), transpose, data_vec)); } Ok(()) @@ -3098,9 +3009,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { self.bound_attrib_buffers.borrow_mut().insert(attrib_id, JS::from_ref(&*buffer_array)); - let msg = CanvasMsg::WebGL( - WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset as u32)); - self.ipc_renderer.send(msg).unwrap() + let msg = WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset as u32); + self.send_command(msg); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4 @@ -3109,9 +3019,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidValue) } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Viewport(x, y, width, height))) - .unwrap() + self.send_command(WebGLCommand::Viewport(x, y, width, height)) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 @@ -3456,13 +3364,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { pub trait LayoutCanvasWebGLRenderingContextHelpers { #[allow(unsafe_code)] - unsafe fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg>; + unsafe fn canvas_data_source(&self) -> HTMLCanvasDataSource; } impl LayoutCanvasWebGLRenderingContextHelpers for LayoutJS<WebGLRenderingContext> { #[allow(unsafe_code)] - unsafe fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> { - (*self.unsafe_get()).ipc_renderer.clone() + unsafe fn canvas_data_source(&self) -> HTMLCanvasDataSource { + HTMLCanvasDataSource::WebGL((*self.unsafe_get()).layout_handle()) } } diff --git a/components/script/dom/webglshader.rs b/components/script/dom/webglshader.rs index edd9cf7bdb3..cf6fc55072d 100644 --- a/components/script/dom/webglshader.rs +++ b/components/script/dom/webglshader.rs @@ -4,7 +4,7 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use angle::hl::{BuiltInResources, Output, ShaderValidator}; -use canvas_traits::CanvasMsg; +use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLMsgSender, WebGLParameter, WebGLResult, WebGLShaderId}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::WebGLShaderBinding; use dom::bindings::js::Root; @@ -13,11 +13,8 @@ use dom::bindings::str::DOMString; use dom::webglobject::WebGLObject; use dom::window::Window; use dom_struct::dom_struct; -use ipc_channel::ipc::IpcSender; use std::cell::Cell; use std::sync::{ONCE_INIT, Once}; -use webrender_api; -use webrender_api::{WebGLCommand, WebGLParameter, WebGLResult, WebGLShaderId}; #[derive(Clone, Copy, PartialEq, Debug, JSTraceable, HeapSizeOf)] pub enum ShaderCompilationStatus { @@ -37,7 +34,7 @@ pub struct WebGLShader { attached_counter: Cell<u32>, compilation_status: Cell<ShaderCompilationStatus>, #[ignore_heap_size_of = "Defined in ipc-channel"] - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, } #[cfg(not(target_os = "android"))] @@ -49,7 +46,7 @@ const SHADER_OUTPUT_FORMAT: Output = Output::Essl; static GLSLANG_INITIALIZATION: Once = ONCE_INIT; impl WebGLShader { - fn new_inherited(renderer: IpcSender<CanvasMsg>, + fn new_inherited(renderer: WebGLMsgSender, id: WebGLShaderId, shader_type: u32) -> WebGLShader { @@ -68,18 +65,18 @@ impl WebGLShader { } pub fn maybe_new(window: &Window, - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, shader_type: u32) -> Option<Root<WebGLShader>> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateShader(shader_type, sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + renderer.send(WebGLCommand::CreateShader(shader_type, sender)).unwrap(); let result = receiver.recv().unwrap(); result.map(|shader_id| WebGLShader::new(window, renderer, shader_id, shader_type)) } pub fn new(window: &Window, - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, id: WebGLShaderId, shader_type: u32) -> Root<WebGLShader> { @@ -118,7 +115,7 @@ impl WebGLShader { // will succeed. // It could be interesting to retrieve the info log from the paint thread though let msg = WebGLCommand::CompileShader(self.id, translated_source); - self.renderer.send(CanvasMsg::WebGL(msg)).unwrap(); + self.renderer.send(msg).unwrap(); self.compilation_status.set(ShaderCompilationStatus::Succeeded); }, Err(error) => { @@ -142,7 +139,7 @@ impl WebGLShader { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteShader(self.id))); + let _ = self.renderer.send(WebGLCommand::DeleteShader(self.id)); } } @@ -170,8 +167,8 @@ impl WebGLShader { /// glGetParameter pub fn parameter(&self, param_id: u32) -> WebGLResult<WebGLParameter> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::GetShaderParameter(self.id, param_id, sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + self.renderer.send(WebGLCommand::GetShaderParameter(self.id, param_id, sender)).unwrap(); receiver.recv().unwrap() } diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index 88d5faaf5c8..048af5d10e0 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -3,7 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl -use canvas_traits::CanvasMsg; + +use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLError, WebGLMsgSender, WebGLResult, WebGLTextureId}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::codegen::Bindings::WebGLTextureBinding; @@ -13,11 +14,8 @@ use dom::webgl_validations::types::{TexImageTarget, TexFormat, TexDataType}; use dom::webglobject::WebGLObject; use dom::window::Window; use dom_struct::dom_struct; -use ipc_channel::ipc::IpcSender; use std::cell::Cell; use std::cmp; -use webrender_api; -use webrender_api::{WebGLCommand, WebGLError, WebGLResult, WebGLTextureId}; pub enum TexParameterValue { Float(f32), @@ -46,11 +44,11 @@ pub struct WebGLTexture { min_filter: Cell<Option<u32>>, mag_filter: Cell<Option<u32>>, #[ignore_heap_size_of = "Defined in ipc-channel"] - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, } impl WebGLTexture { - fn new_inherited(renderer: IpcSender<CanvasMsg>, + fn new_inherited(renderer: WebGLMsgSender, id: WebGLTextureId) -> WebGLTexture { WebGLTexture { @@ -67,17 +65,17 @@ impl WebGLTexture { } } - pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>) + pub fn maybe_new(window: &Window, renderer: WebGLMsgSender) -> Option<Root<WebGLTexture>> { - let (sender, receiver) = webrender_api::channel::msg_channel().unwrap(); - renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateTexture(sender))).unwrap(); + let (sender, receiver) = webgl_channel().unwrap(); + renderer.send(WebGLCommand::CreateTexture(sender)).unwrap(); let result = receiver.recv().unwrap(); result.map(|texture_id| WebGLTexture::new(window, renderer, texture_id)) } pub fn new(window: &Window, - renderer: IpcSender<CanvasMsg>, + renderer: WebGLMsgSender, id: WebGLTextureId) -> Root<WebGLTexture> { reflect_dom_object(box WebGLTexture::new_inherited(renderer, id), @@ -113,7 +111,7 @@ impl WebGLTexture { self.target.set(Some(target)); } - let msg = CanvasMsg::WebGL(WebGLCommand::BindTexture(target, Some(self.id))); + let msg = WebGLCommand::BindTexture(target, Some(self.id)); self.renderer.send(msg).unwrap(); Ok(()) @@ -168,7 +166,7 @@ impl WebGLTexture { return Err(WebGLError::InvalidOperation); } - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::GenerateMipmap(target))).unwrap(); + self.renderer.send(WebGLCommand::GenerateMipmap(target)).unwrap(); if self.base_mipmap_level + base_image_info.get_max_mimap_levels() == 0 { return Err(WebGLError::InvalidOperation); @@ -181,7 +179,7 @@ impl WebGLTexture { pub fn delete(&self) { if !self.is_deleted.get() { self.is_deleted.set(true); - let _ = self.renderer.send(CanvasMsg::WebGL(WebGLCommand::DeleteTexture(self.id))); + let _ = self.renderer.send(WebGLCommand::DeleteTexture(self.id)); } } @@ -216,7 +214,7 @@ impl WebGLTexture { constants::LINEAR_MIPMAP_LINEAR => { self.min_filter.set(Some(int_value as u32)); self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::TexParameteri(target, name, int_value))) + .send(WebGLCommand::TexParameteri(target, name, int_value)) .unwrap(); Ok(()) }, @@ -230,7 +228,7 @@ impl WebGLTexture { constants::LINEAR => { self.mag_filter.set(Some(int_value as u32)); self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::TexParameteri(target, name, int_value))) + .send(WebGLCommand::TexParameteri(target, name, int_value)) .unwrap(); Ok(()) }, @@ -245,7 +243,7 @@ impl WebGLTexture { constants::MIRRORED_REPEAT | constants::REPEAT => { self.renderer - .send(CanvasMsg::WebGL(WebGLCommand::TexParameteri(target, name, int_value))) + .send(WebGLCommand::TexParameteri(target, name, int_value)) .unwrap(); Ok(()) }, diff --git a/components/script/dom/webgluniformlocation.rs b/components/script/dom/webgluniformlocation.rs index 228808303c4..47292adeb18 100644 --- a/components/script/dom/webgluniformlocation.rs +++ b/components/script/dom/webgluniformlocation.rs @@ -3,12 +3,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl +use canvas_traits::webgl::WebGLProgramId; use dom::bindings::codegen::Bindings::WebGLUniformLocationBinding; use dom::bindings::js::Root; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::window::Window; use dom_struct::dom_struct; -use webrender_api::WebGLProgramId; #[dom_struct] pub struct WebGLUniformLocation { diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 90693a2ccbf..2da650ee1ee 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -5,6 +5,7 @@ use app_units::Au; use base64; use bluetooth_traits::BluetoothRequest; +use canvas_traits::webgl::WebGLChan; use cssparser::{Parser, ParserInput}; use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType}; use dom::bindings::cell::DOMRefCell; @@ -264,7 +265,11 @@ pub struct Window { /// A handle for communicating messages to the webvr thread, if available. #[ignore_heap_size_of = "channels are hard"] - webvr_thread: Option<IpcSender<WebVRMsg>>, + webgl_chan: WebGLChan, + + /// A handle for communicating messages to the webvr thread, if available. + #[ignore_heap_size_of = "channels are hard"] + webvr_chan: Option<IpcSender<WebVRMsg>>, /// A map for storing the previous permission state read results. permission_state_invocation_results: DOMRefCell<HashMap<String, PermissionState>>, @@ -380,8 +385,12 @@ impl Window { self.current_viewport.clone().get() } + pub fn webgl_chan(&self) -> WebGLChan { + self.webgl_chan.clone() + } + pub fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> { - self.webvr_thread.clone() + self.webvr_chan.clone() } fn new_paint_worklet(&self) -> Root<Worklet> { @@ -1800,7 +1809,8 @@ impl Window { origin: MutableOrigin, navigation_start: u64, navigation_start_precise: f64, - webvr_thread: Option<IpcSender<WebVRMsg>>) + webgl_chan: WebGLChan, + webvr_chan: Option<IpcSender<WebVRMsg>>) -> Root<Window> { let layout_rpc: Box<LayoutRPC + Send> = { let (rpc_send, rpc_recv) = channel(); @@ -1866,7 +1876,8 @@ impl Window { scroll_offsets: DOMRefCell::new(HashMap::new()), media_query_lists: WeakMediaQueryListVec::new(), test_runner: Default::default(), - webvr_thread: webvr_thread, + webgl_chan: webgl_chan, + webvr_chan: webvr_chan, permission_state_invocation_results: DOMRefCell::new(HashMap::new()), pending_layout_images: DOMRefCell::new(HashMap::new()), unminified_js_dir: DOMRefCell::new(None), diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index ea8038897ac..4a05002637a 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -18,6 +18,7 @@ //! loop. use bluetooth_traits::BluetoothRequest; +use canvas_traits::webgl::WebGLPipeline; use devtools; use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo}; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; @@ -508,8 +509,11 @@ pub struct ScriptThread { /// The unit of related similar-origin browsing contexts' list of MutationObserver objects mutation_observers: DOMRefCell<Vec<JS<MutationObserver>>>, + /// A handle to the webgl thread + webgl_chan: WebGLPipeline, + /// A handle to the webvr thread, if available - webvr_thread: Option<IpcSender<WebVRMsg>>, + webvr_chan: Option<IpcSender<WebVRMsg>>, /// The worklet thread pool worklet_thread_pool: DOMRefCell<Option<Rc<WorkletThreadPool>>>, @@ -881,7 +885,8 @@ impl ScriptThread { layout_to_constellation_chan: state.layout_to_constellation_chan, - webvr_thread: state.webvr_thread, + webgl_chan: state.webgl_chan, + webvr_chan: state.webvr_chan, worklet_thread_pool: Default::default(), @@ -2028,7 +2033,8 @@ impl ScriptThread { origin, incomplete.navigation_start, incomplete.navigation_start_precise, - self.webvr_thread.clone()); + self.webgl_chan.channel(), + self.webvr_chan.clone()); // Initialize the browsing context for the window. let window_proxy = self.local_window_proxy(&window, diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index e3e956096bb..7c0f97ef917 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -43,7 +43,7 @@ pub mod rpc; pub mod wrapper_traits; use atomic_refcell::AtomicRefCell; -use canvas_traits::CanvasMsg; +use canvas_traits::canvas::CanvasMsg; use core::nonzero::NonZero; use ipc_channel::ipc::IpcSender; use libc::c_void; @@ -124,8 +124,13 @@ pub enum LayoutElementType { SVGSVGElement, } +pub enum HTMLCanvasDataSource { + WebGL(webrender_api::ImageKey), + Image(Option<IpcSender<CanvasMsg>>) +} + pub struct HTMLCanvasData { - pub ipc_renderer: Option<IpcSender<CanvasMsg>>, + pub source: HTMLCanvasDataSource, pub width: u32, pub height: u32, } diff --git a/components/script_traits/Cargo.toml b/components/script_traits/Cargo.toml index 70fcdbb3f33..2c083b2773c 100644 --- a/components/script_traits/Cargo.toml +++ b/components/script_traits/Cargo.toml @@ -25,7 +25,6 @@ libc = "0.2" metrics = {path = "../metrics"} msg = {path = "../msg"} net_traits = {path = "../net_traits"} -offscreen_gl_context = { version = "0.11", features = ["serde"] } profile_traits = {path = "../profile_traits"} rustc-serialize = "0.3.4" serde = "1.0" diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 85122d35c3c..4a197e759ff 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -24,7 +24,6 @@ extern crate ipc_channel; extern crate libc; extern crate msg; extern crate net_traits; -extern crate offscreen_gl_context; extern crate profile_traits; extern crate rustc_serialize; #[macro_use] extern crate serde; @@ -39,6 +38,7 @@ mod script_msg; pub mod webdriver_msg; use bluetooth_traits::BluetoothRequest; +use canvas_traits::webgl::WebGLPipeline; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; use euclid::{Size2D, Length, Point2D, Vector2D, Rect, ScaleFactor, TypedSize2D}; use gfx_traits::Epoch; @@ -524,8 +524,10 @@ pub struct InitialScriptState { pub pipeline_namespace_id: PipelineNamespaceId, /// A ping will be sent on this channel once the script thread shuts down. pub content_process_shutdown_chan: IpcSender<()>, + /// A channel to the webgl thread used in this pipeline. + pub webgl_chan: WebGLPipeline, /// A channel to the webvr thread, if available. - pub webvr_thread: Option<IpcSender<WebVRMsg>> + pub webvr_chan: Option<IpcSender<WebVRMsg>> } /// This trait allows creating a `ScriptThread` without depending on the `script` @@ -759,8 +761,6 @@ pub enum ConstellationMsg { Reload(TopLevelBrowsingContextId), /// A log entry, with the top-level browsing context id and thread name LogEntry(Option<TopLevelBrowsingContextId>, Option<String>, LogEntry), - /// Set the WebVR thread channel. - SetWebVRThread(IpcSender<WebVRMsg>), /// Dispatch WebVR events to the subscribed script threads. WebVREvents(Vec<PipelineId>, Vec<WebVREvent>), /// Create a new top level browsing context. diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 4fd8fca5c7f..156f85a2be7 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -12,7 +12,7 @@ use LoadData; use MozBrowserEvent; use WorkerGlobalScopeInit; use WorkerScriptLoadOrigin; -use canvas_traits::CanvasMsg; +use canvas_traits::canvas::CanvasMsg; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use euclid::{Point2D, Size2D, TypedSize2D}; use ipc_channel::ipc::IpcSender; @@ -21,7 +21,6 @@ use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use net_traits::CoreResourceMsg; use net_traits::request::RequestInit; use net_traits::storage_thread::StorageType; -use offscreen_gl_context::{GLContextAttributes, GLLimits}; use servo_url::ImmutableOrigin; use servo_url::ServoUrl; use style_traits::CSSPixel; @@ -78,11 +77,6 @@ pub enum ScriptMsg { /// Requests that a new 2D canvas thread be created. (This is done in the constellation because /// 2D canvases may use the GPU and we don't want to give untrusted content access to the GPU.) CreateCanvasPaintThread(Size2D<i32>, IpcSender<IpcSender<CanvasMsg>>), - /// Requests that a new WebGL thread be created. (This is done in the constellation because - /// WebGL uses the GPU and we don't want to give untrusted content access to the GPU.) - CreateWebGLPaintThread(Size2D<i32>, - GLContextAttributes, - IpcSender<Result<(IpcSender<CanvasMsg>, GLLimits), String>>), /// Notifies the constellation that this frame has received focus. Focus, /// Forward an event that was sent to the parent window. diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 07212a2b2d1..93e6d4cf454 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -68,6 +68,8 @@ fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) { } use bluetooth::BluetoothThreadFactory; use bluetooth_traits::BluetoothRequest; +use canvas::gl_context::GLContextFactory; +use canvas::webgl_thread::WebGLThreads; use compositing::IOCompositor; use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver, InitialCompositorState}; use compositing::windowing::WindowEvent; @@ -149,7 +151,7 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static { let mut resource_path = resources_dir_path().unwrap(); resource_path.push("shaders"); - let (webrender, webrender_api_sender) = { + let (mut webrender, webrender_api_sender) = { // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up! let scale_factor = window.hidpi_factor().get(); let device_pixel_ratio = match opts.device_pixels_per_px { @@ -211,7 +213,7 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static { debugger_chan, devtools_chan, supports_clipboard, - &webrender, + &mut webrender, webrender_document, webrender_api_sender); @@ -288,7 +290,7 @@ fn create_constellation(user_agent: Cow<'static, str>, debugger_chan: Option<debugger::Sender>, devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>, supports_clipboard: bool, - webrender: &webrender::Renderer, + webrender: &mut webrender::Renderer, webrender_document: webrender_api::DocumentId, webrender_api_sender: webrender_api::RenderApiSender) -> (Sender<ConstellationMsg>, SWManagerSenders) { @@ -304,6 +306,30 @@ fn create_constellation(user_agent: Cow<'static, str>, let resource_sender = public_resource_threads.sender(); + let (webvr_chan, webvr_constellation_sender, webvr_compositor) = if PREFS.is_webvr_enabled() { + // WebVR initialization + let (mut handler, sender) = WebVRCompositorHandler::new(); + let (webvr_thread, constellation_sender) = WebVRThread::spawn(sender); + handler.set_webvr_thread_sender(webvr_thread.clone()); + (Some(webvr_thread), Some(constellation_sender), Some(handler)) + } else { + (None, None, None) + }; + + // GLContext factory used to create WebGL Contexts + let gl_factory = if opts::get().should_use_osmesa() { + GLContextFactory::current_osmesa_handle().unwrap() + } else { + GLContextFactory::current_native_handle(&compositor_proxy).unwrap() + }; + + // Initialize WebGL Thread entry point. + let (webgl_threads, image_handler) = WebGLThreads::new(gl_factory, + 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); + let initial_state = InitialConstellationState { compositor_proxy, debugger_chan, @@ -317,20 +343,17 @@ fn create_constellation(user_agent: Cow<'static, str>, supports_clipboard, webrender_document, webrender_api_sender, + webgl_threads, + webvr_chan, }; let (constellation_chan, from_swmanager_sender) = Constellation::<script_layout_interface::message::Msg, layout_thread::LayoutThread, script::script_thread::ScriptThread>::start(initial_state); - if PREFS.is_webvr_enabled() { - // WebVR initialization - let (mut handler, sender) = WebVRCompositorHandler::new(); - let webvr_thread = WebVRThread::spawn(constellation_chan.clone(), sender); - handler.set_webvr_thread_sender(webvr_thread.clone()); - - webrender.set_vr_compositor_handler(handler); - constellation_chan.send(ConstellationMsg::SetWebVRThread(webvr_thread)).unwrap(); + if let Some(webvr_constellation_sender) = webvr_constellation_sender { + // Set constellation channel used by WebVR thread to broadcast events + webvr_constellation_sender.send(constellation_chan.clone()).unwrap(); } // channels to communicate with Service Worker Manager diff --git a/components/webvr/Cargo.toml b/components/webvr/Cargo.toml index f7edd95d6d8..f6a7427a709 100644 --- a/components/webvr/Cargo.toml +++ b/components/webvr/Cargo.toml @@ -10,10 +10,11 @@ name = "webvr" path = "lib.rs" [dependencies] +canvas_traits = {path = "../canvas_traits"} +euclid = "0.15" ipc-channel = "0.8" log = "0.3" msg = {path = "../msg"} script_traits = {path = "../script_traits"} servo_config = {path = "../config"} webvr_traits = {path = "../webvr_traits" } -webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} diff --git a/components/webvr/lib.rs b/components/webvr/lib.rs index 62f3e992fdc..0ad9722b21e 100644 --- a/components/webvr/lib.rs +++ b/components/webvr/lib.rs @@ -4,13 +4,14 @@ #![deny(unsafe_code)] +extern crate canvas_traits; +extern crate euclid; extern crate ipc_channel; #[macro_use] extern crate log; extern crate msg; extern crate script_traits; extern crate servo_config; -extern crate webrender_api; extern crate webvr_traits; mod webvr_thread; diff --git a/components/webvr/webvr_thread.rs b/components/webvr/webvr_thread.rs index ec550153870..77f42a6b39e 100644 --- a/components/webvr/webvr_thread.rs +++ b/components/webvr/webvr_thread.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use canvas_traits::webgl; +use euclid::Size2D; use ipc_channel::ipc; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use msg::constellation_msg::PipelineId; @@ -11,8 +13,6 @@ use std::{thread, time}; use std::collections::{HashMap, HashSet}; use std::sync::mpsc; use std::sync::mpsc::{Receiver, Sender}; -use webrender_api; -use webrender_api::DeviceIntSize; use webvr_traits::{WebVRMsg, WebVRResult}; use webvr_traits::webvr::*; @@ -34,7 +34,7 @@ use webvr_traits::webvr::*; /// ids using the WebVR APIs. These ids are used to implement privacy guidelines defined in the WebVR Spec. /// * When a JavaScript thread gains access to present to a headset, WebVRThread is not used as a intermediary in /// the VRDisplay.requestAnimationFrame loop in order to minimize latency. A direct communication with WebRender -/// is used instead. See WebVRCompositorHandler and the VRCompositorCommanda for more details. +/// is used instead. See WebVRCompositorHandler and the WebVRCommands for more details. pub struct WebVRThread { receiver: IpcReceiver<WebVRMsg>, sender: IpcSender<WebVRMsg>, @@ -66,15 +66,17 @@ impl WebVRThread { } } - pub fn spawn(constellation_chan: Sender<ConstellationMsg>, - vr_compositor_chan: WebVRCompositorSender) - -> IpcSender<WebVRMsg> { + pub fn spawn(vr_compositor_chan: WebVRCompositorSender) + -> (IpcSender<WebVRMsg>, Sender<Sender<ConstellationMsg>>) { let (sender, receiver) = ipc::channel().unwrap(); + let (constellation_sender, constellation_receiver) = mpsc::channel(); let sender_clone = sender.clone(); thread::Builder::new().name("WebVRThread".into()).spawn(move || { + let constellation_chan = constellation_receiver.recv().unwrap(); WebVRThread::new(receiver, sender_clone, constellation_chan, vr_compositor_chan).start(); }).expect("Thread spawning failed"); - sender + + (sender, constellation_sender) } fn start(&mut self) { @@ -305,7 +307,7 @@ impl WebVRThread { pub struct WebVRCompositor(*mut VRDisplay); pub struct WebVRCompositorHandler { - compositors: HashMap<webrender_api::VRCompositorId, WebVRCompositor>, + compositors: HashMap<webgl::WebVRDeviceId, WebVRCompositor>, webvr_thread_receiver: Receiver<Option<WebVRCompositor>>, webvr_thread_sender: Option<IpcSender<WebVRMsg>> } @@ -328,14 +330,14 @@ impl WebVRCompositorHandler { } } -impl webrender_api::VRCompositorHandler for WebVRCompositorHandler { +impl webgl::WebVRRenderHandler for WebVRCompositorHandler { #[allow(unsafe_code)] - fn handle(&mut self, cmd: webrender_api::VRCompositorCommand, texture: Option<(u32, DeviceIntSize)>) { + fn handle(&mut self, cmd: webgl::WebVRCommand, texture: Option<(u32, Size2D<i32>)>) { match cmd { - webrender_api::VRCompositorCommand::Create(compositor_id) => { + webgl::WebVRCommand::Create(compositor_id) => { self.create_compositor(compositor_id); } - webrender_api::VRCompositorCommand::SyncPoses(compositor_id, near, far, sender) => { + webgl::WebVRCommand::SyncPoses(compositor_id, near, far, sender) => { if let Some(compositor) = self.compositors.get(&compositor_id) { let pose = unsafe { (*compositor.0).sync_poses(); @@ -346,7 +348,7 @@ impl webrender_api::VRCompositorHandler for WebVRCompositorHandler { let _ = sender.send(Err(())); } } - webrender_api::VRCompositorCommand::SubmitFrame(compositor_id, left_bounds, right_bounds) => { + webgl::WebVRCommand::SubmitFrame(compositor_id, left_bounds, right_bounds) => { if let Some(compositor) = self.compositors.get(&compositor_id) { if let Some((texture_id, size)) = texture { let layer = VRLayer { @@ -361,7 +363,7 @@ impl webrender_api::VRCompositorHandler for WebVRCompositorHandler { } } } - webrender_api::VRCompositorCommand::Release(compositor_id) => { + webgl::WebVRCommand::Release(compositor_id) => { self.compositors.remove(&compositor_id); } } @@ -370,7 +372,7 @@ impl webrender_api::VRCompositorHandler for WebVRCompositorHandler { impl WebVRCompositorHandler { #[allow(unsafe_code)] - fn create_compositor(&mut self, display_id: webrender_api::VRCompositorId) { + fn create_compositor(&mut self, display_id: webgl::WebVRDeviceId) { let sender = match self.webvr_thread_sender { Some(ref s) => s, None => return, |