mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Add WebRender integration to Servo.
WebRender is an experimental GPU accelerated rendering backend for Servo. The WebRender backend can be specified by running Servo with the -w option (otherwise the default rendering backend will be used). WebRender has many bugs, and missing features - but it is usable to browse most websites - please report any WebRender specific rendering bugs you encounter!
This commit is contained in:
parent
f7f0eea470
commit
c0531c312f
75 changed files with 2869 additions and 888 deletions
|
@ -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"]}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
self.perform_updates_after_scroll();
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue