Bug 1558926 - Part 3: Add support for additional WebRender display list data
authorMiko Mynttinen <mikokm@gmail.com>
Mon, 27 Jan 2020 14:18:49 +0000
changeset 511862 8ef0c5a62e56ba9a570d53e7a1616d912024420d
parent 511861 8c51225cdfa3e48af497a8d17655e956247abdd7
child 511863 96290c1e1a5fa34484ef328b6f3c12b814efb45c
push id106076
push usermikokm@gmail.com
push dateMon, 27 Jan 2020 14:27:15 +0000
treeherderautoland@84e3a48f0843 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1558926
milestone74.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1558926 - Part 3: Add support for additional WebRender display list data Differential Revision: https://phabricator.services.mozilla.com/D60759
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/wr/webrender_api/src/display_list.rs
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -1390,16 +1390,32 @@ void DisplayListBuilder::PushBoxShadow(
     const wr::BorderRadius& aBorderRadius,
     const wr::BoxShadowClipMode& aClipMode) {
   wr_dp_push_box_shadow(mWrState, aRect, MergeClipLeaf(aClip),
                         aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
                         aBoxBounds, aOffset, aColor, aBlurRadius, aSpreadRadius,
                         aBorderRadius, aClipMode);
 }
 
+void DisplayListBuilder::ReuseItem(wr::ItemKey aKey) {
+  wr_dp_push_reuse_item(mWrState, aKey);
+}
+
+void DisplayListBuilder::StartCachedItem(wr::ItemKey aKey) {
+  wr_dp_start_cached_item(mWrState, aKey);
+}
+
+void DisplayListBuilder::EndCachedItem(wr::ItemKey aKey) {
+  wr_dp_end_cached_item(mWrState, aKey);
+}
+
+void DisplayListBuilder::SetDisplayListCacheSize(const size_t aCacheSize) {
+  wr_dp_set_cache_size(mWrState, aCacheSize);
+}
+
 Maybe<layers::ScrollableLayerGuid::ViewID>
 DisplayListBuilder::GetContainingFixedPosScrollTarget(
     const ActiveScrolledRoot* aAsr) {
   return mActiveFixedPosTracker
              ? mActiveFixedPosTracker->GetScrollTargetForASR(aAsr)
              : Nothing();
 }
 
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -395,16 +395,17 @@ class DisplayListBuilder final {
                      RenderRoot aRenderRoot = RenderRoot::Default);
   DisplayListBuilder(DisplayListBuilder&&) = default;
 
   ~DisplayListBuilder();
 
   void Save();
   void Restore();
   void ClearSave();
+
   usize Dump(usize aIndent, const Maybe<usize>& aStart,
              const Maybe<usize>& aEnd);
 
   void Finalize(wr::LayoutSize& aOutContentSizes,
                 wr::BuiltDisplayList& aOutDisplayList);
   void Finalize(layers::RenderRootDisplayListData& aOutTransaction);
 
   RenderRoot GetRenderRoot() const { return mRenderRoot; }
@@ -573,20 +574,31 @@ class DisplayListBuilder final {
   void PushBoxShadow(const wr::LayoutRect& aRect, const wr::LayoutRect& aClip,
                      bool aIsBackfaceVisible, const wr::LayoutRect& aBoxBounds,
                      const wr::LayoutVector2D& aOffset,
                      const wr::ColorF& aColor, const float& aBlurRadius,
                      const float& aSpreadRadius,
                      const wr::BorderRadius& aBorderRadius,
                      const wr::BoxShadowClipMode& aClipMode);
 
+  void StartCachedItem(wr::ItemKey aKey);
+  void EndCachedItem(wr::ItemKey aKey);
+  void ReuseItem(wr::ItemKey aKey);
+  void SetDisplayListCacheSize(const size_t aCacheSize);
+
   uint64_t CurrentClipChainId() const {
     return mCurrentSpaceAndClipChain.clip_chain;
   }
 
+  const wr::WrSpaceAndClipChain& CurrentSpaceAndClipChain() const {
+    return mCurrentSpaceAndClipChain;
+  }
+
+  const wr::PipelineId& CurrentPipelineId() const { return mPipelineId; }
+
   // Checks to see if the innermost enclosing fixed pos item has the same
   // ASR. If so, it returns the scroll target for that fixed-pos item.
   // Otherwise, it returns Nothing().
   Maybe<layers::ScrollableLayerGuid::ViewID> GetContainingFixedPosScrollTarget(
       const ActiveScrolledRoot* aAsr);
 
   Maybe<SideBits> GetContainingFixedPosSideBits(const ActiveScrolledRoot* aAsr);
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -3479,16 +3479,54 @@ pub extern "C" fn wr_dp_push_box_shadow(
                           color,
                           blur_radius,
                           spread_radius,
                           border_radius,
                           clip_mode);
 }
 
 #[no_mangle]
+pub extern "C" fn wr_dp_start_cached_item(state: &mut WrState,
+                                          key: ItemKey) {
+    debug_assert!(state.current_item_key.is_none(), "Nested item keys");
+    state.current_item_key = Some(key);
+
+    state.frame_builder.dl_builder.start_extra_data_chunk();
+}
+
+#[no_mangle]
+pub extern "C" fn wr_dp_end_cached_item(state: &mut WrState,
+                                        key: ItemKey) {
+    // Avoid pushing reuse item marker when no extra data was written.
+    if state.frame_builder.dl_builder.end_extra_data_chunk() > 0 {
+        state.frame_builder.dl_builder.push_reuse_item(key);
+    }
+
+    debug_assert!(state.current_item_key.is_some(), "Nested item keys");
+    state.current_item_key = None;
+}
+
+#[no_mangle]
+pub extern "C" fn wr_dp_push_reuse_item(state: &mut WrState,
+                                        key: ItemKey) {
+    state.frame_builder
+        .dl_builder
+        .push_reuse_item(key);
+}
+
+#[no_mangle]
+pub extern "C" fn wr_dp_set_cache_size(state: &mut WrState,
+                                       cache_size: usize) {
+    state.frame_builder
+        .dl_builder
+        .set_cache_size(cache_size);
+}
+
+
+#[no_mangle]
 pub extern "C" fn wr_dump_display_list(state: &mut WrState,
                                        indent: usize,
                                        start: *const usize,
                                        end: *const usize) -> usize {
     let start = unsafe { start.as_ref().cloned() };
     let end = unsafe { end.as_ref().cloned() };
     let range = Range { start, end };
     let mut sink = Cursor::new(Vec::new());
--- a/gfx/wr/webrender_api/src/display_list.rs
+++ b/gfx/wr/webrender_api/src/display_list.rs
@@ -13,16 +13,17 @@ use serde::{Deserialize, Serialize};
 use std::io::{stdout, Write};
 use std::marker::PhantomData;
 use std::ops::Range;
 use std::mem;
 use std::collections::HashMap;
 use time::precise_time_ns;
 // local imports
 use crate::display_item as di;
+use crate::display_item_cache::*;
 use crate::api::{PipelineId, PropertyBinding};
 use crate::gradient_builder::GradientBuilder;
 use crate::color::ColorF;
 use crate::font::{FontInstanceKey, GlyphInstance, GlyphOptions};
 use crate::image::{ColorDepth, ImageKey};
 use crate::units::*;
 
 
@@ -125,21 +126,28 @@ pub struct BuiltDisplayListDescriptor {
     /// The second IPC time stamp: after serialization
     builder_finish_time: u64,
     /// The third IPC time stamp: just before sending
     send_start_time: u64,
     /// The amount of clipping nodes created while building this display list.
     total_clip_nodes: usize,
     /// The amount of spatial nodes created while building this display list.
     total_spatial_nodes: usize,
+    /// The size of the cache for this display list.
+    cache_size: usize,
+    /// The offset for additional display list data.
+    extra_data_offset: usize,
 }
 
+impl BuiltDisplayListDescriptor {}
+
 pub struct BuiltDisplayListIter<'a> {
     list: &'a BuiltDisplayList,
     data: &'a [u8],
+    cache: Option<&'a DisplayItemCache>,
     cur_item: di::DisplayItem,
     cur_stops: ItemRange<'a, di::GradientStop>,
     cur_glyphs: ItemRange<'a, GlyphInstance>,
     cur_filters: ItemRange<'a, di::FilterOp>,
     cur_filter_data: Vec<TempFilterData<'a>>,
     cur_filter_primitives: ItemRange<'a, di::FilterPrimitive>,
     cur_clip_chain_items: ItemRange<'a, di::ClipId>,
     cur_complex_clip: ItemRange<'a, di::ComplexClipRegion>,
@@ -227,35 +235,36 @@ enum Peek {
 #[derive(Clone)]
 pub struct AuxIter<'a, T> {
     item: T,
     data: &'a [u8],
     size: usize,
 //    _boo: PhantomData<T>,
 }
 
-impl BuiltDisplayListDescriptor {}
-
 impl BuiltDisplayList {
     pub fn from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> Self {
         BuiltDisplayList { data, descriptor }
     }
 
     pub fn into_data(mut self) -> (Vec<u8>, BuiltDisplayListDescriptor) {
         self.descriptor.send_start_time = precise_time_ns();
         (self.data, self.descriptor)
     }
 
     pub fn data(&self) -> &[u8] {
         &self.data[..]
     }
 
-    // Currently redundant with data, but may be useful if we add extra data to dl
     pub fn item_slice(&self) -> &[u8] {
-        &self.data[..]
+        &self.data[..self.descriptor.extra_data_offset]
+    }
+
+    pub fn extra_slice(&self) -> &[u8] {
+        &self.data[self.descriptor.extra_data_offset..]
     }
 
     pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
         &self.descriptor
     }
 
     pub fn times(&self) -> (u64, u64, u64) {
         (
@@ -269,17 +278,32 @@ impl BuiltDisplayList {
         self.descriptor.total_clip_nodes
     }
 
     pub fn total_spatial_nodes(&self) -> usize {
         self.descriptor.total_spatial_nodes
     }
 
     pub fn iter(&self) -> BuiltDisplayListIter {
-        BuiltDisplayListIter::new(self)
+        BuiltDisplayListIter::new(self, self.item_slice(), None)
+    }
+
+    pub fn extra_data_iter(&self) -> BuiltDisplayListIter {
+        BuiltDisplayListIter::new(self, self.extra_slice(), None)
+    }
+
+    pub fn iter_with_cache<'a>(
+        &'a self,
+        cache: &'a DisplayItemCache
+    ) -> BuiltDisplayListIter<'a> {
+        BuiltDisplayListIter::new(self, self.item_slice(), Some(cache))
+    }
+
+    pub fn cache_size(&self) -> usize {
+        self.descriptor.cache_size
     }
 }
 
 /// Returns the byte-range the slice occupied.
 fn skip_slice<'a, T: peek_poke::Peek>(data: &mut &'a [u8]) -> ItemRange<'a, T> {
     let mut skip_offset = 0usize;
     *data = peek_from_slice(data, &mut skip_offset);
     let (skip, rest) = data.split_at(skip_offset);
@@ -289,24 +313,25 @@ fn skip_slice<'a, T: peek_poke::Peek>(da
 
     ItemRange {
         bytes: skip,
         _boo: PhantomData,
     }
 }
 
 impl<'a> BuiltDisplayListIter<'a> {
-    pub fn new(list: &'a BuiltDisplayList) -> Self {
-        Self::new_with_list_and_data(list, list.item_slice())
-    }
-
-    pub fn new_with_list_and_data(list: &'a BuiltDisplayList, data: &'a [u8]) -> Self {
-        BuiltDisplayListIter {
+    pub fn new(
+        list: &'a BuiltDisplayList,
+        data: &'a [u8],
+        cache: Option<&'a DisplayItemCache>,
+    ) -> Self {
+        Self {
             list,
             data,
+            cache,
             cur_item: di::DisplayItem::PopStackingContext,
             cur_stops: ItemRange::default(),
             cur_glyphs: ItemRange::default(),
             cur_filters: ItemRange::default(),
             cur_filter_data: Vec::new(),
             cur_filter_primitives: ItemRange::default(),
             cur_clip_chain_items: ItemRange::default(),
             cur_complex_clip: ItemRange::default(),
@@ -757,25 +782,28 @@ impl<'de> Deserialize<'de> for BuiltDisp
             // the aux data is serialized after the item, hence the temporary
             data.extend(temp.drain(..));
         }
 
         // Add `DisplayItem::max_size` zone of zeroes to the end of display list
         // so there is at least this amount available in the display list during
         // serialization.
         ensure_red_zone::<di::DisplayItem>(&mut data);
+        let extra_data_offset = data.len();
 
         Ok(BuiltDisplayList {
             data,
             descriptor: BuiltDisplayListDescriptor {
                 builder_start_time: 0,
                 builder_finish_time: 1,
                 send_start_time: 0,
                 total_clip_nodes,
                 total_spatial_nodes,
+                extra_data_offset,
+                cache_size: 0,
             },
         })
     }
 }
 
 #[derive(Clone, Debug)]
 pub struct SaveState {
     dl_len: usize,
@@ -783,25 +811,32 @@ pub struct SaveState {
     next_spatial_index: usize,
     next_clip_chain_id: u64,
 }
 
 #[derive(Clone)]
 pub struct DisplayListBuilder {
     pub data: Vec<u8>,
     pub pipeline_id: PipelineId,
+
+    extra_data: Vec<u8>,
+    extra_data_chunk_len: usize,
+    writing_extra_data_chunk: bool,
+
     next_clip_index: usize,
     next_spatial_index: usize,
     next_clip_chain_id: u64,
     builder_start_time: u64,
 
     /// The size of the content of this display list. This is used to allow scrolling
     /// outside the bounds of the display list items themselves.
     content_size: LayoutSize,
     save_state: Option<SaveState>,
+
+    cache_size: usize,
 }
 
 impl DisplayListBuilder {
     pub fn new(pipeline_id: PipelineId, content_size: LayoutSize) -> Self {
         Self::with_capacity(pipeline_id, content_size, 0)
     }
 
     pub fn with_capacity(
@@ -809,22 +844,28 @@ impl DisplayListBuilder {
         content_size: LayoutSize,
         capacity: usize,
     ) -> Self {
         let start_time = precise_time_ns();
 
         DisplayListBuilder {
             data: Vec::with_capacity(capacity),
             pipeline_id,
+
+            extra_data: Vec::new(),
+            extra_data_chunk_len: 0,
+            writing_extra_data_chunk: false,
+
             next_clip_index: FIRST_CLIP_NODE_INDEX,
             next_spatial_index: FIRST_SPATIAL_NODE_INDEX,
             next_clip_chain_id: 0,
             builder_start_time: start_time,
             content_size,
             save_state: None,
+            cache_size: 0,
         }
     }
 
     /// Return the content size for this display list
     pub fn content_size(&self) -> LayoutSize {
         self.content_size
     }
 
@@ -886,37 +927,45 @@ impl DisplayListBuilder {
     where
         W: Write
     {
         let mut temp = BuiltDisplayList::default();
         mem::swap(&mut temp.data, &mut self.data);
 
         let mut index: usize = 0;
         {
-            let mut iter = BuiltDisplayListIter::new(&temp);
+            let mut iter = temp.iter();
             while let Some(item) = iter.next_raw() {
                 if index >= range.start.unwrap_or(0) && range.end.map_or(true, |e| index < e) {
                     writeln!(sink, "{}{:?}", "  ".repeat(indent), item.item()).unwrap();
                 }
                 index += 1;
             }
         }
 
         self.data = temp.data;
         index
     }
 
+    fn active_buffer(&mut self) -> &mut Vec<u8> {
+        if self.writing_extra_data_chunk {
+            &mut self.extra_data
+        } else {
+            &mut self.data
+        }
+    }
+
     /// Add an item to the display list.
     ///
     /// NOTE: It is usually preferable to use the specialized methods to push
     /// display items. Pushing unexpected or invalid items here may
     /// result in WebRender panicking or behaving in unexpected ways.
     #[inline]
     pub fn push_item(&mut self, item: &di::DisplayItem) {
-        poke_into_vec(item, &mut self.data);
+        poke_into_vec(item, self.active_buffer());
     }
 
     fn push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I)
     where
         I: IntoIterator,
         I::IntoIter: ExactSizeIterator,
         I::Item: Poke,
     {
@@ -952,17 +1001,17 @@ impl DisplayListBuilder {
     /// NOTE: Pushing unexpected or invalid items to the display list
     /// may result in panic and confusion.
     pub fn push_iter<I>(&mut self, iter: I)
     where
         I: IntoIterator,
         I::IntoIter: ExactSizeIterator,
         I::Item: Poke,
     {
-        Self::push_iter_impl(&mut self.data, iter);
+        Self::push_iter_impl(self.active_buffer(), iter);
     }
 
     pub fn push_rect(
         &mut self,
         common: &di::CommonItemProperties,
         color: ColorF,
     ) {
         let item = di::DisplayItem::Rectangle(di::RectangleDisplayItem {
@@ -1541,34 +1590,68 @@ impl DisplayListBuilder {
         });
         self.push_item(&item);
     }
 
     pub fn pop_all_shadows(&mut self) {
         self.push_item(&di::DisplayItem::PopAllShadows);
     }
 
+    pub fn start_extra_data_chunk(&mut self) {
+        self.writing_extra_data_chunk = true;
+        self.extra_data_chunk_len = self.extra_data.len();
+    }
+
+    // Returns the amount of bytes written to extra data buffer.
+    pub fn end_extra_data_chunk(&mut self) -> usize {
+        self.writing_extra_data_chunk = false;
+        self.extra_data.len() - self.extra_data_chunk_len
+    }
+
+    pub fn push_reuse_item(
+        &mut self,
+        key: di::ItemKey,
+    ) {
+        let item = di::DisplayItem::ReuseItem(key);
+        self.push_item(&item);
+    }
+
+    pub fn set_cache_size(
+        &mut self,
+        cache_size: usize,
+    ) {
+        self.cache_size = cache_size;
+    }
+
     pub fn finalize(mut self) -> (PipelineId, LayoutSize, BuiltDisplayList) {
         assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save");
 
         // Add `DisplayItem::max_size` zone of zeroes to the end of display list
         // so there is at least this amount available in the display list during
         // serialization.
         ensure_red_zone::<di::DisplayItem>(&mut self.data);
 
+        let extra_data_offset = self.data.len();
+
+        if self.extra_data.len() > 0 {
+            ensure_red_zone::<di::DisplayItem>(&mut self.extra_data);
+            self.data.extend(self.extra_data);
+        }
+
         let end_time = precise_time_ns();
-
         (
             self.pipeline_id,
             self.content_size,
             BuiltDisplayList {
                 descriptor: BuiltDisplayListDescriptor {
                     builder_start_time: self.builder_start_time,
                     builder_finish_time: end_time,
                     send_start_time: 0,
                     total_clip_nodes: self.next_clip_index,
                     total_spatial_nodes: self.next_spatial_index,
+                    cache_size: self.cache_size,
+                    extra_data_offset,
                 },
                 data: self.data,
             },
         )
     }
 }