diff --git a/gfx/webrender/src/clip.rs b/gfx/webrender/src/clip.rs index b5281aebfa00..86aef91e571f 100644 --- a/gfx/webrender/src/clip.rs +++ b/gfx/webrender/src/clip.rs @@ -102,7 +102,7 @@ pub struct ClipDataMarker; pub type ClipDataStore = intern::DataStore; pub type ClipDataHandle = intern::Handle; pub type ClipDataUpdateList = intern::UpdateList; -pub type ClipDataInterner = intern::Interner; +pub type ClipDataInterner = intern::Interner; // Result of comparing a clip node instance against a local rect. #[derive(Debug)] @@ -752,6 +752,20 @@ impl ClipRegion> { } } +/// 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 diff --git a/gfx/webrender/src/display_list_flattener.rs b/gfx/webrender/src/display_list_flattener.rs index 855c8e3bc14f..8c621a10abfb 100644 --- a/gfx/webrender/src/display_list_flattener.rs +++ b/gfx/webrender/src/display_list_flattener.rs @@ -13,7 +13,7 @@ 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}; @@ -25,7 +25,7 @@ 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}; @@ -799,7 +799,12 @@ impl<'a> DisplayListFlattener<'a> { 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( @@ -825,7 +830,12 @@ impl<'a> DisplayListFlattener<'a> { ) -> 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, @@ -1003,7 +1013,13 @@ impl<'a> DisplayListFlattener<'a> { 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. @@ -1326,7 +1342,10 @@ impl<'a> DisplayListFlattener<'a> { 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 @@ -1341,7 +1360,10 @@ impl<'a> DisplayListFlattener<'a> { 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 @@ -1357,7 +1379,10 @@ impl<'a> DisplayListFlattener<'a> { 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 @@ -1514,7 +1539,13 @@ impl<'a> DisplayListFlattener<'a> { ); 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, diff --git a/gfx/webrender/src/intern.rs b/gfx/webrender/src/intern.rs index a3d45d03909f..d9b0a5f0f728 100644 --- a/gfx/webrender/src/intern.rs +++ b/gfx/webrender/src/intern.rs @@ -173,28 +173,29 @@ impl ops::IndexMut> for DataStore { /// an update list of additions / removals. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct Interner { +pub struct Interner { /// Uniquely map an interning key to a handle map: FastHashMap>, /// List of free slots in the data store for re-use. free_list: Vec, - /// 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>, /// 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>, } -impl Interner where S: Eq + Hash + Clone + Debug, M: Copy + Debug { +impl Interner 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(), } } @@ -202,10 +203,14 @@ impl Interner where S: Eq + Hash + Clone + Debug, M: Copy + Debug { /// 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( &mut self, data: &S, - ) -> Handle { + f: F, + ) -> Handle 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. @@ -218,7 +223,8 @@ impl Interner where S: Eq + Hash + Clone + Debug, M: Copy + Debug { 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; @@ -229,11 +235,7 @@ impl Interner where S: Eq + Hash + Clone + Debug, M: Copy + Debug { // 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. @@ -253,6 +255,18 @@ impl Interner where S: Eq + Hash + Clone + Debug, M: Copy + Debug { // 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 } @@ -299,3 +313,13 @@ impl Interner where S: Eq + Hash + Clone + Debug, M: Copy + Debug { updates } } + +/// Retrieve the local data for an item from the interner via handle +impl ops::Index> for Interner where S: Eq + Clone + Hash + Debug, M: Copy + Debug { + type Output = D; + fn index(&self, handle: Handle) -> &D { + let item = &self.local_data[handle.index]; + assert_eq!(item.epoch, handle.epoch); + &item.data + } +} diff --git a/gfx/webrender/src/prim_store.rs b/gfx/webrender/src/prim_store.rs index 0b43332b4df6..6a646609860e 100644 --- a/gfx/webrender/src/prim_store.rs +++ b/gfx/webrender/src/prim_store.rs @@ -275,6 +275,19 @@ impl GpuCacheAddress { } } +/// 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)] @@ -315,7 +328,7 @@ pub struct PrimitiveDataMarker; pub type PrimitiveDataStore = intern::DataStore; pub type PrimitiveDataHandle = intern::Handle; pub type PrimitiveDataUpdateList = intern::UpdateList; -pub type PrimitiveDataInterner = intern::Interner; +pub type PrimitiveDataInterner = intern::Interner; // Maintains a list of opacity bindings that have been collapsed into // the color of a single primitive. This is an important optimization diff --git a/gfx/webrender_bindings/revision.txt b/gfx/webrender_bindings/revision.txt index f02cd3c1cf95..bf5b44e2b232 100644 --- a/gfx/webrender_bindings/revision.txt +++ b/gfx/webrender_bindings/revision.txt @@ -1 +1 @@ -a8817b943a2fd0038307a7432fdf5cbccf4a943e +a7052abfe8e41bcc8904cb5b3add99735fedcd1f