New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplify the ClipId -> CST id mapping code. #2925
Conversation
Gecko try looks good. |
Pending try with the two follow up commits: |
Try still looks good 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but needs @mrobinson to review as well if they are available
@@ -1772,16 +1772,16 @@ impl ClipBatcher { | |||
) { | |||
let mut coordinate_system_id = coordinate_system_id; | |||
for work_item in clips.iter() { | |||
let info = clip_store | |||
.get_opt(&work_item.clip_sources) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: why get_opt
if we follow with expect
right away?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because (for now) we only have a weak handle here, so the freelist API doesn't guarantee it's present, but we know that it should be due to usage here. I intend to refactor how we store clip sources as part of this work.
} | ||
|
||
impl ClipSources { | ||
pub fn new(clips: Vec<ClipSource>) -> Self { | ||
pub fn new( | ||
clips: Vec<ClipSource>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could use Iterator<Item = ClipSource>
to avoid heap allocation on the client
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not clear to me how this avoids an allocation in this case - could you expand on that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function doesn't need a vec, since it goes through the elements and constructs other stuff from them. But it's currently requiring the caller to have that vec. If this function gets IntoIterator
instead, the caller may still provide a vec, or they can just construct a complex iterator (with chain()
, zip()
, etc) that is completely on the stack. IIRC, there is at least one place in code where this would be handy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you're right - I misread that it took ownership of it, missing the collect
. Although, having tried to make that change it seems to flow on to changing several other functions, so perhaps better to leave for now (since this PR doesn't actually change that code), unless I'm missing an obvious way to make this change locally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be correct to change the calling functions as well, where possible, but at the same time Vec
implements IntoIterator
so those changes are not required. I'll be happy to follow up with this refactor ;)
self.cached_clip_chain_index = Some((*id, index)); | ||
index | ||
pub fn map_spatial_node(&mut self, id: ClipId, index: SpatialNodeIndex) { | ||
debug_assert!(!self.spatial_node_map.contains_key(&id)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: could use the returned value from insert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
webrender/src/hit_test.rs
Outdated
@@ -34,6 +34,29 @@ pub struct HitTestClipNode { | |||
regions: Vec<HitTestRegion>, | |||
} | |||
|
|||
impl HitTestClipNode { | |||
fn new(node: &ClipNode, clip_store: &ClipStore) -> HitTestClipNode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: -> Self
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There are some upcoming changes which will modify how and when we store and represent clip nodes and chains. These changes are necessary to allow WR to rasterize pictures in a different coordinate space than just screen space. This patch simplifies the mapping of ClipId to array indices in the clip-scroll tree. This will make it simpler to make the changes discussed above - specifically, we can unify how we handle clip nodes with the per-primitive complex clips. The code this removes was a performance optimization to avoid hashmap lookups. I did some profiling on a number of real world sites and also on some gecko layer stress tests, and didn't find any noticeable regression from simplifying this code. However, once the work above has been completed, we could re-investigate how to optimize this mapping process, if it ever shows up in a profile. In one of the stress tests [1] for spatial and clip node creation, the code is now slightly faster with this patch (28ms vs 29ms). [1] https://mattwoodrow.github.io/dl-test/dl-test.html?count=50000&layer=inactive
@@ -56,8 +56,8 @@ pub struct ClipIdToIndexMapper { | |||
|
|||
impl ClipIdToIndexMapper { | |||
pub fn add_clip_chain(&mut self, id: ClipId, index: ClipChainIndex) { | |||
debug_assert!(!self.clip_chain_map.contains_key(&id)); | |||
self.clip_chain_map.insert(id, index); | |||
let _is_new_key = self.clip_chain_map.insert(id, index).is_none(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: let's not confuse the reader with is_none()
here and instead move it inside the assert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
If the LRU cache and non-hashing mapping aren't important to the code, then these changes simplify the code a lot. Looks good to me. |
@mrobinson Thanks for taking a look! I think it's possible we will want the non-hashing optimization back in the future (especially for stress tests), but it doesn't seem to be providing a huge win right now (I wonder if we're either hashing less than we used to, or perhaps it's not such an issue now that we are using the Fx hasher instead of Fnv?). |
@glennw It's an interesting question. It could be that this approach is still hashing quite a bit less than when we were not storing ClipScrollTree nodes in vectors and converting the ids to indexes. |
@bors-servo r=kvark,mrobinson |
📌 Commit 66ad1c4 has been approved by |
Simplify the ClipId -> CST id mapping code. There are some upcoming changes which will modify how and when we store and represent clip nodes and chains. These changes are necessary to allow WR to rasterize pictures in a different coordinate space than just screen space. This patch simplifies the mapping of ClipId to array indices in the clip-scroll tree. This will make it simpler to make the changes discussed above - specifically, we can unify how we handle clip nodes with the per-primitive complex clips. The code this removes was a performance optimization to avoid hashmap lookups. I did some profiling on a number of real world sites and also on some gecko layer stress tests, and didn't find any noticeable regression from simplifying this code. However, once the work above has been completed, we could re-investigate how to optimize this mapping process, if it ever shows up in a profile. In one of the stress tests [1] for spatial and clip node creation, the code is now slightly faster with this patch (28ms vs 29ms). [1] https://mattwoodrow.github.io/dl-test/dl-test.html?count=50000&layer=inactive <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/2925) <!-- Reviewable:end -->
☀️ Test successful - status-appveyor, status-taskcluster |
Replace heap allocation of clip-related objects with iteration This PR makes scene building faster by doing less heap allocations. r? @gankro or @gw3583 cc @gw3583 - this is a follow-up to #2925 that I figured I'd forget about if I don't do it now ;) <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/2943) <!-- Reviewable:end -->
There are some upcoming changes which will modify how and when
we store and represent clip nodes and chains. These changes are
necessary to allow WR to rasterize pictures in a different coordinate
space than just screen space.
This patch simplifies the mapping of ClipId to array indices in
the clip-scroll tree. This will make it simpler to make the
changes discussed above - specifically, we can unify how we handle
clip nodes with the per-primitive complex clips.
The code this removes was a performance optimization to avoid
hashmap lookups. I did some profiling on a number of real world
sites and also on some gecko layer stress tests, and didn't find
any noticeable regression from simplifying this code. However,
once the work above has been completed, we could re-investigate
how to optimize this mapping process, if it ever shows up in a
profile.
In one of the stress tests [1] for spatial and clip node creation,
the code is now slightly faster with this patch (28ms vs 29ms).
[1] https://mattwoodrow.github.io/dl-test/dl-test.html?count=50000&layer=inactive
This change is