Bug 1501325 - Update webrender to a7052abfe8e41bcc8904cb5b3add99735fedcd1f. r=kats
authorWR Updater Bot <graphics-team@mozilla.staktrace.com>
Tue, 23 Oct 2018 15:26:49 +0000
changeset 490944 a4f2759633f74ba30a73a35bc5e32fbaf0f7c0a0
parent 490943 be341c9164faf9dadb373ca93e0a67637647b86e
child 490945 1944104ccd9dfe6f8db7a698a5847240274611ee
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewerskats
bugs1501325
milestone65.0a1
Bug 1501325 - Update webrender to a7052abfe8e41bcc8904cb5b3add99735fedcd1f. r=kats Differential Revision: https://phabricator.services.mozilla.com/D9541
gfx/webrender/src/clip.rs
gfx/webrender/src/display_list_flattener.rs
gfx/webrender/src/intern.rs
gfx/webrender/src/prim_store.rs
gfx/webrender_bindings/revision.txt
--- a/gfx/webrender/src/clip.rs
+++ b/gfx/webrender/src/clip.rs
@@ -97,17 +97,17 @@ use util::{extract_inner_rect_safe, proj
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Clone, Copy, Debug)]
 pub struct ClipDataMarker;
 
 pub type ClipDataStore = intern::DataStore<ClipItemKey, ClipNode, ClipDataMarker>;
 pub type ClipDataHandle = intern::Handle<ClipDataMarker>;
 pub type ClipDataUpdateList = intern::UpdateList<ClipItemKey>;
-pub type ClipDataInterner = intern::Interner<ClipItemKey, ClipDataMarker>;
+pub type ClipDataInterner = intern::Interner<ClipItemKey, ClipItemSceneData, ClipDataMarker>;
 
 // Result of comparing a clip node instance against a local rect.
 #[derive(Debug)]
 enum ClipResult {
     // The clip does not affect the region at all.
     Accept,
     // The clip prevents the region from being drawn.
     Reject,
@@ -747,16 +747,30 @@ impl ClipRegion<Option<ComplexClipRegion
         ClipRegion {
             main: local_clip.translate(reference_frame_relative_offset),
             image_mask: None,
             complex_clips: None,
         }
     }
 }
 
+/// The information about an interned clip item that
+/// is stored and available in the scene builder
+/// thread.
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct ClipItemSceneData {
+    // TODO(gw): We will store the local clip rect of
+    //           the clip item here. This will allow
+    //           calculation of the local clip rect
+    //           for a primitive and its clip chain
+    //           during scene building, rather than
+    //           frame building.
+}
+
 // The ClipItemKey is a hashable representation of the contents
 // of a clip item. It is used during interning to de-duplicate
 // clip nodes between frames and display lists. This allows quick
 // comparison of clip node equality by handle, and also allows
 // the uploaded GPU cache handle to be retained between display lists.
 // TODO(gw): Maybe we should consider constructing these directly
 //           in the DL builder?
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
--- a/gfx/webrender/src/display_list_flattener.rs
+++ b/gfx/webrender/src/display_list_flattener.rs
@@ -8,29 +8,29 @@ use api::{ClipId, ColorF, ComplexClipReg
 use api::{DisplayItemRef, ExtendMode, ExternalScrollId};
 use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, GradientStop};
 use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, ColorDepth};
 use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
 use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId};
 use api::{PropertyBinding, ReferenceFrame, RepeatMode, ScrollFrameDisplayItem, ScrollSensitivity};
 use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
 use api::{ClipMode, TransformStyle, YuvColorSpace, YuvData};
-use clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore};
+use clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore, ClipItemSceneData};
 use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex};
 use euclid::vec2;
 use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
 use glyph_rasterizer::FontInstance;
 use gpu_cache::GpuCacheHandle;
 use gpu_types::BrushFlags;
 use hit_test::{HitTestingItem, HitTestingRun};
 use image::simplify_repeated_primitive;
 use internal_types::{FastHashMap, FastHashSet};
 use picture::{Picture3DContext, PictureCompositeMode, PictureIdGenerator, PicturePrimitive};
 use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, PrimitiveInstance};
-use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveOpacity, PrimitiveKey};
+use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveOpacity, PrimitiveKey, PrimitiveSceneData};
 use prim_store::{BorderSource, BrushSegment, BrushSegmentVec, PrimitiveContainer, PrimitiveDataHandle, PrimitiveStore};
 use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitive, PictureIndex};
 use render_backend::{DocumentView};
 use resource_cache::{FontInstanceMap, ImageRequest};
 use scene::{Scene, ScenePipeline, StackingContextHelpers};
 use scene_builder::DocumentResources;
 use spatial_node::{StickyFrameInfo};
 use std::{f32, mem};
@@ -794,17 +794,22 @@ impl<'a> DisplayListFlattener<'a> {
         if clip_items.is_empty() {
             parent_clip_chain_id
         } else {
             let mut clip_chain_id = parent_clip_chain_id;
 
             for item in clip_items {
                 // Intern this clip item, and store the handle
                 // in the clip chain node.
-                let handle = self.resources.clip_interner.intern(&item);
+                let handle = self.resources
+                    .clip_interner
+                    .intern(&item, || {
+                        ClipItemSceneData {
+                        }
+                    });
 
                 clip_chain_id = self.clip_store
                                     .add_clip_chain_node(
                                         handle,
                                         spatial_node_index,
                                         clip_chain_id,
                                     );
             }
@@ -820,17 +825,22 @@ impl<'a> DisplayListFlattener<'a> {
         &mut self,
         info: &LayoutPrimitiveInfo,
         clip_chain_id: ClipChainId,
         spatial_node_index: SpatialNodeIndex,
         container: PrimitiveContainer,
     ) -> PrimitiveInstance {
         let prim_key = PrimitiveKey::new(info.is_backface_visible);
 
-        let prim_data_handle = self.resources.prim_interner.intern(&prim_key);
+        let prim_data_handle = self.resources
+            .prim_interner
+            .intern(&prim_key, || {
+                PrimitiveSceneData {
+                }
+            });
 
         let prim_index = self.prim_store.add_primitive(
             &info.rect,
             &info.clip_rect,
             container,
         );
 
         PrimitiveInstance::new(
@@ -998,17 +1008,23 @@ impl<'a> DisplayListFlattener<'a> {
 
         // Force an intermediate surface if the stacking context
         // has a clip node. In the future, we may decide during
         // prepare step to skip the intermediate surface if the
         // clip node doesn't affect the stacking context rect.
         let should_isolate = clipping_node.is_some();
 
         let prim_key = PrimitiveKey::new(is_backface_visible);
-        let primitive_data_handle = self.resources.prim_interner.intern(&prim_key);
+        let primitive_data_handle = self.resources
+            .prim_interner
+            .intern(&prim_key, || {
+                PrimitiveSceneData {
+                }
+            }
+        );
 
         // Push the SC onto the stack, so we know how to handle things in
         // pop_stacking_context.
         self.sc_stack.push(FlattenedStackingContext {
             primitives: Vec::new(),
             pipeline_id,
             primitive_data_handle,
             requested_raster_space,
@@ -1321,48 +1337,57 @@ impl<'a> DisplayListFlattener<'a> {
         // handle to a clip chain node, parented to form a chain.
         // TODO(gw): We could re-structure this to share some of the
         //           interning and chaining code.
 
         // Build the clip sources from the supplied region.
         let handle = self
             .resources
             .clip_interner
-            .intern(&ClipItemKey::rectangle(clip_region.main, ClipMode::Clip));
+            .intern(&ClipItemKey::rectangle(clip_region.main, ClipMode::Clip), || {
+                ClipItemSceneData {
+                }
+            });
 
         parent_clip_chain_index = self
             .clip_store
             .add_clip_chain_node(
                 handle,
                 spatial_node,
                 parent_clip_chain_index,
             );
         clip_count += 1;
 
         if let Some(ref image_mask) = clip_region.image_mask {
             let handle = self
                 .resources
                 .clip_interner
-                .intern(&ClipItemKey::image_mask(image_mask));
+                .intern(&ClipItemKey::image_mask(image_mask), || {
+                    ClipItemSceneData {
+                    }
+                });
 
             parent_clip_chain_index = self
                 .clip_store
                 .add_clip_chain_node(
                     handle,
                     spatial_node,
                     parent_clip_chain_index,
                 );
             clip_count += 1;
         }
 
         for region in clip_region.complex_clips {
             let handle = self
                 .resources
                 .clip_interner
-                .intern(&ClipItemKey::rounded_rect(region.rect, region.radii, region.mode));
+                .intern(&ClipItemKey::rounded_rect(region.rect, region.radii, region.mode), || {
+                    ClipItemSceneData {
+                    }
+                });
 
             parent_clip_chain_index = self
                 .clip_store
                 .add_clip_chain_node(
                     handle,
                     spatial_node,
                     parent_clip_chain_index,
                 );
@@ -1509,17 +1534,23 @@ impl<'a> DisplayListFlattener<'a> {
                         let shadow_prim = BrushPrimitive::new_picture(shadow_pic_index);
                         let shadow_prim_index = self.prim_store.add_primitive(
                             &LayoutRect::zero(),
                             &max_clip,
                             PrimitiveContainer::Brush(shadow_prim),
                         );
 
                         let shadow_prim_key = PrimitiveKey::new(true);
-                        let shadow_prim_data_handle = self.resources.prim_interner.intern(&shadow_prim_key);
+                        let shadow_prim_data_handle = self.resources
+                            .prim_interner
+                            .intern(&shadow_prim_key, || {
+                                PrimitiveSceneData {
+                                }
+                            }
+                        );
 
                         let shadow_prim_instance = PrimitiveInstance::new(
                             shadow_prim_index,
                             shadow_prim_data_handle,
                             pending_shadow.clip_and_scroll.clip_chain_id,
                             pending_shadow.clip_and_scroll.spatial_node_index,
                         );
 
--- a/gfx/webrender/src/intern.rs
+++ b/gfx/webrender/src/intern.rs
@@ -168,77 +168,79 @@ impl<S, T, M> ops::IndexMut<Handle<M>> f
 
 /// The main interning data structure. This lives in the
 /// scene builder thread, and handles hashing and interning
 /// unique data structures. It also manages a free-list for
 /// the items in the data store, which is synchronized via
 /// an update list of additions / removals.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-pub struct Interner<S : Eq + Hash + Clone + Debug, M> {
+pub struct Interner<S : Eq + Hash + Clone + Debug, D, M> {
     /// Uniquely map an interning key to a handle
     map: FastHashMap<S, Handle<M>>,
     /// List of free slots in the data store for re-use.
     free_list: Vec<usize>,
-    /// The next index to append items to if free-list is empty.
-    next_index: usize,
     /// Pending list of updates that need to be applied.
     updates: Vec<Update<S>>,
     /// The current epoch for the interner.
     current_epoch: Epoch,
+    /// The information associated with each interned
+    /// item that can be accessed by the interner.
+    local_data: Vec<Item<D>>,
 }
 
-impl<S, M> Interner<S, M> where S: Eq + Hash + Clone + Debug, M: Copy + Debug {
+impl<S, D, M> Interner<S, D, M> where S: Eq + Hash + Clone + Debug, M: Copy + Debug {
     /// Construct a new interner
     pub fn new() -> Self {
         Interner {
             map: FastHashMap::default(),
             free_list: Vec::new(),
-            next_index: 0,
             updates: Vec::new(),
             current_epoch: Epoch(1),
+            local_data: Vec::new(),
         }
     }
 
     /// Intern a data structure, and return a handle to
     /// that data. The handle can then be stored in the
     /// frame builder, and safely accessed via the data
     /// store that lives in the frame builder thread.
-    pub fn intern(
+    /// The provided closure is invoked to build the
+    /// local data about an interned structure if the
+    /// key isn't already interned.
+    pub fn intern<F>(
         &mut self,
         data: &S,
-    ) -> Handle<M> {
+        f: F,
+    ) -> Handle<M> where F: FnOnce() -> D {
         // Use get_mut rather than entry here to avoid
         // cloning the (sometimes large) key in the common
         // case, where the data already exists in the interner.
         if let Some(handle) = self.map.get_mut(data) {
             // Update the epoch in the data store. This
             // is not strictly needed for correctness, but
             // is used to ensure items are only accessed
             // via valid handles.
             if handle.epoch != self.current_epoch {
                 self.updates.push(Update {
                     index: handle.index,
                     kind: UpdateKind::UpdateEpoch,
-                })
+                });
+                self.local_data[handle.index].epoch = self.current_epoch;
             }
             handle.epoch = self.current_epoch;
             return *handle;
         }
 
         // We need to intern a new data item. First, find out
         // if there is a spare slot in the free-list that we
         // can use. Otherwise, append to the end of the list.
         let index = match self.free_list.pop() {
             Some(index) => index,
-            None => {
-                let index = self.next_index;
-                self.next_index += 1;
-                index
-            }
+            None => self.local_data.len(),
         };
 
         // Add a pending update to insert the new data.
         self.updates.push(Update {
             index,
             kind: UpdateKind::Insert(data.clone()),
         });
 
@@ -248,16 +250,28 @@ impl<S, M> Interner<S, M> where S: Eq + 
             epoch: self.current_epoch,
             _marker: PhantomData,
         };
 
         // Store this handle so the next time it is
         // interned, it gets re-used.
         self.map.insert(data.clone(), handle);
 
+        // Create the local data for this item that is
+        // being interned.
+        let local_item = Item {
+            epoch: self.current_epoch,
+            data: f(),
+        };
+        if self.local_data.len() == index {
+            self.local_data.push(local_item);
+        } else {
+            self.local_data[index] = local_item;
+        }
+
         handle
     }
 
     /// Retrieve the pending list of updates for an interner
     /// that need to be applied to the data store. Also run
     /// a GC step that removes old entries.
     pub fn end_frame_and_get_pending_updates(&mut self) -> UpdateList<S> {
         let mut updates = mem::replace(&mut self.updates, Vec::new());
@@ -294,8 +308,18 @@ impl<S, M> Interner<S, M> where S: Eq + 
         };
 
         // Begin the next epoch
         self.current_epoch = Epoch(self.current_epoch.0 + 1);
 
         updates
     }
 }
+
+/// Retrieve the local data for an item from the interner via handle
+impl<S, D, M> ops::Index<Handle<M>> for Interner<S, D, M> where S: Eq + Clone + Hash + Debug, M: Copy + Debug {
+    type Output = D;
+    fn index(&self, handle: Handle<M>) -> &D {
+        let item = &self.local_data[handle.index];
+        assert_eq!(item.epoch, handle.epoch);
+        &item.data
+    }
+}
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -270,16 +270,29 @@ impl GpuCacheAddress {
     pub fn as_int(&self) -> i32 {
         // TODO(gw): Temporarily encode GPU Cache addresses as a single int.
         //           In the future, we can change the PrimitiveInstanceData struct
         //           to use 2x u16 for the vertex attribute instead of an i32.
         self.v as i32 * MAX_VERTEX_TEXTURE_WIDTH as i32 + self.u as i32
     }
 }
 
+/// The information about an interned primitive that
+/// is stored and available in the scene builder
+/// thread.
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct PrimitiveSceneData {
+    // TODO(gw): We will store the local clip rect of
+    //           the primitive here. This will allow
+    //           fast calculation of the tight local
+    //           bounding rect of a primitive during
+    //           picture traversal.
+}
+
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct PrimitiveKey {
     pub is_backface_visible: bool,
 }
 
 impl PrimitiveKey {
@@ -310,17 +323,17 @@ impl From<PrimitiveKey> for PrimitiveTem
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Clone, Copy, Debug)]
 pub struct PrimitiveDataMarker;
 
 pub type PrimitiveDataStore = intern::DataStore<PrimitiveKey, PrimitiveTemplate, PrimitiveDataMarker>;
 pub type PrimitiveDataHandle = intern::Handle<PrimitiveDataMarker>;
 pub type PrimitiveDataUpdateList = intern::UpdateList<PrimitiveKey>;
-pub type PrimitiveDataInterner = intern::Interner<PrimitiveKey, PrimitiveDataMarker>;
+pub type PrimitiveDataInterner = intern::Interner<PrimitiveKey, PrimitiveSceneData, PrimitiveDataMarker>;
 
 // Maintains a list of opacity bindings that have been collapsed into
 // the color of a single primitive. This is an important optimization
 // that avoids allocating an intermediate surface for most common
 // uses of opacity filters.
 #[derive(Debug)]
 pub struct OpacityBinding {
     bindings: Vec<PropertyBinding<f32>>,
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-a8817b943a2fd0038307a7432fdf5cbccf4a943e
+a7052abfe8e41bcc8904cb5b3add99735fedcd1f