Backed out 3 changesets (bug 1551187) for webrender bustages CLOSED TREE
authorBogdan Tara <btara@mozilla.com>
Wed, 15 May 2019 16:54:37 +0300
changeset 532755 52456bf79f9f9e7b26ecb5d9445d5f29fbd18627
parent 532754 b464eba7f66ca02f0e3f48d692da1c92ac871c9b
child 532756 68e703f2f17b61b73652afed22ebff6afd43e503
push id11272
push userapavel@mozilla.com
push dateThu, 16 May 2019 15:28:22 +0000
treeherdermozilla-beta@2265bfc5920d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1551187
milestone68.0a1
backs out3339438190872637a2fbb4225ff3dc71e61721a9
dc83934fa03259f44e80c9529320b280d15ae042
aa02e32fd5bfe34931068d3906cc68a3993ad60e
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
Backed out 3 changesets (bug 1551187) for webrender bustages CLOSED TREE Backed out changeset 333943819087 (bug 1551187) Backed out changeset dc83934fa032 (bug 1551187) Backed out changeset aa02e32fd5bf (bug 1551187)
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/frame_builder.rs
gfx/wr/webrender/src/glyph_rasterizer/mod.rs
gfx/wr/webrender/src/glyph_rasterizer/no_pathfinder.rs
gfx/wr/webrender/src/glyph_rasterizer/pathfinder.rs
gfx/wr/webrender/src/internal_types.rs
gfx/wr/webrender/src/lib.rs
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/prim_store/mod.rs
gfx/wr/webrender/src/prim_store/picture.rs
gfx/wr/webrender/src/prim_store/text_run.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/render_task.rs
gfx/wr/webrender/src/renderer.rs
gfx/wr/webrender/src/resource_cache.rs
gfx/wr/webrender/src/tiling.rs
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -16,17 +16,17 @@ use crate::gpu_types::{PrimitiveHeader, 
 use crate::internal_types::{FastHashMap, SavedTargetIndex, TextureSource, Filter};
 use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive};
 use crate::prim_store::{DeferredResolve, EdgeAaSegmentMask, PrimitiveInstanceKind, PrimitiveVisibilityIndex};
 use crate::prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex};
 use crate::prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, VECS_PER_SEGMENT};
 use crate::prim_store::{recompute_snap_offsets};
 use crate::prim_store::image::ImageSource;
 use crate::render_backend::DataStores;
-use crate::render_task::{RenderTaskAddress, RenderTaskId, RenderTaskGraph, TileBlit};
+use crate::render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree, TileBlit};
 use crate::renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
 use crate::renderer::{BLOCKS_PER_UV_RECT, MAX_VERTEX_TEXTURE_WIDTH};
 use crate::resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache, ImageProperties};
 use smallvec::SmallVec;
 use std::{f32, i32, usize};
 use crate::tiling::{RenderTargetContext};
 use crate::util::{project_rect, TransformedRectKind};
 
@@ -563,17 +563,17 @@ impl BatchBuilder {
 
     /// Add a picture to a given batch builder.
     pub fn add_pic_to_batch(
         &mut self,
         pic: &PicturePrimitive,
         batcher: &mut AlphaBatchBuilder,
         ctx: &RenderTargetContext,
         gpu_cache: &mut GpuCache,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         deferred_resolves: &mut Vec<DeferredResolve>,
         prim_headers: &mut PrimitiveHeaders,
         transforms: &mut TransformPalette,
         root_spatial_node_index: SpatialNodeIndex,
         z_generator: &mut ZBufferIdGenerator,
     ) {
         // Add each run in this picture to the batch.
         for prim_instance in &pic.prim_list.prim_instances {
@@ -597,17 +597,17 @@ impl BatchBuilder {
     // example if it encounters a picture where the items
     // in that picture are being drawn into the same target.
     fn add_prim_to_batch(
         &mut self,
         prim_instance: &PrimitiveInstance,
         batcher: &mut AlphaBatchBuilder,
         ctx: &RenderTargetContext,
         gpu_cache: &mut GpuCache,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         deferred_resolves: &mut Vec<DeferredResolve>,
         prim_headers: &mut PrimitiveHeaders,
         transforms: &mut TransformPalette,
         root_spatial_node_index: SpatialNodeIndex,
         z_generator: &mut ZBufferIdGenerator,
     ) {
         if prim_instance.visibility_info == PrimitiveVisibilityIndex::INVALID {
             return;
@@ -1322,17 +1322,17 @@ impl BatchBuilder {
                                         // Draw an instance per shadow first, following by the content.
 
                                         // The shadows and the content get drawn as a brush image.
                                         let kind = BatchKind::Brush(
                                             BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
                                         );
 
                                         // Gets the saved render task ID of the content, which is
-                                        // deeper in the render task graph than the direct child.
+                                        // deeper in the render task tree than the direct child.
                                         let secondary_id = picture.secondary_render_task_id.expect("no secondary!?");
                                         let saved_index = render_tasks[secondary_id].saved_index.expect("no saved index!?");
                                         debug_assert_ne!(saved_index, SavedTargetIndex::PENDING);
 
                                         // Build BatchTextures for shadow/content
                                         let shadow_textures = BatchTextures::render_target_cache();
                                         let content_textures = BatchTextures {
                                             colors: [
@@ -1359,17 +1359,16 @@ impl BatchBuilder {
                                         for (shadow, shadow_gpu_data) in shadows.iter().zip(picture.extra_gpu_data_handles.iter()) {
                                             // Get the GPU cache address of the extra data handle.
                                             let shadow_prim_address = gpu_cache.get_address(shadow_gpu_data);
 
                                             let shadow_rect = prim_header.local_rect.translate(&shadow.offset);
 
                                             let shadow_prim_header = PrimitiveHeader {
                                                 local_rect: shadow_rect,
-                                                snap_offsets: prim_info.shadow_snap_offsets,
                                                 specific_prim_address: shadow_prim_address,
                                                 ..prim_header
                                             };
 
                                             let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, z_id, [
                                                 ShaderColorMode::Alpha as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                                                 RasterizationSpace::Screen as i32,
                                                 get_shader_opacity(1.0),
@@ -1414,28 +1413,129 @@ impl BatchBuilder {
 
                                         batcher.current_batch_list().push_single_instance(
                                             content_key,
                                             bounding_rect,
                                             z_id_content,
                                             PrimitiveInstanceData::from(content_instance),
                                         );
                                     }
+                                    Filter::DropShadow(shadow) => {
+                                        // Draw an instance of the shadow first, following by the content.
+
+                                        // Both the shadow and the content get drawn as a brush image.
+                                        let kind = BatchKind::Brush(
+                                            BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
+                                        );
+
+                                        // Gets the saved render task ID of the content, which is
+                                        // deeper in the render task tree than the direct child.
+                                        let secondary_id = picture.secondary_render_task_id.expect("no secondary!?");
+                                        let saved_index = render_tasks[secondary_id].saved_index.expect("no saved index!?");
+                                        debug_assert_ne!(saved_index, SavedTargetIndex::PENDING);
+
+                                        // Build BatchTextures for shadow/content
+                                        let shadow_textures = BatchTextures::render_target_cache();
+                                        let content_textures = BatchTextures {
+                                            colors: [
+                                                TextureSource::RenderTaskCache(saved_index),
+                                                TextureSource::Invalid,
+                                                TextureSource::Invalid,
+                                            ],
+                                        };
+
+                                        // Build batch keys for shadow/content
+                                        let shadow_key = BatchKey::new(kind, non_segmented_blend_mode, shadow_textures);
+                                        let content_key = BatchKey::new(kind, non_segmented_blend_mode, content_textures);
+
+                                        // Retrieve the UV rect addresses for shadow/content.
+                                        let cache_task_id = surface.expect("bug: surface must be allocated by now");
+                                        let shadow_uv_rect_address = render_tasks[cache_task_id]
+                                            .get_texture_address(gpu_cache)
+                                            .as_int();
+                                        let content_uv_rect_address = render_tasks[secondary_id]
+                                            .get_texture_address(gpu_cache)
+                                            .as_int();
+
+                                        // Get the GPU cache address of the extra data handle.
+                                        let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_data_handles[0]);
+
+                                        let z_id_shadow = z_id;
+                                        let z_id_content = z_generator.next();
+
+                                        let content_prim_header_index = prim_headers.push(&prim_header, z_id_content, [
+                                            ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
+                                            RasterizationSpace::Screen as i32,
+                                            get_shader_opacity(1.0),
+                                            0,
+                                        ]);
+
+                                        let shadow_rect = prim_header.local_rect.translate(&shadow.offset);
+
+                                        let shadow_prim_header = PrimitiveHeader {
+                                            local_rect: shadow_rect,
+                                            snap_offsets: prim_info.shadow_snap_offsets,
+                                            specific_prim_address: shadow_prim_address,
+                                            ..prim_header
+                                        };
+
+                                        let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, z_id_shadow, [
+                                            ShaderColorMode::Alpha as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
+                                            RasterizationSpace::Screen as i32,
+                                            get_shader_opacity(1.0),
+                                            0,
+                                        ]);
+
+                                        let shadow_instance = BrushInstance {
+                                            prim_header_index: shadow_prim_header_index,
+                                            clip_task_address,
+                                            render_task_address,
+                                            segment_index: INVALID_SEGMENT_INDEX,
+                                            edge_flags: EdgeAaSegmentMask::empty(),
+                                            brush_flags,
+                                            user_data: shadow_uv_rect_address,
+                                        };
+
+                                        let content_instance = BrushInstance {
+                                            prim_header_index: content_prim_header_index,
+                                            clip_task_address,
+                                            render_task_address,
+                                            segment_index: INVALID_SEGMENT_INDEX,
+                                            edge_flags: EdgeAaSegmentMask::empty(),
+                                            brush_flags,
+                                            user_data: content_uv_rect_address,
+                                        };
+
+                                        batcher.current_batch_list().push_single_instance(
+                                            shadow_key,
+                                            bounding_rect,
+                                            z_id_shadow,
+                                            PrimitiveInstanceData::from(shadow_instance),
+                                        );
+
+                                        batcher.current_batch_list().push_single_instance(
+                                            content_key,
+                                            bounding_rect,
+                                            z_id_content,
+                                            PrimitiveInstanceData::from(content_instance),
+                                        );
+                                    }
                                     _ => {
                                         let filter_mode = match filter {
                                             Filter::Identity => 1, // matches `Contrast(1)`
                                             Filter::Blur(..) => 0,
                                             Filter::Contrast(..) => 1,
                                             Filter::Grayscale(..) => 2,
                                             Filter::HueRotate(..) => 3,
                                             Filter::Invert(..) => 4,
                                             Filter::Saturate(..) => 5,
                                             Filter::Sepia(..) => 6,
                                             Filter::Brightness(..) => 7,
                                             Filter::Opacity(..) => 8,
+                                            Filter::DropShadow(..) |
                                             Filter::DropShadowStack(..) => 9,
                                             Filter::ColorMatrix(..) => 10,
                                             Filter::SrgbToLinear => 11,
                                             Filter::LinearToSrgb => 12,
                                             Filter::ComponentTransfer => unreachable!(),
                                         };
 
                                         let user_data = match filter {
@@ -1450,17 +1550,18 @@ impl BatchBuilder {
                                                 (amount * 65536.0) as i32
                                             }
                                             Filter::SrgbToLinear | Filter::LinearToSrgb => 0,
                                             Filter::HueRotate(angle) => {
                                                 (0.01745329251 * angle * 65536.0) as i32
                                             }
                                             // Go through different paths
                                             Filter::Blur(..) |
-                                            Filter::DropShadowStack(..) => {
+                                            Filter::DropShadowStack(..) |
+                                            Filter::DropShadow(..) => {
                                                 unreachable!();
                                             }
                                             Filter::ColorMatrix(_) => {
                                                 picture.extra_gpu_data_handles[0].as_int(gpu_cache)
                                             }
                                             Filter::ComponentTransfer => unreachable!(),
                                         };
 
@@ -2368,17 +2469,17 @@ impl BatchBuilder {
         segment: &BrushSegment,
         segment_data: &SegmentInstanceData,
         segment_index: i32,
         batch_kind: BrushBatchKind,
         prim_header_index: PrimitiveHeaderIndex,
         alpha_blend_mode: BlendMode,
         bounding_rect: &PictureRect,
         transform_kind: TransformedRectKind,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         z_id: ZBufferId,
         prim_opacity: PrimitiveOpacity,
         render_task_address: RenderTaskAddress,
         clip_task_index: ClipTaskIndex,
         ctx: &RenderTargetContext,
     ) {
         debug_assert!(clip_task_index != ClipTaskIndex::INVALID);
 
@@ -2430,17 +2531,17 @@ impl BatchBuilder {
         brush_segments: Option<&[BrushSegment]>,
         prim_opacity: PrimitiveOpacity,
         params: &BrushBatchParameters,
         alpha_blend_mode: BlendMode,
         non_segmented_blend_mode: BlendMode,
         prim_header_index: PrimitiveHeaderIndex,
         bounding_rect: &PictureRect,
         transform_kind: TransformedRectKind,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         z_id: ZBufferId,
         render_task_address: RenderTaskAddress,
         clip_task_index: ClipTaskIndex,
         ctx: &RenderTargetContext,
     ) {
         match (brush_segments, &params.segment_data) {
             (Some(ref brush_segments), SegmentDataKind::Instanced(ref segment_data)) => {
                 // In this case, we have both a list of segments, and a list of
@@ -2699,17 +2800,17 @@ impl PrimitiveInstance {
             Some(ImageProperties { external_image: Some(_), .. }) => {
                 false
             }
             _ => true
         }
     }
 }
 
-impl RenderTaskGraph {
+impl RenderTaskTree {
     fn resolve_surface(
         &self,
         task_id: RenderTaskId,
         gpu_cache: &GpuCache,
     ) -> (GpuCacheAddress, BatchTextures) {
         (
             self[task_id].get_texture_address(gpu_cache),
             BatchTextures::render_target_cache(),
@@ -3167,17 +3268,17 @@ impl<'a, 'rc> RenderTargetContext<'a, 'r
     /// Retrieve the GPU task address for a given clip task instance.
     /// Returns None if the segment was completely clipped out.
     /// Returns Some(OPAQUE_TASK_ADDRESS) if no clip mask is needed.
     /// Returns Some(task_address) if there was a valid clip mask.
     fn get_clip_task_address(
         &self,
         clip_task_index: ClipTaskIndex,
         offset: i32,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
     ) -> Option<RenderTaskAddress> {
         let address = match self.scratch.clip_mask_instances[clip_task_index.0 as usize + offset as usize] {
             ClipMaskKind::Mask(task_id) => {
                 render_tasks.get_task_address(task_id)
             }
             ClipMaskKind::None => {
                 OPAQUE_TASK_ADDRESS
             }
@@ -3189,17 +3290,17 @@ impl<'a, 'rc> RenderTargetContext<'a, 'r
         Some(address)
     }
 
     /// Helper function to get the clip task address for a
     /// non-segmented primitive.
     fn get_prim_clip_task_address(
         &self,
         clip_task_index: ClipTaskIndex,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
     ) -> Option<RenderTaskAddress> {
         self.get_clip_task_address(
             clip_task_index,
             0,
             render_tasks,
         )
     }
 }
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -16,17 +16,17 @@ use crate::hit_test::HitTestingSceneStat
 use crate::internal_types::{FastHashMap, PlaneSplitter};
 use crate::picture::{PictureUpdateState, SurfaceInfo, ROOT_SURFACE_INDEX, SurfaceIndex};
 use crate::picture::{RetainedTiles, TileCache, DirtyRegion, SurfaceRenderTasks};
 use crate::prim_store::{PrimitiveStore, SpaceMapper, PictureIndex, PrimitiveDebugId, PrimitiveScratchBuffer};
 #[cfg(feature = "replay")]
 use crate::prim_store::{PrimitiveStoreStats};
 use crate::profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
 use crate::render_backend::{DataStores, FrameStamp};
-use crate::render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskGraph, RenderTaskGraphCounters};
+use crate::render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree, RenderTaskTreeCounters};
 use crate::resource_cache::{ResourceCache};
 use crate::scene::{ScenePipeline, SceneProperties};
 use crate::scene_builder::DocumentStats;
 use crate::segment::SegmentBuilder;
 use std::{f32, mem};
 use std::sync::Arc;
 use crate::tiling::{Frame, RenderPassKind, RenderTargetContext, RenderTarget};
 use crate::util::MaxRect;
@@ -128,32 +128,32 @@ pub struct FrameVisibilityState<'a> {
     pub clip_store: &'a mut ClipStore,
     pub resource_cache: &'a mut ResourceCache,
     pub gpu_cache: &'a mut GpuCache,
     pub scratch: &'a mut PrimitiveScratchBuffer,
     pub tile_cache: Option<TileCache>,
     pub retained_tiles: &'a mut RetainedTiles,
     pub data_stores: &'a mut DataStores,
     pub clip_chain_stack: ClipChainStack,
-    pub render_tasks: &'a mut RenderTaskGraph,
+    pub render_tasks: &'a mut RenderTaskTree,
 }
 
 pub struct FrameBuildingContext<'a> {
     pub global_device_pixel_scale: DevicePixelScale,
     pub scene_properties: &'a SceneProperties,
     pub pipelines: &'a FastHashMap<PipelineId, Arc<ScenePipeline>>,
     pub screen_world_rect: WorldRect,
     pub clip_scroll_tree: &'a ClipScrollTree,
     pub max_local_clip: LayoutRect,
     pub debug_flags: DebugFlags,
     pub fb_config: &'a FrameBuilderConfig,
 }
 
 pub struct FrameBuildingState<'a> {
-    pub render_tasks: &'a mut RenderTaskGraph,
+    pub render_tasks: &'a mut RenderTaskTree,
     pub profile_counters: &'a mut FrameProfileCounters,
     pub clip_store: &'a mut ClipStore,
     pub resource_cache: &'a mut ResourceCache,
     pub gpu_cache: &'a mut GpuCache,
     pub transforms: &'a mut TransformPalette,
     pub segment_builder: SegmentBuilder,
     pub surfaces: &'a mut Vec<SurfaceInfo>,
     pub dirty_region_stack: Vec<DirtyRegion>,
@@ -298,17 +298,17 @@ impl FrameBuilder {
     /// primitives in screen space.
     fn build_layer_screen_rects_and_cull_layers(
         &mut self,
         screen_world_rect: WorldRect,
         clip_scroll_tree: &ClipScrollTree,
         pipelines: &FastHashMap<PipelineId, Arc<ScenePipeline>>,
         resource_cache: &mut ResourceCache,
         gpu_cache: &mut GpuCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         profile_counters: &mut FrameProfileCounters,
         global_device_pixel_scale: DevicePixelScale,
         scene_properties: &SceneProperties,
         transform_palette: &mut TransformPalette,
         data_stores: &mut DataStores,
         surfaces: &mut Vec<SurfaceInfo>,
         scratch: &mut PrimitiveScratchBuffer,
         debug_flags: DebugFlags,
@@ -511,17 +511,17 @@ impl FrameBuilder {
         layer: DocumentLayer,
         device_origin: DeviceIntPoint,
         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 RenderTaskGraphCounters,
+        render_task_counters: &mut RenderTaskTreeCounters,
         debug_flags: DebugFlags,
     ) -> Frame {
         profile_scope!("build");
         profile_marker!("BuildFrame");
 
         let mut profile_counters = FrameProfileCounters::new();
         profile_counters
             .total_primitives
@@ -534,17 +534,17 @@ impl FrameBuilder {
 
         clip_scroll_tree.update_tree(
             pan,
             scene_properties,
         );
         let mut transform_palette = clip_scroll_tree.build_transform_palette();
         self.clip_store.clear_old_instances();
 
-        let mut render_tasks = RenderTaskGraph::new(
+        let mut render_tasks = RenderTaskTree::new(
             stamp.frame_id(),
             render_task_counters,
         );
         let mut surfaces = Vec::new();
 
         let output_size = self.output_rect.size.to_i32();
         let screen_world_rect = (self.output_rect.to_f32() / global_device_pixel_scale).round_out();
 
--- a/gfx/wr/webrender/src/glyph_rasterizer/mod.rs
+++ b/gfx/wr/webrender/src/glyph_rasterizer/mod.rs
@@ -840,17 +840,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 crate::texture_cache::TextureCache;
         use crate::glyph_cache::GlyphCache;
         use crate::gpu_cache::GpuCache;
-        use crate::render_task::{RenderTaskCache, RenderTaskGraph, RenderTaskGraphCounters};
+        use crate::render_task::{RenderTaskCache, RenderTaskTree, RenderTaskTreeCounters};
         use crate::profiler::TextureCacheProfileCounters;
         use api::{FontKey, FontInstanceKey, FontTemplate, FontRenderMode,
                   IdNamespace, ColorU};
         use api::units::{Au, DevicePoint};
         use crate::render_backend::FrameId;
         use thread_profiler::register_thread_with_profiler;
         use std::sync::Arc;
         use crate::glyph_rasterizer::{FontInstance, BaseFontInstance, GlyphKey, GlyphRasterizer};
@@ -862,17 +862,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 = RenderTaskGraph::new(FrameId::INVALID, &RenderTaskGraphCounters::new());
+        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/glyph_rasterizer/no_pathfinder.rs
+++ b/gfx/wr/webrender/src/glyph_rasterizer/no_pathfinder.rs
@@ -13,17 +13,17 @@ use rayon::prelude::*;
 use std::sync::{Arc, MutexGuard};
 use crate::platform::font::FontContext;
 use crate::glyph_rasterizer::{FontInstance, FontContexts, GlyphKey};
 use crate::glyph_rasterizer::{GlyphRasterizer, GlyphRasterJob, GlyphRasterJobs};
 use crate::glyph_cache::{GlyphCache, CachedGlyphInfo, GlyphCacheEntry};
 use crate::resource_cache::CachedImageData;
 use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction};
 use crate::gpu_cache::GpuCache;
-use crate::render_task::{RenderTaskGraph, RenderTaskCache};
+use crate::render_task::{RenderTaskTree, RenderTaskCache};
 use crate::profiler::TextureCacheProfileCounters;
 use std::collections::hash_map::Entry;
 
 impl FontContexts {
     /// Get access to the font context associated to the current thread.
     pub fn lock_current_context(&self) -> MutexGuard<FontContext> {
         let id = self.current_worker_id();
         self.lock_context(id)
@@ -39,17 +39,17 @@ impl GlyphRasterizer {
     pub fn request_glyphs(
         &mut self,
         glyph_cache: &mut GlyphCache,
         font: FontInstance,
         glyph_keys: &[GlyphKey],
         texture_cache: &mut TextureCache,
         gpu_cache: &mut GpuCache,
         _: &mut RenderTaskCache,
-        _: &mut RenderTaskGraph,
+        _: &mut RenderTaskTree,
     ) {
         assert!(
             self.font_contexts
                 .lock_shared_context()
                 .has_font(&font.font_key)
         );
         let mut new_glyphs = Vec::new();
 
@@ -134,17 +134,17 @@ impl GlyphRasterizer {
     }
 
     pub fn resolve_glyphs(
         &mut self,
         glyph_cache: &mut GlyphCache,
         texture_cache: &mut TextureCache,
         gpu_cache: &mut GpuCache,
         _: &mut RenderTaskCache,
-        _: &mut RenderTaskGraph,
+        _: &mut RenderTaskTree,
         _: &mut TextureCacheProfileCounters,
     ) {
         // Pull rasterized glyphs from the queue and update the caches.
         while self.pending_glyphs > 0 {
             self.pending_glyphs -= 1;
 
             // TODO: rather than blocking until all pending glyphs are available
             // we could try_recv and steal work from the thread pool to take advantage
--- a/gfx/wr/webrender/src/glyph_rasterizer/pathfinder.rs
+++ b/gfx/wr/webrender/src/glyph_rasterizer/pathfinder.rs
@@ -5,17 +5,17 @@
 //! Module only available when pathfinder is activated
 
 use api::{FontKey, FontTemplate, NativeFontHandle};
 use api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel};
 use euclid::{TypedPoint2D, TypedSize2D, TypedVector2D};
 use pathfinder_font_renderer;
 use pathfinder_partitioner::mesh::Mesh as PathfinderMesh;
 use pathfinder_path_utils::cubic_to_quadratic::CubicToQuadraticTransformer;
-use crate::render_task::{RenderTask, RenderTaskGraph, RenderTaskCache, RenderTaskCacheKey,
+use crate::render_task::{RenderTask, RenderTaskTree, RenderTaskCache, RenderTaskCacheKey,
                          RenderTaskCacheEntryHandle, RenderTaskCacheKeyKind, RenderTaskId,
                          RenderTaskLocation};
 use crate::resource_cache::CacheItem;
 use std::ops::Deref;
 use std::sync::{Arc, Mutex, MutexGuard};
 use crate::glyph_rasterizer::AddFont;
 use crate::internal_types::ResourceCacheError;
 use crate::glyph_cache::{GlyphCache, GlyphCacheEntry, CachedGlyphInfo};
@@ -117,17 +117,17 @@ impl GlyphRasterizer {
         &mut self,
         glyph_key: &GlyphKey,
         font: &FontInstance,
         scale: f32,
         cached_glyph_info: CachedGlyphInfo,
         texture_cache: &mut TextureCache,
         gpu_cache: &mut GpuCache,
         render_task_cache: &mut RenderTaskCache,
-        render_task_tree: &mut RenderTaskGraph,
+        render_task_tree: &mut RenderTaskTree,
     ) -> Result<(RenderTaskCacheEntryHandle,GlyphFormat), ()> {
         let mut pathfinder_font_context = self.font_contexts.lock_pathfinder_context();
         let render_task_cache_key = cached_glyph_info.render_task_cache_key;
         let (glyph_origin, glyph_size) = (cached_glyph_info.origin, render_task_cache_key.size);
         let user_data = [glyph_origin.x as f32, (glyph_origin.y - glyph_size.height) as f32, scale];
         let handle = render_task_cache.request_render_task(render_task_cache_key,
                                                            texture_cache,
                                                            gpu_cache,
@@ -152,17 +152,17 @@ impl GlyphRasterizer {
     pub fn request_glyphs(
         &mut self,
         glyph_cache: &mut GlyphCache,
         font: FontInstance,
         glyph_keys: &[GlyphKey],
         texture_cache: &mut TextureCache,
         gpu_cache: &mut GpuCache,
         render_task_cache: &mut RenderTaskCache,
-        render_task_tree: &mut RenderTaskGraph,
+        render_task_tree: &mut RenderTaskTree,
     ) {
         debug_assert!(self.font_contexts.lock_shared_context().has_font(&font.font_key));
 
         let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font_mut(font.clone());
 
         let (x_scale, y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0));
         let scale = font.oversized_scale_factor(x_scale, y_scale) as f32;
 
@@ -239,17 +239,17 @@ impl GlyphRasterizer {
     }
 
     pub fn resolve_glyphs(
         &mut self,
         _: &mut GlyphCache,
         _: &mut TextureCache,
         _: &mut GpuCache,
         _: &mut RenderTaskCache,
-        _: &mut RenderTaskGraph,
+        _: &mut RenderTaskTree,
         _: &mut TextureCacheProfileCounters,
     ) {
         self.remove_dead_fonts();
     }
 }
 
 impl FontContexts {
     pub fn lock_pathfinder_context(&self) -> MutexGuard<PathfinderFontContext> {
@@ -264,17 +264,17 @@ fn compute_embolden_amount(ppem: f32) ->
 
 fn request_render_task_from_pathfinder(
     glyph_key: &GlyphKey,
     font: &FontInstance,
     scale: f32,
     glyph_origin: &DeviceIntPoint,
     glyph_size: &DeviceIntSize,
     font_context: &mut PathfinderFontContext,
-    render_tasks: &mut RenderTaskGraph,
+    render_tasks: &mut RenderTaskTree,
 ) -> Result<RenderTaskId, ()> {
     let size = font.size.scale_by(scale.recip());
     let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
         font_key: font.font_key.clone(),
         size,
     };
 
     // TODO: pathfinder will need to support 2D subpixel offset
--- a/gfx/wr/webrender/src/internal_types.rs
+++ b/gfx/wr/webrender/src/internal_types.rs
@@ -7,17 +7,16 @@ use api::{ImageFormat, ItemTag, Notifica
 use api::units::*;
 use api;
 use crate::device::TextureFilter;
 use crate::renderer::PipelineInfo;
 use crate::gpu_cache::GpuCacheUpdateList;
 use fxhash::FxHasher;
 use plane_split::BspSplitter;
 use crate::profiler::BackendProfileCounters;
-use smallvec::SmallVec;
 use std::{usize, i32};
 use std::collections::{HashMap, HashSet};
 use std::f32;
 use std::hash::BuildHasherDefault;
 use std::path::PathBuf;
 use std::sync::Arc;
 
 #[cfg(feature = "capture")]
@@ -45,31 +44,36 @@ pub enum Filter {
     Brightness(f32),
     Contrast(f32),
     Grayscale(f32),
     HueRotate(f32),
     Invert(f32),
     Opacity(api::PropertyBinding<f32>, f32),
     Saturate(f32),
     Sepia(f32),
-    DropShadowStack(SmallVec<[Shadow; 1]>),
-    ColorMatrix(Box<[f32; 20]>),
+    DropShadow(Shadow),
+    #[allow(dead_code)]
+    DropShadowStack(Vec<Shadow>),
+    ColorMatrix([f32; 20]),
     SrgbToLinear,
     LinearToSrgb,
     ComponentTransfer,
 }
 
 impl Filter {
     /// Ensure that the parameters for a filter operation
     /// are sensible.
     pub fn sanitize(&mut self) {
         match self {
             Filter::Blur(ref mut radius) => {
                 *radius = radius.min(MAX_BLUR_RADIUS);
             }
+            Filter::DropShadow(ref mut shadow) => {
+                shadow.blur_radius = shadow.blur_radius.min(MAX_BLUR_RADIUS);
+            }
             Filter::DropShadowStack(ref mut stack) => {
                 for shadow in stack {
                     shadow.blur_radius = shadow.blur_radius.min(MAX_BLUR_RADIUS);
                 }
             }
             _ => {},
         }
     }
@@ -80,16 +84,17 @@ impl Filter {
             Filter::Blur(..) |
             Filter::Brightness(..) |
             Filter::Contrast(..) |
             Filter::Grayscale(..) |
             Filter::HueRotate(..) |
             Filter::Invert(..) |
             Filter::Saturate(..) |
             Filter::Sepia(..) |
+            Filter::DropShadow(..) |
             Filter::DropShadowStack(..) |
             Filter::ColorMatrix(..) |
             Filter::SrgbToLinear |
             Filter::LinearToSrgb |
             Filter::ComponentTransfer  => true,
             Filter::Opacity(_, amount) => {
                 amount > OPACITY_EPSILON
             }
@@ -112,24 +117,25 @@ impl Filter {
                 for shadow in shadows {
                     if shadow.offset.x != 0.0 || shadow.offset.y != 0.0 || shadow.blur_radius != 0.0 {
                         return false;
                     }
                 }
 
                 true
             }
-            Filter::ColorMatrix(ref matrix) => {
-                **matrix == [
-                    1.0, 0.0, 0.0, 0.0,
-                    0.0, 1.0, 0.0, 0.0,
-                    0.0, 0.0, 1.0, 0.0,
-                    0.0, 0.0, 0.0, 1.0,
-                    0.0, 0.0, 0.0, 0.0
-                ]
+            Filter::DropShadow(shadow) => {
+                shadow.offset.x == 0.0 && shadow.offset.y == 0.0 && shadow.blur_radius == 0.0
+            },
+            Filter::ColorMatrix(matrix) => {
+                matrix == [1.0, 0.0, 0.0, 0.0,
+                           0.0, 1.0, 0.0, 0.0,
+                           0.0, 0.0, 1.0, 0.0,
+                           0.0, 0.0, 0.0, 1.0,
+                           0.0, 0.0, 0.0, 0.0]
             }
             Filter::SrgbToLinear |
             Filter::LinearToSrgb |
             Filter::ComponentTransfer => false,
         }
     }
 }
 
@@ -141,21 +147,21 @@ impl From<FilterOp> for Filter {
             FilterOp::Brightness(b) => Filter::Brightness(b),
             FilterOp::Contrast(c) => Filter::Contrast(c),
             FilterOp::Grayscale(g) => Filter::Grayscale(g),
             FilterOp::HueRotate(h) => Filter::HueRotate(h),
             FilterOp::Invert(i) => Filter::Invert(i),
             FilterOp::Opacity(binding, opacity) => Filter::Opacity(binding, opacity),
             FilterOp::Saturate(s) => Filter::Saturate(s),
             FilterOp::Sepia(s) => Filter::Sepia(s),
-            FilterOp::ColorMatrix(mat) => Filter::ColorMatrix(Box::new(mat)),
+            FilterOp::DropShadow(shadow) => Filter::DropShadow(shadow),
+            FilterOp::ColorMatrix(mat) => Filter::ColorMatrix(mat),
             FilterOp::SrgbToLinear => Filter::SrgbToLinear,
             FilterOp::LinearToSrgb => Filter::LinearToSrgb,
             FilterOp::ComponentTransfer => Filter::ComponentTransfer,
-            FilterOp::DropShadow(shadow) => Filter::DropShadowStack(smallvec![shadow]),
         }
     }
 }
 
 /// An ID for a texture that is owned by the `texture_cache` module.
 ///
 /// This can include atlases or standalone textures allocated via the texture
 /// cache (e.g.  if an image is too large to be added to an atlas). The texture
--- a/gfx/wr/webrender/src/lib.rs
+++ b/gfx/wr/webrender/src/lib.rs
@@ -183,17 +183,16 @@ extern crate pathfinder_partitioner;
 extern crate pathfinder_path_utils;
 extern crate plane_split;
 extern crate rayon;
 #[cfg(feature = "ron")]
 extern crate ron;
 #[cfg(feature = "debugger")]
 extern crate serde_json;
 extern crate sha2;
-#[macro_use]
 extern crate smallvec;
 extern crate time;
 #[cfg(feature = "debugger")]
 extern crate ws;
 #[cfg(feature = "debugger")]
 extern crate image_loader;
 #[cfg(feature = "debugger")]
 extern crate base64;
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -2524,16 +2524,72 @@ impl PicturePrimitive {
                             frame_state.render_tasks,
                             RenderTargetKind::Color,
                             ClearMode::Transparent,
                             None,
                         );
 
                         (blur_render_task_id, picture_task_id)
                     }
+                    PictureCompositeMode::Filter(Filter::DropShadow(shadow)) => {
+                        let blur_std_deviation = shadow.blur_radius * device_pixel_scale.0;
+                        let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
+                        let rounded_std_dev = blur_std_deviation.round();
+                        let rounded_std_dev = DeviceSize::new(rounded_std_dev, rounded_std_dev);
+                        // The clipped field is the part of the picture that is visible
+                        // on screen. The unclipped field is the screen-space rect of
+                        // the complete picture, if no screen / clip-chain was applied
+                        // (this includes the extra space for blur region). To ensure
+                        // that we draw a large enough part of the picture to get correct
+                        // blur results, inflate that clipped area by the blur range, and
+                        // then intersect with the total screen rect, to minimize the
+                        // allocation size.
+                        let mut device_rect = clipped.inflate(blur_range, blur_range)
+                                .intersection(&unclipped.to_i32())
+                                .unwrap();
+                        device_rect.size = RenderTask::adjusted_blur_source_size(
+                            device_rect.size,
+                            rounded_std_dev,
+                        );
+
+                        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,
+                            Vec::new(),
+                            uv_rect_kind,
+                            raster_spatial_node_index,
+                            device_pixel_scale,
+                        );
+                        picture_task.mark_for_saving();
+
+                        let picture_task_id = frame_state.render_tasks.add(picture_task);
+
+                        let blur_render_task_id = RenderTask::new_blur(
+                            rounded_std_dev,
+                            picture_task_id,
+                            frame_state.render_tasks,
+                            RenderTargetKind::Color,
+                            ClearMode::Transparent,
+                            None,
+                        );
+
+                        self.secondary_render_task_id = Some(picture_task_id);
+
+                        (blur_render_task_id, picture_task_id)
+                    }
                     PictureCompositeMode::Filter(Filter::DropShadowStack(ref shadows)) => {
                         let mut max_std_deviation = 0.0;
                         for shadow in shadows {
                             // TODO(nical) presumably we should compute the clipped rect for each shadow
                             // and compute the union of them to determine what we need to rasterize and blur?
                             max_std_deviation = f32::max(max_std_deviation, shadow.blur_radius * device_pixel_scale.0);
                         }
         
@@ -2584,17 +2640,17 @@ impl PicturePrimitive {
                                 frame_state.render_tasks,
                                 RenderTargetKind::Color,
                                 ClearMode::Transparent,
                                 Some(&mut blur_tasks),
                             );      
                         }
         
                         // TODO(nical) the second one should to be the blur's task id but we have several blurs now
-                        (blur_render_task_id, picture_task_id)
+                        (picture_task_id, blur_render_task_id)
                     }
                     PictureCompositeMode::MixBlend(..) if !frame_context.fb_config.gpu_supports_advanced_blend => {
                         let uv_rect_kind = calculate_uv_rect_kind(
                             &pic_rect,
                             &transform,
                             &clipped,
                             device_pixel_scale,
                             true,
@@ -3133,16 +3189,19 @@ impl PicturePrimitive {
             let mut surface_rect = {
                 let surface = state.current_surface_mut();
                 // Inflate the local bounding rect if required by the filter effect.
                 // This inflaction factor is to be applied to the surface itsefl.
                 // TODO: in prepare_for_render we round before multiplying with the
                 // blur sample scale. Should we do this here as well?
                 let inflation_size = match raster_config.composite_mode {
                     PictureCompositeMode::Filter(Filter::Blur(_)) => surface.inflation_factor,
+                    PictureCompositeMode::Filter(Filter::DropShadow(shadow)) => {
+                        (shadow.blur_radius * BLUR_SAMPLE_SCALE).ceil()
+                    }
                     PictureCompositeMode::Filter(Filter::DropShadowStack(ref shadows)) => {
                         let mut max = 0.0;
                         for shadow in shadows {
                             max = f32::max(max, shadow.blur_radius * BLUR_SAMPLE_SCALE);
                         }
                         max.ceil()
                     }
                     _ => 0.0,
@@ -3168,16 +3227,21 @@ impl PicturePrimitive {
                     raster_config.establishes_raster_root = false;
                     state.are_raster_roots_assigned = false;
                 }
             }
 
             // Drop shadows draw both a content and shadow rect, so need to expand the local
             // rect of any surfaces to be composited in parent surfaces correctly.
             match raster_config.composite_mode {
+                PictureCompositeMode::Filter(Filter::DropShadow(shadow)) => {
+                    let content_rect = surface_rect;
+                    let shadow_rect = surface_rect.translate(&shadow.offset);
+                    surface_rect = content_rect.union(&shadow_rect);
+                }
                 PictureCompositeMode::Filter(Filter::DropShadowStack(ref shadows)) => {
                     for shadow in shadows {
                         let content_rect = surface_rect;
                         let shadow_rect = surface_rect.translate(&shadow.offset);
                         surface_rect = content_rect.union(&shadow_rect);
                     }
                 }
                 _ => {}
@@ -3226,16 +3290,49 @@ impl PicturePrimitive {
         //           with a ColorMatrix, which stores the color matrix here. It's
         //           probably worth tidying this code up to be a bit more consistent.
         //           Perhaps store the color matrix after the common data, even though
         //           it's not used by that shader.
 
         match raster_config.composite_mode {
             PictureCompositeMode::TileCache { .. } => {}
             PictureCompositeMode::Filter(Filter::Blur(..)) => {}
+            PictureCompositeMode::Filter(Filter::DropShadow(shadow)) => {
+                if self.extra_gpu_data_handles.is_empty() {
+                    self.extra_gpu_data_handles.push(GpuCacheHandle::new());
+                }
+
+                if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handles[0]) {
+                    // TODO(gw): This is very hacky code below! It stores an extra
+                    //           brush primitive below for the special case of a
+                    //           drop-shadow where we need a different local
+                    //           rect for the shadow. To tidy this up in future,
+                    //           we could consider abstracting the code in prim_store.rs
+                    //           that writes a brush primitive header.
+
+                    // Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
+                    //  [brush specific data]
+                    //  [segment_rect, segment data]
+                    let shadow_rect = self.snapped_local_rect.translate(&shadow.offset);
+
+                    // ImageBrush colors
+                    request.push(shadow.color.premultiplied());
+                    request.push(PremultipliedColorF::WHITE);
+                    request.push([
+                        self.snapped_local_rect.size.width,
+                        self.snapped_local_rect.size.height,
+                        0.0,
+                        0.0,
+                    ]);
+
+                    // segment rect / extra data
+                    request.push(shadow_rect);
+                    request.push([0.0, 0.0, 0.0, 0.0]);
+                }
+            }
             PictureCompositeMode::Filter(Filter::DropShadowStack(ref shadows)) => {
                 self.extra_gpu_data_handles.resize(shadows.len(), GpuCacheHandle::new());
                 for (shadow, extra_handle) in shadows.iter().zip(self.extra_gpu_data_handles.iter_mut()) {
                     if let Some(mut request) = frame_state.gpu_cache.request(extra_handle) {
                         // Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
                         //  [brush specific data]
                         //  [segment_rect, segment data]
                         let shadow_rect = self.snapped_local_rect.translate(&shadow.offset);
@@ -3253,17 +3350,17 @@ impl PicturePrimitive {
                         // segment rect / extra data
                         request.push(shadow_rect);
                         request.push([0.0, 0.0, 0.0, 0.0]);
                     }
                 }
             }
             PictureCompositeMode::MixBlend(..) if !frame_context.fb_config.gpu_supports_advanced_blend => {}
             PictureCompositeMode::Filter(ref filter) => {
-                if let Filter::ColorMatrix(ref m) = *filter {
+                if let Filter::ColorMatrix(m) = *filter {
                     if self.extra_gpu_data_handles.is_empty() {
                         self.extra_gpu_data_handles.push(GpuCacheHandle::new());
                     }
                     if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handles[0]) {
                         for i in 0..5 {
                             request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
                         }
                     }
--- a/gfx/wr/webrender/src/prim_store/mod.rs
+++ b/gfx/wr/webrender/src/prim_store/mod.rs
@@ -1412,17 +1412,17 @@ pub struct PrimitiveInstance {
     pub prim_origin: LayoutPoint,
 
     /// Local space clip rect for this instance
     pub local_clip_rect: LayoutRect,
 
     #[cfg(debug_assertions)]
     pub id: PrimitiveDebugId,
 
-    /// The last frame ID (of the `RenderTaskGraph`) this primitive
+    /// The last frame ID (of the `RenderTaskTree`) this primitive
     /// was prepared for rendering in.
     #[cfg(debug_assertions)]
     pub prepared_frame_id: FrameId,
 
     /// If this primitive is visible, an index into the instance
     /// visibility scratch buffer. If not visible, INVALID.
     pub visibility_info: PrimitiveVisibilityIndex,
 
@@ -1876,16 +1876,17 @@ impl PrimitiveStore {
                     } else {
                         frame_state.clip_chain_stack.pop_clip();
                     }
 
                     let shadow_rect = match pic.raster_config {
                         Some(ref rc) => match rc.composite_mode {
                             // If we have a drop shadow filter, we also need to include the shadow in
                             // our local rect for the purpose of calculating the size of the picture.
+                            PictureCompositeMode::Filter(Filter::DropShadow(shadow)) => pic.snapped_local_rect.translate(&shadow.offset),
                             PictureCompositeMode::Filter(Filter::DropShadowStack(ref shadows)) => {
                                 let mut rect = LayoutRect::zero();
                                 for shadow in shadows {
                                     rect = rect.union(&pic.snapped_local_rect.translate(&shadow.offset));
                                 }
 
                                 rect
                             }
@@ -2166,33 +2167,38 @@ impl PrimitiveStore {
         // TODO(gw): In future, if we support specifying a flag which gets the
         //           stretch size from the segment rect in the shaders, we can
         //           remove this invalidation here completely.
         if let Some(ref raster_config) = pic.raster_config {
             // Inflate the local bounding rect if required by the filter effect.
             // This inflaction factor is to be applied to the surface itself.
             let inflation_size = match raster_config.composite_mode {
                 PictureCompositeMode::Filter(Filter::Blur(_)) => surface.inflation_factor,
+                PictureCompositeMode::Filter(Filter::DropShadow(shadow)) => {
+                    (shadow.blur_radius * BLUR_SAMPLE_SCALE).ceil()
+                }
                 PictureCompositeMode::Filter(Filter::DropShadowStack(ref shadows)) => {
                     let mut max = 0.0;
                     for shadow in shadows {
                         max = f32::max(max, shadow.blur_radius * BLUR_SAMPLE_SCALE);
                     }
                     max.ceil()
                 }
                 _ => 0.0,
             };
             surface_rect = surface_rect.inflate(inflation_size, inflation_size);
 
             // Layout space for the picture is picture space from the
             // perspective of its child primitives.
             let pic_local_rect = surface_rect * TypedScale::new(1.0);
             if pic.snapped_local_rect != pic_local_rect {
                 match raster_config.composite_mode {
-                    PictureCompositeMode::Filter(Filter::DropShadowStack(..)) => {
+                    PictureCompositeMode::Filter(Filter::DropShadow(..)) 
+                    | PictureCompositeMode::Filter(Filter::DropShadowStack(..))
+                    => {
                         for handle in &pic.extra_gpu_data_handles {
                             frame_state.gpu_cache.invalidate(handle);
                         }
                     }
                     _ => {}
                 }
                 // Invalidate any segments built for this picture, since the local
                 // rect has changed.
@@ -2671,17 +2677,17 @@ impl PrimitiveStore {
                 let dirty_region = frame_state.current_dirty_region();
 
                 // Check if the primitive world rect intersects with the overall dirty rect first.
                 match visibility_info.clipped_world_rect.intersection(&dirty_region.combined.world_rect) {
                     Some(rect) => {
                         // It does intersect the overall dirty rect, so it *might* be visible.
                         // Store this reduced rect here, which is used for clip mask and other
                         // render task size calculations. In future, we may consider creating multiple
-                        // render task graphs, one per dirty region.
+                        // render task trees, one per dirty region.
                         visibility_info.clipped_world_rect = rect;
 
                         // If there is more than one dirty region, it's possible that this primitive
                         // is inside the overal dirty rect, but doesn't intersect any of the individual
                         // dirty rects. If that's the case, then we can skip drawing this primitive too.
                         if dirty_region.dirty_rects.len() > 1 {
                             for (region_index, region) in dirty_region.dirty_rects.iter().enumerate() {
                                 if visibility_info.clipped_world_rect.intersects(&region.world_rect) {
--- a/gfx/wr/webrender/src/prim_store/picture.rs
+++ b/gfx/wr/webrender/src/prim_store/picture.rs
@@ -33,16 +33,17 @@ pub enum PictureCompositeKey {
     Contrast(Au),
     Grayscale(Au),
     HueRotate(Au),
     Invert(Au),
     Opacity(Au),
     OpacityBinding(PropertyBindingId, Au),
     Saturate(Au),
     Sepia(Au),
+    DropShadow(VectorKey, Au, ColorU),
     DropShadowStack(Vec<(VectorKey, Au, ColorU)>),
     ColorMatrix([Au; 20]),
     SrgbToLinear,
     LinearToSrgb,
     ComponentTransfer(ItemUid),
 
     // MixBlendMode
     Multiply,
@@ -100,16 +101,19 @@ impl From<Option<PictureCompositeMode>> 
                     Filter::Identity => PictureCompositeKey::Identity,
                     Filter::DropShadowStack(ref shadows) => {
                         PictureCompositeKey::DropShadowStack(
                             shadows.iter().map(|shadow| {
                                 (shadow.offset.into(), Au::from_f32_px(shadow.blur_radius), shadow.color.into())
                             }).collect()
                         )
                     }
+                    Filter::DropShadow(shadow) => {
+                        PictureCompositeKey::DropShadow(shadow.offset.into(), Au::from_f32_px(shadow.blur_radius), shadow.color.into())
+                    }
                     Filter::Opacity(binding, _) => {
                         match binding {
                             PropertyBinding::Value(value) => {
                                 PictureCompositeKey::Opacity(Au::from_f32_px(value))
                             }
                             PropertyBinding::Binding(key, default) => {
                                 PictureCompositeKey::OpacityBinding(key.id, Au::from_f32_px(default))
                             }
--- a/gfx/wr/webrender/src/prim_store/text_run.rs
+++ b/gfx/wr/webrender/src/prim_store/text_run.rs
@@ -8,17 +8,17 @@ use crate::display_list_flattener::{Crea
 use crate::frame_builder::FrameBuildingState;
 use crate::glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
 use crate::gpu_cache::GpuCache;
 use crate::intern;
 use crate::internal_types::LayoutPrimitiveInfo;
 use crate::picture::SurfaceInfo;
 use crate::prim_store::{PrimitiveOpacity, PrimitiveSceneData,  PrimitiveScratchBuffer};
 use crate::prim_store::{PrimitiveStore, PrimKeyCommonData, PrimTemplateCommonData};
-use crate::render_task::{RenderTaskGraph};
+use crate::render_task::{RenderTaskTree};
 use crate::renderer::{MAX_VERTEX_TEXTURE_WIDTH};
 use crate::resource_cache::{ResourceCache};
 use crate::util::{MatrixHelpers};
 use crate::prim_store::{InternablePrimitive, PrimitiveInstanceKind};
 use std::ops;
 use std::sync::Arc;
 use crate::storage;
 use crate::util::PrimaryArc;
@@ -288,17 +288,17 @@ impl TextRunPrimitive {
         prim_offset: LayoutVector2D,
         specified_font: &FontInstance,
         glyphs: &[GlyphInstance],
         transform: &LayoutToWorldTransform,
         surface: &SurfaceInfo,
         raster_space: RasterSpace,
         resource_cache: &mut ResourceCache,
         gpu_cache: &mut GpuCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         scratch: &mut PrimitiveScratchBuffer,
     ) {
         let device_pixel_scale = surface.device_pixel_scale;
 
         let cache_dirty = self.update_font_instance(
             specified_font,
             device_pixel_scale,
             transform,
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -33,17 +33,17 @@ use crate::intern::DataStore;
 use crate::internal_types::{DebugOutput, FastHashMap, FastHashSet, RenderedDocument, ResultMsg};
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use crate::picture::RetainedTiles;
 use crate::prim_store::{PrimitiveScratchBuffer, PrimitiveInstance};
 use crate::prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData};
 use crate::prim_store::interned::*;
 use crate::profiler::{BackendProfileCounters, IpcProfileCounters, ResourceProfileCounters};
 use crate::record::ApiRecordingReceiver;
-use crate::render_task::RenderTaskGraphCounters;
+use crate::render_task::RenderTaskTreeCounters;
 use crate::renderer::{AsyncPropertySampler, PipelineInfo};
 use crate::resource_cache::ResourceCache;
 #[cfg(feature = "replay")]
 use crate::resource_cache::PlainCacheOwn;
 #[cfg(any(feature = "capture", feature = "replay"))]
 use crate::resource_cache::PlainResources;
 use crate::scene::{Scene, SceneProperties};
 use crate::scene_builder::*;
@@ -346,19 +346,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 graph to pre-allocate memory up-front
+    /// Keep track of the size of render task tree to pre-allocate memory up-front
     /// the next frame.
-    render_task_counters: RenderTaskGraphCounters,
+    render_task_counters: RenderTaskTreeCounters,
 }
 
 impl Document {
     pub fn new(
         id: DocumentId,
         size: DeviceIntSize,
         layer: DocumentLayer,
         default_device_pixel_ratio: f32,
@@ -382,17 +382,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: RenderTaskGraphCounters::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 {
@@ -1817,17 +1817,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: RenderTaskGraphCounters::new(),
+                render_task_counters: RenderTaskTreeCounters::new(),
             };
 
             let frame_name = format!("frame-{}-{}", id.namespace_id.0, id.id);
             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
@@ -73,61 +73,61 @@ impl RenderTaskId {
 #[repr(C)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTaskAddress(pub u16);
 
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-pub struct RenderTaskGraph {
+pub struct RenderTaskTree {
     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,
 }
 
 #[derive(Debug)]
-pub struct RenderTaskGraphCounters {
+pub struct RenderTaskTreeCounters {
     tasks_len: usize,
     task_data_len: usize,
     cacheable_render_tasks_len: usize,
 }
 
-impl RenderTaskGraphCounters {
+impl RenderTaskTreeCounters {
     pub fn new() -> Self {
-        RenderTaskGraphCounters {
+        RenderTaskTreeCounters {
             tasks_len: 0,
             task_data_len: 0,
             cacheable_render_tasks_len: 0,
         }
     }
 }
 
-impl RenderTaskGraph {
-    pub fn new(frame_id: FrameId, counters: &RenderTaskGraphCounters) -> Self {
+impl RenderTaskTree {
+    pub fn new(frame_id: FrameId, counters: &RenderTaskTreeCounters) -> 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 {
+        RenderTaskTree {
             tasks: Vec::with_capacity(counters.tasks_len + extra_items),
             task_data: Vec::with_capacity(counters.task_data_len + extra_items),
             cacheable_render_tasks: Vec::with_capacity(counters.cacheable_render_tasks_len + extra_items),
             next_saved: SavedTargetIndex(0),
             frame_id,
         }
     }
 
-    pub fn counters(&self) -> RenderTaskGraphCounters {
-        RenderTaskGraphCounters {
+    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 _;
@@ -407,26 +407,26 @@ impl RenderTaskGraph {
     }
 
     #[cfg(debug_assertions)]
     pub fn frame_id(&self) -> FrameId {
         self.frame_id
     }
 }
 
-impl ops::Index<RenderTaskId> for RenderTaskGraph {
+impl ops::Index<RenderTaskId> for RenderTaskTree {
     type Output = RenderTask;
     fn index(&self, id: RenderTaskId) -> &RenderTask {
         #[cfg(debug_assertions)]
         debug_assert_eq!(self.frame_id, id.frame_id);
         &self.tasks[id.index as usize]
     }
 }
 
-impl ops::IndexMut<RenderTaskId> for RenderTaskGraph {
+impl ops::IndexMut<RenderTaskId> for RenderTaskTree {
     fn index_mut(&mut self, id: RenderTaskId) -> &mut RenderTask {
         #[cfg(debug_assertions)]
         debug_assert_eq!(self.frame_id, id.frame_id);
         &mut self.tasks[id.index as usize]
     }
 }
 
 /// Identifies the output buffer location for a given `RenderTask`.
@@ -873,17 +873,17 @@ impl RenderTask {
 
     pub fn new_mask(
         outer_rect: DeviceIntRect,
         clip_node_range: ClipNodeRange,
         root_spatial_node_index: SpatialNodeIndex,
         clip_store: &mut ClipStore,
         gpu_cache: &mut GpuCache,
         resource_cache: &mut ResourceCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         clip_data_store: &mut ClipDataStore,
         snap_offsets: SnapOffsets,
         device_pixel_scale: DevicePixelScale,
         fb_config: &FrameBuilderConfig,
     ) -> Self {
         // 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
@@ -1040,17 +1040,17 @@ impl RenderTask {
     //           |
     //    HorizontalBlurTask: Apply the separable horizontal blur to the vertical blur.
     //           |
     //           +---- This is stored as the input task to the primitive shader.
     //
     pub fn new_blur(
         blur_std_deviation: DeviceSize,
         src_task_id: RenderTaskId,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         target_kind: RenderTargetKind,
         clear_mode: ClearMode,
         mut blur_cache: Option<&mut BlurTaskCache>,
     ) -> RenderTaskId {
         // Adjust large std deviation value.
         let mut adjusted_blur_std_deviation = blur_std_deviation;
         let (blur_target_size, uv_rect_kind) = {
             let src_task = &render_tasks[src_task_id];
@@ -1148,17 +1148,17 @@ impl RenderTask {
                 instances,
             }),
             ClearMode::Transparent,
         )
     }
 
     pub fn new_scaling(
         src_task_id: RenderTaskId,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         target_kind: RenderTargetKind,
         target_size: DeviceIntSize,
     ) -> Self {
         let uv_rect_kind = render_tasks[src_task_id].uv_rect_kind();
 
         RenderTask::with_dynamic_location(
             target_size,
             vec![src_task_id],
@@ -1459,17 +1459,17 @@ impl RenderTask {
                 user_data: [0.0; 3],
                 uv_rect_kind,
             };
             image_source.write_gpu_blocks(&mut request);
         }
     }
 
     #[cfg(feature = "debugger")]
-    pub fn print_with<T: PrintTreePrinter>(&self, pt: &mut T, tree: &RenderTaskGraph) -> bool {
+    pub fn print_with<T: PrintTreePrinter>(&self, pt: &mut T, tree: &RenderTaskTree) -> bool {
         match self.kind {
             RenderTaskKind::Picture(ref task) => {
                 pt.new_level(format!("Picture of {:?}", task.pic_index));
             }
             RenderTaskKind::CacheMask(ref task) => {
                 pt.new_level(format!("CacheMask with {} clips", task.clip_node_range.count));
                 pt.add_item(format!("rect: {:?}", task.actual_rect));
             }
@@ -1630,17 +1630,17 @@ impl RenderTaskCache {
         });
     }
 
     fn alloc_render_task(
         entry: &mut RenderTaskCacheEntry,
         render_task_id: RenderTaskId,
         gpu_cache: &mut GpuCache,
         texture_cache: &mut TextureCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
     ) {
         let render_task = &mut render_tasks[render_task_id];
         let target_kind = render_task.target_kind();
 
         // Find out what size to alloc in the texture cache.
         let size = match render_task.location {
             RenderTaskLocation::Fixed(..) |
             RenderTaskLocation::TextureCache { .. } => {
@@ -1700,23 +1700,23 @@ impl RenderTaskCache {
         };
     }
 
     pub fn request_render_task<F>(
         &mut self,
         key: RenderTaskCacheKey,
         texture_cache: &mut TextureCache,
         gpu_cache: &mut GpuCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         user_data: Option<[f32; 3]>,
         is_opaque: bool,
         f: F,
     ) -> Result<RenderTaskCacheEntryHandle, ()>
     where
-        F: FnOnce(&mut RenderTaskGraph) -> Result<RenderTaskId, ()>,
+        F: FnOnce(&mut RenderTaskTree) -> Result<RenderTaskId, ()>,
     {
         // Get the texture cache handle for this cache key,
         // or create one.
         let cache_entries = &mut self.cache_entries;
         let entry_handle = self.map.entry(key).or_insert_with(|| {
             let entry = RenderTaskCacheEntry {
                 handle: TextureCacheHandle::invalid(),
                 user_data,
@@ -1779,29 +1779,29 @@ impl RenderTaskCache {
     }
 }
 
 // TODO(gw): Rounding the content rect here to device pixels is not
 // technically correct. Ideally we should ceil() here, and ensure that
 // the extra part pixel in the case of fractional sizes is correctly
 // handled. For now, just use rounding which passes the existing
 // Gecko tests.
-// Note: zero-square tasks are prohibited in WR task graph, so
+// Note: zero-square tasks are prohibited in WR task tree, so
 // we ensure each dimension to be at least the length of 1 after rounding.
 pub fn to_cache_size(size: DeviceSize) -> DeviceIntSize {
     DeviceIntSize::new(
         1.max(size.width.round() as i32),
         1.max(size.height.round() as i32),
     )
 }
 
 // Dump an SVG visualization of the render graph for debugging purposes
 #[allow(dead_code)]
 pub fn dump_render_tasks_as_svg(
-    render_tasks: &RenderTaskGraph,
+    render_tasks: &RenderTaskTree,
     passes: &[RenderPass],
     output: &mut dyn io::Write,
 ) -> io::Result<()> {
     use svg_fmt::*;
 
     let node_width = 80.0;
     let node_height = 30.0;
     let vertical_spacing = 8.0;
@@ -1991,18 +1991,18 @@ fn diamond_task_graph() {
     //     [b1]
     //    /    \
     // [a]      [main_pic]
     //    \    /
     //     [b2]
 
     let color = RenderTargetKind::Color;
 
-    let counters = RenderTaskGraphCounters::new();
-    let mut tasks = RenderTaskGraph::new(FrameId::first(), &counters);
+    let counters = RenderTaskTreeCounters::new();
+    let mut tasks = RenderTaskTree::new(FrameId::first(), &counters);
 
     let a = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), Vec::new()));
     let b1 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), vec![a]));
     let b2 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), vec![a]));
 
     let main_pic = tasks.add(RenderTask::new_test(
         color,
         RenderTaskLocation::Fixed(rect(0, 0, 3200, 1800)),
@@ -2028,18 +2028,18 @@ fn diamond_task_graph() {
 
 #[test]
 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 counters = RenderTaskTreeCounters::new();
+    let mut tasks = RenderTaskTree::new(FrameId::first(), &counters);
 
     let pic = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), Vec::new()));
     let scale1 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), vec![pic]));
     let scale2 = tasks.add(RenderTask::new_test(color, dyn_location(160, 160), vec![scale1]));
     let scale3 = tasks.add(RenderTask::new_test(color, dyn_location(80, 80), vec![scale2]));
     let scale4 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), vec![scale3]));
 
     let vblur1 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), vec![scale4]));
@@ -2113,18 +2113,18 @@ fn blur_task_graph() {
 
 #[test]
 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 counters = RenderTaskTreeCounters::new();
+    let mut tasks = RenderTaskTree::new(FrameId::first(), &counters);
 
     let a1 = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), Vec::new()));
     let _a2 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), vec![a1]));
 
     let b1 = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), Vec::new()));
     let b2 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), vec![b1]));
     let _b3 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), vec![b2]));
 
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -77,17 +77,17 @@ use crate::profiler::{BackendProfileCoun
 use crate::profiler::{Profiler, ChangeIndicator};
 use crate::device::query::{GpuProfiler, GpuDebugMethod};
 use rayon::{ThreadPool, ThreadPoolBuilder};
 use crate::record::ApiRecordingReceiver;
 use crate::render_backend::{FrameId, RenderBackend};
 use crate::scene_builder::{SceneBuilder, LowPrioritySceneBuilder};
 use crate::shade::{Shaders, WrShaders};
 use smallvec::SmallVec;
-use crate::render_task::{RenderTask, RenderTaskData, RenderTaskKind, RenderTaskGraph};
+use crate::render_task::{RenderTask, RenderTaskData, RenderTaskKind, RenderTaskTree};
 use crate::resource_cache::ResourceCache;
 use crate::util::drain_filter;
 
 use std;
 use std::cmp;
 use std::collections::{HashMap, VecDeque};
 use std::collections::hash_map::Entry;
 use std::f32;
@@ -3578,17 +3578,17 @@ impl Renderer {
 
     //TODO: make this nicer. Currently we can't accept `&mut self` because the `DrawTarget` parameter
     // needs to borrow self.texture_resolver
     fn handle_blits(
         gpu_profile: &mut GpuProfiler<GpuProfileTag>,
         device: &mut Device,
         texture_resolver: &TextureResolver,
         blits: &[BlitJob],
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         draw_target: DrawTarget,
         content_origin: &DeviceIntPoint,
     ) {
         if blits.is_empty() {
             return;
         }
 
         let _timer = gpu_profile.start_timer(GPU_TAG_BLIT);
@@ -3663,17 +3663,17 @@ impl Renderer {
 
     fn draw_color_target(
         &mut self,
         draw_target: DrawTarget,
         target: &ColorRenderTarget,
         content_origin: DeviceIntPoint,
         clear_color: Option<[f32; 4]>,
         clear_depth: Option<f32>,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         projection: &Transform3D<f32>,
         frame_id: GpuFrameId,
         stats: &mut RendererStats,
     ) {
         self.profile_counters.color_targets.inc();
         let _gm = self.gpu_profile.start_marker("color target");
 
         // sanity check for the depth buffer
@@ -4188,17 +4188,17 @@ impl Renderer {
         }
     }
 
     fn draw_alpha_target(
         &mut self,
         draw_target: DrawTarget,
         target: &AlphaRenderTarget,
         projection: &Transform3D<f32>,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         stats: &mut RendererStats,
     ) {
         self.profile_counters.alpha_targets.inc();
         let _gm = self.gpu_profile.start_marker("alpha target");
         let alpha_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_ALPHA);
 
         {
             let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_TARGET);
@@ -4303,17 +4303,17 @@ impl Renderer {
         self.gpu_profile.finish_sampler(alpha_sampler);
     }
 
     fn draw_texture_cache_target(
         &mut self,
         texture: &CacheTextureId,
         layer: LayerIndex,
         target: &TextureCacheRenderTarget,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         stats: &mut RendererStats,
     ) {
         let texture_source = TextureSource::TextureCache(*texture);
         let (target_size, projection) = {
             let texture = self.texture_resolver
                 .resolve(&texture_source)
                 .expect("BUG: invalid target texture");
             let target_size = texture.get_dimensions();
--- a/gfx/wr/webrender/src/resource_cache.rs
+++ b/gfx/wr/webrender/src/resource_cache.rs
@@ -25,17 +25,17 @@ use crate::glyph_cache::GlyphCacheEntry;
 use crate::glyph_rasterizer::{BaseFontInstance, FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer};
 use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
 use crate::gpu_types::UvRectKind;
 use crate::image::{compute_tile_size, compute_tile_range, for_each_tile_in_range};
 use crate::internal_types::{FastHashMap, FastHashSet, TextureSource, TextureUpdateList};
 use crate::profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
 use crate::render_backend::{FrameId, FrameStamp};
 use crate::render_task::{RenderTaskCache, RenderTaskCacheKey, RenderTaskId};
-use crate::render_task::{RenderTaskCacheEntry, RenderTaskCacheEntryHandle, RenderTaskGraph};
+use crate::render_task::{RenderTaskCacheEntry, RenderTaskCacheEntryHandle, RenderTaskTree};
 use smallvec::SmallVec;
 use std::collections::hash_map::Entry::{self, Occupied, Vacant};
 use std::collections::hash_map::IterMut;
 use std::collections::VecDeque;
 use std::{cmp, mem};
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::os::raw::c_void;
@@ -531,21 +531,21 @@ impl ResourceCache {
     // task. If the item is already cached, the texture cache
     // handle will be returned. Otherwise, the user supplied
     // closure will be invoked to generate the render task
     // chain that is required to draw this task.
     pub fn request_render_task<F>(
         &mut self,
         key: RenderTaskCacheKey,
         gpu_cache: &mut GpuCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         user_data: Option<[f32; 3]>,
         is_opaque: bool,
         f: F,
-    ) -> RenderTaskCacheEntryHandle where F: FnOnce(&mut RenderTaskGraph) -> RenderTaskId {
+    ) -> RenderTaskCacheEntryHandle where F: FnOnce(&mut RenderTaskTree) -> RenderTaskId {
         self.cached_render_tasks.request_render_task(
             key,
             &mut self.texture_cache,
             gpu_cache,
             render_tasks,
             user_data,
             is_opaque,
             |render_task_tree| Ok(f(render_task_tree))
@@ -1372,17 +1372,17 @@ impl ResourceCache {
         }
     }
 
     pub fn request_glyphs(
         &mut self,
         mut font: FontInstance,
         glyph_keys: &[GlyphKey],
         gpu_cache: &mut GpuCache,
-        render_task_tree: &mut RenderTaskGraph,
+        render_task_tree: &mut RenderTaskTree,
     ) {
         debug_assert_eq!(self.state, State::AddResources);
 
         self.glyph_rasterizer.prepare_font(&mut font);
         self.glyph_rasterizer.request_glyphs(
             &mut self.cached_glyphs,
             font,
             glyph_keys,
@@ -1588,17 +1588,17 @@ impl ResourceCache {
         // pop the old frame and push a new one
         self.deleted_blob_keys.pop_front();
         self.deleted_blob_keys.push_back(Vec::new());
     }
 
     pub fn block_until_all_resources_added(
         &mut self,
         gpu_cache: &mut GpuCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         texture_cache_profile: &mut TextureCacheProfileCounters,
     ) {
         profile_scope!("block_until_all_resources_added");
 
         debug_assert_eq!(self.state, State::AddResources);
         self.state = State::QueryResources;
 
         self.glyph_rasterizer.resolve_glyphs(
--- a/gfx/wr/webrender/src/tiling.rs
+++ b/gfx/wr/webrender/src/tiling.rs
@@ -22,17 +22,17 @@ use crate::internal_types::{CacheTexture
 #[cfg(feature = "pathfinder")]
 use pathfinder_partitioner::mesh::Mesh;
 use crate::picture::{RecordedDirtyRegion, SurfaceInfo};
 use crate::prim_store::gradient::GRADIENT_FP_STOPS;
 use crate::prim_store::{PrimitiveStore, DeferredResolve, PrimitiveScratchBuffer};
 use crate::profiler::FrameProfileCounters;
 use crate::render_backend::{DataStores, FrameId};
 use crate::render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind};
-use crate::render_task::{BlurTask, ClearMode, GlyphTask, RenderTaskLocation, RenderTaskGraph, ScalingTask};
+use crate::render_task::{BlurTask, ClearMode, GlyphTask, RenderTaskLocation, RenderTaskTree, ScalingTask};
 use crate::resource_cache::ResourceCache;
 use std::{cmp, usize, f32, i32, mem};
 use crate::texture_allocator::{ArrayAllocationTracker, FreeRectSlice};
 
 
 const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16);
 const STYLE_MASK: i32 = 0x00FF_FF00;
 
@@ -87,17 +87,17 @@ pub trait RenderTarget {
     ) -> Self;
 
     /// Optional hook to provide additional processing for the target at the
     /// end of the build phase.
     fn build(
         &mut self,
         _ctx: &mut RenderTargetContext,
         _gpu_cache: &mut GpuCache,
-        _render_tasks: &mut RenderTaskGraph,
+        _render_tasks: &mut RenderTaskTree,
         _deferred_resolves: &mut Vec<DeferredResolve>,
         _prim_headers: &mut PrimitiveHeaders,
         _transforms: &mut TransformPalette,
         _z_generator: &mut ZBufferIdGenerator,
     ) {
     }
 
     /// Associates a `RenderTask` with this target. That task must be assigned
@@ -109,17 +109,17 @@ pub trait RenderTarget {
     /// bit of extra overhead to store the image key here and the resolve them
     /// in the build step separately.  BUT: if/when we add more texture cache
     /// target jobs, we might want to tidy this up.
     fn add_task(
         &mut self,
         task_id: RenderTaskId,
         ctx: &RenderTargetContext,
         gpu_cache: &mut GpuCache,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         clip_store: &ClipStore,
         transforms: &mut TransformPalette,
         deferred_resolves: &mut Vec<DeferredResolve>,
     );
 
     fn needs_depth(&self) -> bool;
     fn must_be_drawn(&self) -> bool;
 
@@ -196,17 +196,17 @@ impl<T: RenderTarget> RenderTargetList<T
             gpu_supports_fast_clears,
         }
     }
 
     fn build(
         &mut self,
         ctx: &mut RenderTargetContext,
         gpu_cache: &mut GpuCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         deferred_resolves: &mut Vec<DeferredResolve>,
         saved_index: Option<SavedTargetIndex>,
         prim_headers: &mut PrimitiveHeaders,
         transforms: &mut TransformPalette,
         z_generator: &mut ZBufferIdGenerator,
     ) {
         debug_assert_eq!(None, self.saved_index);
         self.saved_index = saved_index;
@@ -399,17 +399,17 @@ impl RenderTarget for ColorRenderTarget 
             batch_builder: BatchBuilder::new(),
         }
     }
 
     fn build(
         &mut self,
         ctx: &mut RenderTargetContext,
         gpu_cache: &mut GpuCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         deferred_resolves: &mut Vec<DeferredResolve>,
         prim_headers: &mut PrimitiveHeaders,
         transforms: &mut TransformPalette,
         z_generator: &mut ZBufferIdGenerator,
     ) {
         let mut merged_batches = AlphaBatchContainer::new(None, Vec::new());
 
         for task_id in &self.alpha_tasks {
@@ -473,17 +473,17 @@ impl RenderTarget for ColorRenderTarget 
         }
     }
 
     fn add_task(
         &mut self,
         task_id: RenderTaskId,
         ctx: &RenderTargetContext,
         gpu_cache: &mut GpuCache,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         _: &ClipStore,
         _: &mut TransformPalette,
         deferred_resolves: &mut Vec<DeferredResolve>,
     ) {
         let task = &render_tasks[task_id];
 
         match task.kind {
             RenderTaskKind::VerticalBlur(ref info) => {
@@ -641,17 +641,17 @@ impl RenderTarget for AlphaRenderTarget 
         }
     }
 
     fn add_task(
         &mut self,
         task_id: RenderTaskId,
         ctx: &RenderTargetContext,
         gpu_cache: &mut GpuCache,
-        render_tasks: &RenderTaskGraph,
+        render_tasks: &RenderTaskTree,
         clip_store: &ClipStore,
         transforms: &mut TransformPalette,
         _: &mut Vec<DeferredResolve>,
     ) {
         let task = &render_tasks[task_id];
         let (target_rect, _) = task.get_target_rect();
 
         match task.clear_mode {
@@ -781,17 +781,17 @@ impl TextureCacheRenderTarget {
             line_decorations: vec![],
             gradients: vec![],
         }
     }
 
     fn add_task(
         &mut self,
         task_id: RenderTaskId,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
     ) {
         let task_address = render_tasks.get_task_address(task_id);
         let src_task_address = render_tasks[task_id].children.get(0).map(|src_task_id| {
             render_tasks.get_task_address(*src_task_id)
         });
 
         let task = &mut render_tasks[task_id];
         let target_rect = task.get_target_rect();
@@ -927,17 +927,17 @@ pub enum RenderPassKind {
 /// target to do all of the rendering for that pass. See `RenderTargetList`.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderPass {
     /// The kind of pass, as well as the set of targets associated with that
     /// kind of pass.
     pub kind: RenderPassKind,
     /// The set of tasks to be performed in this pass, as indices into the
-    /// `RenderTaskGraph`.
+    /// `RenderTaskTree`.
     pub tasks: Vec<RenderTaskId>,
 }
 
 impl RenderPass {
     /// Creates a pass for the main framebuffer. There is only one of these, and
     /// it is always the last pass.
     pub fn new_main_framebuffer(
         screen_size: DeviceIntSize,
@@ -1005,17 +1005,17 @@ impl RenderPass {
     ///
     /// Among other things, this allocates output regions for each of our tasks
     /// (added via `add_render_task`) in a RenderTarget and assigns it into that
     /// target.
     pub fn build(
         &mut self,
         ctx: &mut RenderTargetContext,
         gpu_cache: &mut GpuCache,
-        render_tasks: &mut RenderTaskGraph,
+        render_tasks: &mut RenderTaskTree,
         deferred_resolves: &mut Vec<DeferredResolve>,
         clip_store: &ClipStore,
         transforms: &mut TransformPalette,
         prim_headers: &mut PrimitiveHeaders,
         z_generator: &mut ZBufferIdGenerator,
     ) {
         profile_scope!("RenderPass::build");
 
@@ -1198,17 +1198,17 @@ pub struct Frame {
     pub device_rect: DeviceIntRect,
     pub background_color: Option<ColorF>,
     pub layer: DocumentLayer,
     pub passes: Vec<RenderPass>,
     #[cfg_attr(any(feature = "capture", feature = "replay"), serde(default = "FrameProfileCounters::new", skip))]
     pub profile_counters: FrameProfileCounters,
 
     pub transform_palette: Vec<TransformData>,
-    pub render_tasks: RenderTaskGraph,
+    pub render_tasks: RenderTaskTree,
     pub prim_headers: PrimitiveHeaders,
 
     /// The GPU cache frame that the contents of Self depend on
     pub gpu_cache_frame_id: FrameId,
 
     /// List of textures that we don't know about yet
     /// from the backend thread. The render thread
     /// will use a callback to resolve these and