Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Use a Pbuffer surface when the onscreen surface is not available for snapshotting on Android #27141

Merged
merged 14 commits into from
Jul 20, 2021

Conversation

dnfield
Copy link
Contributor

@dnfield dnfield commented Jul 2, 2021

When rasterizing a Picture or Scene, we normally try to use the on screen surface. If it's not available, we go down a raster based path. However, this won't work if the image contains images that were uploaded via the resource context - Skia won't draw the pixels into the resulting picture.

We can't use the resource context from the raster thread either, and rasterizing the image on the IO thread has been attempted but does not work.

This patch adds a 1x1 pbuffer for use if the on screen surface is not available, and rasterizes using that. It only applies to Android since it is GL and background specific - on the iOS GL backend it would be illegal to use the GPU from the background anyway.

Fixes flutter/flutter#73675
Fixes flutter/flutter#86680

Need to figure out the right way to add this test case: flutter/flutter#73675 (comment)

@dnfield
Copy link
Contributor Author

dnfield commented Jul 2, 2021

Something's wrong here - in the midst of refacotring/cleaning up I broke the test I have.

@dnfield dnfield closed this Jul 2, 2021
@dnfield dnfield reopened this Jul 7, 2021
stderr=subprocess.STDOUT,
universal_newlines=True,
)
return process
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes here are to run multiple firebase testlab tests in parallel. Now that we're running two this makes a difference. The new test executes pretty quickly but still requires setup/upload/results processing time.

@dnfield dnfield marked this pull request as ready for review July 16, 2021 17:09
@dnfield
Copy link
Contributor Author

dnfield commented Jul 16, 2021

This patch is ready for review.

@dnfield
Copy link
Contributor Author

dnfield commented Jul 16, 2021

Sorry for the size, a substantial number of files are testing support related files :\

if (!surface_) {
pbuffer_surface = delegate_.CreateSnapshotSurface();
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the redundancy of surface_ versus pbuffer_surface be reduced?

e.g. with something like

Surface* snapshot_surface = nullptr;
if (surface_ && surface_->GetContext()) {
  snapshot_surface = surface_.get();
} else {
  pbuffer_surface = delegate_.CreateSnapshotSurface();
  if (pbuffer_surface && pbuffer_surface->GetContext())
    snapshot_surface = pbuffer_surface.get();
}

The rest of the method can then only use snapshot_surface

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd ahve to manually delete the surface if it came from CreateSnapshotSurface then though. like pbuffer_surface.release() and then a delete at the end if it's not nullptr and not the surface_.get(). Is there some way I'm missing?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pbuffer_surface would be a unique_ptr declared at the same scope as snapshot_surface. If pbuffer_surface is assigned then it will be deleted when the function exits.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I get it now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

///
/// This is the only public method of this interface called on the
/// raster task runner.
virtual std::unique_ptr<Surface> CreateRasterSnapshotSurface();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to avoid having a method on PlatformView which is a special case that is not called on the platform thread?

One potential option would be creating another interface similar to ExternalViewEmbedder that is instantiated by the PlatformView and then given to the Rasterizer by the Shell.

Like AndroidExternalViewEmbedder, this object could hold a reference to the AndroidContext and use that to create the pbuffer surface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea. I'll try to do this - I think it'll get rid of some of the funky threading concerns around accessing the platform view.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, latest commit has these changes. This gets rid of the threading concern/note that I had in platform view before. @chinmaygarde FYI

@dnfield
Copy link
Contributor Author

dnfield commented Jul 19, 2021

Build failure is because the gradlew script is missing from the project dir. Currently it's gitignored. @blasten is there a better way to handle this than checking in gradlew?

@blasten
Copy link

blasten commented Jul 19, 2021

If the intention is to build with Gradle, then there are two options, but really just one (see 2).

  1. Run with the installed version of gradle gradle <task-name>. Unfortunately, this version must match the version required by the project, which makes a direct dependency on the environment, and doesn't scale if you later check in another project, and it requires a different version.

  2. Check in gradlew. Generate the wrapper with gradle wrapper assuming you have the right version locally.

@dnfield
Copy link
Contributor Author

dnfield commented Jul 20, 2021

@blasten - looks like gradlew is unhappy with buildtools?

https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket.appspot.com/8841170477406727600/+/u/build_android_profile_x64__default_clang_x64_gen_snapshot_/build_android_profile_x64_default_clang_x64_gen_snapshot/stdout#L8363_8

[3880/3895] ACTION //flutter/testing/scenario_app/android:android_lint(//build/toolchain/android:clang_x64)
 FAILED: scenario_app/build/reports 
 python ../../flutter/testing/rules/run_gradle.py /b/s/w/ir/cache/builder/src/flutter/testing/scenario_app/android lint --no-daemon -Pflutter_jar=/b/s/w/ir/cache/builder/src/out/android_profile_x64/flutter.jar -Pout_dir=/b/s/w/ir/cache/builder/src/out/android_profile_x64/scenario_app --project-cache-dir=\"/b/s/w/ir/cache/builder/src/out/android_profile_x64/scenario_app/.gradle\" --gradle-user-home=\"/b/s/w/ir/cache/builder/src/out/android_profile_x64/scenario_app/.gradle\" -Plibapp=/b/s/w/ir/cache/builder/src/out/android_profile_x64/gen/flutter/testing/scenario_app/android/libs
 FAILURE: Build failed with an exception.
 * What went wrong:
 Could not determine the dependencies of task ':app:compileReleaseJavaWithJavac'.
 > Installed Build Tools revision 29.0.2 is corrupted. Remove and install again using the SDK Manager.

@dnfield
Copy link
Contributor Author

dnfield commented Jul 20, 2021

Checking if it's a flake...

@dnfield
Copy link
Contributor Author

dnfield commented Jul 20, 2021

AFAICT gradle is trying to download buildtools 30.0.2 and CI doesn't like it.

I don't have permissions to update the CIPD packages to add 30.0.2 and roll us to that. @blasten @godofredoc

std::unique_ptr<Surface> CreateSnapshotSurface() override;

private:
std::shared_ptr<AndroidSurface> android_surface_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should hold a reference to the AndroidSurface instead of converting AndroidSurface into a shared pointer.
(similar to the AndroidContext& held by the AndroidExternalViewEmbedder)

I don't think it's safe to delete the last AndroidSurface pointer on a thread other than the platform thread.

Normally this would not happen because the Shell would delete the Rasterizer before the PlatformView, which would ensure that the PlatformView's pointer to the AndroidSurface would be the last to go. But if the PlatformView must be responsible for deleting the AndroidSurface, then I'd prefer to formalize that by having the PlatformView hold a unique_ptr.

Alternatively, CreateSnapshotSurface could be moved out of AndroidSurface and into AndroidContext. The AndroidSurfaceGL::CreatePbufferSurface implementation is delegating to AndroidContextGL and does not use any of AndroidSurfaceGL's state.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do need an AndroidSurfaceGL to create a GPUSurfaceGL which is what the rasterizer expects to interact with. I'll ook at using the ref.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a ref is less than ideal because it access a bunch of non-const methods.

I'm using a weak_ptr which I think should be safe w.r.t. your concerns.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok - weak_ptr doesn't actually solve this problem, because we'd still potentially release the shared_ptr on the wrong thread. changed to a non-const reference.

@dnfield dnfield merged commit a1180b1 into flutter:master Jul 20, 2021
dnfield added a commit that referenced this pull request Jul 20, 2021
…ble for snapshotting on Android (#27141)"

This reverts commit a1180b1.
dnfield added a commit that referenced this pull request Jul 20, 2021
…ble for snapshotting on Android (#27141)" (#27607)

This reverts commit a1180b1.
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 21, 2021
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 21, 2021
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 21, 2021
dnfield added a commit to dnfield/engine that referenced this pull request Jul 21, 2021
dnfield added a commit that referenced this pull request Jul 21, 2021
* Reland "Use a Pbuffer surface when the onscreen surface is not available for snapshotting on Android (#27141)" (#27607)"

This reverts commit 0c121d3.

* Do not let gradle download SDK deps
naudzghebre pushed a commit to naudzghebre/engine that referenced this pull request Sep 2, 2021
naudzghebre pushed a commit to naudzghebre/engine that referenced this pull request Sep 2, 2021
naudzghebre pushed a commit to naudzghebre/engine that referenced this pull request Sep 2, 2021
* Reland "Use a Pbuffer surface when the onscreen surface is not available for snapshotting on Android (flutter#27141)" (flutter#27607)"

This reverts commit 0c121d3.

* Do not let gradle download SDK deps
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
3 participants