-
Notifications
You must be signed in to change notification settings - Fork 6k
Only creates 'onscreen_surface_' when it's not available in 'AndroidSurfaceGL::CreateSnapshotSurface' #30590
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. |
|
|
||
| std::unique_ptr<Surface> AndroidSurfaceGL::CreatePbufferSurface() { | ||
| onscreen_surface_ = GLContextPtr()->CreatePbufferSurface(); | ||
| if (!onscreen_surface_ || !onscreen_surface_->IsValid()) { |
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.
Maybe just an early return instead? This needs a test 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.
If we early return, then Rasterizer::DoMakeRasterSnapshot will execute the following logic, which will change from hardware rasterization to software rasterization. The performance will be a little bit worse, but the logic should be correct. If you think an early return is more reasonable, I'm happy to tweak the code.
engine/shell/common/rasterizer.cc
Lines 292 to 297 in 30f048d
| if (!snapshot_surface) { | |
| // Raster surface is fine if there is no on screen surface. This might | |
| // happen in case of software rendering. | |
| sk_sp<SkSurface> sk_surface = SkSurface::MakeRaster(image_info); | |
| result = DrawSnapshot(sk_surface, draw_callback); | |
| } else { |
And about test, I'm not sure how to test this, would you mind giving me some suggestions ? Thank you :) .
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 thought about it again, the early return will introduce a new problem. If Rasterizer::DoMakeRasterSnapshot is executed multiple times when the app is in the background. The first time there is no problem, and AndroidSurfaceGL::on_screen_surface_ which size is 1x1 is created, but the second time, because AndroidSurfaceGL::on_screen_surface_ already exists, it is returned early. As a result, Rasterizer::DoMakeRasterSnapshot has changed from hardware rasterization to software rasterization.
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 the part I'm not clear on is how we'd get here.
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 the part I'm not clear on is how we'd get here.
Although I can't provide a reproducible sample, it appeared many times in my application, and I finally found the reason for the problem by printing the Log, and the problem was triggered by this line of code.
https://github.com/flutter/flutter/blob/019f03374c5b106c3fde05c8eee930cd26b8ffff/packages/flutter/lib/src/painting/shader_warm_up.dart#L95
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 this is a combination of a few things:
- The platform thread creates the onscreen surface
- It then calls
Shell::NotifyCreated - NotifyCreated fire and forgets the UI task runner, which might schedule an image decode (this is a recent change, from November or Decemberish)
- The rasterizer setup is called, but now there's a race where the UI thread might have asked the rasterizer to make a snapshot before it has been setup
- If the UI thread beats rasterizer setup, the rasterizer will say it doesn't have a surface to work with and ask for a snapshotting surface. The AndroidContextGL creates a pbuffer surface for this and sets it as the onscreen_surface_, which destroys the one we actually want.
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.
So what I think should happen here is the following:
- Rename
AndroidSurfaceGL::CreatePbufferSurfaceto something likeAndroidSurfaceGL::GetOrCreateSnapshotSurface. - Have that renamed method only create the Pbuffer surface if
onscreen_surface_is null/invalid. Otherwise, returnonscreen_surface_. - Write a test that exercises this, e.g. latch the raster task runner before
NotifyCreatedis called, run some Dart code that calls and completestoImage, unlatch the raster task runner, make sure the rasterizer surface is the right one.
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.
Have that renamed method only create the Pbuffer surface if onscreen_surface_ is null/invalid. Otherwise, return onscreen_surface_.
What happens if the buffer isn't a Pbuffer at this time? Does it make sense to destroy the existing surface and then create the actual Pbuffer?
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.
No. We just want to make sure that we have a GPU backed surface and don't end up in the software backend code.
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.
So what I think should happen here is the following:
- Rename
AndroidSurfaceGL::CreatePbufferSurfaceto something likeAndroidSurfaceGL::GetOrCreateSnapshotSurface.- Have that renamed method only create the Pbuffer surface if
onscreen_surface_is null/invalid. Otherwise, returnonscreen_surface_.- Write a test that exercises this, e.g. latch the raster task runner before
NotifyCreatedis called, run some Dart code that calls and completestoImage, unlatch the raster task runner, make sure the rasterizer surface is the right one.
@dnfield
We can't return onscreen_surface_ because the type of the return value is std::unique_ptr<Surface>, but the type of onscreen_surface_ is std::unique_ptr<AndroidEGLSurface>. So in either case we have to create a new std::unique_ptr<Surface>. so I renamed it to AndroidSurfaceGL::CreateSnapshotSurface. I also added test cases as you said in discord.
…urfaceGL::CreatePbufferSurface'
754f1c4 to
822d4af
Compare
| // |GPUSurfaceGLDelegate| | ||
| sk_sp<const GrGLInterface> GetGLInterface() const override; | ||
|
|
||
| AndroidEGLSurface* GetOnscreenSurface() const { |
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.
Please add a doc comment, probably explaining that this is only intended for tests.
e.g.
// Obtain a raw pointer to the AndroidEGLSurface. This method is intended for use in tests. Callers must not delete this pointer.
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 went ahead and made this change so we can just get this landed, rather than wait for another time zone cycle :)
dnfield
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 with doc nit
…AndroidSurfaceGL::CreateSnapshotSurface' (flutter/engine#30590)
…urfaceGL::CreateSnapshotSurface' (flutter#30590) * Only creates 'onscreen_surface_' when it's not available in 'AndroidSurfaceGL::CreatePbufferSurface' * Rename the function and add some unit tests * Update android_surface_gl.h Co-authored-by: Dan Field <[email protected]>
fix issue: flutter/flutter#95957
There will be a situation where
AndroidSurfaceGL::on_screen_surface_is set, butRasterizer::surface_has not been set. So when'AndroidSurfaceGL::CreatePbufferSurface' is called,AndroidSurfaceGL::on_screen_surface_may already exist. At this time, we should not generate a new one, but should directly use the existing one.Pre-launch Checklist
writing and running engine tests.
///).