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
WIP: API to track damage rectangles #21009
Conversation
7a54b54
to
ded66c2
Compare
matrix.preTranslate(x,y) is identical to matrix.setConcat(matrix, SkMatrix::Translate(x,y));
0519e1f
to
fc8fffc
Compare
Damage rectangle can be determined by providing optional FrameDamage argument to CompositorContext::ScopedFrame::Render
fc8fffc
to
f1b22b3
Compare
|
||
for (auto i = preroll_context.mutators_stack.Begin(); | ||
i != preroll_context.mutators_stack.End(); ++i) { | ||
auto type = (*i)->GetType(); |
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.
A performance idea. Rather than keep the mutators in a stack, keep them in a manually linked list starting from most recent. This loop then becomes e.mutators = preroll_context.mutators
. No copy is needed because each chain will be unique even if future nodes mutate preroll_context.mutators
and once a linked-list-mutator is added to the chain, its next pointer never changes. It can be popped, and another mutator can be added in its place, but it will never point at a different "next mutator".
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.
(with shared pointers in the linked list of course)
flow/damage_context.h
Outdated
|
||
struct DamageResult { | ||
std::unique_ptr<FrameDescription> frame_description; | ||
SkRect damage_rect; |
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.
Rather than hard code this to have a single exposed damage rect, why not have the rect be private and have an add method that can choose to do a single rect or multiple rects. For this first pass it might just join to a single global rect. In the future we can maintain a list of rects.
Readback should support iterating a list of damage rects (which would be just one for now).
Optionally, a global damage rect could be requested for cases where the caller wants to do a quick rejection of something on the entire set of damage regardless of whether the implementation kept multiple rects or not.
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.
I wanted to talk about this. I agree that api should expose a list.
In theory we can use SkRegion to get a perfect list of non overlapping rectangles, but the issue here is that we also need to restrict rendering to those rectangles. That'd need either a preroll (for culling) and a paint for each rectangle, or cull only once for union and have skia clip to a complex shape.
So we might want to find a middle ground, i.e. if we have two small non overlapping rectangle in each corner, render them separately, but for most overlapped rectangles just join them.
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.
I don't think we need to implement the multi-rect accumulation in the first pass, I was just saying that we should create an implementation that will work when we do. SkRegion supports iterating rectangles and if we had an IRect vector that would as well.
We should be able to pre-roll only once and then do multiple paint passes.
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 commit introduces DamageArea
class instead of exposing single rect. The CompositorContext
behavior is changed so that it culls on DamageArea::bounds()
and then clips and paints individual rects (DamageArea::GetRects()
). At this point DamageArea
only provides one rect identical to bounds.
flow/damage_context.cc
Outdated
DamageContext::DamageResult DamageContext::FinishFrame() { | ||
DamageResult res; | ||
LayerEntrySet entries; | ||
entries.insert(layer_entries_.begin(), layer_entries_.end()); |
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.
Order matters. If we draw a rectangle and then a circle in one frame and in the next we've reversed their order and drawn the circle and then the rectangle (ignoring the fact that simply drawing a rectangle and a circle would get combined into a Picture, but generalize those concepts to 2 different engine layers that change order) - we need to repaint them. Using a set says that as long as they are still in the scene in the same device location we don't care when they get repainted. That is not true.
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.
Indeed. Thanks for pointing this out. I'll address this.
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.
knopp@b50df38 should take care of layers that are identical but painted in different order.
@knopp do you save the previous painting to a texture ? I didn't found it. Maybe I miss your key point. In this solution, raster thread will need to call every layer's preroll and paint, even I just update a small rect, is that right? |
b74cc95
to
116b346
Compare
@fredlee12345678, if damage rect is requested, a quick preroll (no raster cache) will first happen for every layer to determine damage rect, and then another "real" preroll, with raster cache enabled will be performed that will also cull layers that are outside of dirty rect. after that, paint will happen for layers that have not been culled by preroll (layers that intersect damage rect) and the painting will also be clipped to damage rect by skia. |
116b346
to
4805738
Compare
So...For example, I write a scroll view using grid widget have 10 cells, and I just change 1 cell. So my question is that, how many preroll function and paint function will you call? as your description, so will call 10 quick preroll, and 10 "real" preroll, and how many paint will happen? just painting the dirty layer, so how about the other 9 layers? do you restore the result of other 9 layers in damage context or other place? |
These need to contribute to damage rect
IIf we go with deep compare this certainly helps performance However ideally we should just hash the content and compare hashes
This needs to be done as quickly as possible in order to determine dirty rectangle which will be used to cull layers in “real” preroll.
659936f
to
7184a54
Compare
@fredlee12345678 how many layers will be painted depends on whether each cell has repaint boundary and also whether the backbuffer is intact. so in case, where cell has repaint boundary and back buffer was blit from and not flipped, we can in theory repaint just one cell. |
In compositor_context.cc: if (canvas()) { The canvas has been cleared. If you don't paint the other cells, it will blank. So how do you resolve this case? |
@fredlee12345678, if you look right before the code you pasted: if (canvas() && damage_rect != frame_rect) {
canvas()->save();
canvas()->clipRect(damage_rect);
} Clearing the canvas and subsequent drawing is clipped on damage rect. |
Left some suggestions in flutter/flutter#33939 (comment) |
Moved to #21126. |
Description
This PR adds api to track damage rectangles during rendering. Usage is relatively simple, it introduces the following structure in
compositor_context.h
This can be provided as argument to
CompositorContext::ScopedFrame::Raster
. The caller is responsible for providingprevious_frame_description
, which was obtained during previous rasterization to current framebuffer, as well as storing incomingframe_description
.Related Issues
flutter/flutter#33939
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.Breaking Change
This shouldn't be breaking change, if
frame_damage
is not provided (default).However it does prevent rendering of picture, physical shape and texture layers that are outside of cull rect.
Did any tests fail when you ran them? Please read [handling breaking changes].