aboutsummaryrefslogtreecommitdiffstats
path: root/components/compositing/compositor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/compositing/compositor.rs')
-rw-r--r--components/compositing/compositor.rs321
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
+ }
}
}
}