-
Notifications
You must be signed in to change notification settings - Fork 6k
Started providing the GPU sync switch to Rasterizer.DrawToSurface() #28383
Started providing the GPU sync switch to Rasterizer.DrawToSurface() #28383
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat. If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
gaaclarke
left a comment
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 think you are right that this is the best approach to fix these bugs for now. You make a compelling argument that this could fix the linked issue but we don't 100% know. We do know it does fix some issues.
In the future we should look into implementing a solution that doesn't require a mutex lock every frame.
fml/synchronization/sync_switch.h
Outdated
|
|
||
| private: | ||
| mutable std::mutex mutex_; | ||
| mutable std::recursive_mutex mutex_; |
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.
Is there a reason this is recursive? I'd rather not make it recursive. I don't think anyone under DoDraw should be executing the sync switch, no?
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.
Replaced here with std::recursive_mutex is to let Scenario App Integration Tests pass,This is the test result before the replacement:https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8837385340239046353/+/u/Scenario_App_Integration_Tests/stdout?format=raw.
The reason is that external view embedders also use SyncSwitch. #22302
So there are two options.
- Use
std::recursive_mutexinstead ofstd::mutex. This solution has a small workload but may have poor performance - Remove the SyncSwitch used by external view embedders. This solution may have some workload
Please let me know if you prefer the second option, my original plan was to land this PR first, and then see if we can remove the SyncSwitch in the external view embedders.
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 think we should do the second thing, remove the sync switch from the external view embedders, this lock supersedes that one.
Rasterizer::Draw
-> Rasterizer::DoDraw
-> Rasterizer::DrawToSurface
-> FlutterPlatformViewsController::SubmitFrame
-> SyncSwitch::Execute
However look at Rasterizer::DrawLastLayerTree, potentially that is using the sync switch since that calls Rasterizer::DrawToSurface outside of Rasterizer::Draw
Rasterizer::DrawLastLayerTree
-> Rasterizer::DrawToSurface
-> FlutterPlatformViewsController::SubmitFrame
-> SyncSwitch::Execute
That means we should use the sync switch in Rasterizer::DrawToSurface instead of Rasterizer::Draw. Instead of removing or adding a sync switch, we can think of this as just moving the existing one in FlutterPlatformViewsController up one more layer. From the stack traces we've seen this should be a good place to have it still.
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.
Currently, if we are in the background, the RasterStatus we return is RasterStatus::kDiscarded.I can be sure that there is no problem, because the following code also returns RasterStatus::kDiscarded in Draw.
if (discardCallback(*layer_tree.get())) {
raster_status = RasterStatus::kDiscarded;
}
But if we move sync switch to Rasterizer::DrawToSurface, and in the background in iOS we retuns RasterStatus::kDiscarded from Rasterizer::DrawToSurface, how should Rasterizer::DoDraw handle it?
https://github.com/flutter/engine/blob/master/shell/common/rasterizer.cc#L380-L388
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.
RasterStatus::kDiscarded is Added by #21179.
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'd return kDiscarded from DrawToSurface and in DoDraw expand the branch that checks return codes to early out like so:
RasterStatus raster_status =
DrawToSurface(*frame_timings_recorder, *layer_tree);
if (raster_status == RasterStatus::kSuccess) {
last_layer_tree_ = std::move(layer_tree);
} else if (raster_status == RasterStatus::kResubmit ||
raster_status == RasterStatus::kSkipAndRetry) {
resubmitted_layer_tree_ = std::move(layer_tree);
return raster_status;
} else if (raster_status = RasterStatus::kDiscarded) {
return raster_status;
}I think that should be 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.
I got it. Another problem is that we need to wrap a method outside DrawToSurface to handle sync switch (such as DrawToSurfaceWrapper), DoDraw and DrawLastLayerTree should call DrawToSurfaceWrapper instead of DrawToSurface . Here I need a good method name because I am not a native speaker.
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.
"Wrapper" isn't that good since it doesn't tell you anything interesting about the code's semantics, just how it is structured.
How about his:
RasterStatus DrawToSurface() {
RasterStatus result;
...
IsGpuDisabledSyncSwitch().execute(Handlers()
.SetIfTrue([]{result = kDiscarded;})
.SetIfFalse([]{result = DrawToSurfaceUnSafe()});
...
}We use the "UnSafe" postfix in other code in the engine to denote the context with which it should be used is enforced higher in the call stack.
Is that was you were asking about?
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.
Is that was you were asking about?
Yes, I got it
shell/common/rasterizer.cc
Outdated
| } else { | ||
| raster_status = | ||
| DoDraw(std::move(frame_timings_recorder), std::move(layer_tree)); | ||
| if (!layer_tree || !surface_) { |
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.
Leave this to DoDraw, this creates an early return that didn't exist previously.
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.
The early return here is used to ensure that surface_ is not null pointer, because we need to use it right away
if (surface_->AllowsDrawingWhenGpuDisabled()) {
raster_status = DoDraw(std::move(frame_timings_recorder),
std::move(layer_tree));
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.
Good call, lets change it to:
if (!layer_tree || !surface_) {
raster_status = RasterStatus::kFailed;
} else if (surface_->AllowsDrawingWhenGpuDisabled()) {
raster_status = DoDraw(...);
} else {
...
}This removes the new early out. You can remove the check inside of DoDraw too now that it is here (replace it with asserts is probably better).
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. I’m not sure if assertions can be used here, so I’ll just keep the original logic unchanged.
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.
(although this becomes moot if we make the change I just suggested in the other comment, moving the sync switch to DrawToSurface)
|
@ColdPaleLight let me know if you need any help with this PR. There are some internal customers that are interested in the fix and I'm able to take over if you don't have the time to work on this. You've been really helpful in the past, I just wanted to offer to help if you need it. |
|
Can you also make sure that "Allow edits by maintainers" is enabled. That way I can tweak the PR quickly instead of waiting for your time zone, as long as you are ok with that. |
|
Hi, @gaaclarke |
I have plenty of time, and I will try my best to land the PR as soon as possible |
"Allow edits by maintainers" is enable. You can directly modify the code if you need. |
…ers (flutter#22302)" This reverts commit 1c3bc02.
This reverts commit d1875bd.
|
I added a few unit tests to |
|
Hi, @gaaclarke
You can review this PR again. By the way, my time zone is GMT + 8,You can directly edit the code yourself if you can’t contact me. |
gaaclarke
left a comment
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.
Code looks good. I updated the tests and added some comments. I'll approve this once my changes pass CI. Thanks again for all your help! =)
shell/common/rasterizer_unittests.cc
Outdated
| bool AllowsDrawingWhenGpuDisabled() const override { | ||
| return allows_drawing_when_gpu_disabled_; | ||
| } |
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 should be a mock method too.
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
| EXPECT_TRUE(result); | ||
| auto no_discard = [](LayerTree&) { return false; }; |
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.
All of these tests have the same asserts. They aren't asserting any different behavior for the different variables.
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
| return raster_status; | ||
| } | ||
|
|
||
| RasterStatus Rasterizer::DrawToSurfaceUnsafe( |
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.
Add a comment about why it is unsafe.
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
gaaclarke
left a comment
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!
…lutter#28383) Co-authored-by: Aaron Clarke <gaaclarke>
* Roll Skia cherrypicks * Revert "Reland enable DisplayList by default (#27892)" (#28308) * Started providing the GPU sync switch to Rasterizer.DrawToSurface() (#28383) Co-authored-by: Aaron Clarke <gaaclarke> * Update licenses_skia * update .ci.yaml Co-authored-by: Jim Graham <flar@google.com> Co-authored-by: ColdPaleLight <31977171+ColdPaleLight@users.noreply.github.com>
* Started providing the GPU sync switch to Rasterizer.DrawToSurface() (#28383) Co-authored-by: Aaron Clarke <gaaclarke> * 'add branch flutter-2.6-candidate.3 to enabled_branches in .ci.yaml' * Roll skia cherrypicks * update licenses_skia Co-authored-by: ColdPaleLight <31977171+ColdPaleLight@users.noreply.github.com>
|
@gaaclarke @christopherfujino flutter 2.0.6 requests to merge the code. flutter-1.26-candidate.17 |
Update
virtual bool AllowsDrawingWhenGpuDisabled() consttoflutter:Surfaceto distinguish whetherRasterizer::DrawToSurfaceneeds to use sync switchRasterizer::DrawToSurfaceuses sync switch on iOS's OpenGLES and Metal implementation. IfRasterizer::DrawToSurfaceis called in the background, this frame will be discarded.Origin
virtual bool IsAllowDrawingToSurfaceWhenGpuDisabled() consttoflutter:Surfaceto distinguish whetherRasterizer.Drawneeds to usegpu_disable_sync_switchRasterizer.Drawusesgpu_disable_sync_switchon iOS's OpenGLES and Metal implementation. IfRasterizer.Drawis called in the background, this frame will be discarded.SyncSwitchrecursiveFixes issue:
flutter/flutter#89171
maybe can fix: flutter/flutter#89204(edit gaaclarke: we have evidence that it's a different issue).about test:
If we confirm to use this patch, I can add tests
Pre-launch Checklist
writing and running engine tests.
///).