Bug 1476368 - Preallocate the render task tree. r=kvark
authorNicolas Silva <nsilva@mozilla.com>
Fri, 15 Feb 2019 16:57:43 +0000
changeset 459739 b7ad79d07c44df3b899f186d4dce51264c642b31
parent 459738 d4c7ca5bb69df8e0c5b6dcfb139fc7741470941b
child 459740 a500b4dd9ee59b049d7e83de95219b0c99ae00ef
push id35570
push usercsabou@mozilla.com
push dateMon, 18 Feb 2019 15:51:41 +0000
treeherdermozilla-central@4a53bea7d587 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskvark
bugs1476368
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1476368 - Preallocate the render task tree. r=kvark Differential Revision: https://phabricator.services.mozilla.com/D19916
gfx/wr/webrender/src/frame_builder.rs
gfx/wr/webrender/src/glyph_rasterizer/mod.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/render_task.rs
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -14,17 +14,17 @@ use hit_test::{HitTester, HitTestingRun}
 use internal_types::{FastHashMap, PlaneSplitter};
 use picture::{PictureSurface, PictureUpdateState, SurfaceInfo, ROOT_SURFACE_INDEX, SurfaceIndex};
 use picture::{RetainedTiles, TileCache, DirtyRegion};
 use prim_store::{PrimitiveStore, SpaceMapper, PictureIndex, PrimitiveDebugId, PrimitiveScratchBuffer};
 #[cfg(feature = "replay")]
 use prim_store::{PrimitiveStoreStats};
 use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
 use render_backend::{DataStores, FrameStamp};
-use render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree};
+use render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree, RenderTaskTreeCounters};
 use resource_cache::{ResourceCache};
 use scene::{ScenePipeline, SceneProperties};
 use segment::SegmentBuilder;
 use spatial_node::SpatialNode;
 use std::{f32, mem};
 use std::sync::Arc;
 use tiling::{Frame, RenderPass, RenderPassKind, RenderTargetContext, RenderTarget};
 
@@ -498,16 +498,17 @@ impl FrameBuilder {
         device_pixel_scale: DevicePixelScale,
         layer: DocumentLayer,
         pan: WorldPoint,
         texture_cache_profile: &mut TextureCacheProfileCounters,
         gpu_cache_profile: &mut GpuCacheProfileCounters,
         scene_properties: &SceneProperties,
         data_stores: &mut DataStores,
         scratch: &mut PrimitiveScratchBuffer,
+        render_task_counters: &mut RenderTaskTreeCounters,
         debug_flags: DebugFlags,
     ) -> Frame {
         profile_scope!("build");
         profile_marker!("BuildFrame");
         debug_assert!(
             DeviceIntRect::new(DeviceIntPoint::zero(), self.window_size)
                 .contains_rect(&self.screen_rect)
         );
@@ -525,17 +526,20 @@ impl FrameBuilder {
         let mut transform_palette = TransformPalette::new();
         clip_scroll_tree.update_tree(
             pan,
             scene_properties,
             Some(&mut transform_palette),
         );
         self.clip_store.clear_old_instances();
 
-        let mut render_tasks = RenderTaskTree::new(stamp.frame_id());
+        let mut render_tasks = RenderTaskTree::new(
+            stamp.frame_id(),
+            render_task_counters,
+        );
         let mut surfaces = Vec::new();
 
         let screen_size = self.screen_rect.size.to_i32();
         let screen_world_rect = (self.screen_rect.to_f32() / device_pixel_scale).round_out();
 
         let main_render_task_id = self.build_layer_screen_rects_and_cull_layers(
             screen_world_rect,
             clip_scroll_tree,
@@ -635,17 +639,17 @@ impl FrameBuilder {
                     }
                 }
             }
         }
 
         let gpu_cache_frame_id = gpu_cache.end_frame(gpu_cache_profile).frame_id();
 
         render_tasks.write_task_data(device_pixel_scale);
-
+        *render_task_counters = render_tasks.counters();
         resource_cache.end_frame(texture_cache_profile);
 
         Frame {
             window_size: self.window_size,
             inner_rect: self.screen_rect,
             device_pixel_ratio: device_pixel_scale.0,
             background_color: self.background_color,
             layer,
--- a/gfx/wr/webrender/src/glyph_rasterizer/mod.rs
+++ b/gfx/wr/webrender/src/glyph_rasterizer/mod.rs
@@ -707,17 +707,17 @@ mod test_glyph_rasterizer {
         // 50 glyphs each, deletes the font and waits for the result.
 
         use rayon::ThreadPoolBuilder;
         use std::fs::File;
         use std::io::Read;
         use texture_cache::TextureCache;
         use glyph_cache::GlyphCache;
         use gpu_cache::GpuCache;
-        use render_task::{RenderTaskCache, RenderTaskTree};
+        use render_task::{RenderTaskCache, RenderTaskTree, RenderTaskTreeCounters};
         use profiler::TextureCacheProfileCounters;
         use api::{FontKey, FontTemplate, FontRenderMode,
                   IdNamespace, ColorF, ColorU, DevicePoint};
         use render_backend::FrameId;
         use app_units::Au;
         use thread_profiler::register_thread_with_profiler;
         use std::sync::Arc;
         use glyph_rasterizer::{FontInstance, GlyphKey, GlyphRasterizer};
@@ -729,17 +729,17 @@ mod test_glyph_rasterizer {
             })
             .build();
         let workers = Arc::new(worker.unwrap());
         let mut glyph_rasterizer = GlyphRasterizer::new(workers).unwrap();
         let mut glyph_cache = GlyphCache::new();
         let mut gpu_cache = GpuCache::new_for_testing();
         let mut texture_cache = TextureCache::new_for_testing(2048, 1024);
         let mut render_task_cache = RenderTaskCache::new();
-        let mut render_task_tree = RenderTaskTree::new(FrameId::INVALID);
+        let mut render_task_tree = RenderTaskTree::new(FrameId::INVALID, &RenderTaskTreeCounters::new());
         let mut font_file =
             File::open("../wrench/reftests/text/VeraBd.ttf").expect("Couldn't open font file");
         let mut font_data = vec![];
         font_file
             .read_to_end(&mut font_data)
             .expect("failed to read font file");
 
         let font_key = FontKey::new(IdNamespace(0), 0);
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -31,16 +31,17 @@ use hit_test::{HitTest, HitTester};
 use intern_types;
 use internal_types::{DebugOutput, FastHashMap, FastHashSet, RenderedDocument, ResultMsg};
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use picture::RetainedTiles;
 use prim_store::{PrimitiveScratchBuffer, PrimitiveInstance};
 use prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData};
 use profiler::{BackendProfileCounters, IpcProfileCounters, ResourceProfileCounters};
 use record::ApiRecordingReceiver;
+use render_task::RenderTaskTreeCounters;
 use renderer::{AsyncPropertySampler, PipelineInfo};
 use resource_cache::ResourceCache;
 #[cfg(feature = "replay")]
 use resource_cache::PlainCacheOwn;
 #[cfg(any(feature = "capture", feature = "replay"))]
 use resource_cache::PlainResources;
 use scene::{Scene, SceneProperties};
 use scene_builder::*;
@@ -341,16 +342,19 @@ struct Document {
     has_built_scene: bool,
 
     data_stores: DataStores,
 
     /// Contains various vecs of data that is used only during frame building,
     /// where we want to recycle the memory each new display list, to avoid constantly
     /// re-allocating and moving memory around.
     scratch: PrimitiveScratchBuffer,
+    /// Keep track of the size of render task tree to pre-allocate memory up-front
+    /// the next frame.
+    render_task_counters: RenderTaskTreeCounters,
 }
 
 impl Document {
     pub fn new(
         id: DocumentId,
         window_size: DeviceIntSize,
         layer: DocumentLayer,
         default_device_pixel_ratio: f32,
@@ -374,16 +378,17 @@ impl Document {
             hit_tester: None,
             dynamic_properties: SceneProperties::new(),
             frame_is_valid: false,
             hit_tester_is_valid: false,
             rendered_frame_is_valid: false,
             has_built_scene: false,
             data_stores: DataStores::default(),
             scratch: PrimitiveScratchBuffer::new(),
+            render_task_counters: RenderTaskTreeCounters::new(),
         }
     }
 
     fn can_render(&self) -> bool {
         self.frame_builder.is_some() && self.scene.has_root_pipeline()
     }
 
     fn has_pixels(&self) -> bool {
@@ -516,16 +521,17 @@ impl Document {
                 accumulated_scale_factor,
                 self.view.layer,
                 pan,
                 &mut resource_profile.texture_cache,
                 &mut resource_profile.gpu_cache,
                 &self.dynamic_properties,
                 &mut self.data_stores,
                 &mut self.scratch,
+                &mut self.render_task_counters,
                 debug_flags,
             );
             self.hit_tester = Some(frame_builder.create_hit_tester(
                 &self.clip_scroll_tree,
                 &self.data_stores.clip,
             ));
             frame
         };
@@ -1746,16 +1752,17 @@ impl RenderBackend {
                 dynamic_properties: SceneProperties::new(),
                 hit_tester: None,
                 frame_is_valid: false,
                 hit_tester_is_valid: false,
                 rendered_frame_is_valid: false,
                 has_built_scene: false,
                 data_stores,
                 scratch: PrimitiveScratchBuffer::new(),
+                render_task_counters: RenderTaskTreeCounters::new(),
             };
 
             let frame_name = format!("frame-{}-{}", (id.0).0, id.1);
             let frame = CaptureConfig::deserialize::<Frame, _>(root, frame_name);
             let build_frame = match frame {
                 Some(frame) => {
                     info!("\tloaded a built frame with {} passes", frame.passes.len());
 
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -83,27 +83,52 @@ pub struct RenderTaskTree {
     /// picture tasks.
     ///
     /// We render these unconditionally before-rendering the rest of the tree.
     pub cacheable_render_tasks: Vec<RenderTaskId>,
     next_saved: SavedTargetIndex,
     frame_id: FrameId,
 }
 
+#[derive(Debug)]
+pub struct RenderTaskTreeCounters {
+    tasks_len: usize,
+    task_data_len: usize,
+    cacheable_render_tasks_len: usize,
+}
+
+impl RenderTaskTreeCounters {
+    pub fn new() -> Self {
+        RenderTaskTreeCounters {
+            tasks_len: 0,
+            task_data_len: 0,
+            cacheable_render_tasks_len: 0,
+        }
+    }
+}
+
 impl RenderTaskTree {
-    pub fn new(frame_id: FrameId) -> Self {
+    pub fn new(frame_id: FrameId, counters: &RenderTaskTreeCounters) -> Self {
         RenderTaskTree {
-            tasks: Vec::new(),
-            task_data: Vec::new(),
-            cacheable_render_tasks: Vec::new(),
+            tasks: Vec::with_capacity(counters.tasks_len),
+            task_data: Vec::with_capacity(counters.task_data_len),
+            cacheable_render_tasks: Vec::with_capacity(counters.cacheable_render_tasks_len),
             next_saved: SavedTargetIndex(0),
             frame_id,
         }
     }
 
+    pub fn counters(&self) -> RenderTaskTreeCounters {
+        RenderTaskTreeCounters {
+            tasks_len: self.tasks.len(),
+            task_data_len: self.task_data.len(),
+            cacheable_render_tasks_len: self.cacheable_render_tasks.len(),
+        }
+    }
+
     pub fn add(&mut self, task: RenderTask) -> RenderTaskId {
         let index = self.tasks.len() as _;
         self.tasks.push(task);
         RenderTaskId {
             index,
             #[cfg(debug_assertions)]
             frame_id: self.frame_id,
         }