Bug 1611176 - Avoid expensive memmoves when adding render tasks. r=gw
authorNicolas Silva <nsilva@mozilla.com>
Thu, 23 Jan 2020 19:26:13 +0000
changeset 511570 e30053699db0bc3c77888e789f0ba576f0904d1f
parent 511569 686c9a8825377021ef9aa445b22b759800dc6546
child 511571 4a6071f143a5ffca548f745084b5652c40f66829
push id37049
push userrmaries@mozilla.com
push dateFri, 24 Jan 2020 03:50:24 +0000
treeherdermozilla-central@e05793f68994 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1611176
milestone74.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 1611176 - Avoid expensive memmoves when adding render tasks. r=gw On pages with many render tasks (typically a lot of text shadows), we spend a lot of time moving RenderTask which is a fairly large struct into the render graph's buffer. This patch avoids it by using the VecHelper trick of allocaitng space before initializing the value. Some RenderTask::new_* methods which take the render task graph in parameter were modified to add the task and return the task ID to work around borrow-checking restriction. Differential Revision: https://phabricator.services.mozilla.com/D60854
gfx/wr/webrender/src/frame_builder.rs
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/prim_store/image.rs
gfx/wr/webrender/src/prim_store/mod.rs
gfx/wr/webrender/src/render_task.rs
gfx/wr/webrender/src/render_task_graph.rs
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -265,30 +265,30 @@ impl FrameBuilder {
             max_local_clip: LayoutRect::new(
                 LayoutPoint::new(-MAX_CLIP_COORD, -MAX_CLIP_COORD),
                 LayoutSize::new(2.0 * MAX_CLIP_COORD, 2.0 * MAX_CLIP_COORD),
             ),
             debug_flags,
             fb_config: &scene.config,
         };
 
-        let root_render_task = RenderTask::new_picture(
-            RenderTaskLocation::Fixed(scene.output_rect),
-            scene.output_rect.size.to_f32(),
-            scene.root_pic_index,
-            DeviceIntPoint::zero(),
-            UvRectKind::Rect,
-            ROOT_SPATIAL_NODE_INDEX,
-            global_device_pixel_scale,
-            PrimitiveVisibilityMask::all(),
-            None,
+        let root_render_task_id = render_tasks.add().init(
+            RenderTask::new_picture(
+                RenderTaskLocation::Fixed(scene.output_rect),
+                scene.output_rect.size.to_f32(),
+                scene.root_pic_index,
+                DeviceIntPoint::zero(),
+                UvRectKind::Rect,
+                ROOT_SPATIAL_NODE_INDEX,
+                global_device_pixel_scale,
+                PrimitiveVisibilityMask::all(),
+                None,
+            )
         );
 
-        let root_render_task_id = render_tasks.add(root_render_task);
-
         // Construct a dummy root surface, that represents the
         // main framebuffer surface.
         let root_surface = SurfaceInfo::new(
             ROOT_SPATIAL_NODE_INDEX,
             ROOT_SPATIAL_NODE_INDEX,
             0.0,
             global_screen_world_rect,
             &scene.clip_scroll_tree,
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -3750,30 +3750,30 @@ impl PicturePrimitive {
                         let uv_rect_kind = calculate_uv_rect_kind(
                             &pic_rect,
                             &transform,
                             &device_rect,
                             device_pixel_scale,
                             true,
                         );
 
-                        let picture_task = RenderTask::new_picture(
-                            RenderTaskLocation::Dynamic(None, device_rect.size),
-                            unclipped.size,
-                            pic_index,
-                            device_rect.origin,
-                            uv_rect_kind,
-                            surface_spatial_node_index,
-                            device_pixel_scale,
-                            PrimitiveVisibilityMask::all(),
-                            None,
+                        let picture_task_id = frame_state.render_tasks.add().init(
+                            RenderTask::new_picture(
+                                RenderTaskLocation::Dynamic(None, device_rect.size),
+                                unclipped.size,
+                                pic_index,
+                                device_rect.origin,
+                                uv_rect_kind,
+                                surface_spatial_node_index,
+                                device_pixel_scale,
+                                PrimitiveVisibilityMask::all(),
+                                None,
+                            )
                         );
 
-                        let picture_task_id = frame_state.render_tasks.add(picture_task);
-
                         let blur_render_task_id = RenderTask::new_blur(
                             blur_std_deviation,
                             picture_task_id,
                             frame_state.render_tasks,
                             RenderTargetKind::Color,
                             ClearMode::Transparent,
                             None,
                             original_size,
@@ -3813,30 +3813,32 @@ impl PicturePrimitive {
                         let uv_rect_kind = calculate_uv_rect_kind(
                             &pic_rect,
                             &transform,
                             &device_rect,
                             device_pixel_scale,
                             true,
                         );
 
-                        let mut picture_task = RenderTask::new_picture(
-                            RenderTaskLocation::Dynamic(None, device_rect.size),
-                            unclipped.size,
-                            pic_index,
-                            device_rect.origin,
-                            uv_rect_kind,
-                            surface_spatial_node_index,
-                            device_pixel_scale,
-                            PrimitiveVisibilityMask::all(),
-                            None,
-                        );
-                        picture_task.mark_for_saving();
-
-                        let picture_task_id = frame_state.render_tasks.add(picture_task);
+                        let picture_task_id = frame_state.render_tasks.add().init({
+                            let mut picture_task = RenderTask::new_picture(
+                                RenderTaskLocation::Dynamic(None, device_rect.size),
+                                unclipped.size,
+                                pic_index,
+                                device_rect.origin,
+                                uv_rect_kind,
+                                surface_spatial_node_index,
+                                device_pixel_scale,
+                                PrimitiveVisibilityMask::all(),
+                                None,
+                            );
+                            picture_task.mark_for_saving();
+
+                            picture_task
+                        });
 
                         self.secondary_render_task_id = Some(picture_task_id);
 
                         let mut blur_tasks = BlurTaskCache::default();
 
                         self.extra_gpu_data_handles.resize(shadows.len(), GpuCacheHandle::new());
 
                         let mut blur_render_task_id = picture_task_id;
@@ -3860,91 +3862,91 @@ impl PicturePrimitive {
                         let uv_rect_kind = calculate_uv_rect_kind(
                             &pic_rect,
                             &transform,
                             &clipped,
                             device_pixel_scale,
                             true,
                         );
 
-                        let picture_task = RenderTask::new_picture(
-                            RenderTaskLocation::Dynamic(None, clipped.size),
-                            unclipped.size,
-                            pic_index,
-                            clipped.origin,
-                            uv_rect_kind,
-                            surface_spatial_node_index,
-                            device_pixel_scale,
-                            PrimitiveVisibilityMask::all(),
-                            None,
-                        );
-
-                        let readback_task_id = frame_state.render_tasks.add(
+                        let readback_task_id = frame_state.render_tasks.add().init(
                             RenderTask::new_readback(clipped)
                         );
 
                         frame_state.render_tasks.add_dependency(
                             frame_state.surfaces[parent_surface_index.0].render_tasks.unwrap().port,
                             readback_task_id,
                         );
 
                         self.secondary_render_task_id = Some(readback_task_id);
 
-                        let render_task_id = frame_state.render_tasks.add(picture_task);
+                        let render_task_id = frame_state.render_tasks.add().init(
+                            RenderTask::new_picture(
+                                RenderTaskLocation::Dynamic(None, clipped.size),
+                                unclipped.size,
+                                pic_index,
+                                clipped.origin,
+                                uv_rect_kind,
+                                surface_spatial_node_index,
+                                device_pixel_scale,
+                                PrimitiveVisibilityMask::all(),
+                                None,
+                            )
+                        );
 
                         Some((render_task_id, render_task_id))
                     }
                     PictureCompositeMode::Filter(..) => {
                         let uv_rect_kind = calculate_uv_rect_kind(
                             &pic_rect,
                             &transform,
                             &clipped,
                             device_pixel_scale,
                             true,
                         );
 
-                        let picture_task = RenderTask::new_picture(
-                            RenderTaskLocation::Dynamic(None, clipped.size),
-                            unclipped.size,
-                            pic_index,
-                            clipped.origin,
-                            uv_rect_kind,
-                            surface_spatial_node_index,
-                            device_pixel_scale,
-                            PrimitiveVisibilityMask::all(),
-                            None,
+                        let render_task_id = frame_state.render_tasks.add().init(
+                            RenderTask::new_picture(
+                                RenderTaskLocation::Dynamic(None, clipped.size),
+                                unclipped.size,
+                                pic_index,
+                                clipped.origin,
+                                uv_rect_kind,
+                                surface_spatial_node_index,
+                                device_pixel_scale,
+                                PrimitiveVisibilityMask::all(),
+                                None,
+                            )
                         );
 
-                        let render_task_id = frame_state.render_tasks.add(picture_task);
-
                         Some((render_task_id, render_task_id))
                     }
                     PictureCompositeMode::ComponentTransferFilter(..) => {
                         let uv_rect_kind = calculate_uv_rect_kind(
                             &pic_rect,
                             &transform,
                             &clipped,
                             device_pixel_scale,
                             true,
                         );
 
-                        let picture_task = RenderTask::new_picture(
-                            RenderTaskLocation::Dynamic(None, clipped.size),
-                            unclipped.size,
-                            pic_index,
-                            clipped.origin,
-                            uv_rect_kind,
-                            surface_spatial_node_index,
-                            device_pixel_scale,
-                            PrimitiveVisibilityMask::all(),
-                            None,
+                        let render_task_id = frame_state.render_tasks.add().init(
+                            RenderTask::new_picture(
+                                RenderTaskLocation::Dynamic(None, clipped.size),
+                                unclipped.size,
+                                pic_index,
+                                clipped.origin,
+                                uv_rect_kind,
+                                surface_spatial_node_index,
+                                device_pixel_scale,
+                                PrimitiveVisibilityMask::all(),
+                                None,
+                            )
                         );
 
-                        let render_task_id = frame_state.render_tasks.add(picture_task);
-
                         Some((render_task_id, render_task_id))
                     }
                     PictureCompositeMode::TileCache { .. } => {
                         let tile_cache = self.tile_cache.as_mut().unwrap();
                         let mut first = true;
 
                         // Get the overall world space rect of the picture cache. Used to clip
                         // the tile rects below for occlusion testing to the relevant area.
@@ -4133,33 +4135,33 @@ impl PicturePrimitive {
                                 // CPUs). Round the rect here before casting to integer device pixels
                                 // to ensure the scissor rect is correct.
                                 let scissor_rect = (scissor_rect * device_pixel_scale).round();
                                 let surface = descriptor.resolve(
                                     frame_state.resource_cache,
                                     tile_cache.current_tile_size,
                                 );
 
-                                let task = RenderTask::new_picture(
-                                    RenderTaskLocation::PictureCache {
-                                        size: tile_cache.current_tile_size,
-                                        surface,
-                                    },
-                                    tile_cache.current_tile_size.to_f32(),
-                                    pic_index,
-                                    content_origin.to_i32(),
-                                    UvRectKind::Rect,
-                                    surface_spatial_node_index,
-                                    device_pixel_scale,
-                                    *visibility_mask,
-                                    Some(scissor_rect.to_i32()),
+                                let render_task_id = frame_state.render_tasks.add().init(
+                                    RenderTask::new_picture(
+                                        RenderTaskLocation::PictureCache {
+                                            size: tile_cache.current_tile_size,
+                                            surface,
+                                        },
+                                        tile_cache.current_tile_size.to_f32(),
+                                        pic_index,
+                                        content_origin.to_i32(),
+                                        UvRectKind::Rect,
+                                        surface_spatial_node_index,
+                                        device_pixel_scale,
+                                        *visibility_mask,
+                                        Some(scissor_rect.to_i32()),
+                                    )
                                 );
 
-                                let render_task_id = frame_state.render_tasks.add(task);
-
                                 frame_state.render_tasks.add_dependency(
                                     frame_state.surfaces[parent_surface_index.0].render_tasks.unwrap().port,
                                     render_task_id,
                                 );
 
                                 if first {
                                     // TODO(gw): Maybe we can restructure this code to avoid the
                                     //           first hack here. Or at least explain it with a follow up
@@ -4197,55 +4199,55 @@ impl PicturePrimitive {
                         let uv_rect_kind = calculate_uv_rect_kind(
                             &pic_rect,
                             &transform,
                             &clipped,
                             device_pixel_scale,
                             supports_snapping,
                         );
 
-                        let picture_task = RenderTask::new_picture(
-                            RenderTaskLocation::Dynamic(None, clipped.size),
-                            unclipped.size,
-                            pic_index,
-                            clipped.origin,
-                            uv_rect_kind,
-                            surface_spatial_node_index,
-                            device_pixel_scale,
-                            PrimitiveVisibilityMask::all(),
-                            None,
+                        let render_task_id = frame_state.render_tasks.add().init(
+                            RenderTask::new_picture(
+                                RenderTaskLocation::Dynamic(None, clipped.size),
+                                unclipped.size,
+                                pic_index,
+                                clipped.origin,
+                                uv_rect_kind,
+                                surface_spatial_node_index,
+                                device_pixel_scale,
+                                PrimitiveVisibilityMask::all(),
+                                None,
+                            )
                         );
 
-                        let render_task_id = frame_state.render_tasks.add(picture_task);
-
                         Some((render_task_id, render_task_id))
                     }
                     PictureCompositeMode::SvgFilter(ref primitives, ref filter_datas) => {
                         let uv_rect_kind = calculate_uv_rect_kind(
                             &pic_rect,
                             &transform,
                             &clipped,
                             device_pixel_scale,
                             true,
                         );
 
-                        let picture_task = RenderTask::new_picture(
-                            RenderTaskLocation::Dynamic(None, clipped.size),
-                            unclipped.size,
-                            pic_index,
-                            clipped.origin,
-                            uv_rect_kind,
-                            surface_spatial_node_index,
-                            device_pixel_scale,
-                            PrimitiveVisibilityMask::all(),
-                            None,
+                        let picture_task_id = frame_state.render_tasks.add().init(
+                            RenderTask::new_picture(
+                                RenderTaskLocation::Dynamic(None, clipped.size),
+                                unclipped.size,
+                                pic_index,
+                                clipped.origin,
+                                uv_rect_kind,
+                                surface_spatial_node_index,
+                                device_pixel_scale,
+                                PrimitiveVisibilityMask::all(),
+                                None,
+                            )
                         );
 
-                        let picture_task_id = frame_state.render_tasks.add(picture_task);
-
                         let filter_task_id = RenderTask::new_svg_filter(
                             primitives,
                             filter_datas,
                             &mut frame_state.render_tasks,
                             clipped.size,
                             uv_rect_kind,
                             picture_task_id,
                             device_pixel_scale,
--- a/gfx/wr/webrender/src/prim_store/image.rs
+++ b/gfx/wr/webrender/src/prim_store/image.rs
@@ -232,45 +232,34 @@ impl ImageData {
                                 frame_state.gpu_cache,
                                 frame_state.render_tasks,
                                 None,
                                 image_properties.descriptor.is_opaque(),
                                 |render_tasks| {
                                     // Create a task to blit from the texture cache to
                                     // a normal transient render task surface. This will
                                     // copy only the sub-rect, if specified.
-                                    let cache_to_target_task = if false {
-                                        // TODO: figure out if/when this can be used
-                                        RenderTask::new_blit_with_padding(
-                                            *size,
-                                            padding,
-                                            BlitSource::Image { key: image_cache_key },
-                                        )
-                                    } else {
-                                        RenderTask::new_scaling_with_padding(
-                                            BlitSource::Image { key: image_cache_key },
-                                            render_tasks,
-                                            target_kind,
-                                            *size,
-                                            padding,
-                                        )
-                                    };
-                                    let cache_to_target_task_id = render_tasks.add(cache_to_target_task);
+                                    // TODO: figure out if/when we can do a blit instead.
+                                    let cache_to_target_task_id = RenderTask::new_scaling_with_padding(
+                                        BlitSource::Image { key: image_cache_key },
+                                        render_tasks,
+                                        target_kind,
+                                        *size,
+                                        padding,
+                                    );
 
                                     // Create a task to blit the rect from the child render
                                     // task above back into the right spot in the persistent
                                     // render target cache.
-                                    let target_to_cache_task = RenderTask::new_blit(
+                                    render_tasks.add().init(RenderTask::new_blit(
                                         *size,
                                         BlitSource::RenderTask {
                                             task_id: cache_to_target_task_id,
                                         },
-                                    );
-
-                                    render_tasks.add(target_to_cache_task)
+                                    ))
                                 }
                             ));
                         }
                         ImageSource::Default => {}
                     }
 
                     if is_opaque {
                         PrimitiveOpacity::from_alpha(self.color.a)
--- a/gfx/wr/webrender/src/prim_store/mod.rs
+++ b/gfx/wr/webrender/src/prim_store/mod.rs
@@ -1058,30 +1058,28 @@ impl BrushSegment {
                     device_pixel_scale,
                 ) {
                     Some(info) => info,
                     None => {
                         return ClipMaskKind::Clipped;
                     }
                 };
 
-                let clip_task = RenderTask::new_mask(
+                let clip_task_id = RenderTask::new_mask(
                     device_rect.to_i32(),
                     clip_chain.clips_range,
                     root_spatial_node_index,
                     frame_state.clip_store,
                     frame_state.gpu_cache,
                     frame_state.resource_cache,
                     frame_state.render_tasks,
                     clip_data_store,
                     device_pixel_scale,
                     frame_context.fb_config,
                 );
-
-                let clip_task_id = frame_state.render_tasks.add(clip_task);
                 let port = frame_state
                     .surfaces[surface_index.0]
                     .render_tasks
                     .unwrap_or_else(|| panic!("bug: no task for surface {:?}", surface_index))
                     .port;
                 frame_state.render_tasks.add_dependency(port, clip_task_id);
                 ClipMaskKind::Mask(clip_task_id)
             }
@@ -2898,24 +2896,23 @@ impl PrimitiveStore {
                             size: task_size,
                             kind: RenderTaskCacheKeyKind::LineDecoration(cache_key.clone()),
                         },
                         frame_state.gpu_cache,
                         frame_state.render_tasks,
                         None,
                         false,
                         |render_tasks| {
-                            let task = RenderTask::new_line_decoration(
+                            render_tasks.add().init(RenderTask::new_line_decoration(
                                 task_size,
                                 cache_key.style,
                                 cache_key.orientation,
                                 cache_key.wavy_line_thickness.to_f32_px(),
                                 LayoutSize::from_au(cache_key.size),
-                            );
-                            render_tasks.add(task)
+                            ))
                         }
                     ));
                 }
             }
             PrimitiveInstanceKind::TextRun { run_index, data_handle, .. } => {
                 let prim_data = &mut data_stores.text_run[*data_handle];
                 let run = &mut self.text_runs[*run_index];
 
@@ -3020,27 +3017,25 @@ impl PrimitiveStore {
 
                     handles.push(frame_state.resource_cache.request_render_task(
                         cache_key,
                         frame_state.gpu_cache,
                         frame_state.render_tasks,
                         None,
                         false,          // TODO(gw): We don't calculate opacity for borders yet!
                         |render_tasks| {
-                            let task = RenderTask::new_border_segment(
+                            render_tasks.add().init(RenderTask::new_border_segment(
                                 cache_size,
                                 build_border_instances(
                                     &segment.cache_key,
                                     cache_size,
                                     &border_data.border,
                                     scale,
                                 ),
-                            );
-
-                            render_tasks.add(task)
+                            ))
                         }
                     ));
                 }
 
                 *cache_handles = scratch
                     .border_cache_handles
                     .extend(handles);
             }
@@ -3202,25 +3197,23 @@ impl PrimitiveStore {
                             size,
                             kind: RenderTaskCacheKeyKind::Gradient(cache_key),
                         },
                         frame_state.gpu_cache,
                         frame_state.render_tasks,
                         None,
                         prim_data.stops_opacity.is_opaque,
                         |render_tasks| {
-                            let task = RenderTask::new_gradient(
+                            render_tasks.add().init(RenderTask::new_gradient(
                                 size,
                                 stops,
                                 orientation,
                                 start_point,
                                 end_point,
-                            );
-
-                            render_tasks.add(task)
+                            ))
                         }
                     ));
                 }
 
                 if prim_data.tile_spacing != LayoutSize::zero() {
                     // We are performing the decomposition on the CPU here, no need to
                     // have it in the shader.
                     prim_data.common.may_need_repetition = false;
@@ -4019,30 +4012,28 @@ impl PrimitiveInstance {
             // need to allocate for the clip mask, as well as interpolated
             // snap offsets.
             if let Some(device_rect) = get_clipped_device_rect(
                 &unclipped,
                 &pic_state.map_raster_to_world,
                 prim_info.clipped_world_rect,
                 device_pixel_scale,
             ) {
-                let clip_task = RenderTask::new_mask(
+                let clip_task_id = RenderTask::new_mask(
                     device_rect,
                     prim_info.clip_chain.clips_range,
                     root_spatial_node_index,
                     frame_state.clip_store,
                     frame_state.gpu_cache,
                     frame_state.resource_cache,
                     frame_state.render_tasks,
                     &mut data_stores.clip,
                     device_pixel_scale,
                     frame_context.fb_config,
                 );
-
-                let clip_task_id = frame_state.render_tasks.add(clip_task);
                 if self.is_chased() {
                     println!("\tcreated task {:?} with device rect {:?}",
                         clip_task_id, device_rect);
                 }
                 // Set the global clip mask instance for this primitive.
                 let clip_task_index = ClipTaskIndex(scratch.clip_mask_instances.len() as _);
                 scratch.clip_mask_instances.push(ClipMaskKind::Mask(clip_task_id));
                 prim_info.clip_task_index = clip_task_index;
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -521,17 +521,17 @@ impl RenderTask {
         root_spatial_node_index: SpatialNodeIndex,
         clip_store: &mut ClipStore,
         gpu_cache: &mut GpuCache,
         resource_cache: &mut ResourceCache,
         render_tasks: &mut RenderTaskGraph,
         clip_data_store: &mut ClipDataStore,
         device_pixel_scale: DevicePixelScale,
         fb_config: &FrameBuilderConfig,
-    ) -> Self {
+    ) -> RenderTaskId {
         // Step through the clip sources that make up this mask. If we find
         // any box-shadow clip sources, request that image from the render
         // task cache. This allows the blurred box-shadow rect to be cached
         // in the texture cache across frames.
         // TODO(gw): Consider moving this logic outside this function, especially
         //           as we add more clip sources that depend on render tasks.
         // TODO(gw): If this ever shows up in a profile, we could pre-calculate
         //           whether a ClipSources contains any box-shadows and skip
@@ -558,25 +558,23 @@ impl RenderTask {
                             kind: RenderTaskCacheKeyKind::BoxShadow(cache_key),
                         },
                         gpu_cache,
                         render_tasks,
                         None,
                         false,
                         |render_tasks| {
                             // Draw the rounded rect.
-                            let mask_task = RenderTask::new_rounded_rect_mask(
+                            let mask_task_id = render_tasks.add().init(RenderTask::new_rounded_rect_mask(
                                 cache_size,
                                 clip_data_address,
                                 source.minimal_shadow_rect.origin,
                                 device_pixel_scale,
                                 fb_config,
-                            );
-
-                            let mask_task_id = render_tasks.add(mask_task);
+                            ));
 
                             // Blur it
                             RenderTask::new_blur(
                                 DeviceSize::new(blur_radius_dp, blur_radius_dp),
                                 mask_task_id,
                                 render_tasks,
                                 RenderTargetKind::Alpha,
                                 ClearMode::Zero,
@@ -605,26 +603,28 @@ impl RenderTask {
         // the first (primary) clip mask will overwrite all the clip mask pixels with
         // blending disabled to set to the initial value.
         let clear_mode = if needs_clear {
             ClearMode::One
         } else {
             ClearMode::DontCare
         };
 
-        RenderTask::with_dynamic_location(
-            outer_rect.size,
-            smallvec![],
-            RenderTaskKind::CacheMask(CacheMaskTask {
-                actual_rect: outer_rect,
-                clip_node_range,
-                root_spatial_node_index,
-                device_pixel_scale,
-            }),
-            clear_mode,
+        render_tasks.add().init(
+            RenderTask::with_dynamic_location(
+                outer_rect.size,
+                smallvec![],
+                RenderTaskKind::CacheMask(CacheMaskTask {
+                    actual_rect: outer_rect,
+                    clip_node_range,
+                    root_spatial_node_index,
+                    device_pixel_scale,
+                }),
+                clear_mode,
+            )
         )
     }
 
     pub fn new_rounded_rect_mask(
         size: DeviceIntSize,
         clip_data_address: GpuCacheAddress,
         local_pos: LayoutPoint,
         device_pixel_scale: DevicePixelScale,
@@ -715,23 +715,22 @@ impl RenderTask {
             adjusted_blur_target_size = (blur_target_size.to_f32() / scale_factor).to_i32();
 
             let cached_task = match blur_cache {
                 Some(ref mut cache) => cache.get(&BlurTaskKey::DownScale(n_downscales)).cloned(),
                 None => None,
             };
 
             downscaling_src_task_id = cached_task.unwrap_or_else(|| {
-                let downscaling_task = RenderTask::new_scaling(
+                RenderTask::new_scaling(
                     downscaling_src_task_id,
                     render_tasks,
                     target_kind,
                     adjusted_blur_target_size,
-                );
-                render_tasks.add(downscaling_task)
+                )
             });
 
             if let Some(ref mut cache) = blur_cache {
                 cache.insert(BlurTaskKey::DownScale(n_downscales), downscaling_src_task_id);
             }
 
             n_downscales += 1;
         }
@@ -742,45 +741,41 @@ impl RenderTask {
         let cached_task = match blur_cache {
             Some(ref mut cache) => cache.get(&blur_key).cloned(),
             None => None,
         };
 
         let blur_region = blur_region / (scale_factor as i32);
 
         let blur_task_id = cached_task.unwrap_or_else(|| {
-            let blur_task_v = RenderTask::with_dynamic_location(
+            let blur_task_v = render_tasks.add().init(RenderTask::with_dynamic_location(
                 adjusted_blur_target_size,
                 smallvec![downscaling_src_task_id],
                 RenderTaskKind::VerticalBlur(BlurTask {
                     blur_std_deviation: adjusted_blur_std_deviation.height,
                     target_kind,
                     uv_rect_handle: GpuCacheHandle::new(),
                     blur_region,
                     uv_rect_kind,
                 }),
                 clear_mode,
-            );
-
-            let blur_task_v_id = render_tasks.add(blur_task_v);
+            ));
 
-            let blur_task_h = RenderTask::with_dynamic_location(
+            render_tasks.add().init(RenderTask::with_dynamic_location(
                 adjusted_blur_target_size,
-                smallvec![blur_task_v_id],
+                smallvec![blur_task_v],
                 RenderTaskKind::HorizontalBlur(BlurTask {
                     blur_std_deviation: adjusted_blur_std_deviation.width,
                     target_kind,
                     uv_rect_handle: GpuCacheHandle::new(),
                     blur_region,
                     uv_rect_kind,
                 }),
                 clear_mode,
-            );
-
-            render_tasks.add(blur_task_h)
+            ))
         });
 
         if let Some(ref mut cache) = blur_cache {
             cache.insert(blur_key, blur_task_id);
         }
 
         blur_task_id
     }
@@ -799,48 +794,50 @@ impl RenderTask {
         )
     }
 
     pub fn new_scaling(
         src_task_id: RenderTaskId,
         render_tasks: &mut RenderTaskGraph,
         target_kind: RenderTargetKind,
         size: DeviceIntSize,
-    ) -> Self {
+    ) -> RenderTaskId {
         Self::new_scaling_with_padding(
             BlitSource::RenderTask { task_id: src_task_id },
             render_tasks,
             target_kind,
             size,
             DeviceIntSideOffsets::zero(),
         )
     }
 
     pub fn new_scaling_with_padding(
         source: BlitSource,
         render_tasks: &mut RenderTaskGraph,
         target_kind: RenderTargetKind,
         padded_size: DeviceIntSize,
         padding: DeviceIntSideOffsets,
-    ) -> Self {
+    ) -> RenderTaskId {
         let (uv_rect_kind, children, image) = match source {
             BlitSource::RenderTask { task_id } => (render_tasks[task_id].uv_rect_kind(), smallvec![task_id], None),
             BlitSource::Image { key } => (UvRectKind::Rect, smallvec![], Some(key)),
         };
 
-        RenderTask::with_dynamic_location(
-            padded_size,
-            children,
-            RenderTaskKind::Scaling(ScalingTask {
-                target_kind,
-                image,
-                uv_rect_kind,
-                padding,
-            }),
-            ClearMode::DontCare,
+        render_tasks.add().init(
+            RenderTask::with_dynamic_location(
+                padded_size,
+                children,
+                RenderTaskKind::Scaling(ScalingTask {
+                    target_kind,
+                    image,
+                    uv_rect_kind,
+                    padding,
+                }),
+                ClearMode::DontCare,
+            )
         )
     }
 
     pub fn new_svg_filter(
         filter_primitives: &[FilterPrimitive],
         filter_datas: &[SFilterData],
         render_tasks: &mut RenderTaskGraph,
         content_size: DeviceIntSize,
@@ -866,32 +863,30 @@ impl RenderTask {
             // TODO(cbrewster): Not sure we can assume that the original input is sRGB.
             let (mut task_id, input_color_space) = match input.to_index(cur_index) {
                 Some(index) => (outputs[index], filter_primitives[index].color_space),
                 None => (original, ColorSpace::Srgb),
             };
 
             match (input_color_space, color_space) {
                 (ColorSpace::Srgb, ColorSpace::LinearRgb) => {
-                    let task = RenderTask::new_svg_filter_primitive(
+                    task_id = render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                         smallvec![task_id],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::SrgbToLinear,
-                    );
-                    task_id = render_tasks.add(task);
+                    ));
                 },
                 (ColorSpace::LinearRgb, ColorSpace::Srgb) => {
-                    let task = RenderTask::new_svg_filter_primitive(
+                    task_id = render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                         smallvec![task_id],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::LinearToSrgb,
-                    );
-                    task_id = render_tasks.add(task);
+                    ));
                 },
                 _ => {},
             }
 
             task_id
         };
 
         let mut outputs = vec![];
@@ -925,56 +920,53 @@ impl RenderTask {
                         filter_primitives,
                         render_tasks,
                         cur_index,
                         &outputs,
                         original_task_id,
                         primitive.color_space
                     );
 
-                    let task = RenderTask::new_svg_filter_primitive(
+                    render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                         smallvec![input_1_task_id, input_2_task_id],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::Blend(blend.mode),
-                    );
-                    render_tasks.add(task)
+                    ))
                 },
                 FilterPrimitiveKind::Flood(ref flood) => {
-                    let task = RenderTask::new_svg_filter_primitive(
+                    render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                         smallvec![],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::Flood(flood.color),
-                    );
-                    render_tasks.add(task)
+                    ))
                 }
                 FilterPrimitiveKind::Blur(ref blur) => {
                     let blur_std_deviation = blur.radius * device_pixel_scale.0;
                     let input_task_id = get_task_input(
                         &blur.input,
                         filter_primitives,
                         render_tasks,
                         cur_index,
                         &outputs,
                         original_task_id,
                         primitive.color_space
                     );
 
-                    // TODO: This is a hack to ensure that a blur task's input is always in the blur's previous pass.
-                    let svg_task = RenderTask::new_svg_filter_primitive(
-                        smallvec![input_task_id],
-                        content_size,
-                        uv_rect_kind,
-                        SvgFilterInfo::Identity,
-                    );
-
                     RenderTask::new_blur(
                         DeviceSize::new(blur_std_deviation, blur_std_deviation),
-                        render_tasks.add(svg_task),
+                        // TODO: This is a hack to ensure that a blur task's input is always
+                        // in the blur's previous pass.
+                        render_tasks.add().init(RenderTask::new_svg_filter_primitive(
+                            smallvec![input_task_id],
+                            content_size,
+                            uv_rect_kind,
+                            SvgFilterInfo::Identity,
+                        )),
                         render_tasks,
                         RenderTargetKind::Color,
                         ClearMode::Transparent,
                         None,
                         content_size,
                     )
                 }
                 FilterPrimitiveKind::Opacity(ref opacity) => {
@@ -983,82 +975,80 @@ impl RenderTask {
                         filter_primitives,
                         render_tasks,
                         cur_index,
                         &outputs,
                         original_task_id,
                         primitive.color_space
                     );
 
-                    let task = RenderTask::new_svg_filter_primitive(
+                    render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                         smallvec![input_task_id],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::Opacity(opacity.opacity),
-                    );
-                    render_tasks.add(task)
+                    ))
                 }
                 FilterPrimitiveKind::ColorMatrix(ref color_matrix) => {
                     let input_task_id = get_task_input(
                         &color_matrix.input,
                         filter_primitives,
                         render_tasks,
                         cur_index,
                         &outputs,
                         original_task_id,
                         primitive.color_space
                     );
 
-                    let task = RenderTask::new_svg_filter_primitive(
+                    render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                         smallvec![input_task_id],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::ColorMatrix(Box::new(color_matrix.matrix)),
-                    );
-                    render_tasks.add(task)
+                    ))
                 }
                 FilterPrimitiveKind::DropShadow(ref drop_shadow) => {
                     let input_task_id = get_task_input(
                         &drop_shadow.input,
                         filter_primitives,
                         render_tasks,
                         cur_index,
                         &outputs,
                         original_task_id,
                         primitive.color_space
                     );
 
                     let blur_std_deviation = drop_shadow.shadow.blur_radius * device_pixel_scale.0;
                     let offset = drop_shadow.shadow.offset * LayoutToWorldScale::new(1.0) * device_pixel_scale;
 
-                    let offset_task = RenderTask::new_svg_filter_primitive(
-                        smallvec![input_task_id],
-                        content_size,
-                        uv_rect_kind,
-                        SvgFilterInfo::Offset(offset),
+                    let offset_task_id = render_tasks.add().init(
+                        RenderTask::new_svg_filter_primitive(
+                            smallvec![input_task_id],
+                            content_size,
+                            uv_rect_kind,
+                            SvgFilterInfo::Offset(offset),
+                        )
                     );
-                    let offset_task_id = render_tasks.add(offset_task);
 
                     let blur_task_id = RenderTask::new_blur(
                         DeviceSize::new(blur_std_deviation, blur_std_deviation),
                         offset_task_id,
                         render_tasks,
                         RenderTargetKind::Color,
                         ClearMode::Transparent,
                         None,
                         content_size,
                     );
 
-                    let task = RenderTask::new_svg_filter_primitive(
+                    render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                         smallvec![input_task_id, blur_task_id],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::DropShadow(drop_shadow.shadow.color),
-                    );
-                    render_tasks.add(task)
+                    ))
                 }
                 FilterPrimitiveKind::ComponentTransfer(ref component_transfer) => {
                     let input_task_id = get_task_input(
                         &component_transfer.input,
                         filter_primitives,
                         render_tasks,
                         cur_index,
                         &outputs,
@@ -1066,44 +1056,42 @@ impl RenderTask {
                         primitive.color_space
                     );
 
                     let filter_data = &filter_datas[cur_filter_data];
                     cur_filter_data += 1;
                     if filter_data.is_identity() {
                         input_task_id
                     } else {
-                        let task = RenderTask::new_svg_filter_primitive(
+                        render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                             smallvec![input_task_id],
                             content_size,
                             uv_rect_kind,
                             SvgFilterInfo::ComponentTransfer(filter_data.clone()),
-                        );
-                        render_tasks.add(task)
+                        ))
                     }
                 }
                 FilterPrimitiveKind::Offset(ref info) => {
                     let input_task_id = get_task_input(
                         &info.input,
                         filter_primitives,
                         render_tasks,
                         cur_index,
                         &outputs,
                         original_task_id,
                         primitive.color_space
                     );
 
                     let offset = info.offset * LayoutToWorldScale::new(1.0) * device_pixel_scale;
-                    let offset_task = RenderTask::new_svg_filter_primitive(
+                    render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                         smallvec![input_task_id],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::Offset(offset),
-                    );
-                    render_tasks.add(offset_task)
+                    ))
                 }
                 FilterPrimitiveKind::Composite(info) => {
                     let input_1_task_id = get_task_input(
                         &info.input1,
                         filter_primitives,
                         render_tasks,
                         cur_index,
                         &outputs,
@@ -1115,40 +1103,38 @@ impl RenderTask {
                         filter_primitives,
                         render_tasks,
                         cur_index,
                         &outputs,
                         original_task_id,
                         primitive.color_space
                     );
 
-                    let task = RenderTask::new_svg_filter_primitive(
+                    render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                         smallvec![input_1_task_id, input_2_task_id],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::Composite(info.operator),
-                    );
-                    render_tasks.add(task)
+                    ))
                 }
             };
             outputs.push(render_task_id);
         }
 
         // The output of a filter is the output of the last primitive in the chain.
         let mut render_task_id = *outputs.last().unwrap();
 
         // Convert to sRGB if needed
         if filter_primitives.last().unwrap().color_space == ColorSpace::LinearRgb {
-            let task = RenderTask::new_svg_filter_primitive(
+            render_task_id = render_tasks.add().init(RenderTask::new_svg_filter_primitive(
                 smallvec![render_task_id],
                 content_size,
                 uv_rect_kind,
                 SvgFilterInfo::LinearToSrgb,
-            );
-            render_task_id = render_tasks.add(task);
+            ));
         }
 
         render_task_id
     }
 
     pub fn new_svg_filter_primitive(
         tasks: TaskDependencies,
         target_size: DeviceIntSize,
@@ -1553,16 +1539,17 @@ impl RenderTask {
             }
         }
 
         pt.end_level();
         true
     }
 
     /// Mark this render task for keeping the results alive up until the end of the frame.
+    #[inline]
     pub fn mark_for_saving(&mut self) {
         match self.location {
             RenderTaskLocation::Fixed(..) |
             RenderTaskLocation::Dynamic(..) => {
                 self.saved_index = Some(SavedTargetIndex::PENDING);
             }
             RenderTaskLocation::TextureCache { .. } |
             RenderTaskLocation::PictureCache { .. } => {
--- a/gfx/wr/webrender/src/render_task_graph.rs
+++ b/gfx/wr/webrender/src/render_task_graph.rs
@@ -6,32 +6,55 @@
 use api::ImageFormat;
 use api::units::*;
 use crate::internal_types::{CacheTextureId, FastHashMap, SavedTargetIndex};
 use crate::render_backend::FrameId;
 use crate::render_target::{RenderTarget, RenderTargetKind, RenderTargetList, ColorRenderTarget};
 use crate::render_target::{PictureCacheTarget, TextureCacheRenderTarget, AlphaRenderTarget};
 use crate::render_task::{BlitSource, RenderTask, RenderTaskKind, RenderTaskAddress, RenderTaskData};
 use crate::render_task::{RenderTaskLocation};
+use crate::util::{VecHelper, Allocation};
 use std::{cmp, usize, f32, i32, u32};
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTaskGraph {
     pub tasks: Vec<RenderTask>,
     pub task_data: Vec<RenderTaskData>,
     /// Tasks that don't have dependencies, and that may be shared between
     /// 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,
 }
 
+/// Allows initializing a render task directly into the render task buffer.
+///
+/// See utils::VecHelpers. RenderTask is fairly large so avoiding the move when
+/// pushing into the vector can save a lot of exensive memcpys on pages with many
+/// render tasks.
+pub struct RenderTaskAllocation<'a> {
+    alloc: Allocation<'a, RenderTask>,
+    #[cfg(debug_assertions)]
+    frame_id: FrameId,
+}
+
+impl<'l> RenderTaskAllocation<'l> {
+    #[inline(always)]
+    pub fn init(self, value: RenderTask) -> RenderTaskId {
+        RenderTaskId {
+            index: self.alloc.init(value) as u32,
+            #[cfg(debug_assertions)]
+            frame_id: self.frame_id,
+        }
+    }
+}
+
 impl RenderTaskGraph {
     pub fn new(frame_id: FrameId, counters: &RenderTaskGraphCounters) -> Self {
         // Preallocate a little more than what we needed in the previous frame so that small variations
         // in the number of items don't cause us to constantly reallocate.
         let extra_items = 8;
         RenderTaskGraph {
             tasks: Vec::with_capacity(counters.tasks_len + extra_items),
             task_data: Vec::with_capacity(counters.task_data_len + extra_items),
@@ -44,21 +67,19 @@ impl RenderTaskGraph {
     pub fn counters(&self) -> RenderTaskGraphCounters {
         RenderTaskGraphCounters {
             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,
+    pub fn add(&mut self) -> RenderTaskAllocation {
+        RenderTaskAllocation {
+            alloc: self.tasks.alloc(),
             #[cfg(debug_assertions)]
             frame_id: self.frame_id,
         }
     }
 
     /// Express a render task dependency between a parent and child task.
     /// This is used to assign tasks to render passes.
     pub fn add_dependency(
@@ -169,23 +190,23 @@ impl RenderTaskGraph {
                 &mut max_depth,
             );
         }
 
         let offset = passes.len();
 
         passes.reserve(max_depth as usize + 1);
         for _ in 0..max_depth {
-            passes.push(RenderPass::new_off_screen(screen_size, gpu_supports_fast_clears));
+            passes.alloc().init(RenderPass::new_off_screen(screen_size, gpu_supports_fast_clears));
         }
 
         if for_main_framebuffer {
-            passes.push(RenderPass::new_main_framebuffer(screen_size, gpu_supports_fast_clears));
+            passes.alloc().init(RenderPass::new_main_framebuffer(screen_size, gpu_supports_fast_clears));
         } else {
-            passes.push(RenderPass::new_off_screen(screen_size, gpu_supports_fast_clears));
+            passes.alloc().init(RenderPass::new_off_screen(screen_size, gpu_supports_fast_clears));
         }
 
         // Assign tasks to their render passes.
         for task_index in 0..self.tasks.len() {
             if task_max_depths[task_index] < 0 {
                 // The task wasn't visited, it means it doesn't contribute to this frame.
                 continue;
             }
@@ -310,17 +331,17 @@ impl RenderTaskGraph {
                 }
 
                 let blit_id = RenderTaskId {
                     index: self.tasks.len() as u32,
                     #[cfg(debug_assertions)]
                     frame_id: self.frame_id,
                 };
 
-                self.tasks.push(blit);
+                self.tasks.alloc().init(blit);
 
                 passes[child_pass_index as usize + 1].tasks.push(blit_id);
 
                 self.tasks[task_index].children[nth_child] = blit_id;
                 task_redirects[child_task_index] = Some(blit_id);
             }
         }
     }
@@ -710,21 +731,21 @@ fn diamond_task_graph() {
     //    \    /
     //     [b2]
 
     let color = RenderTargetKind::Color;
 
     let counters = RenderTaskGraphCounters::new();
     let mut tasks = RenderTaskGraph::new(FrameId::first(), &counters);
 
-    let a = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
-    let b1 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a]));
-    let b2 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a]));
+    let a = tasks.add().init(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
+    let b1 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a]));
+    let b2 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a]));
 
-    let main_pic = tasks.add(RenderTask::new_test(
+    let main_pic = tasks.add().init(RenderTask::new_test(
         color,
         RenderTaskLocation::Fixed(rect(0, 0, 3200, 1800)),
         smallvec![b1, b2],
     ));
 
     let initial_number_of_tasks = tasks.tasks.len();
 
     let passes = tasks.generate_passes(Some(main_pic), size2(3200, 1800), true);
@@ -747,41 +768,41 @@ fn blur_task_graph() {
     // This test simulates a complicated shadow stack effect with target allocation
     // conflicts to resolve.
 
     let color = RenderTargetKind::Color;
 
     let counters = RenderTaskGraphCounters::new();
     let mut tasks = RenderTaskGraph::new(FrameId::first(), &counters);
 
-    let pic = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
-    let scale1 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![pic]));
-    let scale2 = tasks.add(RenderTask::new_test(color, dyn_location(160, 160), smallvec![scale1]));
-    let scale3 = tasks.add(RenderTask::new_test(color, dyn_location(80, 80), smallvec![scale2]));
-    let scale4 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale3]));
+    let pic = tasks.add().init(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
+    let scale1 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![pic]));
+    let scale2 = tasks.add().init(RenderTask::new_test(color, dyn_location(160, 160), smallvec![scale1]));
+    let scale3 = tasks.add().init(RenderTask::new_test(color, dyn_location(80, 80), smallvec![scale2]));
+    let scale4 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale3]));
 
-    let vblur1 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale4]));
-    let hblur1 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![vblur1]));
+    let vblur1 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale4]));
+    let hblur1 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![vblur1]));
 
-    let vblur2 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale4]));
-    let hblur2 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![vblur2]));
+    let vblur2 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale4]));
+    let hblur2 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![vblur2]));
 
     // Insert a task that is an even number of passes away from its dependency.
     // This means the source and destination are on the same target and we have to resolve
     // this conflict by automatically inserting a blit task.
-    let vblur3 = tasks.add(RenderTask::new_test(color, dyn_location(80, 80), smallvec![scale3]));
-    let hblur3 = tasks.add(RenderTask::new_test(color, dyn_location(80, 80), smallvec![vblur3]));
+    let vblur3 = tasks.add().init(RenderTask::new_test(color, dyn_location(80, 80), smallvec![scale3]));
+    let hblur3 = tasks.add().init(RenderTask::new_test(color, dyn_location(80, 80), smallvec![vblur3]));
 
     // Insert a task that is an odd number > 1 of passes away from its dependency.
     // This should force us to mark the dependency "for saving" to keep its content valid
     // until the task can access it.
-    let vblur4 = tasks.add(RenderTask::new_test(color, dyn_location(160, 160), smallvec![scale2]));
-    let hblur4 = tasks.add(RenderTask::new_test(color, dyn_location(160, 160), smallvec![vblur4]));
+    let vblur4 = tasks.add().init(RenderTask::new_test(color, dyn_location(160, 160), smallvec![scale2]));
+    let hblur4 = tasks.add().init(RenderTask::new_test(color, dyn_location(160, 160), smallvec![vblur4]));
 
-    let main_pic = tasks.add(RenderTask::new_test(
+    let main_pic = tasks.add().init(RenderTask::new_test(
         color,
         RenderTaskLocation::Fixed(rect(0, 0, 3200, 1800)),
         smallvec![hblur1, hblur2, hblur3, hblur4],
     ));
 
     let initial_number_of_tasks = tasks.tasks.len();
 
     let passes = tasks.generate_passes(Some(main_pic), size2(3200, 1800), true);
@@ -832,24 +853,24 @@ fn culled_tasks() {
     // This test checks that tasks that do not contribute to the frame don't appear in the
     // generated passes.
 
     let color = RenderTargetKind::Color;
 
     let counters = RenderTaskGraphCounters::new();
     let mut tasks = RenderTaskGraph::new(FrameId::first(), &counters);
 
-    let a1 = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
-    let _a2 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a1]));
+    let a1 = tasks.add().init(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
+    let _a2 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a1]));
 
-    let b1 = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
-    let b2 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![b1]));
-    let _b3 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![b2]));
+    let b1 = tasks.add().init(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
+    let b2 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![b1]));
+    let _b3 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![b2]));
 
-    let main_pic = tasks.add(RenderTask::new_test(
+    let main_pic = tasks.add().init(RenderTask::new_test(
         color,
         RenderTaskLocation::Fixed(rect(0, 0, 3200, 1800)),
         smallvec![b2],
     ));
 
     let initial_number_of_tasks = tasks.tasks.len();
 
     let passes = tasks.generate_passes(Some(main_pic), size2(3200, 1800), true);