Transparent slices with "gaps" are too expensive
Categories
(Core :: Graphics: WebRender, defect, P3)
Tracking
()
People
(Reporter: mstange, Assigned: gw)
References
Details
Attachments
(4 files)
At the moment, transparent slices have a cost that's based on the size of their bounding box. Extra cost from transparent parts in the bounding box can easily tip the scales such that not creating a slice (and drawing the items into an existing slice) would have been cheaper.
For example, if you have two 10x10 items in two opposite corners of a 1000x1000 area, this slice adds 1000x1000 pixels of OS compositor overdraw to the window. Only 2x10x10 of that overdraw is useful, the rest is wasted memory bandwidth.
Let's say these two items are located in different tiles, and there's an entire empty tile between them. Now there are two things we can do to reduce OS compositor overdraw:
- We can discard tiles in the middle that are entirely empty.
- For the tiles that contain content, we can compute a separate clip per tile, so that the empty padding around the content of those tiles can be clipped away and no longer impacts OS compositor cost.
We were doing 1 up until bug 1604827. We have never done 2 - the clip has always been per-slice (i.e. shared between all tiles of a slice) and this has always caused unnecessary overdraw cost.
We need to bring back the ability to do 1. If we want to do 2 separately, we can file a new bug for it.
I'm going to attach a few screenshots with large red areas (from gfx.core-animation.tint-opaque
) which indicate unnecessary OS compositor overdraw from transparent gaps.
Reporter | ||
Comment 1•5 years ago
|
||
80% of the browser window is overlaid with transparent pixels from the slice that contains the URL bar at the top and the status bar at the bottom.
Reporter | ||
Comment 2•5 years ago
•
|
||
The two scrollbars are assigned to the same slice (bug?) and make a large red bounding box.
Reporter | ||
Comment 3•5 years ago
|
||
Updated•5 years ago
|
Reporter | ||
Comment 4•5 years ago
•
|
||
Example of layerization trade-offs with fixed element + scrolling
In this example I'd like to compute the "cost" of a scroll on a page with scrolled content and a fixed element.
We estimate the cost of a frame as rasterization cost + compositing cost. We express these costs as "number of pixels drawn to", as percentages of the content area.
Let's say the scrolled content has an overdraw factor of 1.3 and the fixed element is transparent and covers 20% of the content area and also has an internal overdraw of 1.3.
Case 1: One slice, scrolled
If we draw the fixed content into the opaque scrolled slice, we get the following costs:
Initial paint:
rasterization cost + compositing cost
= 1.3 * 100% + 1.3 * 20% for rasterization + 100% for OS compositing of the opaque layer
= 130% + 26% + 100% = 256%
Scroll that doesn't need new tiles:
rasterization cost + compositing cost
= 0% rasterization for the scrolled content that doesn't overlap the fixed element
+ 1.3 * 20% + 1.3 * 20% rasterization of the content that overlaps with the fixed element
+ 100% for OS compositing of the opaque layer
= 2 * 1.3 * 20% + 100% = 52% + 100% = 152%
Case 2: Two slices, one scrolled and one fixed
If we put the fixed content into a transparent fixed slice, we get the following costs:
Initial paint:
rasterization cost + compositing cost
= 1.3 * 100% + 1.3 * 20% for rasterization
+ 100% for OS compositing of the opaque layer
+ 20% for OS compositing of the transparent layer
= 130% + 26% + 100% + 20% = 276%
Scroll that doesn't need new tiles:
rasterization cost + compositing cost
= 0% rasterization for the scrolled content
+ 0% rasterization for the fixed content
+ 120% compositing
= 120%
Evaluation
One slice | Two slices | |
---|---|---|
Initial frame | 256% | 276% |
Frame with scroll | 152% | 120% |
So we pay 20% on the initial paint and save 32% per scroll. That would be worth doing!
Where do these 32% savings come from? They come from the fact that the additional compositor overdraw is less than the drawing overdraw. The "drawing overdraw" for the affected area is 2.6, and the additional "compositor overdraw" for the affected area is 1. (2.6 - 1) = 1.6, 1.6 * 20% = 32%.
So in this case, creating the slice is worth doing because 2.6 is more than 1, i.e. because the "drawing overdraw" for the area in the affected slices is larger than one.
The cost of transparent gaps
Now, what happens if we have gaps in the transparent slice? This reduces the "drawing overdraw" in the slice to something that's less than one! Let's say only 10% of the transparent slice's bounding box are covered with content, and 90% are empty. The "drawing overdraw" in those 10% is still 1.3 in our example. But the overall "drawing overdraw" in the slice is now 0.13. If we plug this number into the calculation above, we get:
(0.13 - 1) * 20% = -0.87 * 20% = -17.4%
In other words, having the separate slice increases the cost of a scroll, by a pixel count of 17.4% of the size of the content area.
As soon as the compositor needs to composite transparency, the chances that performance benefits from a separate slice go down rapidly. We should make layerization decisions in such a way that the compositor never has to touch pixels that regular drawing wouldn't touch.
Assignee | ||
Comment 5•5 years ago
|
||
I completely agree - I've noticed this myself.
I think the simplest way to solve this for now is to add a flag that is passed to the native compositor trait specifying if a tile is empty.
In this way, native compositors can:
- If using a tile-based implementation (mac + current DC impl) - take advantage of this to skip tile creation / blending completely.
- If using a virtual surface backed implementation, allocate the tile surface.
This still means paying the performance cost if using virtual surfaces, but is a quick fix / workaround for now while we work out a better long term solution. Does this seem reasonable?
Assignee | ||
Comment 6•5 years ago
|
||
I think that doing option (2) [providing a per-tile clip rect] should be quite straightforward, now that I have thought about it a bit more.
I think this will effectively solve both issues, since an empty tile could be completely skipped by the empty clip rect.
I'm going to prototype this today.
Reporter | ||
Comment 7•5 years ago
|
||
(In reply to Glenn Watson [:gw] from comment #6)
I think that doing option (2) [providing a per-tile clip rect] should be quite straightforward, now that I have thought about it a bit more.
I think this will effectively solve both issues, since an empty tile could be completely skipped by the empty clip rect.
That sounds great!
Assignee | ||
Comment 8•5 years ago
|
||
This adds support for holes within virtual surfaces. On platforms
that don't use virtual surfaces, this just works by destroying
the tile that is empty so it never gets composited.
Assignee | ||
Comment 9•5 years ago
|
||
This implements the first part - supporting empty tiles (holes) in surfaces. I'm working on the second part (per-tile clip rects to reduce pixel count further) as a follow up.
Comment 10•5 years ago
|
||
Comment 11•5 years ago
|
||
bugherder |
Updated•5 years ago
|
Description
•