mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Store pipelines in the Compositor
Instead of cloning pipelines and storing them once per layer, store them globally in the compositor and access them via id. This trades lots of unnecessary duplication for a HashMap lookup.
This commit is contained in:
parent
c5994c65ef
commit
b60f354405
2 changed files with 96 additions and 82 deletions
|
@ -19,7 +19,7 @@ use geom::rect::{Rect, TypedRect};
|
|||
use geom::size::TypedSize2D;
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use gfx::paint_task::Msg as PaintMsg;
|
||||
use gfx::paint_task::{PaintChan, PaintRequest};
|
||||
use gfx::paint_task::PaintRequest;
|
||||
use layers::geometry::{DevicePixel, LayerPixel};
|
||||
use layers::layers::{BufferRequest, Layer, LayerBufferSet};
|
||||
use layers::rendergl;
|
||||
|
@ -154,22 +154,22 @@ struct HitTestResult {
|
|||
}
|
||||
|
||||
struct PipelineDetails {
|
||||
/// The pipeline associated with this PipelineDetails object.
|
||||
pipeline: Option<CompositionPipeline>,
|
||||
|
||||
/// The status of this pipeline's ScriptTask.
|
||||
ready_state: ReadyState,
|
||||
|
||||
/// The status of this pipeline's PaintTask.
|
||||
paint_state: PaintState,
|
||||
|
||||
/// The channel to this pipeline's PaintTask,
|
||||
paint_task_channel: Option<PaintChan>,
|
||||
}
|
||||
|
||||
impl PipelineDetails {
|
||||
fn new() -> PipelineDetails {
|
||||
PipelineDetails {
|
||||
pipeline: None,
|
||||
ready_state: ReadyState::Blank,
|
||||
paint_state: PaintState::Painting,
|
||||
paint_task_channel: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -408,6 +408,20 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
return self.pipeline_details.get_mut(&pipeline_id).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_pipeline<'a>(&'a self, pipeline_id: PipelineId) -> &'a CompositionPipeline {
|
||||
match self.pipeline_details.get(&pipeline_id) {
|
||||
Some(ref details) => {
|
||||
match details.pipeline {
|
||||
Some(ref pipeline) => pipeline,
|
||||
None => panic!("Compositor layer has an unitialized pipeline ({}).",
|
||||
pipeline_id),
|
||||
|
||||
}
|
||||
}
|
||||
None => panic!("Compositor layer has an unknown pipeline ({}).", pipeline_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn change_page_title(&mut self, _: PipelineId, title: Option<String>) {
|
||||
self.window.set_page_title(title);
|
||||
}
|
||||
|
@ -464,7 +478,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
|
||||
// If we have an old root layer, release all old tiles before replacing it.
|
||||
match self.scene.root {
|
||||
Some(ref mut layer) => layer.clear_all_tiles(),
|
||||
Some(ref layer) => layer.clear_all_tiles(self),
|
||||
None => { }
|
||||
}
|
||||
self.scene.root = Some(self.create_frame_tree_root_layers(frame_tree, None));
|
||||
|
@ -491,13 +505,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
scroll_policy: ScrollPolicy::Scrollable,
|
||||
};
|
||||
|
||||
let root_layer = CompositorData::new_layer(pipeline.clone(),
|
||||
layer_properties,
|
||||
let root_layer = CompositorData::new_layer(layer_properties,
|
||||
WantsScrollEventsFlag::WantsScrollEvents,
|
||||
opts::get().tile_size);
|
||||
|
||||
self.get_or_create_pipeline_details(pipeline.id).paint_task_channel =
|
||||
Some(pipeline.paint_chan.clone());
|
||||
self.get_or_create_pipeline_details(pipeline.id).pipeline = Some(pipeline.clone());
|
||||
|
||||
// All root layers mask to bounds.
|
||||
*root_layer.masks_to_bounds.borrow_mut() = true;
|
||||
|
@ -569,9 +581,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
if need_new_base_layer {
|
||||
root_layer.update_layer_except_bounds(layer_properties);
|
||||
|
||||
let root_layer_pipeline = root_layer.extra_data.borrow().pipeline.clone();
|
||||
let base_layer = CompositorData::new_layer(
|
||||
root_layer_pipeline.clone(),
|
||||
layer_properties,
|
||||
WantsScrollEventsFlag::DoesntWantScrollEvents,
|
||||
opts::get().tile_size);
|
||||
|
@ -603,9 +613,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
None => return, // This pipeline is in the process of shutting down.
|
||||
};
|
||||
|
||||
let root_layer_pipeline = root_layer.extra_data.borrow().pipeline.clone();
|
||||
let new_layer = CompositorData::new_layer(root_layer_pipeline,
|
||||
layer_properties,
|
||||
let new_layer = CompositorData::new_layer(layer_properties,
|
||||
WantsScrollEventsFlag::DoesntWantScrollEvents,
|
||||
root_layer.tile_size);
|
||||
root_layer.add_child(new_layer);
|
||||
|
@ -694,18 +702,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
None => {}
|
||||
}
|
||||
|
||||
match self.pipeline_details.entry(pipeline_id) {
|
||||
Occupied(entry) => {
|
||||
match entry.get().paint_task_channel {
|
||||
Some(ref channel) => {
|
||||
let message = PaintMsg::UnusedBuffer(new_layer_buffer_set.buffers);
|
||||
let _ = channel.send_opt(message);
|
||||
}
|
||||
None => panic!("Received buffers for an uninitialized pipeline!"),
|
||||
}
|
||||
}
|
||||
Vacant(_) => panic!("Received buffers for an unknown pipeline!"),
|
||||
}
|
||||
let pipeline = self.get_pipeline(pipeline_id);
|
||||
let message = PaintMsg::UnusedBuffer(new_layer_buffer_set.buffers);
|
||||
let _ = pipeline.paint_chan.send_opt(message);
|
||||
}
|
||||
|
||||
fn assign_painted_buffers_to_layer(&mut self,
|
||||
|
@ -722,7 +721,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
|
||||
// FIXME(pcwalton): This is going to cause problems with inconsistent frames since
|
||||
// we only composite one layer at a time.
|
||||
assert!(layer.add_buffers(new_layer_buffer_set, epoch));
|
||||
assert!(layer.add_buffers(self, new_layer_buffer_set, epoch));
|
||||
self.composite_if_necessary();
|
||||
}
|
||||
|
||||
|
@ -820,7 +819,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
debug!("osmain: loading URL `{}`", url_string);
|
||||
self.got_load_complete_message = false;
|
||||
let root_pipeline_id = match self.scene.root {
|
||||
Some(ref layer) => layer.extra_data.borrow().pipeline.id.clone(),
|
||||
Some(ref layer) => layer.get_pipeline_id(),
|
||||
None => panic!("Compositor: Received WindowEvent::LoadUrl without initialized compositor \
|
||||
layers"),
|
||||
};
|
||||
|
@ -838,14 +837,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
MouseWindowEvent::MouseUp(_, p) => p,
|
||||
};
|
||||
match self.find_topmost_layer_at_point(point / self.scene.scale) {
|
||||
Some(result) => result.layer.send_mouse_event(mouse_window_event, result.point),
|
||||
Some(result) => result.layer.send_mouse_event(self, mouse_window_event, result.point),
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn on_mouse_window_move_event_class(&self, cursor: TypedPoint2D<DevicePixel, f32>) {
|
||||
match self.find_topmost_layer_at_point(cursor / self.scene.scale) {
|
||||
Some(result) => result.layer.send_mouse_move_event(result.point),
|
||||
Some(result) => result.layer.send_mouse_move_event(self, result.point),
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
@ -957,25 +956,21 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
|
||||
fn convert_buffer_requests_to_pipeline_requests_map(&self,
|
||||
requests: Vec<(Rc<Layer<CompositorData>>,
|
||||
Vec<BufferRequest>)>) ->
|
||||
HashMap<PipelineId, (PaintChan,
|
||||
Vec<PaintRequest>)> {
|
||||
Vec<BufferRequest>)>)
|
||||
-> HashMap<PipelineId, Vec<PaintRequest>> {
|
||||
let scale = self.device_pixels_per_page_px();
|
||||
let mut results:
|
||||
HashMap<PipelineId, (PaintChan, Vec<PaintRequest>)> = HashMap::new();
|
||||
let mut results: HashMap<PipelineId, Vec<PaintRequest>> = HashMap::new();
|
||||
|
||||
for (layer, mut layer_requests) in requests.into_iter() {
|
||||
let &(_, ref mut vec) =
|
||||
match results.entry(layer.extra_data.borrow().pipeline.id) {
|
||||
Occupied(mut entry) => {
|
||||
*entry.get_mut() =
|
||||
(layer.extra_data.borrow().pipeline.paint_chan.clone(), vec!());
|
||||
entry.into_mut()
|
||||
}
|
||||
Vacant(entry) => {
|
||||
entry.set((layer.extra_data.borrow().pipeline.paint_chan.clone(), vec!()))
|
||||
}
|
||||
};
|
||||
let vec = match results.entry(layer.get_pipeline_id()) {
|
||||
Occupied(mut entry) => {
|
||||
*entry.get_mut() = Vec::new();
|
||||
entry.into_mut()
|
||||
}
|
||||
Vacant(entry) => {
|
||||
entry.set(Vec::new())
|
||||
}
|
||||
};
|
||||
|
||||
// All the BufferRequests are in layer/device coordinates, but the paint task
|
||||
// wants to know the page coordinates. We scale them before sending them.
|
||||
|
@ -1011,7 +1006,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
if layer.extra_data.borrow().id == LayerId::null() {
|
||||
let layer_rect = Rect(-layer.extra_data.borrow().scroll_offset.to_untyped(),
|
||||
layer.bounds.borrow().size.to_untyped());
|
||||
let pipeline = &layer.extra_data.borrow().pipeline;
|
||||
let pipeline = self.get_pipeline(layer.get_pipeline_id());
|
||||
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
||||
chan.send(ConstellationControlMsg::Viewport(pipeline.id.clone(), layer_rect));
|
||||
}
|
||||
|
@ -1047,9 +1042,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.convert_buffer_requests_to_pipeline_requests_map(layers_and_requests);
|
||||
|
||||
let mut num_paint_msgs_sent = 0;
|
||||
for (_pipeline_id, (chan, requests)) in pipeline_requests.into_iter() {
|
||||
for (pipeline_id, requests) in pipeline_requests.into_iter() {
|
||||
num_paint_msgs_sent += 1;
|
||||
let _ = chan.send_opt(PaintMsg::Paint(requests));
|
||||
let _ = self.get_pipeline(pipeline_id).paint_chan.send_opt(PaintMsg::Paint(requests));
|
||||
}
|
||||
|
||||
self.add_outstanding_paint_msg(num_paint_msgs_sent);
|
||||
|
@ -1267,7 +1262,7 @@ fn find_layer_with_pipeline_and_layer_id_for_layer(layer: Rc<Layer<CompositorDat
|
|||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId)
|
||||
-> Option<Rc<Layer<CompositorData>>> {
|
||||
if layer.extra_data.borrow().pipeline.id == pipeline_id &&
|
||||
if layer.extra_data.borrow().pipeline_id == pipeline_id &&
|
||||
layer.extra_data.borrow().id == layer_id {
|
||||
return Some(layer);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use compositor_task::LayerProperties;
|
||||
use pipeline::CompositionPipeline;
|
||||
use compositor::IOCompositor;
|
||||
use windowing::{MouseWindowEvent, WindowMethods};
|
||||
|
||||
use azure::azure_hl;
|
||||
|
@ -20,13 +20,15 @@ use layers::platform::surface::NativeSurfaceMethods;
|
|||
use script_traits::CompositorEvent::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent};
|
||||
use script_traits::{ScriptControlChan, ConstellationControlMsg};
|
||||
use servo_msg::compositor_msg::{Epoch, LayerId, ScrollPolicy};
|
||||
use servo_msg::constellation_msg::PipelineId;
|
||||
use std::num::Float;
|
||||
use std::num::FloatMath;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct CompositorData {
|
||||
/// This layer's pipeline. BufferRequests and mouse events will be sent through this.
|
||||
pub pipeline: CompositionPipeline,
|
||||
/// This layer's pipeline id. The compositor can associate this id with an
|
||||
/// actual CompositionPipeline.
|
||||
pub pipeline_id: PipelineId,
|
||||
|
||||
/// The ID of this layer within the pipeline.
|
||||
pub id: LayerId,
|
||||
|
@ -47,13 +49,12 @@ pub struct CompositorData {
|
|||
}
|
||||
|
||||
impl CompositorData {
|
||||
pub fn new_layer(pipeline: CompositionPipeline,
|
||||
layer_properties: LayerProperties,
|
||||
pub fn new_layer(layer_properties: LayerProperties,
|
||||
wants_scroll_events: WantsScrollEventsFlag,
|
||||
tile_size: uint)
|
||||
-> Rc<Layer<CompositorData>> {
|
||||
let new_compositor_data = CompositorData {
|
||||
pipeline: pipeline,
|
||||
pipeline_id: layer_properties.pipeline_id,
|
||||
id: layer_properties.id,
|
||||
wants_scroll_events: wants_scroll_events,
|
||||
scroll_policy: layer_properties.scroll_policy,
|
||||
|
@ -68,20 +69,24 @@ impl CompositorData {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait CompositorLayer {
|
||||
pub trait CompositorLayer<Window: WindowMethods> {
|
||||
fn update_layer_except_bounds(&self, layer_properties: LayerProperties);
|
||||
|
||||
fn update_layer(&self, layer_properties: LayerProperties);
|
||||
|
||||
fn add_buffers(&self, new_buffers: Box<LayerBufferSet>, epoch: Epoch) -> bool;
|
||||
fn add_buffers(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
new_buffers: Box<LayerBufferSet>,
|
||||
epoch: Epoch)
|
||||
-> bool;
|
||||
|
||||
/// Destroys all layer tiles, sending the buffers back to the painter to be destroyed or
|
||||
/// reused.
|
||||
fn clear(&self);
|
||||
fn clear(&self, compositor: &IOCompositor<Window>);
|
||||
|
||||
/// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
|
||||
/// painter to be destroyed or reused.
|
||||
fn clear_all_tiles(&self);
|
||||
fn clear_all_tiles(&self, compositor: &IOCompositor<Window>);
|
||||
|
||||
/// Destroys all tiles of all layers, including children, *without* sending them back to the
|
||||
/// painter. You must call this only when the paint task is destined to be going down;
|
||||
|
@ -104,10 +109,12 @@ pub trait CompositorLayer {
|
|||
// sends the event off to the appropriate pipeline. NB: the cursor position is in
|
||||
// page coordinates.
|
||||
fn send_mouse_event(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
event: MouseWindowEvent,
|
||||
cursor: TypedPoint2D<LayerPixel, f32>);
|
||||
|
||||
fn send_mouse_move_event(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
cursor: TypedPoint2D<LayerPixel, f32>);
|
||||
|
||||
fn clamp_scroll_offset_and_scroll_layer(&self,
|
||||
|
@ -120,6 +127,9 @@ pub trait CompositorLayer {
|
|||
|
||||
/// Return a flag describing how this layer deals with scroll events.
|
||||
fn wants_scroll_events(&self) -> WantsScrollEventsFlag;
|
||||
|
||||
/// Return the pipeline id associated with this layer.
|
||||
fn get_pipeline_id(&self) -> PipelineId;
|
||||
}
|
||||
|
||||
#[deriving(Copy, PartialEq, Clone)]
|
||||
|
@ -165,7 +175,7 @@ pub enum ScrollEventResult {
|
|||
ScrollPositionUnchanged,
|
||||
}
|
||||
|
||||
impl CompositorLayer for Layer<CompositorData> {
|
||||
impl<Window: WindowMethods> CompositorLayer<Window> for Layer<CompositorData> {
|
||||
fn update_layer_except_bounds(&self, layer_properties: LayerProperties) {
|
||||
self.extra_data.borrow_mut().epoch = layer_properties.epoch;
|
||||
self.extra_data.borrow_mut().scroll_policy = layer_properties.scroll_policy;
|
||||
|
@ -190,33 +200,35 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
//
|
||||
// If the epoch of the message does not match the layer's epoch, the message is ignored, the
|
||||
// layer buffer set is consumed, and None is returned.
|
||||
fn add_buffers(&self, new_buffers: Box<LayerBufferSet>, epoch: Epoch) -> bool {
|
||||
fn add_buffers(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
new_buffers: Box<LayerBufferSet>,
|
||||
epoch: Epoch)
|
||||
-> bool {
|
||||
if self.extra_data.borrow().epoch != epoch {
|
||||
debug!("add_buffers: compositor epoch mismatch: {} != {}, id: {}",
|
||||
self.extra_data.borrow().epoch,
|
||||
epoch,
|
||||
self.extra_data.borrow().pipeline.id);
|
||||
let msg = PaintMsg::UnusedBuffer(new_buffers.buffers);
|
||||
let _ = self.extra_data.borrow().pipeline.paint_chan.send_opt(msg);
|
||||
self.get_pipeline_id());
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let _ = pipeline.paint_chan.send_opt(PaintMsg::UnusedBuffer(new_buffers.buffers));
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
for buffer in new_buffers.buffers.into_iter().rev() {
|
||||
self.add_buffer(buffer);
|
||||
}
|
||||
for buffer in new_buffers.buffers.into_iter().rev() {
|
||||
self.add_buffer(buffer);
|
||||
}
|
||||
|
||||
let unused_buffers = self.collect_unused_buffers();
|
||||
if !unused_buffers.is_empty() { // send back unused buffers
|
||||
let msg = PaintMsg::UnusedBuffer(unused_buffers);
|
||||
let _ = self.extra_data.borrow().pipeline.paint_chan.send_opt(msg);
|
||||
}
|
||||
let unused_buffers = self.collect_unused_buffers();
|
||||
if !unused_buffers.is_empty() { // send back unused buffers
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let _ = pipeline.paint_chan.send_opt(PaintMsg::UnusedBuffer(unused_buffers));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn clear(&self) {
|
||||
fn clear(&self, compositor: &IOCompositor<Window>) {
|
||||
let mut buffers = self.collect_buffers();
|
||||
|
||||
if !buffers.is_empty() {
|
||||
|
@ -227,16 +239,17 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
buffer.mark_wont_leak()
|
||||
}
|
||||
|
||||
let _ = self.extra_data.borrow().pipeline.paint_chan.send_opt(PaintMsg::UnusedBuffer(buffers));
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let _ = pipeline.paint_chan.send_opt(PaintMsg::UnusedBuffer(buffers));
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
|
||||
/// painter to be destroyed or reused.
|
||||
fn clear_all_tiles(&self) {
|
||||
self.clear();
|
||||
fn clear_all_tiles(&self, compositor: &IOCompositor<Window>) {
|
||||
self.clear(compositor);
|
||||
for kid in self.children().iter() {
|
||||
kid.clear_all_tiles();
|
||||
kid.clear_all_tiles(compositor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,6 +327,7 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
}
|
||||
|
||||
fn send_mouse_event(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
event: MouseWindowEvent,
|
||||
cursor: TypedPoint2D<LayerPixel, f32>) {
|
||||
let event_point = cursor.to_untyped();
|
||||
|
@ -325,15 +339,17 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
MouseWindowEvent::MouseUp(button, _) =>
|
||||
MouseUpEvent(button, event_point),
|
||||
};
|
||||
let pipeline = &self.extra_data.borrow().pipeline;
|
||||
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
||||
let _ = chan.send_opt(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message));
|
||||
}
|
||||
|
||||
fn send_mouse_move_event(&self,
|
||||
compositor: &IOCompositor<Window>,
|
||||
cursor: TypedPoint2D<LayerPixel, f32>) {
|
||||
let message = MouseMoveEvent(cursor.to_untyped());
|
||||
let pipeline = &self.extra_data.borrow().pipeline;
|
||||
let pipeline = compositor.get_pipeline(self.get_pipeline_id());
|
||||
let ScriptControlChan(ref chan) = pipeline.script_chan;
|
||||
let _ = chan.send_opt(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message));
|
||||
}
|
||||
|
@ -362,4 +378,7 @@ impl CompositorLayer for Layer<CompositorData> {
|
|||
self.extra_data.borrow().wants_scroll_events
|
||||
}
|
||||
|
||||
fn get_pipeline_id(&self) -> PipelineId {
|
||||
self.extra_data.borrow().pipeline_id
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue