diff options
75 files changed, 2871 insertions, 890 deletions
diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index 96f7a3c0777..34451e67931 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -33,6 +33,9 @@ git = "https://github.com/ecoal95/rust-offscreen-rendering-context" [dependencies.ipc-channel] git = "https://github.com/servo/ipc-channel" +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + [dependencies] log = "0.3" num = "0.1.24" diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 92b3863cdf9..1bcf294d3b6 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -24,6 +24,7 @@ use std::sync::mpsc::{Sender, channel}; use util::opts; use util::thread::spawn_named; use util::vec::byte_swap; +use webrender_traits; impl<'a> CanvasPaintThread<'a> { /// It reads image data from the canvas @@ -63,6 +64,8 @@ pub struct CanvasPaintThread<'a> { path_builder: PathBuilder, state: CanvasPaintState<'a>, saved_states: Vec<CanvasPaintState<'a>>, + webrender_api: Option<webrender_traits::RenderApi>, + webrender_image_key: Option<webrender_traits::ImageKey>, } #[derive(Clone)] @@ -102,27 +105,34 @@ impl<'a> CanvasPaintState<'a> { } impl<'a> CanvasPaintThread<'a> { - fn new(size: Size2D<i32>) -> CanvasPaintThread<'a> { + fn new(size: Size2D<i32>, + webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> CanvasPaintThread<'a> { let draw_target = CanvasPaintThread::create(size); let path_builder = draw_target.create_path_builder(); + let webrender_api = webrender_api_sender.map(|wr| wr.create_api()); + let webrender_image_key = webrender_api.as_ref().map(|wr| wr.alloc_image()); CanvasPaintThread { drawtarget: draw_target, path_builder: path_builder, state: CanvasPaintState::new(), saved_states: Vec::new(), + webrender_api: webrender_api, + webrender_image_key: webrender_image_key, } } /// Creates a new `CanvasPaintThread` and returns the out-of-process sender and the in-process /// sender for it. - pub fn start(size: Size2D<i32>) -> (IpcSender<CanvasMsg>, Sender<CanvasMsg>) { + pub fn start(size: Size2D<i32>, + webrender_api_sender: Option<webrender_traits::RenderApiSender>) + -> (IpcSender<CanvasMsg>, Sender<CanvasMsg>) { // TODO(pcwalton): Ask the pipeline to create this for us instead of spawning it directly. // This will be needed for multiprocess Servo. let (out_of_process_chan, out_of_process_port) = ipc::channel::<CanvasMsg>().unwrap(); let (in_process_chan, in_process_port) = channel(); ROUTER.route_ipc_receiver_to_mpsc_sender(out_of_process_port, in_process_chan.clone()); spawn_named("CanvasThread".to_owned(), move || { - let mut painter = CanvasPaintThread::new(size); + let mut painter = CanvasPaintThread::new(size, webrender_api_sender); loop { let msg = in_process_port.recv(); match msg.unwrap() { @@ -190,8 +200,8 @@ impl<'a> CanvasPaintThread<'a> { }, CanvasMsg::FromLayout(message) => { match message { - FromLayoutMsg::SendPixelContents(chan) => { - painter.send_pixel_contents(chan) + FromLayoutMsg::SendData(chan) => { + painter.send_data(chan) } } } @@ -519,9 +529,24 @@ impl<'a> CanvasPaintThread<'a> { self.drawtarget = CanvasPaintThread::create(size); } - fn send_pixel_contents(&mut self, chan: IpcSender<IpcSharedMemory>) { + fn send_data(&mut self, chan: IpcSender<CanvasData>) { self.drawtarget.snapshot().get_data_surface().with_data(|element| { - chan.send(IpcSharedMemory::from_bytes(element)).unwrap(); + if let Some(ref webrender_api) = self.webrender_api { + let size = self.drawtarget.get_size(); + let mut bytes = Vec::new(); + bytes.extend_from_slice(element); + webrender_api.update_image(self.webrender_image_key.unwrap(), + size.width as u32, + size.height as u32, + webrender_traits::ImageFormat::RGBA8, + bytes); + } + + let pixel_data = CanvasPixelData { + image_data: IpcSharedMemory::from_bytes(element), + image_key: self.webrender_image_key, + }; + chan.send(CanvasData::Pixels(pixel_data)).unwrap(); }) } diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs index 7377e0385c7..5ee82053005 100644 --- a/components/canvas/lib.rs +++ b/components/canvas/lib.rs @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#![feature(nonzero)] #![feature(plugin)] #![plugin(plugins)] @@ -19,6 +18,7 @@ extern crate log; extern crate num; extern crate offscreen_gl_context; extern crate util; +extern crate webrender_traits; pub mod canvas_paint_thread; mod premultiplytable; diff --git a/components/canvas/webgl_paint_thread.rs b/components/canvas/webgl_paint_thread.rs index 913ef1b33ce..271ba0e2052 100644 --- a/components/canvas/webgl_paint_thread.rs +++ b/components/canvas/webgl_paint_thread.rs @@ -2,9 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::{CanvasCommonMsg, CanvasMsg, CanvasWebGLMsg, FromLayoutMsg, FromPaintMsg}; -use canvas_traits::{WebGLError, WebGLFramebufferBindingRequest, WebGLParameter, WebGLResult}; -use core::nonzero::NonZero; +use canvas_traits::{CanvasCommonMsg, CanvasMsg, CanvasPixelData, CanvasData, CanvasWebGLMsg}; +use canvas_traits::{FromLayoutMsg, FromPaintMsg}; use euclid::size::Size2D; use gleam::gl; use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory}; @@ -15,186 +14,59 @@ use std::borrow::ToOwned; use std::sync::mpsc::{Sender, channel}; use util::thread::spawn_named; use util::vec::byte_swap; +use webrender_traits; + +enum WebGLPaintTaskData { + WebRender(webrender_traits::RenderApi, webrender_traits::WebGLContextId), + Servo(GLContext<NativeGLContext>), +} pub struct WebGLPaintThread { size: Size2D<i32>, - original_context_size: Size2D<i32>, - gl_context: GLContext<NativeGLContext>, + data: WebGLPaintTaskData, } impl WebGLPaintThread { - fn new(size: Size2D<i32>, attrs: GLContextAttributes) -> Result<WebGLPaintThread, &'static str> { - let context = try!(GLContext::new(size, attrs, ColorAttachmentType::Texture, None)); - - // NOTE: As of right now this is always equal to the size parameter, - // but this doesn't have to be true. Firefox after failing with - // the requested size, tries with the nearest powers of two, for example. - let real_size = context.borrow_draw_buffer().unwrap().size(); + fn new(size: Size2D<i32>, + attrs: GLContextAttributes, + webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> Result<WebGLPaintThread, String> { + let data = if let Some(sender) = webrender_api_sender { + let webrender_api = sender.create_api(); + let id = try!(webrender_api.request_webgl_context(&size, attrs)); + WebGLPaintTaskData::WebRender(webrender_api, id) + } else { + let context = try!(GLContext::<NativeGLContext>::new(size, attrs, ColorAttachmentType::Texture, None)); + WebGLPaintTaskData::Servo(context) + }; Ok(WebGLPaintThread { - size: real_size, - original_context_size: real_size, - gl_context: context + size: size, + data: data, }) } - /// In this function the gl commands are called. - /// Those messages that just involve a gl call have the call inlined, - /// processing of messages that require extra work are moved to functions - /// - /// NB: Not gl-related validations (names, lengths, accepted parameters...) are - /// done in the corresponding DOM interfaces pub fn handle_webgl_message(&self, message: CanvasWebGLMsg) { debug!("WebGL message: {:?}", message); - - match message { - CanvasWebGLMsg::GetContextAttributes(sender) => - self.context_attributes(sender), - CanvasWebGLMsg::ActiveTexture(target) => - gl::active_texture(target), - CanvasWebGLMsg::AttachShader(program_id, shader_id) => - gl::attach_shader(program_id, shader_id), - CanvasWebGLMsg::BindAttribLocation(program_id, index, name) => - gl::bind_attrib_location(program_id, index, &name), - CanvasWebGLMsg::BlendColor(r, g, b, a) => - gl::blend_color(r, g, b, a), - CanvasWebGLMsg::BlendEquation(mode) => - gl::blend_equation(mode), - CanvasWebGLMsg::BlendEquationSeparate(mode_rgb, mode_alpha) => - gl::blend_equation_separate(mode_rgb, mode_alpha), - CanvasWebGLMsg::BlendFunc(src, dest) => - gl::blend_func(src, dest), - CanvasWebGLMsg::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha) => - gl::blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha), - CanvasWebGLMsg::BufferData(buffer_type, data, usage) => - gl::buffer_data(buffer_type, &data, usage), - CanvasWebGLMsg::BufferSubData(buffer_type, offset, data) => - gl::buffer_sub_data(buffer_type, offset, &data), - CanvasWebGLMsg::Clear(mask) => - gl::clear(mask), - CanvasWebGLMsg::ClearColor(r, g, b, a) => - gl::clear_color(r, g, b, a), - CanvasWebGLMsg::ClearDepth(depth) => - gl::clear_depth(depth), - CanvasWebGLMsg::ClearStencil(stencil) => - gl::clear_stencil(stencil), - CanvasWebGLMsg::ColorMask(r, g, b, a) => - gl::color_mask(r, g, b, a), - CanvasWebGLMsg::CullFace(mode) => - gl::cull_face(mode), - CanvasWebGLMsg::DepthFunc(func) => - gl::depth_func(func), - CanvasWebGLMsg::DepthMask(flag) => - gl::depth_mask(flag), - CanvasWebGLMsg::DepthRange(near, far) => - gl::depth_range(near, far), - CanvasWebGLMsg::Disable(cap) => - gl::disable(cap), - CanvasWebGLMsg::Enable(cap) => - gl::enable(cap), - CanvasWebGLMsg::FrontFace(mode) => - gl::front_face(mode), - CanvasWebGLMsg::DrawArrays(mode, first, count) => - gl::draw_arrays(mode, first, count), - CanvasWebGLMsg::DrawElements(mode, count, type_, offset) => - gl::draw_elements(mode, count, type_, offset as u32), - CanvasWebGLMsg::Hint(name, val) => - gl::hint(name, val), - CanvasWebGLMsg::LineWidth(width) => - gl::line_width(width), - CanvasWebGLMsg::PixelStorei(name, val) => - gl::pixel_store_i(name, val), - CanvasWebGLMsg::PolygonOffset(factor, units) => - gl::polygon_offset(factor, units), - CanvasWebGLMsg::Scissor(x, y, width, height) => - gl::scissor(x, y, width, height), - CanvasWebGLMsg::EnableVertexAttribArray(attrib_id) => - gl::enable_vertex_attrib_array(attrib_id), - CanvasWebGLMsg::GetAttribLocation(program_id, name, chan) => - self.attrib_location(program_id, name, chan), - CanvasWebGLMsg::GetBufferParameter(target, param_id, chan) => - self.buffer_parameter(target, param_id, chan), - CanvasWebGLMsg::GetParameter(param_id, chan) => - self.parameter(param_id, chan), - CanvasWebGLMsg::GetProgramParameter(program_id, param_id, chan) => - self.program_parameter(program_id, param_id, chan), - CanvasWebGLMsg::GetShaderParameter(shader_id, param_id, chan) => - self.shader_parameter(shader_id, param_id, chan), - CanvasWebGLMsg::GetUniformLocation(program_id, name, chan) => - self.uniform_location(program_id, name, chan), - CanvasWebGLMsg::CompileShader(shader_id, source) => - self.compile_shader(shader_id, source), - CanvasWebGLMsg::CreateBuffer(chan) => - self.create_buffer(chan), - CanvasWebGLMsg::CreateFramebuffer(chan) => - self.create_framebuffer(chan), - CanvasWebGLMsg::CreateRenderbuffer(chan) => - self.create_renderbuffer(chan), - CanvasWebGLMsg::CreateTexture(chan) => - self.create_texture(chan), - CanvasWebGLMsg::CreateProgram(chan) => - self.create_program(chan), - CanvasWebGLMsg::CreateShader(shader_type, chan) => - self.create_shader(shader_type, chan), - CanvasWebGLMsg::DeleteBuffer(id) => - gl::delete_buffers(&[id]), - CanvasWebGLMsg::DeleteFramebuffer(id) => - gl::delete_framebuffers(&[id]), - CanvasWebGLMsg::DeleteRenderbuffer(id) => - gl::delete_renderbuffers(&[id]), - CanvasWebGLMsg::DeleteTexture(id) => - gl::delete_textures(&[id]), - CanvasWebGLMsg::DeleteProgram(id) => - gl::delete_program(id), - CanvasWebGLMsg::DeleteShader(id) => - gl::delete_shader(id), - CanvasWebGLMsg::BindBuffer(target, id) => - gl::bind_buffer(target, id), - CanvasWebGLMsg::BindFramebuffer(target, request) => - self.bind_framebuffer(target, request), - CanvasWebGLMsg::BindRenderbuffer(target, id) => - gl::bind_renderbuffer(target, id), - CanvasWebGLMsg::BindTexture(target, id) => - gl::bind_texture(target, id), - CanvasWebGLMsg::LinkProgram(program_id) => - gl::link_program(program_id), - CanvasWebGLMsg::Uniform1f(uniform_id, x) => - gl::uniform_1f(uniform_id, x), - CanvasWebGLMsg::Uniform4f(uniform_id, x, y, z, w) => - gl::uniform_4f(uniform_id, x, y, z, w), - CanvasWebGLMsg::UseProgram(program_id) => - gl::use_program(program_id), - CanvasWebGLMsg::VertexAttrib(attrib_id, x, y, z, w) => - gl::vertex_attrib_4f(attrib_id, x, y, z, w), - CanvasWebGLMsg::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) => - gl::vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset as u32), - CanvasWebGLMsg::Viewport(x, y, width, height) => - gl::viewport(x, y, width, height), - CanvasWebGLMsg::TexImage2D(target, level, internal, width, height, format, data_type, data) => - gl::tex_image_2d(target, level, internal, width, height, /*border*/0, format, data_type, Some(&data)), - CanvasWebGLMsg::TexParameteri(target, name, value) => - gl::tex_parameter_i(target, name, value), - CanvasWebGLMsg::TexParameterf(target, name, value) => - gl::tex_parameter_f(target, name, value), - CanvasWebGLMsg::DrawingBufferWidth(sender) => - self.send_drawing_buffer_width(sender), - CanvasWebGLMsg::DrawingBufferHeight(sender) => - self.send_drawing_buffer_height(sender), + match self.data { + WebGLPaintTaskData::WebRender(ref api, id) => { + api.send_webgl_command(id, message); + } + WebGLPaintTaskData::Servo(ref ctx) => { + message.apply(ctx); + } } - - // FIXME: Use debug_assertions once tests are run with them - let error = gl::get_error(); - assert!(error == gl::NO_ERROR, "Unexpected WebGL error: 0x{:x} ({})", error, error); } /// Creates a new `WebGLPaintThread` and returns the out-of-process sender and the in-process /// sender for it. - pub fn start(size: Size2D<i32>, attrs: GLContextAttributes) - -> Result<(IpcSender<CanvasMsg>, Sender<CanvasMsg>), &'static str> { + pub fn start(size: Size2D<i32>, + attrs: GLContextAttributes, + webrender_api_sender: Option<webrender_traits::RenderApiSender>) + -> Result<(IpcSender<CanvasMsg>, Sender<CanvasMsg>), String> { let (in_process_chan, in_process_port) = channel(); let (result_chan, result_port) = channel(); spawn_named("WebGLThread".to_owned(), move || { - let mut painter = match WebGLPaintThread::new(size, attrs) { + let mut painter = match WebGLPaintThread::new(size, attrs, webrender_api_sender) { Ok(thread) => { result_chan.send(Ok(())).unwrap(); thread @@ -217,8 +89,8 @@ impl WebGLPaintThread { }, CanvasMsg::FromLayout(message) => { match message { - FromLayoutMsg::SendPixelContents(chan) => - painter.send_pixel_contents(chan), + FromLayoutMsg::SendData(chan) => + painter.send_data(chan), } } CanvasMsg::FromPaint(message) => { @@ -239,319 +111,40 @@ impl WebGLPaintThread { }) } - #[inline] - fn context_attributes(&self, sender: IpcSender<GLContextAttributes>) { - sender.send(*self.gl_context.borrow_attributes()).unwrap() - } - - #[inline] - fn send_drawing_buffer_width(&self, sender: IpcSender<i32>) { - sender.send(self.size.width).unwrap() - } - - #[inline] - fn send_drawing_buffer_height(&self, sender: IpcSender<i32>) { - sender.send(self.size.height).unwrap() - } - - fn create_buffer(&self, chan: IpcSender<Option<NonZero<u32>>>) { - let buffer = gl::gen_buffers(1)[0]; - let buffer = if buffer == 0 { - None - } else { - Some(unsafe { NonZero::new(buffer) }) - }; - chan.send(buffer).unwrap(); - } - - fn create_framebuffer(&self, chan: IpcSender<Option<NonZero<u32>>>) { - let framebuffer = gl::gen_framebuffers(1)[0]; - let framebuffer = if framebuffer == 0 { - None - } else { - Some(unsafe { NonZero::new(framebuffer) }) - }; - chan.send(framebuffer).unwrap(); - } - - fn create_renderbuffer(&self, chan: IpcSender<Option<NonZero<u32>>>) { - let renderbuffer = gl::gen_renderbuffers(1)[0]; - let renderbuffer = if renderbuffer == 0 { - None - } else { - Some(unsafe { NonZero::new(renderbuffer) }) - }; - chan.send(renderbuffer).unwrap(); - } - - fn create_texture(&self, chan: IpcSender<Option<NonZero<u32>>>) { - let texture = gl::gen_framebuffers(1)[0]; - let texture = if texture == 0 { - None - } else { - Some(unsafe { NonZero::new(texture) }) - }; - chan.send(texture).unwrap(); - } - - fn create_program(&self, chan: IpcSender<Option<NonZero<u32>>>) { - let program = gl::create_program(); - let program = if program == 0 { - None - } else { - Some(unsafe { NonZero::new(program) }) - }; - - chan.send(program).unwrap(); - } - - fn create_shader(&self, shader_type: u32, chan: IpcSender<Option<NonZero<u32>>>) { - let shader = gl::create_shader(shader_type); - let shader = if shader == 0 { - None - } else { - Some(unsafe { NonZero::new(shader) }) - }; - chan.send(shader).unwrap(); - } - - #[inline] - fn bind_framebuffer(&self, target: u32, request: WebGLFramebufferBindingRequest) { - let id = match request { - WebGLFramebufferBindingRequest::Explicit(id) => id, - WebGLFramebufferBindingRequest::Default => - self.gl_context.borrow_draw_buffer().unwrap().get_framebuffer(), - }; - - gl::bind_framebuffer(target, id); - } - - #[inline] - fn compile_shader(&self, shader_id: u32, source: String) { - gl::shader_source(shader_id, &[source.as_bytes()]); - gl::compile_shader(shader_id); - } - - fn attrib_location(&self, program_id: u32, name: String, chan: IpcSender<Option<i32>> ) { - let attrib_location = gl::get_attrib_location(program_id, &name); - - let attrib_location = if attrib_location == -1 { - None - } else { - Some(attrib_location) - }; - - chan.send(attrib_location).unwrap(); - } - - fn parameter(&self, - param_id: u32, - chan: IpcSender<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, ecoal95): 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 buffer_parameter(&self, - target: u32, - param_id: u32, - chan: IpcSender<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(&self, - program_id: u32, - param_id: u32, - chan: IpcSender<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, param_id) != 0)), - gl::ATTACHED_SHADERS | - gl::ACTIVE_ATTRIBUTES | - gl::ACTIVE_UNIFORMS => - Ok(WebGLParameter::Int(gl::get_program_iv(program_id, param_id))), - _ => Err(WebGLError::InvalidEnum), - }; - - chan.send(result).unwrap(); - } - - fn shader_parameter(&self, - shader_id: u32, - param_id: u32, - chan: IpcSender<WebGLResult<WebGLParameter>>) { - let result = match param_id { - gl::SHADER_TYPE => - Ok(WebGLParameter::Int(gl::get_shader_iv(shader_id, param_id))), - gl::DELETE_STATUS | - gl::COMPILE_STATUS => - Ok(WebGLParameter::Bool(gl::get_shader_iv(shader_id, param_id) != 0)), - _ => Err(WebGLError::InvalidEnum), - }; - - chan.send(result).unwrap(); - } - - fn uniform_location(&self, program_id: u32, name: String, chan: IpcSender<Option<i32>>) { - let location = gl::get_uniform_location(program_id, &name); - let location = if location == -1 { - None - } else { - Some(location) - }; + fn send_data(&mut self, chan: IpcSender<CanvasData>) { + match self.data { + WebGLPaintTaskData::Servo(_) => { + let width = self.size.width as usize; + let height = self.size.height as usize; + + let mut pixels = 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]); + } - chan.send(location).unwrap(); - } + // rgba -> bgra + byte_swap(&mut pixels); - fn send_pixel_contents(&mut self, chan: IpcSender<IpcSharedMemory>) { - // FIXME(#5652, dmarcos) Instead of a readback strategy we have - // to layerize the canvas. - // TODO(pcwalton): We'd save a copy if we had an `IpcSharedMemoryBuilder` abstraction that - // allowed you to mutate in-place before freezing the object for sending. - let width = self.size.width as usize; - let height = self.size.height as usize; + let pixel_data = CanvasPixelData { + image_data: IpcSharedMemory::from_bytes(&pixels[..]), + image_key: None, + }; - let mut pixels = 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]); + chan.send(CanvasData::Pixels(pixel_data)).unwrap(); + } + WebGLPaintTaskData::WebRender(_, id) => { + chan.send(CanvasData::WebGL(id)).unwrap(); + } } - - // rgba -> bgra - byte_swap(&mut pixels); - chan.send(IpcSharedMemory::from_bytes(&pixels[..])).unwrap(); } fn send_native_surface(&self, _: Sender<NativeSurface>) { @@ -561,18 +154,28 @@ impl WebGLPaintThread { } fn recreate(&mut self, size: Size2D<i32>) -> Result<(), &'static str> { - if size.width > self.original_context_size.width || - size.height > self.original_context_size.height { - try!(self.gl_context.resize(size)); - self.size = self.gl_context.borrow_draw_buffer().unwrap().size(); - } else { - self.size = size; - unsafe { gl::Scissor(0, 0, size.width, size.height); } + match self.data { + WebGLPaintTaskData::Servo(ref mut context) => { + if size.width > self.size.width || + size.height > self.size.height { + try!(context.resize(size)); + self.size = context.borrow_draw_buffer().unwrap().size(); + } else { + self.size = size; + unsafe { gl::Scissor(0, 0, size.width, size.height); } + } + } + WebGLPaintTaskData::WebRender(_, _) => { + // TODO + } } + Ok(()) } fn init(&mut self) { - self.gl_context.make_current().unwrap(); + if let WebGLPaintTaskData::Servo(ref context) = self.data { + context.make_current().unwrap(); + } } } diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml index 0b5962e5802..d1985af2a6b 100644 --- a/components/canvas_traits/Cargo.toml +++ b/components/canvas_traits/Cargo.toml @@ -34,6 +34,9 @@ path = "../plugins" [dependencies.util] path = "../util" +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + [dependencies] cssparser = {version = "0.5.3", features = ["heap_size", "serde-serialization"]} euclid = {version = "0.6.2", features = ["plugins"]} diff --git a/components/canvas_traits/lib.rs b/components/canvas_traits/lib.rs index 4dc0a5904f8..8d6769da02a 100644 --- a/components/canvas_traits/lib.rs +++ b/components/canvas_traits/lib.rs @@ -5,7 +5,6 @@ #![crate_name = "canvas_traits"] #![crate_type = "rlib"] #![feature(custom_derive)] -#![feature(nonzero)] #![feature(plugin)] #![plugin(heapsize_plugin, plugins, serde_macros)] @@ -20,13 +19,13 @@ extern crate layers; extern crate offscreen_gl_context; extern crate serde; extern crate util; +extern crate webrender_traits; use azure::azure::{AzColor, AzFloat}; use azure::azure_hl::{CapStyle, CompositionOp, JoinStyle}; use azure::azure_hl::{ColorPattern, DrawTarget, Pattern}; use azure::azure_hl::{ExtendMode, GradientStop, LinearGradientPattern, RadialGradientPattern}; use azure::azure_hl::{SurfaceFormat, SurfacePattern}; -use core::nonzero::NonZero; use cssparser::RGBA; use euclid::matrix2d::Matrix2D; use euclid::point::Point2D; @@ -35,13 +34,14 @@ use euclid::size::Size2D; use gfx_traits::color; use ipc_channel::ipc::{IpcSender, IpcSharedMemory}; use layers::platform::surface::NativeSurface; -use offscreen_gl_context::GLContextAttributes; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::default::Default; -use std::fmt; use std::str::FromStr; use std::sync::mpsc::Sender; +pub use webrender_traits::{WebGLFramebufferBindingRequest, WebGLError, WebGLParameter, WebGLResult, WebGLContextId}; +pub use webrender_traits::WebGLCommand as CanvasWebGLMsg; + #[derive(Clone, Deserialize, Serialize)] pub enum FillRule { Nonzero, @@ -64,8 +64,20 @@ pub enum CanvasCommonMsg { } #[derive(Clone, Deserialize, Serialize)] +pub enum CanvasData { + Pixels(CanvasPixelData), + WebGL(WebGLContextId), +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct CanvasPixelData { + pub image_data: IpcSharedMemory, + pub image_key: Option<webrender_traits::ImageKey>, +} + +#[derive(Clone, Deserialize, Serialize)] pub enum FromLayoutMsg { - SendPixelContents(IpcSender<IpcSharedMemory>), + SendData(IpcSender<CanvasData>), } #[derive(Clone)] @@ -124,178 +136,6 @@ pub enum Canvas2dMsg { SetShadowColor(RGBA), } -#[derive(Clone, Deserialize, Serialize)] -pub enum CanvasWebGLMsg { - GetContextAttributes(IpcSender<GLContextAttributes>), - ActiveTexture(u32), - BlendColor(f32, f32, f32, f32), - BlendEquation(u32), - BlendEquationSeparate(u32, u32), - BlendFunc(u32, u32), - BlendFuncSeparate(u32, u32, u32, u32), - AttachShader(u32, u32), - BindAttribLocation(u32, 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(u32, String), - CreateBuffer(IpcSender<Option<NonZero<u32>>>), - CreateFramebuffer(IpcSender<Option<NonZero<u32>>>), - CreateRenderbuffer(IpcSender<Option<NonZero<u32>>>), - CreateTexture(IpcSender<Option<NonZero<u32>>>), - CreateProgram(IpcSender<Option<NonZero<u32>>>), - CreateShader(u32, IpcSender<Option<NonZero<u32>>>), - DeleteBuffer(u32), - DeleteFramebuffer(u32), - DeleteRenderbuffer(u32), - DeleteTexture(u32), - DeleteProgram(u32), - DeleteShader(u32), - BindBuffer(u32, u32), - BindFramebuffer(u32, WebGLFramebufferBindingRequest), - BindRenderbuffer(u32, u32), - BindTexture(u32, u32), - DrawArrays(u32, i32, i32), - DrawElements(u32, i32, u32, i64), - EnableVertexAttribArray(u32), - GetBufferParameter(u32, u32, IpcSender<WebGLResult<WebGLParameter>>), - GetParameter(u32, IpcSender<WebGLResult<WebGLParameter>>), - GetProgramParameter(u32, u32, IpcSender<WebGLResult<WebGLParameter>>), - GetShaderParameter(u32, u32, IpcSender<WebGLResult<WebGLParameter>>), - GetAttribLocation(u32, String, IpcSender<Option<i32>>), - GetUniformLocation(u32, String, IpcSender<Option<i32>>), - PolygonOffset(f32, f32), - Scissor(i32, i32, i32, i32), - Hint(u32, u32), - LineWidth(f32), - PixelStorei(u32, i32), - LinkProgram(u32), - Uniform1f(i32, f32), - Uniform4f(i32, f32, f32, f32, f32), - UseProgram(u32), - VertexAttrib(u32, f32, f32, f32, f32), - 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), - DrawingBufferWidth(IpcSender<i32>), - DrawingBufferHeight(IpcSender<i32>), -} - -impl fmt::Debug for CanvasWebGLMsg { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use CanvasWebGLMsg::*; - let name = match *self { - GetContextAttributes(..) => "GetContextAttributes", - ActiveTexture(..) => "ActiveTexture", - BlendColor(..) => "BlendColor", - BlendEquation(..) => "BlendEquation", - BlendEquationSeparate(..) => "BlendEquationSeparate", - BlendFunc(..) => "BlendFunc", - BlendFuncSeparate(..) => "BlendFuncSeparate", - AttachShader(..) => "AttachShader", - BindAttribLocation(..) => "BindAttribLocation", - BufferData(..) => "BufferData", - BufferSubData(..) => "BufferSubData", - Clear(..) => "Clear", - ClearColor(..) => "ClearColor", - ClearDepth(..) => "ClearDepth", - ClearStencil(..) => "ClearStencil", - ColorMask(..) => "ColorMask", - 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", - DrawArrays(..) => "DrawArrays", - DrawElements(..) => "DrawElements", - EnableVertexAttribArray(..) => "EnableVertexAttribArray", - GetBufferParameter(..) => "GetBufferParameter", - GetParameter(..) => "GetParameter", - GetProgramParameter(..) => "GetProgramParameter", - GetShaderParameter(..) => "GetShaderParameter", - GetAttribLocation(..) => "GetAttribLocation", - GetUniformLocation(..) => "GetUniformLocation", - PolygonOffset(..) => "PolygonOffset", - Scissor(..) => "Scissor", - Hint(..) => "Hint", - LineWidth(..) => "LineWidth", - PixelStorei(..) => "PixelStorei", - LinkProgram(..) => "LinkProgram", - Uniform4f(..) => "Uniform4f", - Uniform1f(..) => "Uniform1f", - UseProgram(..) => "UseProgram", - VertexAttrib(..) => "VertexAttrib", - VertexAttribPointer2f(..) => "VertexAttribPointer2f", - Viewport(..) => "Viewport", - TexImage2D(..) => "TexImage2D", - TexParameteri(..) => "TexParameteri", - TexParameterf(..) => "TexParameterf", - DrawingBufferWidth(..) => "DrawingBufferWidth", - DrawingBufferHeight(..) => "DrawingBufferHeight", - }; - - write!(f, "CanvasWebGLMsg::{}(..)", name) - } -} - -#[derive(Clone, Copy, PartialEq, Deserialize, Serialize, HeapSizeOf)] -pub enum WebGLError { - InvalidEnum, - InvalidOperation, - InvalidValue, - OutOfMemory, - ContextLost, -} - -pub type WebGLResult<T> = Result<T, WebGLError>; - -#[derive(Clone, Deserialize, Serialize)] -pub enum WebGLFramebufferBindingRequest { - Explicit(u32), - Default, -} - -#[derive(Clone, Deserialize, Serialize)] -pub enum WebGLParameter { - Int(i32), - Bool(bool), - String(String), - Float(f32), - Invalid, -} - #[derive(Clone, Deserialize, Serialize, HeapSizeOf)] pub struct CanvasGradientStop { pub offset: f64, diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index a190ddb73f2..389b669d607 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -81,6 +81,12 @@ git = "https://github.com/servo/gaol" [target.aarch64-unknown-linux-gnu.dependencies.gaol] git = "https://github.com/servo/gaol" +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + +[dependencies.webrender] +git = "https://github.com/glennw/webrender" + [dependencies] app_units = {version = "0.2.1", features = ["plugins"]} euclid = {version = "0.6.2", features = ["plugins"]} diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index f75126cab28..e8ac9a88c22 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -6,7 +6,7 @@ use CompositorMsg as ConstellationMsg; use app_units::Au; use compositor_layer::{CompositorData, CompositorLayer, RcCompositorLayer, WantsScrollEventsFlag}; use compositor_thread::{CompositorEventListener, CompositorProxy}; -use compositor_thread::{CompositorReceiver, InitialCompositorState, Msg}; +use compositor_thread::{CompositorReceiver, InitialCompositorState, Msg, RenderListener}; use constellation::SendableFrameTree; use euclid::point::TypedPoint2D; use euclid::rect::TypedRect; @@ -27,15 +27,15 @@ use layers::rendergl; use layers::rendergl::RenderContext; use layers::scene::Scene; use layout_traits::LayoutControlChan; -use msg::constellation_msg::{Image, PixelFormat}; +use msg::constellation_msg::{ConvertPipelineIdFromWebRender, ConvertPipelineIdToWebRender, Image, PixelFormat}; use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData}; use msg::constellation_msg::{NavigationDirection, PipelineId, WindowSizeData}; use pipeline::CompositionPipeline; use profile_traits::mem::{self, ReportKind, Reporter, ReporterRequest}; use profile_traits::time::{self, ProfilerCategory, profile}; -use script_traits::CompositorEvent::{MouseMoveEvent, TouchEvent}; +use script_traits::CompositorEvent::{MouseMoveEvent, MouseButtonEvent, TouchEvent}; use script_traits::{AnimationState, ConstellationControlMsg, LayoutControlMsg}; -use script_traits::{MouseButton, TouchEventType, TouchId}; +use script_traits::{MouseButton, MouseEventType, TouchEventType, TouchId}; use scrolling::ScrollingTimerProxy; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::{HashMap, HashSet}; @@ -51,6 +51,8 @@ use url::Url; use util::geometry::{PagePx, ScreenPx, ViewportPx}; use util::opts; use util::print_tree::PrintTree; +use webrender; +use webrender_traits; use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg}; #[derive(Debug, PartialEq)] @@ -192,6 +194,12 @@ pub struct IOCompositor<Window: WindowMethods> { /// The id of the pipeline that was last sent a mouse move event, if any. last_mouse_move_recipient: Option<PipelineId>, + + /// The webrender renderer, if enabled. + webrender: Option<webrender::Renderer>, + + /// The webrender interface, if enabled. + webrender_api: Option<webrender_traits::RenderApi>, } pub struct ScrollZoomEvent { @@ -261,7 +269,23 @@ pub enum CompositeTarget { PngFile } -fn initialize_png(width: usize, height: usize) -> (Vec<gl::GLuint>, Vec<gl::GLuint>) { +struct RenderTargetInfo { + framebuffer_ids: Vec<gl::GLuint>, + texture_ids: Vec<gl::GLuint>, + renderbuffer_ids: Vec<gl::GLuint>, +} + +impl RenderTargetInfo { + fn empty() -> RenderTargetInfo { + RenderTargetInfo { + framebuffer_ids: Vec::new(), + texture_ids: Vec::new(), + renderbuffer_ids: Vec::new() + } + } +} + +fn initialize_png(width: usize, height: usize) -> RenderTargetInfo { let framebuffer_ids = gl::gen_framebuffers(1); gl::bind_framebuffer(gl::FRAMEBUFFER, framebuffer_ids[0]); @@ -278,13 +302,64 @@ fn initialize_png(width: usize, height: usize) -> (Vec<gl::GLuint>, Vec<gl::GLui gl::bind_texture(gl::TEXTURE_2D, 0); - (framebuffer_ids, texture_ids) + let renderbuffer_ids = if opts::get().use_webrender { + let renderbuffer_ids = gl::gen_renderbuffers(1); + gl::bind_renderbuffer(gl::RENDERBUFFER, renderbuffer_ids[0]); + gl::renderbuffer_storage(gl::RENDERBUFFER, + gl::STENCIL_INDEX8, + width as GLsizei, + height as GLsizei); + gl::framebuffer_renderbuffer(gl::FRAMEBUFFER, + gl::STENCIL_ATTACHMENT, + gl::RENDERBUFFER, + renderbuffer_ids[0]); + renderbuffer_ids + } else { + Vec::new() + }; + + RenderTargetInfo { + framebuffer_ids: framebuffer_ids, + texture_ids: texture_ids, + renderbuffer_ids: renderbuffer_ids + } } pub fn reporter_name() -> String { "compositor-reporter".to_owned() } +struct RenderNotifier { + compositor_proxy: Box<CompositorProxy>, + constellation_chan: Sender<ConstellationMsg>, +} + +impl RenderNotifier { + fn new(compositor_proxy: Box<CompositorProxy>, + constellation_chan: Sender<ConstellationMsg>) -> RenderNotifier { + RenderNotifier { + compositor_proxy: compositor_proxy, + constellation_chan: constellation_chan, + } + } +} + +impl webrender_traits::RenderNotifier for RenderNotifier { + fn new_frame_ready(&mut self) { + self.compositor_proxy.recomposite(); + } + + fn pipeline_size_changed(&mut self, + pipeline_id: webrender_traits::PipelineId, + size: Option<Size2D<f32>>) { + let pipeline_id = pipeline_id.from_webrender(); + let size = size.unwrap_or(Size2D::zero()); + + self.constellation_chan.send(ConstellationMsg::FrameSize(pipeline_id, + size)).unwrap(); + } +} + impl<Window: WindowMethods> IOCompositor<Window> { fn new(window: Rc<Window>, state: InitialCompositorState) -> IOCompositor<Window> { @@ -306,6 +381,11 @@ impl<Window: WindowMethods> IOCompositor<Window> { Some(_) => CompositeTarget::PngFile, None => CompositeTarget::Window }; + + let webrender_api = state.webrender_api_sender.map(|sender| { + sender.create_api() + }); + let native_display = window.native_display(); IOCompositor { window: window, @@ -345,6 +425,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { surface_map: SurfaceMap::new(BUFFER_MAP_SIZE), pending_subpages: HashSet::new(), last_mouse_move_recipient: None, + webrender: state.webrender, + webrender_api: webrender_api, } } @@ -352,6 +434,14 @@ impl<Window: WindowMethods> IOCompositor<Window> { -> IOCompositor<Window> { let mut compositor = IOCompositor::new(window, state); + if let Some(ref mut webrender) = compositor.webrender { + let compositor_proxy_for_webrender = compositor.channel_to_self + .clone_compositor_proxy(); + let render_notifier = RenderNotifier::new(compositor_proxy_for_webrender, + compositor.constellation_chan.clone()); + webrender.set_render_notifier(Box::new(render_notifier)); + } + // Set the size of the root layer. compositor.update_zoom_transform(); @@ -674,6 +764,11 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.root_pipeline = Some(frame_tree.pipeline.clone()); + if let Some(ref webrender_api) = self.webrender_api { + let pipeline_id = frame_tree.pipeline.id.to_webrender(); + webrender_api.set_root_pipeline(pipeline_id); + } + // If we have an old root layer, release all old tiles before replacing it. let old_root_layer = self.scene.root.take(); if let Some(ref old_root_layer) = old_root_layer { @@ -1172,6 +1267,36 @@ impl<Window: WindowMethods> IOCompositor<Window> { MouseWindowEvent::MouseDown(_, p) => p, MouseWindowEvent::MouseUp(_, p) => p, }; + + if let Some(ref webrender_api) = self.webrender_api { + let root_pipeline_id = match self.get_root_pipeline_id() { + Some(root_pipeline_id) => root_pipeline_id, + None => return, + }; + let root_pipeline = match self.pipeline(root_pipeline_id) { + Some(root_pipeline) => root_pipeline, + None => return, + }; + + let translated_point = + webrender_api.translate_point_to_layer_space(&point.to_untyped()); + let event_to_send = match mouse_window_event { + MouseWindowEvent::Click(button, _) => { + MouseButtonEvent(MouseEventType::Click, button, translated_point) + } + MouseWindowEvent::MouseDown(button, _) => { + MouseButtonEvent(MouseEventType::MouseDown, button, translated_point) + } + MouseWindowEvent::MouseUp(button, _) => { + MouseButtonEvent(MouseEventType::MouseUp, button, translated_point) + } + }; + root_pipeline.script_chan + .send(ConstellationControlMsg::SendEvent(root_pipeline_id, + event_to_send)) + .unwrap(); + } + match self.find_topmost_layer_at_point(point / self.scene.scale) { Some(result) => result.layer.send_mouse_event(self, mouse_window_event, result.point), None => {}, @@ -1184,6 +1309,25 @@ impl<Window: WindowMethods> IOCompositor<Window> { return } + if let Some(ref webrender_api) = self.webrender_api { + let root_pipeline_id = match self.get_root_pipeline_id() { + Some(root_pipeline_id) => root_pipeline_id, + None => return, + }; + let root_pipeline = match self.pipeline(root_pipeline_id) { + Some(root_pipeline) => root_pipeline, + None => return, + }; + + let translated_point = + webrender_api.translate_point_to_layer_space(&cursor.to_untyped()); + let event_to_send = MouseMoveEvent(Some(translated_point)); + root_pipeline.script_chan + .send(ConstellationControlMsg::SendEvent(root_pipeline_id, + event_to_send)) + .unwrap(); + } + match self.find_topmost_layer_at_point(cursor / self.scene.scale) { Some(result) => { // In the case that the mouse was previously over a different layer, @@ -1285,30 +1429,52 @@ impl<Window: WindowMethods> IOCompositor<Window> { fn process_pending_scroll_events(&mut self) { let had_events = self.pending_scroll_zoom_events.len() > 0; - for event in std_mem::replace(&mut self.pending_scroll_zoom_events, - Vec::new()) { - let delta = event.delta / self.scene.scale; - let cursor = event.cursor.as_f32() / self.scene.scale; - if let Some(ref mut layer) = self.scene.root { - layer.handle_scroll_event(delta, cursor); + match self.webrender_api { + Some(ref webrender_api) => { + // Batch up all scroll events into one, or else we'll do way too much painting. + let mut total_delta = None; + let mut last_cursor = Point2D::zero(); + for scroll_event in self.pending_scroll_zoom_events.drain(..) { + let this_delta = scroll_event.delta / self.scene.scale; + last_cursor = scroll_event.cursor.as_f32() / self.scene.scale; + match total_delta { + None => total_delta = Some(this_delta), + Some(ref mut total_delta) => *total_delta = *total_delta + this_delta, + } + } + // TODO(gw): Support zoom (WR issue #28). + if let Some(total_delta) = total_delta { + webrender_api.scroll(total_delta.to_untyped(), last_cursor.to_untyped()); + } } + None => { + for event in std_mem::replace(&mut self.pending_scroll_zoom_events, + Vec::new()) { + let delta = event.delta / self.scene.scale; + let cursor = event.cursor.as_f32() / self.scene.scale; - if event.magnification != 1.0 { - self.zoom_action = true; - self.zoom_time = precise_time_s(); - self.viewport_zoom = ScaleFactor::new( - (self.viewport_zoom.get() * event.magnification) - .min(self.max_viewport_zoom.as_ref().map_or(MAX_ZOOM, ScaleFactor::get)) - .max(self.min_viewport_zoom.as_ref().map_or(MIN_ZOOM, ScaleFactor::get))); - self.update_zoom_transform(); - } + if let Some(ref mut layer) = self.scene.root { + layer.handle_scroll_event(delta, cursor); + } - self.perform_updates_after_scroll(); - } + if event.magnification != 1.0 { + self.zoom_action = true; + self.zoom_time = precise_time_s(); + self.viewport_zoom = ScaleFactor::new( + (self.viewport_zoom.get() * event.magnification) + .min(self.max_viewport_zoom.as_ref().map_or(MAX_ZOOM, ScaleFactor::get)) + .max(self.min_viewport_zoom.as_ref().map_or(MIN_ZOOM, ScaleFactor::get))); + self.update_zoom_transform(); + } + + self.perform_updates_after_scroll(); + } - if had_events { - self.send_viewport_rects_for_all_layers(); + if had_events { + self.send_viewport_rects_for_all_layers(); + } + } } } @@ -1542,6 +1708,10 @@ impl<Window: WindowMethods> IOCompositor<Window> { /// Returns true if any buffer requests were sent or false otherwise. fn send_buffer_requests_for_all_layers(&mut self) -> bool { + if self.webrender.is_some() { + return false; + } + if let Some(ref root_layer) = self.scene.root { root_layer.update_transform_state(&Matrix4::identity(), &Matrix4::identity(), @@ -1656,7 +1826,15 @@ impl<Window: WindowMethods> IOCompositor<Window> { // frame tree. let mut pipeline_epochs = HashMap::new(); for (id, details) in &self.pipeline_details { - pipeline_epochs.insert(*id, details.current_epoch); + if let Some(ref webrender) = self.webrender { + let webrender_pipeline_id = id.to_webrender(); + if let Some(webrender_traits::Epoch(epoch)) = webrender.current_epoch(webrender_pipeline_id) { + let epoch = Epoch(epoch); + pipeline_epochs.insert(*id, epoch); + } + } else { + pipeline_epochs.insert(*id, details.current_epoch); + } } // Pass the pipeline/epoch states to the constellation and check @@ -1707,7 +1885,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { /// is WindowAndPng Ok(Some(png::Image)) is returned. pub fn composite_specific_target(&mut self, target: CompositeTarget) -> Result<Option<Image>, UnableToComposite> { - if !self.context.is_some() { + if self.context.is_none() && self.webrender.is_none() { return Err(UnableToComposite::NoContext) } let (width, height) = @@ -1716,6 +1894,11 @@ impl<Window: WindowMethods> IOCompositor<Window> { return Err(UnableToComposite::WindowUnprepared) } + if let Some(ref mut webrender) = self.webrender { + assert!(self.context.is_none()); + webrender.update(); + } + let wait_for_stable_image = match target { CompositeTarget::WindowAndPng | CompositeTarget::PngFile => true, CompositeTarget::Window => opts::get().exit_after_load, @@ -1738,8 +1921,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { } } - let (framebuffer_ids, texture_ids) = match target { - CompositeTarget::Window => (vec!(), vec!()), + let render_target_info = match target { + CompositeTarget::Window => RenderTargetInfo::empty(), _ => initialize_png(width, height) }; @@ -1760,7 +1943,10 @@ impl<Window: WindowMethods> IOCompositor<Window> { }; // Paint the scene. - if let Some(ref layer) = self.scene.root { + if let Some(ref mut webrender) = self.webrender { + assert!(self.context.is_none()); + webrender.render(self.window_size.to_untyped()); + } else if let Some(ref layer) = self.scene.root { match self.context { Some(context) => { if let Some((point, size)) = self.viewport { @@ -1790,16 +1976,21 @@ impl<Window: WindowMethods> IOCompositor<Window> { let rv = match target { CompositeTarget::Window => None, CompositeTarget::WindowAndPng => { - let img = self.draw_img(framebuffer_ids, texture_ids, width, height); + let img = self.draw_img(render_target_info, + width, + height); Some(Image { width: img.width(), height: img.height(), format: PixelFormat::RGB8, bytes: IpcSharedMemory::from_bytes(&*img), + id: None, }) } CompositeTarget::PngFile => { - let img = self.draw_img(framebuffer_ids, texture_ids, width, height); + let img = self.draw_img(render_target_info, + width, + height); let path = opts::get().output_file.as_ref().unwrap(); let mut file = File::create(path).unwrap(); DynamicImage::ImageRgb8(img).save(&mut file, ImageFormat::PNG).unwrap(); @@ -1820,8 +2011,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { } fn draw_img(&self, - framebuffer_ids: Vec<gl::GLuint>, - texture_ids: Vec<gl::GLuint>, + render_target_info: RenderTargetInfo, width: usize, height: usize) -> RgbImage { @@ -1832,8 +2022,11 @@ impl<Window: WindowMethods> IOCompositor<Window> { gl::bind_framebuffer(gl::FRAMEBUFFER, 0); - gl::delete_buffers(&texture_ids); - gl::delete_frame_buffers(&framebuffer_ids); + gl::delete_buffers(&render_target_info.texture_ids); + gl::delete_frame_buffers(&render_target_info.framebuffer_ids); + if opts::get().use_webrender { + gl::delete_renderbuffers(&render_target_info.renderbuffer_ids); + } // flip image vertically (texture is upside down) let orig_pixels = pixels.clone(); @@ -1859,10 +2052,12 @@ impl<Window: WindowMethods> IOCompositor<Window> { } fn initialize_compositing(&mut self) { - let show_debug_borders = opts::get().show_debug_borders; - self.context = Some(rendergl::RenderContext::new(self.native_display.clone(), - show_debug_borders, - opts::get().output_file.is_some())) + if self.webrender.is_none() { + let show_debug_borders = opts::get().show_debug_borders; + self.context = Some(rendergl::RenderContext::new(self.native_display.clone(), + show_debug_borders, + opts::get().output_file.is_some())) + } } fn find_topmost_layer_at_point_for_layer(&self, @@ -1951,6 +2146,10 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.surface_map.insert_surfaces(&self.native_display, surfaces); } + fn get_root_pipeline_id(&self) -> Option<PipelineId> { + self.scene.root.as_ref().map(|root_layer| root_layer.extra_data.borrow().pipeline_id) + } + #[allow(dead_code)] fn dump_layer_tree(&self) { if !opts::get().dump_layer_tree { @@ -2076,19 +2275,37 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind /// /// This is used when resizing the window. fn repaint_synchronously(&mut self) { - while self.shutdown_state != ShutdownState::ShuttingDown { - let msg = self.port.recv_compositor_msg(); - let received_new_buffers = match msg { - Msg::AssignPaintedBuffers(..) => true, - _ => false, - }; - let keep_going = self.handle_browser_message(msg); - if received_new_buffers { - self.composite(); - break + if self.webrender.is_none() { + while self.shutdown_state != ShutdownState::ShuttingDown { + let msg = self.port.recv_compositor_msg(); + let received_new_buffers = match msg { + Msg::AssignPaintedBuffers(..) => true, + _ => false, + }; + let keep_going = self.handle_browser_message(msg); + if received_new_buffers { + self.composite(); + break + } + if !keep_going { + break + } } - if !keep_going { - break + } else { + while self.shutdown_state != ShutdownState::ShuttingDown { + let msg = self.port.recv_compositor_msg(); + let need_recomposite = match msg { + Msg::RecompositeAfterScroll => true, + _ => false, + }; + let keep_going = self.handle_browser_message(msg); + if need_recomposite { + self.composite(); + break + } + if !keep_going { + break + } } } } diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index 618bac9674b..f9f0c03d1e3 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -26,6 +26,8 @@ use url::Url; use windowing::{WindowEvent, WindowMethods}; pub use constellation::SendableFrameTree; pub use windowing; +use webrender; +use webrender_traits; /// Sends messages to the compositor. This is a trait supplied by the port because the method used /// to communicate with the compositor may have to kick OS event loops awake, communicate cross- @@ -100,6 +102,16 @@ pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'stati } } +pub trait RenderListener { + fn recomposite(&mut self); +} + +impl RenderListener for Box<CompositorProxy + 'static> { + fn recomposite(&mut self) { + self.send(Msg::RecompositeAfterScroll); + } +} + /// Implementation of the abstract `PaintListener` interface. impl PaintListener for Box<CompositorProxy + 'static + Send> { fn native_display(&mut self) -> Option<NativeDisplay> { @@ -301,4 +313,7 @@ pub struct InitialCompositorState { pub time_profiler_chan: time::ProfilerChan, /// A channel to the memory profiler thread. pub mem_profiler_chan: mem::ProfilerChan, + /// Instance of webrender API if enabled + pub webrender: Option<webrender::Renderer>, + pub webrender_api_sender: Option<webrender_traits::RenderApiSender>, } diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index a08687bb680..b7a57f7069e 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -63,6 +63,7 @@ use url::Url; use util::geometry::PagePx; use util::thread::spawn_named; use util::{opts, prefs}; +use webrender_traits; #[derive(Debug, PartialEq)] enum ReadyToSave { @@ -181,6 +182,9 @@ pub struct Constellation<LTF, STF> { /// Document states for loaded pipelines (used only when writing screenshots). document_states: HashMap<PipelineId, DocumentState>, + + // Webrender interface, if enabled. + webrender_api_sender: Option<webrender_traits::RenderApiSender>, } /// State needed to construct a constellation. @@ -203,6 +207,8 @@ pub struct InitialConstellationState { pub mem_profiler_chan: mem::ProfilerChan, /// Whether the constellation supports the clipboard. pub supports_clipboard: bool, + /// Optional webrender API reference (if enabled). + pub webrender_api_sender: Option<webrender_traits::RenderApiSender>, } /// Stores the navigation context for a single frame in the frame tree. @@ -347,6 +353,7 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> scheduler_chan: TimerScheduler::start(), child_processes: Vec::new(), document_states: HashMap::new(), + webrender_api_sender: state.webrender_api_sender, }; let namespace_id = constellation.next_pipeline_namespace_id(); PipelineNamespace::install(namespace_id); @@ -399,6 +406,7 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> load_data: load_data, device_pixel_ratio: self.window_size.device_pixel_ratio, pipeline_namespace_id: self.next_pipeline_namespace_id(), + webrender_api_sender: self.webrender_api_sender.clone(), }); if spawning_paint_only { @@ -1196,7 +1204,9 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> size: &Size2D<i32>, response_sender: IpcSender<(IpcSender<CanvasMsg>, usize)>) { let id = self.canvas_paint_threads.len(); - let (out_of_process_sender, in_process_sender) = CanvasPaintThread::start(*size); + let webrender_api = self.webrender_api_sender.clone(); + let (out_of_process_sender, in_process_sender) = CanvasPaintThread::start(*size, + webrender_api); self.canvas_paint_threads.push(in_process_sender); response_sender.send((out_of_process_sender, id)).unwrap() } @@ -1206,13 +1216,14 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> size: &Size2D<i32>, attributes: GLContextAttributes, response_sender: IpcSender<Result<(IpcSender<CanvasMsg>, usize), String>>) { - let response = match WebGLPaintThread::start(*size, attributes) { + let webrender_api = self.webrender_api_sender.clone(); + let response = match WebGLPaintThread::start(*size, attributes, webrender_api) { Ok((out_of_process_sender, in_process_sender)) => { let id = self.webgl_paint_threads.len(); self.webgl_paint_threads.push(in_process_sender); Ok((out_of_process_sender, id)) }, - Err(msg) => Err(msg.to_owned()), + Err(msg) => Err(msg), }; response_sender.send(response).unwrap() diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index 6434c3a8939..410b007a3a6 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -48,6 +48,8 @@ extern crate time; extern crate url; #[macro_use] extern crate util; +extern crate webrender; +extern crate webrender_traits; pub use compositor_thread::{CompositorEventListener, CompositorProxy, CompositorThread}; pub use constellation::Constellation; diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index 2a4e3b1999e..bbf892048c8 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -35,6 +35,7 @@ use util::geometry::{PagePx, ViewportPx}; use util::ipc::OptionalIpcSender; use util::opts::{self, Opts}; use util::prefs; +use webrender_traits; /// A uniquely-identifiable pipeline of script thread, layout thread, and paint thread. pub struct Pipeline { @@ -113,6 +114,8 @@ pub struct InitialPipelineState { pub load_data: LoadData, /// The ID of the pipeline namespace for this script thread. pub pipeline_namespace_id: PipelineNamespaceId, + /// Optional webrender api (if enabled). + pub webrender_api_sender: Option<webrender_traits::RenderApiSender>, } impl Pipeline { @@ -225,6 +228,7 @@ impl Pipeline { 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, }; let privileged_pipeline_content = PrivilegedPipelineContent { @@ -376,6 +380,7 @@ pub struct UnprivilegedPipelineContent { layout_content_process_shutdown_port: IpcReceiver<()>, script_content_process_shutdown_chan: IpcSender<()>, script_content_process_shutdown_port: IpcReceiver<()>, + webrender_api_sender: Option<webrender_traits::RenderApiSender>, } impl UnprivilegedPipelineContent { @@ -419,7 +424,8 @@ impl UnprivilegedPipelineContent { self.time_profiler_chan, self.mem_profiler_chan, self.layout_shutdown_chan, - self.layout_content_process_shutdown_chan.clone()); + self.layout_content_process_shutdown_chan.clone(), + self.webrender_api_sender); if wait_for_completion { self.script_content_process_shutdown_port.recv().unwrap(); diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml index b9e577d3e90..58863a275c1 100644 --- a/components/gfx/Cargo.toml +++ b/components/gfx/Cargo.toml @@ -69,6 +69,9 @@ features = ["plugins"] [dependencies.ipc-channel] git = "https://github.com/servo/ipc-channel" +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + [target.x86_64-apple-darwin.dependencies] core-foundation = "0.2" core-graphics = "0.2" diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index f3aad7848c7..5b0e3935904 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -45,6 +45,7 @@ use util::linked_list::prepend_from; use util::opts; use util::print_tree::PrintTree; use util::range::Range; +use webrender_traits::WebGLContextId; pub use style::dom::OpaqueNode; @@ -641,7 +642,10 @@ impl StackingContext { layer_info: layer_info, last_child_layer_info: None, }; - StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context); + // webrender doesn't care about layers in the display list - it's handled internally. + if !opts::get().use_webrender { + StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context); + } stacking_context } @@ -681,7 +685,8 @@ impl StackingContext { // TODO(gw): This is a hack to avoid running the DL optimizer // on 3d transformed tiles. We should have a better solution // than just disabling the opts here. - if paint_context.layer_kind == LayerKind::HasTransform { + if paint_context.layer_kind == LayerKind::HasTransform || + opts::get().use_webrender { // webrender takes care of all culling via aabb tree! self.draw_into_context(&self.display_list, paint_context, &transform, @@ -775,6 +780,9 @@ struct StackingContextLayerCreator { impl StackingContextLayerCreator { fn new() -> StackingContextLayerCreator { + // webrender doesn't care about layers in the display list - it's handled internally. + debug_assert!(!opts::get().use_webrender); + StackingContextLayerCreator { display_list_for_next_layer: None, next_layer_info: None, @@ -969,6 +977,7 @@ pub enum DisplayItem { SolidColorClass(Box<SolidColorDisplayItem>), TextClass(Box<TextDisplayItem>), ImageClass(Box<ImageDisplayItem>), + WebGLClass(Box<WebGLDisplayItem>), BorderClass(Box<BorderDisplayItem>), GradientClass(Box<GradientDisplayItem>), LineClass(Box<LineDisplayItem>), @@ -976,6 +985,7 @@ pub enum DisplayItem { StackingContextClass(Arc<StackingContext>), LayeredItemClass(Box<LayeredItem>), NoopClass(Box<BaseDisplayItem>), + IframeClass(Box<IframeDisplayItem>), } /// Information common to all display items. @@ -1236,6 +1246,20 @@ pub struct ImageDisplayItem { pub image_rendering: image_rendering::T, } +#[derive(Clone, HeapSizeOf, Deserialize, Serialize)] +pub struct WebGLDisplayItem { + pub base: BaseDisplayItem, + #[ignore_heap_size_of = "Defined in webrender_traits"] + pub context_id: WebGLContextId, +} + + +/// Paints an iframe. +#[derive(Clone, HeapSizeOf, Deserialize, Serialize)] +pub struct IframeDisplayItem { + pub base: BaseDisplayItem, + pub iframe: PipelineId, +} /// Paints a gradient. #[derive(Clone, Deserialize, HeapSizeOf, Serialize)] @@ -1450,6 +1474,10 @@ impl DisplayItem { image_item.image_rendering.clone()); } + DisplayItem::WebGLClass(_) => { + panic!("Shouldn't be here, WebGL display items are created just with webrender"); + } + DisplayItem::BorderClass(ref border) => { paint_context.draw_border(&border.base.bounds, &border.border_widths, @@ -1499,6 +1527,7 @@ impl DisplayItem { DisplayItem::LayeredItemClass(_) => panic!("Found layered item during drawing."), DisplayItem::NoopClass(_) => { } + DisplayItem::IframeClass(..) => {} } } @@ -1507,6 +1536,7 @@ impl DisplayItem { DisplayItem::SolidColorClass(ref solid_color) => Some(&solid_color.base), DisplayItem::TextClass(ref text) => Some(&text.base), DisplayItem::ImageClass(ref image_item) => Some(&image_item.base), + DisplayItem::WebGLClass(ref webgl_item) => Some(&webgl_item.base), DisplayItem::BorderClass(ref border) => Some(&border.base), DisplayItem::GradientClass(ref gradient) => Some(&gradient.base), DisplayItem::LineClass(ref line) => Some(&line.base), @@ -1514,6 +1544,7 @@ impl DisplayItem { DisplayItem::LayeredItemClass(ref layered_item) => layered_item.item.base(), DisplayItem::NoopClass(ref base_item) => Some(base_item), DisplayItem::StackingContextClass(_) => None, + DisplayItem::IframeClass(ref iframe) => Some(&iframe.base), } } @@ -1563,6 +1594,7 @@ impl fmt::Debug for DisplayItem { solid_color.color.a), DisplayItem::TextClass(_) => "Text".to_owned(), DisplayItem::ImageClass(_) => "Image".to_owned(), + DisplayItem::WebGLClass(_) => "WebGL".to_owned(), DisplayItem::BorderClass(_) => "Border".to_owned(), DisplayItem::GradientClass(_) => "Gradient".to_owned(), DisplayItem::LineClass(_) => "Line".to_owned(), @@ -1571,6 +1603,7 @@ impl fmt::Debug for DisplayItem { DisplayItem::LayeredItemClass(ref layered_item) => format!("LayeredItem({:?})", layered_item.item), DisplayItem::NoopClass(_) => "Noop".to_owned(), + DisplayItem::IframeClass(_) => "Iframe".to_owned(), }, self.bounds(), ) diff --git a/components/gfx/font.rs b/components/gfx/font.rs index bb9ff7b3d45..8e5a80939ab 100644 --- a/components/gfx/font.rs +++ b/components/gfx/font.rs @@ -23,6 +23,7 @@ use text::shaping::ShaperMethods; use time; use unicode_script::Script; use util::cache::HashCache; +use webrender_traits; static TEXT_SHAPING_PERFORMANCE_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; @@ -100,6 +101,7 @@ pub struct Font { pub shaper: Option<Shaper>, pub shape_cache: HashCache<ShapeCacheEntry, Arc<GlyphStore>>, pub glyph_advance_cache: HashCache<u32, FractionalPixel>, + pub font_key: Option<webrender_traits::FontKey>, } bitflags! { diff --git a/components/gfx/font_cache_thread.rs b/components/gfx/font_cache_thread.rs index 6a2b5b4a033..89eefe9205b 100644 --- a/components/gfx/font_cache_thread.rs +++ b/components/gfx/font_cache_thread.rs @@ -24,12 +24,19 @@ use url::Url; use util::prefs; use util::str::LowercaseString; use util::thread::spawn_named; +use webrender_traits; /// A list of font templates that make up a given font family. struct FontTemplates { templates: Vec<FontTemplate>, } +#[derive(Serialize, Deserialize, Debug)] +pub struct FontTemplateInfo { + pub font_template: Arc<FontTemplateData>, + pub font_key: Option<webrender_traits::FontKey>, +} + impl FontTemplates { fn new() -> FontTemplates { FontTemplates { @@ -73,7 +80,8 @@ impl FontTemplates { } } - let template = FontTemplate::new(identifier, maybe_data); + let template = FontTemplate::new(identifier, + maybe_data); self.templates.push(template); } } @@ -91,7 +99,7 @@ pub enum Command { /// Reply messages sent from the font cache thread to the FontContext caller. #[derive(Deserialize, Serialize, Debug)] pub enum Reply { - GetFontTemplateReply(Option<Arc<FontTemplateData>>), + GetFontTemplateReply(Option<FontTemplateInfo>), } /// The font cache thread itself. It maintains a list of reference counted @@ -104,6 +112,8 @@ struct FontCache { web_families: HashMap<LowercaseString, FontTemplates>, font_context: FontContextHandle, resource_thread: ResourceThread, + webrender_api: Option<webrender_traits::RenderApi>, + webrender_fonts: HashMap<Atom, webrender_traits::FontKey>, } fn populate_generic_fonts() -> HashMap<FontFamily, LowercaseString> { @@ -285,24 +295,46 @@ impl FontCache { } } + fn get_font_template_info(&mut self, template: Arc<FontTemplateData>) -> FontTemplateInfo { + let webrender_fonts = &mut self.webrender_fonts; + let font_key = self.webrender_api.as_ref().map(|webrender_api| { + *webrender_fonts.entry(template.identifier.clone()).or_insert_with(|| { + match (template.bytes_if_in_memory(), template.native_font()) { + (Some(bytes), _) => webrender_api.add_raw_font(bytes), + (None, Some(native_font)) => webrender_api.add_native_font(native_font), + (None, None) => webrender_api.add_raw_font(template.bytes().clone()), + } + }) + }); + + FontTemplateInfo { + font_template: template, + font_key: font_key, + } + } + fn find_font_template(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor) - -> Option<Arc<FontTemplateData>> { - self.find_font_in_web_family(family, desc) + -> Option<FontTemplateInfo> { + let template = self.find_font_in_web_family(family, desc) .or_else(|| { let transformed_family = self.transform_family(family); self.find_font_in_local_family(&transformed_family, desc) - }) + }); + + template.map(|template| { + self.get_font_template_info(template) + }) } fn last_resort_font_template(&mut self, desc: &FontTemplateDescriptor) - -> Arc<FontTemplateData> { + -> FontTemplateInfo { let last_resort = last_resort_font_families(); for family in &last_resort { let family = LowercaseString::new(family); let maybe_font_in_family = self.find_font_in_local_family(&family, desc); if let Some(family) = maybe_font_in_family { - return family; + return self.get_font_template_info(family) } } @@ -318,7 +350,8 @@ pub struct FontCacheThread { } impl FontCacheThread { - pub fn new(resource_thread: ResourceThread) -> FontCacheThread { + pub fn new(resource_thread: ResourceThread, + webrender_api: Option<webrender_traits::RenderApi>) -> FontCacheThread { let (chan, port) = ipc::channel().unwrap(); let channel_to_self = chan.clone(); @@ -334,6 +367,8 @@ impl FontCacheThread { web_families: HashMap::new(), font_context: FontContextHandle::new(), resource_thread: resource_thread, + webrender_api: webrender_api, + webrender_fonts: HashMap::new(), }; cache.refresh_local_families(); @@ -346,7 +381,7 @@ impl FontCacheThread { } pub fn find_font_template(&self, family: FontFamily, desc: FontTemplateDescriptor) - -> Option<Arc<FontTemplateData>> { + -> Option<FontTemplateInfo> { let (response_chan, response_port) = ipc::channel().unwrap(); self.chan.send(Command::GetFontTemplate(family, desc, response_chan)).unwrap(); @@ -361,7 +396,7 @@ impl FontCacheThread { } pub fn last_resort_font_template(&self, desc: FontTemplateDescriptor) - -> Arc<FontTemplateData> { + -> FontTemplateInfo { let (response_chan, response_port) = ipc::channel().unwrap(); self.chan.send(Command::GetLastResortFontTemplate(desc, response_chan)).unwrap(); diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs index 8262b0d15fb..7cb95e6fc54 100644 --- a/components/gfx/font_context.rs +++ b/components/gfx/font_context.rs @@ -28,6 +28,7 @@ use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use string_cache::Atom; use style::computed_values::{font_style, font_variant}; use util::cache::HashCache; +use webrender_traits; #[cfg(any(target_os = "linux", target_os = "android", target_os = "windows"))] fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont { @@ -105,9 +106,12 @@ impl FontContext { } /// Create a font for use in layout calculations. - fn create_layout_font(&self, template: Arc<FontTemplateData>, - descriptor: FontTemplateDescriptor, pt_size: Au, - variant: font_variant::T) -> Result<Font, ()> { + fn create_layout_font(&self, + template: Arc<FontTemplateData>, + descriptor: FontTemplateDescriptor, + pt_size: Au, + variant: font_variant::T, + font_key: Option<webrender_traits::FontKey>) -> Result<Font, ()> { // TODO: (Bug #3463): Currently we only support fake small-caps // painting. We should also support true small-caps (where the // font supports it) in the future. @@ -133,6 +137,7 @@ impl FontContext { metrics: metrics, shape_cache: HashCache::new(), glyph_advance_cache: HashCache::new(), + font_key: font_key, } }) } @@ -201,14 +206,15 @@ impl FontContext { } if !cache_hit { - let font_template = self.font_cache_thread.find_font_template(family.clone(), - desc.clone()); - match font_template { - Some(font_template) => { - let layout_font = self.create_layout_font(font_template, + let template_info = self.font_cache_thread.find_font_template(family.clone(), + desc.clone()); + match template_info { + Some(template_info) => { + let layout_font = self.create_layout_font(template_info.font_template, desc.clone(), style.font_size, - style.font_variant); + style.font_variant, + template_info.font_key); let font = match layout_font { Ok(layout_font) => { let layout_font = Rc::new(RefCell::new(layout_font)); @@ -250,11 +256,12 @@ impl FontContext { } if !cache_hit { - let font_template = self.font_cache_thread.last_resort_font_template(desc.clone()); - let layout_font = self.create_layout_font(font_template, + let template_info = self.font_cache_thread.last_resort_font_template(desc.clone()); + let layout_font = self.create_layout_font(template_info.font_template, desc.clone(), style.font_size, - style.font_variant); + style.font_variant, + template_info.font_key); match layout_font { Ok(layout_font) => { let layout_font = Rc::new(RefCell::new(layout_font)); diff --git a/components/gfx/lib.rs b/components/gfx/lib.rs index 4d17ad41cb1..cb2576dba5c 100644 --- a/components/gfx/lib.rs +++ b/components/gfx/lib.rs @@ -75,6 +75,7 @@ extern crate unicode_script; extern crate url; #[macro_use] extern crate util; +extern crate webrender_traits; pub use paint_context::PaintContext; diff --git a/components/gfx/platform/freetype/font_template.rs b/components/gfx/platform/freetype/font_template.rs index 30f4ffd5437..55a530a7050 100644 --- a/components/gfx/platform/freetype/font_template.rs +++ b/components/gfx/platform/freetype/font_template.rs @@ -5,6 +5,7 @@ use std::fs::File; use std::io::Read; use string_cache::Atom; +use webrender_traits::NativeFontHandle; /// Platform specific font representation for Linux. /// The identifier is an absolute path, and the bytes @@ -36,4 +37,22 @@ impl FontTemplateData { identifier: identifier, } } + + /// Returns a clone of the data in this font. This may be a hugely expensive + /// operation (depending on the platform) which performs synchronous disk I/O + /// and should never be done lightly. + pub fn bytes(&self) -> Vec<u8> { + self.bytes.clone() + } + + /// Returns a clone of the bytes in this font if they are in memory. This function never + /// performs disk I/O. + pub fn bytes_if_in_memory(&self) -> Option<Vec<u8>> { + Some(self.bytes()) + } + + /// Returns the native font that underlies this font template, if applicable. + pub fn native_font(&self) -> Option<NativeFontHandle> { + None + } } diff --git a/components/gfx/platform/macos/font_template.rs b/components/gfx/platform/macos/font_template.rs index d6ee6b9f3f0..f15527e6a9f 100644 --- a/components/gfx/platform/macos/font_template.rs +++ b/components/gfx/platform/macos/font_template.rs @@ -9,9 +9,12 @@ use core_text::font::CTFont; use serde::de::{Error, Visitor}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::borrow::ToOwned; +use std::fs::File; +use std::io::Read; use std::ops::Deref; use std::sync::Mutex; use string_cache::Atom; +use url::Url; /// Platform specific font representation for mac. /// The identifier is a PostScript font name. The @@ -62,6 +65,39 @@ impl FontTemplateData { } ctfont.as_ref().map(|ctfont| (*ctfont).clone()) } + + /// Returns a clone of the data in this font. This may be a hugely expensive + /// operation (depending on the platform) which performs synchronous disk I/O + /// and should never be done lightly. + pub fn bytes(&self) -> Vec<u8> { + match self.bytes_if_in_memory() { + Some(font_data) => return font_data, + None => {} + } + + let path = Url::parse(&*self.ctfont() + .expect("No Core Text font available!") + .url() + .expect("No URL for Core Text font!") + .get_string() + .to_string()).expect("Couldn't parse Core Text font URL!") + .to_file_path() + .expect("Core Text font didn't name a path!"); + let mut bytes = Vec::new(); + File::open(path).expect("Couldn't open font file!").read_to_end(&mut bytes).unwrap(); + bytes + } + + /// Returns a clone of the bytes in this font if they are in memory. This function never + /// performs disk I/O. + pub fn bytes_if_in_memory(&self) -> Option<Vec<u8>> { + self.font_data.clone() + } + + /// Returns the native font that underlies this font template, if applicable. + pub fn native_font(&self) -> Option<CGFont> { + self.ctfont().map(|ctfont| ctfont.copy_to_CGFont()) + } } #[derive(Debug)] diff --git a/components/gfx/text/text_run.rs b/components/gfx/text/text_run.rs index 5b8acb5e1c5..5a3d086de7e 100644 --- a/components/gfx/text/text_run.rs +++ b/components/gfx/text/text_run.rs @@ -13,6 +13,7 @@ use std::sync::Arc; use text::glyph::{CharIndex, GlyphStore}; use util::range::Range; use util::vec::{Comparator, FullBinarySearchMethods}; +use webrender_traits; thread_local! { static INDEX_OF_FIRST_GLYPH_RUN_CACHE: Cell<Option<(*const TextRun, CharIndex, usize)>> = @@ -27,6 +28,7 @@ pub struct TextRun { pub font_template: Arc<FontTemplateData>, pub actual_pt_size: Au, pub font_metrics: FontMetrics, + pub font_key: Option<webrender_traits::FontKey>, /// The glyph runs that make up this text run. pub glyphs: Arc<Vec<GlyphRun>>, pub bidi_level: u8, @@ -177,6 +179,7 @@ impl<'a> TextRun { text: Arc::new(text), font_metrics: font.metrics.clone(), font_template: font.handle.template(), + font_key: font.font_key, actual_pt_size: font.actual_pt_size, glyphs: Arc::new(glyphs), bidi_level: bidi_level, diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index d549967e753..99bf99cd47a 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -56,6 +56,9 @@ path = "../util" [dependencies.ipc-channel] git = "https://github.com/servo/ipc-channel" +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + [dependencies] app_units = {version = "0.2.1", features = ["plugins"]} bitflags = "0.3" diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 00f1d9e4d75..275e69f1e04 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -13,7 +13,7 @@ use app_units::{Au, AU_PER_PX}; use azure::azure_hl::Color; use block::BlockFlow; -use canvas_traits::{CanvasMsg, FromLayoutMsg}; +use canvas_traits::{CanvasMsg, CanvasPixelData, CanvasData, FromLayoutMsg}; use context::LayoutContext; use euclid::num::Zero; use euclid::{Matrix4, Point2D, Point3D, Rect, SideOffsets2D, Size2D}; @@ -26,7 +26,7 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayIte use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion}; use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection}; use gfx::display_list::{GradientDisplayItem}; -use gfx::display_list::{GradientStop, ImageDisplayItem, LayeredItem, LayerInfo}; +use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGLDisplayItem, LayeredItem, LayerInfo}; use gfx::display_list::{LineDisplayItem, OpaqueNode, SolidColorDisplayItem}; use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation}; use gfx::paint_thread::THREAD_TINT_COLORS; @@ -50,8 +50,7 @@ use style::properties::style_structs::Border; use style::properties::{self, ComputedValues}; use style::values::RGBA; use style::values::computed; -use style::values::computed::LinearGradient; -use style::values::computed::{LengthOrNone, LengthOrPercentage, LengthOrPercentageOrAuto}; +use style::values::computed::{LengthOrNone, LengthOrPercentage, LengthOrPercentageOrAuto, LinearGradient}; use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection}; use style_traits::cursor::Cursor; use table_cell::CollapsedBordersForCell; @@ -948,9 +947,12 @@ impl FragmentDisplayListBuilding for Fragment { stacking_relative_flow_origin, self); - if !stacking_relative_border_box.intersects(stacking_relative_display_port) { - debug!("Fragment::build_display_list: outside display port"); - return + // webrender deals with all culling via aabb + if !opts::get().use_webrender { + if !stacking_relative_border_box.intersects(stacking_relative_display_port) { + debug!("Fragment::build_display_list: outside display port"); + return + } } // Calculate the clip rect. If there's nothing to render at all, don't even construct @@ -1112,20 +1114,31 @@ impl FragmentDisplayListBuilding for Fragment { } SpecificFragmentInfo::Iframe(ref fragment_info) => { if !stacking_relative_content_box.is_empty() { - let layer_id = self.layer_id(); - display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem { - item: DisplayItem::NoopClass( - box BaseDisplayItem::new(&stacking_relative_content_box, - DisplayItemMetadata::new(self.node, - &*self.style, - Cursor::DefaultCursor), - clip)), - layer_id: layer_id - })); - - display_list.layer_info.push_back(LayerInfo::new(layer_id, - ScrollPolicy::Scrollable, - Some(fragment_info.pipeline_id))); + if opts::get().use_webrender { + display_list.content.push_back(DisplayItem::IframeClass(box IframeDisplayItem { + base: BaseDisplayItem::new(&stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + clip), + iframe: fragment_info.pipeline_id, + })); + } else { + let layer_id = self.layer_id(); + display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem { + item: DisplayItem::NoopClass( + box BaseDisplayItem::new(&stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + clip)), + layer_id: layer_id + })); + + display_list.layer_info.push_back(LayerInfo::new(layer_id, + ScrollPolicy::Scrollable, + Some(fragment_info.pipeline_id))); + } } } SpecificFragmentInfo::Image(ref mut image_fragment) => { @@ -1144,7 +1157,6 @@ impl FragmentDisplayListBuilding for Fragment { } } SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => { - // TODO(ecoal95): make the canvas with a renderer use the custom layer let width = canvas_fragment_info.replaced_image_fragment_info .computed_inline_size.map_or(0, |w| w.to_px() as usize); let height = canvas_fragment_info.replaced_image_fragment_info @@ -1156,7 +1168,7 @@ impl FragmentDisplayListBuilding for Fragment { let ipc_renderer = ipc_renderer.lock().unwrap(); let (sender, receiver) = ipc::channel().unwrap(); ipc_renderer.send(CanvasMsg::FromLayout( - FromLayoutMsg::SendPixelContents(sender))).unwrap(); + FromLayoutMsg::SendData(sender))).unwrap(); let data = receiver.recv().unwrap(); // Propagate the layer and the renderer to the paint thread. @@ -1165,31 +1177,54 @@ impl FragmentDisplayListBuilding for Fragment { data }, - None => IpcSharedMemory::from_byte(0xFFu8, width * height * 4), - }; - let display_item = DisplayItem::ImageClass(box ImageDisplayItem { - base: BaseDisplayItem::new(&stacking_relative_content_box, - DisplayItemMetadata::new(self.node, - &*self.style, - Cursor::DefaultCursor), - clip), - image: Arc::new(Image { - width: width as u32, - height: height as u32, - format: PixelFormat::RGBA8, - bytes: canvas_data, + None => CanvasData::Pixels(CanvasPixelData { + image_data: IpcSharedMemory::from_byte(0xFFu8, width * height * 4), + image_key: None, }), - stretch_size: stacking_relative_content_box.size, - image_rendering: image_rendering::T::Auto, - }); + }; - display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem { - item: display_item, - layer_id: layer_id - })); + let display_item = match canvas_data { + CanvasData::Pixels(canvas_data) => { + DisplayItem::ImageClass(box ImageDisplayItem { + base: BaseDisplayItem::new(&stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + clip), + image: Arc::new(Image { + width: width as u32, + height: height as u32, + format: PixelFormat::RGBA8, + bytes: canvas_data.image_data, + id: canvas_data.image_key, + }), + stretch_size: stacking_relative_content_box.size, + image_rendering: image_rendering::T::Auto, + }) + } + CanvasData::WebGL(context_id) => { + DisplayItem::WebGLClass(box WebGLDisplayItem { + base: BaseDisplayItem::new(&stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + clip), + context_id: context_id, + }) + } + }; + + if opts::get().use_webrender { + display_list.content.push_back(display_item); + } else { + display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem { + item: display_item, + layer_id: layer_id + })); - display_list.layer_info.push_back( - LayerInfo::new(layer_id, ScrollPolicy::Scrollable, None)); + display_list.layer_info.push_back( + LayerInfo::new(layer_id, ScrollPolicy::Scrollable, None)); + } } } SpecificFragmentInfo::UnscannedText(_) => { @@ -1993,4 +2028,3 @@ pub enum StackingContextCreationMode { OuterScrollWrapper, InnerScrollWrapper, } - diff --git a/components/layout/inline.rs b/components/layout/inline.rs index d20fb2224a1..1516fd636eb 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -1928,9 +1928,14 @@ impl InlineMetrics { #[inline] pub fn from_font_metrics(font_metrics: &FontMetrics, line_height: Au) -> InlineMetrics { let leading = line_height - (font_metrics.ascent + font_metrics.descent); + // Calculating the half leading here and then using leading - half_leading + // below ensure that we don't introduce any rounding accuracy issues here. + // The invariant is that the resulting total line height must exactly + // equal the requested line_height. + let half_leading = leading.scale_by(0.5); InlineMetrics { - block_size_above_baseline: font_metrics.ascent + leading.scale_by(0.5), - depth_below_baseline: font_metrics.descent + leading.scale_by(0.5), + block_size_above_baseline: font_metrics.ascent + half_leading, + depth_below_baseline: font_metrics.descent + leading - half_leading, ascent: font_metrics.ascent, } } diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index a540039c51b..a772e0eb043 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -35,7 +35,7 @@ use ipc_channel::router::ROUTER; use layout_debug; use layout_traits::LayoutThreadFactory; use log; -use msg::constellation_msg::{ConstellationChan, Failure, PipelineId}; +use msg::constellation_msg::{ConstellationChan, ConvertPipelineIdToWebRender, Failure, PipelineId}; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread}; use parallel; use profile_traits::mem::{self, Report, ReportKind, ReportsChan}; @@ -80,6 +80,8 @@ use util::opts; use util::thread; use util::thread_state; use util::workqueue::WorkQueue; +use webrender_helpers::WebRenderStackingContextConverter; +use webrender_traits; use wrapper::{LayoutNode, NonOpaqueStyleAndLayoutData, ServoLayoutNode, ThreadSafeLayoutNode}; /// The number of screens of data we're allowed to generate display lists for in each direction. @@ -221,6 +223,8 @@ pub struct LayoutThread { /// The CSS error reporter for all CSS loaded in this layout thread error_reporter: CSSErrorReporter, + // Webrender interface, if enabled. + webrender_api: Option<webrender_traits::RenderApi>, } impl LayoutThreadFactory for LayoutThread { @@ -240,7 +244,8 @@ impl LayoutThreadFactory for LayoutThread { time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, shutdown_chan: IpcSender<()>, - content_process_shutdown_chan: IpcSender<()>) { + content_process_shutdown_chan: IpcSender<()>, + webrender_api_sender: Option<webrender_traits::RenderApiSender>) { let ConstellationChan(con_chan) = constellation_chan.clone(); thread::spawn_named_with_send_on_failure(format!("LayoutThread {:?}", id), thread_state::LAYOUT, @@ -258,7 +263,8 @@ impl LayoutThreadFactory for LayoutThread { image_cache_thread, font_cache_thread, time_profiler_chan, - mem_profiler_chan.clone()); + mem_profiler_chan.clone(), + webrender_api_sender); let reporter_name = format!("layout-reporter-{}", id); mem_profiler_chan.run_with_memory_reporting(|| { @@ -367,7 +373,8 @@ impl LayoutThread { image_cache_thread: ImageCacheThread, font_cache_thread: FontCacheThread, time_profiler_chan: time::ProfilerChan, - mem_profiler_chan: mem::ProfilerChan) + mem_profiler_chan: mem::ProfilerChan, + webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> LayoutThread { let device = Device::new( MediaType::Screen, @@ -437,6 +444,7 @@ impl LayoutThread { expired_animations: Arc::new(RwLock::new(HashMap::new())), epoch: Epoch(0), viewport_size: Size2D::new(Au(0), Au(0)), + webrender_api: webrender_api_sender.map(|wr| wr.create_api()), rw_data: Arc::new(Mutex::new( LayoutThreadData { constellation_chan: constellation_chan, @@ -705,7 +713,8 @@ impl LayoutThread { self.time_profiler_chan.clone(), self.mem_profiler_chan.clone(), info.layout_shutdown_chan, - info.content_process_shutdown_chan); + info.content_process_shutdown_chan, + self.webrender_api.as_ref().map(|wr| wr.clone_sender())); } /// Enters a quiescent state in which no new messages will be processed until an `ExitNow` is @@ -908,9 +917,40 @@ impl LayoutThread { debug!("Layout done!"); self.epoch.next(); - self.paint_chan - .send(LayoutToPaintMsg::PaintInit(self.epoch, paint_layer)) - .unwrap(); + + if opts::get().use_webrender { + let api = self.webrender_api.as_ref().unwrap(); + // TODO: Avoid the temporary conversion and build webrender sc/dl directly! + let Epoch(epoch_number) = self.epoch; + let epoch = webrender_traits::Epoch(epoch_number); + let pipeline_id = self.id.to_webrender(); + + // TODO(gw) For now only create a root scrolling layer! + let root_scroll_layer_id = webrender_traits::ScrollLayerId::new(pipeline_id, 0); + let sc_id = rw_data.stacking_context.as_ref() + .unwrap() + .convert_to_webrender(&self.webrender_api.as_ref().unwrap(), + pipeline_id, + epoch, + Some(root_scroll_layer_id)); + let root_background_color = webrender_traits::ColorF::new(root_background_color.r, + root_background_color.g, + root_background_color.b, + root_background_color.a); + + let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(), + self.viewport_size.height.to_f32_px()); + + api.set_root_stacking_context(sc_id, + root_background_color, + epoch, + pipeline_id, + viewport_size); + } else { + self.paint_chan + .send(LayoutToPaintMsg::PaintInit(self.epoch, paint_layer)) + .unwrap(); + } } }); } diff --git a/components/layout/lib.rs b/components/layout/lib.rs index 498e91fb206..431f576ca78 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -59,6 +59,7 @@ extern crate unicode_script; extern crate url; #[macro_use] extern crate util; +extern crate webrender_traits; #[macro_use] mod layout_debug; @@ -95,4 +96,5 @@ mod table_rowgroup; mod table_wrapper; mod text; mod traversal; +mod webrender_helpers; mod wrapper; diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs new file mode 100644 index 00000000000..a1ab8fac3fe --- /dev/null +++ b/components/layout/webrender_helpers.rs @@ -0,0 +1,481 @@ +/* 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/. */ + +// TODO(gw): This contains helper traits and implementations for converting Servo display lists +// into WebRender display lists. In the future, this step should be completely removed. +// This might be achieved by sharing types between WR and Servo display lists, or +// completely converting layout to directly generate WebRender display lists, for example. + +use app_units::Au; +use azure::azure_hl::Color; +use euclid::num::Zero; +use euclid::{Point2D, Rect, Size2D}; +use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion}; +use gfx::display_list::{DisplayItem, DisplayList}; +use gfx::display_list::{GradientStop, StackingContext}; +use gfx_traits::ScrollPolicy; +use msg::constellation_msg::ConvertPipelineIdToWebRender; +use style::computed_values::filter::{self, Filter}; +use style::computed_values::{image_rendering, mix_blend_mode}; +use style::values::computed::BorderStyle; +use webrender_traits; + +pub trait WebRenderStackingContextConverter { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch, + scroll_layer_id: Option<webrender_traits::ScrollLayerId>) + -> webrender_traits::StackingContextId; +} + +trait WebRenderDisplayListConverter { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch) -> webrender_traits::DisplayListBuilder; +} + +trait WebRenderDisplayItemConverter { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch, + level: webrender_traits::StackingLevel, + builder: &mut webrender_traits::DisplayListBuilder); +} + +trait ToBorderStyle { + fn to_border_style(&self) -> webrender_traits::BorderStyle; +} + +impl ToBorderStyle for BorderStyle { + fn to_border_style(&self) -> webrender_traits::BorderStyle { + match *self { + BorderStyle::none => webrender_traits::BorderStyle::None, + BorderStyle::solid => webrender_traits::BorderStyle::Solid, + BorderStyle::double => webrender_traits::BorderStyle::Double, + BorderStyle::dotted => webrender_traits::BorderStyle::Dotted, + BorderStyle::dashed => webrender_traits::BorderStyle::Dashed, + BorderStyle::hidden => webrender_traits::BorderStyle::Hidden, + BorderStyle::groove => webrender_traits::BorderStyle::Groove, + BorderStyle::ridge => webrender_traits::BorderStyle::Ridge, + BorderStyle::inset => webrender_traits::BorderStyle::Inset, + BorderStyle::outset => webrender_traits::BorderStyle::Outset, + } + } +} + +trait ToBoxShadowClipMode { + fn to_clip_mode(&self) -> webrender_traits::BoxShadowClipMode; +} + +impl ToBoxShadowClipMode for BoxShadowClipMode { + fn to_clip_mode(&self) -> webrender_traits::BoxShadowClipMode { + match *self { + BoxShadowClipMode::None => webrender_traits::BoxShadowClipMode::None, + BoxShadowClipMode::Inset => webrender_traits::BoxShadowClipMode::Inset, + BoxShadowClipMode::Outset => webrender_traits::BoxShadowClipMode::Outset, + } + } +} + +trait ToSizeF { + fn to_sizef(&self) -> Size2D<f32>; +} + +trait ToPointF { + fn to_pointf(&self) -> Point2D<f32>; +} + +impl ToPointF for Point2D<Au> { + fn to_pointf(&self) -> Point2D<f32> { + Point2D::new(self.x.to_f32_px(), self.y.to_f32_px()) + } +} + +impl ToSizeF for Size2D<Au> { + fn to_sizef(&self) -> Size2D<f32> { + Size2D::new(self.width.to_f32_px(), self.height.to_f32_px()) + } +} + +trait ToRectF { + fn to_rectf(&self) -> Rect<f32>; +} + +impl ToRectF for Rect<Au> { + fn to_rectf(&self) -> Rect<f32> { + let x = self.origin.x.to_f32_px(); + let y = self.origin.y.to_f32_px(); + let w = self.size.width.to_f32_px(); + let h = self.size.height.to_f32_px(); + Rect::new(Point2D::new(x, y), Size2D::new(w, h)) + } +} + +trait ToColorF { + fn to_colorf(&self) -> webrender_traits::ColorF; +} + +impl ToColorF for Color { + fn to_colorf(&self) -> webrender_traits::ColorF { + webrender_traits::ColorF::new(self.r, self.g, self.b, self.a) + } +} + +trait ToGradientStop { + fn to_gradient_stop(&self) -> webrender_traits::GradientStop; +} + +impl ToGradientStop for GradientStop { + fn to_gradient_stop(&self) -> webrender_traits::GradientStop { + webrender_traits::GradientStop { + offset: self.offset, + color: self.color.to_colorf(), + } + } +} + +trait ToClipRegion { + fn to_clip_region(&self) -> webrender_traits::ClipRegion; +} + +impl ToClipRegion for ClippingRegion { + fn to_clip_region(&self) -> webrender_traits::ClipRegion { + webrender_traits::ClipRegion::new(self.main.to_rectf(), + self.complex.iter().map(|complex_clipping_region| { + webrender_traits::ComplexClipRegion::new( + complex_clipping_region.rect.to_rectf(), + complex_clipping_region.radii.to_border_radius(), + ) + }).collect()) + } +} + +trait ToBorderRadius { + fn to_border_radius(&self) -> webrender_traits::BorderRadius; +} + +impl ToBorderRadius for BorderRadii<Au> { + fn to_border_radius(&self) -> webrender_traits::BorderRadius { + webrender_traits::BorderRadius { + top_left: self.top_left.to_sizef(), + top_right: self.top_right.to_sizef(), + bottom_left: self.bottom_left.to_sizef(), + bottom_right: self.bottom_right.to_sizef(), + } + } +} + +trait ToBlendMode { + fn to_blend_mode(&self) -> webrender_traits::MixBlendMode; +} + +impl ToBlendMode for mix_blend_mode::T { + fn to_blend_mode(&self) -> webrender_traits::MixBlendMode { + match *self { + mix_blend_mode::T::normal => webrender_traits::MixBlendMode::Normal, + mix_blend_mode::T::multiply => webrender_traits::MixBlendMode::Multiply, + mix_blend_mode::T::screen => webrender_traits::MixBlendMode::Screen, + mix_blend_mode::T::overlay => webrender_traits::MixBlendMode::Overlay, + mix_blend_mode::T::darken => webrender_traits::MixBlendMode::Darken, + mix_blend_mode::T::lighten => webrender_traits::MixBlendMode::Lighten, + mix_blend_mode::T::color_dodge => webrender_traits::MixBlendMode::ColorDodge, + mix_blend_mode::T::color_burn => webrender_traits::MixBlendMode::ColorBurn, + mix_blend_mode::T::hard_light => webrender_traits::MixBlendMode::HardLight, + mix_blend_mode::T::soft_light => webrender_traits::MixBlendMode::SoftLight, + mix_blend_mode::T::difference => webrender_traits::MixBlendMode::Difference, + mix_blend_mode::T::exclusion => webrender_traits::MixBlendMode::Exclusion, + mix_blend_mode::T::hue => webrender_traits::MixBlendMode::Hue, + mix_blend_mode::T::saturation => webrender_traits::MixBlendMode::Saturation, + mix_blend_mode::T::color => webrender_traits::MixBlendMode::Color, + mix_blend_mode::T::luminosity => webrender_traits::MixBlendMode::Luminosity, + } + } +} + +trait ToImageRendering { + fn to_image_rendering(&self) -> webrender_traits::ImageRendering; +} + +impl ToImageRendering for image_rendering::T { + fn to_image_rendering(&self) -> webrender_traits::ImageRendering { + match *self { + image_rendering::T::CrispEdges => webrender_traits::ImageRendering::CrispEdges, + image_rendering::T::Auto => webrender_traits::ImageRendering::Auto, + image_rendering::T::Pixelated => webrender_traits::ImageRendering::Pixelated, + } + } +} + +trait ToFilterOps { + fn to_filter_ops(&self) -> Vec<webrender_traits::FilterOp>; +} + +impl ToFilterOps for filter::T { + fn to_filter_ops(&self) -> Vec<webrender_traits::FilterOp> { + let mut result = Vec::with_capacity(self.filters.len()); + for filter in self.filters.iter() { + match *filter { + Filter::Blur(radius) => result.push(webrender_traits::FilterOp::Blur(radius)), + Filter::Brightness(amount) => result.push(webrender_traits::FilterOp::Brightness(amount)), + Filter::Contrast(amount) => result.push(webrender_traits::FilterOp::Contrast(amount)), + Filter::Grayscale(amount) => result.push(webrender_traits::FilterOp::Grayscale(amount)), + Filter::HueRotate(angle) => result.push(webrender_traits::FilterOp::HueRotate(angle.0)), + Filter::Invert(amount) => result.push(webrender_traits::FilterOp::Invert(amount)), + Filter::Opacity(amount) => result.push(webrender_traits::FilterOp::Opacity(amount)), + Filter::Saturate(amount) => result.push(webrender_traits::FilterOp::Saturate(amount)), + Filter::Sepia(amount) => result.push(webrender_traits::FilterOp::Sepia(amount)), + } + } + result + } +} + +impl WebRenderStackingContextConverter for StackingContext { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch, + scroll_layer_id: Option<webrender_traits::ScrollLayerId>) + -> webrender_traits::StackingContextId { + let scroll_policy = self.layer_info + .map_or(webrender_traits::ScrollPolicy::Scrollable, |info| { + match info.scroll_policy { + ScrollPolicy::Scrollable => webrender_traits::ScrollPolicy::Scrollable, + ScrollPolicy::FixedPosition => webrender_traits::ScrollPolicy::Fixed, + } + }); + + let mut sc = webrender_traits::StackingContext::new(scroll_layer_id, + scroll_policy, + self.bounds.to_rectf(), + self.overflow.to_rectf(), + self.z_index, + &self.transform, + &self.perspective, + self.establishes_3d_context, + self.blend_mode.to_blend_mode(), + self.filters.to_filter_ops()); + + let dl_builder = self.display_list.convert_to_webrender(api, + pipeline_id, + epoch); + api.add_display_list(dl_builder, &mut sc, pipeline_id, epoch); + + api.add_stacking_context(sc, pipeline_id, epoch) + } +} + +impl WebRenderDisplayListConverter for Box<DisplayList> { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch) -> webrender_traits::DisplayListBuilder { + let mut builder = webrender_traits::DisplayListBuilder::new(); + + for item in &self.background_and_borders { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::BackgroundAndBorders, + &mut builder); + } + + for item in &self.block_backgrounds_and_borders { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::BlockBackgroundAndBorders, + &mut builder); + } + + for item in &self.floats { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::Floats, + &mut builder); + } + + for item in &self.content { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::Content, + &mut builder); + } + + for item in &self.positioned_content { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::PositionedContent, + &mut builder); + } + + for item in &self.outlines { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::Outlines, + &mut builder); + } + + builder + } +} + +impl WebRenderDisplayItemConverter for DisplayItem { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch, + level: webrender_traits::StackingLevel, + builder: &mut webrender_traits::DisplayListBuilder) { + match *self { + DisplayItem::SolidColorClass(ref item) => { + let color = item.color.to_colorf(); + if color.a > 0.0 { + builder.push_rect(level, + item.base.bounds.to_rectf(), + item.base.clip.to_clip_region(), + color); + } + } + DisplayItem::TextClass(ref item) => { + let mut origin = item.baseline_origin.clone(); + let mut glyphs = vec!(); + + for slice in item.text_run.natural_word_slices_in_visual_order(&item.range) { + for glyph in slice.glyphs.iter_glyphs_for_char_range(&slice.range) { + let glyph_advance = glyph.advance(); + let glyph_offset = glyph.offset().unwrap_or(Point2D::zero()); + let glyph = webrender_traits::GlyphInstance { + index: glyph.id(), + x: (origin.x + glyph_offset.x).to_f32_px(), + y: (origin.y + glyph_offset.y).to_f32_px(), + }; + origin = Point2D::new(origin.x + glyph_advance, origin.y); + glyphs.push(glyph); + }; + } + + if glyphs.len() > 0 { + builder.push_text(level, + item.base.bounds.to_rectf(), + item.base.clip.to_clip_region(), + glyphs, + item.text_run.font_key.expect("Font not added to webrender!"), + item.text_color.to_colorf(), + item.text_run.actual_pt_size, + item.blur_radius); + } + } + DisplayItem::ImageClass(ref item) => { + if let Some(id) = item.image.id { + if item.stretch_size.width > Au(0) && + item.stretch_size.height > Au(0) { + builder.push_image(level, + item.base.bounds.to_rectf(), + item.base.clip.to_clip_region(), + item.stretch_size.to_sizef(), + item.image_rendering.to_image_rendering(), + id); + } + } + } + DisplayItem::WebGLClass(ref item) => { + builder.push_webgl_canvas(level, + item.base.bounds.to_rectf(), + item.base.clip.to_clip_region(), + item.context_id); + } + DisplayItem::BorderClass(ref item) => { + let rect = item.base.bounds.to_rectf(); + let left = webrender_traits::BorderSide { + width: item.border_widths.left.to_f32_px(), + color: item.color.left.to_colorf(), + style: item.style.left.to_border_style(), + }; + let top = webrender_traits::BorderSide { + width: item.border_widths.top.to_f32_px(), + color: item.color.top.to_colorf(), + style: item.style.top.to_border_style(), + }; + let right = webrender_traits::BorderSide { + width: item.border_widths.right.to_f32_px(), + color: item.color.right.to_colorf(), + style: item.style.right.to_border_style(), + }; + let bottom = webrender_traits::BorderSide { + width: item.border_widths.bottom.to_f32_px(), + color: item.color.bottom.to_colorf(), + style: item.style.bottom.to_border_style(), + }; + let radius = item.radius.to_border_radius(); + builder.push_border(level, + rect, + item.base.clip.to_clip_region(), + left, + top, + right, + bottom, + radius); + } + DisplayItem::GradientClass(ref item) => { + let rect = item.base.bounds.to_rectf(); + let start_point = item.start_point.to_pointf(); + let end_point = item.end_point.to_pointf(); + let mut stops = Vec::new(); + for stop in &item.stops { + stops.push(stop.to_gradient_stop()); + } + builder.push_gradient(level, + rect, + item.base.clip.to_clip_region(), + start_point, + end_point, + stops); + } + DisplayItem::LineClass(..) => { + println!("TODO DisplayItem::LineClass"); + } + DisplayItem::LayeredItemClass(..) | + DisplayItem::NoopClass(..) => { + panic!("Unexpected in webrender!"); + } + DisplayItem::BoxShadowClass(ref item) => { + let rect = item.base.bounds.to_rectf(); + let box_bounds = item.box_bounds.to_rectf(); + builder.push_box_shadow(level, + rect, + item.base.clip.to_clip_region(), + box_bounds, + item.offset.to_pointf(), + item.color.to_colorf(), + item.blur_radius.to_f32_px(), + item.spread_radius.to_f32_px(), + item.border_radius.to_f32_px(), + item.clip_mode.to_clip_mode()); + } + DisplayItem::IframeClass(ref item) => { + let rect = item.base.bounds.to_rectf(); + let pipeline_id = item.iframe.to_webrender(); + builder.push_iframe(level, + rect, + item.base.clip.to_clip_region(), + pipeline_id); + } + DisplayItem::StackingContextClass(ref item) => { + let stacking_context_id = item.convert_to_webrender(api, + pipeline_id, + epoch, + None); + builder.push_stacking_context(level, stacking_context_id); + } + } + } +} diff --git a/components/layout_traits/Cargo.toml b/components/layout_traits/Cargo.toml index 33353c52773..1afb7d9b920 100644 --- a/components/layout_traits/Cargo.toml +++ b/components/layout_traits/Cargo.toml @@ -28,6 +28,9 @@ path = "../util" [dependencies.ipc-channel] git = "https://github.com/servo/ipc-channel" +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + [dependencies] serde = "0.6" serde_macros = "0.6" diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs index e5b39a1db4b..2be15566199 100644 --- a/components/layout_traits/lib.rs +++ b/components/layout_traits/lib.rs @@ -14,6 +14,7 @@ extern crate script_traits; extern crate serde; extern crate url; extern crate util; +extern crate webrender_traits; // This module contains traits in layout used generically // in the rest of Servo. @@ -54,5 +55,6 @@ pub trait LayoutThreadFactory { time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, shutdown_chan: IpcSender<()>, - content_process_shutdown_chan: IpcSender<()>); + content_process_shutdown_chan: IpcSender<()>, + webrender_api_sender: Option<webrender_traits::RenderApiSender>); } diff --git a/components/msg/Cargo.toml b/components/msg/Cargo.toml index b96bdeb953a..05f84756a5f 100644 --- a/components/msg/Cargo.toml +++ b/components/msg/Cargo.toml @@ -20,6 +20,9 @@ git = "https://github.com/servo/ipc-channel" [dependencies.plugins] path = "../plugins" +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + [dependencies] bitflags = "0.3" cssparser = {version = "0.5.3", features = ["heap_size", "serde-serialization"]} diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index adefb76010c..83f308b26fd 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -17,6 +17,7 @@ use std::fmt; use url::Url; use util::geometry::{PagePx, ViewportPx}; use webdriver_msg::{LoadStatus, WebDriverScriptCommand}; +use webrender_traits; #[derive(Deserialize, Serialize)] pub struct ConstellationChan<T: Deserialize + Serialize>(pub IpcSender<T>); @@ -207,7 +208,7 @@ pub enum WebDriverCommandMsg { TakeScreenshot(PipelineId, IpcSender<Option<Image>>), } -#[derive(Deserialize, Eq, PartialEq, Serialize, HeapSizeOf)] +#[derive(Clone, Copy, Deserialize, Eq, PartialEq, Serialize, HeapSizeOf)] pub enum PixelFormat { K8, // Luminance channel only KA8, // Luminance + alpha @@ -228,6 +229,8 @@ pub struct Image { pub format: PixelFormat, #[ignore_heap_size_of = "Defined in ipc-channel"] pub bytes: IpcSharedMemory, + #[ignore_heap_size_of = "Defined in webrender_traits"] + pub id: Option<webrender_traits::ImageKey>, } /// Similar to net::resource_thread::LoadData @@ -353,3 +356,28 @@ impl fmt::Display for PipelineId { #[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] pub struct SubpageId(pub u32); + +pub trait ConvertPipelineIdToWebRender { + fn to_webrender(&self) -> webrender_traits::PipelineId; +} + +pub trait ConvertPipelineIdFromWebRender { + fn from_webrender(&self) -> PipelineId; +} + +impl ConvertPipelineIdToWebRender for PipelineId { + fn to_webrender(&self) -> webrender_traits::PipelineId { + let PipelineNamespaceId(namespace_id) = self.namespace_id; + let PipelineIndex(index) = self.index; + webrender_traits::PipelineId(namespace_id, index) + } +} + +impl ConvertPipelineIdFromWebRender for webrender_traits::PipelineId { + fn from_webrender(&self) -> PipelineId { + PipelineId { + namespace_id: PipelineNamespaceId(self.0), + index: PipelineIndex(self.1), + } + } +} diff --git a/components/msg/lib.rs b/components/msg/lib.rs index febf188fd77..93a513ef742 100644 --- a/components/msg/lib.rs +++ b/components/msg/lib.rs @@ -16,6 +16,7 @@ extern crate rustc_serialize; extern crate serde; extern crate url; extern crate util; +extern crate webrender_traits; pub mod constellation_msg; pub mod webdriver_msg; diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml index 5aef635d0fe..ae03f560029 100644 --- a/components/net/Cargo.toml +++ b/components/net/Cargo.toml @@ -28,6 +28,9 @@ path = "../msg" [dependencies.ipc-channel] git = "https://github.com/servo/ipc-channel" +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + [dependencies] hyper = { version = "0.7", features = [ "serde-serialization" ] } log = "0.3" diff --git a/components/net/image_cache_thread.rs b/components/net/image_cache_thread.rs index e7d960068e0..22797bda379 100644 --- a/components/net/image_cache_thread.rs +++ b/components/net/image_cache_thread.rs @@ -5,7 +5,7 @@ use immeta::load_from_buf; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; -use net_traits::image::base::{Image, ImageMetadata, load_from_memory}; +use net_traits::image::base::{Image, ImageMetadata, load_from_memory, PixelFormat}; use net_traits::image_cache_thread::ImageResponder; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheCommand, ImageCacheThread, ImageState}; use net_traits::image_cache_thread::{ImageCacheResult, ImageOrMetadataAvailable, ImageResponse, UsePlaceholder}; @@ -23,6 +23,7 @@ use url::Url; use util::resource_files::resources_dir_path; use util::thread::spawn_named; use util::threadpool::ThreadPool; +use webrender_traits; /// /// TODO(gw): Remaining work on image cache: @@ -51,6 +52,12 @@ struct PendingLoad { url: Arc<Url> } +enum LoadResult { + Loaded(Image), + PlaceholderLoaded(Arc<Image>), + None +} + impl PendingLoad { fn new(url: Arc<Url>) -> PendingLoad { PendingLoad { @@ -250,6 +257,9 @@ struct ImageCache { // The placeholder image used when an image fails to load placeholder_image: Option<Arc<Image>>, + + // Webrender API instance, if enabled. + webrender_api: Option<webrender_traits::RenderApi>, } /// Message that the decoder worker threads send to main image cache thread. @@ -265,6 +275,16 @@ enum SelectResult { Decoder(DecoderMsg), } +fn convert_format(format: PixelFormat) -> webrender_traits::ImageFormat { + match format { + PixelFormat::K8 | PixelFormat::KA8 => { + panic!("Not support by webrender yet"); + } + PixelFormat::RGB8 => webrender_traits::ImageFormat::RGB8, + PixelFormat::RGBA8 => webrender_traits::ImageFormat::RGBA8, + } +} + impl ImageCache { fn run(&mut self) { let mut exit_sender: Option<IpcSender<()>> = None; @@ -381,10 +401,10 @@ impl ImageCache { Err(_) => { match self.placeholder_image.clone() { Some(placeholder_image) => { - self.complete_load(msg.key, ImageResponse::PlaceholderLoaded( + self.complete_load(msg.key, LoadResult::PlaceholderLoaded( placeholder_image)) } - None => self.complete_load(msg.key, ImageResponse::None), + None => self.complete_load(msg.key, LoadResult::None), } } } @@ -395,16 +415,34 @@ impl ImageCache { // Handle a message from one of the decoder worker threads fn handle_decoder(&mut self, msg: DecoderMsg) { let image = match msg.image { - None => ImageResponse::None, - Some(image) => ImageResponse::Loaded(Arc::new(image)), + None => LoadResult::None, + Some(image) => LoadResult::Loaded(image), }; self.complete_load(msg.key, image); } // Change state of a url from pending -> loaded. - fn complete_load(&mut self, key: LoadKey, image_response: ImageResponse) { + fn complete_load(&mut self, key: LoadKey, mut load_result: LoadResult) { let pending_load = self.pending_loads.remove(&key).unwrap(); + if let Some(ref webrender_api) = self.webrender_api { + match load_result { + LoadResult::Loaded(ref mut image) => { + let format = convert_format(image.format); + let mut bytes = Vec::new(); + bytes.extend_from_slice(&*image.bytes); + image.id = Some(webrender_api.add_image(image.width, image.height, format, bytes)); + } + LoadResult::PlaceholderLoaded(..) | LoadResult::None => {} + } + } + + let image_response = match load_result { + LoadResult::Loaded(image) => ImageResponse::Loaded(Arc::new(image)), + LoadResult::PlaceholderLoaded(image) => ImageResponse::PlaceholderLoaded(image), + LoadResult::None => ImageResponse::None, + }; + let completed_load = CompletedLoad::new(image_response.clone()); self.completed_loads.insert(pending_load.url, completed_load); @@ -510,7 +548,8 @@ impl ImageCache { } /// Create a new image cache. -pub fn new_image_cache_thread(resource_thread: ResourceThread) -> ImageCacheThread { +pub fn new_image_cache_thread(resource_thread: ResourceThread, + webrender_api: Option<webrender_traits::RenderApi>) -> ImageCacheThread { let (ipc_command_sender, ipc_command_receiver) = ipc::channel().unwrap(); let (progress_sender, progress_receiver) = channel(); let (decoder_sender, decoder_receiver) = channel(); @@ -526,7 +565,14 @@ pub fn new_image_cache_thread(resource_thread: ResourceThread) -> ImageCacheThre file.read_to_end(&mut image_data) }); let placeholder_image = result.ok().map(|_| { - Arc::new(load_from_memory(&image_data).unwrap()) + let mut image = load_from_memory(&image_data).unwrap(); + if let Some(ref webrender_api) = webrender_api { + let format = convert_format(image.format); + let mut bytes = Vec::new(); + bytes.extend_from_slice(&*image.bytes); + image.id = Some(webrender_api.add_image(image.width, image.height, format, bytes)); + } + Arc::new(image) }); // Ask the router to proxy messages received over IPC to us. @@ -543,6 +589,7 @@ pub fn new_image_cache_thread(resource_thread: ResourceThread) -> ImageCacheThre completed_loads: HashMap::new(), resource_thread: resource_thread, placeholder_image: placeholder_image, + webrender_api: webrender_api, }; cache.run(); diff --git a/components/net/lib.rs b/components/net/lib.rs index 143672962cb..fa354bfc439 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -27,6 +27,7 @@ extern crate time; extern crate url; extern crate util; extern crate uuid; +extern crate webrender_traits; extern crate websocket; pub mod about_loader; diff --git a/components/net_traits/image/base.rs b/components/net_traits/image/base.rs index 7faf439e34b..84612aae52b 100644 --- a/components/net_traits/image/base.rs +++ b/components/net_traits/image/base.rs @@ -5,6 +5,7 @@ use ipc_channel::ipc::IpcSharedMemory; use piston_image::{self, DynamicImage, GenericImage, ImageFormat}; use stb_image::image as stb_image2; +use util::opts; use util::vec::byte_swap; pub use msg::constellation_msg::{Image, ImageMetadata, PixelFormat}; @@ -15,14 +16,25 @@ pub use msg::constellation_msg::{Image, ImageMetadata, PixelFormat}; // TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this. fn byte_swap_and_premultiply(data: &mut [u8]) { let length = data.len(); + + // No need to pre-multiply alpha when using direct GPU rendering. + let premultiply_alpha = !opts::get().use_webrender; + for i in (0..length).step_by(4) { let r = data[i + 2]; let g = data[i + 1]; let b = data[i + 0]; let a = data[i + 3]; - data[i + 0] = ((r as u32) * (a as u32) / 255) as u8; - data[i + 1] = ((g as u32) * (a as u32) / 255) as u8; - data[i + 2] = ((b as u32) * (a as u32) / 255) as u8; + + if premultiply_alpha { + data[i + 0] = ((r as u32) * (a as u32) / 255) as u8; + data[i + 1] = ((g as u32) * (a as u32) / 255) as u8; + data[i + 2] = ((b as u32) * (a as u32) / 255) as u8; + } else { + data[i + 0] = r; + data[i + 1] = g; + data[i + 2] = b; + } } } @@ -58,6 +70,7 @@ pub fn load_from_memory(buffer: &[u8]) -> Option<Image> { height: image.height as u32, format: PixelFormat::RGBA8, bytes: IpcSharedMemory::from_bytes(&image.data[..]), + id: None, }) } stb_image2::LoadResult::ImageF32(_image) => { @@ -83,6 +96,7 @@ pub fn load_from_memory(buffer: &[u8]) -> Option<Image> { height: rgba.height(), format: PixelFormat::RGBA8, bytes: IpcSharedMemory::from_bytes(&*rgba), + id: None, }) } Err(e) => { diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 3ab122d2bf7..0288efc206a 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::{CanvasMsg, FromLayoutMsg}; +use canvas_traits::{CanvasMsg, FromLayoutMsg, CanvasData}; use dom::attr::Attr; use dom::attr::AttrValue; use dom::bindings::cell::DOMRefCell; @@ -202,10 +202,17 @@ impl HTMLCanvasElement { let data = if let Some(renderer) = self.ipc_renderer() { let (sender, receiver) = ipc::channel().unwrap(); - let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendPixelContents(sender)); + let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendData(sender)); renderer.send(msg).unwrap(); - receiver.recv().unwrap().to_vec() + match receiver.recv().unwrap() { + CanvasData::Pixels(pixel_data) + => pixel_data.image_data.to_vec(), + CanvasData::WebGL(_) + // TODO(ecoal95): Not sure if WebGL canvas is required for 2d spec, + // but I think it's not. + => return None, + } } else { repeat(0xffu8).take((size.height as usize) * (size.width as usize) * 4).collect() }; diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index ff2d6968e9a..aba9e32b45f 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -72,6 +72,7 @@ pub struct WebGLRenderingContext { #[ignore_heap_size_of = "Defined in ipc-channel"] ipc_renderer: IpcSender<CanvasMsg>, canvas: JS<HTMLCanvasElement>, + #[ignore_heap_size_of = "Defined in webrender_traits"] last_error: Cell<Option<WebGLError>>, texture_unpacking_settings: Cell<TextureUnpacking>, bound_texture_2d: MutNullableHeap<JS<WebGLTexture>>, @@ -462,6 +463,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Some(data) => data, None => return self.webgl_error(InvalidValue), }; + if offset < 0 { return self.webgl_error(InvalidValue); } diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 39b651e0912..9c4a7af6185 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", "gfx_tests 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "glutin_app 0.0.1", "image 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", @@ -42,6 +42,8 @@ dependencies = [ "util 0.0.1", "util_tests 0.0.1", "webdriver_server 0.0.1", + "webrender 0.1.0 (git+https://github.com/glennw/webrender)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -152,7 +154,7 @@ dependencies = [ "canvas_traits 0.0.1", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", "log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -160,6 +162,7 @@ dependencies = [ "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", "plugins 0.0.1", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -179,6 +182,7 @@ dependencies = [ "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -200,7 +204,7 @@ name = "cgl" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -273,7 +277,7 @@ dependencies = [ "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", "gfx_traits 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", @@ -292,6 +296,8 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender 0.1.0 (git+https://github.com/glennw/webrender)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -680,6 +686,7 @@ dependencies = [ "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -728,7 +735,7 @@ dependencies = [ [[package]] name = "gleam" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -748,7 +755,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "compositing 0.0.1", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", "msg 0.0.1", "net_traits 0.0.1", @@ -904,7 +911,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -965,7 +972,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "glx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1018,6 +1025,7 @@ dependencies = [ "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -1034,6 +1042,7 @@ dependencies = [ "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -1194,6 +1203,7 @@ dependencies = [ "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -1218,6 +1228,7 @@ dependencies = [ "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", "websocket 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1334,7 +1345,7 @@ dependencies = [ "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1560,6 +1571,22 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "rustc_version" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scoped_threadpool" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "script" version = "0.0.1" dependencies = [ @@ -1660,6 +1687,11 @@ dependencies = [ ] [[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "serde" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1766,7 +1798,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "expat-sys 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "glx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "io-surface 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2175,6 +2207,42 @@ dependencies = [ ] [[package]] +name = "webrender" +version = "0.1.0" +source = "git+https://github.com/glennw/webrender#90cd6afdd64cdb48f606dbe0ce5d1ac352329004" +dependencies = [ + "app_units 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-text 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", + "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "scoped_threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", +] + +[[package]] +name = "webrender_traits" +version = "0.1.0" +source = "git+https://github.com/glennw/webrender_traits#8ccc1608590d219d1df54e49f2f1e887995b4d60" +dependencies = [ + "app_units 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", + "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "websocket" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index c4d2c6d9f36..9bea00cd956 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -52,6 +52,12 @@ name = "reftest" path = "../../tests/reftest.rs" harness = false +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + +[dependencies.webrender] +git = "https://github.com/glennw/webrender" + [features] default = ["glutin_app", "window", "webdriver"] window = ["glutin_app/window"] diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 6544b69e002..67b6875da48 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -48,6 +48,9 @@ mod export { #[cfg(feature = "webdriver")] extern crate webdriver_server; +extern crate webrender; +extern crate webrender_traits; + #[cfg(feature = "webdriver")] fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) { webdriver_server::start_server(port, constellation); @@ -82,6 +85,7 @@ use std::borrow::Borrow; use std::rc::Rc; use std::sync::mpsc::Sender; use util::opts; +use util::resource_files::resources_dir_path; pub use _util as util; pub use export::canvas; @@ -147,6 +151,35 @@ impl Browser { devtools::start_server(port) }); + let (webrender, webrender_api_sender) = if opts::get().use_webrender { + let mut resource_path = resources_dir_path(); + resource_path.push("shaders"); + + // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up! + let hidpi_factor = window.as_ref() + .map(|window| window.hidpi_factor().get()) + .unwrap_or(1.0); + 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 => hidpi_factor, + } + }; + + let (webrender, webrender_sender) = + webrender::Renderer::new(webrender::RendererOptions { + device_pixel_ratio: device_pixel_ratio, + resource_path: resource_path, + enable_aa: opts.enable_text_antialiasing, + enable_msaa: opts.use_msaa, + enable_profiler: opts.webrender_stats, + }); + (Some(webrender), Some(webrender_sender)) + } else { + (None, None) + }; + // Create the constellation, which maintains the engine // pipelines, including the script and layout threads, as well // as the navigation context. @@ -155,7 +188,8 @@ impl Browser { time_profiler_chan.clone(), mem_profiler_chan.clone(), devtools_chan, - supports_clipboard); + supports_clipboard, + webrender_api_sender.clone()); if cfg!(feature = "webdriver") { if let Some(port) = opts.webdriver_port { @@ -171,6 +205,8 @@ impl Browser { constellation_chan: constellation_chan, time_profiler_chan: time_profiler_chan, mem_profiler_chan: mem_profiler_chan, + webrender: webrender, + webrender_api_sender: webrender_api_sender, }); Browser { @@ -200,11 +236,13 @@ fn create_constellation(opts: opts::Opts, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>, - supports_clipboard: bool) -> Sender<ConstellationMsg> { + supports_clipboard: bool, + webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> Sender<ConstellationMsg> { let resource_thread = new_resource_thread(opts.user_agent.clone(), devtools_chan.clone()); - - let image_cache_thread = new_image_cache_thread(resource_thread.clone()); - let font_cache_thread = FontCacheThread::new(resource_thread.clone()); + let image_cache_thread = new_image_cache_thread(resource_thread.clone(), + webrender_api_sender.as_ref().map(|wr| wr.create_api())); + let font_cache_thread = FontCacheThread::new(resource_thread.clone(), + webrender_api_sender.as_ref().map(|wr| wr.create_api())); let storage_thread: StorageThread = StorageThreadFactory::new(); let initial_state = InitialConstellationState { @@ -217,6 +255,7 @@ fn create_constellation(opts: opts::Opts, time_profiler_chan: time_profiler_chan, mem_profiler_chan: mem_profiler_chan, supports_clipboard: supports_clipboard, + webrender_api_sender: webrender_api_sender, }; let constellation_chan = Constellation::<layout::layout_thread::LayoutThread, diff --git a/components/util/opts.rs b/components/util/opts.rs index b154abe211f..d2dbdc1c382 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -183,6 +183,15 @@ pub struct Opts { /// Enable vsync in the compositor pub enable_vsync: bool, + + /// True to enable the webrender painting/compositing backend. + pub use_webrender: bool, + + /// True to show webrender profiling stats on screen. + pub webrender_stats: bool, + + /// True if WebRender should use multisample antialiasing. + pub use_msaa: bool, } fn print_usage(app: &str, opts: &Options) { @@ -272,6 +281,12 @@ pub struct DebugOptions { /// Disable vsync in the compositor pub disable_vsync: bool, + + /// Show webrender profiling stats on screen. + pub webrender_stats: bool, + + /// Use multisample antialiasing in WebRender. + pub use_msaa: bool, } @@ -307,6 +322,8 @@ impl DebugOptions { "gc-profile" => debug_options.gc_profile = true, "load-webfonts-synchronously" => debug_options.load_webfonts_synchronously = true, "disable-vsync" => debug_options.disable_vsync = true, + "wr-stats" => debug_options.webrender_stats = true, + "msaa" => debug_options.use_msaa = true, "" => {}, _ => return Err(option) }; @@ -354,6 +371,8 @@ pub fn print_debug_usage(app: &str) -> ! { "Load web fonts synchronously to avoid non-deterministic network-driven reflows"); print_option("disable-vsync", "Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate"); + print_option("wr-stats", "Show WebRender profiler on screen."); + print_option("msaa", "Use multisample antialiasing in WebRender."); println!(""); @@ -483,6 +502,9 @@ pub fn default_opts() -> Opts { exit_after_load: false, no_native_titlebar: false, enable_vsync: true, + use_webrender: false, + webrender_stats: false, + use_msaa: false, } } @@ -526,6 +548,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { opts.optmulti("", "pref", "A preference to set to enable", "dom.mozbrowser.enabled"); opts.optflag("b", "no-native-titlebar", "Do not use native titlebar"); + opts.optflag("w", "webrender", "Use webrender backend"); let opt_match = match opts.parse(args) { Ok(m) => m, @@ -668,6 +691,8 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { (contents, url) }).collect(); + let use_webrender = opt_match.opt_present("w") && !opt_match.opt_present("z"); + let opts = Opts { is_running_problem_test: is_running_problem_test, url: Some(url), @@ -717,6 +742,9 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { exit_after_load: opt_match.opt_present("x"), no_native_titlebar: opt_match.opt_present("b"), enable_vsync: !debug_options.disable_vsync, + use_webrender: use_webrender, + webrender_stats: debug_options.webrender_stats, + use_msaa: debug_options.use_msaa, }; set_defaults(opts); diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 67981691d4a..e81d1997c68 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -12,7 +12,7 @@ dependencies = [ "devtools 0.0.1", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "glutin_app 0.0.1", "js 0.1.2 (git+https://github.com/servo/rust-mozjs)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", @@ -141,7 +141,7 @@ dependencies = [ "canvas_traits 0.0.1", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", "log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -149,6 +149,7 @@ dependencies = [ "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", "plugins 0.0.1", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -168,6 +169,7 @@ dependencies = [ "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -189,7 +191,7 @@ name = "cgl" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -247,7 +249,7 @@ dependencies = [ "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", "gfx_traits 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", @@ -266,6 +268,8 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender 0.1.0 (git+https://github.com/glennw/webrender)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -621,6 +625,7 @@ dependencies = [ "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -660,7 +665,7 @@ dependencies = [ [[package]] name = "gleam" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -680,7 +685,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "compositing 0.0.1", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", "msg 0.0.1", "net_traits 0.0.1", @@ -836,7 +841,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -897,7 +902,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "glx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -950,6 +955,7 @@ dependencies = [ "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -966,6 +972,7 @@ dependencies = [ "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -1126,6 +1133,7 @@ dependencies = [ "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -1150,6 +1158,7 @@ dependencies = [ "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", "websocket 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1240,7 +1249,7 @@ dependencies = [ "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1448,6 +1457,22 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "rustc_version" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scoped_threadpool" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "script" version = "0.0.1" dependencies = [ @@ -1539,6 +1564,11 @@ dependencies = [ ] [[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "serde" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1587,7 +1617,7 @@ dependencies = [ "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "glutin_app 0.0.1", "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", @@ -1606,6 +1636,8 @@ dependencies = [ "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "webdriver_server 0.0.1", + "webrender 0.1.0 (git+https://github.com/glennw/webrender)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -1680,7 +1712,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "expat-sys 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "glx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "io-surface 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2061,6 +2093,42 @@ dependencies = [ ] [[package]] +name = "webrender" +version = "0.1.0" +source = "git+https://github.com/glennw/webrender#90cd6afdd64cdb48f606dbe0ce5d1ac352329004" +dependencies = [ + "app_units 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-text 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", + "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "scoped_threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", +] + +[[package]] +name = "webrender_traits" +version = "0.1.0" +source = "git+https://github.com/glennw/webrender_traits#8ccc1608590d219d1df54e49f2f1e887995b4d60" +dependencies = [ + "app_units 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", + "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "websocket" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs index ccc31dce4f4..6eb3d935032 100644 --- a/ports/glutin/window.rs +++ b/ports/glutin/window.rs @@ -68,6 +68,8 @@ const CMD_OR_ALT: constellation_msg::KeyModifiers = ALT; #[cfg(feature = "window")] const LINE_HEIGHT: f32 = 38.0; +const MULTISAMPLES: u16 = 16; + /// The type of a window. #[cfg(feature = "window")] pub struct Window { @@ -88,18 +90,27 @@ impl Window { parent: Option<glutin::WindowID>) -> Rc<Window> { let width = window_size.to_untyped().width; let height = window_size.to_untyped().height; - let mut builder = glutin::WindowBuilder::new().with_title("Servo".to_string()) - .with_decorations(!opts::get().no_native_titlebar) - .with_dimensions(width, height) - .with_gl(Window::gl_version()) - .with_visibility(is_foreground) - .with_parent(parent) - .with_multitouch(); + let mut builder = + glutin::WindowBuilder::new().with_title("Servo".to_string()) + .with_decorations(!opts::get().no_native_titlebar) + .with_dimensions(width, height) + .with_gl(Window::gl_version()) + .with_visibility(is_foreground) + .with_parent(parent) + .with_multitouch(); if opts::get().enable_vsync { builder = builder.with_vsync(); } + if opts::get().use_webrender { + builder = builder.with_stencil_buffer(8); + } + + if opts::get().use_msaa { + builder = builder.with_multisampling(MULTISAMPLES) + } + let mut glutin_window = builder.build().unwrap(); unsafe { glutin_window.make_current().expect("Failed to make context current!") } @@ -144,7 +155,11 @@ impl Window { #[cfg(not(target_os = "android"))] fn gl_version() -> GlRequest { - GlRequest::Specific(Api::OpenGl, (2, 1)) + if opts::get().use_webrender { + GlRequest::Specific(Api::OpenGl, (3, 2)) + } else { + GlRequest::Specific(Api::OpenGl, (2, 1)) + } } #[cfg(target_os = "android")] @@ -305,32 +320,49 @@ impl Window { use std::thread; use std::time::Duration; - // TODO(gw): This is an awful hack to work around the - // broken way we currently call X11 from multiple threads. - // - // On some (most?) X11 implementations, blocking here - // with XPeekEvent results in the paint thread getting stuck - // in XGetGeometry randomly. When this happens the result - // is that until you trigger the XPeekEvent to return - // (by moving the mouse over the window) the paint thread - // never completes and you don't see the most recent - // results. - // - // For now, poll events and sleep for ~1 frame if there - // are no events. This means we don't spin the CPU at - // 100% usage, but is far from ideal! - // - // See https://github.com/servo/servo/issues/5780 - // - let first_event = self.window.poll_events().next(); - - match first_event { - Some(event) => { - self.handle_window_event(event) - } - None => { - thread::sleep(Duration::from_millis(16)); - false + // WebRender can use the normal blocking event check and proper vsync, + // because it doesn't call X11 functions from another thread, so doesn't + // hit the same issues explained below. + if opts::get().use_webrender { + let event = self.window.wait_events().next().unwrap(); + let mut close = self.handle_window_event(event); + if !close { + while let Some(event) = self.window.poll_events().next() { + if self.handle_window_event(event) { + close = true; + break + } + } + } + close + } else { + // TODO(gw): This is an awful hack to work around the + // broken way we currently call X11 from multiple threads. + // + // On some (most?) X11 implementations, blocking here + // with XPeekEvent results in the paint thread getting stuck + // in XGetGeometry randomly. When this happens the result + // is that until you trigger the XPeekEvent to return + // (by moving the mouse over the window) the paint thread + // never completes and you don't see the most recent + // results. + // + // For now, poll events and sleep for ~1 frame if there + // are no events. This means we don't spin the CPU at + // 100% usage, but is far from ideal! + // + // See https://github.com/servo/servo/issues/5780 + // + let first_event = self.window.poll_events().next(); + + match first_event { + Some(event) => { + self.handle_window_event(event) + } + None => { + thread::sleep(Duration::from_millis(16)); + false + } } } } diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index 6e0dabac33f..43c8639fc52 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -8,7 +8,7 @@ dependencies = [ "errno 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", "layout 0.0.1", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -133,7 +133,7 @@ dependencies = [ "canvas_traits 0.0.1", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", "log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -141,6 +141,7 @@ dependencies = [ "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", "plugins 0.0.1", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -160,6 +161,7 @@ dependencies = [ "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -181,7 +183,7 @@ name = "cgl" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -239,7 +241,7 @@ dependencies = [ "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", "gfx_traits 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", @@ -258,6 +260,8 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender 0.1.0 (git+https://github.com/glennw/webrender)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -623,6 +627,7 @@ dependencies = [ "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -662,7 +667,7 @@ dependencies = [ [[package]] name = "gleam" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -817,7 +822,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -878,7 +883,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "glx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -931,6 +936,7 @@ dependencies = [ "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -947,6 +953,7 @@ dependencies = [ "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -1107,6 +1114,7 @@ dependencies = [ "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -1131,6 +1139,7 @@ dependencies = [ "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", "websocket 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1221,7 +1230,7 @@ dependencies = [ "core-foundation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1429,6 +1438,22 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "rustc_version" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scoped_threadpool" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "script" version = "0.0.1" dependencies = [ @@ -1520,6 +1545,11 @@ dependencies = [ ] [[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "serde" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1568,7 +1598,7 @@ dependencies = [ "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", "layers 0.2.2 (git+https://github.com/servo/rust-layers)", "layout 0.0.1", @@ -1585,6 +1615,8 @@ dependencies = [ "style 0.0.1", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webrender 0.1.0 (git+https://github.com/glennw/webrender)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", ] [[package]] @@ -1659,7 +1691,7 @@ dependencies = [ "cgl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "expat-sys 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "glx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "io-surface 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2009,6 +2041,42 @@ dependencies = [ ] [[package]] +name = "webrender" +version = "0.1.0" +source = "git+https://github.com/glennw/webrender#90cd6afdd64cdb48f606dbe0ce5d1ac352329004" +dependencies = [ + "app_units 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-text 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", + "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "scoped_threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "webrender_traits 0.1.0 (git+https://github.com/glennw/webrender_traits)", +] + +[[package]] +name = "webrender_traits" +version = "0.1.0" +source = "git+https://github.com/glennw/webrender_traits#8ccc1608590d219d1df54e49f2f1e887995b4d60" +dependencies = [ + "app_units 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)", + "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "websocket" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/resources/shaders/blend.fs.glsl b/resources/shaders/blend.fs.glsl new file mode 100644 index 00000000000..8dc29cf4d8f --- /dev/null +++ b/resources/shaders/blend.fs.glsl @@ -0,0 +1,193 @@ +/* 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/. */ + +vec3 Multiply(vec3 Cb, vec3 Cs) { + return Cb * Cs; +} + +vec3 Screen(vec3 Cb, vec3 Cs) { + return Cb + Cs - (Cb * Cs); +} + +vec3 HardLight(vec3 Cb, vec3 Cs) { + vec3 m = Multiply(Cb, 2.0 * Cs); + vec3 s = Screen(Cb, 2.0 * Cs - 1.0); + vec3 edge = vec3(0.5, 0.5, 0.5); + return mix(m, s, step(edge, Cs)); +} + +// TODO: Worth doing with mix/step? Check GLSL output. +float ColorDodge(float Cb, float Cs) { + if (Cb == 0.0) + return 0.0; + else if (Cs == 1.0) + return 1.0; + else + return min(1.0, Cb / (1.0 - Cs)); +} + +// TODO: Worth doing with mix/step? Check GLSL output. +float ColorBurn(float Cb, float Cs) { + if (Cb == 1.0) + return 1.0; + else if (Cs == 0.0) + return 0.0; + else + return 1.0 - min(1.0, (1.0 - Cb) / Cs); +} + +float SoftLight(float Cb, float Cs) { + if (Cs <= 0.5) { + return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb); + } else { + float D; + + if (Cb <= 0.25) + D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb; + else + D = sqrt(Cb); + + return Cb + (2.0 * Cs - 1.0) * (D - Cb); + } +} + +vec3 Difference(vec3 Cb, vec3 Cs) { + return abs(Cb - Cs); +} + +vec3 Exclusion(vec3 Cb, vec3 Cs) { + return Cb + Cs - 2.0 * Cb * Cs; +} + +// These functions below are taken from the spec. +// There's probably a much quicker way to implement +// them in GLSL... +float Sat(vec3 c) { + return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); +} + +float Lum(vec3 c) { + vec3 f = vec3(0.3, 0.59, 0.11); + return dot(c, f); +} + +vec3 ClipColor(vec3 C) { + float L = Lum(C); + float n = min(C.r, min(C.g, C.b)); + float x = max(C.r, max(C.g, C.b)); + + if (n < 0.0) + C = L + (((C - L) * L) / (L - n)); + + if (x > 1.0) + C = L + (((C - L) * (1.0 - L)) / (x - L)); + + return C; +} + +vec3 SetLum(vec3 C, float l) { + float d = l - Lum(C); + return ClipColor(C + d); +} + +void SetSatInner(inout float Cmin, inout float Cmid, inout float Cmax, float s) { + if (Cmax > Cmin) { + Cmid = (((Cmid - Cmin) * s) / (Cmax - Cmin)); + Cmax = s; + } else { + Cmid = 0.0; + Cmax = 0.0; + } + Cmin = 0.0; +} + +vec3 SetSat(vec3 C, float s) { + if (C.r <= C.g) { + if (C.g <= C.b) { + SetSatInner(C.r, C.g, C.b, s); + } else { + if (C.r <= C.b) { + SetSatInner(C.r, C.b, C.g, s); + } else { + SetSatInner(C.b, C.r, C.g, s); + } + } + } else { + if (C.r <= C.b) { + SetSatInner(C.g, C.r, C.b, s); + } else { + if (C.g <= C.b) { + SetSatInner(C.g, C.b, C.r, s); + } else { + SetSatInner(C.b, C.g, C.r, s); + } + } + } + return C; +} + +vec3 Hue(vec3 Cb, vec3 Cs) { + return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)); +} + +vec3 Saturation(vec3 Cb, vec3 Cs) { + return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)); +} + +vec3 Color(vec3 Cb, vec3 Cs) { + return SetLum(Cs, Lum(Cb)); +} + +vec3 Luminosity(vec3 Cb, vec3 Cs) { + return SetLum(Cb, Lum(Cs)); +} + +void main(void) +{ + vec3 Cs = Texture(sDiffuse, vColorTexCoord).xyz; + vec3 Cb = Texture(sMask, vMaskTexCoord).xyz; + + // TODO: Relies on the ordering of MixBlendMode enum! + // TODO: May be best to have separate shaders (esp. on Tegra) + int blend_mode = int(uBlendParams.x); + + // Return yellow if none of the branches match (shouldn't happen). + vec3 result = vec3(1.0, 1.0, 0.0); + + if (blend_mode == 2) { + result = Screen(Cb, Cs); + } else if (blend_mode == 3) { + result = HardLight(Cs, Cb); // Overlay is inverse of Hardlight + } else if (blend_mode == 6) { + result.r = ColorDodge(Cb.r, Cs.r); + result.g = ColorDodge(Cb.g, Cs.g); + result.b = ColorDodge(Cb.b, Cs.b); + } else if (blend_mode == 7) { + result.r = ColorBurn(Cb.r, Cs.r); + result.g = ColorBurn(Cb.g, Cs.g); + result.b = ColorBurn(Cb.b, Cs.b); + } else if (blend_mode == 8) { + result = HardLight(Cb, Cs); + } else if (blend_mode == 9) { + result.r = SoftLight(Cb.r, Cs.r); + result.g = SoftLight(Cb.g, Cs.g); + result.b = SoftLight(Cb.b, Cs.b); + } else if (blend_mode == 10) { + result = Difference(Cb, Cs); + } else if (blend_mode == 11) { + result = Exclusion(Cb, Cs); + } else if (blend_mode == 12) { + result = Hue(Cb, Cs); + } else if (blend_mode == 13) { + result = Saturation(Cb, Cs); + } else if (blend_mode == 14) { + result = Color(Cb, Cs); + } else if (blend_mode == 15) { + result = Luminosity(Cb, Cs); + } + + // TODO: Handle output alpha correctly. + SetFragColor(vec4(result, 1.0)); +} + diff --git a/resources/shaders/blend.vs.glsl b/resources/shaders/blend.vs.glsl new file mode 100644 index 00000000000..031ccacdc1b --- /dev/null +++ b/resources/shaders/blend.vs.glsl @@ -0,0 +1,10 @@ +/* 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/. */ + +void main(void) +{ + vColorTexCoord = aColorTexCoordRectTop.xy; + vMaskTexCoord = aMaskTexCoordRectTop.xy / 65535.0; + gl_Position = uTransform * vec4(aPosition, 1.0); +} diff --git a/resources/shaders/blit.fs.glsl b/resources/shaders/blit.fs.glsl new file mode 100644 index 00000000000..135553a8029 --- /dev/null +++ b/resources/shaders/blit.fs.glsl @@ -0,0 +1,9 @@ +/* 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/. */ + +void main(void) +{ + vec4 diffuse = Texture(sDiffuse, vColorTexCoord); + SetFragColor(diffuse * vColor); +} diff --git a/resources/shaders/blit.vs.glsl b/resources/shaders/blit.vs.glsl new file mode 100644 index 00000000000..4d1e4dad739 --- /dev/null +++ b/resources/shaders/blit.vs.glsl @@ -0,0 +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/. */ + +void main(void) +{ + vColor = aColorRectTL / 255.0; + vColorTexCoord = aColorTexCoordRectTop.xy; + vec4 pos = vec4(aPosition, 1.0); + pos.xy = SnapToPixels(pos.xy); + gl_Position = uTransform * pos; +} diff --git a/resources/shaders/blur.fs.glsl b/resources/shaders/blur.fs.glsl new file mode 100644 index 00000000000..c20a774f488 --- /dev/null +++ b/resources/shaders/blur.fs.glsl @@ -0,0 +1,44 @@ +/* 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/. */ + +// `vBorderPosition` is the position of the source texture in the atlas. + +float gauss(float x, float sigma) { + return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma)); +} + +void main(void) { +#ifdef SERVO_ES2 + // TODO(gw): for loops have to be unrollable on es2. + SetFragColor(vec4(1.0, 0.0, 0.0, 1.0)); +#else + vec2 sideOffsets = (vDestTextureSize - vSourceTextureSize) / 2.0; + int range = int(vBlurRadius) * 3; + float sigma = vBlurRadius / 2.0; + vec4 value = vec4(0.0); + vec2 sourceTextureUvOrigin = vBorderPosition.xy; + vec2 sourceTextureUvSize = vBorderPosition.zw - sourceTextureUvOrigin; + for (int offset = -range; offset <= range; offset++) { + float offsetF = float(offset); + vec2 lColorTexCoord = (vColorTexCoord.xy * vDestTextureSize - sideOffsets) / + vSourceTextureSize; + lColorTexCoord += vec2(offsetF) / vSourceTextureSize * uDirection; + vec4 x = lColorTexCoord.x >= 0.0 && + lColorTexCoord.x <= 1.0 && + lColorTexCoord.y >= 0.0 && + lColorTexCoord.y <= 1.0 ? + Texture(sDiffuse, lColorTexCoord * sourceTextureUvSize + sourceTextureUvOrigin) : + vec4(0.0); + + // Alpha must be premultiplied in order to properly blur the alpha channel. + value += vec4(x.rgb * x.a, x.a) * gauss(offsetF, sigma); + } + + // Unpremultiply the alpha. + value = vec4(value.rgb / value.a, value.a); + + SetFragColor(value); +#endif +} + diff --git a/resources/shaders/blur.vs.glsl b/resources/shaders/blur.vs.glsl new file mode 100644 index 00000000000..4e03cf38a67 --- /dev/null +++ b/resources/shaders/blur.vs.glsl @@ -0,0 +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/. */ + +void main(void) +{ + vColorTexCoord = aColorTexCoordRectTop.xy; + vBorderPosition = aBorderPosition; + vBlurRadius = aBlurRadius; + vDestTextureSize = aDestTextureSize; + vSourceTextureSize = aSourceTextureSize; + gl_Position = uTransform * vec4(aPosition, 1.0); +} + diff --git a/resources/shaders/border.fs.glsl b/resources/shaders/border.fs.glsl new file mode 100644 index 00000000000..32d1930aa5a --- /dev/null +++ b/resources/shaders/border.fs.glsl @@ -0,0 +1,41 @@ +/* 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/. */ + +/* + Ellipse equation: + + (x-h)^2 (y-k)^2 + ------- + ------- <= 1 + rx^2 ry^2 + + */ + +float Value(vec2 position) { + float outer_rx = vBorderRadii.x; + float outer_ry = vBorderRadii.y; + float outer_dx = position.x * position.x / (outer_rx * outer_rx); + float outer_dy = position.y * position.y / (outer_ry * outer_ry); + if (outer_dx + outer_dy > 1.0) + return 0.0; + + float inner_rx = vBorderRadii.z; + float inner_ry = vBorderRadii.w; + if (inner_rx == 0.0 || inner_ry == 0.0) + return 1.0; + + float inner_dx = position.x * position.x / (inner_rx * inner_rx); + float inner_dy = position.y * position.y / (inner_ry * inner_ry); + return inner_dx + inner_dy >= 1.0 ? 1.0 : 0.0; +} + +void main(void) +{ + vec2 position = vPosition - vBorderPosition.xy; + vec4 pixelBounds = vec4(floor(position.x), floor(position.y), + ceil(position.x), ceil(position.y)); + float value = (Value(pixelBounds.xy) + Value(pixelBounds.zy) + + Value(pixelBounds.xw) + Value(pixelBounds.zw)) / 4.0; + SetFragColor(vec4(vColor.rgb, mix(1.0 - vColor.a, vColor.a, value))); +} + diff --git a/resources/shaders/border.vs.glsl b/resources/shaders/border.vs.glsl new file mode 100644 index 00000000000..cbd9cdcd0c1 --- /dev/null +++ b/resources/shaders/border.vs.glsl @@ -0,0 +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/. */ + +void main(void) +{ + vColor = aColorRectTL; + vPosition = aPosition.xy; + vBorderPosition = aBorderPosition; + vBorderRadii = aBorderRadii; + gl_Position = uTransform * vec4(aPosition, 1.0); +} diff --git a/resources/shaders/box_shadow.fs.glsl b/resources/shaders/box_shadow.fs.glsl new file mode 100644 index 00000000000..5d7c6db6d59 --- /dev/null +++ b/resources/shaders/box_shadow.fs.glsl @@ -0,0 +1,146 @@ +/* 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/. */ + +// See http://asciimath.org to render the equations here. + +// The Gaussian function used for blurring: +// +// G_sigma(x) = 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) +float gauss(float x, float sigma) { + float sigmaPow2 = sigma * sigma; + return 1.0 / sqrt(6.283185307179586 * sigmaPow2) * exp(-(x * x) / (2.0 * sigmaPow2)); +} + +// An approximation of the error function, which is related to the integral of the Gaussian +// function: +// +// "erf"(x) = 2/sqrt(pi) int_0^x e^(-t^2) dt +// ~~ 1 - 1 / (1 + a_1 x + a_2 x^2 + a_3 x^3 + a_4 x^4)^4 +// +// where: +// +// a_1 = 0.278393, a_2 = 0.230389, a_3 = 0.000972, a_4 = 0.078108 +// +// This approximation is accurate to `5 xx 10^-4`, more than accurate enough for our purposes. +// +// See: https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions +float erf(float x) { + bool negative = x < 0.0; + if (negative) + x = -x; + float x2 = x * x; + float x3 = x2 * x; + float x4 = x2 * x2; + float denom = 1.0 + 0.278393 * x + 0.230389 * x2 + 0.000972 * x3 + 0.078108 * x4; + float result = 1.0 - 1.0 / (denom * denom * denom * denom); + return negative ? -result : result; +} + +// A useful helper for calculating integrals of the Gaussian function via the error function: +// +// "erf"_sigma(x) = 2 int 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) dx +// = "erf"(x/(sigma sqrt(2))) +float erfSigma(float x, float sigma) { + return erf(x / (sigma * 1.4142135623730951)); +} + +// Returns the blurred color value from the box itself (not counting any rounded corners). `p_0` is +// the vector distance to the top left corner of the box; `p_1` is the vector distance to its +// bottom right corner. +// +// "colorFromRect"_sigma(p_0, p_1) +// = int_{p_{0_y}}^{p_{1_y}} int_{p_{1_x}}^{p_{0_x}} G_sigma(y) G_sigma(x) dx dy +// = 1/4 ("erf"_sigma(p_{1_x}) - "erf"_sigma(p_{0_x})) +// ("erf"_sigma(p_{1_y}) - "erf"_sigma(p_{0_y})) +float colorFromRect(vec2 p0, vec2 p1, float sigma) { + return (erfSigma(p1.x, sigma) - erfSigma(p0.x, sigma)) * + (erfSigma(p1.y, sigma) - erfSigma(p0.y, sigma)) / 4.0; +} + +// Returns the `x` coordinate on the ellipse with the given radii for the given `y` coordinate: +// +// "ellipsePoint"(y, y_0, a, b) = a sqrt(1 - ((y - y_0) / b)^2) +float ellipsePoint(float y, float y0, vec2 radii) { + float bStep = (y - y0) / radii.y; + return radii.x * sqrt(1.0 - bStep * bStep); +} + +// A helper function to compute the value that needs to be subtracted to accommodate the border +// corners. +// +// "colorCutout"_sigma(x_{0_l}, x_{0_r}, y_0, y_{min}, y_{max}, a, b) +// = int_{y_{min}}^{y_{max}} +// int_{x_{0_r} + "ellipsePoint"(y, y_0, a, b)}^{x_{0_r} + a} G_sigma(y) G_sigma(x) dx +// + int_{x_{0_l} - a}^{x_{0_l} - "ellipsePoint"(y, y_0, a, b)} G_sigma(y) G_sigma(x) +// dx dy +// = int_{y_{min}}^{y_{max}} 1/2 G_sigma(y) +// ("erf"_sigma(x_{0_r} + a) - "erf"_sigma(x_{0_r} + "ellipsePoint"(y, y_0, a, b)) + +// "erf"_sigma(x_{0_l} - "ellipsePoint"(y, y_0, a, b)) - "erf"_sigma(x_{0_l} - a)) +// +// with the outer integral evaluated numerically. +float colorCutoutGeneral(float x0l, + float x0r, + float y0, + float yMin, + float yMax, + vec2 radii, + float sigma) { + float sum = 0.0; + for (float y = yMin; y <= yMax; y += 1.0) { + float xEllipsePoint = ellipsePoint(y, y0, radii); + sum += gauss(y, sigma) * + (erfSigma(x0r + radii.x, sigma) - erfSigma(x0r + xEllipsePoint, sigma) + + erfSigma(x0l - xEllipsePoint, sigma) - erfSigma(x0l - radii.x, sigma)); + } + return sum / 2.0; +} + +// The value that needs to be subtracted to accommodate the top border corners. +float colorCutoutTop(float x0l, float x0r, float y0, vec2 radii, float sigma) { + return colorCutoutGeneral(x0l, x0r, y0, y0, y0 + radii.y, radii, sigma); +} + +// The value that needs to be subtracted to accommodate the bottom border corners. +float colorCutoutBottom(float x0l, float x0r, float y0, vec2 radii, float sigma) { + return colorCutoutGeneral(x0l, x0r, y0, y0 - radii.y, y0, radii, sigma); +} + +// The blurred color value for the point at `pos` with the top left corner of the box at +// `p_{0_"rect"}` and the bottom right corner of the box at `p_{1_"rect"}`. +float color(vec2 pos, vec2 p0Rect, vec2 p1Rect, vec2 radii, float sigma) { + // Compute the vector distances `p_0` and `p_1`. + vec2 p0 = p0Rect - pos, p1 = p1Rect - pos; + + // Compute the basic color `"colorFromRect"_sigma(p_0, p_1)`. This is all we have to do if + // the box is unrounded. + float cRect = colorFromRect(p0, p1, sigma); + if (radii.x == 0.0 || radii.y == 0.0) + return cRect; + + // Compute the inner corners of the box, taking border radii into account: `x_{0_l}`, + // `y_{0_t}`, `x_{0_r}`, and `y_{0_b}`. + float x0l = p0.x + radii.x; + float y0t = p1.y - radii.y; + float x0r = p1.x - radii.x; + float y0b = p0.y + radii.y; + + // Compute the final color: + // + // "colorFromRect"_sigma(p_0, p_1) - + // ("colorCutoutTop"_sigma(x_{0_l}, x_{0_r}, y_{0_t}, a, b) + + // "colorCutoutBottom"_sigma(x_{0_l}, x_{0_r}, y_{0_b}, a, b)) + float cCutoutTop = colorCutoutTop(x0l, x0r, y0t, radii, sigma); + float cCutoutBottom = colorCutoutBottom(x0l, x0r, y0b, radii, sigma); + return cRect - (cCutoutTop + cCutoutBottom); +} + +void main(void) { + vec2 pos = vPosition.xy; + vec2 p0Rect = vBorderPosition.xy, p1Rect = vBorderPosition.zw; + vec2 radii = vBorderRadii.xy; + float sigma = vBlurRadius / 2.0; + float value = color(pos, p0Rect, p1Rect, radii, sigma); + SetFragColor(vec4(vColor.rgb, max(value, 0.0))); +} + diff --git a/resources/shaders/box_shadow.vs.glsl b/resources/shaders/box_shadow.vs.glsl new file mode 100644 index 00000000000..de3793c211e --- /dev/null +++ b/resources/shaders/box_shadow.vs.glsl @@ -0,0 +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/. */ + +void main(void) +{ + vPosition = aPosition.xy; + vColor = aColorRectTL; + vBorderPosition = aBorderPosition; + vBorderRadii = aBorderRadii; + vBlurRadius = aBlurRadius; + gl_Position = uTransform * vec4(aPosition, 1.0); +} + diff --git a/resources/shaders/clear.fs.glsl b/resources/shaders/clear.fs.glsl new file mode 100644 index 00000000000..658ac27488c --- /dev/null +++ b/resources/shaders/clear.fs.glsl @@ -0,0 +1,8 @@ +/* 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/. */ + +void main(void) +{ + SetFragColor(vColor); +} diff --git a/resources/shaders/clear.vs.glsl b/resources/shaders/clear.vs.glsl new file mode 100644 index 00000000000..491f3ea3863 --- /dev/null +++ b/resources/shaders/clear.vs.glsl @@ -0,0 +1,9 @@ +/* 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/. */ + +void main(void) +{ + vColor = aColorRectTL / 255.0; + gl_Position = uTransform * vec4(aPosition, 1.0); +} diff --git a/resources/shaders/debug_color.fs.glsl b/resources/shaders/debug_color.fs.glsl new file mode 100644 index 00000000000..658ac27488c --- /dev/null +++ b/resources/shaders/debug_color.fs.glsl @@ -0,0 +1,8 @@ +/* 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/. */ + +void main(void) +{ + SetFragColor(vColor); +} diff --git a/resources/shaders/debug_color.vs.glsl b/resources/shaders/debug_color.vs.glsl new file mode 100644 index 00000000000..78e7a306c20 --- /dev/null +++ b/resources/shaders/debug_color.vs.glsl @@ -0,0 +1,11 @@ +/* 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/. */ + +void main(void) +{ + vColor = aColorRectTL; + vec4 pos = vec4(aPosition, 1.0); + pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio; + gl_Position = uTransform * pos; +} diff --git a/resources/shaders/debug_font.fs.glsl b/resources/shaders/debug_font.fs.glsl new file mode 100644 index 00000000000..8b68e085cfb --- /dev/null +++ b/resources/shaders/debug_font.fs.glsl @@ -0,0 +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/. */ + +void main(void) +{ +#ifdef SERVO_ES2 + float alpha = Texture(sDiffuse, vColorTexCoord.xy).a; +#else + float alpha = Texture(sDiffuse, vColorTexCoord.xy).r; +#endif + SetFragColor(vec4(vColor.xyz, vColor.w * alpha)); +} diff --git a/resources/shaders/debug_font.vs.glsl b/resources/shaders/debug_font.vs.glsl new file mode 100644 index 00000000000..9d9f38653cb --- /dev/null +++ b/resources/shaders/debug_font.vs.glsl @@ -0,0 +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/. */ + +void main(void) +{ + vColor = aColorRectTL; + vColorTexCoord = aColorTexCoordRectTop.xy; + vec4 pos = vec4(aPosition, 1.0); + pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio; + gl_Position = uTransform * pos; +} diff --git a/resources/shaders/es2_common.fs.glsl b/resources/shaders/es2_common.fs.glsl new file mode 100644 index 00000000000..088bc670036 --- /dev/null +++ b/resources/shaders/es2_common.fs.glsl @@ -0,0 +1,42 @@ +/* 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/. */ + +#version 110 + +#define SERVO_ES2 + +precision highp float; + +uniform sampler2D sDiffuse; +uniform sampler2D sMask; +uniform vec4 uBlendParams; +uniform vec4 uAtlasParams; +uniform vec2 uDirection; +uniform vec4 uFilterParams; + +varying vec2 vPosition; +varying vec4 vColor; +varying vec2 vColorTexCoord; +varying vec2 vMaskTexCoord; +varying vec4 vBorderPosition; +varying vec4 vBorderRadii; +varying vec2 vDestTextureSize; +varying vec2 vSourceTextureSize; +varying float vBlurRadius; +varying vec4 vTileParams; +varying vec4 vClipInRect; +varying vec4 vClipOutRect; + +vec4 Texture(sampler2D sampler, vec2 texCoord) { + return texture2D(sampler, texCoord); +} + +float GetAlphaFromMask(vec4 mask) { + return mask.a; +} + +void SetFragColor(vec4 color) { + gl_FragColor = color; +} + diff --git a/resources/shaders/es2_common.vs.glsl b/resources/shaders/es2_common.vs.glsl new file mode 100644 index 00000000000..ccb8c3dcec5 --- /dev/null +++ b/resources/shaders/es2_common.vs.glsl @@ -0,0 +1,70 @@ +/* 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/. */ + +#version 110 + +#define SERVO_ES2 + +uniform mat4 uTransform; +uniform vec4 uOffsets[32]; +uniform vec4 uClipRects[64]; +uniform mat4 uMatrixPalette[32]; +uniform vec2 uDirection; +uniform vec4 uBlendParams; +uniform vec4 uFilterParams; +uniform float uDevicePixelRatio; +uniform vec4 uTileParams[64]; + +attribute vec3 aPosition; +attribute vec4 aPositionRect; // Width can be negative to flip horizontally (for border corners). +attribute vec4 aColorRectTL; +attribute vec4 aColorRectTR; +attribute vec4 aColorRectBR; +attribute vec4 aColorRectBL; +attribute vec4 aColorTexCoordRectTop; +attribute vec4 aColorTexCoordRectBottom; +attribute vec4 aMaskTexCoordRectTop; +attribute vec4 aMaskTexCoordRectBottom; +attribute vec4 aBorderPosition; +attribute vec4 aBorderRadii; +attribute vec2 aSourceTextureSize; +attribute vec2 aDestTextureSize; +attribute float aBlurRadius; +// x = matrix index; y = clip-in rect; z = clip-out rect; w = tile params index. +// +// A negative w value activates border corner mode. In this mode, the TR and BL colors are ignored, +// the color of the top left corner applies to all vertices of the top left triangle, and the color +// of the bottom right corner applies to all vertices of the bottom right triangle. +attribute vec4 aMisc; + +varying vec2 vPosition; +varying vec4 vColor; +varying vec2 vColorTexCoord; +varying vec2 vMaskTexCoord; +varying vec4 vBorderPosition; +varying vec4 vBorderRadii; +varying vec2 vDestTextureSize; +varying vec2 vSourceTextureSize; +varying float vBlurRadius; +varying vec4 vTileParams; +varying vec4 vClipInRect; +varying vec4 vClipOutRect; + +int Bottom7Bits(int value) { + return value % 0x80; +} + +bool IsBottomTriangle() { + // FIXME(pcwalton): No gl_VertexID in OpenGL ES 2. We'll need some extra data. + return false; +} + +vec2 SnapToPixels(vec2 pos) +{ + // Snap the vertex to pixel position to guarantee correct texture + // sampling when using bilinear filtering. + + // TODO(gw): ES2 doesn't have round(). Do we ever get negative coords here? + return floor(0.5 + pos * uDevicePixelRatio) / uDevicePixelRatio; +} diff --git a/resources/shaders/filter.fs.glsl b/resources/shaders/filter.fs.glsl new file mode 100644 index 00000000000..b4b5b707d5f --- /dev/null +++ b/resources/shaders/filter.fs.glsl @@ -0,0 +1,148 @@ +/* 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/. */ + +vec3 rgbToHsv(vec3 c) { + float value = max(max(c.r, c.g), c.b); + + float chroma = value - min(min(c.r, c.g), c.b); + if (chroma == 0.0) { + return vec3(0.0); + } + float saturation = chroma / value; + + float hue; + if (c.r == value) + hue = (c.g - c.b) / chroma; + else if (c.g == value) + hue = 2.0 + (c.b - c.r) / chroma; + else // if (c.b == value) + hue = 4.0 + (c.r - c.g) / chroma; + + hue *= 1.0/6.0; + if (hue < 0.0) + hue += 1.0; + return vec3(hue, saturation, value); +} + +vec3 hsvToRgb(vec3 c) { + if (c.s == 0.0) { + return vec3(c.z); + } + + float hue = c.x * 6.0; + int sector = int(hue); + float residualHue = hue - float(sector); + + vec3 pqt = c.z * vec3(1.0 - c.y, 1.0 - c.y * residualHue, 1.0 - c.y * (1.0 - residualHue)); + if (sector == 0) + return vec3(c.z, pqt.z, pqt.x); + if (sector == 1) + return vec3(pqt.y, c.z, pqt.x); + if (sector == 2) + return vec3(pqt.x, c.z, pqt.z); + if (sector == 3) + return vec3(pqt.x, pqt.y, c.z); + if (sector == 4) + return vec3(pqt.z, pqt.x, c.z); + return vec3(c.z, pqt.x, pqt.y); +} + +float gauss(float x, float sigma) { + if (sigma == 0.0) + return 1.0; + return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma)); +} + +vec4 Blur(float radius, vec2 direction) { +#ifdef SERVO_ES2 + // TODO(gw): for loops have to be unrollable on es2. + return vec4(1.0, 0.0, 0.0, 1.0); +#else + int range = int(radius) * 3; + float sigma = radius / 2.0; + vec4 color = vec4(0.0); + for (int offset = -range; offset <= range; offset++) { + float offsetF = float(offset); + + // Here, we use the vMaskTexCoord.xy (i.e. the muv) to store the texture size. + vec2 texCoord = vColorTexCoord.xy + vec2(offsetF) / vMaskTexCoord.xy * direction; + vec4 x = texCoord.x >= 0.0 && + texCoord.x <= 1.0 && + texCoord.y >= 0.0 && + texCoord.y <= 1.0 ? + Texture(sDiffuse, texCoord) : + vec4(0.0); + color += x * gauss(offsetF, sigma); + } + return color; +#endif +} + +vec4 Contrast(vec4 Cs, float amount) { + return vec4(Cs.rgb * amount - 0.5 * amount + 0.5, 1.0); +} + +vec4 Grayscale(vec4 Cs, float amount) { + float ia = 1.0 - amount; + return mat4(vec4(0.2126 + 0.7874 * ia, 0.2126 - 0.2126 * ia, 0.2126 - 0.2126 * ia, 0.0), + vec4(0.7152 - 0.7152 * ia, 0.7152 + 0.2848 * ia, 0.7152 - 0.7152 * ia, 0.0), + vec4(0.0722 - 0.0722 * ia, 0.0722 - 0.0722 * ia, 0.0722 + 0.9278 * ia, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)) * Cs; +} + +vec4 HueRotate(vec4 Cs, float amount) { + vec3 CsHsv = rgbToHsv(Cs.rgb); + CsHsv.x = mod(CsHsv.x + amount / 6.283185307179586, 1.0); + return vec4(hsvToRgb(CsHsv), Cs.a); +} + +vec4 Invert(vec4 Cs, float amount) { + return mix(Cs, vec4(1.0, 1.0, 1.0, Cs.a) - vec4(Cs.rgb, 0.0), amount); +} + +vec4 Saturate(vec4 Cs, float amount) { + return vec4(hsvToRgb(min(vec3(1.0, amount, 1.0) * rgbToHsv(Cs.rgb), vec3(1.0))), Cs.a); +} + +vec4 Sepia(vec4 Cs, float amount) { + float ia = 1.0 - amount; + return mat4(vec4(0.393 + 0.607 * ia, 0.349 - 0.349 * ia, 0.272 - 0.272 * ia, 0.0), + vec4(0.769 - 0.769 * ia, 0.686 + 0.314 * ia, 0.534 - 0.534 * ia, 0.0), + vec4(0.189 - 0.189 * ia, 0.168 - 0.168 * ia, 0.131 + 0.869 * ia, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)) * Cs; +} + +void main(void) +{ + // TODO: May be best to have separate shaders (esp. on Tegra) + int filterOp = int(uFilterParams.x); + float amount = uFilterParams.y; + + // Return yellow if none of the branches match (shouldn't happen). + vec4 result = vec4(1.0, 1.0, 0.0, 1.0); + + if (filterOp == 0) { + // Gaussian blur is specially handled: + result = Blur(amount, uFilterParams.zw); + } else { + vec4 Cs = Texture(sDiffuse, vColorTexCoord); + + if (filterOp == 1) { + result = Contrast(Cs, amount); + } else if (filterOp == 2) { + result = Grayscale(Cs, amount); + } else if (filterOp == 3) { + result = HueRotate(Cs, amount); + } else if (filterOp == 4) { + result = Invert(Cs, amount); + } else if (filterOp == 5) { + result = Saturate(Cs, amount); + } else if (filterOp == 6) { + result = Sepia(Cs, amount); + } + } + + SetFragColor(result); +} + diff --git a/resources/shaders/filter.vs.glsl b/resources/shaders/filter.vs.glsl new file mode 100644 index 00000000000..a8d526383bc --- /dev/null +++ b/resources/shaders/filter.vs.glsl @@ -0,0 +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/. */ + +void main(void) +{ + vColorTexCoord = aColorTexCoordRectTop.xy; + vMaskTexCoord = aMaskTexCoordRectTop.xy; + vec4 pos = vec4(aPosition, 1.0); + pos.xy = SnapToPixels(pos.xy); + gl_Position = uTransform * pos; +} diff --git a/resources/shaders/gl3_common.fs.glsl b/resources/shaders/gl3_common.fs.glsl new file mode 100644 index 00000000000..fc8878a9f17 --- /dev/null +++ b/resources/shaders/gl3_common.fs.glsl @@ -0,0 +1,41 @@ +/* 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/. */ + +#version 150 + +#define SERVO_GL3 + +uniform sampler2D sDiffuse; +uniform sampler2D sMask; +uniform vec4 uBlendParams; +uniform vec2 uDirection; +uniform vec4 uFilterParams; + +in vec2 vPosition; +in vec4 vColor; +in vec2 vColorTexCoord; +in vec2 vMaskTexCoord; +in vec4 vBorderPosition; +in vec4 vBorderRadii; +in vec2 vDestTextureSize; +in vec2 vSourceTextureSize; +in float vBlurRadius; +in vec4 vTileParams; +in vec4 vClipInRect; +in vec4 vClipOutRect; + +out vec4 oFragColor; + +vec4 Texture(sampler2D sampler, vec2 texCoord) { + return texture(sampler, texCoord); +} + +float GetAlphaFromMask(vec4 mask) { + return mask.r; +} + +void SetFragColor(vec4 color) { + oFragColor = color; +} + diff --git a/resources/shaders/gl3_common.vs.glsl b/resources/shaders/gl3_common.vs.glsl new file mode 100644 index 00000000000..0732a50c5b7 --- /dev/null +++ b/resources/shaders/gl3_common.vs.glsl @@ -0,0 +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/. */ + +#version 150 + +#define SERVO_GL3 + +uniform mat4 uTransform; +uniform vec4 uOffsets[32]; +uniform vec4 uClipRects[64]; +uniform mat4 uMatrixPalette[32]; +uniform vec2 uDirection; +uniform vec4 uBlendParams; +uniform vec4 uFilterParams; +uniform float uDevicePixelRatio; +uniform vec4 uTileParams[64]; +uniform vec4 uAtlasParams; + +in vec3 aPosition; +in vec4 aPositionRect; // Width can be negative to flip horizontally (for border corners). +in vec4 aColorRectTL; +in vec4 aColorRectTR; +in vec4 aColorRectBR; +in vec4 aColorRectBL; +in vec4 aColorTexCoordRectTop; +in vec4 aColorTexCoordRectBottom; +in vec4 aMaskTexCoordRectTop; +in vec4 aMaskTexCoordRectBottom; +in vec4 aBorderPosition; +in vec4 aBorderRadii; +in vec2 aSourceTextureSize; +in vec2 aDestTextureSize; +in float aBlurRadius; +// x = matrix index; y = clip-in rect; z = clip-out rect; w = tile params index. +// +// A negative w value activates border corner mode. In this mode, the TR and BL colors are ignored, +// the color of the top left corner applies to all vertices of the top left triangle, and the color +// of the bottom right corner applies to all vertices of the bottom right triangle. +in vec4 aMisc; + +out vec2 vPosition; +out vec4 vColor; +out vec2 vColorTexCoord; +out vec2 vMaskTexCoord; +out vec4 vBorderPosition; +out vec4 vBorderRadii; +out vec2 vDestTextureSize; +out vec2 vSourceTextureSize; +out float vBlurRadius; +out vec4 vTileParams; +out vec4 vClipInRect; +out vec4 vClipOutRect; + +int Bottom7Bits(int value) { + return value & 0x7f; +} + +bool IsBottomTriangle() { + return gl_VertexID > 2; +} + +vec2 SnapToPixels(vec2 pos) +{ + // Snap the vertex to pixel position to guarantee correct texture + // sampling when using bilinear filtering. + return round(pos * uDevicePixelRatio) / uDevicePixelRatio; +} diff --git a/resources/shaders/mask.fs.glsl b/resources/shaders/mask.fs.glsl new file mode 100644 index 00000000000..658ac27488c --- /dev/null +++ b/resources/shaders/mask.fs.glsl @@ -0,0 +1,8 @@ +/* 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/. */ + +void main(void) +{ + SetFragColor(vColor); +} diff --git a/resources/shaders/mask.vs.glsl b/resources/shaders/mask.vs.glsl new file mode 100644 index 00000000000..491f3ea3863 --- /dev/null +++ b/resources/shaders/mask.vs.glsl @@ -0,0 +1,9 @@ +/* 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/. */ + +void main(void) +{ + vColor = aColorRectTL / 255.0; + gl_Position = uTransform * vec4(aPosition, 1.0); +} diff --git a/resources/shaders/quad.fs.glsl b/resources/shaders/quad.fs.glsl new file mode 100644 index 00000000000..8909cd0755a --- /dev/null +++ b/resources/shaders/quad.fs.glsl @@ -0,0 +1,38 @@ +/* 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/. */ + +// GLSL point in rect test. +// See: https://stackoverflow.com/questions/12751080/glsl-point-inside-box-test +bool PointInRect(vec2 p, vec2 p0, vec2 p1) +{ + vec2 s = step(p0, p) - step(p1, p); + return s.x * s.y != 0.0; +} + +void main(void) +{ + // Clip out. + if (PointInRect(vPosition, vClipOutRect.xy, vClipOutRect.zw)) { + discard; + } + + // Clip in. + if (!PointInRect(vPosition, vClipInRect.xy, vClipInRect.zw)) { + discard; + } + + // Apply image tiling parameters (offset and scale) to color UVs. + vec2 colorTexCoord = vTileParams.xy + fract(vColorTexCoord.xy) * vTileParams.zw; + vec2 maskTexCoord = vMaskTexCoord.xy; + + // Fetch the diffuse and mask texels. + vec4 diffuse = Texture(sDiffuse, colorTexCoord); + vec4 mask = Texture(sMask, maskTexCoord); + + // Extract alpha from the mask (component depends on platform) + float alpha = GetAlphaFromMask(mask); + + // Write the final fragment color. + SetFragColor(diffuse * vec4(vColor.rgb, vColor.a * alpha)); +} diff --git a/resources/shaders/quad.vs.glsl b/resources/shaders/quad.vs.glsl new file mode 100644 index 00000000000..5b43fc539b2 --- /dev/null +++ b/resources/shaders/quad.vs.glsl @@ -0,0 +1,112 @@ +/* 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/. */ + +vec2 Bilerp2(vec2 tl, vec2 tr, vec2 br, vec2 bl, vec2 st) { + return mix(mix(tl, bl, st.y), mix(tr, br, st.y), st.x); +} + +vec4 Bilerp4(vec4 tl, vec4 tr, vec4 br, vec4 bl, vec2 st) { + return mix(mix(tl, bl, st.y), mix(tr, br, st.y), st.x); +} + +void main(void) +{ + // Extract the image tiling parameters. + // These are passed to the fragment shader, since + // the uv interpolation must be done per-fragment. + vTileParams = uTileParams[Bottom7Bits(int(aMisc.w))]; + + // Determine clip rects. + vClipOutRect = uClipRects[int(aMisc.z)]; + vec4 clipInRect = uClipRects[int(aMisc.y)]; + + // Extract the complete (stacking context + css transform) transform + // for this vertex. Transform the position by it. + vec2 offsetParams = uOffsets[Bottom7Bits(int(aMisc.x))].xy; + mat4 matrix = uMatrixPalette[Bottom7Bits(int(aMisc.x))]; + + vec2 p0 = aPositionRect.xy + offsetParams; + vec2 p1 = p0 + aPositionRect.zw; + + vec2 rect_origin = SnapToPixels(p0); + vec2 rect_size = SnapToPixels(p1) - rect_origin; + + // Determine the position, color, and mask texture coordinates of this vertex. + vec4 localPos = vec4(0.0, 0.0, 0.0, 1.0); + bool isBorderCorner = int(aMisc.w) >= 0x80; + bool isBottomTriangle = IsBottomTriangle(); + if (aPosition.y == 0.0) { + localPos.y = rect_origin.y; + if (aPosition.x == 0.0) { + localPos.x = rect_origin.x; + if (isBorderCorner) { + vColor = isBottomTriangle ? aColorRectBL : aColorRectTR; + } + } else { + localPos.x = rect_origin.x + rect_size.x; + if (isBorderCorner) { + vColor = aColorRectTR; + } + } + } else { + localPos.y = rect_origin.y + rect_size.y; + if (aPosition.x == 0.0) { + localPos.x = rect_origin.x; + if (isBorderCorner) { + vColor = aColorRectBL; + } + } else { + localPos.x = rect_origin.x + rect_size.x; + if (isBorderCorner) { + vColor = isBottomTriangle ? aColorRectBL : aColorRectTR; + } + } + } + + // Rotate or clip as necessary. If there is no rotation, we can clip here in the vertex shader + // and save a whole bunch of fragment shader invocations. If there is a rotation, we fall back + // to FS clipping. + // + // The rotation angle is encoded as a negative bottom left u coordinate. (uv coordinates should + // always be nonnegative normally, and gradients don't use color textures, so this is fine.) + vec4 colorTexCoordRectBottom = aColorTexCoordRectBottom; + vec2 localST; + if (colorTexCoordRectBottom.z < 0.0) { + float angle = -colorTexCoordRectBottom.z; + vec2 center = rect_origin + rect_size / 2.0; + vec2 translatedPos = localPos.xy - center; + localST = (localPos.xy - rect_origin) / rect_size; + localPos.xy = vec2(translatedPos.x * cos(angle) - translatedPos.y * sin(angle), + translatedPos.x * sin(angle) + translatedPos.y * cos(angle)) + center; + colorTexCoordRectBottom.z = aColorTexCoordRectTop.x; + vClipInRect = clipInRect; + } else { + localPos.x = clamp(localPos.x, clipInRect.x, clipInRect.z); + localPos.y = clamp(localPos.y, clipInRect.y, clipInRect.w); + localST = (localPos.xy - rect_origin) / rect_size; + vClipInRect = vec4(-1e37, -1e37, 1e38, 1e38); + } + + vColorTexCoord = Bilerp2(aColorTexCoordRectTop.xy, aColorTexCoordRectTop.zw, + colorTexCoordRectBottom.xy, colorTexCoordRectBottom.zw, + localST); + vMaskTexCoord = Bilerp2(aMaskTexCoordRectTop.xy, aMaskTexCoordRectTop.zw, + aMaskTexCoordRectBottom.xy, aMaskTexCoordRectBottom.zw, + localST); + if (!isBorderCorner) { + vColor = Bilerp4(aColorRectTL, aColorRectTR, aColorRectBR, aColorRectBL, localST); + } + + // Normalize the vertex color and mask texture coordinates. + vColor /= 255.0; + vMaskTexCoord /= uAtlasParams.zw; + + vPosition = localPos.xy; + + vec4 worldPos = matrix * localPos; + + // Transform by the orthographic projection into clip space. + gl_Position = uTransform * worldPos; +} + diff --git a/resources/shaders/tile.fs.glsl b/resources/shaders/tile.fs.glsl new file mode 100644 index 00000000000..3355ee4646f --- /dev/null +++ b/resources/shaders/tile.fs.glsl @@ -0,0 +1,11 @@ +/* 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/. */ + +void main(void) { + vec2 textureSize = vBorderPosition.zw - vBorderPosition.xy; + vec2 colorTexCoord = vBorderPosition.xy + mod(vColorTexCoord.xy, 1.0) * textureSize; + vec4 diffuse = Texture(sDiffuse, colorTexCoord); + SetFragColor(diffuse); +} + diff --git a/resources/shaders/tile.vs.glsl b/resources/shaders/tile.vs.glsl new file mode 100644 index 00000000000..7f57bf1e360 --- /dev/null +++ b/resources/shaders/tile.vs.glsl @@ -0,0 +1,11 @@ +/* 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/. */ + +void main(void) +{ + vColorTexCoord = aBorderRadii.xy; + vBorderPosition = aBorderPosition; + gl_Position = uTransform * vec4(aPosition, 1.0); +} + diff --git a/tests/unit/gfx/font_cache_thread.rs b/tests/unit/gfx/font_cache_thread.rs index e44b7908b16..035ad7e8365 100644 --- a/tests/unit/gfx/font_cache_thread.rs +++ b/tests/unit/gfx/font_cache_thread.rs @@ -11,7 +11,7 @@ use style::font_face::Source; fn test_local_web_font() { let (inp_chan, _) = ipc::channel().unwrap(); let (out_chan, out_receiver) = ipc::channel().unwrap(); - let font_cache_thread = FontCacheThread::new(inp_chan); + let font_cache_thread = FontCacheThread::new(inp_chan, None); let family_name = FontFamily::FamilyName(From::from("test family")); let variant_name = FontFamily::FamilyName(From::from("test font face")); diff --git a/tests/wpt/harness/wptrunner/browsers/servo.py b/tests/wpt/harness/wptrunner/browsers/servo.py index 0f6e11f6779..42300e2b453 100644 --- a/tests/wpt/harness/wptrunner/browsers/servo.py +++ b/tests/wpt/harness/wptrunner/browsers/servo.py @@ -58,7 +58,7 @@ def update_properties(): def render_arg(render_backend): - return {"cpu": "--cpu", "webrender": "--webrender"}[render_backend] + return {"cpu": "--cpu", "webrender": "-w"}[render_backend] class ServoBrowser(NullBrowser): |