--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -320,37 +320,41 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "canvas"
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)",
"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)",
"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)",
]
[[package]]
name = "canvas_traits"
version = "0.0.1"
dependencies = [
"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)",
"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)",
]
[[package]]
name = "caseless"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
@@ -521,17 +525,16 @@ dependencies = [
"ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
"layout_traits 0.0.1",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"metrics 0.0.1",
"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)",
"servo_config 0.0.1",
"servo_rand 0.0.1",
"servo_remutex 0.0.1",
"servo_url 0.0.1",
"style_traits 0.0.1",
@@ -2591,17 +2594,16 @@ dependencies = [
"heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper_serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"servo_atoms 0.0.1",
"servo_url 0.0.1",
"style_traits 0.0.1",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3524,22 +3526,23 @@ dependencies = [
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
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",
]
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
--- a/servo/components/canvas/Cargo.toml
+++ b/servo/components/canvas/Cargo.toml
@@ -7,17 +7,18 @@ publish = false
[lib]
name = "canvas"
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"
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"]}
--- a/servo/components/canvas/canvas_paint_thread.rs
+++ b/servo/components/canvas/canvas_paint_thread.rs
@@ -3,17 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use azure::azure::AzFloat;
use azure::azure_hl::{AntialiasMode, CapStyle, CompositionOp, JoinStyle};
use azure::azure_hl::{BackendType, DrawOptions, DrawTarget, Pattern, StrokeOptions, SurfaceFormat};
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};
use num_traits::ToPrimitive;
use std::borrow::ToOwned;
use std::mem;
use std::sync::Arc;
use std::thread;
@@ -188,38 +188,32 @@ impl<'a> CanvasPaintThread<'a> {
Canvas2dMsg::PutImageData(imagedata, offset, image_data_size, dirty_rect)
=> painter.put_image_data(imagedata, offset, image_data_size, dirty_rect),
Canvas2dMsg::SetShadowOffsetX(value) => painter.set_shadow_offset_x(value),
Canvas2dMsg::SetShadowOffsetY(value) => painter.set_shadow_offset_y(value),
Canvas2dMsg::SetShadowBlur(value) => painter.set_shadow_blur(value),
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) => {
painter.send_pixels(chan)
}
}
}
CanvasMsg::FromLayout(message) => {
match message {
FromLayoutMsg::SendData(chan) => {
painter.send_data(chan)
}
}
}
- CanvasMsg::WebGL(_) => panic!("Wrong WebGL message sent to Canvas2D thread"),
- CanvasMsg::WebVR(_) => panic!("Wrong WebVR message sent to Canvas2D thread"),
}
}
}).expect("Thread spawning failed");
sender
}
fn save_context_state(&mut self) {
@@ -566,17 +560,17 @@ impl<'a> CanvasPaintThread<'a> {
}
fn send_pixels(&mut self, chan: IpcSender<Option<Vec<u8>>>) {
self.drawtarget.snapshot().get_data_surface().with_data(|element| {
chan.send(Some(element.into())).unwrap();
})
}
- 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();
let descriptor = webrender_api::ImageDescriptor {
width: size.width as u32,
height: size.height as u32,
stride: None,
format: webrender_api::ImageFormat::BGRA8,
@@ -609,17 +603,17 @@ impl<'a> CanvasPaintThread<'a> {
updates.delete_image(image_key);
}
self.webrender_api.update_resources(updates);
let data = CanvasImageData {
image_key: self.image_key.unwrap(),
};
- chan.send(CanvasData::Image(data)).unwrap();
+ chan.send(data).unwrap();
})
}
fn image_data(&self, dest_rect: Rect<i32>, canvas_size: Size2D<f64>, chan: IpcSender<Vec<u8>>) {
let mut dest_data = self.read_pixels(dest_rect, canvas_size);
// bgra -> rgba
byte_swap(&mut dest_data);
new file mode 100644
--- /dev/null
+++ b/servo/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));
+ }
+}
--- a/servo/components/canvas/lib.rs
+++ b/servo/components/canvas/lib.rs
@@ -1,21 +1,23 @@
/* 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/. */
#![deny(unsafe_code)]
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;
new file mode 100644
--- /dev/null
+++ b/servo/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);
+ }
+}
copy from servo/tests/unit/style/rule_tree/mod.rs
copy to servo/components/canvas/webgl_mode/mod.rs
--- a/servo/tests/unit/style/rule_tree/mod.rs
+++ b/servo/components/canvas/webgl_mode/mod.rs
@@ -1,5 +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 bench;
+mod inprocess;
+pub use self::inprocess::WebGLThreads;
deleted file mode 100644
--- a/servo/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);
- }
- }
-}
new file mode 100644
--- /dev/null
+++ b/servo/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());
+ }
+}
--- a/servo/components/canvas_traits/Cargo.toml
+++ b/servo/components/canvas_traits/Cargo.toml
@@ -10,10 +10,13 @@ name = "canvas_traits"
path = "lib.rs"
[dependencies]
cssparser = "0.19"
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"]}
copy from servo/components/canvas_traits/lib.rs
copy to servo/components/canvas_traits/canvas.rs
--- a/servo/components/canvas_traits/lib.rs
+++ b/servo/components/canvas_traits/canvas.rs
@@ -1,76 +1,40 @@
/* 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/. */
-#![crate_name = "canvas_traits"]
-#![crate_type = "rlib"]
-
-#![deny(unsafe_code)]
-
-extern crate cssparser;
-extern crate euclid;
-extern crate heapsize;
-#[macro_use] extern crate heapsize_derive;
-extern crate ipc_channel;
-#[macro_use] extern crate serde;
-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};
+use webrender_api;
#[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 {
+ Recreate(Size2D<i32>),
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,
@@ -101,16 +65,26 @@ pub enum Canvas2dMsg {
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 {
--- a/servo/components/canvas_traits/lib.rs
+++ b/servo/components/canvas_traits/lib.rs
@@ -1,435 +1,25 @@
/* 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/. */
#![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;
new file mode 100644
--- /dev/null
+++ b/servo/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)
+ }
+}
new file mode 100644
--- /dev/null
+++ b/servo/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()
+}
new file mode 100644
--- /dev/null
+++ b/servo/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()
+ }
+}
new file mode 100644
--- /dev/null
+++ b/servo/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);
--- a/servo/components/constellation/Cargo.toml
+++ b/servo/components/constellation/Cargo.toml
@@ -25,17 +25,16 @@ hyper = "0.10"
ipc-channel = "0.8"
itertools = "0.5"
layout_traits = {path = "../layout_traits"}
log = "0.3.5"
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"
style_traits = {path = "../style_traits"}
servo_config = {path = "../config"}
servo_rand = {path = "../rand"}
servo_remutex = {path = "../remutex"}
servo_url = {path = "../url"}
--- a/servo/components/constellation/constellation.rs
+++ b/servo/components/constellation/constellation.rs
@@ -65,18 +65,18 @@
//! Since there is only one constellation, and its responsibilities include crash reporting,
//! it is very important that it does not panic.
use backtrace::Backtrace;
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;
use compositing::compositor_thread::Msg as ToCompositorMsg;
use debugger;
use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
use euclid::{Size2D, TypedSize2D, ScaleFactor};
use event_loop::EventLoop;
@@ -91,17 +91,16 @@ use log::{Log, LogLevel, LogLevelFilter,
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId};
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
use net_traits::{self, IpcSend, FetchResponseMsg, ResourceThreads};
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;
use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg, DiscardBrowsingContext};
use script_traits::{DocumentActivity, DocumentState, LayoutControlMsg, LoadData};
use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerSchedulerMsg};
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
@@ -293,18 +292,21 @@ pub struct Constellation<Message, LTF, S
/// The random number generator and probability for closing pipelines.
/// This is for testing the hardening of the constellation.
random_pipeline_closure: Option<(ServoRng, f32)>,
/// 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.
pub struct InitialConstellationState {
/// A channel through which messages can be sent to the compositor.
pub compositor_proxy: CompositorProxy,
/// A channel to the debugger, if applicable.
@@ -332,16 +334,22 @@ pub struct InitialConstellationState {
pub mem_profiler_chan: mem::ProfilerChan,
/// Webrender document ID.
pub webrender_document: webrender_api::DocumentId,
/// 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,
}
/// Data needed for webdriver
struct WebDriverData {
load_channel: Option<(PipelineId, IpcSender<webdriver_msg::LoadStatus>)>,
@@ -576,17 +584,18 @@ impl<Message, LTF, STF> Constellation<Me
handled_warnings: VecDeque::new(),
random_pipeline_closure: opts::get().random_pipeline_closure_probability.map(|prob| {
let seed = opts::get().random_pipeline_closure_seed.unwrap_or_else(random);
let rng = ServoRng::from_seed(&[seed]);
warn!("Randomly closing pipelines.");
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();
}).expect("Thread spawning failed");
(compositor_sender, swmanager_sender)
}
@@ -695,17 +704,18 @@ impl<Message, LTF, STF> Constellation<Me
event_loop,
load_data,
device_pixel_ratio: self.window_size.device_pixel_ratio,
pipeline_namespace_id: self.next_pipeline_namespace_id(),
prev_visibility,
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 {
Ok(result) => result,
Err(e) => return self.handle_send_error(pipeline_id, e),
};
if let Some(host) = host {
@@ -989,20 +999,16 @@ impl<Message, LTF, STF> Constellation<Me
}
FromCompositorMsg::Reload(top_level_browsing_context_id) => {
debug!("constellation got reload message");
self.handle_reload_msg(top_level_browsing_context_id);
}
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);
}
}
}
fn handle_request_from_script(&mut self, message: (PipelineId, FromScriptMsg)) {
@@ -1149,20 +1155,16 @@ impl<Message, LTF, STF> Constellation<Me
if source_is_top_level_pipeline {
self.compositor_proxy.send(ToCompositorMsg::HeadParsed(source_top_ctx_id));
}
}
FromScriptMsg::CreateCanvasPaintThread(size, sender) => {
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));
}
FromScriptMsg::SetDocumentState(state) => {
debug!("constellation got SetDocumentState message");
self.document_states.insert(source_pipeline_id, state);
}
@@ -1362,17 +1364,22 @@ impl<Message, LTF, STF> Constellation<Me
debug!("Exiting service worker manager thread.");
if let Some(mgr) = self.swmanager_chan.as_ref() {
if let Err(e) = mgr.send(ServiceWorkerMsg::Exit) {
warn!("Exit service worker manager failed ({})", e);
}
}
- 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);
}
}
debug!("Exiting timer scheduler.");
if let Err(e) = self.scheduler_chan.send(TimerSchedulerMsg::Exit) {
@@ -2130,29 +2137,16 @@ impl<Message, LTF, STF> Constellation<Me
let webrender_api = self.webrender_api_sender.clone();
let sender = CanvasPaintThread::start(*size, webrender_api,
opts::get().enable_canvas_antialiasing);
if let Err(e) = response_sender.send(sender) {
warn!("Create canvas paint thread response failed ({})", e);
}
}
- 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.
match msg {
WebDriverCommandMsg::GetWindowSize(_, reply) => {
let _ = reply.send(self.window_size);
},
WebDriverCommandMsg::SetWindowSize(top_level_browsing_context_id, size, reply) => {
--- a/servo/components/constellation/lib.rs
+++ b/servo/components/constellation/lib.rs
@@ -25,17 +25,16 @@ extern crate ipc_channel;
extern crate itertools;
extern crate layout_traits;
#[macro_use]
extern crate log;
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;
extern crate servo_config;
extern crate servo_rand;
extern crate servo_remutex;
extern crate servo_url;
extern crate style_traits;
--- a/servo/components/constellation/pipeline.rs
+++ b/servo/components/constellation/pipeline.rs
@@ -1,13 +1,14 @@
/* 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 bluetooth_traits::BluetoothRequest;
+use canvas_traits::webgl::WebGLPipeline;
use compositing::CompositionPipeline;
use compositing::CompositorProxy;
use compositing::compositor_thread::Msg as CompositorMsg;
use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
use euclid::{TypedSize2D, ScaleFactor};
use event_loop::EventLoop;
use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::Error;
@@ -166,18 +167,22 @@ pub struct InitialPipelineState {
/// Webrender api.
pub webrender_api_sender: webrender_api::RenderApiSender,
/// The ID of the document processed by this script thread.
pub webrender_document: webrender_api::DocumentId,
/// 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 {
/// Starts a layout thread, and possibly a script thread, in
/// a new process if requested.
pub fn spawn<Message, LTF, STF>(state: InitialPipelineState) -> Result<Pipeline, Error>
where LTF: LayoutThreadFactory<Message=Message>,
STF: ScriptThreadFactory<Message=Message>
@@ -265,17 +270,18 @@ impl Pipeline {
pipeline_port: pipeline_port,
pipeline_namespace_id: state.pipeline_namespace_id,
layout_content_process_shutdown_chan: layout_content_process_shutdown_chan,
layout_content_process_shutdown_port: layout_content_process_shutdown_port,
script_content_process_shutdown_chan: script_content_process_shutdown_chan,
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.
//
// Yes, that's all there is to it!
if opts::multiprocess() {
let _ = unprivileged_pipeline_content.spawn_multiprocess()?;
} else {
@@ -465,17 +471,18 @@ pub struct UnprivilegedPipelineContent {
pipeline_port: IpcReceiver<LayoutControlMsg>,
pipeline_namespace_id: PipelineNamespaceId,
layout_content_process_shutdown_chan: IpcSender<()>,
layout_content_process_shutdown_port: IpcReceiver<()>,
script_content_process_shutdown_chan: IpcSender<()>,
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 {
pub fn start_all<Message, LTF, STF>(self, wait_for_completion: bool)
where LTF: LayoutThreadFactory<Message=Message>,
STF: ScriptThreadFactory<Message=Message>
{
let image_cache = Arc::new(ImageCacheImpl::new(self.webrender_api_sender.create_api()));
@@ -494,17 +501,18 @@ impl UnprivilegedPipelineContent {
resource_threads: self.resource_threads,
image_cache: image_cache.clone(),
time_profiler_chan: self.time_profiler_chan.clone(),
mem_profiler_chan: self.mem_profiler_chan.clone(),
devtools_chan: self.devtools_chan,
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,
self.top_level_browsing_context_id,
self.load_data.url,
self.parent_info.is_some(),
layout_pair,
self.pipeline_port,
--- a/servo/components/gfx/display_list/mod.rs
+++ b/servo/components/gfx/display_list/mod.rs
@@ -29,17 +29,17 @@ use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
use style::computed_values::{border_style, image_rendering};
use style::values::computed::Filter;
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;
/// The factor that we multiply the blur radius by in order to inflate the boundaries of display
/// items that involve a blur. This ensures that the display item boundaries include all the ink.
pub static BLUR_INFLATION_FACTOR: i32 = 3;
#[derive(HeapSizeOf, Deserialize, Serialize)]
@@ -594,17 +594,16 @@ impl ScrollRoot {
/// One drawing command in the list.
#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
pub enum DisplayItem {
SolidColor(Box<SolidColorDisplayItem>),
Text(Box<TextDisplayItem>),
Image(Box<ImageDisplayItem>),
- WebGL(Box<WebGLDisplayItem>),
Border(Box<BorderDisplayItem>),
Gradient(Box<GradientDisplayItem>),
RadialGradient(Box<RadialGradientDisplayItem>),
Line(Box<LineDisplayItem>),
BoxShadow(Box<BoxShadowDisplayItem>),
PushTextShadow(Box<PushTextShadowDisplayItem>),
PopTextShadow(Box<PopTextShadowDisplayItem>),
Iframe(Box<IframeDisplayItem>),
@@ -924,24 +923,16 @@ pub struct ImageDisplayItem {
/// The amount of space to add to the right and bottom part of each tile, when the image
/// is tiled.
pub tile_spacing: Size2D<Au>,
/// The algorithm we should use to stretch the image. See `image_rendering` in CSS-IMAGES-3 §
/// 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 {
pub base: BaseDisplayItem,
pub iframe: PipelineId,
}
/// Paints a gradient.
@@ -1245,17 +1236,16 @@ pub enum BoxShadowClipMode {
}
impl DisplayItem {
pub fn base(&self) -> &BaseDisplayItem {
match *self {
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,
DisplayItem::Line(ref line) => &line.base,
DisplayItem::BoxShadow(ref box_shadow) => &box_shadow.base,
DisplayItem::PushTextShadow(ref push_text_shadow) => &push_text_shadow.base,
DisplayItem::PopTextShadow(ref pop_text_shadow) => &pop_text_shadow.base,
DisplayItem::Iframe(ref iframe) => &iframe.base,
@@ -1371,17 +1361,16 @@ impl fmt::Debug for DisplayItem {
solid_color.color.b,
solid_color.color.a),
DisplayItem::Text(ref text) => {
format!("Text ({:?})",
&text.text_run.text[
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(),
DisplayItem::Line(_) => "Line".to_owned(),
DisplayItem::BoxShadow(_) => "BoxShadow".to_owned(),
DisplayItem::PushTextShadow(_) => "PushTextShadow".to_owned(),
DisplayItem::PopTextShadow(_) => "PopTextShadow".to_owned(),
DisplayItem::Iframe(_) => "Iframe".to_owned(),
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -7,33 +7,33 @@
//! Other browser engines sometimes call this "painting", but it is more accurately called display
//! list building, as the actual painting does not happen here—only deciding *what* we're going to
//! paint.
#![deny(unsafe_code)]
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};
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection};
use gfx::display_list::{GradientDisplayItem, IframeDisplayItem, ImageBorder, ImageDisplayItem};
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;
use list_item::ListItemFlow;
use model::{self, MaybeAuto};
use msg::constellation_msg::BrowsingContextId;
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::UsePlaceholder;
@@ -1973,56 +1973,53 @@ impl FragmentDisplayListBuilding for Fra
image_rendering: self.style.get_inheritedbox().image_rendering.clone(),
}));
}
}
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
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(
&stacking_relative_content_box,
build_local_clip(&self.style),
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);
}
SpecificFragmentInfo::UnscannedText(_) => {
panic!("Shouldn't see unscanned fragments here.")
}
SpecificFragmentInfo::TableColumn(_) => {
panic!("Shouldn't see table column fragments here.")
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -3,17 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! The `Fragment` type, which represents the leaves of the layout tree.
#![deny(unsafe_code)]
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;
use flow::{self, ImmutableFlowUtils};
use flow_ref::FlowRef;
use gfx;
use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode};
use gfx::text::glyph::ByteIndex;
@@ -25,17 +25,17 @@ use ipc_channel::ipc::IpcSender;
#[cfg(debug_assertions)]
use layout_debug;
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, SizeConstraint};
use model::{style_length, ToGfxMatrix};
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};
use servo_url::ServoUrl;
use std::{f32, fmt};
use std::borrow::ToOwned;
use std::cmp::{Ordering, max, min};
use std::collections::LinkedList;
@@ -48,16 +48,17 @@ use style::logical_geometry::{Direction,
use style::properties::ComputedValues;
use style::selector_parser::RestyleDamage;
use style::servo::restyle_damage::RECONSTRUCT_FLOW;
use style::str::char_is_whitespace;
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.
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
static FONT_SUPERSCRIPT_OFFSET_RATIO: f32 = 0.34;
// https://drafts.csswg.org/css-images/#default-object-size
static DEFAULT_REPLACED_WIDTH: i32 = 300;
@@ -317,27 +318,41 @@ impl InlineAbsoluteFragmentInfo {
pub fn new(flow_ref: FlowRef) -> InlineAbsoluteFragmentInfo {
InlineAbsoluteFragmentInfo {
flow_ref: flow_ref,
}
}
}
#[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),
}
}
}
#[derive(Clone)]
pub struct SvgFragmentInfo {
--- a/servo/components/layout/webrender_helpers.rs
+++ b/servo/components/layout/webrender_helpers.rs
@@ -300,21 +300,16 @@ impl WebRenderDisplayItemConverter for D
Some(item.base.local_clip),
item.stretch_size.to_sizef(),
item.tile_spacing.to_sizef(),
item.image_rendering.to_image_rendering(),
id);
}
}
}
- 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();
let details = match item.details {
BorderDetails::Normal(ref border) => {
let left = webrender_api::BorderSide {
color: border.color.left,
--- a/servo/components/script/dom/bindings/trace.rs
+++ b/servo/components/script/dom/bindings/trace.rs
@@ -25,18 +25,21 @@
//! will add the object to the graph, and will trace that object as well.
//! 5. When the GC finishes tracing, it [`finalizes`](../index.html#destruction)
//! any reflectors that were not reachable.
//!
//! The `unsafe_no_jsmanaged_fields!()` macro adds an empty implementation of
//! `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;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::js::{JS, Root};
use dom::bindings::refcounted::{Trusted, TrustedPromise};
use dom::bindings::reflector::{DomObject, Reflector};
use dom::bindings::str::{DOMString, USVString};
@@ -100,18 +103,17 @@ use style::properties::PropertyDeclarati
use style::selector_parser::{PseudoElement, Snapshot};
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
use style::stylesheets::{CssRules, FontFaceRule, KeyframesRule, MediaRule};
use style::stylesheets::{NamespaceRule, StyleRule, ImportRule, SupportsRule, ViewportRule};
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.
pub unsafe trait JSTraceable {
/// Trace `self`.
unsafe fn trace(&self, trc: *mut JSTracer);
}
@@ -386,18 +388,23 @@ unsafe_no_jsmanaged_fields!(ResourceThre
unsafe_no_jsmanaged_fields!(StatusCode);
unsafe_no_jsmanaged_fields!(SystemTime);
unsafe_no_jsmanaged_fields!(Instant);
unsafe_no_jsmanaged_fields!(RelativePos);
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);
unsafe_no_jsmanaged_fields!(WebGLTextureId);
unsafe_no_jsmanaged_fields!(WebGLVertexArrayId);
unsafe_no_jsmanaged_fields!(MediaList);
unsafe_no_jsmanaged_fields!(WebVRGamepadHand);
unsafe_no_jsmanaged_fields!(ScriptToConstellationChan);
@@ -461,16 +468,30 @@ unsafe impl<T: Send> JSTraceable for Rec
unsafe impl<T: Send> JSTraceable for Sender<T> {
#[inline]
unsafe fn trace(&self, _: *mut JSTracer) {
// Do nothing
}
}
+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) {
// Do nothing
}
}
unsafe impl JSTraceable for Transform3D<f64> {
--- a/servo/components/script/dom/canvasgradient.rs
+++ b/servo/components/script/dom/canvasgradient.rs
@@ -1,13 +1,13 @@
/* 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::{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;
use dom::bindings::codegen::Bindings::CanvasGradientBinding;
use dom::bindings::codegen::Bindings::CanvasGradientBinding::CanvasGradientMethods;
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::js::Root;
use dom::bindings::num::Finite;
--- a/servo/components/script/dom/canvaspattern.rs
+++ b/servo/components/script/dom/canvaspattern.rs
@@ -1,13 +1,13 @@
/* 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::{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};
use dom::canvasgradient::ToFillOrStrokeStyle;
use dom::globalscope::GlobalScope;
use dom_struct::dom_struct;
use euclid::Size2D;
--- a/servo/components/script/dom/canvasrenderingcontext2d.rs
+++ b/servo/components/script/dom/canvasrenderingcontext2d.rs
@@ -1,16 +1,16 @@
/* 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::{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;
use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasFillRule;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasImageSource;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineCap;
@@ -158,30 +158,26 @@ impl CanvasRenderingContext2D {
let boxed = box CanvasRenderingContext2D::new_inherited(global, Some(canvas), image_cache, base_url, size);
reflect_dom_object(boxed, global, CanvasRenderingContext2DBinding::Wrap)
}
// https://html.spec.whatwg.org/multipage/#concept-canvas-set-bitmap-dimensions
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();
}
// https://html.spec.whatwg.org/multipage/#reset-the-rendering-context-to-its-default-state
fn reset_to_initial_state(&self) {
self.saved_states.borrow_mut().clear();
*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);
}
}
fn update_transform(&self) {
self.ipc_renderer
@@ -1387,17 +1383,17 @@ impl CanvasRenderingContext2DMethods for
.send(CanvasMsg::Canvas2d(Canvas2dMsg::SetShadowColor(color)))
.unwrap()
}
}
}
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)
}
}
}
pub fn parse_color(string: &str) -> Result<RGBA, ()> {
let mut input = ParserInput::new(string);
let mut parser = Parser::new(&mut input);
--- a/servo/components/script/dom/htmlcanvaselement.rs
+++ b/servo/components/script/dom/htmlcanvaselement.rs
@@ -1,14 +1,14 @@
/* 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 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;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes;
use dom::bindings::codegen::UnionTypes::CanvasRenderingContext2DOrWebGLRenderingContext;
use dom::bindings::conversions::ConversionResult;
@@ -25,21 +25,21 @@ use dom::htmlelement::HTMLElement;
use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
use dom_struct::dom_struct;
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};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
@@ -101,31 +101,32 @@ pub trait LayoutHTMLCanvasElementHelpers
fn get_height(&self) -> LengthOrPercentageOrAuto;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
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()),
}
}
}
#[allow(unsafe_code)]
fn get_width(&self) -> LengthOrPercentageOrAuto {
@@ -145,25 +146,16 @@ impl LayoutHTMLCanvasElementHelpers for
.map(AttrValue::as_uint_px_dimension)
.unwrap_or(LengthOrPercentageOrAuto::Auto)
}
}
}
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);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(window.upcast::<GlobalScope>(), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_ref(&*context)));
}
@@ -216,32 +208,36 @@ impl HTMLCanvasElement {
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
let size = self.get_size();
if size.width == 0 || size.height == 0 {
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))
}
}
impl HTMLCanvasElementMethods for HTMLCanvasElement {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
--- a/servo/components/script/dom/paintrenderingcontext2d.rs
+++ b/servo/components/script/dom/paintrenderingcontext2d.rs
@@ -1,15 +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 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;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods;
use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding;
use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding::PaintRenderingContext2DMethods;
use dom::bindings::codegen::UnionTypes::HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue;
use dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern;
@@ -53,19 +53,19 @@ impl PaintRenderingContext2D {
}
pub fn new(global: &PaintWorkletGlobalScope) -> Root<PaintRenderingContext2D> {
reflect_dom_object(box PaintRenderingContext2D::new_inherited(global),
global,
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> {
self.context.take_missing_image_urls()
}
pub fn set_bitmap_dimensions(&self,
size: TypedSize2D<f32, CSSPixel>,
--- a/servo/components/script/dom/paintworkletglobalscope.rs
+++ b/servo/components/script/dom/paintworkletglobalscope.rs
@@ -1,13 +1,12 @@
/* 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::CanvasData;
use dom::bindings::callback::CallbackContainer;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::PaintWorkletGlobalScopeBinding;
use dom::bindings::codegen::Bindings::PaintWorkletGlobalScopeBinding::PaintWorkletGlobalScopeMethods;
use dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
use dom::bindings::conversions::get_property;
use dom::bindings::conversions::get_property_jsval;
use dom::bindings::error::Error;
@@ -293,17 +292,17 @@ impl PaintWorkletGlobalScope {
debug!("Paint function threw an exception {}.", name);
unsafe { JS_ClearPendingException(cx); }
return self.invalid_image(size_in_dpx, missing_image_urls);
}
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,
};
DrawAPaintImageResult {
width: size_in_dpx.width,
height: size_in_dpx.height,
format: PixelFormat::BGRA8,
image_key: image_key,
--- a/servo/components/script/dom/vrdisplay.rs
+++ b/servo/components/script/dom/vrdisplay.rs
@@ -1,13 +1,13 @@
/* 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::CanvasMsg;
+use canvas_traits::webgl::{webgl_channel, WebGLReceiver, WebVRCommand};
use core::ops::Deref;
use dom::bindings::callback::ExceptionHandling;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceBinding::PerformanceMethods;
use dom::bindings::codegen::Bindings::VRDisplayBinding;
use dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
use dom::bindings::codegen::Bindings::VRDisplayBinding::VREye;
use dom::bindings::codegen::Bindings::VRLayerBinding::VRLayer;
@@ -27,28 +27,26 @@ use dom::promise::Promise;
use dom::vrdisplaycapabilities::VRDisplayCapabilities;
use dom::vrdisplayevent::VRDisplayEvent;
use dom::vreyeparameters::VREyeParameters;
use dom::vrframedata::VRFrameData;
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;
use script_thread::Runnable;
use std::cell::Cell;
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]
pub struct VRDisplay {
eventtarget: EventTarget,
#[ignore_heap_size_of = "Defined in rust-webvr"]
display: DOMRefCell<WebVRDisplayData>,
depth_near: Cell<f64>,
@@ -66,17 +64,17 @@ pub struct VRDisplay {
#[ignore_heap_size_of = "Defined in rust-webvr"]
next_raf_id: Cell<u32>,
/// List of request animation frame callbacks
#[ignore_heap_size_of = "closures are hard"]
raf_callback_list: DOMRefCell<Vec<(u32, Option<Rc<FrameRequestCallback>>)>>,
// 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>,
}
unsafe_no_jsmanaged_fields!(WebVRDisplayData);
unsafe_no_jsmanaged_fields!(WebVRFrameData);
unsafe_no_jsmanaged_fields!(WebVRLayer);
@@ -381,21 +379,20 @@ impl VRDisplayMethods for VRDisplay {
// https://w3c.github.io/webvr/#dom-vrdisplay-submitframe
fn SubmitFrame(&self) {
if !self.presenting.get() {
warn!("VRDisplay not presenting");
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
fn GetLayers(&self) -> Vec<VRLayer> {
// WebVR spec: MUST return an empty array if the VRDisplay is not currently presenting
if !self.presenting.get() {
return Vec::new();
}
@@ -484,21 +481,21 @@ impl VRDisplay {
fn notify_event(&self, event: &WebVRDisplayEvent) {
let root = Root::from_ref(&*self);
let event = VRDisplayEvent::new_from_webvr(&self.global(), &root, &event);
event.upcast::<Event>().fire(self.global().upcast::<EventTarget>());
}
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();
let far_init = self.depth_far.get();
// The render loop at native headset frame rate is implemented using a dedicated thread.
// Every loop iteration syncs pose data with the HMD, submits the pixels to the display and waits for Vsync.
// Both the requestAnimationFrame call of a VRDisplay in the JavaScript thread and the VRSyncPoses call
@@ -506,28 +503,28 @@ impl VRDisplay {
// while the render thread is syncing the VRFrameData to be used for the current frame.
// This thread runs until the user calls ExitPresent, the tab is closed or some unexpected error happened.
thread::Builder::new().name("WebVR_RAF".into()).spawn(move || {
let (raf_sender, raf_receiver) = mpsc::channel();
let mut near = near_init;
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 {
address: address.clone(),
sender: raf_sender.clone()
};
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() {
near = depth.0;
far = depth.1;
} else {
// Stop thread
// ExitPresent called or some error happened
@@ -536,20 +533,19 @@ impl VRDisplay {
}
}).expect("Thread spawning failed");
}
fn stop_present(&self) {
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.
// In this case we don't want to wait for WebVR Thread response.
fn force_stop_present(&self) {
self.webvr_thread().send(WebVRMsg::ExitPresent(self.global().pipeline_id(),
self.display.borrow().display_id,
None))
@@ -622,17 +618,17 @@ impl Runnable for NotifyDisplayRAF {
fn handler(self: Box<Self>) {
let display = self.address.root();
display.handle_raf(&self.sender);
}
}
-// 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 {
Some(ref values) => {
if values.len() == 0 {
return Ok(())
}
if values.len() != 4 {
--- a/servo/components/script/dom/webgl_extensions/ext/oesvertexarrayobject.rs
+++ b/servo/components/script/dom/webgl_extensions/ext/oesvertexarrayobject.rs
@@ -1,26 +1,25 @@
/* 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::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};
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::webglrenderingcontext::WebGLRenderingContext;
use dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
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 {
reflector_: Reflector,
ctx: JS<WebGLRenderingContext>,
bound_vao: MutNullableJS<WebGLVertexArrayObjectOES>,
}
@@ -43,49 +42,49 @@ impl OESVertexArrayObject {
}
rval.get()
}
}
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))
}
// https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
fn DeleteVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
if let Some(vao) = vao {
if vao.is_deleted() {
return;
}
// Unbind deleted VAO if currently bound
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));
}
}
// Remove VAO references from buffers
let buffers = vao.bound_attrib_buffers();
for buffer in buffers {
buffer.remove_vao_reference(vao.id());
}
if let Some(buffer) = vao.bound_buffer_element_array() {
buffer.remove_vao_reference(vao.id());
}
// 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();
}
}
// https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
fn IsVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool {
// Conformance tests expect false if vao never bound
vao.map_or(false, |vao| !vao.is_deleted() && vao.ever_bound())
@@ -109,27 +108,27 @@ impl OESVertexArrayObjectMethods for OES
}
if let Some(vao) = vao {
if vao.is_deleted() {
self.ctx.webgl_error(WebGLError::InvalidOperation);
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));
// Restore WebGLRenderingContext current bindings
let buffers = vao.borrow_bound_attrib_buffers();
self.ctx.set_bound_attrib_buffers(buffers.iter().map(|(k, v)| (*k, &**v)));
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());
}
}
}
impl WebGLExtension for OESVertexArrayObject {
type Extension = OESVertexArrayObject;
--- a/servo/components/script/dom/webgl_extensions/ext/webglvertexarrayobjectoes.rs
+++ b/servo/components/script/dom/webgl_extensions/ext/webglvertexarrayobjectoes.rs
@@ -1,26 +1,26 @@
/* 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::WebGLVertexArrayId;
use core::cell::Ref;
use core::iter::FromIterator;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::WebGLVertexArrayObjectOESBinding;
use dom::bindings::js::{JS, MutNullableJS};
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::globalscope::GlobalScope;
use dom::webglbuffer::WebGLBuffer;
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 {
webgl_object_: WebGLObject,
id: WebGLVertexArrayId,
ever_bound: Cell<bool>,
is_deleted: Cell<bool>,
bound_attrib_buffers: DOMRefCell<HashMap<u32, JS<WebGLBuffer>>>,
--- a/servo/components/script/dom/webgl_extensions/extensions.rs
+++ b/servo/components/script/dom/webgl_extensions/extensions.rs
@@ -1,12 +1,13 @@
/* 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::WebGLError;
use core::iter::FromIterator;
use core::nonzero::NonZero;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::js::Root;
use dom::bindings::trace::JSTraceable;
use dom::webglrenderingcontext::WebGLRenderingContext;
@@ -14,17 +15,16 @@ use gleam::gl::GLenum;
use heapsize::HeapSizeOf;
use js::jsapi::{JSContext, JSObject};
use js::jsval::JSVal;
use ref_filter_map::ref_filter_map;
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.
// Example: https://www.khronos.org/registry/webgl/extensions/OES_texture_float/
const DEFAULT_DISABLED_TEX_TYPES: [GLenum; 2] = [
constants::FLOAT, OESTextureHalfFloatConstants::HALF_FLOAT_OES
];
--- a/servo/components/script/dom/webgl_validations/tex_image_2d.rs
+++ b/servo/components/script/dom/webgl_validations/tex_image_2d.rs
@@ -1,19 +1,19 @@
/* 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::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)]
pub enum TexImageValidationError {
/// An invalid texture target was passed, it contains the invalid target.
InvalidTextureTarget(u32),
/// The passed texture target was not bound.
TextureTargetNotBound(u32),
--- a/servo/components/script/dom/webglbuffer.rs
+++ b/servo/components/script/dom/webglbuffer.rs
@@ -1,69 +1,68 @@
/* 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/. */
// 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;
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 {
webgl_object: WebGLObject,
id: WebGLBufferId,
/// The target to which this buffer was bound the first time
target: Cell<Option<u32>>,
capacity: Cell<usize>,
is_deleted: Cell<bool>,
// The Vertex Array Objects that are referencing this buffer
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 {
webgl_object: WebGLObject::new_inherited(),
id: id,
target: Cell::new(None),
capacity: Cell::new(0),
is_deleted: Cell::new(false),
vao_references: DOMRefCell::new(None),
pending_delete: Cell::new(false),
renderer: renderer,
}
}
- 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),
window, WebGLBufferBinding::Wrap)
}
}
@@ -76,44 +75,42 @@ impl WebGLBuffer {
pub fn bind(&self, target: u32) -> WebGLResult<()> {
if let Some(previous_target) = self.target.get() {
if target != previous_target {
return Err(WebGLError::InvalidOperation);
}
} 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(())
}
pub fn buffer_data(&self, target: u32, data: &[u8], usage: u32) -> WebGLResult<()> {
if let Some(previous_target) = self.target.get() {
if target != previous_target {
return Err(WebGLError::InvalidOperation);
}
}
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(())
}
pub fn capacity(&self) -> usize {
self.capacity.get()
}
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));
}
}
pub fn is_deleted(&self) -> bool {
self.is_deleted.get()
}
pub fn target(&self) -> Option<u32> {
@@ -139,17 +136,17 @@ impl WebGLBuffer {
map.insert(id);
*vao_refs = Some(map);
}
pub fn remove_vao_reference(&self, id: WebGLVertexArrayId) {
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);
}
}
}
}
impl Drop for WebGLBuffer {
fn drop(&mut self) {
--- a/servo/components/script/dom/webglframebuffer.rs
+++ b/servo/components/script/dom/webglframebuffer.rs
@@ -1,28 +1,27 @@
/* 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/. */
// 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;
use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::reflect_dom_object;
use dom::webglobject::WebGLObject;
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)]
enum WebGLFramebufferAttachment {
Renderbuffer(JS<WebGLRenderbuffer>),
Texture { texture: JS<WebGLTexture>, level: i32 },
}
@@ -31,28 +30,28 @@ pub struct WebGLFramebuffer {
webgl_object: WebGLObject,
id: WebGLFramebufferId,
/// target can only be gl::FRAMEBUFFER at the moment
target: Cell<Option<u32>>,
is_deleted: Cell<bool>,
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.
color: DOMRefCell<Option<WebGLFramebufferAttachment>>,
depth: DOMRefCell<Option<WebGLFramebufferAttachment>>,
stencil: DOMRefCell<Option<WebGLFramebufferAttachment>>,
depthstencil: DOMRefCell<Option<WebGLFramebufferAttachment>>,
}
impl WebGLFramebuffer {
- fn new_inherited(renderer: IpcSender<CanvasMsg>,
+ fn new_inherited(renderer: WebGLMsgSender,
id: WebGLFramebufferId)
-> WebGLFramebuffer {
WebGLFramebuffer {
webgl_object: WebGLObject::new_inherited(),
id: id,
target: Cell::new(None),
is_deleted: Cell::new(false),
renderer: renderer,
@@ -60,27 +59,27 @@ impl WebGLFramebuffer {
status: Cell::new(constants::FRAMEBUFFER_UNSUPPORTED),
color: DOMRefCell::new(None),
depth: DOMRefCell::new(None),
stencil: DOMRefCell::new(None),
depthstencil: DOMRefCell::new(None),
}
}
- 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),
window,
WebGLFramebufferBinding::Wrap)
}
}
@@ -93,23 +92,23 @@ impl WebGLFramebuffer {
pub fn bind(&self, target: u32) {
// Update the framebuffer status on binding. It may have
// changed if its attachments were resized or deleted while
// we've been unbound.
self.update_status();
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));
}
}
pub fn is_deleted(&self) -> bool {
self.is_deleted.get()
}
pub fn size(&self) -> Option<(i32, i32)> {
@@ -200,20 +199,20 @@ impl WebGLFramebuffer {
}
_ => {
*binding.borrow_mut() = None;
None
}
};
- 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(())
}
pub fn texture2d(&self, attachment: u32, textarget: u32, texture: Option<&WebGLTexture>,
level: i32) -> WebGLResult<()> {
let binding = match attachment {
@@ -276,21 +275,21 @@ impl WebGLFramebuffer {
}
_ => {
*binding.borrow_mut() = None;
None
}
};
- 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(())
}
fn with_matching_renderbuffers<F>(&self, rb: &WebGLRenderbuffer, mut closure: F)
where F: FnMut(&DOMRefCell<Option<WebGLFramebufferAttachment>>)
{
--- a/servo/components/script/dom/webglprogram.rs
+++ b/servo/components/script/dom/webglprogram.rs
@@ -1,70 +1,68 @@
/* 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/. */
// 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};
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::webglactiveinfo::WebGLActiveInfo;
use dom::webglobject::WebGLObject;
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 {
webgl_object: WebGLObject,
id: WebGLProgramId,
is_deleted: Cell<bool>,
link_called: Cell<bool>,
linked: Cell<bool>,
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 {
webgl_object: WebGLObject::new_inherited(),
id: id,
is_deleted: Cell::new(false),
link_called: Cell::new(false),
linked: Cell::new(false),
fragment_shader: Default::default(),
vertex_shader: Default::default(),
renderer: renderer,
}
}
- 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),
window,
WebGLProgramBinding::Wrap)
}
}
@@ -73,17 +71,17 @@ impl WebGLProgram {
pub fn id(&self) -> WebGLProgramId {
self.id
}
/// glDeleteProgram
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();
}
if let Some(shader) = self.vertex_shader.get() {
shader.decrement_attached_counter();
}
@@ -112,39 +110,39 @@ impl WebGLProgram {
}
match self.vertex_shader.get() {
Some(ref shader) if shader.successfully_compiled() => {},
_ => return Ok(()), // callers use gl.LINK_STATUS to check link errors
}
self.linked.set(true);
- self.renderer.send(CanvasMsg::WebGL(WebGLCommand::LinkProgram(self.id))).unwrap();
+ self.renderer.send(WebGLCommand::LinkProgram(self.id)).unwrap();
Ok(())
}
/// glUseProgram
pub fn use_program(&self) -> WebGLResult<()> {
if self.is_deleted() {
return Err(WebGLError::InvalidOperation);
}
if !self.linked.get() {
return Err(WebGLError::InvalidOperation);
}
- self.renderer.send(CanvasMsg::WebGL(WebGLCommand::UseProgram(self.id))).unwrap();
+ self.renderer.send(WebGLCommand::UseProgram(self.id)).unwrap();
Ok(())
}
/// glValidateProgram
pub fn validate(&self) -> WebGLResult<()> {
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(())
}
/// glAttachShader
pub fn attach_shader(&self, shader: &WebGLShader) -> WebGLResult<()> {
if self.is_deleted() || shader.is_deleted() {
return Err(WebGLError::InvalidOperation);
}
@@ -161,17 +159,17 @@ impl WebGLProgram {
// shader.
if shader_slot.get().is_some() {
return Err(WebGLError::InvalidOperation);
}
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(())
}
/// glDetachShader
pub fn detach_shader(&self, shader: &WebGLShader) -> WebGLResult<()> {
if self.is_deleted() {
return Err(WebGLError::InvalidOperation);
@@ -191,17 +189,17 @@ impl WebGLProgram {
None =>
return Err(WebGLError::InvalidOperation),
_ => {}
}
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(())
}
/// glBindAttribLocation
pub fn bind_attrib_location(&self, index: u32, name: DOMString) -> WebGLResult<()> {
if self.is_deleted() {
return Err(WebGLError::InvalidOperation);
@@ -211,42 +209,42 @@ impl WebGLProgram {
}
// Check if the name is reserved
if name.starts_with("gl_") || name.starts_with("webgl") || name.starts_with("_webgl_") {
return Err(WebGLError::InvalidOperation);
}
self.renderer
- .send(CanvasMsg::WebGL(WebGLCommand::BindAttribLocation(self.id, index, String::from(name))))
+ .send(WebGLCommand::BindAttribLocation(self.id, index, String::from(name)))
.unwrap();
Ok(())
}
pub fn get_active_uniform(&self, index: u32) -> WebGLResult<Root<WebGLActiveInfo>> {
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)|
WebGLActiveInfo::new(self.global().as_window(), size, ty, DOMString::from(name)))
}
/// glGetActiveAttrib
pub fn get_active_attrib(&self, index: u32) -> WebGLResult<Root<WebGLActiveInfo>> {
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)|
WebGLActiveInfo::new(self.global().as_window(), size, ty, DOMString::from(name)))
}
/// glGetAttribLocation
pub fn get_attrib_location(&self, name: DOMString) -> WebGLResult<Option<i32>> {
@@ -261,19 +259,19 @@ impl WebGLProgram {
if name.starts_with("gl_") {
return Err(WebGLError::InvalidOperation);
}
if name.starts_with("webgl") || name.starts_with("_webgl_") {
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())
}
/// glGetUniformLocation
pub fn get_uniform_location(&self, name: DOMString) -> WebGLResult<Option<i32>> {
if !self.is_linked() || self.is_deleted() {
return Err(WebGLError::InvalidOperation);
@@ -282,19 +280,19 @@ impl WebGLProgram {
return Err(WebGLError::InvalidValue);
}
// Check if the name is reserved
if name.starts_with("webgl") || name.starts_with("_webgl_") {
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())
}
/// glGetProgramInfoLog
pub fn get_info_log(&self) -> WebGLResult<String> {
if self.is_deleted() {
return Err(WebGLError::InvalidOperation);
@@ -303,25 +301,25 @@ impl WebGLProgram {
let shaders_compiled = match (self.fragment_shader.get(), self.vertex_shader.get()) {
(Some(fs), Some(vs)) => fs.successfully_compiled() && vs.successfully_compiled(),
_ => false
};
if !shaders_compiled {
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()
}
}
impl Drop for WebGLProgram {
fn drop(&mut self) {
self.delete();
}
--- a/servo/components/script/dom/webglrenderbuffer.rs
+++ b/servo/components/script/dom/webglrenderbuffer.rs
@@ -1,64 +1,61 @@
/* 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/. */
// 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;
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 {
webgl_object: WebGLObject,
id: WebGLRenderbufferId,
ever_bound: Cell<bool>,
is_deleted: Cell<bool>,
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 {
webgl_object: WebGLObject::new_inherited(),
id: id,
ever_bound: Cell::new(false),
is_deleted: Cell::new(false),
renderer: renderer,
internal_format: Cell::new(None),
size: Cell::new(None),
}
}
- 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),
window,
WebGLRenderbufferBinding::Wrap)
}
}
@@ -69,24 +66,24 @@ impl WebGLRenderbuffer {
}
pub fn size(&self) -> Option<(i32, i32)> {
self.size.get()
}
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));
}
}
pub fn is_deleted(&self) -> bool {
self.is_deleted.get()
}
pub fn ever_bound(&self) -> bool {
@@ -105,17 +102,16 @@ impl WebGLRenderbuffer {
_ => return Err(WebGLError::InvalidEnum),
};
// FIXME: Check that w/h are < MAX_RENDERBUFFER_SIZE
// 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)));
Ok(())
}
}
--- a/servo/components/script/dom/webglrenderingcontext.rs
+++ b/servo/components/script/dom/webglrenderingcontext.rs
@@ -1,30 +1,33 @@
/* 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 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;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes};
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods;
use dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
use dom::bindings::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::inheritance::Castable;
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};
use dom::webgl_extensions::WebGLExtensions;
use dom::webgl_validations::WebGLValidator;
use dom::webgl_validations::tex_image_2d::{CommonTexImage2DValidator, CommonTexImage2DValidatorResult};
use dom::webgl_validations::tex_image_2d::{TexImage2DValidator, TexImage2DValidatorResult};
use dom::webgl_validations::types::{TexDataType, TexFormat, TexImageTarget};
@@ -37,31 +40,28 @@ use dom::webglrenderbuffer::WebGLRenderb
use dom::webglshader::WebGLShader;
use dom::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
use dom::webgltexture::{TexParameterValue, WebGLTexture};
use dom::webgluniformlocation::WebGLUniformLocation;
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};
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;
macro_rules! handle_potential_webgl_error {
($context:ident, $call:expr, $return_on_error:expr) => {
match $call {
Ok(ret) => ret,
@@ -87,19 +87,17 @@ macro_rules! handle_potential_webgl_erro
macro_rules! handle_object_deletion {
($self_:expr, $binding:expr, $object:ident, $unbind_command:expr) => {
if let Some(bound_object) = $binding.get() {
if bound_object.id() == $object.id() {
$binding.set(None);
}
if let Some(command) = $unbind_command {
- $self_.ipc_renderer
- .send(CanvasMsg::WebGL(command))
- .unwrap();
+ $self_.send_command(command);
}
}
};
}
macro_rules! object_binding_to_js_or_null {
($cx: expr, $binding:expr) => {
{
@@ -130,22 +128,25 @@ bitflags! {
const PREMULTIPLY_ALPHA = 0x02,
const CONVERT_COLORSPACE = 0x04,
}
}
#[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>,
bound_framebuffer: MutNullableJS<WebGLFramebuffer>,
bound_renderbuffer: MutNullableJS<WebGLRenderbuffer>,
bound_texture_2d: MutNullableJS<WebGLTexture>,
bound_texture_cube_map: MutNullableJS<WebGLTexture>,
bound_buffer_array: MutNullableJS<WebGLBuffer>,
@@ -153,40 +154,42 @@ pub struct WebGLRenderingContext {
bound_attrib_buffers: DOMRefCell<HashMap<u32, JS<WebGLBuffer>>>,
current_program: MutNullableJS<WebGLProgram>,
#[ignore_heap_size_of = "Because it's small"]
current_vertex_attrib_0: Cell<(f32, f32, f32, f32)>,
#[ignore_heap_size_of = "Because it's small"]
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 {
fn new_inherited(window: &Window,
canvas: &HTMLCanvasElement,
size: Size2D<i32>,
attrs: GLContextAttributes)
-> Result<WebGLRenderingContext, String> {
if let Some(true) = PREFS.get("webgl.testing.context_creation_error").as_boolean() {
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),
texture_unpacking_alignment: Cell::new(4),
bound_framebuffer: MutNullableJS::new(None),
bound_texture_2d: MutNullableJS::new(None),
bound_texture_cube_map: MutNullableJS::new(None),
bound_buffer_array: MutNullableJS::new(None),
@@ -248,41 +251,53 @@ impl WebGLRenderingContext {
self.bound_buffer_element_array.get()
}
pub fn set_bound_buffer_element_array(&self, buffer: Option<&WebGLBuffer>) {
self.bound_buffer_element_array.set(buffer);
}
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 {
&self.extension_manager
}
pub fn webgl_error(&self, err: WebGLError) {
// TODO(emilio): Add useful debug messages to this
@@ -365,19 +380,17 @@ impl WebGLRenderingContext {
if indx > self.limits.max_vertex_attribs {
return self.webgl_error(InvalidValue);
}
if indx == 0 {
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)> {
match self.bound_framebuffer.get() {
Some(fb) => return fb.size(),
// The window system framebuffer is bound
None => return Some((self.DrawingBufferWidth(),
@@ -700,18 +713,18 @@ impl WebGLRenderingContext {
(data, size, false)
},
// TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D,
// but we need to refactor it moving it to `HTMLCanvasElement` and support
// WebGLContext (probably via GetPixels()).
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLCanvasElement(canvas) => {
if let Some((mut data, size)) = canvas.fetch_all_data() {
+ // Pixels got from Canvas have already alpha premultiplied
byte_swap(&mut data);
- // Pixels got from Canvas have already alpha premultiplied
(data, size, true)
} else {
return Err(());
}
},
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLVideoElement(_rooted_video)
=> unimplemented!(),
};
@@ -940,35 +953,31 @@ impl WebGLRenderingContext {
level,
Some(data_type)));
// Set the unpack alignment. For textures coming from arrays,
// this will be the current value of the context's
// 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();
let internal_format = self.extension_manager.get_effective_tex_internal_format(format, data_type);
// TODO(emilio): convert colorspace if requested
let msg = WebGLCommand::TexImage2D(target.as_gl_constant(), level as i32,
internal_format as i32,
width as i32, height as i32,
format,
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);
}
}
fn tex_sub_image_2d(&self,
texture: Root<WebGLTexture>,
@@ -1000,57 +1009,74 @@ impl WebGLRenderingContext {
return self.webgl_error(InvalidOperation);
}
// Set the unpack alignment. For textures coming from arrays,
// this will be the current value of the context's
// 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(),
level as i32, xoffset, yoffset,
width as i32, height as i32,
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
fn validate_feature_enum(&self, cap: u32) -> bool {
match cap {
constants::BLEND | constants::CULL_FACE | constants::DEPTH_TEST | constants::DITHER |
constants::POLYGON_OFFSET_FILL | constants::SAMPLE_ALPHA_TO_COVERAGE | constants::SAMPLE_COVERAGE |
constants::SAMPLE_COVERAGE_INVERT | constants::SCISSOR_TEST | constants::STENCIL_TEST => true,
_ => {
self.webgl_error(InvalidEnum);
false
},
}
}
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();
}
}
// FIXME: After [1] lands and the relevant Servo and codegen PR too, we should
// convert all our raw JSObject pointers to proper types.
//
// [1]: https://github.com/servo/rust-mozjs/pull/304
#[allow(unsafe_code)]
@@ -1096,55 +1122,46 @@ unsafe fn fallible_array_buffer_view_to_
impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1
fn Canvas(&self) -> Root<HTMLCanvasElement> {
Root::from_ref(&*self.canvas)
}
// 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"),
WebGLParameter::Float(_) => panic!("Buffer parameter should not be float"),
WebGLParameter::FloatArray(_) => panic!("Buffer parameter should not be float array"),
WebGLParameter::String(_) => panic!("Buffer parameter should not be string"),
WebGLParameter::Invalid => NullValue(),
}
@@ -1200,20 +1217,19 @@ impl WebGLRenderingContextMethods for We
},
Err(error) => {
self.webgl_error(error);
return NullValue();
}
}
}
- 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),
WebGLParameter::Float(val) => DoubleValue(val as f64),
WebGLParameter::FloatArray(_) => panic!("Parameter should not be float array"),
WebGLParameter::String(val) => {
rooted!(in(cx) let mut rval = UndefinedValue());
val.to_jsval(cx, rval.handle_mut());
@@ -1238,23 +1254,23 @@ impl WebGLRenderingContextMethods for We
constants::NO_ERROR
};
self.last_error.set(None);
error_code
}
// 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 {
alpha: attrs.alpha,
antialias: attrs.antialias,
depth: attrs.depth,
failIfMajorPerformanceCaveat: false,
preferLowPowerToHighPerformance: false,
@@ -1280,79 +1296,74 @@ impl WebGLRenderingContextMethods for We
self.extension_manager.init_once(|| {
self.get_gl_extensions()
});
self.extension_manager.get_or_init_extension(&name, self)
}
// 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
fn BlendEquation(&self, mode: u32) {
if mode != constants::FUNC_ADD {
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
fn BlendEquationSeparate(&self, mode_rgb: u32, mode_alpha: u32) {
if mode_rgb != constants::FUNC_ADD || mode_alpha != constants::FUNC_ADD {
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
fn BlendFunc(&self, src_factor: u32, dest_factor: u32) {
// From the WebGL 1.0 spec, 6.13: Viewport Depth Range:
//
// A call to blendFunc will generate an INVALID_OPERATION error if one of the two
// factors is set to CONSTANT_COLOR or ONE_MINUS_CONSTANT_COLOR and the other to
// CONSTANT_ALPHA or ONE_MINUS_CONSTANT_ALPHA.
if has_invalid_blend_constants(src_factor, dest_factor) {
return self.webgl_error(InvalidOperation);
}
if has_invalid_blend_constants(dest_factor, src_factor) {
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
fn BlendFuncSeparate(&self, src_rgb: u32, dest_rgb: u32, src_alpha: u32, dest_alpha: u32) {
// From the WebGL 1.0 spec, 6.13: Viewport Depth Range:
//
// A call to blendFuncSeparate will generate an INVALID_OPERATION error if srcRGB is
// set to CONSTANT_COLOR or ONE_MINUS_CONSTANT_COLOR and dstRGB is set to
// CONSTANT_ALPHA or ONE_MINUS_CONSTANT_ALPHA or vice versa.
if has_invalid_blend_constants(src_rgb, dest_rgb) {
return self.webgl_error(InvalidOperation);
}
if has_invalid_blend_constants(dest_rgb, src_rgb) {
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
fn AttachShader(&self, program: Option<&WebGLProgram>, shader: Option<&WebGLShader>) {
if let Some(program) = program {
if let Some(shader) = shader {
handle_potential_webgl_error!(self, program.attach_shader(shader));
}
@@ -1388,19 +1399,17 @@ impl WebGLRenderingContextMethods for We
if let Some(buffer) = buffer {
match buffer.bind(target) {
Ok(_) => slot.set(Some(buffer)),
Err(e) => return self.webgl_error(e),
}
} 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));
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6
fn BindFramebuffer(&self, target: u32, framebuffer: Option<&WebGLFramebuffer>) {
if target != constants::FRAMEBUFFER {
return self.webgl_error(InvalidOperation);
}
@@ -1415,17 +1424,17 @@ impl WebGLRenderingContextMethods for We
return self.webgl_error(InvalidOperation);
} else {
framebuffer.bind(target);
self.bound_framebuffer.set(Some(framebuffer));
}
} 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);
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7
fn BindRenderbuffer(&self, target: u32, renderbuffer: Option<&WebGLRenderbuffer>) {
if target != constants::RENDERBUFFER {
return self.webgl_error(InvalidEnum);
@@ -1437,19 +1446,17 @@ impl WebGLRenderingContextMethods for We
// returns. The conformance tests don't cover this case.
Some(renderbuffer) if !renderbuffer.is_deleted() => {
self.bound_renderbuffer.set(Some(renderbuffer));
renderbuffer.bind(target);
}
_ => {
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));
}
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn BindTexture(&self, target: u32, texture: Option<&WebGLTexture>) {
let slot = match target {
constants::TEXTURE_2D => &self.bound_texture_2d,
@@ -1460,19 +1467,17 @@ impl WebGLRenderingContextMethods for We
if let Some(texture) = texture {
match texture.bind(target) {
Ok(_) => slot.set(Some(texture)),
Err(err) => return self.webgl_error(err),
}
} 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));
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn GenerateMipmap(&self, target: u32) {
let slot = match target {
constants::TEXTURE_2D => &self.bound_texture_2d,
constants::TEXTURE_CUBE_MAP => &self.bound_texture_cube_map,
@@ -1580,19 +1585,17 @@ impl WebGLRenderingContextMethods for We
if offset < 0 {
return Ok(self.webgl_error(InvalidValue));
}
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(())
}
#[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
unsafe fn CompressedTexImage2D(&self, cx: *mut JSContext, _target: u32, _level: i32, _internal_format: u32,
_width: i32, _height: i32, _border: i32, pixels: *mut JSObject) -> Fallible<()> {
@@ -1665,17 +1668,17 @@ impl WebGLRenderingContextMethods for We
let msg = WebGLCommand::CopyTexImage2D(target.as_gl_constant(),
level as i32,
internal_format.as_gl_constant(),
x, y,
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
fn CopyTexSubImage2D(&self, target: u32, level: i32, xoffset: i32, yoffset: i32,
x: i32, y: i32, width: i32, height: i32) {
if !self.validate_framebuffer_complete() {
return;
}
@@ -1709,178 +1712,156 @@ impl WebGLRenderingContextMethods for We
return;
}
let msg = WebGLCommand::CopyTexSubImage2D(target.as_gl_constant(),
level as i32, xoffset, yoffset,
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
fn Clear(&self, mask: u32) {
if !self.validate_framebuffer_complete() {
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),
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
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),
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn DepthFunc(&self, func: u32) {
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::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
fn DepthRange(&self, near: f32, far: f32) {
// From the WebGL 1.0 spec, 6.12: Viewport Depth Range:
//
// "A call to depthRange will generate an
// INVALID_OPERATION error if zNear is greater than
// zFar."
if near > far {
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));
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn CompileShader(&self, shader: Option<&WebGLShader>) {
if let Some(shader) = shader {
shader.compile()
}
}
// TODO(emilio): Probably in the future we should keep track of the
// 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
fn CreateShader(&self, shader_type: u32) -> Option<Root<WebGLShader>> {
match shader_type {
constants::VERTEX_SHADER | constants::FRAGMENT_SHADER => {},
_ => {
self.webgl_error(InvalidEnum);
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
fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
if let Some(buffer) = buffer {
if buffer.is_attached_to_vao() {
// WebGL spec: The buffers attached to VAOs should still not be deleted.
// They are deleted after the VAO is deleted.
@@ -1994,19 +1975,17 @@ impl WebGLRenderingContextMethods for We
if first < 0 || count < 0 {
return self.webgl_error(InvalidValue);
}
if !self.validate_framebuffer_complete() {
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),
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11
fn DrawElements(&self, mode: u32, count: i32, type_: u32, offset: i64) {
@@ -2060,45 +2039,39 @@ impl WebGLRenderingContextMethods for We
return;
}
match mode {
constants::POINTS | constants::LINE_STRIP |
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),
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn EnableVertexAttribArray(&self, attrib_id: u32) {
if attrib_id > self.limits.max_vertex_attribs {
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
fn DisableVertexAttribArray(&self, attrib_id: u32) {
if attrib_id > self.limits.max_vertex_attribs {
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
fn GetActiveUniform(&self, program: Option<&WebGLProgram>, index: u32) -> Option<Root<WebGLActiveInfo>> {
let program = match program {
Some(program) => program,
None => {
// Reasons to generate InvalidValue error
@@ -2218,21 +2191,21 @@ impl WebGLRenderingContextMethods for We
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetShaderPrecisionFormat(&self,
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))
},
Err(error) => {
self.webgl_error(error);
None
}
@@ -2263,18 +2236,18 @@ impl WebGLRenderingContextMethods for We
if pname == constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING {
rooted!(in(cx) let mut jsval = NullValue());
if let Some(buffer) = self.bound_attrib_buffers.borrow().get(&index) {
buffer.to_jsval(cx, jsval.handle_mut());
}
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),
WebGLParameter::Bool(val) => BooleanValue(val),
WebGLParameter::String(_) => panic!("Vertex attrib should not be string"),
WebGLParameter::Float(_) => panic!("Vertex attrib should not be float"),
WebGLParameter::FloatArray(val) => {
rooted!(in(cx) let mut result = UndefinedValue());
@@ -2282,18 +2255,18 @@ impl WebGLRenderingContextMethods for We
result.get()
}
WebGLParameter::Invalid => NullValue(),
}
}
// 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
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn Hint(&self, target: u32, mode: u32) {
if target != constants::GENERATE_MIPMAP_HINT {
return self.webgl_error(InvalidEnum);
@@ -2302,34 +2275,30 @@ impl WebGLRenderingContextMethods for We
match mode {
constants::FASTEST |
constants::NICEST |
constants::DONT_CARE => (),
_ => 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
fn IsBuffer(&self, buffer: Option<&WebGLBuffer>) -> bool {
buffer.map_or(false, |buf| buf.target().is_some() && !buf.is_deleted())
}
// TODO: We could write this without IPC, recording the calls to `enable` and `disable`.
// 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();
}
false
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6
fn IsFramebuffer(&self, frame_buffer: Option<&WebGLFramebuffer>) -> bool {
@@ -2357,19 +2326,17 @@ impl WebGLRenderingContextMethods for We
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn LineWidth(&self, width: f32) {
if width.is_nan() || width <= 0f32 {
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
// readback to render to the page.
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn PixelStorei(&self, param_name: u32, param_value: i32) {
let mut texture_settings = self.texture_unpacking_settings.get();
match param_name {
@@ -2415,19 +2382,17 @@ impl WebGLRenderingContextMethods for We
return;
},
_ => return self.webgl_error(InvalidEnum),
}
}
// 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)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.12
unsafe fn ReadPixels(&self, cx: *mut JSContext, x: i32, y: i32, width: i32, height: i32,
format: u32, pixel_type: u32, pixels: *mut JSObject) -> Fallible<()> {
if pixels.is_null() {
return Ok(self.webgl_error(InvalidValue));
@@ -2517,121 +2482,105 @@ impl WebGLRenderingContextMethods for We
}
if y + height > fb_height {
height = fb_height - y;
}
}
_ => 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();
for i in 0..height {
for j in 0..(width * cpp) {
data[(dst_offset + i * stride + j) as usize] =
result[(i * width * cpp + j) as usize];
}
}
Ok(())
}
// 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
fn Scissor(&self, x: i32, y: i32, width: i32, height: i32) {
if width < 0 || height < 0 {
return self.webgl_error(InvalidValue)
}
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
fn StencilFunc(&self, func: u32, ref_: i32, mask: u32) {
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),
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn StencilFuncSeparate(&self, face: u32, func: u32, ref_: i32, mask: u32) {
match face {
constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => (),
_ => return self.webgl_error(InvalidEnum),
}
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),
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
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)
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn StencilOpSeparate(&self, face: u32, fail: u32, zfail: u32, zpass: u32) {
match face {
constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => (),
_ => return self.webgl_error(InvalidEnum),
}
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)
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn LinkProgram(&self, program: Option<&WebGLProgram>) {
if let Some(program) = program {
@@ -2653,261 +2602,229 @@ impl WebGLRenderingContextMethods for We
shader.and_then(|s| s.source())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform1f(&self,
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))
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform1i(&self,
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))
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn Uniform1iv(&self,
cx: *mut JSContext,
uniform: Option<&WebGLUniformLocation>,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn Uniform1fv(&self,
cx: *mut JSContext,
uniform: Option<&WebGLUniformLocation>,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform2f(&self,
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));
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn Uniform2fv(&self,
cx: *mut JSContext,
uniform: Option<&WebGLUniformLocation>,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
let data_vec = typed_array_or_sequence_to_vec::<Float32>(cx, data, ())?;
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform2i(&self,
uniform: Option<&WebGLUniformLocation>,
x: i32, y: i32) {
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));
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn Uniform2iv(&self,
cx: *mut JSContext,
uniform: Option<&WebGLUniformLocation>,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
let data_vec = typed_array_or_sequence_to_vec::<Int32>(cx, data, ConversionBehavior::Default)?;
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform3f(&self,
uniform: Option<&WebGLUniformLocation>,
x: f32, y: f32, z: f32) {
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));
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn Uniform3fv(&self,
cx: *mut JSContext,
uniform: Option<&WebGLUniformLocation>,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
let data_vec = typed_array_or_sequence_to_vec::<Float32>(cx, data, ())?;
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform3i(&self,
uniform: Option<&WebGLUniformLocation>,
x: i32, y: i32, z: i32) {
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))
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn Uniform3iv(&self,
cx: *mut JSContext,
uniform: Option<&WebGLUniformLocation>,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
let data_vec = typed_array_or_sequence_to_vec::<Int32>(cx, data, ConversionBehavior::Default)?;
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform4i(&self,
uniform: Option<&WebGLUniformLocation>,
x: i32, y: i32, z: i32, w: i32) {
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))
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn Uniform4iv(&self,
cx: *mut JSContext,
uniform: Option<&WebGLUniformLocation>,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
let data_vec = typed_array_or_sequence_to_vec::<Int32>(cx, data, ConversionBehavior::Default)?;
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform4f(&self,
uniform: Option<&WebGLUniformLocation>,
x: f32, y: f32, z: f32, w: f32) {
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))
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn Uniform4fv(&self,
cx: *mut JSContext,
uniform: Option<&WebGLUniformLocation>,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
let data_vec = typed_array_or_sequence_to_vec::<Float32>(cx, data, ())?;
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn UniformMatrix2fv(&self,
@@ -2915,19 +2832,17 @@ impl WebGLRenderingContextMethods for We
uniform: Option<&WebGLUniformLocation>,
transpose: bool,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
let data_vec = typed_array_or_sequence_to_vec::<Float32>(cx, data, ())?;
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn UniformMatrix3fv(&self,
@@ -2935,19 +2850,17 @@ impl WebGLRenderingContextMethods for We
uniform: Option<&WebGLUniformLocation>,
transpose: bool,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
let data_vec = typed_array_or_sequence_to_vec::<Float32>(cx, data, ())?;
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
#[allow(unsafe_code)]
unsafe fn UniformMatrix4fv(&self,
@@ -2955,19 +2868,17 @@ impl WebGLRenderingContextMethods for We
uniform: Option<&WebGLUniformLocation>,
transpose: bool,
data: *mut JSObject) -> Fallible<()> {
assert!(!data.is_null());
let data_vec = typed_array_or_sequence_to_vec::<Float32>(cx, data, ())?;
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(())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn UseProgram(&self, program: Option<&WebGLProgram>) {
if let Some(program) = program {
@@ -3093,30 +3004,27 @@ impl WebGLRenderingContextMethods for We
}
},
_ => return self.webgl_error(InvalidEnum),
}
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
fn Viewport(&self, x: i32, y: i32, width: i32, height: i32) {
if width < 0 || height < 0 {
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
#[allow(unsafe_code)]
unsafe fn TexImage2D(&self,
cx: *mut JSContext,
target: u32,
level: i32,
@@ -3451,23 +3359,23 @@ impl WebGLRenderingContextMethods for We
Some(fb) => handle_potential_webgl_error!(self, fb.texture2d(attachment, textarget, texture, level)),
None => self.webgl_error(InvalidOperation),
};
}
}
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())
}
}
#[derive(Debug, PartialEq)]
pub enum UniformSetterType {
Int,
IntVec2,
IntVec3,
--- a/servo/components/script/dom/webglshader.rs
+++ b/servo/components/script/dom/webglshader.rs
@@ -1,28 +1,25 @@
/* 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/. */
// 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;
use dom::bindings::reflector::reflect_dom_object;
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 {
NotCompiled,
Succeeded,
Failed,
}
@@ -32,29 +29,29 @@ pub struct WebGLShader {
id: WebGLShaderId,
gl_type: u32,
source: DOMRefCell<Option<DOMString>>,
info_log: DOMRefCell<Option<String>>,
is_deleted: Cell<bool>,
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"))]
const SHADER_OUTPUT_FORMAT: Output = Output::Glsl;
#[cfg(target_os = "android")]
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 {
GLSLANG_INITIALIZATION.call_once(|| ::angle::hl::initialize().unwrap());
WebGLShader {
webgl_object: WebGLObject::new_inherited(),
id: id,
gl_type: shader_type,
@@ -63,28 +60,28 @@ impl WebGLShader {
is_deleted: Cell::new(false),
attached_counter: Cell::new(0),
compilation_status: Cell::new(ShaderCompilationStatus::NotCompiled),
renderer: renderer,
}
}
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> {
reflect_dom_object(box WebGLShader::new_inherited(renderer, id, shader_type),
window,
WebGLShaderBinding::Wrap)
}
}
@@ -113,17 +110,17 @@ impl WebGLShader {
¶ms).unwrap();
match validator.compile_and_translate(&[source]) {
Ok(translated_source) => {
debug!("Shader translated: {}", translated_source);
// NOTE: At this point we should be pretty sure that the compilation in the paint thread
// 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) => {
self.compilation_status.set(ShaderCompilationStatus::Failed);
debug!("Shader {} compilation failed: {}", self.id, error);
},
}
@@ -137,17 +134,17 @@ impl WebGLShader {
}
/// Mark this shader as deleted (if it wasn't previously)
/// and delete it as if calling glDeleteShader.
/// Currently does not check if shader is attached
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));
}
}
pub fn is_deleted(&self) -> bool {
self.is_deleted.get()
}
pub fn is_attached(&self) -> bool {
@@ -165,18 +162,18 @@ impl WebGLShader {
/// glGetShaderInfoLog
pub fn info_log(&self) -> Option<String> {
self.info_log.borrow().clone()
}
/// 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()
}
/// Get the shader source
pub fn source(&self) -> Option<DOMString> {
self.source.borrow().clone()
}
--- a/servo/components/script/dom/webgltexture.rs
+++ b/servo/components/script/dom/webgltexture.rs
@@ -1,28 +1,26 @@
/* 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/. */
// 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;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
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),
Int(i32),
}
const MAX_LEVEL_COUNT: usize = 31;
const MAX_FACE_COUNT: usize = 6;
@@ -41,48 +39,48 @@ pub struct WebGLTexture {
image_info_array: DOMRefCell<[ImageInfo; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>,
/// Face count can only be 1 or 6
face_count: Cell<u8>,
base_mipmap_level: u32,
// Store information for min and mag filters
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 {
webgl_object: WebGLObject::new_inherited(),
id: id,
target: Cell::new(None),
is_deleted: Cell::new(false),
face_count: Cell::new(0),
base_mipmap_level: 0,
min_filter: Cell::new(None),
mag_filter: Cell::new(None),
image_info_array: DOMRefCell::new([ImageInfo::new(); MAX_LEVEL_COUNT * MAX_FACE_COUNT]),
renderer: renderer,
}
}
- 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),
window,
WebGLTextureBinding::Wrap)
}
}
@@ -108,17 +106,17 @@ impl WebGLTexture {
constants::TEXTURE_2D => 1,
constants::TEXTURE_CUBE_MAP => 6,
_ => return Err(WebGLError::InvalidOperation)
};
self.face_count.set(face_count);
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(())
}
pub fn initialize(&self,
target: TexImageTarget,
width: u32,
@@ -163,30 +161,30 @@ impl WebGLTexture {
if !base_image_info.is_power_of_two() {
return Err(WebGLError::InvalidOperation);
}
if base_image_info.is_compressed_format() {
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);
}
let last_level = self.base_mipmap_level + base_image_info.get_max_mimap_levels() - 1;
self.populate_mip_chain(self.base_mipmap_level, last_level)
}
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));
}
}
pub fn is_deleted(&self) -> bool {
self.is_deleted.get()
}
pub fn target(&self) -> Option<u32> {
@@ -211,46 +209,46 @@ impl WebGLTexture {
constants::NEAREST |
constants::LINEAR |
constants::NEAREST_MIPMAP_NEAREST |
constants::LINEAR_MIPMAP_NEAREST |
constants::NEAREST_MIPMAP_LINEAR |
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(())
},
_ => Err(WebGLError::InvalidEnum),
}
},
constants::TEXTURE_MAG_FILTER => {
match int_value as u32 {
constants::NEAREST |
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(())
},
_ => Err(WebGLError::InvalidEnum),
}
},
constants::TEXTURE_WRAP_S |
constants::TEXTURE_WRAP_T => {
match int_value as u32 {
constants::CLAMP_TO_EDGE |
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(())
},
_ => Err(WebGLError::InvalidEnum),
}
},
--- a/servo/components/script/dom/webgluniformlocation.rs
+++ b/servo/components/script/dom/webgluniformlocation.rs
@@ -1,19 +1,19 @@
/* 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/. */
// 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 {
reflector_: Reflector,
id: i32,
program_id: WebGLProgramId,
}
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -1,15 +1,16 @@
/* 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 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;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventHandlerBinding::OnBeforeUnloadEventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
@@ -259,17 +260,21 @@ pub struct Window {
/// All the MediaQueryLists we need to update
media_query_lists: WeakMediaQueryListVec,
test_runner: MutNullableJS<TestRunner>,
/// 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>>,
/// All of the elements that have an outstanding image request that was
/// initiated by layout during a reflow. They are stored in the script thread
/// to ensure that the element can be marked dirty when the image data becomes
/// available at some point in the future.
@@ -375,18 +380,22 @@ impl Window {
pub fn set_scroll_offsets(&self, offsets: HashMap<UntrustedNodeAddress, Vector2D<f32>>) {
*self.scroll_offsets.borrow_mut() = offsets
}
pub fn current_viewport(&self) -> Rect<Au> {
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> {
debug!("Creating new paint worklet.");
Worklet::new(self, WorkletGlobalScopeType::Paint)
}
pub fn permission_state_invocation_results(&self) -> &DOMRefCell<HashMap<String, PermissionState>> {
@@ -1795,17 +1804,18 @@ impl Window {
timer_event_chan: IpcSender<TimerEvent>,
layout_chan: Sender<Msg>,
id: PipelineId,
parent_info: Option<(PipelineId, FrameType)>,
window_size: Option<WindowSizeData>,
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();
layout_chan.send(Msg::GetRPC(rpc_send)).unwrap();
rpc_recv.recv().unwrap()
};
let error_reporter = CSSErrorReporter {
pipelineid: id,
@@ -1861,17 +1871,18 @@ impl Window {
devtools_marker_sender: DOMRefCell::new(None),
devtools_markers: DOMRefCell::new(HashSet::new()),
webdriver_script_chan: DOMRefCell::new(None),
ignore_further_async_events: Default::default(),
error_reporter: error_reporter,
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),
test_worklet: Default::default(),
paint_worklet: Default::default(),
};
unsafe {
--- a/servo/components/script/script_thread.rs
+++ b/servo/components/script/script_thread.rs
@@ -13,16 +13,17 @@
//! noting when they pertain to ongoing loads (such as resizes/viewport adjustments). When the
//! initial response is received for an ongoing load, the second phase starts - the frame tree
//! entry is created, along with the Window and Document objects, and the appropriate parser
//! takes over the response body. Once parsing is complete, the document lifecycle for loading
//! a page runs its course and the script thread returns to processing events in the main event
//! loop.
use bluetooth_traits::BluetoothRequest;
+use canvas_traits::webgl::WebGLPipeline;
use devtools;
use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo};
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use devtools_traits::CSSError;
use document_loader::DocumentLoader;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
@@ -503,18 +504,21 @@ pub struct ScriptThread {
microtask_queue: MicrotaskQueue,
/// Microtask Queue for adding support for mutation observer microtasks
mutation_observer_compound_microtask_queued: Cell<bool>,
/// 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>>>,
/// A list of pipelines containing documents that finished loading all their blocking
/// resources during a turn of the event loop.
docs_with_no_blocking_loads: DOMRefCell<HashSet<JS<Document>>>,
@@ -876,17 +880,18 @@ impl ScriptThread {
microtask_queue: MicrotaskQueue::default(),
mutation_observer_compound_microtask_queued: Default::default(),
mutation_observers: Default::default(),
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(),
docs_with_no_blocking_loads: Default::default(),
transitioning_nodes: Default::default(),
custom_element_reaction_stack: CustomElementReactionStack::new(),
@@ -2023,17 +2028,18 @@ impl ScriptThread {
ipc_timer_event_chan,
incomplete.layout_chan,
incomplete.pipeline_id,
incomplete.parent_info,
incomplete.window_size,
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,
incomplete.browsing_context_id,
incomplete.top_level_browsing_context_id,
incomplete.parent_info);
window.init_window_proxy(&window_proxy);
--- a/servo/components/script_layout_interface/lib.rs
+++ b/servo/components/script_layout_interface/lib.rs
@@ -38,17 +38,17 @@ extern crate style;
extern crate webrender_api;
pub mod message;
pub mod reporter;
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;
use net_traits::image_cache::PendingImageId;
use script_traits::UntrustedNodeAddress;
use servo_url::ServoUrl;
use std::sync::atomic::AtomicIsize;
use style::data::ElementData;
@@ -119,18 +119,23 @@ pub enum LayoutElementType {
HTMLTableColElement,
HTMLTableElement,
HTMLTableRowElement,
HTMLTableSectionElement,
HTMLTextAreaElement,
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,
}
pub struct SVGSVGData {
pub width: u32,
pub height: u32,
}
--- a/servo/components/script_traits/Cargo.toml
+++ b/servo/components/script_traits/Cargo.toml
@@ -20,17 +20,16 @@ heapsize = "0.4"
heapsize_derive = "0.1"
hyper = "0.10"
hyper_serde = "0.7"
ipc-channel = "0.8"
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"
servo_atoms = {path = "../atoms"}
servo_url = {path = "../url"}
style_traits = {path = "../style_traits", features = ["servo"]}
time = "0.1.12"
url = {version = "1.2", features = ["heap_size"]}
--- a/servo/components/script_traits/lib.rs
+++ b/servo/components/script_traits/lib.rs
@@ -19,31 +19,31 @@ extern crate heapsize;
#[macro_use]
extern crate heapsize_derive;
extern crate hyper;
extern crate hyper_serde;
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;
extern crate servo_atoms;
extern crate servo_url;
extern crate style_traits;
extern crate time;
extern crate webrender_api;
extern crate webvr_traits;
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;
use heapsize::HeapSizeOf;
use hyper::header::Headers;
use hyper::method::Method;
use ipc_channel::{Error as IpcError};
use ipc_channel::ipc::{IpcReceiver, IpcSender};
@@ -519,18 +519,20 @@ pub struct InitialScriptState {
/// A channel to the developer tools, if applicable.
pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// Information about the initial window size.
pub window_size: Option<WindowSizeData>,
/// The ID of the pipeline namespace for this script thread.
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`
/// crate.
pub trait ScriptThreadFactory {
/// Type of message sent from script to layout.
type Message;
/// Create a `ScriptThread`.
@@ -754,18 +756,16 @@ pub enum ConstellationMsg {
/// Requests that the constellation instruct layout to begin a new tick of the animation.
TickAnimation(PipelineId, AnimationTickType),
/// Dispatch a webdriver command
WebDriverCommand(WebDriverCommandMsg),
/// Reload a top-level browsing context.
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.
NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>),
/// Make browser visible.
SelectBrowser(TopLevelBrowsingContextId),
}
--- a/servo/components/script_traits/script_msg.rs
+++ b/servo/components/script_traits/script_msg.rs
@@ -7,26 +7,25 @@ use CompositorEvent;
use DocumentState;
use IFrameLoadInfo;
use IFrameLoadInfoWithData;
use LayoutControlMsg;
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;
use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, TraversalDirection};
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;
use style_traits::cursor::Cursor;
use style_traits::viewport::ViewportConstraints;
use webrender_api::ClipId;
/// Messages from the layout to the constellation.
@@ -73,21 +72,16 @@ pub enum ScriptMsg {
/// Broadcast a storage event to every same-origin pipeline.
/// The strings are key, old value and new value.
BroadcastStorageEvent(StorageType, ServoUrl, Option<String>, Option<String>, Option<String>),
/// Indicates whether this pipeline is currently running animations.
ChangeRunningAnimationsState(AnimationState),
/// 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.
ForwardEvent(PipelineId, CompositorEvent),
/// Requests that the constellation retrieve the current contents of the clipboard
GetClipboardContents(IpcSender<String>),
/// Get the browsing context id for a given pipeline.
GetBrowsingContextId(PipelineId, IpcSender<Option<BrowsingContextId>>),
--- a/servo/components/servo/lib.rs
+++ b/servo/components/servo/lib.rs
@@ -63,16 +63,18 @@ fn webdriver(port: u16, constellation: S
webdriver_server::start_server(port, constellation);
}
#[cfg(not(feature = "webdriver"))]
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;
use compositing::windowing::WindowMethods;
use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent};
use constellation::{FromCompositorLogger, FromScriptLogger};
#[cfg(not(target_os = "windows"))]
use constellation::content_process_sandbox_profile;
@@ -144,17 +146,17 @@ impl<Window> Servo<Window> where Window:
});
let devtools_chan = opts.devtools_port.map(|port| {
devtools::start_server(port)
});
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 {
Some(device_pixels_per_px) => device_pixels_per_px,
None => match opts.output_file {
Some(_) => 1.0,
None => scale_factor,
}
@@ -206,17 +208,17 @@ impl<Window> Servo<Window> where Window:
let (constellation_chan, sw_senders) = create_constellation(opts.user_agent.clone(),
opts.config_dir.clone(),
compositor_proxy.clone_compositor_proxy(),
time_profiler_chan.clone(),
mem_profiler_chan.clone(),
debugger_chan,
devtools_chan,
supports_clipboard,
- &webrender,
+ &mut webrender,
webrender_document,
webrender_api_sender);
// Send the constellation's swmanager sender to service worker manager thread
script::init_service_workers(sw_senders);
if cfg!(feature = "webdriver") {
if let Some(port) = opts.webdriver_port {
@@ -283,59 +285,80 @@ fn create_compositor_channel(event_loop_
fn create_constellation(user_agent: Cow<'static, str>,
config_dir: Option<PathBuf>,
compositor_proxy: CompositorProxy,
time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan,
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) {
let bluetooth_thread: IpcSender<BluetoothRequest> = BluetoothThreadFactory::new();
let (public_resource_threads, private_resource_threads) =
new_resource_threads(user_agent,
devtools_chan.clone(),
time_profiler_chan.clone(),
config_dir);
let font_cache_thread = FontCacheThread::new(public_resource_threads.sender(),
Some(webrender_api_sender.create_api()));
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,
devtools_chan,
bluetooth_thread,
font_cache_thread,
public_resource_threads,
private_resource_threads,
time_profiler_chan,
mem_profiler_chan,
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
let sw_senders = SWManagerSenders {
swmanager_sender: from_swmanager_sender,
resource_sender: resource_sender
};
--- a/servo/components/webvr/Cargo.toml
+++ b/servo/components/webvr/Cargo.toml
@@ -5,15 +5,16 @@ authors = ["The Servo Project Developers
license = "MPL-2.0"
publish = false
[lib]
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"]}
--- a/servo/components/webvr/lib.rs
+++ b/servo/components/webvr/lib.rs
@@ -1,17 +1,18 @@
/* 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/. */
#![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;
pub use webvr_thread::{WebVRThread, WebVRCompositorHandler};
--- a/servo/components/webvr/webvr_thread.rs
+++ b/servo/components/webvr/webvr_thread.rs
@@ -1,23 +1,23 @@
/* 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;
+use euclid::Size2D;
use ipc_channel::ipc;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use msg::constellation_msg::PipelineId;
use script_traits::ConstellationMsg;
use servo_config::prefs::PREFS;
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::*;
/// WebVRThread owns native VRDisplays, handles their life cycle inside Servo and
/// acts a doorman for untrusted VR requests from DOM Objects. These are the key components
/// * WebVRThread::spawn() creates a long living thread that waits for VR Commands from DOM objects
/// and handles them in its trusted thread. The back and forth comunication with DOM is implemented
/// using IPC-channels. This thread creates the VRServiceManager instance, which handles the life cycle
@@ -29,17 +29,17 @@ use webvr_traits::webvr::*;
/// is only created when there is at least one live JavaScript context using the WebVR APIs and shuts down it when
/// the tab is closed. A single instance of the thread is used to handle multiple JavaScript contexts.
/// Constellation channel is used to notify events to the Script Thread.
/// * When the WeVR APIs are used in a tab, it's pipeline_id is registered using the RegisterContext message. When
/// the tab is closed, UnregisterContext message is sent. This way the WebVR thread has a list of the pipeline
/// 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>,
service: VRServiceManager,
contexts: HashSet<PipelineId>,
constellation_chan: Sender<ConstellationMsg>,
vr_compositor_chan: WebVRCompositorSender,
polling_events: bool,
@@ -61,25 +61,27 @@ impl WebVRThread {
contexts: HashSet::new(),
constellation_chan: constellation_chan,
vr_compositor_chan: vr_compositor_chan,
polling_events: false,
presenting: HashMap::new()
}
}
- 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) {
while let Ok(msg) = self.receiver.recv() {
match msg {
WebVRMsg::RegisterContext(context) => {
self.handle_register_context(context);
self.schedule_poll_events();
@@ -300,17 +302,17 @@ impl WebVRThread {
/// VRDisplays pointers are guaranteed to be valid memory:
/// * VRDisplays are owned by the VRServiceManager which lives in the WebVRThread.
/// * WebVRCompositorHandler is stopped automatically when a JS tab is closed or the whole browser is closed.
/// * WebVRThread and its VRDisplays are destroyed after all tabs are dropped and the browser is about to exit.
/// WebVRThread is closed using the Exit message.
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>>
}
#[allow(unsafe_code)]
unsafe impl Send for WebVRCompositor {}
pub type WebVRCompositorSender = Sender<Option<WebVRCompositor>>;
@@ -323,59 +325,59 @@ impl WebVRCompositorHandler {
webvr_thread_receiver: receiver,
webvr_thread_sender: None
});
(instance, sender)
}
}
-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();
(*compositor.0).synced_frame_data(near, far).to_bytes()
};
let _ = sender.send(Ok(pose));
} else {
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 {
texture_id: texture_id,
left_bounds: left_bounds,
right_bounds: right_bounds,
texture_size: Some((size.width as u32, size.height as u32))
};
unsafe {
(*compositor.0).submit_frame(&layer);
}
}
}
}
- webrender_api::VRCompositorCommand::Release(compositor_id) => {
+ webgl::WebVRCommand::Release(compositor_id) => {
self.compositors.remove(&compositor_id);
}
}
}
}
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,
};
sender.send(WebVRMsg::CreateCompositor(display_id as u32)).unwrap();
let display = self.webvr_thread_receiver.recv().unwrap();