aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/compositing/buffer_map.rs (renamed from components/gfx/buffer_map.rs)19
-rw-r--r--components/compositing/compositor.rs86
-rw-r--r--components/compositing/compositor_layer.rs35
-rw-r--r--components/compositing/compositor_task.rs18
-rw-r--r--components/compositing/headless.rs1
-rw-r--r--components/compositing/lib.rs2
-rw-r--r--components/gfx/lib.rs2
-rw-r--r--components/gfx/paint_task.rs226
-rw-r--r--components/msg/compositor_msg.rs5
-rw-r--r--components/servo/Cargo.lock2
-rw-r--r--ports/cef/Cargo.lock2
-rw-r--r--ports/gonk/Cargo.lock2
12 files changed, 174 insertions, 226 deletions
diff --git a/components/gfx/buffer_map.rs b/components/compositing/buffer_map.rs
index 2de24c99a73..8e514eab87c 100644
--- a/components/gfx/buffer_map.rs
+++ b/components/compositing/buffer_map.rs
@@ -8,7 +8,6 @@ use euclid::size::Size2D;
use layers::platform::surface::NativeDisplay;
use layers::layers::LayerBuffer;
use std::hash::{Hash, Hasher};
-use std::mem;
/// This is a struct used to store buffers when they are not in use.
/// The paint task can quickly query for a particular size of buffer when it
@@ -70,6 +69,13 @@ impl BufferMap {
}
}
+ pub fn insert_buffers(&mut self, display: &NativeDisplay, buffers: Vec<Box<LayerBuffer>>) {
+ for mut buffer in buffers.into_iter() {
+ buffer.mark_wont_leak();
+ self.insert(display, buffer)
+ }
+ }
+
/// Insert a new buffer into the map.
pub fn insert(&mut self, display: &NativeDisplay, new_buffer: Box<LayerBuffer>) {
let new_key = BufferKey::get(new_buffer.get_size_2d());
@@ -150,17 +156,6 @@ impl BufferMap {
ret
}
- /// Destroys all buffers.
- pub fn clear(&mut self, display: &NativeDisplay) {
- let map = mem::replace(&mut self.map, HashMap::new());
- for (_, value) in map.into_iter() {
- for tile in value.buffers.into_iter() {
- tile.destroy(display)
- }
- }
- self.mem = 0
- }
-
pub fn mem(&self) -> usize {
self.mem
}
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index ace2a499b66..b02027e4672 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -2,6 +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 buffer_map::BufferMap;
use compositor_layer::{CompositorData, CompositorLayer, WantsScrollEventsFlag};
use compositor_task::{CompositorEventListener, CompositorProxy, CompositorReceiver};
use compositor_task::Msg;
@@ -51,6 +52,8 @@ use url::Url;
use util::geometry::{Au, PagePx, ScreenPx, ViewportPx};
use util::opts;
+const BUFFER_MAP_SIZE : usize = 10000000;
+
/// Holds the state when running reftests that determines when it is
/// safe to save the output image.
#[derive(Copy, Clone, PartialEq)]
@@ -154,6 +157,9 @@ pub struct IOCompositor<Window: WindowMethods> {
/// Used by the logic that determines when it is safe to output an
/// image for the reftest framework.
ready_to_save_state: ReadyState,
+
+ /// A data structure to store unused LayerBuffers.
+ buffer_map: BufferMap,
}
pub struct ScrollEvent {
@@ -290,6 +296,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
last_composite_time: 0,
has_seen_quit_event: false,
ready_to_save_state: ReadyState::Unknown,
+ buffer_map: BufferMap::new(BUFFER_MAP_SIZE),
}
}
@@ -387,6 +394,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
+ (Msg::ReturnUnusedLayerBuffers(layer_buffers),
+ ShutdownState::NotShuttingDown) => {
+ self.cache_unused_buffers(layer_buffers);
+ }
+
(Msg::ScrollFragmentPoint(pipeline_id, layer_id, point),
ShutdownState::NotShuttingDown) => {
self.scroll_fragment_to_point(pipeline_id, layer_id, point);
@@ -547,10 +559,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.root_pipeline = Some(frame_tree.pipeline.clone());
// If we have an old root layer, release all old tiles before replacing it.
- match self.scene.root {
- Some(ref layer) => layer.clear_all_tiles(self),
- None => { }
+ let old_root_layer = self.scene.root.take();
+ if let Some(ref old_root_layer) = old_root_layer {
+ old_root_layer.clear_all_tiles(self)
}
+
self.scene.root = Some(self.create_frame_tree_root_layers(frame_tree, None));
self.scene.set_root_layer_size(self.window_size.as_f32());
@@ -616,13 +629,15 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
fn remove_pipeline_root_layer(&mut self, pipeline_id: PipelineId) {
- if let Some(ref root_layer) = self.scene.root {
- // Remove all the compositor layers for this pipeline
- // and send any owned buffers back to the paint task.
- root_layer.remove_root_layer_with_pipeline_id(self, pipeline_id);
+ let root_layer = match self.scene.root {
+ Some(ref root_layer) => root_layer.clone(),
+ None => return,
+ };
- self.pipeline_details.remove(&pipeline_id);
- }
+ // Remove all the compositor layers for this pipeline and recache
+ // any buffers that they owned.
+ root_layer.remove_root_layer_with_pipeline_id(self, pipeline_id);
+ self.pipeline_details.remove(&pipeline_id);
}
fn update_layer_if_exists(&mut self, pipeline_id: PipelineId, properties: LayerProperties) -> bool {
@@ -787,9 +802,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
- let pipeline = self.get_pipeline(pipeline_id);
- let message = PaintMsg::UnusedBuffer(new_layer_buffer_set.buffers);
- let _ = pipeline.paint_chan.send(message);
+ self.cache_unused_buffers(new_layer_buffer_set.buffers);
}
fn assign_painted_buffers_to_layer(&mut self,
@@ -1141,7 +1154,29 @@ impl<Window: WindowMethods> IOCompositor<Window> {
chan.send(ConstellationMsg::KeyEvent(key, state, modifiers)).unwrap()
}
- fn convert_buffer_requests_to_pipeline_requests_map(&self,
+ fn fill_paint_request_with_cached_layer_buffers(&mut self, paint_request: &mut PaintRequest) {
+ if opts::get().gpu_painting {
+ return;
+ }
+
+ for buffer_request in paint_request.buffer_requests.iter_mut() {
+ if self.buffer_map.mem() == 0 {
+ return;
+ }
+
+ if let Some(mut buffer) = self.buffer_map.find(buffer_request.screen_rect.size) {
+ buffer.rect = buffer_request.page_rect;
+ buffer.screen_pos = buffer_request.screen_rect;
+ buffer.resolution = paint_request.scale;
+ buffer.native_surface.mark_wont_leak();
+ buffer.painted_with_cpu = true;
+ buffer.content_age = buffer_request.content_age;
+ buffer_request.layer_buffer = Some(buffer);
+ }
+ }
+ }
+
+ fn convert_buffer_requests_to_pipeline_requests_map(&mut self,
requests: Vec<(Rc<Layer<CompositorData>>,
Vec<BufferRequest>)>)
-> HashMap<PipelineId, Vec<PaintRequest>> {
@@ -1173,29 +1208,20 @@ impl<Window: WindowMethods> IOCompositor<Window> {
LayerKind::Layer2D
};
- vec.push(PaintRequest {
+ let mut paint_request = PaintRequest {
buffer_requests: layer_requests,
scale: scale.get(),
layer_id: layer.extra_data.borrow().id,
epoch: layer.extra_data.borrow().requested_epoch,
layer_kind: layer_kind,
- });
+ };
+ self.fill_paint_request_with_cached_layer_buffers(&mut paint_request);
+ vec.push(paint_request);
}
results
}
- fn send_back_unused_buffers(&mut self,
- unused_buffers: Vec<(Rc<Layer<CompositorData>>,
- Vec<Box<LayerBuffer>>)>) {
- for (layer, buffers) in unused_buffers.into_iter() {
- if !buffers.is_empty() {
- let pipeline = self.get_pipeline(layer.pipeline_id());
- let _ = pipeline.paint_chan.send_opt(PaintMsg::UnusedBuffer(buffers));
- }
- }
- }
-
fn send_viewport_rect_for_layer(&self, layer: Rc<Layer<CompositorData>>) {
if layer.extra_data.borrow().id == LayerId::null() {
let layer_rect = Rect::new(-layer.extra_data.borrow().scroll_offset.to_untyped(),
@@ -1230,7 +1256,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.scene.get_buffer_requests(&mut layers_and_requests, &mut unused_buffers);
// Return unused tiles first, so that they can be reused by any new BufferRequests.
- self.send_back_unused_buffers(unused_buffers);
+ self.cache_unused_buffers(unused_buffers);
if layers_and_requests.len() == 0 {
return false;
@@ -1528,6 +1554,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
None => None,
}
}
+
+ pub fn cache_unused_buffers(&mut self, buffers: Vec<Box<LayerBuffer>>) {
+ if !buffers.is_empty() {
+ self.buffer_map.insert_buffers(&self.native_display, buffers);
+ }
+ }
}
fn find_layer_with_pipeline_and_layer_id_for_layer(layer: Rc<Layer<CompositorData>>,
diff --git a/components/compositing/compositor_layer.rs b/components/compositing/compositor_layer.rs
index 1be9df64ca9..707b7ce06b6 100644
--- a/components/compositing/compositor_layer.rs
+++ b/components/compositing/compositor_layer.rs
@@ -10,7 +10,6 @@ use euclid::length::Length;
use euclid::point::{Point2D, TypedPoint2D};
use euclid::size::TypedSize2D;
use euclid::rect::Rect;
-use gfx::paint_task::Msg as PaintMsg;
use layers::color::Color;
use layers::geometry::LayerPixel;
use layers::layers::{Layer, LayerBufferSet};
@@ -76,25 +75,25 @@ pub trait CompositorLayer {
fn update_layer(&self, layer_properties: LayerProperties);
fn add_buffers<Window>(&self,
- compositor: &IOCompositor<Window>,
+ compositor: &mut IOCompositor<Window>,
new_buffers: Box<LayerBufferSet>,
epoch: Epoch)
where Window: WindowMethods;
/// Destroys all layer tiles, sending the buffers back to the painter to be destroyed or
/// reused.
- fn clear<Window>(&self, compositor: &IOCompositor<Window>) where Window: WindowMethods;
+ fn clear<Window>(&self, compositor: &mut IOCompositor<Window>) where Window: WindowMethods;
/// 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<Window>(&self, compositor: &IOCompositor<Window>)
+ fn clear_all_tiles<Window>(&self, compositor: &mut IOCompositor<Window>)
where Window: WindowMethods;
/// Removes the root layer (and any children) for a given pipeline from the
/// compositor. Buffers that the compositor is holding are returned to the
/// owning paint task.
fn remove_root_layer_with_pipeline_id<Window>(&self,
- compositor: &IOCompositor<Window>,
+ compositor: &mut IOCompositor<Window>,
pipeline_id: PipelineId)
where Window: WindowMethods;
@@ -214,7 +213,7 @@ 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<Window>(&self,
- compositor: &IOCompositor<Window>,
+ compositor: &mut IOCompositor<Window>,
new_buffers: Box<LayerBufferSet>,
epoch: Epoch)
where Window: WindowMethods {
@@ -225,33 +224,21 @@ impl CompositorLayer for Layer<CompositorData> {
self.add_buffer(buffer);
}
- let unused_buffers = self.collect_unused_buffers();
- if !unused_buffers.is_empty() { // send back unused buffers
- let pipeline = compositor.get_pipeline(self.pipeline_id());
- let _ = pipeline.paint_chan.send(PaintMsg::UnusedBuffer(unused_buffers));
- }
+ compositor.cache_unused_buffers(self.collect_unused_buffers())
}
- fn clear<Window>(&self, compositor: &IOCompositor<Window>) where Window: WindowMethods {
- let mut buffers = self.collect_buffers();
+ fn clear<Window>(&self, compositor: &mut IOCompositor<Window>) where Window: WindowMethods {
+ let buffers = self.collect_buffers();
if !buffers.is_empty() {
- // We have no way of knowing without a race whether the paint task is even up and
- // running, but mark the buffers as not leaking. If the paint task died, then the
- // buffers are going to be cleaned up.
- for buffer in buffers.iter_mut() {
- buffer.mark_wont_leak()
- }
-
- let pipeline = compositor.get_pipeline(self.pipeline_id());
- let _ = pipeline.paint_chan.send(PaintMsg::UnusedBuffer(buffers));
+ compositor.cache_unused_buffers(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<Window>(&self,
- compositor: &IOCompositor<Window>)
+ compositor: &mut IOCompositor<Window>)
where Window: WindowMethods {
self.clear(compositor);
for kid in self.children().iter() {
@@ -260,7 +247,7 @@ impl CompositorLayer for Layer<CompositorData> {
}
fn remove_root_layer_with_pipeline_id<Window>(&self,
- compositor: &IOCompositor<Window>,
+ compositor: &mut IOCompositor<Window>,
pipeline_id: PipelineId)
where Window: WindowMethods {
// Find the child that is the root layer for this pipeline.
diff --git a/components/compositing/compositor_task.rs b/components/compositing/compositor_task.rs
index 3c4521e1a81..15e5f59f513 100644
--- a/components/compositing/compositor_task.rs
+++ b/components/compositing/compositor_task.rs
@@ -14,7 +14,7 @@ use windowing::{WindowEvent, WindowMethods};
use euclid::point::Point2D;
use euclid::rect::Rect;
use layers::platform::surface::NativeDisplay;
-use layers::layers::LayerBufferSet;
+use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
use msg::compositor_msg::{Epoch, LayerId, LayerProperties, FrameTreeId};
use msg::compositor_msg::{PaintListener, ScriptListener};
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
@@ -111,6 +111,18 @@ impl PaintListener for Box<CompositorProxy+'static+Send> {
self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id));
}
+ fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>) {
+ let mut layer_buffers = Vec::new();
+ for request in buffer_requests.into_iter() {
+ if let Some(layer_buffer) = request.layer_buffer {
+ layer_buffers.push(layer_buffer);
+ }
+ }
+ if !layer_buffers.is_empty() {
+ self.send(Msg::ReturnUnusedLayerBuffers(layer_buffers));
+ }
+ }
+
fn initialize_layers_for_pipeline(&mut self,
pipeline_id: PipelineId,
properties: Vec<LayerProperties>,
@@ -184,6 +196,9 @@ pub enum Msg {
NewFavicon(Url),
/// <head> tag finished parsing
HeadParsed,
+ /// Signal that the paint task ignored the paint requests that carried
+ /// these layer buffers, so that they can be re-added to the surface cache.
+ ReturnUnusedLayerBuffers(Vec<Box<LayerBuffer>>),
}
impl Debug for Msg {
@@ -212,6 +227,7 @@ impl Debug for Msg {
Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
Msg::NewFavicon(..) => write!(f, "NewFavicon"),
Msg::HeadParsed => write!(f, "HeadParsed"),
+ Msg::ReturnUnusedLayerBuffers(..) => write!(f, "ReturnUnusedLayerBuffers"),
}
}
}
diff --git a/components/compositing/headless.rs b/components/compositing/headless.rs
index a92906d6756..c4a4368d49b 100644
--- a/components/compositing/headless.rs
+++ b/components/compositing/headless.rs
@@ -111,6 +111,7 @@ impl CompositorEventListener for NullCompositor {
Msg::IsReadyToSaveImageReply(..) => {}
Msg::NewFavicon(..) => {}
Msg::HeadParsed => {}
+ Msg::ReturnUnusedLayerBuffers(..) => {}
}
true
}
diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs
index ba2934216e6..c3f64f8703f 100644
--- a/components/compositing/lib.rs
+++ b/components/compositing/lib.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![feature(box_syntax)]
+#![feature(iter_cmp)]
#![feature(slice_bytes)]
#![feature(vec_push_all)]
@@ -43,6 +44,7 @@ pub use constellation::Constellation;
pub mod compositor_task;
+mod buffer_map;
mod compositor_layer;
mod compositor;
mod headless;
diff --git a/components/gfx/lib.rs b/components/gfx/lib.rs
index bc9b0b94eaf..5f147f8adb4 100644
--- a/components/gfx/lib.rs
+++ b/components/gfx/lib.rs
@@ -9,7 +9,6 @@
#![feature(custom_derive)]
#![feature(hashmap_hasher)]
#![cfg_attr(any(target_os="linux", target_os = "android"), feature(heap_api))]
-#![feature(iter_cmp)]
#![feature(plugin)]
#![feature(str_char)]
#![feature(vec_push_all)]
@@ -76,7 +75,6 @@ pub mod font_cache_task;
pub mod font_template;
// Misc.
-mod buffer_map;
mod filters;
// Platform-specific implementations.
diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs
index 68aaa3726ff..698d9501140 100644
--- a/components/gfx/paint_task.rs
+++ b/components/gfx/paint_task.rs
@@ -4,7 +4,6 @@
//! The task that handles all painting.
-use buffer_map::BufferMap;
use display_list::{self, StackingContext};
use font_cache_task::FontCacheTask;
use font_context::FontContext;
@@ -25,7 +24,7 @@ use msg::compositor_msg::{LayerProperties, PaintListener, ScrollPolicy};
use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::{ConstellationChan, Failure, PipelineId};
use msg::constellation_msg::PipelineExitType;
-use profile_traits::mem::{self, Report, Reporter, ReportsChan};
+use profile_traits::mem::{self, Reporter, ReportsChan};
use profile_traits::time::{self, profile};
use rand::{self, Rng};
use skia::SkiaGrGLNativeContextRef;
@@ -75,7 +74,6 @@ pub enum Msg {
PaintInit(Epoch, Arc<StackingContext>),
CanvasLayer(LayerId, Arc<Mutex<Sender<CanvasMsg>>>),
Paint(Vec<PaintRequest>, FrameTreeId),
- UnusedBuffer(Vec<Box<LayerBuffer>>),
PaintPermissionGranted,
PaintPermissionRevoked,
CollectReports(ReportsChan),
@@ -111,7 +109,7 @@ impl Reporter for PaintChan {
pub struct PaintTask<C> {
id: PipelineId,
- url: Url,
+ _url: Url,
port: Receiver<Msg>,
compositor: C,
constellation_chan: ConstellationChan,
@@ -125,9 +123,6 @@ pub struct PaintTask<C> {
/// The name used for the task's memory reporter.
pub reporter_name: String,
- /// The native graphics context.
- native_display: Option<NativeDisplay>,
-
/// The root stacking context sent to us by the layout thread.
root_stacking_context: Option<Arc<StackingContext>>,
@@ -137,16 +132,9 @@ pub struct PaintTask<C> {
/// The current epoch counter is passed by the layout task
current_epoch: Option<Epoch>,
- /// A data structure to store unused LayerBuffers
- buffer_map: BufferMap,
-
/// Communication handles to each of the worker threads.
worker_threads: Vec<WorkerThreadProxy>,
- /// Tracks the number of buffers that the compositor currently owns. The
- /// PaintTask waits to exit until all buffers are returned.
- used_buffer_count: usize,
-
/// A map to track the canvas specific layers
canvas_map: HashMap<LayerId, Arc<Mutex<Sender<CanvasMsg>>>>,
}
@@ -192,31 +180,22 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
// FIXME: rust/#5967
let mut paint_task = PaintTask {
id: id,
- url: url,
+ _url: url,
port: port,
compositor: compositor,
constellation_chan: constellation_chan,
time_profiler_chan: time_profiler_chan,
mem_profiler_chan: mem_profiler_chan,
reporter_name: reporter_name,
- native_display: native_display,
root_stacking_context: None,
paint_permission: false,
current_epoch: None,
- buffer_map: BufferMap::new(10000000),
worker_threads: worker_threads,
- used_buffer_count: 0,
canvas_map: HashMap::new()
};
paint_task.start();
- // Destroy all the buffers.
- match paint_task.native_display.as_ref() {
- Some(ctx) => paint_task.buffer_map.clear(ctx),
- None => (),
- }
-
// Tell all the worker threads to shut down.
for worker_thread in paint_task.worker_threads.iter_mut() {
worker_thread.exit()
@@ -231,8 +210,6 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
fn start(&mut self) {
debug!("PaintTask: beginning painting loop");
- let mut exit_response_channel : Option<Sender<()>> = None;
- let mut waiting_for_compositor_buffers_to_exit = false;
loop {
match self.port.recv().unwrap() {
Msg::PaintInit(epoch, stacking_context) => {
@@ -246,11 +223,6 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
continue;
}
- // If waiting to exit, ignore any more paint commands
- if waiting_for_compositor_buffers_to_exit {
- continue;
- }
-
self.initialize_layers();
}
// Inserts a new canvas renderer to the layer map
@@ -266,46 +238,25 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
continue;
}
- // If waiting to exit, ignore any more paint commands
- if waiting_for_compositor_buffers_to_exit {
- continue;
- }
-
let mut replies = Vec::new();
for PaintRequest { buffer_requests, scale, layer_id, epoch, layer_kind }
in requests.into_iter() {
if self.current_epoch == Some(epoch) {
self.paint(&mut replies, buffer_requests, scale, layer_id, layer_kind);
} else {
- debug!("painter epoch mismatch: {:?} != {:?}", self.current_epoch, epoch);
+ debug!("PaintTask: Ignoring requests with epoch mismatch: {:?} != {:?}",
+ self.current_epoch,
+ epoch);
+ self.compositor.ignore_buffer_requests(buffer_requests);
}
}
- for reply in replies.iter() {
- let &(_, ref buffer_set) = reply;
- self.used_buffer_count += (*buffer_set).buffers.len();
- }
-
debug!("PaintTask: returning surfaces");
self.compositor.assign_painted_buffers(self.id,
self.current_epoch.unwrap(),
replies,
frame_tree_id);
}
- Msg::UnusedBuffer(unused_buffers) => {
- debug!("PaintTask {:?}: Received {} unused buffers", self.id, unused_buffers.len());
- self.used_buffer_count -= unused_buffers.len();
-
- for buffer in unused_buffers.into_iter().rev() {
- self.buffer_map.insert(native_display!(self), buffer);
- }
-
- if waiting_for_compositor_buffers_to_exit && self.used_buffer_count == 0 {
- debug!("PaintTask: Received all loaned buffers, exiting.");
- exit_response_channel.map(|channel| channel.send(()));
- break;
- }
- }
Msg::PaintPermissionGranted => {
self.paint_permission = true;
@@ -316,88 +267,25 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
Msg::PaintPermissionRevoked => {
self.paint_permission = false;
}
- Msg::CollectReports(reports_chan) => {
- // FIXME(njn): should eventually measure other parts of the paint task.
- let mut reports = vec![];
- reports.push(Report {
- path: path!["pages", format!("url({})", self.url), "paint-task", "buffer-map"],
- size: self.buffer_map.mem(),
- });
- reports_chan.send(reports);
+ Msg::CollectReports(_) => {
+ // FIXME(njn): should eventually measure the paint task.
}
- Msg::Exit(response_channel, exit_type) => {
+ Msg::Exit(response_channel, _) => {
let msg = mem::ProfilerMsg::UnregisterReporter(self.reporter_name.clone());
self.mem_profiler_chan.send(msg);
- // Ask the compositor to return any used buffers it
- // is holding for this paint task. This previously was
- // sent from the constellation. However, it needs to be sent
- // from here to avoid a race condition with the paint
- // messages above.
+ // Ask the compositor to remove any layers it is holding for this paint task.
+ // FIXME(mrobinson): This can probably move back to the constellation now.
self.compositor.notify_paint_task_exiting(self.id);
- let should_wait_for_compositor_buffers = match exit_type {
- PipelineExitType::Complete => false,
- PipelineExitType::PipelineOnly => self.used_buffer_count != 0
- };
-
- if !should_wait_for_compositor_buffers {
- debug!("PaintTask: Exiting without waiting for compositor buffers.");
- response_channel.map(|channel| channel.send(()));
- break;
- }
-
- // If we own buffers in the compositor and we are not exiting completely, wait
- // for the compositor to return buffers, so that we can release them properly.
- // When doing a complete exit, the compositor lets all buffers leak.
- debug!("PaintTask {:?}: Saw ExitMsg, {} buffers in use", self.id, self.used_buffer_count);
- waiting_for_compositor_buffers_to_exit = true;
- exit_response_channel = response_channel;
+ debug!("PaintTask: Exiting.");
+ response_channel.map(|channel| channel.send(()));
+ break;
}
}
}
}
- /// Retrieves an appropriately-sized layer buffer from the cache to match the requirements of
- /// the given tile, or creates one if a suitable one cannot be found.
- fn find_or_create_layer_buffer_for_tile(&mut self, tile: &BufferRequest, scale: f32)
- -> Option<Box<LayerBuffer>> {
- let width = tile.screen_rect.size.width;
- let height = tile.screen_rect.size.height;
- if opts::get().gpu_painting {
- return None
- }
-
- match self.buffer_map.find(tile.screen_rect.size) {
- Some(mut buffer) => {
- buffer.rect = tile.page_rect;
- buffer.screen_pos = tile.screen_rect;
- buffer.resolution = scale;
- buffer.native_surface.mark_wont_leak();
- buffer.painted_with_cpu = true;
- buffer.content_age = tile.content_age;
- return Some(buffer)
- }
- None => {}
- }
-
- // Create an empty native surface. We mark it as not leaking
- // in case it dies in transit to the compositor task.
- let mut native_surface: NativeSurface =
- layers::platform::surface::NativeSurface::new(native_display!(self),
- Size2D::new(width as i32, height as i32));
- native_surface.mark_wont_leak();
-
- Some(box LayerBuffer {
- native_surface: native_surface,
- rect: tile.page_rect,
- screen_pos: tile.screen_rect,
- resolution: scale,
- painted_with_cpu: true,
- content_age: tile.content_age,
- })
- }
-
/// Paints one layer and places the painted tiles in `replies`.
fn paint(&mut self,
replies: &mut Vec<(LayerId, Box<LayerBufferSet>)>,
@@ -423,10 +311,8 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
let tile_count = tiles.len();
for (i, tile) in tiles.into_iter().enumerate() {
let thread_id = i % self.worker_threads.len();
- let layer_buffer = self.find_or_create_layer_buffer_for_tile(&tile, scale);
self.worker_threads[thread_id].paint_tile(thread_id,
tile,
- layer_buffer,
stacking_context.clone(),
scale,
layer_kind);
@@ -559,13 +445,11 @@ impl WorkerThreadProxy {
fn paint_tile(&mut self,
thread_id: usize,
tile: BufferRequest,
- layer_buffer: Option<Box<LayerBuffer>>,
stacking_context: Arc<StackingContext>,
scale: f32,
layer_kind: LayerKind) {
let msg = MsgToWorkerThread::PaintTile(thread_id,
tile,
- layer_buffer,
stacking_context,
scale,
layer_kind);
@@ -613,14 +497,13 @@ impl WorkerThread {
loop {
match self.receiver.recv().unwrap() {
MsgToWorkerThread::Exit => break,
- MsgToWorkerThread::PaintTile(thread_id, tile, layer_buffer, stacking_context, scale, layer_kind) => {
+ MsgToWorkerThread::PaintTile(thread_id, tile, stacking_context, scale, layer_kind) => {
let draw_target = self.optimize_and_paint_tile(thread_id,
&tile,
stacking_context,
scale,
layer_kind);
- let buffer = self.create_layer_buffer_for_painted_tile(&tile,
- layer_buffer,
+ let buffer = self.create_layer_buffer_for_painted_tile(tile,
draw_target,
scale);
self.sender.send(MsgFromWorkerThread::PaintedTile(buffer)).unwrap()
@@ -715,32 +598,18 @@ impl WorkerThread {
draw_target
}
- fn create_layer_buffer_for_painted_tile(&mut self,
- tile: &BufferRequest,
- layer_buffer: Option<Box<LayerBuffer>>,
- draw_target: DrawTarget,
- scale: f32)
- -> Box<LayerBuffer> {
- // Extract the texture from the draw target and place it into its slot in the buffer. If
- // using CPU painting, upload it first.
- //
- // FIXME(pcwalton): We should supply the texture and native surface *to* the draw target in
- // GPU painting mode, so that it doesn't have to recreate it.
- if !opts::get().gpu_painting {
- let mut buffer = layer_buffer.unwrap();
- draw_target.snapshot().get_data_surface().with_data(|data| {
- buffer.native_surface.upload(native_display!(self), data);
- debug!("painting worker thread uploading to native surface {}",
- buffer.native_surface.get_id());
- });
- return buffer
- }
-
+ fn create_layer_buffer_for_gpu_painted_tile(&mut self,
+ tile: BufferRequest,
+ draw_target: DrawTarget,
+ scale: f32)
+ -> Box<LayerBuffer> {
// GPU painting path:
draw_target.make_current();
// We mark the native surface as not leaking in case the surfaces
// die on their way to the compositor task.
+ // FIXME(pcwalton): We should supply the texture and native surface *to* the draw target in
+ // GPU painting mode, so that it doesn't have to recreate it.
let mut native_surface: NativeSurface =
NativeSurface::from_draw_target_backing(draw_target.steal_draw_target_backing());
native_surface.mark_wont_leak();
@@ -754,11 +623,56 @@ impl WorkerThread {
content_age: tile.content_age,
}
}
+
+ fn create_layer_buffer_for_cpu_painted_tile(&mut self,
+ mut tile: BufferRequest,
+ draw_target: DrawTarget,
+ scale: f32)
+ -> Box<LayerBuffer> {
+ let mut layer_buffer = tile.layer_buffer.take().unwrap_or_else(|| {
+ // Create an empty native surface. We mark it as not leaking
+ // in case it dies in transit to the compositor task.
+ let width = tile.screen_rect.size.width;
+ let height = tile.screen_rect.size.height;
+ let mut native_surface: NativeSurface =
+ layers::platform::surface::NativeSurface::new(native_display!(self),
+ Size2D::new(width as i32, height as i32));
+ native_surface.mark_wont_leak();
+
+ box LayerBuffer {
+ native_surface: native_surface,
+ rect: tile.page_rect,
+ screen_pos: tile.screen_rect,
+ resolution: scale,
+ painted_with_cpu: true,
+ content_age: tile.content_age,
+ }
+ });
+
+ draw_target.snapshot().get_data_surface().with_data(|data| {
+ layer_buffer.native_surface.upload(native_display!(self), data);
+ debug!("painting worker thread uploading to native surface {}",
+ layer_buffer.native_surface.get_id());
+ });
+ layer_buffer
+ }
+
+ fn create_layer_buffer_for_painted_tile(&mut self,
+ tile: BufferRequest,
+ draw_target: DrawTarget,
+ scale: f32)
+ -> Box<LayerBuffer> {
+ if opts::get().gpu_painting {
+ self.create_layer_buffer_for_gpu_painted_tile(tile, draw_target, scale)
+ } else {
+ self.create_layer_buffer_for_cpu_painted_tile(tile, draw_target, scale)
+ }
+ }
}
enum MsgToWorkerThread {
Exit,
- PaintTile(usize, BufferRequest, Option<Box<LayerBuffer>>, Arc<StackingContext>, f32, LayerKind),
+ PaintTile(usize, BufferRequest, Arc<StackingContext>, f32, LayerKind),
}
enum MsgFromWorkerThread {
diff --git a/components/msg/compositor_msg.rs b/components/msg/compositor_msg.rs
index 24c948cdb9f..80f0548dbc4 100644
--- a/components/msg/compositor_msg.rs
+++ b/components/msg/compositor_msg.rs
@@ -8,7 +8,7 @@ use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::Matrix4;
use layers::platform::surface::NativeDisplay;
-use layers::layers::LayerBufferSet;
+use layers::layers::{BufferRequest, LayerBufferSet};
use std::fmt::{Formatter, Debug};
use std::fmt;
@@ -108,6 +108,9 @@ pub trait PaintListener {
replies: Vec<(LayerId, Box<LayerBufferSet>)>,
frame_tree_id: FrameTreeId);
+ /// Inform the compositor that these buffer requests will be ignored.
+ fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>);
+
// Notification that the paint task wants to exit.
fn notify_paint_task_exiting(&mut self, pipeline_id: PipelineId);
}
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock
index 78236a22a4b..82652008b21 100644
--- a/components/servo/Cargo.lock
+++ b/components/servo/Cargo.lock
@@ -640,7 +640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "layers"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-layers#01bfc9fbb0748af62d89720f67a84e9542fad1d1"
+source = "git+https://github.com/servo/rust-layers#fff80972a75b5c4bce731de2ee2452bb8ef96430"
dependencies = [
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
"cgl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock
index d79dbf5450b..097e24b04ac 100644
--- a/ports/cef/Cargo.lock
+++ b/ports/cef/Cargo.lock
@@ -632,7 +632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "layers"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-layers#01bfc9fbb0748af62d89720f67a84e9542fad1d1"
+source = "git+https://github.com/servo/rust-layers#fff80972a75b5c4bce731de2ee2452bb8ef96430"
dependencies = [
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
"cgl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock
index 88eee3bc717..203fe5bb1e4 100644
--- a/ports/gonk/Cargo.lock
+++ b/ports/gonk/Cargo.lock
@@ -566,7 +566,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "layers"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-layers#01bfc9fbb0748af62d89720f67a84e9542fad1d1"
+source = "git+https://github.com/servo/rust-layers#fff80972a75b5c4bce731de2ee2452bb8ef96430"
dependencies = [
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
"cgl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",