diff options
-rw-r--r-- | components/compositing/buffer_map.rs (renamed from components/gfx/buffer_map.rs) | 19 | ||||
-rw-r--r-- | components/compositing/compositor.rs | 86 | ||||
-rw-r--r-- | components/compositing/compositor_layer.rs | 35 | ||||
-rw-r--r-- | components/compositing/compositor_task.rs | 18 | ||||
-rw-r--r-- | components/compositing/headless.rs | 1 | ||||
-rw-r--r-- | components/compositing/lib.rs | 2 | ||||
-rw-r--r-- | components/gfx/lib.rs | 2 | ||||
-rw-r--r-- | components/gfx/paint_task.rs | 226 | ||||
-rw-r--r-- | components/msg/compositor_msg.rs | 5 | ||||
-rw-r--r-- | components/servo/Cargo.lock | 2 | ||||
-rw-r--r-- | ports/cef/Cargo.lock | 2 | ||||
-rw-r--r-- | ports/gonk/Cargo.lock | 2 |
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)", |