diff options
Diffstat (limited to 'components/compositing/compositor.rs')
-rw-r--r-- | components/compositing/compositor.rs | 321 |
1 files changed, 269 insertions, 52 deletions
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 + } } } } |