Skip to content

Commit 5619d83

Browse files
committed
Reland "Use a Pbuffer surface when the onscreen surface is not available for snapshotting on Android (flutter#27141)" (flutter#27607)"
This reverts commit 0c121d3.
1 parent ff7b6e8 commit 5619d83

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+985
-106
lines changed

BUILD.gn

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ group("flutter") {
121121
public_deps += [ "//flutter/testing/scenario_app" ]
122122
}
123123

124+
if (is_android && flutter_runtime_mode == "profile" &&
125+
current_cpu == "arm64") {
126+
public_deps += [ "//flutter/testing/android_background_image" ]
127+
}
128+
124129
# Compile all unittests targets if enabled.
125130
if (enable_unittests) {
126131
public_deps += [

ci/firebase_testlab.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,28 @@
1919

2020

2121
def RunFirebaseTest(apk, results_dir):
22-
try:
23-
# game-loop tests are meant for OpenGL apps.
24-
# This type of test will give the application a handle to a file, and
25-
# we'll write the timeline JSON to that file.
26-
# See https://firebase.google.com/docs/test-lab/android/game-loop
27-
# Pixel 4. As of this commit, this is a highly available device in FTL.
28-
subprocess.check_output([
29-
'gcloud',
30-
'--project', 'flutter-infra',
31-
'firebase', 'test', 'android', 'run',
32-
'--type', 'game-loop',
33-
'--app', apk,
34-
'--timeout', '2m',
35-
'--results-bucket', bucket,
36-
'--results-dir', results_dir,
37-
'--device', 'model=flame,version=29',
38-
])
39-
except subprocess.CalledProcessError as ex:
40-
print(ex.output)
41-
# Recipe will retry return codes from firebase that indicate an infra
42-
# failure.
43-
sys.exit(ex.returncode)
22+
# game-loop tests are meant for OpenGL apps.
23+
# This type of test will give the application a handle to a file, and
24+
# we'll write the timeline JSON to that file.
25+
# See https://firebase.google.com/docs/test-lab/android/game-loop
26+
# Pixel 4. As of this commit, this is a highly available device in FTL.
27+
process = subprocess.Popen(
28+
[
29+
'gcloud',
30+
'--project', 'flutter-infra',
31+
'firebase', 'test', 'android', 'run',
32+
'--type', 'game-loop',
33+
'--app', apk,
34+
'--timeout', '2m',
35+
'--results-bucket', bucket,
36+
'--results-dir', results_dir,
37+
'--device', 'model=flame,version=29',
38+
],
39+
stdout=subprocess.PIPE,
40+
stderr=subprocess.STDOUT,
41+
universal_newlines=True,
42+
)
43+
return process
4444

4545

4646
def CheckLogcat(results_dir):
@@ -87,13 +87,25 @@ def main():
8787
git_revision = subprocess.check_output(
8888
['git', 'rev-parse', 'HEAD'], cwd=script_dir).strip()
8989

90+
results = []
9091
for apk in apks:
9192
results_dir = '%s/%s/%s' % (os.path.basename(apk), git_revision, args.build_id)
92-
93-
RunFirebaseTest(apk, results_dir)
93+
process = RunFirebaseTest(apk, results_dir)
94+
results.append((results_dir, process))
95+
96+
for results_dir, process in results:
97+
for line in iter(process.stdout.readline, ""):
98+
print(line.strip())
99+
return_code = process.wait()
100+
if return_code != 0:
101+
print('Firebase test failed ' + returncode)
102+
sys.exit(process.returncode)
103+
104+
print('Checking logcat for %s' % results_dir)
94105
CheckLogcat(results_dir)
95106
# scenario_app produces a timeline, but the android image test does not.
96107
if 'scenario' in apk:
108+
print('Checking timeline for %s' % results_dir)
97109
CheckTimeline(results_dir)
98110

99111
return 0

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ FILE: ../../../flutter/shell/common/shell_unittests.cc
725725
FILE: ../../../flutter/shell/common/skia_event_tracer_impl.cc
726726
FILE: ../../../flutter/shell/common/skia_event_tracer_impl.h
727727
FILE: ../../../flutter/shell/common/skp_shader_warmup_unittests.cc
728+
FILE: ../../../flutter/shell/common/snapshot_surface_producer.h
728729
FILE: ../../../flutter/shell/common/switches.cc
729730
FILE: ../../../flutter/shell/common/switches.h
730731
FILE: ../../../flutter/shell/common/thread_host.cc
@@ -932,6 +933,8 @@ FILE: ../../../flutter/shell/platform/android/surface/android_surface.cc
932933
FILE: ../../../flutter/shell/platform/android/surface/android_surface.h
933934
FILE: ../../../flutter/shell/platform/android/surface/android_surface_mock.cc
934935
FILE: ../../../flutter/shell/platform/android/surface/android_surface_mock.h
936+
FILE: ../../../flutter/shell/platform/android/surface/snapshot_surface_producer.cc
937+
FILE: ../../../flutter/shell/platform/android/surface/snapshot_surface_producer.h
935938
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.cc
936939
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.h
937940
FILE: ../../../flutter/shell/platform/common/accessibility_bridge.cc

shell/common/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ source_set("common") {
8989
"shell_io_manager.h",
9090
"skia_event_tracer_impl.cc",
9191
"skia_event_tracer_impl.h",
92+
"snapshot_surface_producer.h",
9293
"switches.cc",
9394
"switches.h",
9495
"thread_host.cc",

shell/common/platform_view.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ void PlatformView::SetViewportMetrics(const ViewportMetrics& metrics) {
6767

6868
void PlatformView::NotifyCreated() {
6969
std::unique_ptr<Surface> surface;
70-
7170
// Threading: We want to use the platform view on the non-platform thread.
7271
// Using the weak pointer is illegal. But, we are going to introduce a latch
7372
// so that the platform view is not collected till the surface is obtained.
@@ -182,4 +181,9 @@ void PlatformView::UpdateAssetResolverByType(
182181
delegate_.UpdateAssetResolverByType(std::move(updated_asset_resolver), type);
183182
}
184183

184+
std::unique_ptr<SnapshotSurfaceProducer>
185+
PlatformView::CreateSnapshotSurfaceProducer() {
186+
return nullptr;
187+
}
188+
185189
} // namespace flutter

shell/common/platform_view.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class PlatformView {
6262
/// Metal, Vulkan) specific. This is usually a sign to the
6363
/// rasterizer to set up and begin rendering to that surface.
6464
///
65-
/// @param[in] surface The surface
65+
/// @param[in] surface The surface
6666
///
6767
virtual void OnPlatformViewCreated(std::unique_ptr<Surface> surface) = 0;
6868

@@ -796,6 +796,22 @@ class PlatformView {
796796
std::unique_ptr<AssetResolver> updated_asset_resolver,
797797
AssetResolver::AssetResolverType type);
798798

799+
//--------------------------------------------------------------------------
800+
/// @brief Creates an object that produces surfaces suitable for raster
801+
/// snapshotting. The rasterizer will request this surface if no
802+
/// on screen surface is currently available when an application
803+
/// requests a snapshot, e.g. if `Scene.toImage` or
804+
/// `Picture.toImage` are called while the application is in the
805+
/// background.
806+
///
807+
/// Not all backends support this kind of surface usage, and the
808+
/// default implementation returns nullptr. Platforms should
809+
/// override this if they can support GPU operations in the
810+
/// background and support GPU resource context usage.
811+
///
812+
virtual std::unique_ptr<SnapshotSurfaceProducer>
813+
CreateSnapshotSurfaceProducer();
814+
799815
protected:
800816
PlatformView::Delegate& delegate_;
801817
const TaskRunners task_runners_;
@@ -804,8 +820,7 @@ class PlatformView {
804820
SkISize size_;
805821
fml::WeakPtrFactory<PlatformView> weak_factory_;
806822

807-
// Unlike all other methods on the platform view, this is called on the
808-
// raster task runner.
823+
// This is the only method called on the raster task runner.
809824
virtual std::unique_ptr<Surface> CreateRenderingSurface();
810825

811826
private:

shell/common/rasterizer.cc

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,22 @@ sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
258258
sk_sp<SkImage> result;
259259
SkImageInfo image_info = SkImageInfo::MakeN32Premul(
260260
size.width(), size.height(), SkColorSpace::MakeSRGB());
261-
if (surface_ == nullptr || surface_->GetContext() == nullptr) {
261+
262+
std::unique_ptr<Surface> pbuffer_surface;
263+
Surface* snapshot_surface = nullptr;
264+
if (surface_ && surface_->GetContext()) {
265+
snapshot_surface = surface_.get();
266+
} else if (snapshot_surface_producer_) {
267+
pbuffer_surface = snapshot_surface_producer_->CreateSnapshotSurface();
268+
if (pbuffer_surface && pbuffer_surface->GetContext())
269+
snapshot_surface = pbuffer_surface.get();
270+
}
271+
272+
if (!snapshot_surface) {
262273
// Raster surface is fine if there is no on screen surface. This might
263274
// happen in case of software rendering.
264-
sk_sp<SkSurface> surface = SkSurface::MakeRaster(image_info);
265-
result = DrawSnapshot(surface, draw_callback);
275+
sk_sp<SkSurface> sk_surface = SkSurface::MakeRaster(image_info);
276+
result = DrawSnapshot(sk_surface, draw_callback);
266277
} else {
267278
delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
268279
fml::SyncSwitch::Handlers()
@@ -271,12 +282,14 @@ sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
271282
result = DrawSnapshot(surface, draw_callback);
272283
})
273284
.SetIfFalse([&] {
274-
auto context_switch = surface_->MakeRenderContextCurrent();
285+
FML_DCHECK(snapshot_surface);
286+
auto context_switch =
287+
snapshot_surface->MakeRenderContextCurrent();
275288
if (!context_switch->GetResult()) {
276289
return;
277290
}
278291

279-
GrRecordingContext* context = surface_->GetContext();
292+
GrRecordingContext* context = snapshot_surface->GetContext();
280293
auto max_size = context->maxRenderTargetSize();
281294
double scale_factor = std::min(
282295
1.0, static_cast<double>(max_size) /
@@ -294,19 +307,19 @@ sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
294307

295308
// When there is an on screen surface, we need a render target
296309
// SkSurface because we want to access texture backed images.
297-
sk_sp<SkSurface> surface =
310+
sk_sp<SkSurface> sk_surface =
298311
SkSurface::MakeRenderTarget(context, // context
299312
SkBudgeted::kNo, // budgeted
300313
image_info // image info
301314
);
302-
if (!surface) {
315+
if (!sk_surface) {
303316
FML_LOG(ERROR)
304317
<< "DoMakeRasterSnapshot can not create GPU render target";
305318
return;
306319
}
307320

308-
surface->getCanvas()->scale(scale_factor, scale_factor);
309-
result = DrawSnapshot(surface, draw_callback);
321+
sk_surface->getCanvas()->scale(scale_factor, scale_factor);
322+
result = DrawSnapshot(sk_surface, draw_callback);
310323
}));
311324
}
312325

@@ -700,6 +713,11 @@ void Rasterizer::SetExternalViewEmbedder(
700713
external_view_embedder_ = view_embedder;
701714
}
702715

716+
void Rasterizer::SetSnapshotSurfaceProducer(
717+
std::unique_ptr<SnapshotSurfaceProducer> producer) {
718+
snapshot_surface_producer_ = std::move(producer);
719+
}
720+
703721
void Rasterizer::FireNextFrameCallbackIfPresent() {
704722
if (!next_frame_callback_) {
705723
return;

shell/common/rasterizer.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "flutter/fml/time/time_point.h"
2525
#include "flutter/lib/ui/snapshot_delegate.h"
2626
#include "flutter/shell/common/pipeline.h"
27+
#include "flutter/shell/common/snapshot_surface_producer.h"
2728

2829
namespace flutter {
2930

@@ -98,7 +99,7 @@ class Rasterizer final : public SnapshotDelegate {
9899
/// currently only created by the shell (which also sets itself up
99100
/// as the rasterizer delegate).
100101
///
101-
/// @param[in] delegate The rasterizer delegate.
102+
/// @param[in] delegate The rasterizer delegate.
102103
///
103104
Rasterizer(Delegate& delegate);
104105

@@ -349,6 +350,17 @@ class Rasterizer final : public SnapshotDelegate {
349350
void SetExternalViewEmbedder(
350351
const std::shared_ptr<ExternalViewEmbedder>& view_embedder);
351352

353+
//----------------------------------------------------------------------------
354+
/// @brief Set the snapshot surface producer. This is done on shell
355+
/// initialization. This is non-null on platforms that support taking
356+
/// GPU accelerated raster snapshots in the background.
357+
///
358+
/// @param[in] producer A surface producer for raster snapshotting when the
359+
/// onscreen surface is not available.
360+
///
361+
void SetSnapshotSurfaceProducer(
362+
std::unique_ptr<SnapshotSurfaceProducer> producer);
363+
352364
//----------------------------------------------------------------------------
353365
/// @brief Returns a pointer to the compositor context used by this
354366
/// rasterizer. This pointer will never be `nullptr`.
@@ -434,6 +446,7 @@ class Rasterizer final : public SnapshotDelegate {
434446
private:
435447
Delegate& delegate_;
436448
std::unique_ptr<Surface> surface_;
449+
std::unique_ptr<SnapshotSurfaceProducer> snapshot_surface_producer_;
437450
std::unique_ptr<flutter::CompositorContext> compositor_context_;
438451
// This is the last successfully rasterized layer tree.
439452
std::unique_ptr<flutter::LayerTree> last_layer_tree_;

shell/common/rasterizer_unittests.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class MockDelegate : public Rasterizer::Delegate {
3030
MOCK_CONST_METHOD0(GetTaskRunners, const TaskRunners&());
3131
MOCK_CONST_METHOD0(GetIsGpuDisabledSyncSwitch,
3232
std::shared_ptr<const fml::SyncSwitch>());
33+
MOCK_METHOD0(CreateSnapshotSurface, std::unique_ptr<Surface>());
3334
};
3435

3536
class MockSurface : public Surface {

shell/common/shell.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,8 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
634634
// Set the external view embedder for the rasterizer.
635635
auto view_embedder = platform_view_->CreateExternalViewEmbedder();
636636
rasterizer_->SetExternalViewEmbedder(view_embedder);
637+
rasterizer_->SetSnapshotSurfaceProducer(
638+
platform_view_->CreateSnapshotSurfaceProducer());
637639

638640
// The weak ptr must be generated in the platform thread which owns the unique
639641
// ptr.

0 commit comments

Comments
 (0)